1 | #!/usr/bin/env python |
---|
2 | |
---|
3 | # This file is part of PARPG. |
---|
4 | |
---|
5 | # PARPG is free software: you can redistribute it and/or modify |
---|
6 | # it under the terms of the GNU General Public License as published by |
---|
7 | # the Free Software Foundation, either version 3 of the License, or |
---|
8 | # (at your option) any later version. |
---|
9 | |
---|
10 | # PARPG is distributed in the hope that it will be useful, |
---|
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | # GNU General Public License for more details. |
---|
14 | |
---|
15 | # You should have received a copy of the GNU General Public License |
---|
16 | # along with PARPG. If not, see <http://www.gnu.org/licenses/> |
---|
17 | |
---|
18 | import sys |
---|
19 | import pygame |
---|
20 | |
---|
21 | # place defines here |
---|
22 | |
---|
23 | TILE_WIDTH = 72 |
---|
24 | TILE_HEIGHT = 36 |
---|
25 | # is this is true, output a file of the pics together in the current folder |
---|
26 | STITCH = False |
---|
27 | |
---|
28 | # this is very much a simple routine, but we still have a simple class |
---|
29 | |
---|
30 | class TileImage: |
---|
31 | def __init__(self, picture, name, y_off): |
---|
32 | self.image = picture |
---|
33 | self.filename = name |
---|
34 | self.y_offset = y_off |
---|
35 | |
---|
36 | def writeXML(name, y_off): |
---|
37 | """Write the XML file as well |
---|
38 | Always the same small file so we do it automatically""" |
---|
39 | # we need to strip off the entire path up to the last |
---|
40 | # TODO: this code will not work on windows |
---|
41 | # strip off the png part and replace with the XML |
---|
42 | filename = name.split('/')[-1] |
---|
43 | if(filename == name): |
---|
44 | filename = name.split('\\')[-1] |
---|
45 | x_file = open(name[:-4]+".xml","wt") |
---|
46 | x_file.write('''<?fife type="object"?>\n''') |
---|
47 | x_file.write('''<object id="''') |
---|
48 | x_file.write(filename[:-4]) |
---|
49 | x_file.write('''" namespace="PARPG" blocking="1" static="1">\n''') |
---|
50 | x_file.write(''' <image source="''') |
---|
51 | x_file.write(filename) |
---|
52 | x_file.write('''" direction="0"''') |
---|
53 | x_file.write(''' y_offset="''') |
---|
54 | x_file.write(y_off) |
---|
55 | x_file.write('''" />\n''') |
---|
56 | # the \n\n is ESSENTIAL otherwise the XML parser in FIFE craps out! |
---|
57 | x_file.write('''</object>\n\n''') |
---|
58 | x_file.close |
---|
59 | |
---|
60 | def stitchImages(files, width, height): |
---|
61 | """Put the images together and output them to stitched.png""" |
---|
62 | new_image = pygame.Surface((width, height), pygame.SRCALPHA, 32) |
---|
63 | x_pos = 0 |
---|
64 | for i in files: |
---|
65 | new_image.blit(i.image, (x_pos, 0)) |
---|
66 | x_pos += i.image.get_width() |
---|
67 | pygame.image.save(new_image, "stitched.png") |
---|
68 | |
---|
69 | def saveFiles(files): |
---|
70 | """Given a list of TileImages, output them as seperate files |
---|
71 | Returns True if it worked""" |
---|
72 | # files is a list of TileImages |
---|
73 | complete = [] |
---|
74 | width = 0 |
---|
75 | height = 0 |
---|
76 | for i in files: |
---|
77 | width += i.image.get_width() |
---|
78 | if(i.image.get_height() > height): |
---|
79 | height = i.image.get_height() |
---|
80 | try: |
---|
81 | pygame.image.save(i.image, i.filename) |
---|
82 | # output the XML file as well |
---|
83 | writeXML(i.filename, str(i.y_offset)) |
---|
84 | except: |
---|
85 | print "Error: Failed to save",i.filename |
---|
86 | # if we saved some anyway, then tell the user |
---|
87 | if(complete != []): |
---|
88 | print " Managed to save", |
---|
89 | for name in complete: |
---|
90 | print name, |
---|
91 | print "\n" |
---|
92 | return False |
---|
93 | complete.append(i.filename) |
---|
94 | # seems like all was ok |
---|
95 | if(STITCH == True): |
---|
96 | stitchImages(files, width, height) |
---|
97 | return True |
---|
98 | |
---|
99 | def splitImage(image, filename, data): |
---|
100 | """Quite complex this, as there are many differing layouts on the |
---|
101 | hexes that we could be dealing with. We blit from left to right |
---|
102 | data holds the hex position changes in [x,y] format. |
---|
103 | by one and the y value staying the same (on the grid map)""" |
---|
104 | # the starting point for the grab is always the middle of the image |
---|
105 | height = (image.get_height() / 2) + (TILE_HEIGHT / 2) |
---|
106 | x_pos = 0 |
---|
107 | file_counter = 0 |
---|
108 | tiles = [] |
---|
109 | height_adjust = 0 |
---|
110 | y_off_next = -((height - TILE_HEIGHT) / 2) |
---|
111 | for t in data: |
---|
112 | y_off = y_off_next |
---|
113 | if(t == 'm'): |
---|
114 | # switchback, so this tile must fill the whole width |
---|
115 | width += TILE_WIDTH / 2 |
---|
116 | height_adjust = TILE_HEIGHT / 2 |
---|
117 | y_off_next += (TILE_HEIGHT / 4) + (TILE_HEIGHT / 2) |
---|
118 | xoff = 0 |
---|
119 | elif(t == 'r'): |
---|
120 | # moving forward on the y axis |
---|
121 | width = TILE_WIDTH / 2 |
---|
122 | height_adjust = - (TILE_HEIGHT / 2) |
---|
123 | y_off_next += TILE_HEIGHT / 4 |
---|
124 | xoff = TILE_WIDTH / 2 |
---|
125 | elif(t == 'l'): |
---|
126 | # moving forward on the x axis |
---|
127 | width = TILE_WIDTH / 2 |
---|
128 | height_adjust = TILE_HEIGHT / 2 |
---|
129 | y_off_next -= TILE_HEIGHT / 4 |
---|
130 | xoff = 0 |
---|
131 | else: |
---|
132 | # TODO: Handle integer moves (i.e. > 1 tile up down) |
---|
133 | print "Error: Can't handle integer tile moves yet" |
---|
134 | sys.exit(False) |
---|
135 | # if the image is 256, then adjust |
---|
136 | # bug in the FIFE OpenGL code |
---|
137 | if(height == 256): |
---|
138 | height += 1 |
---|
139 | # build the new surface |
---|
140 | new_surface = pygame.Surface((TILE_WIDTH, height), \ |
---|
141 | pygame.SRCALPHA, 32) |
---|
142 | # now blit a strip of the image across |
---|
143 | new_surface.blit(image, (0+xoff, 0), pygame.Rect(x_pos, 0, \ |
---|
144 | width, height)) |
---|
145 | # store the image for later |
---|
146 | tiles.append(TileImage(new_surface, \ |
---|
147 | filename + chr(ord('a')+file_counter) + ".png",y_off)) |
---|
148 | file_counter += 1 |
---|
149 | # amend variables |
---|
150 | x_pos += width |
---|
151 | height += height_adjust |
---|
152 | return tiles |
---|
153 | |
---|
154 | def convertFiles(filename, txt_data): |
---|
155 | """Take a file, slice into seperate images and then save these new images |
---|
156 | as filename0, filename1 ... filenameN |
---|
157 | Returns True if everything worked |
---|
158 | The second string gives the offsets from left to right. The first tile |
---|
159 | on the LHS MUST be in the centre of the image""" |
---|
160 | # first we need to ensure that the data sent is correct. split it up first |
---|
161 | data=[] |
---|
162 | for i in txt_data: |
---|
163 | data.append(i) |
---|
164 | if(len(data) < 2): |
---|
165 | print "Error: Invalid tile data layout" |
---|
166 | return False |
---|
167 | # validate each data statement |
---|
168 | for i in data: |
---|
169 | if((i != 'l')and(i != 'r')and(i != 'm')and(i.isdigit() == False)): |
---|
170 | # some issue |
---|
171 | print "Error: Can't decode tile string structure" |
---|
172 | return False |
---|
173 | # then load the file |
---|
174 | try: |
---|
175 | image = pygame.image.load(filename) |
---|
176 | except(pygame.error): |
---|
177 | print "Error: Couldn't load", filename |
---|
178 | return False |
---|
179 | # split into seperate files |
---|
180 | # the [:-4] is used to split off the .png from the filename |
---|
181 | images = splitImage(image, filename[:-4], data) |
---|
182 | # save it and we are done |
---|
183 | if(images == []): |
---|
184 | # something funny happened |
---|
185 | print "Error: Couldn't splice given image file" |
---|
186 | return False |
---|
187 | return(saveFiles(images)) |
---|
188 | |
---|
189 | if __name__=="__main__": |
---|
190 | # check we have some options |
---|
191 | if(len(sys.argv) < 3): |
---|
192 | sys.stderr.write("Error: Not enough data given\n") |
---|
193 | sys.exit(False) |
---|
194 | # ok, so init pygame and do it |
---|
195 | pygame.init() |
---|
196 | sys.exit(convertFiles(sys.argv[1], sys.argv[2])) |
---|
197 | |
---|