2016-08-22 21:17:57 +03:00
|
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
// File: ModelLoadSDKMESH.cpp
|
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
2018-02-24 09:08:23 +03:00
|
|
|
// Licensed under the MIT License.
|
2016-08-22 21:17:57 +03:00
|
|
|
//
|
|
|
|
// http://go.microsoft.com/fwlink/?LinkID=615561
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#include "Model.h"
|
|
|
|
|
|
|
|
#include "Effects.h"
|
|
|
|
#include "VertexTypes.h"
|
|
|
|
|
|
|
|
#include "DirectXHelpers.h"
|
|
|
|
#include "PlatformHelpers.h"
|
|
|
|
#include "BinaryReader.h"
|
|
|
|
#include "DescriptorHeap.h"
|
|
|
|
#include "CommonStates.h"
|
|
|
|
|
|
|
|
#include "SDKMesh.h"
|
|
|
|
|
|
|
|
using namespace DirectX;
|
|
|
|
using Microsoft::WRL::ComPtr;
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
2016-10-06 00:35:54 +03:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
PER_VERTEX_COLOR = 0x1,
|
|
|
|
SKINNING = 0x2,
|
|
|
|
DUAL_TEXTURE = 0x4,
|
|
|
|
NORMAL_MAPS = 0x8,
|
|
|
|
BIASED_VERTEX_NORMALS = 0x10,
|
|
|
|
};
|
|
|
|
|
2016-08-22 21:17:57 +03:00
|
|
|
int GetUniqueTextureIndex(const wchar_t* textureName, std::map<std::wstring, int>& textureDictionary)
|
|
|
|
{
|
|
|
|
if (textureName == nullptr || !textureName[0])
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
auto i = textureDictionary.find(textureName);
|
|
|
|
if (i == std::cend(textureDictionary))
|
|
|
|
{
|
|
|
|
int index = static_cast<int>(textureDictionary.size());
|
|
|
|
textureDictionary[textureName] = index;
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return i->second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InitMaterial(
|
|
|
|
const DXUT::SDKMESH_MATERIAL& mh,
|
2016-10-06 00:35:54 +03:00
|
|
|
unsigned int flags,
|
2016-08-22 21:17:57 +03:00
|
|
|
_Out_ Model::ModelMaterialInfo& m,
|
|
|
|
_Inout_ std::map<std::wstring, int32_t>& textureDictionary)
|
|
|
|
{
|
|
|
|
wchar_t matName[DXUT::MAX_MATERIAL_NAME];
|
|
|
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mh.Name, -1, matName, DXUT::MAX_MATERIAL_NAME);
|
|
|
|
|
|
|
|
wchar_t diffuseName[DXUT::MAX_TEXTURE_NAME];
|
|
|
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mh.DiffuseTexture, -1, diffuseName, DXUT::MAX_TEXTURE_NAME);
|
|
|
|
|
|
|
|
wchar_t specularName[DXUT::MAX_TEXTURE_NAME];
|
|
|
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mh.SpecularTexture, -1, specularName, DXUT::MAX_TEXTURE_NAME);
|
|
|
|
|
|
|
|
wchar_t normalName[DXUT::MAX_TEXTURE_NAME];
|
|
|
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mh.NormalTexture, -1, normalName, DXUT::MAX_TEXTURE_NAME);
|
|
|
|
|
2016-10-06 00:35:54 +03:00
|
|
|
if ((flags & DUAL_TEXTURE) && !mh.SpecularTexture[0])
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
|
|
|
DebugTrace("WARNING: Material '%s' has multiple texture coords but not multiple textures\n", mh.Name);
|
2016-10-06 00:35:54 +03:00
|
|
|
flags &= ~DUAL_TEXTURE;
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
|
2016-10-06 00:35:54 +03:00
|
|
|
if (flags & NORMAL_MAPS)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
|
|
|
if (!mh.NormalTexture[0])
|
|
|
|
{
|
2016-10-06 00:35:54 +03:00
|
|
|
flags &= ~NORMAL_MAPS;
|
2016-08-22 21:17:57 +03:00
|
|
|
*normalName = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (mh.NormalTexture[0])
|
|
|
|
{
|
|
|
|
DebugTrace("WARNING: Material '%s' has a normal map, but vertex buffer is missing tangents\n", mh.Name);
|
|
|
|
*normalName = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
m = {};
|
|
|
|
m.name = matName;
|
2016-10-06 00:35:54 +03:00
|
|
|
m.perVertexColor = (flags & PER_VERTEX_COLOR) != 0;
|
|
|
|
m.enableSkinning = (flags & SKINNING) != 0;
|
|
|
|
m.enableDualTexture = (flags & DUAL_TEXTURE) != 0;
|
|
|
|
m.enableNormalMaps = (flags & NORMAL_MAPS) != 0;
|
|
|
|
m.biasedVertexNormals = (flags & BIASED_VERTEX_NORMALS) != 0;
|
|
|
|
|
2017-06-08 02:30:35 +03:00
|
|
|
if (mh.Ambient.x == 0 && mh.Ambient.y == 0 && mh.Ambient.z == 0 && mh.Ambient.w == 0
|
|
|
|
&& mh.Diffuse.x == 0 && mh.Diffuse.y == 0 && mh.Diffuse.z == 0 && mh.Diffuse.w == 0)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2017-06-08 02:30:35 +03:00
|
|
|
// SDKMESH material color block is uninitalized; assume defaults
|
|
|
|
m.diffuseColor = XMFLOAT3(1.f, 1.f, 1.f);
|
|
|
|
m.alphaValue = 1.f;
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-06-08 02:30:35 +03:00
|
|
|
m.ambientColor = XMFLOAT3(mh.Ambient.x, mh.Ambient.y, mh.Ambient.z);
|
|
|
|
m.diffuseColor = XMFLOAT3(mh.Diffuse.x, mh.Diffuse.y, mh.Diffuse.z);
|
|
|
|
m.emissiveColor = XMFLOAT3(mh.Emissive.x, mh.Emissive.y, mh.Emissive.z);
|
|
|
|
|
|
|
|
if (mh.Diffuse.w != 1.f && mh.Diffuse.w != 0.f)
|
|
|
|
{
|
|
|
|
m.alphaValue = mh.Diffuse.w;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m.alphaValue = 1.f;
|
|
|
|
|
|
|
|
if (mh.Power)
|
|
|
|
{
|
|
|
|
m.specularPower = mh.Power;
|
|
|
|
m.specularColor = XMFLOAT3(mh.Specular.x, mh.Specular.y, mh.Specular.z);
|
|
|
|
}
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
m.diffuseTextureIndex = GetUniqueTextureIndex(diffuseName, textureDictionary);
|
|
|
|
m.specularTextureIndex = GetUniqueTextureIndex(specularName, textureDictionary);
|
|
|
|
m.normalTextureIndex = GetUniqueTextureIndex(normalName, textureDictionary);
|
|
|
|
|
|
|
|
m.samplerIndex = (m.diffuseTextureIndex == -1) ? -1 : static_cast<int>(CommonStates::SamplerIndex::AnisotropicWrap);
|
2016-10-06 00:35:54 +03:00
|
|
|
m.samplerIndex2 = (flags & DUAL_TEXTURE) ? static_cast<int>(CommonStates::SamplerIndex::AnisotropicWrap) : -1;
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
// Direct3D 9 Vertex Declaration to Direct3D 12 Input Layout mapping
|
|
|
|
|
2016-10-06 00:35:54 +03:00
|
|
|
unsigned int GetInputLayoutDesc(
|
|
|
|
_In_reads_(32) const DXUT::D3DVERTEXELEMENT9 decl[],
|
|
|
|
std::vector<D3D12_INPUT_ELEMENT_DESC>& inputDesc)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2016-09-29 05:46:31 +03:00
|
|
|
static const D3D12_INPUT_ELEMENT_DESC s_elements[] =
|
2018-03-16 22:03:02 +03:00
|
|
|
{
|
|
|
|
{ "SV_Position", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
|
|
|
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
|
|
|
{ "COLOR", 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
|
|
|
{ "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
|
|
|
{ "BINORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
|
|
|
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
|
|
|
{ "BLENDINDICES", 0, DXGI_FORMAT_R8G8B8A8_UINT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
|
|
|
{ "BLENDWEIGHT", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
2016-08-22 21:17:57 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
using namespace DXUT;
|
|
|
|
|
|
|
|
uint32_t offset = 0;
|
|
|
|
uint32_t texcoords = 0;
|
2016-10-06 00:35:54 +03:00
|
|
|
unsigned int flags = 0;
|
2016-08-22 21:17:57 +03:00
|
|
|
|
|
|
|
bool posfound = false;
|
|
|
|
|
|
|
|
for (uint32_t index = 0; index < DXUT::MAX_VERTEX_ELEMENTS; ++index)
|
|
|
|
{
|
|
|
|
if (decl[index].Usage == 0xFF)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (decl[index].Type == D3DDECLTYPE_UNUSED)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (decl[index].Offset != offset)
|
|
|
|
break;
|
|
|
|
|
2016-09-29 05:46:31 +03:00
|
|
|
if (decl[index].Usage == D3DDECLUSAGE_POSITION)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
|
|
|
if (decl[index].Type == D3DDECLTYPE_FLOAT3)
|
|
|
|
{
|
2016-09-29 05:46:31 +03:00
|
|
|
inputDesc.push_back(s_elements[0]);
|
2016-08-22 21:17:57 +03:00
|
|
|
offset += 12;
|
2016-09-29 05:46:31 +03:00
|
|
|
posfound = true;
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
2016-09-29 05:46:31 +03:00
|
|
|
else if (decl[index].Usage == D3DDECLUSAGE_NORMAL
|
|
|
|
|| decl[index].Usage == D3DDECLUSAGE_TANGENT
|
|
|
|
|| decl[index].Usage == D3DDECLUSAGE_BINORMAL)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2016-09-29 05:46:31 +03:00
|
|
|
size_t base = 1;
|
|
|
|
if (decl[index].Usage == D3DDECLUSAGE_TANGENT)
|
|
|
|
base = 3;
|
|
|
|
else if (decl[index].Usage == D3DDECLUSAGE_BINORMAL)
|
|
|
|
base = 4;
|
|
|
|
|
|
|
|
D3D12_INPUT_ELEMENT_DESC desc = s_elements[base];
|
|
|
|
|
|
|
|
bool unk = false;
|
|
|
|
switch (decl[index].Type)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
case D3DDECLTYPE_FLOAT3: assert(desc.Format == DXGI_FORMAT_R32G32B32_FLOAT); offset += 12; break;
|
|
|
|
case D3DDECLTYPE_UBYTE4N: desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; flags |= BIASED_VERTEX_NORMALS; offset += 4; break;
|
|
|
|
case D3DDECLTYPE_SHORT4N: desc.Format = DXGI_FORMAT_R16G16B16A16_SNORM; offset += 8; break;
|
|
|
|
case D3DDECLTYPE_FLOAT16_4: desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; offset += 8; break;
|
|
|
|
case D3DDECLTYPE_DXGI_R10G10B10A2_UNORM: desc.Format = DXGI_FORMAT_R10G10B10A2_UNORM; flags |= BIASED_VERTEX_NORMALS; offset += 4; break;
|
|
|
|
case D3DDECLTYPE_DXGI_R11G11B10_FLOAT: desc.Format = DXGI_FORMAT_R11G11B10_FLOAT; flags |= BIASED_VERTEX_NORMALS; offset += 4; break;
|
|
|
|
case D3DDECLTYPE_DXGI_R8G8B8A8_SNORM: desc.Format = DXGI_FORMAT_R8G8B8A8_SNORM; offset += 4; break;
|
|
|
|
|
|
|
|
#if defined(_XBOX_ONE) && defined(_TITLE)
|
|
|
|
case (32 + DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM): desc.Format = DXGI_FORMAT_R10G10B10_SNORM_A2_UNORM; offset += 4; break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
default:
|
|
|
|
unk = true;
|
|
|
|
break;
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
2016-09-29 05:46:31 +03:00
|
|
|
|
|
|
|
if (unk)
|
2016-08-22 21:17:57 +03:00
|
|
|
break;
|
2016-09-29 05:46:31 +03:00
|
|
|
|
|
|
|
if (decl[index].Usage == D3DDECLUSAGE_TANGENT)
|
2016-10-06 00:35:54 +03:00
|
|
|
{
|
|
|
|
flags |= NORMAL_MAPS;
|
|
|
|
}
|
2016-09-29 05:46:31 +03:00
|
|
|
|
|
|
|
inputDesc.push_back(desc);
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
2016-09-29 05:46:31 +03:00
|
|
|
else if (decl[index].Usage == D3DDECLUSAGE_COLOR)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2016-09-29 05:46:31 +03:00
|
|
|
D3D12_INPUT_ELEMENT_DESC desc = s_elements[2];
|
|
|
|
|
|
|
|
bool unk = false;
|
|
|
|
switch (decl[index].Type)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
case D3DDECLTYPE_FLOAT4: desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; offset += 16; break;
|
|
|
|
case D3DDECLTYPE_D3DCOLOR: assert(desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM); offset += 4; break;
|
|
|
|
case D3DDECLTYPE_UBYTE4N: desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; offset += 4; break;
|
|
|
|
case D3DDECLTYPE_FLOAT16_4: desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; offset += 8; break;
|
|
|
|
case D3DDECLTYPE_DXGI_R10G10B10A2_UNORM: desc.Format = DXGI_FORMAT_R10G10B10A2_UNORM; offset += 4; break;
|
|
|
|
case D3DDECLTYPE_DXGI_R11G11B10_FLOAT: desc.Format = DXGI_FORMAT_R11G11B10_FLOAT; offset += 4; break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
unk = true;
|
|
|
|
break;
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
2016-09-29 05:46:31 +03:00
|
|
|
|
|
|
|
if (unk)
|
2016-08-22 21:17:57 +03:00
|
|
|
break;
|
2016-09-29 05:46:31 +03:00
|
|
|
|
2016-10-06 00:35:54 +03:00
|
|
|
flags |= PER_VERTEX_COLOR;
|
2016-09-29 05:46:31 +03:00
|
|
|
|
|
|
|
inputDesc.push_back(desc);
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
else if (decl[index].Usage == D3DDECLUSAGE_TEXCOORD)
|
|
|
|
{
|
2016-09-29 05:46:31 +03:00
|
|
|
D3D12_INPUT_ELEMENT_DESC desc = s_elements[5];
|
2016-08-22 21:17:57 +03:00
|
|
|
desc.SemanticIndex = decl[index].UsageIndex;
|
|
|
|
|
|
|
|
bool unk = false;
|
|
|
|
switch (decl[index].Type)
|
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
case D3DDECLTYPE_FLOAT1: desc.Format = DXGI_FORMAT_R32_FLOAT; offset += 4; break;
|
|
|
|
case D3DDECLTYPE_FLOAT2: assert(desc.Format == DXGI_FORMAT_R32G32_FLOAT); offset += 8; break;
|
|
|
|
case D3DDECLTYPE_FLOAT3: desc.Format = DXGI_FORMAT_R32G32B32_FLOAT; offset += 12; break;
|
|
|
|
case D3DDECLTYPE_FLOAT4: desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; offset += 16; break;
|
|
|
|
case D3DDECLTYPE_FLOAT16_2: desc.Format = DXGI_FORMAT_R16G16_FLOAT; offset += 4; break;
|
|
|
|
case D3DDECLTYPE_FLOAT16_4: desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; offset += 8; break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
unk = true;
|
|
|
|
break;
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (unk)
|
|
|
|
break;
|
|
|
|
|
|
|
|
++texcoords;
|
|
|
|
|
|
|
|
inputDesc.push_back(desc);
|
|
|
|
}
|
2016-09-29 05:46:31 +03:00
|
|
|
else if (decl[index].Usage == D3DDECLUSAGE_BLENDINDICES)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2016-09-29 05:46:31 +03:00
|
|
|
if (decl[index].Type == D3DDECLTYPE_UBYTE4)
|
|
|
|
{
|
2016-10-06 00:35:54 +03:00
|
|
|
flags |= SKINNING;
|
2016-09-29 05:46:31 +03:00
|
|
|
inputDesc.push_back(s_elements[6]);
|
|
|
|
offset += 4;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
2016-09-29 05:46:31 +03:00
|
|
|
else if (decl[index].Usage == D3DDECLUSAGE_BLENDWEIGHT)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2016-09-29 05:46:31 +03:00
|
|
|
if (decl[index].Type == D3DDECLTYPE_UBYTE4N)
|
|
|
|
{
|
2016-10-06 00:35:54 +03:00
|
|
|
flags |= SKINNING;
|
2016-09-29 05:46:31 +03:00
|
|
|
inputDesc.push_back(s_elements[7]);
|
|
|
|
offset += 4;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!posfound)
|
|
|
|
throw std::exception("SV_Position is required");
|
|
|
|
|
|
|
|
if (texcoords == 2)
|
|
|
|
{
|
2016-10-06 00:35:54 +03:00
|
|
|
flags |= DUAL_TEXTURE;
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
2016-10-06 00:35:54 +03:00
|
|
|
|
|
|
|
return flags;
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//======================================================================================
|
|
|
|
// Model Loader
|
|
|
|
//======================================================================================
|
|
|
|
|
|
|
|
_Use_decl_annotations_
|
2018-03-16 22:03:02 +03:00
|
|
|
std::unique_ptr<Model> DirectX::Model::CreateFromSDKMESH(const uint8_t* meshData, size_t dataSize)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
if (!meshData)
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("meshData cannot be null");
|
|
|
|
|
|
|
|
// File Headers
|
2018-03-16 22:03:02 +03:00
|
|
|
if (dataSize < sizeof(DXUT::SDKMESH_HEADER))
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("End of file");
|
2018-03-16 22:03:02 +03:00
|
|
|
auto header = reinterpret_cast<const DXUT::SDKMESH_HEADER*>(meshData);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
size_t headerSize = sizeof(DXUT::SDKMESH_HEADER)
|
|
|
|
+ header->NumVertexBuffers * sizeof(DXUT::SDKMESH_VERTEX_BUFFER_HEADER)
|
|
|
|
+ header->NumIndexBuffers * sizeof(DXUT::SDKMESH_INDEX_BUFFER_HEADER);
|
|
|
|
if (header->HeaderSize != headerSize)
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("Not a valid SDKMESH file");
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (dataSize < header->HeaderSize)
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("End of file");
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (header->Version != DXUT::SDKMESH_FILE_VERSION)
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("Not a supported SDKMESH version");
|
2018-03-16 22:03:02 +03:00
|
|
|
|
|
|
|
if (header->IsBigEndian)
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("Loading BigEndian SDKMESH files not supported");
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (!header->NumMeshes)
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("No meshes found");
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (!header->NumVertexBuffers)
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("No vertex buffers found");
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (!header->NumIndexBuffers)
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("No index buffers found");
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (!header->NumTotalSubsets)
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("No subsets found");
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (!header->NumMaterials)
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("No materials found");
|
|
|
|
|
|
|
|
// Sub-headers
|
2018-03-16 22:03:02 +03:00
|
|
|
if (dataSize < header->VertexStreamHeadersOffset
|
|
|
|
|| (dataSize < (header->VertexStreamHeadersOffset + header->NumVertexBuffers * sizeof(DXUT::SDKMESH_VERTEX_BUFFER_HEADER))))
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("End of file");
|
2018-03-16 22:03:02 +03:00
|
|
|
auto vbArray = reinterpret_cast<const DXUT::SDKMESH_VERTEX_BUFFER_HEADER*>(meshData + header->VertexStreamHeadersOffset);
|
|
|
|
|
|
|
|
if (dataSize < header->IndexStreamHeadersOffset
|
|
|
|
|| (dataSize < (header->IndexStreamHeadersOffset + header->NumIndexBuffers * sizeof(DXUT::SDKMESH_INDEX_BUFFER_HEADER))))
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("End of file");
|
2018-03-16 22:03:02 +03:00
|
|
|
auto ibArray = reinterpret_cast<const DXUT::SDKMESH_INDEX_BUFFER_HEADER*>(meshData + header->IndexStreamHeadersOffset);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (dataSize < header->MeshDataOffset
|
|
|
|
|| (dataSize < (header->MeshDataOffset + header->NumMeshes * sizeof(DXUT::SDKMESH_MESH))))
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("End of file");
|
2018-03-16 22:03:02 +03:00
|
|
|
auto meshArray = reinterpret_cast<const DXUT::SDKMESH_MESH*>(meshData + header->MeshDataOffset);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (dataSize < header->SubsetDataOffset
|
|
|
|
|| (dataSize < (header->SubsetDataOffset + header->NumTotalSubsets * sizeof(DXUT::SDKMESH_SUBSET))))
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("End of file");
|
2018-03-16 22:03:02 +03:00
|
|
|
auto subsetArray = reinterpret_cast<const DXUT::SDKMESH_SUBSET*>(meshData + header->SubsetDataOffset);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (dataSize < header->FrameDataOffset
|
|
|
|
|| (dataSize < (header->FrameDataOffset + header->NumFrames * sizeof(DXUT::SDKMESH_FRAME))))
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("End of file");
|
|
|
|
// TODO - auto frameArray = reinterpret_cast<const DXUT::SDKMESH_FRAME*>( meshData + header->FrameDataOffset );
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (dataSize < header->MaterialDataOffset
|
|
|
|
|| (dataSize < (header->MaterialDataOffset + header->NumMaterials * sizeof(DXUT::SDKMESH_MATERIAL))))
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("End of file");
|
2018-03-16 22:03:02 +03:00
|
|
|
auto materialArray = reinterpret_cast<const DXUT::SDKMESH_MATERIAL*>(meshData + header->MaterialDataOffset);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
|
|
|
// Buffer data
|
|
|
|
uint64_t bufferDataOffset = header->HeaderSize + header->NonBufferDataSize;
|
2018-03-16 22:03:02 +03:00
|
|
|
if ((dataSize < bufferDataOffset)
|
|
|
|
|| (dataSize < bufferDataOffset + header->BufferDataSize))
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("End of file");
|
2018-03-16 22:03:02 +03:00
|
|
|
const uint8_t* bufferData = meshData + bufferDataOffset;
|
2016-08-22 21:17:57 +03:00
|
|
|
|
|
|
|
// Create vertex buffers
|
|
|
|
std::vector<std::shared_ptr<std::vector<D3D12_INPUT_ELEMENT_DESC>>> vbDecls;
|
2018-03-16 22:03:02 +03:00
|
|
|
vbDecls.resize(header->NumVertexBuffers);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
2016-10-06 00:35:54 +03:00
|
|
|
std::vector<unsigned int> materialFlags;
|
|
|
|
materialFlags.resize(header->NumVertexBuffers);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
for (UINT j = 0; j < header->NumVertexBuffers; ++j)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
|
|
|
auto& vh = vbArray[j];
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (dataSize < vh.DataOffset
|
|
|
|
|| (dataSize < vh.DataOffset + vh.SizeBytes))
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("End of file");
|
|
|
|
|
|
|
|
vbDecls[j] = std::make_shared<std::vector<D3D12_INPUT_ELEMENT_DESC>>();
|
2016-10-06 00:35:54 +03:00
|
|
|
unsigned int flags = GetInputLayoutDesc(vh.Decl, *vbDecls[j].get());
|
|
|
|
|
|
|
|
if (flags & SKINNING)
|
|
|
|
{
|
|
|
|
flags &= ~(DUAL_TEXTURE | NORMAL_MAPS);
|
|
|
|
}
|
|
|
|
if (flags & DUAL_TEXTURE)
|
|
|
|
{
|
|
|
|
flags &= ~NORMAL_MAPS;
|
|
|
|
}
|
|
|
|
|
|
|
|
materialFlags[j] = flags;
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Validate index buffers
|
|
|
|
for (UINT j = 0; j < header->NumIndexBuffers; ++j)
|
|
|
|
{
|
|
|
|
auto& ih = ibArray[j];
|
|
|
|
|
|
|
|
if (dataSize < ih.DataOffset
|
|
|
|
|| (dataSize < ih.DataOffset + ih.SizeBytes))
|
|
|
|
throw std::exception("End of file");
|
|
|
|
|
|
|
|
if (ih.IndexType != DXUT::IT_16BIT && ih.IndexType != DXUT::IT_32BIT)
|
|
|
|
throw std::exception("Invalid index buffer type found");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create meshes
|
|
|
|
std::vector<ModelMaterialInfo> materials;
|
2018-03-16 22:03:02 +03:00
|
|
|
materials.resize(header->NumMaterials);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
|
|
|
std::map<std::wstring, int> textureDictionary;
|
|
|
|
|
|
|
|
std::unique_ptr<Model> model(new Model);
|
2018-03-16 22:03:02 +03:00
|
|
|
model->meshes.reserve(header->NumMeshes);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
|
|
|
uint32_t partCount = 0;
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
for (UINT meshIndex = 0; meshIndex < header->NumMeshes; ++meshIndex)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
auto& mh = meshArray[meshIndex];
|
2016-08-22 21:17:57 +03:00
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (!mh.NumSubsets
|
|
|
|
|| !mh.NumVertexBuffers
|
|
|
|
|| mh.IndexBuffer >= header->NumIndexBuffers
|
|
|
|
|| mh.VertexBuffers[0] >= header->NumVertexBuffers)
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("Invalid mesh found");
|
|
|
|
|
|
|
|
// mh.NumVertexBuffers is sometimes not what you'd expect, so we skip validating it
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (dataSize < mh.SubsetOffset
|
|
|
|
|| (dataSize < mh.SubsetOffset + mh.NumSubsets * sizeof(UINT)))
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("End of file");
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
auto subsets = reinterpret_cast<const UINT*>(meshData + mh.SubsetOffset);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (mh.NumFrameInfluences > 0)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
if (dataSize < mh.FrameInfluenceOffset
|
|
|
|
|| (dataSize < mh.FrameInfluenceOffset + mh.NumFrameInfluences * sizeof(UINT)))
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("End of file");
|
|
|
|
|
|
|
|
// TODO - auto influences = reinterpret_cast<const UINT*>( meshData + mh.FrameInfluenceOffset );
|
|
|
|
}
|
|
|
|
|
|
|
|
auto mesh = std::make_shared<ModelMesh>();
|
2018-03-16 22:03:02 +03:00
|
|
|
wchar_t meshName[DXUT::MAX_MESH_NAME];
|
|
|
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mh.Name, -1, meshName, DXUT::MAX_MESH_NAME);
|
2016-08-22 21:17:57 +03:00
|
|
|
mesh->name = meshName;
|
|
|
|
|
|
|
|
// Extents
|
|
|
|
mesh->boundingBox.Center = mh.BoundingBoxCenter;
|
|
|
|
mesh->boundingBox.Extents = mh.BoundingBoxExtents;
|
2018-03-16 22:03:02 +03:00
|
|
|
BoundingSphere::CreateFromBoundingBox(mesh->boundingSphere, mesh->boundingBox);
|
|
|
|
|
2016-08-22 21:17:57 +03:00
|
|
|
// Create subsets
|
2018-03-16 22:03:02 +03:00
|
|
|
for (UINT j = 0; j < mh.NumSubsets; ++j)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
auto sIndex = subsets[j];
|
|
|
|
if (sIndex >= header->NumTotalSubsets)
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("Invalid mesh found");
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
auto& subset = subsetArray[sIndex];
|
2016-08-22 21:17:57 +03:00
|
|
|
|
|
|
|
D3D_PRIMITIVE_TOPOLOGY primType;
|
2018-03-16 22:03:02 +03:00
|
|
|
switch (subset.PrimitiveType)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
case DXUT::PT_TRIANGLE_LIST: primType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; break;
|
|
|
|
case DXUT::PT_TRIANGLE_STRIP: primType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; break;
|
|
|
|
case DXUT::PT_LINE_LIST: primType = D3D_PRIMITIVE_TOPOLOGY_LINELIST; break;
|
|
|
|
case DXUT::PT_LINE_STRIP: primType = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; break;
|
|
|
|
case DXUT::PT_POINT_LIST: primType = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; break;
|
|
|
|
case DXUT::PT_TRIANGLE_LIST_ADJ: primType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ; break;
|
|
|
|
case DXUT::PT_TRIANGLE_STRIP_ADJ: primType = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ; break;
|
|
|
|
case DXUT::PT_LINE_LIST_ADJ: primType = D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; break;
|
|
|
|
case DXUT::PT_LINE_STRIP_ADJ: primType = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ; break;
|
|
|
|
|
|
|
|
case DXUT::PT_QUAD_PATCH_LIST:
|
|
|
|
case DXUT::PT_TRIANGLE_PATCH_LIST:
|
|
|
|
throw std::exception("Direct3D9 era tessellation not supported");
|
|
|
|
|
|
|
|
default:
|
|
|
|
throw std::exception("Unknown primitive type");
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
if (subset.MaterialID >= header->NumMaterials)
|
2016-08-22 21:17:57 +03:00
|
|
|
throw std::exception("Invalid mesh found");
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
auto& mat = materials[subset.MaterialID];
|
2016-08-22 21:17:57 +03:00
|
|
|
|
|
|
|
const size_t vi = mh.VertexBuffers[0];
|
2016-10-06 00:35:54 +03:00
|
|
|
InitMaterial(
|
|
|
|
materialArray[subset.MaterialID],
|
|
|
|
materialFlags[vi],
|
|
|
|
mat,
|
|
|
|
textureDictionary);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
|
|
|
auto part = new ModelMeshPart(partCount++);
|
|
|
|
|
|
|
|
const auto& vh = vbArray[mh.VertexBuffers[0]];
|
|
|
|
const auto& ih = ibArray[mh.IndexBuffer];
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
part->indexCount = static_cast<uint32_t>(subset.IndexCount);
|
|
|
|
part->startIndex = static_cast<uint32_t>(subset.IndexStart);
|
|
|
|
part->vertexOffset = static_cast<uint32_t>(subset.VertexStart);
|
|
|
|
part->vertexStride = static_cast<uint32_t>(vh.StrideBytes);
|
|
|
|
part->vertexCount = static_cast<uint32_t>(subset.VertexCount);
|
2016-09-27 02:53:46 +03:00
|
|
|
part->primitiveType = primType;
|
2018-03-16 22:03:02 +03:00
|
|
|
part->indexFormat = (ibArray[mh.IndexBuffer].IndexType == DXUT::IT_32BIT) ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT;
|
2016-08-22 21:17:57 +03:00
|
|
|
|
|
|
|
// Vertex data
|
2018-04-03 10:53:52 +03:00
|
|
|
auto verts = bufferData + (vh.DataOffset - bufferDataOffset);
|
2018-03-16 22:03:02 +03:00
|
|
|
part->vertexBuffer = GraphicsMemory::Get().Allocate((size_t)vh.SizeBytes);
|
|
|
|
memcpy(part->vertexBuffer.Memory(), verts, (size_t)vh.SizeBytes);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
|
|
|
// Index data
|
2018-04-03 10:53:52 +03:00
|
|
|
auto indices = bufferData + (ih.DataOffset - bufferDataOffset);
|
2018-03-16 22:03:02 +03:00
|
|
|
part->indexBuffer = GraphicsMemory::Get().Allocate((size_t)ih.SizeBytes);
|
|
|
|
memcpy(part->indexBuffer.Memory(), indices, (size_t)ih.SizeBytes);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
|
|
|
part->materialIndex = subset.MaterialID;
|
2018-03-16 22:03:02 +03:00
|
|
|
part->vbDecl = vbDecls[mh.VertexBuffers[0]];
|
2016-08-22 21:17:57 +03:00
|
|
|
|
|
|
|
if (mat.alphaValue < 1.0f)
|
2018-03-16 22:03:02 +03:00
|
|
|
mesh->alphaMeshParts.emplace_back(part);
|
2016-08-22 21:17:57 +03:00
|
|
|
else
|
2018-03-16 22:03:02 +03:00
|
|
|
mesh->opaqueMeshParts.emplace_back(part);
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
model->meshes.emplace_back(mesh);
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the materials and texture names into contiguous arrays
|
|
|
|
model->materials = std::move(materials);
|
|
|
|
model->textureNames.resize(textureDictionary.size());
|
|
|
|
for (auto texture = std::cbegin(textureDictionary); texture != std::cend(textureDictionary); ++texture)
|
|
|
|
{
|
|
|
|
model->textureNames[texture->second] = texture->first;
|
|
|
|
}
|
|
|
|
|
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
_Use_decl_annotations_
|
2018-03-16 22:03:02 +03:00
|
|
|
std::unique_ptr<Model> DirectX::Model::CreateFromSDKMESH(const wchar_t* szFileName)
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
|
|
|
size_t dataSize = 0;
|
|
|
|
std::unique_ptr<uint8_t[]> data;
|
2018-03-16 22:03:02 +03:00
|
|
|
HRESULT hr = BinaryReader::ReadEntireFile(szFileName, data, &dataSize);
|
|
|
|
if (FAILED(hr))
|
2016-08-22 21:17:57 +03:00
|
|
|
{
|
2018-03-16 22:03:02 +03:00
|
|
|
DebugTrace("CreateFromSDKMESH failed (%08X) loading '%ls'\n", hr, szFileName);
|
|
|
|
throw std::exception("CreateFromSDKMESH");
|
2016-08-22 21:17:57 +03:00
|
|
|
}
|
|
|
|
|
2018-03-16 22:03:02 +03:00
|
|
|
auto model = CreateFromSDKMESH(data.get(), dataSize);
|
2016-08-22 21:17:57 +03:00
|
|
|
|
|
|
|
model->name = szFileName;
|
|
|
|
|
|
|
|
return model;
|
|
|
|
}
|