1 /***************************************************************************
2                           shp.c -  description
3                              -------------------
4     begin                : Tue Mar 12 2002
5     copyright            : (C) 2001 by Michael Speck
6     email                : kulkanie@gmx.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <dirent.h>
22 #include <sys/stat.h>
23 #include <SDL_endian.h>
24 #include "misc.h"
25 #include "shp.h"
26 
27 /*
28 ====================================================================
29 Externals
30 ====================================================================
31 */
32 extern char *source_path;
33 extern char *dest_path;
34 extern int use_def_pal;
35 
36 /*
37 ====================================================================
38 Default palette. Used if icon is not associated with a palette.
39 ====================================================================
40 */
41 typedef struct { int r; int g; int b; } RGB_Entry;
42 RGB_Entry def_pal[256] =  {
43 {   0,   0,   0},{   0,   0, 171},{   0, 171,   0},  // 0-2
44 {   0, 171, 171},{ 171,   0,   0},{ 171,   0, 171},  // 3-5
45 { 171,  87,   0},{ 171, 171, 171},{  87,  87,  87},  // 6-8
46 {  87,  87, 255},{  87, 255,  87},{  87, 255, 255},  // 9-11
47 { 255,  87,  87},{ 255,  87, 255},{ 255, 255,  87},  // 12-14
48 { 255, 255, 255},{  79,   0,   0},{ 107,   0,   0},  // 15-17
49 { 135,   0,   0},{ 167,   7,   0},{ 195,  11,   0},  // 18-20
50 { 223,  19,   0},{ 255,   0,   0},{ 255,  83,  19},  // 21-23
51 { 255, 131,  39},{ 255, 175,  59},{ 255, 211,  79},  // 24-26
52 { 255, 243,  99},{ 243, 255, 123},{ 255, 255, 255},  // 27-29
53 { 223, 235, 223},{ 195, 211, 195},{ 167, 191, 167},  // 30-32
54 { 139, 171, 139},{ 119, 151, 119},{  95, 131,  95},  // 33-35
55 {  75, 111,  75},{  59,  91,  59},{  43,  71,  43},  // 36-38
56 { 255, 255, 255},{ 227, 231, 243},{ 215, 219, 235},  // 39-41
57 { 203, 211, 231},{ 191, 199, 227},{ 183, 191, 223},  // 42-44
58 { 171, 183, 219},{ 163, 175, 211},{ 151, 163, 207},  // 45-47
59 { 139, 155, 203},{ 131, 147, 199},{ 123, 139, 191},  // 48-50
60 { 115, 131, 187},{ 107, 123, 183},{  99, 119, 179},  // 51-53
61 {  91, 111, 175},{ 255, 255, 255},{ 231, 239, 239},  // 54-56
62 { 211, 219, 219},{ 191, 203, 203},{ 171, 187, 187},  // 57-59
63 { 151, 171, 171},{ 135, 155, 155},{ 119, 139, 139},  // 60-62
64 {  99, 123, 123},{  87, 107, 107},{  71,  91,  91},  // 63-65
65 {  55,  75,  75},{  43,  59,  59},{  31,  43,  43},  // 66-68
66 {  15,  27,  27},{   7,  11,  11},{ 255, 243, 143},  // 69-71
67 { 247, 231, 135},{ 239, 219, 127},{ 231, 211, 123},  // 72-74
68 { 227, 199, 119},{ 219, 191, 111},{ 211, 179, 107},  // 75-77
69 { 207, 171, 103},{ 187, 195,  39},{ 251, 243, 167},  // 78-80
70 { 239, 235, 163},{ 227, 227, 159},{ 215, 215, 151},  // 81-83
71 { 199, 203, 147},{ 187, 191, 143},{ 175, 179, 135},  // 84-86
72 { 159, 167, 131},{ 147, 155, 123},{ 135, 143, 115},  // 87-89
73 { 223, 219, 123},{ 207, 207, 119},{ 195, 195, 119},  // 90-92
74 { 179, 179, 115},{ 163, 167, 111},{ 151, 155, 107},  // 93-95
75 { 139, 143, 103},{ 127, 131,  95},{ 115, 119,  91},  // 96-98
76 { 195, 195, 119},{  51,  39,  27},{  55,  43,  31},  // 99-101
77 {  63,  47,  35},{  71,  55,  39},{  75,  59,  43},  // 102-104
78 {  83,  67,  43},{  91,  71,  51},{  95,  79,  55},  // 105-107
79 { 103,  83,  59},{ 111,  91,  63},{ 191, 131,  47},  // 108-110
80 { 254, 254, 254},{ 255, 255, 151},{ 255,  87, 255},  // 111-113 111=blink white
81                                                      // 112= blink gold
82 { 111,  91,  63},{ 115,  95,  67},{ 123, 103,  71},  // 114-116
83 { 131, 111,  75},{ 139, 119,  83},{ 255, 255,  87},  // 117-119
84 {   0, 171,   0},{  87,  87, 255},{   0,   0, 171},  // 120-122
85 { 135, 143, 115},{ 159, 167, 131},{  95, 223, 255},  // 123-125
86 { 203, 211, 231},{ 231, 211, 171},{  59,   0,   0},  // 126-128
87 {  83,   0,   0},{ 103,   0,   0},{ 127,   7,   0},  // 129-131
88 { 147,  11,   0},{ 167,  15,   0},{ 191,   0,   0},  // 132-134
89 { 191,  63,  15},{ 191,  99,  31},{ 191, 131,  47},  // 135-137
90 { 191, 159,  59},{ 191, 183,  75},{ 183, 191,  95},  // 138-140
91 { 191, 191, 191},{ 167, 179, 167},{ 147, 159, 147},  // 141-143
92 { 127, 143, 127},{ 107, 131, 107},{  91, 115,  91},  // 144-146
93 {  71,  99,  71},{  59,  83,  59},{  47,  71,  47},  // 147-149
94 {  35,  55,  35},{ 191, 191, 191},{ 171, 175, 183},  // 150-152
95 { 163, 167, 179},{ 155, 159, 175},{ 143, 151, 171},  // 153-155
96 { 139, 143, 167},{ 131, 139, 167},{ 123, 131, 159},  // 156-158
97 { 115, 123, 155},{ 107, 119, 155},{  99, 111, 151},  // 159-161
98 {  95, 107, 143},{  87,  99, 143},{  83,  95, 139},  // 162-164
99 {  75,  91, 135},{  71,  83, 131},{ 191, 191, 191},  // 165-167
100 { 175, 179, 179},{ 159, 167, 167},{ 143, 155, 155},  // 168-170
101 { 131, 143, 143},{ 115, 131, 131},{ 103, 119, 119},  // 171-173
102 {  91, 107, 107},{  75,  95,  95},{  67,  83,  83},  // 174-176
103 {  55,  71,  71},{  43,  59,  59},{  35,  47,  47},  // 177-179
104 {  23,  35,  35},{  11,  23,  23},{   7,  11,  11},  // 180-182
105 { 191, 183, 107},{ 187, 175, 103},{ 179, 167,  95},  // 183-185
106 { 175, 159,  95},{ 171, 151,  91},{ 167, 143,  83},  // 186-188
107 { 159, 135,  83},{ 155, 131,  79},{ 143, 147,  31},  // 189-191
108 { 191, 183, 127},{ 179, 179, 123},{ 171, 171, 119},  // 192-194
109 { 163, 163, 115},{ 151, 155, 111},{ 143, 143, 107},  // 195-197
110 { 131, 135, 103},{ 119, 127,  99},{ 111, 119,  95},  // 198-200
111 { 103, 107,  87},{ 167, 167,  95},{ 155, 155,  91},  // 201-203
112 { 147, 147,  91},{ 135, 135,  87},{ 123, 127,  83},  // 204-206
113 { 115, 119,  83},{ 107, 107,  79},{  95,  99,  71},  // 207-209
114 {  87,  91,  71},{ 147, 147,  91},{ 147, 127,  87},  // 210-212
115 { 155, 135,  91},{ 163, 143,  95},{ 171, 151, 103},  // 213-215
116 { 179, 155, 107},{ 187, 167, 115},{ 195, 175, 119},  // 216-218
117 { 203, 183, 127},{ 211, 191, 131},{ 219, 199, 139},  // 219-221
118 { 143,  91,  31},{ 255,  87, 255},{ 191, 191, 115},  // 222-224 224=blink dark
119 { 255,  87, 255},{ 223, 207, 143},{ 231, 215, 147},  // 225-227
120 { 239, 223, 155},{ 247, 231, 163},{ 255, 239, 171},  // 228-230
121 { 191, 191,  67},{   0, 131,   0},{  67,  67, 191},  // 231-233
122 {   0,   0, 131},{ 103, 107,  87},{ 119, 127,  99},  // 234-236
123 {  71, 167, 191},{ 155, 159, 175},{ 175, 159, 131},  // 237-239
124 { 135, 143, 115},{ 159, 167, 131},{ 255,  35,  35},  // 240-242
125 {  43, 199, 183},{  43, 171, 199},{  43, 127, 199},  // 243-245
126 {  43,  83, 199},{  47,  43, 199},{  91,  43, 199},  // 246-248
127 { 135,  43, 199},{ 179,  43, 199},{ 199,  43, 175},  // 249-251
128 { 199,  43, 131},{ 199,  43,  87},{ 199,  43,  43},  // 252-254
129 { 255, 119, 123}};                                   // 255
130 
131 /*
132 ====================================================================
133 Locals
134 ====================================================================
135 */
136 
137 /*
138 ====================================================================
139 Read icon header from file pos.
140 ====================================================================
141 */
shp_read_icon_header(FILE * file,Icon_Header * header)142 static void shp_read_icon_header( FILE *file, Icon_Header *header )
143 {
144     memset( header, 0, sizeof( Icon_Header ) );
145     _fread( &header->height, 2, 1, file );
146     header->height = SDL_SwapLE16(header->height);
147     header->height++; /* if y1 == y2 it is at least one line anyway */
148     _fread( &header->width, 2, 1, file );
149     header->width = SDL_SwapLE16(header->width);
150     header->width++;
151     _fread( &header->cx, 2, 1, file );
152     header->cx = SDL_SwapLE16(header->cx);
153     _fread( &header->cy, 2, 1, file );
154     header->cy = SDL_SwapLE16(header->cy);
155     _fread( &header->x1, 4, 1, file );
156     header->x1 = SDL_SwapLE32(header->x1);
157     _fread( &header->y1, 4, 1, file );
158     header->y1 = SDL_SwapLE32(header->y1);
159     _fread( &header->x2, 4, 1, file );
160     header->x2 = SDL_SwapLE32(header->x2);
161     _fread( &header->y2, 4, 1, file );
162     header->y2 = SDL_SwapLE32(header->y2);
163     header->valid = 1;
164     if ( header->x1 >= header->width || header->x2 >= header->width )
165         header->valid = 0;
166     if ( header->y1 >= header->height || header->y2 >= header->height )
167         header->valid = 0;
168     if ( header->x1 < 0 ) {
169         header->x1 = 0;
170         header->actual_width = header->x2;
171     }
172     else
173         header->actual_width = header->x2 - header->x1 + 1;
174     if ( header->y1 < 0 ) {
175         header->y1 = 0;
176         header->actual_height = abs( header->y1 ) + header->y2 + 1;
177     }
178     else
179         header->actual_height = header->y2 - header->y1 + 1;
180 }
181 
182 /*
183 ====================================================================
184 Read palette from file pos.
185 ====================================================================
186 */
shp_read_palette(FILE * file,RGB_Entry * pal)187 static void shp_read_palette( FILE *file, RGB_Entry *pal )
188 {
189     int i;
190     int count = 0;
191     int id;
192     int part;
193     memset( pal, 0, sizeof( RGB_Entry ) * 256 );
194     _fread( &count, 4, 1, file );
195     count = SDL_SwapLE32(count);
196     for ( i = 0; i < count; i++ ) {
197         id = 0; _fread( &id, 1, 1, file );
198         if ( id >= 256 ) id = 255;
199         part = 0; _fread( &part, 1, 1, file ); pal[id].r = part * 4;
200         part = 0; _fread( &part, 1, 1, file ); pal[id].g = part * 4;
201         part = 0; _fread( &part, 1, 1, file ); pal[id].b = part * 4;
202     }
203 }
204 
205 /*
206 ====================================================================
207 Read raw SHP icon data from file and draw it to 'surf' at 'y'
208 interpreting the indices of the icon as palette entry indices.
209 ====================================================================
210 */
shp_read_icon(FILE * file,SDL_Surface * surf,int y,RGB_Entry * pal,Icon_Header * header)211 static void shp_read_icon( FILE *file, SDL_Surface *surf, int y, RGB_Entry *pal, Icon_Header *header )
212 {
213     int bytes, flag;
214     int x = 0, i, y1 = header->y1;
215     Uint8 buf;
216     Uint32 ckey = MAPRGB( CKEY_RED, CKEY_GREEN, CKEY_BLUE ); /* transparent color key */
217     /* read */
218     while ( y1 <= header->y2 ) {
219         buf = 0; _fread( &buf, 1, 1, file );
220         flag = buf % 2; bytes = buf / 2;
221         if ( bytes == 0 && flag == 1 ) {
222             /* transparency */
223             buf = 0; _fread( &buf, 1, 1, file );
224             for ( i = 0; i < buf; i++ )
225                 set_pixel( surf, x++ + header->x1, y + y1, ckey );
226         }
227         else
228             if ( bytes == 0 ) {
229                 /* end of line */
230                 y1++;
231                 x = 0;
232             }
233             else
234                 if ( flag == 0 ) {
235                     /* byte row */
236                     buf = 0; _fread( &buf, 1, 1, file );
237                     for ( i = 0; i < bytes; i++ )
238                         set_pixel( surf, x++ + header->x1, y + y1, MAPRGB( pal[buf].r, pal[buf].g, pal[buf].b ) );
239                 }
240                 else {
241                     /* bytes != 0 && flag == 1: read next bytes uncompressed */
242                     for ( i = 0; i < bytes; i++ ) {
243                         buf = 0; _fread( &buf, 1, 1, file );
244                         set_pixel( surf, x++ + header->x1, y + y1, MAPRGB( pal[buf].r, pal[buf].g, pal[buf].b ) );
245                     }
246                 }
247     }
248 }
249 
250 /*
251 ====================================================================
252 Publics
253 ====================================================================
254 */
255 
256 /*
257 ====================================================================
258 Draw a pixel at x,y in surf.
259 ====================================================================
260 */
set_pixel(SDL_Surface * surf,int x,int y,int pixel)261 void set_pixel( SDL_Surface *surf, int x, int y, int pixel )
262 {
263     int pos = 0;
264 
265     pos = y * surf->pitch + x * surf->format->BytesPerPixel;
266     memcpy( surf->pixels + pos, &pixel, surf->format->BytesPerPixel );
267 }
get_pixel(SDL_Surface * surf,int x,int y)268 Uint32 get_pixel( SDL_Surface *surf, int x, int y )
269 {
270     int pos = 0;
271     Uint32 pixel = 0;
272     pos = y * surf->pitch + x * surf->format->BytesPerPixel;
273     memcpy( &pixel, surf->pixels + pos, surf->format->BytesPerPixel );
274     return pixel;
275 }
276 
277 /*
278 ====================================================================
279 Load a SHP file to a PG_Shp struct.
280 Since SHP files are only found in source path (=original PG data),
281 for simplicity this function only gets the file name and the
282 source_path is always prepended for opening the file.
283 ====================================================================
284 */
shp_load(const char * fname)285 PG_Shp *shp_load( const char *fname )
286 {
287     int i;
288     FILE *file = 0;
289     char path[MAXPATHLEN];
290     int dummy;
291     int width = 0, height = 0;
292     int old_pos, pos, pal_pos;
293     PG_Shp *shp = 0;
294     SDL_PixelFormat *pf = SDL_GetVideoSurface()->format;
295     Uint32 ckey = MAPRGB( CKEY_RED, CKEY_GREEN, CKEY_BLUE ); /* transparent color key */
296     Icon_Header header;
297     RGB_Entry pal[256];
298     RGB_Entry *actual_pal = 0;
299     int icon_maxw = 60, icon_maxh = 50;
300 
301     snprintf( path, MAXPATHLEN, "%s/%s", source_path, fname );
302     if ( ( file = fopen_ic( path, "rb" ) ) == NULL ) {
303         printf("Could not open file %s\n",path);
304         return NULL;
305     }
306 
307     /* magic */
308     _fread( &dummy, 4, 1, file );
309     /* shp struct */
310     shp = calloc( 1, sizeof( PG_Shp ) );
311     /* icon count */
312     _fread( &shp->count, 4, 1, file );
313     shp->count = SDL_SwapLE32(shp->count);
314     if ( shp->count == 0 ) {
315         fprintf( stderr, "%s: no icons found\n", path );
316         goto failure;
317     }
318     /* create surface (measure size first) */
319     for ( i = 0; i < shp->count; i++ ) {
320         /* read file position of actual data and palette */
321         _fread( &pos, 4, 1, file );
322         pos = SDL_SwapLE32(pos);
323         _fread( &dummy, 4, 1, file );
324         old_pos = ftell( file );
325         /* read header */
326         fseek( file, pos, SEEK_SET );
327         shp_read_icon_header( file, &header );
328         /* XXX if icon is too large, ignore it and replace with an empty
329          * icon of maximum size; use hardcoded limit which is basically okay
330          * as we convert PG data and can assume the icons have size of map
331          * tile at maximum. */
332         if ( header.width > icon_maxw || header.height > icon_maxh ) {
333             fprintf( stderr, "Icon %d in %s is too large (%dx%d), replacing "
334                                         "with empty icon\n", i, fname,
335                                         header.width,header.height  );
336             header.width = icon_maxw;
337             header.height = icon_maxh;
338             header.valid = 0;
339         }
340         if ( header.width > width )
341             width = header.width;
342         height += header.height;
343         fseek( file, old_pos, SEEK_SET );
344     }
345     shp->surf = SDL_CreateRGBSurface( SDL_SWSURFACE, width, height, pf->BitsPerPixel, pf->Rmask, pf->Gmask, pf->Bmask, pf->Amask );
346     if ( shp->surf == 0 ) {
347         fprintf( stderr, "error creating surface: %s\n", SDL_GetError() );
348         goto failure;
349     }
350     SDL_FillRect( shp->surf, 0, ckey );
351     /* read icons */
352     shp->offsets = calloc( shp->count, sizeof( int ) );
353     shp->headers = calloc( shp->count, sizeof( Icon_Header ) );
354     fseek( file, 8, SEEK_SET );
355     for ( i = 0; i < shp->count; i++ ) {
356         /* read position of data and palette */
357         pos = pal_pos = 0;
358         _fread( &pos, 4, 1, file );
359         pos = SDL_SwapLE32(pos);
360         _fread( &pal_pos, 4, 1, file );
361         pal_pos = SDL_SwapLE32(pal_pos);
362         old_pos = ftell( file );
363         /* read palette */
364         if ( !use_def_pal && pal_pos > 0 ) {
365             fseek( file, pal_pos, SEEK_SET );
366             shp_read_palette( file, pal );
367             actual_pal = pal;
368         }
369         else
370             actual_pal = def_pal;
371         /* read header */
372         fseek( file, pos, SEEK_SET );
373         shp_read_icon_header( file, &header );
374         /* see comment in measure loop above; have empty icon if too large */
375         if ( header.width > icon_maxw || header.height > icon_maxh ) {
376             /* error message already given in measure loop */
377             header.width = icon_maxw;
378             header.height = icon_maxh;
379             header.valid = 0;
380         }
381         if ( header.valid )
382             shp_read_icon( file, shp->surf, shp->offsets[i], actual_pal, &header );
383         if ( i < shp->count - 1 )
384             shp->offsets[i + 1] = shp->offsets[i] + header.height;
385         memcpy( &shp->headers[i], &header, sizeof( Icon_Header ) );
386         fseek( file, old_pos, SEEK_SET );
387     }
388     fclose( file );
389     return shp;
390 failure:
391     if ( file ) fclose( file );
392     if ( shp ) shp_free( &shp );
393     return 0;
394 }
395 
396 /*
397 ====================================================================
398 Free a PG_Shp struct.
399 ====================================================================
400 */
shp_free(PG_Shp ** shp)401 void shp_free( PG_Shp **shp )
402 {
403     if ( *shp == 0 ) return;
404     if ( (*shp)->headers ) free( (*shp)->headers );
405     if ( (*shp)->offsets ) free( (*shp)->offsets );
406     if ( (*shp)->surf ) SDL_FreeSurface( (*shp)->surf );
407     free( *shp ); *shp = 0;
408 }
409 
410 /*
411 ====================================================================
412 Read all SHP files in source directory and save to directory
413 '.view' in dest directory.
414 ====================================================================
415 */
shp_all_to_bmp(void)416 int shp_all_to_bmp( void )
417 {
418     char path[MAXPATHLEN];
419     int length;
420     DIR *dir = 0;
421     PG_Shp *shp;
422     struct dirent *dirent = 0;
423     /* open directory */
424     if ( ( dir = opendir( source_path ) ) == 0 ) {
425         fprintf( stderr, "%s: can't open directory\n", source_path );
426         return 0;
427     }
428     while ( ( dirent = readdir( dir ) ) != 0 ) {
429         if ( dirent->d_name[0] == '.' ) continue;
430         if ( !strncmp( "tacally.shp", strlower( dirent->d_name ), 11 ) ) continue;
431         if ( !strncmp( "tacgerm.shp", strlower( dirent->d_name ), 11 ) ) continue;
432         if ( !strncmp( "a_", strlower( dirent->d_name ), 2 ) ) continue;
433         length = strlen( dirent->d_name );
434         if ( (dirent->d_name[length - 1] != 'P' || dirent->d_name[length - 2] != 'H' || dirent->d_name[length - 3] != 'S') &&
435              (dirent->d_name[length - 1] != 'p' || dirent->d_name[length - 2] != 'h' || dirent->d_name[length - 3] != 's') )
436             continue;
437         printf( "%s...\n", dirent->d_name );
438         if ( ( shp = shp_load( dirent->d_name ) ) == 0 ) continue;
439         snprintf( path, MAXPATHLEN, "%s/.view/%s.bmp", dest_path, dirent->d_name );
440         SDL_SaveBMP( shp->surf, path );
441         shp_free( &shp );
442     }
443     closedir( dir );
444     return 1;
445 }
446