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