Skip to content

Instantly share code, notes, and snippets.

@heinezen
Last active March 29, 2018 05:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save heinezen/6ec3e95becc26bb3bb794cf7d66f266a to your computer and use it in GitHub Desktop.
Save heinezen/6ec3e95becc26bb3bb794cf7d66f266a to your computer and use it in GitHub Desktop.
Converting SLP terrain files to flat texture
#!/usr/bin/env python3
# Copyright 2018-2018 the openage authors. See copying.md for legal info.
"""
Transforms the dimetric tiles converted from SLP files to cartesian format.
"""
import math
import argparse
from PIL import Image
def main():
"""
CLI entry point
"""
args = get_args()
inputfile = args.inputfile
# This should always be a 979x499 image
org_img = Image.open(inputfile)
tr_img = merge(org_img)
tr_img = transform(tr_img)
# Rotate is unnecessary, but HD edition does it for some reason
# tr_img = tr_img.rotate(270)
output_name = inputfile.split(".")[0] + "_flat"
to_file(tr_img, output_name)
return 0
def get_args():
"""
Get CLI arguments.
"""
parser = argparse.ArgumentParser(description=("Transforms the tiled SLP files "
"to cartesian projection."))
parser.add_argument('inputfile')
return parser.parse_args()
def merge(img):
"""
This operation merges the single tiles together. The image converted
from SLP contains 100 (10x10) different tiles for each terrain.
"""
# Our merge result will be slightly smaller than the SLP image
merge_img = Image.new('RGBA', (962, 481), (0, 0, 0, 0))
# The size of each tile in the SLP
slp_tile_width = 98
slp_tile_height = 49
# Merge offset
merge_offset_x = (1/2) * slp_tile_width
merge_offset_y = math.floor((1/2) * slp_tile_height)
# The tiles in the SLP image work like a matrix. The tile at position
# (0,0) will be put at the corresponding position - using AoE2 coordinates -
# in the merge result. The AoE2 coordinate system origin point is in
# the left corner, so our tile (0,0) goes there.
for slp_y in range(0, 10):
# The (x,y) coordinates of the tile from the source image
slp_coord_x = 0
slp_coord_y = slp_y * (slp_tile_height + 1)
merge_coord_y = 216 - (slp_y * merge_offset_y)
for slp_x in range(0, 10):
# The destination x-coordinate in the merge image
merge_coord_x = (int)((slp_x * (merge_offset_x -1))
+ slp_y * (merge_offset_x - 1))
merge_img.alpha_composite(img, (merge_coord_x, merge_coord_y),
(slp_coord_x, slp_coord_y,
(slp_coord_x + slp_tile_width),
(slp_coord_y + slp_tile_height)))
slp_coord_x += slp_tile_width
merge_coord_y += merge_offset_y
return merge_img
def transform(img):
"""
Dimetric to flat transformation.
"""
res_x, res_y = img.size
tr_res_x = (int)((1/2) * res_x)
tr_img = Image.new('RGBA', (tr_res_x, res_y), (0, 0, 0, 0))
# Get the pixels
org_pixels = img.load()
tr_pixels = tr_img.load()
# Transform the image
for x_coord in range(0, tr_res_x):
for y_coord in range(0, res_y):
# This uses the exact calculation as in transform()
tr_x = (1 * x_coord + tr_res_x - 1) - 1 * y_coord
if x_coord+y_coord < res_y:
tr_y = math.ceil(0.5 * x_coord + 0.5 * y_coord)
else:
tr_y = math.floor(0.5 * x_coord + 0.5 * y_coord)
# We just need to swap (tr_x,tr_y) and (x,y) from the other
# function to revert the projection
tr_pixels[x_coord, y_coord] = org_pixels[tr_x, tr_y]
tr_img = tr_img.rotate(270)
return tr_img
def to_file(img, filename):
"""
Writes the transformed result to file.
"""
# Use this for debugging:
# img.show()
try:
img.save(filename + ".png", "PNG")
except IOError:
print("File could not be written")
return 0
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment