xoreos  0.0.5
model_kotor.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 cchargin's KotOR model specs
26  * (<https://home.comcast.net/~cchargin/kotor/mdl_info.html>).
27  */
28 
29 #include "src/common/error.h"
30 #include "src/common/maths.h"
31 #include "src/common/readstream.h"
32 #include "src/common/encoding.h"
33 #include "src/common/strutil.h"
34 
35 #include "src/aurora/types.h"
36 #include "src/aurora/resman.h"
37 
43 
46 
48 
49 // This is included if a mesh wants a unique name.
50 #include "src/common/uuid.h"
51 
52 // Disable the "unused variable" warnings while most stuff is still stubbed
54 
55 static const int kNodeFlagHasHeader = 0x0001;
56 static const int kNodeFlagHasLight = 0x0002;
57 static const int kNodeFlagHasEmitter = 0x0004;
58 static const int kNodeFlagHasReference = 0x0010;
59 static const int kNodeFlagHasMesh = 0x0020;
60 static const int kNodeFlagHasSkin = 0x0040;
61 static const int kNodeFlagHasAnim = 0x0080;
62 static const int kNodeFlagHasDangly = 0x0100;
63 static const int kNodeFlagHasAABB = 0x0200;
64 
67 static const uint32 kControllerTypeScale = 36;
68 static const uint32 kControllerTypeColor = 76;
69 static const uint32 kControllerTypeRadius = 88;
72 static const uint32 kControllerTypeMultiplier = 140;
73 static const uint32 kControllerTypeAlphaEnd = 80;
75 static const uint32 kControllerTypeBirthRate = 88;
76 static const uint32 kControllerTypeBounce_Co = 92;
77 static const uint32 kControllerTypeColorEnd = 96;
78 static const uint32 kControllerTypeColorStart = 108;
80 static const uint32 kControllerTypeDrag = 124;
81 static const uint32 kControllerTypeFPS = 128;
82 static const uint32 kControllerTypeFrameEnd = 132;
83 static const uint32 kControllerTypeFrameStart = 136;
84 static const uint32 kControllerTypeGrav = 140;
85 static const uint32 kControllerTypeLifeExp = 144;
86 static const uint32 kControllerTypeMass = 148;
90 static const uint32 kControllerTypeRandVel = 164;
91 static const uint32 kControllerTypeSizeStart = 168;
92 static const uint32 kControllerTypeSizeEnd = 172;
94 static const uint32 kControllerTypeSizeEnd_Y = 180;
95 static const uint32 kControllerTypeSpread = 184;
96 static const uint32 kControllerTypeThreshold = 188;
97 static const uint32 kControllerTypeVelocity = 192;
98 static const uint32 kControllerTypeXSize = 196;
99 static const uint32 kControllerTypeYSize = 200;
104 static const uint32 kControllerTypeDetonate = 228;
105 static const uint32 kControllerTypeAlphaMid = 464;
106 static const uint32 kControllerTypeColorMid = 468;
110 static const uint32 kControllerTypeSizeMid = 484;
111 static const uint32 kControllerTypeSizeMid_Y = 488;
113 static const uint32 kControllerTypeAlpha = 128;
114 
115 namespace Graphics {
116 
117 namespace Aurora {
118 
120  const Common::UString &t, bool k2, bool x) :
121  mdl(0), mdx(0), state(0), texture(t), kotor2(k2), xbox(x), mdxStructSize(0), vertexCount(0),
122  offNodeData(0) {
123 
124  try {
125 
126  if (!(mdl = ResMan.getResource(name, ::Aurora::kFileTypeMDL)))
127  throw Common::Exception("No such MDL \"%s\"", name.c_str());
128  if (!(mdx = ResMan.getResource(name, ::Aurora::kFileTypeMDX)))
129  throw Common::Exception("No such MDX \"%s\"", name.c_str());
130 
131  } catch (...) {
132  delete mdl;
133  delete mdx;
134  throw;
135  }
136 }
137 
139  delete mdl;
140  delete mdx;
141 
142  clear();
143 }
144 
146  for (std::list<ModelNode_KotOR *>::iterator n = nodes.begin(); n != nodes.end(); ++n)
147  delete *n;
148  nodes.clear();
149 
150  delete state;
151  state = 0;
152 }
153 
154 
155 Model_KotOR::Model_KotOR(const Common::UString &name, bool kotor2, bool xbox, ModelType type,
156  const Common::UString &texture, ModelCache *modelCache) :
157  Model(type) {
158 
159  _fileName = name;
160  _positionRelative = true;
161 
162  ParserContext ctx(name, texture, kotor2, xbox);
163 
164  load(ctx);
165 
166  if (_skinned)
167  makeBoneNodeMap();
168 
169  loadSuperModel(modelCache, kotor2, xbox);
170 
171  finalize();
172 }
173 
175 }
176 
178  if (ctx.mdl->readUint32LE() != 0)
179  throw Common::Exception("Unsupported KotOR ASCII MDL");
180 
181  uint32 sizeModelData = ctx.mdl->readUint32LE();
182  uint32 sizeRawData = ctx.mdl->readUint32LE();
183 
184  ctx.offModelData = 12;
185  ctx.offRawData = ctx.offModelData + sizeModelData;
186 
187  ctx.mdl->skip(8); // Function pointers
188 
190  ctx.mdlName = _name;
191 
192  uint32 nodeHeadPointer = ctx.mdl->readUint32LE();
193  uint32 nodeCount = ctx.mdl->readUint32LE();
194 
195  ctx.mdl->skip(24 + 4); // Unknown + Reference count
196 
197  uint8 type = ctx.mdl->readByte();
198 
199  ctx.mdl->skip(3 + 2); // Padding + Unknown
200 
201  uint8 classification = ctx.mdl->readByte();
202  uint8 fogged = ctx.mdl->readByte();
203 
204  ctx.mdl->skip(4); // Unknown
205 
206  uint32 animOffset, animCount;
207  readArrayDef(*ctx.mdl, animOffset, animCount);
208 
209  ctx.mdl->skip(4); // Parent model pointer
210 
211  float boundingMin[3], boundingMax[3];
212 
213  boundingMin[0] = ctx.mdl->readIEEEFloatLE();
214  boundingMin[1] = ctx.mdl->readIEEEFloatLE();
215  boundingMin[2] = ctx.mdl->readIEEEFloatLE();
216 
217  boundingMax[0] = ctx.mdl->readIEEEFloatLE();
218  boundingMax[1] = ctx.mdl->readIEEEFloatLE();
219  boundingMax[2] = ctx.mdl->readIEEEFloatLE();
220 
221  float radius = ctx.mdl->readIEEEFloatLE();
222 
223  float modelScale = ctx.mdl->readIEEEFloatLE();
224 
226 
227  ctx.mdl->skip(4); // Root node pointer again
228 
229  ctx.mdl->skip(12); // Unknown
230 
231  uint32 nameOffset, nameCount;
232  readArrayDef(*ctx.mdl, nameOffset, nameCount);
233 
234  std::vector<uint32> nameOffsets;
235  readArray(*ctx.mdl, ctx.offModelData + nameOffset, nameCount, nameOffsets);
236 
237  readStrings(*ctx.mdl, nameOffsets, ctx.offModelData, ctx.names);
238 
239  newState(ctx);
240 
241  ModelNode_KotOR *rootNode = new ModelNode_KotOR(*this);
242  ctx.nodes.push_back(rootNode);
243 
244  ctx.mdl->seek(ctx.offModelData + nodeHeadPointer);
245  rootNode->load(ctx);
246 
247  addState(ctx);
248 
249  std::vector<uint32> animOffsets;
250  readArray(*ctx.mdl, ctx.offModelData + animOffset, animCount, animOffsets);
251 
252  for (std::vector<uint32>::const_iterator offset = animOffsets.begin(); offset != animOffsets.end(); ++offset) {
253  newState(ctx);
254 
255  if (readAnim(ctx, ctx.offModelData + *offset))
256  addState(ctx);
257 
258  ctx.clear();
259  }
260 }
261 
263  ctx.mdl->seek(offset);
264 
265  ctx.mdl->skip(8); // Function pointers
266 
268 
269  if (_stateMap.find(ctx.state->name) != _stateMap.end()) {
270  /* TODO: This happens on two models in module 001EBO, the first area of
271  * KotOR2 (the Ebon Hawk drifting in space):
272  * - "f3p1a" in model "S_Female01" (90 and 93 model nodes)
273  * - "walkinj" in model "P_HK47" (53 and 38 model nodes)
274  *
275  * We currently keep the first animation and throw away all subsequent
276  * duplicates. Maybe that's the right way, maybe not.
277  */
278 
279  warning("Duplicate animation \"%s\" in model \"%s\"", ctx.state->name.c_str(), _name.c_str());
280  return false;
281  }
282 
283  uint32 nodeHeadPointer = ctx.mdl->readUint32LE();
284  uint32 nodeCount = ctx.mdl->readUint32LE();
285 
286  ctx.mdl->skip(24 + 4); // Unknown + Reference count
287 
288  uint8 type = ctx.mdl->readByte();
289 
290  ctx.mdl->skip(3); // Padding + Unknown
291 
292  float animLength = ctx.mdl->readIEEEFloatLE();
293  float transTime = ctx.mdl->readIEEEFloatLE();
294 
296 
297  uint32 eventOffset, eventCount;
298  readArrayDef(*ctx.mdl, eventOffset, eventCount);
299 
300  ctx.mdl->skip(4); // Padding + Unknown
301 
302  ModelNode_KotOR *rootNode = new ModelNode_KotOR(*this);
303  ctx.nodes.push_back(rootNode);
304 
305  ctx.mdl->seek(ctx.offModelData + nodeHeadPointer);
306  rootNode->load(ctx);
307 
308  Animation *anim = new Animation();
309 
310  anim->setName(ctx.state->name);
311  anim->setLength(animLength);
312  anim->setTransTime(transTime);
313 
314  _animationMap.insert(std::make_pair(ctx.state->name, anim));
315 
316  for (std::list<ModelNode_KotOR *>::iterator n = ctx.nodes.begin(); n != ctx.nodes.end(); ++n) {
317  AnimNode *animnode = new AnimNode(*n);
318 
319  anim->addAnimNode(animnode);
320  }
321 
322  return true;
323 }
324 
325 void Model_KotOR::loadSuperModel(ModelCache *modelCache, bool kotor2, bool xbox) {
326  if (!_superModelName.empty() && _superModelName != "NULL") {
327  bool foundInCache = false;
328 
329  if (modelCache) {
330  ModelCache::iterator super = modelCache->find(_superModelName);
331  if (super != modelCache->end()) {
332  _superModel = super->second;
333 
334  foundInCache = true;
335  }
336  }
337 
338  if (!_superModel)
339  _superModel = new Model_KotOR(_superModelName, kotor2, xbox, _type, "", modelCache);
340 
341  if (modelCache && !foundInCache)
342  modelCache->insert(std::make_pair(_superModelName, _superModel));
343  }
344 }
345 
347  const std::vector<uint32> &offsets, uint32 offset,
348  std::vector<Common::UString> &strings) {
349 
350  size_t pos = mdl.pos();
351 
352  strings.reserve(offsets.size());
353  for (std::vector<uint32>::const_iterator o = offsets.begin(); o != offsets.end(); ++o) {
354  mdl.seek(offset + *o);
355 
356  strings.push_back(Common::readString(mdl, Common::kEncodingASCII));
357  }
358 
359  mdl.seek(pos);
360 }
361 
363  ctx.clear();
364 
365  ctx.state = new State;
366 }
367 
369  if (!ctx.state || ctx.nodes.empty()) {
370  ctx.clear();
371  return;
372  }
373 
374  for (std::list<ModelNode_KotOR *>::iterator n = ctx.nodes.begin();
375  n != ctx.nodes.end(); ++n) {
376 
377  ctx.state->nodeList.push_back(*n);
378  ctx.state->nodeMap.insert(std::make_pair((*n)->getName(), *n));
379 
380  if (!(*n)->getParent())
381  ctx.state->rootNodes.push_back(*n);
382  }
383 
384  _stateList.push_back(ctx.state);
385  _stateMap.insert(std::make_pair(ctx.state->name, ctx.state));
386 
387  if (!_currentState)
388  _currentState = ctx.state;
389 
390  ctx.state = 0;
391 
392  ctx.nodes.clear();
393 }
394 
396  const NodeList &nodes = getNodes();
397  for (NodeList::const_iterator n = nodes.begin();
398  n != nodes.end(); ++n) {
399  ModelNode *node = *n;
400  node->computeInverseBindPose();
401 
402  ModelNode::Mesh *mesh = node->getMesh();
403  if (mesh && mesh->skin) {
404  ModelNode::Skin *skin = mesh->skin;
405  skin->boneNodeMap.resize(skin->boneMappingCount);
406  for (uint16 i = 0; i < skin->boneMappingCount; ++i) {
407  int index = static_cast<int>(skin->boneMapping[i]);
408  if (index != -1)
409  skin->boneNodeMap[index] = getNode(i);
410  }
411  }
412  }
413 }
414 
415 
417  ModelNode(model) {
418 }
419 
421 }
422 
424  uint16 flags = ctx.mdl->readUint16LE();
425  uint16 superNode = ctx.mdl->readUint16LE();
426 
427  _nodeNumber = ctx.mdl->readUint16LE();
428 
429  if (_nodeNumber < ctx.names.size())
430  _name = ctx.names[_nodeNumber];
431 
432  ctx.mdl->skip(6 + 4); // Unknown + parent pointer
433 
434  _position [0] = ctx.mdl->readIEEEFloatLE();
435  _position [1] = ctx.mdl->readIEEEFloatLE();
436  _position [2] = ctx.mdl->readIEEEFloatLE();
437  _orientation[3] = Common::rad2deg(acos(ctx.mdl->readIEEEFloatLE()) * 2.0f);
438  _orientation[0] = ctx.mdl->readIEEEFloatLE();
439  _orientation[1] = ctx.mdl->readIEEEFloatLE();
440  _orientation[2] = ctx.mdl->readIEEEFloatLE();
441 
442  _positionBuffer[0] = _position[0];
443  _positionBuffer[1] = _position[1];
444  _positionBuffer[2] = _position[2];
445 
450 
451  uint32 childrenOffset, childrenCount;
452  Model::readArrayDef(*ctx.mdl, childrenOffset, childrenCount);
453 
454  std::vector<uint32> children;
455  Model::readArray(*ctx.mdl, ctx.offModelData + childrenOffset, childrenCount, children);
456 
457  uint32 controllerKeyOffset, controllerKeyCount;
458  Model::readArrayDef(*ctx.mdl, controllerKeyOffset, controllerKeyCount);
459 
460  uint32 controllerDataOffset, controllerDataCount;
461  Model::readArrayDef(*ctx.mdl, controllerDataOffset, controllerDataCount);
462 
463  std::vector<float> controllerDataFloat;
464  Model::readArray(*ctx.mdl, ctx.offModelData + controllerDataOffset,
465  controllerDataCount, controllerDataFloat);
466 
467  std::vector<uint32> controllerDataInt;
468  Model::readArray(*ctx.mdl, ctx.offModelData + controllerDataOffset,
469  controllerDataCount, controllerDataInt);
470 
471  readNodeControllers(ctx, ctx.offModelData + controllerKeyOffset,
472  controllerKeyCount, controllerDataFloat, controllerDataInt);
473 
474  if ((flags & 0xFC00) != 0)
475  throw Common::Exception("Unknown node flags %04X", flags);
476 
477  if (flags & kNodeFlagHasLight) {
478  // TODO: Light
479  ctx.mdl->skip(0x5C);
480  }
481 
482  if (flags & kNodeFlagHasEmitter) {
483  // TODO: Emitter
484  ctx.mdl->skip(0xD8);
485  }
486 
487  if (flags & kNodeFlagHasReference) {
488  // TODO: Reference
489  ctx.mdl->skip(0x44);
490  }
491 
492  if (flags & kNodeFlagHasMesh) {
493  readMesh(ctx);
494  }
495 
496  if (flags & kNodeFlagHasSkin) {
497  readSkin(ctx);
498  _model->setSkinned(true);
499  }
500 
501  if (flags & kNodeFlagHasAnim) {
502  // TODO: Anim
503  ctx.mdl->skip(0x38);
504  }
505 
506  if (flags & kNodeFlagHasDangly) {
507  // TODO: Dangly
508  ctx.mdl->skip(0x18);
509  }
510 
511  if (flags & kNodeFlagHasAABB) {
512  // TODO: AABB
513  ctx.mdl->skip(0x4);
514  }
515 
516  for (std::vector<uint32>::const_iterator child = children.begin(); child != children.end(); ++child) {
517  ModelNode_KotOR *childNode = new ModelNode_KotOR(*_model);
518  ctx.nodes.push_back(childNode);
519 
520  childNode->setParent(this);
521 
522  ctx.mdl->seek(ctx.offModelData + *child);
523  childNode->load(ctx);
524  }
525 
526  if (_mesh && _mesh->data) {
527  Common::UString meshName = ctx.mdlName;
528  meshName += ".";
529  if (ctx.state->name.size() != 0) {
530  meshName += ctx.state->name;
531  } else {
532  meshName += "xoreos.default";
533  }
534  meshName += ".";
535  meshName += _name;
536 #ifdef MESH_KOTOR_USE_MESHMAN
537 
546  Graphics::Mesh::Mesh *mystery_mesh = MeshMan.getMesh(meshName);
547  if (ctx.state->name.size() == 0) {
548  while (mystery_mesh) {
549  meshName += "_";
550  mystery_mesh = MeshMan.getMesh(meshName);
551  }
552  }
553 
554  if (!mystery_mesh) {
555  Graphics::Mesh::Mesh *checkMesh = MeshMan.getMesh(meshName);
556  if (checkMesh) {
557  delete _mesh->data->rawMesh;
558  _mesh->data->rawMesh = checkMesh;
559  } else {
560  _mesh->data->rawMesh->setName(meshName);
561  _mesh->data->rawMesh->init();
562  MeshMan.addMesh(_mesh->data->rawMesh);
563  }
564  } else {
565  delete _mesh->data->rawMesh;
566  _mesh->data->rawMesh = mystery_mesh;
567  }
568 #else
569 
575  meshName += "#" + Common::generateIDRandomString();
576  _mesh->data->rawMesh->setName(meshName);
577  _mesh->data->rawMesh->init();
578 
579  MeshMan.addMesh(_mesh->data->rawMesh);
580 #endif
581 
582  if (GfxMan.isRendererExperimental())
583  buildMaterial();
584  }
585 }
586 
588  uint32 offset, uint32 count, std::vector<float> &dataFloat, std::vector<uint32> &dataInt) {
589  uint32 pos = ctx.mdl->seek(offset);
590  for (uint32 i = 0; i < count; i++) {
591  uint32 type = ctx.mdl->readUint32LE();
592  ctx.mdl->skip(2);
593  uint16 rowCount = ctx.mdl->readUint16LE();
594  uint16 timeIndex = ctx.mdl->readUint16LE();
595  uint16 dataIndex = ctx.mdl->readUint16LE();
596  uint8 columnCount = ctx.mdl->readByte();
597  ctx.mdl->skip(3);
598  switch (type) {
600  readPositionController(columnCount, rowCount, timeIndex, dataIndex, dataFloat);
601  break;
603  readOrientationController(columnCount, rowCount, timeIndex, dataIndex, dataFloat, dataInt);
604  break;
605  }
606  }
607  ctx.mdl->seek(pos);
608 }
609 
612 }
613 
614 void ModelNode_KotOR::readPositionController(uint8 columnCount, uint16 rowCount, uint16 timeIndex,
615  uint16 dataIndex, std::vector<float> &data) {
616  bool bezier = columnCount & 16;
617  switch (columnCount) {
618  case 3:
619  case 19:
620  for (int r = 0; r < rowCount; r++) {
622  p.time = data[timeIndex + r];
623  int index = dataIndex + (bezier ? 9 : 3) * r;
624  p.x = data[index + 0];
625  p.y = data[index + 1];
626  p.z = data[index + 2];
627  _positionFrames.push_back(p);
628  }
629  break;
630  default:
631  warning("Position controller with %d values", columnCount);
632  break;
633  }
634 }
635 
637  uint16 timeIndex, uint16 dataIndex, std::vector<float> &dataFloat, std::vector<uint32> &dataInt) {
638  switch (columnCount) {
639  case 2:
640  for (int r = 0; r < rowCount; r++) {
642  q.time = dataFloat[timeIndex + r];
643 
644  uint32 temp = dataInt[dataIndex + r];
645  q.x = 1.0f - static_cast<float>(temp & 0x7ff) / 1023.0f;
646  q.y = 1.0f - static_cast<float>((temp >> 11) & 0x7ff) / 1023.0f;
647  q.z = 1.0f - static_cast<float>(temp >> 22) / 511.0f;
648 
649  float temp2 = q.x * q.x + q.y * q.y + q.z * q.z;
650  if (temp2 < 1.0f)
651  q.q = -sqrtf(1.0f - temp2);
652  else {
653  temp2 = sqrtf(temp2);
654  q.x = q.x / temp2;
655  q.y = q.y / temp2;
656  q.z = q.z / temp2;
657  q.q = 0.0f;
658  }
659 
660  _orientationFrames.push_back(q);
661  }
662  break;
663  case 4:
664  for (int r = 0; r < rowCount; r++) {
666  q.time = dataFloat[timeIndex + r];
667  int index = dataIndex + 4 * r;
668  q.x = dataFloat[index + 0];
669  q.y = dataFloat[index + 1];
670  q.z = dataFloat[index + 2];
671  q.q = dataFloat[index + 3];
672  _orientationFrames.push_back(q);
673  }
674  break;
675  default:
676  warning("Orientation controller with %d values", columnCount);
677  break;
678  }
679 }
680 
682  size_t P = ctx.mdl->pos();
683 
684  ctx.mdl->skip(8); // Function pointers
685 
686  uint32 facesOffset, facesCount;
687  Model::readArrayDef(*ctx.mdl, facesOffset, facesCount);
688 
689  float boundingMin[3], boundingMax[3];
690 
691  boundingMin[0] = ctx.mdl->readIEEEFloatLE();
692  boundingMin[1] = ctx.mdl->readIEEEFloatLE();
693  boundingMin[2] = ctx.mdl->readIEEEFloatLE();
694 
695  boundingMax[0] = ctx.mdl->readIEEEFloatLE();
696  boundingMax[1] = ctx.mdl->readIEEEFloatLE();
697  boundingMax[2] = ctx.mdl->readIEEEFloatLE();
698 
699  float radius = ctx.mdl->readIEEEFloatLE();
700 
701  float pointsAverage[3];
702  pointsAverage[0] = ctx.mdl->readIEEEFloatLE();
703  pointsAverage[1] = ctx.mdl->readIEEEFloatLE();
704  pointsAverage[2] = ctx.mdl->readIEEEFloatLE();
705 
706  _mesh = new Mesh();
707 
708  _mesh->diffuse[0] = ctx.mdl->readIEEEFloatLE();
709  _mesh->diffuse[1] = ctx.mdl->readIEEEFloatLE();
710  _mesh->diffuse[2] = ctx.mdl->readIEEEFloatLE();
711 
712  _mesh->ambient[0] = ctx.mdl->readIEEEFloatLE();
713  _mesh->ambient[1] = ctx.mdl->readIEEEFloatLE();
714  _mesh->ambient[2] = ctx.mdl->readIEEEFloatLE();
715 
716  _mesh->specular[0] = 0;
717  _mesh->specular[1] = 0;
718  _mesh->specular[2] = 0;
719 
720  uint32 transparencyHint = ctx.mdl->readUint32LE();
721 
722  _mesh->hasTransparencyHint = true;
723  _mesh->transparencyHint = (transparencyHint != 0);
724 
725  std::vector<Common::UString> textures;
726 
727  textures.push_back(Common::readStringFixed(*ctx.mdl, Common::kEncodingASCII, 32));
728  textures.push_back(Common::readStringFixed(*ctx.mdl, Common::kEncodingASCII, 32));
729 
730  ctx.mdl->skip(24); // Unknown
731 
732  ctx.mdl->skip(12); // Vertex indices counts
733 
734  uint32 offOffVerts, offOffVertsCount;
735  Model::readArrayDef(*ctx.mdl, offOffVerts, offOffVertsCount);
736 
737  if (offOffVertsCount > 1)
738  throw Common::Exception("Face offsets offsets count wrong (%d)", offOffVertsCount);
739 
740  ctx.mdl->skip(12); // Unknown
741 
742  ctx.mdl->skip(24 + 16); // Unknown
743 
744  ctx.mdxStructSize = ctx.mdl->readUint32LE();
745 
746  ctx.mdl->skip(8); // Unknown
747 
748  uint32 offNormals = ctx.mdl->readUint32LE();
749 
750  ctx.mdl->skip(4); // Unknown
751 
752  uint32 offUV[2];
753  offUV[0] = ctx.mdl->readUint32LE();
754  offUV[1] = ctx.mdl->readUint32LE();
755 
756  ctx.mdl->skip(24); // Unknown
757 
758  ctx.vertexCount = ctx.mdl->readUint16LE();
759  uint16 textureCount = ctx.mdl->readUint16LE();
760 
761  ctx.mdl->skip(2);
762 
763  byte unknownFlag1 = ctx.mdl->readByte();
764  _mesh->shadow = ctx.mdl->readByte() == 1;
765  byte unknownFlag2 = ctx.mdl->readByte();
766  _mesh->render = ctx.mdl->readByte() == 1;
767 
768  ctx.mdl->skip(10);
769 
770  if (ctx.kotor2)
771  ctx.mdl->skip(8);
772 
773  ctx.offNodeData = ctx.mdl->readUint32LE();
774 
775  ctx.mdl->skip(4);
776 
777  if ((offOffVertsCount < 1) || (ctx.vertexCount == 0) || (facesCount == 0))
778  return;
779 
780  _render = _mesh->render;
781  _mesh->data = new MeshData();
784 
785  uint32 endPos = ctx.mdl->pos();
786 
787  if (textureCount > 2) {
788  warning("Model_KotOR::readMesh(): textureCount > 2 (%d)", textureCount);
789  textureCount = 2;
790  }
791 
792  if ((textureCount > 0) && !ctx.texture.empty())
793  textures[0] = ctx.texture;
794 
795  textures.resize(textureCount);
796  loadTextures(textures);
797 
798 
799  // Read vertices (interleaved)
800 
801  VertexDecl vertexDecl;
802 
803  vertexDecl.push_back(VertexAttrib(VPOSITION, 3, GL_FLOAT));
804  vertexDecl.push_back(VertexAttrib(VNORMAL , 3, GL_FLOAT));
805  for (uint t = 0; t < textureCount; t++)
806  vertexDecl.push_back(VertexAttrib(VTCOORD + t , 2, GL_FLOAT));
807 
809  _mesh->data->initialVertexCoords.resize(3 * ctx.vertexCount);
810 
811  float *v = reinterpret_cast<float *>(_mesh->data->rawMesh->getVertexBuffer()->getData());
812  float *iv = _mesh->data->initialVertexCoords.data();
813 
814  for (uint32 i = 0; i < ctx.vertexCount; i++) {
815  // Position
816  ctx.mdx->seek(ctx.offNodeData + i * ctx.mdxStructSize);
817  iv[0] = ctx.mdx->readIEEEFloatLE();
818  iv[1] = ctx.mdx->readIEEEFloatLE();
819  iv[2] = ctx.mdx->readIEEEFloatLE();
820  *v++ = iv[0];
821  *v++ = iv[1];
822  *v++ = iv[2];
823  iv += 3;
824 
825  // Normal
826  //ctx.mdx->seek(offNodeData + i * mdxStructSize + offNormals);
827  *v++ = ctx.mdx->readIEEEFloatLE();
828  *v++ = ctx.mdx->readIEEEFloatLE();
829  *v++ = ctx.mdx->readIEEEFloatLE();
830 
831  // TexCoords
832  for (uint16 t = 0; t < textureCount; t++) {
833  if (offUV[t] != 0xFFFFFFFF) {
834  ctx.mdx->seek(ctx.offNodeData + i * ctx.mdxStructSize + offUV[t]);
835  *v++ = ctx.mdx->readIEEEFloatLE();
836  *v++ = ctx.mdx->readIEEEFloatLE();
837  } else {
838  *v++ = 0.0f;
839  *v++ = 0.0f;
840  }
841  }
842  }
843 
844 
845  // Read faces
846 
847  ctx.mdl->seek(ctx.offModelData + offOffVerts);
848  uint32 offVerts = ctx.mdl->readUint32LE();
849 
850  ctx.mdl->seek(ctx.offModelData + offVerts);
851 
852  _mesh->data->rawMesh->getIndexBuffer()->setSize(facesCount * 3, sizeof(uint16), GL_UNSIGNED_SHORT);
853 
854  uint16 *f = reinterpret_cast<uint16 *>(_mesh->data->rawMesh->getIndexBuffer()->getData());
855  for (uint32 i = 0; i < facesCount * 3; i++)
856  f[i] = ctx.mdl->readUint16LE();
857 
858  createBound();
859 
860  ctx.mdl->seek(endPos);
861 }
862 
864  /* The models found in the Xbox versions store bone indices as int16,
865  * while the Windows/Mac/Linux versions use floats. */
866 
867  ctx.mdl->skip(ctx.xbox ? 8 : 12);
868  uint32 mdxOffsetBoneWeights = ctx.mdl->readUint32LE();
869  uint32 mdxOffsetBoneMappingId = ctx.mdl->readUint32LE();
870  uint32 boneMappingOffset = ctx.mdl->readUint32LE();
871  uint32 boneMappingCount = ctx.mdl->readUint32LE();
872  ctx.mdl->skip(72);
873 
874  _mesh->skin = new Skin();
875  _mesh->skin->boneMappingCount = boneMappingCount;
876 
877  const uint32 pos = ctx.mdl->seek(ctx.offModelData + boneMappingOffset);
878 
879  for (uint32 i = 0; i < boneMappingCount; i++) {
880  const float index = ctx.xbox ? static_cast<float>(ctx.mdl->readSint16LE()) : ctx.mdl->readIEEEFloatLE();
881 
882  _mesh->skin->boneMapping.push_back(index);
883  }
884 
885  ctx.mdl->seek(pos);
886 
887  std::vector<float> &boneWeights = _mesh->skin->boneWeights;
888  std::vector<float> &boneMappingId = _mesh->skin->boneMappingId;
889 
890  for (int i = 0; i < ctx.vertexCount; i++) {
891  // Bone weights
892  ctx.mdx->seek(ctx.offNodeData + i * ctx.mdxStructSize + mdxOffsetBoneWeights);
893  boneWeights.push_back(ctx.mdx->readIEEEFloatLE());
894  boneWeights.push_back(ctx.mdx->readIEEEFloatLE());
895  boneWeights.push_back(ctx.mdx->readIEEEFloatLE());
896  boneWeights.push_back(ctx.mdx->readIEEEFloatLE());
897 
898  // Bone mapping identifiers
899  ctx.mdx->seek(ctx.offNodeData + i * ctx.mdxStructSize + mdxOffsetBoneMappingId);
900  boneMappingId.push_back(ctx.xbox ? static_cast<float>(ctx.mdx->readSint16LE()) : ctx.mdx->readIEEEFloatLE());
901  boneMappingId.push_back(ctx.xbox ? static_cast<float>(ctx.mdx->readSint16LE()) : ctx.mdx->readIEEEFloatLE());
902  boneMappingId.push_back(ctx.xbox ? static_cast<float>(ctx.mdx->readSint16LE()) : ctx.mdx->readIEEEFloatLE());
903  boneMappingId.push_back(ctx.xbox ? static_cast<float>(ctx.mdx->readSint16LE()) : ctx.mdx->readIEEEFloatLE());
904  }
905 }
906 
907 } // End of namespace Aurora
908 
909 } // End of namespace Graphics
static const uint32 kControllerTypeBounce_Co
Definition: model_kotor.cpp:76
#define ResMan
Shortcut for accessing the sound manager.
Definition: resman.h:557
GLvoid * getData()
Access buffer data.
Definition: indexbuffer.cpp:78
A node within an animation.
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
void newState(ParserContext &ctx)
Generic image decoder interface.
static const uint32 kControllerTypePercentEnd
std::vector< float > boneMapping
Definition: modelnode.h:149
NodeMap nodeMap
The nodes within the state, indexed by name.
Definition: model.h:207
static const uint32 kControllerTypeBlurLength
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
static const int kNodeFlagHasEmitter
Definition: model_kotor.cpp:57
static const uint32 P[kRoundCount+2]
Definition: blowfish.cpp:93
Model_KotOR(const Common::UString &name, bool kotor2, bool xbox, ModelType type=kModelTypeObject, const Common::UString &texture="", ModelCache *modelCache=0)
A class holding an UTF-8 string.
Definition: ustring.h:48
static const uint32 kControllerTypePercentMid
Geometry, BioWare model.
Definition: types.h:73
void setLength(float length)
Definition: animation.cpp:62
static const int kNodeFlagHasReference
Definition: model_kotor.cpp:58
virtual size_t seek(ptrdiff_t offset, Origin whence=kOriginBegin)=0
Sets the stream position indicator for the stream.
An animation to be applied to a model.
static const uint32 kControllerTypeOrientation
Definition: model_kotor.cpp:66
friend class Animation
Definition: model.h:307
Vertex position.
Definition: vertexbuffer.h:36
static const uint32 kControllerTypeAlpha
static const uint32 kControllerTypeSpread
Definition: model_kotor.cpp:95
VertexBuffer * getVertexBuffer()
Definition: mesh.cpp:39
std::vector< float > boneWeights
Definition: modelnode.h:151
void makeBoneNodeMap()
Map bone indices to model node references for better peformance.
static const uint32 kControllerTypeScale
Definition: model_kotor.cpp:67
static const uint32 kControllerTypeSizeEnd
Definition: model_kotor.cpp:92
bool readAnim(ParserContext &ctx, uint32 offset)
void loadTextures(const std::vector< Common::UString > &textures)
Definition: modelnode.cpp:340
uint8_t uint8
Definition: types.h:200
static const uint32 kControllerTypePosition
Definition: model_kotor.cpp:65
void init()
General mesh initialisation, queuing the mesh for GL resource creation.
Definition: mesh.cpp:71
The Aurora texture manager.
static const uint32 kControllerTypeRandVel
Definition: model_kotor.cpp:90
static const int kNodeFlagHasAABB
Definition: model_kotor.cpp:63
bool render
Render this mesh?
Definition: modelnode.h:183
Common::UString name
The state&#39;s name.
Definition: model.h:204
Mathematical helpers.
NodeList rootNodes
The nodes in the state without a parent.
Definition: model.h:209
void setParent(ModelNode *parent)
Set the node&#39;s parent.
Definition: modelnode.cpp:143
static const uint32 kControllerTypeCombineTime
Definition: model_kotor.cpp:79
void setVertexDeclInterleave(uint32 vertCount, VertexDecl &decl)
Set the interleaved vertex declaration for this buffer.
State * _currentState
The current state.
Definition: model.h:227
Common::SeekableReadStream * mdl
Definition: model_kotor.h:50
Utility functions for generating unique IDs.
Diffuse textures first, then blend the environment map in.
Definition: modelnode.h:131
bool _render
Render the node?
Definition: modelnode.h:235
Geometry, model mesh data.
Definition: types.h:184
static const uint32 kControllerTypeMass
Definition: model_kotor.cpp:86
Common::UString _fileName
The model&#39;s file name.
Definition: model.h:218
static const uint32 kControllerTypeThreshold
Definition: model_kotor.cpp:96
std::vector< VertexAttrib > VertexDecl
Vertex data layout.
Definition: vertexbuffer.h:63
static const uint32 kControllerTypeVelocity
Definition: model_kotor.cpp:97
#define IGNORE_UNUSED_VARIABLES
Definition: system.h:423
Utility templates and functions for working with strings and streams.
static const uint32 kControllerTypeP2P_Bezier3
Definition: model_kotor.cpp:88
static const uint32 kControllerTypeDrag
Definition: model_kotor.cpp:80
std::vector< ModelNode * > boneNodeMap
Definition: modelnode.h:153
Exception that provides a stack of explanations.
Definition: error.h:36
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
ParserContext(const Common::UString &name, const Common::UString &t, bool k2, bool x)
Basic exceptions to throw.
static const uint32 kControllerTypeLightningDelay
static const uint32 kControllerTypeColorEnd
Definition: model_kotor.cpp:77
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
static const uint32 kControllerTypeGrav
Definition: model_kotor.cpp:84
static const uint32 kControllerTypeSizeMid_Y
AnimationMap _animationMap
Map of all animations in this model.
Definition: model.h:231
std::vector< float > initialVertexCoords
Initial node vertex coordinates.
Definition: modelnode.h:161
void load(Model_KotOR::ParserContext &ctx)
ModelType
The display type of a model.
Definition: types.h:51
static const uint32 kControllerTypeShadowRadius
Definition: model_kotor.cpp:70
ModelType _type
The model&#39;s type.
Definition: model.h:216
uint16_t uint16
Definition: types.h:202
void addState(ParserContext &ctx)
static const uint32 kControllerTypeYSize
Definition: model_kotor.cpp:99
void setTransTime(float transtime)
Definition: animation.cpp:70
static const int kNodeFlagHasSkin
Definition: model_kotor.cpp:60
static const uint32 kControllerTypeAlphaStart
Definition: model_kotor.cpp:74
void loadSuperModel(ModelCache *modelCache, bool kotor2, bool xbox)
virtual void buildMaterial()
Definition: modelnode.cpp:1008
static void readArray(Common::SeekableReadStream &stream, uint32 offset, uint32 count, std::vector< T > &values)
Definition: model.cpp:902
void readStrings(Common::SeekableReadStream &mdl, const std::vector< uint32 > &offsets, uint32 offset, std::vector< Common::UString > &strings)
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
static const uint32 kControllerTypeMultiplier
Definition: model_kotor.cpp:72
static const uint32 kControllerTypeLifeExp
Definition: model_kotor.cpp:85
static const uint32 kControllerTypeBirthRate
Definition: model_kotor.cpp:75
static const uint32 kControllerTypeVerticalDisplacement
Definition: model_kotor.cpp:71
static const uint32 kControllerTypeAlphaMid
void readNodeControllers(Model_KotOR::ParserContext &ctx, uint32 offset, uint32 count, std::vector< float > &dataFloat, std::vector< uint32 > &dataInt)
static const uint32 kControllerTypeParticleRot
Definition: model_kotor.cpp:89
float ambient[3]
Ambient color.
Definition: modelnode.h:173
Utility functions for working with differing string encodings.
The global shader material manager.
bool empty() const
Is the string empty?
Definition: ustring.cpp:245
The global shader surface manager.
static const uint32 kControllerTypeSizeMid
const std::list< ModelNode * > & getNodes()
Get all nodes in the current state.
Definition: model.cpp:472
float specular[3]
Specular color.
Definition: modelnode.h:175
Common::SeekableReadStream * mdx
Definition: model_kotor.h:51
static const uint32 kControllerTypeSizeEnd_Y
Definition: model_kotor.cpp:94
StackException Exception
Definition: error.h:59
static const uint32 kControllerTypeLightningScale
std::vector< QuaternionKeyFrame > _orientationFrames
Keyframes for orientation animation.
Definition: modelnode.h:229
FORCEINLINE int16 readSint16LE()
Read a signed 16-bit word stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:188
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 kControllerTypeSelfIllumColor
void warning(const char *s,...)
Definition: util.cpp:33
Loading MDL files found in Star Wars: Knights of the Old Republic.
void readPositionController(uint8 columnCount, uint16 rowCount, uint16 timeIndex, uint16 dataIndex, std::vector< float > &data)
StateMap _stateMap
All states within this model, index by name.
Definition: model.h:226
Basic reading stream interfaces.
std::list< ModelNode * > NodeList
Definition: model.h:197
virtual size_t pos() const =0
Obtains the current value of the stream position indicator of the stream.
std::vector< Common::UString > names
Definition: model_kotor.h:67
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 kControllerTypeFrameStart
Definition: model_kotor.cpp:83
void readOrientationController(uint8 columnCount, uint16 rowCount, uint16 timeIndex, uint16 dataIndex, std::vector< float > &dataFloat, std::vector< uint32 > &dataInt)
std::vector< float > boneMappingId
Definition: modelnode.h:152
#define MeshMan
Shortcut for accessing the shader manager.
Definition: meshman.h:74
static const uint32 kControllerTypeXSize
Definition: model_kotor.cpp:98
Basic type definitions to handle files used in BioWare&#39;s Aurora engine.
Plain, unextended ASCII (7bit clean).
Definition: encoding.h:40
static const uint32 kControllerTypeSizeStart
Definition: model_kotor.cpp:91
static const int kNodeFlagHasLight
Definition: model_kotor.cpp:56
Graphics::Mesh::Mesh * rawMesh
Node raw mesh data.
Definition: modelnode.h:159
static const uint32 kControllerTypeColorStart
Definition: model_kotor.cpp:78
Common::UString _name
The node&#39;s name.
Definition: modelnode.h:216
static const int kNodeFlagHasAnim
Definition: model_kotor.cpp:61
static const int kNodeFlagHasMesh
Definition: model_kotor.cpp:59
A texture as used in the Aurora engines.
bool shadow
Does the node have a shadow?
Definition: modelnode.h:184
EnvironmentMapMode envMapMode
The way the environment map is applied.
Definition: modelnode.h:166
uint32_t uint32
Definition: types.h:204
static const uint32 kControllerTypeLightningRadius
static const uint32 kControllerTypeSizeStart_Y
Definition: model_kotor.cpp:93
static void readArrayDef(Common::SeekableReadStream &stream, uint32 &offset, uint32 &count)
Definition: model.cpp:886
GLvoid * getData()
Access buffer data.
void readSkin(Model_KotOR::ParserContext &ctx)
float diffuse[3]
Diffuse color.
Definition: modelnode.h:174
void setName(Common::UString &name)
Definition: animation.cpp:58
float _orientation[4]
Orientation of the node.
Definition: modelnode.h:223
Model * _superModel
The actual super model.
Definition: model.h:223
UString readString(SeekableReadStream &stream, Encoding encoding)
Read a string with the given encoding of a stream.
Definition: encoding.cpp:287
void addAnimNode(AnimNode *node)
Definition: animation.cpp:100
static float rad2deg(float rad)
Definition: maths.h:93
void finalize()
Finalize the loading procedure.
Definition: model.cpp:807
static const uint32 kControllerTypeFPS
Definition: model_kotor.cpp:81
UString readStringFixed(SeekableReadStream &stream, Encoding encoding, size_t length)
Read length bytes as a string with the given encoding out of a stream.
Definition: encoding.cpp:297
void readMesh(Model_KotOR::ParserContext &ctx)
void setName(const Common::UString &name)
Definition: mesh.cpp:47
std::vector< PositionKeyFrame > _positionFrames
Keyframes for position animation.
Definition: modelnode.h:228
static const uint32 kControllerTypeAlphaEnd
Definition: model_kotor.cpp:73
static const uint32 kControllerTypeDetonate
UString generateIDRandomString()
Definition: uuid.cpp:37
static const uint32 kControllerTypeColor
Definition: model_kotor.cpp:68
ModelNode * getNode(const Common::UString &node)
Get the specified node, from the current state.
Definition: model.cpp:379
StateList _stateList
All states within this model.
Definition: model.h:225
static const int kNodeFlagHasDangly
Definition: model_kotor.cpp:62
Common::UString _superModelName
Name of the super model.
Definition: model.h:222
static const uint32 kControllerTypeRadius
Definition: model_kotor.cpp:69
Generic vertex attribute data.
Definition: vertexbuffer.h:43
Interface for a seekable & readable data stream.
Definition: readstream.h:265
void load(ParserContext &ctx)
static const uint32 kControllerTypeFrameEnd
Definition: model_kotor.cpp:82
byte readByte()
Read an unsigned byte from the stream and return it.
Definition: readstream.h:92
IndexBuffer * getIndexBuffer()
Definition: mesh.cpp:43
static IGNORE_UNUSED_VARIABLES const int kNodeFlagHasHeader
Definition: model_kotor.cpp:55
#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.
uint8 byte
Definition: types.h:209
static const uint32 kControllerTypeP2P_Bezier2
Definition: model_kotor.cpp:87
void setSkinned(bool skinned)
Set the flag if the model has skinned animations.
Definition: model.cpp:616
static const uint32 kControllerTypePercentStart
unsigned int uint
Definition: types.h:211
std::list< ModelNode_KotOR * > nodes
Definition: model_kotor.h:57
static const uint32 kControllerTypeColorMid