Model_ma.cpp 28 KB

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