Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
MeshImporter.cpp
Go to the documentation of this file.
1
2
5
11
15
19
20namespace Divide {
21
22namespace {
23 constexpr U16 BYTE_BUFFER_VERSION = 1u;
24 const char* g_parsedAssetGeometryExt = "DVDGeom";
25 const char* g_parsedAssetAnimationExt = "DVDAnim";
26};
27
28GeometryFormat GetGeometryFormatForExtension(const char* extension) noexcept
29{
30 if (Util::CompareIgnoreCase(extension, "3ds"))
31 {
33 }
34
35 if (Util::CompareIgnoreCase(extension, "ase"))
36 {
38 }
39
40 if (Util::CompareIgnoreCase(extension, "fbx"))
41 {
43 }
44
45 if (Util::CompareIgnoreCase(extension, "md2"))
46 {
48 }
49
50 if (Util::CompareIgnoreCase(extension, "md5mesh"))
51 {
53 }
54
55 if (Util::CompareIgnoreCase(extension, "obj"))
56 {
58 }
59
60 if (Util::CompareIgnoreCase(extension, "x"))
61 {
62 return GeometryFormat::X;
63 }
64
65 if (Util::CompareIgnoreCase(extension, "dae"))
66 {
68 }
69
70 if (Util::CompareIgnoreCase(extension, "gltf") ||
71 Util::CompareIgnoreCase(extension, "glb"))
72 {
74 }
75
76 if (Util::CompareIgnoreCase(extension, g_parsedAssetAnimationExt))
77 {
79 }
80
81 if (Util::CompareIgnoreCase(extension, g_parsedAssetGeometryExt))
82 {
84 }
85
87}
88
89namespace Import
90{
91 bool ImportData::saveToFile([[maybe_unused]] PlatformContext& context, const ResourcePath& path, const std::string_view fileName)
92 {
93 ByteBuffer tempBuffer;
94 assert(_vertexBuffer != nullptr);
95 tempBuffer << BYTE_BUFFER_VERSION;
96 tempBuffer << _ID("BufferEntryPoint");
97 tempBuffer << _modelName;
98 tempBuffer << _modelPath;
99 tempBuffer << _animationCount;
100
101 if (_vertexBuffer->serialize(tempBuffer))
102 {
103 tempBuffer << to_U32(_subMeshData.size());
104 for (const SubMeshData& subMesh : _subMeshData)
105 {
106 if (!subMesh.serialize(tempBuffer))
107 {
108 //handle error
109 }
110 }
111 if (!_nodeData.serialize(tempBuffer))
112 {
113 //handle error
114 }
115
116 // Animations are handled by the SceneAnimator I/O
117 return tempBuffer.dumpToFile(path, Util::StringFormat("{}.{}", fileName, g_parsedAssetGeometryExt));
118 }
119
120 return false;
121 }
122
123 bool ImportData::loadFromFile(PlatformContext& context, const ResourcePath& path, const std::string_view fileName)
124 {
125 ByteBuffer tempBuffer;
126 if (tempBuffer.loadFromFile(path, Util::StringFormat( "{}.{}", fileName, g_parsedAssetGeometryExt ) ))
127 {
128 auto tempVer = decltype(BYTE_BUFFER_VERSION){0};
129 tempBuffer >> tempVer;
130 if (tempVer == BYTE_BUFFER_VERSION)
131 {
132 U64 signature;
133 tempBuffer >> signature;
134 if (signature != _ID("BufferEntryPoint"))
135 {
136 return false;
137 }
138
139 tempBuffer >> _modelName;
140 tempBuffer >> _modelPath;
141 tempBuffer >> _animationCount;
142
143 VertexBuffer::Descriptor vbDescriptor{};
144 vbDescriptor._name = _modelName;
145 vbDescriptor._allowDynamicUpdates = false;
146 vbDescriptor._keepCPUData = true;
147 vbDescriptor._largeIndices = true;
148
149 _vertexBuffer = context.gfx().newVB( vbDescriptor );
150 if (_vertexBuffer->deserialize(tempBuffer))
151 {
152 U32 subMeshCount = 0;
153 tempBuffer >> subMeshCount;
154 _subMeshData.resize(subMeshCount);
155 for (SubMeshData& subMesh : _subMeshData)
156 {
157 if (!subMesh.deserialize(tempBuffer))
158 {
159 //handle error
161 }
162 }
163
164 if (!_nodeData.deserialize(tempBuffer))
165 {
166 //handle error
168 }
169
170 _loadedFromFile = true;
171 return true;
172 }
173 }
174 }
175
176 return false;
177 }
178
180 {
181 dataOut << _name;
182 dataOut << _index;
183 dataOut << _boneCount;
184 dataOut << _lodCount;
185 dataOut << _partitionIDs;
186 dataOut << _minPos;
187 dataOut << _maxPos;
188 dataOut << _worldOffset;
189 for (const auto& triangle : _triangles)
190 {
191 dataOut << triangle;
192 }
193
194 return _material.serialize(dataOut);
195 }
196
198 {
199 dataIn >> _name;
200 dataIn >> _index;
201 dataIn >> _boneCount;
202 dataIn >> _lodCount;
203 dataIn >> _partitionIDs;
204 dataIn >> _minPos;
205 dataIn >> _maxPos;
206 dataIn >> _worldOffset;
207 for (auto& triangle : _triangles)
208 {
209 dataIn >> triangle;
210 }
211
212 return _material.deserialize(dataIn);
213 }
214
216 {
217 dataOut << _ignoreTexDiffuseAlpha;
218 dataOut << _doubleSided;
219 dataOut << _name;
220 dataOut << to_U32(_shadingMode);
221 dataOut << to_U32(_bumpMethod);
222 dataOut << baseColour();
223 dataOut << emissive();
224 dataOut << ambient();
225 dataOut << specular();
226 dataOut << specGloss();
227 dataOut << CLAMPED_01(metallic());
228 dataOut << CLAMPED_01(roughness());
229 dataOut << CLAMPED_01(parallaxFactor());
230 for (const TextureEntry& texture : _textures)
231 {
232 if (!texture.serialize(dataOut))
233 {
234 //handle error
236 }
237 }
238
239 return true;
240 }
241
243 {
244 FColour3 tempColourRGB = {};
245 FColour4 tempColourRGBA = {};
246 SpecularGlossiness tempSG = {};
247 U32 temp = {};
248 F32 temp2 = {};
249
250 dataIn >> _ignoreTexDiffuseAlpha;
251 dataIn >> _doubleSided;
252 dataIn >> _name;
253 dataIn >> temp; _shadingMode = static_cast<ShadingMode>(temp);
254 dataIn >> temp; _bumpMethod = static_cast<BumpMethod>(temp);
255 dataIn >> tempColourRGBA; baseColour(tempColourRGBA);
256 dataIn >> tempColourRGB; emissive(tempColourRGB);
257 dataIn >> tempColourRGB; ambient(tempColourRGB);
258 dataIn >> tempColourRGBA; specular(tempColourRGBA);
259 dataIn >> tempSG; specGloss(tempSG);
260 dataIn >> temp2; metallic(temp2);
261 dataIn >> temp2; roughness(temp2);
262 dataIn >> temp2; parallaxFactor(temp2);
263 for (TextureEntry& texture : _textures)
264 {
265 if (!texture.deserialize(dataIn))
266 {
267 //handle error
269 }
270 }
271
272 return true;
273 }
274
276 {
277 dataOut << _textureName;
278 dataOut << _texturePath;
279 dataOut << _srgb;
280 dataOut << _useDDSCache;
281 dataOut << _isNormalMap;
282 dataOut << _alphaForTransparency;
283 dataOut << to_U32(_wrapU);
284 dataOut << to_U32(_wrapV);
285 dataOut << to_U32(_wrapW);
286 dataOut << to_U32(_operation);
287 return true;
288 }
289
291 {
292 U32 data = 0u;
293 dataIn >> _textureName;
294 dataIn >> _texturePath;
295 dataIn >> _srgb;
296 dataIn >> _useDDSCache;
297 dataIn >> _isNormalMap;
298 dataIn >> _alphaForTransparency;
299 dataIn >> data; _wrapU = static_cast<TextureWrap>(data);
300 dataIn >> data; _wrapV = static_cast<TextureWrap>(data);
301 dataIn >> data; _wrapW = static_cast<TextureWrap>(data);
302 dataIn >> data; _operation = static_cast<TextureOperation>(data);
303 return true;
304 }
305};
307 {
308 Time::ProfileTimer importTimer = {};
309 importTimer.start();
310
311 bool success = false;
312 if (!context.config().debug.cache.enabled ||
313 !context.config().debug.cache.geometry ||
314 !dataOut.loadFromFile( context, Paths::g_geometryCacheLocation, dataOut.modelName() ) )
315 {
316 Console::printfn(LOCALE_STR("MESH_NOT_LOADED_FROM_FILE"), dataOut.modelName());
317
318 if (DVDConverter::Load(context, dataOut))
319 {
320 if (dataOut.saveToFile(context, Paths::g_geometryCacheLocation, dataOut.modelName()))
321 {
322 Console::printfn(LOCALE_STR("MESH_SAVED_TO_FILE"), dataOut.modelName());
323 }
324 else
325 {
326 Console::printfn(LOCALE_STR("MESH_NOT_SAVED_TO_FILE"), dataOut.modelName());
327 }
328 success = true;
329 }
330 }
331 else
332 {
333 Console::printfn(LOCALE_STR("MESH_LOADED_FROM_FILE"), dataOut.modelName());
334 dataOut.fromFile(true);
335 success = true;
336 }
337
338 importTimer.stop();
339 Console::d_printfn(LOCALE_STR("LOAD_MESH_TIME"),
340 dataOut.modelName(),
341 Time::MicrosecondsToMilliseconds<F32>(importTimer.get()));
342
343 return success;
344 }
345
347 {
348 Time::ProfileTimer importTimer;
349
350 importTimer.start();
351 Import::ImportData tempMeshData( mesh->assetLocation(), mesh->assetName() );
352 if (!MeshImporter::loadMeshDataFromFile( context, tempMeshData ))
353 {
354 return false;
355 }
356 mesh->renderState().drawState(true);
357 mesh->geometryBuffer( tempMeshData._vertexBuffer );
358 mesh->setAnimationCount(tempMeshData._animationCount);
359
360 std::atomic_uint taskCounter(0u);
361
362 for (const Import::SubMeshData& subMeshData : tempMeshData._subMeshData)
363 {
364 const size_t boneCount = tempMeshData._animationCount > 0u ? subMeshData.boneCount() : 0u;
365
366 // Submesh is created as a resource when added to the SceneGraph
367 ResourceDescriptor<SubMesh> subMeshDescriptor( subMeshData.name().c_str() );
368 subMeshDescriptor.data(
369 {
370 boneCount,
371 subMeshData.index(),
372 0u
373 });
374
375 Handle<SubMesh> tempSubMeshHandle = CreateResource(subMeshDescriptor );
376
377 SubMesh* tempSubMesh = Get(tempSubMeshHandle);
378 // it may already be loaded
379 if (!tempSubMesh->parentMesh())
380 {
381 Attorney::MeshImporter::addSubMesh(*mesh, tempSubMeshHandle, subMeshData.index());
382 Attorney::SubMeshMesh::setParentMesh( *tempSubMesh, mesh );
383
384 for (U8 lod = 0u, j = 0u; lod < subMeshData.lodCount(); ++lod)
385 {
386 if (!subMeshData._triangles[lod].empty())
387 {
388 tempSubMesh->setGeometryPartitionID(j, subMeshData._partitionIDs[j]);
389 tempSubMesh->addTriangles(subMeshData._partitionIDs[j], subMeshData._triangles[j]);
390 ++j;
391 }
392 }
393
394 Attorney::SubMeshMeshImporter::setBoundingBox(*tempSubMesh, subMeshData.minPos(), subMeshData.maxPos(), subMeshData.worldOffset());
395
396 if (tempSubMesh->getMaterialTpl() != INVALID_HANDLE<Material>)
397 {
398 tempSubMesh->setMaterialTpl(loadSubMeshMaterial(subMeshData._material, tempMeshData.fromFile(), boneCount > 0, taskCounter));
399 }
400 }
401 }
402
404
405 if ( tempMeshData._animationCount > 0u )
406 {
407 SceneAnimator* animator = mesh->getAnimator();
408 DIVIDE_ASSERT(animator != nullptr);
409
410 // Animation versioning is handled internally.
411 ByteBuffer tempBuffer;
412
413 const string saveFileName = Util::StringFormat( "{}.{}", tempMeshData.modelName(), g_parsedAssetAnimationExt );
414 if (tempBuffer.loadFromFile(Paths::g_geometryCacheLocation, saveFileName ))
415 {
416 animator->load(context, tempBuffer);
417 }
418 else
419 {
420 if (!tempMeshData.loadedFromFile())
421 {
422 // We lose ownership of animations here ...
424
425 animator->init(context, tempMeshData._skeleton, tempMeshData._bones);
426 animator->save(context, tempBuffer);
427 if (!tempBuffer.dumpToFile(Paths::g_geometryCacheLocation, saveFileName ))
428 {
429 //handle error
431 }
432 }
433 else
434 {
435 //handle error. No ASSIMP animation data available
437 }
438 }
439 }
440
441 WAIT_FOR_CONDITION(taskCounter.load() == 0);
442
443 importTimer.stop();
444 Console::d_printfn(LOCALE_STR("PARSE_MESH_TIME"),
445 tempMeshData.modelName(),
446 Time::MicrosecondsToMilliseconds<F32>(importTimer.get()));
447
448 return mesh->load( context );
449 }
450
452 Handle<Material> MeshImporter::loadSubMeshMaterial( const Import::MaterialData& importData, const bool loadedFromCache, bool skinned, std::atomic_uint& taskCounter)
453 {
454 bool wasInCache = false;
455 Handle<Material> tempMaterialHandle = CreateResource(ResourceDescriptor<Material>(importData.name().c_str()), wasInCache);
456 if (wasInCache)
457 {
458 return tempMaterialHandle;
459 }
460
461 ResourcePtr<Material> tempMaterial = Get(tempMaterialHandle);
462
463 if (!loadedFromCache)
464 {
465 tempMaterial->ignoreXMLData(true);
466 }
467
468 tempMaterial->properties().hardwareSkinning(skinned);
469 tempMaterial->properties().emissive(importData.emissive());
470 tempMaterial->properties().ambient(importData.ambient());
471 tempMaterial->properties().specular(importData.specular().rgb);
472 tempMaterial->properties().shininess(importData.specular().a);
473 tempMaterial->properties().specGloss(importData.specGloss());
474 tempMaterial->properties().metallic(importData.metallic());
475 tempMaterial->properties().roughness(importData.roughness());
476 tempMaterial->properties().parallaxFactor(importData.parallaxFactor());
477
478 tempMaterial->properties().baseColour(importData.baseColour());
479 tempMaterial->properties().ignoreTexDiffuseAlpha(importData.ignoreTexDiffuseAlpha());
480 tempMaterial->properties().shadingMode(importData.shadingMode());
481 tempMaterial->properties().bumpMethod(importData.bumpMethod());
482 tempMaterial->properties().doubleSided(importData.doubleSided());
483
484 SamplerDescriptor textureSampler = {};
485
486 TextureDescriptor textureDescriptor
487 {
489 };
490
491 for (U32 i = 0; i < to_base(TextureSlot::COUNT); ++i)
492 {
493 const Import::TextureEntry& tex = importData._textures[i];
494 if (!tex.textureName().empty())
495 {
496 textureSampler._wrapU = tex.wrapU();
497 textureSampler._wrapV = tex.wrapV();
498 textureSampler._wrapW = tex.wrapW();
499
500 if ( tex.srgb() )
501 {
502 textureDescriptor._packing = GFXImagePacking::NORMALIZED_SRGB;
503 }
504
505 textureDescriptor._textureOptions._useDDSCache = tex.useDDSCache();
506 textureDescriptor._textureOptions._isNormalMap = tex.isNormalMap();
507 textureDescriptor._textureOptions._alphaChannelTransparency = tex.alphaForTransparency();
508
509 ResourceDescriptor<Texture> texture(tex.textureName(), textureDescriptor );
510 texture.assetName(tex.textureName());
511 texture.assetLocation(tex.texturePath());
512 // No need to fire off additional threads just to wait on the result immediately after
513 texture.waitForReady(true);
514
515 tempMaterial->setTexture(static_cast<TextureSlot>(i),
516 CreateResource( texture, taskCounter ),
517 textureSampler,
518 tex.operation());
519 }
520 }
521
522 return tempMaterialHandle;
523 }
524} //namespace Divide
#define WAIT_FOR_CONDITION(...)
#define LOCALE_STR(X)
Definition: Localization.h:91
#define DIVIDE_ASSERT(...)
#define DIVIDE_UNEXPECTED_CALL()
static void addSubMesh(Mesh &parentMesh, const Handle< SubMesh > subMesh, const U32 index)
Definition: Mesh.h:123
static void setNodeData(Mesh &parentMesh, const MeshNodeData &nodeStructure)
Definition: Mesh.h:118
static void registerAnimations(SceneAnimator &animator, const vector< AnimEvaluator * > &animations)
PASS OWNERSHIP OF ANIMATIONS TO THE ANIMATOR!!!
static void setParentMesh(SubMesh &subMesh, ResourcePtr< Mesh > parentMesh)
Definition: SubMesh.h:117
static void setBoundingBox(SubMesh &subMesh, const vec3< F32 > &min, const vec3< F32 > &max, const vec3< F32 > &worldOffset) noexcept
Definition: SubMesh.h:129
bool loadFromFile(const ResourcePath &path, std::string_view fileName, const U8 version=BUFFER_FORMAT_VERSION)
Definition: ByteBuffer.cpp:57
bool dumpToFile(const ResourcePath &path, std::string_view fileName, const U8 version=BUFFER_FORMAT_VERSION)
Saves the entire buffer contents to file. Always appends the version at the end of the file.
Definition: ByteBuffer.cpp:47
VertexBuffer_ptr newVB(const VertexBuffer::Descriptor &descriptor)
Create and return a new vertex array (VAO + VB + IB).
Definition: GFXDevice.cpp:3101
static bool loadMesh(PlatformContext &context, ResourcePtr< Mesh > mesh)
static Handle< Material > loadSubMeshMaterial(const Import::MaterialData &importData, bool loadedFromCache, bool skinned, std::atomic_uint &taskCounter)
Load the material for the current SubMesh.
static bool loadMeshDataFromFile(PlatformContext &context, Import::ImportData &dataOut)
GFXDevice & gfx() noexcept
Configuration & config() noexcept
bool init(PlatformContext &context, Bone *skeleton, const vector< Bone * > &bones)
This will build the skeleton based on the scene passed to it and CLEAR EVERYTHING.
void save(PlatformContext &context, ByteBuffer &dataOut) const
void load(PlatformContext &context, ByteBuffer &dataIn)
bool Load(PlatformContext &context, Import::ImportData &target)
Str StringFormat(const char *fmt, Args &&...args)
bool CompareIgnoreCase(const char *a, const char *b) noexcept
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
constexpr U32 to_U32(const T value)
T * ResourcePtr
Definition: Resource.h:112
uint8_t U8
GeometryFormat
Definition: MeshImporter.h:43
GeometryFormat GetGeometryFormatForExtension(const char *extension) noexcept
constexpr U16 BYTE_BUFFER_VERSION
TextureOperation
How should each texture be added.
uint16_t U16
constexpr U64 _ID(const char *const str, const U64 value=val_64_const) noexcept
FORCE_INLINE Handle< T > CreateResource(const ResourceDescriptor< T > &descriptor, bool &wasInCache, std::atomic_uint &taskCounter)
FORCE_INLINE T * Get(const Handle< T > handle)
uint32_t U32
TextureSlot
Definition: Material.h:76
uint64_t U64
::value constexpr T CLAMPED_01(T n) noexcept
Definition: MathHelper.inl:134
constexpr auto to_base(const Type value) -> Type
struct Divide::Configuration::Debug::Cache cache
struct Divide::Configuration::Debug debug
static NO_INLINE void d_printfn(const char *format, T &&... args)
static NO_INLINE void printfn(const char *format, T &&... args)
VertexBuffer_ptr _vertexBuffer
Definition: MeshImporter.h:159
vector< SubMeshData > _subMeshData
Definition: MeshImporter.h:167
Divide::MeshNodeData _nodeData
Definition: MeshImporter.h:166
vector< Bone * > _bones
Definition: MeshImporter.h:165
bool loadFromFile(PlatformContext &context, const ResourcePath &path, std::string_view fileName)
vector< AnimEvaluator * > _animations
Definition: MeshImporter.h:170
bool saveToFile(PlatformContext &context, const ResourcePath &path, std::string_view fileName)
bool deserialize(ByteBuffer &dataIn)
bool serialize(ByteBuffer &dataOut) const
std::array< TextureEntry, to_base(TextureSlot::COUNT)> _textures
Definition: MeshImporter.h:109
vector< vec3< U32 > > _triangles[MAX_LOD_LEVELS]
Definition: MeshImporter.h:134
std::array< U16, MAX_LOD_LEVELS > _partitionIDs
Definition: MeshImporter.h:133
bool serialize(ByteBuffer &dataOut) const
bool deserialize(ByteBuffer &dataIn)
Definition: MeshImporter.h:70
bool serialize(ByteBuffer &dataOut) const
bool deserialize(ByteBuffer &dataIn)
bool deserialize(ByteBuffer &dataIn)
Definition: Mesh.cpp:194
bool serialize(ByteBuffer &dataOut) const
Definition: Mesh.cpp:182
TextureWrap _wrapU
Texture wrap mode (Or S-R-T)