1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "sys/platform.h"
30 #include "framework/Common.h"
31 #include "framework/FileSystem.h"
32 
33 #include "renderer/Model_ase.h"
34 
35 /*
36 ======================================================================
37 
38 	Parses 3D Studio Max ASCII export files.
39 	The goal is to parse the information into memory exactly as it is
40 	represented in the file.  Users of the data will then move it
41 	into a form that is more convenient for them.
42 
43 ======================================================================
44 */
45 
46 
47 #define VERBOSE( x ) { if ( ase.verbose ) { common->Printf x ; } }
48 
49 // working variables used during parsing
50 typedef struct {
51 	const char	*buffer;
52 	const char	*curpos;
53 	int			len;
54 	char		token[1024];
55 
56 	bool	verbose;
57 
58 	aseModel_t	*model;
59 	aseObject_t	*currentObject;
60 	aseMesh_t	*currentMesh;
61 	aseMaterial_t	*currentMaterial;
62 	int			currentFace;
63 	int			currentVertex;
64 } ase_t;
65 
66 static ase_t ase;
67 
68 
ASE_GetCurrentMesh(void)69 static aseMesh_t *ASE_GetCurrentMesh( void )
70 {
71 	return ase.currentMesh;
72 }
73 
CharIsTokenDelimiter(int ch)74 static int CharIsTokenDelimiter( int ch )
75 {
76 	if ( ch <= 32 )
77 		return 1;
78 	return 0;
79 }
80 
ASE_GetToken(bool restOfLine)81 static int ASE_GetToken( bool restOfLine )
82 {
83 	int i = 0;
84 
85 	if ( ase.buffer == 0 )
86 		return 0;
87 
88 	if ( ( ase.curpos - ase.buffer ) == ase.len )
89 		return 0;
90 
91 	// skip over crap
92 	while ( ( ( ase.curpos - ase.buffer ) < ase.len ) &&
93 			( *ase.curpos <= 32 ) )
94 	{
95 		ase.curpos++;
96 	}
97 
98 	while ( ( ase.curpos - ase.buffer ) < ase.len )
99 	{
100 		ase.token[i] = *ase.curpos;
101 
102 		ase.curpos++;
103 		i++;
104 
105 		if ( ( CharIsTokenDelimiter( ase.token[i-1] ) && !restOfLine ) ||
106 			 ( ( ase.token[i-1] == '\n' ) || ( ase.token[i-1] == '\r' ) ) )
107 		{
108 			ase.token[i-1] = 0;
109 			break;
110 		}
111 	}
112 
113 	ase.token[i] = 0;
114 
115 	return 1;
116 }
117 
ASE_ParseBracedBlock(void (* parser)(const char * token))118 static void ASE_ParseBracedBlock( void (*parser)( const char *token ) )
119 {
120 	int indent = 0;
121 
122 	while ( ASE_GetToken( false ) )
123 	{
124 		if ( !strcmp( ase.token, "{" ) )
125 		{
126 			indent++;
127 		}
128 		else if ( !strcmp( ase.token, "}" ) )
129 		{
130 			--indent;
131 			if ( indent == 0 )
132 				break;
133 			else if ( indent < 0 )
134 				common->Error( "Unexpected '}'" );
135 		}
136 		else
137 		{
138 			if ( parser )
139 				parser( ase.token );
140 		}
141 	}
142 }
143 
ASE_SkipEnclosingBraces(void)144 static void ASE_SkipEnclosingBraces( void )
145 {
146 	int indent = 0;
147 
148 	while ( ASE_GetToken( false ) )
149 	{
150 		if ( !strcmp( ase.token, "{" ) )
151 		{
152 			indent++;
153 		}
154 		else if ( !strcmp( ase.token, "}" ) )
155 		{
156 			indent--;
157 			if ( indent == 0 )
158 				break;
159 			else if ( indent < 0 )
160 				common->Error( "Unexpected '}'" );
161 		}
162 	}
163 }
164 
ASE_SkipRestOfLine(void)165 static void ASE_SkipRestOfLine( void )
166 {
167 	ASE_GetToken( true );
168 }
169 
ASE_KeyMAP_DIFFUSE(const char * token)170 static void ASE_KeyMAP_DIFFUSE( const char *token )
171 {
172 	aseMaterial_t	*material;
173 
174 	if ( !strcmp( token, "*BITMAP" ) )
175 	{
176 		idStr	qpath;
177 		idStr	matname;
178 
179 		ASE_GetToken( false );
180 
181 		// remove the quotes
182 		char *s = strstr( ase.token + 1, "\"" );
183 		if ( s ) {
184 			*s = 0;
185 		}
186 		matname = ase.token + 1;
187 
188 		// convert the 3DSMax material pathname to a qpath
189 		matname.BackSlashesToSlashes();
190 		qpath = fileSystem->OSPathToRelativePath( matname );
191 		idStr::Copynz( ase.currentMaterial->name, qpath, sizeof( ase.currentMaterial->name ) );
192 	}
193 	else if ( !strcmp( token, "*UVW_U_OFFSET" ) )
194 	{
195 		material = ase.model->materials[ase.model->materials.Num() - 1];
196 		ASE_GetToken( false );
197 		material->uOffset = atof( ase.token );
198 	}
199 	else if ( !strcmp( token, "*UVW_V_OFFSET" ) )
200 	{
201 		material = ase.model->materials[ase.model->materials.Num() - 1];
202 		ASE_GetToken( false );
203 		material->vOffset = atof( ase.token );
204 	}
205 	else if ( !strcmp( token, "*UVW_U_TILING" ) )
206 	{
207 		material = ase.model->materials[ase.model->materials.Num() - 1];
208 		ASE_GetToken( false );
209 		material->uTiling = atof( ase.token );
210 	}
211 	else if ( !strcmp( token, "*UVW_V_TILING" ) )
212 	{
213 		material = ase.model->materials[ase.model->materials.Num() - 1];
214 		ASE_GetToken( false );
215 		material->vTiling = atof( ase.token );
216 	}
217 	else if ( !strcmp( token, "*UVW_ANGLE" ) )
218 	{
219 		material = ase.model->materials[ase.model->materials.Num() - 1];
220 		ASE_GetToken( false );
221 		material->angle = atof( ase.token );
222 	}
223 	else
224 	{
225 	}
226 }
227 
ASE_KeyMATERIAL(const char * token)228 static void ASE_KeyMATERIAL( const char *token )
229 {
230 	if ( !strcmp( token, "*MAP_DIFFUSE" ) )
231 	{
232 		ASE_ParseBracedBlock( ASE_KeyMAP_DIFFUSE );
233 	}
234 	else
235 	{
236 	}
237 }
238 
ASE_KeyMATERIAL_LIST(const char * token)239 static void ASE_KeyMATERIAL_LIST( const char *token )
240 {
241 	if ( !strcmp( token, "*MATERIAL_COUNT" ) )
242 	{
243 		ASE_GetToken( false );
244 		VERBOSE( ( "..num materials: %s\n", ase.token ) );
245 	}
246 	else if ( !strcmp( token, "*MATERIAL" ) )
247 	{
248 		VERBOSE( ( "..material %d\n", ase.model->materials.Num() ) );
249 
250 		ase.currentMaterial = (aseMaterial_t *)Mem_Alloc( sizeof( aseMaterial_t ) );
251 		memset( ase.currentMaterial, 0, sizeof( aseMaterial_t ) );
252 		ase.currentMaterial->uTiling = 1;
253 		ase.currentMaterial->vTiling = 1;
254 		ase.model->materials.Append(ase.currentMaterial);
255 
256 		ASE_ParseBracedBlock( ASE_KeyMATERIAL );
257 	}
258 }
259 
ASE_KeyNODE_TM(const char * token)260 static void ASE_KeyNODE_TM( const char *token )
261 {
262 	int		i;
263 
264 	if ( !strcmp( token, "*TM_ROW0" ) ) {
265 		for ( i = 0 ; i < 3 ; i++ ) {
266 			ASE_GetToken( false );
267 			ase.currentObject->mesh.transform[0][i] = atof( ase.token );
268 		}
269 	} else if ( !strcmp( token, "*TM_ROW1" ) ) {
270 		for ( i = 0 ; i < 3 ; i++ ) {
271 			ASE_GetToken( false );
272 			ase.currentObject->mesh.transform[1][i] = atof( ase.token );
273 		}
274 	} else if ( !strcmp( token, "*TM_ROW2" ) ) {
275 		for ( i = 0 ; i < 3 ; i++ ) {
276 			ASE_GetToken( false );
277 			ase.currentObject->mesh.transform[2][i] = atof( ase.token );
278 		}
279 	} else if ( !strcmp( token, "*TM_ROW3" ) ) {
280 		for ( i = 0 ; i < 3 ; i++ ) {
281 			ASE_GetToken( false );
282 			ase.currentObject->mesh.transform[3][i] = atof( ase.token );
283 		}
284 	}
285 }
286 
ASE_KeyMESH_VERTEX_LIST(const char * token)287 static void ASE_KeyMESH_VERTEX_LIST( const char *token )
288 {
289 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
290 
291 	if ( !strcmp( token, "*MESH_VERTEX" ) )
292 	{
293 		ASE_GetToken( false );		// skip number
294 
295 		ASE_GetToken( false );
296 		pMesh->vertexes[ase.currentVertex].x = atof( ase.token );
297 
298 		ASE_GetToken( false );
299 		pMesh->vertexes[ase.currentVertex].y = atof( ase.token );
300 
301 		ASE_GetToken( false );
302 		pMesh->vertexes[ase.currentVertex].z = atof( ase.token );
303 
304 		ase.currentVertex++;
305 
306 		if ( ase.currentVertex > pMesh->numVertexes )
307 		{
308 			common->Error( "ase.currentVertex >= pMesh->numVertexes" );
309 		}
310 	}
311 	else
312 	{
313 		common->Error( "Unknown token '%s' while parsing MESH_VERTEX_LIST", token );
314 	}
315 }
316 
ASE_KeyMESH_FACE_LIST(const char * token)317 static void ASE_KeyMESH_FACE_LIST( const char *token )
318 {
319 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
320 
321 	if ( !strcmp( token, "*MESH_FACE" ) )
322 	{
323 		ASE_GetToken( false );	// skip face number
324 
325 		// we are flipping the order here to change the front/back facing
326 		// from 3DS to our standard (clockwise facing out)
327 		ASE_GetToken( false );	// skip label
328 		ASE_GetToken( false );	// first vertex
329 		pMesh->faces[ase.currentFace].vertexNum[0] = atoi( ase.token );
330 
331 		ASE_GetToken( false );	// skip label
332 		ASE_GetToken( false );	// second vertex
333 		pMesh->faces[ase.currentFace].vertexNum[2] = atoi( ase.token );
334 
335 		ASE_GetToken( false );	// skip label
336 		ASE_GetToken( false );	// third vertex
337 		pMesh->faces[ase.currentFace].vertexNum[1] = atoi( ase.token );
338 
339 		ASE_GetToken( true );
340 
341 		// we could parse material id and smoothing groups here
342 /*
343 		if ( ( p = strstr( ase.token, "*MESH_MTLID" ) ) != 0 )
344 		{
345 			p += strlen( "*MESH_MTLID" ) + 1;
346 			mtlID = atoi( p );
347 		}
348 		else
349 		{
350 			common->Error( "No *MESH_MTLID found for face!" );
351 		}
352 */
353 
354 		ase.currentFace++;
355 	}
356 	else
357 	{
358 		common->Error( "Unknown token '%s' while parsing MESH_FACE_LIST", token );
359 	}
360 }
361 
ASE_KeyTFACE_LIST(const char * token)362 static void ASE_KeyTFACE_LIST( const char *token )
363 {
364 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
365 
366 	if ( !strcmp( token, "*MESH_TFACE" ) )
367 	{
368 		int a, b, c;
369 
370 		ASE_GetToken( false );
371 
372 		ASE_GetToken( false );
373 		a = atoi( ase.token );
374 		ASE_GetToken( false );
375 		c = atoi( ase.token );
376 		ASE_GetToken( false );
377 		b = atoi( ase.token );
378 
379 		pMesh->faces[ase.currentFace].tVertexNum[0] = a;
380 		pMesh->faces[ase.currentFace].tVertexNum[1] = b;
381 		pMesh->faces[ase.currentFace].tVertexNum[2] = c;
382 
383 		ase.currentFace++;
384 	}
385 	else
386 	{
387 		common->Error( "Unknown token '%s' in MESH_TFACE", token );
388 	}
389 }
390 
ASE_KeyCFACE_LIST(const char * token)391 static void ASE_KeyCFACE_LIST( const char *token )
392 {
393 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
394 
395 	if ( !strcmp( token, "*MESH_CFACE" ) )
396 	{
397 		ASE_GetToken( false );
398 
399 		for ( int i = 0 ; i < 3 ; i++ ) {
400 			ASE_GetToken( false );
401 			int a = atoi( ase.token );
402 
403 			// we flip the vertex order to change the face direction to our style
404 			static int remap[3] = { 0, 2, 1 };
405 			pMesh->faces[ase.currentFace].vertexColors[remap[i]][0] = pMesh->cvertexes[a][0] * 255;
406 			pMesh->faces[ase.currentFace].vertexColors[remap[i]][1] = pMesh->cvertexes[a][1] * 255;
407 			pMesh->faces[ase.currentFace].vertexColors[remap[i]][2] = pMesh->cvertexes[a][2] * 255;
408 		}
409 
410 		ase.currentFace++;
411 	}
412 	else
413 	{
414 		common->Error( "Unknown token '%s' in MESH_CFACE", token );
415 	}
416 }
417 
ASE_KeyMESH_TVERTLIST(const char * token)418 static void ASE_KeyMESH_TVERTLIST( const char *token )
419 {
420 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
421 
422 	if ( !strcmp( token, "*MESH_TVERT" ) )
423 	{
424 		char u[80], v[80], w[80];
425 
426 		ASE_GetToken( false );
427 
428 		ASE_GetToken( false );
429 		strcpy( u, ase.token );
430 
431 		ASE_GetToken( false );
432 		strcpy( v, ase.token );
433 
434 		ASE_GetToken( false );
435 		strcpy( w, ase.token );
436 
437 		pMesh->tvertexes[ase.currentVertex].x = atof( u );
438 		// our OpenGL second texture axis is inverted from MAX's sense
439 		pMesh->tvertexes[ase.currentVertex].y = 1.0f - atof( v );
440 
441 		ase.currentVertex++;
442 
443 		if ( ase.currentVertex > pMesh->numTVertexes )
444 		{
445 			common->Error( "ase.currentVertex > pMesh->numTVertexes" );
446 		}
447 	}
448 	else
449 	{
450 		common->Error( "Unknown token '%s' while parsing MESH_TVERTLIST", token );
451 	}
452 }
453 
ASE_KeyMESH_CVERTLIST(const char * token)454 static void ASE_KeyMESH_CVERTLIST( const char *token )
455 {
456 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
457 
458 	pMesh->colorsParsed = true;
459 
460 	if ( !strcmp( token, "*MESH_VERTCOL" ) )
461 	{
462 		ASE_GetToken( false );
463 
464 		ASE_GetToken( false );
465 		pMesh->cvertexes[ase.currentVertex][0] = atof( token );
466 
467 		ASE_GetToken( false );
468 		pMesh->cvertexes[ase.currentVertex][1] = atof( token );
469 
470 		ASE_GetToken( false );
471 		pMesh->cvertexes[ase.currentVertex][2] = atof( token );
472 
473 		ase.currentVertex++;
474 
475 		if ( ase.currentVertex > pMesh->numCVertexes )
476 		{
477 			common->Error( "ase.currentVertex > pMesh->numCVertexes" );
478 		}
479 	}
480 	else {
481 		common->Error( "Unknown token '%s' while parsing MESH_CVERTLIST", token );
482 	}
483 }
484 
ASE_KeyMESH_NORMALS(const char * token)485 static void ASE_KeyMESH_NORMALS( const char *token )
486 {
487 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
488 	aseFace_t	*f;
489 	idVec3		n;
490 
491 	pMesh->normalsParsed = true;
492 	f = &pMesh->faces[ase.currentFace];
493 
494 	if ( !strcmp( token, "*MESH_FACENORMAL" ) )
495 	{
496 		int	num;
497 
498 		ASE_GetToken( false );
499 		num = atoi( ase.token );
500 
501 		if ( num >= pMesh->numFaces || num < 0 ) {
502 			common->Error( "MESH_NORMALS face index out of range: %i", num );
503 		}
504 
505 		if ( num != ase.currentFace ) {
506 			common->Error( "MESH_NORMALS face index != currentFace" );
507 		}
508 
509 		ASE_GetToken( false );
510 		n[0] = atof( ase.token );
511 		ASE_GetToken( false );
512 		n[1] = atof( ase.token );
513 		ASE_GetToken( false );
514 		n[2]= atof( ase.token );
515 
516 		f->faceNormal[0] = n[0] * pMesh->transform[0][0] + n[1] * pMesh->transform[1][0] + n[2] * pMesh->transform[2][0];
517 		f->faceNormal[1] = n[0] * pMesh->transform[0][1] + n[1] * pMesh->transform[1][1] + n[2] * pMesh->transform[2][1];
518 		f->faceNormal[2] = n[0] * pMesh->transform[0][2] + n[1] * pMesh->transform[1][2] + n[2] * pMesh->transform[2][2];
519 
520 		f->faceNormal.Normalize();
521 
522 		ase.currentFace++;
523 	}
524 	else if ( !strcmp( token, "*MESH_VERTEXNORMAL" ) )
525 	{
526 		int	num;
527 		int	v;
528 
529 		ASE_GetToken( false );
530 		num = atoi( ase.token );
531 
532 		if ( num >= pMesh->numVertexes || num < 0 ) {
533 			common->Error( "MESH_NORMALS vertex index out of range: %i", num );
534 		}
535 
536 		f = &pMesh->faces[ ase.currentFace - 1 ];
537 
538 		for ( v = 0 ; v < 3 ; v++ ) {
539 			if ( num == f->vertexNum[ v ] ) {
540 				break;
541 			}
542 		}
543 
544 		if ( v == 3 ) {
545 			common->Error( "MESH_NORMALS vertex index doesn't match face" );
546 		}
547 
548 		ASE_GetToken( false );
549 		n[0] = atof( ase.token );
550 		ASE_GetToken( false );
551 		n[1] = atof( ase.token );
552 		ASE_GetToken( false );
553 		n[2]= atof( ase.token );
554 
555 		f->vertexNormals[ v ][0] = n[0] * pMesh->transform[0][0] + n[1] * pMesh->transform[1][0] + n[2] * pMesh->transform[2][0];
556 		f->vertexNormals[ v ][1] = n[0] * pMesh->transform[0][1] + n[1] * pMesh->transform[1][1] + n[2] * pMesh->transform[2][1];
557 		f->vertexNormals[ v ][2] = n[0] * pMesh->transform[0][2] + n[1] * pMesh->transform[1][2] + n[2] * pMesh->transform[2][2];
558 
559 		f->vertexNormals[v].Normalize();
560 	}
561 }
562 
ASE_KeyMESH(const char * token)563 static void ASE_KeyMESH( const char *token )
564 {
565 	aseMesh_t *pMesh = ASE_GetCurrentMesh();
566 
567 	if ( !strcmp( token, "*TIMEVALUE" ) )
568 	{
569 		ASE_GetToken( false );
570 
571 		pMesh->timeValue = atoi( ase.token );
572 		VERBOSE( ( ".....timevalue: %d\n", pMesh->timeValue ) );
573 	}
574 	else if ( !strcmp( token, "*MESH_NUMVERTEX" ) )
575 	{
576 		ASE_GetToken( false );
577 
578 		pMesh->numVertexes = atoi( ase.token );
579 		VERBOSE( ( ".....num vertexes: %d\n", pMesh->numVertexes ) );
580 	}
581 	else if ( !strcmp( token, "*MESH_NUMTVERTEX" ) )
582 	{
583 		ASE_GetToken( false );
584 
585 		pMesh->numTVertexes = atoi( ase.token );
586 		VERBOSE( ( ".....num tvertexes: %d\n", pMesh->numTVertexes ) );
587 	}
588 	else if ( !strcmp( token, "*MESH_NUMCVERTEX" ) )
589 	{
590 		ASE_GetToken( false );
591 
592 		pMesh->numCVertexes = atoi( ase.token );
593 		VERBOSE( ( ".....num cvertexes: %d\n", pMesh->numCVertexes ) );
594 	}
595 	else if ( !strcmp( token, "*MESH_NUMFACES" ) )
596 	{
597 		ASE_GetToken( false );
598 
599 		pMesh->numFaces = atoi( ase.token );
600 		VERBOSE( ( ".....num faces: %d\n", pMesh->numFaces ) );
601 	}
602 	else if ( !strcmp( token, "*MESH_NUMTVFACES" ) )
603 	{
604 		ASE_GetToken( false );
605 
606 		pMesh->numTVFaces = atoi( ase.token );
607 		VERBOSE( ( ".....num tvfaces: %d\n", pMesh->numTVFaces ) );
608 
609 		if ( pMesh->numTVFaces != pMesh->numFaces )
610 		{
611 			common->Error( "MESH_NUMTVFACES != MESH_NUMFACES" );
612 		}
613 	}
614 	else if ( !strcmp( token, "*MESH_NUMCVFACES" ) )
615 	{
616 		ASE_GetToken( false );
617 
618 		pMesh->numCVFaces = atoi( ase.token );
619 		VERBOSE( ( ".....num cvfaces: %d\n", pMesh->numCVFaces ) );
620 
621 		if ( pMesh->numTVFaces != pMesh->numFaces )
622 		{
623 			common->Error( "MESH_NUMCVFACES != MESH_NUMFACES" );
624 		}
625 	}
626 	else if ( !strcmp( token, "*MESH_VERTEX_LIST" ) )
627 	{
628 		pMesh->vertexes = (idVec3 *)Mem_Alloc( sizeof( idVec3 ) * pMesh->numVertexes );
629 		ase.currentVertex = 0;
630 		VERBOSE( ( ".....parsing MESH_VERTEX_LIST\n" ) );
631 		ASE_ParseBracedBlock( ASE_KeyMESH_VERTEX_LIST );
632 	}
633 	else if ( !strcmp( token, "*MESH_TVERTLIST" ) )
634 	{
635 		ase.currentVertex = 0;
636 		pMesh->tvertexes = (idVec2 *)Mem_Alloc( sizeof( idVec2 ) * pMesh->numTVertexes );
637 		VERBOSE( ( ".....parsing MESH_TVERTLIST\n" ) );
638 		ASE_ParseBracedBlock( ASE_KeyMESH_TVERTLIST );
639 	}
640 	else if ( !strcmp( token, "*MESH_CVERTLIST" ) )
641 	{
642 		ase.currentVertex = 0;
643 		pMesh->cvertexes = (idVec3 *)Mem_Alloc( sizeof( idVec3 ) * pMesh->numCVertexes );
644 		VERBOSE( ( ".....parsing MESH_CVERTLIST\n" ) );
645 		ASE_ParseBracedBlock( ASE_KeyMESH_CVERTLIST );
646 	}
647 	else if ( !strcmp( token, "*MESH_FACE_LIST" ) )
648 	{
649 		pMesh->faces = (aseFace_t *)Mem_Alloc( sizeof( aseFace_t ) * pMesh->numFaces );
650 		ase.currentFace = 0;
651 		VERBOSE( ( ".....parsing MESH_FACE_LIST\n" ) );
652 		ASE_ParseBracedBlock( ASE_KeyMESH_FACE_LIST );
653 	}
654 	else if ( !strcmp( token, "*MESH_TFACELIST" ) )
655 	{
656 		if ( !pMesh->faces ) {
657 			common->Error( "*MESH_TFACELIST before *MESH_FACE_LIST" );
658 		}
659 		ase.currentFace = 0;
660 		VERBOSE( ( ".....parsing MESH_TFACE_LIST\n" ) );
661 		ASE_ParseBracedBlock( ASE_KeyTFACE_LIST );
662 	}
663 	else if ( !strcmp( token, "*MESH_CFACELIST" ) )
664 	{
665 		if ( !pMesh->faces ) {
666 			common->Error( "*MESH_CFACELIST before *MESH_FACE_LIST" );
667 		}
668 		ase.currentFace = 0;
669 		VERBOSE( ( ".....parsing MESH_CFACE_LIST\n" ) );
670 		ASE_ParseBracedBlock( ASE_KeyCFACE_LIST );
671 	}
672 	else if ( !strcmp( token, "*MESH_NORMALS" ) )
673 	{
674 		if ( !pMesh->faces ) {
675 			common->Warning( "*MESH_NORMALS before *MESH_FACE_LIST" );
676 		}
677 		ase.currentFace = 0;
678 		VERBOSE( ( ".....parsing MESH_NORMALS\n" ) );
679 		ASE_ParseBracedBlock( ASE_KeyMESH_NORMALS );
680 	}
681 }
682 
ASE_KeyMESH_ANIMATION(const char * token)683 static void ASE_KeyMESH_ANIMATION( const char *token )
684 {
685 	aseMesh_t *mesh;
686 
687 	// loads a single animation frame
688 	if ( !strcmp( token, "*MESH" ) )
689 	{
690 		VERBOSE( ( "...found MESH\n" ) );
691 
692 		mesh = (aseMesh_t *)Mem_Alloc( sizeof( aseMesh_t ) );
693 		memset( mesh, 0, sizeof( aseMesh_t ) );
694 		ase.currentMesh = mesh;
695 
696 		ase.currentObject->frames.Append( mesh );
697 
698 		ASE_ParseBracedBlock( ASE_KeyMESH );
699 	}
700 	else
701 	{
702 		common->Error( "Unknown token '%s' while parsing MESH_ANIMATION", token );
703 	}
704 }
705 
ASE_KeyGEOMOBJECT(const char * token)706 static void ASE_KeyGEOMOBJECT( const char *token )
707 {
708 	aseObject_t	*object;
709 
710 	object = ase.currentObject;
711 
712 	if ( !strcmp( token, "*NODE_NAME" ) )
713 	{
714 		ASE_GetToken( true );
715 		VERBOSE( ( " %s\n", ase.token ) );
716 		idStr::Copynz( object->name, ase.token, sizeof( object->name ) );
717 	}
718 	else if ( !strcmp( token, "*NODE_PARENT" ) )
719 	{
720 		ASE_SkipRestOfLine();
721 	}
722 	// ignore unused data blocks
723 	else if ( !strcmp( token, "*NODE_TM" ) ||
724 			  !strcmp( token, "*TM_ANIMATION" ) )
725 	{
726 		ASE_ParseBracedBlock( ASE_KeyNODE_TM );
727 	}
728 	// ignore regular meshes that aren't part of animation
729 	else if ( !strcmp( token, "*MESH" ) )
730 	{
731 		ase.currentMesh = &ase.currentObject->mesh;
732 		ASE_ParseBracedBlock( ASE_KeyMESH );
733 	}
734 	// according to spec these are obsolete
735 	else if ( !strcmp( token, "*MATERIAL_REF" ) )
736 	{
737 		ASE_GetToken( false );
738 
739 		object->materialRef = atoi( ase.token );
740 	}
741 	// loads a sequence of animation frames
742 	else if ( !strcmp( token, "*MESH_ANIMATION" ) )
743 	{
744 		VERBOSE( ( "..found MESH_ANIMATION\n" ) );
745 
746 		ASE_ParseBracedBlock( ASE_KeyMESH_ANIMATION );
747 	}
748 	// skip unused info
749 	else if ( !strcmp( token, "*PROP_MOTIONBLUR" ) ||
750 			  !strcmp( token, "*PROP_CASTSHADOW" ) ||
751 			  !strcmp( token, "*PROP_RECVSHADOW" ) )
752 	{
753 		ASE_SkipRestOfLine();
754 	}
755 
756 }
757 
ASE_ParseGeomObject(void)758 void ASE_ParseGeomObject( void ) {
759 	aseObject_t	*object;
760 
761 	VERBOSE( ("GEOMOBJECT" ) );
762 
763 	object = (aseObject_t *)Mem_Alloc( sizeof( aseObject_t ) );
764 	memset( object, 0, sizeof( aseObject_t ) );
765 	ase.model->objects.Append( object );
766 	ase.currentObject = object;
767 
768 	object->frames.Resize(32, 32);
769 
770 	ASE_ParseBracedBlock( ASE_KeyGEOMOBJECT );
771 }
772 
ASE_KeyGROUP(const char * token)773 static void ASE_KeyGROUP( const char *token )
774 {
775 	if ( !strcmp( token, "*GEOMOBJECT" ) ) {
776 		ASE_ParseGeomObject();
777 	}
778 }
779 
780 /*
781 =================
782 ASE_Parse
783 =================
784 */
ASE_Parse(const char * buffer,bool verbose)785 aseModel_t *ASE_Parse( const char *buffer, bool verbose ) {
786 	memset( &ase, 0, sizeof( ase ) );
787 
788 	ase.verbose = verbose;
789 
790 	ase.buffer = buffer;
791 	ase.len = strlen( buffer );
792 	ase.curpos = ase.buffer;
793 	ase.currentObject = NULL;
794 
795 	// NOTE: using new operator because aseModel_t contains idList class objects
796 	ase.model = new aseModel_t;
797 	memset( ase.model, 0, sizeof( aseModel_t ) );
798 	ase.model->objects.Resize( 32, 32 );
799 	ase.model->materials.Resize( 32, 32 );
800 
801 	while ( ASE_GetToken( false ) ) {
802 		if ( !strcmp( ase.token, "*3DSMAX_ASCIIEXPORT" ) ||
803 			 !strcmp( ase.token, "*COMMENT" ) ) {
804 			ASE_SkipRestOfLine();
805 		} else if ( !strcmp( ase.token, "*SCENE" ) ) {
806 			ASE_SkipEnclosingBraces();
807 		} else if ( !strcmp( ase.token, "*GROUP" ) ) {
808 			ASE_GetToken( false );		// group name
809 			ASE_ParseBracedBlock( ASE_KeyGROUP );
810 		} else if ( !strcmp( ase.token, "*SHAPEOBJECT" ) ) {
811 			ASE_SkipEnclosingBraces();
812 		} else if ( !strcmp( ase.token, "*CAMERAOBJECT" ) ) {
813 			ASE_SkipEnclosingBraces();
814 		} else if ( !strcmp( ase.token, "*MATERIAL_LIST" ) ) {
815 			VERBOSE( ("MATERIAL_LIST\n") );
816 
817 			ASE_ParseBracedBlock( ASE_KeyMATERIAL_LIST );
818 		} else if ( !strcmp( ase.token, "*GEOMOBJECT" ) ) {
819 			ASE_ParseGeomObject();
820 		} else if ( ase.token[0] ) {
821 			common->Printf( "Unknown token '%s'\n", ase.token );
822 		}
823 	}
824 
825 	return ase.model;
826 }
827 
828 /*
829 =================
830 ASE_Load
831 =================
832 */
ASE_Load(const char * fileName)833 aseModel_t *ASE_Load( const char *fileName ) {
834 	char *buf;
835 	ID_TIME_T timeStamp;
836 	aseModel_t *ase;
837 
838 	fileSystem->ReadFile( fileName, (void **)&buf, &timeStamp );
839 	if ( !buf ) {
840 		return NULL;
841 	}
842 
843 	ase = ASE_Parse( buf, false );
844 	ase->timeStamp = timeStamp;
845 
846 	fileSystem->FreeFile( buf );
847 
848 	return ase;
849 }
850 
851 /*
852 =================
853 ASE_Free
854 =================
855 */
ASE_Free(aseModel_t * ase)856 void ASE_Free( aseModel_t *ase ) {
857 	int					i, j;
858 	aseObject_t			*obj;
859 	aseMesh_t			*mesh;
860 	aseMaterial_t		*material;
861 
862 	if ( !ase ) {
863 		return;
864 	}
865 	for ( i = 0; i < ase->objects.Num(); i++ ) {
866 		obj = ase->objects[i];
867 		for ( j = 0; j < obj->frames.Num(); j++ ) {
868 			mesh = obj->frames[j];
869 			if ( mesh->vertexes ) {
870 				Mem_Free( mesh->vertexes );
871 			}
872 			if ( mesh->tvertexes ) {
873 				Mem_Free( mesh->tvertexes );
874 			}
875 			if ( mesh->cvertexes ) {
876 				Mem_Free( mesh->cvertexes );
877 			}
878 			if ( mesh->faces ) {
879 				Mem_Free( mesh->faces );
880 			}
881 			Mem_Free( mesh );
882 		}
883 
884 		obj->frames.Clear();
885 
886 		// free the base nesh
887 		mesh = &obj->mesh;
888 		if ( mesh->vertexes ) {
889 			Mem_Free( mesh->vertexes );
890 		}
891 		if ( mesh->tvertexes ) {
892 			Mem_Free( mesh->tvertexes );
893 		}
894 		if ( mesh->cvertexes ) {
895 			Mem_Free( mesh->cvertexes );
896 		}
897 		if ( mesh->faces ) {
898 			Mem_Free( mesh->faces );
899 		}
900 		Mem_Free( obj );
901 	}
902 	ase->objects.Clear();
903 
904 	for ( i = 0; i < ase->materials.Num(); i++ ) {
905 		material = ase->materials[i];
906 		Mem_Free( material );
907 	}
908 	ase->materials.Clear();
909 
910 	delete ase;
911 }
912