This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/ripper/conv_sprite.c

345 lines
9.4 KiB
C

//=======================================================================
// Copyright XashXT Group 2007 ©
// conv_sprite.c - convert q1\hl\spr32 sprites
//=======================================================================
#include "ripper.h"
#include "mathlib.h"
#include "pal_utils.h"
#include "qc_gen.h"
/*
========================================================================
.SPR sprite file format
========================================================================
*/
#define IDSPRQ1HEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I') // little-endian "IDSP"
#define SPRITEQ1_VERSION 1
#define SPRITEHL_VERSION 2
#define SPRITE32_VERSION 32
typedef struct
{
int ident;
int version;
int type;
int texFormat; // Half-Life stuff only
float boundingradius; // software rendering stuff
int width;
int height;
int numframes;
float beamlength; // software rendering stuff
synctype_t synctype;
} dspritehl_t;
typedef struct
{
int origin[2];
int width;
int height;
} dspriteframe_t;
//
// sprite_decompiler.c
//
void *SPR_ConvertFrame( const char *name, void *pin, int framenum, int groupframenum )
{
rgbdata_t pix;
dspriteframe_t *pinframe;
char framename[256];
byte *fin, *fout, *fpal;
int i, p, pixels, width, height;
pinframe = (dspriteframe_t *)pin;
width = LittleLong (pinframe->width);
height = LittleLong (pinframe->height);
fin = (byte *)(pinframe + 1);
if( width <= 0 || height <= 0 )
{
// Note: in Q1 exist sprites with blank frames
spr.totalframes--;
return (void *)((byte *)(pinframe + 1));
}
fout = Mem_Alloc( zonepool, width * height * 4 );
// extract sprite name from path
FS_FileBase( name, framename );
com.strcat( framename, va("_%i", framenum ));
memset( &pix, 0, sizeof(pix));
if( spr.truecolor )
{
pixels = width * height * 4;
Mem_Copy( fout, fin, pixels );
}
else
{
pixels = width * height;
fpal = (byte *)(&spr.palette[0][0]);
// expand image to 32-bit rgba buffer
for (i = 0; i < pixels; i++ )
{
p = fin[i];
fout[(i<<2)+0] = fpal[(p<<2)+0];
fout[(i<<2)+1] = fpal[(p<<2)+1];
fout[(i<<2)+2] = fpal[(p<<2)+2];
fout[(i<<2)+3] = fpal[(p<<2)+3];
}
}
if( groupframenum )
{
i = groupframenum - 1;
com.strncpy( spr.group[spr.numgroup].frame[i].name, framename, MAX_STRING );
spr.group[spr.numgroup].frame[i].origin[0] = -(float)LittleLong(pinframe->origin[0]);
spr.group[spr.numgroup].frame[i].origin[1] = (float)LittleLong(pinframe->origin[1]);
spr.group[spr.numgroup].frame[i].width = (float)LittleLong(pinframe->width);
spr.group[spr.numgroup].frame[i].height = (float)LittleLong(pinframe->height);
}
else
{
com.strncpy( spr.frame[framenum].name, framename, MAX_STRING );
spr.frame[framenum].origin[0] = -(float)LittleLong(pinframe->origin[0]);
spr.frame[framenum].origin[1] = (float)LittleLong(pinframe->origin[1]);
spr.frame[framenum].width = (float)LittleLong(pinframe->width);
spr.frame[framenum].height = (float)LittleLong(pinframe->height);
}
// preparing for write
pix.width = width;
pix.height = height;
pix.numLayers = 1;
pix.numMips = 1;
pix.type = PF_RGBA_32;
pix.buffer = fout;
pix.size = width * height * 4;
if( spr.texFormat >= SPR_INDEXALPHA )
pix.flags |= IMAGE_HAS_ALPHA;
FS_SaveImage( va("%s/sprites/%s.tga", gs_gamedir, framename ), &pix );
Mem_Free( fout ); // release buffer
// jump to next frame
return (void *)((byte *)(pinframe + 1) + pixels ); // no mipmap stored
}
void *SPR_ConvertGroup( const char *name, void *pin, int framenum )
{
dspritegroup_t *pingroup;
int i, numframes;
dspriteinterval_t *pin_intervals;
void *ptemp;
pingroup = (dspritegroup_t *)pin;
numframes = LittleLong( pingroup->numframes );
pin_intervals = (dspriteinterval_t *)(pingroup + 1);
for (i = 0; i < numframes; i++)
{
spr.group[spr.numgroup].interval[i] = LittleLong( pin_intervals->interval );
pin_intervals++;
}
// update global numframes
spr.group[spr.numgroup].numframes = numframes - 1;
ptemp = (void *)pin_intervals;
for (i = 0; i < numframes; i++ )
{
ptemp = SPR_ConvertFrame( name, ptemp, framenum + i, i + 1 );
}
spr.numgroup++;
return ptemp;
}
bool SPR_WriteScript( const char *name )
{
int i, j;
file_t *f = FS_Open( va("%s/sprites/%s.qc", gs_gamedir, name ), "w" );
if( !f )
{
Msg("Can't generate qc-script \"%s.qc\"\n", name );
return false;
}
// description
FS_Printf(f,"//=======================================================================\n");
FS_Printf(f,"//\t\t\tCopyright XashXT Group 2007 ©\n");
FS_Printf(f,"//\t\t\twritten by Xash Miptex Decompiler\n", name );
FS_Printf(f,"//=======================================================================\n");
// sprite header
FS_Printf(f, "\n$spritename\t%s.spr\n", name );
FS_Printf(f, "$type\t\t%s\n",SPR_RenderType());
FS_Printf(f, "$texture\t\t%s\n\n",SPR_RenderMode());
// frames description
for( i = 0; i < spr.totalframes - spr.numgroup; i++)
{
FS_Printf(f,"$load\t\t%s.tga\n", spr.frame[i].name );
FS_Printf(f,"$frame\t\t0 0 %d %d", spr.frame[i].width, spr.frame[i].height );
if(!spr.frame[i].origin[0] && !spr.frame[i].origin[1]) FS_Print(f, "\n" );
else FS_Printf(f, " %.1f %d %d\n", 0.1f, spr.frame[i].origin[0],spr.frame[i].origin[1]);
}
for( i = 0; i < spr.numgroup; i++ )
{
FS_Print(f, "$group\n{\n" );
for( j = 0; j < spr.group[i].numframes; j++)
{
FS_Printf(f,"\t$load\t\t%s.tga\n", spr.group[i].frame[j].name );
FS_Printf(f,"\t$frame\t\t0 0 %d %d", spr.group[i].frame[j].width, spr.group[i].frame[j].height );
if( spr.group[i].interval[j] ) FS_Printf(f, " %g", spr.group[i].interval[j] );
if(!spr.group[i].frame[j].origin[0] && !spr.group[i].frame[j].origin[1]) FS_Print(f, "\n" );
else FS_Printf(f, " %d %d\n", spr.group[i].frame[j].origin[0],spr.group[i].frame[j].origin[1]);
}
FS_Print(f, "}\n" );
}
FS_Print(f,"\n" );
FS_Close(f);
Msg("%s.spr\n", name ); // echo to console about current sprite
return true;
}
/*
============
ConvSPR
============
*/
bool ConvSPR( const char *name, char *buffer, int filesize )
{
int i, version;
dframetype_t *pframetype;
string scriptname;
dsprite_t *pin;
dspritehl_t *pinhl;
short *numi;
pin = (dsprite_t *)buffer;
version = LittleLong( pin->version );
memset( &spr, 0, sizeof(spr));
if( pin->ident != IDSPRQ1HEADER )
{
// ignore Xash sprites silently
if( pin->ident != IDSPRITEHEADER)
Msg("\"%s\" have invalid header\n", name );
return false;
}
switch( version )
{
case SPRITEQ1_VERSION:
spr.totalframes = LittleLong( pin->numframes );
spr.texFormat = SPR_INDEXALPHA; // constant
spr.type = LittleLong( pin->type );
// palette setup
Conv_GetPaletteQ1(); // setup palette
Mem_Copy( spr.palette, d_currentpal, 1024 );
pframetype = (dframetype_t *)(pin + 1);
spr.truecolor = false;
break;
case SPRITE32_VERSION:
spr.totalframes = LittleLong( pin->numframes );
spr.texFormat = SPR_ADDITIVE; // constant
spr.type = LittleLong( pin->type );
pframetype = (dframetype_t *)(pin + 1);
spr.truecolor = true;
break;
case SPRITEHL_VERSION:
pinhl = (dspritehl_t *)buffer; // reorganize header
spr.totalframes = LittleLong( pinhl->numframes );
spr.texFormat = LittleLong( pinhl->texFormat );
spr.type = LittleLong( pinhl->type );
numi = (short *)(pinhl + 1);
spr.truecolor = false;
if( LittleShort(*numi) == 256 )
{
byte *src = (byte *)(numi + 1);
switch( spr.texFormat )
{
case SPR_ADDGLOW:
case SPR_ADDITIVE:
for (i = 0; i < 256; i++)
{
spr.palette[i][0] = *src++;
spr.palette[i][1] = *src++;
spr.palette[i][2] = *src++;
spr.palette[i][3] = 255;
}
break;
case SPR_INDEXALPHA:
for (i = 0; i < 256; i++)
{
spr.palette[i][0] = *src++;
spr.palette[i][1] = *src++;
spr.palette[i][2] = *src++;
spr.palette[i][3] = i;
}
break;
case SPR_ALPHTEST:
for (i = 0; i < 256; i++)
{
spr.palette[i][0] = *src++;
spr.palette[i][1] = *src++;
spr.palette[i][2] = *src++;
spr.palette[i][3] = 255;
}
memset( spr.palette[255], 0, sizeof(uint)); // last entry
break;
default: Msg("Warning: %s.spr have unknown texFormat %i\n", name, spr.texFormat );
case SPR_NORMAL:
for (i = 0; i < 256; i++)
{
spr.palette[i][0] = *src++;
spr.palette[i][1] = *src++;
spr.palette[i][2] = *src++;
spr.palette[i][3] = 0;
}
break;
}
// get frametype for first frame
pframetype = (dframetype_t *)(src);
}
else
{
Msg("\"%s.spr\" have invalid palette size\n", name );
return false;
}
break;
default:
Msg("\"%s.spr\" unknown version\n", name );
return false;
}
// save frames as normal images
for (i = 0; i < spr.totalframes; i++ )
{
frametype_t frametype = LittleLong( pframetype->type );
if( frametype == SPR_SINGLE )
{
pframetype = (dframetype_t *)SPR_ConvertFrame( name, (pframetype + 1), i, 0 );
}
else if( frametype == SPR_GROUP )
{
pframetype = (dframetype_t *)SPR_ConvertGroup( name, (pframetype + 1), i );
}
if( pframetype == NULL ) break; // technically an error
}
// write script file and out
FS_FileBase( name, scriptname );
return SPR_WriteScript( scriptname );
}