2 Copyright (C) 1998 BJ Eirich (aka vecna)
\r
3 This program is free software; you can redistribute it and/or
\r
4 modify it under the terms of the GNU General Public License
\r
5 as published by the Free Software Foundation; either version 2
\r
6 of the License, or (at your option) any later version.
\r
7 This program is distributed in the hope that it will be useful,
\r
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
\r
10 See the GNU General Public Lic
\r
11 See the GNU General Public License for more details.
\r
12 You should have received a copy of the GNU General Public License
\r
13 along with this program; if not, write to the Free Software
\r
14 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
\r
18 // V2 PCX to CHR converter w/ makefiles
\r
21 // aen@verge-rpg.com
\r
28 #include <sys/stat.h>
\r
32 ////////////////////////////////////////////////////////////////////////////
\r
33 ////////////////////////////////////////////////////////////////////////////
\r
35 typedef unsigned char byte;
\r
36 typedef unsigned short word;
\r
37 typedef unsigned long quad;
\r
39 static void fputw(word w, FILE *fp) { fwrite(&w,1,2,fp); }
\r
40 static void fputd(quad d, FILE *fp) { fwrite(&d,1,4,fp); }
\r
41 static word fgetw(FILE *fp) { word w; fread(&w,1,2,fp); return w; }
\r
42 quad fgetd(FILE *fp) { quad d; fread(&d,1,4,fp); return d; }
\r
44 // skips the number of bytes in the file; just seeks past them
\r
45 static void fskip(int bytes, FILE *fp)
\r
46 { fseek(fp,bytes,SEEK_CUR); }
\r
48 static void fputraw(char *raw, int bytes, FILE *fp)
\r
49 { fwrite(raw, 1,bytes, fp); }
\r
51 // writes a null-terminated string to the file
\r
52 void fputstrz(char *str, FILE *fp)
\r
53 { fputraw(str, strlen(str)+1, fp); }
\r
55 // writes a string to the file (without the null-terminator), preceeded by
\r
56 // a quad length marker
\r
57 static void fputstrn(char *str, FILE *fp)
\r
58 { int n=strlen(str)+1; fputd(n,fp); fputraw(str,n,fp); }
\r
60 ////////////////////////////////////////////////////////////////////////////
\r
61 ////////////////////////////////////////////////////////////////////////////
\r
63 #define CHRMAK_VER_MAJ 0
\r
64 #define CHRMAK_VER_MIN 1
\r
65 #define CHRMAK_VER_STR "0.1b"
\r
66 #define CHRMAK_AUTHORS "aen"
\r
69 static char *mak_base=0;
\r
70 static char *makp=0;
\r
71 static int mak_bytes=0;
\r
72 static char mak_tok_ident[256];
\r
73 static char mak_tok_val[256];
\r
74 static int mak_tok_valn=0; // numeric val of mak_tok
\r
75 static int mak_line=0;
\r
78 static char chrmak_makefile[256];
\r
80 static char pcx_name[256]; static int got_pcx_name=0;
\r
81 static char chr_name[256]; static int got_chr_name=0;
\r
82 static int frame_w=0; static int got_frame_w=0;
\r
83 static int frame_h=0; static int got_frame_h=0;
\r
84 static int hot_x=0; static int got_hot_x=0;
\r
85 static int hot_y=0; static int got_hot_y=0;
\r
86 static int hot_w=0; static int got_hot_w=0;
\r
87 static int hot_h=0; static int got_hot_h=0;
\r
88 static int per_row=0; static int got_per_row=0;
\r
89 static int total_frames=0; static int got_total_frames=0;
\r
90 static int lidle=0; static int got_lidle=0;
\r
91 static int ridle=0; static int got_ridle=0;
\r
92 static int uidle=0; static int got_uidle=0;
\r
93 static int didle=0; static int got_didle=0;
\r
94 static char lscript[256]; static int got_lscript=0;
\r
95 static char rscript[256]; static int got_rscript=0;
\r
96 static char uscript[256]; static int got_uscript=0;
\r
97 static char dscript[256]; static int got_dscript=0;
\r
99 void warning(char *message, ...)
\r
101 static char buffer[256];
\r
104 va_start(args, message);
\r
105 vsprintf(buffer, message, args);
\r
108 printf("%s \n", buffer);
\r
111 static void fatal(char *message, ...)
\r
113 static char buffer[256];
\r
116 va_start(args, message);
\r
117 vsprintf(buffer, message, args);
\r
120 printf("%s \n", buffer);
\r
126 // Watcom has one of these
\r
127 static int filelength(int handle)
\r
129 struct stat fileinfo;
\r
130 if (-1 == fstat(handle, &fileinfo))
\r
131 fatal("error fstating");
\r
132 return fileinfo.st_size;
\r
136 static int streq(char *a, char *b)
\r
146 static void usage()
\r
148 printf("usage: chrmak <makefile> \n");
\r
152 static void banner()
\r
154 printf("chrmak v%s
\1e by %s \n", CHRMAK_VER_STR, CHRMAK_AUTHORS);
\r
157 static void parse_args(int argc, char *argv[])
\r
162 strcpy(chrmak_makefile, argv[1]);
\r
165 static void skip_cpp_comment()
\r
168 while (*makp && '\n'!=*makp)
\r
174 static void skip_c_comment()
\r
177 while (*makp && ('*'!=makp[0] || '/'!=makp[1]))
\r
181 if ('/'==makp[0] && '*'==makp[1])
\r
189 static void parse_whitespace()
\r
194 if (isspace(*makp))
\r
196 while (*makp && isspace(*makp))
\r
204 if ('/'==makp[0] && '/'==makp[1])
\r
205 { skip_cpp_comment(); continue; }
\r
206 if ('/'==makp[0] && '*'==makp[1])
\r
207 { skip_c_comment(); continue; }
\r
212 static void grab_ident()
\r
214 char *t=mak_tok_ident;
\r
215 while (isalnum(*makp) || '_'==*makp)
\r
218 strlwr(mak_tok_ident);
\r
221 static void grab_val()
\r
223 char *t=mak_tok_val;
\r
224 while (isalnum(*makp) || '_'==*makp)
\r
227 mak_tok_valn=atoi(mak_tok_val);
\r
230 static int ident_is(char *id) { return streq(mak_tok_ident,id); }
\r
232 static void do_assign()
\r
234 if (ident_is("pcx_name"))
\r
235 { strcpy(pcx_name, mak_tok_val); got_pcx_name=1; return; }
\r
236 else if (ident_is("chr_name"))
\r
237 { strcpy(chr_name, mak_tok_val); got_chr_name=1; return; }
\r
238 else if (ident_is("frame_w"))
\r
239 { frame_w=mak_tok_valn; got_frame_w=1; return; }
\r
240 else if (ident_is("frame_h"))
\r
241 { frame_h=mak_tok_valn; got_frame_h=1; return; }
\r
242 else if (ident_is("hot_x"))
\r
243 { hot_x=mak_tok_valn; got_hot_x=1; return; }
\r
244 else if (ident_is("hot_y"))
\r
245 { hot_y=mak_tok_valn; got_hot_y=1; return; }
\r
246 else if (ident_is("hot_w"))
\r
247 { hot_w=mak_tok_valn; got_hot_w=1; return; }
\r
248 else if (ident_is("hot_h"))
\r
249 { hot_h=mak_tok_valn; got_hot_h=1; return; }
\r
250 else if (ident_is("per_row"))
\r
251 { per_row=mak_tok_valn; got_per_row=1; return; }
\r
252 else if (ident_is("total_frames"))
\r
253 { total_frames=mak_tok_valn; got_total_frames=1; return; }
\r
254 else if (ident_is("lidle"))
\r
255 { lidle=mak_tok_valn; got_lidle=1; return; }
\r
256 else if (ident_is("ridle"))
\r
257 { ridle=mak_tok_valn; got_ridle=1; return; }
\r
258 else if (ident_is("uidle"))
\r
259 { uidle=mak_tok_valn; got_uidle=1; return; }
\r
260 else if (ident_is("didle"))
\r
261 { didle=mak_tok_valn; got_didle=1; return; }
\r
262 else if (ident_is("lscript"))
\r
263 { strcpy(lscript, mak_tok_val); got_lscript=1; return; }
\r
264 else if (ident_is("rscript"))
\r
265 { strcpy(rscript, mak_tok_val); got_rscript=1; return; }
\r
266 else if (ident_is("uscript"))
\r
267 { strcpy(uscript, mak_tok_val); got_uscript=1; return; }
\r
268 else if (ident_is("dscript"))
\r
269 { strcpy(dscript, mak_tok_val); got_dscript=1; return; }
\r
271 fatal("%s: unknown ident '%s' on line %i",
\r
272 chrmak_makefile, mak_tok_ident, mak_line);
\r
275 static int parse_assign()
\r
277 int last_line=0; // helper for error detection
\r
279 parse_whitespace();
\r
282 else if (isalpha(*makp))
\r
284 grab_ident(); // get ident
\r
285 last_line=mak_line;
\r
287 parse_whitespace(); // expect
\r
288 if ('=' != *makp++)
\r
289 fatal("%s: expected = on line %i", chrmak_makefile, last_line);
\r
291 parse_whitespace(); // get val
\r
293 last_line=mak_line;
\r
297 parse_whitespace(); // expect
\r
298 if (';' != *makp++)
\r
299 fatal("%s: expected ; on line %i", chrmak_makefile, last_line);
\r
300 else while (';'==*makp) makp++;
\r
304 fatal("%s: expected ident, got '%c' on line %i",
\r
305 chrmak_makefile, *makp, mak_line);
\r
309 static void check_needs()
\r
311 if (!got_pcx_name) fatal("%s: pcx_name missing", chrmak_makefile);
\r
312 if (!got_chr_name) fatal("%s: chr_name missing", chrmak_makefile);
\r
313 if (!got_frame_w) fatal("%s: frame_w missing", chrmak_makefile);
\r
314 if (!got_frame_h) fatal("%s: frame_h missing", chrmak_makefile);
\r
315 if (!got_hot_x) fatal("%s: hot_x missing", chrmak_makefile);
\r
316 if (!got_hot_y) fatal("%s: hot_y missing", chrmak_makefile);
\r
317 if (!got_hot_w) fatal("%s: hot_w missing", chrmak_makefile);
\r
318 if (!got_hot_h) fatal("%s: hot_h missing", chrmak_makefile);
\r
319 if (!got_per_row) fatal("%s: per_row missing", chrmak_makefile);
\r
320 if (!got_total_frames) fatal("%s: total_frames missing", chrmak_makefile);
\r
321 if (!got_lidle) fatal("%s: lidle missing", chrmak_makefile);
\r
322 if (!got_ridle) fatal("%s: ridle missing", chrmak_makefile);
\r
323 if (!got_uidle) fatal("%s: uidle missing", chrmak_makefile);
\r
324 if (!got_didle) fatal("%s: didle missing", chrmak_makefile);
\r
325 if (!got_lscript) fatal("%s: lscript missing", chrmak_makefile);
\r
326 if (!got_rscript) fatal("%s: rscript missing", chrmak_makefile);
\r
327 if (!got_uscript) fatal("%s: uscript missing", chrmak_makefile);
\r
328 if (!got_dscript) fatal("%s: dscript missing", chrmak_makefile);
\r
331 static void parse_makefile()
\r
335 printf("ú parsing %s \r", chrmak_makefile);
\r
338 fp=fopen(chrmak_makefile, "rb");
\r
339 if (!fp) fatal("unable to open %s", chrmak_makefile);
\r
341 mak_bytes=filelength(fileno(fp)); // calc bytes
\r
342 mak_base=new char [mak_bytes+1]; // alloc room
\r
343 fread(mak_base,1,mak_bytes,fp); // read bytes
\r
344 mak_base[mak_bytes]=0; // null-term
\r
345 makp=mak_base; // setup cur byte ptr
\r
348 while (!parse_assign())
\r
351 // got everything we need?
\r
354 delete[]mak_base; mak_base=0;
\r
363 ////////////////////////////////////////////////////////////////////////////
\r
364 // PCX & COMPRESS STUFF ////////////////////////////////////////////////////
\r
365 ////////////////////////////////////////////////////////////////////////////
\r
367 static FILE *chrfp=0;
\r
368 static FILE *pcxfp=0;
\r
369 static byte *virscr=0;
\r
371 int manufacturer=0; // pcx header
\r
380 int color_planes=0;
\r
382 int palette_type=0;
\r
386 int image_width=0,image_depth=0;
\r
389 void LoadPCXHeader()
\r
391 manufacturer = fgetc(pcxfp); // always 10
\r
392 version = fgetc(pcxfp); // should be 5?
\r
393 encoding = fgetc(pcxfp); // always 1
\r
394 bpp = fgetc(pcxfp); // bits per pixel
\r
396 xmin = fgetw(pcxfp); // grab window
\r
397 ymin = fgetw(pcxfp);
\r
398 xmax = fgetw(pcxfp);
\r
399 ymax = fgetw(pcxfp);
\r
400 image_width = xmax-xmin+1; // calc dims
\r
401 image_depth = ymax-ymin+1;
\r
403 hres = fgetw(pcxfp);
\r
404 vres = fgetw(pcxfp);
\r
406 fread(palette,1,48,pcxfp); // ega color map
\r
408 reserved = fgetc(pcxfp);
\r
409 color_planes = fgetc(pcxfp); // should be 1
\r
411 bpl = fgetw(pcxfp); // bytes per line
\r
412 palette_type = fgetw(pcxfp);
\r
414 fread(filler,1,58,pcxfp); // nothing important here
\r
417 void ReadPCXLine(byte *dest)
\r
419 int i=0,c=0,n=0,run=0;
\r
422 for (n=0; n<image_width; n+=run)
\r
424 // assume single pixel
\r
430 // calc run and grab color
\r
434 // now replicate run bytes
\r
435 for (i=0; i<run; i++)
\r
436 dest[vidoffset+n+i]=(byte)c;
\r
438 // skip row padding, if any
\r
439 fskip(bpl-image_width,pcxfp);
\r
442 void LoadPCX(char *filename)
\r
447 if (pcxfp) fclose(pcxfp);
\r
448 pcxfp=fopen(filename,"rb");
\r
450 { printf("unable to open %s", filename);
\r
457 // allocate image data
\r
458 if (virscr) { free(virscr); virscr=0; }
\r
459 virscr=(byte *)malloc(image_width*image_depth);
\r
461 // decompress image data
\r
462 for (i=0; i<image_depth; i++)
\r
463 { vidoffset=i*image_width;
\r
464 ReadPCXLine(virscr);
\r
468 if (fgetc(pcxfp) == 12)
\r
469 fread(pal,1,768,pcxfp);
\r
475 static int bufsize=0;
\r
476 static byte *csrc=0, *cb=0;
\r
478 static void emitc(byte b) { *csrc++=b, bufsize++; }
\r
480 static void Compress(byte *p, int len)
\r
483 byte byt=0,samect=0;
\r
491 while (samect<254 && i<len && byt==p[i])
\r
494 if (samect==2 && byt != 0xFF) { emitc(byt); }
\r
495 if (samect==3 && byt != 0xFF) { emitc(byt); emitc(byt); }
\r
496 if (samect>3 || byt == 0xFF)
\r
506 static byte *raw=0,*r=0;
\r
508 static void dumpframe(int x, int y)
\r
510 byte *src=&virscr[(y*image_width)+x];
\r
512 for (y=0; y<frame_h; y++)
\r
514 for (x=0; x<frame_w; x++)
\r
520 ////////////////////////////////////////////////////////////////////////////
\r
521 ////////////////////////////////////////////////////////////////////////////
\r
523 static void WriteFrames(char *filename, FILE *dump)
\r
528 printf(" ú reading image %s \r", pcx_name);
\r
536 printf(" ú collecting frames \r");
\r
539 // setup bufs for raw data/compression
\r
540 raw_bytes = total_frames * (frame_w*frame_h);
\r
541 cb = (byte *)malloc(raw_bytes);
\r
542 raw = (byte *)malloc(raw_bytes); r=raw;
\r
544 // dump all frames in row major byte order into 'raw'
\r
545 for (i=0; i<10; i++)
\r
546 for (j=0; j<per_row; j++)
\r
548 if ((i*per_row)+j<total_frames)
\r
549 dumpframe(1+(j*(frame_w+1)), 1+(i*(frame_h+1)));
\r
555 printf(" ú compressing \r");
\r
558 // smush the sucker
\r
559 Compress(raw, raw_bytes);
\r
561 fputd(bufsize,dump); // compressed data bytes
\r
562 fputraw((char *)cb,bufsize,dump); // compressed data
\r
572 static void WriteInfo(FILE *dump)
\r
574 fputc(2, dump); // version
\r
575 fputw((word)frame_w, dump); // frame dims
\r
576 fputw((word)frame_h, dump);
\r
577 fputw((word)hot_x, dump); // hotspot coords
\r
578 fputw((word)hot_y, dump);
\r
579 fputw((word)hot_w, dump); // hotspot dims
\r
580 fputw((word)hot_h, dump);
\r
581 fputw((word)total_frames, dump); // total frames
\r
584 static void WriteScripts(FILE *fp)
\r
591 fputstrn(lscript,fp);
\r
592 fputstrn(rscript,fp);
\r
593 fputstrn(uscript,fp);
\r
594 fputstrn(dscript,fp);
\r
597 static void write_chr()
\r
599 strcat(pcx_name, ".pcx");
\r
600 strcat(chr_name, ".chr");
\r
605 printf("pcx_name: %s \n", pcx_name);
\r
606 printf("chr_name: %s \n", chr_name);
\r
607 printf("frame_w: %i \n", frame_w);
\r
608 printf("frame_h: %i \n", frame_h);
\r
609 printf("hot_x: %i \n", hot_x);
\r
610 printf("hot_y: %i \n", hot_y);
\r
611 printf("hot_w: %i \n", hot_w);
\r
612 printf("hot_h: %i \n", hot_h);
\r
613 printf("per_row: %i \n", per_row);
\r
614 printf("total_frames: %i \n", total_frames);
\r
615 printf("lidle: %i \n", lidle);
\r
616 printf("ridle: %i \n", ridle);
\r
617 printf("uidle: %i \n", uidle);
\r
618 printf("didle: %i \n", didle);
\r
619 printf("lscript: %s \n", lscript);
\r
620 printf("rscript: %s \n", rscript);
\r
621 printf("uscript: %s \n", uscript);
\r
622 printf("dscript: %s \n", dscript);
\r
627 printf("> dumping %s \n", chr_name);
\r
630 chrfp=fopen(chr_name, "wb");
\r
631 if (!chrfp) fatal("unable to open %s", chr_name);
\r
634 WriteFrames(pcx_name,chrfp);
\r
635 WriteScripts(chrfp);
\r
639 printf("complete! \n");
\r
643 int main(int argc, char *argv[])
\r
647 parse_args(argc, argv);
\r