TDME2  1.9.200
TMReader.cpp
Go to the documentation of this file.
2 
3 #include <array>
4 #include <memory>
5 #include <string>
6 #include <unordered_map>
7 #include <vector>
8 
9 #include <tdme/tdme.h>
11 #include <tdme/engine/Texture.h>
14 #include <tdme/engine/Color4.h>
15 #include <tdme/engine/model/Face.h>
21 #include <tdme/engine/model/Node.h>
29 #include <tdme/math/Matrix3x3.h>
30 #include <tdme/math/Matrix4x4.h>
31 #include <tdme/math/Vector3.h>
34 
35 using std::array;
36 using std::make_unique;
37 using std::string;
38 using std::to_string;
39 using std::unordered_map;
40 using std::unique_ptr;
41 using std::vector;
42 
68 
69 Model* TMReader::read(const string& pathName, const string& fileName, bool useBC7TextureCompression)
70 {
71  vector<uint8_t> data;
72  FileSystem::getInstance()->getContent(pathName, fileName, data);
73  return read(data, pathName, fileName, useBC7TextureCompression);
74 }
75 
76 Model* TMReader::read(const vector<uint8_t>& data, const string& pathName, const string& fileName, bool useBC7TextureCompression) {
77  //
78  class EmbeddedTexturesRAII {
79  public:
80  EmbeddedTexturesRAII(const unordered_map<string, Texture*>& embeddedTextures): embeddedTextures(embeddedTextures) {}
81  ~EmbeddedTexturesRAII() {
82  for (const auto& [embeddedTextureId, embeddedTexture]: embeddedTextures) embeddedTexture->releaseReference();
83  }
84  private:
85  const unordered_map<string, Texture*>& embeddedTextures;
86  };
87  //
88  unordered_map<string, Texture*> embeddedTextures;
89  EmbeddedTexturesRAII embeddedTexturesRAII(embeddedTextures);
90  //
91  TMReaderInputStream is(&data);
92  auto fileId = is.readString();
93  if (fileId.length() == 0 || fileId != "TDME Model") {
94  throw ModelFileIOException("File is not a TDME model file, file id = '" +fileId + "'");
95  }
96  array<uint8_t, 3> version;
97  version[0] = is.readByte();
98  version[1] = is.readByte();
99  version[2] = is.readByte();
100  if ((version[0] != 1 || version[1] != 0 || version[2] != 0) &&
101  (version[0] != 1 || version[1] != 9 || version[2] != 9) &&
102  (version[0] != 1 || version[1] != 9 || version[2] != 10) &&
103  (version[0] != 1 || version[1] != 9 || version[2] != 11) &&
104  (version[0] != 1 || version[1] != 9 || version[2] != 12) &&
105  (version[0] != 1 || version[1] != 9 || version[2] != 13) &&
106  (version[0] != 1 || version[1] != 9 || version[2] != 14) &&
107  (version[0] != 1 || version[1] != 9 || version[2] != 15) &&
108  (version[0] != 1 || version[1] != 9 || version[2] != 16) &&
109  (version[0] != 1 || version[1] != 9 || version[2] != 17) &&
110  (version[0] != 1 || version[1] != 9 || version[2] != 18) &&
111  (version[0] != 1 || version[1] != 9 || version[2] != 19) &&
112  (version[0] != 1 || version[1] != 9 || version[2] != 20)) {
113  throw ModelFileIOException(
114  "Version mismatch, should be 1.0.0, 1.9.9, 1.9.10, 1.9.11, 1.9.12, 1.9.13, 1.9.14, 1.9.15, 1.9.16, 1.9.17, 1.9.18, 1.9.19, 1.9.20 but is " +
115  to_string(version[0]) +
116  "." +
117  to_string(version[1]) +
118  "." +
119  to_string(version[2])
120  );
121  }
122  auto name = is.readString();
123  auto upVector = UpVector::valueOf(is.readString());
124  auto rotationOrder = RotationOrder::valueOf(is.readString());
125  auto shaderModel = ShaderModel::SPECULAR;
126  if ((version[0] == 1 && version[1] == 9 && version[2] == 14) ||
127  (version[0] == 1 && version[1] == 9 && version[2] == 15) ||
128  (version[0] == 1 && version[1] == 9 && version[2] == 16) ||
129  (version[0] == 1 && version[1] == 9 && version[2] == 17) ||
130  (version[0] == 1 && version[1] == 9 && version[2] == 18) ||
131  (version[0] == 1 && version[1] == 9 && version[2] == 19) ||
132  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
133  shaderModel = ShaderModel::valueOf(is.readString());
134  }
135  auto embedSpecularTextures = false;
136  auto embedPBRTextures = false;
137  if ((version[0] == 1 && version[1] == 9 && version[2] == 18) ||
138  (version[0] == 1 && version[1] == 9 && version[2] == 19) ||
139  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
140  embedSpecularTextures = is.readBoolean();
141  embedPBRTextures = is.readBoolean();
142  }
143  array<float, 3> boundingBoxMinXYZ;
144  is.readFloatArray(boundingBoxMinXYZ);
145  array<float, 3> boundingBoxMaxXYZ;
146  is.readFloatArray(boundingBoxMaxXYZ);
147  auto boundingBox = make_unique<BoundingBox>(Vector3(boundingBoxMinXYZ), Vector3(boundingBoxMaxXYZ));
148  auto model = make_unique<Model>(
149  fileName,
150  fileName.empty() == true?name:fileName,
151  upVector,
152  rotationOrder,
153  boundingBox.release()
154  );
155  model->setShaderModel(shaderModel);
156  model->setEmbedSpecularTextures(embedSpecularTextures);
157  model->setEmbedPBRTextures(embedPBRTextures);
158  model->setFPS(is.readFloat());
159  array<float, 16> importTransformMatrixArray;
160  is.readFloatArray(importTransformMatrixArray);
161  model->setImportTransformMatrix(importTransformMatrixArray);
162  if ((version[0] == 1 && version[1] == 9 && version[2] == 17) ||
163  (version[0] == 1 && version[1] == 9 && version[2] == 18) ||
164  (version[0] == 1 && version[1] == 9 && version[2] == 19) ||
165  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
166  readEmbeddedTextures(&is, embeddedTextures, version);
167  }
168  auto materialCount = is.readInt();
169  for (auto i = 0; i < materialCount; i++) {
170  auto material = readMaterial(pathName, &is, model.get(), embeddedTextures, useBC7TextureCompression, version);
171  model->getMaterials()[material->getId()] = material;
172  }
173  readSubNodes(&is, model.get(), nullptr, model->getSubNodes());
174  auto animationSetupCount = is.readInt();
175  for (auto i = 0; i < animationSetupCount; i++) {
176  readAnimationSetup(&is, model.get(), version);
177  }
178  if (model->getAnimationSetup(Model::ANIMATIONSETUP_DEFAULT) == nullptr) {
179  model->addAnimationSetup(Model::ANIMATIONSETUP_DEFAULT, 0, 0, true);
180  }
181  //
182  return model.release();
183 }
184 
185 const string TMReader::getTexturePath(const string& modelPathName, const string& texturePathName, const string& textureFileName) {
186  if (FileSystem::getInstance()->exists(texturePathName + "/" + textureFileName) == true) {
187  return texturePathName;
188  } else
189  if (FileSystem::getInstance()->exists(modelPathName + "/" + textureFileName) == true) {
190  return modelPathName;
191  } else
192  if (FileSystem::getInstance()->exists(FileSystem::getInstance()->getPathName(modelPathName) + "/" + textureFileName) == true) {
193  return FileSystem::getInstance()->getPathName(modelPathName);
194  } else {
195  return texturePathName;
196  }
197 }
198 
199 void TMReader::readEmbeddedTextures(TMReaderInputStream* is, unordered_map<string, Texture*>& embeddedTextures, const array<uint8_t, 3>& version) {
200  auto embeddedTextureCount = is->readInt();
201  for (auto i = 0; i < embeddedTextureCount; i++) {
202  auto embeddedTextureId = is->readString();
203  auto embeddedTextureType = is->readByte();
204  // png
205  if (embeddedTextureType == 1) {
207  auto magFilter = Texture::TEXTUREFILTER_LINEAR;
208  if ((version[0] == 1 && version[1] == 9 && version[2] == 19) ||
209  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
210  minFilter = static_cast<Texture::TextureFilter>(is->readByte());
211  magFilter = static_cast<Texture::TextureFilter>(is->readByte());
212  }
213  auto textureSize = is->readInt();
214  vector<uint8_t> pngData;
215  pngData.resize(textureSize);
216  for (auto j = 0; j < textureSize; j++) pngData[j] = is->readByte();
217  auto embeddedTexture =
218  unique_ptr<
219  Texture,
220  decltype([](Texture* texture){ texture->releaseReference(); })
221  >(
222  PNGTextureReader::read(embeddedTextureId, pngData, true)
223  );
224  if (embeddedTexture != nullptr) {
225  embeddedTexture->acquireReference();
226  if ((version[0] == 1 && version[1] == 9 && version[2] == 19) ||
227  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
228  embeddedTexture->setMinFilter(minFilter);
229  embeddedTexture->setMagFilter(magFilter);
230  }
231  embeddedTexture->setUseCompression(false);
232  embeddedTextures[embeddedTextureId] = embeddedTexture.get();
233  embeddedTexture->acquireReference();
234  }
235  } else
236  // bc7
237  if (embeddedTextureType == 2) {
238  auto width = is->readInt();
239  auto height = is->readInt();
240  auto textureWidth = is->readInt();
241  auto textureHeight = is->readInt();
242  auto bitsPerPixel = is->readByte();
244  auto magFilter = Texture::TEXTUREFILTER_LINEAR;
245  if ((version[0] == 1 && version[1] == 9 && version[2] == 19) ||
246  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
247  minFilter = static_cast<Texture::TextureFilter>(is->readByte());
248  magFilter = static_cast<Texture::TextureFilter>(is->readByte());
249  }
250  auto textureSize = is->readInt();
251  ByteBuffer bc7Data(textureSize);
252  for (auto j = 0; j < textureSize; j++) bc7Data.put(is->readByte());
253  auto embeddedTexture =
254  unique_ptr<
255  Texture,
256  decltype([](Texture* texture){ texture->releaseReference(); })
257  >(
258  new Texture(
259  embeddedTextureId,
262  width,
263  height,
264  textureWidth,
265  textureHeight,
267  bc7Data
268  )
269  );
270  embeddedTexture->acquireReference();
271  //
272  if ((version[0] == 1 && version[1] == 9 && version[2] == 19) ||
273  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
274  embeddedTexture->setMinFilter(minFilter);
275  embeddedTexture->setMagFilter(magFilter);
276  }
277  //
278  embeddedTexture->setUseCompression(true);
279  embeddedTextures[embeddedTextureId] = embeddedTexture.get();
280  embeddedTexture->acquireReference();
281  } else
282  // bc7 with mip maps
283  if (embeddedTextureType == 3) {
284  // base texture
285  auto width = is->readInt();
286  auto height = is->readInt();
287  auto textureWidth = is->readInt();
288  auto textureHeight = is->readInt();
289  auto bitsPerPixel = is->readByte();
291  auto magFilter = Texture::TEXTUREFILTER_LINEAR;
292  if ((version[0] == 1 && version[1] == 9 && version[2] == 19) ||
293  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
294  minFilter = static_cast<Texture::TextureFilter>(is->readByte());
295  magFilter = static_cast<Texture::TextureFilter>(is->readByte());
296  }
297  auto textureSize = is->readInt();
298  ByteBuffer bc7Data(textureSize);
299  for (auto j = 0; j < textureSize; j++) bc7Data.put(is->readByte());
300  auto embeddedTexture =
301  unique_ptr<
302  Texture,
303  decltype([](Texture* texture){ texture->releaseReference(); })
304  >(
305  new Texture(
306  embeddedTextureId,
309  width,
310  height,
311  textureWidth,
312  textureHeight,
314  bc7Data
315  )
316  );
317  embeddedTexture->acquireReference();
318  //
319  if ((version[0] == 1 && version[1] == 9 && version[2] == 19) ||
320  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
321  embeddedTexture->setMinFilter(minFilter);
322  embeddedTexture->setMagFilter(magFilter);
323  }
324  // mip maps
325  auto mipMapTextureCount = is->readByte();
326  embeddedTexture->setUseMipMap(mipMapTextureCount > 0);
327  vector<Texture::MipMapTexture> mipMapTextures;
328  for (auto j = 0; j < mipMapTextureCount; j++) {
329  Texture::TextureFormat mipMapTextureFormat = static_cast<Texture::TextureFormat>(is->readByte());
330  auto mipMapWidth = static_cast<uint16_t>(is->readInt());
331  auto mipMapHeight = static_cast<uint16_t>(is->readInt());
332  auto mipMapSize = is->readInt();
333  mipMapTextures.emplace_back(
334  mipMapTextureFormat,
335  mipMapWidth,
336  mipMapHeight,
337  ByteBuffer(mipMapSize)
338  );
339  auto& mipMapBC7Data = mipMapTextures[mipMapTextures.size() - 1].textureData;
340  for (auto k = 0; k < mipMapSize; k++) {
341  mipMapBC7Data.put(is->readByte());
342  }
343  }
344  embeddedTexture->setMipMapTextures(mipMapTextures);
345  //
346  embeddedTexture->setUseCompression(true);
347  embeddedTextures[embeddedTextureId] = embeddedTexture.get();
348  embeddedTexture->acquireReference();
349  }
350  }
351 }
352 
353 Material* TMReader::readMaterial(const string& pathName, TMReaderInputStream* is, Model* model, const unordered_map<string, Texture*>& embeddedTextures, bool useBC7TextureCompression, const array<uint8_t, 3>& version)
354 {
355  // TODO: minFilter, magFilter for non embedded textures
356  auto id = is->readString();
357  auto m = make_unique<Material>(id);
358  auto smp = make_unique<SpecularMaterialProperties>();
359  auto smpEmbbededTextures = model->hasEmbeddedSpecularTextures();
360  if (version[0] == 1 && version[1] == 9 && version[2] == 17) {
361  smpEmbbededTextures = is->readBoolean();
362  }
363  array<float, 4> colorRGBAArray;
364  is->readFloatArray(colorRGBAArray);
365  smp->setAmbientColor(Color4(colorRGBAArray));
366  is->readFloatArray(colorRGBAArray);
367  smp->setDiffuseColor(Color4(colorRGBAArray));
368  is->readFloatArray(colorRGBAArray);
369  smp->setSpecularColor(Color4(colorRGBAArray));
370  is->readFloatArray(colorRGBAArray);
371  smp->setEmissionColor(Color4(colorRGBAArray));
372  smp->setShininess(is->readFloat());
373  if ((version[0] == 1 && version[1] == 9 && version[2] == 15) ||
374  (version[0] == 1 && version[1] == 9 && version[2] == 16) ||
375  (version[0] == 1 && version[1] == 9 && version[2] == 17) ||
376  (version[0] == 1 && version[1] == 9 && version[2] == 18) ||
377  (version[0] == 1 && version[1] == 9 && version[2] == 19) ||
378  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
379  smp->setTextureAtlasSize(is->readInt());
380  }
381  auto diffuseTexturePathName = is->readString();
382  auto diffuseTextureFileName = is->readString();
383  auto diffuseTransparencyTexturePathName = is->readString();
384  auto diffuseTransparencyTextureFileName = is->readString();
385  if (smpEmbbededTextures == false && diffuseTextureFileName.empty() == false) {
386  smp->setDiffuseTexture(
387  getTexturePath(pathName, diffuseTexturePathName, diffuseTextureFileName),
388  diffuseTextureFileName,
389  getTexturePath(pathName, diffuseTransparencyTexturePathName, diffuseTransparencyTextureFileName),
390  diffuseTransparencyTextureFileName
391  );
392  if (smp->getDiffuseTexture() != nullptr) smp->getDiffuseTexture()->setUseCompression(useBC7TextureCompression);
393  }
394  auto specularTexturePathName = is->readString();
395  auto specularTextureFileName = is->readString();
396  if (smpEmbbededTextures == false && specularTextureFileName.empty() == false) {
397  smp->setSpecularTexture(
398  getTexturePath(pathName, specularTexturePathName, specularTextureFileName),
399  specularTextureFileName
400  );
401  if (smp->getSpecularTexture() != nullptr) smp->getSpecularTexture()->setUseCompression(useBC7TextureCompression);
402  }
403  auto normalTexturePathName = is->readString();
404  auto normalTextureFileName = is->readString();
405  if (smpEmbbededTextures == false && normalTextureFileName.empty() == false) {
406  smp->setNormalTexture(
407  getTexturePath(pathName, normalTexturePathName, normalTextureFileName),
408  normalTextureFileName
409  );
410  if (smp->getNormalTexture() != nullptr) smp->getNormalTexture()->setUseCompression(useBC7TextureCompression);
411  }
412  if ((version[0] == 1 && version[1] == 9 && version[2] == 9) ||
413  (version[0] == 1 && version[1] == 9 && version[2] == 10) ||
414  (version[0] == 1 && version[1] == 9 && version[2] == 11)) {
415  auto displacementTexturePathName = is->readString();
416  auto displacementTextureFileName = is->readString();
417  }
418  if ((version[0] == 1 && version[1] == 9 && version[2] == 15) ||
419  (version[0] == 1 && version[1] == 9 && version[2] == 16) ||
420  (version[0] == 1 && version[1] == 9 && version[2] == 17) ||
421  (version[0] == 1 && version[1] == 9 && version[2] == 18) ||
422  (version[0] == 1 && version[1] == 9 && version[2] == 19) ||
423  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
424  smp->setDiffuseTextureTransparency(is->readBoolean());
425  }
426  smp->setDiffuseTextureMaskedTransparency(is->readBoolean());
427  if ((version[0] == 1 && version[1] == 9 && version[2] == 9) ||
428  (version[0] == 1 && version[1] == 9 && version[2] == 10) ||
429  (version[0] == 1 && version[1] == 9 && version[2] == 11) ||
430  (version[0] == 1 && version[1] == 9 && version[2] == 12) ||
431  (version[0] == 1 && version[1] == 9 && version[2] == 13) ||
432  (version[0] == 1 && version[1] == 9 && version[2] == 14) ||
433  (version[0] == 1 && version[1] == 9 && version[2] == 15) ||
434  (version[0] == 1 && version[1] == 9 && version[2] == 16) ||
435  (version[0] == 1 && version[1] == 9 && version[2] == 17) ||
436  (version[0] == 1 && version[1] == 9 && version[2] == 18) ||
437  (version[0] == 1 && version[1] == 9 && version[2] == 19) ||
438  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
439  smp->setDiffuseTextureMaskedTransparencyThreshold(is->readFloat());
440  }
441  if ((version[0] == 1 && version[1] == 9 && version[2] == 16) ||
442  (version[0] == 1 && version[1] == 9 && version[2] == 17) ||
443  (version[0] == 1 && version[1] == 9 && version[2] == 18) ||
444  (version[0] == 1 && version[1] == 9 && version[2] == 19) ||
445  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
446  m->setDoubleSided(is->readBoolean());
447  }
448  if ((version[0] == 1 && version[1] == 9 && version[2] == 10) ||
449  (version[0] == 1 && version[1] == 9 && version[2] == 11) ||
450  (version[0] == 1 && version[1] == 9 && version[2] == 12) ||
451  (version[0] == 1 && version[1] == 9 && version[2] == 13) ||
452  (version[0] == 1 && version[1] == 9 && version[2] == 14) ||
453  (version[0] == 1 && version[1] == 9 && version[2] == 15) ||
454  (version[0] == 1 && version[1] == 9 && version[2] == 16) ||
455  (version[0] == 1 && version[1] == 9 && version[2] == 17) ||
456  (version[0] == 1 && version[1] == 9 && version[2] == 18) ||
457  (version[0] == 1 && version[1] == 9 && version[2] == 19) ||
458  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
459  array<float, 9> textureMatrix;
460  is->readFloatArray(textureMatrix);
461  smp->setTextureMatrix(Matrix3x3(textureMatrix));
462  }
463  if ((version[0] == 1 && version[1] == 9 && version[2] == 17) ||
464  (version[0] == 1 && version[1] == 9 && version[2] == 18) ||
465  (version[0] == 1 && version[1] == 9 && version[2] == 19) ||
466  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
467  if (smpEmbbededTextures == true) {
468  // diffuse
469  if (diffuseTextureFileName.empty() == false) {
470  auto diffuseTextureTransparency = smp->getDiffuseTextureTransparency();
471  auto diffuseTextureMaskedTransparency = smp->getDiffuseTextureMaskedTransparencyThreshold();
472  auto diffuseTexture = getEmbeddedTexture(embeddedTextures, diffuseTextureFileName);
473  if (diffuseTexture != nullptr) smp->setDiffuseTexture(diffuseTexture);
474  smp->setDiffuseTextureTransparency(diffuseTextureTransparency);
475  smp->setDiffuseTextureMaskedTransparency(diffuseTextureMaskedTransparency);
476  }
477  // specular
478  if (specularTextureFileName.empty() == false) {
479  auto specularTexture = getEmbeddedTexture(embeddedTextures, specularTextureFileName);
480  if (specularTexture != nullptr) smp->setSpecularTexture(specularTexture);
481  }
482  // normal
483  if (normalTextureFileName.empty() == false) {
484  auto normalTexture = getEmbeddedTexture(embeddedTextures, normalTextureFileName);
485  if (normalTexture != nullptr) smp->setNormalTexture(normalTexture);
486  }
487  }
488  }
489  m->setSpecularMaterialProperties(smp.release());
490  if ((version[0] == 1 && version[1] == 9 && version[2] == 13) ||
491  (version[0] == 1 && version[1] == 9 && version[2] == 14) ||
492  (version[0] == 1 && version[1] == 9 && version[2] == 15) ||
493  (version[0] == 1 && version[1] == 9 && version[2] == 16) ||
494  (version[0] == 1 && version[1] == 9 && version[2] == 17) ||
495  (version[0] == 1 && version[1] == 9 && version[2] == 18) ||
496  (version[0] == 1 && version[1] == 9 && version[2] == 19) ||
497  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
498  if (is->readBoolean() == true) {
499  auto pmp = make_unique<PBRMaterialProperties>();
500  auto pmpEmbeddedTextures = model->hasEmbeddedPBRTextures();
501  if (version[0] == 1 && version[1] == 9 && version[2] == 17) {
502  pmpEmbeddedTextures = is->readBoolean();
503  }
504  is->readFloatArray(colorRGBAArray);
505  pmp->setBaseColorFactor(Color4(colorRGBAArray));
506  auto baseColorTexturePathName = is->readString();
507  auto baseColorTextureFileName = is->readString();
508  if (pmpEmbeddedTextures == false && baseColorTextureFileName.empty() == false) {
509  pmp->setBaseColorTexture(baseColorTexturePathName, baseColorTextureFileName);
510  if (pmp->getBaseColorTexture() != nullptr) pmp->getBaseColorTexture()->setUseCompression(useBC7TextureCompression);
511  }
512  pmp->setBaseColorTextureMaskedTransparency(is->readBoolean());
513  pmp->setBaseColorTextureMaskedTransparency(is->readFloat());
514  pmp->setMetallicFactor(is->readFloat());
515  pmp->setRoughnessFactor(is->readFloat());
516  auto metallicRoughnessTexturePathName = is->readString();
517  auto metallicRoughnessTextureFileName = is->readString();
518  if (pmpEmbeddedTextures && metallicRoughnessTextureFileName.empty() == false) {
519  pmp->setMetallicRoughnessTexture(metallicRoughnessTexturePathName, metallicRoughnessTextureFileName);
520  if (pmp->getMetallicRoughnessTexture() != nullptr) pmp->getMetallicRoughnessTexture()->setUseCompression(useBC7TextureCompression);
521  }
522  pmp->setNormalScale(is->readFloat());
523  auto pbrNormalTexturePathName = is->readString();
524  auto pbrNormalTextureFileName = is->readString();
525  if (pmpEmbeddedTextures == false && pbrNormalTextureFileName.empty() == false) {
526  pmp->setNormalTexture(pbrNormalTexturePathName, pbrNormalTextureFileName);
527  if (pmp->getNormalTexture() != nullptr) pmp->getNormalTexture()->setUseCompression(useBC7TextureCompression);
528  }
529  string pbrEmissiveTexturePathName;
530  string pbrEmissiveTextureFileName;
531  if ((version[0] == 1 && version[1] == 9 && version[2] == 20)) {
532  is->readFloatArray(colorRGBAArray);
533  pmp->setEmissiveFactor(Color4(colorRGBAArray));
534  pbrEmissiveTexturePathName = is->readString();
535  pbrEmissiveTextureFileName = is->readString();
536  if (pmpEmbeddedTextures == false && pbrEmissiveTextureFileName.empty() == false) {
537  pmp->setEmissiveTexture(pbrEmissiveTexturePathName, pbrEmissiveTextureFileName);
538  if (pmp->getEmissiveTexture() != nullptr) pmp->getEmissiveTexture()->setUseCompression(useBC7TextureCompression);
539  }
540  }
541  pmp->setExposure(is->readFloat());
542  if ((version[0] == 1 && version[1] == 9 && version[2] == 17) ||
543  (version[0] == 1 && version[1] == 9 && version[2] == 18) ||
544  (version[0] == 1 && version[1] == 9 && version[2] == 19) ||
545  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
546  if (pmpEmbeddedTextures == true) {
547  // base color
548  if (baseColorTextureFileName.empty() == false) {
549  auto baseColorTextureTransparency = pmp->hasBaseColorTextureTransparency();
550  auto baseColorTextureMaskedTransparency = pmp->hasBaseColorTextureMaskedTransparency();
551  auto baseColorTexture = getEmbeddedTexture(embeddedTextures, baseColorTextureFileName);
552  if (baseColorTexture != nullptr) pmp->setBaseColorTexture(baseColorTexture);
553  pmp->setBaseColorTextureTransparency(baseColorTextureTransparency);
554  pmp->setBaseColorTextureMaskedTransparency(baseColorTextureMaskedTransparency);
555  }
556  // metallic roughness
557  if (metallicRoughnessTextureFileName.empty() == false) {
558  auto metallicRoughnessTexture = getEmbeddedTexture(embeddedTextures, metallicRoughnessTextureFileName);
559  if (metallicRoughnessTexture != nullptr) pmp->setMetallicRoughnessTexture(metallicRoughnessTexture);
560  }
561  // normal
562  if (pbrNormalTextureFileName.empty() == false) {
563  auto pbrNormalTexture = getEmbeddedTexture(embeddedTextures, pbrNormalTextureFileName);
564  if (pbrNormalTexture != nullptr) pmp->setNormalTexture(pbrNormalTexture);
565  }
566  // emissive
567  if ((version[0] == 1 && version[1] == 9 && version[2] == 20)) {
568  if (pbrEmissiveTextureFileName.empty() == false) {
569  auto pbrEmissiveTexture = getEmbeddedTexture(embeddedTextures, pbrEmissiveTextureFileName);
570  if (pbrEmissiveTexture != nullptr) pmp->setEmissiveTexture(pbrEmissiveTexture);
571  }
572  }
573  }
574  }
575  m->setPBRMaterialProperties(pmp.release());
576  }
577  }
578  //
579  return m.release();
580 }
581 
582 void TMReader::readAnimationSetup(TMReaderInputStream* is, Model* model, const array<uint8_t, 3>& version) {
583  auto id = is->readString();
584  auto overlayFromNodeId = is->readString();
585  auto startFrame = is->readInt();
586  auto endFrame = is->readInt();
587  auto loop = is->readBoolean();
588  auto speed = 1.0f;
589  if ((version[0] == 1 && version[1] == 9 && version[2] == 11) ||
590  (version[0] == 1 && version[1] == 9 && version[2] == 12) ||
591  (version[0] == 1 && version[1] == 9 && version[2] == 13) ||
592  (version[0] == 1 && version[1] == 9 && version[2] == 14) ||
593  (version[0] == 1 && version[1] == 9 && version[2] == 15) ||
594  (version[0] == 1 && version[1] == 9 && version[2] == 16) ||
595  (version[0] == 1 && version[1] == 9 && version[2] == 17) ||
596  (version[0] == 1 && version[1] == 9 && version[2] == 18) ||
597  (version[0] == 1 && version[1] == 9 && version[2] == 19) ||
598  (version[0] == 1 && version[1] == 9 && version[2] == 20)) {
599  speed = is->readFloat();
600  }
601  if (overlayFromNodeId.length() == 0) {
602  model->addAnimationSetup(id, startFrame, endFrame, loop, speed);
603  } else {
604  model->addOverlayAnimationSetup(id, overlayFromNodeId, startFrame, endFrame, loop, speed);
605  }
606 }
607 
608 const vector<Vector3> TMReader::readVertices(TMReaderInputStream* is)
609 {
610  vector<Vector3> v;
611  array<float, 3> vXYZ;
612  if (is->readBoolean() == true) {
613  v.resize(is->readInt());
614  for (auto i = 0; i < v.size(); i++) {
615  is->readFloatArray(vXYZ);
616  v[i].set(vXYZ);
617  }
618  }
619  return v;
620 }
621 
623 {
624  array<float, 2> tcUV;
625  vector<Vector2> tc;
626  if (is->readBoolean() == true) {
627  tc.resize(is->readInt());
628  for (auto i = 0; i < tc.size(); i++) {
629  is->readFloatArray(tcUV);
630  tc[i] = Vector2(tcUV);
631  }
632  }
633  return tc;
634 }
635 
636 bool TMReader::readIndices(TMReaderInputStream* is, array<int32_t, 3>* indices)
637 {
638  if (is->readBoolean() == false) {
639  return false;
640  } else {
641  auto length = is->readInt();
642  if (length != indices->size()) {
643  throw ModelFileIOException("Wrong indices array size");
644  }
645  for (auto i = 0; i < indices->size(); i++) {
646  (*indices)[i] = is->readInt();
647  }
648  return true;
649  }
650 }
651 
653 {
654  if (is->readBoolean() == false) {
655  return nullptr;
656  } else {
657  array<float, 16> matrixArray;
658  auto frames = is->readInt();
659  auto animation = make_unique<Animation>();
660  vector<Matrix4x4> transformMatrices;
661  transformMatrices.resize(frames);
662  for (auto i = 0; i < transformMatrices.size(); i++) {
663  is->readFloatArray(matrixArray);
664  transformMatrices[i].set(matrixArray);
665  }
666  animation->setTransformMatrices(transformMatrices);
667  g->setAnimation(animation.release());
668  return g->getAnimation();
669  }
670 }
671 
673 {
674  vector<FacesEntity> facesEntities;
675  facesEntities.resize(is->readInt());
676  for (auto i = 0; i < facesEntities.size(); i++) {
677  facesEntities[i] = FacesEntity(g, is->readString());
678  if (is->readBoolean() == true) {
679  Material* material = nullptr;
680  auto materialIt = g->getModel()->getMaterials().find(is->readString());
681  if (materialIt != g->getModel()->getMaterials().end()) {
682  material = materialIt->second;
683  }
684  facesEntities[i].setMaterial(material);
685  }
686  vector<Face> faces;
687  faces.resize(is->readInt());
688  array<int32_t,3> vertexIndices;
689  array<int32_t,3> normalIndices;
690  array<int32_t,3> textureCoordinateIndices;
691  array<int32_t,3> tangentIndices;
692  array<int32_t,3> bitangentIndices;
693  bool haveTextureCoordinateIndices;
694  bool haveTangentIndices;
695  bool haveBitangentIndices;
696  for (auto j = 0; j < faces.size(); j++) {
697  readIndices(is, &vertexIndices);
698  readIndices(is, &normalIndices);
699  haveTextureCoordinateIndices = readIndices(is, &textureCoordinateIndices);
700  haveTangentIndices = readIndices(is, &tangentIndices);
701  haveBitangentIndices = readIndices(is, &bitangentIndices);
702  faces[j] = Face(g,
703  vertexIndices[0], vertexIndices[1], vertexIndices[2],
704  normalIndices[0], normalIndices[1], normalIndices[2]
705  );
706  if (haveTextureCoordinateIndices == true) {
707  faces[j].setTextureCoordinateIndices(
708  textureCoordinateIndices[0], textureCoordinateIndices[1], textureCoordinateIndices[2]
709  );
710  }
711  if (haveTangentIndices == true && haveBitangentIndices == true) {
712  faces[j].setTangentIndices(tangentIndices[0], tangentIndices[1], tangentIndices[2]);
713  faces[j].setBitangentIndices(bitangentIndices[0], bitangentIndices[1], bitangentIndices[2]);
714  }
715  }
716  facesEntities[i].setFaces(faces);
717  }
718  g->setFacesEntities(facesEntities);
719 }
720 
722 {
723  array<float, 16> matrixArray;
724  Joint joint(is->readString());
725  is->readFloatArray(matrixArray);
726  joint.setBindMatrix(Matrix4x4(matrixArray));
727  return joint;
728 }
729 
731 {
732 
733  int32_t jointIndex = is->readInt();
734  int32_t weightIndex = is->readInt();
735  return JointWeight(jointIndex, weightIndex);
736 }
737 
739 {
740  if (is->readBoolean() == true) {
741  auto skinning = make_unique<Skinning>();
742  skinning->setWeights(is->readFloatVector());
743  vector<Joint> joints;
744  joints.resize(is->readInt());
745  for (auto i = 0; i < joints.size(); i++) {
746  joints[i] = readSkinningJoint(is);
747  }
748  skinning->setJoints(joints);
749  vector<vector<JointWeight>> verticesJointsWeight;
750  verticesJointsWeight.resize(is->readInt());
751  for (auto i = 0; i < verticesJointsWeight.size(); i++) {
752  verticesJointsWeight[i].resize(is->readInt());
753  for (auto j = 0; j < verticesJointsWeight[i].size(); j++) {
754  verticesJointsWeight[i][j] = readSkinningJointWeight(is);
755  }
756  }
757  skinning->setVerticesJointsWeights(verticesJointsWeight);
758  g->setSkinning(skinning.release());
759  }
760 }
761 
762 void TMReader::readSubNodes(TMReaderInputStream* is, Model* model, Node* parentNode, unordered_map<string, Node*>& subNodes)
763 {
764  auto subNodeCount = is->readInt();
765  for (auto i = 0; i < subNodeCount; i++) {
766  auto subNode = readNode(is, model, parentNode);
767  subNodes[subNode->getId()] = subNode;
768  model->getNodes()[subNode->getId()] = subNode;
769  }
770 }
771 
773 {
774 
775  auto nodeId = is->readString();
776  auto nodeName = is->readString();
777  auto node = make_unique<Node>(model, parentNode, nodeId, nodeName);
778  node->setJoint(is->readBoolean());
779  array<float, 16> matrixArray;
780  is->readFloatArray(matrixArray);
781  node->setTransformMatrix(Matrix4x4(matrixArray));
782  vector<Vector3> vertices = readVertices(is);
783  node->setVertices(vertices);
784  vector<Vector3> normals = readVertices(is);
785  node->setNormals(normals);
786  vector<Vector2> textureCoordinates = readTextureCoordinates(is);
787  node->setTextureCoordinates(textureCoordinates);
788  vector<Vector3> tangents = readVertices(is);
789  node->setTangents(tangents);
790  vector<Vector3> bitangents = readVertices(is);
791  node->setBitangents(bitangents);
792  readAnimation(is, node.get());
793  readSkinning(is, node.get());
794  readFacesEntities(is, node.get());
795  readSubNodes(is, model, parentNode, node->getSubNodes());
796  return node.release();
797 }
Color 4 definition class.
Definition: Color4.h:18
Texture entity.
Definition: Texture.h:24
static TextureFormat getBC7FormatByPixelBitsPerPixel(int bpp)
Return BC7 RGB/A texture format by bits per pixel.
Definition: Texture.h:98
static TextureDepth getRGBDepthByPixelBitsPerPixel(int bpp)
Return RGB/A texture depth by bits per pixel.
Definition: Texture.h:59
@ TEXTUREFILTER_LINEAR_MIPMAP_LINEAR
Definition: Texture.h:49
bool readBoolean()
Reads a boolean from input stream.
Definition: TMReader.h:65
void readFloatArray(array< float, 16 > &data)
Reads a float array from input stream.
Definition: TMReader.h:134
const vector< float > readFloatVector()
Reads a float array from input stream.
Definition: TMReader.h:209
int32_t readInt()
Reads a integer from input stream.
Definition: TMReader.h:87
const string readString()
Reads a string from input stream.
Definition: TMReader.h:116
float readFloat()
Reads a float from input stream.
Definition: TMReader.h:101
int8_t readByte()
Reads a byte from input stream.
Definition: TMReader.h:75
static void readSubNodes(TMReaderInputStream *is, Model *model, Node *parentNode, unordered_map< string, Node * > &subNodes)
Read sub nodes.
Definition: TMReader.cpp:762
static Joint readSkinningJoint(TMReaderInputStream *is)
Read skinning joint.
Definition: TMReader.cpp:721
static Material * readMaterial(const string &pathName, TMReaderInputStream *is, Model *model, const unordered_map< string, Texture * > &embeddedTextures, bool useBC7TextureCompression, const array< uint8_t, 3 > &version)
Read material.
Definition: TMReader.cpp:353
static const string getTexturePath(const string &modelPathName, const string &texturePathName, const string &textureFileName)
Get texture path.
Definition: TMReader.cpp:185
static const vector< Vector3 > readVertices(TMReaderInputStream *is)
Read vertices from input stream.
Definition: TMReader.cpp:608
static const vector< Vector2 > readTextureCoordinates(TMReaderInputStream *is)
Read texture coordinates from input stream.
Definition: TMReader.cpp:622
static Animation * readAnimation(TMReaderInputStream *is, Node *g)
Read animation from input stream into node.
Definition: TMReader.cpp:652
static void readFacesEntities(TMReaderInputStream *is, Node *g)
Read faces entities from input stream.
Definition: TMReader.cpp:672
static void readAnimationSetup(TMReaderInputStream *is, Model *model, const array< uint8_t, 3 > &version)
Read animation setup.
Definition: TMReader.cpp:582
static void readSkinning(TMReaderInputStream *is, Node *g)
Read skinning from input stream.
Definition: TMReader.cpp:738
static bool readIndices(TMReaderInputStream *is, array< int32_t, 3 > *indices)
Read indices from input stream.
Definition: TMReader.cpp:636
static void readEmbeddedTextures(TMReaderInputStream *is, unordered_map< string, Texture * > &embeddedTextures, const array< uint8_t, 3 > &version)
Read material.
Definition: TMReader.cpp:199
static JointWeight readSkinningJointWeight(TMReaderInputStream *is)
Read skinning joint weight.
Definition: TMReader.cpp:730
static Texture * getEmbeddedTexture(const unordered_map< string, Texture * > &embeddedTextures, const string &fileName)
Read material.
Definition: TMReader.h:270
static Model * read(const string &pathName, const string &fileName, bool useBC7TextureCompression=true)
TDME model format reader.
Definition: TMReader.cpp:69
static Node * readNode(TMReaderInputStream *is, Model *model, Node *parentNode)
Write node to output stream.
Definition: TMReader.cpp:772
Represents a model face, consisting of vertex, normal, tangent and bitangent vectors,...
Definition: Face.h:18
Node faces entity A node can have multiple entities containing faces and a applied material.
Definition: FacesEntity.h:23
Joint / Bone.
Definition: Joint.h:19
void setBindMatrix(const Matrix4x4 &bindMatrix)
Bind matrix.
Definition: Joint.h:56
Represents a material.
Definition: Material.h:23
Representation of a 3D model.
Definition: Model.h:35
unordered_map< string, Material * > & getMaterials()
Returns all object materials.
Definition: Model.h:185
bool hasEmbeddedPBRTextures() const
Definition: Model.h:410
unordered_map< string, Node * > & getNodes()
Returns all object's nodes.
Definition: Model.h:199
AnimationSetup * addAnimationSetup(const string &id, int32_t startFrame, int32_t endFrame, bool loop, float speed=1.0f)
Adds an base animation setup.
Definition: Model.cpp:101
AnimationSetup * addOverlayAnimationSetup(const string &id, const string &overlayFromNodeId, int32_t startFrame, int32_t endFrame, bool loop, float speed=1.0f)
Adds an overlay animation setup.
Definition: Model.cpp:113
bool hasEmbeddedSpecularTextures() const
Definition: Model.h:395
Model node.
Definition: Node.h:32
unordered_map< string, Node * > & getSubNodes()
Definition: Node.h:293
void setAnimation(Animation *animation)
Sets animation object.
Definition: Node.cpp:95
void setFacesEntities(const vector< FacesEntity > &facesEntities)
Set up faces entities.
Definition: Node.cpp:121
void setSkinning(Skinning *skinning)
Sets skinning object.
Definition: Node.cpp:99
Model * getModel()
Definition: Node.h:74
Animation * getAnimation()
Definition: Node.h:229
Represents specular material properties.
Represents rotation orders of a model.
Definition: RotationOrder.h:23
Skinning definition for nodes.
Definition: Skinning.h:25
Represents specular material properties.
Model up vector.
Definition: UpVector.h:20
Axis aligned bounding box used for frustum, this is not directly connectable with physics engine.
Definition: BoundingBox.h:26
Matrix3x3 class representing matrix3x3 mathematical structure and operations for 2d space.
Definition: Matrix3x3.h:20
Matrix4x4 class representing matrix4x4 mathematical structure and operations for 3d space.
Definition: Matrix4x4.h:23
Vector2 class representing vector2 mathematical structure and operations with x, y components.
Definition: Vector2.h:20
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Definition: Vector3.h:20
File system singleton class.
Definition: FileSystem.h:17
Buffer * put(uint8_t value)
Put value into buffer.
Definition: Buffer.h:115
Byte buffer class.
Definition: ByteBuffer.h:27
virtual void releaseReference()
Releases a reference, thus decrementing the counter and delete it if reference counter is zero.
Definition: Reference.h:38