Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

aselib.c (20423B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 
     23 #include "aselib.h"
     24 
     25 #include <assert.h>
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 
     29 #define MAX_ASE_MATERIALS			32
     30 #define MAX_ASE_OBJECTS				64
     31 #define MAX_ASE_ANIMATIONS			32
     32 #define MAX_ASE_ANIMATION_FRAMES	512
     33 
     34 #define VERBOSE( x ) { if ( ase.verbose ) { printf x ; } }
     35 
     36 typedef struct
     37 {
     38 	float x, y, z;
     39 	float nx, ny, nz;
     40 	float s, t;
     41 } aseVertex_t;
     42 
     43 typedef struct
     44 {
     45 	float s, t;
     46 } aseTVertex_t;
     47 
     48 typedef int aseFace_t[3];
     49 
     50 typedef struct
     51 {
     52 	int numFaces;
     53 	int numVertexes;
     54 	int numTVertexes;
     55 
     56 	int timeValue;
     57 
     58 	aseVertex_t		*vertexes;
     59 	aseTVertex_t	*tvertexes;
     60 	aseFace_t		*faces, *tfaces;
     61 
     62 	int currentFace, currentVertex;
     63 } aseMesh_t;
     64 
     65 typedef struct
     66 {
     67 	int			numFrames;
     68 	aseMesh_t	frames[MAX_ASE_ANIMATION_FRAMES];
     69 
     70 	int		   currentFrame;
     71 } aseMeshAnimation_t;
     72 
     73 typedef struct
     74 {
     75 	char name[128];
     76 } aseMaterial_t;
     77 
     78 /*
     79 ** contains the animate sequence of a single surface
     80 ** using a single material
     81 */
     82 typedef struct
     83 {
     84 	char name[128];
     85 
     86 	int materialRef;
     87 	int numAnimations;
     88 
     89 	aseMeshAnimation_t	anim;
     90 
     91 } aseGeomObject_t;
     92 
     93 typedef struct
     94 {
     95 	int				numMaterials;
     96 	aseMaterial_t	materials[MAX_ASE_MATERIALS];
     97 	aseGeomObject_t objects[MAX_ASE_OBJECTS];
     98 
     99 	char	*buffer;
    100 	char	*curpos;
    101 	int		 len;
    102 
    103 	int			currentObject;
    104 	qboolean	verbose;
    105 	qboolean	grabAnims;
    106 
    107 } ase_t;
    108 
    109 static char s_token[1024];
    110 static ase_t ase;
    111 
    112 static void ASE_Process( void );
    113 static void ASE_FreeGeomObject( int ndx );
    114 
    115 /*
    116 ** ASE_Load
    117 */
    118 void ASE_Load( const char *filename, qboolean verbose, qboolean grabAnims )
    119 {
    120 	FILE *fp = fopen( filename, "rb" );
    121 
    122 	if ( !fp )
    123 		Error( "File not found '%s'", filename );
    124 
    125 	memset( &ase, 0, sizeof( ase ) );
    126 
    127 	ase.verbose = verbose;
    128 	ase.grabAnims = grabAnims;
    129 	ase.len = Q_filelength( fp );
    130 
    131 	ase.curpos = ase.buffer = malloc( ase.len );
    132 
    133 	printf( "Processing '%s'\n", filename );
    134 
    135 	if ( fread( ase.buffer, ase.len, 1, fp ) != 1 )
    136 	{
    137 		fclose( fp );
    138 		Error( "fread() != -1 for '%s'", filename );
    139 	}
    140 
    141 	fclose( fp );
    142 
    143 	ASE_Process();
    144 }
    145 
    146 /*
    147 ** ASE_Free
    148 */
    149 void ASE_Free( void )
    150 {
    151 	int i;
    152 
    153 	for ( i = 0; i < ase.currentObject; i++ )
    154 	{
    155 		ASE_FreeGeomObject( i );
    156 	}
    157 }
    158 
    159 /*
    160 ** ASE_GetNumSurfaces
    161 */
    162 int ASE_GetNumSurfaces( void )
    163 {
    164 	return ase.currentObject;
    165 }
    166 
    167 /*
    168 ** ASE_GetSurfaceName
    169 */
    170 const char *ASE_GetSurfaceName( int which )
    171 {
    172 	aseGeomObject_t *pObject = &ase.objects[which];
    173 
    174 	if ( !pObject->anim.numFrames )
    175 		return 0;
    176 
    177 	return pObject->name;
    178 }
    179 
    180 /*
    181 ** ASE_GetSurfaceAnimation
    182 **
    183 ** Returns an animation (sequence of polysets)
    184 */
    185 polyset_t *ASE_GetSurfaceAnimation( int which, int *pNumFrames, int skipFrameStart, int skipFrameEnd, int maxFrames )
    186 {
    187 	aseGeomObject_t *pObject = &ase.objects[which];
    188 	polyset_t *psets;
    189 	int numFramesInAnimation;
    190 	int numFramesToKeep;
    191 	int i, f;
    192 
    193 	if ( !pObject->anim.numFrames )
    194 		return 0;
    195 
    196 	if ( pObject->anim.numFrames > maxFrames && maxFrames != -1 )
    197 	{
    198 		numFramesInAnimation = maxFrames;
    199 	}
    200 	else 
    201 	{
    202 		numFramesInAnimation = pObject->anim.numFrames;
    203 		if ( maxFrames != -1 )
    204 			printf( "WARNING: ASE_GetSurfaceAnimation maxFrames > numFramesInAnimation\n" );
    205 	}
    206 
    207 	if ( skipFrameEnd != -1 )
    208 		numFramesToKeep = numFramesInAnimation - ( skipFrameEnd - skipFrameStart + 1 );
    209 	else
    210 		numFramesToKeep = numFramesInAnimation;
    211 
    212 	*pNumFrames = numFramesToKeep;
    213 
    214 	psets = calloc( sizeof( polyset_t ) * numFramesToKeep, 1 );
    215 
    216 	for ( f = 0, i = 0; i < numFramesInAnimation; i++ )
    217 	{
    218 		int t;
    219 		aseMesh_t *pMesh = &pObject->anim.frames[i];
    220 
    221 		if ( skipFrameStart != -1 )
    222 		{
    223 			if ( i >= skipFrameStart && i <= skipFrameEnd )
    224 				continue;
    225 		}
    226 
    227 		strcpy( psets[f].name, pObject->name );
    228 		strcpy( psets[f].materialname, ase.materials[pObject->materialRef].name );
    229 
    230 		psets[f].triangles = calloc( sizeof( triangle_t ) * pObject->anim.frames[i].numFaces, 1 );
    231 		psets[f].numtriangles = pObject->anim.frames[i].numFaces;
    232 
    233 		for ( t = 0; t < pObject->anim.frames[i].numFaces; t++ )
    234 		{
    235 			int k;
    236 
    237 			for ( k = 0; k < 3; k++ )
    238 			{
    239 				psets[f].triangles[t].verts[k][0] = pMesh->vertexes[pMesh->faces[t][k]].x;
    240 				psets[f].triangles[t].verts[k][1] = pMesh->vertexes[pMesh->faces[t][k]].y;
    241 				psets[f].triangles[t].verts[k][2] = pMesh->vertexes[pMesh->faces[t][k]].z;
    242 
    243 				if ( pMesh->tvertexes && pMesh->tfaces )
    244 				{
    245 					psets[f].triangles[t].texcoords[k][0] = pMesh->tvertexes[pMesh->tfaces[t][k]].s;
    246 					psets[f].triangles[t].texcoords[k][1] = pMesh->tvertexes[pMesh->tfaces[t][k]].t;
    247 				}
    248 
    249 			}
    250 		}
    251 
    252 		f++;
    253 	}
    254 
    255 	return psets;
    256 }
    257 
    258 static void ASE_FreeGeomObject( int ndx )
    259 {
    260 	aseGeomObject_t *pObject;
    261 	int i;
    262 
    263 	pObject = &ase.objects[ndx];
    264 
    265 	for ( i = 0; i < pObject->anim.numFrames; i++ )
    266 	{
    267 		if ( pObject->anim.frames[i].vertexes )
    268 		{
    269 			free( pObject->anim.frames[i].vertexes );
    270 		}
    271 		if ( pObject->anim.frames[i].tvertexes )
    272 		{
    273 			free( pObject->anim.frames[i].tvertexes );
    274 		}
    275 		if ( pObject->anim.frames[i].faces )
    276 		{
    277 			free( pObject->anim.frames[i].faces );
    278 		}
    279 		if ( pObject->anim.frames[i].tfaces )
    280 		{
    281 			free( pObject->anim.frames[i].tfaces );
    282 		}
    283 	}
    284 
    285 	memset( pObject, 0, sizeof( *pObject ) );
    286 }
    287 
    288 static aseMesh_t *ASE_GetCurrentMesh( void )
    289 {
    290 	aseGeomObject_t *pObject;
    291 
    292 	if ( ase.currentObject >= MAX_ASE_OBJECTS )
    293 	{
    294 		Error( "Too many GEOMOBJECTs" );
    295 		return 0; // never called
    296 	}
    297 
    298 	pObject = &ase.objects[ase.currentObject];
    299 
    300 	if ( pObject->anim.currentFrame >= MAX_ASE_ANIMATION_FRAMES )
    301 	{
    302 		Error( "Too many MESHes" );
    303 		return 0;
    304 	}
    305 
    306 	return &pObject->anim.frames[pObject->anim.currentFrame];
    307 }
    308 
    309 static int CharIsTokenDelimiter( int ch )
    310 {
    311 	if ( ch <= 32 )
    312 		return 1;
    313 	return 0;
    314 }
    315 
    316 static int ASE_GetToken( qboolean restOfLine )
    317 {
    318 	int i = 0;
    319 
    320 	if ( ase.buffer == 0 )
    321 		return 0;
    322 
    323 	if ( ( ase.curpos - ase.buffer ) == ase.len )
    324 		return 0;
    325 
    326 	// skip over crap
    327 	while ( ( ( ase.curpos - ase.buffer ) < ase.len ) &&
    328 		    ( *ase.curpos <= 32 ) )
    329 	{
    330 		ase.curpos++;
    331 	}
    332 
    333 	while ( ( ase.curpos - ase.buffer ) < ase.len )
    334 	{
    335 		s_token[i] = *ase.curpos;
    336 
    337 		ase.curpos++;
    338 		i++;
    339 
    340 		if ( ( CharIsTokenDelimiter( s_token[i-1] ) && !restOfLine ) ||
    341 			 ( ( s_token[i-1] == '\n' ) || ( s_token[i-1] == '\r' ) ) )
    342 		{
    343 			s_token[i-1] = 0;
    344 			break;
    345 		}
    346 	}
    347 
    348 	s_token[i] = 0;
    349 
    350 	return 1;
    351 }
    352 
    353 static void ASE_ParseBracedBlock( void (*parser)( const char *token ) )
    354 {
    355 	int indent = 0;
    356 
    357 	while ( ASE_GetToken( qfalse ) )
    358 	{
    359 		if ( !strcmp( s_token, "{" ) )
    360 		{
    361 			indent++;
    362 		}
    363 		else if ( !strcmp( s_token, "}" ) )
    364 		{
    365 			--indent;
    366 			if ( indent == 0 )
    367 				break;
    368 			else if ( indent < 0 )
    369 				Error( "Unexpected '}'" );
    370 		}
    371 		else
    372 		{
    373 			if ( parser )
    374 				parser( s_token );
    375 		}
    376 	}
    377 }
    378 
    379 static void ASE_SkipEnclosingBraces( void )
    380 {
    381 	int indent = 0;
    382 
    383 	while ( ASE_GetToken( qfalse ) )
    384 	{
    385 		if ( !strcmp( s_token, "{" ) )
    386 		{
    387 			indent++;
    388 		}
    389 		else if ( !strcmp( s_token, "}" ) )
    390 		{
    391 			indent--;
    392 			if ( indent == 0 )
    393 				break;
    394 			else if ( indent < 0 )
    395 				Error( "Unexpected '}'" );
    396 		}
    397 	}
    398 }
    399 
    400 static void ASE_SkipRestOfLine( void )
    401 {
    402 	ASE_GetToken( qtrue );
    403 }
    404 
    405 static void ASE_KeyMAP_DIFFUSE( const char *token )
    406 {
    407 	char buffer[1024], buff1[1024], buff2[1024];
    408   char *buf1, *buf2;
    409 	int i = 0, count;
    410 
    411 	if ( !strcmp( token, "*BITMAP" ) )
    412 	{
    413 		ASE_GetToken( qfalse );
    414 
    415 		strcpy( buffer, s_token + 1 );
    416 		if ( strchr( buffer, '"' ) )
    417 			*strchr( buffer, '"' ) = 0;
    418 
    419 		while ( buffer[i] )
    420 		{
    421 			if ( buffer[i] == '\\' )
    422 				buffer[i] = '/';
    423 			i++;
    424 		}
    425 
    426     buf1 = buffer;
    427     buf2 = gamedir;
    428     // need to compare win32 volumes to potential unix junk
    429     // 
    430     if ( (gamedir[1] == ':' && (buffer[0] == '/' && buffer[1] == '/')) ||
    431       (buffer[1] == ':' && (gamedir[0] == '/' && gamedir[1] == '/')) ) {
    432       if (buffer[1] == ':') {
    433         buf1 = buffer + 2;
    434         buf2 = gamedir + 2;
    435       } else {
    436         buf1 = gamedir + 2;
    437         buf2 = buffer +2;
    438       }
    439       count = 0;
    440       while (*buf2 && count < 2) {
    441         if (*buf2 == '/') {
    442           count++;
    443         }
    444         buf2++;
    445       }
    446     } 
    447     strcpy(buff1, buf1);
    448     strlwr(buff1);
    449     strcpy(buff2, buf2);
    450     strlwr(buff2);
    451     if ( strstr( buff2, buff1 + 2 ) )
    452 		{
    453 			strcpy( ase.materials[ase.numMaterials].name, strstr( buff2, buff1 + 2 ) + strlen( buff1 ) - 2 );
    454 		}
    455 		else
    456 		{
    457 			sprintf( ase.materials[ase.numMaterials].name, "(not converted: '%s')", buffer );
    458 			printf( "WARNING: illegal material name '%s'\n", buffer );
    459 		}
    460 	}
    461 	else
    462 	{
    463 	}
    464 }
    465 
    466 static void ASE_KeyMATERIAL( const char *token )
    467 {
    468 	if ( !strcmp( token, "*MAP_DIFFUSE" ) )
    469 	{
    470 		ASE_ParseBracedBlock( ASE_KeyMAP_DIFFUSE );
    471 	}
    472 	else
    473 	{
    474 	}
    475 }
    476 
    477 static void ASE_KeyMATERIAL_LIST( const char *token )
    478 {
    479 	if ( !strcmp( token, "*MATERIAL_COUNT" ) )
    480 	{
    481 		ASE_GetToken( qfalse );
    482 		VERBOSE( ( "..num materials: %s\n", s_token ) );
    483 		if ( atoi( s_token ) > MAX_ASE_MATERIALS )
    484 		{
    485 			Error( "Too many materials!" );
    486 		}
    487 		ase.numMaterials = 0;
    488 	}
    489 	else if ( !strcmp( token, "*MATERIAL" ) )
    490 	{
    491 		VERBOSE( ( "..material %d ", ase.numMaterials ) );
    492 		ASE_ParseBracedBlock( ASE_KeyMATERIAL );
    493 		ase.numMaterials++;
    494 	}
    495 }
    496 
    497 static void ASE_KeyMESH_VERTEX_LIST( const char *token )
    498 {
    499 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
    500 
    501 	if ( !strcmp( token, "*MESH_VERTEX" ) )
    502 	{
    503 		ASE_GetToken( qfalse );		// skip number
    504 
    505 		ASE_GetToken( qfalse );
    506 		pMesh->vertexes[pMesh->currentVertex].y = atof( s_token );
    507 
    508 		ASE_GetToken( qfalse );
    509 		pMesh->vertexes[pMesh->currentVertex].x = -atof( s_token );
    510 
    511 		ASE_GetToken( qfalse );
    512 		pMesh->vertexes[pMesh->currentVertex].z = atof( s_token );
    513 
    514 		pMesh->currentVertex++;
    515 
    516 		if ( pMesh->currentVertex > pMesh->numVertexes )
    517 		{
    518 			Error( "pMesh->currentVertex >= pMesh->numVertexes" );
    519 		}
    520 	}
    521 	else
    522 	{
    523 		Error( "Unknown token '%s' while parsing MESH_VERTEX_LIST", token );
    524 	}
    525 }
    526 
    527 static void ASE_KeyMESH_FACE_LIST( const char *token )
    528 {
    529 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
    530 
    531 	if ( !strcmp( token, "*MESH_FACE" ) )
    532 	{
    533 		ASE_GetToken( qfalse );	// skip face number
    534 
    535 		ASE_GetToken( qfalse );	// skip label
    536 		ASE_GetToken( qfalse );	// first vertex
    537 		pMesh->faces[pMesh->currentFace][0] = atoi( s_token );
    538 
    539 		ASE_GetToken( qfalse );	// skip label
    540 		ASE_GetToken( qfalse );	// second vertex
    541 		pMesh->faces[pMesh->currentFace][2] = atoi( s_token );
    542 
    543 		ASE_GetToken( qfalse );	// skip label
    544 		ASE_GetToken( qfalse );	// third vertex
    545 		pMesh->faces[pMesh->currentFace][1] = atoi( s_token );
    546 
    547 		ASE_GetToken( qtrue );
    548 
    549 /*
    550 		if ( ( p = strstr( s_token, "*MESH_MTLID" ) ) != 0 )
    551 		{
    552 			p += strlen( "*MESH_MTLID" ) + 1;
    553 			mtlID = atoi( p );
    554 		}
    555 		else
    556 		{
    557 			Error( "No *MESH_MTLID found for face!" );
    558 		}
    559 */
    560 
    561 		pMesh->currentFace++;
    562 	}
    563 	else
    564 	{
    565 		Error( "Unknown token '%s' while parsing MESH_FACE_LIST", token );
    566 	}
    567 }
    568 
    569 static void ASE_KeyTFACE_LIST( const char *token )
    570 {
    571 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
    572 
    573 	if ( !strcmp( token, "*MESH_TFACE" ) )
    574 	{
    575 		int a, b, c;
    576 
    577 		ASE_GetToken( qfalse );
    578 
    579 		ASE_GetToken( qfalse );
    580 		a = atoi( s_token );
    581 		ASE_GetToken( qfalse );
    582 		c = atoi( s_token );
    583 		ASE_GetToken( qfalse );
    584 		b = atoi( s_token );
    585 
    586 		pMesh->tfaces[pMesh->currentFace][0] = a;
    587 		pMesh->tfaces[pMesh->currentFace][1] = b;
    588 		pMesh->tfaces[pMesh->currentFace][2] = c;
    589 
    590 		pMesh->currentFace++;
    591 	}
    592 	else
    593 	{
    594 		Error( "Unknown token '%s' in MESH_TFACE", token );
    595 	}
    596 }
    597 
    598 static void ASE_KeyMESH_TVERTLIST( const char *token )
    599 {
    600 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
    601 
    602 	if ( !strcmp( token, "*MESH_TVERT" ) )
    603 	{
    604 		char u[80], v[80], w[80];
    605 
    606 		ASE_GetToken( qfalse );
    607 
    608 		ASE_GetToken( qfalse );
    609 		strcpy( u, s_token );
    610 
    611 		ASE_GetToken( qfalse );
    612 		strcpy( v, s_token );
    613 
    614 		ASE_GetToken( qfalse );
    615 		strcpy( w, s_token );
    616 
    617 		pMesh->tvertexes[pMesh->currentVertex].s = atof( u );
    618 		pMesh->tvertexes[pMesh->currentVertex].t = 1.0f - atof( v );
    619 
    620 		pMesh->currentVertex++;
    621 
    622 		if ( pMesh->currentVertex > pMesh->numTVertexes )
    623 		{
    624 			Error( "pMesh->currentVertex > pMesh->numTVertexes" );
    625 		}
    626 	}
    627 	else
    628 	{
    629 		Error( "Unknown token '%s' while parsing MESH_TVERTLIST" );
    630 	}
    631 }
    632 
    633 static void ASE_KeyMESH( const char *token )
    634 {
    635 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
    636 
    637 	if ( !strcmp( token, "*TIMEVALUE" ) )
    638 	{
    639 		ASE_GetToken( qfalse );
    640 
    641 		pMesh->timeValue = atoi( s_token );
    642 		VERBOSE( ( ".....timevalue: %d\n", pMesh->timeValue ) );
    643 	}
    644 	else if ( !strcmp( token, "*MESH_NUMVERTEX" ) )
    645 	{
    646 		ASE_GetToken( qfalse );
    647 
    648 		pMesh->numVertexes = atoi( s_token );
    649 		VERBOSE( ( ".....TIMEVALUE: %d\n", pMesh->timeValue ) );
    650 		VERBOSE( ( ".....num vertexes: %d\n", pMesh->numVertexes ) );
    651 	}
    652 	else if ( !strcmp( token, "*MESH_NUMFACES" ) )
    653 	{
    654 		ASE_GetToken( qfalse );
    655 
    656 		pMesh->numFaces = atoi( s_token );
    657 		VERBOSE( ( ".....num faces: %d\n", pMesh->numFaces ) );
    658 	}
    659 	else if ( !strcmp( token, "*MESH_NUMTVFACES" ) )
    660 	{
    661 		ASE_GetToken( qfalse );
    662 
    663 		if ( atoi( s_token ) != pMesh->numFaces )
    664 		{
    665 			Error( "MESH_NUMTVFACES != MESH_NUMFACES" );
    666 		}
    667 	}
    668 	else if ( !strcmp( token, "*MESH_NUMTVERTEX" ) )
    669 	{
    670 		ASE_GetToken( qfalse );
    671 
    672 		pMesh->numTVertexes = atoi( s_token );
    673 		VERBOSE( ( ".....num tvertexes: %d\n", pMesh->numTVertexes ) );
    674 	}
    675 	else if ( !strcmp( token, "*MESH_VERTEX_LIST" ) )
    676 	{
    677 		pMesh->vertexes = calloc( sizeof( aseVertex_t ) * pMesh->numVertexes, 1 );
    678 		pMesh->currentVertex = 0;
    679 		VERBOSE( ( ".....parsing MESH_VERTEX_LIST\n" ) );
    680 		ASE_ParseBracedBlock( ASE_KeyMESH_VERTEX_LIST );
    681 	}
    682 	else if ( !strcmp( token, "*MESH_TVERTLIST" ) )
    683 	{
    684 		pMesh->currentVertex = 0;
    685 		pMesh->tvertexes = calloc( sizeof( aseTVertex_t ) * pMesh->numTVertexes, 1 );
    686 		VERBOSE( ( ".....parsing MESH_TVERTLIST\n" ) );
    687 		ASE_ParseBracedBlock( ASE_KeyMESH_TVERTLIST );
    688 	}
    689 	else if ( !strcmp( token, "*MESH_FACE_LIST" ) )
    690 	{
    691 		pMesh->faces = calloc( sizeof( aseFace_t ) * pMesh->numFaces, 1 );
    692 		pMesh->currentFace = 0;
    693 		VERBOSE( ( ".....parsing MESH_FACE_LIST\n" ) );
    694 		ASE_ParseBracedBlock( ASE_KeyMESH_FACE_LIST );
    695 	}
    696 	else if ( !strcmp( token, "*MESH_TFACELIST" ) )
    697 	{
    698 		pMesh->tfaces = calloc( sizeof( aseFace_t ) * pMesh->numFaces, 1 );
    699 		pMesh->currentFace = 0;
    700 		VERBOSE( ( ".....parsing MESH_TFACE_LIST\n" ) );
    701 		ASE_ParseBracedBlock( ASE_KeyTFACE_LIST );
    702 	}
    703 	else if ( !strcmp( token, "*MESH_NORMALS" ) )
    704 	{
    705 		ASE_ParseBracedBlock( 0 );
    706 	}
    707 }
    708 
    709 static void ASE_KeyMESH_ANIMATION( const char *token )
    710 {
    711 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
    712 
    713 	// loads a single animation frame
    714 	if ( !strcmp( token, "*MESH" ) )
    715 	{
    716 		VERBOSE( ( "...found MESH\n" ) );
    717 		assert( pMesh->faces == 0 );
    718 		assert( pMesh->vertexes == 0 );
    719 		assert( pMesh->tvertexes == 0 );
    720 		memset( pMesh, 0, sizeof( *pMesh ) );
    721 
    722 		ASE_ParseBracedBlock( ASE_KeyMESH );
    723 
    724 		if ( ++ase.objects[ase.currentObject].anim.currentFrame == MAX_ASE_ANIMATION_FRAMES )
    725 		{
    726 			Error( "Too many animation frames" );
    727 		}
    728 	}
    729 	else
    730 	{
    731 		Error( "Unknown token '%s' while parsing MESH_ANIMATION", token );
    732 	}
    733 }
    734 
    735 static void ASE_KeyGEOMOBJECT( const char *token )
    736 {
    737 	if ( !strcmp( token, "*NODE_NAME" ) )
    738 	{
    739 		char *name = ase.objects[ase.currentObject].name;
    740 
    741 		ASE_GetToken( qtrue );
    742 		VERBOSE( ( " %s\n", s_token ) );
    743 		strcpy( ase.objects[ase.currentObject].name, s_token + 1 );
    744 		if ( strchr( ase.objects[ase.currentObject].name, '"' ) )
    745 			*strchr( ase.objects[ase.currentObject].name, '"' ) = 0;
    746 
    747 		if ( strstr( name, "tag" ) == name )
    748 		{
    749 			while ( strchr( name, '_' ) != strrchr( name, '_' ) )
    750 			{
    751 				*strrchr( name, '_' ) = 0;
    752 			}
    753 			while ( strrchr( name, ' ' ) )
    754 			{
    755 				*strrchr( name, ' ' ) = 0;
    756 			}
    757 		}
    758 	}
    759 	else if ( !strcmp( token, "*NODE_PARENT" ) )
    760 	{
    761 		ASE_SkipRestOfLine();
    762 	}
    763 	// ignore unused data blocks
    764 	else if ( !strcmp( token, "*NODE_TM" ) ||
    765 		      !strcmp( token, "*TM_ANIMATION" ) )
    766 	{
    767 		ASE_ParseBracedBlock( 0 );
    768 	}
    769 	// ignore regular meshes that aren't part of animation
    770 	else if ( !strcmp( token, "*MESH" ) && !ase.grabAnims )
    771 	{
    772 /*
    773 		if ( strstr( ase.objects[ase.currentObject].name, "tag_" ) == ase.objects[ase.currentObject].name ) 
    774 		{
    775 			s_forceStaticMesh = true;
    776 			ASE_ParseBracedBlock( ASE_KeyMESH );
    777 			s_forceStaticMesh = false;
    778 		}
    779 */
    780 		ASE_ParseBracedBlock( ASE_KeyMESH );
    781 		if ( ++ase.objects[ase.currentObject].anim.currentFrame == MAX_ASE_ANIMATION_FRAMES )
    782 		{
    783 			Error( "Too many animation frames" );
    784 		}
    785 		ase.objects[ase.currentObject].anim.numFrames = ase.objects[ase.currentObject].anim.currentFrame;
    786 		ase.objects[ase.currentObject].numAnimations++;
    787 /*
    788 		// ignore meshes that aren't part of animations if this object isn't a 
    789 		// a tag
    790 		else
    791 		{
    792 			ASE_ParseBracedBlock( 0 );
    793 		}
    794 */
    795 	}
    796 	// according to spec these are obsolete
    797 	else if ( !strcmp( token, "*MATERIAL_REF" ) )
    798 	{
    799 		ASE_GetToken( qfalse );
    800 
    801 		ase.objects[ase.currentObject].materialRef = atoi( s_token );
    802 	}
    803 	// loads a sequence of animation frames
    804 	else if ( !strcmp( token, "*MESH_ANIMATION" ) )
    805 	{
    806 		if ( ase.grabAnims )
    807 		{
    808 			VERBOSE( ( "..found MESH_ANIMATION\n" ) );
    809 
    810 			if ( ase.objects[ase.currentObject].numAnimations )
    811 			{
    812 				Error( "Multiple MESH_ANIMATIONS within a single GEOM_OBJECT" );
    813 			}
    814 			ASE_ParseBracedBlock( ASE_KeyMESH_ANIMATION );
    815 			ase.objects[ase.currentObject].anim.numFrames = ase.objects[ase.currentObject].anim.currentFrame;
    816 			ase.objects[ase.currentObject].numAnimations++;
    817 		}
    818 		else
    819 		{
    820 			ASE_SkipEnclosingBraces();
    821 		}
    822 	}
    823 	// skip unused info
    824 	else if ( !strcmp( token, "*PROP_MOTIONBLUR" ) ||
    825 		      !strcmp( token, "*PROP_CASTSHADOW" ) ||
    826 			  !strcmp( token, "*PROP_RECVSHADOW" ) )
    827 	{
    828 		ASE_SkipRestOfLine();
    829 	}
    830 }
    831 
    832 static void ConcatenateObjects( aseGeomObject_t *pObjA, aseGeomObject_t *pObjB )
    833 {
    834 }
    835 
    836 static void CollapseObjects( void )
    837 {
    838 	int i;
    839 	int numObjects = ase.currentObject;
    840 
    841 	for ( i = 0; i < numObjects; i++ )
    842 	{
    843 		int j;
    844 
    845 		// skip tags
    846 		if ( strstr( ase.objects[i].name, "tag" ) == ase.objects[i].name )
    847 		{
    848 			continue;
    849 		}
    850 
    851 		if ( !ase.objects[i].numAnimations )
    852 		{
    853 			continue;
    854 		}
    855 
    856 		for ( j = i + 1; j < numObjects; j++ )
    857 		{
    858 			if ( strstr( ase.objects[j].name, "tag" ) == ase.objects[j].name )
    859 			{
    860 				continue;
    861 			}
    862 			if ( ase.objects[i].materialRef == ase.objects[j].materialRef )
    863 			{
    864 				if ( ase.objects[j].numAnimations )
    865 				{
    866 					ConcatenateObjects( &ase.objects[i], &ase.objects[j] );
    867 				}
    868 			}
    869 		}
    870 	}
    871 }
    872 
    873 /*
    874 ** ASE_Process
    875 */
    876 static void ASE_Process( void )
    877 {
    878 	while ( ASE_GetToken( qfalse ) )
    879 	{
    880 		if ( !strcmp( s_token, "*3DSMAX_ASCIIEXPORT" ) ||
    881 			 !strcmp( s_token, "*COMMENT" ) )
    882 		{
    883 			ASE_SkipRestOfLine();
    884 		}
    885 		else if ( !strcmp( s_token, "*SCENE" ) )
    886 			ASE_SkipEnclosingBraces();
    887 		else if ( !strcmp( s_token, "*MATERIAL_LIST" ) )
    888 		{
    889 			VERBOSE( ("MATERIAL_LIST\n") );
    890 
    891 			ASE_ParseBracedBlock( ASE_KeyMATERIAL_LIST );
    892 		}
    893 		else if ( !strcmp( s_token, "*GEOMOBJECT" ) )
    894 		{
    895 			VERBOSE( ("GEOMOBJECT" ) );
    896 
    897 			ASE_ParseBracedBlock( ASE_KeyGEOMOBJECT );
    898 
    899 			if ( strstr( ase.objects[ase.currentObject].name, "Bip" ) ||
    900 				 strstr( ase.objects[ase.currentObject].name, "ignore_" ) )
    901 			{
    902 				ASE_FreeGeomObject( ase.currentObject );
    903 				VERBOSE( ( "(discarding BIP/ignore object)\n" ) );
    904 			}
    905 			else if ( ( strstr( ase.objects[ase.currentObject].name, "h_" ) != ase.objects[ase.currentObject].name ) &&
    906 				      ( strstr( ase.objects[ase.currentObject].name, "l_" ) != ase.objects[ase.currentObject].name ) &&
    907 					  ( strstr( ase.objects[ase.currentObject].name, "u_" ) != ase.objects[ase.currentObject].name ) &&
    908 					  ( strstr( ase.objects[ase.currentObject].name, "tag" ) != ase.objects[ase.currentObject].name ) &&
    909 					  ase.grabAnims )
    910 			{
    911 				VERBOSE( ( "(ignoring improperly labeled object '%s')\n", ase.objects[ase.currentObject].name ) );
    912 				ASE_FreeGeomObject( ase.currentObject );
    913 			}
    914 			else
    915 			{
    916 				if ( ++ase.currentObject == MAX_ASE_OBJECTS )
    917 				{
    918 					Error( "Too many GEOMOBJECTs" );
    919 				}
    920 			}
    921 		}
    922 		else if ( s_token[0] )
    923 		{
    924 			printf( "Unknown token '%s'\n", s_token );
    925 		}
    926 	}
    927 
    928 	if ( !ase.currentObject )
    929 		Error( "No animation data!" );
    930 
    931 	CollapseObjects();
    932 }
    933