lowpoly-walking-simulator/directx11_hellovr/DirectXTK/Src/ModelLoadSDKMESH.cpp

936 lines
34 KiB
C++
Raw Normal View History

2024-11-14 11:54:38 +00:00
//--------------------------------------------------------------------------------------
// File: ModelLoadSDKMESH.cpp
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// http://go.microsoft.com/fwlink/?LinkId=248929
//--------------------------------------------------------------------------------------
#include "pch.h"
#include "Model.h"
#include "Effects.h"
#include "VertexTypes.h"
#include "DirectXHelpers.h"
#include "PlatformHelpers.h"
#include "BinaryReader.h"
using namespace DirectX;
using Microsoft::WRL::ComPtr;
#pragma warning(disable : 4121)
//--------------------------------------------------------------------------------------
// SDKMESH format is generated by the legacy DirectX SDK's Content Exporter and
// originally rendered by the DXUT helper class SDKMesh
//
// http://go.microsoft.com/fwlink/?LinkId=226208
//--------------------------------------------------------------------------------------
namespace DXUT
{
// .SDKMESH files
// SDKMESH_HEADER
// SDKMESH_VERTEX_BUFFER_HEADER header->VertexStreamHeadersOffset
// SDKMESH_INDEX_BUFFER_HEADER header->IndexStreamHeadersOffset
// SDKMESH_MESH header->MeshDataOffset
// SDKMESH_SUBSET header->SubsetDataOffset
// SDKMESH_FRAME header->FrameDataOffset
// SDKMESH_MATERIAL header->MaterialDataOffset
// [header->NonBufferDataSize]
// { [ header->NumVertexBuffers]
// VB data
// }
// { [ header->NumIndexBuffers]
// IB data
// }
// .SDDKANIM files
// SDKANIMATION_FILE_HEADER
// BYTE[] - Length of fileheader->AnimationDataSize
// .SDKMESH uses Direct3D 9 decls, but only a subset of these is ever generated by the legacy DirectX SDK Content Exporter
// D3DDECLUSAGE_POSITION / D3DDECLTYPE_FLOAT3
// (D3DDECLUSAGE_BLENDWEIGHT / D3DDECLTYPE_UBYTE4N
// D3DDECLUSAGE_BLENDINDICES / D3DDECLTYPE_UBYTE4)?
// (D3DDECLUSAGE_NORMAL / D3DDECLTYPE_FLOAT3, D3DDECLTYPE_FLOAT16_4, D3DDECLTYPE_SHORT4N, D3DDECLTYPE_UBYTE4N, or D3DDECLTYPE_DEC3N [not supported])?
// (D3DDECLUSAGE_COLOR / D3DDECLTYPE_D3DCOLOR)?
// (D3DDECLUSAGE_TEXCOORD / D3DDECLTYPE_FLOAT1, D3DDECLTYPE_FLOAT2 or D3DDECLTYPE_FLOAT16_2, D3DDECLTYPE_FLOAT3 or D3DDECLTYPE_FLOAT16_4, D3DDECLTYPE_FLOAT4 or D3DDECLTYPE_FLOAT16_4)*
// (D3DDECLUSAGE_TANGENT / same as D3DDECLUSAGE_NORMAL)?
// (D3DDECLUSAGE_BINORMAL / same as D3DDECLUSAGE_NORMAL)?
enum D3DDECLUSAGE
{
D3DDECLUSAGE_POSITION = 0,
D3DDECLUSAGE_BLENDWEIGHT =1,
D3DDECLUSAGE_BLENDINDICES =2,
D3DDECLUSAGE_NORMAL =3,
D3DDECLUSAGE_TEXCOORD = 5,
D3DDECLUSAGE_TANGENT = 6,
D3DDECLUSAGE_BINORMAL = 7,
D3DDECLUSAGE_COLOR = 10,
};
enum D3DDECLTYPE
{
D3DDECLTYPE_FLOAT1 = 0, // 1D float expanded to (value, 0., 0., 1.)
D3DDECLTYPE_FLOAT2 = 1, // 2D float expanded to (value, value, 0., 1.)
D3DDECLTYPE_FLOAT3 = 2, // 3D float expanded to (value, value, value, 1.)
D3DDECLTYPE_FLOAT4 = 3, // 4D float
D3DDECLTYPE_D3DCOLOR = 4, // 4D packed unsigned bytes mapped to 0. to 1. range
// Input is in D3DCOLOR format (ARGB) expanded to (R, G, B, A)
D3DDECLTYPE_UBYTE4 = 5, // 4D unsigned byte
D3DDECLTYPE_UBYTE4N = 8, // Each of 4 bytes is normalized by dividing to 255.0
D3DDECLTYPE_SHORT4N = 10, // 4D signed short normalized (v[0]/32767.0,v[1]/32767.0,v[2]/32767.0,v[3]/32767.0)
// Note: There is no equivalent to D3DDECLTYPE_DEC3N (14) as a DXGI_FORMAT
D3DDECLTYPE_FLOAT16_2 = 15, // Two 16-bit floating point values, expanded to (value, value, 0, 1)
D3DDECLTYPE_FLOAT16_4 = 16, // Four 16-bit floating point values
D3DDECLTYPE_UNUSED = 17, // When the type field in a decl is unused.
};
#pragma pack(push,4)
struct D3DVERTEXELEMENT9
{
WORD Stream; // Stream index
WORD Offset; // Offset in the stream in bytes
BYTE Type; // Data type
BYTE Method; // Processing method
BYTE Usage; // Semantics
BYTE UsageIndex; // Semantic index
};
#pragma pack(pop)
//--------------------------------------------------------------------------------------
// Hard Defines for the various structures
//--------------------------------------------------------------------------------------
const uint32_t SDKMESH_FILE_VERSION = 101;
const uint32_t MAX_VERTEX_ELEMENTS = 32;
const uint32_t MAX_VERTEX_STREAMS = 16;
const uint32_t MAX_FRAME_NAME = 100;
const uint32_t MAX_MESH_NAME = 100;
const uint32_t MAX_SUBSET_NAME = 100;
const uint32_t MAX_MATERIAL_NAME = 100;
const uint32_t MAX_TEXTURE_NAME = MAX_PATH;
const uint32_t MAX_MATERIAL_PATH = MAX_PATH;
const uint32_t INVALID_FRAME = uint32_t(-1);
const uint32_t INVALID_MESH = uint32_t(-1);
const uint32_t INVALID_MATERIAL = uint32_t(-1);
const uint32_t INVALID_SUBSET = uint32_t(-1);
const uint32_t INVALID_ANIMATION_DATA = uint32_t(-1);
const uint32_t INVALID_SAMPLER_SLOT = uint32_t(-1);
const uint32_t ERROR_RESOURCE_VALUE = 1;
template<typename TYPE> bool IsErrorResource( TYPE data )
{
if( ( TYPE )ERROR_RESOURCE_VALUE == data )
return true;
return false;
}
//--------------------------------------------------------------------------------------
// Enumerated Types. These will have mirrors in both D3D9 and D3D11
//--------------------------------------------------------------------------------------
enum SDKMESH_PRIMITIVE_TYPE
{
PT_TRIANGLE_LIST = 0,
PT_TRIANGLE_STRIP,
PT_LINE_LIST,
PT_LINE_STRIP,
PT_POINT_LIST,
PT_TRIANGLE_LIST_ADJ,
PT_TRIANGLE_STRIP_ADJ,
PT_LINE_LIST_ADJ,
PT_LINE_STRIP_ADJ,
PT_QUAD_PATCH_LIST,
PT_TRIANGLE_PATCH_LIST,
};
enum SDKMESH_INDEX_TYPE
{
IT_16BIT = 0,
IT_32BIT,
};
enum FRAME_TRANSFORM_TYPE
{
FTT_RELATIVE = 0,
FTT_ABSOLUTE, //This is not currently used but is here to support absolute transformations in the future
};
//--------------------------------------------------------------------------------------
// Structures.
//--------------------------------------------------------------------------------------
#pragma pack(push,8)
struct SDKMESH_HEADER
{
//Basic Info and sizes
UINT Version;
BYTE IsBigEndian;
UINT64 HeaderSize;
UINT64 NonBufferDataSize;
UINT64 BufferDataSize;
//Stats
UINT NumVertexBuffers;
UINT NumIndexBuffers;
UINT NumMeshes;
UINT NumTotalSubsets;
UINT NumFrames;
UINT NumMaterials;
//Offsets to Data
UINT64 VertexStreamHeadersOffset;
UINT64 IndexStreamHeadersOffset;
UINT64 MeshDataOffset;
UINT64 SubsetDataOffset;
UINT64 FrameDataOffset;
UINT64 MaterialDataOffset;
};
struct SDKMESH_VERTEX_BUFFER_HEADER
{
UINT64 NumVertices;
UINT64 SizeBytes;
UINT64 StrideBytes;
D3DVERTEXELEMENT9 Decl[MAX_VERTEX_ELEMENTS];
union
{
UINT64 DataOffset;
ID3D11Buffer* pVB11;
};
};
struct SDKMESH_INDEX_BUFFER_HEADER
{
UINT64 NumIndices;
UINT64 SizeBytes;
UINT IndexType;
union
{
UINT64 DataOffset;
ID3D11Buffer* pIB11;
};
};
struct SDKMESH_MESH
{
char Name[MAX_MESH_NAME];
BYTE NumVertexBuffers;
UINT VertexBuffers[MAX_VERTEX_STREAMS];
UINT IndexBuffer;
UINT NumSubsets;
UINT NumFrameInfluences; //aka bones
DirectX::XMFLOAT3 BoundingBoxCenter;
DirectX::XMFLOAT3 BoundingBoxExtents;
union
{
UINT64 SubsetOffset;
INT* pSubsets;
};
union
{
UINT64 FrameInfluenceOffset;
UINT* pFrameInfluences;
};
};
struct SDKMESH_SUBSET
{
char Name[MAX_SUBSET_NAME];
UINT MaterialID;
UINT PrimitiveType;
UINT64 IndexStart;
UINT64 IndexCount;
UINT64 VertexStart;
UINT64 VertexCount;
};
struct SDKMESH_FRAME
{
char Name[MAX_FRAME_NAME];
UINT Mesh;
UINT ParentFrame;
UINT ChildFrame;
UINT SiblingFrame;
DirectX::XMFLOAT4X4 Matrix;
UINT AnimationDataIndex; //Used to index which set of keyframes transforms this frame
};
struct SDKMESH_MATERIAL
{
char Name[MAX_MATERIAL_NAME];
// Use MaterialInstancePath
char MaterialInstancePath[MAX_MATERIAL_PATH];
// Or fall back to d3d8-type materials
char DiffuseTexture[MAX_TEXTURE_NAME];
char NormalTexture[MAX_TEXTURE_NAME];
char SpecularTexture[MAX_TEXTURE_NAME];
DirectX::XMFLOAT4 Diffuse;
DirectX::XMFLOAT4 Ambient;
DirectX::XMFLOAT4 Specular;
DirectX::XMFLOAT4 Emissive;
FLOAT Power;
union
{
UINT64 Force64_1; //Force the union to 64bits
ID3D11Texture2D* pDiffuseTexture11;
};
union
{
UINT64 Force64_2; //Force the union to 64bits
ID3D11Texture2D* pNormalTexture11;
};
union
{
UINT64 Force64_3; //Force the union to 64bits
ID3D11Texture2D* pSpecularTexture11;
};
union
{
UINT64 Force64_4; //Force the union to 64bits
ID3D11ShaderResourceView* pDiffuseRV11;
};
union
{
UINT64 Force64_5; //Force the union to 64bits
ID3D11ShaderResourceView* pNormalRV11;
};
union
{
UINT64 Force64_6; //Force the union to 64bits
ID3D11ShaderResourceView* pSpecularRV11;
};
};
struct SDKANIMATION_FILE_HEADER
{
UINT Version;
BYTE IsBigEndian;
UINT FrameTransformType;
UINT NumFrames;
UINT NumAnimationKeys;
UINT AnimationFPS;
UINT64 AnimationDataSize;
UINT64 AnimationDataOffset;
};
struct SDKANIMATION_DATA
{
DirectX::XMFLOAT3 Translation;
DirectX::XMFLOAT4 Orientation;
DirectX::XMFLOAT3 Scaling;
};
struct SDKANIMATION_FRAME_DATA
{
char FrameName[MAX_FRAME_NAME];
union
{
UINT64 DataOffset;
SDKANIMATION_DATA* pAnimationData;
};
};
#pragma pack(pop)
}; // namespace
static_assert( sizeof(DXUT::D3DVERTEXELEMENT9) == 8, "Direct3D9 Decl structure size incorrect" );
static_assert( sizeof(DXUT::SDKMESH_HEADER)== 104, "SDK Mesh structure size incorrect" );
static_assert( sizeof(DXUT::SDKMESH_VERTEX_BUFFER_HEADER) == 288, "SDK Mesh structure size incorrect" );
static_assert( sizeof(DXUT::SDKMESH_INDEX_BUFFER_HEADER) == 32, "SDK Mesh structure size incorrect" );
static_assert( sizeof(DXUT::SDKMESH_MESH) == 224, "SDK Mesh structure size incorrect" );
static_assert( sizeof(DXUT::SDKMESH_SUBSET) == 144, "SDK Mesh structure size incorrect" );
static_assert( sizeof(DXUT::SDKMESH_FRAME) == 184, "SDK Mesh structure size incorrect" );
static_assert( sizeof(DXUT::SDKMESH_MATERIAL) == 1256, "SDK Mesh structure size incorrect" );
static_assert( sizeof(DXUT::SDKANIMATION_FILE_HEADER) == 40, "SDK Mesh structure size incorrect" );
static_assert( sizeof(DXUT::SDKANIMATION_DATA) == 40, "SDK Mesh structure size incorrect" );
static_assert( sizeof(DXUT::SDKANIMATION_FRAME_DATA) == 112, "SDK Mesh structure size incorrect" );
//--------------------------------------------------------------------------------------
struct MaterialRecordSDKMESH
{
std::shared_ptr<IEffect> effect;
bool alpha;
};
static void LoadMaterial( _In_ const DXUT::SDKMESH_MATERIAL& mh,
_In_ bool perVertexColor, _In_ bool enableSkinning, _In_ bool enableDualTexture,
_Inout_ IEffectFactory& fxFactory, _Inout_ MaterialRecordSDKMESH& m )
{
WCHAR matName[ DXUT::MAX_MATERIAL_NAME ];
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, mh.Name, -1, matName, DXUT::MAX_MATERIAL_NAME );
WCHAR txtName[ DXUT::MAX_TEXTURE_NAME ];
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, mh.DiffuseTexture, -1, txtName, DXUT::MAX_TEXTURE_NAME );
WCHAR txtName2[ DXUT::MAX_TEXTURE_NAME ];
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, mh.SpecularTexture, -1, txtName2, DXUT::MAX_TEXTURE_NAME );
EffectFactory::EffectInfo info;
info.name = matName;
info.perVertexColor = perVertexColor;
info.enableSkinning = enableSkinning;
info.enableDualTexture = enableDualTexture;
info.ambientColor = XMFLOAT3( mh.Ambient.x, mh.Ambient.y, mh.Ambient.z );
info.diffuseColor = XMFLOAT3( mh.Diffuse.x, mh.Diffuse.y, mh.Diffuse.z );
info.emissiveColor= XMFLOAT3( mh.Emissive.x, mh.Emissive.y, mh.Emissive.z );
if ( mh.Diffuse.w != 1.f && mh.Diffuse.w != 0.f )
{
info.alpha = mh.Diffuse.w;
}
else
info.alpha = 1.f;
if ( mh.Power )
{
info.specularPower = mh.Power;
info.specularColor = XMFLOAT3( mh.Specular.x, mh.Specular.y, mh.Specular.z );
}
info.texture = txtName;
info.texture2 = txtName2;
m.effect = fxFactory.CreateEffect( info, nullptr );
m.alpha = (info.alpha < 1.f);
}
//--------------------------------------------------------------------------------------
// Direct3D 9 Vertex Declaration to DirectInput 11 Input Layout mapping
static void GetInputLayoutDesc( _In_reads_(32) const DXUT::D3DVERTEXELEMENT9 decl[], std::vector<D3D11_INPUT_ELEMENT_DESC>& inputDesc,
bool &perVertexColor, bool& enableSkinning, bool& dualTexture )
{
static const D3D11_INPUT_ELEMENT_DESC elements[] =
{
{ "SV_Position", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "BINORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "BLENDINDICES",0, DXGI_FORMAT_R8G8B8A8_UINT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "BLENDWEIGHT", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
using namespace DXUT;
uint32_t offset = 0;
uint32_t texcoords = 0;
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;
if ( decl[index].Usage == D3DDECLUSAGE_POSITION && decl[index].Type == D3DDECLTYPE_FLOAT3 )
{
inputDesc.push_back( elements[0] );
offset += 12;
posfound = true;
}
else if ( decl[index].Usage == D3DDECLUSAGE_NORMAL )
{
if ( decl[index].Type == D3DDECLTYPE_FLOAT3 )
{
inputDesc.push_back( elements[1] );
offset += 12;
}
else if ( decl[index].Type == D3DDECLTYPE_FLOAT16_4 )
{
D3D11_INPUT_ELEMENT_DESC desc = elements[1];
desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT;
inputDesc.push_back( desc );
offset += 8;
}
else if ( decl[index].Type == D3DDECLTYPE_SHORT4N )
{
D3D11_INPUT_ELEMENT_DESC desc = elements[1];
desc.Format = DXGI_FORMAT_R16G16B16A16_SNORM;
inputDesc.push_back( desc );
offset += 8;
}
else if ( decl[index].Type == D3DDECLTYPE_UBYTE4N )
{
D3D11_INPUT_ELEMENT_DESC desc = elements[1];
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
inputDesc.push_back( desc );
offset += 4;
}
else
break;
}
else if ( decl[index].Usage == D3DDECLUSAGE_COLOR && decl[index].Type == D3DDECLTYPE_D3DCOLOR )
{
inputDesc.push_back( elements[2] );
offset += 4;
perVertexColor = true;
}
else if ( decl[index].Usage == D3DDECLUSAGE_TANGENT )
{
if ( decl[index].Type == D3DDECLTYPE_FLOAT3 )
{
inputDesc.push_back( elements[3] );
offset += 12;
}
else if ( decl[index].Type == D3DDECLTYPE_FLOAT16_4 )
{
D3D11_INPUT_ELEMENT_DESC desc = elements[3];
desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT;
inputDesc.push_back( desc );
offset += 8;
}
else if ( decl[index].Type == D3DDECLTYPE_SHORT4N )
{
D3D11_INPUT_ELEMENT_DESC desc = elements[3];
desc.Format = DXGI_FORMAT_R16G16B16A16_SNORM;
inputDesc.push_back( desc );
offset += 8;
}
else if ( decl[index].Type == D3DDECLTYPE_UBYTE4N )
{
D3D11_INPUT_ELEMENT_DESC desc = elements[3];
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
inputDesc.push_back( desc );
offset += 4;
}
else
break;
}
else if ( decl[index].Usage == D3DDECLUSAGE_BINORMAL )
{
if ( decl[index].Type == D3DDECLTYPE_FLOAT3 )
{
inputDesc.push_back( elements[4] );
offset += 12;
}
else if ( decl[index].Type == D3DDECLTYPE_FLOAT16_4 )
{
D3D11_INPUT_ELEMENT_DESC desc = elements[4];
desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT;
inputDesc.push_back( desc );
offset += 8;
}
else if ( decl[index].Type == D3DDECLTYPE_SHORT4N )
{
D3D11_INPUT_ELEMENT_DESC desc = elements[4];
desc.Format = DXGI_FORMAT_R16G16B16A16_SNORM;
inputDesc.push_back( desc );
offset += 8;
}
else if ( decl[index].Type == D3DDECLTYPE_UBYTE4N )
{
D3D11_INPUT_ELEMENT_DESC desc = elements[4];
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
inputDesc.push_back( desc );
offset += 4;
}
else
break;
}
else if ( decl[index].Usage == D3DDECLUSAGE_TEXCOORD )
{
D3D11_INPUT_ELEMENT_DESC desc = elements[5];
desc.SemanticIndex = decl[index].UsageIndex;
bool unk = false;
switch( decl[index].Type )
{
case D3DDECLTYPE_FLOAT2: offset += 8; break;
case D3DDECLTYPE_FLOAT1: desc.Format = DXGI_FORMAT_R32_FLOAT; offset += 4; 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;
}
if ( unk )
break;
++texcoords;
inputDesc.push_back( desc );
}
else if ( decl[index].Usage == D3DDECLUSAGE_BLENDINDICES && decl[index].Type == D3DDECLTYPE_UBYTE4 )
{
enableSkinning = true;
inputDesc.push_back( elements[6] );
offset += 4;
}
else if ( decl[index].Usage == D3DDECLUSAGE_BLENDWEIGHT && decl[index].Type == D3DDECLTYPE_UBYTE4N )
{
enableSkinning = true;
inputDesc.push_back( elements[7] );
offset += 4;
}
else
break;
}
if ( !posfound )
throw std::exception("SV_Position is required");
if ( texcoords == 2 )
{
dualTexture = true;
}
}
// Helper for creating a D3D input layout.
static void CreateInputLayout(_In_ ID3D11Device* device, _In_ IEffect* effect, std::vector<D3D11_INPUT_ELEMENT_DESC>& inputDesc, _Out_ ID3D11InputLayout** pInputLayout)
{
void const* shaderByteCode;
size_t byteCodeLength;
effect->GetVertexShaderBytecode(&shaderByteCode, &byteCodeLength);
ThrowIfFailed(
device->CreateInputLayout(inputDesc.data(),
static_cast<UINT>( inputDesc.size() ),
shaderByteCode, byteCodeLength,
pInputLayout)
);
SetDebugObjectName(*pInputLayout, "ModelSDKMESH");
}
//======================================================================================
// Model Loader
//======================================================================================
_Use_decl_annotations_
std::unique_ptr<Model> DirectX::Model::CreateFromSDKMESH( ID3D11Device* d3dDevice, const uint8_t* meshData, size_t dataSize, IEffectFactory& fxFactory, bool ccw, bool pmalpha )
{
if ( !d3dDevice || !meshData )
throw std::exception("Device and meshData cannot be null");
// File Headers
if ( dataSize < sizeof(DXUT::SDKMESH_HEADER) )
throw std::exception("End of file");
auto header = reinterpret_cast<const DXUT::SDKMESH_HEADER*>( meshData );
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 )
throw std::exception("Not a valid SDKMESH file");
if ( dataSize < header->HeaderSize )
throw std::exception("End of file");
if( header->Version != DXUT::SDKMESH_FILE_VERSION )
throw std::exception("Not a supported SDKMESH version");
if ( header->IsBigEndian )
throw std::exception("Loading BigEndian SDKMESH files not supported");
if ( !header->NumMeshes )
throw std::exception("No meshes found");
if ( !header->NumVertexBuffers )
throw std::exception("No vertex buffers found");
if ( !header->NumIndexBuffers )
throw std::exception("No index buffers found");
if ( !header->NumTotalSubsets )
throw std::exception("No subsets found");
if ( !header->NumMaterials )
throw std::exception("No materials found");
// Sub-headers
if ( dataSize < header->VertexStreamHeadersOffset
|| ( dataSize < (header->VertexStreamHeadersOffset + header->NumVertexBuffers * sizeof(DXUT::SDKMESH_VERTEX_BUFFER_HEADER) ) ) )
throw std::exception("End of file");
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) ) ) )
throw std::exception("End of file");
auto ibArray = reinterpret_cast<const DXUT::SDKMESH_INDEX_BUFFER_HEADER*>( meshData + header->IndexStreamHeadersOffset );
if ( dataSize < header->MeshDataOffset
|| ( dataSize < (header->MeshDataOffset + header->NumMeshes * sizeof(DXUT::SDKMESH_MESH) ) ) )
throw std::exception("End of file");
auto meshArray = reinterpret_cast<const DXUT::SDKMESH_MESH*>( meshData + header->MeshDataOffset );
if ( dataSize < header->SubsetDataOffset
|| ( dataSize < (header->SubsetDataOffset + header->NumTotalSubsets * sizeof(DXUT::SDKMESH_SUBSET) ) ) )
throw std::exception("End of file");
auto subsetArray = reinterpret_cast<const DXUT::SDKMESH_SUBSET*>( meshData + header->SubsetDataOffset );
if ( dataSize < header->FrameDataOffset
|| (dataSize < (header->FrameDataOffset + header->NumFrames * sizeof(DXUT::SDKMESH_FRAME) ) ) )
throw std::exception("End of file");
// TODO - auto frameArray = reinterpret_cast<const DXUT::SDKMESH_FRAME*>( meshData + header->FrameDataOffset );
if ( dataSize < header->MaterialDataOffset
|| (dataSize < (header->MaterialDataOffset + header->NumMaterials * sizeof(DXUT::SDKMESH_MATERIAL) ) ) )
throw std::exception("End of file");
auto materialArray = reinterpret_cast<const DXUT::SDKMESH_MATERIAL*>( meshData + header->MaterialDataOffset );
// Buffer data
uint64_t bufferDataOffset = header->HeaderSize + header->NonBufferDataSize;
if ( ( dataSize < bufferDataOffset )
|| ( dataSize < bufferDataOffset + header->BufferDataSize ) )
throw std::exception("End of file");
const uint8_t* bufferData = meshData + bufferDataOffset;
// Create vertex buffers
std::vector<ComPtr<ID3D11Buffer>> vbs;
vbs.resize( header->NumVertexBuffers );
std::vector<std::shared_ptr<std::vector<D3D11_INPUT_ELEMENT_DESC>>> vbDecls;
vbDecls.resize( header->NumVertexBuffers );
std::vector<bool> perVertexColor;
perVertexColor.resize( header->NumVertexBuffers );
std::vector<bool> enableSkinning;
enableSkinning.resize( header->NumVertexBuffers );
std::vector<bool> enableDualTexture;
enableDualTexture.resize( header->NumVertexBuffers );
for( UINT j=0; j < header->NumVertexBuffers; ++j )
{
auto& vh = vbArray[j];
if ( dataSize < vh.DataOffset
|| ( dataSize < vh.DataOffset + vh.SizeBytes ) )
throw std::exception("End of file");
vbDecls[j] = std::make_shared<std::vector<D3D11_INPUT_ELEMENT_DESC>>();
bool vertColor = false;
bool skinning = false;
bool dualTexture = false;
GetInputLayoutDesc( vh.Decl, *vbDecls[j].get(), vertColor, skinning, dualTexture );
perVertexColor[j] = vertColor;
enableSkinning[j] = skinning;
enableDualTexture[j] = dualTexture;
auto verts = reinterpret_cast<const uint8_t*>( bufferData + (vh.DataOffset - bufferDataOffset) );
D3D11_BUFFER_DESC desc = {0};
desc.Usage = D3D11_USAGE_DEFAULT;
desc.ByteWidth = static_cast<UINT>( vh.SizeBytes );
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA initData = {0};
initData.pSysMem = verts;
ThrowIfFailed(
d3dDevice->CreateBuffer( &desc, &initData, &vbs[j] )
);
SetDebugObjectName( vbs[j].Get(), "ModelSDKMESH" );
}
// Create index buffers
std::vector<ComPtr<ID3D11Buffer>> ibs;
ibs.resize( header->NumIndexBuffers );
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");
auto indices = reinterpret_cast<const uint8_t*>( bufferData + (ih.DataOffset - bufferDataOffset) );
D3D11_BUFFER_DESC desc = {0};
desc.Usage = D3D11_USAGE_DEFAULT;
desc.ByteWidth = static_cast<UINT>( ih.SizeBytes );
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
D3D11_SUBRESOURCE_DATA initData = {0};
initData.pSysMem = indices;
ThrowIfFailed(
d3dDevice->CreateBuffer( &desc, &initData, &ibs[j] )
);
SetDebugObjectName( ibs[j].Get(), "ModelSDKMESH" );
}
// Create meshes
std::vector<MaterialRecordSDKMESH> materials;
materials.resize( header->NumMaterials );
std::unique_ptr<Model> model(new Model());
model->meshes.reserve( header->NumMeshes );
for( UINT meshIndex = 0; meshIndex < header->NumMeshes; ++meshIndex )
{
auto& mh = meshArray[ meshIndex ];
if ( !mh.NumSubsets
|| !mh.NumVertexBuffers
|| mh.IndexBuffer >= header->NumIndexBuffers
|| mh.VertexBuffers[0] >= header->NumVertexBuffers )
throw std::exception("Invalid mesh found");
// mh.NumVertexBuffers is sometimes not what you'd expect, so we skip validating it
if ( dataSize < mh.SubsetOffset
|| (dataSize < mh.SubsetOffset + mh.NumSubsets*sizeof(UINT) ) )
throw std::exception("End of file");
auto subsets = reinterpret_cast<const UINT*>( meshData + mh.SubsetOffset );
if ( mh.NumFrameInfluences > 0 )
{
if ( dataSize < mh.FrameInfluenceOffset
|| (dataSize < mh.FrameInfluenceOffset + mh.NumFrameInfluences*sizeof(UINT) ) )
throw std::exception("End of file");
// TODO - auto influences = reinterpret_cast<const UINT*>( meshData + mh.FrameInfluenceOffset );
}
auto mesh = std::make_shared<ModelMesh>();
WCHAR meshName[ DXUT::MAX_MESH_NAME ];
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, mh.Name, -1, meshName, DXUT::MAX_MESH_NAME );
mesh->name = meshName;
mesh->ccw = ccw;
mesh->pmalpha = pmalpha;
// Extents
mesh->boundingBox.Center = mh.BoundingBoxCenter;
mesh->boundingBox.Extents = mh.BoundingBoxExtents;
BoundingSphere::CreateFromBoundingBox( mesh->boundingSphere, mesh->boundingBox );
// Create subsets
mesh->meshParts.reserve( mh.NumSubsets );
for( UINT j = 0; j < mh.NumSubsets; ++j )
{
auto sIndex = subsets[ j ];
if ( sIndex >= header->NumTotalSubsets )
throw std::exception("Invalid mesh found");
auto& subset = subsetArray[ sIndex ];
D3D11_PRIMITIVE_TOPOLOGY primType;
switch( subset.PrimitiveType )
{
case DXUT::PT_TRIANGLE_LIST: primType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; break;
case DXUT::PT_TRIANGLE_STRIP: primType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; break;
case DXUT::PT_LINE_LIST: primType = D3D11_PRIMITIVE_TOPOLOGY_LINELIST; break;
case DXUT::PT_LINE_STRIP: primType = D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP; break;
case DXUT::PT_POINT_LIST: primType = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; break;
case DXUT::PT_TRIANGLE_LIST_ADJ: primType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ; break;
case DXUT::PT_TRIANGLE_STRIP_ADJ: primType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ; break;
case DXUT::PT_LINE_LIST_ADJ: primType = D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ; break;
case DXUT::PT_LINE_STRIP_ADJ: primType = D3D11_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");
}
if ( subset.MaterialID >= header->NumMaterials )
throw std::exception("Invalid mesh found");
auto& mat = materials[ subset.MaterialID ];
if ( !mat.effect )
{
size_t vi = mh.VertexBuffers[0];
LoadMaterial( materialArray[ subset.MaterialID ],
perVertexColor[vi], enableSkinning[vi], enableDualTexture[vi],
fxFactory, mat );
}
ComPtr<ID3D11InputLayout> il;
CreateInputLayout( d3dDevice, mat.effect.get(), *vbDecls[ mh.VertexBuffers[0] ].get(), &il );
auto part = new ModelMeshPart();
part->isAlpha = mat.alpha;
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>( vbArray[ mh.VertexBuffers[0] ].StrideBytes );
part->indexFormat = ( ibArray[ mh.IndexBuffer ].IndexType == DXUT::IT_32BIT ) ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT;
part->primitiveType = primType;
part->inputLayout = il;
part->indexBuffer = ibs[ mh.IndexBuffer ];
part->vertexBuffer = vbs[ mh.VertexBuffers[0] ];
part->effect = mat.effect;
part->vbDecl = vbDecls[ mh.VertexBuffers[0] ];
mesh->meshParts.emplace_back( part );
}
model->meshes.emplace_back( mesh );
}
return model;
}
//--------------------------------------------------------------------------------------
_Use_decl_annotations_
std::unique_ptr<Model> DirectX::Model::CreateFromSDKMESH( ID3D11Device* d3dDevice, const wchar_t* szFileName, IEffectFactory& fxFactory, bool ccw, bool pmalpha )
{
size_t dataSize = 0;
std::unique_ptr<uint8_t[]> data;
HRESULT hr = BinaryReader::ReadEntireFile( szFileName, data, &dataSize );
if ( FAILED(hr) )
{
DebugTrace( "CreateFromSDKMESH failed (%08X) loading '%ls'\n", hr, szFileName );
throw std::exception( "CreateFromSDKMESH" );
}
auto model = CreateFromSDKMESH( d3dDevice, data.get(), dataSize, fxFactory, ccw, pmalpha );
model->name = szFileName;
return model;
}