/* Copyright (C) 1996-1997 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA See file, 'COPYING', for details. */ // // spritegen.c: generates a .spr file from a series of .lbm frame files. // Result is stored in /raid/quake/id1/sprites/.spr. // #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include "QF/dstring.h" #include "QF/image.h" #include "QF/pcx.h" #include "QF/qendian.h" #include "QF/qtypes.h" #include "QF/quakeio.h" #include "QF/script.h" #include "QF/spritegn.h" #include "QF/sys.h" #define MAX_BUFFER_SIZE 0x100000 #define MAX_FRAMES 1000 tex_t *image; dsprite_t sprite; byte *lumpbuffer, *plump; dstring_t *spritedir; dstring_t *spriteoutname; int framesmaxs[2]; int framecount; script_t scr; typedef struct { spriteframetype_t type; // single frame or group of frames void *pdata; // either a dspriteframe_t or group info float interval; // only used for frames in groups int numgroupframes; // only used by group headers } spritepackage_t; spritepackage_t frames[MAX_FRAMES]; static void FinishSprite (void); static void Cmd_Spritename (void); /* ============ WriteFrame ============ */ static void WriteFrame (QFile *spriteouthandle, int framenum) { dspriteframe_t *pframe; dspriteframe_t frametemp; pframe = (dspriteframe_t *)frames[framenum].pdata; frametemp.origin[0] = LittleLong (pframe->origin[0]); frametemp.origin[1] = LittleLong (pframe->origin[1]); frametemp.width = LittleLong (pframe->width); frametemp.height = LittleLong (pframe->height); Qwrite (spriteouthandle, &frametemp, sizeof (frametemp)); Qwrite (spriteouthandle, (byte *)(pframe + 1), pframe->height * pframe->width); } /* ============ WriteSprite ============ */ static void WriteSprite (QFile *spriteouthandle) { int i, groupframe, curframe; dsprite_t spritetemp; sprite.boundingradius = sqrt (((framesmaxs[0] >> 1) * (framesmaxs[0] >> 1)) + ((framesmaxs[1] >> 1) * (framesmaxs[1] >> 1))); // // write out the sprite header // spritetemp.type = LittleLong (sprite.type); spritetemp.boundingradius = LittleFloat (sprite.boundingradius); spritetemp.width = LittleLong (framesmaxs[0]); spritetemp.height = LittleLong (framesmaxs[1]); spritetemp.numframes = LittleLong (sprite.numframes); spritetemp.beamlength = LittleFloat (sprite.beamlength); spritetemp.synctype = LittleFloat (sprite.synctype); spritetemp.version = LittleLong (SPR_VERSION); spritetemp.ident = LittleLong (IDHEADER_SPR); Qwrite (spriteouthandle, &spritetemp, sizeof(spritetemp)); // // write out the frames // curframe = 0; for (i=0 ; i 255) || (h > 255)) Sys_Error ("Sprite has a dimension longer than 255"); xh = xl+w; yh = yl+h; pframe = (dspriteframe_t *)plump; frames[framecount].pdata = pframe; frames[framecount].type = SPR_SINGLE; if (Script_TokenAvailable (&scr, false)) { Script_GetToken (&scr, false); frames[framecount].interval = atof (Script_Token (&scr)); if (frames[framecount].interval <= 0.0) Sys_Error ("Non-positive interval"); } else { frames[framecount].interval = 0.1; } if (Script_TokenAvailable (&scr, false)) { Script_GetToken (&scr, false); pframe->origin[0] = -atoi (Script_Token (&scr)); Script_GetToken (&scr, false); pframe->origin[1] = atoi (Script_Token (&scr)); } else { pframe->origin[0] = -(w >> 1); pframe->origin[1] = h >> 1; } pframe->width = w; pframe->height = h; if (w > framesmaxs[0]) framesmaxs[0] = w; if (h > framesmaxs[1]) framesmaxs[1] = h; plump = (byte *)(pframe + 1); screen_p = image->data + yl* image->width + xl; linedelta = image->width - w; for (y=yl ; y= MAX_FRAMES) Sys_Error ("Too many frames; increase MAX_FRAMES\n"); } /* =============== Cmd_GroupStart =============== */ static void Cmd_GroupStart (void) { int groupframe; groupframe = framecount++; frames[groupframe].type = SPR_GROUP; frames[groupframe].numgroupframes = 0; while (1) { if (!Script_GetToken (&scr, true)) Sys_Error ("End of file during group"); if (!strcmp (Script_Token (&scr), "$frame")) { Cmd_Frame (); frames[groupframe].numgroupframes++; } else if (!strcmp (Script_Token (&scr), "$load")) { Cmd_Load (); } else if (!strcmp (Script_Token (&scr), "$groupend")) { break; } else { Sys_Error ("$frame, $load, or $groupend expected\n"); } } if (frames[groupframe].numgroupframes == 0) Sys_Error ("Empty group\n"); } /* =============== ParseScript =============== */ static void ParseScript (void) { while (1) { if (!Script_GetToken (&scr, true)) break; if (!strcmp (Script_Token (&scr), "$load")) { Cmd_Load (); } if (!strcmp (Script_Token (&scr), "$spritename")) { Cmd_Spritename (); } else if (!strcmp (Script_Token (&scr), "$type")) { Cmd_Type (); } else if (!strcmp (Script_Token (&scr), "$beamlength")) { Cmd_Beamlength (); } else if (!strcmp (Script_Token (&scr), "$sync")) { sprite.synctype = ST_SYNC; } else if (!strcmp (Script_Token (&scr), "$frame")) { Cmd_Frame (); sprite.numframes++; } else if (!strcmp (Script_Token (&scr), "$load")) { Cmd_Load (); } else if (!strcmp (Script_Token (&scr), "$groupstart")) { Cmd_GroupStart (); sprite.numframes++; } } } /* ============== Cmd_Spritename ============== */ static void Cmd_Spritename (void) { if (sprite.numframes) FinishSprite (); Script_GetToken (&scr, false); dsprintf (spriteoutname, "%s%s.spr", spritedir->str, Script_Token (&scr)); memset (&sprite, 0, sizeof(sprite)); framecount = 0; framesmaxs[0] = -9999999; framesmaxs[1] = -9999999; lumpbuffer = malloc (MAX_BUFFER_SIZE * 2); // *2 for padding if (!lumpbuffer) Sys_Error ("Couldn't get buffer memory"); plump = lumpbuffer; sprite.synctype = ST_RAND; // default } /* ============== FinishSprite ============== */ static void FinishSprite (void) { QFile *spriteouthandle; if (sprite.numframes == 0) Sys_Error ("no frames\n"); if (!spriteoutname->str) Sys_Error ("Didn't name sprite file"); if ((plump - lumpbuffer) > MAX_BUFFER_SIZE) Sys_Error ("Sprite package too big; increase MAX_BUFFER_SIZE"); spriteouthandle = Qopen (spriteoutname->str, "wb"); printf ("saving in %s\n", spriteoutname->str); WriteSprite (spriteouthandle); Qclose (spriteouthandle); printf ("spritegen: successful\n"); printf ("%d frame(s)\n", sprite.numframes); printf ("%d ungrouped frame(s), including group headers\n", framecount); dstring_clearstr (spriteoutname); // clear for a new sprite } /* ============== main ============== */ int main (int argc, char **argv) { int i, bytes; QFile *file; char *buf; if (argc != 2) Sys_Error ("usage: spritegen file.qc"); spritedir = dstring_newstr (); spriteoutname = dstring_newstr (); i = 1; //SetQdirFromPath (argv[i]); //ExtractFilePath (argv[i], spritedir); // chop the filename // // load the script // file = Qopen (argv[i], "rt"); if (!file) Sys_Error ("couldn't open %s. %s", argv[i], strerror(errno)); bytes = Qfilesize (file); buf = malloc (bytes + 1); bytes = Qread (file, buf, bytes); buf[bytes] = 0; Qclose (file); Script_Start (&scr, argv[i], buf); ParseScript (); FinishSprite (); return 0; }