18#include <assimp/DefaultLogger.hpp>
19#include <assimp/Importer.hpp>
20#include <assimp/Logger.hpp>
21#include <assimp/LogStream.hpp>
22#include <assimp/GltfMaterial.h>
23#include <assimp/postprocess.h>
24#include <assimp/scene.h>
25#include <assimp/types.h>
27#include <meshoptimizer.h>
36 void write(
const char* message)
override
38 Console::printfn(
"{}", message);
50 F32 _boneWeight = 0.0f;
56 Bone* internalNode =
new Bone(pNode->mName.data);
61 internalNode->localTransform(out);
62 internalNode->originalLocalTransform(internalNode->localTransform());
67 for (
U32 i = 0u; i < pNode->mNumChildren; ++i)
76namespace DVDConverter {
126 Assimp::DefaultLogger::create(
"", Assimp::Logger::VERBOSE);
127 Assimp::DefaultLogger::get()->attachStream(
new AssimpStream(), g_severity);
132 Assimp::DefaultLogger::kill();
136 if (node ==
nullptr) {
148 aiVector3D pScaling, pPosition;
149 aiQuaternion pRotation;
150 (axisCorrectionBasis * node->mTransformation).Decompose(pScaling, pRotation, pPosition);
152 vec3<F32>(pPosition.x, pPosition.y, pPosition.y),
153 vec3<F32>(pScaling.x, pScaling.y, pScaling.y),
158 target.
_name = node->mName.C_Str();
160 for (
U32 i = 0u; i < node->mNumMeshes; ++i) {
164 U32 numChildren = 0u;
165 target.
_children.resize(node->mNumChildren);
166 for (
U32 i = 0u; i < node->mNumChildren; ++i) {
170 return numChildren + node->mNumChildren;
176 const Str<256>& fileName = target.modelName();
178 Assimp::Importer importer;
180 importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, g_removeLinesAndPoints ? aiPrimitiveType_LINE | aiPrimitiveType_POINT : 0);
182 importer.SetPropertyInteger(AI_CONFIG_PP_FD_REMOVE, 1);
183 importer.SetPropertyInteger(AI_CONFIG_IMPORT_TER_MAKE_UVS, 1);
184 importer.SetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 1);
185 importer.SetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, 80.0f);
187 constexpr auto ppSteps = aiProcess_GlobalScale |
188 aiProcess_CalcTangentSpace |
189 aiProcess_JoinIdenticalVertices |
190 aiProcess_ImproveCacheLocality |
191 aiProcess_GenSmoothNormals |
192 aiProcess_LimitBoneWeights |
193 aiProcess_RemoveRedundantMaterials |
195 aiProcess_SplitLargeMeshes |
196 aiProcess_FindInstances |
197 aiProcess_Triangulate |
198 aiProcess_GenUVCoords |
199 aiProcess_SortByPType |
200 aiProcess_FindDegenerates |
201 aiProcess_FindInvalidData |
203 aiProcess_OptimizeMeshes |
204 aiProcess_GenBoundingBoxes |
205 aiProcess_TransformUVCoords;
207 const string modelPath = (filePath / fileName).
string();
208 const aiScene* aiScenePointer = importer.ReadFile( modelPath.c_str(),
to_U32(ppSteps) );
216 aiMatrix4x4 axisCorrectionBasis;
217 if (aiScenePointer->mMetaData)
219 I32 UpAxis = 1, UpAxisSign = 1, FrontAxis = 2, FrontAxisSign = 1, CoordAxis = 0, CoordAxisSign = 1;
220 D64 UnitScaleFactor = 1.0;
221 aiScenePointer->mMetaData->Get<
int>(
"UpAxis", UpAxis);
222 aiScenePointer->mMetaData->Get<
int>(
"UpAxisSign", UpAxisSign);
223 aiScenePointer->mMetaData->Get<
int>(
"FrontAxis", FrontAxis);
224 aiScenePointer->mMetaData->Get<
int>(
"FrontAxisSign", FrontAxisSign);
225 aiScenePointer->mMetaData->Get<
int>(
"CoordAxis", CoordAxis);
226 aiScenePointer->mMetaData->Get<
int>(
"CoordAxisSign", CoordAxisSign);
227 aiScenePointer->mMetaData->Get<
D64>(
"UnitScaleFactor", UnitScaleFactor);
229 aiVector3D upVec, forwardVec, rightVec;
230 upVec[
to_U32(UpAxis)] =
to_F32(UpAxisSign * UnitScaleFactor);
231 forwardVec[
to_U32(FrontAxis)] =
to_F32(FrontAxisSign * UnitScaleFactor);
232 rightVec[
to_U32(CoordAxis)] =
to_F32(CoordAxisSign * UnitScaleFactor);
234 axisCorrectionBasis = aiMatrix4x4(rightVec.x, rightVec.y, rightVec.z, 0.f,
235 upVec.x, upVec.y, upVec.z, 0.f,
236 forwardVec.x, forwardVec.y, forwardVec.z, 0.f,
248 if ( aiScenePointer->HasAnimations() )
250 target.
_skeleton = CreateBoneTree(aiScenePointer->mRootNode,
nullptr);
256 for (
U16 meshPointer = 0u; meshPointer < aiScenePointer->mNumMeshes; ++meshPointer )
258 const aiMesh* mesh = aiScenePointer->mMeshes[meshPointer];
259 for (
U32 n = 0; n < mesh->mNumBones; ++n )
261 const aiBone* bone = mesh->mBones[n];
264 DIVIDE_ASSERT( found !=
nullptr,
"DVDConverter::Load: Invalid skeleton detected while extracting bone data!" );
266 if ( found->boneID() == -1 )
269 found->offsetMatrix( out );
270 found->boneID( boneID++ );
271 target.
_bones.push_back( found );
276 for (
U32 i = 0u; i < aiScenePointer->mNumAnimations; ++i)
278 const aiAnimation* animation = aiScenePointer->mAnimations[i];
279 if (
IS_ZERO(animation->mDuration))
290 const U32 numMeshes = aiScenePointer->mNumMeshes;
296 constexpr U8 maxModelNameLength = 16;
297 constexpr U8 maxMeshNameLength = 64;
300 if (modelName.length() > maxModelNameLength)
302 modelName = modelName.substr(0, maxModelNameLength);
305 for (
U16 n = 0u; n < numMeshes; ++n)
307 const aiMesh* currentMesh = aiScenePointer->mMeshes[n];
309 if (currentMesh->mNumVertices == 0)
314 const string subMeshName = currentMesh->mName.length == 0 ?
Util::StringFormat(
"submesh_{}", n) : currentMesh->mName.C_Str();
318 subMeshTemp.name(fullName.length() >= maxMeshNameLength ? fullName.substr(0, maxMeshNameLength - 1u).c_str() : fullName.c_str());
319 subMeshTemp.index(
to_U32(n));
320 subMeshTemp.boneCount(
to_U8(currentMesh->mNumBones));
328 to_U16(currentMesh->mMaterialIndex),
329 Str<128>(subMeshTemp.name().c_str()) +
"_material",
345 size_t indexCount = 0u, vertexCount = 0u;
348 for (
U8 lod = 0u; lod < data.lodCount(); ++lod )
350 indexCount += data.
_indices[lod].size();
351 vertexCount += data.
_vertices[lod].size();
357 descriptor._keepCPUData =
true;
358 descriptor._largeIndices = vertexCount >=
U16_MAX;
359 descriptor._name = target.modelName();
367 U32 previousOffset = 0u;
374 U8 subMeshBoneOffset = 0u;
375 for (
U8 lod = 0u; lod < data.lodCount(); ++lod )
377 const size_t idxCount = data.
_indices[lod].size();
382 subMeshBoneOffset += data.boneCount();
388 const auto& indices = data.
_indices[lod];
389 for (
size_t i = 0; i < idxCount; i += 3)
391 const U32 triangleTemp[3] =
393 indices[i + 0] + previousOffset,
394 indices[i + 1] + previousOffset,
395 indices[i + 2] + previousOffset
398 data.
_triangles[lod].emplace_back(triangleTemp[0], triangleTemp[1], triangleTemp[2]);
406 const U32 vertCount =
to_U32(vertices.size());
408 for (
U32 i = 0; i < vertCount; ++i)
410 const U32 targetIdx = i + previousOffset;
429 for (
U32 i = 0; i < vertCount; ++i)
431 const U32 targetIdx = i + previousOffset;
435 for (
U8& idx : boneIndices.
_v)
437 idx += subMeshBoneOffset;
445 subMeshBoneOffset += data.boneCount();
446 previousOffset +=
to_U32(vertices.size());
457 subMeshData.maxPos( { source->mAABB.mMax.x, source->mAABB.mMax.y, source->mAABB.mMax.z } );
458 subMeshData.minPos( { source->mAABB.mMin.x, source->mAABB.mMin.y, source->mAABB.mMin.z } );
459 subMeshData.worldOffset( isAnimated ?
VECTOR3_ZERO : ((subMeshData.maxPos() + subMeshData.minPos()) * 0.5f) );
460 subMeshData.maxPos( subMeshData.maxPos() - subMeshData.worldOffset() );
461 subMeshData.minPos( subMeshData.minPos() - subMeshData.worldOffset() );
464 for (
U32 j = 0u, k = 0u; k < source->mNumFaces; ++k)
466 const U32* indices = source->mFaces[k].mIndices;
468 input_indices[j++] = indices[0];
469 input_indices[j++] = indices[1];
470 input_indices[j++] = indices[2];
474 for (
U32 j = 0u; j < source->mNumVertices; ++j)
476 const aiVector3D position = source->mVertices[j];
477 const aiVector3D normal = source->mNormals[j];
479 vertices[j].position.set(
vec3<F32>{ position.
x, position.y, position.z } - subMeshData.worldOffset());
480 vertices[j].normal.set( normal.x, normal.y, normal.z );
485 if (source->mTextureCoords[0] !=
nullptr)
487 for (
U32 j = 0u; j < source->mNumVertices; ++j)
489 const aiVector3D texCoord = source->mTextureCoords[0][j];
490 vertices[j].texcoord.set(texCoord.x, texCoord.y, texCoord.z);
495 if (source->mTangents !=
nullptr)
497 for (
U32 j = 0u; j < source->mNumVertices; ++j)
499 const aiVector3D tangent = source->mTangents[j];
500 vertices[j].tangent.set( tangent.x, tangent.y, tangent.z, 1.f);
509 if (source->mNumBones > 0u)
516 for (
U32 boneIndex = 0u; boneIndex < source->mNumBones; ++boneIndex )
520 assert( bone->boneID() != -1);
522 aiVertexWeight* weights = source->mBones[boneIndex]->mWeights;
523 U32 numWeights = source->mBones[boneIndex]->mNumWeights;
524 for (
U32 weightIndex = 0; weightIndex < numWeights; ++weightIndex )
526 U32 vertexId = weights[weightIndex].mVertexId;
527 F32 weight = weights[weightIndex].mWeight;
528 assert( vertexId <= vertices.size() );
531 for (
U8 i = 0; i < 4u; ++i )
546 constexpr F32 kThreshold = 1.02f;
547 constexpr D64 target_factor = 0.75;
548 constexpr F32 target_error = 1e-3f;
551 auto& target_indices = subMeshData.
_indices[0];
552 auto& target_vertices = subMeshData.
_vertices[0];
556 const size_t vertex_count = meshopt_generateVertexRemap( remap.data(),
557 input_indices.data(),
558 input_indices.size(),
560 source->mNumVertices,
562 const size_t index_count = input_indices.size();
563 target_indices.resize( index_count );
564 meshopt_remapIndexBuffer(target_indices.data(),
565 input_indices.data(),
566 input_indices.size(),
570 input_indices.clear();
572 target_vertices.resize( vertex_count );
573 meshopt_remapVertexBuffer( target_vertices.data(),
575 source->mNumVertices,
581 meshopt_optimizeVertexCache( target_indices.data(),
582 target_indices.data(),
584 target_vertices.size() );
586 meshopt_optimizeOverdraw( target_indices.data(),
587 target_indices.data(),
589 &target_vertices[0].position.x,
590 target_vertices.size(),
595 const size_t next_vertices = meshopt_optimizeVertexFetch( target_vertices.data(),
596 target_indices.data(),
598 target_vertices.data(),
599 target_vertices.size(),
601 target_vertices.resize( next_vertices );
603 subMeshData.lodCount( 1u );
606 if ( subMeshData.
_indices[0].size() >= g_minIndexCountForAutoLoD)
610 auto& target_indices = subMeshData.
_indices[i];
611 auto& target_vertices = subMeshData.
_vertices[i];
612 auto& source_indices = subMeshData.
_indices[i - 1];
613 auto& source_vertices = subMeshData.
_vertices[i - i];
615 const size_t target_index_count = size_t(
static_cast<D64>(source_indices.size()) * target_factor );
617 target_indices.resize( source_indices.size() );
619 const size_t next_indices = meshopt_simplify( target_indices.data(),
620 source_indices.data(),
621 source_indices.size(),
622 &source_vertices[0].position.x,
623 source_vertices.size(),
627 if (next_indices == source_indices.size() )
632 target_indices.resize( next_indices );
635 meshopt_optimizeVertexCache(target_indices.data(),
636 target_indices.data(),
637 target_indices.size(),
638 source_vertices.size() );
640 meshopt_optimizeOverdraw( target_indices.data(),
641 target_indices.data(),
642 target_indices.size(),
643 &source_vertices[0].position.x,
644 source_vertices.size(),
648 target_vertices.resize( source_vertices.size() );
649 const size_t next_vertices = meshopt_optimizeVertexFetch( target_vertices.data(),
650 target_indices.data(),
651 target_indices.size(),
652 source_vertices.data(),
653 source_vertices.size(),
655 target_vertices.resize( next_vertices );
657 subMeshData.lodCount(subMeshData.lodCount() + 1u);
664 const aiScene* source,
666 const U16 materialIndex,
669 bool convertHeightToBumpMap)
672 const aiMaterial* mat = source->mMaterials[materialIndex];
678 if (AI_SUCCESS == mat->Get(AI_MATKEY_NAME, matName)) {
679 material.name(matName.C_Str());
681 material.name(materialName);
684 I32 shadingModel = 0, flags = 0;
685 if (AI_SUCCESS == aiGetMaterialInteger(mat, AI_MATKEY_SHADING_MODEL, &shadingModel)) {
704 if (AI_SUCCESS == aiGetMaterialFloat(mat, AI_MATKEY_GLOSSINESS_FACTOR, &temp)) {
707 DIVIDE_ASSERT(AI_SUCCESS == aiGetMaterialFloat(mat, AI_MATKEY_METALLIC_FACTOR, &temp));
710 aiGetMaterialInteger(mat, AI_MATKEY_TEXFLAGS_DIFFUSE(0), &flags);
711 const bool hasIgnoreAlphaFlag = (flags & aiTextureFlags_IgnoreAlpha) != 0;
712 if (hasIgnoreAlphaFlag) {
713 material.ignoreTexDiffuseAlpha(
true);
715 const bool hasUseAlphaFlag = (flags & aiTextureFlags_UseAlpha) != 0;
716 if (hasUseAlphaFlag) {
717 material.ignoreTexDiffuseAlpha(
false);
722 material.baseColour(
FColour4(0.8f, 0.8f, 0.8f, 1.f));
724 if (AI_SUCCESS == aiGetMaterialColor(mat, AI_MATKEY_COLOR_DIFFUSE, &diffuse)) {
725 material.baseColour(
FColour4(diffuse.r, diffuse.g, diffuse.b, diffuse.a));
733 if (AI_SUCCESS == aiGetMaterialFloat(mat, AI_MATKEY_OPACITY, &alpha)) {
735 }
else if (AI_SUCCESS == aiGetMaterialFloat(mat, AI_MATKEY_TRANSPARENCYFACTOR, &alpha)) {
740 if (set && alpha > 0.f && alpha < 1.f) {
741 FColour4 base = material.baseColour();
743 material.baseColour(base);
748 F32 specShininess = 0.f;
749 if (AI_SUCCESS == aiGetMaterialFloat(mat, AI_MATKEY_SHININESS, &specShininess)) {
755 specShininess *= 10.f;
763 REMAP(specShininess, 0.f, 511.f, 0.f, 1000.f);
770 CLAMP(specShininess, 0.f, 1000.f);
775 F32 specStrength = 1.f;
776 aiGetMaterialFloat(mat, AI_MATKEY_SHININESS_STRENGTH, &specStrength);
778 aiColor4D specular = {1.f, 1.f, 1.f, 1.f};
779 aiGetMaterialColor(mat, AI_MATKEY_COLOR_SPECULAR, &specular);
781 material.specular({ specular.r * specStrength, specular.g * specStrength, specular.b * specStrength, specShininess });
784 material.emissive(
FColour3(0.f, 0.f, 0.f));
787 if (AI_SUCCESS == aiGetMaterialColor(mat, AI_MATKEY_COLOR_EMISSIVE, &emissive)) {
788 material.emissive(
FColour3(emissive.r, emissive.g, emissive.b));
792 material.ambient(
FColour3(0.f, 0.f, 0.f));
794 if (AI_SUCCESS == aiGetMaterialColor(mat, AI_MATKEY_COLOR_AMBIENT, &ambient)) {
800 material.metallic(0.f);
801 material.roughness(1.f);
803 F32 roughness = 0.f, metallic = 0.f;
805 if (AI_SUCCESS == aiGetMaterialFloat(mat, AI_MATKEY_METALLIC_FACTOR, &metallic)) {
806 material.metallic(metallic);
809 if (AI_SUCCESS == aiGetMaterialFloat(mat, AI_MATKEY_ROUGHNESS_FACTOR, &roughness)) {
810 material.roughness(roughness);
816 specularTemp.
rg = {1.f, 1.f};
817 aiGetMaterialFloat(mat, AI_MATKEY_SPECULAR_FACTOR, &specularTemp.
r);
818 aiGetMaterialFloat(mat, AI_MATKEY_GLOSSINESS_FACTOR, &specularTemp.
g);
819 material.specular(specularTemp);
823 F32 bumpScaling = 0.0f;
824 if (AI_SUCCESS == aiGetMaterialFloat(mat, AI_MATKEY_BUMPSCALING, &bumpScaling)) {
825 material.parallaxFactor(bumpScaling);
829 aiGetMaterialInteger(mat, AI_MATKEY_TWOSIDED, &twoSided);
830 material.doubleSided(twoSided != 0);
834 aiTextureMapping mapping = aiTextureMapping_OTHER;
837 aiTextureOp op = aiTextureOp_Multiply;
838 aiTextureMapMode mode[3] = { _aiTextureMapMode_Force32Bit,
839 _aiTextureMapMode_Force32Bit,
840 _aiTextureMapMode_Force32Bit };
842 const auto loadTexture = [&material, &modelDirectoryName](
const TextureSlot usage,
TextureOperation texOp,
const aiString& name, aiTextureMapMode* wrapMode,
const bool srgb =
false)
845 constexpr const char* g_backupImageExtensions[] =
847 "png",
"jpg",
"jpeg",
"tga",
"dds"
851 string fileName(name.C_Str());
859 for (
const char* ext : g_backupImageExtensions)
861 fileName = fileNameStem +
"." + ext;
872 filePath = Paths::g_texturesLocation / modelDirectoryName;
880 for (
const char* ext : g_backupImageExtensions)
882 fileName = fileNameStem +
"." + ext;
906 texture.textureName(fileName);
907 texture.texturePath(filePath);
908 texture.operation(texOp);
910 texture.useDDSCache(
true);
922 if (AI_SUCCESS == mat->GetTexture(aiTextureType_BASE_COLOR, 0, &tName, &mapping, &uvInd, &blend, &op, mode) ||
923 AI_SUCCESS == mat->GetTexture(aiTextureType_DIFFUSE, 0, &tName, &mapping, &uvInd, &blend, &op, mode))
925 if (tName.length > 0) {
934 if (AI_SUCCESS == mat->GetTexture(aiTextureType_BASE_COLOR, 1, &tName, &mapping, &uvInd, &blend, &op, mode) ||
935 AI_SUCCESS == mat->GetTexture(aiTextureType_DIFFUSE, 1, &tName, &mapping, &uvInd, &blend, &op, mode))
937 if (tName.length > 0) {
946 if (AI_SUCCESS == mat->GetTexture(aiTextureType_BASE_COLOR, 2, &tName, &mapping, &uvInd, &blend, &op, mode) ||
947 AI_SUCCESS == mat->GetTexture(aiTextureType_DIFFUSE, 2, &tName, &mapping, &uvInd, &blend, &op, mode)) {
951 bool hasNormalMap =
false;
953 if (AI_SUCCESS == mat->GetTexture(aiTextureType_NORMAL_CAMERA, 0, &tName, &mapping, &uvInd, &blend, &op, mode) ||
954 AI_SUCCESS == mat->GetTexture(aiTextureType_NORMALS, 0, &tName, &mapping, &uvInd, &blend, &op, mode))
956 if (tName.length > 0) {
966 if (AI_SUCCESS == mat->GetTexture(aiTextureType_HEIGHT, 0, &tName, &mapping, &uvInd, &blend, &op, mode)) {
967 if (tName.length > 0) {
968 if (convertHeightToBumpMap && !hasNormalMap) {
981 if (AI_SUCCESS == mat->GetTexture(aiTextureType_DISPLACEMENT, 0, &tName, &mapping, &uvInd, &blend, &op, mode)) {
982 if (tName.length > 0) {
991 if (AI_SUCCESS == mat->GetTexture(aiTextureType_OPACITY, 0, &tName, &mapping, &uvInd, &blend, &op, mode)) {
992 if (tName.length > 0) {
1000 if (AI_SUCCESS == mat->GetTexture(aiTextureType_SPECULAR, 0, &tName, &mapping, &uvInd, &blend, &op, mode)) {
1001 if (tName.length > 0) {
1004 material.specular({ 0.f, 0.f, 0.f, material.specular().a });
1011 if (AI_SUCCESS == mat->GetTexture(aiTextureType_EMISSIVE, 0, &tName, &mapping, &uvInd, &blend, &op, mode) ||
1012 AI_SUCCESS == mat->GetTexture(aiTextureType_EMISSION_COLOR, 0, &tName, &mapping, &uvInd, &blend, &op, mode)) {
1013 if (tName.length > 0) {
1020 if (AI_SUCCESS == mat->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE, &tName, &mapping, &uvInd, &blend, &op, mode)) {
1021 if (tName.length > 0) {
1027 if (AI_SUCCESS == mat->GetTexture(aiTextureType_METALNESS, 0, &tName, &mapping, &uvInd, &blend, &op, mode)) {
1028 if (tName.length > 0) {
1034 if (AI_SUCCESS == mat->GetTexture(aiTextureType_DIFFUSE_ROUGHNESS, 0, &tName, &mapping, &uvInd, &blend, &op, mode)) {
1035 if (tName.length > 0) {
1041 if (AI_SUCCESS == mat->GetTexture(aiTextureType_AMBIENT_OCCLUSION, 0, &tName, &mapping, &uvInd, &blend, &op, mode)) {
1042 if (tName.length > 0) {
1049 if (AI_SUCCESS == mat->GetTexture(aiTextureType_SHEEN, 0, &tName, &mapping, &uvInd, &blend, &op, mode)) {
1050 if (tName.length > 0) {
1054 if (AI_SUCCESS == mat->GetTexture(aiTextureType_CLEARCOAT, 0, &tName, &mapping, &uvInd, &blend, &op, mode)) {
1055 if (tName.length > 0) {
1059 if (AI_SUCCESS == mat->GetTexture(aiTextureType_TRANSMISSION, 0, &tName, &mapping, &uvInd, &blend, &op, mode)) {
1060 if (tName.length > 0) {
1064 if (AI_SUCCESS == mat->GetTexture(aiTextureType_UNKNOWN, 0, &tName, &mapping, &uvInd, &blend, &op, mode)) {
1065 if (tName.length > 0) {
size_t hierarchyDepth() const
Bone * find(const string &name)
vector< Bone * > _children
VertexBuffer_ptr newVB(const VertexBuffer::Descriptor &descriptor)
Create and return a new vertex array (VAO + VB + IB).
static constexpr F32 MAX_SHININESS
GFXDevice & gfx() noexcept
void addIndex(const U32 index)
void modifyTexCoordValue(const U32 index, vec2< F32 > newValue)
void modifyBoneWeights(const U32 index, const FColour4 &weights)
void modifyTangentValue(const U32 index, const vec3< F32 > &newValue)
void reserveIndexCount(const size_t size)
void modifyNormalValue(const U32 index, const vec3< F32 > &newValue)
void setVertexCount(const size_t size)
void modifyBoneIndices(const U32 index, const vec4< U8 > indices)
void modifyPositionValue(const U32 index, const vec3< F32 > &newValue)
void TransformMatrix(const aiMatrix4x4 &in, mat4< F32 > &out, const bool rowMajor) noexcept
constexpr bool IS_DEBUG_BUILD
constexpr U16 MAX_BONE_COUNT_PER_NODE
Maximum number of bones available per node.
static hashMap< U32, ShadingMode > fillShadingModeMap()
void LoadSubMeshGeometry(const aiMesh *source, Import::SubMeshData &subMeshData, Import::ImportData &target)
static NO_DESTROY hashMap< U32, TextureOperation > aiTextureOperationTable
void BuildGeometryBuffers(PlatformContext &context, Import::ImportData &target)
static hashMap< U32, TextureOperation > fillTextureOperationMap()
static NO_DESTROY hashMap< U32, TextureWrap > aiTextureMapModeTable
static hashMap< U32, TextureWrap > fillTextureWrapMap()
void LoadSubMeshMaterial(Import::MaterialData &material, const aiScene *source, const ResourcePath &modelDirectoryName, const U16 materialIndex, const Str< 128 > &materialName, const GeometryFormat format, bool convertHeightToBumpMap)
static NO_DESTROY hashMap< U32, ShadingMode > aiShadingModeInternalTable
void OnStartup(const PlatformContext &context)
bool Load(PlatformContext &context, Import::ImportData &target)
U32 PopulateNodeData(aiNode *node, MeshNodeData &target, const aiMatrix4x4 &axisCorrectionBasis)
constexpr U8 MAX_LOD_LEVELS
Str StringFormat(const char *fmt, Args &&...args)
constexpr size_t g_minIndexCountForAutoLoD
constexpr bool g_removeLinesAndPoints
Bone * CreateBoneTree(aiNode *pNode, Bone *parent)
Recursively creates an internal node structure matching the current scene and animation.
Handle console commands that start with a forward slash.
bool IS_ZERO(const T X) noexcept
constexpr U32 to_U32(const T value)
ResourcePath getTopLevelFolderName(const ResourcePath &filePath)
bool IS_IN_RANGE_INCLUSIVE(const T x, const U min, const U max) noexcept
constexpr U16 to_U16(const T value)
constexpr void REMAP(T &input, T in_min, T in_max, T out_min, T out_max, D64 &slopeOut) noexcept
constexpr F32 to_F32(const T value)
void CalculateBoneToWorldTransform(Bone *pInternalNode) noexcept
Calculates the global transformation matrix for the given internal node.
string getExtension(const std::string_view fileName)
GeometryFormat GetGeometryFormatForExtension(const char *extension) noexcept
TextureOperation
How should each texture be added.
eastl::vector< Type > vector
hashAlg::unordered_map< K, V, HashFun, Predicate > hashMap
::value constexpr T MAP(T input, T in_min, T in_max, T out_min, T out_max, D64 &slopeOut) noexcept
constexpr U8 to_U8(const T value)
string stripExtension(const std::string_view fileName) noexcept
mat3< T > GetMatrix(const Quaternion< T > &q) noexcept
::value constexpr void CLAMP(T &n, T min, T max) noexcept
Clamps value n between min and max.
bool COMPARE(T X, U Y) noexcept
bool fileExists(const ResourcePath &filePathAndName)
static const vec3< F32 > VECTOR3_ZERO
constexpr auto to_base(const Type value) -> Type
static NO_INLINE void d_printfn(const char *format, T &&... args)
static NO_INLINE void errorfn(const char *format, T &&... args)
static NO_INLINE void warnfn(const char *format, T &&... args)
VertexBuffer_ptr _vertexBuffer
vector< SubMeshData > _subMeshData
Divide::MeshNodeData _nodeData
vector< AnimEvaluator * > _animations
std::array< TextureEntry, to_base(TextureSlot::COUNT)> _textures
vector< Vertex > _vertices[MAX_LOD_LEVELS]
vector< U32 > _indices[MAX_LOD_LEVELS]
vector< vec3< U32 > > _triangles[MAX_LOD_LEVELS]
AttributeFlags _useAttribute
std::array< U16, MAX_LOD_LEVELS > _partitionIDs
vector< MeshNodeData > _children
vector< U32 > _meshIndices
Index into Mesh::MeshData.
bool _allowDynamicUpdates
void write(const char *message) override