--- /dev/null
+/*\r
+Copyright (C) 1998 BJ Eirich (aka vecna)\r
+This program is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU General Public License\r
+as published by the Free Software Foundation; either version 2\r
+of the License, or (at your option) any later version.\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\r
+See the GNU General Public Lic\r
+See the GNU General Public License for more details.\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
+*/\r
+\r
+// CHRMAK.CC\r
+// V2 PCX to CHR converter w/ makefiles\r
+//\r
+// coded by aen\r
+// aen@verge-rpg.com\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <stdarg.h>\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include <sys/stat.h>\r
+\r
+#include <conio.h>\r
+\r
+////////////////////////////////////////////////////////////////////////////\r
+////////////////////////////////////////////////////////////////////////////\r
+\r
+typedef unsigned char byte;\r
+typedef unsigned short word;\r
+typedef unsigned long quad;\r
+\r
+static void fputw(word w, FILE *fp) { fwrite(&w,1,2,fp); }\r
+static void fputd(quad d, FILE *fp) { fwrite(&d,1,4,fp); }\r
+static word fgetw(FILE *fp) { word w; fread(&w,1,2,fp); return w; }\r
+quad fgetd(FILE *fp) { quad d; fread(&d,1,4,fp); return d; }\r
+\r
+// skips the number of bytes in the file; just seeks past them\r
+static void fskip(int bytes, FILE *fp)\r
+ { fseek(fp,bytes,SEEK_CUR); }\r
+\r
+static void fputraw(char *raw, int bytes, FILE *fp)\r
+ { fwrite(raw, 1,bytes, fp); }\r
+\r
+// writes a null-terminated string to the file\r
+void fputstrz(char *str, FILE *fp)\r
+ { fputraw(str, strlen(str)+1, fp); }\r
+\r
+// writes a string to the file (without the null-terminator), preceeded by\r
+// a quad length marker\r
+static void fputstrn(char *str, FILE *fp)\r
+ { int n=strlen(str)+1; fputd(n,fp); fputraw(str,n,fp); }\r
+\r
+////////////////////////////////////////////////////////////////////////////\r
+////////////////////////////////////////////////////////////////////////////\r
+\r
+#define CHRMAK_VER_MAJ 0\r
+#define CHRMAK_VER_MIN 1\r
+#define CHRMAK_VER_STR "0.1b"\r
+#define CHRMAK_AUTHORS "aen"\r
+\r
+// parsing vars\r
+static char *mak_base=0;\r
+static char *makp=0;\r
+static int mak_bytes=0;\r
+static char mak_tok_ident[256];\r
+static char mak_tok_val[256];\r
+static int mak_tok_valn=0; // numeric val of mak_tok\r
+static int mak_line=0;\r
+\r
+// makefile vars\r
+static char chrmak_makefile[256];\r
+\r
+static char pcx_name[256]; static int got_pcx_name=0;\r
+static char chr_name[256]; static int got_chr_name=0;\r
+static int frame_w=0; static int got_frame_w=0;\r
+static int frame_h=0; static int got_frame_h=0;\r
+static int hot_x=0; static int got_hot_x=0;\r
+static int hot_y=0; static int got_hot_y=0;\r
+static int hot_w=0; static int got_hot_w=0;\r
+static int hot_h=0; static int got_hot_h=0;\r
+static int per_row=0; static int got_per_row=0;\r
+static int total_frames=0; static int got_total_frames=0;\r
+static int lidle=0; static int got_lidle=0;\r
+static int ridle=0; static int got_ridle=0;\r
+static int uidle=0; static int got_uidle=0;\r
+static int didle=0; static int got_didle=0;\r
+static char lscript[256]; static int got_lscript=0;\r
+static char rscript[256]; static int got_rscript=0;\r
+static char uscript[256]; static int got_uscript=0;\r
+static char dscript[256]; static int got_dscript=0;\r
+\r
+void warning(char *message, ...)\r
+{\r
+ static char buffer[256];\r
+ va_list args;\r
+\r
+ va_start(args, message);\r
+ vsprintf(buffer, message, args);\r
+ va_end(args);\r
+\r
+ printf("%s \n", buffer);\r
+}\r
+\r
+static void fatal(char *message, ...)\r
+{\r
+ static char buffer[256];\r
+ va_list args;\r
+\r
+ va_start(args, message);\r
+ vsprintf(buffer, message, args);\r
+ va_end(args);\r
+\r
+ printf("%s \n", buffer);\r
+\r
+ exit(0);\r
+}\r
+\r
+//#ifdef __DJGPP__\r
+// Watcom has one of these\r
+static int filelength(int handle)\r
+{\r
+ struct stat fileinfo;\r
+ if (-1 == fstat(handle, &fileinfo))\r
+ fatal("error fstating");\r
+ return fileinfo.st_size;\r
+}\r
+//#endif\r
+\r
+static int streq(char *a, char *b)\r
+{\r
+ while (*a)\r
+ {\r
+ if (*a++ != *b++)\r
+ return 0;\r
+ }\r
+ return !*b;\r
+}\r
+\r
+static void usage()\r
+{\r
+ printf("usage: chrmak <makefile> \n");\r
+ exit(0);\r
+}\r
+\r
+static void banner()\r
+{\r
+ printf("chrmak v%s \1e by %s \n", CHRMAK_VER_STR, CHRMAK_AUTHORS);\r
+}\r
+\r
+static void parse_args(int argc, char *argv[])\r
+{\r
+ if (argc != 2)\r
+ usage();\r
+\r
+ strcpy(chrmak_makefile, argv[1]);\r
+}\r
+\r
+static void skip_cpp_comment()\r
+{\r
+ makp+=2;\r
+ while (*makp && '\n'!=*makp)\r
+ makp++;\r
+ if (*makp)\r
+ makp++;\r
+}\r
+\r
+static void skip_c_comment()\r
+{\r
+ makp+=2;\r
+ while (*makp && ('*'!=makp[0] || '/'!=makp[1]))\r
+ {\r
+ if ('\n'==*makp)\r
+ mak_line++;\r
+ if ('/'==makp[0] && '*'==makp[1])\r
+ skip_c_comment();\r
+ else makp++;\r
+ }\r
+ if (*makp)\r
+ makp+=2;\r
+}\r
+\r
+static void parse_whitespace()\r
+{\r
+ do {\r
+ if (!*makp)\r
+ return;\r
+ if (isspace(*makp))\r
+ {\r
+ while (*makp && isspace(*makp))\r
+ {\r
+ if ('\n'==*makp)\r
+ mak_line++;\r
+ makp++;\r
+ }\r
+ continue;\r
+ }\r
+ if ('/'==makp[0] && '/'==makp[1])\r
+ { skip_cpp_comment(); continue; }\r
+ if ('/'==makp[0] && '*'==makp[1])\r
+ { skip_c_comment(); continue; }\r
+ break;\r
+ } while (1);\r
+}\r
+\r
+static void grab_ident()\r
+{\r
+ char *t=mak_tok_ident;\r
+ while (isalnum(*makp) || '_'==*makp)\r
+ *t++=*makp++;\r
+ *t=0;\r
+ strlwr(mak_tok_ident);\r
+}\r
+\r
+static void grab_val()\r
+{\r
+ char *t=mak_tok_val;\r
+ while (isalnum(*makp) || '_'==*makp)\r
+ *t++=*makp++;\r
+ *t=0;\r
+ mak_tok_valn=atoi(mak_tok_val);\r
+}\r
+\r
+static int ident_is(char *id) { return streq(mak_tok_ident,id); }\r
+\r
+static void do_assign()\r
+{\r
+ if (ident_is("pcx_name"))\r
+ { strcpy(pcx_name, mak_tok_val); got_pcx_name=1; return; }\r
+ else if (ident_is("chr_name"))\r
+ { strcpy(chr_name, mak_tok_val); got_chr_name=1; return; }\r
+ else if (ident_is("frame_w"))\r
+ { frame_w=mak_tok_valn; got_frame_w=1; return; }\r
+ else if (ident_is("frame_h"))\r
+ { frame_h=mak_tok_valn; got_frame_h=1; return; }\r
+ else if (ident_is("hot_x"))\r
+ { hot_x=mak_tok_valn; got_hot_x=1; return; }\r
+ else if (ident_is("hot_y"))\r
+ { hot_y=mak_tok_valn; got_hot_y=1; return; }\r
+ else if (ident_is("hot_w"))\r
+ { hot_w=mak_tok_valn; got_hot_w=1; return; }\r
+ else if (ident_is("hot_h"))\r
+ { hot_h=mak_tok_valn; got_hot_h=1; return; }\r
+ else if (ident_is("per_row"))\r
+ { per_row=mak_tok_valn; got_per_row=1; return; }\r
+ else if (ident_is("total_frames"))\r
+ { total_frames=mak_tok_valn; got_total_frames=1; return; }\r
+ else if (ident_is("lidle"))\r
+ { lidle=mak_tok_valn; got_lidle=1; return; }\r
+ else if (ident_is("ridle"))\r
+ { ridle=mak_tok_valn; got_ridle=1; return; }\r
+ else if (ident_is("uidle"))\r
+ { uidle=mak_tok_valn; got_uidle=1; return; }\r
+ else if (ident_is("didle"))\r
+ { didle=mak_tok_valn; got_didle=1; return; }\r
+ else if (ident_is("lscript"))\r
+ { strcpy(lscript, mak_tok_val); got_lscript=1; return; }\r
+ else if (ident_is("rscript"))\r
+ { strcpy(rscript, mak_tok_val); got_rscript=1; return; }\r
+ else if (ident_is("uscript"))\r
+ { strcpy(uscript, mak_tok_val); got_uscript=1; return; }\r
+ else if (ident_is("dscript"))\r
+ { strcpy(dscript, mak_tok_val); got_dscript=1; return; }\r
+\r
+ fatal("%s: unknown ident '%s' on line %i",\r
+ chrmak_makefile, mak_tok_ident, mak_line);\r
+}\r
+\r
+static int parse_assign()\r
+{\r
+ int last_line=0; // helper for error detection\r
+\r
+ parse_whitespace();\r
+ if (!*makp)\r
+ return 1;\r
+ else if (isalpha(*makp))\r
+ {\r
+ grab_ident(); // get ident\r
+ last_line=mak_line;\r
+\r
+ parse_whitespace(); // expect\r
+ if ('=' != *makp++)\r
+ fatal("%s: expected = on line %i", chrmak_makefile, last_line);\r
+\r
+ parse_whitespace(); // get val\r
+ grab_val();\r
+ last_line=mak_line;\r
+\r
+ do_assign();\r
+\r
+ parse_whitespace(); // expect\r
+ if (';' != *makp++)\r
+ fatal("%s: expected ; on line %i", chrmak_makefile, last_line);\r
+ else while (';'==*makp) makp++;\r
+\r
+ return 0;\r
+ }\r
+ fatal("%s: expected ident, got '%c' on line %i",\r
+ chrmak_makefile, *makp, mak_line);\r
+ return 1;\r
+}\r
+\r
+static void check_needs()\r
+{\r
+ if (!got_pcx_name) fatal("%s: pcx_name missing", chrmak_makefile);\r
+ if (!got_chr_name) fatal("%s: chr_name missing", chrmak_makefile);\r
+ if (!got_frame_w) fatal("%s: frame_w missing", chrmak_makefile);\r
+ if (!got_frame_h) fatal("%s: frame_h missing", chrmak_makefile);\r
+ if (!got_hot_x) fatal("%s: hot_x missing", chrmak_makefile);\r
+ if (!got_hot_y) fatal("%s: hot_y missing", chrmak_makefile);\r
+ if (!got_hot_w) fatal("%s: hot_w missing", chrmak_makefile);\r
+ if (!got_hot_h) fatal("%s: hot_h missing", chrmak_makefile);\r
+ if (!got_per_row) fatal("%s: per_row missing", chrmak_makefile);\r
+ if (!got_total_frames) fatal("%s: total_frames missing", chrmak_makefile);\r
+ if (!got_lidle) fatal("%s: lidle missing", chrmak_makefile);\r
+ if (!got_ridle) fatal("%s: ridle missing", chrmak_makefile);\r
+ if (!got_uidle) fatal("%s: uidle missing", chrmak_makefile);\r
+ if (!got_didle) fatal("%s: didle missing", chrmak_makefile);\r
+ if (!got_lscript) fatal("%s: lscript missing", chrmak_makefile);\r
+ if (!got_rscript) fatal("%s: rscript missing", chrmak_makefile);\r
+ if (!got_uscript) fatal("%s: uscript missing", chrmak_makefile);\r
+ if (!got_dscript) fatal("%s: dscript missing", chrmak_makefile);\r
+}\r
+\r
+static void parse_makefile()\r
+{\r
+ FILE *fp=0;\r
+\r
+ printf("ú parsing %s \r", chrmak_makefile);\r
+ fflush(stdout);\r
+\r
+ fp=fopen(chrmak_makefile, "rb");\r
+ if (!fp) fatal("unable to open %s", chrmak_makefile);\r
+\r
+ mak_bytes=filelength(fileno(fp)); // calc bytes\r
+ mak_base=new char [mak_bytes+1]; // alloc room\r
+ fread(mak_base,1,mak_bytes,fp); // read bytes\r
+ mak_base[mak_bytes]=0; // null-term\r
+ makp=mak_base; // setup cur byte ptr\r
+ mak_line=1;\r
+\r
+ while (!parse_assign())\r
+ ;\r
+\r
+ // got everything we need?\r
+ check_needs();\r
+\r
+ delete[]mak_base; mak_base=0;\r
+ makp=0;\r
+\r
+ fclose(fp);\r
+\r
+ printf("û \n");\r
+ fflush(stdout);\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////\r
+// PCX & COMPRESS STUFF ////////////////////////////////////////////////////\r
+////////////////////////////////////////////////////////////////////////////\r
+\r
+static FILE *chrfp=0;\r
+static FILE *pcxfp=0;\r
+static byte *virscr=0;\r
+\r
+int manufacturer=0; // pcx header\r
+int version=0;\r
+int encoding=0;\r
+int bpp=0;\r
+int xmin=0,ymin=0;\r
+int xmax=0,ymax=0;\r
+int hres=0,vres=0;\r
+char palette[48];\r
+int reserved=0;\r
+int color_planes=0;\r
+int bpl=0;\r
+int palette_type=0;\r
+char filler[58];\r
+byte pal[768];\r
+\r
+int image_width=0,image_depth=0;\r
+quad vidoffset=0;\r
+\r
+void LoadPCXHeader()\r
+{\r
+ manufacturer = fgetc(pcxfp); // always 10\r
+ version = fgetc(pcxfp); // should be 5?\r
+ encoding = fgetc(pcxfp); // always 1\r
+ bpp = fgetc(pcxfp); // bits per pixel\r
+\r
+ xmin = fgetw(pcxfp); // grab window\r
+ ymin = fgetw(pcxfp);\r
+ xmax = fgetw(pcxfp);\r
+ ymax = fgetw(pcxfp);\r
+ image_width = xmax-xmin+1; // calc dims\r
+ image_depth = ymax-ymin+1;\r
+\r
+ hres = fgetw(pcxfp);\r
+ vres = fgetw(pcxfp);\r
+\r
+ fread(palette,1,48,pcxfp); // ega color map\r
+\r
+ reserved = fgetc(pcxfp);\r
+ color_planes = fgetc(pcxfp); // should be 1\r
+\r
+ bpl = fgetw(pcxfp); // bytes per line\r
+ palette_type = fgetw(pcxfp);\r
+\r
+ fread(filler,1,58,pcxfp); // nothing important here\r
+}\r
+\r
+void ReadPCXLine(byte *dest)\r
+{\r
+ int i=0,c=0,n=0,run=0;\r
+\r
+ // decode a row\r
+ for (n=0; n<image_width; n+=run)\r
+ {\r
+ // assume single pixel\r
+ run=1;\r
+ c=fgetc(pcxfp);\r
+ // is this a run?\r
+ if ((c&192)==192)\r
+ {\r
+ // calc run and grab color\r
+ run=c&63;\r
+ c=fgetc(pcxfp);\r
+ }\r
+ // now replicate run bytes\r
+ for (i=0; i<run; i++)\r
+ dest[vidoffset+n+i]=(byte)c;\r
+ }\r
+ // skip row padding, if any\r
+ fskip(bpl-image_width,pcxfp);\r
+}\r
+\r
+void LoadPCX(char *filename)\r
+{\r
+ int i=0;\r
+\r
+ // open file\r
+ if (pcxfp) fclose(pcxfp);\r
+ pcxfp=fopen(filename,"rb");\r
+ if (!pcxfp)\r
+ { printf("unable to open %s", filename);\r
+ exit(0);\r
+ }\r
+\r
+ // get info\r
+ LoadPCXHeader();\r
+\r
+ // allocate image data\r
+ if (virscr) { free(virscr); virscr=0; }\r
+ virscr=(byte *)malloc(image_width*image_depth);\r
+\r
+ // decompress image data\r
+ for (i=0; i<image_depth; i++)\r
+ { vidoffset=i*image_width;\r
+ ReadPCXLine(virscr);\r
+ }\r
+\r
+ // pal exists?\r
+ if (fgetc(pcxfp) == 12)\r
+ fread(pal,1,768,pcxfp);\r
+\r
+ // done\r
+ fclose(pcxfp);\r
+}\r
+\r
+static int bufsize=0;\r
+static byte *csrc=0, *cb=0;\r
+\r
+static void emitc(byte b) { *csrc++=b, bufsize++; }\r
+\r
+static void Compress(byte *p, int len)\r
+{\r
+ int i=0;\r
+ byte byt=0,samect=0;\r
+\r
+ csrc=cb;\r
+ i=0; bufsize=0;\r
+ do\r
+ {\r
+ byt=p[i++];\r
+ samect=1;\r
+ while (samect<254 && i<len && byt==p[i])\r
+ { samect++; i++; }\r
+\r
+ if (samect==2 && byt != 0xFF) { emitc(byt); }\r
+ if (samect==3 && byt != 0xFF) { emitc(byt); emitc(byt); }\r
+ if (samect>3 || byt == 0xFF)\r
+ {\r
+ emitc(0xFF);\r
+ emitc(samect);\r
+ }\r
+ emitc(byt);\r
+\r
+ } while (i<len);\r
+}\r
+\r
+static byte *raw=0,*r=0;\r
+\r
+static void dumpframe(int x, int y)\r
+{\r
+ byte *src=&virscr[(y*image_width)+x];\r
+\r
+ for (y=0; y<frame_h; y++)\r
+ {\r
+ for (x=0; x<frame_w; x++)\r
+ *r++=src[x];\r
+ src+=image_width;\r
+ }\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////\r
+////////////////////////////////////////////////////////////////////////////\r
+\r
+static void WriteFrames(char *filename, FILE *dump)\r
+{\r
+ int i=0,j=0;\r
+ int raw_bytes=0;\r
+\r
+ printf(" ú reading image %s \r", pcx_name);\r
+ fflush(stdout);\r
+\r
+ LoadPCX(filename);\r
+\r
+ printf(" û \n");\r
+ fflush(stdout);\r
+\r
+ printf(" ú collecting frames \r");\r
+ fflush(stdout);\r
+\r
+ // setup bufs for raw data/compression\r
+ raw_bytes = total_frames * (frame_w*frame_h);\r
+ cb = (byte *)malloc(raw_bytes);\r
+ raw = (byte *)malloc(raw_bytes); r=raw;\r
+\r
+ // dump all frames in row major byte order into 'raw'\r
+ for (i=0; i<10; i++)\r
+ for (j=0; j<per_row; j++)\r
+ {\r
+ if ((i*per_row)+j<total_frames)\r
+ dumpframe(1+(j*(frame_w+1)), 1+(i*(frame_h+1)));\r
+ }\r
+\r
+ printf(" û \n");\r
+ fflush(stdout);\r
+\r
+ printf(" ú compressing \r");\r
+ fflush(stdout);\r
+\r
+ // smush the sucker\r
+ Compress(raw, raw_bytes);\r
+\r
+ fputd(bufsize,dump); // compressed data bytes\r
+ fputraw((char *)cb,bufsize,dump); // compressed data\r
+\r
+ printf(" û \n");\r
+ fflush(stdout);\r
+\r
+ // cleanup bufs\r
+ free(raw);\r
+ free(cb);\r
+}\r
+\r
+static void WriteInfo(FILE *dump)\r
+{\r
+ fputc(2, dump); // version\r
+ fputw((word)frame_w, dump); // frame dims\r
+ fputw((word)frame_h, dump);\r
+ fputw((word)hot_x, dump); // hotspot coords\r
+ fputw((word)hot_y, dump);\r
+ fputw((word)hot_w, dump); // hotspot dims\r
+ fputw((word)hot_h, dump);\r
+ fputw((word)total_frames, dump); // total frames\r
+}\r
+\r
+static void WriteScripts(FILE *fp)\r
+{\r
+ fputd(lidle,fp);\r
+ fputd(ridle,fp);\r
+ fputd(uidle,fp);\r
+ fputd(didle,fp);\r
+\r
+ fputstrn(lscript,fp);\r
+ fputstrn(rscript,fp);\r
+ fputstrn(uscript,fp);\r
+ fputstrn(dscript,fp);\r
+}\r
+\r
+static void write_chr()\r
+{\r
+ strcat(pcx_name, ".pcx");\r
+ strcat(chr_name, ".chr");\r
+\r
+ /*\r
+ // DEBUG\r
+ printf(" \n");\r
+ printf("pcx_name: %s \n", pcx_name);\r
+ printf("chr_name: %s \n", chr_name);\r
+ printf("frame_w: %i \n", frame_w);\r
+ printf("frame_h: %i \n", frame_h);\r
+ printf("hot_x: %i \n", hot_x);\r
+ printf("hot_y: %i \n", hot_y);\r
+ printf("hot_w: %i \n", hot_w);\r
+ printf("hot_h: %i \n", hot_h);\r
+ printf("per_row: %i \n", per_row);\r
+ printf("total_frames: %i \n", total_frames);\r
+ printf("lidle: %i \n", lidle);\r
+ printf("ridle: %i \n", ridle);\r
+ printf("uidle: %i \n", uidle);\r
+ printf("didle: %i \n", didle);\r
+ printf("lscript: %s \n", lscript);\r
+ printf("rscript: %s \n", rscript);\r
+ printf("uscript: %s \n", uscript);\r
+ printf("dscript: %s \n", dscript);\r
+ fflush(stdout);\r
+ getch();\r
+ */\r
+\r
+ printf("> dumping %s \n", chr_name);\r
+ fflush(stdout);\r
+\r
+ chrfp=fopen(chr_name, "wb");\r
+ if (!chrfp) fatal("unable to open %s", chr_name);\r
+\r
+ WriteInfo(chrfp);\r
+ WriteFrames(pcx_name,chrfp);\r
+ WriteScripts(chrfp);\r
+\r
+ fclose(chrfp);\r
+\r
+ printf("complete! \n");\r
+ fflush(stdout);\r
+}\r
+\r
+int main(int argc, char *argv[])\r
+{\r
+ banner();\r
+\r
+ parse_args(argc, argv);\r
+ parse_makefile();\r
+\r
+ write_chr();\r
+\r
+ return 0;\r
+}\r