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 (__linux__) || defined (__APPLE__) || defined (__FreeBSD__)
118 
strlwr(char * string)119 static char* strlwr (char* string)
120 {
121   char *cp;
122   for (cp = string; *cp; ++cp)
123   {
124     if ('A' <= *cp && *cp <= 'Z')
125       *cp += 'a' - 'A';
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 {
138 	FILE *fp = fopen( filename, "rb" );
139 
140 	if ( !fp )
141 		Error( "File not found '%s'", filename );
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 	{
155 		fclose( fp );
156 		Error( "fread() != -1 for '%s'", filename );
157 	}
158 
159 	fclose( fp );
160 
161         strcpy(gl_filename, filename);
162 
163 	ASE_Process();
164 }
165 
166 /*
167 ** ASE_Free
168 */
ASE_Free(void)169 void ASE_Free( void )
170 {
171 	int i;
172 
173 	for ( i = 0; i < ase.currentObject; i++ )
174 	{
175 		ASE_FreeGeomObject( i );
176 	}
177 }
178 
179 /*
180 ** ASE_GetNumSurfaces
181 */
ASE_GetNumSurfaces(void)182 int ASE_GetNumSurfaces( void )
183 {
184 	return ase.currentObject;
185 }
186 
187 /*
188 ** ASE_GetSurfaceName
189 */
ASE_GetSurfaceName(int which)190 const char *ASE_GetSurfaceName( int which )
191 {
192 	aseGeomObject_t *pObject = &ase.objects[which];
193 
194 	if ( !pObject->anim.numFrames )
195 		return 0;
196 
197 	return pObject->name;
198 }
199 
200 /*
201 ** ASE_GetSurfaceAnimation
202 **
203 ** Returns an animation (sequence of polysets)
204 */
ASE_GetSurfaceAnimation(int which,int * pNumFrames,int skipFrameStart,int skipFrameEnd,int maxFrames)205 polyset_t *ASE_GetSurfaceAnimation( int which, int *pNumFrames, int skipFrameStart, int skipFrameEnd, int maxFrames )
206 {
207 	aseGeomObject_t *pObject = &ase.objects[which];
208 	polyset_t *psets;
209 	int numFramesInAnimation;
210 	int numFramesToKeep;
211 	int i, f;
212 
213 	if ( !pObject->anim.numFrames )
214 		return 0;
215 
216 	if ( pObject->anim.numFrames > maxFrames && maxFrames != -1 )
217 	{
218 		numFramesInAnimation = maxFrames;
219 	}
220 	else
221 	{
222 		numFramesInAnimation = pObject->anim.numFrames;
223 		if ( maxFrames != -1 )
224 			Sys_Printf( "WARNING: ASE_GetSurfaceAnimation maxFrames > numFramesInAnimation\n" );
225 	}
226 
227 	if ( skipFrameEnd != -1 )
228 		numFramesToKeep = numFramesInAnimation - ( skipFrameEnd - skipFrameStart + 1 );
229 	else
230 		numFramesToKeep = numFramesInAnimation;
231 
232 	*pNumFrames = numFramesToKeep;
233 
234 	psets = calloc( sizeof( polyset_t ) * numFramesToKeep, 1 );
235 
236 	for ( f = 0, i = 0; i < numFramesInAnimation; i++ )
237 	{
238 		int t;
239 		aseMesh_t *pMesh = &pObject->anim.frames[i];
240 
241 		if ( skipFrameStart != -1 )
242 		{
243 			if ( i >= skipFrameStart && i <= skipFrameEnd )
244 				continue;
245 		}
246 
247 		strcpy( psets[f].name, pObject->name );
248 		strcpy( psets[f].materialname, ase.materials[pObject->materialRef].name );
249 
250 		psets[f].triangles = calloc( sizeof( triangle_t ) * pObject->anim.frames[i].numFaces, 1 );
251 		psets[f].numtriangles = pObject->anim.frames[i].numFaces;
252 
253 		for ( t = 0; t < pObject->anim.frames[i].numFaces; t++ )
254 		{
255 			int k;
256 
257 			for ( k = 0; k < 3; k++ )
258 			{
259 				psets[f].triangles[t].verts[k][0] = pMesh->vertexes[pMesh->faces[t][k]].x;
260 				psets[f].triangles[t].verts[k][1] = pMesh->vertexes[pMesh->faces[t][k]].y;
261 				psets[f].triangles[t].verts[k][2] = pMesh->vertexes[pMesh->faces[t][k]].z;
262 
263 				if ( pMesh->tvertexes && pMesh->tfaces )
264 				{
265 					psets[f].triangles[t].texcoords[k][0] = pMesh->tvertexes[pMesh->tfaces[t][k]].s;
266 					psets[f].triangles[t].texcoords[k][1] = pMesh->tvertexes[pMesh->tfaces[t][k]].t;
267 				}
268 
269 			}
270 		}
271 
272 		f++;
273 	}
274 
275 	return psets;
276 }
277 
ASE_FreeGeomObject(int ndx)278 static void ASE_FreeGeomObject( int ndx )
279 {
280 	aseGeomObject_t *pObject;
281 	int i;
282 
283 	pObject = &ase.objects[ndx];
284 
285 	for ( i = 0; i < pObject->anim.numFrames; i++ )
286 	{
287 		if ( pObject->anim.frames[i].vertexes )
288 		{
289 			free( pObject->anim.frames[i].vertexes );
290 		}
291 		if ( pObject->anim.frames[i].tvertexes )
292 		{
293 			free( pObject->anim.frames[i].tvertexes );
294 		}
295 		if ( pObject->anim.frames[i].faces )
296 		{
297 			free( pObject->anim.frames[i].faces );
298 		}
299 		if ( pObject->anim.frames[i].tfaces )
300 		{
301 			free( pObject->anim.frames[i].tfaces );
302 		}
303 	}
304 
305 	memset( pObject, 0, sizeof( *pObject ) );
306 }
307 
ASE_GetCurrentMesh(void)308 static aseMesh_t *ASE_GetCurrentMesh( void )
309 {
310 	aseGeomObject_t *pObject;
311 
312 	if ( ase.currentObject >= MAX_ASE_OBJECTS )
313 	{
314 		Error( "Too many GEOMOBJECTs" );
315 		return 0; // never called
316 	}
317 
318 	pObject = &ase.objects[ase.currentObject];
319 
320 	if ( pObject->anim.currentFrame >= MAX_ASE_ANIMATION_FRAMES )
321 	{
322 		Error( "Too many MESHes" );
323 		return 0;
324 	}
325 
326 	return &pObject->anim.frames[pObject->anim.currentFrame];
327 }
328 
CharIsTokenDelimiter(int ch)329 static int CharIsTokenDelimiter( int ch )
330 {
331 	if ( ch <= 32 )
332 		return 1;
333 	return 0;
334 }
335 
ASE_GetToken(qboolean restOfLine)336 static int ASE_GetToken( qboolean restOfLine )
337 {
338 	int i = 0;
339 
340 	if ( ase.buffer == 0 )
341 		return 0;
342 
343 	if ( ( ase.curpos - ase.buffer ) == ase.len )
344 		return 0;
345 
346 	// skip over crap
347 	while ( ( ( ase.curpos - ase.buffer ) < ase.len ) &&
348 		    ( *ase.curpos <= 32 ) )
349 	{
350 		ase.curpos++;
351 	}
352 
353 	while ( ( ase.curpos - ase.buffer ) < ase.len )
354 	{
355 		s_token[i] = *ase.curpos;
356 
357 		ase.curpos++;
358 		i++;
359 
360 		if ( ( CharIsTokenDelimiter( s_token[i-1] ) && !restOfLine ) ||
361 			 ( ( s_token[i-1] == '\n' ) || ( s_token[i-1] == '\r' ) ) )
362 		{
363 			s_token[i-1] = 0;
364 			break;
365 		}
366 	}
367 
368 	s_token[i] = 0;
369 
370 	return 1;
371 }
372 
ASE_ParseBracedBlock(void (* parser)(const char * token))373 static void ASE_ParseBracedBlock( void (*parser)( const char *token ) )
374 {
375 	int indent = 0;
376 
377 	while ( ASE_GetToken( qfalse ) )
378 	{
379 		if ( !strcmp( s_token, "{" ) )
380 		{
381 			indent++;
382 		}
383 		else if ( !strcmp( s_token, "}" ) )
384 		{
385 			--indent;
386 			if ( indent == 0 )
387 				break;
388 			else if ( indent < 0 )
389 				Error( "Unexpected '}'" );
390 		}
391 		else
392 		{
393 			if ( parser )
394 				parser( s_token );
395 		}
396 	}
397 }
398 
ASE_SkipEnclosingBraces(void)399 static void ASE_SkipEnclosingBraces( void )
400 {
401 	int indent = 0;
402 
403 	while ( ASE_GetToken( qfalse ) )
404 	{
405 		if ( !strcmp( s_token, "{" ) )
406 		{
407 			indent++;
408 		}
409 		else if ( !strcmp( s_token, "}" ) )
410 		{
411 			indent--;
412 			if ( indent == 0 )
413 				break;
414 			else if ( indent < 0 )
415 				Error( "Unexpected '}'" );
416 		}
417 	}
418 }
419 
ASE_SkipRestOfLine(void)420 static void ASE_SkipRestOfLine( void )
421 {
422 	ASE_GetToken( qtrue );
423 }
424 
ASE_KeyMAP_DIFFUSE(const char * token)425 static void ASE_KeyMAP_DIFFUSE( const char *token )
426 {
427 	char fullpath[1024], bitmap[1024], modeldir[1024];
428 	char filename[1024];
429 	int i = 0, count;
430 
431 	strcpy(filename, gl_filename);
432 
433 	if ( !strcmp( token, "*BITMAP" ) )
434 	{
435 		ASE_GetToken( qfalse );
436 
437 		// the purpose of this whole chunk of code below is to extract the relative path
438 		// from a full path in the ASE
439 
440 		strcpy( bitmap, s_token + 1 );
441 		if ( strchr( bitmap, '"' ) )
442 			*strchr( bitmap, '"' ) = 0;
443 
444 		/* convert backslash to slash */
445 		while ( bitmap[i] )
446 		{
447 			if ( bitmap[i] == '\\' )
448 				bitmap[i] = '/';
449 			i++;
450 		}
451 
452 		/* remove filename from path */
453 		for( i=strlen(filename); i>0; i--)
454 		{
455 			if(filename[i] == '/')
456 			{
457 				filename[i] = '\0';
458 				break;
459 			}
460 		}
461 
462 		/* replaces a relative path with a full path */
463 		if(bitmap[0] == '.' && bitmap[1] == '.' && bitmap[2] == '/')
464 		{
465 			while(bitmap[0] == '.' && bitmap[1] == '.' && bitmap[2] == '/')
466 			{
467 				/* remove last item from path */
468 				for( i=strlen(filename); i>0; i--)
469 				{
470 					if(filename[i] == '/')
471 					{
472 						filename[i] = '\0';
473 						break;
474 					}
475 				}
476 				strcpy(bitmap, &bitmap[3]);
477 			}
478 			strcat(filename, "/");
479 			strcat(filename, bitmap);
480 			strcpy(bitmap, filename);
481 		}
482 
483 		if ( strstr( bitmap, gamedir ) )
484 		{
485 			strcpy( ase.materials[ase.numMaterials].name, strstr( bitmap, gamedir ) + strlen( gamedir ) );
486 			Sys_Printf("material name: \'%s\'\n", strstr( bitmap, gamedir ) + strlen( gamedir ) );
487 		}
488 		else
489 		{
490 			sprintf( ase.materials[ase.numMaterials].name, "(not converted: '%s')", bitmap );
491 			Sys_Printf( "WARNING: illegal material name '%s'\n", bitmap );
492 		}
493 	}
494 	else
495 	{
496 	}
497 }
498 
ASE_KeyMATERIAL(const char * token)499 static void ASE_KeyMATERIAL( const char *token )
500 {
501 	if ( !strcmp( token, "*MAP_DIFFUSE" ) )
502 	{
503 		ASE_ParseBracedBlock( ASE_KeyMAP_DIFFUSE );
504 	}
505 	else
506 	{
507 	}
508 }
509 
ASE_KeyMATERIAL_LIST(const char * token)510 static void ASE_KeyMATERIAL_LIST( const char *token )
511 {
512 	if ( !strcmp( token, "*MATERIAL_COUNT" ) )
513 	{
514 		ASE_GetToken( qfalse );
515 		VERBOSE( ( "..num materials: %s\n", s_token ) );
516 		if ( atoi( s_token ) > MAX_ASE_MATERIALS )
517 		{
518 			Error( "Too many materials!" );
519 		}
520 		ase.numMaterials = 0;
521 	}
522 	else if ( !strcmp( token, "*MATERIAL" ) )
523 	{
524 		VERBOSE( ( "..material %d ", ase.numMaterials ) );
525 		ASE_ParseBracedBlock( ASE_KeyMATERIAL );
526 		ase.numMaterials++;
527 	}
528 }
529 
ASE_KeyMESH_VERTEX_LIST(const char * token)530 static void ASE_KeyMESH_VERTEX_LIST( const char *token )
531 {
532 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
533 
534 	if ( !strcmp( token, "*MESH_VERTEX" ) )
535 	{
536 		ASE_GetToken( qfalse );		// skip number
537 
538 		ASE_GetToken( qfalse );
539 		pMesh->vertexes[pMesh->currentVertex].y = atof( s_token );
540 
541 		ASE_GetToken( qfalse );
542 		pMesh->vertexes[pMesh->currentVertex].x = -atof( s_token );
543 
544 		ASE_GetToken( qfalse );
545 		pMesh->vertexes[pMesh->currentVertex].z = atof( s_token );
546 
547 		pMesh->currentVertex++;
548 
549 		if ( pMesh->currentVertex > pMesh->numVertexes )
550 		{
551 			Error( "pMesh->currentVertex >= pMesh->numVertexes" );
552 		}
553 	}
554 	else
555 	{
556 		Error( "Unknown token '%s' while parsing MESH_VERTEX_LIST", token );
557 	}
558 }
559 
ASE_KeyMESH_FACE_LIST(const char * token)560 static void ASE_KeyMESH_FACE_LIST( const char *token )
561 {
562 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
563 
564 	if ( !strcmp( token, "*MESH_FACE" ) )
565 	{
566 		ASE_GetToken( qfalse );	// skip face number
567 
568 		ASE_GetToken( qfalse );	// skip label
569 		ASE_GetToken( qfalse );	// first vertex
570 		pMesh->faces[pMesh->currentFace][0] = atoi( s_token );
571 
572 		ASE_GetToken( qfalse );	// skip label
573 		ASE_GetToken( qfalse );	// second vertex
574 		pMesh->faces[pMesh->currentFace][2] = atoi( s_token );
575 
576 		ASE_GetToken( qfalse );	// skip label
577 		ASE_GetToken( qfalse );	// third vertex
578 		pMesh->faces[pMesh->currentFace][1] = atoi( s_token );
579 
580 		ASE_GetToken( qtrue );
581 
582 /*
583 		if ( ( p = strstr( s_token, "*MESH_MTLID" ) ) != 0 )
584 		{
585 			p += strlen( "*MESH_MTLID" ) + 1;
586 			mtlID = atoi( p );
587 		}
588 		else
589 		{
590 			Error( "No *MESH_MTLID found for face!" );
591 		}
592 */
593 
594 		pMesh->currentFace++;
595 	}
596 	else
597 	{
598 		Error( "Unknown token '%s' while parsing MESH_FACE_LIST", token );
599 	}
600 }
601 
ASE_KeyTFACE_LIST(const char * token)602 static void ASE_KeyTFACE_LIST( const char *token )
603 {
604 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
605 
606 	if ( !strcmp( token, "*MESH_TFACE" ) )
607 	{
608 		int a, b, c;
609 
610 		ASE_GetToken( qfalse );
611 
612 		ASE_GetToken( qfalse );
613 		a = atoi( s_token );
614 		ASE_GetToken( qfalse );
615 		c = atoi( s_token );
616 		ASE_GetToken( qfalse );
617 		b = atoi( s_token );
618 
619 		pMesh->tfaces[pMesh->currentFace][0] = a;
620 		pMesh->tfaces[pMesh->currentFace][1] = b;
621 		pMesh->tfaces[pMesh->currentFace][2] = c;
622 
623 		pMesh->currentFace++;
624 	}
625 	else
626 	{
627 		Error( "Unknown token '%s' in MESH_TFACE", token );
628 	}
629 }
630 
ASE_KeyMESH_TVERTLIST(const char * token)631 static void ASE_KeyMESH_TVERTLIST( const char *token )
632 {
633 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
634 
635 	if ( !strcmp( token, "*MESH_TVERT" ) )
636 	{
637 		char u[80], v[80], w[80];
638 
639 		ASE_GetToken( qfalse );
640 
641 		ASE_GetToken( qfalse );
642 		strcpy( u, s_token );
643 
644 		ASE_GetToken( qfalse );
645 		strcpy( v, s_token );
646 
647 		ASE_GetToken( qfalse );
648 		strcpy( w, s_token );
649 
650 		pMesh->tvertexes[pMesh->currentVertex].s = atof( u );
651 		pMesh->tvertexes[pMesh->currentVertex].t = 1.0f - atof( v );
652 
653 		pMesh->currentVertex++;
654 
655 		if ( pMesh->currentVertex > pMesh->numTVertexes )
656 		{
657 			Error( "pMesh->currentVertex > pMesh->numTVertexes" );
658 		}
659 	}
660 	else
661 	{
662 		Error( "Unknown token '%s' while parsing MESH_TVERTLIST" );
663 	}
664 }
665 
ASE_KeyMESH(const char * token)666 static void ASE_KeyMESH( const char *token )
667 {
668 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
669 
670 	if ( !strcmp( token, "*TIMEVALUE" ) )
671 	{
672 		ASE_GetToken( qfalse );
673 
674 		pMesh->timeValue = atoi( s_token );
675 		VERBOSE( ( ".....timevalue: %d\n", pMesh->timeValue ) );
676 	}
677 	else if ( !strcmp( token, "*MESH_NUMVERTEX" ) )
678 	{
679 		ASE_GetToken( qfalse );
680 
681 		pMesh->numVertexes = atoi( s_token );
682 		VERBOSE( ( ".....TIMEVALUE: %d\n", pMesh->timeValue ) );
683 		VERBOSE( ( ".....num vertexes: %d\n", pMesh->numVertexes ) );
684 	}
685 	else if ( !strcmp( token, "*MESH_NUMFACES" ) )
686 	{
687 		ASE_GetToken( qfalse );
688 
689 		pMesh->numFaces = atoi( s_token );
690 		VERBOSE( ( ".....num faces: %d\n", pMesh->numFaces ) );
691 	}
692 	else if ( !strcmp( token, "*MESH_NUMTVFACES" ) )
693 	{
694 		ASE_GetToken( qfalse );
695 
696 		if ( atoi( s_token ) != pMesh->numFaces )
697 		{
698 			Error( "MESH_NUMTVFACES != MESH_NUMFACES" );
699 		}
700 	}
701 	else if ( !strcmp( token, "*MESH_NUMTVERTEX" ) )
702 	{
703 		ASE_GetToken( qfalse );
704 
705 		pMesh->numTVertexes = atoi( s_token );
706 		VERBOSE( ( ".....num tvertexes: %d\n", pMesh->numTVertexes ) );
707 	}
708 	else if ( !strcmp( token, "*MESH_VERTEX_LIST" ) )
709 	{
710 		pMesh->vertexes = calloc( sizeof( aseVertex_t ) * pMesh->numVertexes, 1 );
711 		pMesh->currentVertex = 0;
712 		VERBOSE( ( ".....parsing MESH_VERTEX_LIST\n" ) );
713 		ASE_ParseBracedBlock( ASE_KeyMESH_VERTEX_LIST );
714 	}
715 	else if ( !strcmp( token, "*MESH_TVERTLIST" ) )
716 	{
717 		pMesh->currentVertex = 0;
718 		pMesh->tvertexes = calloc( sizeof( aseTVertex_t ) * pMesh->numTVertexes, 1 );
719 		VERBOSE( ( ".....parsing MESH_TVERTLIST\n" ) );
720 		ASE_ParseBracedBlock( ASE_KeyMESH_TVERTLIST );
721 	}
722 	else if ( !strcmp( token, "*MESH_FACE_LIST" ) )
723 	{
724 		pMesh->faces = calloc( sizeof( aseFace_t ) * pMesh->numFaces, 1 );
725 		pMesh->currentFace = 0;
726 		VERBOSE( ( ".....parsing MESH_FACE_LIST\n" ) );
727 		ASE_ParseBracedBlock( ASE_KeyMESH_FACE_LIST );
728 	}
729 	else if ( !strcmp( token, "*MESH_TFACELIST" ) )
730 	{
731 		pMesh->tfaces = calloc( sizeof( aseFace_t ) * pMesh->numFaces, 1 );
732 		pMesh->currentFace = 0;
733 		VERBOSE( ( ".....parsing MESH_TFACE_LIST\n" ) );
734 		ASE_ParseBracedBlock( ASE_KeyTFACE_LIST );
735 	}
736 	else if ( !strcmp( token, "*MESH_NORMALS" ) )
737 	{
738 		ASE_ParseBracedBlock( 0 );
739 	}
740 }
741 
ASE_KeyMESH_ANIMATION(const char * token)742 static void ASE_KeyMESH_ANIMATION( const char *token )
743 {
744 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
745 
746 	// loads a single animation frame
747 	if ( !strcmp( token, "*MESH" ) )
748 	{
749 		VERBOSE( ( "...found MESH\n" ) );
750 		assert( pMesh->faces == 0 );
751 		assert( pMesh->vertexes == 0 );
752 		assert( pMesh->tvertexes == 0 );
753 		memset( pMesh, 0, sizeof( *pMesh ) );
754 
755 		ASE_ParseBracedBlock( ASE_KeyMESH );
756 
757 		if ( ++ase.objects[ase.currentObject].anim.currentFrame == MAX_ASE_ANIMATION_FRAMES )
758 		{
759 			Error( "Too many animation frames" );
760 		}
761 	}
762 	else
763 	{
764 		Error( "Unknown token '%s' while parsing MESH_ANIMATION", token );
765 	}
766 }
767 
ASE_KeyGEOMOBJECT(const char * token)768 static void ASE_KeyGEOMOBJECT( const char *token )
769 {
770 	if ( !strcmp( token, "*NODE_NAME" ) )
771 	{
772 		char *name = ase.objects[ase.currentObject].name;
773 
774 		ASE_GetToken( qtrue );
775 		VERBOSE( ( " %s\n", s_token ) );
776 		strcpy( ase.objects[ase.currentObject].name, s_token + 1 );
777 		if ( strchr( ase.objects[ase.currentObject].name, '"' ) )
778 			*strchr( ase.objects[ase.currentObject].name, '"' ) = 0;
779 
780 		if ( strstr( name, "tag" ) == name )
781 		{
782 			while ( strchr( name, '_' ) != strrchr( name, '_' ) )
783 			{
784 				*strrchr( name, '_' ) = 0;
785 			}
786 			while ( strrchr( name, ' ' ) )
787 			{
788 				*strrchr( name, ' ' ) = 0;
789 			}
790 		}
791 	}
792 	else if ( !strcmp( token, "*NODE_PARENT" ) )
793 	{
794 		ASE_SkipRestOfLine();
795 	}
796 	// ignore unused data blocks
797 	else if ( !strcmp( token, "*NODE_TM" ) ||
798 		      !strcmp( token, "*TM_ANIMATION" ) )
799 	{
800 		ASE_ParseBracedBlock( 0 );
801 	}
802 	// ignore regular meshes that aren't part of animation
803 	else if ( !strcmp( token, "*MESH" ) && !ase.grabAnims )
804 	{
805 /*
806 		if ( strstr( ase.objects[ase.currentObject].name, "tag_" ) == ase.objects[ase.currentObject].name )
807 		{
808 			s_forceStaticMesh = true;
809 			ASE_ParseBracedBlock( ASE_KeyMESH );
810 			s_forceStaticMesh = false;
811 		}
812 */
813 		ASE_ParseBracedBlock( ASE_KeyMESH );
814 		if ( ++ase.objects[ase.currentObject].anim.currentFrame == MAX_ASE_ANIMATION_FRAMES )
815 		{
816 			Error( "Too many animation frames" );
817 		}
818 		ase.objects[ase.currentObject].anim.numFrames = ase.objects[ase.currentObject].anim.currentFrame;
819 		ase.objects[ase.currentObject].numAnimations++;
820 /*
821 		// ignore meshes that aren't part of animations if this object isn't a
822 		// a tag
823 		else
824 		{
825 			ASE_ParseBracedBlock( 0 );
826 		}
827 */
828 	}
829 	// according to spec these are obsolete
830 	else if ( !strcmp( token, "*MATERIAL_REF" ) )
831 	{
832 		ASE_GetToken( qfalse );
833 
834 		ase.objects[ase.currentObject].materialRef = atoi( s_token );
835 	}
836 	// loads a sequence of animation frames
837 	else if ( !strcmp( token, "*MESH_ANIMATION" ) )
838 	{
839 		if ( ase.grabAnims )
840 		{
841 			VERBOSE( ( "..found MESH_ANIMATION\n" ) );
842 
843 			if ( ase.objects[ase.currentObject].numAnimations )
844 			{
845 				Error( "Multiple MESH_ANIMATIONS within a single GEOM_OBJECT" );
846 			}
847 			ASE_ParseBracedBlock( ASE_KeyMESH_ANIMATION );
848 			ase.objects[ase.currentObject].anim.numFrames = ase.objects[ase.currentObject].anim.currentFrame;
849 			ase.objects[ase.currentObject].numAnimations++;
850 		}
851 		else
852 		{
853 			ASE_SkipEnclosingBraces();
854 		}
855 	}
856 	// skip unused info
857 	else if ( !strcmp( token, "*PROP_MOTIONBLUR" ) ||
858 		      !strcmp( token, "*PROP_CASTSHADOW" ) ||
859 			  !strcmp( token, "*PROP_RECVSHADOW" ) )
860 	{
861 		ASE_SkipRestOfLine();
862 	}
863 }
864 
ConcatenateObjects(aseGeomObject_t * pObjA,aseGeomObject_t * pObjB)865 static void ConcatenateObjects( aseGeomObject_t *pObjA, aseGeomObject_t *pObjB )
866 {
867 }
868 
CollapseObjects(void)869 static void CollapseObjects( void )
870 {
871 	int i;
872 	int numObjects = ase.currentObject;
873 
874 	for ( i = 0; i < numObjects; i++ )
875 	{
876 		int j;
877 
878 		// skip tags
879 		if ( strstr( ase.objects[i].name, "tag" ) == ase.objects[i].name )
880 		{
881 			continue;
882 		}
883 
884 		if ( !ase.objects[i].numAnimations )
885 		{
886 			continue;
887 		}
888 
889 		for ( j = i + 1; j < numObjects; j++ )
890 		{
891 			if ( strstr( ase.objects[j].name, "tag" ) == ase.objects[j].name )
892 			{
893 				continue;
894 			}
895 			if ( ase.objects[i].materialRef == ase.objects[j].materialRef )
896 			{
897 				if ( ase.objects[j].numAnimations )
898 				{
899 					ConcatenateObjects( &ase.objects[i], &ase.objects[j] );
900 				}
901 			}
902 		}
903 	}
904 }
905 
906 /*
907 ** ASE_Process
908 */
ASE_Process(void)909 static void ASE_Process( void )
910 {
911 	while ( ASE_GetToken( qfalse ) )
912 	{
913 		if ( !strcmp( s_token, "*3DSMAX_ASCIIEXPORT" ) ||
914 			 !strcmp( s_token, "*COMMENT" ) )
915 		{
916 			ASE_SkipRestOfLine();
917 		}
918 		else if ( !strcmp( s_token, "*SCENE" ) )
919 			ASE_SkipEnclosingBraces();
920 		else if ( !strcmp( s_token, "*MATERIAL_LIST" ) )
921 		{
922 			VERBOSE( ("MATERIAL_LIST\n") );
923 
924 			ASE_ParseBracedBlock( ASE_KeyMATERIAL_LIST );
925 		}
926 		else if ( !strcmp( s_token, "*GEOMOBJECT" ) )
927 		{
928 			VERBOSE( ("GEOMOBJECT" ) );
929 
930 			ASE_ParseBracedBlock( ASE_KeyGEOMOBJECT );
931 
932 			if ( strstr( ase.objects[ase.currentObject].name, "Bip" ) ||
933 				 strstr( ase.objects[ase.currentObject].name, "ignore_" ) )
934 			{
935 				ASE_FreeGeomObject( ase.currentObject );
936 				VERBOSE( ( "(discarding BIP/ignore object)\n" ) );
937 			}
938 			else if ( ( strstr( ase.objects[ase.currentObject].name, "h_" ) != ase.objects[ase.currentObject].name ) &&
939 				      ( strstr( ase.objects[ase.currentObject].name, "l_" ) != ase.objects[ase.currentObject].name ) &&
940 					  ( strstr( ase.objects[ase.currentObject].name, "u_" ) != ase.objects[ase.currentObject].name ) &&
941 					  ( strstr( ase.objects[ase.currentObject].name, "tag" ) != ase.objects[ase.currentObject].name ) &&
942 					  ase.grabAnims )
943 			{
944 				VERBOSE( ( "(ignoring improperly labeled object '%s')\n", ase.objects[ase.currentObject].name ) );
945 				ASE_FreeGeomObject( ase.currentObject );
946 			}
947 			else
948 			{
949 				if ( ++ase.currentObject == MAX_ASE_OBJECTS )
950 				{
951 					Error( "Too many GEOMOBJECTs" );
952 				}
953 			}
954 		}
955 		else if ( s_token[0] )
956 		{
957 			Sys_Printf( "Unknown token '%s'\n", s_token );
958 		}
959 	}
960 
961 	if ( !ase.currentObject )
962 		Error( "No animation data!" );
963 
964 	CollapseObjects();
965 }
966