xoreos  0.0.5
model_dragonage.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 /* Based on tazpn's DAO tools (<http://social.bioware.com/project/218/>)
26  * and DA2 tools (<http://social.bioware.com/project/4253/>), both
27  * released under the terms of the 3-clause BSD license, as well
28  * as the documentation on the Dragon Age Toolset wiki
29  * (<http://social.bioware.com/wiki/datoolset/index.php/Model>).
30  */
31 
32 #include <cstdio>
33 
34 #include "src/common/util.h"
35 #include "src/common/strutil.h"
36 #include "src/common/error.h"
37 #include "src/common/maths.h"
38 #include "src/common/readstream.h"
39 #include "src/common/encoding.h"
40 #include "src/common/filepath.h"
41 #include "src/common/xml.h"
42 
43 #include "src/aurora/util.h"
44 #include "src/aurora/resman.h"
45 #include "src/aurora/aurorafile.h"
46 #include "src/aurora/gff4file.h"
47 
49 
53 
54 // Disable the "unused variable" warnings while most stuff is still stubbed
56 
57 namespace Graphics {
58 
59 namespace Aurora {
60 
61 using Common::XMLParser;
62 using Common::XMLNode;
63 
64 // .--- GFF4 helpers
65 static const uint32 kMMHID = MKTAG('M', 'M', 'H', ' ');
66 static const uint32 kMSHID = MKTAG('M', 'E', 'S', 'H');
67 static const uint32 kVersion01 = MKTAG('V', '0', '.', '1');
68 static const uint32 kVersion10 = MKTAG('V', '1', '.', '0');
69 
70 static const uint32 kNODEID = MKTAG('n', 'o', 'd', 'e');
71 static const uint32 kMSHHID = MKTAG('m', 's', 'h', 'h');
72 static const uint32 kCRSTID = MKTAG('c', 'r', 's', 't');
73 
74 static const uint32 kTRSLID = MKTAG('t', 'r', 's', 'l');
75 static const uint32 kROTAID = MKTAG('r', 'o', 't', 'a');
76 
77 static const uint32 kCHNKID = MKTAG('c', 'h', 'n', 'k');
78 static const uint32 kDECLID = MKTAG('d', 'e', 'c', 'l');
79 
80 static const uint32 kGFFID = MKTAG('G', 'F', 'F', ' ');
81 static const uint32 kXMLID = MKTAG('<', '?', 'x', 'm');
82 
83 static const uint32 kMAOID = MKTAG('M', 'A', 'O', ' ');
84 
85 static const uint32 kFLOTID = MKTAG('f', 'l', 'o', 't');
86 static const uint32 kFLT4ID = MKTAG('f', 'l', 't', '4');
87 static const uint32 kTEXID = MKTAG('t', 'e', 'x', ' ');
88 
89 using ::Aurora::GFF4File;
90 using ::Aurora::GFF4Struct;
92 
96 
97 using namespace ::Aurora::GFF4FieldNamesEnum;
98 
99 static const GFF4Struct *getChild(const GFF4Struct &children, size_t i) {
100  bool isList;
101  GFF4Struct::FieldType type = children.getFieldType(i, isList);
102  if ((type != GFF4Struct::kFieldTypeStruct) || isList)
103  return 0;
104 
105  return children.getStruct(i);
106 }
107 
108 static bool isType(const GFF4Struct *strct, uint32 type) {
109  return strct && (strct->getLabel() == type);
110 }
111 
112 static bool isType(const GFF4Struct &strct, uint32 type) {
113  return isType(&strct, type);
114 }
115 
116 static const GFF4Struct *findMeshChunk(const GFF4Struct &mshTop, const Common::UString &name) {
117  const GFF4List &chunks = mshTop.getList(kGFF4MeshChunks);
118  for (GFF4List::const_iterator c = chunks.begin(); c != chunks.end(); ++c) {
119  if (!isType(*c, kCHNKID))
120  continue;
121 
122  if ((*c)->getString(kGFF4Name).equalsIgnoreCase(name))
123  return *c;
124  }
125 
126  return 0;
127 }
128 // '--- GFF4 helpers
129 
130 
132  mmh(0), msh(0), mmhTop(0), mshTop(0), state(0) {
133 
134  try {
135 
136  open(name);
137 
138  } catch (Common::Exception &e) {
139  delete msh;
140  delete mmh;
141 
142  e.add("Failed to load model \"%s\"", name.c_str());
143  throw e;
144  }
145 }
146 
148  mmhFile = name.toLower();
149 
150  // Open the MMH
151 
152  mmh = new GFF4File(mmhFile, kFileTypeMMH, kMMHID);
153  if (mmh->getTypeVersion() != kVersion01)
154  throw Common::Exception("Unsupported MMH version %s", Common::debugTag(mmh->getTypeVersion()).c_str());
155 
156  mmhTop = &mmh->getTopLevel();
157  mmhName = Common::FilePath::changeExtension(mmhTop->getString(kGFF4MMHName), "").toLower();
158 
159  // Read the MSH file name
160 
161  mshFile = mmhTop->getString(kGFF4MMHModelHierarchyModelDataName).toLower();
162  mshFile = Common::FilePath::changeExtension(mshFile, "");
163 
164  // Open the MSH
165  if (!mshFile.empty()) {
166 
167  msh = new GFF4File(mshFile, kFileTypeMSH, kMSHID);
168  if ((msh->getTypeVersion() != kVersion01) && (msh->getTypeVersion() != kVersion10))
169  throw Common::Exception("Unsupported MSH version %s", Common::debugTag(msh->getTypeVersion()).c_str());
170 
171  mshTop = &msh->getTopLevel();
172  mshName = Common::FilePath::changeExtension(mshTop->getString(kGFF4Name), "").toLower();
173  }
174 }
175 
177  delete msh;
178  delete mmh;
179 
180  clear();
181 }
182 
184  for (std::list<ModelNode_DragonAge *>::iterator n = nodes.begin(); n != nodes.end(); ++n)
185  delete *n;
186  nodes.clear();
187 
188  delete state;
189  state = 0;
190 }
191 
192 
194  _fileName = name;
195 
196  ParserContext ctx(name);
197 
198  load(ctx);
199 
200  finalize();
201 }
202 
204 }
205 
207  _name = ctx.mmhName;
208 
209  // Lax sanity checks
210  /*
211  if (!ctx.mmhName.empty() && (ctx.mmhFile != ctx.mmhName))
212  warning("MMH names don't match (\"%s\" vs. \"%s\")", ctx.mmhFile.c_str(), ctx.mmhName.c_str());
213  if (!ctx.mshName.empty() && (ctx.mshFile != ctx.mshName))
214  warning("MSH names don't match (\"%s\" vs. \"%s\")", ctx.mshFile.c_str(), ctx.mshName.c_str());
215  */
216 
217  const GFF4Struct *rootNodes = ctx.mmhTop->getGeneric(kGFF4MMHChildren);
218  if (!rootNodes)
219  return;
220 
221  newState(ctx);
222 
223  // Create root nodes
224  for (size_t i = 0; i < rootNodes->getFieldCount(); i++) {
225  const GFF4Struct *nodeGFF = getChild(*rootNodes, i);
226  if (!isType(nodeGFF, kNODEID))
227  continue;
228 
229  ModelNode_DragonAge *rootNode = new ModelNode_DragonAge(*this);
230  ctx.nodes.push_back(rootNode);
231 
232  rootNode->load(ctx, *nodeGFF);
233  }
234 
235  addState(ctx);
236 }
237 
239  ctx.clear();
240 
241  ctx.state = new State;
242 }
243 
245  if (!ctx.state || ctx.nodes.empty()) {
246  ctx.clear();
247  return;
248  }
249 
250  for (std::list<ModelNode_DragonAge *>::iterator n = ctx.nodes.begin(); n != ctx.nodes.end(); ++n) {
251  ctx.state->nodeList.push_back(*n);
252  ctx.state->nodeMap.insert(std::make_pair((*n)->getName(), *n));
253 
254  if (!(*n)->getParent())
255  ctx.state->rootNodes.push_back(*n);
256  }
257 
258  _stateList.push_back(ctx.state);
259  _stateMap.insert(std::make_pair(ctx.state->name, ctx.state));
260 
261  if (!_currentState)
262  _currentState = ctx.state;
263 
264  ctx.state = 0;
265 
266  ctx.nodes.clear();
267 }
268 
269 
271 }
272 
274 }
275 
276 // .--- Vertex value reading helpers
278  switch (type) {
282  *f++ = stream.readIEEEFloatLE();
283  *f++ = stream.readIEEEFloatLE();
284  break;
285 
287  *f++ = stream.readByte();
288  *f++ = stream.readByte();
289  break;
290 
293  *f++ = (int16) stream.readUint16LE();
294  *f++ = (int16) stream.readUint16LE();
295  break;
296 
298  *f++ = stream.readByte() / 255.0f;
299  *f++ = stream.readByte() / 255.0f;
300  break;
301 
304  *f++ = ((int16) stream.readUint16LE()) / 32767.0f;
305  *f++ = ((int16) stream.readUint16LE()) / 32767.0f;
306  break;
307 
310  *f++ = stream.readUint16LE() / 65535.0f;
311  *f++ = stream.readUint16LE() / 65535.0f;
312  break;
313 
316  *f++ = readIEEEFloat16(stream.readUint16LE());
317  *f++ = readIEEEFloat16(stream.readUint16LE());
318  break;
319 
320  default:
321  throw Common::Exception("Invalid data type for 2 floats: %u", (uint) type);
322  }
323 }
324 
326  switch (type) {
329  *f++ = stream.readIEEEFloatLE();
330  *f++ = stream.readIEEEFloatLE();
331  *f++ = stream.readIEEEFloatLE();
332  break;
333 
334  case kMeshDeclTypeColor:
335  *f++ = stream.readByte() / 255.0f;
336  *f++ = stream.readByte() / 255.0f;
337  *f++ = stream.readByte() / 255.0f;
338  break;
339 
341  *f++ = stream.readByte();
342  *f++ = stream.readByte();
343  *f++ = stream.readByte();
344  break;
345 
347  *f++ = (int16) stream.readUint16LE();
348  *f++ = (int16) stream.readUint16LE();
349  *f++ = (int16) stream.readUint16LE();
350  break;
351 
353  *f++ = stream.readByte() / 255.0f;
354  *f++ = stream.readByte() / 255.0f;
355  *f++ = stream.readByte() / 255.0f;
356  break;
357 
359  *f++ = ((int16) stream.readUint16LE()) / 32767.0f;
360  *f++ = ((int16) stream.readUint16LE()) / 32767.0f;
361  *f++ = ((int16) stream.readUint16LE()) / 32767.0f;
362  break;
363 
365  *f++ = stream.readUint16LE() / 65535.0f;
366  *f++ = stream.readUint16LE() / 65535.0f;
367  *f++ = stream.readUint16LE() / 65535.0f;
368  break;
369 
371  {
372  uint32 data = stream.readUint32LE();
373 
374  *f++ = (uint16) ((data >> 22) & 0x3FFF);
375  *f++ = (uint16) ((data >> 12) & 0x3FFF);
376  *f++ = (uint16) ((data >> 2) & 0x3FFF);
377  }
378  break;
379 
381  {
382  uint32 data = stream.readUint32LE();
383 
384  *f++ = (uint16) ((data >> 22) & 0x3FFF) / 511.0f;
385  *f++ = (uint16) ((data >> 12) & 0x3FFF) / 511.0f;
386  *f++ = (uint16) ((data >> 2) & 0x3FFF) / 511.0f;
387  }
388  break;
389 
391  *f++ = readIEEEFloat16(stream.readUint16LE());
392  *f++ = readIEEEFloat16(stream.readUint16LE());
393  *f++ = readIEEEFloat16(stream.readUint16LE());
394  break;
395 
396  default:
397  throw Common::Exception("Invalid data type for 3 floats: %u", (uint) type);
398  }
399 }
400 
402  switch (type) {
404  *f++ = stream.readIEEEFloatLE();
405  *f++ = stream.readIEEEFloatLE();
406  *f++ = stream.readIEEEFloatLE();
407  *f++ = 1.0f;
408  break;
409 
411  *f++ = stream.readIEEEFloatLE();
412  *f++ = stream.readIEEEFloatLE();
413  *f++ = stream.readIEEEFloatLE();
414  *f++ = stream.readIEEEFloatLE();
415  break;
416 
417  case kMeshDeclTypeColor:
418  *f++ = stream.readByte() / 255.0f;
419  *f++ = stream.readByte() / 255.0f;
420  *f++ = stream.readByte() / 255.0f;
421  *f++ = stream.readByte() / 255.0f;
422  break;
423 
425  *f++ = stream.readByte();
426  *f++ = stream.readByte();
427  *f++ = stream.readByte();
428  *f++ = stream.readByte();
429  break;
430 
432  *f++ = (int16) stream.readUint16LE();
433  *f++ = (int16) stream.readUint16LE();
434  *f++ = (int16) stream.readUint16LE();
435  *f++ = (int16) stream.readUint16LE();
436  break;
437 
439  *f++ = stream.readByte() / 255.0f;
440  *f++ = stream.readByte() / 255.0f;
441  *f++ = stream.readByte() / 255.0f;
442  *f++ = stream.readByte() / 255.0f;
443  break;
444 
446  *f++ = ((int16) stream.readUint16LE()) / 32767.0f;
447  *f++ = ((int16) stream.readUint16LE()) / 32767.0f;
448  *f++ = ((int16) stream.readUint16LE()) / 32767.0f;
449  *f++ = ((int16) stream.readUint16LE()) / 32767.0f;
450  break;
451 
453  *f++ = stream.readUint16LE() / 65535.0f;
454  *f++ = stream.readUint16LE() / 65535.0f;
455  *f++ = stream.readUint16LE() / 65535.0f;
456  *f++ = stream.readUint16LE() / 65535.0f;
457  break;
458 
460  {
461  uint32 data = stream.readUint32LE();
462 
463  *f++ = (uint16) ((data >> 22) & 0x3FFF);
464  *f++ = (uint16) ((data >> 12) & 0x3FFF);
465  *f++ = (uint16) ((data >> 2) & 0x3FFF);
466  *f++ = (uint16) ( data & 0x0002);
467  }
468  break;
469 
471  {
472  uint32 data = stream.readUint32LE();
473 
474  *f++ = (uint16) ((data >> 22) & 0x3FFF) / 511.0f;
475  *f++ = (uint16) ((data >> 12) & 0x3FFF) / 511.0f;
476  *f++ = (uint16) ((data >> 2) & 0x3FFF) / 511.0f;
477  *f++ = (uint16) ( data & 0x0002) / 4.0f;
478  }
479  break;
480 
482  *f++ = readIEEEFloat16(stream.readUint16LE());
483  *f++ = readIEEEFloat16(stream.readUint16LE());
484  *f++ = readIEEEFloat16(stream.readUint16LE());
485  *f++ = readIEEEFloat16(stream.readUint16LE());
486  break;
487 
488  default:
489  throw Common::Exception("Invalid data type for 4 floats: %u", (uint) type);
490  }
491 }
492 // '--- Vertex value reading helpers
493 
494 void ModelNode_DragonAge::load(Model_DragonAge::ParserContext &ctx, const GFF4Struct &nodeGFF) {
495  _name = nodeGFF.getString(kGFF4MMHName);
496 
497  // Read local translation + rotation of this node
498  readTransformation(nodeGFF);
499 
500  // If this is a mesh node, read the mesh
501  if (isType(nodeGFF, kMSHHID)) {
502  readMesh(ctx, nodeGFF);
503 
504  Common::UString meshName = ctx.mmhName + ctx.mshName;
505  meshName += ".";
506  if (ctx.state->name.size() != 0) {
507  meshName += ctx.state->name;
508  } else {
509  meshName += "xoreos.default";
510  }
511  meshName += ".";
512  meshName += _name;
513 
514  _mesh->data->rawMesh->setName(meshName);
515  _mesh->data->rawMesh->init();
516  if (MeshMan.getMesh(meshName)) {
517  warning("Warning: probable mesh duplication of: %s", meshName.c_str());
518  }
519  MeshMan.addMesh(_mesh->data->rawMesh);
520  }
521 
522  // Read the children
523  readChildren(ctx, nodeGFF);
524 
525  // Create the bounding box
526  createBound();
527 
528  if (GfxMan.isRendererExperimental())
529  buildMaterial();
530 }
531 
532 void ModelNode_DragonAge::readTransformation(const GFF4Struct &nodeGFF) {
533  const GFF4Struct *children = nodeGFF.getGeneric(kGFF4MMHChildren);
534  if (!children)
535  return;
536 
537  for (size_t i = 0; i < children->getFieldCount(); i++) {
538  const GFF4Struct *childGFF = getChild(*children, i);
539 
540  if (isType(childGFF, kTRSLID)) {
541  // Translation
542 
543  double x = 0.0, y = 0.0, z = 0.0, w = 1.0;
544  childGFF->getVector4(kGFF4MMHTranslation, x, y, z, w);
545 
546  _position[0] = x;
547  _position[1] = y;
548  _position[2] = z;
549 
550  } else if (isType(childGFF, kROTAID)) {
551  // Rotation
552 
553  double x = 0.0, y = 0.0, z = 0.0, w = 1.0;
554  childGFF->getVector4(kGFF4MMHRotation, x, y, z, w);
555 
556  _orientation[0] = x;
557  _orientation[1] = y;
558  _orientation[2] = z;
559  _orientation[3] = Common::rad2deg(acos(w) * 2.0);
560  }
561  }
562 }
563 
565  const GFF4Struct *children = nodeGFF.getGeneric(kGFF4MMHChildren);
566  if (!children)
567  return;
568 
569  for (size_t i = 0; i < children->getFieldCount(); i++) {
570  const GFF4Struct *childGFF = getChild(*children, i);
571  if (!isType(childGFF, kNODEID) && !isType(childGFF, kMSHHID) && !isType(childGFF, kCRSTID))
572  continue;
573 
575  ctx.nodes.push_back(childNode);
576 
577  childNode->setParent(this);
578 
579  childNode->load(ctx, *childGFF);
580  }
581 }
582 
583 void ModelNode_DragonAge::sanityCheckMeshChunk(const GFF4Struct &meshChunk) {
584  const uint32 primitiveType = meshChunk.getUint(kGFF4MeshChunkPrimitiveType);
585  if (primitiveType != 0)
586  throw Common::Exception("Unsupported primitive type %u", primitiveType);
587 
588  const uint32 indexFormat = meshChunk.getUint(kGFF4MeshChunkIndexFormat);
589  if (indexFormat != 0)
590  throw Common::Exception("Invalid index format %u", indexFormat);
591 
592  const uint32 baseVertexIndex = meshChunk.getUint(kGFF4MeshChunkBaseVertexIndex);
593  if (baseVertexIndex != 0)
594  throw Common::Exception("Unsupported base vertex index %u", baseVertexIndex);
595 
596  const uint32 minIndex = meshChunk.getUint(kGFF4MeshChunkMinIndex);
597  if (minIndex != 0)
598  throw Common::Exception("Unsupported min index %u", minIndex);
599 }
600 
601 void ModelNode_DragonAge::readMeshDecl(const GFF4Struct &meshChunk, MeshDeclarations &meshDecl) {
602  const GFF4List &chunkDecl = meshChunk.getList(kGFF4MeshChunkVertexDeclarator);
603 
604  for (GFF4List::const_iterator d = chunkDecl.begin(); d != chunkDecl.end(); ++d) {
605  // Go through all structs in the declarator list, look for non-empty declaration
606 
607  if (!isType(*d, kDECLID))
608  continue;
609 
610  const int32 streamIndex = (*d)->getSint(kGFF4MeshVertexDeclaratorStream);
611  if (streamIndex == -1)
612  continue;
613 
614  // Sanity checks
615 
616  if (streamIndex != 0)
617  throw Common::Exception("Unsupported chunk stream index %d", streamIndex);
618 
619  const uint32 usageIndex = (*d)->getUint(kGFF4MeshVertexDeclaratorUsageIndex);
620  if (streamIndex != 0)
621  throw Common::Exception("Unsupported chunk usage index %u", usageIndex);
622 
623  const uint32 method = (*d)->getUint(kGFF4MeshVertexDeclaratorMethod);
624  if (method != 0)
625  throw Common::Exception("Unsupported chunk method %u", method);
626 
627  // Is this declaration even used?
629  if (use == kMeshDeclUseUnused)
630  continue;
631 
632  // Read and add the declaration
633 
634  const int32 offset = (*d)->getSint(kGFF4MeshVertexDeclaratorOffset);
635  const MeshDeclType type = (MeshDeclType) (*d)->getUint(kGFF4MeshVertexDeclaratorDatatype);
636 
637  meshDecl.push_back(MeshDeclaration(use, *d, offset, type));
638  }
639 }
640 
641 void ModelNode_DragonAge::createIndexBuffer(const GFF4Struct &meshChunk,
642  Common::SeekableReadStream &indexData) {
643 
644  uint32 indexCount = meshChunk.getUint(kGFF4MeshChunkIndexCount);
645  _mesh->data->rawMesh->getIndexBuffer()->setSize(indexCount, sizeof(uint16), GL_UNSIGNED_SHORT);
646 
647  const uint32 startIndex = meshChunk.getUint(kGFF4MeshChunkStartIndex);
648  indexData.skip(startIndex * 2);
649 
650  uint16 *indices = reinterpret_cast<uint16 *>(_mesh->data->rawMesh->getIndexBuffer()->getData());
651  while (indexCount-- > 0)
652  *indices++ = indexData.readUint16LE();
653 }
654 
655 void ModelNode_DragonAge::createVertexBuffer(const GFF4Struct &meshChunk,
656  Common::SeekableReadStream &vertexData, const MeshDeclarations &meshDecl) {
657 
658  const size_t vertexPos = vertexData.pos();
659  const uint32 vertexSize = meshChunk.getUint(kGFF4MeshChunkVertexSize);
660  const uint32 vertexCount = meshChunk.getUint(kGFF4MeshChunkVertexCount);
661  const uint32 vertexOffset = meshChunk.getUint(kGFF4MeshChunkVertexOffset);
662 
663  VertexDecl vertexDecl;
664 
665  size_t textureCount = 0;
666  for (MeshDeclarations::const_iterator d = meshDecl.begin(); d != meshDecl.end(); ++d) {
667  switch (d->use) {
669  vertexDecl.push_back(VertexAttrib(VPOSITION, 3, GL_FLOAT));
670  break;
671 
672  case kMeshDeclUseNormal:
673  vertexDecl.push_back(VertexAttrib(VNORMAL, 3, GL_FLOAT));
674  break;
675 
677  vertexDecl.push_back(VertexAttrib(VTCOORD + textureCount++, 2, GL_FLOAT));
678  break;
679 
680  case kMeshDeclUseColor:
681  vertexDecl.push_back(VertexAttrib(VCOLOR, 4, GL_FLOAT));
682  break;
683 
684  default:
685  break;
686  }
687  }
688 
689  _mesh->data->rawMesh->getVertexBuffer()->setVertexDeclInterleave(vertexCount, vertexDecl);
690 
691  float *vData = reinterpret_cast<float *>(_mesh->data->rawMesh->getVertexBuffer()->getData());
692  for (uint32 v = 0; v < vertexCount; v++) {
693 
694  for (MeshDeclarations::const_iterator d = meshDecl.begin(); d != meshDecl.end(); ++d) {
695  vertexData.seek(vertexPos + vertexOffset + v * vertexSize + d->offset);
696 
697  try {
698  switch (d->use) {
700  read3Float32(vertexData, d->type, vData);
701  break;
702 
703  case kMeshDeclUseNormal:
704  read3Float32(vertexData, d->type, vData);
705  break;
706 
708  read2Float32(vertexData, d->type, vData);
709  break;
710 
711  case kMeshDeclUseColor:
712  read4Float32(vertexData, d->type, vData);
713  vData[-1] = 0xFF; // WORKAROUND: Shader side-stepping
714  break;
715 
716  default:
717  break;
718  }
719  } catch (Common::Exception &e) {
720  e.add("While reading mesh declaration with usage %u", d->use);
721  throw e;
722  }
723  }
724  }
725 
726 }
727 
730  GFF4File mao(maoStream, kMAOID);
731 
732  const GFF4Struct &maoTop = mao.getTopLevel();
733 
734  // General properties
735  material.material = maoTop.getString(kGFF4MAOMaterial);
736  material.defaultSemantic = maoTop.getString(kGFF4MAODefaultSemantic);
737 
738  // Floats
739  if (maoTop.hasField(kGFF4MAOFloats)) {
740  const GFF4List &floats = maoTop.getList(kGFF4MAOFloats);
741  for (GFF4List::const_iterator f = floats.begin(); f != floats.end(); ++f) {
742  if (!isType(*f, kFLOTID))
743  continue;
744 
745  material.floats[(*f)->getString(kGFF4MAOFloatName)] = (float) (*f)->getDouble(kGFF4MAOFloatValue);
746  }
747  }
748 
749  // Vectors
750  if (maoTop.hasField(kGFF4MAOVectors)) {
751  const GFF4List &vectors = maoTop.getList(kGFF4MAOVectors);
752  for (GFF4List::const_iterator v = vectors.begin(); v != vectors.end(); ++v) {
753  if (!isType(*v, kFLT4ID))
754  continue;
755 
756  double v1 = 0.0, v2 = 0.0, v3 = 0.0, v4 = 1.0;
757  (*v)->getVector4(kGFF4MAOVectorValue, v1, v2, v3, v4);
758 
759  material.vectors[(*v)->getString(kGFF4MAOVectorName)] = glm::vec4(v1, v2, v3, v4);
760  }
761  }
762 
763  // Textures
764  if (maoTop.hasField(kGFF4MAOTextures)) {
765  const GFF4List &textures = maoTop.getList(kGFF4MAOTextures);
766  for (GFF4List::const_iterator t = textures.begin(); t != textures.end(); ++t) {
767  if (!isType(*t, kTEXID))
768  continue;
769 
770  material.textures[(*t)->getString(kGFF4MAOTextureName)] = (*t)->getString(kGFF4MAOTextureResource);
771  }
772  }
773 }
774 
777  const Common::UString &fileName) {
778 
779  try {
780  XMLParser mao(*maoStream, true, fileName);
781  const XMLNode &maoRoot = mao.getRoot();
782 
783  if (maoRoot.getName() != "materialobject")
784  throw Common::Exception("Invalid XML MAO root element (\"%s\")", maoRoot.getName().c_str());
785 
786  const XMLNode::Children &maoNodes = maoRoot.getChildren();
787  for (XMLNode::Children::const_iterator n = maoNodes.begin(); n != maoNodes.end(); ++n) {
788  if ((*n)->getName() == "material") {
789 
790  material.material = (*n)->getProperty("name");
791 
792  } else if ((*n)->getName() == "defaultsemantic") {
793 
794  material.defaultSemantic = (*n)->getProperty("name");
795 
796  } else if ((*n)->getName() == "float") {
797 
798  float value = 0.0f;
799  std::sscanf((*n)->getProperty("value").c_str(), "%f", &value);
800 
801  material.floats[(*n)->getProperty("name")] = value;
802 
803  } else if ((*n)->getName() == "vector4f") {
804 
805  float v1 = 0.0f, v2 = 0.0f, v3 = 0.0f, v4 = 0.0f;
806  std::sscanf((*n)->getProperty("value").c_str(), "%f %f %f %f", &v1, &v2, &v3, &v4);
807 
808  material.vectors[(*n)->getProperty("name")] = glm::vec4(v1, v2, v3, v4);
809 
810  } else if ((*n)->getName() == "texture") {
811 
812  material.textures[(*n)->getProperty("name")] = (*n)->getProperty("resname");
813 
814  }
815  }
816 
817  } catch (...) {
818  delete maoStream;
819  throw;
820  }
821 
822  delete maoStream;
823 }
824 
826 void ModelNode_DragonAge::readMAO(const Common::UString &materialName, MaterialObject &material) {
827  try {
828 
829  Common::SeekableReadStream *maoStream = ResMan.getResource(materialName, kFileTypeMAO);
830  if (!maoStream)
831  throw Common::Exception("No such MAO");
832 
833  const uint32 tag = ::Aurora::AuroraFile::readHeaderID(*maoStream);
834  maoStream->seek(0);
835 
836  if (tag == kGFFID)
837  readMAOGFF(maoStream, material);
838  else if (tag == kXMLID)
839  readMAOXML(maoStream, material, TypeMan.setFileType(materialName, kFileTypeMAO));
840  else {
841  delete maoStream;
842  throw Common::Exception("Invalid MAO type %s", Common::debugTag(tag).c_str());
843  }
844 
845  } catch (Common::Exception &e) {
846  e.add("Failed to load MAO \"%s\"", materialName.c_str());
847  throw e;
848  }
849 }
850 
851 void ModelNode_DragonAge::loadTextures(const std::vector<Common::UString> &textures,
852  const MaterialObject &material) {
853  /* If this is a texture doing tinting, the alpha channel is wrong (and potentially all 0x00).
854  * Usually, tinting would be done using a shader, but since we don't support that yet, we're
855  * modifying the alpha channel of the texture instead. */
856 
857  const bool fixAlpha = material.defaultSemantic.equalsIgnoreCase("ArmourSkinTint") ||
858  material.material.equalsIgnoreCase("Face.mat") ||
859  material.material.equalsIgnoreCase("Eye.mat");
860  const bool fixHair = material.material.equalsIgnoreCase("HairAlpha.mat");
861 
862  if (fixHair)
863  fixTexturesHair (textures);
864  else if (fixAlpha)
865  fixTexturesAlpha(textures);
866  else
867  ModelNode::loadTextures(textures);
868 }
869 
870 void ModelNode_DragonAge::fixTexturesAlpha(const std::vector<Common::UString> &textures) {
871  std::vector<TextureHandle> handles;
872 
873  for (std::vector<Common::UString>::const_iterator t = textures.begin(); t != textures.end(); ++t) {
874  if (t->empty() || (*t == "NULL") || TextureMan.hasTexture(*t))
875  continue;
876 
877  ImageDecoder *image = 0;
878  try {
879  image = Texture::loadImage(*t);
880  if (image->isCompressed())
881  image->decompress();
882 
883  if (image->getFormatRaw() != kPixelFormatRGBA8)
884  throw 0;
885 
886  for (size_t m = 0; m < image->getMipMapCount(); m++) {
887  const ImageDecoder::MipMap &mipMap = image->getMipMap(m);
888  if ((mipMap.size % 4) != 0)
889  throw 0;
890 
891  for (size_t p = 0; p < mipMap.size; p += 4) {
892  mipMap.data[p + 3] = 0xFF;
893  }
894  }
895 
896  } catch (...) {
897  delete image;
898  continue;
899  }
900 
901  try {
902  handles.push_back(TextureMan.add(Texture::create(image), *t));
903  } catch (...) {
904  }
905  }
906 
907  ModelNode::loadTextures(textures);
908 }
909 
910 void ModelNode_DragonAge::fixTexturesHair(const std::vector<Common::UString> &textures) {
911  std::vector<TextureHandle> handles;
912 
913  for (std::vector<Common::UString>::const_iterator t = textures.begin(); t != textures.end(); ++t) {
914  if (t->empty() || (*t == "NULL") || TextureMan.hasTexture(*t))
915  continue;
916 
917  ImageDecoder *image = 0;
918  try {
919  image = Texture::loadImage(*t);
920  if (image->isCompressed())
921  image->decompress();
922 
923  if (image->getFormatRaw() != kPixelFormatRGBA8)
924  throw 0;
925 
926  for (size_t m = 0; m < image->getMipMapCount(); m++) {
927  const ImageDecoder::MipMap &mipMap = image->getMipMap(m);
928  if ((mipMap.size % 4) != 0)
929  throw 0;
930 
931  for (size_t p = 0; p < mipMap.size; p += 4) {
932  mipMap.data[p + 0] = mipMap.data[p + 3];
933  mipMap.data[p + 1] = mipMap.data[p + 3];
934  mipMap.data[p + 2] = mipMap.data[p + 3];
935  mipMap.data[p + 3] = 0xFF;
936  }
937  }
938 
939  } catch (...) {
940  delete image;
941  continue;
942  }
943 
944  try {
945  handles.push_back(TextureMan.add(Texture::create(image), *t));
946  } catch (...) {
947  }
948  }
949 
950  ModelNode::loadTextures(textures);
951 }
952 
953 void ModelNode_DragonAge::readMesh(Model_DragonAge::ParserContext &ctx, const GFF4Struct &meshGFF) {
954  if (!ctx.mshTop)
955  return;
956 
957  Common::UString meshGroupName = meshGFF.getString(kGFF4MMHMeshGroupName);
958  Common::UString materialName = meshGFF.getString(kGFF4MMHMaterialObject);
959  if (meshGroupName.empty() || materialName.empty())
960  return;
961 
962  const GFF4Struct *meshChunk = findMeshChunk(*ctx.mshTop, meshGroupName);
963  if (!meshChunk)
964  return;
965 
966  sanityCheckMeshChunk(*meshChunk);
967 
968  // Read the mesh indices and vertices, and create our buffers
969 
970  MeshDeclarations meshDecl;
971  readMeshDecl(*meshChunk, meshDecl);
972  if (meshDecl.empty())
973  return;
974 
975  Common::SeekableReadStream *indexData = 0, *vertexData = 0;
976  try {
977 
978  indexData = ctx.mshTop->getData(kGFF4MeshIndexData);
979  if (!indexData)
980  throw Common::Exception("Mesh has mesh declaration but no index data");
981 
982  vertexData = ctx.mshTop->getData(kGFF4MeshVertexData);
983  if (!vertexData)
984  throw Common::Exception("Mesh has mesh declaration but no vertex data");
985 
986  _mesh = new Mesh();
987  _render =_mesh->render = true;
988  _mesh->data = new MeshData();
990 
991  createIndexBuffer (*meshChunk, *indexData);
992  createVertexBuffer(*meshChunk, *vertexData, meshDecl);
993 
994  // Load the material object, grab the diffuse texture and load
995 
996  MaterialObject materialObject;
997  readMAO(materialName, materialObject);
998 
999  std::vector<Common::UString> textures;
1000  textures.push_back(materialObject.textures["mml_tDiffuse"]);
1001  if (textures.back().empty())
1002  textures.back() = materialObject.textures["mml_tPackedTexture"];
1003  if (textures.back().empty())
1004  textures.back() = materialObject.textures["LowLodMap"];
1005 
1006  while (!textures.empty() && textures.back().empty())
1007  textures.pop_back();
1008 
1009  loadTextures(textures, materialObject);
1010 
1011  } catch (...) {
1012  delete indexData;
1013  delete vertexData;
1014  throw;
1015  }
1016 
1017  delete indexData;
1018  delete vertexData;
1019 }
1020 
1021 } // End of namespace Aurora
1022 
1023 } // End of namespace Graphics
static const uint32 kTEXID
#define ResMan
Shortcut for accessing the sound manager.
Definition: resman.h:557
GLvoid * getData()
Access buffer data.
Definition: indexbuffer.cpp:78
static const uint32 kCHNKID
#define MKTAG(a0, a1, a2, a3)
A wrapper macro used around four character constants, like &#39;DATA&#39;, to ensure portability.
Definition: endianness.h:140
void addState(ParserContext &ctx)
uint16 readUint16LE()
Read an unsigned 16-bit word stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:122
Generic image decoder interface.
static const uint32 kMMHID
static const uint32 kMSHHID
NodeMap nodeMap
The nodes within the state, indexed by name.
Definition: model.h:207
std::list< MeshDeclaration > MeshDeclarations
static const uint32 kTRSLID
void add(const char *s,...) GCC_PRINTF(2
Definition: error.cpp:58
Vertex texture coordinates, VTCOORDi = VTCOORD + i.
Definition: vertexbuffer.h:39
uint32 readUint32LE()
Read an unsigned 32-bit word stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:133
void readMAO(const Common::UString &materialName, MaterialObject &material)
Read a material object MAO, which can be encoded in either XML or GFF.
static void read2Float32(Common::ReadStream &stream, MeshDeclType type, float *&f)
Generic interface for a readable data stream.
Definition: readstream.h:64
#define TypeMan
Shortcut for accessing the file type manager.
Definition: util.h:85
static const GFF4Struct * getChild(const GFF4Struct &children, size_t i)
A class holding an UTF-8 string.
Definition: ustring.h:48
Class to parse a ReadStream into a simple XML tree.
Definition: xml.h:51
#define TextureMan
Shortcut for accessing the texture manager.
Definition: textureman.h:127
virtual size_t seek(ptrdiff_t offset, Origin whence=kOriginBegin)=0
Sets the stream position indicator for the stream.
Vertex position.
Definition: vertexbuffer.h:36
VertexBuffer * getVertexBuffer()
Definition: mesh.cpp:39
const UString & getName() const
Definition: xml.cpp:120
std::map< Common::UString, glm::vec4 > vectors
void loadTextures(const std::vector< Common::UString > &textures)
Definition: modelnode.cpp:340
static Texture * create(const Common::UString &name, bool deswizzle=false)
Create a texture from this image resource.
Definition: texture.cpp:323
void init()
General mesh initialisation, queuing the mesh for GL resource creation.
Definition: mesh.cpp:71
The Aurora texture manager.
void readMAOGFF(Common::SeekableReadStream *maoStream, MaterialObject &material)
Read a MAO encoded in a GFF file.
bool render
Render this mesh?
Definition: modelnode.h:183
Model_DragonAge(const Common::UString &name, ModelType type=kModelTypeObject)
static const uint32 kXMLID
Common::ScopedArray< byte > data
The mip map&#39;s data.
Definition: decoder.h:56
Common::UString name
The state&#39;s name.
Definition: model.h:204
Mathematical helpers.
const Children & getChildren() const
Return a list of children.
Definition: xml.cpp:132
4 unsigned integers of 10-bit, 10-bit, 10-bit, 2-bit.
Vertex color.
Definition: vertexbuffer.h:38
NodeList rootNodes
The nodes in the state without a parent.
Definition: model.h:209
Material Object.
Definition: types.h:296
bool equalsIgnoreCase(const UString &str) const
Definition: ustring.cpp:218
void setParent(ModelNode *parent)
Set the node&#39;s parent.
Definition: modelnode.cpp:143
void setVertexDeclInterleave(uint32 vertCount, VertexDecl &decl)
Set the interleaved vertex declaration for this buffer.
State * _currentState
The current state.
Definition: model.h:227
Utility functions to handle files used in BioWare&#39;s Aurora engine.
bool _render
Render the node?
Definition: modelnode.h:235
static const uint32 kVersion01
const GFF4Struct * getGeneric(uint32 field) const
Definition: gff4file.cpp:1378
static const uint32 kCRSTID
Common::UString _fileName
The model&#39;s file name.
Definition: model.h:218
static const uint32 kMAOID
std::vector< VertexAttrib > VertexDecl
Vertex data layout.
Definition: vertexbuffer.h:63
#define IGNORE_UNUSED_VARIABLES
Definition: system.h:423
Utility templates and functions for working with strings and streams.
int16_t int16
Definition: types.h:201
Exception that provides a stack of explanations.
Definition: error.h:36
void readTransformation(const ::Aurora::GFF4Struct &nodeGFF)
void decompress()
Manually decompress the texture image data.
Definition: decoder.cpp:242
Model * _model
The model this node belongs to.
Definition: modelnode.h:207
Common::UString _name
The model&#39;s name.
Definition: model.h:220
Vertex normal.
Definition: vertexbuffer.h:37
static void read4Float32(Common::ReadStream &stream, MeshDeclType type, float *&f)
std::vector< const GFF4Struct * > GFF4List
Definition: types.h:453
Handling version V4.0/V4.1 of BioWare&#39;s GFFs (generic file format).
static const uint32 kROTAID
Basic exceptions to throw.
Common::SeekableReadStream * getData(uint32 field) const
Return the raw data of the field as a Seekable(Sub)ReadStream.
Definition: gff4file.cpp:1407
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
ModelType
The display type of a model.
Definition: types.h:51
uint16_t uint16
Definition: types.h:202
Utility templates and functions.
static ImageDecoder * loadImage(const Common::UString &name, bool deswizzle=false)
Load an image in any of the common texture formats.
Definition: texture.cpp:401
void loadTextures(const std::vector< Common::UString > &textures, const MaterialObject &material)
std::map< Common::UString, Common::UString > textures
virtual void buildMaterial()
Definition: modelnode.cpp:1008
Base for BioWare&#39;s Aurora engine files.
void sanityCheckMeshChunk(const ::Aurora::GFF4Struct &meshChunk)
static void read3Float32(Common::ReadStream &stream, MeshDeclType type, float *&f)
Model Mesh Hierarchy.
Definition: types.h:297
static const uint32 kVersion10
PixelFormatRaw getFormatRaw() const
Return the image data&#39;s raw format.
Definition: decoder.cpp:180
virtual size_t skip(ptrdiff_t offset)
Skip the specified number of bytes, adding that offset to the current position in the stream...
Definition: readstream.h:317
const MipMap & getMipMap(size_t mipMap, size_t layer=0) const
Return a mip map.
Definition: decoder.cpp:204
Utility functions for working with differing string encodings.
XML parsing helpers, using libxml2.
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
static const GFF4Struct * findMeshChunk(const GFF4Struct &mshTop, const Common::UString &name)
MeshDeclUse
Usage information for a mesh declaration part.
StackException Exception
Definition: error.h:59
float _position[3]
Position of the node.
Definition: modelnode.h:221
NodeList nodeList
The nodes within the state.
Definition: model.h:206
static const uint32 kGFFID
void warning(const char *s,...)
Definition: util.cpp:33
Loading MMH+MSH files found in Dragon Age: Origins and Dragon Age 2.
void readMeshDecl(const ::Aurora::GFF4Struct &meshChunk, MeshDeclarations &meshDecl)
StateMap _stateMap
All states within this model, index by name.
Definition: model.h:226
Basic reading stream interfaces.
virtual size_t pos() const =0
Obtains the current value of the stream position indicator of the stream.
MeshDeclType
Type information for a mesh declaration part.
FORCEINLINE float readIEEEFloatLE()
Read a 32-bit IEEE float stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:230
static const uint32 kMSHID
#define MeshMan
Shortcut for accessing the shader manager.
Definition: meshman.h:74
UString toLower() const
Return a lowercased copy of the string.
Definition: ustring.cpp:481
void newState(ParserContext &ctx)
Graphics::Mesh::Mesh * rawMesh
Node raw mesh data.
Definition: modelnode.h:159
Common::UString _name
The node&#39;s name.
Definition: modelnode.h:216
void fixTexturesAlpha(const std::vector< Common::UString > &textures)
A texture as used in the Aurora engines.
void readChildren(Model_DragonAge::ParserContext &ctx, const ::Aurora::GFF4Struct &nodeGFF)
uint32_t uint32
Definition: types.h:204
UString debugTag(uint32 tag, bool trim)
Create an elaborate string from an integer tag, for debugging purposes.
Definition: strutil.cpp:117
void createVertexBuffer(const ::Aurora::GFF4Struct &meshChunk, Common::SeekableReadStream &vertexData, const MeshDeclarations &meshDecl)
GLvoid * getData()
Access buffer data.
float _orientation[4]
Orientation of the node.
Definition: modelnode.h:223
static const uint32 kDECLID
void fixTexturesHair(const std::vector< Common::UString > &textures)
const XMLNode & getRoot() const
Return the XML root node.
Definition: xml.cpp:108
A generic interface for image decoders.
Definition: decoder.h:48
static float rad2deg(float rad)
Definition: maths.h:93
static uint32 readHeaderID(Common::ReadStream &stream)
Read the ID out of a stream.
Definition: aurorafile.cpp:77
void finalize()
Finalize the loading procedure.
Definition: model.cpp:807
static const uint32 kFLT4ID
void setName(const Common::UString &name)
Definition: mesh.cpp:47
float readIEEEFloat16(uint16 value)
Read a half-precision 16-bit IEEE float, converting it into a 32-bit iEEE float.
Definition: util.cpp:198
void createIndexBuffer(const ::Aurora::GFF4Struct &meshChunk, Common::SeekableReadStream &indexData)
size_t getMipMapCount() const
Return the number of mip maps contained in the image.
Definition: decoder.cpp:188
void readMesh(Model_DragonAge::ParserContext &ctx, const ::Aurora::GFF4Struct &meshGFF)
void readMAOXML(Common::SeekableReadStream *maoStream, MaterialObject &material, const Common::UString &fileName)
Read a MAO encoded in an XML file.
StateList _stateList
All states within this model.
Definition: model.h:225
std::list< ModelNode_DragonAge * > nodes
uint32 size
The mip map&#39;s size in bytes.
Definition: decoder.h:54
Generic vertex attribute data.
Definition: vertexbuffer.h:43
Interface for a seekable & readable data stream.
Definition: readstream.h:265
static const uint32 kFLOTID
byte readByte()
Read an unsigned byte from the stream and return it.
Definition: readstream.h:92
IndexBuffer * getIndexBuffer()
Definition: mesh.cpp:43
4 normalized unsigned integers of 10-bit, 10-bit, 10-bit, 2-bit.
bool isCompressed() const
Is the image data compressed?
Definition: decoder.cpp:168
#define GfxMan
Shortcut for accessing the graphics manager.
Definition: graphics.h:299
void setSize(uint32 indexCount, uint32 indexSize, GLenum indexType)
Change buffer size.
Definition: indexbuffer.cpp:65
The global resource manager for Aurora resources.
Utility class for manipulating file paths.
void load(Model_DragonAge::ParserContext &ctx, const ::Aurora::GFF4Struct &nodeGFF)
static const uint32 kNODEID
static UString changeExtension(const UString &p, const UString &ext="")
Change a file name&#39;s extension.
Definition: filepath.cpp:99
unsigned int uint
Definition: types.h:211
static bool isType(const GFF4Struct *strct, uint32 type)
int32_t int32
Definition: types.h:203