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