//-------------------------------------------------------------------------------------- // 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 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 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& 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& inputDesc, _Out_ ID3D11InputLayout** pInputLayout) { void const* shaderByteCode; size_t byteCodeLength; effect->GetVertexShaderBytecode(&shaderByteCode, &byteCodeLength); ThrowIfFailed( device->CreateInputLayout(inputDesc.data(), static_cast( inputDesc.size() ), shaderByteCode, byteCodeLength, pInputLayout) ); SetDebugObjectName(*pInputLayout, "ModelSDKMESH"); } //====================================================================================== // Model Loader //====================================================================================== _Use_decl_annotations_ std::unique_ptr 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( 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( 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( 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( 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( 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( 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( 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> vbs; vbs.resize( header->NumVertexBuffers ); std::vector>> vbDecls; vbDecls.resize( header->NumVertexBuffers ); std::vector perVertexColor; perVertexColor.resize( header->NumVertexBuffers ); std::vector enableSkinning; enableSkinning.resize( header->NumVertexBuffers ); std::vector 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>(); 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( bufferData + (vh.DataOffset - bufferDataOffset) ); D3D11_BUFFER_DESC desc = {0}; desc.Usage = D3D11_USAGE_DEFAULT; desc.ByteWidth = static_cast( 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> 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( bufferData + (ih.DataOffset - bufferDataOffset) ); D3D11_BUFFER_DESC desc = {0}; desc.Usage = D3D11_USAGE_DEFAULT; desc.ByteWidth = static_cast( 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 materials; materials.resize( header->NumMaterials ); std::unique_ptr 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( 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( meshData + mh.FrameInfluenceOffset ); } auto mesh = std::make_shared(); 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 il; CreateInputLayout( d3dDevice, mat.effect.get(), *vbDecls[ mh.VertexBuffers[0] ].get(), &il ); auto part = new ModelMeshPart(); part->isAlpha = mat.alpha; part->indexCount = static_cast( subset.IndexCount ); part->startIndex = static_cast( subset.IndexStart ); part->vertexOffset = static_cast( subset.VertexStart ); part->vertexStride = static_cast( 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 DirectX::Model::CreateFromSDKMESH( ID3D11Device* d3dDevice, const wchar_t* szFileName, IEffectFactory& fxFactory, bool ccw, bool pmalpha ) { size_t dataSize = 0; std::unique_ptr 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; }