Model_ase.cpp (22799B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition 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 BFG Edition 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 #pragma hdrstop 30 #include "../idlib/precompiled.h" 31 32 33 #include "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 69 static aseMesh_t *ASE_GetCurrentMesh() 70 { 71 return ase.currentMesh; 72 } 73 74 static int CharIsTokenDelimiter( int ch ) 75 { 76 if ( ch <= 32 ) 77 return 1; 78 return 0; 79 } 80 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 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 144 static void ASE_SkipEnclosingBraces() 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 165 static void ASE_SkipRestOfLine() 166 { 167 ASE_GetToken( true ); 168 } 169 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 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 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 ), TAG_MODEL ); 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 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 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 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 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 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 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 const int maxLength = 80; 425 char u[maxLength], v[maxLength], w[maxLength]; 426 427 ASE_GetToken( false ); 428 429 ASE_GetToken( false ); 430 strncpy( u, ase.token, maxLength ); u[maxLength-1] = '\0'; 431 432 ASE_GetToken( false ); 433 strncpy( v, ase.token, maxLength ); v[maxLength-1] = '\0'; 434 435 ASE_GetToken( false ); 436 strncpy( w, ase.token, maxLength ); w[maxLength-1] = '\0'; 437 438 pMesh->tvertexes[ase.currentVertex].x = atof( u ); 439 // our OpenGL second texture axis is inverted from MAX's sense 440 pMesh->tvertexes[ase.currentVertex].y = 1.0f - atof( v ); 441 442 ase.currentVertex++; 443 444 if ( ase.currentVertex > pMesh->numTVertexes ) 445 { 446 common->Error( "ase.currentVertex > pMesh->numTVertexes" ); 447 } 448 } 449 else 450 { 451 common->Error( "Unknown token '%s' while parsing MESH_TVERTLIST", token ); 452 } 453 } 454 455 static void ASE_KeyMESH_CVERTLIST( const char *token ) 456 { 457 aseMesh_t *pMesh = ASE_GetCurrentMesh(); 458 459 pMesh->colorsParsed = true; 460 461 if ( !strcmp( token, "*MESH_VERTCOL" ) ) 462 { 463 ASE_GetToken( false ); 464 465 ASE_GetToken( false ); 466 pMesh->cvertexes[ase.currentVertex][0] = atof( token ); 467 468 ASE_GetToken( false ); 469 pMesh->cvertexes[ase.currentVertex][1] = atof( token ); 470 471 ASE_GetToken( false ); 472 pMesh->cvertexes[ase.currentVertex][2] = atof( token ); 473 474 ase.currentVertex++; 475 476 if ( ase.currentVertex > pMesh->numCVertexes ) 477 { 478 common->Error( "ase.currentVertex > pMesh->numCVertexes" ); 479 } 480 } 481 else { 482 common->Error( "Unknown token '%s' while parsing MESH_CVERTLIST", token ); 483 } 484 } 485 486 static void ASE_KeyMESH_NORMALS( const char *token ) 487 { 488 aseMesh_t *pMesh = ASE_GetCurrentMesh(); 489 aseFace_t *f; 490 idVec3 n; 491 492 pMesh->normalsParsed = true; 493 f = &pMesh->faces[ase.currentFace]; 494 495 if ( !strcmp( token, "*MESH_FACENORMAL" ) ) 496 { 497 int num; 498 499 ASE_GetToken( false ); 500 num = atoi( ase.token ); 501 502 if ( num >= pMesh->numFaces || num < 0 ) { 503 common->Error( "MESH_NORMALS face index out of range: %i", num ); 504 } 505 506 if ( num != ase.currentFace ) { 507 common->Error( "MESH_NORMALS face index != currentFace" ); 508 } 509 510 ASE_GetToken( false ); 511 n[0] = atof( ase.token ); 512 ASE_GetToken( false ); 513 n[1] = atof( ase.token ); 514 ASE_GetToken( false ); 515 n[2]= atof( ase.token ); 516 517 f->faceNormal[0] = n[0] * pMesh->transform[0][0] + n[1] * pMesh->transform[1][0] + n[2] * pMesh->transform[2][0]; 518 f->faceNormal[1] = n[0] * pMesh->transform[0][1] + n[1] * pMesh->transform[1][1] + n[2] * pMesh->transform[2][1]; 519 f->faceNormal[2] = n[0] * pMesh->transform[0][2] + n[1] * pMesh->transform[1][2] + n[2] * pMesh->transform[2][2]; 520 521 f->faceNormal.Normalize(); 522 523 ase.currentFace++; 524 } 525 else if ( !strcmp( token, "*MESH_VERTEXNORMAL" ) ) 526 { 527 int num; 528 int v; 529 530 ASE_GetToken( false ); 531 num = atoi( ase.token ); 532 533 if ( num >= pMesh->numVertexes || num < 0 ) { 534 common->Error( "MESH_NORMALS vertex index out of range: %i", num ); 535 } 536 537 f = &pMesh->faces[ ase.currentFace - 1 ]; 538 539 for ( v = 0 ; v < 3 ; v++ ) { 540 if ( num == f->vertexNum[ v ] ) { 541 break; 542 } 543 } 544 545 if ( v >= 3 ) { 546 common->Error( "MESH_NORMALS vertex index doesn't match face" ); 547 return; 548 } 549 550 ASE_GetToken( false ); 551 n[0] = atof( ase.token ); 552 ASE_GetToken( false ); 553 n[1] = atof( ase.token ); 554 ASE_GetToken( false ); 555 n[2]= atof( ase.token ); 556 557 f->vertexNormals[ v ][0] = n[0] * pMesh->transform[0][0] + n[1] * pMesh->transform[1][0] + n[2] * pMesh->transform[2][0]; 558 f->vertexNormals[ v ][1] = n[0] * pMesh->transform[0][1] + n[1] * pMesh->transform[1][1] + n[2] * pMesh->transform[2][1]; 559 f->vertexNormals[ v ][2] = n[0] * pMesh->transform[0][2] + n[1] * pMesh->transform[1][2] + n[2] * pMesh->transform[2][2]; 560 561 f->vertexNormals[v].Normalize(); 562 } 563 } 564 565 static void ASE_KeyMESH( const char *token ) 566 { 567 aseMesh_t *pMesh = ASE_GetCurrentMesh(); 568 569 if ( !strcmp( token, "*TIMEVALUE" ) ) 570 { 571 ASE_GetToken( false ); 572 573 pMesh->timeValue = atoi( ase.token ); 574 VERBOSE( ( ".....timevalue: %d\n", pMesh->timeValue ) ); 575 } 576 else if ( !strcmp( token, "*MESH_NUMVERTEX" ) ) 577 { 578 ASE_GetToken( false ); 579 580 pMesh->numVertexes = atoi( ase.token ); 581 VERBOSE( ( ".....num vertexes: %d\n", pMesh->numVertexes ) ); 582 } 583 else if ( !strcmp( token, "*MESH_NUMTVERTEX" ) ) 584 { 585 ASE_GetToken( false ); 586 587 pMesh->numTVertexes = atoi( ase.token ); 588 VERBOSE( ( ".....num tvertexes: %d\n", pMesh->numTVertexes ) ); 589 } 590 else if ( !strcmp( token, "*MESH_NUMCVERTEX" ) ) 591 { 592 ASE_GetToken( false ); 593 594 pMesh->numCVertexes = atoi( ase.token ); 595 VERBOSE( ( ".....num cvertexes: %d\n", pMesh->numCVertexes ) ); 596 } 597 else if ( !strcmp( token, "*MESH_NUMFACES" ) ) 598 { 599 ASE_GetToken( false ); 600 601 pMesh->numFaces = atoi( ase.token ); 602 VERBOSE( ( ".....num faces: %d\n", pMesh->numFaces ) ); 603 } 604 else if ( !strcmp( token, "*MESH_NUMTVFACES" ) ) 605 { 606 ASE_GetToken( false ); 607 608 pMesh->numTVFaces = atoi( ase.token ); 609 VERBOSE( ( ".....num tvfaces: %d\n", pMesh->numTVFaces ) ); 610 611 if ( pMesh->numTVFaces != pMesh->numFaces ) 612 { 613 common->Error( "MESH_NUMTVFACES != MESH_NUMFACES" ); 614 } 615 } 616 else if ( !strcmp( token, "*MESH_NUMCVFACES" ) ) 617 { 618 ASE_GetToken( false ); 619 620 pMesh->numCVFaces = atoi( ase.token ); 621 VERBOSE( ( ".....num cvfaces: %d\n", pMesh->numCVFaces ) ); 622 623 if ( pMesh->numTVFaces != pMesh->numFaces ) 624 { 625 common->Error( "MESH_NUMCVFACES != MESH_NUMFACES" ); 626 } 627 } 628 else if ( !strcmp( token, "*MESH_VERTEX_LIST" ) ) 629 { 630 pMesh->vertexes = (idVec3 *)Mem_Alloc( sizeof( idVec3 ) * pMesh->numVertexes, TAG_MODEL ); 631 ase.currentVertex = 0; 632 VERBOSE( ( ".....parsing MESH_VERTEX_LIST\n" ) ); 633 ASE_ParseBracedBlock( ASE_KeyMESH_VERTEX_LIST ); 634 } 635 else if ( !strcmp( token, "*MESH_TVERTLIST" ) ) 636 { 637 ase.currentVertex = 0; 638 pMesh->tvertexes = (idVec2 *)Mem_Alloc( sizeof( idVec2 ) * pMesh->numTVertexes, TAG_MODEL ); 639 VERBOSE( ( ".....parsing MESH_TVERTLIST\n" ) ); 640 ASE_ParseBracedBlock( ASE_KeyMESH_TVERTLIST ); 641 } 642 else if ( !strcmp( token, "*MESH_CVERTLIST" ) ) 643 { 644 ase.currentVertex = 0; 645 pMesh->cvertexes = (idVec3 *)Mem_Alloc( sizeof( idVec3 ) * pMesh->numCVertexes, TAG_MODEL ); 646 VERBOSE( ( ".....parsing MESH_CVERTLIST\n" ) ); 647 ASE_ParseBracedBlock( ASE_KeyMESH_CVERTLIST ); 648 } 649 else if ( !strcmp( token, "*MESH_FACE_LIST" ) ) 650 { 651 pMesh->faces = (aseFace_t *)Mem_Alloc( sizeof( aseFace_t ) * pMesh->numFaces, TAG_MODEL ); 652 ase.currentFace = 0; 653 VERBOSE( ( ".....parsing MESH_FACE_LIST\n" ) ); 654 ASE_ParseBracedBlock( ASE_KeyMESH_FACE_LIST ); 655 } 656 else if ( !strcmp( token, "*MESH_TFACELIST" ) ) 657 { 658 if ( !pMesh->faces ) { 659 common->Error( "*MESH_TFACELIST before *MESH_FACE_LIST" ); 660 } 661 ase.currentFace = 0; 662 VERBOSE( ( ".....parsing MESH_TFACE_LIST\n" ) ); 663 ASE_ParseBracedBlock( ASE_KeyTFACE_LIST ); 664 } 665 else if ( !strcmp( token, "*MESH_CFACELIST" ) ) 666 { 667 if ( !pMesh->faces ) { 668 common->Error( "*MESH_CFACELIST before *MESH_FACE_LIST" ); 669 } 670 ase.currentFace = 0; 671 VERBOSE( ( ".....parsing MESH_CFACE_LIST\n" ) ); 672 ASE_ParseBracedBlock( ASE_KeyCFACE_LIST ); 673 } 674 else if ( !strcmp( token, "*MESH_NORMALS" ) ) 675 { 676 if ( !pMesh->faces ) { 677 common->Warning( "*MESH_NORMALS before *MESH_FACE_LIST" ); 678 } 679 ase.currentFace = 0; 680 VERBOSE( ( ".....parsing MESH_NORMALS\n" ) ); 681 ASE_ParseBracedBlock( ASE_KeyMESH_NORMALS ); 682 } 683 } 684 685 static void ASE_KeyMESH_ANIMATION( const char *token ) 686 { 687 aseMesh_t *mesh; 688 689 // loads a single animation frame 690 if ( !strcmp( token, "*MESH" ) ) 691 { 692 VERBOSE( ( "...found MESH\n" ) ); 693 694 mesh = (aseMesh_t *)Mem_Alloc( sizeof( aseMesh_t ), TAG_MODEL ); 695 memset( mesh, 0, sizeof( aseMesh_t ) ); 696 ase.currentMesh = mesh; 697 698 ase.currentObject->frames.Append( mesh ); 699 700 ASE_ParseBracedBlock( ASE_KeyMESH ); 701 } 702 else 703 { 704 common->Error( "Unknown token '%s' while parsing MESH_ANIMATION", token ); 705 } 706 } 707 708 static void ASE_KeyGEOMOBJECT( const char *token ) 709 { 710 aseObject_t *object; 711 712 object = ase.currentObject; 713 714 if ( !strcmp( token, "*NODE_NAME" ) ) 715 { 716 ASE_GetToken( true ); 717 VERBOSE( ( " %s\n", ase.token ) ); 718 idStr::Copynz( object->name, ase.token, sizeof( object->name ) ); 719 } 720 else if ( !strcmp( token, "*NODE_PARENT" ) ) 721 { 722 ASE_SkipRestOfLine(); 723 } 724 // ignore unused data blocks 725 else if ( !strcmp( token, "*NODE_TM" ) || 726 !strcmp( token, "*TM_ANIMATION" ) ) 727 { 728 ASE_ParseBracedBlock( ASE_KeyNODE_TM ); 729 } 730 // ignore regular meshes that aren't part of animation 731 else if ( !strcmp( token, "*MESH" ) ) 732 { 733 ase.currentMesh = &ase.currentObject->mesh; 734 idVec3 transforms[ 4 ]; 735 for ( int i = 0; i < 4; ++i ) { 736 transforms[ i ] = ase.currentMesh->transform[ i ]; 737 } 738 739 memset( ase.currentMesh, 0, sizeof( *ase.currentMesh ) ); 740 for ( int i = 0; i < 4; ++i ) { 741 ase.currentMesh->transform[ i ] = transforms[ i ]; 742 } 743 744 ASE_ParseBracedBlock( ASE_KeyMESH ); 745 } 746 // according to spec these are obsolete 747 else if ( !strcmp( token, "*MATERIAL_REF" ) ) 748 { 749 ASE_GetToken( false ); 750 751 object->materialRef = atoi( ase.token ); 752 } 753 // loads a sequence of animation frames 754 else if ( !strcmp( token, "*MESH_ANIMATION" ) ) 755 { 756 VERBOSE( ( "..found MESH_ANIMATION\n" ) ); 757 758 ASE_ParseBracedBlock( ASE_KeyMESH_ANIMATION ); 759 } 760 // skip unused info 761 else if ( !strcmp( token, "*PROP_MOTIONBLUR" ) || 762 !strcmp( token, "*PROP_CASTSHADOW" ) || 763 !strcmp( token, "*PROP_RECVSHADOW" ) ) 764 { 765 ASE_SkipRestOfLine(); 766 } 767 768 } 769 770 void ASE_ParseGeomObject() { 771 aseObject_t *object; 772 773 VERBOSE( ("GEOMOBJECT" ) ); 774 775 object = (aseObject_t *)Mem_Alloc( sizeof( aseObject_t ), TAG_MODEL ); 776 memset( object, 0, sizeof( aseObject_t ) ); 777 ase.model->objects.Append( object ); 778 ase.currentObject = object; 779 780 object->frames.Resize(32, 32); 781 782 ASE_ParseBracedBlock( ASE_KeyGEOMOBJECT ); 783 } 784 785 static void ASE_KeyGROUP( const char *token ) 786 { 787 if ( !strcmp( token, "*GEOMOBJECT" ) ) { 788 ASE_ParseGeomObject(); 789 } 790 } 791 792 /* 793 ================= 794 ASE_Parse 795 ================= 796 */ 797 aseModel_t *ASE_Parse( const char *buffer, bool verbose ) { 798 memset( &ase, 0, sizeof( ase ) ); 799 800 ase.verbose = verbose; 801 802 ase.buffer = buffer; 803 ase.len = strlen( buffer ); 804 ase.curpos = ase.buffer; 805 ase.currentObject = NULL; 806 807 // NOTE: using new operator because aseModel_t contains idList class objects 808 ase.model = new (TAG_MODEL) aseModel_t; 809 memset( ase.model, 0, sizeof( aseModel_t ) ); 810 ase.model->objects.Resize( 32, 32 ); 811 ase.model->materials.Resize( 32, 32 ); 812 813 while ( ASE_GetToken( false ) ) { 814 if ( !strcmp( ase.token, "*3DSMAX_ASCIIEXPORT" ) || 815 !strcmp( ase.token, "*COMMENT" ) ) { 816 ASE_SkipRestOfLine(); 817 } else if ( !strcmp( ase.token, "*SCENE" ) ) { 818 ASE_SkipEnclosingBraces(); 819 } else if ( !strcmp( ase.token, "*GROUP" ) ) { 820 ASE_GetToken( false ); // group name 821 ASE_ParseBracedBlock( ASE_KeyGROUP ); 822 } else if ( !strcmp( ase.token, "*SHAPEOBJECT" ) ) { 823 ASE_SkipEnclosingBraces(); 824 } else if ( !strcmp( ase.token, "*CAMERAOBJECT" ) ) { 825 ASE_SkipEnclosingBraces(); 826 } else if ( !strcmp( ase.token, "*MATERIAL_LIST" ) ) { 827 VERBOSE( ("MATERIAL_LIST\n") ); 828 829 ASE_ParseBracedBlock( ASE_KeyMATERIAL_LIST ); 830 } else if ( !strcmp( ase.token, "*GEOMOBJECT" ) ) { 831 ASE_ParseGeomObject(); 832 } else if ( ase.token[0] ) { 833 common->Printf( "Unknown token '%s'\n", ase.token ); 834 } 835 } 836 837 return ase.model; 838 } 839 840 /* 841 ================= 842 ASE_Load 843 ================= 844 */ 845 aseModel_t *ASE_Load( const char *fileName ) { 846 char *buf; 847 ID_TIME_T timeStamp; 848 aseModel_t *ase; 849 850 fileSystem->ReadFile( fileName, (void **)&buf, &timeStamp ); 851 if ( !buf ) { 852 return NULL; 853 } 854 855 ase = ASE_Parse( buf, false ); 856 ase->timeStamp = timeStamp; 857 858 fileSystem->FreeFile( buf ); 859 860 return ase; 861 } 862 863 /* 864 ================= 865 ASE_Free 866 ================= 867 */ 868 void ASE_Free( aseModel_t *ase ) { 869 int i, j; 870 aseObject_t *obj; 871 aseMesh_t *mesh; 872 aseMaterial_t *material; 873 874 if ( !ase ) { 875 return; 876 } 877 for ( i = 0; i < ase->objects.Num(); i++ ) { 878 obj = ase->objects[i]; 879 for ( j = 0; j < obj->frames.Num(); j++ ) { 880 mesh = obj->frames[j]; 881 if ( mesh->vertexes ) { 882 Mem_Free( mesh->vertexes ); 883 } 884 if ( mesh->tvertexes ) { 885 Mem_Free( mesh->tvertexes ); 886 } 887 if ( mesh->cvertexes ) { 888 Mem_Free( mesh->cvertexes ); 889 } 890 if ( mesh->faces ) { 891 Mem_Free( mesh->faces ); 892 } 893 Mem_Free( mesh ); 894 } 895 896 obj->frames.Clear(); 897 898 // free the base nesh 899 mesh = &obj->mesh; 900 if ( mesh->vertexes ) { 901 Mem_Free( mesh->vertexes ); 902 } 903 if ( mesh->tvertexes ) { 904 Mem_Free( mesh->tvertexes ); 905 } 906 if ( mesh->cvertexes ) { 907 Mem_Free( mesh->cvertexes ); 908 } 909 if ( mesh->faces ) { 910 Mem_Free( mesh->faces ); 911 } 912 Mem_Free( obj ); 913 } 914 ase->objects.Clear(); 915 916 for ( i = 0; i < ase->materials.Num(); i++ ) { 917 material = ase->materials[i]; 918 Mem_Free( material ); 919 } 920 ase->materials.Clear(); 921 922 delete ase; 923 }