184 | 184 |
}
|
185 | 185 |
|
186 | 186 |
|
187 | |
Mesh::Mesh(IRenderDevice* pDevice, const float4x4& matrix)
|
|
187 |
Mesh::Mesh(const float4x4& matrix)
|
188 | 188 |
{
|
189 | 189 |
Transforms.matrix = matrix;
|
190 | 190 |
}
|
|
256 | 256 |
{
|
257 | 257 |
}
|
258 | 258 |
|
259 | |
void Model::LoadNode(IRenderDevice* pDevice,
|
260 | |
Node* parent,
|
|
259 |
void Model::LoadNode(Node* parent,
|
261 | 260 |
const tinygltf::Node& gltf_node,
|
262 | 261 |
uint32_t nodeIndex,
|
263 | 262 |
const tinygltf::Model& gltf_model,
|
|
265 | 264 |
std::vector<VertexBasicAttribs>& VertexBasicData,
|
266 | 265 |
std::vector<VertexSkinAttribs>* pVertexSkinData)
|
267 | 266 |
{
|
268 | |
std::unique_ptr<Node> NewNode(new Node{});
|
|
267 |
std::unique_ptr<Node> NewNode{new Node{}};
|
269 | 268 |
NewNode->Index = nodeIndex;
|
270 | 269 |
NewNode->Parent = parent;
|
271 | 270 |
NewNode->Name = gltf_node.name;
|
|
303 | 302 |
{
|
304 | 303 |
for (size_t i = 0; i < gltf_node.children.size(); i++)
|
305 | 304 |
{
|
306 | |
LoadNode(pDevice, NewNode.get(), gltf_model.nodes[gltf_node.children[i]], gltf_node.children[i], gltf_model,
|
|
305 |
LoadNode(NewNode.get(), gltf_model.nodes[gltf_node.children[i]], gltf_node.children[i], gltf_model,
|
307 | 306 |
IndexData, VertexBasicData, pVertexSkinData);
|
308 | 307 |
}
|
309 | 308 |
}
|
|
312 | 311 |
if (gltf_node.mesh >= 0)
|
313 | 312 |
{
|
314 | 313 |
const tinygltf::Mesh& gltf_mesh = gltf_model.meshes[gltf_node.mesh];
|
315 | |
std::unique_ptr<Mesh> pNewMesh{new Mesh{pDevice, NewNode->Matrix}};
|
|
314 |
std::unique_ptr<Mesh> pNewMesh{new Mesh{NewNode->Matrix}};
|
316 | 315 |
for (size_t j = 0; j < gltf_mesh.primitives.size(); j++)
|
317 | 316 |
{
|
318 | 317 |
const tinygltf::Primitive& primitive = gltf_mesh.primitives[j];
|
|
599 | 598 |
{
|
600 | 599 |
for (const auto& source : gltf_model.skins)
|
601 | 600 |
{
|
602 | |
std::unique_ptr<Skin> NewSkin(new Skin{});
|
|
601 |
std::unique_ptr<Skin> NewSkin{new Skin{}};
|
603 | 602 |
NewSkin->Name = source.name;
|
604 | 603 |
|
605 | 604 |
// Find skeleton root node
|
|
784 | 783 |
// No reference
|
785 | 784 |
const TextureDesc AtlasDesc = pResourceMgr->GetAtlasDesc(TEX_FORMAT_RGBA8_UNORM);
|
786 | 785 |
|
|
786 |
// Load all mip levels.
|
787 | 787 |
auto pInitData = PrepareGLTFTextureInitData(gltf_image, AlphaCutoff, AtlasDesc.MipLevels);
|
788 | 788 |
|
789 | |
// Init data will be atomically set in the allocation before any other thread may be able to
|
790 | |
// get access to it.
|
|
789 |
// pInitData will be atomically set in the allocation before any other thread may be able to
|
|
790 |
// access it.
|
791 | 791 |
// Note that it is possible that more than one thread prepares pInitData for the same allocation.
|
792 | 792 |
// It it also possible that multiple instances of the same allocation are created before the first
|
793 | 793 |
// is added to the cache. This is all OK though.
|
|
812 | 812 |
pDevice->CreateTexture(TexDesc, nullptr, &TexInfo.pTexture);
|
813 | 813 |
TexInfo.pTexture->GetDefaultView(TEXTURE_VIEW_SHADER_RESOURCE)->SetSampler(pSampler);
|
814 | 814 |
|
|
815 |
// Load only the lowest mip level; other mip levels will be generated on the GPU.
|
815 | 816 |
auto pTexInitData = PrepareGLTFTextureInitData(gltf_image, AlphaCutoff, 1);
|
816 | 817 |
TexInfo.pTexture->SetUserData(pTexInitData);
|
817 | 818 |
}
|
|
827 | 828 |
TextureLoadInfo LoadInfo;
|
828 | 829 |
if (pResourceMgr != nullptr)
|
829 | 830 |
{
|
830 | |
LoadInfo.Name = "Staging upload texture for compressed";
|
|
831 |
LoadInfo.Name = "Staging compressed upload texture";
|
831 | 832 |
LoadInfo.Usage = USAGE_STAGING;
|
832 | 833 |
LoadInfo.BindFlags = BIND_NONE;
|
833 | 834 |
LoadInfo.CPUAccessFlags = CPU_ACCESS_WRITE;
|
834 | 835 |
}
|
|
836 |
else
|
|
837 |
{
|
|
838 |
LoadInfo.Name = "Compressed texture for GLTF model";
|
|
839 |
}
|
835 | 840 |
switch (gltf_image.pixel_type)
|
836 | 841 |
{
|
837 | 842 |
case IMAGE_FILE_FORMAT_DDS:
|
|
856 | 861 |
|
857 | 862 |
pTexInitData->pStagingTex = std::move(pStagingTex);
|
858 | 863 |
|
859 | |
// Init data will be atomically set in the allocation before any other thread may be able to
|
860 | |
// get access to it.
|
861 | |
// Note that it is possible that more than one thread prepares pInitData for the same allocation.
|
|
864 |
// pTexInitData will be atomically set in the allocation before any other thread may be able to
|
|
865 |
// access it.
|
|
866 |
// Note that it is possible that more than one thread prepares pTexInitData for the same allocation.
|
862 | 867 |
// It it also possible that multiple instances of the same allocation are created before the first
|
863 | 868 |
// is added to the cache. This is all OK though.
|
864 | 869 |
TexInfo.pAtlasSuballocation = pResourceMgr->AllocateTextureSpace(TexDesc.Format, TexDesc.Width, TexDesc.Height, CacheId.c_str(), pTexInitData);
|
|
912 | 917 |
|
913 | 918 |
for (Uint32 i = 0; i < Textures.size(); ++i)
|
914 | 919 |
{
|
915 | |
auto& DstTexInfo = Textures[i];
|
916 | |
|
917 | |
ITexture* pTexture = nullptr;
|
918 | |
TextureInitData* pInitData = nullptr;
|
|
920 |
auto& DstTexInfo = Textures[i];
|
|
921 |
ITexture* pTexture = nullptr;
|
|
922 |
|
|
923 |
RefCntAutoPtr<TextureInitData> pInitData;
|
919 | 924 |
if (DstTexInfo.pAtlasSuballocation)
|
920 | 925 |
{
|
921 | 926 |
pTexture = DstTexInfo.pAtlasSuballocation->GetAtlas()->GetTexture(pDevice, pCtx);
|
922 | 927 |
pInitData = ValidatedCast<TextureInitData>(DstTexInfo.pAtlasSuballocation->GetUserData());
|
|
928 |
// User data is only set when the allocation is created, so no other
|
|
929 |
// thread can call SetUserData() in parallel.
|
|
930 |
DstTexInfo.pAtlasSuballocation->SetUserData(nullptr);
|
923 | 931 |
}
|
924 | 932 |
else if (DstTexInfo.pTexture)
|
925 | 933 |
{
|
926 | 934 |
pTexture = DstTexInfo.pTexture;
|
927 | 935 |
pInitData = ValidatedCast<TextureInitData>(pTexture->GetUserData());
|
|
936 |
// User data is only set when the texture is created, so no other
|
|
937 |
// thread can call SetUserData() in parallel.
|
|
938 |
pTexture->SetUserData(nullptr);
|
928 | 939 |
}
|
929 | 940 |
|
930 | 941 |
if (!pTexture)
|
|
932 | 943 |
|
933 | 944 |
if (pInitData == nullptr)
|
934 | 945 |
{
|
935 | |
// Texture data has already been initialized by another model
|
|
946 |
// Shared texture has already been initialized by another model
|
936 | 947 |
continue;
|
937 | 948 |
}
|
938 | 949 |
|
|
1000 | 1011 |
// Texture is already initialized
|
1001 | 1012 |
}
|
1002 | 1013 |
|
1003 | |
if (DstTexInfo.pAtlasSuballocation)
|
1004 | |
{
|
1005 | |
// User data is only set when the allocation is created, so no other
|
1006 | |
// threads can call SetUserData().
|
1007 | |
DstTexInfo.pAtlasSuballocation->SetUserData(nullptr);
|
1008 | |
}
|
1009 | |
else if (DstTexInfo.pTexture)
|
1010 | |
{
|
|
1014 |
if (DstTexInfo.pTexture)
|
|
1015 |
{
|
|
1016 |
// Note that we may need to transition a texture even if it has been fully initialized,
|
|
1017 |
// as is the case with KTX/DDS textures.
|
1011 | 1018 |
VERIFY_EXPR(pTexture == DstTexInfo.pTexture);
|
1012 | 1019 |
Barriers.emplace_back(StateTransitionDesc{pTexture, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_SHADER_RESOURCE, true});
|
1013 | |
|
1014 | |
// User data is only set when the texture is created, so no other
|
1015 | |
// threads can call SetUserData().
|
1016 | |
pTexture->SetUserData(nullptr);
|
1017 | 1020 |
}
|
1018 | 1021 |
}
|
1019 | 1022 |
|
|
1435 | 1438 |
Model::TextureCacheType* const pTextureCache;
|
1436 | 1439 |
ResourceManager* const pResourceMgr;
|
1437 | 1440 |
|
1438 | |
std::vector<RefCntAutoPtr<ITexture>> TextureHold;
|
1439 | |
std::vector<RefCntAutoPtr<ITextureAtlasSuballocation>> TextureAllocationsHold;
|
|
1441 |
std::vector<RefCntAutoPtr<IObject>> TexturesHold;
|
1440 | 1442 |
|
1441 | 1443 |
std::string BaseDir;
|
1442 | 1444 |
};
|
|
1475 | 1477 |
gltf_image->pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
|
1476 | 1478 |
|
1477 | 1479 |
// Keep strong reference to ensure the allocation is alive (second time, but that's fine).
|
1478 | |
pLoaderData->TextureAllocationsHold.emplace_back(std::move(pAllocation));
|
|
1480 |
pLoaderData->TexturesHold.emplace_back(std::move(pAllocation));
|
1479 | 1481 |
|
1480 | 1482 |
return true;
|
1481 | 1483 |
}
|
|
1501 | 1503 |
gltf_image->pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
|
1502 | 1504 |
|
1503 | 1505 |
// Keep strong reference to ensure the texture is alive (second time, but that's fine).
|
1504 | |
pLoaderData->TextureHold.emplace_back(std::move(pTexture));
|
|
1506 |
pLoaderData->TexturesHold.emplace_back(std::move(pTexture));
|
1505 | 1507 |
|
1506 | 1508 |
return true;
|
1507 | 1509 |
}
|
|
1643 | 1645 |
if (auto pAllocation = pLoaderData->pResourceMgr->FindAllocation(filepath.c_str()))
|
1644 | 1646 |
{
|
1645 | 1647 |
// Keep strong reference to ensure the allocation is alive.
|
1646 | |
pLoaderData->TextureAllocationsHold.emplace_back(std::move(pAllocation));
|
|
1648 |
pLoaderData->TexturesHold.emplace_back(std::move(pAllocation));
|
1647 | 1649 |
// Tiny GLTF checks the size of 'out', it can't be empty
|
1648 | 1650 |
out->resize(1);
|
1649 | 1651 |
return true;
|
|
1659 | 1661 |
if (auto pTexture = it->second.Lock())
|
1660 | 1662 |
{
|
1661 | 1663 |
// Keep strong reference to ensure the texture is alive.
|
1662 | |
pLoaderData->TextureHold.emplace_back(std::move(pTexture));
|
|
1664 |
pLoaderData->TexturesHold.emplace_back(std::move(pTexture));
|
1663 | 1665 |
// Tiny GLTF checks the size of 'out', it can't be empty
|
1664 | 1666 |
out->resize(1);
|
1665 | 1667 |
return true;
|
|
1765 | 1767 |
for (size_t i = 0; i < scene.nodes.size(); i++)
|
1766 | 1768 |
{
|
1767 | 1769 |
const tinygltf::Node node = gltf_model.nodes[scene.nodes[i]];
|
1768 | |
LoadNode(pDevice, nullptr, node, scene.nodes[i], gltf_model,
|
|
1770 |
LoadNode(nullptr, node, scene.nodes[i], gltf_model,
|
1769 | 1771 |
IndexData, VertexBasicData,
|
1770 | 1772 |
CI.LoadAnimationAndSkin ? &VertexSkinData : nullptr);
|
1771 | 1773 |
}
|