614 lines
11 KiB
C++
614 lines
11 KiB
C++
/***
|
|
*
|
|
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
|
*
|
|
* This product contains software technology licensed from Id
|
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
****/
|
|
|
|
//
|
|
// spritegen.c: generates a .spr file from a series of .lbm frame files.
|
|
// Result is stored in /raid/quake/id1/sprites/<scriptname>.spr.
|
|
//
|
|
#pragma warning(disable : 4244) // type conversion warning.
|
|
#define INCLUDELIBS
|
|
|
|
|
|
#ifdef NeXT
|
|
#include <libc.h>
|
|
#endif
|
|
|
|
#include "spritegn.h"
|
|
|
|
#define MAX_BUFFER_SIZE 0x100000
|
|
#define MAX_FRAMES 1000
|
|
|
|
dsprite_t sprite;
|
|
byte *byteimage, *lbmpalette;
|
|
int byteimagewidth, byteimageheight;
|
|
byte *lumpbuffer = NULL, *plump;
|
|
char spritedir[1024];
|
|
char spriteoutname[1024];
|
|
int framesmaxs[2];
|
|
int framecount;
|
|
|
|
qboolean do16bit = true;
|
|
|
|
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];
|
|
|
|
void FinishSprite(void);
|
|
void Cmd_Spritename(void);
|
|
|
|
|
|
/*
|
|
============
|
|
WriteFrame
|
|
============
|
|
*/
|
|
void WriteFrame(FILE* 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);
|
|
|
|
SafeWrite(spriteouthandle, &frametemp, sizeof(frametemp));
|
|
SafeWrite(spriteouthandle,
|
|
(byte*)(pframe + 1),
|
|
pframe->height * pframe->width);
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
WriteSprite
|
|
============
|
|
*/
|
|
void WriteSprite(FILE* 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.texFormat = LittleLong(sprite.texFormat);
|
|
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 = static_cast<synctype_t>(LittleFloat(sprite.synctype));
|
|
spritetemp.version = LittleLong(SPRITE_VERSION);
|
|
spritetemp.ident = LittleLong(IDSPRITEHEADER);
|
|
|
|
SafeWrite(spriteouthandle, &spritetemp, sizeof(spritetemp));
|
|
|
|
if (do16bit)
|
|
{
|
|
// Write out palette in 16bit mode
|
|
short cnt = 256;
|
|
SafeWrite(spriteouthandle, (void*)&cnt, sizeof(cnt));
|
|
SafeWrite(spriteouthandle, lbmpalette, cnt * 3);
|
|
}
|
|
|
|
//
|
|
// write out the frames
|
|
//
|
|
curframe = 0;
|
|
|
|
for (i = 0; i < sprite.numframes; i++)
|
|
{
|
|
SafeWrite(spriteouthandle, &frames[curframe].type,
|
|
sizeof(frames[curframe].type));
|
|
|
|
if (frames[curframe].type == SPR_SINGLE)
|
|
{
|
|
//
|
|
// single (non-grouped) frame
|
|
//
|
|
WriteFrame(spriteouthandle, curframe);
|
|
curframe++;
|
|
}
|
|
else
|
|
{
|
|
int j, numframes;
|
|
dspritegroup_t dsgroup;
|
|
float totinterval;
|
|
|
|
groupframe = curframe;
|
|
curframe++;
|
|
numframes = frames[groupframe].numgroupframes;
|
|
|
|
//
|
|
// set and write the group header
|
|
//
|
|
dsgroup.numframes = LittleLong(numframes);
|
|
|
|
SafeWrite(spriteouthandle, &dsgroup, sizeof(dsgroup));
|
|
|
|
//
|
|
// write the interval array
|
|
//
|
|
totinterval = 0.0;
|
|
|
|
for (j = 0; j < numframes; j++)
|
|
{
|
|
dspriteinterval_t temp;
|
|
|
|
totinterval += frames[groupframe + 1 + j].interval;
|
|
temp.interval = LittleFloat(totinterval);
|
|
|
|
SafeWrite(spriteouthandle, &temp, sizeof(temp));
|
|
}
|
|
|
|
for (j = 0; j < numframes; j++)
|
|
{
|
|
WriteFrame(spriteouthandle, curframe);
|
|
curframe++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
ExecCommand
|
|
============
|
|
*/
|
|
int cmdsrun;
|
|
|
|
void ExecCommand(char* cmd, ...)
|
|
{
|
|
int ret;
|
|
char cmdline[1024];
|
|
va_list argptr;
|
|
|
|
cmdsrun++;
|
|
|
|
va_start(argptr, cmd);
|
|
vsprintf(cmdline, cmd, argptr);
|
|
va_end(argptr);
|
|
|
|
// printf ("=============================================================\n");
|
|
// printf ("spritegen: %s\n",cmdline);
|
|
fflush(stdout);
|
|
ret = system(cmdline);
|
|
// printf ("=============================================================\n");
|
|
|
|
if (ret)
|
|
Error("spritegen: exiting due to error");
|
|
}
|
|
|
|
/*
|
|
==============
|
|
LoadScreen
|
|
==============
|
|
*/
|
|
void LoadScreen(char* name)
|
|
{
|
|
static byte origpalette[256 * 3];
|
|
int iError;
|
|
|
|
printf("grabbing from %s...\n", name);
|
|
iError = LoadBMP(name, &byteimage, &lbmpalette);
|
|
if (iError)
|
|
Error("unable to load file \"%s\"\n", name);
|
|
|
|
byteimagewidth = bmhd.w;
|
|
byteimageheight = bmhd.h;
|
|
|
|
if (sprite.numframes == 0)
|
|
memcpy(origpalette, lbmpalette, sizeof(origpalette));
|
|
else if (memcmp(origpalette, lbmpalette, sizeof(origpalette)) != 0)
|
|
{
|
|
Error("bitmap \"%s\" doesn't share a pallette with the previous bitmap\n", name);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
Cmd_Type
|
|
===============
|
|
*/
|
|
void Cmd_Type(void)
|
|
{
|
|
GetToken(false);
|
|
if (!strcmp(token, "vp_parallel_upright"))
|
|
sprite.type = SPR_VP_PARALLEL_UPRIGHT;
|
|
else if (!strcmp(token, "facing_upright"))
|
|
sprite.type = SPR_FACING_UPRIGHT;
|
|
else if (!strcmp(token, "vp_parallel"))
|
|
sprite.type = SPR_VP_PARALLEL;
|
|
else if (!strcmp(token, "oriented"))
|
|
sprite.type = SPR_ORIENTED;
|
|
else if (!strcmp(token, "vp_parallel_oriented"))
|
|
sprite.type = SPR_VP_PARALLEL_ORIENTED;
|
|
else
|
|
Error("Bad sprite type\n");
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
Cmd_Texture
|
|
===============
|
|
*/
|
|
void Cmd_Texture(void)
|
|
{
|
|
GetToken(false);
|
|
|
|
if (!strcmp(token, "additive"))
|
|
sprite.texFormat = SPR_ADDITIVE;
|
|
else if (!strcmp(token, "normal"))
|
|
sprite.texFormat = SPR_NORMAL;
|
|
else if (!strcmp(token, "indexalpha"))
|
|
sprite.texFormat = SPR_INDEXALPHA;
|
|
else if (!strcmp(token, "alphatest"))
|
|
sprite.texFormat = SPR_ALPHTEST;
|
|
else
|
|
Error("Bad sprite texture type\n");
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
Cmd_Beamlength
|
|
===============
|
|
*/
|
|
void Cmd_Beamlength()
|
|
{
|
|
GetToken(false);
|
|
sprite.beamlength = atof(token);
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
Cmd_Load
|
|
===============
|
|
*/
|
|
void Cmd_Load(void)
|
|
{
|
|
GetToken(false);
|
|
LoadScreen(ExpandPathAndArchive(token));
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
Cmd_Frame
|
|
===============
|
|
*/
|
|
void Cmd_Frame()
|
|
{
|
|
int x, y, xl, yl, xh, yh, w, h;
|
|
byte *screen_p, *source;
|
|
int linedelta;
|
|
dspriteframe_t* pframe;
|
|
int pix;
|
|
|
|
GetToken(false);
|
|
xl = atoi(token);
|
|
GetToken(false);
|
|
yl = atoi(token);
|
|
GetToken(false);
|
|
w = atoi(token);
|
|
GetToken(false);
|
|
h = atoi(token);
|
|
|
|
if ((xl & 0x07) || (yl & 0x07) || (w & 0x07) || (h & 0x07))
|
|
Error("Sprite dimensions not multiples of 8\n");
|
|
|
|
if ((w > 256) || (h > 256))
|
|
Error("Sprite has a dimension longer than 256");
|
|
|
|
xh = xl + w;
|
|
yh = yl + h;
|
|
|
|
pframe = (dspriteframe_t*)plump;
|
|
frames[framecount].pdata = pframe;
|
|
frames[framecount].type = SPR_SINGLE;
|
|
|
|
if (TokenAvailable())
|
|
{
|
|
GetToken(false);
|
|
frames[framecount].interval = atof(token);
|
|
if (frames[framecount].interval <= 0.0)
|
|
Error("Non-positive interval");
|
|
}
|
|
else
|
|
{
|
|
frames[framecount].interval = (float)0.1;
|
|
}
|
|
|
|
if (TokenAvailable())
|
|
{
|
|
GetToken(false);
|
|
pframe->origin[0] = -atoi(token);
|
|
GetToken(false);
|
|
pframe->origin[1] = atoi(token);
|
|
}
|
|
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 = byteimage + yl * byteimagewidth + xl;
|
|
linedelta = byteimagewidth - w;
|
|
|
|
source = plump;
|
|
|
|
for (y = yl; y < yh; y++)
|
|
{
|
|
for (x = xl; x < xh; x++)
|
|
{
|
|
pix = *screen_p;
|
|
*screen_p++ = 0;
|
|
// if (pix == 255)
|
|
// pix = 0;
|
|
*plump++ = pix;
|
|
}
|
|
screen_p += linedelta;
|
|
}
|
|
|
|
framecount++;
|
|
if (framecount >= MAX_FRAMES)
|
|
Error("Too many frames; increase MAX_FRAMES\n");
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
Cmd_GroupStart
|
|
===============
|
|
*/
|
|
void Cmd_GroupStart(void)
|
|
{
|
|
int groupframe;
|
|
|
|
groupframe = framecount++;
|
|
|
|
frames[groupframe].type = SPR_GROUP;
|
|
frames[groupframe].numgroupframes = 0;
|
|
|
|
while (1)
|
|
{
|
|
GetToken(true);
|
|
if (endofscript)
|
|
Error("End of file during group");
|
|
|
|
if (!strcmp(token, "$frame"))
|
|
{
|
|
Cmd_Frame();
|
|
frames[groupframe].numgroupframes++;
|
|
}
|
|
else if (!strcmp(token, "$load"))
|
|
{
|
|
Cmd_Load();
|
|
}
|
|
else if (!strcmp(token, "$groupend"))
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
Error("$frame, $load, or $groupend expected\n");
|
|
}
|
|
}
|
|
|
|
if (frames[groupframe].numgroupframes == 0)
|
|
Error("Empty group\n");
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
ParseScript
|
|
===============
|
|
*/
|
|
void ParseScript(void)
|
|
{
|
|
while (1)
|
|
{
|
|
GetToken(true);
|
|
if (endofscript)
|
|
break;
|
|
|
|
if (!strcmp(token, "$load"))
|
|
{
|
|
Cmd_Load();
|
|
}
|
|
if (!strcmp(token, "$spritename"))
|
|
{
|
|
Cmd_Spritename();
|
|
}
|
|
else if (!strcmp(token, "$type"))
|
|
{
|
|
Cmd_Type();
|
|
}
|
|
else if (!strcmp(token, "$texture"))
|
|
{
|
|
Cmd_Texture();
|
|
}
|
|
else if (!strcmp(token, "$beamlength"))
|
|
{
|
|
Cmd_Beamlength();
|
|
}
|
|
else if (!strcmp(token, "$sync"))
|
|
{
|
|
sprite.synctype = ST_SYNC;
|
|
}
|
|
else if (!strcmp(token, "$frame"))
|
|
{
|
|
Cmd_Frame();
|
|
sprite.numframes++;
|
|
}
|
|
else if (!strcmp(token, "$load"))
|
|
{
|
|
Cmd_Load();
|
|
}
|
|
else if (!strcmp(token, "$groupstart"))
|
|
{
|
|
Cmd_GroupStart();
|
|
sprite.numframes++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============
|
|
Cmd_Spritename
|
|
==============
|
|
*/
|
|
void Cmd_Spritename(void)
|
|
{
|
|
if (sprite.numframes)
|
|
FinishSprite();
|
|
|
|
GetToken(false);
|
|
sprintf(spriteoutname, "%s%s.spr", spritedir, token);
|
|
memset(&sprite, 0, sizeof(sprite));
|
|
framecount = 0;
|
|
|
|
framesmaxs[0] = -9999999;
|
|
framesmaxs[1] = -9999999;
|
|
|
|
if (!lumpbuffer)
|
|
lumpbuffer = reinterpret_cast<byte*>(malloc(MAX_BUFFER_SIZE * 2)); // *2 for padding
|
|
|
|
if (!lumpbuffer)
|
|
Error("Couldn't get buffer memory");
|
|
|
|
plump = lumpbuffer;
|
|
sprite.synctype = ST_RAND; // default
|
|
}
|
|
|
|
/*
|
|
==============
|
|
FinishSprite
|
|
==============
|
|
*/
|
|
void FinishSprite(void)
|
|
{
|
|
FILE* spriteouthandle;
|
|
|
|
if (sprite.numframes == 0)
|
|
Error("no frames\n");
|
|
|
|
if (!strlen(spriteoutname))
|
|
Error("Didn't name sprite file");
|
|
|
|
if ((plump - lumpbuffer) > MAX_BUFFER_SIZE)
|
|
Error("Sprite package too big; increase MAX_BUFFER_SIZE");
|
|
|
|
spriteouthandle = SafeOpenWrite(spriteoutname);
|
|
printf("saving in %s\n", spriteoutname);
|
|
WriteSprite(spriteouthandle);
|
|
fclose(spriteouthandle);
|
|
|
|
printf("spritegen: successful\n");
|
|
printf("%d frame(s)\n", sprite.numframes);
|
|
printf("%d ungrouped frame(s), including group headers\n", framecount);
|
|
|
|
spriteoutname[0] = 0; // clear for a new sprite
|
|
}
|
|
|
|
/*
|
|
==============
|
|
main
|
|
|
|
==============
|
|
*/
|
|
extern char qproject[];
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
int i;
|
|
|
|
printf("sprgen.exe v 1.1 (%s)\n", __DATE__);
|
|
printf("----- Sprite Gen ----\n");
|
|
|
|
if (argc < 2 || argc > 7)
|
|
Error("usage: sprgen [-archive directory] [-no16bit] [-proj <project>] file.qc");
|
|
|
|
for (i = 1; i < argc; i++)
|
|
{
|
|
if (*argv[i] == '-')
|
|
{
|
|
if (!strcmp(argv[i], "-archive"))
|
|
{
|
|
archive = true;
|
|
strcpy(archivedir, argv[i + 1]);
|
|
printf("Archiving source to: %s\n", archivedir);
|
|
i++;
|
|
}
|
|
else if (!strcmp(argv[i], "-proj"))
|
|
{
|
|
strcpy(qproject, argv[i + 1]);
|
|
i++;
|
|
}
|
|
else if (!strcmp(argv[i], "-16bit"))
|
|
{
|
|
do16bit = true;
|
|
}
|
|
else if (!strcmp(argv[i], "-no16bit"))
|
|
{
|
|
do16bit = false;
|
|
}
|
|
else
|
|
{
|
|
printf("Unsupported command line flag: '%s'", argv[i]);
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
// SetQdirFromPath ();
|
|
ExtractFilePath(argv[i], spritedir); // chop the filename
|
|
|
|
//
|
|
// load the script
|
|
//
|
|
LoadScriptFile(argv[i]);
|
|
|
|
ParseScript();
|
|
FinishSprite();
|
|
|
|
return 0;
|
|
}
|