C API for GLTFLoader
s-ol
2 years ago
3 | 3 | |
4 | 4 | set(INCLUDE |
5 | 5 | #include/GLTFLoader.hpp |
6 | #include/GLTFResourceManager.hpp | |
6 | 7 | ) |
7 | 8 | |
8 | 9 | set(INTERFACE |
9 | interface/GLTFLoader.hpp | |
10 | interface/GLTFLoader.h | |
10 | 11 | interface/DXSDKMeshLoader.hpp |
11 | interface/GLTFResourceManager.hpp | |
12 | 12 | ) |
13 | 13 | |
14 | 14 | set(SOURCE |
0 | /* | |
1 | * Copyright 2019-2021 Diligent Graphics LLC | |
2 | * Copyright 2015-2019 Egor Yusov | |
3 | * | |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | * | |
16 | * In no event and under no legal theory, whether in tort (including negligence), | |
17 | * contract, or otherwise, unless required by applicable law (such as deliberate | |
18 | * and grossly negligent acts) or agreed to in writing, shall any Contributor be | |
19 | * liable for any damages, including any direct, indirect, special, incidental, | |
20 | * or consequential damages of any character arising as a result of this License or | |
21 | * out of the use or inability to use the software (including but not limited to damages | |
22 | * for loss of goodwill, work stoppage, computer failure or malfunction, or any and | |
23 | * all other commercial damages or losses), even if such Contributor has been advised | |
24 | * of the possibility of such damages. | |
25 | */ | |
26 | ||
27 | #pragma once | |
28 | ||
29 | #include <vector> | |
30 | #include <array> | |
31 | #include <memory> | |
32 | #include <cfloat> | |
33 | #include <unordered_map> | |
34 | #include <mutex> | |
35 | #include <atomic> | |
36 | ||
37 | #include "../../../DiligentCore/Graphics/GraphicsEngine/interface/RenderDevice.h" | |
38 | #include "../../../DiligentCore/Graphics/GraphicsEngine/interface/DeviceContext.h" | |
39 | #include "../../../DiligentCore/Common/interface/RefCntAutoPtr.hpp" | |
40 | #include "../../../DiligentCore/Common/interface/AdvancedMath.hpp" | |
41 | #include "GLTFLoader.h" | |
42 | #include "GLTFResourceManager.hpp" | |
43 | ||
44 | namespace tinygltf | |
45 | { | |
46 | ||
47 | class Node; | |
48 | class Model; | |
49 | ||
50 | } // namespace tinygltf | |
51 | ||
52 | namespace Diligent | |
53 | { | |
54 | ||
55 | namespace GLTF | |
56 | { | |
57 | ||
58 | struct Material | |
59 | { | |
60 | Material() noexcept | |
61 | { | |
62 | TextureIds.fill(-1); | |
63 | } | |
64 | ||
65 | enum PBR_WORKFLOW | |
66 | { | |
67 | PBR_WORKFLOW_METALL_ROUGH = 0, | |
68 | PBR_WORKFLOW_SPEC_GLOSS | |
69 | }; | |
70 | ||
71 | // Material attributes packed in a shader-friendly format | |
72 | struct ShaderAttribs | |
73 | { | |
74 | float4 BaseColorFactor = float4{1, 1, 1, 1}; | |
75 | float4 EmissiveFactor = float4{1, 1, 1, 1}; | |
76 | float4 SpecularFactor = float4{1, 1, 1, 1}; | |
77 | ||
78 | int Workflow = PBR_WORKFLOW_METALL_ROUGH; | |
79 | float BaseColorUVSelector = -1; | |
80 | float PhysicalDescriptorUVSelector = -1; | |
81 | float NormalUVSelector = -1; | |
82 | ||
83 | float OcclusionUVSelector = -1; | |
84 | float EmissiveUVSelector = -1; | |
85 | float BaseColorSlice = 0; | |
86 | float PhysicalDescriptorSlice = 0; | |
87 | ||
88 | float NormalSlice = 0; | |
89 | float OcclusionSlice = 0; | |
90 | float EmissiveSlice = 0; | |
91 | float MetallicFactor = 1; | |
92 | ||
93 | float RoughnessFactor = 1; | |
94 | int AlphaMode = GLTF_MAT_ALPHA_MODE_OPAQUE; | |
95 | float AlphaCutoff = 0.5f; | |
96 | float Dummy0; | |
97 | ||
98 | // When texture atlas is used, UV scale and bias applied to | |
99 | // each texture coordinate set | |
100 | float4 BaseColorUVScaleBias = float4{1, 1, 0, 0}; | |
101 | float4 PhysicalDescriptorUVScaleBias = float4{1, 1, 0, 0}; | |
102 | float4 NormalUVScaleBias = float4{1, 1, 0, 0}; | |
103 | float4 OcclusionUVScaleBias = float4{1, 1, 0, 0}; | |
104 | float4 EmissiveUVScaleBias = float4{1, 1, 0, 0}; | |
105 | }; | |
106 | static_assert(sizeof(ShaderAttribs) % 16 == 0, "ShaderAttribs struct must be 16-byte aligned"); | |
107 | ShaderAttribs Attribs; | |
108 | ||
109 | bool DoubleSided = false; | |
110 | ||
111 | enum TEXTURE_ID | |
112 | { | |
113 | // Base color for metallic-roughness workflow or | |
114 | // diffuse color for specular-glossinees workflow | |
115 | TEXTURE_ID_BASE_COLOR = 0, | |
116 | ||
117 | // Metallic-roughness or specular-glossinees map | |
118 | TEXTURE_ID_PHYSICAL_DESC, | |
119 | ||
120 | TEXTURE_ID_NORMAL_MAP, | |
121 | TEXTURE_ID_OCCLUSION, | |
122 | TEXTURE_ID_EMISSIVE, | |
123 | TEXTURE_ID_NUM_TEXTURES | |
124 | }; | |
125 | // Texture indices in Model.Textures array | |
126 | std::array<int, TEXTURE_ID_NUM_TEXTURES> TextureIds = {}; | |
127 | }; | |
128 | ||
129 | ||
130 | struct Primitive | |
131 | { | |
132 | const Uint32 FirstIndex; | |
133 | const Uint32 IndexCount; | |
134 | const Uint32 VertexCount; | |
135 | const Uint32 MaterialId; | |
136 | ||
137 | const BoundBox BB; | |
138 | ||
139 | Primitive(Uint32 _FirstIndex, | |
140 | Uint32 _IndexCount, | |
141 | Uint32 _VertexCount, | |
142 | Uint32 _MaterialId, | |
143 | const float3& BBMin, | |
144 | const float3& BBMax) : | |
145 | FirstIndex{_FirstIndex}, | |
146 | IndexCount{_IndexCount}, | |
147 | VertexCount{_VertexCount}, | |
148 | MaterialId{_MaterialId}, | |
149 | BB{BBMin, BBMax} | |
150 | { | |
151 | } | |
152 | ||
153 | Primitive(Primitive&&) = default; | |
154 | ||
155 | bool HasIndices() const | |
156 | { | |
157 | return IndexCount > 0; | |
158 | } | |
159 | }; | |
160 | ||
161 | ||
162 | ||
163 | struct Mesh | |
164 | { | |
165 | std::vector<Primitive> Primitives; | |
166 | ||
167 | BoundBox BB; | |
168 | ||
169 | // There may be no primitives in the mesh, in which | |
170 | // case the bounding box will be invalid. | |
171 | bool IsValidBB() const | |
172 | { | |
173 | return !Primitives.empty(); | |
174 | } | |
175 | ||
176 | struct TransformData | |
177 | { | |
178 | float4x4 matrix; | |
179 | std::vector<float4x4> jointMatrices; | |
180 | }; | |
181 | ||
182 | TransformData Transforms; | |
183 | ||
184 | Mesh(const float4x4& matrix); | |
185 | }; | |
186 | ||
187 | ||
188 | struct Node; | |
189 | struct Skin | |
190 | { | |
191 | std::string Name; | |
192 | Node* pSkeletonRoot = nullptr; | |
193 | std::vector<float4x4> InverseBindMatrices; | |
194 | std::vector<Node*> Joints; | |
195 | }; | |
196 | ||
197 | struct Camera | |
198 | { | |
199 | enum class Projection | |
200 | { | |
201 | Unknown, | |
202 | Perspective, | |
203 | Orthographic | |
204 | } Type = Projection::Unknown; | |
205 | ||
206 | std::string Name; | |
207 | ||
208 | struct PerspectiveAttribs | |
209 | { | |
210 | float AspectRatio; | |
211 | float YFov; | |
212 | float ZNear; | |
213 | float ZFar; | |
214 | }; | |
215 | struct OrthographicAttribs | |
216 | { | |
217 | float XMag; | |
218 | float YMag; | |
219 | float ZNear; | |
220 | float ZFar; | |
221 | }; | |
222 | union | |
223 | { | |
224 | PerspectiveAttribs Perspective = {}; | |
225 | OrthographicAttribs Orthographic; | |
226 | }; | |
227 | ||
228 | float4x4 matrix; | |
229 | }; | |
230 | ||
231 | struct Node | |
232 | { | |
233 | std::string Name; | |
234 | Node* Parent = nullptr; | |
235 | Uint32 Index; | |
236 | ||
237 | std::vector<std::unique_ptr<Node>> Children; | |
238 | ||
239 | float4x4 Matrix; | |
240 | std::unique_ptr<Mesh> pMesh; | |
241 | std::unique_ptr<Camera> pCamera; | |
242 | Skin* pSkin = nullptr; | |
243 | Int32 SkinIndex = -1; | |
244 | float3 Translation; | |
245 | float3 Scale = float3{1, 1, 1}; | |
246 | Quaternion Rotation; | |
247 | BoundBox BVH; | |
248 | BoundBox AABB; | |
249 | ||
250 | bool IsValidBVH = false; | |
251 | ||
252 | float4x4 LocalMatrix() const; | |
253 | float4x4 GetMatrix() const; | |
254 | void UpdateTransforms(); | |
255 | }; | |
256 | ||
257 | ||
258 | struct AnimationChannel | |
259 | { | |
260 | enum PATH_TYPE | |
261 | { | |
262 | TRANSLATION, | |
263 | ROTATION, | |
264 | SCALE | |
265 | }; | |
266 | PATH_TYPE PathType; | |
267 | Node* pNode = nullptr; | |
268 | Uint32 SamplerIndex = static_cast<Uint32>(-1); | |
269 | }; | |
270 | ||
271 | ||
272 | struct AnimationSampler | |
273 | { | |
274 | enum INTERPOLATION_TYPE | |
275 | { | |
276 | LINEAR, | |
277 | STEP, | |
278 | CUBICSPLINE | |
279 | }; | |
280 | INTERPOLATION_TYPE Interpolation; | |
281 | std::vector<float> Inputs; | |
282 | std::vector<float4> OutputsVec4; | |
283 | }; | |
284 | ||
285 | struct Animation | |
286 | { | |
287 | std::string Name; | |
288 | std::vector<AnimationSampler> Samplers; | |
289 | std::vector<AnimationChannel> Channels; | |
290 | ||
291 | float Start = std::numeric_limits<float>::max(); | |
292 | float End = std::numeric_limits<float>::min(); | |
293 | }; | |
294 | ||
295 | struct GLTF_TextureCacheType | |
296 | { | |
297 | std::mutex TexturesMtx; | |
298 | ||
299 | std::unordered_map<std::string, RefCntWeakPtr<ITexture>> Textures; | |
300 | }; | |
301 | ||
302 | class Model : public IGLTFModel | |
303 | { | |
304 | public: | |
305 | struct VertexBasicAttribs | |
306 | { | |
307 | float3 pos; | |
308 | float3 normal; | |
309 | float2 uv0; | |
310 | float2 uv1; | |
311 | }; | |
312 | ||
313 | struct VertexSkinAttribs | |
314 | { | |
315 | float4 joint0; | |
316 | float4 weight0; | |
317 | }; | |
318 | ||
319 | Uint32 IndexCount = 0; | |
320 | ||
321 | /// Transformation matrix that transforms unit cube [0,1]x[0,1]x[0,1] into | |
322 | /// axis-aligned bounding box in model space. | |
323 | float4x4 AABBTransform; | |
324 | ||
325 | std::vector<std::unique_ptr<Node>> Nodes; | |
326 | std::vector<Node*> LinearNodes; | |
327 | ||
328 | std::vector<std::unique_ptr<Skin>> Skins; | |
329 | ||
330 | std::vector<RefCntAutoPtr<ISampler>> TextureSamplers; | |
331 | std::vector<Material> Materials; | |
332 | std::vector<Animation> Animations; | |
333 | std::vector<std::string> Extensions; | |
334 | ||
335 | struct Dimensions | |
336 | { | |
337 | float3 min = float3{+FLT_MAX, +FLT_MAX, +FLT_MAX}; | |
338 | float3 max = float3{-FLT_MAX, -FLT_MAX, -FLT_MAX}; | |
339 | } dimensions; | |
340 | ||
341 | Model(IRenderDevice* pDevice, | |
342 | IDeviceContext* pContext, | |
343 | const IGLTFModelCreateInfo& CI); | |
344 | ||
345 | ~Model(); | |
346 | ||
347 | virtual void UpdateAnimation(Uint32 index, float time) override final; | |
348 | ||
349 | virtual void PrepareGPUResources(IRenderDevice* pDevice, IDeviceContext* pCtx) override final; | |
350 | ||
351 | virtual bool IsGPUDataInitialized() const override final | |
352 | { | |
353 | return GPUDataInitialized.load(); | |
354 | } | |
355 | ||
356 | virtual void Transform(const float* Matrix) override final; | |
357 | ||
358 | virtual IBuffer* GetBuffer(GLTF_BUFFER_ID BuffId) override final | |
359 | { | |
360 | return Buffers[BuffId].pBuffer; | |
361 | } | |
362 | ||
363 | virtual ITexture* GetTexture(Uint32 Index) override final | |
364 | { | |
365 | return Textures[Index].pTexture; | |
366 | } | |
367 | ||
368 | virtual Uint32 GetFirstIndexLocation() const override final | |
369 | { | |
370 | auto& IndBuff = Buffers[GLTF_BUFFER_ID_INDEX]; | |
371 | VERIFY(!IndBuff.pSuballocation || IndBuff.pSuballocation->GetOffset() % sizeof(Uint32) == 0, | |
372 | "Allocation offset is not multiple of sizeof(Uint32)"); | |
373 | return IndBuff.pSuballocation ? | |
374 | static_cast<Uint32>(IndBuff.pSuballocation->GetOffset() / sizeof(Uint32)) : | |
375 | 0; | |
376 | } | |
377 | ||
378 | virtual Uint32 GetBaseVertex() const override final | |
379 | { | |
380 | auto& VertBuff = Buffers[GLTF_BUFFER_ID_VERTEX_BASIC_ATTRIBS]; | |
381 | VERIFY(!VertBuff.pSuballocation || VertBuff.pSuballocation->GetOffset() % sizeof(VertexBasicAttribs) == 0, | |
382 | "Allocation offset is not multiple of sizeof(VertexAttribs0)"); | |
383 | return VertBuff.pSuballocation ? | |
384 | static_cast<Uint32>(VertBuff.pSuballocation->GetOffset() / sizeof(VertexBasicAttribs)) : | |
385 | 0; | |
386 | } | |
387 | ||
388 | private: | |
389 | void LoadFromFile(IRenderDevice* pDevice, | |
390 | IDeviceContext* pContext, | |
391 | const IGLTFModelCreateInfo& CI); | |
392 | ||
393 | void LoadNode(Node* parent, | |
394 | const tinygltf::Node& gltf_node, | |
395 | uint32_t nodeIndex, | |
396 | const tinygltf::Model& gltf_model, | |
397 | std::vector<Uint32>& IndexData, | |
398 | std::vector<VertexBasicAttribs>& VertexBasicData, | |
399 | std::vector<VertexSkinAttribs>* pVertexSkinData); | |
400 | ||
401 | void LoadSkins(const tinygltf::Model& gltf_model); | |
402 | ||
403 | void LoadTextures(IRenderDevice* pDevice, | |
404 | const tinygltf::Model& gltf_model, | |
405 | const std::string& BaseDir, | |
406 | GLTF_TextureCacheType* pTextureCache, | |
407 | ResourceManager* pResourceMgr); | |
408 | ||
409 | void LoadTextureSamplers(IRenderDevice* pDevice, const tinygltf::Model& gltf_model); | |
410 | void LoadMaterials(const tinygltf::Model& gltf_model); | |
411 | void LoadAnimations(const tinygltf::Model& gltf_model); | |
412 | void CalculateBoundingBox(Node* node, const Node* parent); | |
413 | void CalculateSceneDimensions(); | |
414 | Node* FindNode(Node* parent, Uint32 index); | |
415 | Node* NodeFromIndex(uint32_t index); | |
416 | ||
417 | std::atomic_bool GPUDataInitialized{false}; | |
418 | ||
419 | struct BufferInfo | |
420 | { | |
421 | RefCntAutoPtr<IBuffer> pBuffer; | |
422 | RefCntAutoPtr<IBufferSuballocation> pSuballocation; | |
423 | }; | |
424 | std::array<BufferInfo, GLTF_BUFFER_ID_NUM_BUFFERS> Buffers; | |
425 | ||
426 | struct TextureInfo | |
427 | { | |
428 | RefCntAutoPtr<ITexture> pTexture; | |
429 | RefCntAutoPtr<ITextureAtlasSuballocation> pAtlasSuballocation; | |
430 | ||
431 | bool IsValid() const | |
432 | { | |
433 | return pTexture || pAtlasSuballocation; | |
434 | } | |
435 | }; | |
436 | std::vector<TextureInfo> Textures; | |
437 | }; | |
438 | ||
439 | } // namespace GLTF | |
440 | ||
441 | } // namespace Diligent |
0 | /* | |
1 | * Copyright 2019-2021 Diligent Graphics LLC | |
2 | * Copyright 2015-2019 Egor Yusov | |
3 | * | |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | * | |
16 | * In no event and under no legal theory, whether in tort (including negligence), | |
17 | * contract, or otherwise, unless required by applicable law (such as deliberate | |
18 | * and grossly negligent acts) or agreed to in writing, shall any Contributor be | |
19 | * liable for any damages, including any direct, indirect, special, incidental, | |
20 | * or consequential damages of any character arising as a result of this License or | |
21 | * out of the use or inability to use the software (including but not limited to damages | |
22 | * for loss of goodwill, work stoppage, computer failure or malfunction, or any and | |
23 | * all other commercial damages or losses), even if such Contributor has been advised | |
24 | * of the possibility of such damages. | |
25 | */ | |
26 | ||
27 | #pragma once | |
28 | ||
29 | #include <mutex> | |
30 | #include <vector> | |
31 | #include <unordered_map> | |
32 | #include <atomic> | |
33 | ||
34 | #include "../../../DiligentCore/Graphics/GraphicsEngine/interface/RenderDevice.h" | |
35 | #include "../../../DiligentCore/Graphics/GraphicsEngine/interface/DeviceContext.h" | |
36 | #include "../../../DiligentCore/Common/interface/RefCntAutoPtr.hpp" | |
37 | #include "../../../DiligentCore/Common/interface/ObjectBase.hpp" | |
38 | #include "../../../DiligentCore/Graphics/GraphicsTools/interface/BufferSuballocator.h" | |
39 | #include "../../../DiligentCore/Graphics/GraphicsTools/interface/DynamicTextureAtlas.h" | |
40 | ||
41 | ||
42 | namespace Diligent | |
43 | { | |
44 | ||
45 | namespace GLTF | |
46 | { | |
47 | ||
48 | /// GLTF resource manager | |
49 | class ResourceManager final : public ObjectBase<IObject> | |
50 | { | |
51 | public: | |
52 | using TBase = ObjectBase<IObject>; | |
53 | ||
54 | struct CreateInfo | |
55 | { | |
56 | const BufferSuballocatorCreateInfo* BuffSuballocators = nullptr; // [NumBuffSuballocators] | |
57 | const DynamicTextureAtlasCreateInfo* TexAtlases = nullptr; // [NumTexAtlases] | |
58 | ||
59 | Uint32 NumBuffSuballocators = 0; | |
60 | Uint32 NumTexAtlases = 0; | |
61 | ||
62 | DynamicTextureAtlasCreateInfo DefaultAtlasDesc; | |
63 | }; | |
64 | ||
65 | static RefCntAutoPtr<ResourceManager> Create(IRenderDevice* pDevice, | |
66 | const CreateInfo& CI); | |
67 | ||
68 | RefCntAutoPtr<IBufferSuballocation> AllocateBufferSpace(Uint32 BufferIndex, | |
69 | Uint32 Size, | |
70 | Uint32 Alignment) | |
71 | { | |
72 | RefCntAutoPtr<IBufferSuballocation> pSuballoc; | |
73 | m_BufferSuballocators[BufferIndex]->Allocate(Size, Alignment, &pSuballoc); | |
74 | return pSuballoc; | |
75 | } | |
76 | ||
77 | RefCntAutoPtr<ITextureAtlasSuballocation> AllocateTextureSpace(TEXTURE_FORMAT Fmt, | |
78 | Uint32 Width, | |
79 | Uint32 Height, | |
80 | const char* CacheId = nullptr, | |
81 | IObject* pUserData = nullptr); | |
82 | ||
83 | RefCntAutoPtr<ITextureAtlasSuballocation> FindAllocation(const char* CacheId); | |
84 | ||
85 | Uint32 GetTextureVersion() | |
86 | { | |
87 | Uint32 Version = 0; | |
88 | ||
89 | std::lock_guard<std::mutex> Lock{m_AtlasesMtx}; | |
90 | for (auto atlas_it : m_Atlases) | |
91 | Version += atlas_it.second->GetVersion(); | |
92 | ||
93 | return Version; | |
94 | } | |
95 | ||
96 | Uint32 GetBufferVersion(Uint32 Index) const | |
97 | { | |
98 | return m_BufferSuballocators[Index]->GetVersion(); | |
99 | } | |
100 | ||
101 | IBuffer* GetBuffer(Uint32 Index, IRenderDevice* pDevice, IDeviceContext* pContext) | |
102 | { | |
103 | return m_BufferSuballocators[Index]->GetBuffer(pDevice, pContext); | |
104 | } | |
105 | ||
106 | ITexture* GetTexture(TEXTURE_FORMAT Fmt, IRenderDevice* pDevice, IDeviceContext* pContext) | |
107 | { | |
108 | decltype(m_Atlases)::iterator cache_it; // NB: can't initialize it without locking the mutex | |
109 | { | |
110 | std::lock_guard<std::mutex> Lock{m_AtlasesMtx}; | |
111 | cache_it = m_Atlases.find(Fmt); | |
112 | if (cache_it == m_Atlases.end()) | |
113 | return nullptr; | |
114 | } | |
115 | ||
116 | return cache_it->second->GetTexture(pDevice, pContext); | |
117 | } | |
118 | ||
119 | // NB: can't return reference here! | |
120 | TextureDesc GetAtlasDesc(TEXTURE_FORMAT Fmt) | |
121 | { | |
122 | { | |
123 | std::lock_guard<std::mutex> Lock{m_AtlasesMtx}; | |
124 | ||
125 | auto cache_it = m_Atlases.find(Fmt); | |
126 | if (cache_it != m_Atlases.end()) | |
127 | return cache_it->second->GetAtlasDesc(); | |
128 | } | |
129 | ||
130 | // Atlas is not present in the map - use default description | |
131 | TextureDesc Desc = m_DefaultAtlasDesc.Desc; | |
132 | Desc.Format = Fmt; | |
133 | return Desc; | |
134 | } | |
135 | ||
136 | private: | |
137 | template <typename AllocatorType, typename ObjectType> | |
138 | friend class Diligent::MakeNewRCObj; | |
139 | ||
140 | ResourceManager(IReferenceCounters* pRefCounters, | |
141 | IRenderDevice* pDevice, | |
142 | const CreateInfo& CI); | |
143 | ||
144 | std::vector<RefCntAutoPtr<IBufferSuballocator>> m_BufferSuballocators; | |
145 | ||
146 | DynamicTextureAtlasCreateInfo m_DefaultAtlasDesc; | |
147 | const std::string m_DefaultAtlasName; | |
148 | ||
149 | using AtlasesHashMapType = std::unordered_map<TEXTURE_FORMAT, RefCntAutoPtr<IDynamicTextureAtlas>, std::hash<Uint32>>; | |
150 | std::mutex m_AtlasesMtx; | |
151 | AtlasesHashMapType m_Atlases; | |
152 | ||
153 | using TexAllocationsHashMapType = std::unordered_map<std::string, RefCntWeakPtr<ITextureAtlasSuballocation>>; | |
154 | std::mutex m_TexAllocationsMtx; | |
155 | TexAllocationsHashMapType m_TexAllocations; | |
156 | }; | |
157 | ||
158 | } // namespace GLTF | |
159 | ||
160 | } // namespace Diligent |
0 | /* | |
1 | * Copyright 2019-2021 Diligent Graphics LLC | |
2 | * Copyright 2015-2019 Egor Yusov | |
3 | * | |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | * | |
16 | * In no event and under no legal theory, whether in tort (including negligence), | |
17 | * contract, or otherwise, unless required by applicable law (such as deliberate | |
18 | * and grossly negligent acts) or agreed to in writing, shall any Contributor be | |
19 | * liable for any damages, including any direct, indirect, special, incidental, | |
20 | * or consequential damages of any character arising as a result of this License or | |
21 | * out of the use or inability to use the software (including but not limited to damages | |
22 | * for loss of goodwill, work stoppage, computer failure or malfunction, or any and | |
23 | * all other commercial damages or losses), even if such Contributor has been advised | |
24 | * of the possibility of such damages. | |
25 | */ | |
26 | ||
27 | #pragma once | |
28 | ||
29 | #include "../../../DiligentCore/Graphics/GraphicsEngine/interface/RenderDevice.h" | |
30 | #include "../../../DiligentCore/Graphics/GraphicsEngine/interface/DeviceContext.h" | |
31 | ||
32 | #if PLATFORM_ANDROID || PLATFORM_LINUX || PLATFORM_MACOS || PLATFORM_IOS || (PLATFORM_WIN32 && !defined(_MSC_VER)) | |
33 | // https://gcc.gnu.org/wiki/Visibility | |
34 | # define API_QUALIFIER __attribute__((visibility("default"))) | |
35 | #elif PLATFORM_WIN32 | |
36 | # define API_QUALIFIER | |
37 | #else | |
38 | # error Unsupported platform | |
39 | #endif | |
40 | ||
41 | ||
42 | DILIGENT_BEGIN_NAMESPACE(Diligent) | |
43 | ||
44 | DILIGENT_BEGIN_NAMESPACE(GLTF) | |
45 | ||
46 | #if DILIGENT_CPP_INTERFACE | |
47 | class ResourceManager; | |
48 | #else | |
49 | struct ResourceManager; | |
50 | typedef struct ResourceManager ResourceManager; | |
51 | #endif | |
52 | ||
53 | struct GLTF_ResourceCacheUseInfo | |
54 | { | |
55 | ResourceManager* pResourceMgr DEFAULT_INITIALIZER(nullptr); | |
56 | ||
57 | Uint8 IndexBufferIdx DEFAULT_INITIALIZER(0); | |
58 | Uint8 VertexBuffer0Idx DEFAULT_INITIALIZER(0); | |
59 | Uint8 VertexBuffer1Idx DEFAULT_INITIALIZER(0); | |
60 | ||
61 | /// Base color texture format. | |
62 | TEXTURE_FORMAT BaseColorFormat DEFAULT_INITIALIZER(TEX_FORMAT_RGBA8_UNORM); | |
63 | ||
64 | /// Base color texture format for alpha-cut and alpha-blend materials. | |
65 | TEXTURE_FORMAT BaseColorAlphaFormat DEFAULT_INITIALIZER(TEX_FORMAT_RGBA8_UNORM); | |
66 | ||
67 | /// Physical descriptor texture format. | |
68 | TEXTURE_FORMAT PhysicalDescFormat DEFAULT_INITIALIZER(TEX_FORMAT_RGBA8_UNORM); | |
69 | ||
70 | /// Normal map format. | |
71 | TEXTURE_FORMAT NormalFormat DEFAULT_INITIALIZER(TEX_FORMAT_RGBA8_UNORM); | |
72 | ||
73 | /// Occlusion texture format. | |
74 | TEXTURE_FORMAT OcclusionFormat DEFAULT_INITIALIZER(TEX_FORMAT_RGBA8_UNORM); | |
75 | ||
76 | /// Emissive texture format. | |
77 | TEXTURE_FORMAT EmissiveFormat DEFAULT_INITIALIZER(TEX_FORMAT_RGBA8_UNORM); | |
78 | }; | |
79 | typedef struct GLTF_ResourceCacheUseInfo GLTF_ResourceCacheUseInfo; | |
80 | ||
81 | enum GLTF_MAT_ALPHA_MODE | |
82 | { | |
83 | GLTF_MAT_ALPHA_MODE_OPAQUE = 0, | |
84 | GLTF_MAT_ALPHA_MODE_MASK, | |
85 | GLTF_MAT_ALPHA_MODE_BLEND, | |
86 | GLTF_MAT_ALPHA_MODE_NUM_MODES | |
87 | }; | |
88 | typedef enum GLTF_MAT_ALPHA_MODE GLTF_MAT_ALPHA_MODE; | |
89 | ||
90 | enum GLTF_BUFFER_ID | |
91 | { | |
92 | GLTF_BUFFER_ID_VERTEX_BASIC_ATTRIBS = 0, | |
93 | GLTF_BUFFER_ID_VERTEX_SKIN_ATTRIBS, | |
94 | GLTF_BUFFER_ID_INDEX, | |
95 | GLTF_BUFFER_ID_NUM_BUFFERS | |
96 | }; | |
97 | typedef enum GLTF_BUFFER_ID GLTF_BUFFER_ID; | |
98 | ||
99 | struct GLTF_TextureCacheType; | |
100 | typedef struct GLTF_TextureCacheType GLTF_TextureCacheType; | |
101 | ||
102 | /// Model create information | |
103 | struct IGLTFModelCreateInfo | |
104 | { | |
105 | /// File name | |
106 | const char* FileName DEFAULT_INITIALIZER(nullptr); | |
107 | ||
108 | /// Optional texture cache to use when loading the model. | |
109 | /// The loader will try to find all the textures in the cache | |
110 | /// and add all new textures to the cache. | |
111 | GLTF_TextureCacheType* pTextureCache DEFAULT_INITIALIZER(nullptr); | |
112 | ||
113 | /// Optional resource cache usage info. | |
114 | GLTF_ResourceCacheUseInfo* pCacheInfo DEFAULT_INITIALIZER(nullptr); | |
115 | ||
116 | /// Whether to load animation and initialize skin attributes | |
117 | /// buffer. | |
118 | bool LoadAnimationAndSkin DEFAULT_INITIALIZER(true); | |
119 | }; | |
120 | typedef struct IGLTFModelCreateInfo IGLTFModelCreateInfo; | |
121 | ||
122 | #define DILIGENT_INTERFACE_NAME IGLTFModel | |
123 | #include "../../../Primitives/interface/DefineInterfaceHelperMacros.h" | |
124 | ||
125 | #define IGLTFModelInclusiveMethods \ | |
126 | IGLTFModelMethods GLTF_Model | |
127 | ||
128 | // clang-format off | |
129 | ||
130 | DILIGENT_BEGIN_INTERFACE1(IGLTFModel) | |
131 | { | |
132 | VIRTUAL void METHOD(UpdateAnimation)(THIS_ Uint32 index, float time) PURE; | |
133 | ||
134 | VIRTUAL void METHOD(PrepareGPUResources)(THIS_ IRenderDevice* pDevice, IDeviceContext* pCtx) PURE; | |
135 | ||
136 | VIRTUAL bool METHOD(IsGPUDataInitialized)(THIS) CONST PURE; | |
137 | ||
138 | VIRTUAL void METHOD(Transform)(THIS_ const float* Matrix) PURE; | |
139 | ||
140 | VIRTUAL IBuffer* METHOD(GetBuffer)(THIS_ GLTF_BUFFER_ID BuffId) PURE; | |
141 | ||
142 | VIRTUAL ITexture* METHOD(GetTexture)(THIS_ Uint32 Index) PURE; | |
143 | ||
144 | VIRTUAL Uint32 METHOD(GetFirstIndexLocation)(THIS) CONST PURE; | |
145 | ||
146 | VIRTUAL Uint32 METHOD(GetBaseVertex)(THIS) CONST PURE; | |
147 | }; | |
148 | DILIGENT_END_INTERFACE | |
149 | ||
150 | #include "../../../Primitives/interface/UndefInterfaceHelperMacros.h" | |
151 | ||
152 | #if DILIGENT_C_INTERFACE | |
153 | ||
154 | # define IGLTFModel_UpdateAnimation(This, ...) CALL_IFACE_METHOD(GLTF_Model, UpdateAnimation, This, __VA_ARGS__) | |
155 | # define IGLTFModel_PrepareGPUResources(This, ...) CALL_IFACE_METHOD(GLTF_Model, PrepareGPUResources, This, __VA_ARGS__) | |
156 | # define IGLTFModel_IsGPUDataInitialized(This) CALL_IFACE_METHOD(GLTF_Model, IsGPUDataInitialized, This) | |
157 | # define IGLTFModel_Transform(This, ...) CALL_IFACE_METHOD(GLTF_Model, Transform, This, __VA_ARGS__) | |
158 | # define IGLTFModel_GetBuffer(This, ...) CALL_IFACE_METHOD(GLTF_Model, GetBuffer, This, __VA_ARGS__) | |
159 | # define IGLTFModel_GetTexture(This, ...) CALL_IFACE_METHOD(GLTF_Model, GetTexture, This, __VA_ARGS__) | |
160 | # define IGLTFModel_GetFirstIndexLocation(This) CALL_IFACE_METHOD(GLTF_Model, GetFirstIndexLocation, This) | |
161 | # define IGLTFModel_GetBaseVertex(This) CALL_IFACE_METHOD(GLTF_Model, GetBaseVertex, This) | |
162 | ||
163 | // clang-format on | |
164 | ||
165 | /// Initializes the renderer | |
166 | API_QUALIFIER | |
167 | struct IGLTFModel* DILIGENT_GLOBAL_FUNCTION(IGLTFModel_Create)(IRenderDevice* pDevice, | |
168 | IDeviceContext* pCtx, | |
169 | const IGLTFModelCreateInfo* CI); | |
170 | ||
171 | API_QUALIFIER | |
172 | void DILIGENT_GLOBAL_FUNCTION(IGLTFModel_Destroy)(struct IGLTFModel* model); | |
173 | #endif | |
174 | ||
175 | DILIGENT_END_NAMESPACE // namespace GLTF | |
176 | ||
177 | DILIGENT_END_NAMESPACE // namespace Diligent |
0 | /* | |
1 | * Copyright 2019-2021 Diligent Graphics LLC | |
2 | * Copyright 2015-2019 Egor Yusov | |
3 | * | |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | * | |
16 | * In no event and under no legal theory, whether in tort (including negligence), | |
17 | * contract, or otherwise, unless required by applicable law (such as deliberate | |
18 | * and grossly negligent acts) or agreed to in writing, shall any Contributor be | |
19 | * liable for any damages, including any direct, indirect, special, incidental, | |
20 | * or consequential damages of any character arising as a result of this License or | |
21 | * out of the use or inability to use the software (including but not limited to damages | |
22 | * for loss of goodwill, work stoppage, computer failure or malfunction, or any and | |
23 | * all other commercial damages or losses), even if such Contributor has been advised | |
24 | * of the possibility of such damages. | |
25 | */ | |
26 | ||
27 | #pragma once | |
28 | ||
29 | #include <vector> | |
30 | #include <array> | |
31 | #include <memory> | |
32 | #include <cfloat> | |
33 | #include <unordered_map> | |
34 | #include <mutex> | |
35 | #include <atomic> | |
36 | ||
37 | #include "../../../DiligentCore/Graphics/GraphicsEngine/interface/RenderDevice.h" | |
38 | #include "../../../DiligentCore/Graphics/GraphicsEngine/interface/DeviceContext.h" | |
39 | #include "../../../DiligentCore/Common/interface/RefCntAutoPtr.hpp" | |
40 | #include "../../../DiligentCore/Common/interface/AdvancedMath.hpp" | |
41 | #include "GLTFResourceManager.hpp" | |
42 | ||
43 | namespace tinygltf | |
44 | { | |
45 | ||
46 | class Node; | |
47 | class Model; | |
48 | ||
49 | } // namespace tinygltf | |
50 | ||
51 | namespace Diligent | |
52 | { | |
53 | ||
54 | namespace GLTF | |
55 | { | |
56 | ||
57 | struct ResourceCacheUseInfo | |
58 | { | |
59 | ResourceManager* pResourceMgr = nullptr; | |
60 | ||
61 | Uint8 IndexBufferIdx = 0; | |
62 | Uint8 VertexBuffer0Idx = 0; | |
63 | Uint8 VertexBuffer1Idx = 0; | |
64 | ||
65 | /// Base color texture format. | |
66 | TEXTURE_FORMAT BaseColorFormat = TEX_FORMAT_RGBA8_UNORM; | |
67 | ||
68 | /// Base color texture format for alpha-cut and alpha-blend materials. | |
69 | TEXTURE_FORMAT BaseColorAlphaFormat = TEX_FORMAT_RGBA8_UNORM; | |
70 | ||
71 | /// Physical descriptor texture format. | |
72 | TEXTURE_FORMAT PhysicalDescFormat = TEX_FORMAT_RGBA8_UNORM; | |
73 | ||
74 | /// Normal map format. | |
75 | TEXTURE_FORMAT NormalFormat = TEX_FORMAT_RGBA8_UNORM; | |
76 | ||
77 | /// Occlusion texture format. | |
78 | TEXTURE_FORMAT OcclusionFormat = TEX_FORMAT_RGBA8_UNORM; | |
79 | ||
80 | /// Emissive texture format. | |
81 | TEXTURE_FORMAT EmissiveFormat = TEX_FORMAT_RGBA8_UNORM; | |
82 | }; | |
83 | ||
84 | struct Material | |
85 | { | |
86 | Material() noexcept | |
87 | { | |
88 | TextureIds.fill(-1); | |
89 | } | |
90 | ||
91 | enum PBR_WORKFLOW | |
92 | { | |
93 | PBR_WORKFLOW_METALL_ROUGH = 0, | |
94 | PBR_WORKFLOW_SPEC_GLOSS | |
95 | }; | |
96 | ||
97 | enum ALPHA_MODE | |
98 | { | |
99 | ALPHA_MODE_OPAQUE = 0, | |
100 | ALPHA_MODE_MASK, | |
101 | ALPHA_MODE_BLEND, | |
102 | ALPHA_MODE_NUM_MODES | |
103 | }; | |
104 | ||
105 | // Material attributes packed in a shader-friendly format | |
106 | struct ShaderAttribs | |
107 | { | |
108 | float4 BaseColorFactor = float4{1, 1, 1, 1}; | |
109 | float4 EmissiveFactor = float4{1, 1, 1, 1}; | |
110 | float4 SpecularFactor = float4{1, 1, 1, 1}; | |
111 | ||
112 | int Workflow = PBR_WORKFLOW_METALL_ROUGH; | |
113 | float BaseColorUVSelector = -1; | |
114 | float PhysicalDescriptorUVSelector = -1; | |
115 | float NormalUVSelector = -1; | |
116 | ||
117 | float OcclusionUVSelector = -1; | |
118 | float EmissiveUVSelector = -1; | |
119 | float BaseColorSlice = 0; | |
120 | float PhysicalDescriptorSlice = 0; | |
121 | ||
122 | float NormalSlice = 0; | |
123 | float OcclusionSlice = 0; | |
124 | float EmissiveSlice = 0; | |
125 | float MetallicFactor = 1; | |
126 | ||
127 | float RoughnessFactor = 1; | |
128 | int AlphaMode = ALPHA_MODE_OPAQUE; | |
129 | float AlphaCutoff = 0.5f; | |
130 | float Dummy0; | |
131 | ||
132 | // When texture atlas is used, UV scale and bias applied to | |
133 | // each texture coordinate set | |
134 | float4 BaseColorUVScaleBias = float4{1, 1, 0, 0}; | |
135 | float4 PhysicalDescriptorUVScaleBias = float4{1, 1, 0, 0}; | |
136 | float4 NormalUVScaleBias = float4{1, 1, 0, 0}; | |
137 | float4 OcclusionUVScaleBias = float4{1, 1, 0, 0}; | |
138 | float4 EmissiveUVScaleBias = float4{1, 1, 0, 0}; | |
139 | }; | |
140 | static_assert(sizeof(ShaderAttribs) % 16 == 0, "ShaderAttribs struct must be 16-byte aligned"); | |
141 | ShaderAttribs Attribs; | |
142 | ||
143 | bool DoubleSided = false; | |
144 | ||
145 | enum TEXTURE_ID | |
146 | { | |
147 | // Base color for metallic-roughness workflow or | |
148 | // diffuse color for specular-glossinees workflow | |
149 | TEXTURE_ID_BASE_COLOR = 0, | |
150 | ||
151 | // Metallic-roughness or specular-glossinees map | |
152 | TEXTURE_ID_PHYSICAL_DESC, | |
153 | ||
154 | TEXTURE_ID_NORMAL_MAP, | |
155 | TEXTURE_ID_OCCLUSION, | |
156 | TEXTURE_ID_EMISSIVE, | |
157 | TEXTURE_ID_NUM_TEXTURES | |
158 | }; | |
159 | // Texture indices in Model.Textures array | |
160 | std::array<int, TEXTURE_ID_NUM_TEXTURES> TextureIds = {}; | |
161 | }; | |
162 | ||
163 | ||
164 | struct Primitive | |
165 | { | |
166 | const Uint32 FirstIndex; | |
167 | const Uint32 IndexCount; | |
168 | const Uint32 VertexCount; | |
169 | const Uint32 MaterialId; | |
170 | ||
171 | const BoundBox BB; | |
172 | ||
173 | Primitive(Uint32 _FirstIndex, | |
174 | Uint32 _IndexCount, | |
175 | Uint32 _VertexCount, | |
176 | Uint32 _MaterialId, | |
177 | const float3& BBMin, | |
178 | const float3& BBMax) : | |
179 | FirstIndex{_FirstIndex}, | |
180 | IndexCount{_IndexCount}, | |
181 | VertexCount{_VertexCount}, | |
182 | MaterialId{_MaterialId}, | |
183 | BB{BBMin, BBMax} | |
184 | { | |
185 | } | |
186 | ||
187 | Primitive(Primitive&&) = default; | |
188 | ||
189 | bool HasIndices() const | |
190 | { | |
191 | return IndexCount > 0; | |
192 | } | |
193 | }; | |
194 | ||
195 | ||
196 | ||
197 | struct Mesh | |
198 | { | |
199 | std::vector<Primitive> Primitives; | |
200 | ||
201 | BoundBox BB; | |
202 | ||
203 | // There may be no primitives in the mesh, in which | |
204 | // case the bounding box will be invalid. | |
205 | bool IsValidBB() const | |
206 | { | |
207 | return !Primitives.empty(); | |
208 | } | |
209 | ||
210 | struct TransformData | |
211 | { | |
212 | float4x4 matrix; | |
213 | std::vector<float4x4> jointMatrices; | |
214 | }; | |
215 | ||
216 | TransformData Transforms; | |
217 | ||
218 | Mesh(const float4x4& matrix); | |
219 | }; | |
220 | ||
221 | ||
222 | struct Node; | |
223 | struct Skin | |
224 | { | |
225 | std::string Name; | |
226 | Node* pSkeletonRoot = nullptr; | |
227 | std::vector<float4x4> InverseBindMatrices; | |
228 | std::vector<Node*> Joints; | |
229 | }; | |
230 | ||
231 | struct Camera | |
232 | { | |
233 | enum class Projection | |
234 | { | |
235 | Unknown, | |
236 | Perspective, | |
237 | Orthographic | |
238 | } Type = Projection::Unknown; | |
239 | ||
240 | std::string Name; | |
241 | ||
242 | struct PerspectiveAttribs | |
243 | { | |
244 | float AspectRatio; | |
245 | float YFov; | |
246 | float ZNear; | |
247 | float ZFar; | |
248 | }; | |
249 | struct OrthographicAttribs | |
250 | { | |
251 | float XMag; | |
252 | float YMag; | |
253 | float ZNear; | |
254 | float ZFar; | |
255 | }; | |
256 | union | |
257 | { | |
258 | PerspectiveAttribs Perspective = {}; | |
259 | OrthographicAttribs Orthographic; | |
260 | }; | |
261 | ||
262 | float4x4 matrix; | |
263 | }; | |
264 | ||
265 | struct Node | |
266 | { | |
267 | std::string Name; | |
268 | Node* Parent = nullptr; | |
269 | Uint32 Index; | |
270 | ||
271 | std::vector<std::unique_ptr<Node>> Children; | |
272 | ||
273 | float4x4 Matrix; | |
274 | std::unique_ptr<Mesh> pMesh; | |
275 | std::unique_ptr<Camera> pCamera; | |
276 | Skin* pSkin = nullptr; | |
277 | Int32 SkinIndex = -1; | |
278 | float3 Translation; | |
279 | float3 Scale = float3{1, 1, 1}; | |
280 | Quaternion Rotation; | |
281 | BoundBox BVH; | |
282 | BoundBox AABB; | |
283 | ||
284 | bool IsValidBVH = false; | |
285 | ||
286 | float4x4 LocalMatrix() const; | |
287 | float4x4 GetMatrix() const; | |
288 | void UpdateTransforms(); | |
289 | }; | |
290 | ||
291 | ||
292 | struct AnimationChannel | |
293 | { | |
294 | enum PATH_TYPE | |
295 | { | |
296 | TRANSLATION, | |
297 | ROTATION, | |
298 | SCALE | |
299 | }; | |
300 | PATH_TYPE PathType; | |
301 | Node* pNode = nullptr; | |
302 | Uint32 SamplerIndex = static_cast<Uint32>(-1); | |
303 | }; | |
304 | ||
305 | ||
306 | struct AnimationSampler | |
307 | { | |
308 | enum INTERPOLATION_TYPE | |
309 | { | |
310 | LINEAR, | |
311 | STEP, | |
312 | CUBICSPLINE | |
313 | }; | |
314 | INTERPOLATION_TYPE Interpolation; | |
315 | std::vector<float> Inputs; | |
316 | std::vector<float4> OutputsVec4; | |
317 | }; | |
318 | ||
319 | struct Animation | |
320 | { | |
321 | std::string Name; | |
322 | std::vector<AnimationSampler> Samplers; | |
323 | std::vector<AnimationChannel> Channels; | |
324 | ||
325 | float Start = std::numeric_limits<float>::max(); | |
326 | float End = std::numeric_limits<float>::min(); | |
327 | }; | |
328 | ||
329 | ||
330 | struct Model | |
331 | { | |
332 | struct VertexBasicAttribs | |
333 | { | |
334 | float3 pos; | |
335 | float3 normal; | |
336 | float2 uv0; | |
337 | float2 uv1; | |
338 | }; | |
339 | ||
340 | struct VertexSkinAttribs | |
341 | { | |
342 | float4 joint0; | |
343 | float4 weight0; | |
344 | }; | |
345 | ||
346 | enum BUFFER_ID | |
347 | { | |
348 | BUFFER_ID_VERTEX_BASIC_ATTRIBS = 0, | |
349 | BUFFER_ID_VERTEX_SKIN_ATTRIBS, | |
350 | BUFFER_ID_INDEX, | |
351 | BUFFER_ID_NUM_BUFFERS | |
352 | }; | |
353 | ||
354 | Uint32 IndexCount = 0; | |
355 | ||
356 | /// Transformation matrix that transforms unit cube [0,1]x[0,1]x[0,1] into | |
357 | /// axis-aligned bounding box in model space. | |
358 | float4x4 AABBTransform; | |
359 | ||
360 | std::vector<std::unique_ptr<Node>> Nodes; | |
361 | std::vector<Node*> LinearNodes; | |
362 | ||
363 | std::vector<std::unique_ptr<Skin>> Skins; | |
364 | ||
365 | std::vector<RefCntAutoPtr<ISampler>> TextureSamplers; | |
366 | std::vector<Material> Materials; | |
367 | std::vector<Animation> Animations; | |
368 | std::vector<std::string> Extensions; | |
369 | ||
370 | struct Dimensions | |
371 | { | |
372 | float3 min = float3{+FLT_MAX, +FLT_MAX, +FLT_MAX}; | |
373 | float3 max = float3{-FLT_MAX, -FLT_MAX, -FLT_MAX}; | |
374 | } dimensions; | |
375 | ||
376 | struct TextureCacheType | |
377 | { | |
378 | std::mutex TexturesMtx; | |
379 | ||
380 | std::unordered_map<std::string, RefCntWeakPtr<ITexture>> Textures; | |
381 | }; | |
382 | ||
383 | /// Model create information | |
384 | struct CreateInfo | |
385 | { | |
386 | /// File name | |
387 | const char* FileName = nullptr; | |
388 | ||
389 | /// Optional texture cache to use when loading the model. | |
390 | /// The loader will try to find all the textures in the cache | |
391 | /// and add all new textures to the cache. | |
392 | TextureCacheType* pTextureCache = nullptr; | |
393 | ||
394 | /// Optional resource cache usage info. | |
395 | ResourceCacheUseInfo* pCacheInfo = nullptr; | |
396 | ||
397 | /// Whether to load animation and initialize skin attributes | |
398 | /// buffer. | |
399 | bool LoadAnimationAndSkin = true; | |
400 | ||
401 | CreateInfo() = default; | |
402 | ||
403 | explicit CreateInfo(const char* _FileName, | |
404 | TextureCacheType* _pTextureCache = nullptr, | |
405 | ResourceCacheUseInfo* _pCacheInfo = nullptr, | |
406 | bool _LoadAnimationAndSkin = true) : | |
407 | // clang-format off | |
408 | FileName {_FileName}, | |
409 | pTextureCache {_pTextureCache}, | |
410 | pCacheInfo {_pCacheInfo}, | |
411 | LoadAnimationAndSkin{_LoadAnimationAndSkin} | |
412 | // clang-format on | |
413 | { | |
414 | } | |
415 | }; | |
416 | Model(IRenderDevice* pDevice, | |
417 | IDeviceContext* pContext, | |
418 | const CreateInfo& CI); | |
419 | ||
420 | ~Model(); | |
421 | ||
422 | void UpdateAnimation(Uint32 index, float time); | |
423 | ||
424 | void PrepareGPUResources(IRenderDevice* pDevice, IDeviceContext* pCtx); | |
425 | ||
426 | bool IsGPUDataInitialized() const | |
427 | { | |
428 | return GPUDataInitialized.load(); | |
429 | } | |
430 | ||
431 | void Transform(const float4x4& Matrix); | |
432 | ||
433 | IBuffer* GetBuffer(BUFFER_ID BuffId) | |
434 | { | |
435 | return Buffers[BuffId].pBuffer; | |
436 | } | |
437 | ||
438 | ITexture* GetTexture(Uint32 Index) | |
439 | { | |
440 | return Textures[Index].pTexture; | |
441 | } | |
442 | ||
443 | Uint32 GetFirstIndexLocation() const | |
444 | { | |
445 | auto& IndBuff = Buffers[BUFFER_ID_INDEX]; | |
446 | VERIFY(!IndBuff.pSuballocation || IndBuff.pSuballocation->GetOffset() % sizeof(Uint32) == 0, | |
447 | "Allocation offset is not multiple of sizeof(Uint32)"); | |
448 | return IndBuff.pSuballocation ? | |
449 | static_cast<Uint32>(IndBuff.pSuballocation->GetOffset() / sizeof(Uint32)) : | |
450 | 0; | |
451 | } | |
452 | ||
453 | Uint32 GetBaseVertex() const | |
454 | { | |
455 | auto& VertBuff = Buffers[BUFFER_ID_VERTEX_BASIC_ATTRIBS]; | |
456 | VERIFY(!VertBuff.pSuballocation || VertBuff.pSuballocation->GetOffset() % sizeof(VertexBasicAttribs) == 0, | |
457 | "Allocation offset is not multiple of sizeof(VertexAttribs0)"); | |
458 | return VertBuff.pSuballocation ? | |
459 | static_cast<Uint32>(VertBuff.pSuballocation->GetOffset() / sizeof(VertexBasicAttribs)) : | |
460 | 0; | |
461 | } | |
462 | ||
463 | private: | |
464 | void LoadFromFile(IRenderDevice* pDevice, | |
465 | IDeviceContext* pContext, | |
466 | const CreateInfo& CI); | |
467 | ||
468 | void LoadNode(Node* parent, | |
469 | const tinygltf::Node& gltf_node, | |
470 | uint32_t nodeIndex, | |
471 | const tinygltf::Model& gltf_model, | |
472 | std::vector<Uint32>& IndexData, | |
473 | std::vector<VertexBasicAttribs>& VertexBasicData, | |
474 | std::vector<VertexSkinAttribs>* pVertexSkinData); | |
475 | ||
476 | void LoadSkins(const tinygltf::Model& gltf_model); | |
477 | ||
478 | void LoadTextures(IRenderDevice* pDevice, | |
479 | const tinygltf::Model& gltf_model, | |
480 | const std::string& BaseDir, | |
481 | TextureCacheType* pTextureCache, | |
482 | ResourceManager* pResourceMgr); | |
483 | ||
484 | void LoadTextureSamplers(IRenderDevice* pDevice, const tinygltf::Model& gltf_model); | |
485 | void LoadMaterials(const tinygltf::Model& gltf_model); | |
486 | void LoadAnimations(const tinygltf::Model& gltf_model); | |
487 | void CalculateBoundingBox(Node* node, const Node* parent); | |
488 | void CalculateSceneDimensions(); | |
489 | Node* FindNode(Node* parent, Uint32 index); | |
490 | Node* NodeFromIndex(uint32_t index); | |
491 | ||
492 | std::atomic_bool GPUDataInitialized{false}; | |
493 | ||
494 | struct BufferInfo | |
495 | { | |
496 | RefCntAutoPtr<IBuffer> pBuffer; | |
497 | RefCntAutoPtr<IBufferSuballocation> pSuballocation; | |
498 | }; | |
499 | std::array<BufferInfo, BUFFER_ID_NUM_BUFFERS> Buffers; | |
500 | ||
501 | struct TextureInfo | |
502 | { | |
503 | RefCntAutoPtr<ITexture> pTexture; | |
504 | RefCntAutoPtr<ITextureAtlasSuballocation> pAtlasSuballocation; | |
505 | ||
506 | bool IsValid() const | |
507 | { | |
508 | return pTexture || pAtlasSuballocation; | |
509 | } | |
510 | }; | |
511 | std::vector<TextureInfo> Textures; | |
512 | }; | |
513 | ||
514 | } // namespace GLTF | |
515 | ||
516 | } // namespace Diligent |
0 | /* | |
1 | * Copyright 2019-2021 Diligent Graphics LLC | |
2 | * Copyright 2015-2019 Egor Yusov | |
3 | * | |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | * | |
16 | * In no event and under no legal theory, whether in tort (including negligence), | |
17 | * contract, or otherwise, unless required by applicable law (such as deliberate | |
18 | * and grossly negligent acts) or agreed to in writing, shall any Contributor be | |
19 | * liable for any damages, including any direct, indirect, special, incidental, | |
20 | * or consequential damages of any character arising as a result of this License or | |
21 | * out of the use or inability to use the software (including but not limited to damages | |
22 | * for loss of goodwill, work stoppage, computer failure or malfunction, or any and | |
23 | * all other commercial damages or losses), even if such Contributor has been advised | |
24 | * of the possibility of such damages. | |
25 | */ | |
26 | ||
27 | #pragma once | |
28 | ||
29 | #include <mutex> | |
30 | #include <vector> | |
31 | #include <unordered_map> | |
32 | #include <atomic> | |
33 | ||
34 | #include "../../../DiligentCore/Graphics/GraphicsEngine/interface/RenderDevice.h" | |
35 | #include "../../../DiligentCore/Graphics/GraphicsEngine/interface/DeviceContext.h" | |
36 | #include "../../../DiligentCore/Common/interface/RefCntAutoPtr.hpp" | |
37 | #include "../../../DiligentCore/Common/interface/ObjectBase.hpp" | |
38 | #include "../../../DiligentCore/Graphics/GraphicsTools/interface/BufferSuballocator.h" | |
39 | #include "../../../DiligentCore/Graphics/GraphicsTools/interface/DynamicTextureAtlas.h" | |
40 | ||
41 | ||
42 | namespace Diligent | |
43 | { | |
44 | ||
45 | namespace GLTF | |
46 | { | |
47 | ||
48 | /// GLTF resource manager | |
49 | class ResourceManager final : public ObjectBase<IObject> | |
50 | { | |
51 | public: | |
52 | using TBase = ObjectBase<IObject>; | |
53 | ||
54 | struct CreateInfo | |
55 | { | |
56 | const BufferSuballocatorCreateInfo* BuffSuballocators = nullptr; // [NumBuffSuballocators] | |
57 | const DynamicTextureAtlasCreateInfo* TexAtlases = nullptr; // [NumTexAtlases] | |
58 | ||
59 | Uint32 NumBuffSuballocators = 0; | |
60 | Uint32 NumTexAtlases = 0; | |
61 | ||
62 | DynamicTextureAtlasCreateInfo DefaultAtlasDesc; | |
63 | }; | |
64 | ||
65 | static RefCntAutoPtr<ResourceManager> Create(IRenderDevice* pDevice, | |
66 | const CreateInfo& CI); | |
67 | ||
68 | RefCntAutoPtr<IBufferSuballocation> AllocateBufferSpace(Uint32 BufferIndex, | |
69 | Uint32 Size, | |
70 | Uint32 Alignment) | |
71 | { | |
72 | RefCntAutoPtr<IBufferSuballocation> pSuballoc; | |
73 | m_BufferSuballocators[BufferIndex]->Allocate(Size, Alignment, &pSuballoc); | |
74 | return pSuballoc; | |
75 | } | |
76 | ||
77 | RefCntAutoPtr<ITextureAtlasSuballocation> AllocateTextureSpace(TEXTURE_FORMAT Fmt, | |
78 | Uint32 Width, | |
79 | Uint32 Height, | |
80 | const char* CacheId = nullptr, | |
81 | IObject* pUserData = nullptr); | |
82 | ||
83 | RefCntAutoPtr<ITextureAtlasSuballocation> FindAllocation(const char* CacheId); | |
84 | ||
85 | Uint32 GetTextureVersion() | |
86 | { | |
87 | Uint32 Version = 0; | |
88 | ||
89 | std::lock_guard<std::mutex> Lock{m_AtlasesMtx}; | |
90 | for (auto atlas_it : m_Atlases) | |
91 | Version += atlas_it.second->GetVersion(); | |
92 | ||
93 | return Version; | |
94 | } | |
95 | ||
96 | Uint32 GetBufferVersion(Uint32 Index) const | |
97 | { | |
98 | return m_BufferSuballocators[Index]->GetVersion(); | |
99 | } | |
100 | ||
101 | IBuffer* GetBuffer(Uint32 Index, IRenderDevice* pDevice, IDeviceContext* pContext) | |
102 | { | |
103 | return m_BufferSuballocators[Index]->GetBuffer(pDevice, pContext); | |
104 | } | |
105 | ||
106 | ITexture* GetTexture(TEXTURE_FORMAT Fmt, IRenderDevice* pDevice, IDeviceContext* pContext) | |
107 | { | |
108 | decltype(m_Atlases)::iterator cache_it; // NB: can't initialize it without locking the mutex | |
109 | { | |
110 | std::lock_guard<std::mutex> Lock{m_AtlasesMtx}; | |
111 | cache_it = m_Atlases.find(Fmt); | |
112 | if (cache_it == m_Atlases.end()) | |
113 | return nullptr; | |
114 | } | |
115 | ||
116 | return cache_it->second->GetTexture(pDevice, pContext); | |
117 | } | |
118 | ||
119 | // NB: can't return reference here! | |
120 | TextureDesc GetAtlasDesc(TEXTURE_FORMAT Fmt) | |
121 | { | |
122 | { | |
123 | std::lock_guard<std::mutex> Lock{m_AtlasesMtx}; | |
124 | ||
125 | auto cache_it = m_Atlases.find(Fmt); | |
126 | if (cache_it != m_Atlases.end()) | |
127 | return cache_it->second->GetAtlasDesc(); | |
128 | } | |
129 | ||
130 | // Atlas is not present in the map - use default description | |
131 | TextureDesc Desc = m_DefaultAtlasDesc.Desc; | |
132 | Desc.Format = Fmt; | |
133 | return Desc; | |
134 | } | |
135 | ||
136 | private: | |
137 | template <typename AllocatorType, typename ObjectType> | |
138 | friend class Diligent::MakeNewRCObj; | |
139 | ||
140 | ResourceManager(IReferenceCounters* pRefCounters, | |
141 | IRenderDevice* pDevice, | |
142 | const CreateInfo& CI); | |
143 | ||
144 | std::vector<RefCntAutoPtr<IBufferSuballocator>> m_BufferSuballocators; | |
145 | ||
146 | DynamicTextureAtlasCreateInfo m_DefaultAtlasDesc; | |
147 | const std::string m_DefaultAtlasName; | |
148 | ||
149 | using AtlasesHashMapType = std::unordered_map<TEXTURE_FORMAT, RefCntAutoPtr<IDynamicTextureAtlas>, std::hash<Uint32>>; | |
150 | std::mutex m_AtlasesMtx; | |
151 | AtlasesHashMapType m_Atlases; | |
152 | ||
153 | using TexAllocationsHashMapType = std::unordered_map<std::string, RefCntWeakPtr<ITextureAtlasSuballocation>>; | |
154 | std::mutex m_TexAllocationsMtx; | |
155 | TexAllocationsHashMapType m_TexAllocations; | |
156 | }; | |
157 | ||
158 | } // namespace GLTF | |
159 | ||
160 | } // namespace Diligent |
245 | 245 | |
246 | 246 | |
247 | 247 | |
248 | Model::Model(IRenderDevice* pDevice, | |
249 | IDeviceContext* pContext, | |
250 | const CreateInfo& CI) | |
248 | Model::Model(IRenderDevice* pDevice, | |
249 | IDeviceContext* pContext, | |
250 | const IGLTFModelCreateInfo& CI) | |
251 | 251 | { |
252 | 252 | LoadFromFile(pDevice, pContext, CI); |
253 | 253 | } |
709 | 709 | void Model::LoadTextures(IRenderDevice* pDevice, |
710 | 710 | const tinygltf::Model& gltf_model, |
711 | 711 | const std::string& BaseDir, |
712 | TextureCacheType* pTextureCache, | |
712 | GLTF_TextureCacheType* pTextureCache, | |
713 | 713 | ResourceManager* pResourceMgr) |
714 | 714 | { |
715 | 715 | for (const tinygltf::Texture& gltf_tex : gltf_model.textures) |
1020 | 1020 | } |
1021 | 1021 | } |
1022 | 1022 | |
1023 | auto UpdateBuffer = [&](BUFFER_ID BuffId) // | |
1023 | auto UpdateBuffer = [&](GLTF_BUFFER_ID BuffId) // | |
1024 | 1024 | { |
1025 | 1025 | auto& BuffInfo = Buffers[BuffId]; |
1026 | 1026 | IBuffer* pBuffer = nullptr; |
1051 | 1051 | if (Buffers[BuffId].pBuffer != nullptr) |
1052 | 1052 | { |
1053 | 1053 | VERIFY_EXPR(Buffers[BuffId].pBuffer == pBuffer); |
1054 | Barriers.emplace_back(StateTransitionDesc{pBuffer, RESOURCE_STATE_UNKNOWN, BuffId == BUFFER_ID_INDEX ? RESOURCE_STATE_INDEX_BUFFER : RESOURCE_STATE_VERTEX_BUFFER, true}); | |
1054 | Barriers.emplace_back(StateTransitionDesc{pBuffer, RESOURCE_STATE_UNKNOWN, BuffId == GLTF_BUFFER_ID_INDEX ? RESOURCE_STATE_INDEX_BUFFER : RESOURCE_STATE_VERTEX_BUFFER, true}); | |
1055 | 1055 | } |
1056 | 1056 | } |
1057 | 1057 | }; |
1058 | 1058 | |
1059 | UpdateBuffer(BUFFER_ID_VERTEX_BASIC_ATTRIBS); | |
1060 | UpdateBuffer(BUFFER_ID_VERTEX_SKIN_ATTRIBS); | |
1061 | UpdateBuffer(BUFFER_ID_INDEX); | |
1059 | UpdateBuffer(GLTF_BUFFER_ID_VERTEX_BASIC_ATTRIBS); | |
1060 | UpdateBuffer(GLTF_BUFFER_ID_VERTEX_SKIN_ATTRIBS); | |
1061 | UpdateBuffer(GLTF_BUFFER_ID_INDEX); | |
1062 | 1062 | |
1063 | 1063 | if (!Barriers.empty()) |
1064 | 1064 | pCtx->TransitionResourceStates(static_cast<Uint32>(Barriers.size()), Barriers.data()); |
1194 | 1194 | const tinygltf::Parameter& param = alpha_mode_it->second; |
1195 | 1195 | if (param.string_value == "BLEND") |
1196 | 1196 | { |
1197 | Mat.Attribs.AlphaMode = Material::ALPHA_MODE_BLEND; | |
1197 | Mat.Attribs.AlphaMode = GLTF_MAT_ALPHA_MODE_BLEND; | |
1198 | 1198 | } |
1199 | 1199 | if (param.string_value == "MASK") |
1200 | 1200 | { |
1201 | Mat.Attribs.AlphaMode = Material::ALPHA_MODE_MASK; | |
1201 | Mat.Attribs.AlphaMode = GLTF_MAT_ALPHA_MODE_MASK; | |
1202 | 1202 | Mat.Attribs.AlphaCutoff = 0.5f; |
1203 | 1203 | } |
1204 | 1204 | } |
1433 | 1433 | |
1434 | 1434 | struct ImageLoaderData |
1435 | 1435 | { |
1436 | Model::TextureCacheType* const pTextureCache; | |
1437 | ResourceManager* const pResourceMgr; | |
1436 | GLTF_TextureCacheType* const pTextureCache; | |
1437 | ResourceManager* const pResourceMgr; | |
1438 | 1438 | |
1439 | 1439 | std::vector<RefCntAutoPtr<IObject>> TexturesHold; |
1440 | 1440 | |
1698 | 1698 | |
1699 | 1699 | } // namespace Callbacks |
1700 | 1700 | |
1701 | void Model::LoadFromFile(IRenderDevice* pDevice, | |
1702 | IDeviceContext* pContext, | |
1703 | const CreateInfo& CI) | |
1701 | void Model::LoadFromFile(IRenderDevice* pDevice, | |
1702 | IDeviceContext* pContext, | |
1703 | const IGLTFModelCreateInfo& CI) | |
1704 | 1704 | { |
1705 | 1705 | if (CI.FileName == nullptr || *CI.FileName == 0) |
1706 | 1706 | LOG_ERROR_AND_THROW("File path must not be empty"); |
1798 | 1798 | |
1799 | 1799 | Extensions = gltf_model.extensionsUsed; |
1800 | 1800 | |
1801 | auto CreateBuffer = [&](BUFFER_ID BuffId, const void* pData, size_t Size, BIND_FLAGS BindFlags, const char* Name) // | |
1801 | auto CreateBuffer = [&](GLTF_BUFFER_ID BuffId, const void* pData, size_t Size, BIND_FLAGS BindFlags, const char* Name) // | |
1802 | 1802 | { |
1803 | 1803 | VERIFY_EXPR(Size > 0); |
1804 | 1804 | |
1808 | 1808 | Uint32 CacheBufferIndex = 0; |
1809 | 1809 | switch (BuffId) |
1810 | 1810 | { |
1811 | case BUFFER_ID_INDEX: | |
1811 | case GLTF_BUFFER_ID_INDEX: | |
1812 | 1812 | CacheBufferIndex = CI.pCacheInfo->IndexBufferIdx; |
1813 | 1813 | break; |
1814 | case BUFFER_ID_VERTEX_BASIC_ATTRIBS: | |
1814 | case GLTF_BUFFER_ID_VERTEX_BASIC_ATTRIBS: | |
1815 | 1815 | CacheBufferIndex = CI.pCacheInfo->VertexBuffer0Idx; |
1816 | 1816 | break; |
1817 | case BUFFER_ID_VERTEX_SKIN_ATTRIBS: | |
1817 | case GLTF_BUFFER_ID_VERTEX_SKIN_ATTRIBS: | |
1818 | 1818 | CacheBufferIndex = CI.pCacheInfo->VertexBuffer1Idx; |
1819 | 1819 | break; |
1820 | 1820 | default: |
1839 | 1839 | } |
1840 | 1840 | }; |
1841 | 1841 | |
1842 | CreateBuffer(BUFFER_ID_VERTEX_BASIC_ATTRIBS, VertexBasicData.data(), VertexBasicData.size() * sizeof(VertexBasicData[0]), | |
1842 | CreateBuffer(GLTF_BUFFER_ID_VERTEX_BASIC_ATTRIBS, VertexBasicData.data(), VertexBasicData.size() * sizeof(VertexBasicData[0]), | |
1843 | 1843 | BIND_VERTEX_BUFFER, "GLTF vertex attribs 0 buffer"); |
1844 | 1844 | |
1845 | 1845 | if (!VertexSkinData.empty()) |
1846 | 1846 | { |
1847 | CreateBuffer(BUFFER_ID_VERTEX_SKIN_ATTRIBS, VertexSkinData.data(), VertexSkinData.size() * sizeof(VertexSkinData[0]), | |
1847 | CreateBuffer(GLTF_BUFFER_ID_VERTEX_SKIN_ATTRIBS, VertexSkinData.data(), VertexSkinData.size() * sizeof(VertexSkinData[0]), | |
1848 | 1848 | BIND_VERTEX_BUFFER, "GLTF vertex attribs 1 buffer"); |
1849 | 1849 | } |
1850 | 1850 | |
1851 | 1851 | if (!IndexData.empty()) |
1852 | 1852 | { |
1853 | CreateBuffer(BUFFER_ID_INDEX, IndexData.data(), IndexData.size() * sizeof(IndexData[0]), | |
1853 | CreateBuffer(GLTF_BUFFER_ID_INDEX, IndexData.data(), IndexData.size() * sizeof(IndexData[0]), | |
1854 | 1854 | BIND_INDEX_BUFFER, "GLTF index buffer"); |
1855 | 1855 | } |
1856 | 1856 | |
1988 | 1988 | } |
1989 | 1989 | } |
1990 | 1990 | |
1991 | void Model::Transform(const float4x4& Matrix) | |
1992 | { | |
1991 | void Model::Transform(const float* _Matrix) | |
1992 | { | |
1993 | auto Matrix = float4x4::MakeMatrix(_Matrix); | |
1993 | 1994 | for (auto& root_node : Nodes) |
1994 | 1995 | { |
1995 | 1996 | root_node->Matrix *= Matrix; |
2032 | 2033 | return nodeFound; |
2033 | 2034 | } |
2034 | 2035 | |
2036 | API_QUALIFIER | |
2037 | IGLTFModel* IGLTFModel_Create(IRenderDevice* pDevice, | |
2038 | IDeviceContext* pCtx, | |
2039 | const IGLTFModelCreateInfo* CI) { | |
2040 | return new Model(pDevice, pCtx, *CI); | |
2041 | } | |
2042 | ||
2043 | API_QUALIFIER | |
2044 | void IGLTFModel_Destroy(IGLTFModel* model) { | |
2045 | delete model; | |
2046 | } | |
2035 | 2047 | |
2036 | 2048 | } // namespace GLTF |
2037 | 2049 | |
2038 | 2050 | } // namespace Diligent |
2051 | ||
2052 | extern "C" | |
2053 | { | |
2054 | API_QUALIFIER | |
2055 | Diligent::GLTF::IGLTFModel* Diligent_IGLTFModel_Create(Diligent::IRenderDevice* pDevice, | |
2056 | Diligent::IDeviceContext* pCtx, | |
2057 | const Diligent::GLTF::IGLTFModelCreateInfo* CI) { | |
2058 | return Diligent::GLTF::IGLTFModel_Create(pDevice, pCtx, CI); | |
2059 | } | |
2060 | ||
2061 | API_QUALIFIER | |
2062 | void Diligent_IGLTFModel_Destroy(Diligent::GLTF::IGLTFModel* model) { | |
2063 | Diligent::GLTF::IGLTFModel_Destroy(model); | |
2064 | } | |
2065 | } |