diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln new file mode 100644 index 000000000..46b37e5ee --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26228.9 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleTexturedDirectx11", "SimpleTexturedDirectx11\SimpleTexturedDirectx11.vcxproj", "{E3B160B5-E71F-4F3F-9310-B8F156F736D8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.ActiveCfg = Debug|x64 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.Build.0 = Debug|x64 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.ActiveCfg = Debug|Win32 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.Build.0 = Debug|Win32 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.ActiveCfg = Release|x64 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.Build.0 = Release|x64 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.ActiveCfg = Release|Win32 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h new file mode 100644 index 000000000..e6a644a94 --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h @@ -0,0 +1,102 @@ +#ifndef MESH_H +#define MESH_H + +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +using namespace DirectX; + +struct VERTEX { + FLOAT X, Y, Z; + XMFLOAT2 texcoord; +}; + +struct Texture { + string type; + string path; + ID3D11ShaderResourceView *texture; +}; + +class Mesh { +public: + vector vertices; + vector indices; + vector textures; + ID3D11Device *dev; + + Mesh(ID3D11Device *dev, vector vertices, vector indices, vector 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(); + } +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; + } +}; + +#endif diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp new file mode 100644 index 000000000..801284383 --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp @@ -0,0 +1,205 @@ +#include "ModelLoader.h" + +ModelLoader::ModelLoader() +{ +} + + +ModelLoader::~ModelLoader() +{ +} + +bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devcon, std::string filename) +{ + Assimp::Importer importer; + + const aiScene* pScene = importer.ReadFile(filename, + aiProcess_Triangulate | + aiProcess_ConvertToLeftHanded); + + if (pScene == NULL) + return false; + + this->directory = filename.substr(0, filename.find_last_of('/')); + + this->dev = dev; + this->hwnd = hwnd; + + processNode(pScene->mRootNode, pScene); + + return true; +} + +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) +{ + // Data to fill + vector vertices; + vector indices; + vector textures; + + if (mesh->mMaterialIndex >= 0) + { + aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex]; + + if (textype.empty()) textype = determineTextureType(scene, mat); + } + + // Walk through each of the mesh's vertices + 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]) + { + vertex.texcoord.x = (float)mesh->mTextureCoords[0][i].x; + vertex.texcoord.y = (float)mesh->mTextureCoords[0][i].y; + } + + vertices.push_back(vertex); + } + + 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) + { + aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; + + vector diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene); + textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); + } + + return Mesh(dev, vertices, indices, textures); +} + +vector ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene) +{ + vector textures; + 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) + { + 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 + HRESULT hr; + Texture texture; + if (textype == "embedded compressed texture") + { + int textureindex = getTextureIndex(&str); + texture.texture = getTextureFromModel(scene, textureindex); + } + else + { + string filename = string(str.C_Str()); + filename = directory + '/' + filename; + wstring filenamews = wstring(filename.begin(), filename.end()); + hr = CreateWICTextureFromFile(dev, devcon, filenamews.c_str(), nullptr, &texture.texture); + if (FAILED(hr)) + MessageBox(hwnd, "Texture couldn't be loaded", "Error!", MB_ICONERROR | MB_OK); + } + texture.type = typeName; + texture.path = str.C_Str(); + textures.push_back(texture); + this->textures_loaded.push_back(texture); // Store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures. + } + } + return textures; +} + +void ModelLoader::Close() +{ + 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++) + { + aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; + meshes.push_back(this->processMesh(mesh, scene)); + } + + for (UINT i = 0; i < node->mNumChildren; i++) + { + this->processNode(node->mChildren[i], scene); + } +} + +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) + { + return "embedded compressed texture"; + } + else + { + return "embedded non-compressed texture"; + } + } + if (textypeteststr.find('.') != string::npos) + { + return "textures are on disk"; + } +} + +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) +{ + HRESULT hr; + ID3D11ShaderResourceView *texture; + + int* size = reinterpret_cast(&scene->mTextures[textureindex]->mWidth); + + hr = CreateWICTextureFromMemory(dev, devcon, reinterpret_cast(scene->mTextures[textureindex]->pcData), *size, nullptr, &texture); + if (FAILED(hr)) + MessageBox(hwnd, "Texture couldn't be created from memory!", "Error!", MB_ICONERROR | MB_OK); + + return texture; +} diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h new file mode 100644 index 000000000..020708fbf --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h @@ -0,0 +1,44 @@ +#ifndef MODEL_LOADER_H +#define MODEL_LOADER_H + +#include +#include +#include + +#include +#include +#include + +#include "Mesh.h" +#include "TextureLoader.h" + +using namespace DirectX; + +class ModelLoader +{ +public: + ModelLoader(); + ~ModelLoader(); + + bool Load(HWND hwnd, ID3D11Device* dev, ID3D11DeviceContext* devcon, std::string filename); + void Draw(ID3D11DeviceContext* devcon); + + void Close(); +private: + ID3D11Device *dev; + ID3D11DeviceContext *devcon; + std::vector meshes; + string directory; + vector textures_loaded; + HWND hwnd; + + void processNode(aiNode* node, const aiScene* scene); + Mesh processMesh(aiMesh* mesh, const aiScene* scene); + vector loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName, const aiScene* scene); + string determineTextureType(const aiScene* scene, aiMaterial* mat); + int getTextureIndex(aiString* str); + ID3D11ShaderResourceView* getTextureFromModel(const aiScene* scene, int textureindex); +}; + +#endif // !MODEL_LOADER_H + diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/PixelShader.hlsl b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/PixelShader.hlsl new file mode 100644 index 000000000..2e8b4eeda --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/PixelShader.hlsl @@ -0,0 +1,9 @@ +Texture2D diffTexture; +SamplerState SampleType; + +float4 main(float4 pos : SV_POSITION, float2 texcoord : TEXCOORD) : SV_TARGET +{ + float4 textureColor = diffTexture.Sample(SampleType, texcoord); + + return textureColor; +} \ No newline at end of file diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj new file mode 100644 index 000000000..fc82bc18e --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj @@ -0,0 +1,146 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8} + SimpleTexturedDirectx11 + 10.0.14393.0 + + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(IncludePath);E:\OpenGL VS Files\include + $(LibraryPath);E:\OpenGL VS Files\lib + + + + Level3 + Disabled + true + + + assimp-vc140-mt.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + + + + + + Pixel + Pixel + Pixel + Pixel + + + Vertex + Vertex + Vertex + Vertex + + + + + + + + + + + \ No newline at end of file diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters new file mode 100644 index 000000000..271300ad8 --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters @@ -0,0 +1,50 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {b6a86d3e-70a5-4d1e-ba05-c20902300206} + + + + + Source Files + + + Source Files + + + Source Files + + + + + Shaders + + + Shaders + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp new file mode 100644 index 000000000..13b3195ca --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp @@ -0,0 +1,691 @@ +//-------------------------------------------------------------------------------------- +// File: WICTextureLoader.cpp +// +// Function for loading a WIC image and creating a Direct3D 11 runtime texture for it +// (auto-generating mipmaps if possible) +// +// Note: Assumes application has already called CoInitializeEx +// +// Warning: CreateWICTexture* functions are not thread-safe if given a d3dContext instance for +// auto-gen mipmap support. +// +// Note these functions are useful for images created as simple 2D textures. For +// more complex resources, DDSTextureLoader is an excellent light-weight runtime loader. +// For a full-featured DDS file reader, writer, and texture processing pipeline see +// the 'Texconv' sample and the 'DirectXTex' library. +// +// 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=248926 +// http://go.microsoft.com/fwlink/?LinkId=248929 +//-------------------------------------------------------------------------------------- + +// We could load multi-frame images (TIFF/GIF) into a texture array. +// For now, we just load the first frame (note: DirectXTex supports multi-frame images) + +#include +#include + +#pragma warning(push) +#pragma warning(disable : 4005) +#include +#pragma warning(pop) + +#include + +#include "TextureLoader.h" + +#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) && !defined(DXGI_1_2_FORMATS) +#define DXGI_1_2_FORMATS +#endif + +//--------------------------------------------------------------------------------- +template class ScopedObject +{ +public: + explicit ScopedObject(T *p = 0) : _pointer(p) {} + ~ScopedObject() + { + if (_pointer) + { + _pointer->Release(); + _pointer = nullptr; + } + } + + bool IsNull() const { return (!_pointer); } + + T& operator*() { return *_pointer; } + T* operator->() { return _pointer; } + T** operator&() { return &_pointer; } + + void Reset(T *p = 0) { if (_pointer) { _pointer->Release(); } _pointer = p; } + + T* Get() const { return _pointer; } + +private: + ScopedObject(const ScopedObject&); + ScopedObject& operator=(const ScopedObject&); + + T* _pointer; +}; + +//------------------------------------------------------------------------------------- +// WIC Pixel Format Translation Data +//------------------------------------------------------------------------------------- +struct WICTranslate +{ + GUID wic; + DXGI_FORMAT format; +}; + +static WICTranslate g_WICFormats[] = +{ + { GUID_WICPixelFormat128bppRGBAFloat, DXGI_FORMAT_R32G32B32A32_FLOAT }, + + { GUID_WICPixelFormat64bppRGBAHalf, DXGI_FORMAT_R16G16B16A16_FLOAT }, + { GUID_WICPixelFormat64bppRGBA, DXGI_FORMAT_R16G16B16A16_UNORM }, + + { GUID_WICPixelFormat32bppRGBA, DXGI_FORMAT_R8G8B8A8_UNORM }, + { GUID_WICPixelFormat32bppBGRA, DXGI_FORMAT_B8G8R8A8_UNORM }, // DXGI 1.1 + { GUID_WICPixelFormat32bppBGR, DXGI_FORMAT_B8G8R8X8_UNORM }, // DXGI 1.1 + + { GUID_WICPixelFormat32bppRGBA1010102XR, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, // DXGI 1.1 + { GUID_WICPixelFormat32bppRGBA1010102, DXGI_FORMAT_R10G10B10A2_UNORM }, + { GUID_WICPixelFormat32bppRGBE, DXGI_FORMAT_R9G9B9E5_SHAREDEXP }, + +#ifdef DXGI_1_2_FORMATS + + { GUID_WICPixelFormat16bppBGRA5551, DXGI_FORMAT_B5G5R5A1_UNORM }, + { GUID_WICPixelFormat16bppBGR565, DXGI_FORMAT_B5G6R5_UNORM }, + +#endif // DXGI_1_2_FORMATS + + { GUID_WICPixelFormat32bppGrayFloat, DXGI_FORMAT_R32_FLOAT }, + { GUID_WICPixelFormat16bppGrayHalf, DXGI_FORMAT_R16_FLOAT }, + { GUID_WICPixelFormat16bppGray, DXGI_FORMAT_R16_UNORM }, + { GUID_WICPixelFormat8bppGray, DXGI_FORMAT_R8_UNORM }, + + { GUID_WICPixelFormat8bppAlpha, DXGI_FORMAT_A8_UNORM }, + +#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) + { GUID_WICPixelFormat96bppRGBFloat, DXGI_FORMAT_R32G32B32_FLOAT }, +#endif +}; + +//------------------------------------------------------------------------------------- +// WIC Pixel Format nearest conversion table +//------------------------------------------------------------------------------------- + +struct WICConvert +{ + GUID source; + GUID target; +}; + +static WICConvert g_WICConvert[] = +{ + // Note target GUID in this conversion table must be one of those directly supported formats (above). + + { GUID_WICPixelFormatBlackWhite, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM + + { GUID_WICPixelFormat1bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat2bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat4bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat8bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + + { GUID_WICPixelFormat2bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM + { GUID_WICPixelFormat4bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM + + { GUID_WICPixelFormat16bppGrayFixedPoint, GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT + { GUID_WICPixelFormat32bppGrayFixedPoint, GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT + +#ifdef DXGI_1_2_FORMATS + + { GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM + +#else + + { GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat16bppBGRA5551, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat16bppBGR565, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + +#endif // DXGI_1_2_FORMATS + + { GUID_WICPixelFormat32bppBGR101010, GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM + + { GUID_WICPixelFormat24bppBGR, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat24bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat32bppPBGRA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat32bppPRGBA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + + { GUID_WICPixelFormat48bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat48bppBGR, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppPRGBA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppPBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + + { GUID_WICPixelFormat48bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat48bppBGRFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppRGBAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppBGRAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat48bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + + { GUID_WICPixelFormat96bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppPRGBAFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppRGBFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppRGBAFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + + { GUID_WICPixelFormat32bppCMYK, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat64bppCMYK, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat40bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat80bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + +#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) + { GUID_WICPixelFormat32bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat64bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppPRGBAHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT +#endif + + // We don't support n-channel formats +}; + +//-------------------------------------------------------------------------------------- +static IWICImagingFactory* _GetWIC() +{ + static IWICImagingFactory* s_Factory = nullptr; + + if (s_Factory) + return s_Factory; + + HRESULT hr = CoCreateInstance( + CLSID_WICImagingFactory, + nullptr, + CLSCTX_INPROC_SERVER, + __uuidof(IWICImagingFactory), + (LPVOID*)&s_Factory + ); + + if (FAILED(hr)) + { + s_Factory = nullptr; + return nullptr; + } + + return s_Factory; +} + +//--------------------------------------------------------------------------------- +static DXGI_FORMAT _WICToDXGI(const GUID& guid) +{ + for (size_t i = 0; i < _countof(g_WICFormats); ++i) + { + if (memcmp(&g_WICFormats[i].wic, &guid, sizeof(GUID)) == 0) + return g_WICFormats[i].format; + } + + return DXGI_FORMAT_UNKNOWN; +} + +//--------------------------------------------------------------------------------- +static size_t _WICBitsPerPixel(REFGUID targetGuid) +{ + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return 0; + + ScopedObject cinfo; + if (FAILED(pWIC->CreateComponentInfo(targetGuid, &cinfo))) + return 0; + + WICComponentType type; + if (FAILED(cinfo->GetComponentType(&type))) + return 0; + + if (type != WICPixelFormat) + return 0; + + ScopedObject pfinfo; + if (FAILED(cinfo->QueryInterface(__uuidof(IWICPixelFormatInfo), reinterpret_cast(&pfinfo)))) + return 0; + + UINT bpp; + if (FAILED(pfinfo->GetBitsPerPixel(&bpp))) + return 0; + + return bpp; +} + +//--------------------------------------------------------------------------------- +static HRESULT CreateTextureFromWIC(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_ IWICBitmapFrameDecode *frame, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize) +{ + UINT width, height; + HRESULT hr = frame->GetSize(&width, &height); + if (FAILED(hr)) + return hr; + + assert(width > 0 && height > 0); + + if (!maxsize) + { + // This is a bit conservative because the hardware could support larger textures than + // the Feature Level defined minimums, but doing it this way is much easier and more + // performant for WIC than the 'fail and retry' model used by DDSTextureLoader + + switch (d3dDevice->GetFeatureLevel()) + { + case D3D_FEATURE_LEVEL_9_1: + case D3D_FEATURE_LEVEL_9_2: + maxsize = 2048 /*D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; + break; + + case D3D_FEATURE_LEVEL_9_3: + maxsize = 4096 /*D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; + break; + + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_10_1: + maxsize = 8192 /*D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; + break; + + default: + maxsize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + break; + } + } + + assert(maxsize > 0); + + UINT twidth, theight; + if (width > maxsize || height > maxsize) + { + float ar = static_cast(height) / static_cast(width); + if (width > height) + { + twidth = static_cast(maxsize); + theight = static_cast(static_cast(maxsize) * ar); + } + else + { + theight = static_cast(maxsize); + twidth = static_cast(static_cast(maxsize) / ar); + } + assert(twidth <= maxsize && theight <= maxsize); + } + else + { + twidth = width; + theight = height; + } + + // Determine format + WICPixelFormatGUID pixelFormat; + hr = frame->GetPixelFormat(&pixelFormat); + if (FAILED(hr)) + return hr; + + WICPixelFormatGUID convertGUID; + memcpy(&convertGUID, &pixelFormat, sizeof(WICPixelFormatGUID)); + + size_t bpp = 0; + + DXGI_FORMAT format = _WICToDXGI(pixelFormat); + if (format == DXGI_FORMAT_UNKNOWN) + { + for (size_t i = 0; i < _countof(g_WICConvert); ++i) + { + if (memcmp(&g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0) + { + memcpy(&convertGUID, &g_WICConvert[i].target, sizeof(WICPixelFormatGUID)); + + format = _WICToDXGI(g_WICConvert[i].target); + assert(format != DXGI_FORMAT_UNKNOWN); + bpp = _WICBitsPerPixel(convertGUID); + break; + } + } + + if (format == DXGI_FORMAT_UNKNOWN) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + else + { + bpp = _WICBitsPerPixel(pixelFormat); + } + + if (!bpp) + return E_FAIL; + + // Verify our target format is supported by the current device + // (handles WDDM 1.0 or WDDM 1.1 device driver cases as well as DirectX 11.0 Runtime without 16bpp format support) + UINT support = 0; + hr = d3dDevice->CheckFormatSupport(format, &support); + if (FAILED(hr) || !(support & D3D11_FORMAT_SUPPORT_TEXTURE2D)) + { + // Fallback to RGBA 32-bit format which is supported by all devices + memcpy(&convertGUID, &GUID_WICPixelFormat32bppRGBA, sizeof(WICPixelFormatGUID)); + format = DXGI_FORMAT_R8G8B8A8_UNORM; + bpp = 32; + } + + // Allocate temporary memory for image + size_t rowPitch = (twidth * bpp + 7) / 8; + size_t imageSize = rowPitch * theight; + + std::unique_ptr temp(new uint8_t[imageSize]); + + // Load image data + if (memcmp(&convertGUID, &pixelFormat, sizeof(GUID)) == 0 + && twidth == width + && theight == height) + { + // No format conversion or resize needed + hr = frame->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + else if (twidth != width || theight != height) + { + // Resize + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + ScopedObject scaler; + hr = pWIC->CreateBitmapScaler(&scaler); + if (FAILED(hr)) + return hr; + + hr = scaler->Initialize(frame, twidth, theight, WICBitmapInterpolationModeFant); + if (FAILED(hr)) + return hr; + + WICPixelFormatGUID pfScaler; + hr = scaler->GetPixelFormat(&pfScaler); + if (FAILED(hr)) + return hr; + + if (memcmp(&convertGUID, &pfScaler, sizeof(GUID)) == 0) + { + // No format conversion needed + hr = scaler->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + else + { + ScopedObject FC; + hr = pWIC->CreateFormatConverter(&FC); + if (FAILED(hr)) + return hr; + + hr = FC->Initialize(scaler.Get(), convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom); + if (FAILED(hr)) + return hr; + + hr = FC->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + } + else + { + // Format conversion but no resize + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + ScopedObject FC; + hr = pWIC->CreateFormatConverter(&FC); + if (FAILED(hr)) + return hr; + + hr = FC->Initialize(frame, convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom); + if (FAILED(hr)) + return hr; + + hr = FC->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + + // See if format is supported for auto-gen mipmaps (varies by feature level) + bool autogen = false; + if (d3dContext != 0 && textureView != 0) // Must have context and shader-view to auto generate mipmaps + { + UINT fmtSupport = 0; + hr = d3dDevice->CheckFormatSupport(format, &fmtSupport); + if (SUCCEEDED(hr) && (fmtSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN)) + { + autogen = true; + } + } + + // Create texture + D3D11_TEXTURE2D_DESC desc; + desc.Width = twidth; + desc.Height = theight; + desc.MipLevels = (autogen) ? 0 : 1; + desc.ArraySize = 1; + desc.Format = format; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = (autogen) ? (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) : (D3D11_BIND_SHADER_RESOURCE); + desc.CPUAccessFlags = 0; + desc.MiscFlags = (autogen) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0; + + D3D11_SUBRESOURCE_DATA initData; + initData.pSysMem = temp.get(); + initData.SysMemPitch = static_cast(rowPitch); + initData.SysMemSlicePitch = static_cast(imageSize); + + ID3D11Texture2D* tex = nullptr; + hr = d3dDevice->CreateTexture2D(&desc, (autogen) ? nullptr : &initData, &tex); + if (SUCCEEDED(hr) && tex != 0) + { + if (textureView != 0) + { + D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; + memset(&SRVDesc, 0, sizeof(SRVDesc)); + SRVDesc.Format = format; + SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + SRVDesc.Texture2D.MipLevels = (autogen) ? -1 : 1; + + hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, textureView); + if (FAILED(hr)) + { + tex->Release(); + return hr; + } + + if (autogen) + { + assert(d3dContext != 0); + d3dContext->UpdateSubresource(tex, 0, nullptr, temp.get(), static_cast(rowPitch), static_cast(imageSize)); + d3dContext->GenerateMips(*textureView); + } + } + + if (texture != 0) + { + *texture = tex; + } + else + { +#if defined(_DEBUG) || defined(PROFILE) + tex->SetPrivateData(WKPDID_D3DDebugObjectName, + sizeof("WICTextureLoader") - 1, + "WICTextureLoader" + ); +#endif + tex->Release(); + } + } + + return hr; +} + +//-------------------------------------------------------------------------------------- +HRESULT CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_bytecount_(wicDataSize) const uint8_t* wicData, + _In_ size_t wicDataSize, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize +) +{ + if (!d3dDevice || !wicData || (!texture && !textureView)) + { + return E_INVALIDARG; + } + + if (!wicDataSize) + { + return E_FAIL; + } + +#ifdef _M_AMD64 + if (wicDataSize > 0xFFFFFFFF) + return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE); +#endif + + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + // Create input stream for memory + ScopedObject stream; + HRESULT hr = pWIC->CreateStream(&stream); + if (FAILED(hr)) + return hr; + + hr = stream->InitializeFromMemory(const_cast(wicData), static_cast(wicDataSize)); + if (FAILED(hr)) + return hr; + + // Initialize WIC + ScopedObject decoder; + hr = pWIC->CreateDecoderFromStream(stream.Get(), 0, WICDecodeMetadataCacheOnDemand, &decoder); + if (FAILED(hr)) + return hr; + + ScopedObject frame; + hr = decoder->GetFrame(0, &frame); + if (FAILED(hr)) + return hr; + + hr = CreateTextureFromWIC(d3dDevice, d3dContext, frame.Get(), texture, textureView, maxsize); + if (FAILED(hr)) + return hr; + +#if defined(_DEBUG) || defined(PROFILE) + if (texture != 0 && *texture != 0) + { + (*texture)->SetPrivateData(WKPDID_D3DDebugObjectName, + sizeof("WICTextureLoader") - 1, + "WICTextureLoader" + ); + } + + if (textureView != 0 && *textureView != 0) + { + (*textureView)->SetPrivateData(WKPDID_D3DDebugObjectName, + sizeof("WICTextureLoader") - 1, + "WICTextureLoader" + ); + } +#endif + + return hr; +} + +//-------------------------------------------------------------------------------------- +HRESULT CreateWICTextureFromFile(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_z_ const wchar_t* fileName, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize) +{ + if (!d3dDevice || !fileName || (!texture && !textureView)) + { + return E_INVALIDARG; + } + + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + // Initialize WIC + ScopedObject decoder; + HRESULT hr = pWIC->CreateDecoderFromFilename(fileName, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &decoder); + if (FAILED(hr)) + return hr; + + ScopedObject frame; + hr = decoder->GetFrame(0, &frame); + if (FAILED(hr)) + return hr; + + hr = CreateTextureFromWIC(d3dDevice, d3dContext, frame.Get(), texture, textureView, maxsize); + if (FAILED(hr)) + return hr; + +#if defined(_DEBUG) || defined(PROFILE) + if (texture != 0 || textureView != 0) + { + CHAR strFileA[MAX_PATH]; + WideCharToMultiByte(CP_ACP, + WC_NO_BEST_FIT_CHARS, + fileName, + -1, + strFileA, + MAX_PATH, + nullptr, + FALSE + ); + const CHAR* pstrName = strrchr(strFileA, '\\'); + if (!pstrName) + { + pstrName = strFileA; + } + else + { + pstrName++; + } + + if (texture != 0 && *texture != 0) + { + (*texture)->SetPrivateData(WKPDID_D3DDebugObjectName, + static_cast(strnlen_s(pstrName, MAX_PATH)), + pstrName + ); + } + + if (textureView != 0 && *textureView != 0) + { + (*textureView)->SetPrivateData(WKPDID_D3DDebugObjectName, + static_cast(strnlen_s(pstrName, MAX_PATH)), + pstrName + ); + } + } +#endif + + return hr; +} diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h new file mode 100644 index 000000000..60308d9fa --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h @@ -0,0 +1,55 @@ +//-------------------------------------------------------------------------------------- +// File: WICTextureLoader.h +// +// Function for loading a WIC image and creating a Direct3D 11 runtime texture for it +// (auto-generating mipmaps if possible) +// +// Note: Assumes application has already called CoInitializeEx +// +// Warning: CreateWICTexture* functions are not thread-safe if given a d3dContext instance for +// auto-gen mipmap support. +// +// Note these functions are useful for images created as simple 2D textures. For +// more complex resources, DDSTextureLoader is an excellent light-weight runtime loader. +// For a full-featured DDS file reader, writer, and texture processing pipeline see +// the 'Texconv' sample and the 'DirectXTex' library. +// +// 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=248926 +// http://go.microsoft.com/fwlink/?LinkId=248929 +//-------------------------------------------------------------------------------------- + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#pragma warning(push) +#pragma warning(disable : 4005) +#include +#pragma warning(pop) + +HRESULT CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_bytecount_(wicDataSize) const uint8_t* wicData, + _In_ size_t wicDataSize, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0 +); + +HRESULT CreateWICTextureFromFile(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_z_ const wchar_t* szFileName, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0 +); + diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/VertexShader.hlsl b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/VertexShader.hlsl new file mode 100644 index 000000000..cf7ee16ac --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/VertexShader.hlsl @@ -0,0 +1,23 @@ +cbuffer ConstantBuffer : register(b0) +{ + matrix World; + matrix View; + matrix Projection; +} + +struct VOut { + float4 pos : SV_POSITION; + float2 texcoord : TEXCOORD; +}; + +VOut main(float4 pos : POSITION, float2 texcoord : TEXCOORD) +{ + VOut output; + + output.pos = mul(pos, World); + output.pos = mul(output.pos, View); + output.pos = mul(output.pos, Projection); + output.texcoord = texcoord; + + return output; +} \ No newline at end of file diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp new file mode 100644 index 000000000..5c5e8a107 --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp @@ -0,0 +1,518 @@ +// --------------------------------------------------------------------------- +// Simple Assimp Directx11 Sample +// This is a very basic sample and only reads diffuse texture +// but this can load both embedded textures in fbx and non-embedded textures +// +// +// Replace ourModel->Load(hwnd, dev, devcon, "Models/myModel.fbx") this with your +// model name (line 480) +// If your model isn't a fbx with embedded textures make sure your model's +// textures are in same directory as your model +// +// +// Written by IAS. :) +// --------------------------------------------------------------------------- + +#include +#include +#include +#include +#include +#include +#include "ModelLoader.h" + +#pragma comment (lib, "d3d11.lib") +#pragma comment (lib, "Dxgi.lib") +#pragma comment(lib,"d3dcompiler.lib") +#pragma comment (lib, "dxguid.lib") + +using namespace DirectX; + +// ------------------------------------------------------------ +// Structs +// ------------------------------------------------------------ +struct ConstantBuffer { + XMMATRIX mWorld; + XMMATRIX mView; + XMMATRIX mProjection; +}; + +// ------------------------------------------------------------ +// Window Variables +// ------------------------------------------------------------ +#define SCREEN_WIDTH 800 +#define SCREEN_HEIGHT 600 + +const char g_szClassName[] = "directxWindowClass"; + + +UINT width, height; +HWND hwnd; + +// ------------------------------------------------------------ +// 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; + +XMMATRIX m_World; +XMMATRIX m_View; +XMMATRIX m_Projection; + +// ------------------------------------------------------------ +// Function identifiers +// ------------------------------------------------------------ + +void InitD3D(HINSTANCE hinstance, HWND hWnd); +void CleanD3D(void); +void RenderFrame(void); + +void InitPipeline(); +void InitGraphics(); + +HRESULT CompileShaderFromFile(LPCWSTR pFileName, const D3D_SHADER_MACRO* pDefines, LPCSTR pEntryPoint, LPCSTR pShaderModel, ID3DBlob** ppBytecodeBlob); +void Throwanerror(LPCSTR errormessage); + +// ------------------------------------------------------------ +// Our Model +// ------------------------------------------------------------ + +ModelLoader *ourModel; + +LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_CLOSE: + DestroyWindow(hwnd); + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return 0; +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, int nCmdShow) +{ + WNDCLASSEX wc; + MSG msg; + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = 0; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = g_szClassName; + wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + if (!RegisterClassEx(&wc)) + { + MessageBox(NULL, "Window Registration Failed!", "Error!", + MB_ICONEXCLAMATION | MB_OK); + return 0; + } + + RECT wr = { 0,0, SCREEN_WIDTH, SCREEN_HEIGHT }; + AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); + + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + g_szClassName, + " Simple Textured Directx11 Sample ", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, wr.right - wr.left, wr.bottom - wr.top, + NULL, NULL, hInstance, NULL + ); + + if (hwnd == NULL) + { + MessageBox(NULL, "Window Creation Failed!", "Error!", + MB_ICONEXCLAMATION | MB_OK); + return 0; + } + + ShowWindow(hwnd, nCmdShow); + UpdateWindow(hwnd); + + width = wr.right - wr.left; + height = wr.bottom - wr.top; + + InitD3D(hInstance, hwnd); + + while (true) + { + + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + + if (msg.message == WM_QUIT) + break; + } + + RenderFrame(); + } + + CleanD3D(); + + return msg.wParam; +} + +void InitD3D(HINSTANCE hinstance, HWND hWnd) +{ + HRESULT hr; + + UINT createDeviceFlags = 0; +#ifdef _DEBUG + createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; +#endif + + D3D_DRIVER_TYPE driverTypes[] = + { + D3D_DRIVER_TYPE_HARDWARE, + D3D_DRIVER_TYPE_WARP, + D3D_DRIVER_TYPE_REFERENCE, + }; + UINT numDriverTypes = ARRAYSIZE(driverTypes); + + D3D_FEATURE_LEVEL featureLevels[] = + { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + }; + UINT numFeatureLevels = ARRAYSIZE(featureLevels); + + for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++) + { + g_driverType = driverTypes[driverTypeIndex]; + hr = D3D11CreateDevice(nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels, + D3D11_SDK_VERSION, &dev, &g_featureLevel, &devcon); + + if (hr == E_INVALIDARG) + { + // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it + hr = D3D11CreateDevice(nullptr, g_driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1, + D3D11_SDK_VERSION, &dev, &g_featureLevel, &devcon); + } + + if (SUCCEEDED(hr)) + break; + } + if (FAILED(hr)) + Throwanerror("Directx Device Creation Failed!"); + + UINT m4xMsaaQuality; + dev->CheckMultisampleQualityLevels( + DXGI_FORMAT_R8G8B8A8_UNORM, 4, &m4xMsaaQuality); + + + // Obtain DXGI factory from device (since we used nullptr for pAdapter above) + IDXGIFactory1* dxgiFactory = nullptr; + { + IDXGIDevice* dxgiDevice = nullptr; + hr = dev->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&dxgiDevice)); + if (SUCCEEDED(hr)) + { + IDXGIAdapter* adapter = nullptr; + hr = dxgiDevice->GetAdapter(&adapter); + if (SUCCEEDED(hr)) + { + hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast(&dxgiFactory)); + adapter->Release(); + } + dxgiDevice->Release(); + } + } + if (FAILED(hr)) + Throwanerror("DXGI Factory couldn't be obtained!"); + + // Create swap chain + IDXGIFactory2* dxgiFactory2 = nullptr; + hr = dxgiFactory->QueryInterface(__uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory2)); + if (dxgiFactory2) + { + // DirectX 11.1 or later + hr = dev->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast(&dev1)); + if (SUCCEEDED(hr)) + { + (void)devcon->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast(&devcon1)); + } + + DXGI_SWAP_CHAIN_DESC1 sd; + ZeroMemory(&sd, sizeof(sd)); + sd.Width = SCREEN_WIDTH; + sd.Height = SCREEN_HEIGHT; + sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.SampleDesc.Count = 4; + sd.SampleDesc.Quality = m4xMsaaQuality - 1; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.BufferCount = 1; + + hr = dxgiFactory2->CreateSwapChainForHwnd(dev, hWnd, &sd, nullptr, nullptr, &swapchain1); + if (SUCCEEDED(hr)) + { + hr = swapchain1->QueryInterface(__uuidof(IDXGISwapChain), reinterpret_cast(&swapchain)); + } + + dxgiFactory2->Release(); + } + else + { + // DirectX 11.0 systems + DXGI_SWAP_CHAIN_DESC sd; + ZeroMemory(&sd, sizeof(sd)); + sd.BufferCount = 1; + sd.BufferDesc.Width = SCREEN_WIDTH; + sd.BufferDesc.Height = SCREEN_HEIGHT; + sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.BufferDesc.RefreshRate.Numerator = 60; + sd.BufferDesc.RefreshRate.Denominator = 1; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.OutputWindow = hWnd; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = m4xMsaaQuality - 1; + sd.Windowed = TRUE; + + hr = dxgiFactory->CreateSwapChain(dev, &sd, &swapchain); + } + + // Note this tutorial doesn't handle full-screen swapchains so we block the ALT+ENTER shortcut + dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER); + + dxgiFactory->Release(); + + if (FAILED(hr)) + Throwanerror("Swapchain Creation Failed!"); + + ID3D11Texture2D *pBackBuffer; + swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); + + dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer); + pBackBuffer->Release(); + + D3D11_TEXTURE2D_DESC descDepth; + ZeroMemory(&descDepth, sizeof(descDepth)); + descDepth.Width = SCREEN_WIDTH; + descDepth.Height = SCREEN_HEIGHT; + descDepth.MipLevels = 1; + descDepth.ArraySize = 1; + descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + descDepth.SampleDesc.Count = 4; + descDepth.SampleDesc.Quality = m4xMsaaQuality - 1; + descDepth.Usage = D3D11_USAGE_DEFAULT; + descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; + descDepth.CPUAccessFlags = 0; + descDepth.MiscFlags = 0; + hr = dev->CreateTexture2D(&descDepth, nullptr, &g_pDepthStencil); + if (FAILED(hr)) + Throwanerror("Depth Stencil Texture couldn't be created!"); + + // Create the depth stencil view + D3D11_DEPTH_STENCIL_VIEW_DESC descDSV; + ZeroMemory(&descDSV, sizeof(descDSV)); + descDSV.Format = descDepth.Format; + descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + descDSV.Texture2D.MipSlice = 0; + hr = dev->CreateDepthStencilView(g_pDepthStencil, 0, &g_pDepthStencilView); + if (FAILED(hr)) + { + Throwanerror("Depth Stencil View couldn't be created!"); + } + + devcon->OMSetRenderTargets(1, &backbuffer, g_pDepthStencilView); + + D3D11_RASTERIZER_DESC rasterDesc; + ID3D11RasterizerState *rasterState; + rasterDesc.AntialiasedLineEnable = false; + rasterDesc.CullMode = D3D11_CULL_BACK; + rasterDesc.DepthBias = 0; + rasterDesc.DepthBiasClamp = 0.0f; + rasterDesc.DepthClipEnable = true; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.FrontCounterClockwise = false; + rasterDesc.MultisampleEnable = false; + rasterDesc.ScissorEnable = false; + rasterDesc.SlopeScaledDepthBias = 0.0f; + + dev->CreateRasterizerState(&rasterDesc, &rasterState); + devcon->RSSetState(rasterState); + + D3D11_VIEWPORT viewport; + ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT)); + + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + viewport.Width = SCREEN_WIDTH; + viewport.Height = SCREEN_HEIGHT; + + devcon->RSSetViewports(1, &viewport); + + InitPipeline(); + InitGraphics(); +} + +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(); +} + +void RenderFrame(void) +{ + static float t = 0.0f; + static ULONGLONG timeStart = 0; + ULONGLONG timeCur = GetTickCount64(); + if (timeStart == 0) + timeStart = timeCur; + t = (timeCur - timeStart) / 1000.0f; + + float clearColor[4] = { 0.0f, 0.2f, 0.4f, 1.0f }; + devcon->ClearRenderTargetView(backbuffer, clearColor); + devcon->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + + devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + m_World = XMMatrixRotationY(-t); + + ConstantBuffer cb; + cb.mWorld = XMMatrixTranspose(m_World); + cb.mView = XMMatrixTranspose(m_View); + cb.mProjection = XMMatrixTranspose(m_Projection); + devcon->UpdateSubresource(pConstantBuffer, 0, nullptr, &cb, 0, 0); + + devcon->VSSetShader(pVS, 0, 0); + devcon->VSSetConstantBuffers(0, 1, &pConstantBuffer); + devcon->PSSetShader(pPS, 0, 0); + devcon->PSSetSamplers(0, 1, &TexSamplerState); + ourModel->Draw(devcon); + + swapchain->Present(0, 0); +} + +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); + + dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS); + dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS); + + D3D11_INPUT_ELEMENT_DESC ied[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 } + }; + + dev->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout); + devcon->IASetInputLayout(pLayout); +} + +void InitGraphics() +{ + HRESULT hr; + + m_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV4, SCREEN_WIDTH / (float)SCREEN_HEIGHT, 0.01f, 1000.0f); + + D3D11_BUFFER_DESC bd; + ZeroMemory(&bd, sizeof(bd)); + + bd.Usage = D3D11_USAGE_DEFAULT; + bd.ByteWidth = sizeof(ConstantBuffer); + bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + bd.CPUAccessFlags = 0; + + hr = dev->CreateBuffer(&bd, nullptr, &pConstantBuffer); + if (FAILED(hr)) + Throwanerror("Constant buffer couldn't be created"); + + D3D11_SAMPLER_DESC sampDesc; + ZeroMemory(&sampDesc, sizeof(sampDesc)); + sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + + hr = dev->CreateSamplerState(&sampDesc, &TexSamplerState); + if (FAILED(hr)) + Throwanerror("Texture sampler state couldn't be created"); + + XMVECTOR Eye = XMVectorSet(0.0f, 5.0f, -300.0f, 0.0f); + XMVECTOR At = XMVectorSet(0.0f, 100.0f, 0.0f, 0.0f); + XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); + m_View = XMMatrixLookAtLH(Eye, At, Up); + + ourModel = new ModelLoader; + if (!ourModel->Load(hwnd, dev, devcon, "Models/myModel.fbx")) + Throwanerror("Model couldn't be loaded"); +} + +HRESULT CompileShaderFromFile(LPCWSTR pFileName, const D3D_SHADER_MACRO* pDefines, LPCSTR pEntryPoint, LPCSTR pShaderModel, ID3DBlob** ppBytecodeBlob) +{ + UINT compileFlags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR; + +#ifdef _DEBUG + compileFlags |= D3DCOMPILE_DEBUG; +#endif + + ID3DBlob* pErrorBlob = NULL; + + HRESULT result = D3DCompileFromFile(pFileName, pDefines, D3D_COMPILE_STANDARD_FILE_INCLUDE, pEntryPoint, pShaderModel, compileFlags, 0, ppBytecodeBlob, &pErrorBlob); + if (FAILED(result)) + { + if (pErrorBlob != NULL) + OutputDebugStringA((LPCSTR)pErrorBlob->GetBufferPointer()); + } + + if (pErrorBlob != NULL) + pErrorBlob->Release(); + + return result; +} + +void Throwanerror(LPCSTR errormessage) +{ + MessageBox(hwnd, errormessage, "Error!", MB_ICONERROR | MB_OK); +} \ No newline at end of file