//-------------------------------------------------------------------------------------- // File: Model.h // // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // // http://go.microsoft.com/fwlink/?LinkId=248929 //-------------------------------------------------------------------------------------- #pragma once #if defined(_XBOX_ONE) && defined(_TITLE) #include <d3d11_x.h> #else #include <d3d11_1.h> #include <dxgiformat.h> #endif #include <cstddef> #include <cstdint> #include <functional> #include <memory> #include <new> #include <set> #include <string> #include <vector> #include <malloc.h> #include <wrl\client.h> #include <DirectXMath.h> #include <DirectXCollision.h> namespace DirectX { inline namespace DX11 { class IEffect; class IEffectFactory; class CommonStates; class ModelMesh; //------------------------------------------------------------------------------ // Model loading options enum ModelLoaderFlags : uint32_t { ModelLoader_Clockwise = 0x0, ModelLoader_CounterClockwise = 0x1, ModelLoader_PremultipledAlpha = 0x2, ModelLoader_MaterialColorsSRGB = 0x4, ModelLoader_AllowLargeModels = 0x8, ModelLoader_IncludeBones = 0x10, ModelLoader_DisableSkinning = 0x20, }; //------------------------------------------------------------------------------ // Frame hierarchy for rigid body and skeletal animation struct ModelBone { ModelBone() noexcept : parentIndex(c_Invalid), childIndex(c_Invalid), siblingIndex(c_Invalid) { } ModelBone(uint32_t parent, uint32_t child, uint32_t sibling) noexcept : parentIndex(parent), childIndex(child), siblingIndex(sibling) { } uint32_t parentIndex; uint32_t childIndex; uint32_t siblingIndex; std::wstring name; using Collection = std::vector<ModelBone>; static constexpr uint32_t c_Invalid = uint32_t(-1); struct aligned_deleter { void operator()(void* p) noexcept { _aligned_free(p); } }; using TransformArray = std::unique_ptr<XMMATRIX[], aligned_deleter>; static TransformArray MakeArray(size_t count) { void* temp = _aligned_malloc(sizeof(XMMATRIX) * count, 16); if (!temp) throw std::bad_alloc(); return TransformArray(static_cast<XMMATRIX*>(temp)); } }; //------------------------------------------------------------------------------ // Each mesh part is a submesh with a single effect class ModelMeshPart { public: ModelMeshPart() noexcept; ModelMeshPart(ModelMeshPart&&) = default; ModelMeshPart& operator= (ModelMeshPart&&) = default; ModelMeshPart(ModelMeshPart const&) = default; ModelMeshPart& operator= (ModelMeshPart const&) = default; virtual ~ModelMeshPart(); using Collection = std::vector<std::unique_ptr<ModelMeshPart>>; using InputLayoutCollection = std::vector<D3D11_INPUT_ELEMENT_DESC>; uint32_t indexCount; uint32_t startIndex; int32_t vertexOffset; uint32_t vertexStride; D3D_PRIMITIVE_TOPOLOGY primitiveType; DXGI_FORMAT indexFormat; Microsoft::WRL::ComPtr<ID3D11InputLayout> inputLayout; Microsoft::WRL::ComPtr<ID3D11Buffer> indexBuffer; Microsoft::WRL::ComPtr<ID3D11Buffer> vertexBuffer; std::shared_ptr<IEffect> effect; std::shared_ptr<InputLayoutCollection> vbDecl; bool isAlpha; // Draw mesh part with custom effect void __cdecl Draw( _In_ ID3D11DeviceContext* deviceContext, _In_ IEffect* ieffect, _In_ ID3D11InputLayout* iinputLayout, _In_ std::function<void __cdecl()> setCustomState = nullptr) const; void __cdecl DrawInstanced( _In_ ID3D11DeviceContext* deviceContext, _In_ IEffect* ieffect, _In_ ID3D11InputLayout* iinputLayout, uint32_t instanceCount, uint32_t startInstanceLocation = 0, _In_ std::function<void __cdecl()> setCustomState = nullptr) const; // Create input layout for drawing with a custom effect. void __cdecl CreateInputLayout(_In_ ID3D11Device* device, _In_ IEffect* ieffect, _Outptr_ ID3D11InputLayout** iinputLayout) const; // Change effect used by part and regenerate input layout (be sure to call Model::Modified as well) void __cdecl ModifyEffect(_In_ ID3D11Device* device, _In_ const std::shared_ptr<IEffect>& ieffect, bool isalpha = false); }; //------------------------------------------------------------------------------ // A mesh consists of one or more model mesh parts class ModelMesh { public: ModelMesh() noexcept; ModelMesh(ModelMesh&&) = default; ModelMesh& operator= (ModelMesh&&) = default; ModelMesh(ModelMesh const&) = default; ModelMesh& operator= (ModelMesh const&) = default; virtual ~ModelMesh(); BoundingSphere boundingSphere; BoundingBox boundingBox; ModelMeshPart::Collection meshParts; uint32_t boneIndex; std::vector<uint32_t> boneInfluences; std::wstring name; bool ccw; bool pmalpha; using Collection = std::vector<std::shared_ptr<ModelMesh>>; // Setup states for drawing mesh void __cdecl PrepareForRendering( _In_ ID3D11DeviceContext* deviceContext, const CommonStates& states, bool alpha = false, bool wireframe = false) const; // Draw the mesh void XM_CALLCONV Draw( _In_ ID3D11DeviceContext* deviceContext, FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection, bool alpha = false, _In_ std::function<void __cdecl()> setCustomState = nullptr) const; // Draw the mesh using model bones void XM_CALLCONV Draw( _In_ ID3D11DeviceContext* deviceContext, size_t nbones, _In_reads_(nbones) const XMMATRIX* boneTransforms, FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection, bool alpha = false, _In_ std::function<void __cdecl()> setCustomState = nullptr) const; // Draw the mesh using skinning void XM_CALLCONV DrawSkinned( _In_ ID3D11DeviceContext* deviceContext, size_t nbones, _In_reads_(nbones) const XMMATRIX* boneTransforms, FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection, bool alpha = false, _In_ std::function<void __cdecl()> setCustomState = nullptr) const; static void SetDepthBufferMode(bool reverseZ) { s_reversez = reverseZ; } private: static bool s_reversez; }; //------------------------------------------------------------------------------ // A model consists of one or more meshes class Model { public: Model() = default; Model(Model&&) = default; Model& operator= (Model&&) = default; Model(Model const& other); Model& operator= (Model const& rhs); virtual ~Model(); ModelMesh::Collection meshes; ModelBone::Collection bones; ModelBone::TransformArray boneMatrices; ModelBone::TransformArray invBindPoseMatrices; std::wstring name; // Draw all the meshes in the model void XM_CALLCONV Draw( _In_ ID3D11DeviceContext* deviceContext, const CommonStates& states, FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection, bool wireframe = false, _In_ std::function<void __cdecl()> setCustomState = nullptr) const; // Draw all the meshes using model bones void XM_CALLCONV Draw( _In_ ID3D11DeviceContext* deviceContext, const CommonStates& states, size_t nbones, _In_reads_(nbones) const XMMATRIX* boneTransforms, FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection, bool wireframe = false, _In_ std::function<void __cdecl()> setCustomState = nullptr) const; // Draw all the meshes using skinning void XM_CALLCONV DrawSkinned( _In_ ID3D11DeviceContext* deviceContext, const CommonStates& states, size_t nbones, _In_reads_(nbones) const XMMATRIX* boneTransforms, FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection, bool wireframe = false, _In_ std::function<void __cdecl()> setCustomState = nullptr) const; // Compute bone positions based on heirarchy and transform matrices void __cdecl CopyAbsoluteBoneTransformsTo( size_t nbones, _Out_writes_(nbones) XMMATRIX* boneTransforms) const; void __cdecl CopyAbsoluteBoneTransforms( size_t nbones, _In_reads_(nbones) const XMMATRIX* inBoneTransforms, _Out_writes_(nbones) XMMATRIX* outBoneTransforms) const; // Set bone matrices to a set of relative tansforms void __cdecl CopyBoneTransformsFrom( size_t nbones, _In_reads_(nbones) const XMMATRIX* boneTransforms); // Copies the relative bone matrices to a transform array void __cdecl CopyBoneTransformsTo( size_t nbones, _Out_writes_(nbones) XMMATRIX* boneTransforms) const; // Notify model that effects, parts list, or mesh list has changed void __cdecl Modified() noexcept { mEffectCache.clear(); } // Update all effects used by the model void __cdecl UpdateEffects(_In_ std::function<void __cdecl(IEffect*)> setEffect); // Loads a model from a Visual Studio Starter Kit .CMO file static std::unique_ptr<Model> __cdecl CreateFromCMO( _In_ ID3D11Device* device, _In_reads_bytes_(dataSize) const uint8_t* meshData, size_t dataSize, _In_ IEffectFactory& fxFactory, ModelLoaderFlags flags = ModelLoader_CounterClockwise, _Out_opt_ size_t* animsOffset = nullptr); static std::unique_ptr<Model> __cdecl CreateFromCMO( _In_ ID3D11Device* device, _In_z_ const wchar_t* szFileName, _In_ IEffectFactory& fxFactory, ModelLoaderFlags flags = ModelLoader_CounterClockwise, _Out_opt_ size_t* animsOffset = nullptr); // Loads a model from a DirectX SDK .SDKMESH file static std::unique_ptr<Model> __cdecl CreateFromSDKMESH( _In_ ID3D11Device* device, _In_reads_bytes_(dataSize) const uint8_t* meshData, _In_ size_t dataSize, _In_ IEffectFactory& fxFactory, ModelLoaderFlags flags = ModelLoader_Clockwise); static std::unique_ptr<Model> __cdecl CreateFromSDKMESH( _In_ ID3D11Device* device, _In_z_ const wchar_t* szFileName, _In_ IEffectFactory& fxFactory, ModelLoaderFlags flags = ModelLoader_Clockwise); // Loads a model from a .VBO file static std::unique_ptr<Model> __cdecl CreateFromVBO( _In_ ID3D11Device* device, _In_reads_bytes_(dataSize) const uint8_t* meshData, _In_ size_t dataSize, _In_ std::shared_ptr<IEffect> ieffect = nullptr, ModelLoaderFlags flags = ModelLoader_Clockwise); static std::unique_ptr<Model> __cdecl CreateFromVBO( _In_ ID3D11Device* device, _In_z_ const wchar_t* szFileName, _In_ std::shared_ptr<IEffect> ieffect = nullptr, ModelLoaderFlags flags = ModelLoader_Clockwise); #if defined(_MSC_VER) && !defined(_NATIVE_WCHAR_T_DEFINED) static std::unique_ptr<Model> __cdecl CreateFromCMO( _In_ ID3D11Device* device, _In_z_ const __wchar_t* szFileName, _In_ IEffectFactory& fxFactory, ModelLoaderFlags flags = ModelLoader_CounterClockwise, _Out_opt_ size_t* animsOffset = nullptr); static std::unique_ptr<Model> __cdecl CreateFromSDKMESH( _In_ ID3D11Device* device, _In_z_ const __wchar_t* szFileName, _In_ IEffectFactory& fxFactory, ModelLoaderFlags flags = ModelLoader_Clockwise); static std::unique_ptr<Model> __cdecl CreateFromVBO( _In_ ID3D11Device* device, _In_z_ const __wchar_t* szFileName, _In_ std::shared_ptr<IEffect> ieffect = nullptr, ModelLoaderFlags flags = ModelLoader_Clockwise); #endif // !_NATIVE_WCHAR_T_DEFINED private: std::set<IEffect*> mEffectCache; void __cdecl ComputeAbsolute(uint32_t index, CXMMATRIX local, size_t nbones, _In_reads_(nbones) const XMMATRIX* inBoneTransforms, _Inout_updates_(nbones) XMMATRIX* outBoneTransforms, size_t& visited) const; }; #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-dynamic-exception-spec" #endif DEFINE_ENUM_FLAG_OPERATORS(ModelLoaderFlags); #ifdef __clang__ #pragma clang diagnostic pop #endif } }