models.c
来自「quake3工具源码。包括生成bsp文件」· C语言 代码 · 共 2,185 行 · 第 1/4 页
C
2,185 行
#include <assert.h>
#include "q3data.h"
//=================================================================
static void OrderSurfaces( void );
static void LoadBase( const char *filename );
static int LoadModelFile( const char *filename, polyset_t **ppsets, int *pnumpolysets );
#define MAX_SURFACE_TRIS (SHADER_MAX_INDEXES / 3)
#define MAX_SURFACE_VERTS SHADER_MAX_VERTEXES
#define MD3_TYPE_UNKNOWN 0
#define MD3_TYPE_BASE3DS 1
#define MD3_TYPE_SPRITE 2
#define MD3_TYPE_ASE 3
#define MAX_ANIM_FRAMES 512
#define MAX_ANIM_SURFACES 32
typedef struct
{
polyset_t *frames;
int numFrames;
} SurfaceAnimation_t;
typedef struct
{
polyset_t *surfaces[MAX_ANIM_SURFACES];
int numSurfaces;
} ObjectAnimationFrame_t;
typedef struct {
vec3_t xyz;
vec3_t normal;
vec3_t color;
float st[2];
int index;
} baseVertex_t;
typedef struct {
baseVertex_t v[3];
} baseTriangle_t;
//================================================================
typedef struct
{
md3Surface_t header;
md3Shader_t shaders[MD3_MAX_SHADERS];
// all verts (xyz_normal)
float *verts[MD3_MAX_FRAMES];
baseTriangle_t baseTriangles[MD3_MAX_TRIANGLES];
// the triangles will be sorted so that they form long generalized tristrips
int orderedTriangles[MD3_MAX_TRIANGLES][3];
int lodTriangles[MD3_MAX_TRIANGLES][3];
baseVertex_t baseVertexes[MD3_MAX_VERTS];
} md3SurfaceData_t;
typedef struct
{
int skinwidth, skinheight;
md3SurfaceData_t surfData[MD3_MAX_SURFACES];
md3Tag_t tags[MD3_MAX_FRAMES][MD3_MAX_TAGS];
md3Frame_t frames[MD3_MAX_FRAMES];
md3Header_t model;
float scale_up; // set by $scale
vec3_t adjust; // set by $origin
vec3_t aseAdjust;
int fixedwidth, fixedheight; // set by $skinsize
int maxSurfaceTris;
int lowerSkipFrameStart, lowerSkipFrameEnd;
int maxUpperFrames;
int maxHeadFrames;
int currentLod;
float lodBias;
int type; // MD3_TYPE_BASE, MD3_TYPE_OLDBASE, MD3_TYPE_ASE, or MD3_TYPE_SPRITE
} q3data;
q3data g_data;
// the command list holds counts, the count * 3 xyz, st, normal indexes
// that are valid for every frame
char g_cddir[1024];
char g_modelname[1024];
//==============================================================
/*
===============
ClearModel
===============
*/
void ClearModel (void)
{
int i;
g_data.type = MD3_TYPE_UNKNOWN;
for ( i = 0; i < MD3_MAX_SURFACES; i++ )
{
memset( &g_data.surfData[i].header, 0, sizeof( g_data.surfData[i].header ) );
memset( &g_data.surfData[i].shaders, 0, sizeof( g_data.surfData[i].shaders ) );
memset( &g_data.surfData[i].verts, 0, sizeof( g_data.surfData[i].verts ) );
}
memset( g_data.tags, 0, sizeof( g_data.tags ) );
for ( i = 0; i < g_data.model.numSurfaces; i++ )
{
int j;
for ( j = 0; j < g_data.surfData[i].header.numShaders; j++ )
{
memset( &g_data.surfData[i].shaders[j], 0, sizeof( g_data.surfData[i].shaders[j] ) );
}
}
memset (&g_data.model, 0, sizeof(g_data.model));
memset (g_cddir, 0, sizeof(g_cddir));
g_modelname[0] = 0;
g_data.scale_up = 1.0;
memset( &g_data.model, 0, sizeof( g_data.model ) );
VectorCopy (vec3_origin, g_data.adjust);
g_data.fixedwidth = g_data.fixedheight = 0;
g_skipmodel = qfalse;
}
/*
** void WriteModelSurface( FILE *modelouthandle, md3SurfaceData_t *pSurfData )
**
** This routine assumes that the file position has been adjusted
** properly prior to entry to point at the beginning of the surface.
**
** Since surface header information is completely relative, we can't
** just randomly seek to an arbitrary surface location right now. Is
** this something we should add?
*/
void WriteModelSurface( FILE *modelouthandle, md3SurfaceData_t *pSurfData )
{
md3Surface_t *pSurf = &pSurfData->header;
md3Shader_t *pShader = pSurfData->shaders;
baseVertex_t *pBaseVertex = pSurfData->baseVertexes;
float **verts = pSurfData->verts;
short xyznormals[MD3_MAX_VERTS][4];
float base_st[MD3_MAX_VERTS][2];
md3Surface_t surftemp;
int f, i, j, k;
if ( strstr( pSurf->name, "tag_" ) == pSurf->name )
return;
//
// write out the header
//
surftemp = *pSurf;
surftemp.ident = LittleLong( MD3_IDENT );
surftemp.flags = LittleLong( pSurf->flags );
surftemp.numFrames = LittleLong( pSurf->numFrames );
surftemp.numShaders = LittleLong( pSurf->numShaders );
surftemp.ofsShaders = LittleLong( pSurf->ofsShaders );
surftemp.ofsTriangles = LittleLong( pSurf->ofsTriangles );
surftemp.numTriangles = LittleLong( pSurf->numTriangles );
surftemp.ofsSt = LittleLong( pSurf->ofsSt );
surftemp.ofsXyzNormals = LittleLong( pSurf->ofsXyzNormals );
surftemp.ofsEnd = LittleLong( pSurf->ofsEnd );
SafeWrite( modelouthandle, &surftemp, sizeof( surftemp ) );
if ( g_verbose )
{
printf( "surface '%s'\n", pSurf->name );
printf( "...num shaders: %d\n", pSurf->numShaders );
}
//
// write out shaders
//
for ( i = 0; i < pSurf->numShaders; i++ )
{
md3Shader_t shadertemp;
if ( g_verbose )
printf( "......'%s'\n", pShader[i].name );
shadertemp = pShader[i];
shadertemp.shaderIndex = LittleLong( shadertemp.shaderIndex );
SafeWrite( modelouthandle, &shadertemp, sizeof( shadertemp ) );
}
//
// write out the triangles
//
for ( i = 0 ; i < pSurf->numTriangles ; i++ )
{
for (j = 0 ; j < 3 ; j++)
{
int ivalue = LittleLong( pSurfData->orderedTriangles[i][j] );
pSurfData->orderedTriangles[i][j] = ivalue;
}
}
SafeWrite( modelouthandle, pSurfData->orderedTriangles, pSurf->numTriangles * sizeof( g_data.surfData[0].orderedTriangles[0] ) );
if ( g_verbose )
{
printf( "\n...num verts: %d\n", pSurf->numVerts );
printf( "...TEX COORDINATES\n" );
}
//
// write out the texture coordinates
//
for ( i = 0; i < pSurf->numVerts ; i++) {
base_st[i][0] = LittleFloat( pBaseVertex[i].st[0] );
base_st[i][1] = LittleFloat( pBaseVertex[i].st[1] );
if ( g_verbose )
printf( "......%d: %f,%f\n", i, base_st[i][0], base_st[i][1] );
}
SafeWrite( modelouthandle, base_st, pSurf->numVerts * sizeof(base_st[0]));
//
// write the xyz_normal
//
if ( g_verbose )
printf( "...XYZNORMALS\n" );
for ( f = 0; f < g_data.model.numFrames; f++ )
{
for (j=0 ; j< pSurf->numVerts; j++)
{
short value;
for (k=0 ; k < 3 ; k++)
{
value = ( short ) ( verts[f][j*6+k] / MD3_XYZ_SCALE );
xyznormals[j][k] = LittleShort( value );
}
NormalToLatLong( &verts[f][j*6+3], (byte *)&xyznormals[j][3] );
}
SafeWrite( modelouthandle, xyznormals, pSurf->numVerts * sizeof( short ) * 4 );
}
}
/*
** void WriteModelFile( FILE *modelouthandle )
**
** CHUNK SIZE
** header sizeof( md3Header_t )
** frames sizeof( md3Frame_t ) * numFrames
** tags sizeof( md3Tag_t ) * numFrames * numTags
** surfaces surfaceSum
*/
void WriteModelFile( FILE *modelouthandle )
{
int f;
int i, j;
md3Header_t modeltemp;
long surfaceSum = 0;
int numRealSurfaces = 0;
int numFrames = g_data.model.numFrames;
// compute offsets for all surfaces, sum their total size
for ( i = 0; i < g_data.model.numSurfaces; i++ )
{
if ( strstr( g_data.surfData[i].header.name, "tag_" ) != g_data.surfData[i].header.name )
{
md3Surface_t *psurf = &g_data.surfData[i].header;
if ( psurf->numTriangles == 0 || psurf->numVerts == 0 )
continue;
//
// the triangle and vertex split threshold is controlled by a parameter
// to $base, a la $base blah.3ds 1900, where "1900" determines the number
// of triangles to split on
//
else if ( psurf->numVerts > MAX_SURFACE_VERTS )
{
Error( "too many vertices\n" );
}
psurf->numFrames = numFrames;
psurf->ofsShaders = sizeof( md3Surface_t );
if ( psurf->numTriangles > MAX_SURFACE_TRIS )
{
Error( "too many faces\n" );
}
psurf->ofsTriangles = psurf->ofsShaders + psurf->numShaders * sizeof( md3Shader_t );
psurf->ofsSt = psurf->ofsTriangles + psurf->numTriangles * sizeof( md3Triangle_t );
psurf->ofsXyzNormals = psurf->ofsSt + psurf->numVerts * sizeof( md3St_t );
psurf->ofsEnd = psurf->ofsXyzNormals + psurf->numFrames * psurf->numVerts * ( sizeof( short ) * 4 );
surfaceSum += psurf->ofsEnd;
numRealSurfaces++;
}
}
g_data.model.ident = MD3_IDENT;
g_data.model.version = MD3_VERSION;
g_data.model.ofsFrames = sizeof(md3Header_t);
g_data.model.ofsTags = g_data.model.ofsFrames + numFrames*sizeof(md3Frame_t);
g_data.model.ofsSurfaces = g_data.model.ofsTags + numFrames*g_data.model.numTags*sizeof(md3Tag_t);
g_data.model.ofsEnd = g_data.model.ofsSurfaces + surfaceSum;
//
// write out the model header
//
modeltemp = g_data.model;
modeltemp.ident = LittleLong( modeltemp.ident );
modeltemp.version = LittleLong( modeltemp.version );
modeltemp.numFrames = LittleLong( modeltemp.numFrames );
modeltemp.numTags = LittleLong( modeltemp.numTags );
modeltemp.numSurfaces = LittleLong( numRealSurfaces );
modeltemp.ofsFrames = LittleLong( modeltemp.ofsFrames );
modeltemp.ofsTags = LittleLong( modeltemp.ofsTags );
modeltemp.ofsSurfaces = LittleLong( modeltemp.ofsSurfaces );
modeltemp.ofsEnd = LittleLong( modeltemp.ofsEnd );
SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp));
//
// write out the frames
//
for (i=0 ; i < numFrames ; i++)
{
vec3_t tmpVec;
float maxRadius = 0;
//
// compute localOrigin and radius
//
g_data.frames[i].localOrigin[0] =
g_data.frames[i].localOrigin[1] =
g_data.frames[i].localOrigin[2] = 0;
for ( j = 0; j < 8; j++ )
{
tmpVec[0] = g_data.frames[i].bounds[(j&1)!=0][0];
tmpVec[1] = g_data.frames[i].bounds[(j&2)!=0][1];
tmpVec[2] = g_data.frames[i].bounds[(j&4)!=0][2];
if ( VectorLength( tmpVec ) > maxRadius )
maxRadius = VectorLength( tmpVec );
}
g_data.frames[i].radius = LittleFloat( maxRadius );
// swap
for (j=0 ; j<3 ; j++) {
g_data.frames[i].bounds[0][j] = LittleFloat( g_data.frames[i].bounds[0][j] );
g_data.frames[i].bounds[1][j] = LittleFloat( g_data.frames[i].bounds[1][j] );
g_data.frames[i].localOrigin[j] = LittleFloat( g_data.frames[i].localOrigin[j] );
}
}
fseek (modelouthandle, g_data.model.ofsFrames, SEEK_SET);
SafeWrite( modelouthandle, g_data.frames, numFrames * sizeof(g_data.frames[0]) );
//
// write out the tags
//
fseek( modelouthandle, g_data.model.ofsTags, SEEK_SET );
for (f=0 ; f<g_data.model.numFrames; f++)
{
int t;
for ( t = 0; t < g_data.model.numTags; t++ )
{
g_data.tags[f][t].origin[0] = LittleFloat(g_data.tags[f][t].origin[0]);
g_data.tags[f][t].origin[1] = LittleFloat(g_data.tags[f][t].origin[1]);
g_data.tags[f][t].origin[2] = LittleFloat(g_data.tags[f][t].origin[2]);
for (j=0 ; j<3 ; j++)
{
g_data.tags[f][t].axis[0][j] = LittleFloat(g_data.tags[f][t].axis[0][j]);
g_data.tags[f][t].axis[1][j] = LittleFloat(g_data.tags[f][t].axis[1][j]);
g_data.tags[f][t].axis[2][j] = LittleFloat(g_data.tags[f][t].axis[2][j]);
}
}
SafeWrite( modelouthandle, g_data.tags[f], g_data.model.numTags * sizeof(md3Tag_t) );
}
//
// write out the surfaces
//
fseek( modelouthandle, g_data.model.ofsSurfaces, SEEK_SET );
for ( i = 0; i < g_data.model.numSurfaces; i++ )
{
WriteModelSurface( modelouthandle, &g_data.surfData[i] );
}
}
/*
===============
FinishModel
===============
*/
void FinishModel ( int type )
{
FILE *modelouthandle;
FILE *defaultSkinHandle;
char name[1024];
int i;
if (!g_data.model.numFrames)
return;
//
// build generalized triangle strips
//
OrderSurfaces();
if ( type == TYPE_PLAYER )
{
// write a default skin file with the contents of the
// surface textures, then clean the surface textures
// so we don't force those textures to be loaded if
// an alternate skin was loaded instead
sprintf( name, "%s%s", writedir, g_modelname );
*strrchr( name, '.' ) = 0;
strcat( name, "_default.skin" );
defaultSkinHandle = fopen( name, "wt" );
for ( i = 0; i < g_data.model.numSurfaces; i++ )
{
fprintf( defaultSkinHandle, "%s,%s\n", g_data.surfData[i].header.name, g_data.surfData[i].shaders[0].name );
g_data.surfData[i].shaders[0].name[0] = 0;
}
fclose( defaultSkinHandle );
}
sprintf (name, "%s%s", writedir, g_modelname);
//
// copy the model and its shaders to release directory tree
// if doing a release build
//
if ( g_release ) {
int i, j;
md3SurfaceData_t *pSurf;
ReleaseFile( g_modelname );
for ( i = 0; i < g_data.model.numSurfaces; i++ ) {
pSurf = &g_data.surfData[i];
for ( j = 0; j < g_data.model.numSkins; j++ ) {
ReleaseShader( pSurf->shaders[j].name );
}
}
return;
}
//
// write the model output file
//
printf ("saving to %s\n", name);
CreatePath (name);
modelouthandle = SafeOpenWrite (name);
WriteModelFile (modelouthandle);
printf ("%4d surfaces\n", g_data.model.numSurfaces);
printf ("%4d frames\n", g_data.model.numFrames);
printf ("%4d tags\n", g_data.model.numTags);
printf ("file size: %d\n", (int)ftell (modelouthandle) );
printf ("---------------------\n");
fclose (modelouthandle);
}
/*
** OrderSurfaces
**
** Reorders triangles in all the surfaces.
*/
static void OrderSurfaces( void )
{
int s;
extern qboolean g_stripify;
// go through each surface and find best strip/fans possible
for ( s = 0; s < g_data.model.numSurfaces; s++ )
{
int mesh[MD3_MAX_TRIANGLES][3];
int i;
printf( "stripifying surface %d/%d with %d tris\n", s, g_data.model.numSurfaces, g_data.surfData[s].header.numTriangles );
for ( i = 0; i < g_data.surfData[s].header.numTriangles; i++ )
{
mesh[i][0] = g_data.surfData[s].lodTriangles[i][0];
mesh[i][1] = g_data.surfData[s].lodTriangles[i][1];
mesh[i][2] = g_data.surfData[s].lodTriangles[i][2];
}
if ( g_stripify )
{
OrderMesh( mesh, // input
g_data.surfData[s].orderedTriangles, // output
g_data.surfData[s].header.numTriangles );
}
else
{
memcpy( g_data.surfData[s].orderedTriangles, mesh, sizeof( int ) * 3 * g_data.surfData[s].header.numTriangles );
}
}
}
/*
===============================================================
BASE FRAME SETUP
===============================================================
*/
/*
============
CopyTrianglesToBaseTriangles
============
*/
static void CopyTrianglesToBaseTriangles(triangle_t *ptri, int numtri, baseTriangle_t *bTri )
{
int i;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?