Model_ma.cpp 29 KB

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