1 /*
2 * importlev - Level importer for Luola
3 * Copyright (C) 2005 Calle Laakkonen
4 *
5 * File : im_wings.c
6 * Description : Importer module for Wings levels. Based on unmakelev
7 * by Pauli Virtanen.
8 * Author(s) : Calle Laakkonen
9 *
10 * Luola is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * Luola is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25 #include <stdlib.h>
26 #include <limits.h>
27 #include <stdio.h>
28 #include <ctype.h>
29
30 #include <SDL.h>
31 #include <SDL_rwops.h>
32 #include <SDL_endian.h>
33
34 #include "im_wings.h"
35
36 static Uint32 lev_width, lev_height;
37 static SDL_Color palette[256];
38 static Uint8* lev_pixels;
39
40 /*
41 * Check if file is a Wings level.
42 * Wings levels have no magic numbers, so this is a bit tricky.
43 */
check_format(FILE * fp)44 static int check_format(FILE *fp) {
45 char buffer[3];
46 Uint16 w,h;
47
48 /* Wings levels start out with a palette. */
49 /* The first color should always be black. */
50 fseek(fp,0,SEEK_SET);
51 fread(buffer,1,3,fp);
52 if(buffer[0] != 0 || buffer[1] != 0 || buffer[2]!=0)
53 return 0;
54
55 /* Check level width and height */
56 /* Usual level size is around 320x400, but we just check */
57 /* that both dimensions are below 1000. */
58 fseek(fp,0x300,SEEK_SET);
59 fread(&w,2,1,fp);
60 fread(&h,2,1,fp);
61
62 if(SDL_SwapLE16(w)<1000 && SDL_SwapLE16(h)<1000) return 1;
63
64 /* If none of these conditions match, this is probably not a Wings level */
65 return 0;
66 }
67
68 /*
69 * Read RLE compressed data from file and unpack it
70 */
decode_pcx(FILE * fp,Uint8 * pixels,Uint32 len)71 static int decode_pcx(FILE *fp,Uint8 *pixels,Uint32 len) {
72 Uint32 pos=0;
73 Uint8 pix;
74
75 while(pos<len) {
76 if(fread(&pix,1,1,fp)!=1) return 1;
77 pos++;
78
79 if(pix>192) {
80 int count=pix-192;
81 if(fread(&pix,1,1,fp)!=1) return 1;
82 pos++;
83 for(;count>0;count--) {
84 *(pixels++) = pix;
85 }
86 } else {
87 *(pixels++) = pix;
88 }
89 }
90 return 0;
91 }
92
93 /*
94 * Load level to memory
95 */
load_level(FILE * fp)96 static int load_level(FILE *fp) {
97 Uint32 datalen;
98 int i;
99
100 /* Read level palette */
101 fseek(fp,0,SEEK_SET);
102
103 for(i=0;i<256;i++) {
104 Uint8 r,g,b;
105 fread(&r,1,1,fp);
106 fread(&g,1,1,fp);
107 fread(&b,1,1,fp);
108
109 palette[i].r = r * 4;
110 palette[i].g = g * 4;
111 palette[i].b = b * 4;
112 }
113
114 /* Read level width and height */
115 fseek(fp,0x300,SEEK_SET);
116 fread(&lev_width,2,1,fp);
117 fread(&lev_height,2,1,fp);
118 lev_width = SDL_SwapLE16(lev_width);
119 lev_height = SDL_SwapLE16(lev_height);
120
121 /* Read level data length */
122 fread(&datalen,4,1,fp);
123 datalen = SDL_SwapLE32(datalen);
124
125 /* Read pixel data (in PCX RLE format) */
126 lev_pixels = malloc(lev_width * lev_height);
127 if(!lev_pixels) {
128 perror("malloc");
129 return 1;
130 }
131 if(decode_pcx(fp,lev_pixels,datalen)) {
132 printf("Error occured while decoding PCX data!\n");
133 return 1;
134 }
135
136 return 0;
137 }
138
139 /*
140 * Unload level
141 */
unload_level(void)142 static void unload_level(void) {
143 free(lev_pixels);
144 }
145
146 /*
147 * Save out the level as a BMP file
148 */
write_bmp(const char * filename)149 static int write_bmp(const char *filename) {
150 SDL_Surface* surface;
151 unsigned int i;
152
153 surface = SDL_CreateRGBSurface(SDL_SWSURFACE, lev_width, lev_height, 8,
154 0xFF, 0xFF, 0xFF, 0);
155
156 if(surface==NULL) {
157 printf("Couldn't create surface: %s\n",SDL_GetError());
158 return 1;
159 }
160 SDL_SetColors(surface, palette, 0, 256);
161 memcpy(surface->pixels,lev_pixels,lev_width*lev_height);
162
163 if(SDL_SaveBMP(surface, filename)) {
164 printf("%s: %s\n",filename,SDL_GetError());
165 return 1;
166 }
167 SDL_FreeSurface(surface);
168
169 return 0;
170 }
171
172 /*
173 * Write out level configuration file
174 */
write_cfg(const char * basename,const char * collmap,const char * thumbnail,const char * filename)175 static int write_cfg(const char *basename,const char *collmap,
176 const char *thumbnail,const char *filename)
177 {
178 const char *slash,*dot;
179 char name[256];
180 FILE *fp;
181 /* First figure out the name of this level */
182 slash = strrchr(basename,'/');
183 if(slash) slash++; else slash=basename;
184 dot = strrchr(slash,'.');
185 if(!dot) dot=slash+strlen(slash);
186 name[0]=0;
187 strncat(name,slash,dot-slash);
188
189 /* Open output file and write */
190 fp = fopen(filename,"w");
191 if(!fp) {
192 perror(filename);
193 return 1;
194 }
195
196 fprintf(fp, "# Wings level configuration file generated with importlev\n");
197 fprintf(fp,"[main]\n");
198 fprintf(fp,"collisionmap = %s\n",collmap);
199 fprintf(fp,"thumbnail = %s\n",thumbnail);
200 fprintf(fp,"name = %s\n", name);
201 fprintf(fp,"zoom = 3\n\n");
202 fprintf(fp,"# Support for the Wings 1.40 palette according to colors.txt\n");
203 fprintf(fp,"[palette]\n");
204 fprintf(fp,"1-31 = ground\n"
205 "32-47 = base\n"
206 "48 = water\n"
207 "49 = waterdown\n"
208 "50 = waterleft\n"
209 "51 = waterright\n"
210 "52 = water\n"
211 "53 = snow\n"
212 "54 = ground\n"
213 "55-56 = explosive\n"
214 "57-63 = ground\n"
215 "80-95 = indestructable\n"
216 "96-111 = ground\n"
217 "112-127 = combustable\n"
218 "128-255 = ground\n");
219 fclose(fp);
220 return 0;
221 }
222
223 /*
224 * Save as a Luola level
225 *
226 * lcmap option is not used for this type of level
227 */
save_level(const char * basename,int lcmap)228 static struct Files save_level(const char *basename,int lcmap) {
229 static char bmpfile[PATH_MAX],cfgfile[PATH_MAX],thumbnailfile[PATH_MAX];
230 struct Files result;
231
232 if(lcmap) {
233 printf("LCMAP not generated for Wings level.\n");
234 }
235 strcpy(bmpfile,basename);
236 strcat(bmpfile,".luola.bmp");
237 strcpy(cfgfile,basename);
238 strcat(cfgfile,".luola.lev");
239 strcpy(thumbnailfile,basename);
240 strcat(thumbnailfile,".thumb.png");
241
242 result.failed=0;
243 result.artwork=NULL;
244 result.collmap=bmpfile;
245 result.cfgfile=cfgfile;
246
247 if(write_bmp(bmpfile)) {
248 result.failed = 1;
249 } else if(write_cfg(basename,bmpfile,thumbnailfile,cfgfile)) {
250 remove(bmpfile);
251 result.failed=1;
252 }
253
254 return result;
255 }
256
257 /*
258 * Register Wings importer
259 */
register_wings(void)260 struct Importer register_wings(void) {
261 struct Importer i;
262 i.name = "Wings";
263 i.aspect = 1.0;
264 i.check_format = check_format;
265 i.load_level = load_level;
266 i.unload_level = unload_level;
267 i.save_level = save_level;
268
269 return i;
270 }
271
272
273