//-------------------------------------------------------------------------------------- // 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 #else #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include 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; 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; static TransformArray MakeArray(size_t count) { void* temp = _aligned_malloc(sizeof(XMMATRIX) * count, 16); if (!temp) throw std::bad_alloc(); return TransformArray(static_cast(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>; using InputLayoutCollection = std::vector; uint32_t indexCount; uint32_t startIndex; int32_t vertexOffset; uint32_t vertexStride; D3D_PRIMITIVE_TOPOLOGY primitiveType; DXGI_FORMAT indexFormat; Microsoft::WRL::ComPtr inputLayout; Microsoft::WRL::ComPtr indexBuffer; Microsoft::WRL::ComPtr vertexBuffer; std::shared_ptr effect; std::shared_ptr vbDecl; bool isAlpha; // Draw mesh part with custom effect void __cdecl Draw( _In_ ID3D11DeviceContext* deviceContext, _In_ IEffect* ieffect, _In_ ID3D11InputLayout* iinputLayout, _In_ std::function 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 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, 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 boneInfluences; std::wstring name; bool ccw; bool pmalpha; using Collection = std::vector>; // 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 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 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 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 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 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 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 setEffect); // Loads a model from a Visual Studio Starter Kit .CMO file static std::unique_ptr __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 __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 __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 __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 __cdecl CreateFromVBO( _In_ ID3D11Device* device, _In_reads_bytes_(dataSize) const uint8_t* meshData, _In_ size_t dataSize, _In_ std::shared_ptr ieffect = nullptr, ModelLoaderFlags flags = ModelLoader_Clockwise); static std::unique_ptr __cdecl CreateFromVBO( _In_ ID3D11Device* device, _In_z_ const wchar_t* szFileName, _In_ std::shared_ptr ieffect = nullptr, ModelLoaderFlags flags = ModelLoader_Clockwise); #if defined(_MSC_VER) && !defined(_NATIVE_WCHAR_T_DEFINED) static std::unique_ptr __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 __cdecl CreateFromSDKMESH( _In_ ID3D11Device* device, _In_z_ const __wchar_t* szFileName, _In_ IEffectFactory& fxFactory, ModelLoaderFlags flags = ModelLoader_Clockwise); static std::unique_ptr __cdecl CreateFromVBO( _In_ ID3D11Device* device, _In_z_ const __wchar_t* szFileName, _In_ std::shared_ptr ieffect = nullptr, ModelLoaderFlags flags = ModelLoader_Clockwise); #endif // !_NATIVE_WCHAR_T_DEFINED private: std::set 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 } }