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