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