├── assets ├── arial.ttf ├── rmlui.png └── demo.rml ├── src ├── core │ ├── CContextManager.h │ ├── CContextManager.cpp │ ├── CSystemInterfaceImpl.h │ ├── CAppManager.h │ ├── shaders │ │ └── shaders.h │ ├── CSystemInterfaceImpl.cpp │ ├── CD3D11Manager.h │ ├── CRenderInterfaceImpl.h │ ├── CRenderInterfaceImpl.cpp │ ├── CD3D11Manager.cpp │ └── CAppManager.cpp ├── utils │ ├── CSingleton.h │ └── TextureStuff.h ├── main.h └── main.cpp ├── README.md ├── CMakeLists.txt ├── .gitignore └── pmm.cmake /assets/arial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martonp96/RmlUi-D3D11/HEAD/assets/arial.ttf -------------------------------------------------------------------------------- /assets/rmlui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/martonp96/RmlUi-D3D11/HEAD/assets/rmlui.png -------------------------------------------------------------------------------- /src/core/CContextManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "utils/CSingleton.h" 3 | #include "RmlUi/Core.h" 4 | 5 | class CContextManager : public CSingleton 6 | { 7 | Rml::Context* context; 8 | public: 9 | void Create(); 10 | Rml::Context* GetContext(); 11 | }; -------------------------------------------------------------------------------- /src/utils/CSingleton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | class CSingleton 5 | { 6 | protected: 7 | CSingleton() = default; 8 | virtual ~CSingleton() = default; 9 | 10 | public: 11 | static inline T* Get() 12 | { 13 | static T s; 14 | return &s; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RmlUi with D3D11 renderer 2 | 3 | ## Build 4 | CMake is needed to generate the project. Run the following command then open the solution file from the newly created directory: 5 | 6 | ``` 7 | cmake -B build 8 | ``` 9 | 10 | ## Rootex 11 | This implementation was based on Rootex: https://github.com/sdslabs/Rootex 12 | -------------------------------------------------------------------------------- /src/core/CContextManager.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | void CContextManager::Create() 4 | { 5 | context = Rml::CreateContext("main", Rml::Vector2i(1280, 800)); 6 | 7 | if (!context) 8 | { 9 | CAppManager::Get()->Msg("Context couldn't be created!"); 10 | } 11 | } 12 | 13 | Rml::Context* CContextManager::GetContext() 14 | { 15 | return context; 16 | } -------------------------------------------------------------------------------- /src/main.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std::chrono_literals; 8 | 9 | #include "core/CAppManager.h" 10 | #include "core/CD3D11Manager.h" 11 | #include "core/CSystemInterfaceImpl.h" 12 | #include "core/CRenderInterfaceImpl.h" 13 | #include "core/CContextManager.h" -------------------------------------------------------------------------------- /assets/demo.rml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Demo 4 | 25 | 26 | 27 | This is a sample. 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/core/CSystemInterfaceImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "utils/CSingleton.h" 3 | #include 4 | #include 5 | 6 | class CSystemInterfaceImpl : public Rml::SystemInterface, public CSingleton 7 | { 8 | std::chrono::steady_clock::time_point startTime; 9 | double GetElapsedTime() override; 10 | void SetClipboardText(const Rml::String& text) override; 11 | void GetClipboardText(Rml::String& text) override; 12 | 13 | bool LogMessage(Rml::Log::Type type, const Rml::String& message) override; 14 | 15 | public: 16 | void SetStartTime(); 17 | }; -------------------------------------------------------------------------------- /src/core/CAppManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "utils/CSingleton.h" 3 | 4 | class CAppManager : public CSingleton 5 | { 6 | bool isRunning; 7 | HWND window; 8 | int width; 9 | int height; 10 | 11 | public: 12 | void Create(int _width, int _height); 13 | void WndProc(UINT msg, WPARAM wParam, LPARAM lParam); 14 | bool IsRunning(); 15 | void HandleMessages(); 16 | 17 | int GetWidth() 18 | { 19 | return width; 20 | } 21 | 22 | int GetHeight() 23 | { 24 | return height; 25 | } 26 | 27 | HWND GetWindow() 28 | { 29 | return window; 30 | } 31 | 32 | void Msg(const char* message, ...); 33 | }; -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | project(rmluidx11) 4 | 5 | file(GLOB_RECURSE PROJECT_SOURCE_FILES "src/*.h" "src/*.cpp") 6 | 7 | macro(GroupSources curdir groupindex) 8 | file(GLOB children RELATIVE ${curdir} ${curdir}/*) 9 | 10 | foreach(child ${children}) 11 | if(IS_DIRECTORY ${curdir}/${child}) 12 | GroupSources(${curdir}/${child} ${groupindex}/${child}) 13 | else() 14 | 15 | string(REPLACE "/" "\\" groupname ${groupindex}) 16 | 17 | source_group(${groupname} FILES ${curdir}/${child}) 18 | endif() 19 | endforeach() 20 | endmacro() 21 | 22 | GroupSources(${PROJECT_SOURCE_DIR}/src "Source Files") 23 | 24 | include(pmm.cmake) 25 | pmm( 26 | VCPKG 27 | REVISION master 28 | TRIPLET x64-windows 29 | REQUIRES rmlui directxtk 30 | ) 31 | 32 | find_package(RmlUi CONFIG REQUIRED) 33 | find_package(directxtk CONFIG REQUIRED) 34 | 35 | add_executable(rmluidx11 ${PROJECT_SOURCE_FILES}) 36 | 37 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 38 | add_definitions(-DUNICODE -D_UNICODE) 39 | 40 | target_link_libraries(rmluidx11 PRIVATE d3d11.lib) 41 | target_link_libraries(rmluidx11 PRIVATE d3dcompiler.lib) 42 | target_link_libraries(rmluidx11 PRIVATE Microsoft::DirectXTK) 43 | target_link_libraries(rmluidx11 PRIVATE RmlCore RmlDebugger) 44 | 45 | include_directories("./" "./src") 46 | 47 | set_property(TARGET rmluidx11 PROPERTY VS_DEBUGGER_WORKING_DIRECTORY $) 48 | 49 | add_custom_command(TARGET rmluidx11 POST_BUILD 50 | COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/assets/ $ 51 | ) 52 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include "RmlUi/Core.h" 3 | #include "RmlUi/Debugger.h" 4 | 5 | int main(int argc, char* argv[]) 6 | { 7 | CAppManager::Get()->Create(1280, 720); 8 | CD3D11Manager::Get()->Create(); 9 | 10 | CSystemInterfaceImpl::Get()->SetStartTime(); 11 | 12 | Rml::SetSystemInterface(CSystemInterfaceImpl::Get()); 13 | Rml::SetRenderInterface(CRenderInterfaceImpl::Get()); 14 | 15 | CRenderInterfaceImpl::Get()->Init(); 16 | 17 | if (!Rml::Initialise()) 18 | { 19 | CAppManager::Get()->Msg("Failed to init RmlUi!"); 20 | } 21 | 22 | CContextManager::Get()->Create(); 23 | auto context = CContextManager::Get()->GetContext(); 24 | 25 | Rml::Debugger::Initialise(context); 26 | Rml::Debugger::SetVisible(true); 27 | 28 | if (!Rml::LoadFontFace("arial.ttf")) 29 | CAppManager::Get()->Msg("Couldn't load font!"); 30 | 31 | Rml::ElementDocument* document = context->LoadDocument("demo.rml"); 32 | 33 | if (document) 34 | document->Show(); 35 | else 36 | CAppManager::Get()->Msg("Document couldn't be created!"); 37 | 38 | while (CAppManager::Get()->IsRunning()) 39 | { 40 | CAppManager::Get()->HandleMessages(); 41 | 42 | context->Update(); 43 | 44 | CD3D11Manager::Get()->PreRender(); 45 | context->Render(); 46 | 47 | CD3D11Manager::Get()->Render(); 48 | } 49 | 50 | CD3D11Manager::Get()->Shutdown(); 51 | 52 | context->UnloadAllDocuments(); 53 | Rml::RemoveContext(context->GetName()); 54 | 55 | Rml::Debugger::Shutdown(); 56 | Rml::Shutdown(); 57 | } -------------------------------------------------------------------------------- /src/core/shaders/shaders.h: -------------------------------------------------------------------------------- 1 | 2 | static const char* g_pixelShader = R"( 3 | #define CONCAT(a, b) a##b 4 | 5 | #define DIFFUSE_PS_CPP 1 6 | #define DIFFUSE_PS_HLSL CONCAT(t, DIFFUSE_PS_CPP) 7 | 8 | #define SAMPLER_PS_CPP 1 9 | #define SAMPLER_PS_HLSL CONCAT(s, SAMPLER_PS_CPP) 10 | 11 | Texture2D ShaderTexture : register(DIFFUSE_PS_HLSL); 12 | SamplerState SampleType : register(SAMPLER_PS_HLSL); 13 | 14 | struct UIPixelInput 15 | { 16 | float4 screenPosition : SV_POSITION; 17 | float4 color : COLOR; 18 | float2 tex : TEXCOORD0; 19 | }; 20 | 21 | float4 main(UIPixelInput input) : SV_TARGET 22 | { 23 | clip(input.color.a - 0.0001f); 24 | 25 | float4 color = ShaderTexture.Sample(SampleType, input.tex) * input.color; 26 | 27 | return color; 28 | })"; 29 | 30 | static const char* g_vertexShader = R"( 31 | #define CONCAT(a, b) a##b 32 | 33 | #define PER_OBJECT_VS_CPP 3 34 | #define PER_OBJECT_VS_HLSL CONCAT(b, PER_OBJECT_VS_CPP) 35 | 36 | cbuffer CBuf : register(PER_OBJECT_VS_HLSL) 37 | { 38 | matrix M; 39 | }; 40 | 41 | struct UIVertexInputType 42 | { 43 | float2 position : POSITION; 44 | float4 color : COLOR; 45 | float2 tex : TEXCOORD0; 46 | }; 47 | 48 | struct UIPixelInput 49 | { 50 | float4 screenPosition : SV_POSITION; 51 | float4 color : COLOR; 52 | float2 tex : TEXCOORD0; 53 | }; 54 | 55 | UIPixelInput main(UIVertexInputType input) 56 | { 57 | UIPixelInput output; 58 | output.screenPosition = mul(float4(input.position, 0.0f, 1.0f), M); 59 | output.screenPosition.x -= 1.0f; 60 | output.screenPosition.y -= 1.0f; 61 | output.screenPosition.y *= -1; 62 | output.color = input.color; 63 | output.tex.x = input.tex.x; 64 | output.tex.y = input.tex.y; 65 | 66 | return output; 67 | })"; -------------------------------------------------------------------------------- /src/utils/TextureStuff.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef DirectX::SimpleMath::Matrix Matrix; 4 | typedef DirectX::SimpleMath::Vector2 Vector2; 5 | typedef DirectX::SimpleMath::Vector3 Vector3; 6 | typedef DirectX::SimpleMath::Vector4 Vector4; 7 | typedef DirectX::SimpleMath::Quaternion Quaternion; 8 | typedef DirectX::SimpleMath::Ray Ray; 9 | typedef DirectX::BoundingBox BoundingBox; 10 | typedef DirectX::SimpleMath::Color Color; 11 | 12 | struct VertexData 13 | { 14 | Vector3 position; 15 | Vector3 normal; 16 | Vector2 textureCoord; 17 | Vector3 tangent; 18 | }; 19 | 20 | struct InstanceData 21 | { 22 | Matrix transform; 23 | Matrix inverseTransposeTransform; 24 | Color color; 25 | 26 | InstanceData() = default; 27 | InstanceData(const Matrix& matrix, const Color& instanceColor) 28 | { 29 | transform = matrix; 30 | inverseTransposeTransform = matrix.Invert().Transpose(); 31 | color = instanceColor; 32 | } 33 | }; 34 | 35 | struct UIVertexData 36 | { 37 | Vector2 position; 38 | char color[4]; 39 | Vector2 textureCoord; 40 | }; 41 | 42 | struct AnimatedVertexData : public VertexData 43 | { 44 | int boneIndices[4]; 45 | Vector4 boneWeights; 46 | }; 47 | 48 | struct FXAAData 49 | { 50 | Vector3 position; 51 | Vector2 texturecoord; 52 | }; 53 | 54 | class Texture 55 | { 56 | ID3D11ShaderResourceView* srv_texture; 57 | public: 58 | Texture(const char* source, int width, int height) : srv_texture(nullptr) 59 | { 60 | srv_texture = CD3D11Manager::Get()->CreateTextureFromPixels(source, width, height); 61 | } 62 | 63 | Texture(const char* source) : srv_texture(nullptr) 64 | { 65 | srv_texture = CD3D11Manager::Get()->CreateTextureFromFile(source); 66 | } 67 | 68 | ~Texture() 69 | { 70 | if (srv_texture) 71 | { 72 | srv_texture->Release(); 73 | srv_texture = nullptr; 74 | } 75 | } 76 | 77 | ID3D11ShaderResourceView* getShaderResourceView() 78 | { 79 | return srv_texture; 80 | } 81 | }; 82 | -------------------------------------------------------------------------------- /src/core/CSystemInterfaceImpl.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | double CSystemInterfaceImpl::GetElapsedTime() 4 | { 5 | std::chrono::duration secs = std::chrono::steady_clock::now() - startTime; 6 | return secs.count(); 7 | } 8 | 9 | void CSystemInterfaceImpl::SetClipboardText(const Rml::String& text) 10 | { 11 | if (OpenClipboard(CAppManager::Get()->GetWindow())) 12 | { 13 | OpenClipboard(0); 14 | EmptyClipboard(); 15 | HGLOBAL hg = GlobalAlloc(GMEM_MOVEABLE, text.size()); 16 | if (!hg) { 17 | CloseClipboard(); 18 | return; 19 | } 20 | memcpy(GlobalLock(hg), text.c_str(), text.size()); 21 | GlobalUnlock(hg); 22 | SetClipboardData(CF_UNICODETEXT, hg); 23 | CloseClipboard(); 24 | GlobalFree(hg); 25 | } 26 | } 27 | 28 | void CSystemInterfaceImpl::GetClipboardText(Rml::String& text) 29 | { 30 | if (OpenClipboard(CAppManager::Get()->GetWindow())) 31 | { 32 | HANDLE hData = GetClipboardData(CF_UNICODETEXT); 33 | if (hData == nullptr) 34 | return; 35 | 36 | wchar_t* pszText = static_cast(GlobalLock(hData)); 37 | if (pszText == nullptr) 38 | return; 39 | 40 | text = Rml::String(); 41 | GlobalUnlock(hData); 42 | CloseClipboard(); 43 | } 44 | } 45 | 46 | bool CSystemInterfaceImpl::LogMessage(Rml::Log::Type type, const Rml::String& message) 47 | { 48 | std::stringstream str; 49 | switch (type) 50 | { 51 | case Rml::Log::Type::LT_ERROR: 52 | str << "[ERROR]"; 53 | break; 54 | case Rml::Log::Type::LT_ASSERT: 55 | str << "[ASSERT]"; 56 | break; 57 | case Rml::Log::Type::LT_WARNING: 58 | str << "[WARNING]"; 59 | break; 60 | case Rml::Log::Type::LT_INFO: 61 | str << "[INFO]"; 62 | break; 63 | case Rml::Log::Type::LT_DEBUG: 64 | str << "[DEBUG]"; 65 | break; 66 | default: 67 | str << "[DEFAULT]"; 68 | } 69 | 70 | str << " " << message.c_str(); 71 | 72 | printf("%s\n", str.str().c_str()); 73 | 74 | return true; 75 | } 76 | 77 | void CSystemInterfaceImpl::SetStartTime() 78 | { 79 | startTime = std::chrono::steady_clock::now(); 80 | } -------------------------------------------------------------------------------- /src/core/CD3D11Manager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "utils/CSingleton.h" 3 | #include 4 | #include 5 | #include 6 | 7 | class CD3D11Manager : public CSingleton 8 | { 9 | ID3D11Device* device; 10 | ID3D11DeviceContext* context; 11 | IDXGISwapChain* swapChain; 12 | ID3D11RenderTargetView* rtw; 13 | 14 | ID3D11BlendState* alphaBS; 15 | ID3D11RasterizerState* rs; 16 | ID3D11RasterizerState* scissoredRs; 17 | ID3D11DepthStencilState* depthStencil; 18 | ID3D11DepthStencilView* mainDSV; 19 | 20 | ID3D11Texture2D* m_OffScreenTexture; 21 | ID3D11RenderTargetView* m_OffScreenRTV; 22 | ID3D11ShaderResourceView* m_OffScreenSRV; 23 | 24 | std::shared_ptr m_BasicPostProcess; 25 | 26 | Microsoft::WRL::ComPtr vs; 27 | Microsoft::WRL::ComPtr ps; 28 | Microsoft::WRL::ComPtr il; 29 | 30 | int width, height; 31 | public: 32 | void Create(); 33 | void PreRender(); 34 | void Render(); 35 | void Shutdown(); 36 | 37 | ID3D11DeviceContext* GetContext() { return context; } 38 | 39 | Microsoft::WRL::ComPtr CompileShader(const char* shaderBuf, const char* entryPoint, const char* profile); 40 | void CreateShaders(); 41 | void SetShaders(); 42 | void CreateBS(DXGI_SWAP_CHAIN_DESC); 43 | void SetAlphaBS(); 44 | Microsoft::WRL::ComPtr CreateBuffer(const char* data, size_t size, D3D11_BIND_FLAG bindFlags, D3D11_USAGE usage, int cpuAccess); 45 | void EditBuffer(const char* data, size_t byteSize, ID3D11Buffer* bufferPointer); 46 | void DrawIndexed(UINT number); 47 | void SetTemporaryRS(); 48 | void SetTemporaryScissoredRS(); 49 | void SetScissorRectangle(int x, int y, int width, int height); 50 | 51 | ID3D11ShaderResourceView* CreateTextureFromFile(const char* imageFileData); 52 | ID3D11ShaderResourceView* CreateTextureFromPixels(const char* imageRawData, unsigned int width, unsigned int height); 53 | 54 | template 55 | void EditBuffer(const T& data, ID3D11Buffer* bufferPointer); 56 | 57 | template 58 | Microsoft::WRL::ComPtr CreateBuffer(const T& data, D3D11_BIND_FLAG bindFlags, D3D11_USAGE usage, D3D11_CPU_ACCESS_FLAG cpuAccess); 59 | }; 60 | 61 | template 62 | inline void CD3D11Manager::EditBuffer(const T& data, ID3D11Buffer* bufferPointer) 63 | { 64 | EditBuffer((const char*)&data, sizeof(T), bufferPointer); 65 | } 66 | 67 | template 68 | inline Microsoft::WRL::ComPtr CD3D11Manager::CreateBuffer(const T& data, D3D11_BIND_FLAG bindFlags, D3D11_USAGE usage, D3D11_CPU_ACCESS_FLAG cpuAccess) 69 | { 70 | return CreateBuffer((const char*)&data, sizeof(T), bindFlags, usage, cpuAccess); 71 | } -------------------------------------------------------------------------------- /src/core/CRenderInterfaceImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "utils/CSingleton.h" 3 | #include 4 | #include "SimpleMath.h" 5 | #include "utils/TextureStuff.h" 6 | 7 | class CRenderInterfaceImpl : public Rml::RenderInterface, public CSingleton 8 | { 9 | struct GeometryData 10 | { 11 | public: 12 | Microsoft::WRL::ComPtr vertexBuffer; 13 | unsigned int vertexStride; 14 | unsigned int vertexCount; 15 | 16 | Microsoft::WRL::ComPtr indexBuffer; 17 | unsigned int indexCount; 18 | DXGI_FORMAT indexFormat; 19 | 20 | Rml::TextureHandle textureHandle; 21 | 22 | GeometryData(const UIVertexData* vertices, size_t verticesSize, int* indices, size_t indicesSize, Rml::TextureHandle texture) 23 | : vertexBuffer(nullptr), vertexStride(0), vertexCount(0), textureHandle(texture), indexBuffer(nullptr), indexCount(0), indexFormat(DXGI_FORMAT::DXGI_FORMAT_UNKNOWN) 24 | { 25 | vertexBuffer = CD3D11Manager::Get()->CreateBuffer((const char*)vertices, sizeof(UIVertexData)*verticesSize, D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_IMMUTABLE, 0); 26 | vertexStride = sizeof(UIVertexData); 27 | vertexCount = verticesSize; 28 | 29 | indexBuffer = CD3D11Manager::Get()->CreateBuffer((const char*)indices, sizeof(int) * indicesSize, D3D11_BIND_INDEX_BUFFER, D3D11_USAGE_IMMUTABLE, 0); 30 | indexCount = indicesSize; 31 | indexFormat = DXGI_FORMAT_R32_UINT; 32 | } 33 | }; 34 | 35 | uint32_t textureCount; 36 | 37 | Matrix m_UITransform; 38 | Microsoft::WRL::ComPtr m_ModelMatrixBuffer = nullptr; 39 | std::unordered_map> textures; 40 | 41 | Texture* whiteTexture; 42 | 43 | int width, height; 44 | 45 | void Render(GeometryData* geometry, const Rml::Vector2f& translation); 46 | 47 | virtual void RenderGeometry(Rml::Vertex* vertices, int numVertices, int* indices, int numIndices, Rml::TextureHandle texture, const Rml::Vector2f& translation) override; 48 | 49 | virtual Rml::CompiledGeometryHandle CompileGeometry(Rml::Vertex* vertices, int numVertices, int* indices, int numIndices, Rml::TextureHandle texture) override; 50 | virtual void RenderCompiledGeometry(Rml::CompiledGeometryHandle geometry, const Rml::Vector2f& translation) override; 51 | virtual void ReleaseCompiledGeometry(Rml::CompiledGeometryHandle geometry) override; 52 | 53 | virtual bool LoadTexture(Rml::TextureHandle& textureHandle, Rml::Vector2i& textureDimensions, const Rml::String& source) override; 54 | virtual bool GenerateTexture(Rml::TextureHandle& textureHandle, const uint8_t* source, const Rml::Vector2i& sourceDimensions) override; 55 | virtual void ReleaseTexture(Rml::TextureHandle texture); 56 | 57 | virtual void EnableScissorRegion(bool enable) override; 58 | virtual void SetScissorRegion(int x, int y, int width, int height) override; 59 | 60 | virtual void SetTransform(const Rml::Matrix4f* transform) override; 61 | public: 62 | void Init(); 63 | }; -------------------------------------------------------------------------------- /src/core/CRenderInterfaceImpl.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | #define PER_OBJECT_VS_CPP 3 4 | #define DIFFUSE_PS_CPP 1 5 | 6 | struct PerUIVSCB 7 | { 8 | Matrix Model; 9 | PerUIVSCB() = default; 10 | PerUIVSCB(const Matrix& model) 11 | { 12 | Model = model.Transpose(); 13 | } 14 | }; 15 | 16 | void CRenderInterfaceImpl::Init() 17 | { 18 | width = CAppManager::Get()->GetWidth(); 19 | height = CAppManager::Get()->GetHeight(); 20 | 21 | m_ModelMatrixBuffer = CD3D11Manager::Get()->CreateBuffer(PerUIVSCB(), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); 22 | 23 | char whiteBuf[4] = { 0xFF, 0xFF, 0xFF, 0xFF }; 24 | textures[0] = std::make_shared(whiteBuf, 1, 1); 25 | } 26 | 27 | void CRenderInterfaceImpl::Render(GeometryData* geometry, const Rml::Vector2f& translation) 28 | { 29 | auto deviceMgr = CD3D11Manager::Get(); 30 | 31 | const UINT offset = 0u; 32 | deviceMgr->GetContext()->IASetVertexBuffers(0u, 1, geometry->vertexBuffer.GetAddressOf(), &geometry->vertexStride, &offset); 33 | deviceMgr->GetContext()->IASetIndexBuffer(geometry->indexBuffer.Get(), geometry->indexFormat, 0u); 34 | 35 | deviceMgr->SetShaders(); 36 | 37 | auto shit = PerUIVSCB(Matrix::CreateTranslation(translation.x, translation.y, 0.0f) * m_UITransform * Matrix::CreateOrthographic(width, height, 0.0f, 10000.0f)); 38 | 39 | deviceMgr->EditBuffer(shit, m_ModelMatrixBuffer.Get()); 40 | deviceMgr->GetContext()->VSSetConstantBuffers(PER_OBJECT_VS_CPP, 1, m_ModelMatrixBuffer.GetAddressOf()); 41 | 42 | ID3D11ShaderResourceView* srvs[1]; 43 | 44 | auto srv = textures[geometry->textureHandle]->getShaderResourceView(); 45 | srvs[0] = srv ? srv : textures[0]->getShaderResourceView(); 46 | 47 | deviceMgr->GetContext()->PSSetShaderResources(DIFFUSE_PS_CPP, 1, srvs); 48 | 49 | deviceMgr->GetContext()->DrawIndexed(geometry->indexCount, 0u, 0u); 50 | } 51 | 52 | void CRenderInterfaceImpl::RenderGeometry(Rml::Vertex* vertices, int numVertices, int* indices, int numIndices, Rml::TextureHandle texture, const Rml::Vector2f& translation) 53 | { 54 | GeometryData geometry((UIVertexData*)vertices, numVertices, (int*)indices, numIndices, texture); 55 | Render(&geometry, translation); 56 | } 57 | 58 | Rml::CompiledGeometryHandle CRenderInterfaceImpl::CompileGeometry(Rml::Vertex* vertices, int numVertices, int* indices, int numIndices, Rml::TextureHandle texture) 59 | { 60 | return (Rml::CompiledGeometryHandle) new GeometryData((UIVertexData*)vertices, numVertices, (int*)indices, numIndices, texture); 61 | } 62 | 63 | void CRenderInterfaceImpl::RenderCompiledGeometry(Rml::CompiledGeometryHandle geometry, const Rml::Vector2f& translation) 64 | { 65 | Render((GeometryData*)geometry, translation); 66 | } 67 | 68 | void CRenderInterfaceImpl::ReleaseCompiledGeometry(Rml::CompiledGeometryHandle geometry) 69 | { 70 | delete (GeometryData*)geometry; 71 | } 72 | 73 | bool CRenderInterfaceImpl::LoadTexture(Rml::TextureHandle& textureHandle, Rml::Vector2i& textureDimensions, const Rml::String& source) 74 | { 75 | printf("LoadTexture %s\n", source.c_str()); 76 | 77 | textureHandle = ++textureCount; 78 | textures[textureHandle] = std::make_shared(source.c_str()); 79 | 80 | return true; 81 | } 82 | 83 | bool CRenderInterfaceImpl::GenerateTexture(Rml::TextureHandle& textureHandle, const byte* source, const Rml::Vector2i& sourceDimensions) 84 | { 85 | textureHandle = ++textureCount; 86 | printf("GenerateTexture %d\n", textureHandle); 87 | 88 | textures[textureHandle] = std::make_shared((const char*)source, sourceDimensions.x, sourceDimensions.y); 89 | return textures[textureHandle] != nullptr; 90 | } 91 | 92 | void CRenderInterfaceImpl::ReleaseTexture(Rml::TextureHandle texture) 93 | { 94 | printf("ReleaseTexture %d\n", texture); 95 | textures[texture].reset(); 96 | } 97 | 98 | void CRenderInterfaceImpl::EnableScissorRegion(bool enable) 99 | { 100 | enable ? CD3D11Manager::Get()->SetTemporaryScissoredRS() : CD3D11Manager::Get()->SetTemporaryRS(); 101 | } 102 | 103 | void CRenderInterfaceImpl::SetScissorRegion(int x, int y, int _width, int _height) 104 | { 105 | CD3D11Manager::Get()->SetScissorRectangle(x, y, _width, _height); 106 | } 107 | 108 | void CRenderInterfaceImpl::SetTransform(const Rml::Matrix4f* transform) 109 | { 110 | if (!transform) 111 | { 112 | m_UITransform = Matrix::Identity; 113 | return; 114 | } 115 | m_UITransform = Matrix(transform->data()); 116 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # build 7 | _pmm/ 8 | *.vcxproj 9 | *.vcxproj.filters 10 | *.sln 11 | *.sh 12 | *.bat 13 | build/ 14 | 15 | # CMake 16 | CMakeLists.txt.user 17 | CMakeCache.txt 18 | CMakeFiles 19 | CMakeScripts 20 | Testing 21 | Makefile 22 | cmake_install.cmake 23 | install_manifest.txt 24 | compile_commands.json 25 | CTestTestfile.cmake 26 | _deps 27 | 28 | # User-specific files 29 | *.rsuser 30 | *.suo 31 | *.user 32 | *.userosscache 33 | *.sln.docstates 34 | 35 | # User-specific files (MonoDevelop/Xamarin Studio) 36 | *.userprefs 37 | 38 | # Mono auto generated files 39 | mono_crash.* 40 | 41 | # Build results 42 | [Dd]ebug/ 43 | [Dd]ebugPublic/ 44 | [Rr]elease/ 45 | [Rr]eleases/ 46 | x64/ 47 | x86/ 48 | [Aa][Rr][Mm]/ 49 | [Aa][Rr][Mm]64/ 50 | bld/ 51 | [Bb]in/ 52 | [Oo]bj/ 53 | [Ll]og/ 54 | [Ll]ogs/ 55 | 56 | # Visual Studio 2015/2017 cache/options directory 57 | .vs/ 58 | # Uncomment if you have tasks that create the project's static files in wwwroot 59 | #wwwroot/ 60 | 61 | # Visual Studio 2017 auto generated files 62 | Generated\ Files/ 63 | 64 | # MSTest test Results 65 | [Tt]est[Rr]esult*/ 66 | [Bb]uild[Ll]og.* 67 | 68 | # NUnit 69 | *.VisualState.xml 70 | TestResult.xml 71 | nunit-*.xml 72 | 73 | # Build Results of an ATL Project 74 | [Dd]ebugPS/ 75 | [Rr]eleasePS/ 76 | dlldata.c 77 | 78 | # Benchmark Results 79 | BenchmarkDotNet.Artifacts/ 80 | 81 | # .NET Core 82 | project.lock.json 83 | project.fragment.lock.json 84 | artifacts/ 85 | 86 | # StyleCop 87 | StyleCopReport.xml 88 | 89 | # Files built by Visual Studio 90 | *_i.c 91 | *_p.c 92 | *_h.h 93 | *.ilk 94 | *.meta 95 | *.obj 96 | *.iobj 97 | *.pch 98 | *.pdb 99 | *.ipdb 100 | *.pgc 101 | *.pgd 102 | *.rsp 103 | *.sbr 104 | *.tlb 105 | *.tli 106 | *.tlh 107 | *.tmp 108 | *.tmp_proj 109 | *_wpftmp.csproj 110 | *.log 111 | *.vspscc 112 | *.vssscc 113 | .builds 114 | *.pidb 115 | *.svclog 116 | *.scc 117 | 118 | # Chutzpah Test files 119 | _Chutzpah* 120 | 121 | # Visual C++ cache files 122 | ipch/ 123 | *.aps 124 | *.ncb 125 | *.opendb 126 | *.opensdf 127 | *.sdf 128 | *.cachefile 129 | *.VC.db 130 | *.VC.VC.opendb 131 | 132 | # Visual Studio profiler 133 | *.psess 134 | *.vsp 135 | *.vspx 136 | *.sap 137 | 138 | # Visual Studio Trace Files 139 | *.e2e 140 | 141 | # TFS 2012 Local Workspace 142 | $tf/ 143 | 144 | # Guidance Automation Toolkit 145 | *.gpState 146 | 147 | # ReSharper is a .NET coding add-in 148 | _ReSharper*/ 149 | *.[Rr]e[Ss]harper 150 | *.DotSettings.user 151 | 152 | # TeamCity is a build add-in 153 | _TeamCity* 154 | 155 | # DotCover is a Code Coverage Tool 156 | *.dotCover 157 | 158 | # AxoCover is a Code Coverage Tool 159 | .axoCover/* 160 | !.axoCover/settings.json 161 | 162 | # Visual Studio code coverage results 163 | *.coverage 164 | *.coveragexml 165 | 166 | # NCrunch 167 | _NCrunch_* 168 | .*crunch*.local.xml 169 | nCrunchTemp_* 170 | 171 | # MightyMoose 172 | *.mm.* 173 | AutoTest.Net/ 174 | 175 | # Web workbench (sass) 176 | .sass-cache/ 177 | 178 | # Installshield output folder 179 | [Ee]xpress/ 180 | 181 | # DocProject is a documentation generator add-in 182 | DocProject/buildhelp/ 183 | DocProject/Help/*.HxT 184 | DocProject/Help/*.HxC 185 | DocProject/Help/*.hhc 186 | DocProject/Help/*.hhk 187 | DocProject/Help/*.hhp 188 | DocProject/Help/Html2 189 | DocProject/Help/html 190 | 191 | # Click-Once directory 192 | publish/ 193 | 194 | # Publish Web Output 195 | *.[Pp]ublish.xml 196 | *.azurePubxml 197 | # Note: Comment the next line if you want to checkin your web deploy settings, 198 | # but database connection strings (with potential passwords) will be unencrypted 199 | *.pubxml 200 | *.publishproj 201 | 202 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 203 | # checkin your Azure Web App publish settings, but sensitive information contained 204 | # in these scripts will be unencrypted 205 | PublishScripts/ 206 | 207 | # NuGet Packages 208 | *.nupkg 209 | # NuGet Symbol Packages 210 | *.snupkg 211 | # The packages folder can be ignored because of Package Restore 212 | **/[Pp]ackages/* 213 | # except build/, which is used as an MSBuild target. 214 | !**/[Pp]ackages/build/ 215 | # Uncomment if necessary however generally it will be regenerated when needed 216 | #!**/[Pp]ackages/repositories.config 217 | # NuGet v3's project.json files produces more ignorable files 218 | *.nuget.props 219 | *.nuget.targets 220 | 221 | # Microsoft Azure Build Output 222 | csx/ 223 | *.build.csdef 224 | 225 | # Microsoft Azure Emulator 226 | ecf/ 227 | rcf/ 228 | 229 | # Windows Store app package directories and files 230 | AppPackages/ 231 | BundleArtifacts/ 232 | Package.StoreAssociation.xml 233 | _pkginfo.txt 234 | *.appx 235 | *.appxbundle 236 | *.appxupload 237 | 238 | # Visual Studio cache files 239 | # files ending in .cache can be ignored 240 | *.[Cc]ache 241 | # but keep track of directories ending in .cache 242 | !?*.[Cc]ache/ 243 | 244 | # Others 245 | ClientBin/ 246 | ~$* 247 | *~ 248 | *.dbmdl 249 | *.dbproj.schemaview 250 | *.jfm 251 | *.pfx 252 | *.publishsettings 253 | orleans.codegen.cs 254 | 255 | # Including strong name files can present a security risk 256 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 257 | #*.snk 258 | 259 | # Since there are multiple workflows, uncomment next line to ignore bower_components 260 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 261 | #bower_components/ 262 | 263 | # RIA/Silverlight projects 264 | Generated_Code/ 265 | 266 | # Backup & report files from converting an old project file 267 | # to a newer Visual Studio version. Backup files are not needed, 268 | # because we have git ;-) 269 | _UpgradeReport_Files/ 270 | Backup*/ 271 | UpgradeLog*.XML 272 | UpgradeLog*.htm 273 | ServiceFabricBackup/ 274 | *.rptproj.bak 275 | 276 | # SQL Server files 277 | *.mdf 278 | *.ldf 279 | *.ndf 280 | 281 | # Business Intelligence projects 282 | *.rdl.data 283 | *.bim.layout 284 | *.bim_*.settings 285 | *.rptproj.rsuser 286 | *- [Bb]ackup.rdl 287 | *- [Bb]ackup ([0-9]).rdl 288 | *- [Bb]ackup ([0-9][0-9]).rdl 289 | 290 | # Microsoft Fakes 291 | FakesAssemblies/ 292 | 293 | # GhostDoc plugin setting file 294 | *.GhostDoc.xml 295 | 296 | # Node.js Tools for Visual Studio 297 | .ntvs_analysis.dat 298 | node_modules/ 299 | 300 | # Visual Studio 6 build log 301 | *.plg 302 | 303 | # Visual Studio 6 workspace options file 304 | *.opt 305 | 306 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 307 | *.vbw 308 | 309 | # Visual Studio LightSwitch build output 310 | **/*.HTMLClient/GeneratedArtifacts 311 | **/*.DesktopClient/GeneratedArtifacts 312 | **/*.DesktopClient/ModelManifest.xml 313 | **/*.Server/GeneratedArtifacts 314 | **/*.Server/ModelManifest.xml 315 | _Pvt_Extensions 316 | 317 | # Paket dependency manager 318 | .paket/paket.exe 319 | paket-files/ 320 | 321 | # FAKE - F# Make 322 | .fake/ 323 | 324 | # CodeRush personal settings 325 | .cr/personal 326 | 327 | # Python Tools for Visual Studio (PTVS) 328 | __pycache__/ 329 | *.pyc 330 | 331 | # Cake - Uncomment if you are using it 332 | # tools/** 333 | # !tools/packages.config 334 | 335 | # Tabs Studio 336 | *.tss 337 | 338 | # Telerik's JustMock configuration file 339 | *.jmconfig 340 | 341 | # BizTalk build output 342 | *.btp.cs 343 | *.btm.cs 344 | *.odx.cs 345 | *.xsd.cs 346 | 347 | # OpenCover UI analysis results 348 | OpenCover/ 349 | 350 | # Azure Stream Analytics local run output 351 | ASALocalRun/ 352 | 353 | # MSBuild Binary and Structured Log 354 | *.binlog 355 | 356 | # NVidia Nsight GPU debugger configuration file 357 | *.nvuser 358 | 359 | # MFractors (Xamarin productivity tool) working folder 360 | .mfractor/ 361 | 362 | # Local History for Visual Studio 363 | .localhistory/ 364 | 365 | # BeatPulse healthcheck temp database 366 | healthchecksdb 367 | 368 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 369 | MigrationBackup/ 370 | 371 | # Ionide (cross platform F# VS Code tools) working folder 372 | .ionide/ 373 | -------------------------------------------------------------------------------- /pmm.cmake: -------------------------------------------------------------------------------- 1 | #[[ 2 | MIT License 3 | 4 | Copyright (c) 2021 vector-of-bool 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | //////////////////////////////////////////////////////////////////////////////// 25 | 26 | PPPPPPPPPPPPPPPP MMMMMM MMMMMM MMMMMM MMMMMM 27 | P:::::::::::::::P M:::::M M:::::M M:::::M M:::::M 28 | P:::::PPPPPP:::::P M::::::M M::::::M M::::::M M::::::M 29 | PP::::P P:::::P M:::::::M M:::::::M M:::::::M M:::::::M 30 | P:::P P:::::P M::::::::M M::::::::M M::::::::M M::::::::M 31 | P:::P P:::::P M:::::::::M M:::::::::M M:::::::::M M:::::::::M 32 | P:::PPPPPP:::::P M:::::M::::M M::::M:::::M M:::::M::::M M::::M:::::M 33 | P::::::::::::PP M::::M M::::M M::::M M::::M M::::M M::::M M::::M M::::M 34 | P:::PPPPPPPPP M::::M M::::M::::M M::::M M::::M M::::M::::M M::::M 35 | P:::P M::::M M:::::::M M::::M M::::M M:::::::M M::::M 36 | P:::P M::::M M:::::M M::::M M::::M M:::::M M::::M 37 | P:::P M::::M MMMMM M::::M M::::M MMMMM M::::M 38 | PP:::::PP M::::M M::::M M::::M M::::M 39 | P:::::::P M::::M M::::M M::::M M::::M 40 | P:::::::P M::::M M::::M M::::M M::::M 41 | PPPPPPPPP MMMMMM MMMMMM MMMMMM MMMMMM 42 | 43 | ]] 44 | 45 | #[[ Version: 46 | 47 | 888 888 d8b 48 | 888 888 Y8P 49 | 888 888 50 | Y88b d88P .d88b. 888d888 .d8888b 888 .d88b. 88888b. d8b 51 | Y88b d88P d8P Y8b 888P" 88K 888 d88""88b 888 "88b Y8P 52 | Y88o88P 88888888 888 "Y8888b. 888 888 888 888 888 53 | Y888P Y8b. 888 X88 888 Y88..88P 888 888 d8b 54 | Y8P "Y8888 888 88888P' 888 "Y88P" 888 888 Y8P 55 | 56 | The version of PMM that will be downloaded if no PMM_VERSION was specified 57 | before include()-ing this file. You can change this version here to update 58 | the version of PMM that is used by your project: ]] 59 | 60 | set(PMM_VERSION_INIT "2.0.0") 61 | 62 | # (See the README below for more information) 63 | # 64 | 65 | #[[ README: 66 | 67 | 8888888b. 888 888b d888 68 | 888 Y88b 888 8888b d8888 69 | 888 888 888 88888b.d88888 70 | 888 d88P .d88b. 8888b. .d88888 888Y88888P888 .d88b. d8b 71 | 8888888P" d8P Y8b "88b d88" 888 888 Y888P 888 d8P Y8b Y8P 72 | 888 T88b 88888888 .d888888 888 888 888 Y8P 888 88888888 73 | 888 T88b Y8b. 888 888 Y88b 888 888 " 888 Y8b. d8b 74 | 888 T88b "Y8888 "Y888888 "Y88888 888 888 "Y8888 Y8P 75 | 76 | #################################################################### 77 | 78 | This script is the "entrypoint" for PMM. 79 | 80 | This file should be COPIED and COMMITTED into the source tree of the project 81 | that wishes to use PMM. Do not use a file(DOWNLOAD), FetchContent(), or other 82 | pre-build script to download this file: It is intended to live in the source 83 | tree of its users and be very rarely be manually updated. This file is 84 | in-and-of-itself a FetchContent()-like script that will download and import 85 | the full PMM code. 86 | 87 | This script will not automatically upgrade the version of PMM that is imported 88 | unless you specifically request it. You can be assured that the PMM code being 89 | pulled is deterministic over time. 90 | 91 | The version of PMM that is bootstrapped by this script is controlled by a 92 | single CMake variable 'PMM_VERSION' that can be set before include()-ing this 93 | file. Additionally, the 'set(PMM_VERSION_INIT)' line above this readme can be 94 | modified to control the PMM version. 95 | 96 | HINT: You can run this script with CMake directly via 'cmake -P pmm.cmake' for 97 | additional command-line functionality. ]] 98 | 99 | 100 | #[[ Options: 101 | 102 | .d88888b. 888 d8b 103 | d88P" "Y88b 888 Y8P 104 | 888 888 888 105 | 888 888 88888b. 888888 888 .d88b. 88888b. .d8888b d8b 106 | 888 888 888 "88b 888 888 d88""88b 888 "88b 88K Y8P 107 | 888 888 888 888 888 888 888 888 888 888 "Y8888b. 108 | Y88b. .d88P 888 d88P Y88b. 888 Y88..88P 888 888 X88 d8b 109 | "Y88888P" 88888P" "Y888 888 "Y88P" 888 888 88888P' Y8P 110 | 888 111 | 888 112 | 888 113 | 114 | ############################################################## 115 | 116 | The lines below set options that control how PMM is bootstrapped. These 117 | options can all be tweaked in one of two ways: 118 | 119 | - Change the default value of the option here in pmm.cmake in the associated 120 | call to pmm_option(). This is useful if you want to make a customized 121 | version of PMM and pmm.cmake to distribute and reuse between projects. 122 | 123 | - Set the associated variable before include()-ing this file. This is 124 | preferred for temporary changes, or for one-off projects that need custom 125 | values. 126 | 127 | The average user will not need to modify any variables except PMM_VERSION. 128 | 129 | Each option is documented below. Additional options and controls for PMM are 130 | documented in the README of the PMM repository. 131 | 132 | ]] 133 | 134 | # (Helpful macro to set a variable if it isn't already set) 135 | macro(pmm_option varname) 136 | if(NOT DEFINED "${varname}" AND NOT DEFINED "CACHE{${varname}}") 137 | set("${varname}" "${ARGN}") 138 | endif() 139 | endmacro() 140 | 141 | #[[ PMM_VERSION 142 | 143 | d8888b. .88b d88. .88b d88. db db d88888b d8888b. .d8888. d888888b .d88b. d8b db 144 | 88 `8D 88'YbdP`88 88'YbdP`88 88 88 88' 88 `8D 88' YP `88' .8P Y8. 888o 88 145 | 88oodD' 88 88 88 88 88 88 Y8 8P 88ooooo 88oobY' `8bo. 88 88 88 88V8o 88 146 | 88~~~ 88 88 88 88 88 88 `8b d8' 88~~~~~ 88`8b `Y8b. 88 88 88 88 V8o88 147 | 88 88 88 88 88 88 88 `8bd8' 88. 88 `88. db 8D .88. `8b d8' 88 V888 148 | 88 YP YP YP YP YP YP C88888D YP Y88888P 88 YD `8888Y' Y888888P `Y88P' VP V8P 149 | 150 | 'PMM_VERSION' will controls what version of PMM will be bootstrapped by this 151 | file. 152 | 153 | The initial value is controlled by 'PMM_VERSION_INIT', which is defined near 154 | the top of this file. Permanently updating the PMM version used by the 155 | project should be done by modifying 'PMM_VERSION_INIT' above directly rather 156 | than setting 'PMM_VERSION' 157 | 158 | ]] 159 | 160 | pmm_option(PMM_VERSION ${PMM_VERSION_INIT}) 161 | 162 | #[[ PMM_URL_BASE 163 | 164 | d8888b. .88b d88. .88b d88. db db d8888b. db d8888b. .d8b. .d8888. d88888b 165 | 88 `8D 88'YbdP`88 88'YbdP`88 88 88 88 `8D 88 88 `8D d8' `8b 88' YP 88' 166 | 88oodD' 88 88 88 88 88 88 88 88 88oobY' 88 88oooY' 88ooo88 `8bo. 88ooooo 167 | 88~~~ 88 88 88 88 88 88 88 88 88`8b 88 88~~~b. 88~~~88 `Y8b. 88~~~~~ 168 | 88 88 88 88 88 88 88 88b d88 88 `88. 88booo. 88 8D 88 88 db 8D 88. 169 | 88 YP YP YP YP YP YP C88888D ~Y8888P' 88 YD Y88888P C88888D Y8888P' YP YP `8888Y' Y88888P 170 | 171 | 'PMM_URL_BASE' sets the root URL from which all versions of PMM can be 172 | downloaded. This value is used to construct 'PMM_URL'. 173 | 174 | ]] 175 | 176 | pmm_option(PMM_URL_BASE "https://vector-of-bool.github.io/pmm") 177 | 178 | #[[ PMM_URL 179 | 180 | d8888b. .88b d88. .88b d88. db db d8888b. db 181 | 88 `8D 88'YbdP`88 88'YbdP`88 88 88 88 `8D 88 182 | 88oodD' 88 88 88 88 88 88 88 88 88oobY' 88 183 | 88~~~ 88 88 88 88 88 88 88 88 88`8b 88 184 | 88 88 88 88 88 88 88 88b d88 88 `88. 88booo. 185 | 88 YP YP YP YP YP YP C88888D ~Y8888P' 88 YD Y88888P 186 | 187 | 'PMM_URL' is a URL that points to the "directory" that contains the PMM 188 | source code for a given version. 189 | 190 | The default value is the subdirectory of '${PMM_URL_BASE}' with a name of 191 | '${PMM_VERSION}'. 192 | 193 | ]] 194 | 195 | pmm_option(PMM_URL "${PMM_URL_BASE}/${PMM_VERSION}") 196 | 197 | #[[ PMM_DIR 198 | 199 | d8888b. .88b d88. .88b d88. d8888b. d888888b d8888b. 200 | 88 `8D 88'YbdP`88 88'YbdP`88 88 `8D `88' 88 `8D 201 | 88oodD' 88 88 88 88 88 88 88 88 88 88oobY' 202 | 88~~~ 88 88 88 88 88 88 88 88 88 88`8b 203 | 88 88 88 88 88 88 88 88 .8D .88. 88 `88. 204 | 88 YP YP YP YP YP YP C88888D Y8888D' Y888888P 88 YD 205 | 206 | 'PMM_DIR' is the base directory where PMM will write the bootstrapped copy 207 | of PMM. The default is a subdirectory of the CMake build directory qualified 208 | by the version of PMM that was downloaded. 209 | 210 | ]] 211 | 212 | pmm_option(PMM_DIR "${CMAKE_BINARY_DIR}/_pmm/${PMM_VERSION}") 213 | 214 | #[[ PMM_MODULE 215 | 216 | d8888b. .88b d88. .88b d88. .88b d88. .d88b. d8888b. db db db d88888b 217 | 88 `8D 88'YbdP`88 88'YbdP`88 88'YbdP`88 .8P Y8. 88 `8D 88 88 88 88' 218 | 88oodD' 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88ooooo 219 | 88~~~ 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88~~~~~ 220 | 88 88 88 88 88 88 88 88 88 88 `8b d8' 88 .8D 88b d88 88booo. 88. 221 | 88 YP YP YP YP YP YP C88888D YP YP YP `Y88P' Y8888D' ~Y8888P' Y88888P Y88888P 222 | 223 | 'PMM_MODULE' is the absolute path to the pmm.cmake script (this file). It 224 | should not be changed or set unless you *really* know what you are doing. 225 | 226 | ]] 227 | 228 | pmm_option(PMM_MODULE "${CMAKE_CURRENT_LIST_FILE}") 229 | 230 | ################################################################################ 231 | ################################################################################ 232 | ################################################################################ 233 | ################################################################################ 234 | 235 | #[[ 236 | 237 | The code below is the implementation of the bootstrapping process for PMM. 238 | You should not change any of the code below. 239 | 240 | ]] 241 | 242 | # The file that we first download 243 | set(_PMM_ENTRY_FILE "${PMM_DIR}/entry.cmake") 244 | 245 | # Guard against multiple processes trying to use the PMM dir simultaneously 246 | file(LOCK "${PMM_DIR}/_init-pmm" 247 | GUARD PROCESS 248 | TIMEOUT 10 249 | RESULT_VARIABLE _lock_res 250 | ) 251 | if(NOT _lock_res STREQUAL "0") 252 | message(WARNING "PMM entry didn't lock the directory [${PMM_DIR}] successfully (${_lock_res}). We'll continue as best we can.") 253 | set(_pmm_init_did_lock FALSE) 254 | else() 255 | set(_pmm_init_did_lock TRUE) 256 | endif() 257 | 258 | if(NOT EXISTS "${_PMM_ENTRY_FILE}" OR PMM_ALWAYS_DOWNLOAD) 259 | file( 260 | DOWNLOAD "${PMM_URL}/entry.cmake" 261 | "${_PMM_ENTRY_FILE}.tmp" 262 | STATUS pair 263 | ) 264 | list(GET pair 0 rc) 265 | list(GET pair 1 msg) 266 | if(rc) 267 | message(FATAL_ERROR "Failed to download PMM entry file: ${msg}") 268 | endif() 269 | file(RENAME "${_PMM_ENTRY_FILE}.tmp" "${_PMM_ENTRY_FILE}") 270 | endif() 271 | 272 | set(_PMM_BOOTSTRAP_VERSION 4) 273 | include("${_PMM_ENTRY_FILE}") 274 | 275 | if(_pmm_init_did_lock) 276 | file(LOCK "${PMM_DIR}/_init-pmm" RELEASE) 277 | endif() 278 | -------------------------------------------------------------------------------- /src/core/CD3D11Manager.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include 3 | #include 4 | #include "WICTextureLoader.h" 5 | #include 6 | #include 7 | #include "shaders/shaders.h" 8 | 9 | void CD3D11Manager::Create() 10 | { 11 | width = CAppManager::Get()->GetWidth(); 12 | height = CAppManager::Get()->GetHeight(); 13 | 14 | DXGI_SWAP_CHAIN_DESC sd = { 0 }; 15 | sd.BufferDesc.Width = width; 16 | sd.BufferDesc.Height = height; 17 | sd.BufferDesc.RefreshRate.Numerator = 0; 18 | sd.BufferDesc.RefreshRate.Denominator = 1; 19 | sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 20 | sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; 21 | sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; 22 | sd.SampleDesc.Count = 1; 23 | sd.SampleDesc.Quality = 0; 24 | sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT; 25 | sd.BufferCount = 2; 26 | sd.OutputWindow = CAppManager::Get()->GetWindow(); 27 | sd.Windowed = true; 28 | sd.SwapEffect = DXGI_SWAP_EFFECT::DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; 29 | 30 | UINT createDeviceFlags = 0; 31 | #if defined(DEBUG) || defined(_DEBUG) 32 | createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; 33 | #endif 34 | D3D_FEATURE_LEVEL featureLevel; 35 | const D3D_FEATURE_LEVEL featureLevelArray[1] = { D3D_FEATURE_LEVEL_11_0 }; 36 | if (D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDeviceFlags, featureLevelArray, 1, D3D11_SDK_VERSION, &sd, &swapChain, &device, &featureLevel, &context) != S_OK) 37 | { 38 | CAppManager::Get()->Msg("Failed to create d3d11 device!"); 39 | } 40 | 41 | D3D11_VIEWPORT vp; 42 | vp.Width = width; 43 | vp.Height = height; 44 | vp.MinDepth = 0; 45 | vp.MaxDepth = 1; 46 | vp.TopLeftX = 0; 47 | vp.TopLeftY = 0; 48 | 49 | context->RSSetViewports(1u, &vp); 50 | 51 | ID3D11Texture2D* pBackBuffer; 52 | swapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); 53 | device->CreateRenderTargetView(pBackBuffer, NULL, &rtw); 54 | pBackBuffer->Release(); 55 | 56 | CreateShaders(); 57 | CreateBS(sd); 58 | } 59 | 60 | void CD3D11Manager::Shutdown() 61 | { 62 | if (device) 63 | { 64 | device->Release(); 65 | device = nullptr; 66 | } 67 | 68 | if (context) 69 | { 70 | context->Release(); 71 | context = nullptr; 72 | } 73 | 74 | if (swapChain) 75 | { 76 | swapChain->Release(); 77 | swapChain = nullptr; 78 | } 79 | } 80 | 81 | void CD3D11Manager::CreateBS(DXGI_SWAP_CHAIN_DESC sd) 82 | { 83 | D3D11_BLEND_DESC blendDesc; 84 | ZeroMemory(&blendDesc, sizeof(D3D11_BLEND_DESC)); 85 | blendDesc.AlphaToCoverageEnable = false; 86 | blendDesc.IndependentBlendEnable = false; 87 | D3D11_RENDER_TARGET_BLEND_DESC renderBlendDesc; 88 | blendDesc.RenderTarget[0].BlendEnable = TRUE; 89 | blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; 90 | blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; 91 | blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; 92 | blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; 93 | blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; 94 | blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; 95 | blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 96 | device->CreateBlendState(&blendDesc, &alphaBS); 97 | 98 | { 99 | D3D11_DEPTH_STENCIL_DESC dsDesc = { 0 }; 100 | dsDesc.DepthEnable = TRUE; 101 | dsDesc.DepthFunc = D3D11_COMPARISON_LESS; 102 | dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; 103 | device->CreateDepthStencilState(&dsDesc, &depthStencil); 104 | context->OMSetDepthStencilState(depthStencil, 1u); 105 | //m_StencilRef = 1u; 106 | } 107 | 108 | { 109 | D3D11_RASTERIZER_DESC rsDesc; 110 | rsDesc.FillMode = D3D11_FILL_SOLID; 111 | rsDesc.CullMode = D3D11_CULL_NONE; 112 | rsDesc.FrontCounterClockwise = FALSE; 113 | rsDesc.DepthBias = 0; 114 | rsDesc.SlopeScaledDepthBias = 0.0f; 115 | rsDesc.DepthBiasClamp = 0.0f; 116 | rsDesc.DepthClipEnable = FALSE; 117 | rsDesc.ScissorEnable = FALSE; 118 | rsDesc.MultisampleEnable = FALSE; 119 | rsDesc.AntialiasedLineEnable = FALSE; 120 | 121 | device->CreateRasterizerState(&rsDesc, &rs); 122 | } 123 | 124 | { 125 | D3D11_RASTERIZER_DESC rsDesc; 126 | rsDesc.FillMode = D3D11_FILL_SOLID; 127 | rsDesc.CullMode = D3D11_CULL_NONE; 128 | rsDesc.FrontCounterClockwise = FALSE; 129 | rsDesc.DepthBias = 0; 130 | rsDesc.SlopeScaledDepthBias = 0.0f; 131 | rsDesc.DepthBiasClamp = 0.0f; 132 | rsDesc.DepthClipEnable = TRUE; 133 | rsDesc.ScissorEnable = TRUE; 134 | rsDesc.MultisampleEnable = FALSE; 135 | rsDesc.AntialiasedLineEnable = FALSE; 136 | 137 | device->CreateRasterizerState(&rsDesc, &scissoredRs); 138 | } 139 | 140 | { 141 | D3D11_TEXTURE2D_DESC textureDesc; 142 | ZeroMemory(&textureDesc, sizeof(textureDesc)); 143 | textureDesc.Width = width; 144 | textureDesc.Height = height; 145 | textureDesc.MipLevels = 1; 146 | textureDesc.ArraySize = 1; 147 | textureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; 148 | textureDesc.SampleDesc.Count = 1; 149 | textureDesc.Usage = D3D11_USAGE_DEFAULT; 150 | textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; 151 | textureDesc.CPUAccessFlags = 0; 152 | textureDesc.MiscFlags = 0; 153 | 154 | device->CreateTexture2D(&textureDesc, NULL, &m_OffScreenTexture); 155 | 156 | D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc; 157 | renderTargetViewDesc.Format = textureDesc.Format; 158 | renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; 159 | renderTargetViewDesc.Texture2D.MipSlice = 0; 160 | 161 | device->CreateRenderTargetView(m_OffScreenTexture, &renderTargetViewDesc, &m_OffScreenRTV); 162 | 163 | D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc; 164 | shaderResourceViewDesc.Format = textureDesc.Format; 165 | shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; 166 | shaderResourceViewDesc.Texture2D.MostDetailedMip = 0; 167 | shaderResourceViewDesc.Texture2D.MipLevels = 1; 168 | 169 | device->CreateShaderResourceView(m_OffScreenTexture, &shaderResourceViewDesc, &m_OffScreenSRV); 170 | } 171 | 172 | m_BasicPostProcess.reset(new DirectX::BasicPostProcess(device)); 173 | } 174 | 175 | void CD3D11Manager::PreRender() 176 | { 177 | context->OMSetRenderTargets(1, &rtw, nullptr); 178 | 179 | m_BasicPostProcess->SetSourceTexture(m_OffScreenSRV); 180 | m_BasicPostProcess->SetEffect(DirectX::BasicPostProcess::Effect::Copy); 181 | m_BasicPostProcess->Process(context); 182 | 183 | SetAlphaBS(); 184 | } 185 | 186 | void CD3D11Manager::Render() 187 | { 188 | swapChain->Present(0, 0); 189 | } 190 | 191 | void CD3D11Manager::EditBuffer(const char* data, size_t byteSize, ID3D11Buffer* bufferPointer) 192 | { 193 | D3D11_MAPPED_SUBRESOURCE subresource; 194 | context->Map(bufferPointer, 0u, D3D11_MAP_WRITE_DISCARD, 0u, &subresource); 195 | memcpy(subresource.pData, data, byteSize); 196 | context->Unmap(bufferPointer, 0); 197 | } 198 | 199 | void CD3D11Manager::DrawIndexed(UINT number) 200 | { 201 | //printf("DrawIndexed %d\n", number); 202 | context->DrawIndexed(number, 0u, 0u); 203 | } 204 | 205 | void CD3D11Manager::SetTemporaryRS() 206 | { 207 | context->RSSetState(rs); 208 | } 209 | 210 | void CD3D11Manager::SetTemporaryScissoredRS() 211 | { 212 | context->RSSetState(scissoredRs); 213 | } 214 | 215 | void CD3D11Manager::SetScissorRectangle(int x, int y, int _width, int _height) 216 | { 217 | D3D11_RECT rect; 218 | rect.left = x; 219 | rect.right = x + _width; 220 | rect.top = y; 221 | rect.bottom = y + _height; 222 | 223 | context->RSSetScissorRects(1, &rect); 224 | } 225 | 226 | void CD3D11Manager::SetShaders() 227 | { 228 | context->VSSetShader(vs.Get(), nullptr, 0u); 229 | context->PSSetShader(ps.Get(), nullptr, 0u); 230 | context->IASetInputLayout(il.Get()); 231 | context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 232 | } 233 | 234 | void CD3D11Manager::SetAlphaBS() 235 | { 236 | static float blendFactors[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; 237 | context->OMSetBlendState(alphaBS, blendFactors, 0xffffffff); 238 | } 239 | 240 | ID3D11ShaderResourceView* CD3D11Manager::CreateTextureFromFile(const char* path) 241 | { 242 | Microsoft::WRL::ComPtr textureResource; 243 | ID3D11ShaderResourceView* textureView; 244 | 245 | std::ifstream file(path, std::ios::in | std::ios::binary | std::ios::ate); 246 | 247 | if (!file.is_open()) { 248 | CAppManager::Get()->Msg("Failed to open file: %s", path); 249 | return nullptr; 250 | } 251 | 252 | auto size = file.tellg(); 253 | auto imageFileData = new char[size]; 254 | file.seekg(0, std::ios::beg); 255 | file.read(imageFileData, size); 256 | file.close(); 257 | 258 | auto hr = DirectX::CreateWICTextureFromMemoryEx(device, (const uint8_t*)imageFileData, size, 0, D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0, DirectX::WIC_LOADER_IGNORE_SRGB | DirectX::WIC_LOADER_FORCE_RGBA32, textureResource.GetAddressOf(), &textureView); 259 | 260 | if (FAILED(hr)) 261 | { 262 | CAppManager::Get()->Msg("Could not create texture from file data: 0x%08x", hr); 263 | return nullptr; 264 | } 265 | 266 | return textureView; 267 | } 268 | 269 | ID3D11ShaderResourceView* CD3D11Manager::CreateTextureFromPixels(const char* imageRawData, unsigned int _width, unsigned int _height) 270 | { 271 | D3D11_TEXTURE2D_DESC textureDesc = {}; 272 | 273 | textureDesc.Width = _width; 274 | textureDesc.Height = _height; 275 | textureDesc.MipLevels = 1; 276 | textureDesc.ArraySize = 1; 277 | textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 278 | textureDesc.SampleDesc.Count = 1; 279 | textureDesc.Usage = D3D11_USAGE_DEFAULT; 280 | textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; 281 | textureDesc.CPUAccessFlags = 0; 282 | textureDesc.MiscFlags = 0; 283 | 284 | D3D11_SUBRESOURCE_DATA data = {}; 285 | data.pSysMem = imageRawData; 286 | data.SysMemPitch = _width * 4; 287 | 288 | Microsoft::WRL::ComPtr texture2D; 289 | auto hr = device->CreateTexture2D(&textureDesc, &data, &texture2D); 290 | if (FAILED(hr)) 291 | { 292 | CAppManager::Get()->Msg("Could not create texture 2D from pixel data: 0x%08x", hr); 293 | } 294 | 295 | D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; 296 | srvDesc.Format = textureDesc.Format; 297 | srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; 298 | srvDesc.Texture2D.MostDetailedMip = 0; 299 | srvDesc.Texture2D.MipLevels = 1; 300 | 301 | ID3D11ShaderResourceView* textureSRV; 302 | device->CreateShaderResourceView(texture2D.Get(), &srvDesc, &textureSRV); 303 | 304 | return textureSRV; 305 | } 306 | 307 | Microsoft::WRL::ComPtr CD3D11Manager::CreateBuffer(const char* data, size_t size, D3D11_BIND_FLAG bindFlags, D3D11_USAGE usage, int cpuAccess) 308 | { 309 | D3D11_BUFFER_DESC bd = { 0 }; 310 | bd.BindFlags = bindFlags; 311 | bd.Usage = usage; 312 | bd.CPUAccessFlags = cpuAccess; 313 | bd.MiscFlags = 0u; 314 | bd.ByteWidth = size; 315 | bd.StructureByteStride = 0u; 316 | D3D11_SUBRESOURCE_DATA sd = { 0 }; 317 | sd.pSysMem = data; 318 | 319 | Microsoft::WRL::ComPtr buffer; 320 | device->CreateBuffer(&bd, &sd, &buffer); 321 | return buffer; 322 | } 323 | 324 | void CD3D11Manager::CreateShaders() 325 | { 326 | auto psBlob = CompileShader(g_pixelShader, "main", "ps_4_0"); 327 | auto vsBlob = CompileShader(g_vertexShader, "main", "vs_4_0"); 328 | 329 | device->CreatePixelShader(psBlob->GetBufferPointer(), psBlob->GetBufferSize(), nullptr, &ps); 330 | device->CreateVertexShader(vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), nullptr, &vs); 331 | 332 | std::vector vertexDescArray; 333 | UINT offset = 0; 334 | 335 | D3D11_INPUT_ELEMENT_DESC desc; 336 | desc.SemanticName = "POSITION"; 337 | desc.SemanticIndex = 0; 338 | desc.Format = DXGI_FORMAT_R32G32_FLOAT; 339 | desc.InputSlot = 0; 340 | desc.AlignedByteOffset = offset; 341 | desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; 342 | desc.InstanceDataStepRate = 0; 343 | offset += sizeof(float) * 2; 344 | vertexDescArray.push_back(desc); 345 | 346 | desc.SemanticName = "COLOR"; 347 | desc.SemanticIndex = 0; 348 | desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 349 | desc.InputSlot = 0; 350 | desc.AlignedByteOffset = offset; 351 | desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; 352 | desc.InstanceDataStepRate = 0; 353 | offset += sizeof(char) * 4; 354 | vertexDescArray.push_back(desc); 355 | 356 | desc.SemanticName = "TEXCOORD"; 357 | desc.SemanticIndex = 0; 358 | desc.Format = DXGI_FORMAT_R32G32_FLOAT; 359 | desc.InputSlot = 0; 360 | desc.AlignedByteOffset = offset; 361 | desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; 362 | desc.InstanceDataStepRate = 0; 363 | offset += sizeof(float) * 2; 364 | vertexDescArray.push_back(desc); 365 | 366 | device->CreateInputLayout( 367 | vertexDescArray.data(), vertexDescArray.size(), 368 | vsBlob->GetBufferPointer(), 369 | vsBlob->GetBufferSize(), 370 | &il); 371 | 372 | //context->IASetInputLayout(il.Get()); 373 | } 374 | 375 | Microsoft::WRL::ComPtr CD3D11Manager::CompileShader(const char* shaderBuf, const char* entryPoint, const char* profile) 376 | { 377 | Microsoft::WRL::ComPtr shaderBlob; 378 | Microsoft::WRL::ComPtr errorBlob; 379 | 380 | UINT flags = D3DCOMPILE_ENABLE_STRICTNESS; 381 | #if defined(DEBUG) || defined(_DEBUG) 382 | flags |= D3DCOMPILE_DEBUG; 383 | #else 384 | flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3; 385 | #endif 386 | 387 | const D3D_SHADER_MACRO defines[1] = { NULL, NULL }; 388 | auto hr = D3DCompile( 389 | shaderBuf, 390 | strlen(shaderBuf), 391 | NULL, 392 | defines, 393 | D3D_COMPILE_STANDARD_FILE_INCLUDE, 394 | entryPoint, 395 | profile, 396 | flags, 397 | 0, 398 | &shaderBlob, 399 | &errorBlob); 400 | 401 | if (FAILED(hr)) 402 | { 403 | CAppManager::Get()->Msg("Failed to create the shader: 0x%08x", hr); 404 | } 405 | 406 | if (errorBlob) 407 | { 408 | CAppManager::Get()->Msg("Error when compiling shader: %s", (char*)errorBlob->GetBufferPointer()); 409 | } 410 | 411 | return shaderBlob; 412 | } -------------------------------------------------------------------------------- /src/core/CAppManager.cpp: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | #include 3 | 4 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 5 | { 6 | if (msg == WM_SYSCOMMAND && wParam == SC_CLOSE) 7 | PostQuitMessage(0); 8 | 9 | CAppManager::Get()->WndProc(msg, wParam, lParam); 10 | return ::DefWindowProc(hWnd, msg, wParam, lParam); 11 | } 12 | 13 | #define KEYMAP_SIZE 256 14 | static Rml::Input::KeyIdentifier KeyIdentifierMap[KEYMAP_SIZE]; 15 | 16 | void InitialiseKeymap() 17 | { 18 | // Initialise the key map with default values. 19 | memset(KeyIdentifierMap, 0, sizeof(KeyIdentifierMap)); 20 | 21 | // Assign individual values. 22 | KeyIdentifierMap['A'] = Rml::Input::KI_A; 23 | KeyIdentifierMap['B'] = Rml::Input::KI_B; 24 | KeyIdentifierMap['C'] = Rml::Input::KI_C; 25 | KeyIdentifierMap['D'] = Rml::Input::KI_D; 26 | KeyIdentifierMap['E'] = Rml::Input::KI_E; 27 | KeyIdentifierMap['F'] = Rml::Input::KI_F; 28 | KeyIdentifierMap['G'] = Rml::Input::KI_G; 29 | KeyIdentifierMap['H'] = Rml::Input::KI_H; 30 | KeyIdentifierMap['I'] = Rml::Input::KI_I; 31 | KeyIdentifierMap['J'] = Rml::Input::KI_J; 32 | KeyIdentifierMap['K'] = Rml::Input::KI_K; 33 | KeyIdentifierMap['L'] = Rml::Input::KI_L; 34 | KeyIdentifierMap['M'] = Rml::Input::KI_M; 35 | KeyIdentifierMap['N'] = Rml::Input::KI_N; 36 | KeyIdentifierMap['O'] = Rml::Input::KI_O; 37 | KeyIdentifierMap['P'] = Rml::Input::KI_P; 38 | KeyIdentifierMap['Q'] = Rml::Input::KI_Q; 39 | KeyIdentifierMap['R'] = Rml::Input::KI_R; 40 | KeyIdentifierMap['S'] = Rml::Input::KI_S; 41 | KeyIdentifierMap['T'] = Rml::Input::KI_T; 42 | KeyIdentifierMap['U'] = Rml::Input::KI_U; 43 | KeyIdentifierMap['V'] = Rml::Input::KI_V; 44 | KeyIdentifierMap['W'] = Rml::Input::KI_W; 45 | KeyIdentifierMap['X'] = Rml::Input::KI_X; 46 | KeyIdentifierMap['Y'] = Rml::Input::KI_Y; 47 | KeyIdentifierMap['Z'] = Rml::Input::KI_Z; 48 | 49 | KeyIdentifierMap['0'] = Rml::Input::KI_0; 50 | KeyIdentifierMap['1'] = Rml::Input::KI_1; 51 | KeyIdentifierMap['2'] = Rml::Input::KI_2; 52 | KeyIdentifierMap['3'] = Rml::Input::KI_3; 53 | KeyIdentifierMap['4'] = Rml::Input::KI_4; 54 | KeyIdentifierMap['5'] = Rml::Input::KI_5; 55 | KeyIdentifierMap['6'] = Rml::Input::KI_6; 56 | KeyIdentifierMap['7'] = Rml::Input::KI_7; 57 | KeyIdentifierMap['8'] = Rml::Input::KI_8; 58 | KeyIdentifierMap['9'] = Rml::Input::KI_9; 59 | 60 | KeyIdentifierMap[VK_BACK] = Rml::Input::KI_BACK; 61 | KeyIdentifierMap[VK_TAB] = Rml::Input::KI_TAB; 62 | 63 | KeyIdentifierMap[VK_CLEAR] = Rml::Input::KI_CLEAR; 64 | KeyIdentifierMap[VK_RETURN] = Rml::Input::KI_RETURN; 65 | 66 | KeyIdentifierMap[VK_PAUSE] = Rml::Input::KI_PAUSE; 67 | KeyIdentifierMap[VK_CAPITAL] = Rml::Input::KI_CAPITAL; 68 | 69 | KeyIdentifierMap[VK_KANA] = Rml::Input::KI_KANA; 70 | KeyIdentifierMap[VK_HANGUL] = Rml::Input::KI_HANGUL; 71 | KeyIdentifierMap[VK_JUNJA] = Rml::Input::KI_JUNJA; 72 | KeyIdentifierMap[VK_FINAL] = Rml::Input::KI_FINAL; 73 | KeyIdentifierMap[VK_HANJA] = Rml::Input::KI_HANJA; 74 | KeyIdentifierMap[VK_KANJI] = Rml::Input::KI_KANJI; 75 | 76 | KeyIdentifierMap[VK_ESCAPE] = Rml::Input::KI_ESCAPE; 77 | 78 | KeyIdentifierMap[VK_CONVERT] = Rml::Input::KI_CONVERT; 79 | KeyIdentifierMap[VK_NONCONVERT] = Rml::Input::KI_NONCONVERT; 80 | KeyIdentifierMap[VK_ACCEPT] = Rml::Input::KI_ACCEPT; 81 | KeyIdentifierMap[VK_MODECHANGE] = Rml::Input::KI_MODECHANGE; 82 | 83 | KeyIdentifierMap[VK_SPACE] = Rml::Input::KI_SPACE; 84 | KeyIdentifierMap[VK_PRIOR] = Rml::Input::KI_PRIOR; 85 | KeyIdentifierMap[VK_NEXT] = Rml::Input::KI_NEXT; 86 | KeyIdentifierMap[VK_END] = Rml::Input::KI_END; 87 | KeyIdentifierMap[VK_HOME] = Rml::Input::KI_HOME; 88 | KeyIdentifierMap[VK_LEFT] = Rml::Input::KI_LEFT; 89 | KeyIdentifierMap[VK_UP] = Rml::Input::KI_UP; 90 | KeyIdentifierMap[VK_RIGHT] = Rml::Input::KI_RIGHT; 91 | KeyIdentifierMap[VK_DOWN] = Rml::Input::KI_DOWN; 92 | KeyIdentifierMap[VK_SELECT] = Rml::Input::KI_SELECT; 93 | KeyIdentifierMap[VK_PRINT] = Rml::Input::KI_PRINT; 94 | KeyIdentifierMap[VK_EXECUTE] = Rml::Input::KI_EXECUTE; 95 | KeyIdentifierMap[VK_SNAPSHOT] = Rml::Input::KI_SNAPSHOT; 96 | KeyIdentifierMap[VK_INSERT] = Rml::Input::KI_INSERT; 97 | KeyIdentifierMap[VK_DELETE] = Rml::Input::KI_DELETE; 98 | KeyIdentifierMap[VK_HELP] = Rml::Input::KI_HELP; 99 | 100 | KeyIdentifierMap[VK_LWIN] = Rml::Input::KI_LWIN; 101 | KeyIdentifierMap[VK_RWIN] = Rml::Input::KI_RWIN; 102 | KeyIdentifierMap[VK_APPS] = Rml::Input::KI_APPS; 103 | 104 | KeyIdentifierMap[VK_SLEEP] = Rml::Input::KI_SLEEP; 105 | 106 | KeyIdentifierMap[VK_NUMPAD0] = Rml::Input::KI_NUMPAD0; 107 | KeyIdentifierMap[VK_NUMPAD1] = Rml::Input::KI_NUMPAD1; 108 | KeyIdentifierMap[VK_NUMPAD2] = Rml::Input::KI_NUMPAD2; 109 | KeyIdentifierMap[VK_NUMPAD3] = Rml::Input::KI_NUMPAD3; 110 | KeyIdentifierMap[VK_NUMPAD4] = Rml::Input::KI_NUMPAD4; 111 | KeyIdentifierMap[VK_NUMPAD5] = Rml::Input::KI_NUMPAD5; 112 | KeyIdentifierMap[VK_NUMPAD6] = Rml::Input::KI_NUMPAD6; 113 | KeyIdentifierMap[VK_NUMPAD7] = Rml::Input::KI_NUMPAD7; 114 | KeyIdentifierMap[VK_NUMPAD8] = Rml::Input::KI_NUMPAD8; 115 | KeyIdentifierMap[VK_NUMPAD9] = Rml::Input::KI_NUMPAD9; 116 | KeyIdentifierMap[VK_MULTIPLY] = Rml::Input::KI_MULTIPLY; 117 | KeyIdentifierMap[VK_ADD] = Rml::Input::KI_ADD; 118 | KeyIdentifierMap[VK_SEPARATOR] = Rml::Input::KI_SEPARATOR; 119 | KeyIdentifierMap[VK_SUBTRACT] = Rml::Input::KI_SUBTRACT; 120 | KeyIdentifierMap[VK_DECIMAL] = Rml::Input::KI_DECIMAL; 121 | KeyIdentifierMap[VK_DIVIDE] = Rml::Input::KI_DIVIDE; 122 | KeyIdentifierMap[VK_F1] = Rml::Input::KI_F1; 123 | KeyIdentifierMap[VK_F2] = Rml::Input::KI_F2; 124 | KeyIdentifierMap[VK_F3] = Rml::Input::KI_F3; 125 | KeyIdentifierMap[VK_F4] = Rml::Input::KI_F4; 126 | KeyIdentifierMap[VK_F5] = Rml::Input::KI_F5; 127 | KeyIdentifierMap[VK_F6] = Rml::Input::KI_F6; 128 | KeyIdentifierMap[VK_F7] = Rml::Input::KI_F7; 129 | KeyIdentifierMap[VK_F8] = Rml::Input::KI_F8; 130 | KeyIdentifierMap[VK_F9] = Rml::Input::KI_F9; 131 | KeyIdentifierMap[VK_F10] = Rml::Input::KI_F10; 132 | KeyIdentifierMap[VK_F11] = Rml::Input::KI_F11; 133 | KeyIdentifierMap[VK_F12] = Rml::Input::KI_F12; 134 | KeyIdentifierMap[VK_F13] = Rml::Input::KI_F13; 135 | KeyIdentifierMap[VK_F14] = Rml::Input::KI_F14; 136 | KeyIdentifierMap[VK_F15] = Rml::Input::KI_F15; 137 | KeyIdentifierMap[VK_F16] = Rml::Input::KI_F16; 138 | KeyIdentifierMap[VK_F17] = Rml::Input::KI_F17; 139 | KeyIdentifierMap[VK_F18] = Rml::Input::KI_F18; 140 | KeyIdentifierMap[VK_F19] = Rml::Input::KI_F19; 141 | KeyIdentifierMap[VK_F20] = Rml::Input::KI_F20; 142 | KeyIdentifierMap[VK_F21] = Rml::Input::KI_F21; 143 | KeyIdentifierMap[VK_F22] = Rml::Input::KI_F22; 144 | KeyIdentifierMap[VK_F23] = Rml::Input::KI_F23; 145 | KeyIdentifierMap[VK_F24] = Rml::Input::KI_F24; 146 | 147 | KeyIdentifierMap[VK_NUMLOCK] = Rml::Input::KI_NUMLOCK; 148 | KeyIdentifierMap[VK_SCROLL] = Rml::Input::KI_SCROLL; 149 | 150 | KeyIdentifierMap[VK_OEM_NEC_EQUAL] = Rml::Input::KI_OEM_NEC_EQUAL; 151 | 152 | KeyIdentifierMap[VK_OEM_FJ_JISHO] = Rml::Input::KI_OEM_FJ_JISHO; 153 | KeyIdentifierMap[VK_OEM_FJ_MASSHOU] = Rml::Input::KI_OEM_FJ_MASSHOU; 154 | KeyIdentifierMap[VK_OEM_FJ_TOUROKU] = Rml::Input::KI_OEM_FJ_TOUROKU; 155 | KeyIdentifierMap[VK_OEM_FJ_LOYA] = Rml::Input::KI_OEM_FJ_LOYA; 156 | KeyIdentifierMap[VK_OEM_FJ_ROYA] = Rml::Input::KI_OEM_FJ_ROYA; 157 | 158 | KeyIdentifierMap[VK_SHIFT] = Rml::Input::KI_LSHIFT; 159 | KeyIdentifierMap[VK_CONTROL] = Rml::Input::KI_LCONTROL; 160 | KeyIdentifierMap[VK_MENU] = Rml::Input::KI_LMENU; 161 | 162 | KeyIdentifierMap[VK_BROWSER_BACK] = Rml::Input::KI_BROWSER_BACK; 163 | KeyIdentifierMap[VK_BROWSER_FORWARD] = Rml::Input::KI_BROWSER_FORWARD; 164 | KeyIdentifierMap[VK_BROWSER_REFRESH] = Rml::Input::KI_BROWSER_REFRESH; 165 | KeyIdentifierMap[VK_BROWSER_STOP] = Rml::Input::KI_BROWSER_STOP; 166 | KeyIdentifierMap[VK_BROWSER_SEARCH] = Rml::Input::KI_BROWSER_SEARCH; 167 | KeyIdentifierMap[VK_BROWSER_FAVORITES] = Rml::Input::KI_BROWSER_FAVORITES; 168 | KeyIdentifierMap[VK_BROWSER_HOME] = Rml::Input::KI_BROWSER_HOME; 169 | 170 | KeyIdentifierMap[VK_VOLUME_MUTE] = Rml::Input::KI_VOLUME_MUTE; 171 | KeyIdentifierMap[VK_VOLUME_DOWN] = Rml::Input::KI_VOLUME_DOWN; 172 | KeyIdentifierMap[VK_VOLUME_UP] = Rml::Input::KI_VOLUME_UP; 173 | KeyIdentifierMap[VK_MEDIA_NEXT_TRACK] = Rml::Input::KI_MEDIA_NEXT_TRACK; 174 | KeyIdentifierMap[VK_MEDIA_PREV_TRACK] = Rml::Input::KI_MEDIA_PREV_TRACK; 175 | KeyIdentifierMap[VK_MEDIA_STOP] = Rml::Input::KI_MEDIA_STOP; 176 | KeyIdentifierMap[VK_MEDIA_PLAY_PAUSE] = Rml::Input::KI_MEDIA_PLAY_PAUSE; 177 | KeyIdentifierMap[VK_LAUNCH_MAIL] = Rml::Input::KI_LAUNCH_MAIL; 178 | KeyIdentifierMap[VK_LAUNCH_MEDIA_SELECT] = Rml::Input::KI_LAUNCH_MEDIA_SELECT; 179 | KeyIdentifierMap[VK_LAUNCH_APP1] = Rml::Input::KI_LAUNCH_APP1; 180 | KeyIdentifierMap[VK_LAUNCH_APP2] = Rml::Input::KI_LAUNCH_APP2; 181 | 182 | KeyIdentifierMap[VK_OEM_1] = Rml::Input::KI_OEM_1; 183 | KeyIdentifierMap[VK_OEM_PLUS] = Rml::Input::KI_OEM_PLUS; 184 | KeyIdentifierMap[VK_OEM_COMMA] = Rml::Input::KI_OEM_COMMA; 185 | KeyIdentifierMap[VK_OEM_MINUS] = Rml::Input::KI_OEM_MINUS; 186 | KeyIdentifierMap[VK_OEM_PERIOD] = Rml::Input::KI_OEM_PERIOD; 187 | KeyIdentifierMap[VK_OEM_2] = Rml::Input::KI_OEM_2; 188 | KeyIdentifierMap[VK_OEM_3] = Rml::Input::KI_OEM_3; 189 | 190 | KeyIdentifierMap[VK_OEM_4] = Rml::Input::KI_OEM_4; 191 | KeyIdentifierMap[VK_OEM_5] = Rml::Input::KI_OEM_5; 192 | KeyIdentifierMap[VK_OEM_6] = Rml::Input::KI_OEM_6; 193 | KeyIdentifierMap[VK_OEM_7] = Rml::Input::KI_OEM_7; 194 | KeyIdentifierMap[VK_OEM_8] = Rml::Input::KI_OEM_8; 195 | 196 | KeyIdentifierMap[VK_OEM_AX] = Rml::Input::KI_OEM_AX; 197 | KeyIdentifierMap[VK_OEM_102] = Rml::Input::KI_OEM_102; 198 | KeyIdentifierMap[VK_ICO_HELP] = Rml::Input::KI_ICO_HELP; 199 | KeyIdentifierMap[VK_ICO_00] = Rml::Input::KI_ICO_00; 200 | 201 | KeyIdentifierMap[VK_PROCESSKEY] = Rml::Input::KI_PROCESSKEY; 202 | 203 | KeyIdentifierMap[VK_ICO_CLEAR] = Rml::Input::KI_ICO_CLEAR; 204 | 205 | KeyIdentifierMap[VK_ATTN] = Rml::Input::KI_ATTN; 206 | KeyIdentifierMap[VK_CRSEL] = Rml::Input::KI_CRSEL; 207 | KeyIdentifierMap[VK_EXSEL] = Rml::Input::KI_EXSEL; 208 | KeyIdentifierMap[VK_EREOF] = Rml::Input::KI_EREOF; 209 | KeyIdentifierMap[VK_PLAY] = Rml::Input::KI_PLAY; 210 | KeyIdentifierMap[VK_ZOOM] = Rml::Input::KI_ZOOM; 211 | KeyIdentifierMap[VK_PA1] = Rml::Input::KI_PA1; 212 | KeyIdentifierMap[VK_OEM_CLEAR] = Rml::Input::KI_OEM_CLEAR; 213 | } 214 | 215 | void CAppManager::Create(int _width, int _height) 216 | { 217 | width = _width; 218 | height = _height; 219 | 220 | WNDCLASS wc = { }; 221 | 222 | wc.lpfnWndProc = ::WndProc; 223 | wc.hInstance = GetModuleHandle(NULL); 224 | wc.lpszClassName = L"app_window"; 225 | 226 | RegisterClass(&wc); 227 | 228 | window = CreateWindowEx(0, wc.lpszClassName, L"RmlUi DirectX11", WS_OVERLAPPEDWINDOW, 100, 100, width, height, NULL, NULL, wc.hInstance, NULL); 229 | ShowWindow(window, SW_SHOWDEFAULT); 230 | UpdateWindow(window); 231 | 232 | isRunning = true; 233 | 234 | InitialiseKeymap(); 235 | } 236 | 237 | static int GetKeyModifierState() 238 | { 239 | int key_modifier_state = 0; 240 | 241 | // Query the state of all modifier keys 242 | if (GetKeyState(VK_CAPITAL) & 1) 243 | { 244 | key_modifier_state |= Rml::Input::KM_CAPSLOCK; 245 | } 246 | 247 | if (HIWORD(GetKeyState(VK_SHIFT)) & 1) 248 | { 249 | key_modifier_state |= Rml::Input::KM_SHIFT; 250 | } 251 | 252 | if (GetKeyState(VK_NUMLOCK) & 1) 253 | { 254 | key_modifier_state |= Rml::Input::KM_NUMLOCK; 255 | } 256 | 257 | if (HIWORD(GetKeyState(VK_CONTROL)) & 1) 258 | { 259 | key_modifier_state |= Rml::Input::KM_CTRL; 260 | } 261 | 262 | if (HIWORD(GetKeyState(VK_MENU)) & 1) 263 | { 264 | key_modifier_state |= Rml::Input::KM_ALT; 265 | } 266 | 267 | return key_modifier_state; 268 | } 269 | 270 | void CAppManager::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) 271 | { 272 | auto context = CContextManager::Get()->GetContext(); 273 | 274 | if (msg == WM_MOUSEMOVE) 275 | { 276 | const int& x = LOWORD(lParam); 277 | const int& y = HIWORD(lParam); 278 | 279 | auto m_IsMouseOver = (x >= 0 && x < 1280) && (y >= 0 && y <= 768); 280 | if (m_IsMouseOver) 281 | { 282 | context->ProcessMouseMove((x - 0) * 1.f, (y - 0) * 1.f, GetKeyModifierState()); 283 | } 284 | } 285 | 286 | switch (msg) 287 | { 288 | case WM_LBUTTONDOWN: 289 | context->ProcessMouseButtonDown(0, GetKeyModifierState()); 290 | break; 291 | 292 | case WM_LBUTTONUP: 293 | context->ProcessMouseButtonUp(0, GetKeyModifierState()); 294 | break; 295 | 296 | case WM_RBUTTONDOWN: 297 | context->ProcessMouseButtonDown(1, GetKeyModifierState()); 298 | break; 299 | 300 | case WM_RBUTTONUP: 301 | context->ProcessMouseButtonUp(1, GetKeyModifierState()); 302 | break; 303 | 304 | case WM_MBUTTONDOWN: 305 | context->ProcessMouseButtonDown(2, GetKeyModifierState()); 306 | break; 307 | 308 | case WM_MBUTTONUP: 309 | context->ProcessMouseButtonUp(2, GetKeyModifierState()); 310 | break; 311 | 312 | case WM_MOUSEWHEEL: 313 | context->ProcessMouseWheel(static_cast((short)HIWORD(wParam)) / static_cast(-WHEEL_DELTA), GetKeyModifierState()); 314 | break; 315 | 316 | case WM_KEYDOWN: 317 | context->ProcessKeyDown(KeyIdentifierMap[wParam], GetKeyModifierState()); 318 | break; 319 | 320 | case WM_KEYUP: 321 | context->ProcessKeyUp(KeyIdentifierMap[wParam], GetKeyModifierState()); 322 | break; 323 | 324 | case WM_CHAR: 325 | static char16_t firstU16CodeUnit = 0; 326 | 327 | char16_t c = (char16_t)wParam; 328 | Rml::Character character = (Rml::Character)c; 329 | 330 | // Windows sends two-wide characters as two messages. 331 | if (c >= 0xD800 && c < 0xDC00) 332 | { 333 | // First 16-bit code unit of a two-wide character. 334 | firstU16CodeUnit = c; 335 | } 336 | else 337 | { 338 | if (c >= 0xDC00 && c < 0xE000 && firstU16CodeUnit != 0) 339 | { 340 | // Second 16-bit code unit of a two-wide character. 341 | // Encode a single code point as a UTF-8 string. 342 | //RMLUICORE_API String ToUTF8(Character character); 343 | 344 | // Encode an array of code points as a UTF-8 string. 345 | //RMLUICORE_API String ToUTF8(const Character * characters, int num_characters); 346 | 347 | Rml::String utf8 = Rml::StringUtilities::ToUTF8(character); 348 | character = Rml::StringUtilities::ToCharacter(utf8.data()); 349 | } 350 | else if (c == '\r') 351 | { 352 | // Windows sends new-lines as carriage returns, convert to endlines. 353 | character = (Rml::Character)'\n'; 354 | } 355 | 356 | firstU16CodeUnit = 0; 357 | 358 | // Only send through printable characters. 359 | if (((char32_t)character >= 32 || character == (Rml::Character)'\n') && character != (Rml::Character)127) 360 | context->ProcessTextInput(character); 361 | } 362 | break; 363 | } 364 | } 365 | 366 | bool CAppManager::IsRunning() 367 | { 368 | return isRunning; 369 | } 370 | 371 | void CAppManager::HandleMessages() 372 | { 373 | MSG msg; 374 | while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) 375 | { 376 | TranslateMessage(&msg); 377 | DispatchMessage(&msg); 378 | if (msg.message == WM_QUIT) 379 | isRunning = false; 380 | } 381 | } 382 | 383 | void CAppManager::Msg(const char* message, ...) 384 | { 385 | char buf[256]; 386 | 387 | va_list va; 388 | va_start(va, message); 389 | 390 | vsprintf(buf, message, va); 391 | vprintf(message, va); 392 | printf("\n"); 393 | va_end(va); 394 | 395 | MessageBoxA(window, buf, "", 0); 396 | } --------------------------------------------------------------------------------