From ed52abbec59881abc349ecc2fcd427f363f6a71a Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Tue, 23 Apr 2019 09:15:54 -0700 Subject: Moved GLTFLoader structures to the header --- AssetLoader/src/GLTFLoader.cpp | 1994 ++++++++++++++++++---------------------- 1 file changed, 900 insertions(+), 1094 deletions(-) (limited to 'AssetLoader/src/GLTFLoader.cpp') diff --git a/AssetLoader/src/GLTFLoader.cpp b/AssetLoader/src/GLTFLoader.cpp index fb3d0d0..2b94c4b 100644 --- a/AssetLoader/src/GLTFLoader.cpp +++ b/AssetLoader/src/GLTFLoader.cpp @@ -26,7 +26,6 @@ #include #include "GLTFLoader.h" -#include "AdvancedMath.h" #include "MapHelper.h" #include "CommonlyUsedStates.h" @@ -38,1334 +37,1141 @@ #include "../../External/tinygltf/tiny_gltf.h" - -// Changing this value here also requires changing it in the vertex shader -#define MAX_NUM_JOINTS 128u - namespace Diligent { namespace GLTF { - RefCntAutoPtr TextureFromGLTFImage(IRenderDevice* pDevice, - IDeviceContext* pCtx, - const tinygltf::Image& gltfimage, - ISampler* pSampler) + +RefCntAutoPtr TextureFromGLTFImage(IRenderDevice* pDevice, + IDeviceContext* pCtx, + const tinygltf::Image& gltfimage, + ISampler* pSampler) +{ + std::vector RGBA; + const Uint8* pTextureData = nullptr; + if (gltfimage.component == 3) { - std::vector RGBA; - const Uint8* pTextureData = nullptr; - if (gltfimage.component == 3) + RGBA.resize(gltfimage.width * gltfimage.height * 4); + auto rgb = gltfimage.image.begin(); + auto rgba = RGBA.begin(); + for (int i = 0; i < gltfimage.width * gltfimage.height; ++i) { - RGBA.resize(gltfimage.width * gltfimage.height * 4); - auto rgb = gltfimage.image.begin(); - auto rgba = RGBA.begin(); - for (int i = 0; i < gltfimage.width * gltfimage.height; ++i) + for (int j = 0; j < 3; ++j) { - for (int j = 0; j < 3; ++j) - { - rgba[j] = rgb[j]; - } - rgba += 4; - rgb += 3; + rgba[j] = rgb[j]; } - pTextureData = RGBA.data(); - } - else if (gltfimage.component == 4) - { - pTextureData = gltfimage.image.data(); - } - else - { - UNEXPECTED("Unexpected number of color components in gltf image: ", gltfimage.component); + rgba += 4; + rgb += 3; } + pTextureData = RGBA.data(); + } + else if (gltfimage.component == 4) + { + pTextureData = gltfimage.image.data(); + } + else + { + UNEXPECTED("Unexpected number of color components in gltf image: ", gltfimage.component); + } - TextureDesc TexDesc; - TexDesc.Name = "GLTF Texture"; - TexDesc.Type = RESOURCE_DIM_TEX_2D; - TexDesc.Usage = USAGE_DEFAULT; - TexDesc.BindFlags = BIND_SHADER_RESOURCE; - TexDesc.Width = gltfimage.width; - TexDesc.Height = gltfimage.height; - TexDesc.Format = TEX_FORMAT_RGBA8_UNORM; - TexDesc.MipLevels = 0; - TexDesc.MiscFlags = MISC_TEXTURE_FLAG_GENERATE_MIPS; - RefCntAutoPtr pTexture; + TextureDesc TexDesc; + TexDesc.Name = "GLTF Texture"; + TexDesc.Type = RESOURCE_DIM_TEX_2D; + TexDesc.Usage = USAGE_DEFAULT; + TexDesc.BindFlags = BIND_SHADER_RESOURCE; + TexDesc.Width = gltfimage.width; + TexDesc.Height = gltfimage.height; + TexDesc.Format = TEX_FORMAT_RGBA8_UNORM; + TexDesc.MipLevels = 0; + TexDesc.MiscFlags = MISC_TEXTURE_FLAG_GENERATE_MIPS; + RefCntAutoPtr pTexture; - pDevice->CreateTexture(TexDesc, nullptr, &pTexture); - Box UpdateBox; - UpdateBox.MaxX = TexDesc.Width; - UpdateBox.MaxY = TexDesc.Height; - TextureSubResData Level0Data(pTextureData, gltfimage.width*4); - pCtx->UpdateTexture(pTexture, 0, 0, UpdateBox, Level0Data, RESOURCE_STATE_TRANSITION_MODE_NONE, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); - pCtx->GenerateMips(pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE)); - pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE)->SetSampler(pSampler); - - return pTexture; - } + pDevice->CreateTexture(TexDesc, nullptr, &pTexture); + Box UpdateBox; + UpdateBox.MaxX = TexDesc.Width; + UpdateBox.MaxY = TexDesc.Height; + TextureSubResData Level0Data(pTextureData, gltfimage.width*4); + pCtx->UpdateTexture(pTexture, 0, 0, UpdateBox, Level0Data, RESOURCE_STATE_TRANSITION_MODE_NONE, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + pCtx->GenerateMips(pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE)); + pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE)->SetSampler(pSampler); + + return pTexture; +} + + + +Mesh::Mesh(IRenderDevice* pDevice, const float4x4& matrix) +{ + uniformBlock.matrix = matrix; + + BufferDesc BuffDesc; + BuffDesc.Name = "GLTF mesh Uniform buffer"; + BuffDesc.uiSizeInBytes = sizeof(UniformBlock); + BuffDesc.BindFlags = BIND_UNIFORM_BUFFER; + BuffDesc.Usage = USAGE_DYNAMIC; + BuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE; + + BufferData BuffData(&uniformBlock, sizeof(uniformBlock)); + pDevice->CreateBuffer(BuffDesc, &BuffData, &pUniformBuffer); +}; + +void Mesh::SetBoundingBox(const float3& min, const float3& max) +{ + BB.Min = min; + BB.Max = max; + IsValidBB = true; +} - struct Material - { - enum ALPHA_MODE - { - ALPHAMODE_OPAQUE, - ALPHAMODE_MASK, - ALPHAMODE_BLEND - }; - ALPHA_MODE AlphaMode = ALPHAMODE_OPAQUE; - - float AlphaCutoff = 1.0f; - float MetallicFactor = 1.0f; - float RoughnessFactor = 1.0f; - float4 BaseColorFactor = float4(1.0f, 1.0f, 1.0f, 1.0f); - float4 EmissiveFactor = float4(1.0f, 1.0f, 1.0f, 1.0f); - - RefCntAutoPtr pBaseColorTexture; - RefCntAutoPtr pMetallicRoughnessTexture; - RefCntAutoPtr pNormalTexture; - RefCntAutoPtr pOcclusionTexture; - RefCntAutoPtr pEmissiveTexture; - - struct TextureCoordinateSets - { - Uint8 BaseColor = 0; - Uint8 MetallicRoughness = 0; - Uint8 SpecularGlossiness = 0; - Uint8 Normal = 0; - Uint8 Occlusion = 0; - Uint8 Emissive = 0; - }; - TextureCoordinateSets TexCoordSets; - - struct Extension - { - RefCntAutoPtr pSpecularGlossinessTexture; - RefCntAutoPtr pDiffuseTexture; - float4 DiffuseFactor = float4(1.0f, 1.0f, 1.0f, 1.0f); - float3 SpecularFactor = float3(0.0f, 0.0f, 0.0f); - }; - Extension extension; - - struct PbrWorkflows - { - bool MetallicRoughness = true; - bool SpecularGlossiness = false; - }; - PbrWorkflows pbrWorkflows; - }; - - struct Primitive + + +float4x4 Node::LocalMatrix()const +{ + return float4x4::TranslationGL(Translation) * QuaternionToMatrix(Rotation) * float4x4::Scale(Scale) * Matrix; +} + +float4x4 Node::GetMatrix()const +{ + auto mat = LocalMatrix(); + auto* p = Parent; + while (p != nullptr) + { + mat = mat * p->LocalMatrix(); + p = p->Parent; + } + return mat; +} + +void Node::Update(IDeviceContext* pCtx) +{ + if (Mesh) { - Uint32 FirstIndex = 0; - Uint32 IndexCount = 0; - Uint32 VertexCount = 0; - Material& material; - bool hasIndices; - - BoundBox BB; - bool IsValidBB = false; - - Primitive(Uint32 _FirstIndex, - Uint32 _IndexCount, - Uint32 _VertexCount, - Material& _material) : - FirstIndex (_FirstIndex), - IndexCount (_IndexCount), - VertexCount (_VertexCount), - material (_material), - hasIndices (_IndexCount > 0) + auto mat = GetMatrix(); + if (Skin != nullptr) { + Mesh->uniformBlock.matrix = mat; + // Update join matrices + auto InverseTransform = mat.Inverse(); + size_t numJoints = std::min((uint32_t)Skin->Joints.size(), Mesh::UniformBlock::MaxNumJoints); + for (size_t i = 0; i < numJoints; i++) + { + auto* JointNode = Skin->Joints[i]; + auto JointMat = JointNode->GetMatrix() * Skin->InverseBindMatrices[i]; + JointMat = InverseTransform * JointMat; + Mesh->uniformBlock.jointMatrix[i] = JointMat; + } + Mesh->uniformBlock.jointcount = (float)numJoints; + MapHelper UniformData(pCtx, Mesh->pUniformBuffer, MAP_WRITE, MAP_FLAG_DISCARD); + *UniformData = Mesh->uniformBlock; } - - void SetBoundingBox(const float3& min, const float3& max) + else { - BB.Min = min; - BB.Max = max; - IsValidBB = true; + MapHelper UniformData(pCtx, Mesh->pUniformBuffer, MAP_WRITE, MAP_FLAG_DISCARD); + UniformData->matrix = mat; } - }; + } + for (auto& child : Children) { + child->Update(pCtx); + } +} - struct Mesh - { - std::vector> Primitives; - BoundBox BB; - BoundBox AABB; - bool IsValidBB = false; - RefCntAutoPtr pUniformBuffer; - struct UniformBlock - { - float4x4 matrix; - float4x4 jointMatrix[MAX_NUM_JOINTS] = {}; - float jointcount = 0; - } uniformBlock; - Mesh(IRenderDevice* pDevice, const float4x4& matrix) - { - uniformBlock.matrix = matrix; - - BufferDesc BuffDesc; - BuffDesc.Name = "GLTF mesh Uniform buffer"; - BuffDesc.uiSizeInBytes = sizeof(UniformBlock); - BuffDesc.BindFlags = BIND_UNIFORM_BUFFER; - BuffDesc.Usage = USAGE_DYNAMIC; - BuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE; - - BufferData BuffData(&uniformBlock, sizeof(uniformBlock)); - pDevice->CreateBuffer(BuffDesc, &BuffData, &pUniformBuffer); - }; +void Model::Destroy() +{ + pVertexBuffer.Release(); + pIndexBuffer.Release(); + Nodes.clear(); + LinearNodes.clear(); + Skins.clear(); + Textures.clear(); + TextureSamplers.clear(); + Materials.clear(); + Animations.clear(); + Extensions.clear(); +}; + +void Model::LoadNode(IRenderDevice* pDevice, + Node* parent, + const tinygltf::Node& gltf_node, + uint32_t nodeIndex, + const tinygltf::Model& gltf_model, + std::vector& indexBuffer, + std::vector& vertexBuffer, + float globalscale) +{ + std::unique_ptr NewNode(new Node{}); + NewNode->Index = nodeIndex; + NewNode->Parent = parent; + NewNode->Name = gltf_node.name; + NewNode->SkinIndex = gltf_node.skin; + NewNode->Matrix = float4x4::Identity(); + + // Generate local node matrix + //float3 Translation; + if (gltf_node.translation.size() == 3) + { + NewNode->Translation = float3::MakeVector(gltf_node.translation.data()); + } - void SetBoundingBox(const float3& min, const float3& max) - { - BB.Min = min; - BB.Max = max; - IsValidBB = true; - } - }; + if (gltf_node.rotation.size() == 4) + { + NewNode->Rotation.q = float4::MakeVector(gltf_node.rotation.data()); + //NewNode->rotation = glm::mat4(q); + } + if (gltf_node.scale.size() == 3) + { + NewNode->Scale = float3::MakeVector(gltf_node.scale.data()); + } - struct Node; - struct Skin + if (gltf_node.matrix.size() == 16) { - std::string Name; - Node* pSkeletonRoot = nullptr; - std::vector InverseBindMatrices; - std::vector Joints; + NewNode->Matrix = float4x4::MakeMatrix(gltf_node.matrix.data()); }; - /* - glTF node - */ - struct Node + // Node with children + if (gltf_node.children.size() > 0) { - std::string Name; - Node* Parent = nullptr; - Uint32 Index; - std::vector> Children; - float4x4 Matrix; - std::unique_ptr Mesh; - Skin* Skin = nullptr; - Uint32 SkinIndex = static_cast(-1); - float3 Translation; - float3 Scale = float3(1.0f, 1.0f, 1.0f); - Quaternion Rotation; - BoundBox BVH; - BoundBox AABB; - bool IsValidBVH = false; - - float4x4 LocalMatrix() + for (size_t i = 0; i < gltf_node.children.size(); i++) { - float4x4::TranslationGL(Translation) * QuaternionToMatrix(Rotation) * float4x4::Scale(Scale) * Matrix; + LoadNode(pDevice, NewNode.get(), gltf_model.nodes[gltf_node.children[i]], gltf_node.children[i], gltf_model, indexBuffer, vertexBuffer, globalscale); } + } - float4x4 GetMatrix() + // Node contains mesh data + if (gltf_node.mesh > -1) + { + const tinygltf::Mesh& gltf_mesh = gltf_model.meshes[gltf_node.mesh]; + std::unique_ptr NewMesh(new Mesh(pDevice, NewNode->Matrix)); + for (size_t j = 0; j < gltf_mesh.primitives.size(); j++) { - auto mat = LocalMatrix(); - auto* p = Parent; - while (p != nullptr) + const tinygltf::Primitive& primitive = gltf_mesh.primitives[j]; + uint32_t indexStart = static_cast(indexBuffer.size()); + uint32_t vertexStart = static_cast(vertexBuffer.size()); + uint32_t indexCount = 0; + uint32_t vertexCount = 0; + float3 PosMin; + float3 PosMax; + bool hasSkin = false; + bool hasIndices = primitive.indices > -1; + + // Vertices { - mat = mat * p->LocalMatrix(); - p = p->Parent; + const float* bufferPos = nullptr; + const float* bufferNormals = nullptr; + const float* bufferTexCoordSet0 = nullptr; + const float* bufferTexCoordSet1 = nullptr; + const uint16_t* bufferJoints = nullptr; + const float* bufferWeights = nullptr; + + auto position_it = primitive.attributes.find("POSITION"); + VERIFY(position_it != primitive.attributes.end(), "Position attribute is required"); + + const tinygltf::Accessor& posAccessor = gltf_model.accessors[position_it->second]; + const tinygltf::BufferView& posView = gltf_model.bufferViews[posAccessor.bufferView]; + bufferPos = reinterpret_cast(&(gltf_model.buffers[posView.buffer].data[posAccessor.byteOffset + posView.byteOffset])); + PosMin = + float3 + { + static_cast(posAccessor.minValues[0]), + static_cast(posAccessor.minValues[1]), + static_cast(posAccessor.minValues[2]) + }; + PosMax = + float3 + { + static_cast(posAccessor.maxValues[0]), + static_cast(posAccessor.maxValues[1]), + static_cast(posAccessor.maxValues[2]) + }; + + vertexCount = static_cast(posAccessor.count); + + if (primitive.attributes.find("NORMAL") != primitive.attributes.end()) + { + const tinygltf::Accessor& normAccessor = gltf_model.accessors[primitive.attributes.find("NORMAL")->second]; + const tinygltf::BufferView& normView = gltf_model.bufferViews[normAccessor.bufferView]; + bufferNormals = reinterpret_cast(&(gltf_model.buffers[normView.buffer].data[normAccessor.byteOffset + normView.byteOffset])); + } + + if (primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end()) + { + const tinygltf::Accessor& uvAccessor = gltf_model.accessors[primitive.attributes.find("TEXCOORD_0")->second]; + const tinygltf::BufferView& uvView = gltf_model.bufferViews[uvAccessor.bufferView]; + bufferTexCoordSet0 = reinterpret_cast(&(gltf_model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset])); + } + if (primitive.attributes.find("TEXCOORD_1") != primitive.attributes.end()) + { + const tinygltf::Accessor& uvAccessor = gltf_model.accessors[primitive.attributes.find("TEXCOORD_1")->second]; + const tinygltf::BufferView& uvView = gltf_model.bufferViews[uvAccessor.bufferView]; + bufferTexCoordSet1 = reinterpret_cast(&(gltf_model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset])); + } + + // Skinning + // Joints + if (primitive.attributes.find("JOINTS_0") != primitive.attributes.end()) + { + const tinygltf::Accessor& jointAccessor = gltf_model.accessors[primitive.attributes.find("JOINTS_0")->second]; + const tinygltf::BufferView& jointView = gltf_model.bufferViews[jointAccessor.bufferView]; + bufferJoints = reinterpret_cast(&(gltf_model.buffers[jointView.buffer].data[jointAccessor.byteOffset + jointView.byteOffset])); + } + + if (primitive.attributes.find("WEIGHTS_0") != primitive.attributes.end()) + { + const tinygltf::Accessor& uvAccessor = gltf_model.accessors[primitive.attributes.find("WEIGHTS_0")->second]; + const tinygltf::BufferView& uvView = gltf_model.bufferViews[uvAccessor.bufferView]; + bufferWeights = reinterpret_cast(&(gltf_model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset])); + } + + hasSkin = (bufferJoints != nullptr && bufferWeights != nullptr); + + for (size_t v = 0; v < posAccessor.count; v++) + { + Vertex vert{}; + vert.pos = float4(float3::MakeVector(&bufferPos[v * 3]), 1.0f); + vert.normal = bufferNormals != nullptr ? normalize(float3::MakeVector(&bufferNormals[v * 3])) : float3{0,1,0}; + vert.uv0 = bufferTexCoordSet0 != nullptr ? float2::MakeVector(&bufferTexCoordSet0[v * 2]) : float2{}; + vert.uv1 = bufferTexCoordSet1 != nullptr ? float2::MakeVector(&bufferTexCoordSet1[v * 2]) : float2{}; + + if (hasSkin) + { + vert.joint0 = float4::MakeVector(&bufferJoints [v * 4]); + vert.weight0 = float4::MakeVector(&bufferWeights[v * 4]); + } + vertexBuffer.push_back(vert); + } } - return mat; - } - void Update(IDeviceContext* pCtx) - { - if (Mesh) + // Indices + if (hasIndices) { - auto mat = GetMatrix(); - if (Skin != nullptr) + const tinygltf::Accessor& accessor = gltf_model.accessors[primitive.indices > -1 ? primitive.indices : 0]; + const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView]; + const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer]; + + indexCount = static_cast(accessor.count); + const void *dataPtr = &(buffer.data[accessor.byteOffset + bufferView.byteOffset]); + + switch (accessor.componentType) { - Mesh->uniformBlock.matrix = mat; - // Update join matrices - auto InverseTransform = mat.Inverse(); - size_t numJoints = std::min((uint32_t)Skin->Joints.size(), MAX_NUM_JOINTS); - for (size_t i = 0; i < numJoints; i++) + case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: + { + const uint32_t *buf = static_cast(dataPtr); + for (size_t index = 0; index < accessor.count; index++) + { + indexBuffer.push_back(buf[index] + vertexStart); + } + break; + } + case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: + { + const uint16_t *buf = static_cast(dataPtr); + for (size_t index = 0; index < accessor.count; index++) + { + indexBuffer.push_back(buf[index] + vertexStart); + } + break; + } + case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: { - auto* JointNode = Skin->Joints[i]; - auto JointMat = JointNode->GetMatrix() * Skin->InverseBindMatrices[i]; - JointMat = InverseTransform * JointMat; - Mesh->uniformBlock.jointMatrix[i] = JointMat; + const uint8_t *buf = static_cast(dataPtr); + for (size_t index = 0; index < accessor.count; index++) + { + indexBuffer.push_back(buf[index] + vertexStart); + } + break; } - Mesh->uniformBlock.jointcount = (float)numJoints; - MapHelper UniformData(pCtx, Mesh->pUniformBuffer, MAP_WRITE, MAP_FLAG_DISCARD); - *UniformData = Mesh->uniformBlock; + default: + std::cerr << "Index component type " << accessor.componentType << " not supported!" << std::endl; + return; } - else + } + std::unique_ptr newPrimitive( + new Primitive { - MapHelper UniformData(pCtx, Mesh->pUniformBuffer, MAP_WRITE, MAP_FLAG_DISCARD); - UniformData->matrix = mat; + indexStart, + indexCount, + vertexCount, + primitive.material > -1 ? Materials[primitive.material] : Materials.back() } - } + ); - for (auto& child : Children) { - child->Update(pCtx); - } + newPrimitive->SetBoundingBox(PosMin, PosMax); + NewMesh->Primitives.push_back(std::move(newPrimitive)); } - }; + // Mesh BB from BBs of primitives + for (const auto& prim : NewMesh->Primitives) + { + if (prim->IsValidBB && !NewMesh->IsValidBB) + { + NewMesh->BB = prim->BB; + NewMesh->IsValidBB = true; + } + float3 bb_min = std::min(NewMesh->BB.Min, prim->BB.Min); + float3 bb_max = std::max(NewMesh->BB.Max, prim->BB.Max); + NewMesh->SetBoundingBox(bb_min, bb_max); + } + NewNode->Mesh = std::move(NewMesh); + } - struct AnimationChannel + LinearNodes.push_back(NewNode.get()); + if (parent) { - enum PATH_TYPE - { - TRANSLATION, - ROTATION, - SCALE - }; - PATH_TYPE PathType; - Node* node = nullptr; - Uint32 SamplerIndex = static_cast(-1); - }; + parent->Children.push_back(std::move(NewNode)); + } + else + { + Nodes.push_back(std::move(NewNode)); + } +} - struct AnimationSampler +void Model::LoadSkins(const tinygltf::Model& gltf_model) +{ + for (const auto& source : gltf_model.skins) { - enum INTERPOLATION_TYPE + std::unique_ptr NewSkin( new Skin{} ); + NewSkin->Name = source.name; + + // Find skeleton root node + if (source.skeleton > -1) { - LINEAR, - STEP, - CUBICSPLINE - }; - INTERPOLATION_TYPE Interpolation; - std::vector Inputs; - std::vector OutputsVec4; - }; + NewSkin->pSkeletonRoot = NodeFromIndex(source.skeleton); + } + // Find joint nodes + for (int jointIndex : source.joints) + { + Node* node = NodeFromIndex(jointIndex); + if (node) + { + NewSkin->Joints.push_back(NodeFromIndex(jointIndex)); + } + } - struct Animation - { - std::string Name; - std::vector Samplers; - std::vector Channels; + // Get inverse bind matrices from buffer + if (source.inverseBindMatrices > -1) + { + const tinygltf::Accessor& accessor = gltf_model.accessors[source.inverseBindMatrices]; + const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView]; + const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer]; + NewSkin->InverseBindMatrices.resize(accessor.count); + memcpy(NewSkin->InverseBindMatrices.data(), &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(float4x4)); + } - float Start = std::numeric_limits::max(); - float End = std::numeric_limits::min(); - }; + Skins.push_back(std::move(NewSkin)); + } +} - struct Model +void Model::LoadTextures(IRenderDevice* pDevice, + IDeviceContext* pCtx, + const tinygltf::Model& gltf_model) +{ + for (const tinygltf::Texture& gltf_tex : gltf_model.textures) { - struct Vertex + const tinygltf::Image& gltf_image = gltf_model.images[gltf_tex.source]; + RefCntAutoPtr pSampler; + if (gltf_tex.sampler == -1) + { + // No sampler specified, use a default one + pDevice->CreateSampler(Sam_LinearWrap, &pSampler); + } + else { - float3 pos; - float3 normal; - float2 uv0; - float2 uv1; - float4 joint0; - float4 weight0; - }; + pSampler = TextureSamplers[gltf_tex.sampler]; + } + auto pTexture = TextureFromGLTFImage(pDevice, pCtx, gltf_image, pSampler); + Textures.push_back(std::move(pTexture)); + } +} - RefCntAutoPtr pVertexBuffer; - RefCntAutoPtr pIndexBuffer; - Uint32 IndexCount = 0; +namespace +{ - float4x4 aabb; +TEXTURE_ADDRESS_MODE GetWrapMode(int32_t wrapMode) +{ + switch (wrapMode) + { + case 10497: + return TEXTURE_ADDRESS_WRAP; + case 33071: + return TEXTURE_ADDRESS_CLAMP; + case 33648: + return TEXTURE_ADDRESS_MIRROR; + default: + return TEXTURE_ADDRESS_WRAP; + } +} - std::vector> Nodes; - std::vector LinearNodes; +FILTER_TYPE GetFilterMode(int32_t filterMode) +{ + switch (filterMode) + { + case 9728: + return FILTER_TYPE_POINT; + case 9729: + return FILTER_TYPE_LINEAR; + case 9984: + return FILTER_TYPE_POINT; + case 9985: + return FILTER_TYPE_POINT; + case 9986: + return FILTER_TYPE_LINEAR; + case 9987: + return FILTER_TYPE_LINEAR; + default: + return FILTER_TYPE_LINEAR; + } +} - std::vector> Skins; +} // namespace - std::vector> Textures; - std::vector> TextureSamplers; - std::vector Materials; - std::vector Animations; - std::vector Extensions; +void Model::LoadTextureSamplers(IRenderDevice* pDevice, const tinygltf::Model& gltf_model) +{ + for (const tinygltf::Sampler& smpl : gltf_model.samplers) + { + SamplerDesc SamDesc; + SamDesc.MinFilter = GetFilterMode(smpl.minFilter); + SamDesc.MagFilter = GetFilterMode(smpl.magFilter); + SamDesc.MipFilter = SamDesc.MagFilter; + SamDesc.AddressU = GetWrapMode(smpl.wrapS); + SamDesc.AddressV = GetWrapMode(smpl.wrapT); + SamDesc.AddressW = SamDesc.AddressV; + RefCntAutoPtr pSampler; + pDevice->CreateSampler(SamDesc, &pSampler); + TextureSamplers.push_back(std::move(pSampler)); + } +} - struct Dimensions - { - float3 min = float3(+FLT_MAX, +FLT_MAX, +FLT_MAX); - float3 max = float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); - } dimensions; +void Model::LoadMaterials(const tinygltf::Model& gltf_model) +{ + for (const tinygltf::Material& gltf_mat : gltf_model.materials) + { + Material Mat; - void Destroy() { - pVertexBuffer.Release(); - pIndexBuffer.Release(); - Nodes.clear(); - LinearNodes.clear(); - Skins.clear(); - Textures.clear(); - TextureSamplers.clear(); - Materials.clear(); - Animations.clear(); - Extensions.clear(); - }; - - void LoadNode(IRenderDevice* pDevice, - Node* parent, - const tinygltf::Node& gltf_node, - uint32_t nodeIndex, - const tinygltf::Model& gltf_model, - std::vector& indexBuffer, - std::vector& vertexBuffer, - float globalscale) - { - std::unique_ptr NewNode(new Node{}); - NewNode->Index = nodeIndex; - NewNode->Parent = parent; - NewNode->Name = gltf_node.name; - NewNode->SkinIndex = gltf_node.skin; - NewNode->Matrix = float4x4::Identity(); - - // Generate local node matrix - //float3 Translation; - if (gltf_node.translation.size() == 3) + auto base_color_tex_it = gltf_mat.values.find("baseColorTexture"); + if (base_color_tex_it != gltf_mat.values.end()) { - NewNode->Translation = float3::MakeVector(gltf_node.translation.data()); + Mat.pBaseColorTexture = Textures[base_color_tex_it->second.TextureIndex()]; + Mat.TexCoordSets.BaseColor = static_cast(base_color_tex_it->second.TextureTexCoord()); } + } - if (gltf_node.rotation.size() == 4) + { + auto metal_rough_tex_it = gltf_mat.values.find("metallicRoughnessTexture"); + if (metal_rough_tex_it != gltf_mat.values.end()) { - NewNode->Rotation.q = float4::MakeVector(gltf_node.rotation.data()); - //NewNode->rotation = glm::mat4(q); + Mat.pMetallicRoughnessTexture = Textures[metal_rough_tex_it->second.TextureIndex()]; + Mat.TexCoordSets.MetallicRoughness = static_cast(metal_rough_tex_it->second.TextureTexCoord()); } + } - if (gltf_node.scale.size() == 3) + { + auto rough_factor_it = gltf_mat.values.find("roughnessFactor"); + if (rough_factor_it != gltf_mat.values.end()) { - NewNode->Scale = float3::MakeVector(gltf_node.scale.data()); + Mat.RoughnessFactor = static_cast(rough_factor_it->second.Factor()); } + } - if (gltf_node.matrix.size() == 16) - { - NewNode->Matrix = float4x4::MakeMatrix(gltf_node.matrix.data()); - }; - - // Node with children - if (gltf_node.children.size() > 0) + { + auto metal_factor_it = gltf_mat.values.find("metallicFactor"); + if (metal_factor_it != gltf_mat.values.end()) { - for (size_t i = 0; i < gltf_node.children.size(); i++) - { - LoadNode(pDevice, NewNode.get(), gltf_model.nodes[gltf_node.children[i]], gltf_node.children[i], gltf_model, indexBuffer, vertexBuffer, globalscale); - } + Mat.MetallicFactor = static_cast(metal_factor_it->second.Factor()); } + } - // Node contains mesh data - if (gltf_node.mesh > -1) + { + auto base_col_factor_it = gltf_mat.values.find("baseColorFactor"); + if (base_col_factor_it != gltf_mat.values.end()) { - const tinygltf::Mesh& gltf_mesh = gltf_model.meshes[gltf_node.mesh]; - std::unique_ptr NewMesh(new Mesh(pDevice, NewNode->Matrix)); - for (size_t j = 0; j < gltf_mesh.primitives.size(); j++) - { - const tinygltf::Primitive& primitive = gltf_mesh.primitives[j]; - uint32_t indexStart = static_cast(indexBuffer.size()); - uint32_t vertexStart = static_cast(vertexBuffer.size()); - uint32_t indexCount = 0; - uint32_t vertexCount = 0; - float3 PosMin; - float3 PosMax; - bool hasSkin = false; - bool hasIndices = primitive.indices > -1; - - // Vertices - { - const float* bufferPos = nullptr; - const float* bufferNormals = nullptr; - const float* bufferTexCoordSet0 = nullptr; - const float* bufferTexCoordSet1 = nullptr; - const uint16_t* bufferJoints = nullptr; - const float* bufferWeights = nullptr; - - auto position_it = primitive.attributes.find("POSITION"); - VERIFY(position_it != primitive.attributes.end(), "Position attribute is required"); - - const tinygltf::Accessor& posAccessor = gltf_model.accessors[position_it->second]; - const tinygltf::BufferView& posView = gltf_model.bufferViews[posAccessor.bufferView]; - bufferPos = reinterpret_cast(&(gltf_model.buffers[posView.buffer].data[posAccessor.byteOffset + posView.byteOffset])); - PosMin = - float3 - { - static_cast(posAccessor.minValues[0]), - static_cast(posAccessor.minValues[1]), - static_cast(posAccessor.minValues[2]) - }; - PosMax = - float3 - { - static_cast(posAccessor.maxValues[0]), - static_cast(posAccessor.maxValues[1]), - static_cast(posAccessor.maxValues[2]) - }; - - vertexCount = static_cast(posAccessor.count); - - if (primitive.attributes.find("NORMAL") != primitive.attributes.end()) - { - const tinygltf::Accessor& normAccessor = gltf_model.accessors[primitive.attributes.find("NORMAL")->second]; - const tinygltf::BufferView& normView = gltf_model.bufferViews[normAccessor.bufferView]; - bufferNormals = reinterpret_cast(&(gltf_model.buffers[normView.buffer].data[normAccessor.byteOffset + normView.byteOffset])); - } - - if (primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end()) - { - const tinygltf::Accessor& uvAccessor = gltf_model.accessors[primitive.attributes.find("TEXCOORD_0")->second]; - const tinygltf::BufferView& uvView = gltf_model.bufferViews[uvAccessor.bufferView]; - bufferTexCoordSet0 = reinterpret_cast(&(gltf_model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset])); - } - if (primitive.attributes.find("TEXCOORD_1") != primitive.attributes.end()) - { - const tinygltf::Accessor& uvAccessor = gltf_model.accessors[primitive.attributes.find("TEXCOORD_1")->second]; - const tinygltf::BufferView& uvView = gltf_model.bufferViews[uvAccessor.bufferView]; - bufferTexCoordSet1 = reinterpret_cast(&(gltf_model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset])); - } - - // Skinning - // Joints - if (primitive.attributes.find("JOINTS_0") != primitive.attributes.end()) - { - const tinygltf::Accessor& jointAccessor = gltf_model.accessors[primitive.attributes.find("JOINTS_0")->second]; - const tinygltf::BufferView& jointView = gltf_model.bufferViews[jointAccessor.bufferView]; - bufferJoints = reinterpret_cast(&(gltf_model.buffers[jointView.buffer].data[jointAccessor.byteOffset + jointView.byteOffset])); - } - - if (primitive.attributes.find("WEIGHTS_0") != primitive.attributes.end()) - { - const tinygltf::Accessor& uvAccessor = gltf_model.accessors[primitive.attributes.find("WEIGHTS_0")->second]; - const tinygltf::BufferView& uvView = gltf_model.bufferViews[uvAccessor.bufferView]; - bufferWeights = reinterpret_cast(&(gltf_model.buffers[uvView.buffer].data[uvAccessor.byteOffset + uvView.byteOffset])); - } - - hasSkin = (bufferJoints != nullptr && bufferWeights != nullptr); - - for (size_t v = 0; v < posAccessor.count; v++) - { - Vertex vert{}; - vert.pos = float4(float3::MakeVector(&bufferPos[v * 3]), 1.0f); - vert.normal = bufferNormals != nullptr ? normalize(float3::MakeVector(&bufferNormals[v * 3])) : float3{0,1,0}; - vert.uv0 = bufferTexCoordSet0 != nullptr ? float2::MakeVector(&bufferTexCoordSet0[v * 2]) : float2{}; - vert.uv1 = bufferTexCoordSet1 != nullptr ? float2::MakeVector(&bufferTexCoordSet1[v * 2]) : float2{}; - - if (hasSkin) - { - vert.joint0 = float4::MakeVector(&bufferJoints [v * 4]); - vert.weight0 = float4::MakeVector(&bufferWeights[v * 4]); - } - vertexBuffer.push_back(vert); - } - } - - // Indices - if (hasIndices) - { - const tinygltf::Accessor& accessor = gltf_model.accessors[primitive.indices > -1 ? primitive.indices : 0]; - const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView]; - const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer]; - - indexCount = static_cast(accessor.count); - const void *dataPtr = &(buffer.data[accessor.byteOffset + bufferView.byteOffset]); - - switch (accessor.componentType) - { - case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: - { - const uint32_t *buf = static_cast(dataPtr); - for (size_t index = 0; index < accessor.count; index++) - { - indexBuffer.push_back(buf[index] + vertexStart); - } - break; - } - case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: - { - const uint16_t *buf = static_cast(dataPtr); - for (size_t index = 0; index < accessor.count; index++) - { - indexBuffer.push_back(buf[index] + vertexStart); - } - break; - } - case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: - { - const uint8_t *buf = static_cast(dataPtr); - for (size_t index = 0; index < accessor.count; index++) - { - indexBuffer.push_back(buf[index] + vertexStart); - } - break; - } - default: - std::cerr << "Index component type " << accessor.componentType << " not supported!" << std::endl; - return; - } - } - std::unique_ptr newPrimitive( - new Primitive - { - indexStart, - indexCount, - vertexCount, - primitive.material > -1 ? Materials[primitive.material] : Materials.back() - } - ); - - newPrimitive->SetBoundingBox(PosMin, PosMax); - NewMesh->Primitives.push_back(std::move(newPrimitive)); - } - - // Mesh BB from BBs of primitives - for (const auto& prim : NewMesh->Primitives) - { - if (prim->IsValidBB && !NewMesh->IsValidBB) - { - NewMesh->BB = prim->BB; - NewMesh->IsValidBB = true; - } - float3 bb_min = std::min(NewMesh->BB.Min, prim->BB.Min); - float3 bb_max = std::max(NewMesh->BB.Max, prim->BB.Max); - NewMesh->SetBoundingBox(bb_min, bb_max); - } - NewNode->Mesh = std::move(NewMesh); + Mat.BaseColorFactor = float4::MakeVector(base_col_factor_it->second.ColorFactor().data()); } + } - LinearNodes.push_back(NewNode.get()); - if (parent) + { + auto normal_tex_it = gltf_mat.additionalValues.find("normalTexture"); + if (normal_tex_it != gltf_mat.additionalValues.end()) { - parent->Children.push_back(std::move(NewNode)); + Mat.pNormalTexture = Textures[normal_tex_it->second.TextureIndex()]; + Mat.TexCoordSets.Normal = static_cast(normal_tex_it->second.TextureTexCoord()); } - else + } + + { + auto emssive_tex_it = gltf_mat.additionalValues.find("emissiveTexture"); + if (emssive_tex_it != gltf_mat.additionalValues.end()) { - Nodes.push_back(std::move(NewNode)); + Mat.pEmissiveTexture = Textures[emssive_tex_it->second.TextureIndex()]; + Mat.TexCoordSets.Emissive = static_cast(emssive_tex_it->second.TextureTexCoord()); } } - - void LoadSkins(const tinygltf::Model& gltf_model) { - for (const auto& source : gltf_model.skins) + auto occlusion_tex_it = gltf_mat.additionalValues.find("occlusionTexture"); + if (occlusion_tex_it != gltf_mat.additionalValues.end()) { - std::unique_ptr NewSkin( new Skin{} ); - NewSkin->Name = source.name; - - // Find skeleton root node - if (source.skeleton > -1) - { - NewSkin->pSkeletonRoot = NodeFromIndex(source.skeleton); - } - - // Find joint nodes - for (int jointIndex : source.joints) - { - Node* node = NodeFromIndex(jointIndex); - if (node) - { - NewSkin->Joints.push_back(NodeFromIndex(jointIndex)); - } - } - - // Get inverse bind matrices from buffer - if (source.inverseBindMatrices > -1) - { - const tinygltf::Accessor& accessor = gltf_model.accessors[source.inverseBindMatrices]; - const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView]; - const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer]; - NewSkin->InverseBindMatrices.resize(accessor.count); - memcpy(NewSkin->InverseBindMatrices.data(), &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(float4x4)); - } - - Skins.push_back(std::move(NewSkin)); + Mat.pOcclusionTexture = Textures[occlusion_tex_it->second.TextureIndex()]; + Mat.TexCoordSets.Occlusion = static_cast(occlusion_tex_it->second.TextureTexCoord()); } } - - void LoadTextures(IRenderDevice* pDevice, - IDeviceContext* pCtx, - const tinygltf::Model& gltf_model) { - for (const tinygltf::Texture& gltf_tex : gltf_model.textures) + auto alpha_mode_it = gltf_mat.additionalValues.find("alphaMode"); + if (alpha_mode_it != gltf_mat.additionalValues.end()) { - const tinygltf::Image& gltf_image = gltf_model.images[gltf_tex.source]; - RefCntAutoPtr pSampler; - if (gltf_tex.sampler == -1) + const tinygltf::Parameter& param = alpha_mode_it->second; + if (param.string_value == "BLEND") { - // No sampler specified, use a default one - pDevice->CreateSampler(Sam_LinearWrap, &pSampler); + Mat.AlphaMode = Material::ALPHAMODE_BLEND; } - else + if (param.string_value == "MASK") { - pSampler = TextureSamplers[gltf_tex.sampler]; + Mat.AlphaCutoff = 0.5f; + Mat.AlphaMode = Material::ALPHAMODE_MASK; } - auto pTexture = TextureFromGLTFImage(pDevice, pCtx, gltf_image, pSampler); - Textures.push_back(std::move(pTexture)); } } - TEXTURE_ADDRESS_MODE GetWrapMode(int32_t wrapMode) { - switch (wrapMode) + auto alpha_cutoff_it = gltf_mat.additionalValues.find("alphaCutoff"); + if (alpha_cutoff_it != gltf_mat.additionalValues.end()) { - case 10497: - return TEXTURE_ADDRESS_WRAP; - case 33071: - return TEXTURE_ADDRESS_CLAMP; - case 33648: - return TEXTURE_ADDRESS_MIRROR; - default: - return TEXTURE_ADDRESS_WRAP; + Mat.AlphaCutoff = static_cast(alpha_cutoff_it->second.Factor()); } } - - FILTER_TYPE GetFilterMode(int32_t filterMode) + { - switch (filterMode) + auto emissive_fctr_it = gltf_mat.additionalValues.find("emissiveFactor"); + if (emissive_fctr_it != gltf_mat.additionalValues.end()) { - case 9728: - return FILTER_TYPE_POINT; - case 9729: - return FILTER_TYPE_LINEAR; - case 9984: - return FILTER_TYPE_POINT; - case 9985: - return FILTER_TYPE_POINT; - case 9986: - return FILTER_TYPE_LINEAR; - case 9987: - return FILTER_TYPE_LINEAR; - default: - return FILTER_TYPE_LINEAR; + Mat.EmissiveFactor = float4(float3::MakeVector(emissive_fctr_it->second.ColorFactor().data()), 1.0); + //Mat.EmissiveFactor = float4(0.0f); } } - void LoadTextureSamplers(IRenderDevice* pDevice, const tinygltf::Model& gltf_model) + // Extensions + // @TODO: Find out if there is a nicer way of reading these properties with recent tinygltf headers { - for (const tinygltf::Sampler& smpl : gltf_model.samplers) + auto ext_it = gltf_mat.extensions.find("KHR_materials_pbrSpecularGlossiness"); + if (ext_it != gltf_mat.extensions.end()) { - SamplerDesc SamDesc; - SamDesc.MinFilter = GetFilterMode(smpl.minFilter); - SamDesc.MagFilter = GetFilterMode(smpl.magFilter); - SamDesc.MipFilter = SamDesc.MagFilter; - SamDesc.AddressU = GetWrapMode(smpl.wrapS); - SamDesc.AddressV = GetWrapMode(smpl.wrapT); - SamDesc.AddressW = SamDesc.AddressV; - RefCntAutoPtr pSampler; - pDevice->CreateSampler(SamDesc, &pSampler); - TextureSamplers.push_back(std::move(pSampler)); - } - } - - - void LoadMaterials(const tinygltf::Model& gltf_model) - { - for (const tinygltf::Material& gltf_mat : gltf_model.materials) - { - Material Mat; - - { - auto base_color_tex_it = gltf_mat.values.find("baseColorTexture"); - if (base_color_tex_it != gltf_mat.values.end()) - { - Mat.pBaseColorTexture = Textures[base_color_tex_it->second.TextureIndex()]; - Mat.TexCoordSets.BaseColor = static_cast(base_color_tex_it->second.TextureTexCoord()); - } - } - - { - auto metal_rough_tex_it = gltf_mat.values.find("metallicRoughnessTexture"); - if (metal_rough_tex_it != gltf_mat.values.end()) - { - Mat.pMetallicRoughnessTexture = Textures[metal_rough_tex_it->second.TextureIndex()]; - Mat.TexCoordSets.MetallicRoughness = static_cast(metal_rough_tex_it->second.TextureTexCoord()); - } - } - - { - auto rough_factor_it = gltf_mat.values.find("roughnessFactor"); - if (rough_factor_it != gltf_mat.values.end()) - { - Mat.RoughnessFactor = static_cast(rough_factor_it->second.Factor()); - } - } - - { - auto metal_factor_it = gltf_mat.values.find("metallicFactor"); - if (metal_factor_it != gltf_mat.values.end()) - { - Mat.MetallicFactor = static_cast(metal_factor_it->second.Factor()); - } - } - + if (ext_it->second.Has("specularGlossinessTexture")) { - auto base_col_factor_it = gltf_mat.values.find("baseColorFactor"); - if (base_col_factor_it != gltf_mat.values.end()) - { - Mat.BaseColorFactor = float4::MakeVector(base_col_factor_it->second.ColorFactor().data()); - } + auto index = ext_it->second.Get("specularGlossinessTexture").Get("index"); + Mat.extension.pSpecularGlossinessTexture = Textures[index.Get()]; + auto texCoordSet = ext_it->second.Get("specularGlossinessTexture").Get("texCoord"); + Mat.TexCoordSets.SpecularGlossiness = static_cast(texCoordSet.Get()); + Mat.pbrWorkflows.SpecularGlossiness = true; } + if (ext_it->second.Has("diffuseTexture")) { - auto normal_tex_it = gltf_mat.additionalValues.find("normalTexture"); - if (normal_tex_it != gltf_mat.additionalValues.end()) - { - Mat.pNormalTexture = Textures[normal_tex_it->second.TextureIndex()]; - Mat.TexCoordSets.Normal = static_cast(normal_tex_it->second.TextureTexCoord()); - } + auto index = ext_it->second.Get("diffuseTexture").Get("index"); + Mat.extension.pDiffuseTexture = Textures[index.Get()]; } + if (ext_it->second.Has("diffuseFactor")) { - auto emssive_tex_it = gltf_mat.additionalValues.find("emissiveTexture"); - if (emssive_tex_it != gltf_mat.additionalValues.end()) + auto factor = ext_it->second.Get("diffuseFactor"); + for (uint32_t i = 0; i < factor.ArrayLen(); i++) { - Mat.pEmissiveTexture = Textures[emssive_tex_it->second.TextureIndex()]; - Mat.TexCoordSets.Emissive = static_cast(emssive_tex_it->second.TextureTexCoord()); + auto val = factor.Get(i); + Mat.extension.DiffuseFactor[i] = val.IsNumber() ? (float)val.Get() : (float)val.Get(); } } + if (ext_it->second.Has("specularFactor")) { - auto occlusion_tex_it = gltf_mat.additionalValues.find("occlusionTexture"); - if (occlusion_tex_it != gltf_mat.additionalValues.end()) + auto factor = ext_it->second.Get("specularFactor"); + for (uint32_t i = 0; i < factor.ArrayLen(); i++) { - Mat.pOcclusionTexture = Textures[occlusion_tex_it->second.TextureIndex()]; - Mat.TexCoordSets.Occlusion = static_cast(occlusion_tex_it->second.TextureTexCoord()); - } - } - - { - auto alpha_mode_it = gltf_mat.additionalValues.find("alphaMode"); - if (alpha_mode_it != gltf_mat.additionalValues.end()) - { - const tinygltf::Parameter& param = alpha_mode_it->second; - if (param.string_value == "BLEND") - { - Mat.AlphaMode = Material::ALPHAMODE_BLEND; - } - if (param.string_value == "MASK") - { - Mat.AlphaCutoff = 0.5f; - Mat.AlphaMode = Material::ALPHAMODE_MASK; - } + auto val = factor.Get(i); + Mat.extension.SpecularFactor[i] = val.IsNumber() ? (float)val.Get() : (float)val.Get(); } } + } + } - { - auto alpha_cutoff_it = gltf_mat.additionalValues.find("alphaCutoff"); - if (alpha_cutoff_it != gltf_mat.additionalValues.end()) - { - Mat.AlphaCutoff = static_cast(alpha_cutoff_it->second.Factor()); - } - } - - { - auto emissive_fctr_it = gltf_mat.additionalValues.find("emissiveFactor"); - if (emissive_fctr_it != gltf_mat.additionalValues.end()) - { - Mat.EmissiveFactor = float4(float3::MakeVector(emissive_fctr_it->second.ColorFactor().data()), 1.0); - //Mat.EmissiveFactor = float4(0.0f); - } - } + Materials.push_back(Mat); + } - // Extensions - // @TODO: Find out if there is a nicer way of reading these properties with recent tinygltf headers - { - auto ext_it = gltf_mat.extensions.find("KHR_materials_pbrSpecularGlossiness"); - if (ext_it != gltf_mat.extensions.end()) - { - if (ext_it->second.Has("specularGlossinessTexture")) - { - auto index = ext_it->second.Get("specularGlossinessTexture").Get("index"); - Mat.extension.pSpecularGlossinessTexture = Textures[index.Get()]; - auto texCoordSet = ext_it->second.Get("specularGlossinessTexture").Get("texCoord"); - Mat.TexCoordSets.SpecularGlossiness = static_cast(texCoordSet.Get()); - Mat.pbrWorkflows.SpecularGlossiness = true; - } + // Push a default material at the end of the list for meshes with no material assigned + Materials.push_back(Material{}); +} - if (ext_it->second.Has("diffuseTexture")) - { - auto index = ext_it->second.Get("diffuseTexture").Get("index"); - Mat.extension.pDiffuseTexture = Textures[index.Get()]; - } - if (ext_it->second.Has("diffuseFactor")) - { - auto factor = ext_it->second.Get("diffuseFactor"); - for (uint32_t i = 0; i < factor.ArrayLen(); i++) - { - auto val = factor.Get(i); - Mat.extension.DiffuseFactor[i] = val.IsNumber() ? (float)val.Get() : (float)val.Get(); - } - } +void Model::loadAnimations(const tinygltf::Model& gltf_model) +{ + for (const tinygltf::Animation& gltf_anim : gltf_model.animations) + { + Animation animation{}; + animation.Name = gltf_anim.name; + if (gltf_anim.name.empty()) + { + animation.Name = std::to_string(Animations.size()); + } - if (ext_it->second.Has("specularFactor")) - { - auto factor = ext_it->second.Get("specularFactor"); - for (uint32_t i = 0; i < factor.ArrayLen(); i++) - { - auto val = factor.Get(i); - Mat.extension.SpecularFactor[i] = val.IsNumber() ? (float)val.Get() : (float)val.Get(); - } - } - } - } + // Samplers + for (auto &samp : gltf_anim.samplers) + { + AnimationSampler AnimSampler{}; - Materials.push_back(Mat); + if (samp.interpolation == "LINEAR") + { + AnimSampler.Interpolation = AnimationSampler::INTERPOLATION_TYPE::LINEAR; + } + else if (samp.interpolation == "STEP") + { + AnimSampler.Interpolation = AnimationSampler::INTERPOLATION_TYPE::STEP; + } + else if (samp.interpolation == "CUBICSPLINE") + { + AnimSampler.Interpolation = AnimationSampler::INTERPOLATION_TYPE::CUBICSPLINE; } - // Push a default material at the end of the list for meshes with no material assigned - Materials.push_back(Material{}); - } + // Read sampler input time values + { + const tinygltf::Accessor& accessor = gltf_model.accessors[samp.input]; + const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView]; + const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer]; + VERIFY_EXPR(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT); - void loadAnimations(const tinygltf::Model& gltf_model) - { - for (const tinygltf::Animation& gltf_anim : gltf_model.animations) - { - Animation animation{}; - animation.Name = gltf_anim.name; - if (gltf_anim.name.empty()) + const void *dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset]; + const float *buf = static_cast(dataPtr); + for (size_t index = 0; index < accessor.count; index++) { - animation.Name = std::to_string(Animations.size()); + AnimSampler.Inputs.push_back(buf[index]); } - // Samplers - for (auto &samp : gltf_anim.samplers) + for (auto input : AnimSampler.Inputs) { - AnimationSampler AnimSampler{}; - - if (samp.interpolation == "LINEAR") - { - AnimSampler.Interpolation = AnimationSampler::INTERPOLATION_TYPE::LINEAR; - } - else if (samp.interpolation == "STEP") + if (input < animation.Start) { - AnimSampler.Interpolation = AnimationSampler::INTERPOLATION_TYPE::STEP; + animation.Start = input; } - else if (samp.interpolation == "CUBICSPLINE") + if (input > animation.End) { - AnimSampler.Interpolation = AnimationSampler::INTERPOLATION_TYPE::CUBICSPLINE; + animation.End = input; } + } + } - // Read sampler input time values - { - const tinygltf::Accessor& accessor = gltf_model.accessors[samp.input]; - const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView]; - const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer]; + // Read sampler output T/R/S values + { + const tinygltf::Accessor& accessor = gltf_model.accessors[samp.output]; + const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView]; + const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer]; - VERIFY_EXPR(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT); + VERIFY_EXPR(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT); - const void *dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset]; - const float *buf = static_cast(dataPtr); - for (size_t index = 0; index < accessor.count; index++) - { - AnimSampler.Inputs.push_back(buf[index]); - } + const void *dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset]; - for (auto input : AnimSampler.Inputs) + switch (accessor.type) + { + case TINYGLTF_TYPE_VEC3: + { + const float3* buf = static_cast(dataPtr); + for (size_t index = 0; index < accessor.count; index++) { - if (input < animation.Start) - { - animation.Start = input; - } - if (input > animation.End) - { - animation.End = input; - } + AnimSampler.OutputsVec4.push_back(float4(buf[index], 0.0f)); } + break; } - // Read sampler output T/R/S values + case TINYGLTF_TYPE_VEC4: { - const tinygltf::Accessor& accessor = gltf_model.accessors[samp.output]; - const tinygltf::BufferView& bufferView = gltf_model.bufferViews[accessor.bufferView]; - const tinygltf::Buffer& buffer = gltf_model.buffers[bufferView.buffer]; - - VERIFY_EXPR(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT); - - const void *dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset]; - - switch (accessor.type) + const float4* buf = static_cast(dataPtr); + for (size_t index = 0; index < accessor.count; index++) { - case TINYGLTF_TYPE_VEC3: - { - const float3* buf = static_cast(dataPtr); - for (size_t index = 0; index < accessor.count; index++) - { - AnimSampler.OutputsVec4.push_back(float4(buf[index], 0.0f)); - } - break; - } - - case TINYGLTF_TYPE_VEC4: - { - const float4* buf = static_cast(dataPtr); - for (size_t index = 0; index < accessor.count; index++) - { - AnimSampler.OutputsVec4.push_back(buf[index]); - } - break; - } - - default: - { - LOG_WARNING_MESSAGE("Unknown type", accessor.type); - break; - } + AnimSampler.OutputsVec4.push_back(buf[index]); } + break; } - animation.Samplers.push_back(AnimSampler); - } - - - for (auto& source : gltf_anim.channels) - { - AnimationChannel channel{}; - - if (source.target_path == "rotation") - { - channel.PathType = AnimationChannel::PATH_TYPE::ROTATION; - } - else if (source.target_path == "translation") - { - channel.PathType = AnimationChannel::PATH_TYPE::TRANSLATION; - } - else if (source.target_path == "scale") + default: { - channel.PathType = AnimationChannel::PATH_TYPE::SCALE; + LOG_WARNING_MESSAGE("Unknown type", accessor.type); + break; } - else if (source.target_path == "weights") - { - LOG_WARNING_MESSAGE("Weights not yet supported, skipping channel"); - continue; - } - - channel.SamplerIndex = source.sampler; - channel.node = NodeFromIndex(source.target_node); - if (!channel.node) - { - continue; - } - - animation.Channels.push_back(channel); } - - Animations.push_back(animation); } + + animation.Samplers.push_back(AnimSampler); } - void loadFromFile(IRenderDevice* pDevice, IDeviceContext* pContext, std::string filename, float scale = 1.0f) + for (auto& source : gltf_anim.channels) { - tinygltf::Model gltf_model; - tinygltf::TinyGLTF gltf_context; - std::string error; - std::string warning; - - bool binary = false; - size_t extpos = filename.rfind('.', filename.length()); - if (extpos != std::string::npos) + AnimationChannel channel{}; + + if (source.target_path == "rotation") { - binary = (filename.substr(extpos + 1, filename.length() - extpos) == "glb"); - } - - bool fileLoaded; - if (binary) - fileLoaded = gltf_context.LoadBinaryFromFile(&gltf_model, &error, &warning, filename.c_str()); - else - fileLoaded = gltf_context.LoadASCIIFromFile(&gltf_model, &error, &warning, filename.c_str()); - if (!fileLoaded) + channel.PathType = AnimationChannel::PATH_TYPE::ROTATION; + } + else if (source.target_path == "translation") { - LOG_ERROR_AND_THROW("Failed to load gltf file"); + channel.PathType = AnimationChannel::PATH_TYPE::TRANSLATION; } - - std::vector IndexBuffer; - std::vector VertexBuffer; - - LoadTextureSamplers(pDevice, gltf_model); - LoadTextures(pDevice, pContext, gltf_model); - LoadMaterials(gltf_model); - - // TODO: scene handling with no default scene - const tinygltf::Scene& scene = gltf_model.scenes[gltf_model.defaultScene > -1 ? gltf_model.defaultScene : 0]; - for (size_t i = 0; i < scene.nodes.size(); i++) + else if (source.target_path == "scale") { - const tinygltf::Node node = gltf_model.nodes[scene.nodes[i]]; - LoadNode(pDevice, nullptr, node, scene.nodes[i], gltf_model, IndexBuffer, VertexBuffer, scale); + channel.PathType = AnimationChannel::PATH_TYPE::SCALE; } - - if (gltf_model.animations.size() > 0) + else if (source.target_path == "weights") { - loadAnimations(gltf_model); + LOG_WARNING_MESSAGE("Weights not yet supported, skipping channel"); + continue; } - LoadSkins(gltf_model); - for (auto* node : LinearNodes) + channel.SamplerIndex = source.sampler; + channel.node = NodeFromIndex(source.target_node); + if (!channel.node) { - // Assign skins - if (node->SkinIndex > -1) - { - node->Skin = Skins[node->SkinIndex].get(); - } - - // Initial pose - if (node->Mesh) - { - node->Update(pContext); - } + continue; } + animation.Channels.push_back(channel); + } - Extensions = gltf_model.extensionsUsed; + Animations.push_back(animation); + } +} - size_t vertexBufferSize = VertexBuffer.size() * sizeof(Vertex); - size_t indexBufferSize = IndexBuffer.size() * sizeof(Uint32); - IndexCount = static_cast(IndexBuffer.size()); - VERIFY_EXPR(vertexBufferSize > 0); +void Model::loadFromFile(IRenderDevice* pDevice, IDeviceContext* pContext, std::string filename, float scale) +{ + tinygltf::Model gltf_model; + tinygltf::TinyGLTF gltf_context; + std::string error; + std::string warning; + + bool binary = false; + size_t extpos = filename.rfind('.', filename.length()); + if (extpos != std::string::npos) + { + binary = (filename.substr(extpos + 1, filename.length() - extpos) == "glb"); + } + + bool fileLoaded; + if (binary) + fileLoaded = gltf_context.LoadBinaryFromFile(&gltf_model, &error, &warning, filename.c_str()); + else + fileLoaded = gltf_context.LoadASCIIFromFile(&gltf_model, &error, &warning, filename.c_str()); + if (!fileLoaded) + { + LOG_ERROR_AND_THROW("Failed to load gltf file"); + } - { - BufferDesc VBDesc; - VBDesc.Name = "GLTF vertex buffer"; - VBDesc.uiSizeInBytes = static_cast(vertexBufferSize); - VBDesc.BindFlags = BIND_UNIFORM_BUFFER; - VBDesc.Usage = USAGE_STATIC; - - BufferData BuffData(VertexBuffer.data(), static_cast(vertexBufferSize)); - pDevice->CreateBuffer(VBDesc, &BuffData, &pVertexBuffer); - } + std::vector IndexBuffer; + std::vector VertexBuffer; - if (indexBufferSize > 0) - { - BufferDesc IBDesc; - IBDesc.Name = "GLTF inde buffer"; - IBDesc.uiSizeInBytes = static_cast(vertexBufferSize); - IBDesc.BindFlags = BIND_UNIFORM_BUFFER; - IBDesc.Usage = USAGE_STATIC; - - BufferData BuffData(IndexBuffer.data(), static_cast(indexBufferSize)); - pDevice->CreateBuffer(IBDesc, &BuffData, &pIndexBuffer); - } + LoadTextureSamplers(pDevice, gltf_model); + LoadTextures(pDevice, pContext, gltf_model); + LoadMaterials(gltf_model); - GetSceneDimensions(); - } + // TODO: scene handling with no default scene + const tinygltf::Scene& scene = gltf_model.scenes[gltf_model.defaultScene > -1 ? gltf_model.defaultScene : 0]; + for (size_t i = 0; i < scene.nodes.size(); i++) + { + const tinygltf::Node node = gltf_model.nodes[scene.nodes[i]]; + LoadNode(pDevice, nullptr, node, scene.nodes[i], gltf_model, IndexBuffer, VertexBuffer, scale); + } + if (gltf_model.animations.size() > 0) + { + loadAnimations(gltf_model); + } + LoadSkins(gltf_model); - void DrawNode(IDeviceContext* pCtx, const Node* node) + for (auto* node : LinearNodes) + { + // Assign skins + if (node->SkinIndex > -1) { - if (node->Mesh) - { - for (const auto& primitive : node->Mesh->Primitives) - { - DrawAttribs Attribs(primitive->IndexCount, VT_UINT32, DRAW_FLAG_VERIFY_ALL); - Attribs.FirstIndexLocation = primitive->FirstIndex; - pCtx->Draw(Attribs); - } - } - - for (const auto& child : node->Children) - { - DrawNode(pCtx, child.get()); - } + node->Skin = Skins[node->SkinIndex].get(); } - - void Draw(IDeviceContext* pCtx) + // Initial pose + if (node->Mesh) { - IBuffer* pVertBuffers[] = {pVertexBuffer}; - Uint32 Offsets [] = {0}; - pCtx->SetVertexBuffers(0, 1, pVertBuffers, Offsets, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, SET_VERTEX_BUFFERS_FLAG_RESET); - pCtx->SetIndexBuffer(pIndexBuffer, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); - for (const auto& node : Nodes) - { - DrawNode(pCtx, node.get()); - } + node->Update(pContext); } + } + Extensions = gltf_model.extensionsUsed; - BoundBox GetAABB(const BoundBox& bb, const float4x4& m) - { - float3 min = float3::MakeVector(m[3]); - float3 max = min; - float3 v0, v1; + size_t vertexBufferSize = VertexBuffer.size() * sizeof(Vertex); + size_t indexBufferSize = IndexBuffer.size() * sizeof(Uint32); + IndexCount = static_cast(IndexBuffer.size()); + + VERIFY_EXPR(vertexBufferSize > 0); + + { + BufferDesc VBDesc; + VBDesc.Name = "GLTF vertex buffer"; + VBDesc.uiSizeInBytes = static_cast(vertexBufferSize); + VBDesc.BindFlags = BIND_UNIFORM_BUFFER; + VBDesc.Usage = USAGE_STATIC; - float3 right = float3::MakeVector(m[0]); - v0 = right * bb.Min.x; - v1 = right * bb.Max.x; - min += std::min(v0, v1); - max += std::max(v0, v1); - - float3 up = float3::MakeVector(m[1]); - v0 = up * bb.Min.y; - v1 = up * bb.Max.y; - min += std::min(v0, v1); - max += std::max(v0, v1); - - float3 back = float3::MakeVector(m[2]); - v0 = back * bb.Min.z; - v1 = back * bb.Max.z; - min += std::min(v0, v1); - max += std::max(v0, v1); - - return BoundBox{min, max}; - } + BufferData BuffData(VertexBuffer.data(), static_cast(vertexBufferSize)); + pDevice->CreateBuffer(VBDesc, &BuffData, &pVertexBuffer); + } - void CalculateBoundingBox(Node* node, const Node* parent) - { - BoundBox parentBvh = parent ? parent->BVH : BoundBox{dimensions.min, dimensions.max}; + if (indexBufferSize > 0) + { + BufferDesc IBDesc; + IBDesc.Name = "GLTF inde buffer"; + IBDesc.uiSizeInBytes = static_cast(vertexBufferSize); + IBDesc.BindFlags = BIND_UNIFORM_BUFFER; + IBDesc.Usage = USAGE_STATIC; + + BufferData BuffData(IndexBuffer.data(), static_cast(indexBufferSize)); + pDevice->CreateBuffer(IBDesc, &BuffData, &pIndexBuffer); + } - if (node->Mesh) - { - if (node->Mesh->IsValidBB) - { - node->AABB = GetAABB(node->Mesh->BB, node->GetMatrix()); - if (node->Children.empty()) - { - node->BVH.Min = node->AABB.Min; - node->BVH.Max = node->AABB.Max; - node->IsValidBVH = true; - } - } - } + GetSceneDimensions(); +} - parentBvh.Min = std::min(parentBvh.Min, node->BVH.Min); - parentBvh.Max = std::min(parentBvh.Max, node->BVH.Max); - for (auto& child : node->Children) - { - CalculateBoundingBox(child.get(), node); - } +void Model::DrawNode(IDeviceContext* pCtx, const Node* node) +{ + if (node->Mesh) + { + for (const auto& primitive : node->Mesh->Primitives) + { + DrawAttribs Attribs(primitive->IndexCount, VT_UINT32, DRAW_FLAG_VERIFY_ALL); + Attribs.FirstIndexLocation = primitive->FirstIndex; + pCtx->Draw(Attribs); } + } + + for (const auto& child : node->Children) + { + DrawNode(pCtx, child.get()); + } +} + + +void Model::Draw(IDeviceContext* pCtx) +{ + IBuffer* pVertBuffers[] = {pVertexBuffer}; + Uint32 Offsets [] = {0}; + pCtx->SetVertexBuffers(0, 1, pVertBuffers, Offsets, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, SET_VERTEX_BUFFERS_FLAG_RESET); + pCtx->SetIndexBuffer(pIndexBuffer, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + for (const auto& node : Nodes) + { + DrawNode(pCtx, node.get()); + } +} - void GetSceneDimensions() + +namespace +{ + +BoundBox GetAABB(const BoundBox& bb, const float4x4& m) +{ + float3 min = float3::MakeVector(m[3]); + float3 max = min; + float3 v0, v1; + + float3 right = float3::MakeVector(m[0]); + v0 = right * bb.Min.x; + v1 = right * bb.Max.x; + min += std::min(v0, v1); + max += std::max(v0, v1); + + float3 up = float3::MakeVector(m[1]); + v0 = up * bb.Min.y; + v1 = up * bb.Max.y; + min += std::min(v0, v1); + max += std::max(v0, v1); + + float3 back = float3::MakeVector(m[2]); + v0 = back * bb.Min.z; + v1 = back * bb.Max.z; + min += std::min(v0, v1); + max += std::max(v0, v1); + + return BoundBox{min, max}; +} + +} + +void Model::CalculateBoundingBox(Node* node, const Node* parent) +{ + BoundBox parentBvh = parent ? parent->BVH : BoundBox{dimensions.min, dimensions.max}; + + if (node->Mesh) + { + if (node->Mesh->IsValidBB) { - // Calculate binary volume hierarchy for all nodes in the scene - for (auto* node : LinearNodes) + node->AABB = GetAABB(node->Mesh->BB, node->GetMatrix()); + if (node->Children.empty()) { - CalculateBoundingBox(node, nullptr); + node->BVH.Min = node->AABB.Min; + node->BVH.Max = node->AABB.Max; + node->IsValidBVH = true; } + } + } - dimensions.min = float3(+FLT_MAX, +FLT_MAX, +FLT_MAX); - dimensions.max = float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + parentBvh.Min = std::min(parentBvh.Min, node->BVH.Min); + parentBvh.Max = std::min(parentBvh.Max, node->BVH.Max); - for (const auto* node : LinearNodes) - { - if (node->IsValidBVH) - { - dimensions.min = std::min(dimensions.min, node->BVH.Min); - dimensions.max = std::max(dimensions.max, node->BVH.Max); - } - } + for (auto& child : node->Children) + { + CalculateBoundingBox(child.get(), node); + } +} + +void Model::GetSceneDimensions() +{ + // Calculate binary volume hierarchy for all nodes in the scene + for (auto* node : LinearNodes) + { + CalculateBoundingBox(node, nullptr); + } - // Calculate scene aabb - aabb = float4x4::Scale(dimensions.max[0] - dimensions.min[0], dimensions.max[1] - dimensions.min[1], dimensions.max[2] - dimensions.min[2]); - aabb[3][0] = dimensions.min[0]; - aabb[3][1] = dimensions.min[1]; - aabb[3][2] = dimensions.min[2]; + dimensions.min = float3(+FLT_MAX, +FLT_MAX, +FLT_MAX); + dimensions.max = float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + + for (const auto* node : LinearNodes) + { + if (node->IsValidBVH) + { + dimensions.min = std::min(dimensions.min, node->BVH.Min); + dimensions.max = std::max(dimensions.max, node->BVH.Max); } + } + + // Calculate scene aabb + aabb = float4x4::Scale(dimensions.max[0] - dimensions.min[0], dimensions.max[1] - dimensions.min[1], dimensions.max[2] - dimensions.min[2]); + aabb[3][0] = dimensions.min[0]; + aabb[3][1] = dimensions.min[1]; + aabb[3][2] = dimensions.min[2]; +} + +void Model::UpdateAnimation(IDeviceContext* pContext, Uint32 index, float time) +{ + if (index > static_cast(Animations.size()) - 1) + { + LOG_WARNING_MESSAGE("No animation with index ", index); + return; + } + Animation& animation = Animations[index]; - void UpdateAnimation(IDeviceContext* pContext, Uint32 index, float time) + bool updated = false; + for (auto& channel : animation.Channels) + { + AnimationSampler& sampler = animation.Samplers[channel.SamplerIndex]; + if (sampler.Inputs.size() > sampler.OutputsVec4.size()) { - if (index > static_cast(Animations.size()) - 1) - { - LOG_WARNING_MESSAGE("No animation with index ", index); - return; - } - Animation& animation = Animations[index]; + continue; + } - bool updated = false; - for (auto& channel : animation.Channels) + for (size_t i = 0; i < sampler.Inputs.size() - 1; i++) + { + if ((time >= sampler.Inputs[i]) && (time <= sampler.Inputs[i + 1])) { - AnimationSampler& sampler = animation.Samplers[channel.SamplerIndex]; - if (sampler.Inputs.size() > sampler.OutputsVec4.size()) - { - continue; - } - - for (size_t i = 0; i < sampler.Inputs.size() - 1; i++) + float u = std::max(0.0f, time - sampler.Inputs[i]) / (sampler.Inputs[i + 1] - sampler.Inputs[i]); + if (u <= 1.0f) { - if ((time >= sampler.Inputs[i]) && (time <= sampler.Inputs[i + 1])) + switch (channel.PathType) { - float u = std::max(0.0f, time - sampler.Inputs[i]) / (sampler.Inputs[i + 1] - sampler.Inputs[i]); - if (u <= 1.0f) + case AnimationChannel::PATH_TYPE::TRANSLATION: { - switch (channel.PathType) - { - case AnimationChannel::PATH_TYPE::TRANSLATION: - { - float4 trans = lerp(sampler.OutputsVec4[i], sampler.OutputsVec4[i + 1], u); - channel.node->Translation = float3(trans); - break; - } - - case AnimationChannel::PATH_TYPE::SCALE: - { - float4 scale = lerp(sampler.OutputsVec4[i], sampler.OutputsVec4[i + 1], u); - channel.node->Scale = float3(scale); - break; - } - - case AnimationChannel::PATH_TYPE::ROTATION: - { - Quaternion q1; - q1.q.x = sampler.OutputsVec4[i].x; - q1.q.y = sampler.OutputsVec4[i].y; - q1.q.z = sampler.OutputsVec4[i].z; - q1.q.w = sampler.OutputsVec4[i].w; - - Quaternion q2; - q2.q.x = sampler.OutputsVec4[i + 1].x; - q2.q.y = sampler.OutputsVec4[i + 1].y; - q2.q.z = sampler.OutputsVec4[i + 1].z; - q2.q.w = sampler.OutputsVec4[i + 1].w; - channel.node->Rotation = normalize(slerp(q1, q2, u)); - break; - } - } - updated = true; + float4 trans = lerp(sampler.OutputsVec4[i], sampler.OutputsVec4[i + 1], u); + channel.node->Translation = float3(trans); + break; + } + + case AnimationChannel::PATH_TYPE::SCALE: + { + float4 scale = lerp(sampler.OutputsVec4[i], sampler.OutputsVec4[i + 1], u); + channel.node->Scale = float3(scale); + break; + } + + case AnimationChannel::PATH_TYPE::ROTATION: + { + Quaternion q1; + q1.q.x = sampler.OutputsVec4[i].x; + q1.q.y = sampler.OutputsVec4[i].y; + q1.q.z = sampler.OutputsVec4[i].z; + q1.q.w = sampler.OutputsVec4[i].w; + + Quaternion q2; + q2.q.x = sampler.OutputsVec4[i + 1].x; + q2.q.y = sampler.OutputsVec4[i + 1].y; + q2.q.z = sampler.OutputsVec4[i + 1].z; + q2.q.w = sampler.OutputsVec4[i + 1].w; + channel.node->Rotation = normalize(slerp(q1, q2, u)); + break; } } + updated = true; } } + } + } - if (updated) - { - for (auto& node : Nodes) - { - node->Update(pContext); - } - } + if (updated) + { + for (auto& node : Nodes) + { + node->Update(pContext); } + } +} - Node* FindNode(Node* parent, Uint32 index) +Node* Model::FindNode(Node* parent, Uint32 index) +{ + Node* nodeFound = nullptr; + if (parent->Index == index) + { + return parent; + } + for (auto& child : parent->Children) + { + nodeFound = FindNode(child.get(), index); + if (nodeFound) { - Node* nodeFound = nullptr; - if (parent->Index == index) - { - return parent; - } - for (auto& child : parent->Children) - { - nodeFound = FindNode(child.get(), index); - if (nodeFound) - { - break; - } - } - return nodeFound; + break; } + } + return nodeFound; +} - Node* NodeFromIndex(uint32_t index) +Node* Model::NodeFromIndex(uint32_t index) +{ + Node* nodeFound = nullptr; + for (auto &node : Nodes) + { + nodeFound = FindNode(node.get(), index); + if (nodeFound) { - Node* nodeFound = nullptr; - for (auto &node : Nodes) - { - nodeFound = FindNode(node.get(), index); - if (nodeFound) - { - break; - } - } - return nodeFound; + break; } - }; + } + return nodeFound; +} + } -- cgit v1.2.3