1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- #include "Model_ma.h"
- /*
- ======================================================================
- Parses Maya ASCII files.
- ======================================================================
- */
-
- #define MA_VERBOSE( x ) { if ( maGlobal.verbose ) { common->Printf x ; } }
- // working variables used during parsing
- typedef struct {
- bool verbose;
- maModel_t *model;
- maObject_t *currentObject;
- } ma_t;
- static ma_t maGlobal;
- void MA_ParseNodeHeader(idParser& parser, maNodeHeader_t* header) {
- memset(header, 0, sizeof(maNodeHeader_t));
- idToken token;
- while(parser.ReadToken(&token)) {
- if(!token.Icmp("-")) {
- parser.ReadToken(&token);
- if (!token.Icmp("n")) {
- parser.ReadToken(&token);
- strcpy(header->name, token.c_str());
- } else if (!token.Icmp("p")) {
- parser.ReadToken(&token);
- strcpy(header->parent, token.c_str());
- }
- } else if (!token.Icmp(";")) {
- break;
- }
- }
- }
- bool MA_ParseHeaderIndex(maAttribHeader_t* header, int& minIndex, int& maxIndex, const char* headerType, const char* skipString) {
-
- idParser miniParse;
- idToken token;
- miniParse.LoadMemory(header->name, strlen(header->name), headerType);
- if(skipString) {
- miniParse.SkipUntilString(skipString);
- }
- if(!miniParse.SkipUntilString("[")) {
- //This was just a header
- return false;
- }
- minIndex = miniParse.ParseInt();
- miniParse.ReadToken(&token);
- if(!token.Icmp("]")) {
- maxIndex = minIndex;
- } else {
- maxIndex = miniParse.ParseInt();
- }
- return true;
- }
- bool MA_ParseAttribHeader(idParser &parser, maAttribHeader_t* header) {
-
- idToken token;
- memset(header, 0, sizeof(maAttribHeader_t));
- parser.ReadToken(&token);
- if(!token.Icmp("-")) {
- parser.ReadToken(&token);
- if (!token.Icmp("s")) {
- header->size = parser.ParseInt();
- parser.ReadToken(&token);
- }
- }
- strcpy(header->name, token.c_str());
- return true;
- }
- bool MA_ReadVec3(idParser& parser, idVec3& vec) {
- idToken token;
- if(!parser.SkipUntilString("double3")) {
- throw idException( va("Maya Loader '%s': Invalid Vec3", parser.GetFileName()) );
- return false;
- }
- //We need to flip y and z because of the maya coordinate system
- vec.x = parser.ParseFloat();
- vec.z = parser.ParseFloat();
- vec.y = parser.ParseFloat();
- return true;
- }
- bool IsNodeComplete(idToken& token) {
- if(!token.Icmp("createNode") || !token.Icmp("connectAttr") || !token.Icmp("select")) {
- return true;
- }
- return false;
- }
- bool MA_ParseTransform(idParser& parser) {
- maNodeHeader_t header;
- maTransform_t* transform;
- memset(&header, 0, sizeof(header));
- //Allocate room for the transform
- transform = (maTransform_t *)Mem_Alloc( sizeof( maTransform_t ) );
- memset(transform, 0, sizeof(maTransform_t));
- transform->scale.x = transform->scale.y = transform->scale.z = 1;
- //Get the header info from the transform
- MA_ParseNodeHeader(parser, &header);
- //Read the transform attributes
- idToken token;
- while(parser.ReadToken(&token)) {
- if(IsNodeComplete(token)) {
- parser.UnreadToken(&token);
- break;
- }
- if(!token.Icmp("setAttr")) {
- parser.ReadToken(&token);
- if(!token.Icmp(".t")) {
- if(!MA_ReadVec3(parser, transform->translate)) {
- return false;
- }
- transform->translate.y *= -1;
- } else if (!token.Icmp(".r")) {
- if(!MA_ReadVec3(parser, transform->rotate)) {
- return false;
- }
- } else if (!token.Icmp(".s")) {
- if(!MA_ReadVec3(parser, transform->scale)) {
- return false;
- }
- } else {
- parser.SkipRestOfLine();
- }
- }
- }
- if(header.parent[0] != 0) {
- //Find the parent
- maTransform_t** parent;
- maGlobal.model->transforms.Get(header.parent, &parent);
- if(parent) {
- transform->parent = *parent;
- }
- }
-
- //Add this transform to the list
- maGlobal.model->transforms.Set(header.name, transform);
- return true;
- }
- bool MA_ParseVertex(idParser& parser, maAttribHeader_t* header) {
- maMesh_t* pMesh = &maGlobal.currentObject->mesh;
- idToken token;
- //Allocate enough space for all the verts if this is the first attribute for verticies
- if(!pMesh->vertexes) {
- pMesh->numVertexes = header->size;
- pMesh->vertexes = (idVec3 *)Mem_Alloc( sizeof( idVec3 ) * pMesh->numVertexes );
- }
- //Get the start and end index for this attribute
- int minIndex, maxIndex;
- if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "VertexHeader", NULL)) {
- //This was just a header
- return true;
- }
-
- //Read each vert
- for(int i = minIndex; i <= maxIndex; i++) {
- pMesh->vertexes[i].x = parser.ParseFloat();
- pMesh->vertexes[i].z = parser.ParseFloat();
- pMesh->vertexes[i].y = -parser.ParseFloat();
- }
-
- return true;
- }
- bool MA_ParseVertexTransforms(idParser& parser, maAttribHeader_t* header) {
- maMesh_t* pMesh = &maGlobal.currentObject->mesh;
- idToken token;
- //Allocate enough space for all the verts if this is the first attribute for verticies
- if(!pMesh->vertTransforms) {
- if(header->size == 0) {
- header->size = 1;
- }
- pMesh->numVertTransforms = header->size;
- pMesh->vertTransforms = (idVec4 *)Mem_Alloc( sizeof( idVec4 ) * pMesh->numVertTransforms );
- pMesh->nextVertTransformIndex = 0;
- }
- //Get the start and end index for this attribute
- int minIndex, maxIndex;
- if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "VertexTransformHeader", NULL)) {
- //This was just a header
- return true;
- }
- parser.ReadToken(&token);
- if(!token.Icmp("-")) {
- idToken tk2;
- parser.ReadToken(&tk2);
- if(!tk2.Icmp("type")) {
- parser.SkipUntilString("float3");
- } else {
- parser.UnreadToken(&tk2);
- parser.UnreadToken(&token);
- }
- } else {
- parser.UnreadToken(&token);
- }
- //Read each vert
- for(int i = minIndex; i <= maxIndex; i++) {
- pMesh->vertTransforms[pMesh->nextVertTransformIndex].x = parser.ParseFloat();
- pMesh->vertTransforms[pMesh->nextVertTransformIndex].z = parser.ParseFloat();
- pMesh->vertTransforms[pMesh->nextVertTransformIndex].y = -parser.ParseFloat();
- //w hold the vert index
- pMesh->vertTransforms[pMesh->nextVertTransformIndex].w = i;
- pMesh->nextVertTransformIndex++;
- }
- return true;
- }
- bool MA_ParseEdge(idParser& parser, maAttribHeader_t* header) {
- maMesh_t* pMesh = &maGlobal.currentObject->mesh;
- idToken token;
- //Allocate enough space for all the verts if this is the first attribute for verticies
- if(!pMesh->edges) {
- pMesh->numEdges = header->size;
- pMesh->edges = (idVec3 *)Mem_Alloc( sizeof( idVec3 ) * pMesh->numEdges );
- }
- //Get the start and end index for this attribute
- int minIndex, maxIndex;
- if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "EdgeHeader", NULL)) {
- //This was just a header
- return true;
- }
- //Read each vert
- for(int i = minIndex; i <= maxIndex; i++) {
- pMesh->edges[i].x = parser.ParseFloat();
- pMesh->edges[i].y = parser.ParseFloat();
- pMesh->edges[i].z = parser.ParseFloat();
- }
- return true;
- }
- bool MA_ParseNormal(idParser& parser, maAttribHeader_t* header) {
- maMesh_t* pMesh = &maGlobal.currentObject->mesh;
- idToken token;
- //Allocate enough space for all the verts if this is the first attribute for verticies
- if(!pMesh->normals) {
- pMesh->numNormals = header->size;
- pMesh->normals = (idVec3 *)Mem_Alloc( sizeof( idVec3 ) * pMesh->numNormals );
- }
- //Get the start and end index for this attribute
- int minIndex, maxIndex;
- if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "NormalHeader", NULL)) {
- //This was just a header
- return true;
- }
-
- parser.ReadToken(&token);
- if(!token.Icmp("-")) {
- idToken tk2;
- parser.ReadToken(&tk2);
- if(!tk2.Icmp("type")) {
- parser.SkipUntilString("float3");
- } else {
- parser.UnreadToken(&tk2);
- parser.UnreadToken(&token);
- }
- } else {
- parser.UnreadToken(&token);
- }
-
- //Read each vert
- for(int i = minIndex; i <= maxIndex; i++) {
- pMesh->normals[i].x = parser.ParseFloat();
- //Adjust the normals for the change in coordinate systems
- pMesh->normals[i].z = parser.ParseFloat();
- pMesh->normals[i].y = -parser.ParseFloat();
- pMesh->normals[i].Normalize();
- }
- pMesh->normalsParsed = true;
- pMesh->nextNormal = 0;
- return true;
- }
- bool MA_ParseFace(idParser& parser, maAttribHeader_t* header) {
- maMesh_t* pMesh = &maGlobal.currentObject->mesh;
- idToken token;
- //Allocate enough space for all the verts if this is the first attribute for verticies
- if(!pMesh->faces) {
- pMesh->numFaces = header->size;
- pMesh->faces = (maFace_t *)Mem_Alloc( sizeof( maFace_t ) * pMesh->numFaces );
- }
- //Get the start and end index for this attribute
- int minIndex, maxIndex;
- if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "FaceHeader", NULL)) {
- //This was just a header
- return true;
- }
- //Read the face data
- int currentFace = minIndex-1;
- while(parser.ReadToken(&token)) {
- if(IsNodeComplete(token)) {
- parser.UnreadToken(&token);
- break;
- }
- if(!token.Icmp("f")) {
- int count = parser.ParseInt();
- if(count != 3) {
- throw idException(va("Maya Loader '%s': Face is not a triangle.", parser.GetFileName()));
- return false;
- }
- //Increment the face number because a new face always starts with an "f" token
- currentFace++;
- //We cannot reorder edges until later because the normal processing
- //assumes the edges are in the original order
- pMesh->faces[currentFace].edge[0] = parser.ParseInt();
- pMesh->faces[currentFace].edge[1] = parser.ParseInt();
- pMesh->faces[currentFace].edge[2] = parser.ParseInt();
- //Some more init stuff
- pMesh->faces[currentFace].vertexColors[0] = pMesh->faces[currentFace].vertexColors[1] = pMesh->faces[currentFace].vertexColors[2] = -1;
- } else if(!token.Icmp("mu")) {
- int uvstIndex = parser.ParseInt();
- int count = parser.ParseInt();
- if(count != 3) {
- throw idException(va("Maya Loader '%s': Invalid texture coordinates.", parser.GetFileName()));
- return false;
- }
- pMesh->faces[currentFace].tVertexNum[0] = parser.ParseInt();
- pMesh->faces[currentFace].tVertexNum[1] = parser.ParseInt();
- pMesh->faces[currentFace].tVertexNum[2] = parser.ParseInt();
- } else if(!token.Icmp("mf")) {
- int count = parser.ParseInt();
- if(count != 3) {
- throw idException(va("Maya Loader '%s': Invalid texture coordinates.", parser.GetFileName()));
- return false;
- }
- pMesh->faces[currentFace].tVertexNum[0] = parser.ParseInt();
- pMesh->faces[currentFace].tVertexNum[1] = parser.ParseInt();
- pMesh->faces[currentFace].tVertexNum[2] = parser.ParseInt();
- } else if(!token.Icmp("fc")) {
- int count = parser.ParseInt();
- if(count != 3) {
- throw idException(va("Maya Loader '%s': Invalid vertex color.", parser.GetFileName()));
- return false;
- }
- pMesh->faces[currentFace].vertexColors[0] = parser.ParseInt();
- pMesh->faces[currentFace].vertexColors[1] = parser.ParseInt();
- pMesh->faces[currentFace].vertexColors[2] = parser.ParseInt();
- }
- }
- return true;
- }
- bool MA_ParseColor(idParser& parser, maAttribHeader_t* header) {
- maMesh_t* pMesh = &maGlobal.currentObject->mesh;
- idToken token;
- //Allocate enough space for all the verts if this is the first attribute for verticies
- if(!pMesh->colors) {
- pMesh->numColors = header->size;
- pMesh->colors = (byte *)Mem_Alloc( sizeof( byte ) * pMesh->numColors * 4 );
- }
- //Get the start and end index for this attribute
- int minIndex, maxIndex;
- if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "ColorHeader", NULL)) {
- //This was just a header
- return true;
- }
- //Read each vert
- for(int i = minIndex; i <= maxIndex; i++) {
- pMesh->colors[i*4] = parser.ParseFloat() * 255;
- pMesh->colors[i*4+1] = parser.ParseFloat() * 255;
- pMesh->colors[i*4+2] = parser.ParseFloat() * 255;
- pMesh->colors[i*4+3] = parser.ParseFloat() * 255;
- }
- return true;
- }
- bool MA_ParseTVert(idParser& parser, maAttribHeader_t* header) {
-
- maMesh_t* pMesh = &maGlobal.currentObject->mesh;
- idToken token;
- //This is not the texture coordinates. It is just the name so ignore it
- if(strstr(header->name, "uvsn")) {
- return true;
- }
- //Allocate enough space for all the data
- if(!pMesh->tvertexes) {
- pMesh->numTVertexes = header->size;
- pMesh->tvertexes = (idVec2 *)Mem_Alloc( sizeof( idVec2 ) * pMesh->numTVertexes );
- }
- //Get the start and end index for this attribute
- int minIndex, maxIndex;
- if(!MA_ParseHeaderIndex(header, minIndex, maxIndex, "TextureCoordHeader", "uvsp")) {
- //This was just a header
- return true;
- }
- parser.ReadToken(&token);
- if(!token.Icmp("-")) {
- idToken tk2;
- parser.ReadToken(&tk2);
- if(!tk2.Icmp("type")) {
- parser.SkipUntilString("float2");
- } else {
- parser.UnreadToken(&tk2);
- parser.UnreadToken(&token);
- }
- } else {
- parser.UnreadToken(&token);
- }
- //Read each tvert
- for(int i = minIndex; i <= maxIndex; i++) {
- pMesh->tvertexes[i].x = parser.ParseFloat();
- pMesh->tvertexes[i].y = 1.0f - parser.ParseFloat();
- }
- return true;
- }
- /*
- * Quick check to see if the vert participates in a shared normal
- */
- bool MA_QuickIsVertShared(int faceIndex, int vertIndex) {
-
- maMesh_t* pMesh = &maGlobal.currentObject->mesh;
- int vertNum = pMesh->faces[faceIndex].vertexNum[vertIndex];
-
- for( int i = 0; i < 3; i++) {
- int edge = pMesh->faces[faceIndex].edge[i];
- if(edge < 0) {
- edge = idMath::Fabs(edge)-1;
- }
- if(pMesh->edges[edge].z == 1 && (pMesh->edges[edge].x == vertNum || pMesh->edges[edge].y == vertNum)) {
- return true;
- }
- }
- return false;
- }
- void MA_GetSharedFace(int faceIndex, int vertIndex, int& sharedFace, int& sharedVert) {
- maMesh_t* pMesh = &maGlobal.currentObject->mesh;
- int vertNum = pMesh->faces[faceIndex].vertexNum[vertIndex];
- sharedFace = -1;
- sharedVert = -1;
- //Find a shared edge on this face that contains the specified vert
- for(int edgeIndex = 0; edgeIndex < 3; edgeIndex++) {
- int edge = pMesh->faces[faceIndex].edge[edgeIndex];
- if(edge < 0) {
- edge = idMath::Fabs(edge)-1;
- }
- if(pMesh->edges[edge].z == 1 && (pMesh->edges[edge].x == vertNum || pMesh->edges[edge].y == vertNum)) {
- for(int i = 0; i < faceIndex; i++) {
- for(int j = 0; j < 3; j++) {
- if(pMesh->faces[i].vertexNum[j] == vertNum) {
- sharedFace = i;
- sharedVert = j;
- break;
- }
- }
- }
- }
- if(sharedFace != -1)
- break;
- }
- }
- void MA_ParseMesh(idParser& parser) {
- maObject_t *object;
- object = (maObject_t *)Mem_Alloc( sizeof( maObject_t ) );
- memset( object, 0, sizeof( maObject_t ) );
- maGlobal.model->objects.Append( object );
- maGlobal.currentObject = object;
- object->materialRef = -1;
- //Get the header info from the mesh
- maNodeHeader_t header;
- MA_ParseNodeHeader(parser, &header);
- //Find my parent
- if(header.parent[0] != 0) {
- //Find the parent
- maTransform_t** parent;
- maGlobal.model->transforms.Get(header.parent, &parent);
- if(parent) {
- maGlobal.currentObject->mesh.transform = *parent;
- }
- }
- strcpy(object->name, header.name);
- //Read the transform attributes
- idToken token;
- while(parser.ReadToken(&token)) {
- if(IsNodeComplete(token)) {
- parser.UnreadToken(&token);
- break;
- }
- if(!token.Icmp("setAttr")) {
- maAttribHeader_t header;
- MA_ParseAttribHeader(parser, &header);
- if(strstr(header.name, ".vt")) {
- MA_ParseVertex(parser, &header);
- } else if (strstr(header.name, ".ed")) {
- MA_ParseEdge(parser, &header);
- } else if (strstr(header.name, ".pt")) {
- MA_ParseVertexTransforms(parser, &header);
- } else if (strstr(header.name, ".n")) {
- MA_ParseNormal(parser, &header);
- } else if (strstr(header.name, ".fc")) {
- MA_ParseFace(parser, &header);
- } else if (strstr(header.name, ".clr")) {
- MA_ParseColor(parser, &header);
- } else if (strstr(header.name, ".uvst")) {
- MA_ParseTVert(parser, &header);
- } else {
- parser.SkipRestOfLine();
- }
- }
- }
- maMesh_t* pMesh = &maGlobal.currentObject->mesh;
- //Get the verts from the edge
- for(int i = 0; i < pMesh->numFaces; i++) {
- for(int j = 0; j < 3; j++) {
- int edge = pMesh->faces[i].edge[j];
- if(edge < 0) {
- edge = idMath::Fabs(edge)-1;
- pMesh->faces[i].vertexNum[j] = pMesh->edges[edge].y;
- } else {
- pMesh->faces[i].vertexNum[j] = pMesh->edges[edge].x;
- }
- }
- }
- //Get the normals
- if(pMesh->normalsParsed) {
- for(int i = 0; i < pMesh->numFaces; i++) {
- for(int j = 0; j < 3; j++) {
- //Is this vertex shared
- int sharedFace = -1;
- int sharedVert = -1;
- if(MA_QuickIsVertShared(i, j)) {
- MA_GetSharedFace(i, j, sharedFace, sharedVert);
- }
-
- if(sharedFace != -1) {
- //Get the normal from the share
- pMesh->faces[i].vertexNormals[j] = pMesh->faces[sharedFace].vertexNormals[sharedVert];
- } else {
- //The vertex is not shared so get the next normal
- if(pMesh->nextNormal >= pMesh->numNormals) {
- //We are using more normals than exist
- throw idException(va("Maya Loader '%s': Invalid Normals Index.", parser.GetFileName()));
- }
- pMesh->faces[i].vertexNormals[j] = pMesh->normals[pMesh->nextNormal];
- pMesh->nextNormal++;
- }
- }
- }
- }
- //Now that the normals are good...lets reorder the verts to make the tris face the right way
- for(int i = 0; i < pMesh->numFaces; i++) {
- int tmp = pMesh->faces[i].vertexNum[1];
- pMesh->faces[i].vertexNum[1] = pMesh->faces[i].vertexNum[2];
- pMesh->faces[i].vertexNum[2] = tmp;
-
- idVec3 tmpVec = pMesh->faces[i].vertexNormals[1];
- pMesh->faces[i].vertexNormals[1] = pMesh->faces[i].vertexNormals[2];
- pMesh->faces[i].vertexNormals[2] = tmpVec;
- tmp = pMesh->faces[i].tVertexNum[1];
- pMesh->faces[i].tVertexNum[1] = pMesh->faces[i].tVertexNum[2];
- pMesh->faces[i].tVertexNum[2] = tmp;
- tmp = pMesh->faces[i].vertexColors[1];
- pMesh->faces[i].vertexColors[1] = pMesh->faces[i].vertexColors[2];
- pMesh->faces[i].vertexColors[2] = tmp;
- }
- //Now apply the pt transformations
- for(int i = 0; i < pMesh->numVertTransforms; i++) {
- pMesh->vertexes[(int)pMesh->vertTransforms[i].w] += pMesh->vertTransforms[i].ToVec3();
- }
-
- MA_VERBOSE((va("MESH %s - parent %s\n", header.name, header.parent)));
- MA_VERBOSE((va("\tverts:%d\n",maGlobal.currentObject->mesh.numVertexes)));
- MA_VERBOSE((va("\tfaces:%d\n",maGlobal.currentObject->mesh.numFaces)));
- }
- void MA_ParseFileNode(idParser& parser) {
-
- //Get the header info from the node
- maNodeHeader_t header;
- MA_ParseNodeHeader(parser, &header);
- //Read the transform attributes
- idToken token;
- while(parser.ReadToken(&token)) {
- if(IsNodeComplete(token)) {
- parser.UnreadToken(&token);
- break;
- }
- if(!token.Icmp("setAttr")) {
- maAttribHeader_t attribHeader;
- MA_ParseAttribHeader(parser, &attribHeader);
- if(strstr(attribHeader.name, ".ftn")) {
- parser.SkipUntilString("string");
- parser.ReadToken(&token);
- if(!token.Icmp("(")) {
- parser.ReadToken(&token);
- }
- maFileNode_t* fileNode;
- fileNode = (maFileNode_t*)Mem_Alloc( sizeof( maFileNode_t ) );
- strcpy(fileNode->name, header.name);
- strcpy(fileNode->path, token.c_str());
- maGlobal.model->fileNodes.Set(fileNode->name, fileNode);
- } else {
- parser.SkipRestOfLine();
- }
- }
- }
- }
- void MA_ParseMaterialNode(idParser& parser) {
- //Get the header info from the node
- maNodeHeader_t header;
- MA_ParseNodeHeader(parser, &header);
- maMaterialNode_t* matNode;
- matNode = (maMaterialNode_t*)Mem_Alloc( sizeof( maMaterialNode_t ) );
- memset(matNode, 0, sizeof(maMaterialNode_t));
- strcpy(matNode->name, header.name);
-
- maGlobal.model->materialNodes.Set(matNode->name, matNode);
- }
- void MA_ParseCreateNode(idParser& parser) {
- idToken token;
- parser.ReadToken(&token);
- if(!token.Icmp("transform")) {
- MA_ParseTransform(parser);
- } else if(!token.Icmp("mesh")) {
- MA_ParseMesh(parser);
- } else if(!token.Icmp("file")) {
- MA_ParseFileNode(parser);
- } else if(!token.Icmp("shadingEngine") || !token.Icmp("lambert") || !token.Icmp("phong") || !token.Icmp("blinn") ) {
- MA_ParseMaterialNode(parser);
- }
- }
- int MA_AddMaterial(const char* materialName) {
-
- maMaterialNode_t** destNode;
- maGlobal.model->materialNodes.Get(materialName, &destNode);
- if(destNode) {
- maMaterialNode_t* matNode = *destNode;
- //Iterate down the tree until we get a file
- while(matNode && !matNode->file) {
- matNode = matNode->child;
- }
- if(matNode && matNode->file) {
-
- //Got the file
- maMaterial_t *material;
- material = (maMaterial_t *)Mem_Alloc( sizeof( maMaterial_t ) );
- memset( material, 0, sizeof( maMaterial_t ) );
-
- //Remove the OS stuff
- idStr qPath;
- qPath = fileSystem->OSPathToRelativePath( matNode->file->path );
-
- strcpy(material->name, qPath.c_str());
- maGlobal.model->materials.Append( material );
- return maGlobal.model->materials.Num()-1;
- }
- }
- return -1;
- }
- bool MA_ParseConnectAttr(idParser& parser) {
- idStr temp;
- idStr srcName;
- idStr srcType;
- idStr destName;
- idStr destType;
- idToken token;
- parser.ReadToken(&token);
- temp = token;
- int dot = temp.Find(".");
- if(dot == -1) {
- throw idException(va("Maya Loader '%s': Invalid Connect Attribute.", parser.GetFileName()));
- return false;
- }
- srcName = temp.Left(dot);
- srcType = temp.Right(temp.Length()-dot-1);
- parser.ReadToken(&token);
- temp = token;
- dot = temp.Find(".");
- if(dot == -1) {
- throw idException(va("Maya Loader '%s': Invalid Connect Attribute.", parser.GetFileName()));
- return false;
- }
- destName = temp.Left(dot);
- destType = temp.Right(temp.Length()-dot-1);
- if(srcType.Find("oc") != -1) {
-
- //Is this attribute a material node attribute
- maMaterialNode_t** matNode;
- maGlobal.model->materialNodes.Get(srcName, &matNode);
- if(matNode) {
- maMaterialNode_t** destNode;
- maGlobal.model->materialNodes.Get(destName, &destNode);
- if(destNode) {
- (*destNode)->child = *matNode;
- }
- }
- //Is this attribute a file node
- maFileNode_t** fileNode;
- maGlobal.model->fileNodes.Get(srcName, &fileNode);
- if(fileNode) {
- maMaterialNode_t** destNode;
- maGlobal.model->materialNodes.Get(destName, &destNode);
- if(destNode) {
- (*destNode)->file = *fileNode;
- }
- }
- }
- if(srcType.Find("iog") != -1) {
- //Is this an attribute for one of our meshes
- for(int i = 0; i < maGlobal.model->objects.Num(); i++) {
- if(!strcmp(maGlobal.model->objects[i]->name, srcName)) {
- //maGlobal.model->objects[i]->materialRef = MA_AddMaterial(destName);
- strcpy(maGlobal.model->objects[i]->materialName, destName);
- break;
- }
- }
- }
- return true;
- }
- void MA_BuildScale(idMat4& mat, float x, float y, float z) {
- mat.Identity();
- mat[0][0] = x;
- mat[1][1] = y;
- mat[2][2] = z;
- }
- void MA_BuildAxisRotation(idMat4& mat, float ang, int axis) {
- float sinAng = idMath::Sin(ang);
- float cosAng = idMath::Cos(ang);
- mat.Identity();
- switch(axis) {
- case 0: //x
- mat[1][1] = cosAng;
- mat[1][2] = sinAng;
- mat[2][1] = -sinAng;
- mat[2][2] = cosAng;
- break;
- case 1: //y
- mat[0][0] = cosAng;
- mat[0][2] = -sinAng;
- mat[2][0] = sinAng;
- mat[2][2] = cosAng;
- break;
- case 2://z
- mat[0][0] = cosAng;
- mat[0][1] = sinAng;
- mat[1][0] = -sinAng;
- mat[1][1] = cosAng;
- break;
- }
- }
- void MA_ApplyTransformation(maModel_t *model) {
-
- for(int i = 0; i < model->objects.Num(); i++) {
- maMesh_t* mesh = &model->objects[i]->mesh;
- maTransform_t* transform = mesh->transform;
-
-
- while(transform) {
- idMat4 rotx, roty, rotz;
- idMat4 scale;
- rotx.Identity();
- roty.Identity();
- rotz.Identity();
- if(fabs(transform->rotate.x) > 0.0f) {
- MA_BuildAxisRotation(rotx, DEG2RAD(-transform->rotate.x), 0);
- }
- if(fabs(transform->rotate.y) > 0.0f) {
- MA_BuildAxisRotation(roty, DEG2RAD(transform->rotate.y), 1);
- }
- if(fabs(transform->rotate.z) > 0.0f) {
- MA_BuildAxisRotation(rotz, DEG2RAD(-transform->rotate.z), 2);
- }
- MA_BuildScale(scale, transform->scale.x, transform->scale.y, transform->scale.z);
- //Apply the transformation to each vert
- for(int j = 0; j < mesh->numVertexes; j++) {
- mesh->vertexes[j] = scale * mesh->vertexes[j];
- mesh->vertexes[j] = rotx * mesh->vertexes[j];
- mesh->vertexes[j] = rotz * mesh->vertexes[j];
- mesh->vertexes[j] = roty * mesh->vertexes[j];
-
- mesh->vertexes[j] = mesh->vertexes[j] + transform->translate;
- }
-
- transform = transform->parent;
- }
- }
- }
- /*
- =================
- MA_Parse
- =================
- */
- maModel_t *MA_Parse( const char *buffer, const char* filename, bool verbose ) {
- memset( &maGlobal, 0, sizeof( maGlobal ) );
- maGlobal.verbose = verbose;
-
-
-
- maGlobal.currentObject = NULL;
- // NOTE: using new operator because aseModel_t contains idList class objects
- maGlobal.model = new maModel_t;
- maGlobal.model->objects.Resize( 32, 32 );
- maGlobal.model->materials.Resize( 32, 32 );
-
- idParser parser;
- parser.SetFlags(LEXFL_NOSTRINGCONCAT);
- parser.LoadMemory(buffer, strlen(buffer), filename);
- idToken token;
- while(parser.ReadToken(&token)) {
- if(!token.Icmp("createNode")) {
- MA_ParseCreateNode(parser);
- } else if(!token.Icmp("connectAttr")) {
- MA_ParseConnectAttr(parser);
- }
- }
- //Resolve The Materials
- for(int i = 0; i < maGlobal.model->objects.Num(); i++) {
- maGlobal.model->objects[i]->materialRef = MA_AddMaterial(maGlobal.model->objects[i]->materialName);
- }
-
- //Apply Transformation
- MA_ApplyTransformation(maGlobal.model);
- return maGlobal.model;
- }
- /*
- =================
- MA_Load
- =================
- */
- maModel_t *MA_Load( const char *fileName ) {
- char *buf;
- ID_TIME_T timeStamp;
- maModel_t *ma;
- fileSystem->ReadFile( fileName, (void **)&buf, &timeStamp );
- if ( !buf ) {
- return NULL;
- }
- try {
- ma = MA_Parse( buf, fileName, false );
- ma->timeStamp = timeStamp;
- } catch( idException &e ) {
- common->Warning("%s", e.error);
- if(maGlobal.model) {
- MA_Free(maGlobal.model);
- }
- ma = NULL;
- }
- fileSystem->FreeFile( buf );
- return ma;
- }
- /*
- =================
- MA_Free
- =================
- */
- void MA_Free( maModel_t *ma ) {
- int i;
- maObject_t *obj;
- maMesh_t *mesh;
- maMaterial_t *material;
- if ( !ma ) {
- return;
- }
- for ( i = 0; i < ma->objects.Num(); i++ ) {
- obj = ma->objects[i];
-
- // free the base nesh
- mesh = &obj->mesh;
-
- if ( mesh->vertexes ) {
- Mem_Free( mesh->vertexes );
- }
- if ( mesh->vertTransforms ) {
- Mem_Free( mesh->vertTransforms );
- }
- if ( mesh->normals ) {
- Mem_Free( mesh->normals );
- }
- if ( mesh->tvertexes ) {
- Mem_Free( mesh->tvertexes );
- }
- if ( mesh->edges ) {
- Mem_Free( mesh->edges );
- }
- if ( mesh->colors ) {
- Mem_Free( mesh->colors );
- }
- if ( mesh->faces ) {
- Mem_Free( mesh->faces );
- }
- Mem_Free( obj );
- }
- ma->objects.Clear();
- for ( i = 0; i < ma->materials.Num(); i++ ) {
- material = ma->materials[i];
- Mem_Free( material );
- }
- ma->materials.Clear();
- maTransform_t** trans;
- for ( i = 0; i < ma->transforms.Num(); i++ ) {
- trans = ma->transforms.GetIndex(i);
- Mem_Free( *trans );
- }
- ma->transforms.Clear();
- maFileNode_t** fileNode;
- for ( i = 0; i < ma->fileNodes.Num(); i++ ) {
- fileNode = ma->fileNodes.GetIndex(i);
- Mem_Free( *fileNode );
- }
- ma->fileNodes.Clear();
- maMaterialNode_t** matNode;
- for ( i = 0; i < ma->materialNodes.Num(); i++ ) {
- matNode = ma->materialNodes.GetIndex(i);
- Mem_Free( *matNode );
- }
- ma->materialNodes.Clear();
- delete ma;
- }
|