Model_ma.cpp (28584B)
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 #include "Model_ma.h" 33 34 /* 35 ====================================================================== 36 37 Parses Maya ASCII files. 38 39 ====================================================================== 40 */ 41 42 43 #define MA_VERBOSE( x ) { if ( maGlobal.verbose ) { common->Printf x ; } } 44 45 // working variables used during parsing 46 typedef struct { 47 bool verbose; 48 maModel_t *model; 49 maObject_t *currentObject; 50 } ma_t; 51 52 static ma_t maGlobal; 53 54 55 void MA_ParseNodeHeader(idParser& parser, maNodeHeader_t* header) { 56 57 memset(header, 0, sizeof(maNodeHeader_t)); 58 59 idToken token; 60 while(parser.ReadToken(&token)) { 61 if(!token.Icmp("-")) { 62 parser.ReadToken(&token); 63 if (!token.Icmp("n")) { 64 parser.ReadToken(&token); 65 strcpy(header->name, token.c_str()); 66 } else if (!token.Icmp("p")) { 67 parser.ReadToken(&token); 68 strcpy(header->parent, token.c_str()); 69 } 70 } else if (!token.Icmp(";")) { 71 break; 72 } 73 } 74 } 75 76 bool MA_ParseHeaderIndex(maAttribHeader_t* header, int& minIndex, int& maxIndex, const char* headerType, const char* skipString) { 77 78 idParser miniParse; 79 idToken token; 80 81 miniParse.LoadMemory(header->name, strlen(header->name), headerType); 82 if(skipString) { 83 miniParse.SkipUntilString(skipString); 84 } 85 86 if(!miniParse.SkipUntilString("[")) { 87 //This was just a header 88 return false; 89 } 90 minIndex = miniParse.ParseInt(); 91 miniParse.ReadToken(&token); 92 if(!token.Icmp("]")) { 93 maxIndex = minIndex; 94 } else { 95 maxIndex = miniParse.ParseInt(); 96 } 97 return true; 98 } 99 100 bool MA_ParseAttribHeader(idParser &parser, maAttribHeader_t* header) { 101 102 idToken token; 103 104 memset(header, 0, sizeof(maAttribHeader_t)); 105 106 parser.ReadToken(&token); 107 if(!token.Icmp("-")) { 108 parser.ReadToken(&token); 109 if (!token.Icmp("s")) { 110 header->size = parser.ParseInt(); 111 parser.ReadToken(&token); 112 } 113 } 114 strcpy(header->name, token.c_str()); 115 return true; 116 } 117 118 bool MA_ReadVec3(idParser& parser, idVec3& vec) { 119 idToken token; 120 if(!parser.SkipUntilString("double3")) { 121 throw idException( va("Maya Loader '%s': Invalid Vec3", parser.GetFileName()) ); 122 } 123 124 125 //We need to flip y and z because of the maya coordinate system 126 vec.x = parser.ParseFloat(); 127 vec.z = parser.ParseFloat(); 128 vec.y = parser.ParseFloat(); 129 130 return true; 131 } 132 133 bool IsNodeComplete(idToken& token) { 134 if(!token.Icmp("createNode") || !token.Icmp("connectAttr") || !token.Icmp("select")) { 135 return true; 136 } 137 return false; 138 } 139 140 bool MA_ParseTransform(idParser& parser) { 141 142 maNodeHeader_t header; 143 maTransform_t* transform; 144 memset(&header, 0, sizeof(header)); 145 146 //Allocate room for the transform 147 transform = (maTransform_t *)Mem_Alloc( sizeof( maTransform_t ), TAG_MODEL ); 148 memset(transform, 0, sizeof(maTransform_t)); 149 transform->scale.x = transform->scale.y = transform->scale.z = 1; 150 151 //Get the header info from the transform 152 MA_ParseNodeHeader(parser, &header); 153 154 //Read the transform attributes 155 idToken token; 156 while(parser.ReadToken(&token)) { 157 if(IsNodeComplete(token)) { 158 parser.UnreadToken(&token); 159 break; 160 } 161 if(!token.Icmp("setAttr")) { 162 parser.ReadToken(&token); 163 if(!token.Icmp(".t")) { 164 if(!MA_ReadVec3(parser, transform->translate)) { 165 return false; 166 } 167 transform->translate.y *= -1; 168 } else if (!token.Icmp(".r")) { 169 if(!MA_ReadVec3(parser, transform->rotate)) { 170 return false; 171 } 172 } else if (!token.Icmp(".s")) { 173 if(!MA_ReadVec3(parser, transform->scale)) { 174 return false; 175 } 176 } else { 177 parser.SkipRestOfLine(); 178 } 179 } 180 } 181 182 if(header.parent[0] != 0) { 183 //Find the parent 184 maTransform_t** parent; 185 maGlobal.model->transforms.Get(header.parent, &parent); 186 if(parent) { 187 transform->parent = *parent; 188 } 189 } 190 191 //Add this transform to the list 192 maGlobal.model->transforms.Set(header.name, transform); 193 return true; 194 } 195 196 bool MA_ParseVertex(idParser& parser, maAttribHeader_t* header) { 197 198 maMesh_t* pMesh = &maGlobal.currentObject->mesh; 199 idToken token; 200 201 //Allocate enough space for all the verts if this is the first attribute for verticies 202 if(!pMesh->vertexes) { 203 pMesh->numVertexes = header->size; 204 pMesh->vertexes = (idVec3 *)Mem_Alloc( sizeof( idVec3 ) * pMesh->numVertexes, TAG_MODEL ); 205 } 206 207 //Get the start and end index for this attribute 208 int minIndex, maxIndex; 209 if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "VertexHeader", NULL)) { 210 //This was just a header 211 return true; 212 } 213 214 //Read each vert 215 for(int i = minIndex; i <= maxIndex; i++) { 216 pMesh->vertexes[i].x = parser.ParseFloat(); 217 pMesh->vertexes[i].z = parser.ParseFloat(); 218 pMesh->vertexes[i].y = -parser.ParseFloat(); 219 } 220 221 return true; 222 } 223 224 bool MA_ParseVertexTransforms(idParser& parser, maAttribHeader_t* header) { 225 226 maMesh_t* pMesh = &maGlobal.currentObject->mesh; 227 idToken token; 228 229 //Allocate enough space for all the verts if this is the first attribute for verticies 230 if(!pMesh->vertTransforms) { 231 if(header->size == 0) { 232 header->size = 1; 233 } 234 235 pMesh->numVertTransforms = header->size; 236 pMesh->vertTransforms = (idVec4 *)Mem_Alloc( sizeof( idVec4 ) * pMesh->numVertTransforms, TAG_MODEL ); 237 pMesh->nextVertTransformIndex = 0; 238 } 239 240 //Get the start and end index for this attribute 241 int minIndex, maxIndex; 242 if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "VertexTransformHeader", NULL)) { 243 //This was just a header 244 return true; 245 } 246 247 parser.ReadToken(&token); 248 if(!token.Icmp("-")) { 249 idToken tk2; 250 parser.ReadToken(&tk2); 251 if(!tk2.Icmp("type")) { 252 parser.SkipUntilString("float3"); 253 } else { 254 parser.UnreadToken(&tk2); 255 parser.UnreadToken(&token); 256 } 257 } else { 258 parser.UnreadToken(&token); 259 } 260 261 //Read each vert 262 for(int i = minIndex; i <= maxIndex; i++) { 263 pMesh->vertTransforms[pMesh->nextVertTransformIndex].x = parser.ParseFloat(); 264 pMesh->vertTransforms[pMesh->nextVertTransformIndex].z = parser.ParseFloat(); 265 pMesh->vertTransforms[pMesh->nextVertTransformIndex].y = -parser.ParseFloat(); 266 267 //w hold the vert index 268 pMesh->vertTransforms[pMesh->nextVertTransformIndex].w = i; 269 270 pMesh->nextVertTransformIndex++; 271 } 272 273 return true; 274 } 275 276 bool MA_ParseEdge(idParser& parser, maAttribHeader_t* header) { 277 278 maMesh_t* pMesh = &maGlobal.currentObject->mesh; 279 idToken token; 280 281 //Allocate enough space for all the verts if this is the first attribute for verticies 282 if(!pMesh->edges) { 283 pMesh->numEdges = header->size; 284 pMesh->edges = (idVec3 *)Mem_Alloc( sizeof( idVec3 ) * pMesh->numEdges, TAG_MODEL ); 285 } 286 287 //Get the start and end index for this attribute 288 int minIndex, maxIndex; 289 if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "EdgeHeader", NULL)) { 290 //This was just a header 291 return true; 292 } 293 294 //Read each vert 295 for(int i = minIndex; i <= maxIndex; i++) { 296 pMesh->edges[i].x = parser.ParseFloat(); 297 pMesh->edges[i].y = parser.ParseFloat(); 298 pMesh->edges[i].z = parser.ParseFloat(); 299 } 300 301 return true; 302 } 303 304 bool MA_ParseNormal(idParser& parser, maAttribHeader_t* header) { 305 306 maMesh_t* pMesh = &maGlobal.currentObject->mesh; 307 idToken token; 308 309 //Allocate enough space for all the verts if this is the first attribute for verticies 310 if(!pMesh->normals) { 311 pMesh->numNormals = header->size; 312 pMesh->normals = (idVec3 *)Mem_Alloc( sizeof( idVec3 ) * pMesh->numNormals, TAG_MODEL ); 313 } 314 315 //Get the start and end index for this attribute 316 int minIndex, maxIndex; 317 if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "NormalHeader", NULL)) { 318 //This was just a header 319 return true; 320 } 321 322 323 parser.ReadToken(&token); 324 if(!token.Icmp("-")) { 325 idToken tk2; 326 parser.ReadToken(&tk2); 327 if(!tk2.Icmp("type")) { 328 parser.SkipUntilString("float3"); 329 } else { 330 parser.UnreadToken(&tk2); 331 parser.UnreadToken(&token); 332 } 333 } else { 334 parser.UnreadToken(&token); 335 } 336 337 338 //Read each vert 339 for(int i = minIndex; i <= maxIndex; i++) { 340 pMesh->normals[i].x = parser.ParseFloat(); 341 342 //Adjust the normals for the change in coordinate systems 343 pMesh->normals[i].z = parser.ParseFloat(); 344 pMesh->normals[i].y = -parser.ParseFloat(); 345 346 pMesh->normals[i].Normalize(); 347 348 } 349 350 pMesh->normalsParsed = true; 351 pMesh->nextNormal = 0; 352 353 return true; 354 } 355 356 357 358 bool MA_ParseFace(idParser& parser, maAttribHeader_t* header) { 359 360 maMesh_t* pMesh = &maGlobal.currentObject->mesh; 361 idToken token; 362 363 //Allocate enough space for all the verts if this is the first attribute for verticies 364 if(!pMesh->faces) { 365 pMesh->numFaces = header->size; 366 pMesh->faces = (maFace_t *)Mem_Alloc( sizeof( maFace_t ) * pMesh->numFaces, TAG_MODEL ); 367 } 368 369 //Get the start and end index for this attribute 370 int minIndex, maxIndex; 371 if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "FaceHeader", NULL)) { 372 //This was just a header 373 return true; 374 } 375 376 //Read the face data 377 int currentFace = minIndex-1; 378 while(parser.ReadToken(&token)) { 379 if(IsNodeComplete(token)) { 380 parser.UnreadToken(&token); 381 break; 382 } 383 384 if(!token.Icmp("f")) { 385 int count = parser.ParseInt(); 386 if(count != 3) { 387 throw idException(va("Maya Loader '%s': Face is not a triangle.", parser.GetFileName())); 388 } 389 //Increment the face number because a new face always starts with an "f" token 390 currentFace++; 391 392 //We cannot reorder edges until later because the normal processing 393 //assumes the edges are in the original order 394 pMesh->faces[currentFace].edge[0] = parser.ParseInt(); 395 pMesh->faces[currentFace].edge[1] = parser.ParseInt(); 396 pMesh->faces[currentFace].edge[2] = parser.ParseInt(); 397 398 //Some more init stuff 399 pMesh->faces[currentFace].vertexColors[0] = pMesh->faces[currentFace].vertexColors[1] = pMesh->faces[currentFace].vertexColors[2] = -1; 400 401 } else if(!token.Icmp("mu")) { 402 int uvstIndex = parser.ParseInt(); uvstIndex; 403 int count = parser.ParseInt(); 404 if(count != 3) { 405 throw idException(va("Maya Loader '%s': Invalid texture coordinates.", parser.GetFileName())); 406 } 407 pMesh->faces[currentFace].tVertexNum[0] = parser.ParseInt(); 408 pMesh->faces[currentFace].tVertexNum[1] = parser.ParseInt(); 409 pMesh->faces[currentFace].tVertexNum[2] = parser.ParseInt(); 410 411 } else if(!token.Icmp("mf")) { 412 int count = parser.ParseInt(); 413 if(count != 3) { 414 throw idException(va("Maya Loader '%s': Invalid texture coordinates.", parser.GetFileName())); 415 } 416 pMesh->faces[currentFace].tVertexNum[0] = parser.ParseInt(); 417 pMesh->faces[currentFace].tVertexNum[1] = parser.ParseInt(); 418 pMesh->faces[currentFace].tVertexNum[2] = parser.ParseInt(); 419 420 } else if(!token.Icmp("fc")) { 421 422 int count = parser.ParseInt(); 423 if(count != 3) { 424 throw idException(va("Maya Loader '%s': Invalid vertex color.", parser.GetFileName())); 425 } 426 pMesh->faces[currentFace].vertexColors[0] = parser.ParseInt(); 427 pMesh->faces[currentFace].vertexColors[1] = parser.ParseInt(); 428 pMesh->faces[currentFace].vertexColors[2] = parser.ParseInt(); 429 430 } 431 } 432 433 return true; 434 } 435 436 bool MA_ParseColor(idParser& parser, maAttribHeader_t* header) { 437 438 maMesh_t* pMesh = &maGlobal.currentObject->mesh; 439 idToken token; 440 441 //Allocate enough space for all the verts if this is the first attribute for verticies 442 if(!pMesh->colors) { 443 pMesh->numColors = header->size; 444 pMesh->colors = (byte *)Mem_Alloc( sizeof( byte ) * pMesh->numColors * 4, TAG_MODEL ); 445 } 446 447 //Get the start and end index for this attribute 448 int minIndex, maxIndex; 449 if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "ColorHeader", NULL)) { 450 //This was just a header 451 return true; 452 } 453 454 //Read each vert 455 for(int i = minIndex; i <= maxIndex; i++) { 456 pMesh->colors[i*4] = parser.ParseFloat() * 255; 457 pMesh->colors[i*4+1] = parser.ParseFloat() * 255; 458 pMesh->colors[i*4+2] = parser.ParseFloat() * 255; 459 pMesh->colors[i*4+3] = parser.ParseFloat() * 255; 460 } 461 462 return true; 463 } 464 465 bool MA_ParseTVert(idParser& parser, maAttribHeader_t* header) { 466 467 maMesh_t* pMesh = &maGlobal.currentObject->mesh; 468 idToken token; 469 470 //This is not the texture coordinates. It is just the name so ignore it 471 if(strstr(header->name, "uvsn")) { 472 return true; 473 } 474 475 //Allocate enough space for all the data 476 if(!pMesh->tvertexes) { 477 pMesh->numTVertexes = header->size; 478 pMesh->tvertexes = (idVec2 *)Mem_Alloc( sizeof( idVec2 ) * pMesh->numTVertexes, TAG_MODEL ); 479 } 480 481 //Get the start and end index for this attribute 482 int minIndex, maxIndex; 483 if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "TextureCoordHeader", "uvsp")) { 484 //This was just a header 485 return true; 486 } 487 488 parser.ReadToken(&token); 489 if(!token.Icmp("-")) { 490 idToken tk2; 491 parser.ReadToken(&tk2); 492 if(!tk2.Icmp("type")) { 493 parser.SkipUntilString("float2"); 494 } else { 495 parser.UnreadToken(&tk2); 496 parser.UnreadToken(&token); 497 } 498 } else { 499 parser.UnreadToken(&token); 500 } 501 502 //Read each tvert 503 for(int i = minIndex; i <= maxIndex; i++) { 504 pMesh->tvertexes[i].x = parser.ParseFloat(); 505 pMesh->tvertexes[i].y = 1.0f - parser.ParseFloat(); 506 } 507 508 return true; 509 } 510 511 512 513 /* 514 * Quick check to see if the vert participates in a shared normal 515 */ 516 bool MA_QuickIsVertShared(int faceIndex, int vertIndex) { 517 518 maMesh_t* pMesh = &maGlobal.currentObject->mesh; 519 int vertNum = pMesh->faces[faceIndex].vertexNum[vertIndex]; 520 521 for( int i = 0; i < 3; i++) { 522 int edge = pMesh->faces[faceIndex].edge[i]; 523 if(edge < 0) { 524 edge = idMath::Fabs(edge)-1; 525 } 526 if(pMesh->edges[edge].z == 1 && (pMesh->edges[edge].x == vertNum || pMesh->edges[edge].y == vertNum)) { 527 return true; 528 } 529 } 530 return false; 531 } 532 533 void MA_GetSharedFace(int faceIndex, int vertIndex, int& sharedFace, int& sharedVert) { 534 535 maMesh_t* pMesh = &maGlobal.currentObject->mesh; 536 int vertNum = pMesh->faces[faceIndex].vertexNum[vertIndex]; 537 538 sharedFace = -1; 539 sharedVert = -1; 540 541 //Find a shared edge on this face that contains the specified vert 542 for(int edgeIndex = 0; edgeIndex < 3; edgeIndex++) { 543 544 int edge = pMesh->faces[faceIndex].edge[edgeIndex]; 545 if(edge < 0) { 546 edge = idMath::Fabs(edge)-1; 547 } 548 549 if(pMesh->edges[edge].z == 1 && (pMesh->edges[edge].x == vertNum || pMesh->edges[edge].y == vertNum)) { 550 551 for(int i = 0; i < faceIndex; i++) { 552 553 for(int j = 0; j < 3; j++) { 554 if(pMesh->faces[i].vertexNum[j] == vertNum) { 555 sharedFace = i; 556 sharedVert = j; 557 break; 558 } 559 } 560 } 561 } 562 if(sharedFace != -1) 563 break; 564 565 } 566 } 567 568 void MA_ParseMesh(idParser& parser) { 569 570 maObject_t *object; 571 object = (maObject_t *)Mem_Alloc( sizeof( maObject_t ), TAG_MODEL ); 572 memset( object, 0, sizeof( maObject_t ) ); 573 maGlobal.model->objects.Append( object ); 574 maGlobal.currentObject = object; 575 object->materialRef = -1; 576 577 578 //Get the header info from the mesh 579 maNodeHeader_t header; 580 MA_ParseNodeHeader(parser, &header); 581 582 //Find my parent 583 if(header.parent[0] != 0) { 584 //Find the parent 585 maTransform_t** parent; 586 maGlobal.model->transforms.Get(header.parent, &parent); 587 if(parent) { 588 maGlobal.currentObject->mesh.transform = *parent; 589 } 590 } 591 592 strcpy(object->name, header.name); 593 594 //Read the transform attributes 595 idToken token; 596 while(parser.ReadToken(&token)) { 597 if(IsNodeComplete(token)) { 598 parser.UnreadToken(&token); 599 break; 600 } 601 if(!token.Icmp("setAttr")) { 602 maAttribHeader_t header; 603 MA_ParseAttribHeader(parser, &header); 604 605 if(strstr(header.name, ".vt")) { 606 MA_ParseVertex(parser, &header); 607 } else if (strstr(header.name, ".ed")) { 608 MA_ParseEdge(parser, &header); 609 } else if (strstr(header.name, ".pt")) { 610 MA_ParseVertexTransforms(parser, &header); 611 } else if (strstr(header.name, ".n")) { 612 MA_ParseNormal(parser, &header); 613 } else if (strstr(header.name, ".fc")) { 614 MA_ParseFace(parser, &header); 615 } else if (strstr(header.name, ".clr")) { 616 MA_ParseColor(parser, &header); 617 } else if (strstr(header.name, ".uvst")) { 618 MA_ParseTVert(parser, &header); 619 } else { 620 parser.SkipRestOfLine(); 621 } 622 } 623 } 624 625 626 maMesh_t* pMesh = &maGlobal.currentObject->mesh; 627 628 //Get the verts from the edge 629 for(int i = 0; i < pMesh->numFaces; i++) { 630 for(int j = 0; j < 3; j++) { 631 int edge = pMesh->faces[i].edge[j]; 632 if(edge < 0) { 633 edge = idMath::Fabs(edge)-1; 634 pMesh->faces[i].vertexNum[j] = pMesh->edges[edge].y; 635 } else { 636 pMesh->faces[i].vertexNum[j] = pMesh->edges[edge].x; 637 } 638 } 639 } 640 641 //Get the normals 642 if(pMesh->normalsParsed) { 643 for(int i = 0; i < pMesh->numFaces; i++) { 644 for(int j = 0; j < 3; j++) { 645 646 //Is this vertex shared 647 int sharedFace = -1; 648 int sharedVert = -1; 649 650 if(MA_QuickIsVertShared(i, j)) { 651 MA_GetSharedFace(i, j, sharedFace, sharedVert); 652 } 653 654 if(sharedFace != -1) { 655 //Get the normal from the share 656 pMesh->faces[i].vertexNormals[j] = pMesh->faces[sharedFace].vertexNormals[sharedVert]; 657 658 } else { 659 //The vertex is not shared so get the next normal 660 if(pMesh->nextNormal >= pMesh->numNormals) { 661 //We are using more normals than exist 662 throw idException(va("Maya Loader '%s': Invalid Normals Index.", parser.GetFileName())); 663 } 664 pMesh->faces[i].vertexNormals[j] = pMesh->normals[pMesh->nextNormal]; 665 pMesh->nextNormal++; 666 } 667 } 668 } 669 } 670 671 //Now that the normals are good...lets reorder the verts to make the tris face the right way 672 for(int i = 0; i < pMesh->numFaces; i++) { 673 int tmp = pMesh->faces[i].vertexNum[1]; 674 pMesh->faces[i].vertexNum[1] = pMesh->faces[i].vertexNum[2]; 675 pMesh->faces[i].vertexNum[2] = tmp; 676 677 idVec3 tmpVec = pMesh->faces[i].vertexNormals[1]; 678 pMesh->faces[i].vertexNormals[1] = pMesh->faces[i].vertexNormals[2]; 679 pMesh->faces[i].vertexNormals[2] = tmpVec; 680 681 tmp = pMesh->faces[i].tVertexNum[1]; 682 pMesh->faces[i].tVertexNum[1] = pMesh->faces[i].tVertexNum[2]; 683 pMesh->faces[i].tVertexNum[2] = tmp; 684 685 tmp = pMesh->faces[i].vertexColors[1]; 686 pMesh->faces[i].vertexColors[1] = pMesh->faces[i].vertexColors[2]; 687 pMesh->faces[i].vertexColors[2] = tmp; 688 } 689 690 //Now apply the pt transformations 691 for(int i = 0; i < pMesh->numVertTransforms; i++) { 692 pMesh->vertexes[(int)pMesh->vertTransforms[i].w] += pMesh->vertTransforms[i].ToVec3(); 693 } 694 695 MA_VERBOSE((va("MESH %s - parent %s\n", header.name, header.parent))); 696 MA_VERBOSE((va("\tverts:%d\n",maGlobal.currentObject->mesh.numVertexes))); 697 MA_VERBOSE((va("\tfaces:%d\n",maGlobal.currentObject->mesh.numFaces))); 698 } 699 700 void MA_ParseFileNode(idParser& parser) { 701 702 //Get the header info from the node 703 maNodeHeader_t header; 704 MA_ParseNodeHeader(parser, &header); 705 706 //Read the transform attributes 707 idToken token; 708 while(parser.ReadToken(&token)) { 709 if(IsNodeComplete(token)) { 710 parser.UnreadToken(&token); 711 break; 712 } 713 if(!token.Icmp("setAttr")) { 714 maAttribHeader_t attribHeader; 715 MA_ParseAttribHeader(parser, &attribHeader); 716 717 if(strstr(attribHeader.name, ".ftn")) { 718 parser.SkipUntilString("string"); 719 parser.ReadToken(&token); 720 if(!token.Icmp("(")) { 721 parser.ReadToken(&token); 722 } 723 724 maFileNode_t* fileNode; 725 fileNode = (maFileNode_t*)Mem_Alloc( sizeof( maFileNode_t ), TAG_MODEL ); 726 strcpy(fileNode->name, header.name); 727 strcpy(fileNode->path, token.c_str()); 728 729 maGlobal.model->fileNodes.Set(fileNode->name, fileNode); 730 } else { 731 parser.SkipRestOfLine(); 732 } 733 } 734 } 735 } 736 737 void MA_ParseMaterialNode(idParser& parser) { 738 739 //Get the header info from the node 740 maNodeHeader_t header; 741 MA_ParseNodeHeader(parser, &header); 742 743 maMaterialNode_t* matNode; 744 matNode = (maMaterialNode_t*)Mem_Alloc( sizeof( maMaterialNode_t ), TAG_MODEL ); 745 memset(matNode, 0, sizeof(maMaterialNode_t)); 746 747 strcpy(matNode->name, header.name); 748 749 maGlobal.model->materialNodes.Set(matNode->name, matNode); 750 } 751 752 void MA_ParseCreateNode(idParser& parser) { 753 754 idToken token; 755 parser.ReadToken(&token); 756 757 if(!token.Icmp("transform")) { 758 MA_ParseTransform(parser); 759 } else if(!token.Icmp("mesh")) { 760 MA_ParseMesh(parser); 761 } else if(!token.Icmp("file")) { 762 MA_ParseFileNode(parser); 763 } else if(!token.Icmp("shadingEngine") || !token.Icmp("lambert") || !token.Icmp("phong") || !token.Icmp("blinn") ) { 764 MA_ParseMaterialNode(parser); 765 } 766 } 767 768 769 int MA_AddMaterial(const char* materialName) { 770 771 772 maMaterialNode_t** destNode; 773 maGlobal.model->materialNodes.Get(materialName, &destNode); 774 if(destNode) { 775 maMaterialNode_t* matNode = *destNode; 776 777 //Iterate down the tree until we get a file 778 while(matNode && !matNode->file) { 779 matNode = matNode->child; 780 } 781 if(matNode && matNode->file) { 782 783 //Got the file 784 maMaterial_t *material; 785 material = (maMaterial_t *)Mem_Alloc( sizeof( maMaterial_t ), TAG_MODEL ); 786 memset( material, 0, sizeof( maMaterial_t ) ); 787 788 //Remove the OS stuff 789 idStr qPath; 790 qPath = fileSystem->OSPathToRelativePath( matNode->file->path ); 791 792 strcpy(material->name, qPath.c_str()); 793 794 maGlobal.model->materials.Append( material ); 795 return maGlobal.model->materials.Num()-1; 796 } 797 } 798 return -1; 799 } 800 801 bool MA_ParseConnectAttr(idParser& parser) { 802 803 idStr temp; 804 idStr srcName; 805 idStr srcType; 806 idStr destName; 807 idStr destType; 808 809 idToken token; 810 parser.ReadToken(&token); 811 temp = token; 812 int dot = temp.Find("."); 813 if(dot == -1) { 814 throw idException(va("Maya Loader '%s': Invalid Connect Attribute.", parser.GetFileName())); 815 } 816 srcName = temp.Left(dot); 817 srcType = temp.Right(temp.Length()-dot-1); 818 819 parser.ReadToken(&token); 820 temp = token; 821 dot = temp.Find("."); 822 if(dot == -1) { 823 throw idException(va("Maya Loader '%s': Invalid Connect Attribute.", parser.GetFileName())); 824 } 825 destName = temp.Left(dot); 826 destType = temp.Right(temp.Length()-dot-1); 827 828 if(srcType.Find("oc") != -1) { 829 830 //Is this attribute a material node attribute 831 maMaterialNode_t** matNode; 832 maGlobal.model->materialNodes.Get(srcName, &matNode); 833 if(matNode) { 834 maMaterialNode_t** destNode; 835 maGlobal.model->materialNodes.Get(destName, &destNode); 836 if(destNode) { 837 (*destNode)->child = *matNode; 838 } 839 } 840 841 //Is this attribute a file node 842 maFileNode_t** fileNode; 843 maGlobal.model->fileNodes.Get(srcName, &fileNode); 844 if(fileNode) { 845 maMaterialNode_t** destNode; 846 maGlobal.model->materialNodes.Get(destName, &destNode); 847 if(destNode) { 848 (*destNode)->file = *fileNode; 849 } 850 } 851 } 852 853 if(srcType.Find("iog") != -1) { 854 //Is this an attribute for one of our meshes 855 for(int i = 0; i < maGlobal.model->objects.Num(); i++) { 856 if(!strcmp(maGlobal.model->objects[i]->name, srcName)) { 857 //maGlobal.model->objects[i]->materialRef = MA_AddMaterial(destName); 858 strcpy(maGlobal.model->objects[i]->materialName, destName); 859 break; 860 } 861 } 862 } 863 864 return true; 865 } 866 867 868 void MA_BuildScale(idMat4& mat, float x, float y, float z) { 869 mat.Identity(); 870 mat[0][0] = x; 871 mat[1][1] = y; 872 mat[2][2] = z; 873 } 874 875 void MA_BuildAxisRotation(idMat4& mat, float ang, int axis) { 876 877 float sinAng = idMath::Sin(ang); 878 float cosAng = idMath::Cos(ang); 879 880 mat.Identity(); 881 switch(axis) { 882 case 0: //x 883 mat[1][1] = cosAng; 884 mat[1][2] = sinAng; 885 mat[2][1] = -sinAng; 886 mat[2][2] = cosAng; 887 break; 888 case 1: //y 889 mat[0][0] = cosAng; 890 mat[0][2] = -sinAng; 891 mat[2][0] = sinAng; 892 mat[2][2] = cosAng; 893 break; 894 case 2://z 895 mat[0][0] = cosAng; 896 mat[0][1] = sinAng; 897 mat[1][0] = -sinAng; 898 mat[1][1] = cosAng; 899 break; 900 } 901 } 902 903 void MA_ApplyTransformation(maModel_t *model) { 904 905 for(int i = 0; i < model->objects.Num(); i++) { 906 maMesh_t* mesh = &model->objects[i]->mesh; 907 maTransform_t* transform = mesh->transform; 908 909 910 911 while(transform) { 912 913 idMat4 rotx, roty, rotz; 914 idMat4 scale; 915 916 rotx.Identity(); 917 roty.Identity(); 918 rotz.Identity(); 919 920 if(fabs(transform->rotate.x) > 0.0f) { 921 MA_BuildAxisRotation(rotx, DEG2RAD(-transform->rotate.x), 0); 922 } 923 if(fabs(transform->rotate.y) > 0.0f) { 924 MA_BuildAxisRotation(roty, DEG2RAD(transform->rotate.y), 1); 925 } 926 if(fabs(transform->rotate.z) > 0.0f) { 927 MA_BuildAxisRotation(rotz, DEG2RAD(-transform->rotate.z), 2); 928 } 929 930 MA_BuildScale(scale, transform->scale.x, transform->scale.y, transform->scale.z); 931 932 //Apply the transformation to each vert 933 for(int j = 0; j < mesh->numVertexes; j++) { 934 mesh->vertexes[j] = scale * mesh->vertexes[j]; 935 936 mesh->vertexes[j] = rotx * mesh->vertexes[j]; 937 mesh->vertexes[j] = rotz * mesh->vertexes[j]; 938 mesh->vertexes[j] = roty * mesh->vertexes[j]; 939 940 mesh->vertexes[j] = mesh->vertexes[j] + transform->translate; 941 } 942 943 transform = transform->parent; 944 } 945 } 946 } 947 948 /* 949 ================= 950 MA_Parse 951 ================= 952 */ 953 maModel_t *MA_Parse( const char *buffer, const char* filename, bool verbose ) { 954 memset( &maGlobal, 0, sizeof( maGlobal ) ); 955 956 maGlobal.verbose = verbose; 957 958 959 960 961 maGlobal.currentObject = NULL; 962 963 // NOTE: using new operator because aseModel_t contains idList class objects 964 maGlobal.model = new (TAG_MODEL) maModel_t; 965 maGlobal.model->objects.Resize( 32, 32 ); 966 maGlobal.model->materials.Resize( 32, 32 ); 967 968 969 idParser parser; 970 parser.SetFlags(LEXFL_NOSTRINGCONCAT); 971 parser.LoadMemory(buffer, strlen(buffer), filename); 972 973 idToken token; 974 while(parser.ReadToken(&token)) { 975 976 if(!token.Icmp("createNode")) { 977 MA_ParseCreateNode(parser); 978 } else if(!token.Icmp("connectAttr")) { 979 MA_ParseConnectAttr(parser); 980 } 981 } 982 983 //Resolve The Materials 984 for(int i = 0; i < maGlobal.model->objects.Num(); i++) { 985 maGlobal.model->objects[i]->materialRef = MA_AddMaterial(maGlobal.model->objects[i]->materialName); 986 } 987 988 989 990 //Apply Transformation 991 MA_ApplyTransformation(maGlobal.model); 992 993 return maGlobal.model; 994 } 995 996 /* 997 ================= 998 MA_Load 999 ================= 1000 */ 1001 maModel_t *MA_Load( const char *fileName ) { 1002 char *buf; 1003 ID_TIME_T timeStamp; 1004 maModel_t *ma; 1005 1006 fileSystem->ReadFile( fileName, (void **)&buf, &timeStamp ); 1007 if ( !buf ) { 1008 return NULL; 1009 } 1010 1011 try { 1012 ma = MA_Parse( buf, fileName, false ); 1013 ma->timeStamp = timeStamp; 1014 } catch( idException &e ) { 1015 common->Warning("%s", e.GetError()); 1016 if(maGlobal.model) { 1017 MA_Free(maGlobal.model); 1018 } 1019 ma = NULL; 1020 } 1021 1022 fileSystem->FreeFile( buf ); 1023 1024 return ma; 1025 } 1026 1027 /* 1028 ================= 1029 MA_Free 1030 ================= 1031 */ 1032 void MA_Free( maModel_t *ma ) { 1033 int i; 1034 maObject_t *obj; 1035 maMesh_t *mesh; 1036 maMaterial_t *material; 1037 1038 if ( !ma ) { 1039 return; 1040 } 1041 for ( i = 0; i < ma->objects.Num(); i++ ) { 1042 obj = ma->objects[i]; 1043 1044 // free the base nesh 1045 mesh = &obj->mesh; 1046 1047 if ( mesh->vertexes ) { 1048 Mem_Free( mesh->vertexes ); 1049 } 1050 if ( mesh->vertTransforms ) { 1051 Mem_Free( mesh->vertTransforms ); 1052 } 1053 if ( mesh->normals ) { 1054 Mem_Free( mesh->normals ); 1055 } 1056 if ( mesh->tvertexes ) { 1057 Mem_Free( mesh->tvertexes ); 1058 } 1059 if ( mesh->edges ) { 1060 Mem_Free( mesh->edges ); 1061 } 1062 if ( mesh->colors ) { 1063 Mem_Free( mesh->colors ); 1064 } 1065 if ( mesh->faces ) { 1066 Mem_Free( mesh->faces ); 1067 } 1068 Mem_Free( obj ); 1069 } 1070 ma->objects.Clear(); 1071 1072 for ( i = 0; i < ma->materials.Num(); i++ ) { 1073 material = ma->materials[i]; 1074 Mem_Free( material ); 1075 } 1076 ma->materials.Clear(); 1077 1078 maTransform_t** trans; 1079 for ( i = 0; i < ma->transforms.Num(); i++ ) { 1080 trans = ma->transforms.GetIndex(i); 1081 Mem_Free( *trans ); 1082 } 1083 ma->transforms.Clear(); 1084 1085 1086 maFileNode_t** fileNode; 1087 for ( i = 0; i < ma->fileNodes.Num(); i++ ) { 1088 fileNode = ma->fileNodes.GetIndex(i); 1089 Mem_Free( *fileNode ); 1090 } 1091 ma->fileNodes.Clear(); 1092 1093 maMaterialNode_t** matNode; 1094 for ( i = 0; i < ma->materialNodes.Num(); i++ ) { 1095 matNode = ma->materialNodes.GetIndex(i); 1096 Mem_Free( *matNode ); 1097 } 1098 ma->materialNodes.Clear(); 1099 delete ma; 1100 }