Prechádzať zdrojové kódy

Merge pull request #3053 from malortie/fix-simpledirectx11-sample

Fixed SimpleTexturedDirectX11 sample.
Kim Kulling 5 rokov pred
rodič
commit
1e2c3c9c01

+ 2 - 0
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 )

+ 52 - 0
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_;
+
+}
+}

+ 92 - 0
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 <string>
+#include <locale>
+#include <codecvt>
+
+namespace AssimpSamples {
+namespace SharedCode {
+
+// Used to convert between multibyte and unicode strings.
+class UTFConverter {
+    using UTFConverterImpl = std::wstring_convert<std::codecvt_utf8<wchar_t>, 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

+ 6 - 3
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})

+ 78 - 73
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h

@@ -6,13 +6,14 @@
 #include <sstream>
 #include <iostream>
 #include <vector>
-using namespace std;
-
-#include <vector>
+#include <stdexcept>
 #include <d3d11_1.h>
 #include <DirectXMath.h>
+
 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<VERTEX> vertices;
-	vector<UINT> indices;
-	vector<Texture> textures;
-	ID3D11Device *dev;
-
-	Mesh(ID3D11Device *dev, vector<VERTEX> vertices, vector<UINT> indices, vector<Texture> textures)
-	{
-		this->vertices = vertices;
-		this->indices = indices;
-		this->textures = textures;
-
-		this->dev = dev;
-
-		this->setupMesh(dev);
-	}
-
-	void Draw(ID3D11DeviceContext *devcon)
-	{
-		UINT stride = sizeof(VERTEX);
-		UINT offset = 0;
-
-		devcon->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset);
-		devcon->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0);
-
-		devcon->PSSetShaderResources(0, 1, &textures[0].texture);
-
-		devcon->DrawIndexed(indices.size(), 0, 0);
-	}
-
-	void Close()
-	{
-		VertexBuffer->Release();
-		IndexBuffer->Release();
-	}
+    std::vector<VERTEX> vertices;
+    std::vector<UINT> indices;
+    std::vector<Texture> textures;
+    ID3D11Device *dev;
+
+    Mesh(ID3D11Device *dev, const vector<VERTEX>& vertices, const vector<UINT>& indices, const vector<Texture>& textures) :
+            vertices(vertices),
+            indices(indices),
+            textures(textures),
+            dev(dev),
+            VertexBuffer(nullptr),
+            IndexBuffer(nullptr) {
+        this->setupMesh(this->dev);
+    }
+
+    void Draw(ID3D11DeviceContext *devcon) {
+        UINT stride = sizeof(VERTEX);
+        UINT offset = 0;
+
+        devcon->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset);
+        devcon->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0);
+
+        devcon->PSSetShaderResources(0, 1, &textures[0].texture);
+
+        devcon->DrawIndexed(static_cast<UINT>(indices.size()), 0, 0);
+    }
+
+    void Close() {
+        SafeRelease(VertexBuffer);
+        SafeRelease(IndexBuffer);
+    }
 private:
-	/*  Render data  */
-	ID3D11Buffer *VertexBuffer, *IndexBuffer;
-
-	/*  Functions    */
-	// Initializes all the buffer objects/arrays
-	bool 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_SUBRESOURCE_DATA initData;
-		initData.pSysMem = &vertices[0];
-
-		hr = dev->CreateBuffer(&vbd, &initData, &VertexBuffer);
-		if (FAILED(hr))
-			return false;
-
-		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;
-
-		initData.pSysMem = &indices[0];
-
-		hr = dev->CreateBuffer(&ibd, &initData, &IndexBuffer);
-		if (FAILED(hr))
-			return false;
-	}
+    // Render data
+    ID3D11Buffer *VertexBuffer, *IndexBuffer;
+
+    // Functions
+    // Initializes all the buffer objects/arrays
+    void setupMesh(ID3D11Device *dev) {
+        HRESULT hr;
+
+        D3D11_BUFFER_DESC vbd;
+        vbd.Usage = D3D11_USAGE_IMMUTABLE;
+        vbd.ByteWidth = static_cast<UINT>(sizeof(VERTEX) * vertices.size());
+        vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+        vbd.CPUAccessFlags = 0;
+        vbd.MiscFlags = 0;
+
+        D3D11_SUBRESOURCE_DATA initData;
+        initData.pSysMem = &vertices[0];
+
+        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 = static_cast<UINT>(sizeof(UINT) * indices.size());
+        ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
+        ibd.CPUAccessFlags = 0;
+        ibd.MiscFlags = 0;
+
+        initData.pSysMem = &indices[0];
+
+        hr = dev->CreateBuffer(&ibd, &initData, &IndexBuffer);
+        if (FAILED(hr)) {
+            Close();
+            throw std::runtime_error("Failed to create index buffer.");
+        }
+    }
 };
 
 #endif

+ 46 - 66
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<VERTEX> vertices;
 	vector<UINT> indices;
 	vector<Texture> 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<Texture> 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<Texture> ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene)
-{
+vector<Texture> ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene) {
 	vector<Texture> 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<Texture> 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;
 

+ 57 - 0
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<typename T>
+inline void SafeRelease(T*& x) {
+    if (x) {
+        x->Release();
+        x = nullptr;
+    }
+}

+ 132 - 53
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp

@@ -14,12 +14,16 @@
 // ---------------------------------------------------------------------------
 
 #include <Windows.h>
+#include <shellapi.h>
+#include <stdexcept>
 #include <windowsx.h>
 #include <d3d11_1.h>
 #include <dxgi1_2.h>
 #include <DirectXMath.h>
 #include <d3dcompiler.h>
 #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);
 
-		RenderFrame();
-	}
+				if (msg.message == WM_QUIT)
+					break;
+			}
 
-	CleanD3D();
+			RenderFrame();
+		}
 
-	return msg.wParam;
+		CleanD3D();
+		return static_cast<int>(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;
+	}
 }
 
 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);
-
-	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 (swapchain)
+		swapchain->SetFullscreenState(FALSE, NULL);
+
+	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);
-}
+	throw std::runtime_error(errormessage);
+}

+ 3 - 0
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})

+ 2 - 32
samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp

@@ -21,8 +21,6 @@
 #define STB_IMAGE_IMPLEMENTATION
 #include "contrib/stb_image/stb_image.h"
 
-#include <locale>
-#include <codecvt>
 #include <fstream>
 
 //to map image filenames to textureIds
@@ -35,7 +33,7 @@
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/LogStream.hpp>
-
+#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<std::codecvt_utf8<wchar_t>, 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()
 {