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