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