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 + -
显示快捷键?