diff --git a/CMakeLists.txt b/CMakeLists.txt index 59b79d1c6..0a7f8eeae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -594,6 +594,8 @@ IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) ENDIF () IF ( ASSIMP_BUILD_SAMPLES) + SET( SAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/samples ) + SET( SAMPLES_SHARED_CODE_DIR ${SAMPLES_DIR}/SharedCode ) IF ( WIN32 ) ADD_SUBDIRECTORY( samples/SimpleTexturedOpenGL/ ) ADD_SUBDIRECTORY( samples/SimpleTexturedDirectx11 ) diff --git a/samples/SharedCode/UTFConverter.cpp b/samples/SharedCode/UTFConverter.cpp new file mode 100644 index 000000000..a1bff7e4b --- /dev/null +++ b/samples/SharedCode/UTFConverter.cpp @@ -0,0 +1,52 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +#include "UTFConverter.h" + +namespace AssimpSamples { +namespace SharedCode { + +typename UTFConverter::UTFConverterImpl UTFConverter::impl_; + +} +} diff --git a/samples/SharedCode/UTFConverter.h b/samples/SharedCode/UTFConverter.h new file mode 100644 index 000000000..17e89ee4d --- /dev/null +++ b/samples/SharedCode/UTFConverter.h @@ -0,0 +1,92 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +#ifndef ASSIMP_SAMPLES_SHARED_CODE_UTFCONVERTER_H +#define ASSIMP_SAMPLES_SHARED_CODE_UTFCONVERTER_H + +#include +#include +#include + +namespace AssimpSamples { +namespace SharedCode { + +// Used to convert between multibyte and unicode strings. +class UTFConverter { + using UTFConverterImpl = std::wstring_convert, wchar_t>; +public: + UTFConverter(const char* s) : + s_(s), + ws_(impl_.from_bytes(s)) { + } + UTFConverter(const wchar_t* s) : + s_(impl_.to_bytes(s)), + ws_(s) { + } + UTFConverter(const std::string& s) : + s_(s), + ws_(impl_.from_bytes(s)) { + } + UTFConverter(const std::wstring& s) : + s_(impl_.to_bytes(s)), + ws_(s) { + } + inline const char* c_str() const { + return s_.c_str(); + } + inline const std::string& str() const { + return s_; + } + inline const wchar_t* c_wstr() const { + return ws_.c_str(); + } +private: + static UTFConverterImpl impl_; + std::string s_; + std::wstring ws_; +}; + +} +} + +#endif // ASSIMP_SAMPLES_SHARED_CODE_UTFCONVERTER_H diff --git a/samples/SimpleTexturedDirectx11/CMakeLists.txt b/samples/SimpleTexturedDirectx11/CMakeLists.txt index b1882500e..9016b8869 100644 --- a/samples/SimpleTexturedDirectx11/CMakeLists.txt +++ b/samples/SimpleTexturedDirectx11/CMakeLists.txt @@ -10,12 +10,12 @@ if ( MSVC ) REMOVE_DEFINITIONS( -DUNICODE -D_UNICODE ) endif () +ADD_COMPILE_DEFINITIONS(SHADER_PATH="${CMAKE_CURRENT_SOURCE_DIR}/SimpleTexturedDirectx11/") + INCLUDE_DIRECTORIES( ${Assimp_SOURCE_DIR}/include ${Assimp_SOURCE_DIR}/code - ${OPENGL_INCLUDE_DIR} - ${GLUT_INCLUDE_DIR} - ${Assimp_SOURCE_DIR}/samples/freeglut/include + ${SAMPLES_SHARED_CODE_DIR} ) LINK_DIRECTORIES( @@ -32,6 +32,9 @@ ADD_EXECUTABLE( assimp_simpletextureddirectx11 WIN32 SimpleTexturedDirectx11/TextureLoader.h #SimpleTexturedDirectx11/VertexShader.hlsl SimpleTexturedDirectx11/main.cpp + SimpleTexturedDirectx11/SafeRelease.hpp + ${SAMPLES_SHARED_CODE_DIR}/UTFConverter.cpp + ${SAMPLES_SHARED_CODE_DIR}/UTFConverter.h ) SET_PROPERTY(TARGET assimp_simpletextureddirectx11 PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h index 87433219f..fb2f7f7db 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h @@ -6,13 +6,14 @@ #include #include #include -using namespace std; - -#include +#include #include #include + using namespace DirectX; +#include "SafeRelease.hpp" + struct VERTEX { FLOAT X, Y, Z; XMFLOAT2 texcoord; @@ -22,81 +23,85 @@ struct Texture { string type; string path; ID3D11ShaderResourceView *texture; + + void Release() { + SafeRelease(texture); + } }; class Mesh { public: - vector vertices; - vector indices; - vector textures; - ID3D11Device *dev; + std::vector vertices; + std::vector indices; + std::vector textures; + ID3D11Device *dev; - Mesh(ID3D11Device *dev, vector vertices, vector indices, vector textures) - { - this->vertices = vertices; - this->indices = indices; - this->textures = textures; + Mesh(ID3D11Device *dev, const vector& vertices, const vector& indices, const vector& textures) : + vertices(vertices), + indices(indices), + textures(textures), + dev(dev), + VertexBuffer(nullptr), + IndexBuffer(nullptr) { + this->setupMesh(this->dev); + } - this->dev = dev; + void Draw(ID3D11DeviceContext *devcon) { + UINT stride = sizeof(VERTEX); + UINT offset = 0; - this->setupMesh(dev); - } + devcon->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset); + devcon->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0); - void Draw(ID3D11DeviceContext *devcon) - { - UINT stride = sizeof(VERTEX); - UINT offset = 0; + devcon->PSSetShaderResources(0, 1, &textures[0].texture); - devcon->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset); - devcon->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0); + devcon->DrawIndexed(static_cast(indices.size()), 0, 0); + } - devcon->PSSetShaderResources(0, 1, &textures[0].texture); - - devcon->DrawIndexed(indices.size(), 0, 0); - } - - void Close() - { - VertexBuffer->Release(); - IndexBuffer->Release(); - } + void Close() { + SafeRelease(VertexBuffer); + SafeRelease(IndexBuffer); + } private: - /* Render data */ - ID3D11Buffer *VertexBuffer, *IndexBuffer; + // Render data + ID3D11Buffer *VertexBuffer, *IndexBuffer; - /* Functions */ - // Initializes all the buffer objects/arrays - bool setupMesh(ID3D11Device *dev) - { - HRESULT hr; + // Functions + // Initializes all the buffer objects/arrays + void setupMesh(ID3D11Device *dev) { + HRESULT hr; - D3D11_BUFFER_DESC vbd; - vbd.Usage = D3D11_USAGE_IMMUTABLE; - vbd.ByteWidth = sizeof(VERTEX) * vertices.size(); - vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER; - vbd.CPUAccessFlags = 0; - vbd.MiscFlags = 0; + D3D11_BUFFER_DESC vbd; + vbd.Usage = D3D11_USAGE_IMMUTABLE; + vbd.ByteWidth = static_cast(sizeof(VERTEX) * vertices.size()); + vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbd.CPUAccessFlags = 0; + vbd.MiscFlags = 0; - D3D11_SUBRESOURCE_DATA initData; - initData.pSysMem = &vertices[0]; + D3D11_SUBRESOURCE_DATA initData; + initData.pSysMem = &vertices[0]; - hr = dev->CreateBuffer(&vbd, &initData, &VertexBuffer); - if (FAILED(hr)) - return false; + hr = dev->CreateBuffer(&vbd, &initData, &VertexBuffer); + if (FAILED(hr)) { + Close(); + throw std::runtime_error("Failed to create vertex buffer."); + } - D3D11_BUFFER_DESC ibd; - ibd.Usage = D3D11_USAGE_IMMUTABLE; - ibd.ByteWidth = sizeof(UINT) * indices.size(); - ibd.BindFlags = D3D11_BIND_INDEX_BUFFER; - ibd.CPUAccessFlags = 0; - ibd.MiscFlags = 0; + D3D11_BUFFER_DESC ibd; + ibd.Usage = D3D11_USAGE_IMMUTABLE; + ibd.ByteWidth = static_cast(sizeof(UINT) * indices.size()); + ibd.BindFlags = D3D11_BIND_INDEX_BUFFER; + ibd.CPUAccessFlags = 0; + ibd.MiscFlags = 0; - initData.pSysMem = &indices[0]; + initData.pSysMem = &indices[0]; - hr = dev->CreateBuffer(&ibd, &initData, &IndexBuffer); - if (FAILED(hr)) - return false; - } + hr = dev->CreateBuffer(&ibd, &initData, &IndexBuffer); + if (FAILED(hr)) { + Close(); + throw std::runtime_error("Failed to create index buffer."); + } + } }; #endif diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp index 10ba07a98..1ab5b61fb 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp @@ -1,16 +1,21 @@ #include "ModelLoader.h" -ModelLoader::ModelLoader() -{ +ModelLoader::ModelLoader() : + dev(nullptr), + devcon(nullptr), + meshes(), + directory(), + textures_loaded(), + hwnd(nullptr) { + // empty } -ModelLoader::~ModelLoader() -{ +ModelLoader::~ModelLoader() { + // empty } -bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devcon, std::string filename) -{ +bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devcon, std::string filename) { Assimp::Importer importer; const aiScene* pScene = importer.ReadFile(filename, @@ -20,9 +25,10 @@ bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devc if (pScene == NULL) return false; - this->directory = filename.substr(0, filename.find_last_of('/')); + this->directory = filename.substr(0, filename.find_last_of("/\\")); this->dev = dev; + this->devcon = devcon; this->hwnd = hwnd; processNode(pScene->mRootNode, pScene); @@ -30,41 +36,37 @@ bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devc return true; } -void ModelLoader::Draw(ID3D11DeviceContext * devcon) -{ - for (int i = 0; i < meshes.size(); i++) - { +void ModelLoader::Draw(ID3D11DeviceContext * devcon) { + for (int i = 0; i < meshes.size(); ++i ) { meshes[i].Draw(devcon); } } string textype; -Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene) -{ +Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene) { // Data to fill vector vertices; vector indices; vector textures; - if (mesh->mMaterialIndex >= 0) - { + if (mesh->mMaterialIndex >= 0) { aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex]; - if (textype.empty()) textype = determineTextureType(scene, mat); + if (textype.empty()) { + textype = determineTextureType(scene, mat); + } } // Walk through each of the mesh's vertices - for (UINT i = 0; i < mesh->mNumVertices; i++) - { + for (UINT i = 0; i < mesh->mNumVertices; i++) { VERTEX vertex; vertex.X = mesh->mVertices[i].x; vertex.Y = mesh->mVertices[i].y; vertex.Z = mesh->mVertices[i].z; - if (mesh->mTextureCoords[0]) - { + if (mesh->mTextureCoords[0]) { vertex.texcoord.x = (float)mesh->mTextureCoords[0][i].x; vertex.texcoord.y = (float)mesh->mTextureCoords[0][i].y; } @@ -72,16 +74,14 @@ Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene) vertices.push_back(vertex); } - for (UINT i = 0; i < mesh->mNumFaces; i++) - { + for (UINT i = 0; i < mesh->mNumFaces; i++) { aiFace face = mesh->mFaces[i]; for (UINT j = 0; j < face.mNumIndices; j++) indices.push_back(face.mIndices[j]); } - if (mesh->mMaterialIndex >= 0) - { + if (mesh->mMaterialIndex >= 0) { aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; vector diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene); @@ -91,35 +91,27 @@ Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene) return Mesh(dev, vertices, indices, textures); } -vector ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene) -{ +vector ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene) { vector textures; - for (UINT i = 0; i < mat->GetTextureCount(type); i++) - { + for (UINT i = 0; i < mat->GetTextureCount(type); i++) { aiString str; mat->GetTexture(type, i, &str); // Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture bool skip = false; - for (UINT j = 0; j < textures_loaded.size(); j++) - { - if (std::strcmp(textures_loaded[j].path.c_str(), str.C_Str()) == 0) - { + for (UINT j = 0; j < textures_loaded.size(); j++) { + if (std::strcmp(textures_loaded[j].path.c_str(), str.C_Str()) == 0) { textures.push_back(textures_loaded[j]); skip = true; // A texture with the same filepath has already been loaded, continue to next one. (optimization) break; } } - if (!skip) - { // If texture hasn't been loaded already, load it + if (!skip) { // If texture hasn't been loaded already, load it HRESULT hr; Texture texture; - if (textype == "embedded compressed texture") - { + if (textype == "embedded compressed texture") { int textureindex = getTextureIndex(&str); texture.texture = getTextureFromModel(scene, textureindex); - } - else - { + } else { string filename = string(str.C_Str()); filename = directory + '/' + filename; wstring filenamews = wstring(filename.begin(), filename.end()); @@ -136,64 +128,52 @@ vector ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureTyp return textures; } -void ModelLoader::Close() -{ - for (int i = 0; i < meshes.size(); i++) - { +void ModelLoader::Close() { + for (auto& t : textures_loaded) + t.Release(); + + for (int i = 0; i < meshes.size(); i++) { meshes[i].Close(); } - - dev->Release(); } -void ModelLoader::processNode(aiNode * node, const aiScene * scene) -{ - for (UINT i = 0; i < node->mNumMeshes; i++) - { +void ModelLoader::processNode(aiNode * node, const aiScene * scene) { + for (UINT i = 0; i < node->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; meshes.push_back(this->processMesh(mesh, scene)); } - for (UINT i = 0; i < node->mNumChildren; i++) - { + for (UINT i = 0; i < node->mNumChildren; i++) { this->processNode(node->mChildren[i], scene); } } -string ModelLoader::determineTextureType(const aiScene * scene, aiMaterial * mat) -{ +string ModelLoader::determineTextureType(const aiScene * scene, aiMaterial * mat) { aiString textypeStr; mat->GetTexture(aiTextureType_DIFFUSE, 0, &textypeStr); string textypeteststr = textypeStr.C_Str(); - if (textypeteststr == "*0" || textypeteststr == "*1" || textypeteststr == "*2" || textypeteststr == "*3" || textypeteststr == "*4" || textypeteststr == "*5") - { - if (scene->mTextures[0]->mHeight == 0) - { + if (textypeteststr == "*0" || textypeteststr == "*1" || textypeteststr == "*2" || textypeteststr == "*3" || textypeteststr == "*4" || textypeteststr == "*5") { + if (scene->mTextures[0]->mHeight == 0) { return "embedded compressed texture"; - } - else - { + } else { return "embedded non-compressed texture"; } } - if (textypeteststr.find('.') != string::npos) - { + if (textypeteststr.find('.') != string::npos) { return "textures are on disk"; } return "."; } -int ModelLoader::getTextureIndex(aiString * str) -{ +int ModelLoader::getTextureIndex(aiString * str) { string tistr; tistr = str->C_Str(); tistr = tistr.substr(1); return stoi(tistr); } -ID3D11ShaderResourceView * ModelLoader::getTextureFromModel(const aiScene * scene, int textureindex) -{ +ID3D11ShaderResourceView * ModelLoader::getTextureFromModel(const aiScene * scene, int textureindex) { HRESULT hr; ID3D11ShaderResourceView *texture; diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SafeRelease.hpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SafeRelease.hpp new file mode 100644 index 000000000..2fd80db6c --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SafeRelease.hpp @@ -0,0 +1,57 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +#ifdef _MSC_VER +#pragma once +#endif + +/* Used to reduce to reduce the number of lines when calling Release() + on a D3D interface. Implemented as a template instead of a 'SAFE_RELEASE' + MACRO to ease debugging. */ +template +inline void SafeRelease(T*& x) { + if (x) { + x->Release(); + x = nullptr; + } +} diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp index 2d847095a..781fe89e5 100644 --- a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp @@ -14,12 +14,16 @@ // --------------------------------------------------------------------------- #include +#include +#include #include #include #include #include #include #include "ModelLoader.h" +#include "UTFConverter.h" +#include "SafeRelease.hpp" #pragma comment (lib, "d3d11.lib") #pragma comment (lib, "Dxgi.lib") @@ -27,6 +31,10 @@ #pragma comment (lib, "dxguid.lib") using namespace DirectX; +using namespace AssimpSamples::SharedCode; + +#define VERTEX_SHADER_FILE L"VertexShader.hlsl" +#define PIXEL_SHADER_FILE L"PixelShader.hlsl" // ------------------------------------------------------------ // Structs @@ -45,29 +53,32 @@ struct ConstantBuffer { const char g_szClassName[] = "directxWindowClass"; +static std::string g_ModelPath; UINT width, height; -HWND hwnd; +HWND hwnd = nullptr; // ------------------------------------------------------------ // DirectX Variables // ------------------------------------------------------------ D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL; D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0; -ID3D11Device *dev; -ID3D11Device1 *dev1; -ID3D11DeviceContext *devcon; -ID3D11DeviceContext1 *devcon1; -IDXGISwapChain *swapchain; -IDXGISwapChain1 *swapchain1; -ID3D11RenderTargetView *backbuffer; -ID3D11VertexShader *pVS; -ID3D11PixelShader *pPS; -ID3D11InputLayout *pLayout; -ID3D11Buffer *pConstantBuffer; -ID3D11Texture2D *g_pDepthStencil; -ID3D11DepthStencilView *g_pDepthStencilView; -ID3D11SamplerState *TexSamplerState; +ID3D11Device *dev = nullptr; +ID3D11Device1 *dev1 = nullptr; +ID3D11DeviceContext *devcon = nullptr; +ID3D11DeviceContext1 *devcon1 = nullptr; +IDXGISwapChain *swapchain = nullptr; +IDXGISwapChain1 *swapchain1 = nullptr; +ID3D11RenderTargetView *backbuffer = nullptr; +ID3D11VertexShader *pVS = nullptr; +ID3D11PixelShader *pPS = nullptr; +ID3D11InputLayout *pLayout = nullptr; +ID3D11Buffer *pConstantBuffer = nullptr; +ID3D11Texture2D *g_pDepthStencil = nullptr; +ID3D11DepthStencilView *g_pDepthStencilView = nullptr; +ID3D11SamplerState *TexSamplerState = nullptr; +ID3D11RasterizerState *rasterstate = nullptr; +ID3D11Debug* d3d11debug = nullptr; XMMATRIX m_World; XMMATRIX m_View; @@ -91,7 +102,7 @@ void Throwanerror(LPCSTR errormessage); // Our Model // ------------------------------------------------------------ -ModelLoader *ourModel; +ModelLoader *ourModel = nullptr; LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -109,9 +120,42 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) return 0; } -int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - LPSTR lpCmdLine, int nCmdShow) +int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPWSTR lpCmdLine, int nCmdShow) { + int argc; + LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); + if (!argv) { + MessageBox(NULL, + TEXT("An error occured while reading command line arguments."), + TEXT("Error!"), + MB_ICONERROR | MB_OK); + return EXIT_FAILURE; + } + + // Free memory allocated from CommandLineToArgvW. + auto free_command_line_allocated_memory = [&argv]() { + if (argv) { + LocalFree(argv); + argv = nullptr; + } + }; + + // Ensure that a model file has been specified. + if (argc < 2) { + MessageBox(NULL, + TEXT("No model file specified. The program will now close."), + TEXT("Error!"), + MB_ICONERROR | MB_OK); + free_command_line_allocated_memory(); + return EXIT_FAILURE; + } + + // Retrieve the model file path. + g_ModelPath = UTFConverter(argv[1]).str(); + + free_command_line_allocated_memory(); + WNDCLASSEX wc; MSG msg; @@ -160,26 +204,35 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, width = wr.right - wr.left; height = wr.bottom - wr.top; - InitD3D(hInstance, hwnd); + try { + InitD3D(hInstance, hwnd); - while (true) - { - - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + while (true) { - TranslateMessage(&msg); - DispatchMessage(&msg); - if (msg.message == WM_QUIT) - break; + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + + if (msg.message == WM_QUIT) + break; + } + + RenderFrame(); } - RenderFrame(); + CleanD3D(); + return static_cast(msg.wParam); + } catch (const std::exception& e) { + MessageBox(hwnd, e.what(), TEXT("Error!"), MB_ICONERROR | MB_OK); + CleanD3D(); + return EXIT_FAILURE; + } catch (...) { + MessageBox(hwnd, TEXT("Caught an unknown exception."), TEXT("Error!"), MB_ICONERROR | MB_OK); + CleanD3D(); + return EXIT_FAILURE; } - - CleanD3D(); - - return msg.wParam; } void InitD3D(HINSTANCE hinstance, HWND hWnd) @@ -227,6 +280,12 @@ void InitD3D(HINSTANCE hinstance, HWND hWnd) if (FAILED(hr)) Throwanerror("Directx Device Creation Failed!"); +#if _DEBUG + hr = dev->QueryInterface(IID_PPV_ARGS(&d3d11debug)); + if (FAILED(hr)) + OutputDebugString(TEXT("Failed to retrieve DirectX 11 debug interface.\n")); +#endif + UINT m4xMsaaQuality; dev->CheckMultisampleQualityLevels( DXGI_FORMAT_R8G8B8A8_UNORM, 4, &m4xMsaaQuality); @@ -348,7 +407,6 @@ void InitD3D(HINSTANCE hinstance, HWND hWnd) devcon->OMSetRenderTargets(1, &backbuffer, g_pDepthStencilView); D3D11_RASTERIZER_DESC rasterDesc; - ID3D11RasterizerState *rasterState; rasterDesc.AntialiasedLineEnable = false; rasterDesc.CullMode = D3D11_CULL_BACK; rasterDesc.DepthBias = 0; @@ -360,8 +418,8 @@ void InitD3D(HINSTANCE hinstance, HWND hWnd) rasterDesc.ScissorEnable = false; rasterDesc.SlopeScaledDepthBias = 0.0f; - dev->CreateRasterizerState(&rasterDesc, &rasterState); - devcon->RSSetState(rasterState); + dev->CreateRasterizerState(&rasterDesc, &rasterstate); + devcon->RSSetState(rasterstate); D3D11_VIEWPORT viewport; ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT)); @@ -381,19 +439,38 @@ void InitD3D(HINSTANCE hinstance, HWND hWnd) void CleanD3D(void) { - swapchain->SetFullscreenState(FALSE, NULL); + if (swapchain) + swapchain->SetFullscreenState(FALSE, NULL); - ourModel->Close(); - g_pDepthStencil->Release(); - g_pDepthStencilView->Release(); - pLayout->Release(); - pVS->Release(); - pPS->Release(); - pConstantBuffer->Release(); - swapchain->Release(); - backbuffer->Release(); - dev->Release(); - devcon->Release(); + if (ourModel) { + ourModel->Close(); + delete ourModel; + ourModel = nullptr; + } + SafeRelease(TexSamplerState); + SafeRelease(pConstantBuffer); + SafeRelease(pLayout); + SafeRelease(pVS); + SafeRelease(pPS); + SafeRelease(rasterstate); + SafeRelease(g_pDepthStencilView); + SafeRelease(g_pDepthStencil); + SafeRelease(backbuffer); + SafeRelease(swapchain); + SafeRelease(swapchain1); + SafeRelease(devcon1); + SafeRelease(dev1); + SafeRelease(devcon); +#if _DEBUG + if (d3d11debug) { + OutputDebugString(TEXT("Dumping DirectX 11 live objects.\n")); + d3d11debug->ReportLiveDeviceObjects(D3D11_RLDO_DETAIL); + SafeRelease(d3d11debug); + } else { + OutputDebugString(TEXT("Unable to dump live objects: no DirectX 11 debug interface available.\n")); + } +#endif + SafeRelease(dev); } void RenderFrame(void) @@ -431,8 +508,10 @@ void RenderFrame(void) void InitPipeline() { ID3DBlob *VS, *PS; - CompileShaderFromFile(L"VertexShader.hlsl", 0, "main", "vs_4_0", &VS); - CompileShaderFromFile(L"PixelShader.hlsl", 0, "main", "ps_4_0", &PS); + if(FAILED(CompileShaderFromFile(SHADER_PATH VERTEX_SHADER_FILE, 0, "main", "vs_4_0", &VS))) + Throwanerror(UTFConverter(L"Failed to compile shader from file " VERTEX_SHADER_FILE).c_str()); + if(FAILED(CompileShaderFromFile(SHADER_PATH PIXEL_SHADER_FILE, 0, "main", "ps_4_0", &PS))) + Throwanerror(UTFConverter(L"Failed to compile shader from file " PIXEL_SHADER_FILE).c_str()); dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS); dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS); @@ -485,7 +564,7 @@ void InitGraphics() m_View = XMMatrixLookAtLH(Eye, At, Up); ourModel = new ModelLoader; - if (!ourModel->Load(hwnd, dev, devcon, "Models/myModel.fbx")) + if (!ourModel->Load(hwnd, dev, devcon, g_ModelPath)) Throwanerror("Model couldn't be loaded"); } @@ -514,5 +593,5 @@ HRESULT CompileShaderFromFile(LPCWSTR pFileName, const D3D_SHADER_MACRO* pDefine void Throwanerror(LPCSTR errormessage) { - MessageBox(hwnd, errormessage, "Error!", MB_ICONERROR | MB_OK); -} \ No newline at end of file + throw std::runtime_error(errormessage); +} diff --git a/samples/SimpleTexturedOpenGL/CMakeLists.txt b/samples/SimpleTexturedOpenGL/CMakeLists.txt index adcf882a8..e40c40f29 100644 --- a/samples/SimpleTexturedOpenGL/CMakeLists.txt +++ b/samples/SimpleTexturedOpenGL/CMakeLists.txt @@ -21,6 +21,7 @@ INCLUDE_DIRECTORIES( ${Assimp_SOURCE_DIR}/code ${OPENGL_INCLUDE_DIR} ${GLUT_INCLUDE_DIR} + ${SAMPLES_SHARED_CODE_DIR} ) LINK_DIRECTORIES( @@ -31,6 +32,8 @@ LINK_DIRECTORIES( ADD_EXECUTABLE( assimp_simpletexturedogl WIN32 SimpleTexturedOpenGL/include/boost_includes.h SimpleTexturedOpenGL/src/model_loading.cpp + ${SAMPLES_SHARED_CODE_DIR}/UTFConverter.cpp + ${SAMPLES_SHARED_CODE_DIR}/UTFConverter.h ) SET_PROPERTY(TARGET assimp_simpletexturedogl PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) diff --git a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp index 8c2a08b2e..452c0715c 100644 --- a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp +++ b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp @@ -21,8 +21,6 @@ #define STB_IMAGE_IMPLEMENTATION #include "contrib/stb_image/stb_image.h" -#include -#include #include //to map image filenames to textureIds @@ -35,7 +33,7 @@ #include #include #include - +#include "UTFConverter.h" // The default hard-coded path. Can be overridden by supplying a path through the command line. static std::string modelpath = "../../test/models/OBJ/spider.obj"; @@ -77,35 +75,7 @@ GLuint* textureIds; // pointer to texture Array // Create an instance of the Importer class Assimp::Importer importer; -// Used to convert between multibyte and unicode strings. -class UTFConverter { - using UTFConverterImpl = std::wstring_convert, wchar_t>; -public: - UTFConverter(const char* s) : - s_(s), - ws_(impl_.from_bytes(s)) { - } - UTFConverter(const std::string& s) : - s_(s), - ws_(impl_.from_bytes(s)) { - } - UTFConverter(const std::wstring& s) : - s_(impl_.to_bytes(s)), - ws_(s) { - } - inline const std::string& str() const { - return s_; - } - inline const wchar_t* c_wstr() const { - return ws_.c_str(); - } -private: - static UTFConverterImpl impl_; - std::string s_; - std::wstring ws_; -}; - -typename UTFConverter::UTFConverterImpl UTFConverter::impl_; +using namespace AssimpSamples::SharedCode; void createAILogger() {