diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index dfe0770..0000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto diff --git a/1337.sln b/1337.sln new file mode 100644 index 0000000..2e67d0e --- /dev/null +++ b/1337.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31410.357 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "1337", "1337\1337.vcxproj", "{21F4B5BB-C0FC-4F49-BC65-9C714EFB45A3}" +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 + {21F4B5BB-C0FC-4F49-BC65-9C714EFB45A3}.Debug|x64.ActiveCfg = Debug|x64 + {21F4B5BB-C0FC-4F49-BC65-9C714EFB45A3}.Debug|x64.Build.0 = Debug|x64 + {21F4B5BB-C0FC-4F49-BC65-9C714EFB45A3}.Debug|x86.ActiveCfg = Debug|Win32 + {21F4B5BB-C0FC-4F49-BC65-9C714EFB45A3}.Debug|x86.Build.0 = Debug|Win32 + {21F4B5BB-C0FC-4F49-BC65-9C714EFB45A3}.Release|x64.ActiveCfg = Release|x64 + {21F4B5BB-C0FC-4F49-BC65-9C714EFB45A3}.Release|x64.Build.0 = Release|x64 + {21F4B5BB-C0FC-4F49-BC65-9C714EFB45A3}.Release|x86.ActiveCfg = Release|Win32 + {21F4B5BB-C0FC-4F49-BC65-9C714EFB45A3}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E0E03452-0C7E-4951-9F4D-211B5A74F9F7} + EndGlobalSection +EndGlobal diff --git a/1337.vcxproj b/1337.vcxproj new file mode 100644 index 0000000..c3644e6 --- /dev/null +++ b/1337.vcxproj @@ -0,0 +1,222 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {21f4b5bb-c0fc-4f49-bc65-9c714efb45a3} + 1337 + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + ./;$(IncludePath) + test + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + stdcpplatest + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Document + + + + + + + \ No newline at end of file diff --git a/1337.vcxproj.filters b/1337.vcxproj.filters new file mode 100644 index 0000000..015f6cb --- /dev/null +++ b/1337.vcxproj.filters @@ -0,0 +1,236 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;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 + + + {d5d40d09-3134-47d9-8eb7-cb7c349450ea} + + + {7925eee4-c682-4699-9f0f-64daaac6fb66} + + + {4fd7c9f1-15d5-46d4-920a-46c2ab1ca6f8} + + + {cddc14f1-4f8c-4149-bc5f-e458067f9bac} + + + {11f6b1c5-bc4a-4b79-81c5-53e58e35d534} + + + {714e2610-883e-49ef-aa6c-59e725d865e1} + + + {6db18823-dd9a-4918-9a8b-92d37a3a649b} + + + + + Source Files + + + Header Files\Scanners + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\no_gui + + + Header Files\no_renderer\no_gui + + + Header Files\no_renderer\no_menu + + + + + Header Files + + + Header Files\Scanners + + + Header Files + + + Header Files + + + Header Files + + + Header Files\no_hook + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\FW1FontWrapper + + + Header Files\no_renderer\no_gui + + + Header Files\no_renderer\no_gui + + + Header Files\no_renderer\no_gui + + + Header Files\no_renderer\no_menu + + + Header Files\no_cheat + + + Header Files\no_cheat + + + Header Files\no_cheat + + + Header Files\no_cheat + + + Header Files\no_cheat + + + Header Files\no_cheat + + + + + Header Files\no_cheat + + + Header Files\no_cheat + + + \ No newline at end of file diff --git a/1337.vcxproj.user b/1337.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/1337.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/MemoryHelper.cpp b/MemoryHelper.cpp new file mode 100644 index 0000000..a703514 --- /dev/null +++ b/MemoryHelper.cpp @@ -0,0 +1,84 @@ +#include "MemoryHelper.h" + +uintptr_t MemoryHelper::PatternScanW(uintptr_t pModuleBaseAddress, const char* sSignature, size_t nSelectResultIndex) +{ + static auto patternToByte = [](const char* pattern) + { + auto bytes = std::vector{}; + const auto start = const_cast(pattern); + const auto end = const_cast(pattern) + strlen(pattern); + + for (auto current = start; current < end; ++current) + { + if (*current == '?') + { + ++current; + if (*current == '?') + ++current; + bytes.push_back(-1); + } + else + bytes.push_back(strtoul(current, ¤t, 16)); + } + return bytes; + }; + + const auto dosHeader = (PIMAGE_DOS_HEADER)pModuleBaseAddress; + const auto ntHeaders = (PIMAGE_NT_HEADERS)((std::uint8_t*)pModuleBaseAddress + dosHeader->e_lfanew); + + const auto sizeOfImage = ntHeaders->OptionalHeader.SizeOfImage; + auto patternBytes = patternToByte(sSignature); + const auto scanBytes = reinterpret_cast(pModuleBaseAddress); + + const auto s = patternBytes.size(); + const auto d = patternBytes.data(); + + size_t nFoundResults = 0; + + for (auto i = 0ul; i < sizeOfImage - s; ++i) + { + bool found = true; + + for (auto j = 0ul; j < s; ++j) + { + if (scanBytes[i + j] != d[j] && d[j] != -1) + { + found = false; + break; + } + } + + if (found) + { + if (nSelectResultIndex != 0) + { + if (nFoundResults < nSelectResultIndex) + { + nFoundResults++; + found = false; + } + else + return reinterpret_cast(&scanBytes[i]); + } + else + return reinterpret_cast(&scanBytes[i]); + } + } + + return NULL; +} + +uintptr_t MemoryHelper::PatternScan(const char* sSignature, size_t nSelectResultIndex) +{ + static bool bIsSetted = false; + + static MODULEINFO info = { 0 }; + + if (!bIsSetted) + { + GetModuleInformation(GetCurrentProcess(), GetModuleHandle(0), &info, sizeof(info)); + bIsSetted = true; + } + + return PatternScanW((uintptr_t)info.lpBaseOfDll, sSignature, nSelectResultIndex); +} \ No newline at end of file diff --git a/MemoryHelper.h b/MemoryHelper.h new file mode 100644 index 0000000..81da235 --- /dev/null +++ b/MemoryHelper.h @@ -0,0 +1,12 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace MemoryHelper +{ + uintptr_t PatternScanW(uintptr_t pModuleBaseAddress, const char* sSignature, size_t nSelectResultIndex = 0); + uintptr_t PatternScan(const char* sSignature, size_t nSelectResultIndex = 0); +} \ No newline at end of file diff --git a/README.md b/README.md index 171932d..5c8af7a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,35 @@ -# fortnite undetected cheat - +# Fortnite undetcted hack! + +## Description +This tool provides a range of features to enhance your Fortnite gaming experience. Customize your gameplay with features like aimbot, ESP, exploits, and more. + +## Key Features +- Aimbot with adjustable settings +- Enhanced ESP (Box, Skeleton, Lines, Player Names) +- Stream sniper detection +- Aiming while jumping +- Reduced weapon switch delay +- Improved accuracy with no spread +- Rapid fire mode +- Trigger bot for precise shooting +- AirStuck for tactical advantage +- 360-degree field of view (FOV) +- Instant revive option +- Toggleable FOV circle +- Customizable crosshair + +## Installation +To use this tool on Windows, follow these steps: + +1. Download the latest release from the [Releases](https://github.com/violetrosedev/fortnite-undetected-cheat/releases) page. +2. Run the loader executable file. + +## Configuration +You can configure the settings by [describe how to configure if applicable]. + + +## Acknowledgements +- Special thanks to [violetrosedev]. + +## Disclaimer +This project is for educational and entertainment purposes only. Use it responsibly and at your own risk. diff --git a/Release/dlls/fortnite_undetected.dll b/Release/dlls/fortnite_undetected.dll new file mode 100644 index 0000000..5a12b74 Binary files /dev/null and b/Release/dlls/fortnite_undetected.dll differ diff --git a/Release/loader.exe b/Release/loader.exe new file mode 100644 index 0000000..933a55b Binary files /dev/null and b/Release/loader.exe differ diff --git a/dllmain.cpp b/dllmain.cpp new file mode 100644 index 0000000..a24dda1 --- /dev/null +++ b/dllmain.cpp @@ -0,0 +1,315 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// It's generally a good idea to use "using" statements to make your code more readable +using std::ifstream; +using std::ofstream; +using std::ios; +using std::string; + +// Use the HRESULT type rather than defining your own function pointer types +typedef HRESULT(*PresentFn)(IDXGISwapChain*, UINT, UINT); +inline PresentFn original_present{ }; + +typedef HRESULT(*ResizeFn)(IDXGISwapChain*, UINT, UINT, UINT, DXGI_FORMAT, UINT); +inline ResizeFn original_resize{ }; + +// Declare variables as close to their point of use as possible to improve readability +HRESULT(*present_original)(IDXGISwapChain* swapchain, UINT sync, UINT flags) = nullptr; + +ID3D11Texture2D* RenderTargetTexture; +ID3D11RenderTargetView* RenderTargetView = NULL; + +UINT vps = 1; +ID3D11RasterizerState* rwState; +ID3D11RasterizerState* rsState; +float ScreenCenterX; +float ScreenCenterY; + +// Use bool rather than int for boolean variables +bool firstTime = true; + +unsigned long RGBAtoHEX(int r, int g, int b) +{ + // Use bit shifting instead of multiplying and adding + return ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff); +} + +// Use the no_menu::color type rather than defining your own +void functions_line(int x, int y, int x2, int y2, no_menu::color c) noexcept +{ + color cool_col(c.a, c.r, c.g, c.b); + gui.draw_line(x, y, x2, y2, cool_col); +} + +void functions_rect(int x, int y, int x2, int y2, no_menu::color c) noexcept +{ + color cool_col(c.a, c.r, c.g, c.b); + gui.draw_rect(x, y, x2, y2, cool_col); +} + +void functions_filled_rect(int x, int y, int x2, int y2, no_menu::color c) noexcept +{ + color cool_col(c.a, c.r, c.g, c.b); + gui.fill_rect(x, y, x2, y2, cool_col); +} + +// Use a reference to the string type rather than a pointer to char +const wchar_t* CharToWchar(const string& ch) +{ + // Use the size() function rather than strlen() + const size_t len = ch.size() + 1; + wchar_t* wch = new wchar_t[len]; + mbstowcs(wch, ch.c_str(), len); + return wch; +} + +UINT32 ColorToUint32(const no_menu::color color) +{ + UINT32 result = + (BYTE(color.a) << 24) + + (BYTE(color.r) << 16) + + (BYTE(color.g) << 8) + + BYTE(color.b); + return result; +} + +void functions_text(int x, int y, no_menu::color color, bool center, const string& text) noexcept +{ + if (pFontWrapper) { + // Use the string type rather than a pointer to char + const size_t cSize = text.size() + 1; + wchar_t* wc = new wchar_t[cSize]; + size_t tmp = 0; + mbstowcs_s(&tmp, wc, cSize, text.c_str(), cSize); + + pFontWrapper->DrawString(pContext, wc, 14, x, y, ColorToUint32(color), FW1_RESTORESTATE); + delete[] wc; + } +} +// Use a reference to the string type rather than a pointer to char +void functions_text(int x, int y, no_menu::color color, bool center, const string& text) noexcept +{ + if (pFontWrapper) { + const size_t cSize = text.size() + 1; + wchar_t* wc = new wchar_t[cSize]; + size_t tmp = 0; + mbstowcs_s(&tmp, wc, cSize, text.c_str(), cSize); + + if (center) { + // Use a helper function to get the text size rather than calling the same code multiple times + FW1_RECTF textSize = GetTextSize(pFontWrapper, wc, 14); + pFontWrapper->DrawString(pContext, wc, 14, x - textSize.Right / 2, y, ColorToUint32(color), FW1_RESTORESTATE); + } + else { + pFontWrapper->DrawString(pContext, wc, 14, x, y, ColorToUint32(color), FW1_RESTORESTATE); + } + + delete[] wc; + } +} + +FW1_RECTF GetTextSize(IFW1Factory* pFontFactory, const wchar_t* text, float fontSize) +{ + IFW1FontWrapper* pFontWrapper; + pFontFactory->CreateFontWrapper(pDevice, L"Arial", &pFontWrapper); + + FW1_RECTF textRect = { 0 }; + pFontWrapper->MeasureString(pContext, text, fontSize, &textRect, FW1_RESTORESTATE); + + pFontWrapper->Release(); + + return textRect; +} +HRESULT PresentHook(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags) +{ + if (firstTime) { + pSwapChain->GetDevice(__uuidof(pDevice), (void**)&pDevice); + pDevice->GetImmediateContext(&pContext); + + D3D11_RASTERIZER_DESC rwDesc = {}; + rwDesc.FillMode = D3D11_FILL_SOLID; + rwDesc.CullMode = D3D11_CULL_NONE; + pDevice->CreateRasterizerState(&rwDesc, &rwState); + + D3D11_RASTERIZER_DESC rsDesc = {}; + rsDesc.FillMode = D3D11_FILL_SOLID; + rsDesc.CullMode = D3D11_CULL_BACK; + pDevice->CreateRasterizerState(&rsDesc, &rsState); + + pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&RenderTargetTexture); + pDevice->CreateRenderTargetView(RenderTargetTexture, NULL, &RenderTargetView); + + pContext->OMSetRenderTargets(1, &RenderTargetView, NULL); + + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = 1920; + viewport.Height = 1080; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + pContext->RSSetViewports(1, &viewport); + + ScreenCenterX = viewport.Width / 2.0f; + ScreenCenterY = viewport.Height / 2.0f; + + // Initialize the font wrapper + FW1CreateFactory(FW1_VERSION, &pFontFactory); + pFontFactory->CreateFontWrapper(pDevice, L"Tahoma", &pFontWrapper); + + firstTime = false; + } + + if (GetAsyncKeyState(VK_INSERT)) + menu.show(); + else + menu.hide(); + + if (GetAsyncKeyState(VK_F1)) + pawns.menu_loop(); + else + pawns.hide_menu(); + + // Use a helper function to check if the menu is open + if (IsMenuOpen()) { + // Set the rasterizer state to draw the menu + pContext->RSSetState(rwState); + + // Clear the render target to a solid color + pContext->ClearRenderTargetView(RenderTargetView, ClearColor); + + // Draw the menu + menu.draw(); + + // Present the swap chain + return present_original(pSwapChain, SyncInterval, Flags); + } + else { + // Set the rasterizer state to draw the game + pContext->RSSetState(rsState); + + // Clear the render target to a solid color + pContext->ClearRenderTargetView(RenderTargetView, ClearColor); + + // Draw the game + game.draw(); + + // Present the swap chain + return present_original(pSwapChain, SyncInterval, Flags); +} + +HRESULT ResizeHook(IDXGISwapChain* pSwapChain, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) +{ + // Update the render target size and viewport + RenderTargetTexture->Release(); + RenderTargetView->Release(); + + pSwapChain->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags); + pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&RenderTargetTexture); + pDevice->CreateRenderTargetView(RenderTargetTexture, NULL, &RenderTargetView); + + pContext->OMSetRenderTargets(1, &RenderTargetView, NULL); + + D3D11_VIEWPORT viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = Width; + viewport.Height = Height; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + pContext->RSSetViewports(1, &viewport); + + ScreenCenterX = viewport.Width / 2.0f; + ScreenCenterY = viewport.Height / 2.0f; + + // Call the original resize function + return original_resize(pSwapChain, BufferCount, Width, Height, NewFormat, SwapChainFlags); +} + +bool IsMenuOpen() +{ + return menu.is_open(); +} + +// Other functions + +void no_cheat::pawns_loop::add_pawn(const char* pwn, bool(*func)(), bool(*func2)()) +{ + const size_t len = strlen(pwn) + 1; + wchar_t* wc = new wchar_t[len]; + size_t tmp = 0; + mbstowcs_s(&tmp, wc, len, pwn, len); + menu.add(wc, func, func2); + delete[] wc; +} + +void no_cheat::pawns_loop::add_pawn(const char* pwn, bool(*func)(), bool(*func2)(), no_menu::color c) +{ + const size_t len = strlen(pwn) + 1; + wchar_t* wc = new wchar_t[len]; + size_t tmp = 0; + mbstowcs_s(&tmp, wc, len, pwn, len); + menu.add(wc, func, func2, c); + delete[] wc; +} + +void no_cheat::pawns_loop::add_pawn(const char* pwn, bool(*func)(), bool(*func2)(), no_menu::color c, no_menu::color c2) +{ + const size_t len = strlen(pwn) + 1; + wchar_t* wc = new wchar_t[len]; + size_t tmp = 0; + mbstowcs_s(&tmp, wc, len, pwn, len); + menu.add(wc, func, func2, c, c2); + delete[] wc; +} + +void no_cheat::pawns_loop::add_pawn(const char* pwn, bool(*func)(), bool(*func2)(), no_menu::color c, no_menu::color c2, no_menu::color c3) +{ + const size_t len = strlen(pwn) + 1; + wchar_t* wc = new wchar_t[len]; + size_t tmp = 0; + mbstowcs_s(&tmp, wc, len, pwn, len); + menu.add(wc, func, func2, c, c2, c3); + delete[] wc; +} + +void no_cheat::pawns_loop::add_pawn(const char* pwn, bool(*func)(), bool(*func2)(), no_menu::color c, no_menu::color c2, no_menu::color c3, bool(*func3)()) +{ + const size_t len = strlen(pwn) + 1; + wchar_t* wc = new wchar_t[len]; + size_t tmp = 0; + mbstowcs_s(&tmp, wc, len, pwn, len); + menu.add(wc, func, func2, c, c2, c3, func3); + delete[] wc; +} + +void no_cheat::pawns_loop::add_separator() +{ + menu.add_separator(); +} + +void no_cheat::pawns_loop::menu_loop() +{ + menu.show(); +} + +void no_cheat::pawns_loop::hide_menu() +{ + menu.hide(); +} + +bool no_cheat::pawns_loop::is_menu_open() +{ + return menu.is_open(); +} diff --git a/includes.h b/includes.h new file mode 100644 index 0000000..021635a --- /dev/null +++ b/includes.h @@ -0,0 +1,18 @@ +#define _ + +#include +#include +#include +#include + +#include +#include +#include +#include //generateshader + +#include +#include + + +#pragma comment(lib, "D3dcompiler.lib") +#pragma comment(lib, "d3d11.lib") \ No newline at end of file diff --git a/no_cheat/Aimbot.h b/no_cheat/Aimbot.h new file mode 100644 index 0000000..f6e6e15 --- /dev/null +++ b/no_cheat/Aimbot.h @@ -0,0 +1,104 @@ +#pragma once + +auto GetSyscallIndex(std::string ModuleName, std::string SyscallFunctionName, void* Function) -> bool +{ + auto ModuleBaseAddress = LI_FN(GetModuleHandleA)(ModuleName.c_str()); + if (!ModuleBaseAddress) + ModuleBaseAddress = LI_FN(LoadLibraryA)(ModuleName.c_str()); + if (!ModuleBaseAddress) + return false; + + auto GetFunctionAddress = LI_FN(GetProcAddress)(ModuleBaseAddress, SyscallFunctionName.c_str()); + if (!GetFunctionAddress) + return false; + + auto SyscallIndex = *(DWORD*)((PBYTE)GetFunctionAddress + 4); + + *(DWORD*)((PBYTE)Function + 4) = SyscallIndex; + + return true; +} + +extern "C" +{ + NTSTATUS _NtUserSendInput(UINT a1, LPINPUT Input, int Size); +}; + +VOID send_mouse_input(DWORD dwFlags, DWORD dx, DWORD dy, DWORD dwData, ULONG_PTR dwExtraInfo) +{ + static bool doneonce; + if (!doneonce) + { + if (!GetSyscallIndex(_("win32u.dll"), _("NtUserSendInput"), _NtUserSendInput)) + return; + doneonce = true; + } + + INPUT Input[3] = { 0 }; + Input[0].type = INPUT_MOUSE; + Input[0].mi.dx = dx; + Input[0].mi.dy = dy; + Input[0].mi.mouseData = dwData; + Input[0].mi.dwFlags = dwFlags; + Input[0].mi.time = 0; + Input[0].mi.dwExtraInfo = dwExtraInfo; + + _NtUserSendInput((UINT)1, (LPINPUT)&Input, (INT)sizeof(INPUT)); +} + +bool InitializeAimbot(uintptr_t CurrentPawn) { + + uintptr_t LocalPlayerState = read(LocalPawn + offsets::PlayerState); if (!LocalPlayerState) return false; + uintptr_t LocalTeamIndex = read(LocalPlayerState + offsets::TeamIndex); if (!LocalTeamIndex) return false; + uintptr_t CurrentPawnPlayerState = read(CurrentPawn + offsets::PlayerState); if (!CurrentPawnPlayerState) return false; + uintptr_t CurrentPawnTeamIndex = read(CurrentPawnPlayerState + offsets::TeamIndex); if (!CurrentPawnTeamIndex) return false; + + vec3 LookingAtPoint; + bool IsVisible; + if (CurrentPawn == LocalPawn) return false; + if (Settings::VisibleCheck) { + IsVisible = Framework::Camera::LineOfSightTo((PVOID)PlayerController, (PVOID)CurrentPawn, &LookingAtPoint); + } + + if (Settings::Aimbot and No_Discord::GetAsyncKeyState(VK_RBUTTON) and (LocalTeamIndex != CurrentPawnTeamIndex)) { + if (Settings::Fov360) { + if (Settings::VisibleCheck and IsVisible) { + auto NewCameraRotation = Framework::Camera::CalculateNewRotation(CurrentPawn, LocalPawnRelativeLocation, Settings::AimbotPrediction); + Framework::Pawn::SetControlRotation(NewCameraRotation, false); + if (Settings::TriggerBot and IsVisible) { + send_mouse_input(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); + send_mouse_input(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); + } + } + else if (!Settings::VisibleCheck) { + + auto NewRotation = Framework::Camera::CalculateNewRotation(CurrentPawn, LocalPawnRelativeLocation, Settings::AimbotPrediction); + Framework::Pawn::SetControlRotation(NewRotation, false); + if (Settings::TriggerBot and IsVisible) { + send_mouse_input(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); + send_mouse_input(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); + } + } + } + else if (!Settings::Fov360 and Framework::Utils::InFov(CurrentPawn, Settings::AimbotFovCircle, viewport.Width, viewport.Height)) { + if (Settings::VisibleCheck and IsVisible) { + auto NewCameraRotation = Framework::Camera::CalculateNewRotation(CurrentPawn, LocalPawnRelativeLocation, Settings::AimbotPrediction); + Framework::Pawn::SetControlRotation(NewCameraRotation, false); + if (Settings::TriggerBot and IsVisible) { + send_mouse_input(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); + send_mouse_input(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); + } + } + else if (!Settings::VisibleCheck) { + + auto NewRotation = Framework::Camera::CalculateNewRotation(CurrentPawn, LocalPawnRelativeLocation, Settings::AimbotPrediction); + Framework::Pawn::SetControlRotation(NewRotation, false); + if (Settings::TriggerBot and IsVisible) { + send_mouse_input(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); + send_mouse_input(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); + } + } + } + } + return true; +} \ No newline at end of file diff --git a/no_cheat/Esp.h b/no_cheat/Esp.h new file mode 100644 index 0000000..bc54bc8 --- /dev/null +++ b/no_cheat/Esp.h @@ -0,0 +1,414 @@ +#pragma once + +vec3 head2, neck, pelvis, chest, chesti, chestatright, leftShoulder, rightShoulder, leftElbow, rightElbow, leftHand, rightHand, leftLeg, rightLeg, leftThigh, rightThigh, leftFoot, rightFoot, leftFeet, rightFeet, leftFeetFinger, rightFeetFinger; + +void GetAllBonesPos(uintptr_t CurrentPawn) { + Framework::Pawn::GetBoneLocation(CurrentPawn, 66, &head2); Framework::Pawn::WorldToScreen(head2, &head2); + Framework::Pawn::GetBoneLocation(CurrentPawn, 65, &neck); Framework::Pawn::WorldToScreen(neck, &neck); + Framework::Pawn::GetBoneLocation(CurrentPawn, 2, &pelvis); Framework::Pawn::WorldToScreen(pelvis, &pelvis); + Framework::Pawn::GetBoneLocation(CurrentPawn, 36, &chesti); Framework::Pawn::WorldToScreen(chesti, &chesti); + Framework::Pawn::GetBoneLocation(CurrentPawn, 8, &chestatright); Framework::Pawn::WorldToScreen(chestatright, &chestatright); + Framework::Pawn::GetBoneLocation(CurrentPawn, 9, &leftShoulder); Framework::Pawn::WorldToScreen(leftShoulder, &leftShoulder); + Framework::Pawn::GetBoneLocation(CurrentPawn, 37, &rightShoulder); Framework::Pawn::WorldToScreen(rightShoulder, &rightShoulder); + Framework::Pawn::GetBoneLocation(CurrentPawn, 10, &leftElbow); Framework::Pawn::WorldToScreen(leftElbow, &leftElbow); + Framework::Pawn::GetBoneLocation(CurrentPawn, 38, &rightElbow); Framework::Pawn::WorldToScreen(rightElbow, &rightElbow); + Framework::Pawn::GetBoneLocation(CurrentPawn, 11, &leftHand); Framework::Pawn::WorldToScreen(leftHand, &leftHand); + Framework::Pawn::GetBoneLocation(CurrentPawn, 39, &rightHand); Framework::Pawn::WorldToScreen(rightHand, &rightHand); + Framework::Pawn::GetBoneLocation(CurrentPawn, 67, &leftLeg); Framework::Pawn::WorldToScreen(leftLeg, &leftLeg); + Framework::Pawn::GetBoneLocation(CurrentPawn, 74, &rightLeg); Framework::Pawn::WorldToScreen(rightLeg, &rightLeg); + Framework::Pawn::GetBoneLocation(CurrentPawn, 73, &leftThigh); Framework::Pawn::WorldToScreen(leftThigh, &leftThigh); + Framework::Pawn::GetBoneLocation(CurrentPawn, 80, &rightThigh); Framework::Pawn::WorldToScreen(rightThigh, &rightThigh); + Framework::Pawn::GetBoneLocation(CurrentPawn, 68, &leftFoot); Framework::Pawn::WorldToScreen(leftFoot, &leftFoot); + Framework::Pawn::GetBoneLocation(CurrentPawn, 75, &rightFoot); Framework::Pawn::WorldToScreen(rightFoot, &rightFoot); + Framework::Pawn::GetBoneLocation(CurrentPawn, 71, &leftFeet); Framework::Pawn::WorldToScreen(leftFeet, &leftFeet); + Framework::Pawn::GetBoneLocation(CurrentPawn, 78, &rightFeet); Framework::Pawn::WorldToScreen(rightFeet, &rightFeet); + Framework::Pawn::GetBoneLocation(CurrentPawn, 72, &leftFeetFinger); Framework::Pawn::WorldToScreen(leftFeetFinger, &leftFeetFinger); + Framework::Pawn::GetBoneLocation(CurrentPawn, 79, &rightFeetFinger); Framework::Pawn::WorldToScreen(rightFeetFinger, &rightFeetFinger); + chest.x = chesti.x + ((chestatright.x - chesti.x) / 2); + chest.y = chesti.y; +} +/* +void DrawBox(int x, int y, int PawnWidth, int PawnHeight, color color, int BoxType) +{ + if (BoxType == 0) {//Normal Boxes + x = x - (PawnWidth / 2); + + gui.draw_line(x, y, x + PawnWidth, y, color); //bottom + gui.draw_line(x, y, x, y + PawnHeight, color); //left + gui.draw_line(x + PawnWidth, y, x + PawnWidth, y + PawnHeight, color); //right + gui.draw_line(x, y + PawnHeight, x + PawnWidth, y + PawnHeight, color); //up + } + + if (BoxType == 1) {//Cornered Boxes + float lineW = (PawnWidth / 4); + float lineH = (PawnHeight / 3); + + gui.draw_line(x, y, x, y + lineH, color); //Da in alto a sinistra verso giù + gui.draw_line(x, y, x + lineW, y, color); //Da in alto a sinistra verso destra + gui.draw_line(x + PawnWidth - lineW, y, x + PawnWidth, y, color); //Da al centro in alto a destra verso in alto a destra + gui.draw_line(x + PawnWidth, y, x + PawnWidth, y + lineH, color); //Da in alto a destra verso giù + gui.draw_line(x, y + PawnHeight - lineH, x, y + PawnHeight, color); //Dal centro in basso a sinistra verso in basso a sinistra + gui.draw_line(x, y + PawnHeight, x + lineW, y + PawnHeight, color); //Da in basso a sinitra verso destra + gui.draw_line(x + PawnWidth - lineW, y + PawnHeight, x + PawnWidth, y + PawnHeight, color); //Dal centro in basso basso a desta verso in basso a destra + gui.draw_line(x + PawnWidth, y + PawnHeight - lineH, x + PawnWidth, y + PawnHeight, color); //Dal centro a destra in basso verso in basso a destra + } + + + +} +*/ + +inline bool ProcessEvent(uintptr_t address, void* fnobject, void* parms) +{ + UObject* addr = reinterpret_cast(address); if (!addr) return false; + auto vtable = *reinterpret_cast(addr); if (!vtable) return false; + auto processEventFn = static_cast(vtable[0x68]); if (!processEventFn) return false; + SpoofCall(processEventFn, (void*)addr, (void*)fnobject, (void*)parms); + return true; +} + + +typedef struct { + float X, Y, Z; +} FVector; + + + +struct UPrimitiveComponent_SetActorEnableCollision_Params +{ + bool bNewActorEnableCollision; // (Parm, ZeroConstructor, IsPlainOldData) +}; + +void SetActorEnableCollision(uint64_t pawn, bool bNewActorEnableCollision) { + static PVOID fn = nullptr; + + if (!fn) + fn = Framework::Objects::FindObject(_("PrimitiveComponent.SetActorEnableCollision")); + UPrimitiveComponent_SetActorEnableCollision_Params params; + params.bNewActorEnableCollision = bNewActorEnableCollision; + ProcessEvent(pawn, fn, ¶ms); +} + + +// Function Engine.PrimitiveComponent.SetEnableGravity +struct UPrimitiveComponent_SetEnableGravity_Params +{ + bool bGravityEnabled; // (Parm, ZeroConstructor, IsPlainOldData) +}; +void SetEnableGravity(uint64_t primitive_component, bool bEnable) +{ + static PVOID fn = nullptr; + + if (!fn) + fn = Framework::Objects::FindObject(_("PrimitiveComponent.SetEnableGravity")); + UPrimitiveComponent_SetEnableGravity_Params params; + params.bGravityEnabled = bEnable; + ProcessEvent(primitive_component, fn, ¶ms); +} +//GetDistanceMeters = cameralocation.distance(localpawn) / 100 + +struct UPrimitiveComponent_SetAllPhysicsLinearVelocity_Params +{ + FVector NewVel; // (Parm, IsPlainOldData) + bool bAddToCurrent; // (Parm, ZeroConstructor, IsPlainOldData) +}; + +void SetAllPhysicsAngularVelocity(uint64_t primitive_component, const FVector& NewVel, bool bAddToCurrent) +{ + static PVOID fn = nullptr; + + if (!fn) + fn = Framework::Objects::FindObject(_("PrimitiveComponent.SetPhysicsAngularVelocity")); + + if (!fn) return; + + UPrimitiveComponent_SetAllPhysicsLinearVelocity_Params params; + params.NewVel = NewVel; + params.bAddToCurrent = bAddToCurrent; + + ProcessEvent(primitive_component, fn, ¶ms); +} + +void SetAllPhysicsLinearVelocity(uint64_t primitive_component, const FVector& NewVel, bool bAddToCurrent) +{ + static PVOID fn = nullptr; + + if (!fn) + fn = Framework::Objects::FindObject(_("PrimitiveComponent.SetPhysicsLinearVelocity")); + UPrimitiveComponent_SetAllPhysicsLinearVelocity_Params params; + params.NewVel = NewVel; + params.bAddToCurrent = bAddToCurrent; + + + + + ProcessEvent(primitive_component, fn, ¶ms); +} + +//GCameraCache->Rotation.Yaw = camerarotation.y + +void ProcessVehicle(uintptr_t pawn) +{ + auto rc = read(pawn + offsets::RootComponent);//root component + + if (!rc) + return; + + + + auto loc = read(rc + offsets::RelativeLocation); + + + //if ((LocalPawnRelativeLocation.distance(loc) / 100) > 10) + // return; + + + auto veh_mesh = *(uintptr_t*)(pawn + 0xAD8); if (!veh_mesh) return; + + if (veh_mesh) + { + if (GetAsyncKeyState('O')) + { + SetActorEnableCollision(pawn, false); + + float coeff = (60.0f * 60); + + if (GetAsyncKeyState(VK_SHIFT)) + { + coeff *= 2; + } + + SetAllPhysicsAngularVelocity(veh_mesh, { 0, 0, 0 }, false); + SetAllPhysicsLinearVelocity(veh_mesh, { 0, 0, 0 }, false); + SetEnableGravity(veh_mesh, false); + bool bKp = false; + + if (GetAsyncKeyState('Q') & 0x8000) + { + SetAllPhysicsLinearVelocity(veh_mesh, { 0.f, 0.f, coeff / 2 }, true); + bKp = true; + } + + if (GetAsyncKeyState('E') & 0x8000) + { + SetAllPhysicsLinearVelocity(veh_mesh, { 0.f, 0.f, -(coeff / 2) }, true); + bKp = true; + } + + if (GetAsyncKeyState(0x57)) + { + FVector vel; + auto yaw = CamRot.y; + float theta = 2.f * M_PI * (yaw / 360.f); + + vel.X = (coeff * cos(theta)); + vel.Y = (coeff * sin(theta)); + vel.Z = 0.f; + + SetAllPhysicsLinearVelocity(veh_mesh, vel, true); + bKp = true; + } + if (GetAsyncKeyState(0x53)) + { + FVector vel; + auto yaw = CamRot.y; + float theta = 2.f * M_PI * (yaw / 360.f); + + vel.X = -(coeff * cos(theta)); + vel.Y = -(coeff * sin(theta)); + + SetAllPhysicsLinearVelocity(veh_mesh, vel, true); //{ -80.f, 0.f, 0.f } + bKp = true; + } + if (GetAsyncKeyState(0x41)) // A + { + FVector vel; + auto yaw = CamRot.y; + float theta = 2.f * M_PI * (yaw / 360.f); + + vel.X = (coeff * sin(theta)); + vel.Y = -(coeff * cos(theta)); + + SetAllPhysicsLinearVelocity(veh_mesh, vel, true); //{ -80.f, 0.f, 0.f } + bKp = true; + } + if (GetAsyncKeyState(0x44)) // D + { + FVector vel; + auto yaw = CamRot.y; + float theta = 2.f * M_PI * (yaw / 360.f); + + vel.X = -(coeff * sin(theta)); + vel.Y = (coeff * cos(theta)); + + SetAllPhysicsLinearVelocity(veh_mesh, vel, true); //{ -80.f, 0.f, 0.f } + bKp = true; + } + + if (!bKp || GetAsyncKeyState(VK_SPACE)) + { + SetAllPhysicsLinearVelocity(veh_mesh, { 0.0, 0.0, 0.0 }, false); + } + } + else + { + SetEnableGravity(veh_mesh, true); + SetActorEnableCollision(pawn, true); + } + } +} + + + +UINT32 kekColorToUint32(const color col) +{ + UINT32 result = + (BYTE(col.A) << 24) + + (BYTE(col.R) << 16) + + (BYTE(col.G) << 8) + + BYTE(col.B); + return result; +} + +void DrawBox(vec3 StartBoxLoc, float flWidth, float Height, color color) +{ + StartBoxLoc.x = StartBoxLoc.x - (flWidth / 2); + + gui.draw_line(StartBoxLoc.x, StartBoxLoc.y, StartBoxLoc.x + flWidth, StartBoxLoc.y, color); //bottom + gui.draw_line(StartBoxLoc.x, StartBoxLoc.y, StartBoxLoc.x, StartBoxLoc.y + Height, color); //left + gui.draw_line(StartBoxLoc.x + flWidth, StartBoxLoc.y, StartBoxLoc.x + flWidth, StartBoxLoc.y + Height, color); //right + gui.draw_line(StartBoxLoc.x, StartBoxLoc.y + Height, StartBoxLoc.x + flWidth, StartBoxLoc.y + Height, color); //up +} + +void DrawCorneredBox(int X, int Y, int W, int H, color color) { + float lineW = (W / 4); + float lineH = (H / 3); + + gui.draw_line(X, Y, X, Y + lineH, color); //Da in alto a sinistra verso giù + + gui.draw_line(X, Y, X + lineW, Y, color); //Da in alto a sinistra verso destra + + gui.draw_line(X + W - lineW, Y, X + W, Y, color); //Da al centro in alto a destra verso in alto a destra + + gui.draw_line(X + W, Y, X + W, Y + lineH, color); //Da in alto a destra verso giù + + gui.draw_line(X, Y + H - lineH, X, Y + H, color); //Dal centro in basso a sinistra verso in basso a sinistra + + gui.draw_line(X, Y + H, X + lineW, Y + H, color); //Da in basso a sinitra verso destra + + gui.draw_line(X + W - lineW, Y + H, X + W, Y + H, color); //Dal centro in basso basso a desta verso in basso a destra + + gui.draw_line(X + W, Y + H - lineH, X + W, Y + H, color); //Dal centro a destra in basso verso in basso a destra + +} + + + +bool DrawEsp; + +bool InitializeESP(uintptr_t CurrentPawn) { + if (CurrentPawn == LocalPawn) return false; + + vec3 LookingAtPoint; + bool IsVisible; + if (Settings::VisibleCheck) { + IsVisible = Framework::Camera::LineOfSightTo((PVOID)PlayerController, (PVOID)CurrentPawn, &LookingAtPoint); + } + + vec3 Head_W2S; Framework::Pawn::GetBoneLocation(CurrentPawn, 66, &Head_W2S); Framework::Pawn::WorldToScreen(vec3(Head_W2S.x, Head_W2S.y, Head_W2S.z + 15), &Head_W2S); + vec3 Bottom_W2S; Framework::Pawn::GetBoneLocation(CurrentPawn, 0, &Bottom_W2S); Framework::Pawn::WorldToScreen(Bottom_W2S, &Bottom_W2S); + + GetAllBonesPos(CurrentPawn); + + if (Framework::Utils::IsInScreen(CurrentPawn, viewport.Width, viewport.Height)) { + color BoxesColor; + color SkeletonColor; + color LineColor; + + if (IsVisible) { + BoxesColor = { 255, 0, 0, 0 }; //Visible Color + SkeletonColor = { 255, 222, 0, 52 }; //Visible Color + LineColor = { 0, 0, 0, 52 }; //Visible Color + } + else { + BoxesColor = { 230, 255, 255, 255 }; //Not Visible Color + SkeletonColor = { 230, 255, 255, 255 }; //Not Visible Color + LineColor = { 230, 247, 67, 67 }; //Not Visible Color + } + + int array[20] = { Head_W2S.x, neck.x, pelvis.x, chest.x, leftShoulder.x, rightShoulder.x, leftElbow.x, rightElbow.x, leftHand.x, rightHand.x, leftLeg.x, rightLeg.x, leftThigh.x, rightThigh.x, leftFoot.x, rightFoot.x, leftFeet.x, rightFeet.x, leftFeetFinger.x, rightFeetFinger.x }; + int mostright = array[0]; + int mostleft = array[0]; + if (Settings::ESPType_Value == 0 or Settings::ESPType_Value == 1) { + for (int mostrighti = 0; mostrighti < 20; mostrighti++) { if (array[mostrighti] > mostright) mostright = array[mostrighti]; } + for (int mostlefti = 0; mostlefti < 20; mostlefti++) { if (array[mostlefti] < mostleft) mostleft = array[mostlefti]; } + } + + float PawnHeight = Bottom_W2S.y - Head_W2S.y; + if (PawnHeight < 0) PawnHeight = PawnHeight * (-1.f); + + + + + if (DrawEsp) { + + //Boxes + if (Settings::ESPType_Value == 0) { + DrawBox(Head_W2S, (mostright - mostleft), PawnHeight, BoxesColor); + } + else if (Settings::ESPType_Value == 1) { + DrawCorneredBox(mostleft, Head_W2S.y, (mostright - mostleft), PawnHeight, BoxesColor); + } + + if (Settings::ESP_Skeleton) + { + + gui.draw_line(head2.x, head2.y, neck.x, neck.y, SkeletonColor); + gui.draw_line(neck.x, neck.y, chest.x, chest.y, SkeletonColor); + gui.draw_line(chest.x, chest.y, pelvis.x, pelvis.y, SkeletonColor); + gui.draw_line(chest.x, chest.y, leftShoulder.x, leftShoulder.y, SkeletonColor); + gui.draw_line(chest.x, chest.y, rightShoulder.x, rightShoulder.y, SkeletonColor); + gui.draw_line(leftShoulder.x, leftShoulder.y, leftElbow.x, leftElbow.y, SkeletonColor); + gui.draw_line(rightShoulder.x, rightShoulder.y, rightElbow.x, rightElbow.y, SkeletonColor); + gui.draw_line(leftElbow.x, leftElbow.y, leftHand.x, leftHand.y, SkeletonColor); + gui.draw_line(rightElbow.x, rightElbow.y, rightHand.x, rightHand.y, SkeletonColor); + gui.draw_line(pelvis.x, pelvis.y, leftLeg.x, leftLeg.y, SkeletonColor); + gui.draw_line(pelvis.x, pelvis.y, rightLeg.x, rightLeg.y, SkeletonColor); + gui.draw_line(leftLeg.x, leftLeg.y, leftThigh.x, leftThigh.y, SkeletonColor); + gui.draw_line(rightLeg.x, rightLeg.y, rightThigh.x, rightThigh.y, SkeletonColor); + gui.draw_line(leftThigh.x, leftThigh.y, leftFoot.x, leftFoot.y, SkeletonColor); + gui.draw_line(rightThigh.x, rightThigh.y, rightFoot.x, rightFoot.y, SkeletonColor); + gui.draw_line(leftFoot.x, leftFoot.y, leftFeet.x, leftFeet.y, SkeletonColor); + gui.draw_line(rightFoot.x, rightFoot.y, rightFeet.x, rightFeet.y, SkeletonColor); + gui.draw_line(leftFeet.x, leftFeet.y, leftFeetFinger.x, leftFeetFinger.y, SkeletonColor); + gui.draw_line(rightFeet.x, rightFeet.y, rightFeetFinger.x, rightFeetFinger.y, SkeletonColor); + } + if (Settings::ESP_Lines) { + gui.draw_line(viewport.Width / 2, viewport.Height - 10, pelvis.x, pelvis.y, LineColor); + } + } + + uintptr_t PlayerState = read(CurrentPawn + offsets::PlayerState); if (!PlayerState) return false; + + Framework::Structs::FString PlayerName; + + ProcessEvent(PlayerState, FNObjects::GetPlayerName, &PlayerName); + + if (Settings::ESP_StreamSnipe) { + std::wstring InputStreamSnipePlayer(Settings::ESP_StreamSnipePlayer.begin(), Settings::ESP_StreamSnipePlayer.end()); + if (PlayerName.c_str() == InputStreamSnipePlayer) { + DrawEsp = true; + } + else { + DrawEsp = false; + } + } + else { + DrawEsp = true; + } + + if (Settings::ESP_PlayersNames) { + pFontWrapper->DrawString(pContext, PlayerName.c_str(), 14, Head_W2S.x, Head_W2S.y, kekColorToUint32(SkeletonColor), FW1_RESTORESTATE); + } + } +} diff --git a/no_cheat/Exploits.h b/no_cheat/Exploits.h new file mode 100644 index 0000000..4f23e72 --- /dev/null +++ b/no_cheat/Exploits.h @@ -0,0 +1,37 @@ +#pragma once + +bool InitializeExploits(uintptr_t CurrentPawn) { + uintptr_t CurrentWeapon = read(LocalPawn + offsets::CurrentWeapon); + + if (Settings::NoAnimation and CurrentWeapon) { + write(CurrentWeapon + offsets::bDisableEquipAnimation, true); + } + else { + write(CurrentWeapon + offsets::bDisableEquipAnimation, false); + } + + if (Settings::AimWhileJumping and CurrentWeapon) { + write(CurrentWeapon + offsets::bADSWhileNotOnGround, true); + } + else { + write(CurrentWeapon + offsets::bADSWhileNotOnGround, false); + } + + if (Settings::InstantRevive) { + write(LocalPawn + offsets::ReviveFromDBNOTime, 0.101); + } + + if(Settings::AirStuck and No_Discord::GetAsyncKeyState(VK_MENU)){ //Alt Keybind + write(LocalPawn + offsets::CustomTimeDilation, 0); + } + else if(Settings::AirStuck and !No_Discord::GetAsyncKeyState(VK_MENU)){ //Alt Keybind + write(LocalPawn + offsets::CustomTimeDilation, 1); + } + + if(Settings::RapidFire and CurrentWeapon){ + float a = read(CurrentWeapon + offsets::LastFireTime); + float b = read(CurrentWeapon + offsets::LastFireTimeVerified); + write(CurrentWeapon + offsets::LastFireTime, a + b - 0.0003); //RapidFire value + } + return true; +} diff --git a/no_cheat/NtUserSendInput.asm b/no_cheat/NtUserSendInput.asm new file mode 100644 index 0000000..cddfa05 --- /dev/null +++ b/no_cheat/NtUserSendInput.asm @@ -0,0 +1,12 @@ +.code + +_NtUserSendInput PROC + + mov r10, rcx + mov eax, 3735928559 + syscall + ret + +_NtUserSendInput ENDP + +END \ No newline at end of file diff --git a/no_cheat/PawnsLoop.h b/no_cheat/PawnsLoop.h new file mode 100644 index 0000000..aa1d7e8 --- /dev/null +++ b/no_cheat/PawnsLoop.h @@ -0,0 +1,42 @@ +#pragma once + + +bool PawnsLoop() { + try { + uintptr_t World = read(Uworld); if (!World) return false; + uintptr_t Gameinstance = read(World + offsets::OwningGameInstance); if (!Gameinstance) return false; + uintptr_t World_Players = read(Gameinstance + offsets::LocalPlayers); if (!World_Players) return false; + uintptr_t World_Player = read(World_Players); if (!World_Player) return false; + PlayerController = read(World_Player + offsets::PlayerController); if (!PlayerController) return false; + uintptr_t World_PlayerCameraManager = read(PlayerController + offsets::PlayerCameraManager); if (!World_PlayerCameraManager) return false; + FOVAngle = Framework::Camera::GetFOVAngle(World_PlayerCameraManager); Framework::Camera::GetPlayerViewPoint(World_PlayerCameraManager, &CamLoc, &CamRot); + LocalPawn = read(PlayerController + offsets::AcknowledgedPawn); + uintptr_t PersistentLevel = read(World + offsets::PersistentLevel); if (!PersistentLevel) return false; + uintptr_t AActors = read(PersistentLevel + offsets::AActors); if (!AActors) return false; + uintptr_t ActorCount = read(PersistentLevel + offsets::ActorCount); if (!ActorCount) return false; + uintptr_t LocalRootComponent; vec3 LocalRelativeLocation; + if (IsValidPointer(LocalPawn)) { + LocalRootComponent = read(LocalPawn + 0x130); if (!LocalRootComponent) return false; + LocalRelativeLocation = read(LocalRootComponent + 0x11C); + LocalPawnRelativeLocation = read(LocalRootComponent + 0x11C); + } + + for (int i = 0; i < ActorCount; i++) { + auto CurrentPawn = read(AActors + i * sizeof(uintptr_t)); + + + auto CurrentPawn_ObjectName = Framework::Objects::GetUintObjectName(CurrentPawn); + + if (strstr(CurrentPawn_ObjectName, "PlayerPawn")) { + InitializeESP(CurrentPawn); + if (IsValidPointer(LocalPawn)) { + InitializeAimbot(CurrentPawn); + InitializeExploits(CurrentPawn); + } + } + + + } + } + catch (...) {} +} \ No newline at end of file diff --git a/no_cheat/framework.h b/no_cheat/framework.h new file mode 100644 index 0000000..6eadada --- /dev/null +++ b/no_cheat/framework.h @@ -0,0 +1,522 @@ +#pragma once + +bool IsValidPointer(uintptr_t address) { + if (!IsBadWritePtr((LPVOID)address, (UINT_PTR)8)) return TRUE; + else return false; +} + +template +ReadT read(uintptr_t address, const ReadT& def = ReadT()) { + if (IsValidPointer(address)) { + return *(ReadT*)address; + } +} + +template +WriteT write(uintptr_t address, WriteT value, const WriteT& def = WriteT()) { + if (IsValidPointer(address)) { + *(WriteT*)((PBYTE)address) = value; + } + return 1; +} + +class UClass { +public: + BYTE _padding_0[0x40]; + UClass* SuperClass; +}; + +class UObject { +public: + PVOID VTableObject; + DWORD ObjectFlags; + DWORD InternalIndex; + UClass* Class; + BYTE _padding_0[0x8]; + UObject* Outer; + /* + inline void ProcessEvent(void* fn, void* parms) + { + auto vtable = *reinterpret_cast(this); + auto processEventFn = static_cast(vtable[0x44]); + processEventFn(this, fn, parms); + } + */ + inline BOOLEAN IsA(PVOID parentClass) { + for (auto super = this->Class; super; super = super->SuperClass) { + if (super == parentClass) { + return TRUE; + } + } + + return FALSE; + } +}; + +class FUObjectItem { +public: + UObject* Object; + DWORD Flags; + DWORD ClusterIndex; + DWORD SerialNumber; + DWORD SerialNumber2; +}; + +class TUObjectArray { +public: + FUObjectItem* Objects[9]; +}; + +class GObjects { +public: + TUObjectArray* ObjectArray; + BYTE _padding_0[0xC]; + DWORD ObjectCount; +}; + +GObjects* objects = nullptr; +bool once = false; +namespace Framework { + namespace Structs { + + + struct FMatrix + { + float M[4][4]; + }; + static FMatrix* myMatrix = new FMatrix(); + + + template + struct TArray + { + friend struct FString; + + public: + inline TArray() + { + Data = nullptr; + Count = Max = 0; + }; + + inline int Num() const + { + return Count; + }; + + inline T& operator[](int i) + { + return Data[i]; + }; + + inline const T& operator[](int i) const + { + return Data[i]; + }; + + inline bool IsValidIndex(int i) const + { + return i < Num(); + } + + private: + T* Data; + int32_t Count; + int32_t Max; + }; + + struct FString : private TArray + { + inline FString() + { + }; + + FString(const wchar_t* other) + { + Max = Count = *other ? std::wcslen(other) + 1 : 0; + + if (Count) + { + Data = const_cast(other); + } + }; + + inline bool IsValid() const + { + return Data != nullptr; + } + + inline const wchar_t* c_str() const + { + return Data; + } + + std::string ToString() const + { + auto length = std::wcslen(Data); + std::string str(length, '\0'); + std::use_facet>(std::locale()).narrow(Data, Data + length, '?', &str[0]); + return str; + } + }; + } + namespace Pawn { + static bool GetBoneLocation(uintptr_t CurrentActor, int id, vec3* out) + { + uintptr_t mesh = read(CurrentActor + offsets::Mesh); if (!mesh) return false; + + auto fGetBoneMatrix = ((Structs::FMatrix * (__fastcall*)(uintptr_t, Structs::FMatrix*, int))(BoneMatrix)); + SpoofCall(fGetBoneMatrix, mesh, Structs::myMatrix, id); + + out->x = Structs::myMatrix->M[3][0]; + out->y = Structs::myMatrix->M[3][1]; + out->z = Structs::myMatrix->M[3][2]; + + return true; + } + + static bool WorldToScreen(vec3 WorldLocation, vec3* out) + { + auto WorldToScreen = reinterpret_cast(ProjectWorldToScreen); + + SpoofCall(WorldToScreen, (uintptr_t)PlayerController, WorldLocation, out, (char)0); + + return true; + } + + static void SetControlRotation(vec3 NewRotation, bool bResetCamera = false) + { + auto SetControlRotation_ = (*(void(__fastcall**)(uintptr_t Controller, vec3 NewRotation, bool bResetCamera))(*(uintptr_t*)PlayerController + 0x688)); + SpoofCall(SetControlRotation_, PlayerController, NewRotation, bResetCamera); + } + } + namespace Utils { + inline float GetDistanceLength(vec3 start, vec3 end) { + return float(sqrtf(powf(end.x - start.x, 2.0) + powf(end.y - start.y, 2.0) + powf(end.z - start.z, 2.0))); + } + + bool InFov(uintptr_t CurrentPawn, int FovValue, int Width, int Height) { + vec3 HeadPos; Pawn::GetBoneLocation(CurrentPawn, 66, &HeadPos); Pawn::WorldToScreen(HeadPos, &HeadPos); + auto dx = HeadPos.x - (Width / 2); + auto dy = HeadPos.y - (Height / 2); + auto dist = sqrtf(dx * dx + dy * dy); + + if (dist < FovValue) { + return true; + } + else { + return false; + } + } + + bool IsInScreen(uintptr_t CurrentPawn, int Width, int Height) { + if (CurrentPawn) { + vec3 HeadPos; Pawn::GetBoneLocation(CurrentPawn, 66, &HeadPos); Pawn::WorldToScreen(HeadPos, &HeadPos); + if (((HeadPos.x <= 0 or HeadPos.x > Width) and (HeadPos.y <= 0 or HeadPos.y > Height)) or ((HeadPos.x <= 0 or HeadPos.x > Width) or (HeadPos.y <= 0 or HeadPos.y > Height))) { + return false; + } + else { + return true; + } + } + } + } + namespace Objects { + + static void FreeObjectName(__int64 address) { + auto func = reinterpret_cast<__int64(__fastcall*)(__int64 a1)>(FreeFn); + SpoofCall(func, address); + } + + static const char* GetUintObjectName(uintptr_t Object) + { + if (Object == NULL) return ""; + + auto fGetObjName = reinterpret_cast(GetNameByIndex); + + int index = *(int*)(Object + 0x18); + + Structs::FString result; + SpoofCall(fGetObjName, &index, &result); + + if (result.c_str() == NULL) return ""; + + auto result_str = result.ToString(); + + if (result.c_str() != NULL) + FreeObjectName((__int64)result.c_str()); + + return result_str.c_str(); + } + + + static const char* GetUObjectName(UObject* Object) + { + if (Object == NULL) return ""; + + auto fGetObjName = reinterpret_cast(GetNameByIndex); + + int index = *(int*)(reinterpret_cast(Object) + 0x18); + + Structs::FString result; + SpoofCall(fGetObjName, &index, &result); + + if (result.c_str() == NULL) return ""; + + auto result_str = result.ToString(); + + if (result.c_str() != NULL) + FreeObjectName((__int64)result.c_str()); + + return result_str.c_str(); + } + + + static const char* GetUObjectNameLoop(UObject* Object) { + std::string name(""); + for (auto i = 0; Object; Object = Object->Outer, ++i) { + + auto fGetObjName = reinterpret_cast(GetNameByIndex); + + int index = *(int*)(reinterpret_cast(Object) + 0x18); + + Structs::FString fObjectName; + SpoofCall(fGetObjName, &index, &fObjectName); + + if (!fObjectName.IsValid()) { + break; + } + + auto objectName = fObjectName.ToString(); + + + name = objectName + std::string(i > 0 ? "." : "") + name; + FreeObjectName((uintptr_t)fObjectName.c_str()); + } + + return name.c_str(); + } + + PVOID FindObject(std::string name) { + bool once = false; + if (!once) + { + auto UObjectPtr = MemoryHelper::PatternScan(signatures::Gobject_Sig); + objects = decltype(objects)(RVA(UObjectPtr, 7)); + //std::cout << "obj " << std::hex << objects << "\n"; + //std::cout << "base " << std::hex << GetModuleHandleA(0) << "\n"; + + once = true; + } + for (auto array : objects->ObjectArray->Objects) { + auto fuObject = array; + //Sleep(1); + for (auto i = 0; i < 0x10000 && fuObject->Object; ++i, ++fuObject) { + //Sleep(1); + auto object = fuObject->Object; + if (object->ObjectFlags != 0x41) {} + else { + std::cout << ""; + if (strstr(GetUObjectNameLoop(object), name.c_str())) return object; + } + + //log << GetUObjectName(object) << "\n"; + } + } + return 0; + } + + } + namespace Camera { + static float GetFOVAngle(uintptr_t PlayerCameraManager) + { + auto GetFOVAngle = reinterpret_cast(*(ULONG_PTR*)(*(ULONG_PTR*)PlayerCameraManager + 0x6D0)); + return SpoofCall(GetFOVAngle, (ULONG_PTR)PlayerCameraManager, (char*)0); + } + + static vec3 GetCameraLocation(uintptr_t PlayerCameraManager) + { + auto GetCameraLocation = reinterpret_cast(*(ULONG_PTR*)(*(ULONG_PTR*)PlayerCameraManager + 0x718)); + return SpoofCall(GetCameraLocation, (ULONG_PTR)PlayerCameraManager, (char*)0); + } + + static vec3 GetCameraRotation(uintptr_t PlayerCameraManager) + { + auto GetCameraRotation = reinterpret_cast(*(ULONG_PTR*)(*(ULONG_PTR*)PlayerCameraManager + 0x710)); + return SpoofCall(GetCameraRotation, (ULONG_PTR)PlayerCameraManager, (char*)0); + } + + static bool LineOfSightTo(PVOID PlayerController, PVOID Actor, vec3* ViewPoint) { + auto LOSTo = reinterpret_cast(LineOfS); + return SpoofCall(LOSTo, PlayerController, Actor, ViewPoint); + } + + static bool GetPlayerViewPoint(uintptr_t PlayerController, vec3* vCameraPos, vec3* vCameraRot) + { + if (!PlayerController) return false; + + static uintptr_t pGetPlayerViewPoint = 0; + if (!pGetPlayerViewPoint) + { + uintptr_t VTable = *(uintptr_t*)PlayerController; + if (!VTable) return false; + + pGetPlayerViewPoint = *(uintptr_t*)(VTable + 0x708); + if (!pGetPlayerViewPoint) return false; + } + + auto GetPlayerViewPoint = reinterpret_cast(pGetPlayerViewPoint); + + SpoofCall(GetPlayerViewPoint, (uintptr_t)PlayerController, vCameraPos, vCameraRot); + + return true; + } + + vec3 CalculateNewRotation(uintptr_t CurrentPawn, vec3 LocalRelativeLocation, bool prediction) { + vec3 NewRotationVector = { 0, 0, 0 }; + + vec3 Head_No_W2S, Head_W2S; + Pawn::GetBoneLocation(CurrentPawn, 66, &Head_No_W2S); Pawn::WorldToScreen(vec3(Head_No_W2S.x, Head_No_W2S.y, Head_No_W2S.z + 20), &Head_W2S); + + vec3 PredictionCalculated; + + if (prediction) { + float distance = Utils::GetDistanceLength(LocalRelativeLocation, Head_W2S) / 250; + uintptr_t CurrentPawnRootComponent = read(CurrentPawn + offsets::RootComponent); + vec3 CurrentPawnVelocity = read(CurrentPawnRootComponent + offsets::ComponentVelocity); + + vec3 PositionRecalculated = Head_No_W2S; + float BulletGravity = fabs(-504); + float Time = distance / fabs(30000); + float BulletDrop = (BulletGravity / 250) * Time * Time; + PositionRecalculated.z += BulletDrop * 120; + PositionRecalculated.x += Time * (CurrentPawnVelocity.x); + PositionRecalculated.y += Time * (CurrentPawnVelocity.y); + PositionRecalculated.z += Time * (CurrentPawnVelocity.z); + PredictionCalculated = PositionRecalculated; + } + else { + PredictionCalculated = Head_No_W2S; + } + + vec3 VectorPos = PredictionCalculated - CamLoc; + + float distance = VectorPos.Length(); + + NewRotationVector.x = -((SpoofRuntime::acosf_(VectorPos.z / distance) * (float)(180.0f / M_PI)) - 90.f); + NewRotationVector.y = SpoofRuntime::atan2f_(VectorPos.y, VectorPos.x) * (float)(180.0f / M_PI); + + return NewRotationVector; + } + } +} + + +namespace No_Discord { + + uintptr_t module = (uintptr_t)LI_FN(GetModuleHandleA)(_("DiscordHook64.dll")); + + std::vector pCreatedHooksArray; + bool CreateHook(uintptr_t pOriginal, uintptr_t pHookedFunction, uintptr_t pOriginalCall) + { + static uintptr_t addrCreateHook = NULL; + + if (!addrCreateHook) + addrCreateHook = MemoryHelper::PatternScanW(module, _("41 57 41 56 56 57 55 53 48 83 EC 68 4D 89 C6 49 89 D7")); + + if (!addrCreateHook) + return false; + + using CreateHook_t = uint64_t(__fastcall*)(LPVOID, LPVOID, LPVOID*); + auto fnCreateHook = (CreateHook_t)addrCreateHook; + + return SpoofCall(fnCreateHook, (void*)pOriginal, (void*)pHookedFunction, (void**)pOriginalCall) == 0 ? true : false; + } + + bool EnableHookQue() + { + static uintptr_t addrEnableHookQueu = NULL; + + if (!addrEnableHookQueu) + addrEnableHookQueu = MemoryHelper::PatternScanW(module, _("41 57 41 56 41 55 41 54 56 57 55 53 48 83 EC 38 48 ? ? ? ? ? ? 48 31 E0 48 89 44 24 30 BE 01 00 00 00 31 C0 F0 ? ? ? ? ? ? ? 74 2B")); + + if (!addrEnableHookQueu) + return false; + + using EnableHookQueu_t = uint64_t(__stdcall*)(VOID); + auto fnEnableHookQueu = (EnableHookQueu_t)addrEnableHookQueu; + + return SpoofCall(fnEnableHookQueu) == 0 ? true : false; + } + + short GetAsyncKeyState(int key) + { + static uintptr_t GetAsyncKeyState_addr; + if (!GetAsyncKeyState_addr) + GetAsyncKeyState_addr = MemoryHelper::PatternScanW(module, _("48 FF ? ? ? ? ? CC CC CC CC CC CC CC CC CC 48 FF ? ? ? ? ? CC CC CC CC CC CC CC CC CC 48 83 EC 28 48 ? ? ? ? ? ? 48 85 C9")); + if (!GetAsyncKeyState_addr) + return false; + + auto queuehook = ((short(__fastcall*)(int))(GetAsyncKeyState_addr)); + return SpoofCall(queuehook, key); + } + + bool EnableHook(uintptr_t pTarget, bool bIsEnabled) + { + static uintptr_t addrEnableHook = NULL; + + if (!addrEnableHook) + addrEnableHook = MemoryHelper::PatternScanW(module, _("41 56 56 57 53 48 83 EC 28 49 89 CE BF 01 00 00 00 31 C0 F0 ? ? ? ? ? ? ? 74")); + + if (!addrEnableHook) + return false; + + using EnableHook_t = uint64_t(__fastcall*)(LPVOID, bool); + auto fnEnableHook = (EnableHook_t)addrEnableHook; + + return SpoofCall(fnEnableHook, (void*)pTarget, bIsEnabled) == 0 ? true : false; + } + + + short SetCursorPos(int x, int y) + { + static uintptr_t addrSetCursorPos = NULL; + + if (!addrSetCursorPos) + { + addrSetCursorPos = MemoryHelper::PatternScanW(module, + _("8A 05 ? ? ? ? 84 C0 74 12")); + } + + if (!addrSetCursorPos) + return false; + + using SetCursorPos_t = short(__fastcall*)(int, int); + auto fnSetCursorPos = (SetCursorPos_t)addrSetCursorPos; + + return fnSetCursorPos(x, y); + } + + bool InsertHook(uintptr_t pOriginal, uintptr_t pHookedFunction, uintptr_t pOriginalCall) + { + bool bAlreadyCreated = false; + for (auto _Hook : pCreatedHooksArray) + { + if (_Hook == pOriginal) + { + bAlreadyCreated = true; + break; + } + } + + if (!bAlreadyCreated) + bAlreadyCreated = CreateHook(pOriginal, pHookedFunction, pOriginalCall); + + if (bAlreadyCreated) + if (EnableHook(pOriginal, true)) + if (EnableHookQue()) + return true; + + return false; + } +} \ No newline at end of file diff --git a/no_cheat/no_spoofcall.asm b/no_cheat/no_spoofcall.asm new file mode 100644 index 0000000..9584228 --- /dev/null +++ b/no_cheat/no_spoofcall.asm @@ -0,0 +1,30 @@ +PUBLIC _spoofer_stub + +.code + +_spoofer_stub PROC + pop r11 + add rsp, 8 + mov rax, [rsp + 24] + + mov r10, [rax] + mov [rsp], r10 + + mov r10, [rax + 8] + mov [rax + 8], r11 + + mov [rax + 16], rsi + lea rsi, fixup + mov [rax], rsi + mov rsi, rax + + jmp r10 + +fixup: + sub rsp, 16 + mov rcx, rsi + mov rsi, [rcx + 16] + jmp QWORD PTR [rcx + 8] +_spoofer_stub ENDP + +END \ No newline at end of file diff --git a/no_cheat/no_spoofcall.h b/no_cheat/no_spoofcall.h new file mode 100644 index 0000000..b0dccc3 --- /dev/null +++ b/no_cheat/no_spoofcall.h @@ -0,0 +1,123 @@ +#pragma once + +namespace detail +{ + extern "C" void* _spoofer_stub(); + + template + static inline auto shellcode_stub_helper( + const void* shell, + Args... args + ) -> Ret + { + auto fn = (Ret(*)(Args...))(shell); + return fn(args...); + } + + template + struct argument_remapper + { + template< + typename Ret, + typename First, + typename Second, + typename Third, + typename Fourth, + typename... Pack + > + static auto do_call(const void* shell, void* shell_param, First first, Second second, + Third third, Fourth fourth, Pack... pack) -> Ret + { + return shellcode_stub_helper< Ret, First, Second, Third, Fourth, void*, void*, Pack... >(shell, first, second, third, fourth, shell_param, nullptr, pack...); + } + }; + + template + struct argument_remapper> + { + template< + typename Ret, + typename First = void*, + typename Second = void*, + typename Third = void*, + typename Fourth = void* + > + static auto do_call( + const void* shell, + void* shell_param, + First first = First{}, + Second second = Second{}, + Third third = Third{}, + Fourth fourth = Fourth{} + ) -> Ret + { + return shellcode_stub_helper< + Ret, + First, + Second, + Third, + Fourth, + void*, + void* + >( + shell, + first, + second, + third, + fourth, + shell_param, + nullptr + ); + } + }; +} + +template +static inline auto SpoofCall(Ret(*fn)(Args...), Args... args) -> Ret +{ + static const void* jmprbx = nullptr; + if (!jmprbx) { + const auto ntdll = reinterpret_cast(::GetModuleHandleW(NULL)); + const auto dos = reinterpret_cast(ntdll); + const auto nt = reinterpret_cast(ntdll + dos->e_lfanew); + const auto sections = IMAGE_FIRST_SECTION(nt); + const auto num_sections = nt->FileHeader.NumberOfSections; + + constexpr char section_name[5]{ '.', 't', 'e', 'x', 't' }; + const auto section = std::find_if(sections, sections + num_sections, [&](const auto& s) { + return std::equal(s.Name, s.Name + 5, section_name); + }); + + constexpr unsigned char instr_bytes[2]{ 0xFF, 0x26 }; + const auto va = ntdll + section->VirtualAddress; + jmprbx = std::search(va, va + section->Misc.VirtualSize, instr_bytes, instr_bytes + 2); + } + + struct shell_params + { + const void* trampoline; + void* function; + void* rdx; + }; + + shell_params p + { + jmprbx, + reinterpret_cast(fn) + }; + + using mapper = detail::argument_remapper; + return mapper::template do_call((const void*)&detail::_spoofer_stub, &p, args...); +} + +namespace SpoofRuntime { + inline float acosf_(float x) + { + return SpoofCall(acosf, x); + } + + inline float atan2f_(float x, float y) + { + return SpoofCall(atan2f, x, y); + } +} diff --git a/no_define.h b/no_define.h new file mode 100644 index 0000000..31e92a3 --- /dev/null +++ b/no_define.h @@ -0,0 +1,280 @@ +#pragma once +#define RVA(addr, size) ((uintptr_t)((UINT_PTR)(addr) + *(PINT)((UINT_PTR)(addr) + ((size) - sizeof(INT))) + (size))) +#define M_PI 3.14159265358979323846264338327950288419716939937510 + +//Sigs Addresses +uintptr_t Uworld; +uintptr_t FreeFn; +uintptr_t GetNameByIndex; +uintptr_t LineOfS; +uintptr_t BoneMatrix; +uintptr_t ProjectWorldToScreen; + +//Read Addresses +uintptr_t PlayerController; +uintptr_t LocalPawn; +vec3 LocalPawnRelativeLocation; + + +float FOVAngle; +vec3 CamLoc; +vec3 CamRot; +//updated for chapter 3 +namespace signatures { + const char* Uworld_Sig = "48 89 05 ? ? ? ? 48 8B 4B 78"; //uworld + + const char* Gobject_Sig = "48 8B 05 ? ? ? ? 48 8B 0C C8 48 8B 04 D1"; + + const char* Free_Sig = "48 85 C9 0F 84 ? ? ? ? 53 48 83 EC 20 48 89 7C 24 30 48 8B D9 48 8B 3D ? ? ? ? 48 85 FF 0F 84 ? ? ? ? 48 8B 07 4C 8B 40 30 48 8D 05 ? ? ? ? 4C 3B C0"; //Free + + const char* ProjectWorldToScreen_Sig = "E8 ? ? ? ? 48 8B 5C 24 ? 41 88 07 48 83 C4 30"; //ProjectWorldToScreen + + const char* LineOfSightTo_Sig = "48 8B C4 48 89 58 20 55 56 57 41 54 41 55 41 56 41 57 48 8D 6C 24 ? 48 81 EC ? ? ? ? 0F 29 70 B8 0F 29 78 A8 44 0F 29 40 ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 45 20 45 8A E9"; //LineOfSight + + const char* GetNameByIndex_Sig = "48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 56 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 84 24 ? ? ? ? 48 8B F2 4C 8B F1 E8 ? ? ? ? 45 8B 06 33 ED 41 0F B7 16 41 C1 E8 10 89 54 24 24 44 89 44 24 ? 48 8B 4C 24 ? 48 C1 E9 20 8D 3C 09 4A 03 7C C0 ? 0F B7 17 C1 EA 06 41 39 6E 04"; //GetNameByIndex + + const char* BoneMatrix_Sig = "E8 ? ? ? ? 48 8B 47 30 F3 0F 10 45"; //BoneMatrix + + const char* Spread_Sig = "E8 ? ? ? ? 48 8D 4B 28 E8 ? ? ? ? 48 8B C8"; //Spread + + const char* SpreadCaller_sig = "0F 57 D2 48 8D 4C 24 ? 41 0F 28 CC E8 ? ? ? ? 48 8B 4D B0 0F 28 F0 48 85 C9"; //SpreadCaller + + const char* DiscordPresentScene_sig = "56 57 53 48 83 EC 30 44 89 C6"; //Discord PresentScene +} + +namespace offsets { + uintptr_t OwningGameInstance = 0x190; + uintptr_t LocalPlayers = 0x38; + uintptr_t PlayerController = 0x30; + uintptr_t PlayerCameraManager = 0x2C8; + uintptr_t AcknowledgedPawn = 0x2B0; + + uintptr_t Levels = 0x148; + uintptr_t PersistentLevel = 0x30; + uintptr_t AActors = 0x98; + uintptr_t ActorCount = 0xA0; + + uintptr_t ComponentVelocity = 0x140; + uintptr_t RootComponent = 0x138; + uintptr_t FireStartLoc = 0x8C8; + uintptr_t RelativeLocation = 0x11C; + uintptr_t RelativeRotation = 0x128; + uintptr_t CurrentWeapon = 0x5F8; + uintptr_t PlayerState = 0x240; + uintptr_t Mesh = 0x288; + uintptr_t TeamIndex = 0xF30; + + + //Exploits + uintptr_t bDisableEquipAnimation = 0x2B4; + uintptr_t bADSWhileNotOnGround = 0x3E61; + uintptr_t ReviveFromDBNOTime = 0x3768; + uintptr_t CustomTimeDilation = 0x9C; + uintptr_t LastFireTime = 0x9EC; + uintptr_t LastFireTimeVerified = 0x9F0; + +} + +namespace FNObjects { + PVOID GetPlayerName; +} + +D3D11_VIEWPORT viewport; +no_gui gui; +ID3D11Device* pDevice = NULL; +ID3D11DeviceContext* pContext = NULL; + +IFW1Factory* pFW1Factory = NULL; +IFW1FontWrapper* pFontWrapper = NULL; + +namespace Settings +{ + bool Aimbot = false; + int AimbotFovCircle = 100; + int AimbotSmooth = 0.0f; + static int AimbotBone_Value = 0; + bool AimbotPrediction = false; + + + bool ESP = false; + static int ESPType_Value = 1; + bool ESP_Skeleton = false; + bool ESP_Lines = false; + bool ESP_PlayersNames = false; + bool ESP_StreamSnipe = false; + std::string ESP_StreamSnipePlayer = ""; + + bool ShowFovCircle = true; + bool Variable_For_test = false; + + //Exploits + + bool AimWhileJumping = false; + bool NoAnimation = false; + bool NoSpread = false; + bool RapidFire = false; + bool TriggerBot = false; + bool AirStuck = false; + bool Fov360 = false; + bool InstantRevive = false; + + + + + + bool VisibleCheck = false; + + + + bool Crosshair = false; + bool DebugForTest = false; +} + +namespace UI_Help { + namespace AimbotTab { + void Aimbot() { + no_menu::SetWidgetPosition(129, 58); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[Memory Aimbot] Locks your aim to the player"); + } + + no_menu::SetWidgetPosition(8, 75); + } + + void AimbotFov() { + no_menu::SetWidgetPosition(167, 96); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[Aimbot Fov] The size of the circle where the Aimbot should lock"); + } + + no_menu::SetWidgetPosition(8, 120); + } + + void AimbotSmooth() { + no_menu::SetWidgetPosition(167, 140); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[Aimbot Smooth] The time that the camera takes to lock the player"); + } + + no_menu::SetWidgetPosition(8, 164); + } + + void AimbotBone() { + no_menu::SetWidgetPosition(118, 183); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[Aimbot Bone] You can choose on what bone the Aimbot should lock"); + } + + no_menu::SetWidgetPosition(8, 214); + } + + void AimbotPrediction() { + no_menu::SetWidgetPosition(159, 222); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[Aimbot Prediction BETA] It predicts the player movement"); + } + } + } + + + namespace ESPTab { + void ESP() { + no_menu::SetWidgetPosition(107, 58); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[ESP] You can see Players, Objects, Loot through walls"); + } + + no_menu::SetWidgetPosition(8, 78); + } + } + + namespace ExploitsTab { + void AimWhileJumping() { + no_menu::SetWidgetPosition(154, 59); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[Aim While Jumping] You can Aim while you are jumping"); + } + + no_menu::SetWidgetPosition(8, 74); + } + + void NoAnimations() { + no_menu::SetWidgetPosition(124, 82); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[No Animation] It skips your switch weapon animation"); + } + + no_menu::SetWidgetPosition(8, 99); + } + + void NoSpread() { + no_menu::SetWidgetPosition(96, 107); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[No Spread] It reduces the bullet spread on every weapon"); + } + + no_menu::SetWidgetPosition(8, 126); + } + + void RapidFire() { + no_menu::SetWidgetPosition(102, 134); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[Rapid Fire] It increase the fire rate of some weapons"); + } + + no_menu::SetWidgetPosition(8, 153); + + + } + + void TriggerBot() { + no_menu::SetWidgetPosition(110, 161); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[Trigger Bot] Automatically shoot when a player is visible"); + } + + no_menu::SetWidgetPosition(8, 181); + + } + + void AirStuck() { + no_menu::SetWidgetPosition(88, 189); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[AirStuck] Your player will be frozen and stuck in air when pressing ALT"); + } + + no_menu::SetWidgetPosition(8, 208); + } + + void Fov360() { + no_menu::SetWidgetPosition(80, 216); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[360 Fov] The Aimbot will lock even on players behind you"); + } + + no_menu::SetWidgetPosition(8, 235); + } + + void InstantRevive() { + no_menu::SetWidgetPosition(129, 243); + + if (no_menu::TextHoverable("(?)", no_menu::color({ 255, 231, 94, 230 }))) { + no_menu::MiniBox("[Instant Revive] It sets the revive time to 0 for your team"); + } + } + } + +} diff --git a/no_imports.h b/no_imports.h new file mode 100644 index 0000000..7e76029 --- /dev/null +++ b/no_imports.h @@ -0,0 +1,700 @@ +/* + * Copyright 2018-2020 Justas Masiulis + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + // documentation is available at https://github.com/JustasMasiulis/lazy_importer + +#ifndef LAZY_IMPORTER_HPP +#define LAZY_IMPORTER_HPP + +#define LI_FN(name) \ + ::li::detail::lazy_function<::li::detail::khash(#name), decltype(&name)>() + +#define LI_FN_DEF(name) ::li::detail::lazy_function<::li::detail::khash(#name), name>() + +#define LI_MODULE(name) ::li::detail::lazy_module<::li::detail::khash(name)>() + +// NOTE only std::forward is used from this header. +// If there is a need to eliminate this dependency the function itself is very small. + +#include +#include +#include + +#ifndef LAZY_IMPORTER_NO_FORCEINLINE +#if defined(_MSC_VER) +#define LAZY_IMPORTER_FORCEINLINE __forceinline +#elif defined(__GNUC__) && __GNUC__ > 3 +#define LAZY_IMPORTER_FORCEINLINE inline __attribute__((__always_inline__)) +#else +#define LAZY_IMPORTER_FORCEINLINE inline +#endif +#else +#define LAZY_IMPORTER_FORCEINLINE inline +#endif + +#ifdef LAZY_IMPORTER_CASE_INSENSITIVE +#define LAZY_IMPORTER_TOLOWER(c) (c >= 'A' && c <= 'Z' ? (c | (1 << 5)) : c) +#else +#define LAZY_IMPORTER_TOLOWER(c) (c) +#endif + +namespace li { + namespace detail { + + template + struct pair { + First first; + Second second; + }; + + namespace win { + + struct LIST_ENTRY_T { + const char* Flink; + const char* Blink; + }; + + struct UNICODE_STRING_T { + unsigned short Length; + unsigned short MaximumLength; + wchar_t* Buffer; + }; + + struct PEB_LDR_DATA_T { + unsigned long Length; + unsigned long Initialized; + const char* SsHandle; + LIST_ENTRY_T InLoadOrderModuleList; + }; + + struct PEB_T { + unsigned char Reserved1[2]; + unsigned char BeingDebugged; + unsigned char Reserved2[1]; + const char* Reserved3[2]; + PEB_LDR_DATA_T* Ldr; + }; + + struct LDR_DATA_TABLE_ENTRY_T { + LIST_ENTRY_T InLoadOrderLinks; + LIST_ENTRY_T InMemoryOrderLinks; + LIST_ENTRY_T InInitializationOrderLinks; + const char* DllBase; + const char* EntryPoint; + union { + unsigned long SizeOfImage; + const char* _dummy; + }; + UNICODE_STRING_T FullDllName; + UNICODE_STRING_T BaseDllName; + + LAZY_IMPORTER_FORCEINLINE const LDR_DATA_TABLE_ENTRY_T* + load_order_next() const noexcept + { + return reinterpret_cast( + InLoadOrderLinks.Flink); + } + }; + + struct IMAGE_DOS_HEADER { // DOS .EXE header + unsigned short e_magic; // Magic number + unsigned short e_cblp; // Bytes on last page of file + unsigned short e_cp; // Pages in file + unsigned short e_crlc; // Relocations + unsigned short e_cparhdr; // Size of header in paragraphs + unsigned short e_minalloc; // Minimum extra paragraphs needed + unsigned short e_maxalloc; // Maximum extra paragraphs needed + unsigned short e_ss; // Initial (relative) SS value + unsigned short e_sp; // Initial SP value + unsigned short e_csum; // Checksum + unsigned short e_ip; // Initial IP value + unsigned short e_cs; // Initial (relative) CS value + unsigned short e_lfarlc; // File address of relocation table + unsigned short e_ovno; // Overlay number + unsigned short e_res[4]; // Reserved words + unsigned short e_oemid; // OEM identifier (for e_oeminfo) + unsigned short e_oeminfo; // OEM information; e_oemid specific + unsigned short e_res2[10]; // Reserved words + long e_lfanew; // File address of new exe header + }; + + struct IMAGE_FILE_HEADER { + unsigned short Machine; + unsigned short NumberOfSections; + unsigned long TimeDateStamp; + unsigned long PointerToSymbolTable; + unsigned long NumberOfSymbols; + unsigned short SizeOfOptionalHeader; + unsigned short Characteristics; + }; + + struct IMAGE_EXPORT_DIRECTORY { + unsigned long Characteristics; + unsigned long TimeDateStamp; + unsigned short MajorVersion; + unsigned short MinorVersion; + unsigned long Name; + unsigned long Base; + unsigned long NumberOfFunctions; + unsigned long NumberOfNames; + unsigned long AddressOfFunctions; // RVA from base of image + unsigned long AddressOfNames; // RVA from base of image + unsigned long AddressOfNameOrdinals; // RVA from base of image + }; + + struct IMAGE_DATA_DIRECTORY { + unsigned long VirtualAddress; + unsigned long Size; + }; + + struct IMAGE_OPTIONAL_HEADER64 { + unsigned short Magic; + unsigned char MajorLinkerVersion; + unsigned char MinorLinkerVersion; + unsigned long SizeOfCode; + unsigned long SizeOfInitializedData; + unsigned long SizeOfUninitializedData; + unsigned long AddressOfEntryPoint; + unsigned long BaseOfCode; + unsigned long long ImageBase; + unsigned long SectionAlignment; + unsigned long FileAlignment; + unsigned short MajorOperatingSystemVersion; + unsigned short MinorOperatingSystemVersion; + unsigned short MajorImageVersion; + unsigned short MinorImageVersion; + unsigned short MajorSubsystemVersion; + unsigned short MinorSubsystemVersion; + unsigned long Win32VersionValue; + unsigned long SizeOfImage; + unsigned long SizeOfHeaders; + unsigned long CheckSum; + unsigned short Subsystem; + unsigned short DllCharacteristics; + unsigned long long SizeOfStackReserve; + unsigned long long SizeOfStackCommit; + unsigned long long SizeOfHeapReserve; + unsigned long long SizeOfHeapCommit; + unsigned long LoaderFlags; + unsigned long NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[16]; + }; + + struct IMAGE_OPTIONAL_HEADER32 { + unsigned short Magic; + unsigned char MajorLinkerVersion; + unsigned char MinorLinkerVersion; + unsigned long SizeOfCode; + unsigned long SizeOfInitializedData; + unsigned long SizeOfUninitializedData; + unsigned long AddressOfEntryPoint; + unsigned long BaseOfCode; + unsigned long BaseOfData; + unsigned long ImageBase; + unsigned long SectionAlignment; + unsigned long FileAlignment; + unsigned short MajorOperatingSystemVersion; + unsigned short MinorOperatingSystemVersion; + unsigned short MajorImageVersion; + unsigned short MinorImageVersion; + unsigned short MajorSubsystemVersion; + unsigned short MinorSubsystemVersion; + unsigned long Win32VersionValue; + unsigned long SizeOfImage; + unsigned long SizeOfHeaders; + unsigned long CheckSum; + unsigned short Subsystem; + unsigned short DllCharacteristics; + unsigned long SizeOfStackReserve; + unsigned long SizeOfStackCommit; + unsigned long SizeOfHeapReserve; + unsigned long SizeOfHeapCommit; + unsigned long LoaderFlags; + unsigned long NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[16]; + }; + + struct IMAGE_NT_HEADERS { + unsigned long Signature; + IMAGE_FILE_HEADER FileHeader; +#ifdef _WIN64 + IMAGE_OPTIONAL_HEADER64 OptionalHeader; +#else + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +#endif + }; + + } // namespace win + + // hashing stuff + struct hash_t { + using value_type = unsigned long; + constexpr static value_type offset = 2166136261; + constexpr static value_type prime = 16777619; + constexpr static unsigned long long prime64 = prime; + + LAZY_IMPORTER_FORCEINLINE constexpr static value_type single(value_type value, + char c) noexcept + { + return static_cast( + (value ^ LAZY_IMPORTER_TOLOWER(c)) * + static_cast(prime)); + } + }; + + template + LAZY_IMPORTER_FORCEINLINE constexpr hash_t::value_type + khash(const CharT* str, hash_t::value_type value = hash_t::offset) noexcept + { + return (*str ? khash(str + 1, hash_t::single(value, *str)) : value); + } + + template + LAZY_IMPORTER_FORCEINLINE hash_t::value_type hash(const CharT* str) noexcept + { + hash_t::value_type value = hash_t::offset; + + for (;;) { + char c = *str++; + if (!c) + return value; + value = hash_t::single(value, c); + } + } + + LAZY_IMPORTER_FORCEINLINE hash_t::value_type hash( + const win::UNICODE_STRING_T& str) noexcept + { + auto first = str.Buffer; + const auto last = first + (str.Length / sizeof(wchar_t)); + auto value = hash_t::offset; + for (; first != last; ++first) + value = hash_t::single(value, static_cast(*first)); + + return value; + } + + LAZY_IMPORTER_FORCEINLINE pair hash_forwarded( + const char* str) noexcept + { + pair module_and_function{ + hash_t::offset, hash_t::offset + }; + + for (; *str != '.'; ++str) + module_and_function.first = hash_t::single(module_and_function.first, *str); + + ++str; + + for (; *str; ++str) + module_and_function.second = hash_t::single(module_and_function.second, *str); + + return module_and_function; + } + + + // some helper functions + LAZY_IMPORTER_FORCEINLINE const win::PEB_T* peb() noexcept + { +#if defined(_M_X64) || defined(__amd64__) + return reinterpret_cast(__readgsqword(0x60)); +#elif defined(_M_IX86) || defined(__i386__) + return reinterpret_cast(__readfsdword(0x30)); +#elif defined(_M_ARM) || defined(__arm__) + return *reinterpret_cast(_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30); +#elif defined(_M_ARM64) || defined(__aarch64__) + return *reinterpret_cast(__getReg(18) + 0x60); +#elif defined(_M_IA64) || defined(__ia64__) + return *reinterpret_cast(static_cast(_rdteb()) + 0x60); +#else +#error Unsupported platform. Open an issue and I'll probably add support. +#endif + } + + LAZY_IMPORTER_FORCEINLINE const win::PEB_LDR_DATA_T* ldr() + { + return reinterpret_cast(peb()->Ldr); + } + + LAZY_IMPORTER_FORCEINLINE const win::IMAGE_NT_HEADERS* nt_headers( + const char* base) noexcept + { + return reinterpret_cast( + base + reinterpret_cast(base)->e_lfanew); + } + + LAZY_IMPORTER_FORCEINLINE const win::IMAGE_EXPORT_DIRECTORY* image_export_dir( + const char* base) noexcept + { + return reinterpret_cast( + base + nt_headers(base)->OptionalHeader.DataDirectory->VirtualAddress); + } + + LAZY_IMPORTER_FORCEINLINE const win::LDR_DATA_TABLE_ENTRY_T* ldr_data_entry() noexcept + { + return reinterpret_cast( + ldr()->InLoadOrderModuleList.Flink); + } + + struct exports_directory { + const char* _base; + const win::IMAGE_EXPORT_DIRECTORY* _ied; + unsigned long _ied_size; + + public: + using size_type = unsigned long; + + LAZY_IMPORTER_FORCEINLINE + exports_directory(const char* base) noexcept : _base(base) + { + const auto ied_data_dir = nt_headers(base)->OptionalHeader.DataDirectory[0]; + _ied = reinterpret_cast( + base + ied_data_dir.VirtualAddress); + _ied_size = ied_data_dir.Size; + } + + LAZY_IMPORTER_FORCEINLINE explicit operator bool() const noexcept + { + return reinterpret_cast(_ied) != _base; + } + + LAZY_IMPORTER_FORCEINLINE size_type size() const noexcept + { + return _ied->NumberOfNames; + } + + LAZY_IMPORTER_FORCEINLINE const char* base() const noexcept { return _base; } + LAZY_IMPORTER_FORCEINLINE const win::IMAGE_EXPORT_DIRECTORY* ied() const noexcept + { + return _ied; + } + + LAZY_IMPORTER_FORCEINLINE const char* name(size_type index) const noexcept + { + return reinterpret_cast( + _base + reinterpret_cast( + _base + _ied->AddressOfNames)[index]); + } + + LAZY_IMPORTER_FORCEINLINE const char* address(size_type index) const noexcept + { + const auto* const rva_table = + reinterpret_cast(_base + _ied->AddressOfFunctions); + + const auto* const ord_table = reinterpret_cast( + _base + _ied->AddressOfNameOrdinals); + + return _base + rva_table[ord_table[index]]; + } + + LAZY_IMPORTER_FORCEINLINE bool is_forwarded( + const char* export_address) const noexcept + { + const auto ui_ied = reinterpret_cast(_ied); + return (export_address > ui_ied && export_address < ui_ied + _ied_size); + } + }; + + struct safe_module_enumerator { + using value_type = const detail::win::LDR_DATA_TABLE_ENTRY_T; + value_type* value; + value_type* head; + + LAZY_IMPORTER_FORCEINLINE safe_module_enumerator() noexcept + : safe_module_enumerator(ldr_data_entry()) + {} + + LAZY_IMPORTER_FORCEINLINE + safe_module_enumerator(const detail::win::LDR_DATA_TABLE_ENTRY_T* ldr) noexcept + : value(ldr->load_order_next()), head(value) + {} + + LAZY_IMPORTER_FORCEINLINE void reset() noexcept + { + value = head->load_order_next(); + } + + LAZY_IMPORTER_FORCEINLINE bool next() noexcept + { + value = value->load_order_next(); + + return value != head && value->DllBase; + } + }; + + struct unsafe_module_enumerator { + using value_type = const detail::win::LDR_DATA_TABLE_ENTRY_T*; + value_type value; + + LAZY_IMPORTER_FORCEINLINE unsafe_module_enumerator() noexcept + : value(ldr_data_entry()) + {} + + LAZY_IMPORTER_FORCEINLINE void reset() noexcept { value = ldr_data_entry(); } + + LAZY_IMPORTER_FORCEINLINE bool next() noexcept + { + value = value->load_order_next(); + return true; + } + }; + + // provides the cached functions which use Derive classes methods + template + class lazy_base { + protected: + // This function is needed because every templated function + // with different args has its own static buffer + LAZY_IMPORTER_FORCEINLINE static void*& _cache() noexcept + { + static void* value = nullptr; + return value; + } + + public: + template + LAZY_IMPORTER_FORCEINLINE static T safe() noexcept + { + return Derived::template get(); + } + + template + LAZY_IMPORTER_FORCEINLINE static T cached() noexcept + { + auto& cached = _cache(); + if (!cached) + cached = Derived::template get(); + + return (T)(cached); + } + + template + LAZY_IMPORTER_FORCEINLINE static T safe_cached() noexcept + { + return cached(); + } + }; + + template + struct lazy_module : lazy_base> { + template + LAZY_IMPORTER_FORCEINLINE static T get() noexcept + { + Enum e; + do { + if (hash(e.value->BaseDllName) == Hash) + return (T)(e.value->DllBase); + } while (e.next()); + return {}; + } + + template + LAZY_IMPORTER_FORCEINLINE static T in(Ldr ldr) noexcept + { + safe_module_enumerator e((const detail::win::LDR_DATA_TABLE_ENTRY_T*)(ldr)); + do { + if (hash(e.value->BaseDllName) == Hash) + return (T)(e.value->DllBase); + } while (e.next()); + return {}; + } + + template + LAZY_IMPORTER_FORCEINLINE static T in_cached(Ldr ldr) noexcept + { + auto& cached = lazy_base>::_cache(); + if (!cached) + cached = in(ldr); + + return (T)(cached); + } + }; + + template + struct lazy_function : lazy_base, T> { + using base_type = lazy_base, T>; + + template + LAZY_IMPORTER_FORCEINLINE decltype(auto) operator()(Args&&... args) const + { +#ifndef LAZY_IMPORTER_CACHE_OPERATOR_PARENS + return get()(std::forward(args)...); +#else + return this->cached()(std::forward(args)...); +#endif + } + + template + LAZY_IMPORTER_FORCEINLINE static F get() noexcept + { + // for backwards compatability. + // Before 2.0 it was only possible to resolve forwarded exports when + // this macro was enabled +#ifdef LAZY_IMPORTER_RESOLVE_FORWARDED_EXPORTS + return forwarded(); +#else + + Enum e; + + do { +#ifdef LAZY_IMPORTER_HARDENED_MODULE_CHECKS + if (!e.value->DllBase || !e.value->FullDllName.Length) + continue; +#endif + + const exports_directory exports(e.value->DllBase); + + if (exports) { + auto export_index = exports.size(); + while (export_index--) + if (hash(exports.name(export_index)) == Hash) + return (F)(exports.address(export_index)); + } + } while (e.next()); + return {}; +#endif + } + + template + LAZY_IMPORTER_FORCEINLINE static F forwarded() noexcept + { + detail::win::UNICODE_STRING_T name; + hash_t::value_type module_hash = 0; + auto function_hash = Hash; + + Enum e; + do { + name = e.value->BaseDllName; + name.Length -= 8; // get rid of .dll extension + + if (!module_hash || hash(name) == module_hash) { + const exports_directory exports(e.value->DllBase); + + if (exports) { + auto export_index = exports.size(); + while (export_index--) + if (hash(exports.name(export_index)) == function_hash) { + const auto addr = exports.address(export_index); + + if (exports.is_forwarded(addr)) { + auto hashes = hash_forwarded( + reinterpret_cast(addr)); + + function_hash = hashes.second; + module_hash = hashes.first; + + e.reset(); + break; + } + return (F)(addr); + } + } + } + } while (e.next()); + return {}; + } + + template + LAZY_IMPORTER_FORCEINLINE static F forwarded_safe() noexcept + { + return forwarded(); + } + + template + LAZY_IMPORTER_FORCEINLINE static F forwarded_cached() noexcept + { + auto& value = base_type::_cache(); + if (!value) + value = forwarded(); + return (F)(value); + } + + template + LAZY_IMPORTER_FORCEINLINE static F forwarded_safe_cached() noexcept + { + return forwarded_cached(); + } + + template + LAZY_IMPORTER_FORCEINLINE static F in(Module m) noexcept + { + if (IsSafe && !m) + return {}; + + const exports_directory exports((const char*)(m)); + if (IsSafe && !exports) + return {}; + + for (unsigned long i{};; ++i) { + if (IsSafe && i == exports.size()) + break; + + if (hash(exports.name(i)) == Hash) + return (F)(exports.address(i)); + } + return {}; + } + + template + LAZY_IMPORTER_FORCEINLINE static F in_safe(Module m) noexcept + { + return in(m); + } + + template + LAZY_IMPORTER_FORCEINLINE static F in_cached(Module m) noexcept + { + auto& value = base_type::_cache(); + if (!value) + value = in(m); + return (F)(value); + } + + template + LAZY_IMPORTER_FORCEINLINE static F in_safe_cached(Module m) noexcept + { + return in_cached(m); + } + + template + LAZY_IMPORTER_FORCEINLINE static F nt() noexcept + { + return in(ldr_data_entry()->load_order_next()->DllBase); + } + + template + LAZY_IMPORTER_FORCEINLINE static F nt_safe() noexcept + { + return in_safe(ldr_data_entry()->load_order_next()->DllBase); + } + + template + LAZY_IMPORTER_FORCEINLINE static F nt_cached() noexcept + { + return in_cached(ldr_data_entry()->load_order_next()->DllBase); + } + + template + LAZY_IMPORTER_FORCEINLINE static F nt_safe_cached() noexcept + { + return in_safe_cached(ldr_data_entry()->load_order_next()->DllBase); + } + }; + + } +} // namespace li::detail + +#endif // include guard \ No newline at end of file diff --git a/no_renderer/FW1FontWrapper/CFW1ColorRGBA.cpp b/no_renderer/FW1FontWrapper/CFW1ColorRGBA.cpp new file mode 100644 index 0000000..2e32125 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1ColorRGBA.cpp @@ -0,0 +1,35 @@ +// CFW1ColorRGBA.cpp + +#include "FW1Precompiled.h" + +#include "CFW1ColorRGBA.h" + + +namespace FW1FontWrapper { + + +// Construct +CFW1ColorRGBA::CFW1ColorRGBA() : + m_color32(0xffffffff) +{ +} + + +// Destruct +CFW1ColorRGBA::~CFW1ColorRGBA() { +} + + +// Init +HRESULT CFW1ColorRGBA::initColor(IFW1Factory *pFW1Factory, UINT32 initialColor32) { + HRESULT hResult = initBaseObject(pFW1Factory); + if(FAILED(hResult)) + return hResult; + + m_color32 = initialColor32; + + return S_OK; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1ColorRGBA.h b/no_renderer/FW1FontWrapper/CFW1ColorRGBA.h new file mode 100644 index 0000000..43918b7 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1ColorRGBA.h @@ -0,0 +1,45 @@ +// CFW1ColorRGBA.h + +#ifndef IncludeGuard__FW1_CFW1ColorRGBA +#define IncludeGuard__FW1_CFW1ColorRGBA + +#include "CFW1Object.h" + + +namespace FW1FontWrapper { + + +// A color +class CFW1ColorRGBA : public CFW1Object { + public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + // IFW1Color32 + virtual void STDMETHODCALLTYPE SetColor(UINT32 Color); + virtual void STDMETHODCALLTYPE SetColor(FLOAT Red, FLOAT Green, FLOAT Blue, FLOAT Alpha); + virtual void STDMETHODCALLTYPE SetColor(const FLOAT *pColor); + virtual void STDMETHODCALLTYPE SetColor(const BYTE *pColor); + + virtual UINT32 STDMETHODCALLTYPE GetColor32(); + + // Public functions + public: + CFW1ColorRGBA(); + + HRESULT initColor(IFW1Factory *pFW1Factory, UINT32 initialColor32); + + // Internal functions + private: + virtual ~CFW1ColorRGBA(); + + // Internal data + private: + UINT32 m_color32; +}; + + +}// namespace FW1FontWrapper + + +#endif// IncludeGuard__FW1_CFW1ColorRGBA diff --git a/no_renderer/FW1FontWrapper/CFW1ColorRGBAInterface.cpp b/no_renderer/FW1FontWrapper/CFW1ColorRGBAInterface.cpp new file mode 100644 index 0000000..c9cd278 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1ColorRGBAInterface.cpp @@ -0,0 +1,68 @@ +// CFW1ColorRGBAInterface.cpp + +#include "FW1Precompiled.h" + +#include "CFW1ColorRGBA.h" + + +namespace FW1FontWrapper { + + +// Query interface +HRESULT STDMETHODCALLTYPE CFW1ColorRGBA::QueryInterface(REFIID riid, void **ppvObject) { + if(ppvObject == NULL) + return E_INVALIDARG; + + if(IsEqualIID(riid, __uuidof(IFW1ColorRGBA))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + + return CFW1Object::QueryInterface(riid, ppvObject); +} + + +// Set the color +void STDMETHODCALLTYPE CFW1ColorRGBA::SetColor(UINT32 Color) { + m_color32 = Color; +} + + +// Set the color +void STDMETHODCALLTYPE CFW1ColorRGBA::SetColor(FLOAT Red, FLOAT Green, FLOAT Blue, FLOAT Alpha) { + UINT32 color32; + BYTE *colorBytes = reinterpret_cast(&color32); + colorBytes[0] = static_cast(Red * 255.0f + 0.5f); + colorBytes[1] = static_cast(Green * 255.0f + 0.5f); + colorBytes[2] = static_cast(Blue * 255.0f + 0.5f); + colorBytes[3] = static_cast(Alpha * 255.0f + 0.5f); + + m_color32 = color32; +} + + +// Set the color +void STDMETHODCALLTYPE CFW1ColorRGBA::SetColor(const FLOAT *pColor) { + SetColor(pColor[0], pColor[1], pColor[2], pColor[3]); +} + + +// Set the color +void STDMETHODCALLTYPE CFW1ColorRGBA::SetColor(const BYTE *pColor) { + UINT32 color32; + BYTE *colorBytes = reinterpret_cast(&color32); + for(int i=0; i < 4; ++i) + colorBytes[i] = pColor[i]; + + m_color32 = color32; +} + + +// Get the color +UINT32 STDMETHODCALLTYPE CFW1ColorRGBA::GetColor32() { + return m_color32; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1DWriteRenderTarget.cpp b/no_renderer/FW1FontWrapper/CFW1DWriteRenderTarget.cpp new file mode 100644 index 0000000..6476261 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1DWriteRenderTarget.cpp @@ -0,0 +1,208 @@ +// CFW1DWriteRenderTarget.cpp + +#include "FW1Precompiled.h" + +#include "CFW1DWriteRenderTarget.h" + +#define SAFE_RELEASE(pObject) { if(pObject) { (pObject)->Release(); (pObject) = NULL; } } + + +namespace FW1FontWrapper { + + +// Construct +CFW1DWriteRenderTarget::CFW1DWriteRenderTarget() : + m_pRenderTarget(NULL), + m_hDC(NULL), + m_hBlackBrush(NULL), + m_bmWidthBytes(0), + m_bmBytesPixel(0), + m_renderTargetWidth(0), + m_renderTargetHeight(0) +{ +} + + +// Destruct +CFW1DWriteRenderTarget::~CFW1DWriteRenderTarget() { + if(m_hBlackBrush != NULL) + DeleteObject(m_hBlackBrush); + + SAFE_RELEASE(m_pRenderTarget); + + for(RenderingParamsMap::iterator it = m_renderingParams.begin(); it != m_renderingParams.end(); ++it) + it->second->Release(); +} + + +// Init +HRESULT CFW1DWriteRenderTarget::initRenderTarget( + IFW1Factory *pFW1Factory, + IDWriteFactory *pDWriteFactory, + UINT renderTargetWidth, + UINT renderTargetHeight +) { + HRESULT hResult = initBaseObject(pFW1Factory); + if(FAILED(hResult)) + return hResult; + + if(pDWriteFactory == NULL) + return E_INVALIDARG; + + m_renderTargetWidth = 384; + if(renderTargetWidth > 0) + m_renderTargetWidth = renderTargetWidth; + + m_renderTargetHeight = 384; + if(renderTargetHeight > 0) + m_renderTargetHeight = renderTargetHeight; + + // Create render target + hResult = createRenderTarget(pDWriteFactory); + + if(SUCCEEDED(hResult)) + hResult = S_OK; + + return hResult; +} + + +// Create render target +HRESULT CFW1DWriteRenderTarget::createRenderTarget(IDWriteFactory *pDWriteFactory) { + IDWriteGdiInterop *pGDIInterop; + HRESULT hResult = pDWriteFactory->GetGdiInterop(&pGDIInterop); + if(FAILED(hResult)) { + m_lastError = L"Failed to get GDI interop"; + } + else { + IDWriteBitmapRenderTarget *pRenderTarget; + hResult = pGDIInterop->CreateBitmapRenderTarget( + NULL, + m_renderTargetWidth, + m_renderTargetHeight, + &pRenderTarget + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to create bitmap render target"; + } + else { + hResult = pRenderTarget->SetPixelsPerDip(1.0f); + hResult = S_OK; + + HDC hDC = pRenderTarget->GetMemoryDC(); + if(hDC == NULL) { + m_lastError = L"Failed to get render target DC"; + hResult = E_FAIL; + } + else { + HBRUSH hBrush = CreateSolidBrush(RGB(0, 0, 0)); + if(hBrush == NULL) { + m_lastError = L"Failed to create brush"; + hResult = E_FAIL; + } + else { + HBITMAP hBitmap = static_cast(GetCurrentObject(hDC, OBJ_BITMAP)); + if(hBitmap == NULL) { + m_lastError = L"GetCurrentObject failed"; + hResult = E_FAIL; + } + else { + DIBSECTION dib; + int iResult = GetObject(hBitmap, sizeof(dib), &dib); + if(iResult < sizeof(dib)) { + m_lastError = L"GetObject failed"; + hResult = E_FAIL; + } + else { + // Store render target resources and info + m_pRenderTarget = pRenderTarget; + + m_hDC = hDC; + m_hBlackBrush = hBrush; + + m_bmBits = dib.dsBm.bmBits; + m_bmWidthBytes = static_cast(dib.dsBm.bmWidthBytes); + m_bmBytesPixel = static_cast(dib.dsBm.bmBitsPixel) / 8; + + hResult = S_OK; + } + } + + if(FAILED(hResult)) + DeleteObject(hBrush); + } + } + + if(FAILED(hResult)) + pRenderTarget->Release(); + } + + pGDIInterop->Release(); + } + + // Create rendering params for all accepted rendering modes + if(SUCCEEDED(hResult)) { + const UINT renderingModeCount = 2; + DWRITE_RENDERING_MODE renderingModes[renderingModeCount] = { + DWRITE_RENDERING_MODE_DEFAULT, + DWRITE_RENDERING_MODE_ALIASED + }; + + for(UINT i=0; i < renderingModeCount; ++i) { + DWRITE_RENDERING_MODE renderingMode = renderingModes[i]; + IDWriteRenderingParams *pRenderingParams; + + hResult = pDWriteFactory->CreateCustomRenderingParams( + 1.0f, + 0.0f, + 0.0f, + DWRITE_PIXEL_GEOMETRY_FLAT, + renderingMode, + &pRenderingParams + ); + if(SUCCEEDED(hResult)) + m_renderingParams.insert(std::make_pair(renderingMode, pRenderingParams)); + } + + if(m_renderingParams.empty()) { + m_lastError = L"Failed to create rendering params"; + hResult = E_FAIL; + } + else + hResult = S_OK; + } + + return hResult; +} + + +// Init glyph data +void CFW1DWriteRenderTarget::initGlyphData( + const DWRITE_FONT_METRICS *fontMetrics, + const DWRITE_GLYPH_METRICS *glyphMetrics, + FLOAT fontSize, + DWGlyphData *outGlyphData +) { + // Calculate pixel-space coordinates + FLOAT fscale = fontSize / static_cast(fontMetrics->designUnitsPerEm); + + FLOAT l = static_cast(glyphMetrics->leftSideBearing) * fscale; + FLOAT t = static_cast(glyphMetrics->topSideBearing) * fscale; + + FLOAT r = static_cast(glyphMetrics->rightSideBearing) * fscale; + FLOAT b = static_cast(glyphMetrics->bottomSideBearing) * fscale; + + FLOAT v = static_cast(glyphMetrics->verticalOriginY) * fscale; + + FLOAT aw = static_cast(glyphMetrics->advanceWidth) * fscale; + FLOAT ah = static_cast(glyphMetrics->advanceHeight) * fscale; + + // Set up glyph data + outGlyphData->offsetX = floor(l); + outGlyphData->offsetY = floor(t) - floor(v); + outGlyphData->maxWidth = static_cast(aw - r - l + 2.0f); + outGlyphData->maxHeight = static_cast(ah - b - t + 2.0f); +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1DWriteRenderTarget.h b/no_renderer/FW1FontWrapper/CFW1DWriteRenderTarget.h new file mode 100644 index 0000000..540fecb --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1DWriteRenderTarget.h @@ -0,0 +1,82 @@ +// CFW1DWriteRenderTarget.h + +#ifndef IncludeGuard__FW1_CFW1DWriteRenderTarget +#define IncludeGuard__FW1_CFW1DWriteRenderTarget + +#include "CFW1Object.h" + + +namespace FW1FontWrapper { + + +// Render target that provides pixels of one glyph-image at a time +class CFW1DWriteRenderTarget : public CFW1Object { + public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + // IFW1DWriteRenderTarget + virtual HRESULT STDMETHODCALLTYPE DrawGlyphTemp( + IDWriteFontFace *pFontFace, + UINT16 GlyphIndex, + FLOAT FontSize, + DWRITE_RENDERING_MODE RenderingMode, + DWRITE_MEASURING_MODE MeasuringMode, + FW1_GLYPHIMAGEDATA *pOutData + ); + + // Public functions + public: + CFW1DWriteRenderTarget(); + + HRESULT initRenderTarget( + IFW1Factory *pFW1Factory, + IDWriteFactory *pDWriteFactory, + UINT renderTargetWidth, + UINT renderTargetHeight + ); + + // Internal types + private: + struct DWGlyphData { + FLOAT offsetX; + FLOAT offsetY; + LONG maxWidth; + LONG maxHeight; + }; + + typedef std::map RenderingParamsMap; + + // Internal functions + private: + virtual ~CFW1DWriteRenderTarget(); + + HRESULT createRenderTarget(IDWriteFactory *pDWriteFactory); + + void initGlyphData( + const DWRITE_FONT_METRICS *fontMetrics, + const DWRITE_GLYPH_METRICS *glyphMetrics, + FLOAT fontSize, + DWGlyphData *outGlyphData + ); + + // Internal data + private: + std::wstring m_lastError; + + IDWriteBitmapRenderTarget *m_pRenderTarget; + HDC m_hDC; + HBRUSH m_hBlackBrush; + LPVOID m_bmBits; + UINT m_bmWidthBytes; + UINT m_bmBytesPixel; + UINT m_renderTargetWidth; + UINT m_renderTargetHeight; + RenderingParamsMap m_renderingParams; +}; + + +}// namespace FW1FontWrapper + + +#endif// IncludeGuard__FW1_CFW1DWriteRenderTarget diff --git a/no_renderer/FW1FontWrapper/CFW1DWriteRenderTargetInterface.cpp b/no_renderer/FW1FontWrapper/CFW1DWriteRenderTargetInterface.cpp new file mode 100644 index 0000000..623c6aa --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1DWriteRenderTargetInterface.cpp @@ -0,0 +1,113 @@ +// CFW1DWriteRenderTargetInterface.cpp + +#include "FW1Precompiled.h" + +#include "CFW1DWriteRenderTarget.h" + + +namespace FW1FontWrapper { + + +// Query interface +HRESULT STDMETHODCALLTYPE CFW1DWriteRenderTarget::QueryInterface(REFIID riid, void **ppvObject) { + if(ppvObject == NULL) + return E_INVALIDARG; + + if(IsEqualIID(riid, __uuidof(IFW1DWriteRenderTarget))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + + return CFW1Object::QueryInterface(riid, ppvObject); +} + + +// Draw glyph to temporary storage +HRESULT STDMETHODCALLTYPE CFW1DWriteRenderTarget::DrawGlyphTemp( + IDWriteFontFace *pFontFace, + UINT16 GlyphIndex, + FLOAT FontSize, + DWRITE_RENDERING_MODE RenderingMode, + DWRITE_MEASURING_MODE MeasuringMode, + FW1_GLYPHIMAGEDATA *pOutData +) { + // Font metrics + DWRITE_FONT_METRICS fontMetrics; + pFontFace->GetMetrics(&fontMetrics); + + // Glyph metrics + DWRITE_GLYPH_METRICS glyphMetrics; + HRESULT hResult = pFontFace->GetDesignGlyphMetrics(&GlyphIndex, 1, &glyphMetrics, FALSE); + if(FAILED(hResult)) + return hResult; + + // Calculate pixel measurements + DWGlyphData dwGlyphData; + initGlyphData(&fontMetrics, &glyphMetrics, FontSize, &dwGlyphData); + + // Set up drawing + FLOAT glyphAdvance = 0.0f; + DWRITE_GLYPH_OFFSET glyphOffset = {0.0f, 0.0f}; + + DWRITE_GLYPH_RUN glyphRun; + ZeroMemory(&glyphRun, sizeof(glyphRun)); + glyphRun.fontFace = pFontFace; + glyphRun.fontEmSize = FontSize; + glyphRun.glyphCount = 1; + glyphRun.glyphIndices = &GlyphIndex; + glyphRun.glyphAdvances = &glyphAdvance; + glyphRun.glyphOffsets = &glyphOffset; + + // Clear background + RECT rect; + SetRect(&rect, 0, 0, 2+dwGlyphData.maxWidth+5, 2+dwGlyphData.maxHeight+5); + int iRet = FillRect(m_hDC, &rect, m_hBlackBrush); + if(iRet == 0) { + } + + // Rendering mode + IDWriteRenderingParams *pRenderingParams; + + RenderingParamsMap::iterator it = m_renderingParams.find(RenderingMode); + if(it != m_renderingParams.end()) + pRenderingParams = it->second; + else + pRenderingParams = m_renderingParams.begin()->second; + + // Draw + hResult = m_pRenderTarget->DrawGlyphRun( + 2.0f - dwGlyphData.offsetX, + 2.0f - dwGlyphData.offsetY, + MeasuringMode, + &glyphRun, + pRenderingParams, + RGB(255, 255, 255), + &rect + ); + if(FAILED(hResult)) + return hResult; + + // Clip to valid render target to avoid buffer overruns in case the glyph was too large + rect.left = std::max(rect.left, 0L); + rect.top = std::max(rect.top, 0L); + rect.right = std::min(static_cast(m_renderTargetWidth), rect.right); + rect.bottom = std::min(static_cast(m_renderTargetHeight), rect.bottom); + + // Return glyph data + pOutData->Metrics.OffsetX = dwGlyphData.offsetX + static_cast(rect.left) - 2.0f; + pOutData->Metrics.OffsetY = dwGlyphData.offsetY + static_cast(rect.top) - 2.0f; + pOutData->Metrics.Width = static_cast(rect.right - rect.left); + pOutData->Metrics.Height = static_cast(rect.bottom - rect.top); + pOutData->pGlyphPixels = + static_cast(m_bmBits) + + rect.top * m_bmWidthBytes + + rect.left * m_bmBytesPixel; + pOutData->RowPitch = m_bmWidthBytes; + pOutData->PixelStride = m_bmBytesPixel; + + return S_OK; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1Factory.cpp b/no_renderer/FW1FontWrapper/CFW1Factory.cpp new file mode 100644 index 0000000..541fec1 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1Factory.cpp @@ -0,0 +1,88 @@ +// CFW1Factory.cpp + +#include "FW1Precompiled.h" + +#include "CFW1Factory.h" + + +namespace FW1FontWrapper { + + +// Construct +CFW1Factory::CFW1Factory() : + m_cRefCount(1) +{ + InitializeCriticalSection(&m_errorStringCriticalSection); +} + + +// Destruct +CFW1Factory::~CFW1Factory() { + DeleteCriticalSection(&m_errorStringCriticalSection); +} + + +// Init +HRESULT CFW1Factory::initFactory() { + return S_OK; +} + + +// Create a DWrite factory +HRESULT CFW1Factory::createDWriteFactory(IDWriteFactory **ppDWriteFactory) { + HRESULT hResult = E_FAIL; + + typedef HRESULT (WINAPI * PFN_DWRITECREATEFACTORY)(__in DWRITE_FACTORY_TYPE factoryType, __in REFIID iid, __out IUnknown **factory); + PFN_DWRITECREATEFACTORY pfnDWriteCreateFactory = NULL; + +#ifdef FW1_DELAYLOAD_DWRITE_DLL + HMODULE hDWriteLib = LoadLibrary(TEXT("DWrite.dll")); + if(hDWriteLib == NULL) { + DWORD dwErr = GetLastError(); + dwErr; + setErrorString(L"Failed to load DWrite.dll"); + } + else { + pfnDWriteCreateFactory = + reinterpret_cast(GetProcAddress(hDWriteLib, "DWriteCreateFactory")); + if(pfnDWriteCreateFactory == NULL) { + DWORD dwErr = GetLastError(); + dwErr; + setErrorString(L"Failed to load DWriteCreateFactory"); + } + } +#else + pfnDWriteCreateFactory = DWriteCreateFactory; +#endif + + if(pfnDWriteCreateFactory != NULL) { + IDWriteFactory *pDWriteFactory; + + hResult = pfnDWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast(&pDWriteFactory) + ); + if(FAILED(hResult)) { + setErrorString(L"DWriteCreateFactory failed"); + } + else { + *ppDWriteFactory = pDWriteFactory; + + hResult = S_OK; + } + } + + return hResult; +} + + +// Set error string +void CFW1Factory::setErrorString(const wchar_t *str) { + EnterCriticalSection(&m_errorStringCriticalSection); + m_lastError = str; + LeaveCriticalSection(&m_errorStringCriticalSection); +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1Factory.h b/no_renderer/FW1FontWrapper/CFW1Factory.h new file mode 100644 index 0000000..2afae3b --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1Factory.h @@ -0,0 +1,128 @@ +// CFW1Factory.h + +#ifndef IncludeGuard__FW1_CFW1Factory +#define IncludeGuard__FW1_CFW1Factory + + +namespace FW1FontWrapper { + + +// Factory that creates FW1 objects +class CFW1Factory : public IFW1Factory { + public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + virtual ULONG STDMETHODCALLTYPE AddRef(); + virtual ULONG STDMETHODCALLTYPE Release(); + + // IFW1Factory + virtual HRESULT STDMETHODCALLTYPE CreateFontWrapper( + ID3D11Device *pDevice, + LPCWSTR pszFontFamily, + IFW1FontWrapper **ppFontWrapper + ); + virtual HRESULT STDMETHODCALLTYPE CreateFontWrapper( + ID3D11Device *pDevice, + IDWriteFactory *pDWriteFactory, + const FW1_FONTWRAPPERCREATEPARAMS *pCreateParams, + IFW1FontWrapper **ppFontWrapper + ); + virtual HRESULT STDMETHODCALLTYPE CreateFontWrapper( + ID3D11Device *pDevice, + IFW1GlyphAtlas *pGlyphAtlas, + IFW1GlyphProvider *pGlyphProvider, + IFW1GlyphVertexDrawer *pGlyphVertexDrawer, + IFW1GlyphRenderStates *pGlyphRenderStates, + IDWriteFactory *pDWriteFactory, + const FW1_DWRITEFONTPARAMS *pDefaultFontParams, + IFW1FontWrapper **ppFontWrapper + ); + virtual HRESULT STDMETHODCALLTYPE CreateGlyphVertexDrawer( + ID3D11Device *pDevice, + UINT VertexBufferSize, + IFW1GlyphVertexDrawer **ppGlyphVertexDrawer + ); + virtual HRESULT STDMETHODCALLTYPE CreateGlyphRenderStates( + ID3D11Device *pDevice, + BOOL DisableGeometryShader, + BOOL AnisotropicFiltering, + IFW1GlyphRenderStates **ppGlyphRenderStates + ); + virtual HRESULT STDMETHODCALLTYPE CreateTextRenderer( + IFW1GlyphProvider *pGlyphProvider, + IFW1TextRenderer **ppTextRenderer + ); + virtual HRESULT STDMETHODCALLTYPE CreateTextGeometry( + IFW1TextGeometry **ppTextGeometry + ); + virtual HRESULT STDMETHODCALLTYPE CreateGlyphProvider( + IFW1GlyphAtlas *pGlyphAtlas, + IDWriteFactory *pDWriteFactory, + IDWriteFontCollection *pFontCollection, + UINT MaxGlyphWidth, + UINT MaxGlyphHeight, + IFW1GlyphProvider **ppGlyphProvider + ); + virtual HRESULT STDMETHODCALLTYPE CreateDWriteRenderTarget( + IDWriteFactory *pDWriteFactory, + UINT RenderTargetWidth, + UINT RenderTargetHeight, + IFW1DWriteRenderTarget **ppRenderTarget + ); + virtual HRESULT STDMETHODCALLTYPE CreateGlyphAtlas( + ID3D11Device *pDevice, + UINT GlyphSheetWidth, + UINT GlyphSheetHeight, + BOOL HardwareCoordBuffer, + BOOL AllowOversizedGlyph, + UINT MaxGlyphCountPerSheet, + UINT MipLevels, + UINT MaxGlyphSheetCount, + IFW1GlyphAtlas **ppGlyphAtlas + ); + virtual HRESULT STDMETHODCALLTYPE CreateGlyphSheet( + ID3D11Device *pDevice, + UINT GlyphSheetWidth, + UINT GlyphSheetHeight, + BOOL HardwareCoordBuffer, + BOOL AllowOversizedGlyph, + UINT MaxGlyphCount, + UINT MipLevels, + IFW1GlyphSheet **ppGlyphSheet + ); + virtual HRESULT STDMETHODCALLTYPE CreateColor( + UINT32 Color, + IFW1ColorRGBA **ppColor + ); + + // Public functions + public: + CFW1Factory(); + + HRESULT initFactory(); + + // Internal functions + private: + virtual ~CFW1Factory(); + + HRESULT createDWriteFactory(IDWriteFactory **ppDWriteFactory); + + void setErrorString(const wchar_t *str); + + // Internal data + private: + ULONG m_cRefCount; + + std::wstring m_lastError; + CRITICAL_SECTION m_errorStringCriticalSection; + + private: + CFW1Factory(const CFW1Factory&); + CFW1Factory& operator=(const CFW1Factory&); +}; + + +}// namespace FW1FontWrapper + + +#endif// IncludeGuard__FW1_CFW1Factory diff --git a/no_renderer/FW1FontWrapper/CFW1FactoryInterface.cpp b/no_renderer/FW1FontWrapper/CFW1FactoryInterface.cpp new file mode 100644 index 0000000..90a154b --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1FactoryInterface.cpp @@ -0,0 +1,524 @@ +// CFW1FactoryInterface.cpp + +#include "FW1Precompiled.h" + +#include "CFW1Factory.h" + +#include "CFW1FontWrapper.h" +#include "CFW1GlyphVertexDrawer.h" +#include "CFW1GlyphRenderStates.h" +#include "CFW1TextRenderer.h" +#include "CFW1TextGeometry.h" +#include "CFW1GlyphProvider.h" +#include "CFW1DWriteRenderTarget.h" +#include "CFW1GlyphAtlas.h" +#include "CFW1GlyphSheet.h" +#include "CFW1ColorRGBA.h" + + +namespace FW1FontWrapper { + + +// Query interface +HRESULT STDMETHODCALLTYPE CFW1Factory::QueryInterface(REFIID riid, void **ppvObject) { + if(ppvObject == NULL) + return E_INVALIDARG; + + if(IsEqualIID(riid, __uuidof(IUnknown))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + else if(IsEqualIID(riid, __uuidof(IFW1Factory))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + + *ppvObject = NULL; + return E_NOINTERFACE; +} + + +// Add reference +ULONG STDMETHODCALLTYPE CFW1Factory::AddRef() { + return static_cast(InterlockedIncrement(reinterpret_cast(&m_cRefCount))); +} + + +// Release +ULONG STDMETHODCALLTYPE CFW1Factory::Release() { + ULONG newCount = static_cast(InterlockedDecrement(reinterpret_cast(&m_cRefCount))); + + if(newCount == 0) + delete this; + + return newCount; +} + + +// Create font wrapper with default settings +HRESULT STDMETHODCALLTYPE CFW1Factory::CreateFontWrapper( + ID3D11Device *pDevice, + LPCWSTR pszFontFamily, + IFW1FontWrapper **ppFontWrapper +) { + FW1_FONTWRAPPERCREATEPARAMS createParams; + ZeroMemory(&createParams, sizeof(createParams)); + + createParams.GlyphSheetWidth = 512; + createParams.GlyphSheetHeight = 512; + createParams.MaxGlyphCountPerSheet = 2048; + createParams.SheetMipLevels = 1; + createParams.AnisotropicFiltering = FALSE; + createParams.MaxGlyphWidth = 384; + createParams.MaxGlyphHeight = 384; + createParams.DisableGeometryShader = FALSE; + createParams.VertexBufferSize = 0; + createParams.DefaultFontParams.pszFontFamily = pszFontFamily; + createParams.DefaultFontParams.FontWeight = DWRITE_FONT_WEIGHT_NORMAL; + createParams.DefaultFontParams.FontStyle = DWRITE_FONT_STYLE_NORMAL; + createParams.DefaultFontParams.FontStretch = DWRITE_FONT_STRETCH_NORMAL; + createParams.DefaultFontParams.pszLocale = L""; + + return CreateFontWrapper(pDevice, NULL, &createParams, ppFontWrapper); +} + + +// Create font wrapper +HRESULT STDMETHODCALLTYPE CFW1Factory::CreateFontWrapper( + ID3D11Device *pDevice, + IDWriteFactory *pDWriteFactory, + const FW1_FONTWRAPPERCREATEPARAMS *pCreateParams, + IFW1FontWrapper **ppFontWrapper +) { + if(pCreateParams == NULL || ppFontWrapper == NULL) + return E_INVALIDARG; + + HRESULT hResult; + + // If no DWrite factory is provided, attempt to create one + if(pDWriteFactory == NULL) + hResult = createDWriteFactory(&pDWriteFactory); + else { + pDWriteFactory->AddRef(); + hResult = S_OK; + } + if(FAILED(hResult)) { + } + else { + // Get system font collection + IDWriteFontCollection *pFontCollection; + + hResult = pDWriteFactory->GetSystemFontCollection(&pFontCollection, FALSE); + if(FAILED(hResult)) { + setErrorString(L"GetSystemFontCollection failed"); + } + else { + // Create glyph atlas + IFW1GlyphAtlas *pGlyphAtlas; + + hResult = CreateGlyphAtlas( + pDevice, + pCreateParams->GlyphSheetWidth, + pCreateParams->GlyphSheetHeight, + (pCreateParams->DisableGeometryShader == FALSE) ? TRUE : FALSE, + TRUE, + pCreateParams->MaxGlyphCountPerSheet, + pCreateParams->SheetMipLevels, + 4096, + &pGlyphAtlas + ); + if(FAILED(hResult)) { + } + else { + // Create glyph provider + IFW1GlyphProvider *pGlyphProvider; + + hResult = CreateGlyphProvider( + pGlyphAtlas, + pDWriteFactory, + pFontCollection, + pCreateParams->MaxGlyphWidth, + pCreateParams->MaxGlyphHeight, + &pGlyphProvider + ); + if(FAILED(hResult)) { + } + else { + // Create glyph vertex drawer + IFW1GlyphVertexDrawer *pGlyphVertexDrawer; + + hResult = CreateGlyphVertexDrawer( + pDevice, + pCreateParams->VertexBufferSize, + &pGlyphVertexDrawer + ); + if(FAILED(hResult)) { + } + else { + // Create glyph render states + IFW1GlyphRenderStates *pGlyphRenderStates; + + hResult = CreateGlyphRenderStates( + pDevice, + pCreateParams->DisableGeometryShader, + pCreateParams->AnisotropicFiltering, + &pGlyphRenderStates + ); + if(FAILED(hResult)) { + } + else { + // Create font wrapper + IFW1FontWrapper *pFontWrapper; + + hResult = CreateFontWrapper( + pDevice, + pGlyphAtlas, + pGlyphProvider, + pGlyphVertexDrawer, + pGlyphRenderStates, + pDWriteFactory, + &pCreateParams->DefaultFontParams, + &pFontWrapper + ); + if(FAILED(hResult)) { + } + else { + // Success + *ppFontWrapper = pFontWrapper; + + hResult = S_OK; + } + + pGlyphRenderStates->Release(); + } + + pGlyphVertexDrawer->Release(); + } + + pGlyphProvider->Release(); + } + + pGlyphAtlas->Release(); + } + + pFontCollection->Release(); + } + + pDWriteFactory->Release(); + } + + return hResult; +} + + +// Create font wrapper +HRESULT STDMETHODCALLTYPE CFW1Factory::CreateFontWrapper( + ID3D11Device *pDevice, + IFW1GlyphAtlas *pGlyphAtlas, + IFW1GlyphProvider *pGlyphProvider, + IFW1GlyphVertexDrawer *pGlyphVertexDrawer, + IFW1GlyphRenderStates *pGlyphRenderStates, + IDWriteFactory *pDWriteFactory, + const FW1_DWRITEFONTPARAMS *pDefaultFontParams, + IFW1FontWrapper **ppFontWrapper +) { + if(ppFontWrapper == NULL) + return E_INVALIDARG; + + CFW1FontWrapper *pFontWrapper = new CFW1FontWrapper; + HRESULT hResult = pFontWrapper->initFontWrapper( + this, + pDevice, + pGlyphAtlas, + pGlyphProvider, + pGlyphVertexDrawer, + pGlyphRenderStates, + pDWriteFactory, + pDefaultFontParams + ); + if(FAILED(hResult)) { + pFontWrapper->Release(); + setErrorString(L"initFontWrapper failed"); + } + else { + *ppFontWrapper = pFontWrapper; + + hResult = S_OK; + } + + return hResult; +} + + +// Create glyph vertex drawer +HRESULT STDMETHODCALLTYPE CFW1Factory::CreateGlyphVertexDrawer( + ID3D11Device *pDevice, + UINT VertexBufferSize, + IFW1GlyphVertexDrawer **ppGlyphVertexDrawer +) { + if(ppGlyphVertexDrawer == NULL) + return E_INVALIDARG; + + CFW1GlyphVertexDrawer *pGlyphVertexDrawer = new CFW1GlyphVertexDrawer; + HRESULT hResult = pGlyphVertexDrawer->initVertexDrawer( + this, + pDevice, + VertexBufferSize + ); + if(FAILED(hResult)) { + pGlyphVertexDrawer->Release(); + setErrorString(L"initVertexDrawer failed"); + } + else { + *ppGlyphVertexDrawer = pGlyphVertexDrawer; + + hResult = S_OK; + } + + return hResult; +} + + +// Create glyph render states +HRESULT STDMETHODCALLTYPE CFW1Factory::CreateGlyphRenderStates( + ID3D11Device *pDevice, + BOOL DisableGeometryShader, + BOOL AnisotropicFiltering, + IFW1GlyphRenderStates **ppGlyphRenderStates +) { + if(ppGlyphRenderStates == NULL) + return E_INVALIDARG; + + CFW1GlyphRenderStates *pGlyphRenderStates = new CFW1GlyphRenderStates; + HRESULT hResult = pGlyphRenderStates->initRenderResources( + this, + pDevice, + (DisableGeometryShader == FALSE), + (AnisotropicFiltering != FALSE) + ); + if(FAILED(hResult)) { + pGlyphRenderStates->Release(); + setErrorString(L"initRenderResources failed"); + } + else { + *ppGlyphRenderStates = pGlyphRenderStates; + + hResult = S_OK; + } + + return hResult; +} + + +// Create DWrite text renderer +HRESULT STDMETHODCALLTYPE CFW1Factory::CreateTextRenderer( + IFW1GlyphProvider *pGlyphProvider, + IFW1TextRenderer **ppTextRenderer +) { + if(ppTextRenderer == NULL) + return E_INVALIDARG; + + CFW1TextRenderer *pTextRenderer = new CFW1TextRenderer; + HRESULT hResult = pTextRenderer->initTextRenderer(this, pGlyphProvider); + if(FAILED(hResult)) { + pTextRenderer->Release(); + setErrorString(L"initTextRenderer failed"); + } + else { + *ppTextRenderer = pTextRenderer; + + hResult = S_OK; + } + + return hResult; +} + + +// Create text geometry +HRESULT STDMETHODCALLTYPE CFW1Factory::CreateTextGeometry( + IFW1TextGeometry **ppTextGeometry +) { + if(ppTextGeometry == NULL) + return E_INVALIDARG; + + CFW1TextGeometry *pTextGeometry = new CFW1TextGeometry; + HRESULT hResult = pTextGeometry->initTextGeometry(this); + if(FAILED(hResult)) { + pTextGeometry->Release(); + setErrorString(L"initTextGeometry failed"); + } + else { + *ppTextGeometry = pTextGeometry; + + hResult = S_OK; + } + + return hResult; +} + + +// Create glyph provider +HRESULT STDMETHODCALLTYPE CFW1Factory::CreateGlyphProvider( + IFW1GlyphAtlas *pGlyphAtlas, + IDWriteFactory *pDWriteFactory, + IDWriteFontCollection *pFontCollection, + UINT MaxGlyphWidth, + UINT MaxGlyphHeight, + IFW1GlyphProvider **ppGlyphProvider +) { + if(ppGlyphProvider == NULL) + return E_INVALIDARG; + + CFW1GlyphProvider *pGlyphProvider = new CFW1GlyphProvider; + HRESULT hResult = pGlyphProvider->initGlyphProvider( + this, + pGlyphAtlas, + pDWriteFactory, + pFontCollection, + MaxGlyphWidth, + MaxGlyphHeight + ); + if(FAILED(hResult)) { + pGlyphProvider->Release(); + setErrorString(L"initGlyphProvider failed"); + } + else { + *ppGlyphProvider = pGlyphProvider; + + hResult = S_OK; + } + + return hResult; +} + + +// Create DWrite render target +HRESULT STDMETHODCALLTYPE CFW1Factory::CreateDWriteRenderTarget( + IDWriteFactory *pDWriteFactory, + UINT RenderTargetWidth, + UINT RenderTargetHeight, + IFW1DWriteRenderTarget **ppRenderTarget +) { + if(ppRenderTarget == NULL) + return E_INVALIDARG; + + CFW1DWriteRenderTarget *pRenderTarget = new CFW1DWriteRenderTarget; + HRESULT hResult = pRenderTarget->initRenderTarget(this, pDWriteFactory, RenderTargetWidth, RenderTargetHeight); + if(FAILED(hResult)) { + pRenderTarget->Release(); + setErrorString(L"initRenderTarget failed"); + } + else { + *ppRenderTarget = pRenderTarget; + + hResult = S_OK; + } + + return hResult; +} + + +// Create glyph atlas +HRESULT STDMETHODCALLTYPE CFW1Factory::CreateGlyphAtlas( + ID3D11Device *pDevice, + UINT GlyphSheetWidth, + UINT GlyphSheetHeight, + BOOL HardwareCoordBuffer, + BOOL AllowOversizedGlyph, + UINT MaxGlyphCountPerSheet, + UINT MipLevels, + UINT MaxGlyphSheetCount, + IFW1GlyphAtlas **ppGlyphAtlas +) { + if(ppGlyphAtlas == NULL) + return E_INVALIDARG; + + CFW1GlyphAtlas *pGlyphAtlas = new CFW1GlyphAtlas; + HRESULT hResult = pGlyphAtlas->initGlyphAtlas( + this, + pDevice, + GlyphSheetWidth, + GlyphSheetHeight, + (HardwareCoordBuffer != FALSE), + (AllowOversizedGlyph != FALSE), + MaxGlyphCountPerSheet, + MipLevels, + MaxGlyphSheetCount + ); + if(FAILED(hResult)) { + pGlyphAtlas->Release(); + setErrorString(L"initGlyphAtlas failed"); + } + else { + *ppGlyphAtlas = pGlyphAtlas; + + hResult = S_OK; + } + + return hResult; +} + + +// Create glyph sheet +HRESULT STDMETHODCALLTYPE CFW1Factory::CreateGlyphSheet( + ID3D11Device *pDevice, + UINT GlyphSheetWidth, + UINT GlyphSheetHeight, + BOOL HardwareCoordBuffer, + BOOL AllowOversizedGlyph, + UINT MaxGlyphCount, + UINT MipLevels, + IFW1GlyphSheet **ppGlyphSheet +) { + if(ppGlyphSheet == NULL) + return E_INVALIDARG; + + CFW1GlyphSheet *pGlyphSheet = new CFW1GlyphSheet; + HRESULT hResult = pGlyphSheet->initGlyphSheet( + this, + pDevice, + GlyphSheetWidth, + GlyphSheetHeight, + (HardwareCoordBuffer != FALSE), + (AllowOversizedGlyph != FALSE), + MaxGlyphCount, + MipLevels + ); + if(FAILED(hResult)) { + pGlyphSheet->Release(); + setErrorString(L"initGlyphSheet failed"); + } + else { + *ppGlyphSheet = pGlyphSheet; + + hResult = S_OK; + } + + return hResult; +} + + +// Create color +HRESULT STDMETHODCALLTYPE CFW1Factory::CreateColor(UINT32 Color, IFW1ColorRGBA **ppColor) { + if(ppColor == NULL) + return E_INVALIDARG; + + CFW1ColorRGBA *pColor = new CFW1ColorRGBA; + HRESULT hResult = pColor->initColor(this, Color); + if(FAILED(hResult)) { + pColor->Release(); + setErrorString(L"initColor failed"); + } + else { + *ppColor = pColor; + + hResult = S_OK; + } + + return hResult; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1FontWrapper.cpp b/no_renderer/FW1FontWrapper/CFW1FontWrapper.cpp new file mode 100644 index 0000000..248baf8 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1FontWrapper.cpp @@ -0,0 +1,184 @@ +// CFW1FontWrapper.cpp + +#include "FW1Precompiled.h" + +#include "CFW1FontWrapper.h" + +#define SAFE_RELEASE(pObject) { if(pObject) { (pObject)->Release(); (pObject) = NULL; } } + + +namespace FW1FontWrapper { + + +// Construct +CFW1FontWrapper::CFW1FontWrapper() : + m_pDevice(NULL), + m_featureLevel(D3D_FEATURE_LEVEL_9_1), + m_pDWriteFactory(NULL), + + m_pGlyphAtlas(NULL), + m_pGlyphProvider(NULL), + + m_pGlyphRenderStates(NULL), + m_pGlyphVertexDrawer(NULL), + + m_defaultTextInited(false), + m_pDefaultTextFormat(NULL) +{ + InitializeCriticalSection(&m_textRenderersCriticalSection); + InitializeCriticalSection(&m_textGeometriesCriticalSection); +} + + +// Destruct +CFW1FontWrapper::~CFW1FontWrapper() { + SAFE_RELEASE(m_pFW1Factory); + + SAFE_RELEASE(m_pDevice); + SAFE_RELEASE(m_pDWriteFactory); + + SAFE_RELEASE(m_pGlyphAtlas); + SAFE_RELEASE(m_pGlyphProvider); + + SAFE_RELEASE(m_pGlyphRenderStates); + SAFE_RELEASE(m_pGlyphVertexDrawer); + + while(!m_textRenderers.empty()) { + m_textRenderers.top()->Release(); + m_textRenderers.pop(); + } + + while(!m_textGeometries.empty()) { + m_textGeometries.top()->Release(); + m_textGeometries.pop(); + } + + SAFE_RELEASE(m_pDefaultTextFormat); + + DeleteCriticalSection(&m_textRenderersCriticalSection); + DeleteCriticalSection(&m_textGeometriesCriticalSection); +} + + +// Init +HRESULT CFW1FontWrapper::initFontWrapper( + IFW1Factory *pFW1Factory, + ID3D11Device *pDevice, + IFW1GlyphAtlas *pGlyphAtlas, + IFW1GlyphProvider *pGlyphProvider, + IFW1GlyphVertexDrawer *pGlyphVertexDrawer, + IFW1GlyphRenderStates *pGlyphRenderStates, + IDWriteFactory *pDWriteFactory, + const FW1_DWRITEFONTPARAMS *pDefaultFontParams +) { + HRESULT hResult = initBaseObject(pFW1Factory); + if(FAILED(hResult)) + return hResult; + + if( + pDevice == NULL || + pGlyphAtlas == NULL || + pGlyphProvider == NULL || + pGlyphVertexDrawer == NULL || + pGlyphRenderStates == NULL || + pDWriteFactory == NULL + ) + return E_INVALIDARG; + + pDevice->AddRef(); + m_pDevice = pDevice; + m_featureLevel = m_pDevice->GetFeatureLevel(); + + pDWriteFactory->AddRef(); + m_pDWriteFactory = pDWriteFactory; + + pGlyphAtlas->AddRef(); + m_pGlyphAtlas = pGlyphAtlas; + pGlyphProvider->AddRef(); + m_pGlyphProvider = pGlyphProvider; + + pGlyphRenderStates->AddRef(); + m_pGlyphRenderStates = pGlyphRenderStates; + pGlyphVertexDrawer->AddRef(); + m_pGlyphVertexDrawer = pGlyphVertexDrawer; + + // Create default text format for strings, if provided + if(pDefaultFontParams->pszFontFamily != NULL && pDefaultFontParams->pszFontFamily[0] != 0) { + IDWriteTextFormat *pTextFormat; + hResult = m_pDWriteFactory->CreateTextFormat( + pDefaultFontParams->pszFontFamily, + NULL, + pDefaultFontParams->FontWeight, + pDefaultFontParams->FontStyle, + pDefaultFontParams->FontStretch, + 32.0f, + (pDefaultFontParams->pszLocale != NULL) ? pDefaultFontParams->pszLocale : L"", + &pTextFormat + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to create DWrite text format"; + } + else { + m_pDefaultTextFormat = pTextFormat; + m_defaultTextInited = true; + + hResult = S_OK; + } + } + + return hResult; +} + + +// Create text layout from string +IDWriteTextLayout* CFW1FontWrapper::createTextLayout( + const WCHAR *pszString, + const WCHAR *pszFontFamily, + FLOAT fontSize, + const FW1_RECTF *pLayoutRect, + UINT flags +) { + if(m_defaultTextInited) { + UINT32 stringLength = 0; + while(pszString[stringLength] != 0) + ++stringLength; + + // Create DWrite text layout for the string + IDWriteTextLayout *pTextLayout; + HRESULT hResult = m_pDWriteFactory->CreateTextLayout( + pszString, + stringLength, + m_pDefaultTextFormat, + pLayoutRect->Right - pLayoutRect->Left, + pLayoutRect->Bottom - pLayoutRect->Top, + &pTextLayout + ); + if(SUCCEEDED(hResult)) { + // Layout settings + DWRITE_TEXT_RANGE allText = {0, stringLength}; + pTextLayout->SetFontSize(fontSize, allText); + + if(pszFontFamily != NULL) + pTextLayout->SetFontFamilyName(pszFontFamily, allText); + + if((flags & FW1_NOWORDWRAP) != 0) + pTextLayout->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); + + if(flags & FW1_RIGHT) + pTextLayout->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_TRAILING); + else if(flags & FW1_CENTER) + pTextLayout->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); + if(flags & FW1_BOTTOM) + pTextLayout->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_FAR); + else if(flags & FW1_VCENTER) + pTextLayout->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); + + return pTextLayout; + } + } + + return NULL; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1FontWrapper.h b/no_renderer/FW1FontWrapper/CFW1FontWrapper.h new file mode 100644 index 0000000..370e799 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1FontWrapper.h @@ -0,0 +1,171 @@ +// CFW1FontWrapper.h + +#ifndef IncludeGuard__FW1_CFW1FontWrapper +#define IncludeGuard__FW1_CFW1FontWrapper + +#include "CFW1Object.h" + + +namespace FW1FontWrapper { + + +// Font-wrapper simplifying drawing strings and text-layouts +class CFW1FontWrapper : public CFW1Object { + public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + // IFW1FontWrapper + virtual HRESULT STDMETHODCALLTYPE GetFactory(IFW1Factory **ppFactory); + + virtual HRESULT STDMETHODCALLTYPE GetDevice(ID3D11Device **ppDevice); + virtual HRESULT STDMETHODCALLTYPE GetDWriteFactory(IDWriteFactory **ppDWriteFactory); + virtual HRESULT STDMETHODCALLTYPE GetGlyphAtlas(IFW1GlyphAtlas **ppGlyphAtlas); + virtual HRESULT STDMETHODCALLTYPE GetGlyphProvider(IFW1GlyphProvider **ppGlyphProvider); + virtual HRESULT STDMETHODCALLTYPE GetRenderStates(IFW1GlyphRenderStates **ppRenderStates); + virtual HRESULT STDMETHODCALLTYPE GetVertexDrawer(IFW1GlyphVertexDrawer **ppVertexDrawer); + + virtual void STDMETHODCALLTYPE DrawTextLayout( + ID3D11DeviceContext *pContext, + IDWriteTextLayout *pTextLayout, + FLOAT OriginX, + FLOAT OriginY, + UINT32 Color, + UINT Flags + ); + virtual void STDMETHODCALLTYPE DrawTextLayout( + ID3D11DeviceContext *pContext, + IDWriteTextLayout *pTextLayout, + FLOAT OriginX, + FLOAT OriginY, + UINT32 Color, + const FW1_RECTF *pClipRect, + const FLOAT *pTransformMatrix, + UINT Flags + ); + + virtual void STDMETHODCALLTYPE DrawString( + ID3D11DeviceContext *pContext, + const WCHAR *pszString, + FLOAT FontSize, + FLOAT X, + FLOAT Y, + UINT32 Color, + UINT Flags + ); + virtual void STDMETHODCALLTYPE DrawString( + ID3D11DeviceContext *pContext, + const WCHAR *pszString, + const WCHAR *pszFontFamily, + FLOAT FontSize, + FLOAT X, + FLOAT Y, + UINT32 Color, + UINT Flags + ); + virtual void STDMETHODCALLTYPE DrawString( + ID3D11DeviceContext *pContext, + const WCHAR *pszString, + const WCHAR *pszFontFamily, + FLOAT FontSize, + const FW1_RECTF *pLayoutRect, + UINT32 Color, + const FW1_RECTF *pClipRect, + const FLOAT *pTransformMatrix, + UINT Flags + ); + + virtual FW1_RECTF STDMETHODCALLTYPE MeasureString( + const WCHAR *pszString, + const WCHAR *pszFontFamily, + FLOAT FontSize, + const FW1_RECTF *pLayoutRect, + UINT Flags + ); + + virtual void STDMETHODCALLTYPE AnalyzeString( + ID3D11DeviceContext *pContext, + const WCHAR *pszString, + const WCHAR *pszFontFamily, + FLOAT FontSize, + const FW1_RECTF *pLayoutRect, + UINT32 Color, + UINT Flags, + IFW1TextGeometry *pTextGeometry + ); + + virtual void STDMETHODCALLTYPE AnalyzeTextLayout( + ID3D11DeviceContext *pContext, + IDWriteTextLayout *pTextLayout, + FLOAT OriginX, + FLOAT OriginY, + UINT32 Color, + UINT Flags, + IFW1TextGeometry *pTextGeometry + ); + + virtual void STDMETHODCALLTYPE DrawGeometry( + ID3D11DeviceContext *pContext, + IFW1TextGeometry *pGeometry, + const FW1_RECTF *pClipRect, + const FLOAT *pTransformMatrix, + UINT Flags + ); + + virtual void STDMETHODCALLTYPE Flush(ID3D11DeviceContext *pContext); + + // Public functions + public: + CFW1FontWrapper(); + + HRESULT initFontWrapper( + IFW1Factory *pFW1Factory, + ID3D11Device *pDevice, + IFW1GlyphAtlas *pGlyphAtlas, + IFW1GlyphProvider *pGlyphProvider, + IFW1GlyphVertexDrawer *pGlyphVertexDrawer, + IFW1GlyphRenderStates *pGlyphRenderStates, + IDWriteFactory *pDWriteFactory, + const FW1_DWRITEFONTPARAMS *pDefaultFontParams + ); + + // Internal functions + private: + virtual ~CFW1FontWrapper(); + + IDWriteTextLayout* createTextLayout( + const WCHAR *pszString, + const WCHAR *pszFontFamily, + FLOAT fontSize, + const FW1_RECTF *pLayoutRect, + UINT flags + ); + + // Internal data + private: + std::wstring m_lastError; + + ID3D11Device *m_pDevice; + D3D_FEATURE_LEVEL m_featureLevel; + IDWriteFactory *m_pDWriteFactory; + + IFW1GlyphAtlas *m_pGlyphAtlas; + IFW1GlyphProvider *m_pGlyphProvider; + + IFW1GlyphRenderStates *m_pGlyphRenderStates; + IFW1GlyphVertexDrawer *m_pGlyphVertexDrawer; + + CRITICAL_SECTION m_textRenderersCriticalSection; + std::stack m_textRenderers; + CRITICAL_SECTION m_textGeometriesCriticalSection; + std::stack m_textGeometries; + + bool m_defaultTextInited; + IDWriteTextFormat *m_pDefaultTextFormat; +}; + + +}// namespace FW1FontWrapper + + +#endif// IncludeGuard__FW1_CFW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1FontWrapperInterface.cpp b/no_renderer/FW1FontWrapper/CFW1FontWrapperInterface.cpp new file mode 100644 index 0000000..ac50222 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1FontWrapperInterface.cpp @@ -0,0 +1,398 @@ +// CFW1FontWrapperInterface.cpp + +#include "FW1Precompiled.h" + +#include "CFW1FontWrapper.h" + +#include "CFW1StateSaver.h" + + +namespace FW1FontWrapper { + + +// Query interface +HRESULT STDMETHODCALLTYPE CFW1FontWrapper::QueryInterface(REFIID riid, void **ppvObject) { + if(ppvObject == NULL) + return E_INVALIDARG; + + if(IsEqualIID(riid, __uuidof(IFW1FontWrapper))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + + return CFW1Object::QueryInterface(riid, ppvObject); +} + + +// Get the factory that created this object +HRESULT STDMETHODCALLTYPE CFW1FontWrapper::GetFactory(IFW1Factory **ppFactory) { + if(ppFactory == NULL) + return E_INVALIDARG; + + m_pFW1Factory->AddRef(); + *ppFactory = m_pFW1Factory; + + return S_OK; +} + + +// Get D3D11 device +HRESULT STDMETHODCALLTYPE CFW1FontWrapper::GetDevice(ID3D11Device **ppDevice) { + if(ppDevice == NULL) + return E_INVALIDARG; + + m_pDevice->AddRef(); + *ppDevice = m_pDevice; + + return S_OK; +} + + +// Get DWrite factory +HRESULT STDMETHODCALLTYPE CFW1FontWrapper::GetDWriteFactory(IDWriteFactory **ppDWriteFactory) { + if(ppDWriteFactory == NULL) + return E_INVALIDARG; + + m_pDWriteFactory->AddRef(); + *ppDWriteFactory = m_pDWriteFactory; + + return S_OK; +} + + +// Get glyph atlas +HRESULT STDMETHODCALLTYPE CFW1FontWrapper::GetGlyphAtlas(IFW1GlyphAtlas **ppGlyphAtlas) { + if(ppGlyphAtlas == NULL) + return E_INVALIDARG; + + m_pGlyphAtlas->AddRef(); + *ppGlyphAtlas = m_pGlyphAtlas; + + return S_OK; +} + + +// Get glyph provider +HRESULT STDMETHODCALLTYPE CFW1FontWrapper::GetGlyphProvider(IFW1GlyphProvider **ppGlyphProvider) { + if(ppGlyphProvider == NULL) + return E_INVALIDARG; + + m_pGlyphProvider->AddRef(); + *ppGlyphProvider = m_pGlyphProvider; + + return S_OK; +} + + +// Get render states +HRESULT STDMETHODCALLTYPE CFW1FontWrapper::GetRenderStates(IFW1GlyphRenderStates **ppRenderStates) { + if(ppRenderStates == NULL) + return E_INVALIDARG; + + m_pGlyphRenderStates->AddRef(); + *ppRenderStates = m_pGlyphRenderStates; + + return S_OK; +} + + +// Get vertex drawer +HRESULT STDMETHODCALLTYPE CFW1FontWrapper::GetVertexDrawer(IFW1GlyphVertexDrawer **ppVertexDrawer) { + if(ppVertexDrawer == NULL) + return E_INVALIDARG; + + m_pGlyphVertexDrawer->AddRef(); + *ppVertexDrawer = m_pGlyphVertexDrawer; + + return S_OK; +} + + +// Draw text layout +void STDMETHODCALLTYPE CFW1FontWrapper::DrawTextLayout( + ID3D11DeviceContext *pContext, + IDWriteTextLayout *pTextLayout, + FLOAT OriginX, + FLOAT OriginY, + UINT32 Color, + UINT Flags +) { + DrawTextLayout(pContext, pTextLayout, OriginX, OriginY, Color, NULL, NULL, Flags); +} + + +// Draw text layout +void STDMETHODCALLTYPE CFW1FontWrapper::DrawTextLayout( + ID3D11DeviceContext *pContext, + IDWriteTextLayout *pTextLayout, + FLOAT OriginX, + FLOAT OriginY, + UINT32 Color, + const FW1_RECTF *pClipRect, + const FLOAT *pTransformMatrix, + UINT Flags +) { + IFW1TextGeometry *pTextGeometry = NULL; + + // If needed, get a text geometry to store vertices in + if((Flags & FW1_ANALYZEONLY) == 0 && (Flags & FW1_CACHEONLY) == 0) { + EnterCriticalSection(&m_textGeometriesCriticalSection); + if(!m_textGeometries.empty()) { + pTextGeometry = m_textGeometries.top(); + m_textGeometries.pop(); + } + LeaveCriticalSection(&m_textGeometriesCriticalSection); + + if(pTextGeometry == NULL) { + IFW1TextGeometry *pNewTextGeometry; + HRESULT hResult = m_pFW1Factory->CreateTextGeometry(&pNewTextGeometry); + if(FAILED(hResult)) { + } + else { + pTextGeometry = pNewTextGeometry; + } + } + + if(pTextGeometry != NULL) + pTextGeometry->Clear(); + } + + // Draw + AnalyzeTextLayout(pContext, pTextLayout, OriginX, OriginY, Color, Flags, pTextGeometry); + if((Flags & FW1_ANALYZEONLY) == 0 && (Flags & FW1_CACHEONLY) == 0) { + DrawGeometry(pContext, pTextGeometry, pClipRect, pTransformMatrix, Flags); + } + + if(pTextGeometry != NULL) { + // Keep the text geometry for future use + EnterCriticalSection(&m_textGeometriesCriticalSection); + m_textGeometries.push(pTextGeometry); + LeaveCriticalSection(&m_textGeometriesCriticalSection); + } +} + + +// Draw text +void STDMETHODCALLTYPE CFW1FontWrapper::DrawString( + ID3D11DeviceContext *pContext, + const WCHAR *pszString, + FLOAT FontSize, + FLOAT X, + FLOAT Y, + UINT32 Color, + UINT Flags +) { + FW1_RECTF rect; + + rect.Left = rect.Right = X; + rect.Top = rect.Bottom = Y; + + DrawString(pContext, pszString, NULL, FontSize, &rect, Color, NULL, NULL, Flags | FW1_NOWORDWRAP); + +} + + + + +// Draw text +void STDMETHODCALLTYPE CFW1FontWrapper::DrawString( + ID3D11DeviceContext *pContext, + const WCHAR *pszString, + const WCHAR *pszFontFamily, + FLOAT FontSize, + FLOAT X, + FLOAT Y, + UINT32 Color, + UINT Flags +) { + FW1_RECTF rect; + + rect.Left = rect.Right = X; + rect.Top = rect.Bottom = Y; + + DrawString(pContext, pszString, pszFontFamily, FontSize, &rect, Color, NULL, NULL, Flags | FW1_NOWORDWRAP); +} + + +// Draw text +void STDMETHODCALLTYPE CFW1FontWrapper::DrawString( + ID3D11DeviceContext *pContext, + const WCHAR *pszString, + const WCHAR *pszFontFamily, + FLOAT FontSize, + const FW1_RECTF *pLayoutRect, + UINT32 Color, + const FW1_RECTF *pClipRect, + const FLOAT *pTransformMatrix, + UINT Flags +) { + IDWriteTextLayout *pTextLayout = createTextLayout(pszString, pszFontFamily, FontSize, pLayoutRect, Flags); + if(pTextLayout != NULL) { + // Draw + DrawTextLayout( + pContext, + pTextLayout, + pLayoutRect->Left, + pLayoutRect->Top, + Color, + pClipRect, + pTransformMatrix, + Flags + ); + + pTextLayout->Release(); + } +} + + +// Measure text +FW1_RECTF STDMETHODCALLTYPE CFW1FontWrapper::MeasureString( + const WCHAR *pszString, + const WCHAR *pszFontFamily, + FLOAT FontSize, + const FW1_RECTF *pLayoutRect, + UINT Flags +) { + FW1_RECTF stringRect = {pLayoutRect->Left, pLayoutRect->Top, pLayoutRect->Left, pLayoutRect->Top}; + + IDWriteTextLayout *pTextLayout = createTextLayout(pszString, pszFontFamily, FontSize, pLayoutRect, Flags); + if(pTextLayout != NULL) { + // Get measurements + DWRITE_OVERHANG_METRICS overhangMetrics; + HRESULT hResult = pTextLayout->GetOverhangMetrics(&overhangMetrics); + if(SUCCEEDED(hResult)) { + stringRect.Left = floor(pLayoutRect->Left - overhangMetrics.left); + stringRect.Top = floor(pLayoutRect->Top - overhangMetrics.top); + stringRect.Right = ceil(pLayoutRect->Left + overhangMetrics.right); + stringRect.Bottom = ceil(pLayoutRect->Top + overhangMetrics.bottom); + } + + pTextLayout->Release(); + } + + return stringRect; +} + + +// Create geometry from a string +void STDMETHODCALLTYPE CFW1FontWrapper::AnalyzeString( + ID3D11DeviceContext *pContext, + const WCHAR *pszString, + const WCHAR *pszFontFamily, + FLOAT FontSize, + const FW1_RECTF *pLayoutRect, + UINT32 Color, + UINT Flags, + IFW1TextGeometry *pTextGeometry +) { + IDWriteTextLayout *pTextLayout = createTextLayout(pszString, pszFontFamily, FontSize, pLayoutRect, Flags); + if(pTextLayout != NULL) { + AnalyzeTextLayout( + pContext, + pTextLayout, + pLayoutRect->Left, + pLayoutRect->Top, + Color, + Flags, + pTextGeometry + ); + + pTextLayout->Release(); + } +} + + +// Create geometry from a text layout +void STDMETHODCALLTYPE CFW1FontWrapper::AnalyzeTextLayout( + ID3D11DeviceContext *pContext, + IDWriteTextLayout *pTextLayout, + FLOAT OriginX, + FLOAT OriginY, + UINT32 Color, + UINT Flags, + IFW1TextGeometry *pTextGeometry +) { + // Get a text renderer + IFW1TextRenderer *pTextRenderer = NULL; + + EnterCriticalSection(&m_textRenderersCriticalSection); + if(!m_textRenderers.empty()) { + pTextRenderer = m_textRenderers.top(); + m_textRenderers.pop(); + } + LeaveCriticalSection(&m_textRenderersCriticalSection); + + if(pTextRenderer == NULL) { + IFW1TextRenderer *pNewTextRenderer; + HRESULT hResult = m_pFW1Factory->CreateTextRenderer(m_pGlyphProvider, &pNewTextRenderer); + if(FAILED(hResult)) { + } + else { + pTextRenderer = pNewTextRenderer; + } + } + + // Create geometry + if(pTextRenderer != NULL) { + HRESULT hResult = pTextRenderer->DrawTextLayout(pTextLayout, OriginX, OriginY, Color, Flags, pTextGeometry); + if(FAILED(hResult)) { + } + + // Flush the glyph atlas in case any new glyphs were added + if((Flags & FW1_NOFLUSH) == 0) + m_pGlyphAtlas->Flush(pContext); + + // Keep the text renderer for future use + EnterCriticalSection(&m_textRenderersCriticalSection); + m_textRenderers.push(pTextRenderer); + LeaveCriticalSection(&m_textRenderersCriticalSection); + } +} + + +// Draw vertices +void STDMETHODCALLTYPE CFW1FontWrapper::DrawGeometry( + ID3D11DeviceContext *pContext, + IFW1TextGeometry *pGeometry, + const FW1_RECTF *pClipRect, + const FLOAT *pTransformMatrix, + UINT Flags +) { + FW1_VERTEXDATA vertexData = pGeometry->GetGlyphVerticesTemp(); + if(vertexData.TotalVertexCount > 0 || (Flags & FW1_RESTORESTATE) == 0) { + if(m_featureLevel < D3D_FEATURE_LEVEL_10_0 || m_pGlyphRenderStates->HasGeometryShader() == FALSE) + Flags |= FW1_NOGEOMETRYSHADER; + + // Save state + CFW1StateSaver stateSaver; + bool restoreState = false; + if((Flags & FW1_RESTORESTATE) != 0) { + if(SUCCEEDED(stateSaver.saveCurrentState(pContext))) + restoreState = true; + } + + // Set shaders etc. + if((Flags & FW1_STATEPREPARED) == 0) + m_pGlyphRenderStates->SetStates(pContext, Flags); + if((Flags & FW1_CONSTANTSPREPARED) == 0) + m_pGlyphRenderStates->UpdateShaderConstants(pContext, pClipRect, pTransformMatrix); + + // Draw glyphs + UINT temp = m_pGlyphVertexDrawer->DrawVertices(pContext, m_pGlyphAtlas, &vertexData, Flags, 0xffffffff); + temp; + + // Restore state + if(restoreState) + stateSaver.restoreSavedState(); + } +} + + +// Flush the glyph atlas +void STDMETHODCALLTYPE CFW1FontWrapper::Flush(ID3D11DeviceContext *pContext) { + m_pGlyphAtlas->Flush(pContext); +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphAtlas.cpp b/no_renderer/FW1FontWrapper/CFW1GlyphAtlas.cpp new file mode 100644 index 0000000..6dc3e29 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphAtlas.cpp @@ -0,0 +1,122 @@ +// CFW1GlyphAtlas.cpp + +#include "FW1Precompiled.h" + +#include "CFW1GlyphAtlas.h" + +#define SAFE_RELEASE(pObject) { if(pObject) { (pObject)->Release(); (pObject) = NULL; } } + + +namespace FW1FontWrapper { + + +// Construct +CFW1GlyphAtlas::CFW1GlyphAtlas() : + m_pDevice(NULL), + m_sheetWidth(0), + m_sheetHeight(0), + m_hardwareCoordBuffer(false), + m_allowOversizedGlyph(false), + m_maxGlyphCount(0), + m_mipLevelCount(0), + + m_glyphSheets(0), + m_sheetCount(0), + m_maxSheetCount(0), + m_currentSheetIndex(0), + m_flushedSheetIndex(0) +{ + InitializeCriticalSection(&m_glyphSheetsCriticalSection); +} + + +// Destruct +CFW1GlyphAtlas::~CFW1GlyphAtlas() { + SAFE_RELEASE(m_pDevice); + + for(UINT i=0; i < m_sheetCount; ++i) + m_glyphSheets[i]->Release(); + delete[] m_glyphSheets; + + DeleteCriticalSection(&m_glyphSheetsCriticalSection); +} + + +// Init +HRESULT CFW1GlyphAtlas::initGlyphAtlas( + IFW1Factory *pFW1Factory, + ID3D11Device *pDevice, + UINT sheetWidth, + UINT sheetHeight, + bool coordBuffer, + bool allowOversizedGlyph, + UINT maxGlyphCount, + UINT mipLevelCount, + UINT maxSheetCount +) { + HRESULT hResult = initBaseObject(pFW1Factory); + if(FAILED(hResult)) + return hResult; + + if(pDevice == NULL) + return E_INVALIDARG; + + pDevice->AddRef(); + m_pDevice = pDevice; + + m_sheetWidth = sheetWidth; + m_sheetHeight = sheetHeight; + m_hardwareCoordBuffer = coordBuffer; + m_allowOversizedGlyph = allowOversizedGlyph; + m_mipLevelCount = mipLevelCount; + m_maxGlyphCount = maxGlyphCount; + + m_maxSheetCount = 4096; + if(maxSheetCount > 0 && maxSheetCount < 655536) + m_maxSheetCount = maxSheetCount; + m_glyphSheets = new IFW1GlyphSheet* [m_maxSheetCount]; + + // Default glyph + BYTE glyph0Pixels[256]; + FillMemory(glyph0Pixels, 256, 0xff); + + FW1_GLYPHMETRICS glyph0Metrics; + glyph0Metrics.OffsetX = 0.0f; + glyph0Metrics.OffsetY = 0.0f; + glyph0Metrics.Width = 16; + glyph0Metrics.Height = 16; + + UINT glyph0 = InsertGlyph(&glyph0Metrics, glyph0Pixels, 16, 1); + if(glyph0 == 0xffffffff) + return E_FAIL; + else + return S_OK; +} + + +// Create new glyph sheet +HRESULT CFW1GlyphAtlas::createGlyphSheet(IFW1GlyphSheet **ppGlyphSheet) { + IFW1GlyphSheet *pGlyphSheet; + HRESULT hResult = m_pFW1Factory->CreateGlyphSheet( + m_pDevice, + m_sheetWidth, + m_sheetHeight, + m_hardwareCoordBuffer, + m_allowOversizedGlyph, + m_maxGlyphCount, + m_mipLevelCount, + &pGlyphSheet + ); + if(FAILED(hResult)) { + } + else { + *ppGlyphSheet = pGlyphSheet; + + hResult = S_OK; + } + + return hResult; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphAtlas.h b/no_renderer/FW1FontWrapper/CFW1GlyphAtlas.h new file mode 100644 index 0000000..5e23bd9 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphAtlas.h @@ -0,0 +1,83 @@ +// CFW1GlyphAtlas.h + +#ifndef IncludeGuard__FW1_CFW1GlyphAtlas +#define IncludeGuard__FW1_CFW1GlyphAtlas + +#include "CFW1Object.h" + + +namespace FW1FontWrapper { + + +class CFW1GlyphAtlas : public CFW1Object { + // Interface + public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + // IFW1GlyphAtlas + virtual HRESULT STDMETHODCALLTYPE GetDevice(ID3D11Device **ppDevice); + + virtual UINT STDMETHODCALLTYPE GetTotalGlyphCount(); + virtual UINT STDMETHODCALLTYPE GetSheetCount(); + + virtual HRESULT STDMETHODCALLTYPE GetSheet(UINT SheetIndex, IFW1GlyphSheet **ppGlyphSheet); + + virtual const FW1_GLYPHCOORDS* STDMETHODCALLTYPE GetGlyphCoords(UINT SheetIndex); + virtual HRESULT STDMETHODCALLTYPE BindSheet(ID3D11DeviceContext *pContext, UINT SheetIndex, UINT Flags); + + virtual UINT STDMETHODCALLTYPE InsertGlyph( + const FW1_GLYPHMETRICS *pGlyphMetrics, + const void *pGlyphData, + UINT RowPitch, + UINT PixelStride + ); + virtual UINT STDMETHODCALLTYPE InsertSheet(IFW1GlyphSheet *pGlyphSheet); + virtual void STDMETHODCALLTYPE Flush(ID3D11DeviceContext *pContext); + + // Public functions + public: + CFW1GlyphAtlas(); + + HRESULT initGlyphAtlas( + IFW1Factory *pFW1Factory, + ID3D11Device *pDevice, + UINT sheetWidth, + UINT sheetHeight, + bool coordBuffer, + bool allowOversizedTexture, + UINT maxGlyphCountPerSheet, + UINT mipLevelCount, + UINT maxSheetCount + ); + + // Internal functions + private: + virtual ~CFW1GlyphAtlas(); + + HRESULT createGlyphSheet(IFW1GlyphSheet **ppGlyphSheet); + + // Internal data + private: + ID3D11Device *m_pDevice; + UINT m_sheetWidth; + UINT m_sheetHeight; + bool m_hardwareCoordBuffer; + bool m_allowOversizedGlyph; + UINT m_maxGlyphCount; + UINT m_mipLevelCount; + + IFW1GlyphSheet **m_glyphSheets; + UINT m_sheetCount; + UINT m_maxSheetCount; + UINT m_currentSheetIndex; + UINT m_flushedSheetIndex; + + CRITICAL_SECTION m_glyphSheetsCriticalSection; +}; + + +}// namespace FW1FontWrapper + + +#endif// IncludeGuard__FW1_CFW1GlyphAtlas diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphAtlasInterface.cpp b/no_renderer/FW1FontWrapper/CFW1GlyphAtlasInterface.cpp new file mode 100644 index 0000000..81787d0 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphAtlasInterface.cpp @@ -0,0 +1,197 @@ +// CFW1GlyphAtlasInterface.cpp + +#include "FW1Precompiled.h" + +#include "CFW1GlyphAtlas.h" + + +namespace FW1FontWrapper { + + +// Query interface +HRESULT STDMETHODCALLTYPE CFW1GlyphAtlas::QueryInterface(REFIID riid, void **ppvObject) { + if(ppvObject == NULL) + return E_INVALIDARG; + + if(IsEqualIID(riid, __uuidof(IFW1GlyphAtlas))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + + return CFW1Object::QueryInterface(riid, ppvObject); +} + + +// Get the D3D11 device used by this atlas +HRESULT STDMETHODCALLTYPE CFW1GlyphAtlas::GetDevice(ID3D11Device **ppDevice) { + if(ppDevice == NULL) + return E_INVALIDARG; + + m_pDevice->AddRef(); + *ppDevice = m_pDevice; + + return S_OK; +} + + +// Get total glyph count in atlas +UINT STDMETHODCALLTYPE CFW1GlyphAtlas::GetTotalGlyphCount() { + UINT total = 0; + + for(UINT i=0; i < m_sheetCount; ++i) { + FW1_GLYPHSHEETDESC desc; + m_glyphSheets[i]->GetDesc(&desc); + + total += desc.GlyphCount; + } + + return total; +} + + +// Get sheet count +UINT STDMETHODCALLTYPE CFW1GlyphAtlas::GetSheetCount() { + return m_sheetCount; +} + + +// Get sheet +HRESULT STDMETHODCALLTYPE CFW1GlyphAtlas::GetSheet(UINT SheetIndex, IFW1GlyphSheet **ppGlyphSheet) { + if(ppGlyphSheet == NULL) + return E_INVALIDARG; + + if(SheetIndex < m_sheetCount) { + *ppGlyphSheet = m_glyphSheets[SheetIndex]; + + return S_OK; + } + + *ppGlyphSheet = NULL; + + return E_INVALIDARG; +} + +// Get texture coordinates +const FW1_GLYPHCOORDS* STDMETHODCALLTYPE CFW1GlyphAtlas::GetGlyphCoords(UINT SheetIndex) { + if(SheetIndex < m_sheetCount) + return m_glyphSheets[SheetIndex]->GetGlyphCoords(); + + return 0; +} + + +// Set sheet shader resources +HRESULT STDMETHODCALLTYPE CFW1GlyphAtlas::BindSheet(ID3D11DeviceContext *pContext, UINT SheetIndex, UINT Flags) { + if(SheetIndex < m_sheetCount) + return m_glyphSheets[SheetIndex]->BindSheet(pContext, Flags); + + return E_INVALIDARG; +} + + +// Insert texture into atlas +UINT STDMETHODCALLTYPE CFW1GlyphAtlas::InsertGlyph( + const FW1_GLYPHMETRICS *pGlyphMetrics, + const void *pGlyphData, + UINT RowPitch, + UINT PixelStride +) { + UINT glyphIndex = 0xffffffff; + UINT sheetIndex = 0; + + // Get open sheet range + EnterCriticalSection(&m_glyphSheetsCriticalSection); + UINT start = m_currentSheetIndex; + UINT end = m_sheetCount; + LeaveCriticalSection(&m_glyphSheetsCriticalSection); + + // Attempt to insert glyph + for(UINT i=start; i < end; ++i) { + IFW1GlyphSheet *pGlyphSheet = m_glyphSheets[i]; + + glyphIndex = pGlyphSheet->InsertGlyph(pGlyphMetrics, pGlyphData, RowPitch, PixelStride); + if(glyphIndex != 0xffffffff) { + sheetIndex = i; + break; + } + } + + // Try to create a new glyph sheet on failure + if(glyphIndex == 0xffffffff && m_sheetCount < m_maxSheetCount) { + IFW1GlyphSheet *pGlyphSheet; + if(SUCCEEDED(createGlyphSheet(&pGlyphSheet))) { + glyphIndex = pGlyphSheet->InsertGlyph(pGlyphMetrics, pGlyphData, RowPitch, PixelStride); + + UINT newSheetIndex = InsertSheet(pGlyphSheet); + if(newSheetIndex != 0xffffffff) + sheetIndex = newSheetIndex; + else + glyphIndex = 0xffffffff; + + pGlyphSheet->Release(); + } + } + + if(glyphIndex == 0xffffffff) + return 0xffffffff; + + return (sheetIndex << 16) | glyphIndex; +} + + +// Insert glyph sheets +UINT STDMETHODCALLTYPE CFW1GlyphAtlas::InsertSheet(IFW1GlyphSheet *pGlyphSheet) { + if(pGlyphSheet == NULL) + return 0xffffffff; + + UINT sheetIndex = 0xffffffff; + + EnterCriticalSection(&m_glyphSheetsCriticalSection); + if(m_sheetCount < m_maxSheetCount) { + pGlyphSheet->AddRef(); + + sheetIndex = m_sheetCount; + + m_glyphSheets[sheetIndex] = pGlyphSheet; + + _WriteBarrier(); + MemoryBarrier(); + + ++m_sheetCount; + + // Restrict the number of open sheets + UINT numActiveSheets = 4; + + if(m_sheetCount > m_currentSheetIndex + numActiveSheets) { + m_glyphSheets[m_currentSheetIndex]->CloseSheet(); + + ++m_currentSheetIndex; + } + } + LeaveCriticalSection(&m_glyphSheetsCriticalSection); + + return sheetIndex; +} + + +// Flush all sheets with possible new glyphs +void STDMETHODCALLTYPE CFW1GlyphAtlas::Flush(ID3D11DeviceContext *pContext) { + UINT first = 0; + UINT end = 0; + + EnterCriticalSection(&m_glyphSheetsCriticalSection); + + first = m_flushedSheetIndex; + end = m_sheetCount; + + m_flushedSheetIndex = m_currentSheetIndex; + + LeaveCriticalSection(&m_glyphSheetsCriticalSection); + + for(UINT i=first; i < end; ++i) + m_glyphSheets[i]->Flush(pContext); +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphProvider.cpp b/no_renderer/FW1FontWrapper/CFW1GlyphProvider.cpp new file mode 100644 index 0000000..26b5790 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphProvider.cpp @@ -0,0 +1,315 @@ +// CFW1GlyphProvider.cpp + +#include "FW1Precompiled.h" + +#include "CFW1GlyphProvider.h" + +#define SAFE_RELEASE(pObject) { if(pObject) { (pObject)->Release(); (pObject) = NULL; } } + + +namespace FW1FontWrapper { + + +// Construct +CFW1GlyphProvider::CFW1GlyphProvider() : + m_pGlyphAtlas(NULL), + + m_pDWriteFactory(NULL), + m_maxGlyphWidth(0), + m_maxGlyphHeight(0), + + m_pFontCollection(NULL) +{ + InitializeCriticalSection(&m_renderTargetsCriticalSection); + InitializeCriticalSection(&m_glyphMapsCriticalSection); + InitializeCriticalSection(&m_fontsCriticalSection); + InitializeCriticalSection(&m_insertGlyphCriticalSection); +} + + +// Destruct +CFW1GlyphProvider::~CFW1GlyphProvider() { + SAFE_RELEASE(m_pGlyphAtlas); + + SAFE_RELEASE(m_pDWriteFactory); + + while(!m_glyphRenderTargets.empty()) { + m_glyphRenderTargets.top()->Release(); + m_glyphRenderTargets.pop(); + } + + SAFE_RELEASE(m_pFontCollection); + for(size_t i=0; i < m_fonts.size(); ++i) + SAFE_RELEASE(m_fonts[i].pFontFace); + + for(FontMap::iterator it = m_fontMap.begin(); it != m_fontMap.end(); ++it) { + GlyphMap *glyphMap = (*it).second; + + delete[] glyphMap->glyphs; + delete glyphMap; + } + + DeleteCriticalSection(&m_renderTargetsCriticalSection); + DeleteCriticalSection(&m_glyphMapsCriticalSection); + DeleteCriticalSection(&m_fontsCriticalSection); + DeleteCriticalSection(&m_insertGlyphCriticalSection); +} + + +// Init glyph provider +HRESULT CFW1GlyphProvider::initGlyphProvider( + IFW1Factory *pFW1Factory, + IFW1GlyphAtlas *pGlyphAtlas, + IDWriteFactory *pDWriteFactory, + IDWriteFontCollection *pFontCollection, + UINT maxGlyphWidth, + UINT maxGlyphHeight +) { + HRESULT hResult = initBaseObject(pFW1Factory); + if(FAILED(hResult)) + return hResult; + + if(pGlyphAtlas == NULL || pDWriteFactory == NULL || pFontCollection == NULL) + return E_INVALIDARG; + + pGlyphAtlas->AddRef(); + m_pGlyphAtlas = pGlyphAtlas; + + pDWriteFactory->AddRef(); + m_pDWriteFactory = pDWriteFactory; + + m_maxGlyphWidth = 384; + if(maxGlyphWidth > 0 && maxGlyphWidth <= 8192) + m_maxGlyphWidth = maxGlyphWidth; + m_maxGlyphHeight = 384; + if(maxGlyphHeight > 0 && maxGlyphHeight <= 8192) + m_maxGlyphHeight = maxGlyphHeight; + + pFontCollection->AddRef(); + m_pFontCollection = pFontCollection; + + return S_OK; +} + + +// Get font index from DWrite font-face +UINT CFW1GlyphProvider::getFontIndexFromFontFace(IDWriteFontFace *pFontFace) { + UINT fontIndex = 0xffffffff; + + EnterCriticalSection(&m_fontsCriticalSection); + + // Search for a matching fontface by pointer + for(size_t i=0; i < m_fonts.size(); ++i) { + const FontInfo &fontInfo = m_fonts[i]; + + if(pFontFace == fontInfo.pFontFace) { + fontIndex = static_cast(i); + break; + } + } + + LeaveCriticalSection(&m_fontsCriticalSection); + + // Get font-face name + if(fontIndex == 0xffffffff) { + std::wstring uniqueName = getUniqueNameFromFontFace(pFontFace); + if(uniqueName.size() > 0) { + IDWriteFontFace *pOldFontFace = NULL; + + pFontFace->AddRef(); + + EnterCriticalSection(&m_fontsCriticalSection); + + // Search for a matching fontface by name + for(size_t i=0; i < m_fonts.size(); ++i) { + FontInfo &fontInfo = m_fonts[i]; + + if(fontInfo.uniqueName == uniqueName) { + pOldFontFace = fontInfo.pFontFace; + fontInfo.pFontFace = pFontFace; + fontIndex = static_cast(i); + break; + } + } + + // Add new font + if(fontIndex == 0xffffffff) { + FontInfo fontInfo; + + fontInfo.pFontFace = pFontFace; + fontInfo.uniqueName = uniqueName; + + fontIndex = static_cast(m_fonts.size()); + m_fonts.push_back(fontInfo); + } + + LeaveCriticalSection(&m_fontsCriticalSection); + + SAFE_RELEASE(pOldFontFace); + } + else + fontIndex = 0; + } + + return fontIndex; +} + + +// Get unique name for a DWrite font-face +std::wstring CFW1GlyphProvider::getUniqueNameFromFontFace(IDWriteFontFace *pFontFace) { + std::wstring uniqueName; + + IDWriteFont *pFont; + HRESULT hResult = m_pFontCollection->GetFontFromFontFace(pFontFace, &pFont); + if(SUCCEEDED(hResult)) { + // Family name + IDWriteFontFamily *pFontFamily; + hResult = pFont->GetFontFamily(&pFontFamily); + if(SUCCEEDED(hResult)) { + IDWriteLocalizedStrings *pFamilyNames; + hResult = pFontFamily->GetFamilyNames(&pFamilyNames); + if(SUCCEEDED(hResult)) { + UINT32 index; + BOOL exists; + hResult = pFamilyNames->FindLocaleName(L"en-us", &index, &exists); + if(FAILED(hResult) || !exists) + index = 0; + + if(pFamilyNames->GetCount() > index) { + UINT32 length; + hResult = pFamilyNames->GetStringLength(index, &length); + if(SUCCEEDED(hResult)) { + std::vector str(length+1); + + hResult = pFamilyNames->GetString(index, &str[0], length+1); + if(SUCCEEDED(hResult)) + uniqueName = &str[0]; + } + } + + pFamilyNames->Release(); + } + + pFontFamily->Release(); + } + + // Face name + IDWriteLocalizedStrings *pFaceNames; + hResult = pFont->GetFaceNames(&pFaceNames); + if(SUCCEEDED(hResult)) { + UINT32 index; + BOOL exists; + hResult = pFaceNames->FindLocaleName(L"en-us", &index, &exists); + if(FAILED(hResult) || !exists) + index = 0; + + if(pFaceNames->GetCount() > index) { + UINT32 length; + hResult = pFaceNames->GetStringLength(index, &length); + if(SUCCEEDED(hResult)) { + std::vector str(length+1); + + hResult = pFaceNames->GetString(index, &str[0], length+1); + if(SUCCEEDED(hResult)) + uniqueName.append(&str[0]); + } + } + + pFaceNames->Release(); + } + + // Simulations + if(uniqueName.size() > 0) { + DWRITE_FONT_SIMULATIONS simulations = pFontFace->GetSimulations(); + if(simulations == DWRITE_FONT_SIMULATIONS_BOLD) + uniqueName += L"SimBold"; + else if(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE) + uniqueName += L"SimOblique"; + } + } + + return uniqueName; +} + + +// Render and insert new glyph into a glyph-map +UINT CFW1GlyphProvider::insertNewGlyph(GlyphMap *glyphMap, UINT16 glyphIndex, IDWriteFontFace *pFontFace) { + UINT glyphAtlasId = 0xffffffff; + + // Get a render target + IFW1DWriteRenderTarget *pRenderTarget = NULL; + + EnterCriticalSection(&m_renderTargetsCriticalSection); + + if(!m_glyphRenderTargets.empty()) { + pRenderTarget = m_glyphRenderTargets.top(); + m_glyphRenderTargets.pop(); + } + + LeaveCriticalSection(&m_renderTargetsCriticalSection); + + if(pRenderTarget == NULL) { + IFW1DWriteRenderTarget *pNewRenderTarget; + HRESULT hResult = m_pFW1Factory->CreateDWriteRenderTarget( + m_pDWriteFactory, + m_maxGlyphWidth, + m_maxGlyphHeight, + &pNewRenderTarget + ); + if(FAILED(hResult)) { + } + else { + pRenderTarget = pNewRenderTarget; + } + } + + if(pRenderTarget != NULL) { + // Draw the glyph image + DWRITE_RENDERING_MODE renderingMode = DWRITE_RENDERING_MODE_DEFAULT; + DWRITE_MEASURING_MODE measuringMode = DWRITE_MEASURING_MODE_NATURAL; + if((glyphMap->fontFlags & FW1_ALIASED) != 0) { + renderingMode = DWRITE_RENDERING_MODE_ALIASED; + measuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; + } + + FW1_GLYPHIMAGEDATA glyphData; + HRESULT hResult = pRenderTarget->DrawGlyphTemp( + pFontFace, + glyphIndex, + glyphMap->fontSize, + renderingMode, + measuringMode, + &glyphData + ); + if(FAILED(hResult)) { + } + else { + // Insert into the atlas and the glyph-map + EnterCriticalSection(&m_insertGlyphCriticalSection); + + glyphAtlasId = glyphMap->glyphs[glyphIndex]; + if(glyphAtlasId == 0xffffffff) { + glyphAtlasId = m_pGlyphAtlas->InsertGlyph( + &glyphData.Metrics, + glyphData.pGlyphPixels, + glyphData.RowPitch, + glyphData.PixelStride + ); + if(glyphAtlasId != 0xffffffff) + glyphMap->glyphs[glyphIndex] = glyphAtlasId; + } + + LeaveCriticalSection(&m_insertGlyphCriticalSection); + } + + // Keep the render target for future use + EnterCriticalSection(&m_renderTargetsCriticalSection); + m_glyphRenderTargets.push(pRenderTarget); + LeaveCriticalSection(&m_renderTargetsCriticalSection); + } + + return glyphAtlasId; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphProvider.h b/no_renderer/FW1FontWrapper/CFW1GlyphProvider.h new file mode 100644 index 0000000..c05b1d9 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphProvider.h @@ -0,0 +1,104 @@ +// CFW1GlyphProvider.h + +#ifndef IncludeGuard__FW1_CFW1GlyphProvider +#define IncludeGuard__FW1_CFW1GlyphProvider + +#include "CFW1Object.h" + + +namespace FW1FontWrapper { + + +// Fonts and glyphs-maps collection to match glyphs to images in a glyph-atlas +class CFW1GlyphProvider : public CFW1Object { + public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + // IFW1GlyphProvider + virtual HRESULT STDMETHODCALLTYPE GetGlyphAtlas(IFW1GlyphAtlas **ppGlyphAtlas); + virtual HRESULT STDMETHODCALLTYPE GetDWriteFactory(IDWriteFactory **ppDWriteFactory); + virtual HRESULT STDMETHODCALLTYPE GetDWriteFontCollection(IDWriteFontCollection **ppFontCollection); + + virtual const void* STDMETHODCALLTYPE GetGlyphMapFromFont( + IDWriteFontFace *pFontFace, + FLOAT FontSize, + UINT FontFlags + ); + virtual UINT STDMETHODCALLTYPE GetAtlasIdFromGlyphIndex( + const void* pGlyphMap, + UINT16 GlyphIndex, + IDWriteFontFace *pFontFace, + UINT FontFlags + ); + + // Public functions + public: + CFW1GlyphProvider(); + + HRESULT initGlyphProvider( + IFW1Factory *pFW1Factory, + IFW1GlyphAtlas *pGlyphAtlas, + IDWriteFactory *pDWriteFactory, + IDWriteFontCollection *pFontCollection, + UINT maxGlyphWidth, + UINT maxGlyphHeight + ); + + // Internal types + private: + struct GlyphMap { + FLOAT fontSize; + UINT fontFlags; + + UINT *glyphs; + UINT glyphCount; + }; + + struct FontInfo { + IDWriteFontFace *pFontFace; + std::wstring uniqueName; + }; + + typedef std::pair > FontId; + typedef std::map FontMap; + + FontId makeFontId(UINT fontIndex, UINT fontFlags, FLOAT fontSize) { + UINT relevantFlags = (fontFlags & (FW1_ALIASED)); + return std::make_pair(fontIndex, std::make_pair(relevantFlags, fontSize)); + } + + // Internal functions + private: + virtual ~CFW1GlyphProvider(); + + UINT getFontIndexFromFontFace(IDWriteFontFace *pFontFace); + std::wstring getUniqueNameFromFontFace(IDWriteFontFace *pFontFace); + + UINT insertNewGlyph(GlyphMap *glyphMap, UINT16 glyphIndex, IDWriteFontFace *pFontFace); + + // Internal data + private: + IFW1GlyphAtlas *m_pGlyphAtlas; + + IDWriteFactory *m_pDWriteFactory; + UINT m_maxGlyphWidth; + UINT m_maxGlyphHeight; + std::stack m_glyphRenderTargets; + + IDWriteFontCollection *m_pFontCollection; + std::vector m_fonts; + + FontMap m_fontMap; + + CRITICAL_SECTION m_renderTargetsCriticalSection; + CRITICAL_SECTION m_glyphMapsCriticalSection; + CRITICAL_SECTION m_fontsCriticalSection; + CRITICAL_SECTION m_insertGlyphCriticalSection; +}; + + +}// namespace FW1FontWrapper + + +#endif// IncludeGuard__FW1_CFW1GlyphProvider diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphProviderInterface.cpp b/no_renderer/FW1FontWrapper/CFW1GlyphProviderInterface.cpp new file mode 100644 index 0000000..7a00572 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphProviderInterface.cpp @@ -0,0 +1,168 @@ +// CFW1GlyphProviderInterface.cpp + +#include "FW1Precompiled.h" + +#include "CFW1GlyphProvider.h" + + +namespace FW1FontWrapper { + + +// Query interface +HRESULT STDMETHODCALLTYPE CFW1GlyphProvider::QueryInterface(REFIID riid, void **ppvObject) { + if(ppvObject == NULL) + return E_INVALIDARG; + + if(IsEqualIID(riid, __uuidof(IFW1GlyphProvider))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + + return CFW1Object::QueryInterface(riid, ppvObject); +} + + +// Get glyph atlas +HRESULT STDMETHODCALLTYPE CFW1GlyphProvider::GetGlyphAtlas(IFW1GlyphAtlas **ppGlyphAtlas) { + if(ppGlyphAtlas == NULL) + return E_INVALIDARG; + + m_pGlyphAtlas->AddRef(); + *ppGlyphAtlas = m_pGlyphAtlas; + + return S_OK; +} + + +// Get DWrite factory +HRESULT STDMETHODCALLTYPE CFW1GlyphProvider::GetDWriteFactory(IDWriteFactory **ppDWriteFactory) { + if(ppDWriteFactory == NULL) + return E_INVALIDARG; + + m_pDWriteFactory->AddRef(); + *ppDWriteFactory = m_pDWriteFactory; + + return S_OK; +} + + +// Get DWrite font collection +HRESULT STDMETHODCALLTYPE CFW1GlyphProvider::GetDWriteFontCollection(IDWriteFontCollection **ppFontCollection) { + if(ppFontCollection == NULL) + return E_INVALIDARG; + + m_pFontCollection->AddRef(); + *ppFontCollection = m_pFontCollection; + + return S_OK; +} + + +// Get glyph map +const void* STDMETHODCALLTYPE CFW1GlyphProvider::GetGlyphMapFromFont( + IDWriteFontFace *pFontFace, + FLOAT FontSize, + UINT FontFlags +) { + // Get font id + UINT fontIndex = getFontIndexFromFontFace(pFontFace); + FontId fontId = makeFontId(fontIndex, FontFlags, FontSize); + + const void *glyphMap = 0; + + // Get the glyph-map + EnterCriticalSection(&m_glyphMapsCriticalSection); + FontMap::iterator it = m_fontMap.find(fontId); + if(it != m_fontMap.end()) + glyphMap = (*it).second; + LeaveCriticalSection(&m_glyphMapsCriticalSection); + + if(glyphMap == 0 && (FontFlags & FW1_NONEWGLYPHS) == 0) { + // Create a new glyph-map + GlyphMap *newGlyphMap = new GlyphMap; + newGlyphMap->fontSize = FontSize; + newGlyphMap->fontFlags = FontFlags; + newGlyphMap->glyphCount = pFontFace->GetGlyphCount(); + newGlyphMap->glyphs = new UINT[newGlyphMap->glyphCount]; + for(UINT i=0; i < newGlyphMap->glyphCount; ++i) + newGlyphMap->glyphs[i] = 0xffffffff; + + bool needless = false; + + // Inert the new glyph-map and map the font-id to its index + EnterCriticalSection(&m_glyphMapsCriticalSection); + + it = m_fontMap.find(fontId); + if(it != m_fontMap.end()) { + glyphMap = (*it).second; + needless = true; + } + else { + m_fontMap.insert(std::make_pair(fontId, newGlyphMap)); + glyphMap = newGlyphMap; + } + + LeaveCriticalSection(&m_glyphMapsCriticalSection); + + if(needless) {// Simultaneous creation on two threads + delete[] newGlyphMap->glyphs; + delete newGlyphMap; + } + else { + UINT glyphAtlasId = insertNewGlyph(newGlyphMap, 0, pFontFace); + glyphAtlasId; + } + } + + return glyphMap; +} + + +// Get atlas id of a glyph +UINT STDMETHODCALLTYPE CFW1GlyphProvider::GetAtlasIdFromGlyphIndex( + const void *pGlyphMap, + UINT16 GlyphIndex, + IDWriteFontFace *pFontFace, + UINT FontFlags +) { + GlyphMap *glyphMap = static_cast(const_cast(pGlyphMap)); + + if(glyphMap == 0) + return 0; + + if(GlyphIndex >= glyphMap->glyphCount) + return 0; + + // Get the atlas id for this glyph + UINT glyphAtlasId = glyphMap->glyphs[GlyphIndex]; + if(glyphAtlasId == 0xffffffff && (FontFlags & FW1_NONEWGLYPHS) == 0) + glyphAtlasId = insertNewGlyph(glyphMap, GlyphIndex, pFontFace); + + // Fall back to the font default-glyph or the atlas default-glyph on failure + if(glyphAtlasId == 0xffffffff) { + glyphAtlasId = glyphMap->glyphs[0]; + + if((FontFlags & FW1_NONEWGLYPHS) == 0) { + if(glyphAtlasId == 0xffffffff) { + if(GlyphIndex == 0) + glyphAtlasId = 0; + else + glyphAtlasId = GetAtlasIdFromGlyphIndex(pGlyphMap, 0, pFontFace, FontFlags); + } + + EnterCriticalSection(&m_insertGlyphCriticalSection); + if(glyphMap->glyphs[GlyphIndex] == 0xffffffff) + glyphMap->glyphs[GlyphIndex] = glyphAtlasId; + LeaveCriticalSection(&m_insertGlyphCriticalSection); + } + + if(glyphAtlasId == 0xffffffff) + glyphAtlasId = 0; + } + + return glyphAtlasId; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphRenderStates.cpp b/no_renderer/FW1FontWrapper/CFW1GlyphRenderStates.cpp new file mode 100644 index 0000000..681f5cb --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphRenderStates.cpp @@ -0,0 +1,857 @@ +// CFW1GlyphRenderStates.cpp + +#include "FW1Precompiled.h" + +#include "CFW1GlyphRenderStates.h" + +#define SAFE_RELEASE(pObject) { if(pObject) { (pObject)->Release(); (pObject) = NULL; } } + + +namespace FW1FontWrapper { + + +// Construct +CFW1GlyphRenderStates::CFW1GlyphRenderStates() : + m_pfnD3DCompile(NULL), + + m_pDevice(NULL), + m_featureLevel(D3D_FEATURE_LEVEL_9_1), + + m_pVertexShaderQuad(NULL), + m_pVertexShaderClipQuad(NULL), + m_pQuadInputLayout(NULL), + + m_pVertexShaderPoint(NULL), + m_pPointInputLayout(NULL), + m_pGeometryShaderPoint(NULL), + m_pGeometryShaderClipPoint(NULL), + m_hasGeometryShader(false), + + m_pPixelShader(NULL), + m_pPixelShaderClip(NULL), + + m_pConstantBuffer(NULL), + + m_pBlendState(NULL), + m_pSamplerState(NULL), + m_pRasterizerState(NULL), + m_pDepthStencilState(NULL) +{ +} + + +// Destruct +CFW1GlyphRenderStates::~CFW1GlyphRenderStates() { + SAFE_RELEASE(m_pDevice); + + SAFE_RELEASE(m_pVertexShaderQuad); + SAFE_RELEASE(m_pVertexShaderClipQuad); + SAFE_RELEASE(m_pQuadInputLayout); + + SAFE_RELEASE(m_pVertexShaderPoint); + SAFE_RELEASE(m_pPointInputLayout); + SAFE_RELEASE(m_pGeometryShaderPoint); + SAFE_RELEASE(m_pGeometryShaderClipPoint); + + SAFE_RELEASE(m_pPixelShader); + SAFE_RELEASE(m_pPixelShaderClip); + + SAFE_RELEASE(m_pConstantBuffer); + + SAFE_RELEASE(m_pBlendState); + SAFE_RELEASE(m_pSamplerState); + SAFE_RELEASE(m_pRasterizerState); + SAFE_RELEASE(m_pDepthStencilState); +} + + +// Init +HRESULT CFW1GlyphRenderStates::initRenderResources( + IFW1Factory *pFW1Factory, + ID3D11Device *pDevice, + bool wantGeometryShader, + bool anisotropicFiltering +) { + HRESULT hResult = initBaseObject(pFW1Factory); + if(FAILED(hResult)) + return hResult; + + if(pDevice == NULL) + return E_INVALIDARG; + + pDevice->AddRef(); + m_pDevice = pDevice; + m_featureLevel = m_pDevice->GetFeatureLevel(); + + // D3DCompiler +#ifdef FW1_DELAYLOAD_D3DCOMPILER_XX_DLL + HMODULE hD3DCompiler = LoadLibrary(D3DCOMPILER_DLL); + if(hD3DCompiler == NULL) { + DWORD dwErr = GetLastError(); + dwErr; + m_lastError = std::wstring(L"Failed to load ") + D3DCOMPILER_DLL_W; + hResult = E_FAIL; + } + else { + m_pfnD3DCompile = reinterpret_cast(GetProcAddress(hD3DCompiler, "D3DCompile")); + if(m_pfnD3DCompile == NULL) { + DWORD dwErr = GetLastError(); + dwErr; + m_lastError = std::wstring(L"Failed to load D3DCompile from ") + D3DCOMPILER_DLL_W; + hResult = E_FAIL; + } + else { + hResult = S_OK; + } + } +#else + m_pfnD3DCompile = D3DCompile; + hResult = S_OK; +#endif + + // Create all needed resources + if(SUCCEEDED(hResult)) + hResult = createQuadShaders(); + if(SUCCEEDED(hResult)) + hResult = createPixelShaders(); + if(SUCCEEDED(hResult)) + hResult = createConstantBuffer(); + if(SUCCEEDED(hResult)) + hResult = createRenderStates(anisotropicFiltering); + if(SUCCEEDED(hResult) && wantGeometryShader) { + hResult = createGlyphShaders(); + if(FAILED(hResult)) + hResult = S_OK; + } + + if(SUCCEEDED(hResult)) + hResult = S_OK; + +#ifdef FW1_DELAYLOAD_D3DCOMPILER_XX_DLL + FreeLibrary(hD3DCompiler); +#endif + + return hResult; +} + + +// Create quad shaders +HRESULT CFW1GlyphRenderStates::createQuadShaders() { + // Vertex shaders + const char vsSimpleStr[] = + "cbuffer ShaderConstants : register(b0) {\r\n" + " float4x4 TransformMatrix : packoffset(c0);\r\n" + "};\r\n" + "\r\n" + "struct VSIn {\r\n" + " float4 Position : POSITION;\r\n" + " float4 GlyphColor : GLYPHCOLOR;\r\n" + "};\r\n" + "\r\n" + "struct VSOut {\r\n" + " float4 Position : SV_Position;\r\n" + " float4 GlyphColor : COLOR;\r\n" + " float2 TexCoord : TEXCOORD;\r\n" + "};\r\n" + "\r\n" + "VSOut VS(VSIn Input) {\r\n" + " VSOut Output;\r\n" + " \r\n" + " Output.Position = mul(TransformMatrix, float4(Input.Position.xy, 0.0f, 1.0f));\r\n" + " Output.GlyphColor = Input.GlyphColor;\r\n" + " Output.TexCoord = Input.Position.zw;\r\n" + " \r\n" + " return Output;\r\n" + "}\r\n" + ""; + + const char vsClipStr[] = + "cbuffer ShaderConstants : register(b0) {\r\n" + " float4x4 TransformMatrix : packoffset(c0);\r\n" + " float4 ClipRect : packoffset(c4);\r\n" + "};\r\n" + "\r\n" + "struct VSIn {\r\n" + " float4 Position : POSITION;\r\n" + " float4 GlyphColor : GLYPHCOLOR;\r\n" + "};\r\n" + "\r\n" + "struct VSOut {\r\n" + " float4 Position : SV_Position;\r\n" + " float4 GlyphColor : COLOR;\r\n" + " float2 TexCoord : TEXCOORD;\r\n" + " float4 ClipDistance : CLIPDISTANCE;\r\n" + "};\r\n" + "\r\n" + "VSOut VS(VSIn Input) {\r\n" + " VSOut Output;\r\n" + " \r\n" + " Output.Position = mul(TransformMatrix, float4(Input.Position.xy, 0.0f, 1.0f));\r\n" + " Output.GlyphColor = Input.GlyphColor;\r\n" + " Output.TexCoord = Input.Position.zw;\r\n" + " Output.ClipDistance = ClipRect + float4(Input.Position.xy, -Input.Position.xy);\r\n" + " \r\n" + " return Output;\r\n" + "}\r\n" + ""; + + // Shader compile profile + const char *vs_profile = "vs_4_0_level_9_1"; + if(m_featureLevel >= D3D_FEATURE_LEVEL_11_0) + vs_profile = "vs_5_0"; + else if(m_featureLevel >= D3D_FEATURE_LEVEL_10_0) + vs_profile = "vs_4_0"; + else if(m_featureLevel >= D3D_FEATURE_LEVEL_9_3) + vs_profile = "vs_4_0_level_9_3"; + + // Compile vertex shader + ID3DBlob *pVSCode; + + HRESULT hResult = m_pfnD3DCompile( + vsSimpleStr, + sizeof(vsSimpleStr), + NULL, + NULL, + NULL, + "VS", + vs_profile, + D3DCOMPILE_OPTIMIZATION_LEVEL3, + 0, + &pVSCode, + NULL + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to compile vertex shader"; + } + else { + // Create vertex shader + ID3D11VertexShader *pVS; + + hResult = m_pDevice->CreateVertexShader(pVSCode->GetBufferPointer(), pVSCode->GetBufferSize(), NULL, &pVS); + if(FAILED(hResult)) { + m_lastError = L"Failed to create vertex shader"; + } + else { + // Compile clipping vertex shader + ID3DBlob *pVSClipCode; + + hResult = m_pfnD3DCompile( + vsClipStr, + sizeof(vsClipStr), + NULL, + NULL, + NULL, + "VS", + vs_profile, + D3DCOMPILE_OPTIMIZATION_LEVEL3, + 0, + &pVSClipCode, + NULL + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to compile clipping vertex shader"; + } + else { + // Create vertex shader + ID3D11VertexShader *pVSClip; + + hResult = m_pDevice->CreateVertexShader( + pVSClipCode->GetBufferPointer(), + pVSClipCode->GetBufferSize(), + NULL, + &pVSClip + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to create clipping vertex shader"; + } + else { + // Create input layout + ID3D11InputLayout *pInputLayout; + + // Quad vertex input layout + D3D11_INPUT_ELEMENT_DESC inputElements[] = { + {"POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"GLYPHCOLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0} + }; + + hResult = m_pDevice->CreateInputLayout( + inputElements, + 2, + pVSCode->GetBufferPointer(), + pVSCode->GetBufferSize(), + &pInputLayout + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to create input layout"; + } + else { + // Success + m_pVertexShaderQuad = pVS; + m_pVertexShaderClipQuad = pVSClip; + m_pQuadInputLayout = pInputLayout; + + hResult = S_OK; + } + + if(FAILED(hResult)) + pVSClip->Release(); + } + + pVSClipCode->Release(); + } + + if(FAILED(hResult)) + pVS->Release(); + } + + pVSCode->Release(); + } + + return hResult; +} + +// Create point to quad geometry shader +HRESULT CFW1GlyphRenderStates::createGlyphShaders() { + if(m_featureLevel < D3D_FEATURE_LEVEL_10_0) + return E_FAIL; + + // Geometry shader constructing glyphs from point input and texture buffer + const char gsSimpleStr[] = + "cbuffer ShaderConstants : register(b0) {\r\n" + " float4x4 TransformMatrix : packoffset(c0);\r\n" + "};\r\n" + "\r\n" + "Buffer tex0 : register(t0);\r\n" + "\r\n" + "struct GSIn {\r\n" + " float3 PositionIndex : POSITIONINDEX;\r\n" + " float4 GlyphColor : GLYPHCOLOR;\r\n" + "};\r\n" + "\r\n" + "struct GSOut {\r\n" + " float4 Position : SV_Position;\r\n" + " float4 GlyphColor : COLOR;\r\n" + " float2 TexCoord : TEXCOORD;\r\n" + "};\r\n" + "\r\n" + "[maxvertexcount(4)]\r\n" + "void GS(point GSIn Input[1], inout TriangleStream TriStream) {\r\n" + " const float2 basePosition = Input[0].PositionIndex.xy;\r\n" + " const uint glyphIndex = asuint(Input[0].PositionIndex.z);\r\n" + " \r\n" + " float4 texCoords = tex0.Load(uint2(glyphIndex*2, 0));\r\n" + " float4 offsets = tex0.Load(uint2(glyphIndex*2+1, 0));\r\n" + " \r\n" + " GSOut Output;\r\n" + " Output.GlyphColor = Input[0].GlyphColor;\r\n" + " \r\n" + " float4 positions = basePosition.xyxy + offsets;\r\n" + " \r\n" + " Output.Position = mul(TransformMatrix, float4(positions.xy, 0.0f, 1.0f));\r\n" + " Output.TexCoord = texCoords.xy;\r\n" + " TriStream.Append(Output);\r\n" + " \r\n" + " Output.Position = mul(TransformMatrix, float4(positions.zy, 0.0f, 1.0f));\r\n" + " Output.TexCoord = texCoords.zy;\r\n" + " TriStream.Append(Output);\r\n" + " \r\n" + " Output.Position = mul(TransformMatrix, float4(positions.xw, 0.0f, 1.0f));\r\n" + " Output.TexCoord = texCoords.xw;\r\n" + " TriStream.Append(Output);\r\n" + " \r\n" + " Output.Position = mul(TransformMatrix, float4(positions.zw, 0.0f, 1.0f));\r\n" + " Output.TexCoord = texCoords.zw;\r\n" + " TriStream.Append(Output);\r\n" + " \r\n" + " TriStream.RestartStrip();\r\n" + "}\r\n" + ""; + + // Geometry shader with rect clipping + const char gsClipStr[] = + "cbuffer ShaderConstants : register(b0) {\r\n" + " float4x4 TransformMatrix : packoffset(c0);\r\n" + " float4 ClipRect : packoffset(c4);\r\n" + "};\r\n" + "\r\n" + "Buffer tex0 : register(t0);\r\n" + "\r\n" + "struct GSIn {\r\n" + " float3 PositionIndex : POSITIONINDEX;\r\n" + " float4 GlyphColor : GLYPHCOLOR;\r\n" + "};\r\n" + "\r\n" + "struct GSOut {\r\n" + " float4 Position : SV_Position;\r\n" + " float4 GlyphColor : COLOR;\r\n" + " float2 TexCoord : TEXCOORD;\r\n" + " float4 ClipDistance : SV_ClipDistance;\r\n" + "};\r\n" + "\r\n" + "[maxvertexcount(4)]\r\n" + "void GS(point GSIn Input[1], inout TriangleStream TriStream) {\r\n" + " const float2 basePosition = Input[0].PositionIndex.xy;\r\n" + " const uint glyphIndex = asuint(Input[0].PositionIndex.z);\r\n" + " \r\n" + " float4 texCoords = tex0.Load(uint2(glyphIndex*2, 0));\r\n" + " float4 offsets = tex0.Load(uint2(glyphIndex*2+1, 0));\r\n" + " \r\n" + " GSOut Output;\r\n" + " Output.GlyphColor = Input[0].GlyphColor;\r\n" + " \r\n" + " float4 positions = basePosition.xyxy + offsets;\r\n" + " \r\n" + " Output.Position = mul(TransformMatrix, float4(positions.xy, 0.0f, 1.0f));\r\n" + " Output.TexCoord = texCoords.xy;\r\n" + " Output.ClipDistance = ClipRect + float4(positions.xy, -positions.xy);\r\n" + " TriStream.Append(Output);\r\n" + " \r\n" + " Output.Position = mul(TransformMatrix, float4(positions.zy, 0.0f, 1.0f));\r\n" + " Output.TexCoord = texCoords.zy;\r\n" + " Output.ClipDistance = ClipRect + float4(positions.zy, -positions.zy);\r\n" + " TriStream.Append(Output);\r\n" + " \r\n" + " Output.Position = mul(TransformMatrix, float4(positions.xw, 0.0f, 1.0f));\r\n" + " Output.TexCoord = texCoords.xw;\r\n" + " Output.ClipDistance = ClipRect + float4(positions.xw, -positions.xw);\r\n" + " TriStream.Append(Output);\r\n" + " \r\n" + " Output.Position = mul(TransformMatrix, float4(positions.zw, 0.0f, 1.0f));\r\n" + " Output.TexCoord = texCoords.zw;\r\n" + " Output.ClipDistance = ClipRect + float4(positions.zw, -positions.zw);\r\n" + " TriStream.Append(Output);\r\n" + " \r\n" + " TriStream.RestartStrip();\r\n" + "}\r\n" + ""; + + // Vertex shader + const char vsEmptyStr[] = + "struct GSIn {\r\n" + " float3 PositionIndex : POSITIONINDEX;\r\n" + " float4 GlyphColor : GLYPHCOLOR;\r\n" + "};\r\n" + "\r\n" + "GSIn VS(GSIn Input) {\r\n" + " return Input;\r\n" + "}\r\n" + ""; + + // Shader compile profiles + const char *vs_profile = "vs_4_0"; + const char *gs_profile = "gs_4_0"; + if(m_featureLevel >= D3D_FEATURE_LEVEL_11_0) { + vs_profile = "vs_5_0"; + gs_profile = "gs_5_0"; + } + + // Compile geometry shader + ID3DBlob *pGSCode; + + HRESULT hResult = m_pfnD3DCompile( + gsSimpleStr, + sizeof(gsSimpleStr), + NULL, + NULL, + NULL, + "GS", + gs_profile, + D3DCOMPILE_OPTIMIZATION_LEVEL3, + 0, + &pGSCode, + NULL + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to compile geometry shader"; + } + else { + // Create geometry shader + ID3D11GeometryShader *pGS; + + hResult = m_pDevice->CreateGeometryShader(pGSCode->GetBufferPointer(), pGSCode->GetBufferSize(), NULL, &pGS); + if(FAILED(hResult)) { + m_lastError = L"Failed to create geometry shader"; + } + else { + // Compile clipping geometry shader + ID3DBlob *pGSClipCode; + + hResult = m_pfnD3DCompile( + gsClipStr, + sizeof(gsClipStr), + NULL, + NULL, + NULL, + "GS", + gs_profile, + D3DCOMPILE_OPTIMIZATION_LEVEL3, + 0, + &pGSClipCode, + NULL + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to compile clipping geometry shader"; + } + else { + // Create clipping geometry shader + ID3D11GeometryShader *pGSClip; + + hResult = m_pDevice->CreateGeometryShader( + pGSClipCode->GetBufferPointer(), + pGSClipCode->GetBufferSize(), + NULL, + &pGSClip + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to create clipping geometry shader"; + } + else { + ID3DBlob *pVSEmptyCode; + + // Compile vertex shader + hResult = m_pfnD3DCompile( + vsEmptyStr, + sizeof(vsEmptyStr), + NULL, + NULL, + NULL, + "VS", + vs_profile, + D3DCOMPILE_OPTIMIZATION_LEVEL3, + 0, + &pVSEmptyCode, + NULL + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to compile empty vertex shader"; + } + else { + // Create vertex shader + ID3D11VertexShader *pVSEmpty; + + hResult = m_pDevice->CreateVertexShader( + pVSEmptyCode->GetBufferPointer(), + pVSEmptyCode->GetBufferSize(), + NULL, + &pVSEmpty + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to create empty vertex shader"; + } + else { + ID3D11InputLayout *pInputLayout; + + // Input layout for geometry shader + D3D11_INPUT_ELEMENT_DESC inputElements[] = { + {"POSITIONINDEX", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"GLYPHCOLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0} + }; + + hResult = m_pDevice->CreateInputLayout( + inputElements, + 2, + pVSEmptyCode->GetBufferPointer(), + pVSEmptyCode->GetBufferSize(), + &pInputLayout + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to create input layout for geometry shader"; + } + else { + // Success + m_pVertexShaderPoint = pVSEmpty; + m_pGeometryShaderPoint = pGS; + m_pGeometryShaderClipPoint = pGSClip; + m_pPointInputLayout = pInputLayout; + m_hasGeometryShader = true; + + hResult = S_OK; + } + + if(FAILED(hResult)) + pVSEmpty->Release(); + } + + pVSEmptyCode->Release(); + } + + if(FAILED(hResult)) + pGSClip->Release(); + } + + pGSClipCode->Release(); + } + + if(FAILED(hResult)) + pGS->Release(); + } + + pGSCode->Release(); + } + + return hResult; +} + +// Create pixel shaders +HRESULT CFW1GlyphRenderStates::createPixelShaders() { + // Pixel shader + const char psStr[] = + "SamplerState sampler0 : register(s0);\r\n" + "Texture2D tex0 : register(t0);\r\n" + "\r\n" + "struct PSIn {\r\n" + " float4 Position : SV_Position;\r\n" + " float4 GlyphColor : COLOR;\r\n" + " float2 TexCoord : TEXCOORD;\r\n" + "};\r\n" + "\r\n" + "float4 PS(PSIn Input) : SV_Target {\r\n" + " float a = tex0.Sample(sampler0, Input.TexCoord);\r\n" + " \r\n" + " if(a == 0.0f)\r\n" + " discard;\r\n" + " \r\n" + " return (a * Input.GlyphColor.a) * float4(Input.GlyphColor.rgb, 1.0f);\r\n" + "}\r\n" + ""; + + // Clipping pixel shader + const char psClipStr[] = + "SamplerState sampler0 : register(s0);\r\n" + "Texture2D tex0 : register(t0);\r\n" + "\r\n" + "struct PSIn {\r\n" + " float4 Position : SV_Position;\r\n" + " float4 GlyphColor : COLOR;\r\n" + " float2 TexCoord : TEXCOORD;\r\n" + " float4 ClipDistance : CLIPDISTANCE;\r\n" + "};\r\n" + "\r\n" + "float4 PS(PSIn Input) : SV_Target {\r\n" + " clip(Input.ClipDistance);\r\n" + " \r\n" + " float a = tex0.Sample(sampler0, Input.TexCoord);\r\n" + " \r\n" + " if(a == 0.0f)\r\n" + " discard;\r\n" + " \r\n" + " return (a * Input.GlyphColor.a) * float4(Input.GlyphColor.rgb, 1.0f);\r\n" + "}\r\n" + ""; + + // Shader compile profile + const char *ps_profile = "ps_4_0_level_9_1"; + if(m_featureLevel >= D3D_FEATURE_LEVEL_11_0) + ps_profile = "ps_5_0"; + else if(m_featureLevel >= D3D_FEATURE_LEVEL_10_0) + ps_profile = "ps_4_0"; + else if(m_featureLevel >= D3D_FEATURE_LEVEL_9_3) + ps_profile = "ps_4_0_level_9_3"; + + // Compile pixel shader + ID3DBlob *pPSCode; + + HRESULT hResult = m_pfnD3DCompile( + psStr, + sizeof(psStr), + NULL, + NULL, + NULL, + "PS", + ps_profile, + D3DCOMPILE_OPTIMIZATION_LEVEL3, + 0, + &pPSCode, + NULL + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to compile pixel shader"; + } + else { + // Create pixel shader + ID3D11PixelShader *pPS; + + hResult = m_pDevice->CreatePixelShader(pPSCode->GetBufferPointer(), pPSCode->GetBufferSize(), NULL, &pPS); + if(FAILED(hResult)) { + m_lastError = L"Failed to create pixel shader"; + } + else { + // Compile clipping pixel shader + ID3DBlob *pPSClipCode; + + HRESULT hResult = m_pfnD3DCompile( + psClipStr, + sizeof(psClipStr), + NULL, + NULL, + NULL, + "PS", + ps_profile, + D3DCOMPILE_OPTIMIZATION_LEVEL3, + 0, + &pPSClipCode, + NULL + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to compile clipping pixel shader"; + } + else { + // Create pixel shader + ID3D11PixelShader *pPSClip; + + hResult = m_pDevice->CreatePixelShader( + pPSClipCode->GetBufferPointer(), + pPSClipCode->GetBufferSize(), + NULL, &pPSClip + ); + if(FAILED(hResult)) { + m_lastError = L"Failed to create clipping pixel shader"; + } + else { + // Success + m_pPixelShader = pPS; + m_pPixelShaderClip = pPSClip; + + hResult = S_OK; + } + + pPSClipCode->Release(); + } + + if(FAILED(hResult)) + pPS->Release(); + } + + pPSCode->Release(); + } + + return hResult; +} + + +// Create constant buffer +HRESULT CFW1GlyphRenderStates::createConstantBuffer() { + // Create constant buffer + D3D11_BUFFER_DESC constantBufferDesc; + ID3D11Buffer *pConstantBuffer; + + ZeroMemory(&constantBufferDesc, sizeof(constantBufferDesc)); + constantBufferDesc.ByteWidth = sizeof(ShaderConstants); + constantBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + constantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + + HRESULT hResult = m_pDevice->CreateBuffer(&constantBufferDesc, NULL, &pConstantBuffer); + if(FAILED(hResult)) { + m_lastError = L"Failed to create constant buffer"; + } + else { + // Success + m_pConstantBuffer = pConstantBuffer; + + hResult = S_OK; + } + + return hResult; +} + + +// Create render states +HRESULT CFW1GlyphRenderStates::createRenderStates(bool anisotropicFiltering) { + // Create blend-state + D3D11_BLEND_DESC blendDesc; + ID3D11BlendState *pBlendState; + + ZeroMemory(&blendDesc, sizeof(blendDesc)); + for(int i=0; i < 4; ++i) { + blendDesc.RenderTarget[i].BlendEnable = TRUE; + blendDesc.RenderTarget[i].SrcBlend = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_ZERO; + blendDesc.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendDesc.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + } + + HRESULT hResult = m_pDevice->CreateBlendState(&blendDesc, &pBlendState); + if(FAILED(hResult)) { + m_lastError = L"Failed to create blend state"; + } + else { + // Create sampler state + D3D11_SAMPLER_DESC samplerDesc; + ID3D11SamplerState *pSamplerState; + + ZeroMemory(&samplerDesc, sizeof(samplerDesc)); + if(anisotropicFiltering) { + samplerDesc.Filter = D3D11_FILTER_ANISOTROPIC; + samplerDesc.MaxAnisotropy = 2; + if(m_featureLevel >= D3D_FEATURE_LEVEL_9_2) + samplerDesc.MaxAnisotropy = 5; + } + else + samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; + + hResult = m_pDevice->CreateSamplerState(&samplerDesc, &pSamplerState); + if(FAILED(hResult)) { + m_lastError = L"Failed to create sampler state"; + } + else { + // Create rasterizer state + D3D11_RASTERIZER_DESC rasterizerDesc; + ID3D11RasterizerState *pRasterizerState; + + ZeroMemory(&rasterizerDesc, sizeof(rasterizerDesc)); + rasterizerDesc.FillMode = D3D11_FILL_SOLID; + rasterizerDesc.CullMode = D3D11_CULL_NONE; + rasterizerDesc.FrontCounterClockwise = FALSE; + rasterizerDesc.DepthClipEnable = TRUE; + + hResult = m_pDevice->CreateRasterizerState(&rasterizerDesc, &pRasterizerState); + if(FAILED(hResult)) { + m_lastError = L"Failed to create rasterizer state"; + } + else { + // Create depth-stencil state + D3D11_DEPTH_STENCIL_DESC depthStencilDesc; + ID3D11DepthStencilState *pDepthStencilState; + + ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc)); + depthStencilDesc.DepthEnable = FALSE; + + hResult = m_pDevice->CreateDepthStencilState(&depthStencilDesc, &pDepthStencilState); + if(FAILED(hResult)) { + m_lastError = L"Failed to create depth stencil state"; + } + else { + // Success + m_pBlendState = pBlendState; + m_pSamplerState = pSamplerState; + m_pRasterizerState = pRasterizerState; + m_pDepthStencilState = pDepthStencilState; + + hResult = S_OK; + } + + if(FAILED(hResult)) + pRasterizerState->Release(); + } + + if(FAILED(hResult)) + pSamplerState->Release(); + } + + if(FAILED(hResult)) + pBlendState->Release(); + } + + return hResult; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphRenderStates.h b/no_renderer/FW1FontWrapper/CFW1GlyphRenderStates.h new file mode 100644 index 0000000..2427a64 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphRenderStates.h @@ -0,0 +1,91 @@ +// CFW1GlyphRenderStates.h + +#ifndef IncludeGuard__FW1_CFW1GlyphRenderStates +#define IncludeGuard__FW1_CFW1GlyphRenderStates + +#include "CFW1Object.h" + + +namespace FW1FontWrapper { + + +// Shader etc. needed to draw glyphs +class CFW1GlyphRenderStates : public CFW1Object { + public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + // IFW1GlyphRenderStates + virtual HRESULT STDMETHODCALLTYPE GetDevice(ID3D11Device **ppDevice); + + virtual void STDMETHODCALLTYPE SetStates(ID3D11DeviceContext *pContext, UINT Flags); + virtual void STDMETHODCALLTYPE UpdateShaderConstants( + ID3D11DeviceContext *pContext, + const FW1_RECTF *pClipRect, + const FLOAT *pTransformMatrix + ); + virtual BOOL STDMETHODCALLTYPE HasGeometryShader(); + + // Public functions + public: + CFW1GlyphRenderStates(); + + HRESULT initRenderResources( + IFW1Factory *pFW1Factory, + ID3D11Device *pDevice, + bool wantGeometryShader, + bool anisotropicFiltering + ); + + // Internal types + private: + struct ShaderConstants { + FLOAT TransformMatrix[16]; + FLOAT ClipRect[4]; + }; + + // Internal functions + private: + virtual ~CFW1GlyphRenderStates(); + + HRESULT createQuadShaders(); + HRESULT createGlyphShaders(); + HRESULT createPixelShaders(); + HRESULT createConstantBuffer(); + HRESULT createRenderStates(bool anisotropicFiltering); + + // Internal data + private: + std::wstring m_lastError; + + pD3DCompile m_pfnD3DCompile; + + ID3D11Device *m_pDevice; + D3D_FEATURE_LEVEL m_featureLevel; + + ID3D11VertexShader *m_pVertexShaderQuad; + ID3D11VertexShader *m_pVertexShaderClipQuad; + ID3D11InputLayout *m_pQuadInputLayout; + + ID3D11VertexShader *m_pVertexShaderPoint; + ID3D11InputLayout *m_pPointInputLayout; + ID3D11GeometryShader *m_pGeometryShaderPoint; + ID3D11GeometryShader *m_pGeometryShaderClipPoint; + bool m_hasGeometryShader; + + ID3D11PixelShader *m_pPixelShader; + ID3D11PixelShader *m_pPixelShaderClip; + + ID3D11Buffer *m_pConstantBuffer; + + ID3D11BlendState *m_pBlendState; + ID3D11SamplerState *m_pSamplerState; + ID3D11RasterizerState *m_pRasterizerState; + ID3D11DepthStencilState *m_pDepthStencilState; +}; + + +}// namespace FW1FontWrapper + + +#endif// IncludeGuard__FW1_CFW1GlyphRenderStates diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphRenderStatesInterface.cpp b/no_renderer/FW1FontWrapper/CFW1GlyphRenderStatesInterface.cpp new file mode 100644 index 0000000..13669ab --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphRenderStatesInterface.cpp @@ -0,0 +1,151 @@ +// CFW1GlyphRenderStatesInterface.cpp + +#include "FW1Precompiled.h" + +#include "CFW1GlyphRenderStates.h" + + +namespace FW1FontWrapper { + + +// Query interface +HRESULT STDMETHODCALLTYPE CFW1GlyphRenderStates::QueryInterface(REFIID riid, void **ppvObject) { + if(ppvObject == NULL) + return E_INVALIDARG; + + if(IsEqualIID(riid, __uuidof(IFW1GlyphRenderStates))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + + return CFW1Object::QueryInterface(riid, ppvObject); +} + + +// Get the D3D11 device used by the render states +HRESULT STDMETHODCALLTYPE CFW1GlyphRenderStates::GetDevice(ID3D11Device **ppDevice) { + if(ppDevice == NULL) + return E_INVALIDARG; + + m_pDevice->AddRef(); + *ppDevice = m_pDevice; + + return S_OK; +} + + +// Set render states for glyph drawing +void STDMETHODCALLTYPE CFW1GlyphRenderStates::SetStates(ID3D11DeviceContext *pContext, UINT Flags) { + if(m_hasGeometryShader && ((Flags & FW1_NOGEOMETRYSHADER) == 0)) { + // Point vertices with geometry shader + pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); + pContext->IASetInputLayout(m_pPointInputLayout); + pContext->VSSetShader(m_pVertexShaderPoint, NULL, 0); + if((Flags & FW1_CLIPRECT) != 0) + pContext->GSSetShader(m_pGeometryShaderClipPoint, NULL, 0); + else + pContext->GSSetShader(m_pGeometryShaderPoint, NULL, 0); + pContext->PSSetShader(m_pPixelShader, NULL, 0); + pContext->GSSetConstantBuffers(0, 1, &m_pConstantBuffer); + } + else { + // Quads constructed on the CPU + pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + pContext->IASetInputLayout(m_pQuadInputLayout); + if((Flags & FW1_CLIPRECT) != 0) { + pContext->VSSetShader(m_pVertexShaderClipQuad, NULL, 0); + pContext->PSSetShader(m_pPixelShaderClip, NULL, 0); + } + else { + pContext->VSSetShader(m_pVertexShaderQuad, NULL, 0); + pContext->PSSetShader(m_pPixelShader, NULL, 0); + } + pContext->VSSetConstantBuffers(0, 1, &m_pConstantBuffer); + + if(m_featureLevel >= D3D_FEATURE_LEVEL_10_0) + pContext->GSSetShader(NULL, NULL, 0); + } + + if(m_featureLevel >= D3D_FEATURE_LEVEL_11_0) { + pContext->DSSetShader(NULL, NULL, 0); + pContext->HSSetShader(NULL, NULL, 0); + } + + pContext->OMSetBlendState(m_pBlendState, NULL, 0xffffffff); + pContext->OMSetDepthStencilState(m_pDepthStencilState, 0); + + pContext->RSSetState(m_pRasterizerState); + + pContext->PSSetSamplers(0, 1, &m_pSamplerState); +} + + +// Update constant buffer +void STDMETHODCALLTYPE CFW1GlyphRenderStates::UpdateShaderConstants( + ID3D11DeviceContext *pContext, + const FW1_RECTF *pClipRect, + const FLOAT *pTransformMatrix +) { + // Shader constants + ShaderConstants constants; + ZeroMemory(&constants, sizeof(constants)); + + // Transform matrix + if(pTransformMatrix != NULL) + CopyMemory(constants.TransformMatrix, pTransformMatrix, 16*sizeof(FLOAT)); + else { + // Get viewport size for orthographic transform + FLOAT w = 512.0f; + FLOAT h = 512.0f; + + D3D11_VIEWPORT vp; + UINT nvp = 1; + pContext->RSGetViewports(&nvp, &vp); + if(nvp > 0) { + if(vp.Width >= 1.0f && vp.Height >= 1.0f) { + w = vp.Width; + h = vp.Height; + } + } + + constants.TransformMatrix[0] = 2.0f / w; + constants.TransformMatrix[12] = -1.0f; + constants.TransformMatrix[5] = -2.0f / h; + constants.TransformMatrix[13] = 1.0f; + constants.TransformMatrix[10] = 1.0f; + constants.TransformMatrix[15] = 1.0f; + } + + // Clip rect + if(pClipRect != NULL) { + constants.ClipRect[0] = -pClipRect->Left; + constants.ClipRect[1] = -pClipRect->Top; + constants.ClipRect[2] = pClipRect->Right; + constants.ClipRect[3] = pClipRect->Bottom; + } + else { + constants.ClipRect[0] = FLT_MAX; + constants.ClipRect[1] = FLT_MAX; + constants.ClipRect[2] = FLT_MAX; + constants.ClipRect[3] = FLT_MAX; + } + + // Update constant buffer + D3D11_MAPPED_SUBRESOURCE msr; + HRESULT hResult = pContext->Map(m_pConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &msr); + if(SUCCEEDED(hResult)) { + CopyMemory(msr.pData, &constants, sizeof(constants)); + + pContext->Unmap(m_pConstantBuffer, 0); + } +} + + +// Check for geometry shader +BOOL STDMETHODCALLTYPE CFW1GlyphRenderStates::HasGeometryShader() { + return (m_hasGeometryShader ? TRUE : FALSE); +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphSheet.cpp b/no_renderer/FW1FontWrapper/CFW1GlyphSheet.cpp new file mode 100644 index 0000000..890d876 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphSheet.cpp @@ -0,0 +1,275 @@ +// CFW1GlyphSheet.cpp + +#include "FW1Precompiled.h" + +#include "CFW1GlyphSheet.h" + +#define SAFE_RELEASE(pObject) { if(pObject) { (pObject)->Release(); (pObject) = NULL; } } + + +namespace FW1FontWrapper { + + +// Construct +CFW1GlyphSheet::CFW1GlyphSheet() : + m_sheetWidth(0), + m_sheetHeight(0), + m_hardwareCoordBuffer(false), + m_allowOversizedGlyph(false), + + m_textureData(0), + m_glyphCoords(0), + m_maxGlyphCount(0), + m_glyphCount(0), + m_mipLevelCount(0), + m_alignWidth(0), + + m_pDevice(NULL), + + m_pTexture(NULL), + m_pTextureSRV(NULL), + m_pCoordBuffer(NULL), + m_pCoordBufferSRV(NULL), + + m_closed(false), + m_static(false), + + m_heightRange(0), + + m_updatedGlyphCount(0) +{ + ZeroMemory(&m_dirtyRect, sizeof(m_dirtyRect)); + InitializeCriticalSection(&m_sheetCriticalSection); + InitializeCriticalSection(&m_flushCriticalSection); +} + + +// Destruct +CFW1GlyphSheet::~CFW1GlyphSheet() { + delete[] m_textureData; + delete[] m_glyphCoords; + + SAFE_RELEASE(m_pDevice); + + SAFE_RELEASE(m_pTexture); + SAFE_RELEASE(m_pTextureSRV); + SAFE_RELEASE(m_pCoordBuffer); + SAFE_RELEASE(m_pCoordBufferSRV); + + delete m_heightRange; + + DeleteCriticalSection(&m_sheetCriticalSection); + DeleteCriticalSection(&m_flushCriticalSection); +} + + +// Init +HRESULT CFW1GlyphSheet::initGlyphSheet( + IFW1Factory *pFW1Factory, + ID3D11Device *pDevice, + UINT sheetWidth, + UINT sheetHeight, + bool coordBuffer, + bool allowOversizedGlyph, + UINT maxGlyphCount, + UINT mipLevelCount +) { + HRESULT hResult = initBaseObject(pFW1Factory); + if(FAILED(hResult)) + return hResult; + + if(pDevice == NULL) + return E_INVALIDARG; + + pDevice->AddRef(); + m_pDevice = pDevice; + + // Sheet metrics + m_sheetWidth = 512; + if(sheetWidth > 0) + m_sheetWidth = sheetWidth; + m_sheetHeight = 512; + if(sheetHeight > 0) + m_sheetHeight = sheetHeight; + + if(coordBuffer) { + D3D_FEATURE_LEVEL featureLevel = m_pDevice->GetFeatureLevel(); + if(featureLevel >= D3D_FEATURE_LEVEL_10_0) + m_hardwareCoordBuffer = true; + } + + m_allowOversizedGlyph = allowOversizedGlyph; + + m_maxGlyphCount = 2048; + if(maxGlyphCount > 0 && maxGlyphCount < 65535) + m_maxGlyphCount = maxGlyphCount; + + if(mipLevelCount > 1) { + m_mipLevelCount = std::min(mipLevelCount, 5U);// Reasonable mip limit considering borders + m_alignWidth = (1 << (m_mipLevelCount - 1)); + } + else {// 0 defaults to 1 + m_mipLevelCount = 1; + m_alignWidth = 1; + } + + // Storage + UINT textureSize = m_sheetWidth * m_sheetHeight; + UINT mipSize = textureSize; + for(UINT i=1;i>= 2; + textureSize += mipSize; + } + + m_textureData = new UINT8[textureSize]; + ZeroMemory(m_textureData, textureSize); + + m_glyphCoords = new FW1_GLYPHCOORDS[m_maxGlyphCount]; + + m_heightRange = new HeightRange(m_sheetWidth / m_alignWidth); + + // Device texture/coord-buffer + hResult = createDeviceResources(); + + if(SUCCEEDED(hResult)) + hResult = S_OK; + + return hResult; +} + + +// Create sheet texture and (optionally) coord buffer +HRESULT CFW1GlyphSheet::createDeviceResources() { + // Create sheet texture + D3D11_TEXTURE2D_DESC textureDesc; + ID3D11Texture2D *pTexture; + + ZeroMemory(&textureDesc, sizeof(textureDesc)); + textureDesc.Width = m_sheetWidth; + textureDesc.Height = m_sheetHeight; + textureDesc.ArraySize = 1; + textureDesc.Format = DXGI_FORMAT_R8_UNORM; + textureDesc.SampleDesc.Count = 1; + textureDesc.Usage = D3D11_USAGE_DEFAULT; + textureDesc.MipLevels = m_mipLevelCount; + textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + + HRESULT hResult = m_pDevice->CreateTexture2D(&textureDesc, NULL, &pTexture); + if(FAILED(hResult)) { + m_lastError = L"Failed to create glyph sheet texture"; + } + else { + ID3D11ShaderResourceView *pTextureSRV; + + hResult = m_pDevice->CreateShaderResourceView(pTexture, NULL, &pTextureSRV); + if(FAILED(hResult)) { + m_lastError = L"Failed to create shader resource view for glyph sheet texture"; + } + else { + // Create coord buffer if enabled + if(m_hardwareCoordBuffer) { + D3D11_BUFFER_DESC bufferDesc; + ID3D11Buffer *pBuffer; + + ZeroMemory(&bufferDesc, sizeof(bufferDesc)); + bufferDesc.ByteWidth = m_maxGlyphCount * sizeof(FW1_GLYPHCOORDS); + bufferDesc.Usage = D3D11_USAGE_DEFAULT; + bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + + hResult = m_pDevice->CreateBuffer(&bufferDesc, NULL, &pBuffer); + if(FAILED(hResult)) { + m_lastError = L"Failed to create glyph coord buffer"; + } + else { + D3D11_SHADER_RESOURCE_VIEW_DESC bufferSRVDesc; + ID3D11ShaderResourceView *pBufferSRV; + + ZeroMemory(&bufferSRVDesc, sizeof(bufferSRVDesc)); + bufferSRVDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + bufferSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + bufferSRVDesc.Buffer.ElementOffset = 0; + bufferSRVDesc.Buffer.ElementWidth = m_maxGlyphCount * 2;// Two float4 per glyphcoords + + hResult = m_pDevice->CreateShaderResourceView(pBuffer, &bufferSRVDesc, &pBufferSRV); + if(FAILED(hResult)) { + m_lastError = L"Failed to create shader resource view for glyph coord buffer"; + } + else { + m_pCoordBuffer = pBuffer; + m_pCoordBufferSRV = pBufferSRV; + } + + if(FAILED(hResult)) + pBuffer->Release(); + } + } + + if(SUCCEEDED(hResult)) { + m_pTexture = pTexture; + m_pTextureSRV = pTextureSRV; + } + else + pTextureSRV->Release(); + } + + if(FAILED(hResult)) + pTexture->Release(); + } + + return hResult; +} + + +// Height-range helper class, used to fit glyphs in the sheet + +CFW1GlyphSheet::HeightRange::HeightRange(UINT totalWidth) : m_totalWidth(totalWidth) { + m_heights = new UINT[m_totalWidth]; + ZeroMemory(m_heights, m_totalWidth * sizeof(UINT)); +} + +CFW1GlyphSheet::HeightRange::~HeightRange() { + delete[] m_heights; +} + +UINT CFW1GlyphSheet::HeightRange::findMin(UINT width, UINT *outMin) { + if(width > m_totalWidth) + width = m_totalWidth; + + UINT currentMax = findMax(0, width); + UINT currentMin = currentMax; + UINT minX = 0; + + for(UINT i=1; i < m_totalWidth-width; ++i) { + if(m_heights[i+width-1] >= currentMax) + currentMax = m_heights[i+width-1]; + else if(m_heights[i-1] == currentMax) { + currentMax = findMax(i, width); + if(currentMax < currentMin) { + currentMin = currentMax; + minX = i; + } + } + } + + *outMin = currentMin; + return minX; +} + +void CFW1GlyphSheet::HeightRange::update(UINT startX, UINT width, UINT newHeight) { + if(width > m_totalWidth) + width = m_totalWidth; + + for(UINT i=0; i < width; ++i) + m_heights[startX+i] = newHeight; +} + +UINT CFW1GlyphSheet::HeightRange::findMax(UINT startX, UINT width) { + UINT currentMax = m_heights[startX]; + for(UINT i=1; i < width; ++i) + currentMax = std::max(currentMax, m_heights[startX+i]); + + return currentMax; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphSheet.h b/no_renderer/FW1FontWrapper/CFW1GlyphSheet.h new file mode 100644 index 0000000..8663a0b --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphSheet.h @@ -0,0 +1,141 @@ +// CFW1GlyphSheet.h + +#ifndef IncludeGuard__FW1_CFW1GlyphSheet +#define IncludeGuard__FW1_CFW1GlyphSheet + +#include "CFW1Object.h" + + +namespace FW1FontWrapper { + + +// A texture containing multiple glyphimages +class CFW1GlyphSheet : public CFW1Object { + public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + // IFW1GlyphSheet + virtual HRESULT STDMETHODCALLTYPE GetDevice(ID3D11Device **ppDevice); + virtual void STDMETHODCALLTYPE GetDesc(FW1_GLYPHSHEETDESC *pDesc); + + virtual HRESULT STDMETHODCALLTYPE GetSheetTexture(ID3D11ShaderResourceView **ppSheetTextureSRV); + virtual HRESULT STDMETHODCALLTYPE GetCoordBuffer(ID3D11ShaderResourceView **ppCoordBufferSRV); + + virtual const FW1_GLYPHCOORDS* STDMETHODCALLTYPE GetGlyphCoords(); + virtual HRESULT STDMETHODCALLTYPE BindSheet(ID3D11DeviceContext *pContext, UINT Flags); + + virtual UINT STDMETHODCALLTYPE InsertGlyph( + const FW1_GLYPHMETRICS *pGlyphMetrics, + const void *pGlyphData, + UINT RowPitch, + UINT PixelStride + ); + virtual void STDMETHODCALLTYPE CloseSheet(); + virtual void STDMETHODCALLTYPE Flush(ID3D11DeviceContext *pContext); + + // Public functions + public: + CFW1GlyphSheet(); + + HRESULT initGlyphSheet( + IFW1Factory *pFW1Factory, + ID3D11Device *pDevice, + UINT sheetWidth, + UINT sheetHeight, + bool coordBuffer, + bool allowOversizedGlyph, + UINT maxGlyphCount, + UINT mipLevelCount + ); + + // Internal types + private: + struct RectUI { + UINT left; + UINT top; + UINT right; + UINT bottom; + }; + + class HeightRange { + public: + HeightRange(UINT totalWidth); + ~HeightRange(); + + UINT findMin(UINT width, UINT *outMin); + void update(UINT startX, UINT width, UINT newHeight); + + private: + HeightRange(); + HeightRange(const HeightRange&); + HeightRange& operator=(const HeightRange&); + + UINT findMax(UINT startX, UINT width); + + UINT *m_heights; + UINT m_totalWidth; + }; + + class CriticalSectionLock { + public: + CriticalSectionLock(LPCRITICAL_SECTION pCriticalSection) : m_pCriticalSection(pCriticalSection) { + EnterCriticalSection(m_pCriticalSection); + } + ~CriticalSectionLock() { + LeaveCriticalSection(m_pCriticalSection); + } + + private: + CriticalSectionLock(); + CriticalSectionLock(const CriticalSectionLock&); + CriticalSectionLock& operator=(const CriticalSectionLock&); + + LPCRITICAL_SECTION m_pCriticalSection; + }; + + // Internal functions + private: + virtual ~CFW1GlyphSheet(); + + HRESULT createDeviceResources(); + + // Internal data + private: + std::wstring m_lastError; + + UINT m_sheetWidth; + UINT m_sheetHeight; + bool m_hardwareCoordBuffer; + bool m_allowOversizedGlyph; + UINT m_mipLevelCount; + UINT m_alignWidth; + + UINT8 *m_textureData; + FW1_GLYPHCOORDS *m_glyphCoords; + UINT m_maxGlyphCount; + UINT m_glyphCount; + + ID3D11Device *m_pDevice; + + ID3D11Texture2D *m_pTexture; + ID3D11ShaderResourceView *m_pTextureSRV; + ID3D11Buffer *m_pCoordBuffer; + ID3D11ShaderResourceView *m_pCoordBufferSRV; + + bool m_closed; + bool m_static; + + HeightRange *m_heightRange; + + UINT m_updatedGlyphCount; + RectUI m_dirtyRect; + CRITICAL_SECTION m_sheetCriticalSection; + CRITICAL_SECTION m_flushCriticalSection; +}; + + +}// namespace FW1FontWrapper + + +#endif// IncludeGuard__FW1_CFW1GlyphSheet diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphSheetInterface.cpp b/no_renderer/FW1FontWrapper/CFW1GlyphSheetInterface.cpp new file mode 100644 index 0000000..ad72017 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphSheetInterface.cpp @@ -0,0 +1,311 @@ +// CFW1GlyphSheetInterface.cpp + +#include "FW1Precompiled.h" + +#include "CFW1GlyphSheet.h" + + +namespace FW1FontWrapper { + + +// Query interface +HRESULT STDMETHODCALLTYPE CFW1GlyphSheet::QueryInterface(REFIID riid, void **ppvObject) { + if(ppvObject == NULL) + return E_INVALIDARG; + + if(IsEqualIID(riid, __uuidof(IFW1GlyphSheet))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + + return CFW1Object::QueryInterface(riid, ppvObject); +} + + +// Get the D3D11 device used by this sheet +HRESULT STDMETHODCALLTYPE CFW1GlyphSheet::GetDevice(ID3D11Device **ppDevice) { + if(ppDevice == NULL) + return E_INVALIDARG; + + m_pDevice->AddRef(); + *ppDevice = m_pDevice; + + return S_OK; +} + + +// Get sheet desc +void STDMETHODCALLTYPE CFW1GlyphSheet::GetDesc(FW1_GLYPHSHEETDESC *pDesc) { + pDesc->GlyphCount = m_glyphCount; + pDesc->Width = m_sheetWidth; + pDesc->Height = m_sheetHeight; + pDesc->MipLevels = m_mipLevelCount; +} + + +// Get the sheet texture +HRESULT STDMETHODCALLTYPE CFW1GlyphSheet::GetSheetTexture(ID3D11ShaderResourceView **ppSheetTextureSRV) { + if(ppSheetTextureSRV == NULL) + return E_INVALIDARG; + + m_pTextureSRV->AddRef(); + *ppSheetTextureSRV = m_pTextureSRV; + + return S_OK; +} + + +// Get the glyph coordinate buffer +HRESULT STDMETHODCALLTYPE CFW1GlyphSheet::GetCoordBuffer(ID3D11ShaderResourceView **ppCoordBufferSRV) { + if(ppCoordBufferSRV == NULL) + return E_INVALIDARG; + + if(m_pCoordBufferSRV != NULL) + m_pCoordBufferSRV->AddRef(); + *ppCoordBufferSRV = m_pCoordBufferSRV; + + return S_OK; +} + + +// Get glyph coordinate array for all glyphs in the sheet +const FW1_GLYPHCOORDS* STDMETHODCALLTYPE CFW1GlyphSheet::GetGlyphCoords() { + return m_glyphCoords; +} + + +// Set sheet shader resources +HRESULT STDMETHODCALLTYPE CFW1GlyphSheet::BindSheet(ID3D11DeviceContext *pContext, UINT Flags) { + pContext->PSSetShaderResources(0, 1, &m_pTextureSRV); + if((Flags & FW1_NOGEOMETRYSHADER) == 0 && m_hardwareCoordBuffer) + pContext->GSSetShaderResources(0, 1, &m_pCoordBufferSRV); + + return S_OK; +} + + +// Insert a new glyph in the sheet +UINT STDMETHODCALLTYPE CFW1GlyphSheet::InsertGlyph( + const FW1_GLYPHMETRICS *pGlyphMetrics, + LPCVOID pGlyphData, + UINT RowPitch, + UINT PixelStride +) { + if(m_closed) + return 0xffffffff; + if(m_glyphCount >= m_maxGlyphCount) + return 0xffffffff; + + CriticalSectionLock lock(&m_sheetCriticalSection); + + if(m_closed) + return 0xffffffff; + if(m_glyphCount >= m_maxGlyphCount) + return 0xffffffff; + + const UINT &width = pGlyphMetrics->Width; + const UINT &height = pGlyphMetrics->Height; + + // Position the glyph if it fits + UINT blockWidth = width / m_alignWidth + 1; + if(width % m_alignWidth != 0) + ++blockWidth; + UINT blockHeight = height / m_alignWidth + 1; + if(height % m_alignWidth != 0) + ++blockHeight; + + UINT blockX; + UINT blockY; + UINT positionX; + UINT positionY; + + if(m_glyphCount > 0 || !m_allowOversizedGlyph) { + if(m_alignWidth + width + m_alignWidth > m_sheetWidth) + return 0xffffffff; + + // Position the glyph at the lowest Y possible (fills reasonably well with different sized glyphs) + blockX = m_heightRange->findMin(blockWidth, &blockY); + + positionX = m_alignWidth + blockX * m_alignWidth; + positionY = m_alignWidth + blockY * m_alignWidth; + + if(positionY + height + m_alignWidth > m_sheetHeight) + return 0xffffffff; + } + else { + blockX = 0; + blockY = 0; + + positionX = m_alignWidth; + positionY = m_alignWidth; + } + + m_heightRange->update(blockX, blockWidth, blockY + blockHeight); + + // Store glyph coordinates + FLOAT coordOffset = static_cast(m_alignWidth) * 0.5f; + + UINT alignedWidth = (blockWidth - 1) * m_alignWidth; + UINT alignedHeight = (blockHeight - 1) * m_alignWidth; + + FW1_GLYPHCOORDS glyphCoords; + glyphCoords.TexCoordLeft = (static_cast(positionX) - coordOffset) / static_cast(m_sheetWidth); + glyphCoords.TexCoordTop = (static_cast(positionY) - coordOffset) / static_cast(m_sheetHeight); + glyphCoords.TexCoordRight = + (static_cast(positionX + alignedWidth) + coordOffset) / static_cast(m_sheetWidth); + glyphCoords.TexCoordBottom = + (static_cast(positionY + alignedHeight) + coordOffset) / static_cast(m_sheetHeight); + glyphCoords.PositionLeft = pGlyphMetrics->OffsetX - coordOffset; + glyphCoords.PositionTop = pGlyphMetrics->OffsetY - coordOffset; + glyphCoords.PositionRight = pGlyphMetrics->OffsetX + static_cast(alignedWidth) + coordOffset; + glyphCoords.PositionBottom = pGlyphMetrics->OffsetY + static_cast(alignedHeight) + coordOffset; + + UINT glyphIndex = m_glyphCount; + + m_glyphCoords[glyphIndex] = glyphCoords; + + // Glyph pixels + for(UINT i=0; i < height && i < m_sheetHeight-positionY; ++i) { + const UINT8 *src = static_cast(pGlyphData) + i*RowPitch; + UINT8 *dst = m_textureData + (positionY+i)*m_sheetWidth + positionX; + for(UINT j=0; j < width && j < m_sheetWidth-positionX; ++j) + dst[j] = src[j*PixelStride]; + } + + // Update dirty rect to be flushed to device texture + if(m_updatedGlyphCount == 0) { + m_dirtyRect.left = positionX - m_alignWidth; + m_dirtyRect.top = positionY - m_alignWidth; + m_dirtyRect.right = std::min(positionX + width + m_alignWidth, m_sheetWidth); + m_dirtyRect.bottom = std::min(positionY + height + m_alignWidth, m_sheetHeight); + } + else { + m_dirtyRect.left = std::min(m_dirtyRect.left, positionX - m_alignWidth); + m_dirtyRect.top = std::min(m_dirtyRect.top, positionY - m_alignWidth); + m_dirtyRect.right = std::min(std::max(m_dirtyRect.right, positionX + width + m_alignWidth), m_sheetWidth); + m_dirtyRect.bottom = std::min(std::max(m_dirtyRect.bottom, positionY + height + m_alignWidth), m_sheetHeight); + } + + _WriteBarrier(); + MemoryBarrier(); + + ++m_glyphCount; + ++m_updatedGlyphCount; + + return glyphIndex; +} + + +// Disallow insertion of additional glyphs in this sheet +void STDMETHODCALLTYPE CFW1GlyphSheet::CloseSheet() { + EnterCriticalSection(&m_sheetCriticalSection); + m_closed = true; + LeaveCriticalSection(&m_sheetCriticalSection); +} + + +// Flush any inserted glyphs +void STDMETHODCALLTYPE CFW1GlyphSheet::Flush(ID3D11DeviceContext *pContext) { + EnterCriticalSection(&m_flushCriticalSection); + if(!m_static) { + EnterCriticalSection(&m_sheetCriticalSection); + + UINT glyphCount = m_glyphCount; + RectUI dirtyRect = m_dirtyRect; + + UINT updatedGlyphCount = m_updatedGlyphCount; + m_updatedGlyphCount = 0; + + if(m_closed) + m_static = true; + + LeaveCriticalSection(&m_sheetCriticalSection); + + if(updatedGlyphCount > 0) { + // Update coord buffer + if(m_hardwareCoordBuffer) { + UINT startIndex = glyphCount - updatedGlyphCount; + UINT endIndex = glyphCount; + + D3D11_BOX dstBox; + ZeroMemory(&dstBox, sizeof(dstBox)); + dstBox.left = startIndex * sizeof(FW1_GLYPHCOORDS); + dstBox.right = endIndex * sizeof(FW1_GLYPHCOORDS); + dstBox.top = 0; + dstBox.bottom = 1; + dstBox.front = 0; + dstBox.back = 1; + + pContext->UpdateSubresource( + m_pCoordBuffer, + 0, + &dstBox, + m_glyphCoords + startIndex, + 0, + 0 + ); + } + + // Update texture + if(dirtyRect.right > dirtyRect.left && dirtyRect.bottom > dirtyRect.top) { + UINT8 *srcMem = m_textureData; + + D3D11_BOX dstBox; + ZeroMemory(&dstBox, sizeof(dstBox)); + dstBox.left = dirtyRect.left; + dstBox.right = dirtyRect.right; + dstBox.top = dirtyRect.top; + dstBox.bottom = dirtyRect.bottom; + dstBox.front = 0; + dstBox.back = 1; + + // Update each mip-level + for(UINT i=0; i < m_mipLevelCount; ++i) { + pContext->UpdateSubresource( + m_pTexture, + D3D11CalcSubresource(i, 0, m_mipLevelCount), + &dstBox, + srcMem + dstBox.top * (m_sheetWidth >> i) + dstBox.left, + m_sheetWidth >> i, + 0 + ); + + if(i+1 < m_mipLevelCount) { + UINT8 *nextMip = srcMem + (m_sheetWidth >> i) * (m_sheetHeight >> i); + + dstBox.left >>= 1; + dstBox.right >>= 1; + dstBox.top >>= 1; + dstBox.bottom >>= 1; + + // Calculate the next mip-level for the current dirty-rect + for(UINT j = dstBox.top; j < dstBox.bottom; ++j) { + const UINT8 *src0 = srcMem + j * 2 * (m_sheetWidth >> i); + const UINT8 *src1 = src0 + (m_sheetWidth >> i); + UINT8 *dst = nextMip + j * (m_sheetWidth >> (i+1)); + + for(UINT k = dstBox.left; k < dstBox.right; ++k) { + UINT src = src0[k*2] + src0[k*2+1] + src1[k*2] + src1[k*2+1]; + dst[k] = static_cast(src >> 2); + } + } + + srcMem = nextMip; + } + } + } + } + + // This sheet is now static, save some memory + if(m_static) { + delete[] m_textureData; + m_textureData = 0; + } + } + + LeaveCriticalSection(&m_flushCriticalSection); +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphVertexDrawer.cpp b/no_renderer/FW1FontWrapper/CFW1GlyphVertexDrawer.cpp new file mode 100644 index 0000000..f058469 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphVertexDrawer.cpp @@ -0,0 +1,314 @@ +// CFW1GlyphVertexDrawer.cpp + +#include "FW1Precompiled.h" + +#include "CFW1GlyphVertexDrawer.h" + +#define SAFE_RELEASE(pObject) { if(pObject) { (pObject)->Release(); (pObject) = NULL; } } + + +namespace FW1FontWrapper { + + +// Construct +CFW1GlyphVertexDrawer::CFW1GlyphVertexDrawer() : + m_pDevice(NULL), + + m_pVertexBuffer(NULL), + m_pIndexBuffer(NULL), + m_vertexBufferSize(0), + m_maxIndexCount(0) +{ +} + + +// Destruct +CFW1GlyphVertexDrawer::~CFW1GlyphVertexDrawer() { + SAFE_RELEASE(m_pDevice); + + SAFE_RELEASE(m_pVertexBuffer); + SAFE_RELEASE(m_pIndexBuffer); +} + + +// Init +HRESULT CFW1GlyphVertexDrawer::initVertexDrawer( + IFW1Factory *pFW1Factory, + ID3D11Device *pDevice, + UINT vertexBufferSize +) { + HRESULT hResult = initBaseObject(pFW1Factory); + if(FAILED(hResult)) + return hResult; + + if(pDevice == NULL) + return E_INVALIDARG; + + pDevice->AddRef(); + m_pDevice = pDevice; + D3D_FEATURE_LEVEL featureLevel = m_pDevice->GetFeatureLevel(); + + m_vertexBufferSize = 4096 * 16; + if(vertexBufferSize >= 1024) { + if(featureLevel < D3D_FEATURE_LEVEL_9_2) + vertexBufferSize = std::min(vertexBufferSize, 512U*1024U); + m_vertexBufferSize = vertexBufferSize; + } + + m_maxIndexCount = (m_vertexBufferSize * 3) / (2 * sizeof(QuadVertex)); + if(m_maxIndexCount < 64) + m_maxIndexCount = 64; + + // Create device buffers + hResult = createBuffers(); + + if(SUCCEEDED(hResult)) + hResult = S_OK; + + return hResult; +} + + +// Create vertex/index buffers +HRESULT CFW1GlyphVertexDrawer::createBuffers() { + // Create vertex buffer + D3D11_BUFFER_DESC vertexBufferDesc; + ID3D11Buffer *pVertexBuffer; + + ZeroMemory(&vertexBufferDesc, sizeof(vertexBufferDesc)); + vertexBufferDesc.ByteWidth = m_vertexBufferSize; + vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + + HRESULT hResult = m_pDevice->CreateBuffer(&vertexBufferDesc, NULL, &pVertexBuffer); + if(FAILED(hResult)) { + m_lastError = L"Failed to create vertex buffer"; + } + else { + // Create index buffer + D3D11_BUFFER_DESC indexBufferDesc; + D3D11_SUBRESOURCE_DATA initData; + ID3D11Buffer *pIndexBuffer; + + ZeroMemory(&indexBufferDesc, sizeof(indexBufferDesc)); + indexBufferDesc.ByteWidth = sizeof(UINT16) * m_maxIndexCount; + indexBufferDesc.Usage = D3D11_USAGE_IMMUTABLE; + indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + + UINT16 *indices = new UINT16[m_maxIndexCount]; + for(UINT i=0; i < m_maxIndexCount/6; ++i) { + indices[i*6] = static_cast(i*4); + indices[i*6+1] = static_cast(i*4+1); + indices[i*6+2] = static_cast(i*4+2); + indices[i*6+3] = static_cast(i*4+1); + indices[i*6+4] = static_cast(i*4+3); + indices[i*6+5] = static_cast(i*4+2); + } + + ZeroMemory(&initData, sizeof(initData)); + initData.pSysMem = indices; + + hResult = m_pDevice->CreateBuffer(&indexBufferDesc, &initData, &pIndexBuffer); + if(FAILED(hResult)) { + m_lastError = L"Failed to create index buffer"; + } + else { + // Success + m_pVertexBuffer = pVertexBuffer; + m_pIndexBuffer = pIndexBuffer; + + hResult = S_OK; + } + + delete[] indices; + + if(FAILED(hResult)) + pVertexBuffer->Release(); + } + + return hResult; +} + + +// Draw vertices +UINT CFW1GlyphVertexDrawer::drawVertices( + ID3D11DeviceContext *pContext, + IFW1GlyphAtlas *pGlyphAtlas, + const FW1_VERTEXDATA *vertexData, + UINT preboundSheet +) { + if(vertexData->SheetCount == 0 || vertexData->TotalVertexCount == 0) + return preboundSheet; + + UINT maxVertexCount = m_vertexBufferSize / sizeof(FW1_GLYPHVERTEX); + + UINT currentSheet = 0; + UINT activeSheet = preboundSheet; + UINT currentVertex = 0; + UINT nextSheetStart = vertexData->pVertexCounts[0]; + + while(currentVertex < vertexData->TotalVertexCount) { + // Fill the vertex buffer + UINT vertexCount = std::min(vertexData->TotalVertexCount - currentVertex, maxVertexCount); + + D3D11_MAPPED_SUBRESOURCE msr; + HRESULT hResult = pContext->Map(m_pVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &msr); + if(SUCCEEDED(hResult)) { + CopyMemory(msr.pData, vertexData->pVertices + currentVertex, vertexCount * sizeof(FW1_GLYPHVERTEX)); + + pContext->Unmap(m_pVertexBuffer, 0); + + // Draw all glyphs in the buffer + UINT drawnVertices = 0; + while(drawnVertices < vertexCount) { + while(currentVertex >= nextSheetStart) { + ++currentSheet; + nextSheetStart += vertexData->pVertexCounts[currentSheet]; + } + + if(currentSheet != activeSheet) { + // Bind sheet shader resources + pGlyphAtlas->BindSheet(pContext, currentSheet, 0); + activeSheet = currentSheet; + } + + UINT drawCount = std::min(vertexCount - drawnVertices, nextSheetStart - currentVertex); + pContext->Draw(drawCount, drawnVertices); + + drawnVertices += drawCount; + currentVertex += drawCount; + } + } + else + break; + } + + return activeSheet; +} + + +// Draw vertices as quads +UINT CFW1GlyphVertexDrawer::drawGlyphsAsQuads( + ID3D11DeviceContext *pContext, + IFW1GlyphAtlas *pGlyphAtlas, + const FW1_VERTEXDATA *vertexData, + UINT preboundSheet +) { + if(vertexData->SheetCount == 0 || vertexData->TotalVertexCount == 0) + return preboundSheet; + + UINT maxVertexCount = m_vertexBufferSize / sizeof(QuadVertex); + if(maxVertexCount > 4 * (m_maxIndexCount / 6)) + maxVertexCount = 4 * (m_maxIndexCount / 6); + if(maxVertexCount % 4 != 0) + maxVertexCount -= (maxVertexCount % 4); + + UINT currentSheet = 0; + UINT activeSheet = preboundSheet; + const FW1_GLYPHCOORDS *sheetGlyphCoords = 0; + if(activeSheet < vertexData->SheetCount) + sheetGlyphCoords = pGlyphAtlas->GetGlyphCoords(activeSheet); + UINT currentVertex = 0; + UINT nextSheetStart = vertexData->pVertexCounts[0]; + + while(currentVertex < vertexData->TotalVertexCount) { + // Fill the vertex buffer + UINT vertexCount = std::min((vertexData->TotalVertexCount - currentVertex) * 4, maxVertexCount); + + D3D11_MAPPED_SUBRESOURCE msr; + HRESULT hResult = pContext->Map(m_pVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &msr); + if(SUCCEEDED(hResult)) { + QuadVertex *bufferVertices = static_cast(msr.pData); + + // Convert to quads when filling the buffer + UINT savedCurrentSheet = currentSheet; + UINT savedActiveSheet = activeSheet; + UINT savedNextSheetStart = nextSheetStart; + UINT savedCurrentVertex = currentVertex; + + UINT drawnVertices = 0; + while(drawnVertices < vertexCount) { + while(currentVertex >= nextSheetStart) { + ++currentSheet; + nextSheetStart += vertexData->pVertexCounts[currentSheet]; + } + + if(currentSheet != activeSheet) { + sheetGlyphCoords = pGlyphAtlas->GetGlyphCoords(currentSheet); + activeSheet = currentSheet; + } + + UINT drawCount = std::min(vertexCount - drawnVertices, (nextSheetStart - currentVertex) * 4); + + for(UINT i=0; i < drawCount/4; ++i) { + FW1_GLYPHVERTEX glyphVertex = vertexData->pVertices[currentVertex + i]; + glyphVertex.PositionX = glyphVertex.PositionX; + glyphVertex.PositionY = glyphVertex.PositionY; + + const FW1_GLYPHCOORDS &glyphCoords = sheetGlyphCoords[glyphVertex.GlyphIndex]; + + QuadVertex quadVertex; + + quadVertex.color = glyphVertex.GlyphColor; + + quadVertex.positionX = glyphVertex.PositionX + glyphCoords.PositionLeft; + quadVertex.positionY = glyphVertex.PositionY + glyphCoords.PositionTop; + quadVertex.texCoordX = glyphCoords.TexCoordLeft; + quadVertex.texCoordY = glyphCoords.TexCoordTop; + bufferVertices[drawnVertices + i*4 + 0] = quadVertex; + + quadVertex.positionX = glyphVertex.PositionX + glyphCoords.PositionRight; + quadVertex.texCoordX = glyphCoords.TexCoordRight; + bufferVertices[drawnVertices + i*4 + 1] = quadVertex; + + quadVertex.positionY = glyphVertex.PositionY + glyphCoords.PositionBottom; + quadVertex.texCoordY = glyphCoords.TexCoordBottom; + bufferVertices[drawnVertices + i*4 + 3] = quadVertex; + + quadVertex.positionX = glyphVertex.PositionX + glyphCoords.PositionLeft; + quadVertex.texCoordX = glyphCoords.TexCoordLeft; + bufferVertices[drawnVertices + i*4 + 2] = quadVertex; + } + + drawnVertices += drawCount; + currentVertex += drawCount / 4; + } + + pContext->Unmap(m_pVertexBuffer, 0); + + // Draw all glyphs in the buffer + currentSheet = savedCurrentSheet; + activeSheet = savedActiveSheet; + nextSheetStart = savedNextSheetStart; + currentVertex = savedCurrentVertex; + + drawnVertices = 0; + while(drawnVertices < vertexCount) { + while(currentVertex >= nextSheetStart) { + ++currentSheet; + nextSheetStart += vertexData->pVertexCounts[currentSheet]; + } + + if(currentSheet != activeSheet) { + // Bind sheet shader resources + pGlyphAtlas->BindSheet(pContext, currentSheet, FW1_NOGEOMETRYSHADER); + activeSheet = currentSheet; + } + + UINT drawCount = std::min(vertexCount - drawnVertices, (nextSheetStart - currentVertex) * 4); + pContext->DrawIndexed((drawCount/2)*3, 0, drawnVertices); + + drawnVertices += drawCount; + currentVertex += drawCount / 4; + } + } + else + break; + } + + return activeSheet; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphVertexDrawer.h b/no_renderer/FW1FontWrapper/CFW1GlyphVertexDrawer.h new file mode 100644 index 0000000..d980c71 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphVertexDrawer.h @@ -0,0 +1,80 @@ +// CFW1GlyphVertexDrawer.h + +#ifndef IncludeGuard__FW1_CFW1GlyphVertexDrawer +#define IncludeGuard__FW1_CFW1GlyphVertexDrawer + +#include "CFW1Object.h" + + +namespace FW1FontWrapper { + + +// Draws glyph-vertices from system memory using a dynamic vertex buffer +class CFW1GlyphVertexDrawer : public CFW1Object { + public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + // IFW1GlyphVertexDrawer + virtual HRESULT STDMETHODCALLTYPE GetDevice(ID3D11Device **ppDevice); + + virtual UINT STDMETHODCALLTYPE DrawVertices( + ID3D11DeviceContext *pContext, + IFW1GlyphAtlas *pGlyphAtlas, + const FW1_VERTEXDATA *pVertexData, + UINT Flags, + UINT PreboundSheet + ); + + // Public functions + public: + CFW1GlyphVertexDrawer(); + + HRESULT initVertexDrawer(IFW1Factory *pFW1Factory, ID3D11Device *pDevice, UINT vertexBufferSize); + + // Internal types + private: + struct QuadVertex { + FLOAT positionX; + FLOAT positionY; + FLOAT texCoordX; + FLOAT texCoordY; + UINT32 color; + }; + + // Internal functions + private: + virtual ~CFW1GlyphVertexDrawer(); + + HRESULT createBuffers(); + + UINT drawVertices( + ID3D11DeviceContext *pContext, + IFW1GlyphAtlas *pGlyphAtlas, + const FW1_VERTEXDATA *vertexData, + UINT preboundSheet + ); + UINT drawGlyphsAsQuads( + ID3D11DeviceContext *pContext, + IFW1GlyphAtlas *pGlyphAtlas, + const FW1_VERTEXDATA *vertexData, + UINT preboundSheet + ); + + // Internal data + private: + std::wstring m_lastError; + + ID3D11Device *m_pDevice; + + ID3D11Buffer *m_pVertexBuffer; + ID3D11Buffer *m_pIndexBuffer; + UINT m_vertexBufferSize; + UINT m_maxIndexCount; +}; + + +}// namespace FW1FontWrapper + + +#endif// IncludeGuard__FW1_CFW1GlyphVertexDrawer diff --git a/no_renderer/FW1FontWrapper/CFW1GlyphVertexDrawerInterface.cpp b/no_renderer/FW1FontWrapper/CFW1GlyphVertexDrawerInterface.cpp new file mode 100644 index 0000000..2e49bbc --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1GlyphVertexDrawerInterface.cpp @@ -0,0 +1,66 @@ +// CFW1GlyphVertexDrawerInterface.cpp + +#include "FW1Precompiled.h" + +#include "CFW1GlyphVertexDrawer.h" + + +namespace FW1FontWrapper { + + +// Query interface +HRESULT STDMETHODCALLTYPE CFW1GlyphVertexDrawer::QueryInterface(REFIID riid, void **ppvObject) { + if(ppvObject == NULL) + return E_INVALIDARG; + + if(IsEqualIID(riid, __uuidof(IFW1GlyphVertexDrawer))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + + return CFW1Object::QueryInterface(riid, ppvObject); +} + + +// Get the D3D11 device used by this vetex drawer +HRESULT STDMETHODCALLTYPE CFW1GlyphVertexDrawer::GetDevice(ID3D11Device **ppDevice) { + if(ppDevice == NULL) + return E_INVALIDARG; + + m_pDevice->AddRef(); + *ppDevice = m_pDevice; + + return S_OK; +} + + +// Draw vertices +UINT STDMETHODCALLTYPE CFW1GlyphVertexDrawer::DrawVertices( + ID3D11DeviceContext *pContext, + IFW1GlyphAtlas *pGlyphAtlas, + const FW1_VERTEXDATA *pVertexData, + UINT Flags, + UINT PreboundSheet +) { + UINT stride; + UINT offset = 0; + + if((Flags & FW1_NOGEOMETRYSHADER) == 0) + stride = sizeof(FW1_GLYPHVERTEX); + else { + stride = sizeof(QuadVertex); + if((Flags & FW1_BUFFERSPREPARED) == 0) + pContext->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0); + } + if((Flags & FW1_BUFFERSPREPARED) == 0) + pContext->IASetVertexBuffers(0, 1, &m_pVertexBuffer, &stride, &offset); + + if((Flags & FW1_NOGEOMETRYSHADER) == 0) + return drawVertices(pContext, pGlyphAtlas, pVertexData, PreboundSheet); + else + return drawGlyphsAsQuads(pContext, pGlyphAtlas, pVertexData, PreboundSheet); +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1Object.h b/no_renderer/FW1FontWrapper/CFW1Object.h new file mode 100644 index 0000000..99b7183 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1Object.h @@ -0,0 +1,98 @@ +// CFW1Object.h + +#ifndef IncludeGuard__FW1_CFW1Object +#define IncludeGuard__FW1_CFW1Object + + +namespace FW1FontWrapper { + + +// Helper baseclass to avoid writing IUnknown and IFW1Object implementations once per class +template +class CFW1Object : public IBase { + public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) = 0 { + if(ppvObject == NULL) + return E_INVALIDARG; + + if(IsEqualIID(riid, __uuidof(IUnknown))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + else if(IsEqualIID(riid, __uuidof(IFW1Object))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + + *ppvObject = NULL; + return E_NOINTERFACE; + } + + virtual ULONG STDMETHODCALLTYPE AddRef() { + return static_cast(InterlockedIncrement(reinterpret_cast(&m_cRefCount))); + } + + virtual ULONG STDMETHODCALLTYPE Release() { + ULONG newCount = static_cast(InterlockedDecrement(reinterpret_cast(&m_cRefCount))); + + if(newCount == 0) + delete this; + + return newCount; + } + + // IFW1Object + virtual HRESULT STDMETHODCALLTYPE GetFactory(IFW1Factory **ppFW1Factory) { + if(ppFW1Factory == NULL) + return E_INVALIDARG; + + m_pFW1Factory->AddRef(); + *ppFW1Factory = m_pFW1Factory; + + return S_OK; + } + + // Internal functions + protected: + CFW1Object() : + m_cRefCount(1), + + m_pFW1Factory(NULL) + { + } + + virtual ~CFW1Object() { + if(m_pFW1Factory != NULL) + m_pFW1Factory->Release(); + } + + HRESULT initBaseObject(IFW1Factory *pFW1Factory) { + if(pFW1Factory == NULL) + return E_INVALIDARG; + + pFW1Factory->AddRef(); + m_pFW1Factory = pFW1Factory; + + return S_OK; + } + + // Internal data + protected: + IFW1Factory *m_pFW1Factory; + + private: + ULONG m_cRefCount; + + private: + CFW1Object(const CFW1Object&); + CFW1Object& operator=(const CFW1Object&); +}; + + +}// namespace FW1FontWrapper + + +#endif// IncludeGuard__FW1_CFW1Object diff --git a/no_renderer/FW1FontWrapper/CFW1StateSaver.cpp b/no_renderer/FW1FontWrapper/CFW1StateSaver.cpp new file mode 100644 index 0000000..0ce8165 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1StateSaver.cpp @@ -0,0 +1,216 @@ +// CFW1StateSaver.cpp + +#include "FW1Precompiled.h" + +#include "CFW1StateSaver.h" + +#define SAFE_RELEASE(pObject) { if(pObject) { (pObject)->Release(); (pObject) = NULL; } } + + +namespace FW1FontWrapper { + + +// Construct +CFW1StateSaver::CFW1StateSaver() : + m_savedState(false), + m_featureLevel(D3D_FEATURE_LEVEL_11_0), + m_pContext(NULL), + m_primitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED), + m_pInputLayout(NULL), + m_pBlendState(NULL), + m_sampleMask(0xffffffff), + m_pDepthStencilState(NULL), + m_stencilRef(0), + m_pRasterizerState(NULL), + m_pPSSRV(NULL), + m_pSamplerState(NULL), + m_pVS(NULL), + m_numVSClassInstances(0), + m_pVSConstantBuffer(NULL), + m_pGS(NULL), + m_numGSClassInstances(0), + m_pGSConstantBuffer(NULL), + m_pGSSRV(NULL), + m_pPS(NULL), + m_numPSClassInstances(0), + m_pHS(NULL), + m_numHSClassInstances(0), + m_pDS(NULL), + m_numDSClassInstances(0), + m_pVB(NULL), + m_vertexStride(0), + m_vertexOffset(0), + m_pIndexBuffer(NULL), + m_indexFormat(DXGI_FORMAT_UNKNOWN), + m_indexOffset(0) +{ + for(int i=0; i < 4; ++i) + m_blendFactor[i] = 0.0f; + for(int i=0; i < 256; ++i) { + m_pVSClassInstances[i] = NULL; + m_pGSClassInstances[i] = NULL; + m_pPSClassInstances[i] = NULL; + m_pHSClassInstances[i] = NULL; + m_pDSClassInstances[i] = NULL; + } +} + + +// Destruct +CFW1StateSaver::~CFW1StateSaver() { + releaseSavedState(); +} + + +// Save all states that are changed by the font-wrapper when drawing a string +HRESULT CFW1StateSaver::saveCurrentState(ID3D11DeviceContext *pContext) { + if(m_savedState) + releaseSavedState(); + if(pContext == NULL) + return E_INVALIDARG; + + ID3D11Device *pDevice; + pContext->GetDevice(&pDevice); + if(pDevice != NULL) { + m_featureLevel = pDevice->GetFeatureLevel(); + pDevice->Release(); + } + + pContext->AddRef(); + m_pContext = pContext; + + m_pContext->IAGetPrimitiveTopology(&m_primitiveTopology); + m_pContext->IAGetInputLayout(&m_pInputLayout); + + m_pContext->OMGetBlendState(&m_pBlendState, m_blendFactor, &m_sampleMask); + m_pContext->OMGetDepthStencilState(&m_pDepthStencilState, &m_stencilRef); + + m_pContext->RSGetState(&m_pRasterizerState); + + m_numVSClassInstances = 256; + m_pContext->VSGetShader(&m_pVS, m_pVSClassInstances, &m_numVSClassInstances); + m_pContext->VSGetConstantBuffers(0, 1, &m_pVSConstantBuffer); + + m_numPSClassInstances = 256; + m_pContext->PSGetShader(&m_pPS, m_pPSClassInstances, &m_numPSClassInstances); + m_pContext->PSGetShaderResources(0, 1, &m_pPSSRV); + pContext->PSGetSamplers(0, 1, &m_pSamplerState); + + if(m_featureLevel >= D3D_FEATURE_LEVEL_10_0) { + m_numGSClassInstances = 256; + m_pContext->GSGetShader(&m_pGS, m_pGSClassInstances, &m_numGSClassInstances); + m_pContext->GSGetConstantBuffers(0, 1, &m_pGSConstantBuffer); + + m_pContext->GSGetShaderResources(0, 1, &m_pGSSRV); + + if(m_featureLevel >= D3D_FEATURE_LEVEL_11_0) { + m_numHSClassInstances = 256; + m_pContext->HSGetShader(&m_pHS, m_pHSClassInstances, &m_numHSClassInstances); + + m_numDSClassInstances = 256; + m_pContext->DSGetShader(&m_pDS, m_pDSClassInstances, &m_numDSClassInstances); + } + } + + m_pContext->IAGetVertexBuffers(0, 1, &m_pVB, &m_vertexStride, &m_vertexOffset); + + m_pContext->IAGetIndexBuffer(&m_pIndexBuffer, &m_indexFormat, &m_indexOffset); + + m_savedState = true; + + return S_OK; +} + + +// Restore state +HRESULT CFW1StateSaver::restoreSavedState() { + if(!m_savedState) + return E_FAIL; + + m_pContext->IASetPrimitiveTopology(m_primitiveTopology); + m_pContext->IASetInputLayout(m_pInputLayout); + + m_pContext->OMSetBlendState(m_pBlendState, m_blendFactor, m_sampleMask); + m_pContext->OMSetDepthStencilState(m_pDepthStencilState, m_stencilRef); + + m_pContext->RSSetState(m_pRasterizerState); + + m_pContext->VSSetShader(m_pVS, m_pVSClassInstances, m_numVSClassInstances); + m_pContext->VSSetConstantBuffers(0, 1, &m_pVSConstantBuffer); + + m_pContext->PSSetShader(m_pPS, m_pPSClassInstances, m_numPSClassInstances); + m_pContext->PSSetShaderResources(0, 1, &m_pPSSRV); + m_pContext->PSSetSamplers(0, 1, &m_pSamplerState); + + if(m_featureLevel >= D3D_FEATURE_LEVEL_10_0) { + m_pContext->GSSetShader(m_pGS, m_pGSClassInstances, m_numGSClassInstances); + m_pContext->GSSetConstantBuffers(0, 1, &m_pGSConstantBuffer); + + m_pContext->GSSetShaderResources(0, 1, &m_pGSSRV); + + if(m_featureLevel >= D3D_FEATURE_LEVEL_11_0) { + m_pContext->HSSetShader(m_pHS, m_pHSClassInstances, m_numHSClassInstances); + + m_pContext->DSSetShader(m_pDS, m_pDSClassInstances, m_numDSClassInstances); + } + } + + m_pContext->IASetVertexBuffers(0, 1, &m_pVB, &m_vertexStride, &m_vertexOffset); + + m_pContext->IASetIndexBuffer(m_pIndexBuffer, m_indexFormat, m_indexOffset); + + return S_OK; +} + + +// Release state +void CFW1StateSaver::releaseSavedState() { + m_primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + SAFE_RELEASE(m_pInputLayout); + SAFE_RELEASE(m_pBlendState); + for(int i=0; i < 4; ++i) + m_blendFactor[i] = 0.0f; + m_sampleMask = 0xffffffff; + SAFE_RELEASE(m_pDepthStencilState); + m_stencilRef = 0; + SAFE_RELEASE(m_pRasterizerState); + SAFE_RELEASE(m_pPSSRV); + SAFE_RELEASE(m_pSamplerState); + SAFE_RELEASE(m_pVS); + for(UINT i=0; i < m_numVSClassInstances; ++i) + SAFE_RELEASE(m_pVSClassInstances[i]); + m_numVSClassInstances = 0; + SAFE_RELEASE(m_pVSConstantBuffer); + SAFE_RELEASE(m_pGS); + for(UINT i=0; i < m_numGSClassInstances; ++i) + SAFE_RELEASE(m_pGSClassInstances[i]); + m_numGSClassInstances = 0; + SAFE_RELEASE(m_pGSConstantBuffer); + SAFE_RELEASE(m_pGSSRV); + SAFE_RELEASE(m_pPS); + for(UINT i=0; i < m_numPSClassInstances; ++i) + SAFE_RELEASE(m_pPSClassInstances[i]); + m_numPSClassInstances = 0; + SAFE_RELEASE(m_pHS); + for(UINT i=0; i < m_numHSClassInstances; ++i) + SAFE_RELEASE(m_pHSClassInstances[i]); + m_numHSClassInstances = 0; + SAFE_RELEASE(m_pDS); + for(UINT i=0; i < m_numDSClassInstances; ++i) + SAFE_RELEASE(m_pDSClassInstances[i]); + m_numDSClassInstances = 0; + SAFE_RELEASE(m_pVB); + m_vertexStride = 0; + m_vertexOffset = 0; + SAFE_RELEASE(m_pIndexBuffer); + m_indexFormat = DXGI_FORMAT_UNKNOWN; + m_indexOffset = 0; + + SAFE_RELEASE(m_pContext); + m_featureLevel = D3D_FEATURE_LEVEL_11_0; + + m_savedState = false; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1StateSaver.h b/no_renderer/FW1FontWrapper/CFW1StateSaver.h new file mode 100644 index 0000000..ce27236 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1StateSaver.h @@ -0,0 +1,70 @@ +// CFW1StateSaver.h + +#ifndef IncludeGuard__FW1_CFW1StateSaver +#define IncludeGuard__FW1_CFW1StateSaver + + +namespace FW1FontWrapper { + + +// Saves all the states that can be changed when drawing a string +class CFW1StateSaver { + // Public functions + public: + CFW1StateSaver(); + ~CFW1StateSaver(); + + HRESULT saveCurrentState(ID3D11DeviceContext *pContext); + HRESULT restoreSavedState(); + void releaseSavedState(); + + // Internal data + private: + bool m_savedState; + D3D_FEATURE_LEVEL m_featureLevel; + ID3D11DeviceContext *m_pContext; + D3D11_PRIMITIVE_TOPOLOGY m_primitiveTopology; + ID3D11InputLayout *m_pInputLayout; + ID3D11BlendState *m_pBlendState; + FLOAT m_blendFactor[4]; + UINT m_sampleMask; + ID3D11DepthStencilState *m_pDepthStencilState; + UINT m_stencilRef; + ID3D11RasterizerState *m_pRasterizerState; + ID3D11ShaderResourceView *m_pPSSRV; + ID3D11SamplerState *m_pSamplerState; + ID3D11VertexShader *m_pVS; + ID3D11ClassInstance *m_pVSClassInstances[256]; + UINT m_numVSClassInstances; + ID3D11Buffer *m_pVSConstantBuffer; + ID3D11GeometryShader *m_pGS; + ID3D11ClassInstance *m_pGSClassInstances[256]; + UINT m_numGSClassInstances; + ID3D11Buffer *m_pGSConstantBuffer; + ID3D11ShaderResourceView *m_pGSSRV; + ID3D11PixelShader *m_pPS; + ID3D11ClassInstance *m_pPSClassInstances[256]; + UINT m_numPSClassInstances; + ID3D11HullShader *m_pHS; + ID3D11ClassInstance *m_pHSClassInstances[256]; + UINT m_numHSClassInstances; + ID3D11DomainShader *m_pDS; + ID3D11ClassInstance *m_pDSClassInstances[256]; + UINT m_numDSClassInstances; + ID3D11Buffer *m_pVB; + UINT m_vertexStride; + UINT m_vertexOffset; + ID3D11Buffer *m_pIndexBuffer; + DXGI_FORMAT m_indexFormat; + UINT m_indexOffset; + + private: + CFW1StateSaver(const CFW1StateSaver&); + CFW1StateSaver& operator=(const CFW1StateSaver&); +}; + + +}// namespace FW1FontWrapper + + +#endif// IncludeGuard__FW1_CFW1StateSaver diff --git a/no_renderer/FW1FontWrapper/CFW1TextGeometry.cpp b/no_renderer/FW1FontWrapper/CFW1TextGeometry.cpp new file mode 100644 index 0000000..2dbb2ad --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1TextGeometry.cpp @@ -0,0 +1,34 @@ +// CFW1TextGeometry.cpp + +#include "FW1Precompiled.h" + +#include "CFW1TextGeometry.h" + + +namespace FW1FontWrapper { + + +// Construct +CFW1TextGeometry::CFW1TextGeometry() : + m_maxSheetIndex(0), + m_sorted(false) +{ +} + + +// Destruct +CFW1TextGeometry::~CFW1TextGeometry() { +} + + +// Init glyph provider +HRESULT CFW1TextGeometry::initTextGeometry(IFW1Factory *pFW1Factory) { + HRESULT hResult = initBaseObject(pFW1Factory); + if(FAILED(hResult)) + return hResult; + + return hResult; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1TextGeometry.h b/no_renderer/FW1FontWrapper/CFW1TextGeometry.h new file mode 100644 index 0000000..a7980c5 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1TextGeometry.h @@ -0,0 +1,49 @@ +// CFW1TextGeometry.h + +#ifndef IncludeGuard__FW1_CFW1TextGeometry +#define IncludeGuard__FW1_CFW1TextGeometry + +#include "CFW1Object.h" + + +namespace FW1FontWrapper { + + +// Vector of vertices with sorting per glyph sheet +class CFW1TextGeometry : public CFW1Object { + public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + // IFW1TextGeometry + virtual void STDMETHODCALLTYPE Clear(); + virtual void STDMETHODCALLTYPE AddGlyphVertex(const FW1_GLYPHVERTEX *pVertex); + + virtual FW1_VERTEXDATA STDMETHODCALLTYPE GetGlyphVerticesTemp(); + + // Public functions + public: + CFW1TextGeometry(); + + HRESULT initTextGeometry(IFW1Factory *pFW1Factory); + + // Internal functions + private: + virtual ~CFW1TextGeometry(); + + // Internal data + private: + std::vector m_vertices; + std::vector m_sortedVertices; + + UINT m_maxSheetIndex; + std::vector m_vertexCounts; + std::vector m_vertexStartIndices; + bool m_sorted; +}; + + +}// namespace FW1FontWrapper + + +#endif// IncludeGuard__FW1_CFW1TextGeometry diff --git a/no_renderer/FW1FontWrapper/CFW1TextGeometryInterface.cpp b/no_renderer/FW1FontWrapper/CFW1TextGeometryInterface.cpp new file mode 100644 index 0000000..bb12181 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1TextGeometryInterface.cpp @@ -0,0 +1,113 @@ +// CFW1TextGeometryInterface.cpp + +#include "FW1Precompiled.h" + +#include "CFW1TextGeometry.h" + + +namespace FW1FontWrapper { + + +// Query interface +HRESULT STDMETHODCALLTYPE CFW1TextGeometry::QueryInterface(REFIID riid, void **ppvObject) { + if(ppvObject == NULL) + return E_INVALIDARG; + + if(IsEqualIID(riid, __uuidof(IFW1TextGeometry))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + + return CFW1Object::QueryInterface(riid, ppvObject); +} + + +// Clear geometry +void STDMETHODCALLTYPE CFW1TextGeometry::Clear() { + m_vertices.clear(); + m_maxSheetIndex = 0; + + m_sorted = false; +} + + +// Add a vertex +void STDMETHODCALLTYPE CFW1TextGeometry::AddGlyphVertex(const FW1_GLYPHVERTEX *pVertex) { + m_vertices.push_back(*pVertex); + + UINT sheetIndex = pVertex->GlyphIndex >> 16; + m_maxSheetIndex = std::max(m_maxSheetIndex, sheetIndex); + + m_sorted = false; +} + + +// Get current glyph vertices +FW1_VERTEXDATA STDMETHODCALLTYPE CFW1TextGeometry::GetGlyphVerticesTemp() { + FW1_VERTEXDATA vertexData; + + if(!m_vertices.empty()) { + UINT32 sheetCount = m_maxSheetIndex + 1; + + // Sort and prepare vertices + if(!m_sorted) { + m_sortedVertices.resize(m_vertices.size()); + m_vertexCounts.resize(sheetCount); + m_vertexStartIndices.resize(sheetCount); + + std::fill(m_vertexCounts.begin(), m_vertexCounts.end(), 0); + + UINT * const vertexCounts = &m_vertexCounts[0]; + const FW1_GLYPHVERTEX * const vertices = &m_vertices[0]; + const UINT32 vertexCount = static_cast(m_vertices.size()); + + for(UINT32 i=0; i < vertexCount; ++i) { + UINT32 sheetIndex = vertices[i].GlyphIndex >> 16; + + ++vertexCounts[sheetIndex]; + } + + UINT * const vertexStartIndices = &m_vertexStartIndices[0]; + + UINT currentStartIndex = 0; + for(UINT32 i=0; i < sheetCount; ++i) { + vertexStartIndices[i] = currentStartIndex; + + currentStartIndex += vertexCounts[i]; + } + + FW1_GLYPHVERTEX * const sortedVertices = &m_sortedVertices[0]; + + for(UINT32 i=0; i < vertexCount; ++i) { + const FW1_GLYPHVERTEX &vertex = vertices[i]; + UINT32 sheetIndex = vertex.GlyphIndex >> 16; + + UINT &vertexIndex = vertexStartIndices[sheetIndex]; + + sortedVertices[vertexIndex] = vertex; + sortedVertices[vertexIndex].GlyphIndex &= 0xffff; + + ++vertexIndex; + } + + m_sorted = true; + } + + vertexData.SheetCount = sheetCount; + vertexData.pVertexCounts = &m_vertexCounts[0]; + vertexData.TotalVertexCount = static_cast(m_vertices.size()); + vertexData.pVertices = &m_sortedVertices[0]; + } + else { + vertexData.SheetCount = 0; + vertexData.pVertexCounts = 0; + vertexData.TotalVertexCount = 0; + vertexData.pVertices = 0; + } + + return vertexData; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1TextRenderer.cpp b/no_renderer/FW1FontWrapper/CFW1TextRenderer.cpp new file mode 100644 index 0000000..6561545 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1TextRenderer.cpp @@ -0,0 +1,58 @@ +// CFW1TextRenderer.cpp + +#include "FW1Precompiled.h" + +#include "CFW1TextRenderer.h" + +#define SAFE_RELEASE(pObject) { if(pObject) { (pObject)->Release(); (pObject) = NULL; } } + + +namespace FW1FontWrapper { + + +// Construct +CFW1TextRenderer::CFW1TextRenderer() : + m_pGlyphProvider(NULL), + + m_currentFlags(0), + m_currentColor(0xff000000), + + m_cachedGlyphMap(0), + m_pCachedGlyphMapFontFace(NULL), + m_cachedGlyphMapFontSize(0), + + m_pDWriteTextRendererProxy(0) +{ +} + + +// Destruct +CFW1TextRenderer::~CFW1TextRenderer() { + SAFE_RELEASE(m_pGlyphProvider); + + delete m_pDWriteTextRendererProxy; +} + + +// Init +HRESULT CFW1TextRenderer::initTextRenderer( + IFW1Factory *pFW1Factory, + IFW1GlyphProvider *pGlyphProvider +) { + HRESULT hResult = initBaseObject(pFW1Factory); + if(FAILED(hResult)) + return hResult; + + if(pGlyphProvider == NULL) + return E_INVALIDARG; + + pGlyphProvider->AddRef(); + m_pGlyphProvider = pGlyphProvider; + + m_pDWriteTextRendererProxy = new CDWriteTextRendererProxy(this); + + return S_OK; +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/CFW1TextRenderer.h b/no_renderer/FW1FontWrapper/CFW1TextRenderer.h new file mode 100644 index 0000000..941daa3 --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1TextRenderer.h @@ -0,0 +1,147 @@ +// CFW1TextRenderer.h + +#ifndef IncludeGuard__FW1_CFW1TextRenderer +#define IncludeGuard__FW1_CFW1TextRenderer + +#include "CFW1Object.h" + + +namespace FW1FontWrapper { + + +// Converts a DWrite text layout to vertices +class CFW1TextRenderer : public CFW1Object { + public: + // IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject); + + // IFW1DWriteTextRenderer + virtual HRESULT STDMETHODCALLTYPE GetGlyphProvider(IFW1GlyphProvider **ppGlyphProvider); + + virtual HRESULT STDMETHODCALLTYPE DrawTextLayout( + IDWriteTextLayout *pTextLayout, + FLOAT OriginX, + FLOAT OriginY, + UINT32 Color, + UINT Flags, + IFW1TextGeometry *pTextGeometry + ); + + // Public functions + public: + CFW1TextRenderer(); + + HRESULT initTextRenderer( + IFW1Factory *pFW1Factory, + IFW1GlyphProvider *pGlyphProvider + ); + + // Internal functions + private: + virtual ~CFW1TextRenderer(); + + // IDWritePixelSnapping interface (called via proxy) + HRESULT IsPixelSnappingDisabled(void *clientDrawingContext, BOOL *isDisabled); + HRESULT GetCurrentTransform(void *clientDrawingContext, DWRITE_MATRIX *transform); + HRESULT GetPixelsPerDip(void *clientDrawingContext, FLOAT *pixelsPerDip); + + // IDWriteTextRenderer interface (called via proxy) + HRESULT DrawGlyphRun( + void *clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_MEASURING_MODE measuringMode, + const DWRITE_GLYPH_RUN *glyphRun, + const DWRITE_GLYPH_RUN_DESCRIPTION *glyphRunDescription, + IUnknown *clientDrawingEffect + ); + HRESULT DrawUnderline( + void *clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + const DWRITE_UNDERLINE *underline, + IUnknown *clientDrawingEffect + ); + HRESULT DrawStrikethrough( + void *clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + const DWRITE_STRIKETHROUGH *strikethrough, + IUnknown *clientDrawingEffect + ); + HRESULT DrawInlineObject( + void *clientDrawingContext, + FLOAT originX, + FLOAT originY, + IDWriteInlineObject *inlineObject, + BOOL isSideways, + BOOL isRightToLeft, + IUnknown *clientDrawingEffect + ); + + // Internal data + private: + IFW1GlyphProvider *m_pGlyphProvider; + + UINT m_currentFlags; + UINT32 m_currentColor; + + const void *m_cachedGlyphMap; + IDWriteFontFace *m_pCachedGlyphMapFontFace; + FLOAT m_cachedGlyphMapFontSize; + + + // Proxy for IDWriteTextRenderer interface + private: + class CDWriteTextRendererProxy : public IDWriteTextRenderer { + public: + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) { + return m_realObject->QueryInterface(riid, ppvObject); + } + virtual ULONG STDMETHODCALLTYPE AddRef() { + return m_realObject->AddRef(); + } + virtual ULONG STDMETHODCALLTYPE Release() { + return m_realObject->Release(); + } + + virtual HRESULT STDMETHODCALLTYPE IsPixelSnappingDisabled(void *clientDrawingContext, BOOL *isDisabled) { + return m_realObject->IsPixelSnappingDisabled(clientDrawingContext, isDisabled); + } + virtual HRESULT STDMETHODCALLTYPE GetCurrentTransform(void *clientDrawingContext, DWRITE_MATRIX *transform) { + return m_realObject->GetCurrentTransform(clientDrawingContext, transform); + } + virtual HRESULT STDMETHODCALLTYPE GetPixelsPerDip(void *clientDrawingContext, FLOAT *pixelsPerDip) { + return m_realObject->GetPixelsPerDip(clientDrawingContext, pixelsPerDip); + } + + virtual HRESULT STDMETHODCALLTYPE DrawGlyphRun(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, const DWRITE_GLYPH_RUN *glyphRun, const DWRITE_GLYPH_RUN_DESCRIPTION *glyphRunDescription, IUnknown *clientDrawingEffect) { + return m_realObject->DrawGlyphRun(clientDrawingContext, baselineOriginX, baselineOriginY, measuringMode, glyphRun, glyphRunDescription, clientDrawingEffect); + } + virtual HRESULT STDMETHODCALLTYPE DrawUnderline(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_UNDERLINE *underline, IUnknown *clientDrawingEffect) { + return m_realObject->DrawUnderline(clientDrawingContext, baselineOriginX, baselineOriginY, underline, clientDrawingEffect); + } + virtual HRESULT STDMETHODCALLTYPE DrawStrikethrough(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_STRIKETHROUGH *strikethrough, IUnknown *clientDrawingEffect) { + return m_realObject->DrawStrikethrough(clientDrawingContext, baselineOriginX, baselineOriginY, strikethrough, clientDrawingEffect); + } + virtual HRESULT STDMETHODCALLTYPE DrawInlineObject(void *clientDrawingContext, FLOAT originX, FLOAT originY, IDWriteInlineObject *inlineObject, BOOL isSideways, BOOL isRightToLeft, IUnknown *clientDrawingEffect) { + return m_realObject->DrawInlineObject(clientDrawingContext, originX, originY, inlineObject, isSideways, isRightToLeft, clientDrawingEffect); + } + + public: + CDWriteTextRendererProxy(CFW1TextRenderer *realObject) : m_realObject(realObject) {} + + private: + CDWriteTextRendererProxy(const CDWriteTextRendererProxy&); + CDWriteTextRendererProxy& operator=(const CDWriteTextRendererProxy&); + + private: + CFW1TextRenderer *m_realObject; + } *m_pDWriteTextRendererProxy; +}; + + +}// namespace FW1FontWrapper + + +#endif// IncludeGuard__FW1_CFW1TextRenderer diff --git a/no_renderer/FW1FontWrapper/CFW1TextRendererInterface.cpp b/no_renderer/FW1FontWrapper/CFW1TextRendererInterface.cpp new file mode 100644 index 0000000..46927eb --- /dev/null +++ b/no_renderer/FW1FontWrapper/CFW1TextRendererInterface.cpp @@ -0,0 +1,257 @@ +// CFW1TextRendererInterface.cpp + +#include "FW1Precompiled.h" + +#include "CFW1TextRenderer.h" + + +namespace FW1FontWrapper { + + +// Query interface +HRESULT STDMETHODCALLTYPE CFW1TextRenderer::QueryInterface(REFIID riid, void **ppvObject) { + if(ppvObject == NULL) + return E_INVALIDARG; + + if(IsEqualIID(riid, __uuidof(IDWritePixelSnapping))) { + *ppvObject = static_cast(m_pDWriteTextRendererProxy); + AddRef(); + return S_OK; + } + else if(IsEqualIID(riid, __uuidof(IDWriteTextRenderer))) { + *ppvObject = static_cast(m_pDWriteTextRendererProxy); + AddRef(); + return S_OK; + } + else if(IsEqualIID(riid, __uuidof(IFW1TextRenderer))) { + *ppvObject = static_cast(this); + AddRef(); + return S_OK; + } + + return CFW1Object::QueryInterface(riid, ppvObject); +} + + +// IDWritePixelSnapping method +HRESULT CFW1TextRenderer::IsPixelSnappingDisabled( + void *clientDrawingContext, + BOOL *isDisabled +) { + clientDrawingContext; + + *isDisabled = FALSE; + + return S_OK; +} + + +// IDWritePixelSnapping method +HRESULT CFW1TextRenderer::GetCurrentTransform( + void *clientDrawingContext, + DWRITE_MATRIX *transform +) { + clientDrawingContext; + + transform->dx = 0.0f; + transform->dy = 0.0f; + transform->m11 = 1.0f; + transform->m12 = 0.0f; + transform->m21 = 0.0f; + transform->m22 = 1.0f; + + return S_OK; +} + + +// IDWritePixelSnapping method +HRESULT CFW1TextRenderer::GetPixelsPerDip(void *clientDrawingContext, FLOAT *pixelsPerDip) { + clientDrawingContext; + + *pixelsPerDip = 96.0f; + + return S_OK; +} + + +// IDWriteTextRenderer method +// Convert a run of glyphs to vertices +HRESULT CFW1TextRenderer::DrawGlyphRun( + void *clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + DWRITE_MEASURING_MODE measuringMode, + const DWRITE_GLYPH_RUN *glyphRun, + const DWRITE_GLYPH_RUN_DESCRIPTION *glyphRunDescription, + IUnknown *clientDrawingEffect +) { + glyphRunDescription; + measuringMode; + + const UINT flags = m_currentFlags; + + // Get glyph map for the current font + const void *glyphMap; + if(glyphRun->fontFace == m_pCachedGlyphMapFontFace && glyphRun->fontEmSize == m_cachedGlyphMapFontSize) + glyphMap = m_cachedGlyphMap; + else { + glyphMap = m_pGlyphProvider->GetGlyphMapFromFont(glyphRun->fontFace, glyphRun->fontEmSize, flags); + + // Cache the glyph map as it's likely to be used in subsequent glyph runs + m_cachedGlyphMap = glyphMap; + m_pCachedGlyphMapFontFace = glyphRun->fontFace; + m_cachedGlyphMapFontSize = glyphRun->fontEmSize; + } + + // Skip if not interested in the actual glyphs + if((flags & FW1_ANALYZEONLY) != 0) + return S_OK; + + if((flags & FW1_CACHEONLY) != 0) { + // Only request the glyphs from the provider to have them drawn to the atlas + for(UINT i=0; i < glyphRun->glyphCount; ++i) { + UINT atlasId = m_pGlyphProvider->GetAtlasIdFromGlyphIndex( + glyphMap, + glyphRun->glyphIndices[i], + glyphRun->fontFace, + flags + ); + atlasId; + } + } + else { + // Glyph vertex + FW1_GLYPHVERTEX glyphVertex; + glyphVertex.PositionY = floor(baselineOriginY + 0.5f); + glyphVertex.GlyphColor = m_currentColor; + + float positionX = floor(baselineOriginX + 0.5f); + + // Optional drawing effect + if(clientDrawingEffect != NULL) { + IFW1ColorRGBA *pColor; + HRESULT hResult = clientDrawingEffect->QueryInterface(&pColor); + if(SUCCEEDED(hResult)) { + glyphVertex.GlyphColor = pColor->GetColor32(); + pColor->Release(); + } + } + + // Add a vertex for each glyph in the run + IFW1TextGeometry *pTextGeometry = static_cast(clientDrawingContext); + if(pTextGeometry != NULL) { + for(UINT i=0; i < glyphRun->glyphCount; ++i) { + glyphVertex.GlyphIndex = m_pGlyphProvider->GetAtlasIdFromGlyphIndex( + glyphMap, + glyphRun->glyphIndices[i], + glyphRun->fontFace, + flags + ); + + if((glyphRun->bidiLevel & 0x1) != 0) + positionX -= glyphRun->glyphAdvances[i]; + + glyphVertex.PositionX = floor(positionX + 0.5f); + pTextGeometry->AddGlyphVertex(&glyphVertex); + + if((glyphRun->bidiLevel & 0x1) == 0) + positionX += glyphRun->glyphAdvances[i]; + } + } + } + + return S_OK; +} + + +// IDWriteTextRenderer method +HRESULT CFW1TextRenderer::DrawUnderline( + void *clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + const DWRITE_UNDERLINE *underline, + IUnknown *clientDrawingEffect +) { + clientDrawingContext; + baselineOriginX; + baselineOriginY; + underline; + clientDrawingEffect; + + return E_NOTIMPL; +} + + +// IDWriteTextRenderer method +HRESULT CFW1TextRenderer::DrawStrikethrough( + void *clientDrawingContext, + FLOAT baselineOriginX, + FLOAT baselineOriginY, + const DWRITE_STRIKETHROUGH *strikethrough, + IUnknown *clientDrawingEffect +) { + clientDrawingContext; + baselineOriginX; + baselineOriginY; + strikethrough; + clientDrawingEffect; + + return E_NOTIMPL; +} + + +// IDWriteTextRenderer method +HRESULT CFW1TextRenderer::DrawInlineObject( + void *clientDrawingContext, + FLOAT originX, + FLOAT originY, + IDWriteInlineObject *inlineObject, + BOOL isSideways, + BOOL isRightToLeft, + IUnknown *clientDrawingEffect +) { + clientDrawingContext; + originX; + originY; + inlineObject; + isSideways; + isRightToLeft; + clientDrawingEffect; + + return E_NOTIMPL; +} + + +// Get glyph provider +HRESULT STDMETHODCALLTYPE CFW1TextRenderer::GetGlyphProvider(IFW1GlyphProvider **ppGlyphProvider) { + if(ppGlyphProvider == NULL) + return E_INVALIDARG; + + m_pGlyphProvider->AddRef(); + *ppGlyphProvider = m_pGlyphProvider; + + return S_OK; +} + + +// Draw a text layout +HRESULT STDMETHODCALLTYPE CFW1TextRenderer::DrawTextLayout( + IDWriteTextLayout *pTextLayout, + FLOAT OriginX, + FLOAT OriginY, + UINT32 Color, + UINT Flags, + IFW1TextGeometry *pTextGeometry +) { + m_currentFlags = Flags; + m_currentColor = Color; + + m_cachedGlyphMap = 0; + m_pCachedGlyphMapFontFace = NULL; + m_cachedGlyphMapFontSize = 0.0f; + + return pTextLayout->Draw(pTextGeometry, m_pDWriteTextRendererProxy, OriginX, OriginY); +} + + +}// namespace FW1FontWrapper diff --git a/no_renderer/FW1FontWrapper/FW1CompileSettings.h b/no_renderer/FW1FontWrapper/FW1CompileSettings.h new file mode 100644 index 0000000..4a0db2d --- /dev/null +++ b/no_renderer/FW1FontWrapper/FW1CompileSettings.h @@ -0,0 +1,15 @@ +// FW1CompileSettings.h + +#ifndef IncludeGuard__FW1_FW1CompileSettings_h +#define IncludeGuard__FW1_FW1CompileSettings_h + + +// Define if building a DLL for the font-wrapper +#define FW1_COMPILETODLL + +// Define to use LoadLibrary instead of linking to DLLs +#define FW1_DELAYLOAD_DWRITE_DLL +#define FW1_DELAYLOAD_D3DCOMPILER_XX_DLL + + +#endif// IncludeGuard__FW1_FW1CompileSettings_h diff --git a/no_renderer/FW1FontWrapper/FW1FontWrapper.cpp b/no_renderer/FW1FontWrapper/FW1FontWrapper.cpp new file mode 100644 index 0000000..0745802 --- /dev/null +++ b/no_renderer/FW1FontWrapper/FW1FontWrapper.cpp @@ -0,0 +1,42 @@ +// FW1FontWrapper.cpp + +#include "FW1Precompiled.h" + +#include "CFW1Factory.h" + +#ifndef FW1_DELAYLOAD_DWRITE_DLL + #pragma comment (lib, "DWrite.lib") +#endif + +#ifndef FW1_DELAYLOAD_D3DCOMPILER_XX_DLL + #pragma comment (lib, "DWrite.lib") +#endif + +#ifdef FW1_COMPILETODLL + #ifndef _M_X64 + #pragma comment (linker, "/EXPORT:FW1CreateFactory=_FW1CreateFactory@8,@1") + #endif +#endif + + +// Create FW1 factory +extern "C" HRESULT STDMETHODCALLTYPE FW1CreateFactory(UINT32 Version, IFW1Factory **ppFactory) { + if(Version != FW1_VERSION) + return E_FAIL; + + if(ppFactory == NULL) + return E_INVALIDARG; + + FW1FontWrapper::CFW1Factory *pFactory = new FW1FontWrapper::CFW1Factory; + HRESULT hResult = pFactory->initFactory(); + if(FAILED(hResult)) { + pFactory->Release(); + } + else { + *ppFactory = pFactory; + + hResult = S_OK; + } + + return hResult; +} diff --git a/no_renderer/FW1FontWrapper/FW1FontWrapper.h b/no_renderer/FW1FontWrapper/FW1FontWrapper.h new file mode 100644 index 0000000..369e0ff --- /dev/null +++ b/no_renderer/FW1FontWrapper/FW1FontWrapper.h @@ -0,0 +1,1214 @@ +// FW1FontWrapper.h + +// v1.1, October 2011 +// Written by Erik Rufelt + +#ifndef IncludeGuard__FW1_FW1FontWrapper_h +#define IncludeGuard__FW1_FW1FontWrapper_h + +#include +#include + + +/// The current FW1 version. +/// This constant should be used when calling FW1CreateFactory to make sure the library version matches the headers. +#define FW1_VERSION 0x110f + +#define FW1_DLL_W L"FW1FontWrapper.dll" +#define FW1_DLL_A "FW1FontWrapper.dll" + +#ifdef UNICODE + #define FW1_DLL FW1_DLL_W +#else + #define FW1_DLL FW1_DLL_A +#endif + +/// Describes overrides for how an FW1 operation is performed. +/// These flags can be used for any FW1 methods that take a flags parameter. Not all flags have any meaning for all methods however. +/// Consult the documentation page for a particular method for information on what flags are valid. +enum FW1_TEXT_FLAG { + /// Text is left-aligned. This is the default. + FW1_LEFT = 0x0, + + /// Text is centered horizontally. + FW1_CENTER = 0x1, + + /// Text is right-aligned. + FW1_RIGHT = 0x2, + + /// Text is aligned at the top of the layout-box. This is the default. + FW1_TOP = 0x0, + + /// Text is centered vertically. + FW1_VCENTER = 0x4, + + /// Text is aligned at the bottom of the layout-box. + FW1_BOTTOM = 0x8, + + /// No automatic wrapping when the text overflows the layout-box. + FW1_NOWORDWRAP = 0x10, + + /// Text is drawn without anti-aliasing. + FW1_ALIASED = 0x20, + + /// If a clip-rect is specified together with this flag, all text is clipped to inside the specified rectangle. + FW1_CLIPRECT = 0x40, + + /// No geometry shader is used when drawing glyphs. Indexed quads are constructed on the CPU instead of in the geometry shader. + FW1_NOGEOMETRYSHADER = 0x80, + + /// The transform matrix and the clip-rect is not updated in the internal constant-buffer. Can be used as an optimization when a previous call has already set the correct data. + FW1_CONSTANTSPREPARED = 0x100, + + /// The internal vertex and index buffer (if used) are assumed to already be bound. Can be used as an optimization when a previous call has already set the buffers. + FW1_BUFFERSPREPARED = 0x200, + + /// The correct shaders/constant-buffer etc. are assumed to already be bound. Can be used as an optimization when a previous call has already set the states, or to override the default states. + FW1_STATEPREPARED = 0x400, + + /// Can be used as an optimization on subsequent calls, when drawing several strings with the same settings. + FW1_IMMEDIATECALL = FW1_CONSTANTSPREPARED | FW1_BUFFERSPREPARED | FW1_STATEPREPARED, + + /// When a draw method returns, the device-context will have been restored to the same state as before the call. + FW1_RESTORESTATE = 0x800, + + /// Any new glyphs added during a call are not flushed to the device-resources. + /// It is a good idea to use this flag for text-operations on deferred contexts, when drawing text on multiple threads simultaneously, in order to guarantee the proper order of operations. + FW1_NOFLUSH = 0x1000, + + /// Any new glyphs will be cached in the atlas and glyph-maps, but no geometry is drawn. + FW1_CACHEONLY = 0x2000, + + /// No new glyphs will be added to the atlas or glyph-maps. Any glyphs not already present in the atlas will be replaced with a default fall-back glyph (empty box). + FW1_NONEWGLYPHS = 0x4000, + + /// A text-layout will be run through DirectWrite and new fonts will be prepared, but no actual drawing will take place, and no additional glyphs will be cached. + FW1_ANALYZEONLY = 0x8000, + + /// Don't use. + FW1_UNUSED = 0xffffffff +}; + +/// Coordinates for a single glyph in the atlas. +/// Each glyph image inserted in a glyph sheet texture gets a unique index in that sheet, and a corresponding FW1_GLYPHCOORDS entry in the sheet's coord buffer, describing its location in the sheet as well as its dimensions. +struct FW1_GLYPHCOORDS { + /// The left texture coordinate. + FLOAT TexCoordLeft; + + /// The top texture coordinate. + FLOAT TexCoordTop; + + /// The right texture coordinate. + FLOAT TexCoordRight; + + /// The bottom texture coordinate. + FLOAT TexCoordBottom; + + /// The offset of the left edge of the glyph image, relative its offset in the text. + FLOAT PositionLeft; + + /// The offset of the top edge of the glyph image, relative its offset in the text. + FLOAT PositionTop; + + /// The offset of the right edge of the glyph image, relative its offset in the text. + FLOAT PositionRight; + + /// The offset of the bottom edge of the glyph image, relative its offset in the text. + FLOAT PositionBottom; +}; + +/// Description of a glyph sheet. +/// +struct FW1_GLYPHSHEETDESC { + /// The number of glyphs currently stored in this sheet. + UINT GlyphCount; + + /// The width of this sheet's texture, in pixels. + UINT Width; + + /// The height of this sheet's texture, in pixels. + UINT Height; + + /// The number of mip-levels for this sheet's texture. + UINT MipLevels; +}; + +/// Metrics for a glyph image. +/// This structure is filled in as part of the FW1_GLYPHIMAGEDATA structure when a glyph-image is rendered by IFW1DWriteRenderTarget::DrawGlyphTemp. +struct FW1_GLYPHMETRICS { + /// The horizontal offset from a glyph's position in text to the left edge of its image. + FLOAT OffsetX; + + /// The vertical offset form a glyph's position in text to the top edge of its image. + FLOAT OffsetY; + + /// The width of the glyph image, in pixels. + UINT Width; + + /// The height of the glyph image, in pixels. + UINT Height; +}; + +/// Image data for a glyph. +/// This structure is filled by the IFW1DWriteRenderTarget::DrawGlyphTemp Method. +struct FW1_GLYPHIMAGEDATA { + /// Metrics for the glyph. + FW1_GLYPHMETRICS Metrics; + + /// Pointer to the pixels of the glyph-image. + const void *pGlyphPixels; + + /// The number of bytes in a row of the image data. + UINT RowPitch; + + /// The number of bytes between the start of one pixel and the next. + UINT PixelStride; +}; + +/// A vertex corresponding to a single glyph. +/// When an IFW1TextRenderer draws a string, each output glyph is converted to an FW1_GLYPHVERTEX entry in an IFW1TextGeometry object. +struct FW1_GLYPHVERTEX { + /// The base X position of the glyph. + FLOAT PositionX; + + /// The base Y position of the glyph. + FLOAT PositionY; + + /// The index of the glyph. + UINT32 GlyphIndex; + + /// The color of the glyph, as 0xAaBbGgRr. + UINT32 GlyphColor; +}; + +/// An array of vertices, sorted by glyph-sheet. +/// This structure is returned by the IFW1TextGeometry::GetGlyphVerticesTemp Method. +struct FW1_VERTEXDATA { + /// The number of sheets in the glyph-atlas that are used, starting with the first sheet in the atlas. + UINT SheetCount; + + /// An array of SheetCount unsigned integers, which specify the number of glyphs using each sheet. + /// The sum of all counts is TotalVertexCount. Some counts may be zero. + const UINT *pVertexCounts; + + /// The total number of vertices. + UINT TotalVertexCount; + + /// An array of TotalVertexCount vertices, sorted by sheet. + const FW1_GLYPHVERTEX *pVertices; +}; + +/// A rectangle. +/// +struct FW1_RECTF { + /// The X coordinate of the left edge of the rectangle. + FLOAT Left; + + /// The Y coordinate of the top edge of the rectangle. + FLOAT Top; + + /// The X coordinate of the right edge of the rectangle. + FLOAT Right; + + /// The Y coordinate of the bottom edge of the rectangle. + FLOAT Bottom; +}; + +/// Describes a single font. This structure is used in the FW1_FONTWRAPPERCREATEPARAMS structure. +/// If pszFontFamily is NULL when creating an IFW1FontWrapper object, no default font will be set up. +/// This is perfectly valid when drawing text using one of the DrawTextLayout methods. +/// However, the DrawString methods will silently fail if no default font is set up.
+/// If pszFontFamily is not NULL, the FontWeight, FontStyle and FontStretch members must be set to valid values according to the DirectWrite documentation. +/// Zero is not a valid value for these.
+struct FW1_DWRITEFONTPARAMS { + /// The name of the font-family. Valid values include Arial, Courier New, etc. as long as the specified font is installed. + /// Unavailable fonts will automatically fall back to a different font. + /// This member can be set to NULL, if no default font is desired when using the structure to create a font-wrapper. + LPCWSTR pszFontFamily; + + /// The font weight. See DirectWrite documentation. + DWRITE_FONT_WEIGHT FontWeight; + + /// The font style. See DirectWrite documentation. + DWRITE_FONT_STYLE FontStyle; + + /// The font stretch. See DirectWrite documentation. + DWRITE_FONT_STRETCH FontStretch; + + /// The locale. NULL for default. + LPCWSTR pszLocale; +}; + +/// The FW1_FONTWRAPPERCREATEPARAMS is used with the IFW1Factory::CreateFontWrapper method, and describes settings for the created IFW1FontWrapper object. +/// If a member has the value zero, the default value will be chosen instead. See FW1_DWRITEFONTPARAMS for requirements for its members. +struct FW1_FONTWRAPPERCREATEPARAMS { + /// The width of the glyph sheet textures to store glyph images in. 0 defaults to 512. + UINT GlyphSheetWidth; + + /// The height of the glyph sheet textures to store glyph images in. 0 defaults to 512. + UINT GlyphSheetHeight; + + /// The maximum number of glyphs per texture. A buffer of MaxGlyphCountPerSheet * 32 bytes is preallocated for each sheet. 0 defaults to 2048. + UINT MaxGlyphCountPerSheet; + + /// The number of mip-levels for the glyph sheet textures. 0 defaults to 1. + UINT SheetMipLevels; + + /// If set to TRUE, the sampler-state is created with anisotropic filtering. + BOOL AnisotropicFiltering; + + /// The maximum width of a single glyph. + /// This value is used to decide how large the DirectWrite render target needs to be, which is used when drawing glyph images to put in the atlas. + /// 0 defaults to 384. + UINT MaxGlyphWidth; + + /// The maximum height of a single glyph. + /// This value is used to decide how large the DirectWrite render target needs to be, which is used when drawing glyph images to put in the atlas. + /// 0 defaults to 384. + UINT MaxGlyphHeight; + + /// If set to TRUE, no geometry shader is used. + BOOL DisableGeometryShader; + + /// The size in bytes of the dynamic vertex buffer to upload glyph vertices to when drawing a string. 0 defaults to 4096 * 16.
+ /// Each glyph vertex is either 16 or 20 bytes in size, and each glyph requires either 1 or 4 vertices depending on if the geometry shader is used.
+ UINT VertexBufferSize; + + /// Description of the default font. See FW1_DWRITEFONTPARAMS. + FW1_DWRITEFONTPARAMS DefaultFontParams; +}; + +interface IFW1Factory; +/// All FW1 interfaces (except for IFW1Factory) inherits from IFW1Object. +/// Since all interfaces inhert from IFW1Object, the factory which created an object can always be queried with its GetFactory method. +MIDL_INTERFACE("8D3C3FB1-F2CC-4331-A623-031F74C06617") IFW1Object : public IUnknown { + public: + /// Get the factory that created an object. + /// + /// Standard HRESULT error code. + /// Address of a pointer to an IFW1Factory. + virtual HRESULT STDMETHODCALLTYPE GetFactory( + __out IFW1Factory **ppFactory + ) = 0; +}; + +/// A sheet contains a texture with glyph images, and a coord-buffer with an FW1_GLYPHCOORDS entry for each glyph. +MIDL_INTERFACE("60CAB266-C805-461d-82C0-392472EECEFA") IFW1GlyphSheet : public IFW1Object { + public: + /// Get the ID3D11Device the sheet is created on. + /// + /// Standard HRESULT error code. + /// Address of a pointer to an ID3D11Device. + virtual HRESULT STDMETHODCALLTYPE GetDevice( + __out ID3D11Device **ppDevice + ) = 0; + + /// Get the properties of a glyph sheet. + /// + /// Returns nothing. + /// Pointer to a sheet description. + virtual void STDMETHODCALLTYPE GetDesc( + __out FW1_GLYPHSHEETDESC *pDesc + ) = 0; + + /// Get the ID3D11ShaderResourceView for the sheet's texture. + /// + /// Standard HRESULT error code. + /// Address of a pointer to an ID3D11ShaderResourceView. + virtual HRESULT STDMETHODCALLTYPE GetSheetTexture( + __out ID3D11ShaderResourceView **ppSheetTextureSRV + ) = 0; + + /// Get the ID3D11ShaderResourceView for the sheet's coord buffer. + /// The coord buffer contains 32 bytes per glyph, stored as two float4, representing the data in an FW1_GLYPHCOORDS structure.
+ /// If the sheet is created without a hardware coord buffer, the method will return success and set the coord buffer to NULL. + /// See IFW1Factory::CreateGlyphSheet.
+ /// Standard HRESULT error code. + /// Address of a pointer to an ID3D11ShaderResourceView. + virtual HRESULT STDMETHODCALLTYPE GetCoordBuffer( + __out ID3D11ShaderResourceView **ppCoordBufferSRV + ) = 0; + + /// Get a sheet's coord-buffer, as an array of FW1_GLYPHCOORDS. + /// The returned buffer is valid for the lifetime of the sheet, and may only be read and never altered. + /// The maximum valid index at any given time is one less than the number of glyphs in the sheet, which can be queried using IFW1GlyphSheet::GetDesc. + /// Returns a constant pointer to the sheet's coord-buffer. + virtual const FW1_GLYPHCOORDS* STDMETHODCALLTYPE GetGlyphCoords( + ) = 0; + + /// Set the sheet shader resources on the provided context. + /// This method sets the sheet texture as a pixelshader resource for slot 0, and optionally the coord buffer as geometryshader resource for slot 0. + /// Standard HRESULT error code. + /// The context to set the sheet shader resources on. + /// This parameter can include zero or more of the following values, ORd together. Any additional values are ignored.
+ /// FW1_NOGEOMETRYSHADER: don't bind the coord buffer as a shader-resource for the geometry shader, even if it's available. + /// + virtual HRESULT STDMETHODCALLTYPE BindSheet( + __in ID3D11DeviceContext *pContext, + __in UINT Flags + ) = 0; + + /// Insert a glyph into the sheet. + /// The parameters for this method can be obtained as part of the FW1_GLYPHIMAGEDATA structure filled in by the IFW1DWriteRenderTarget::DrawGlyphTemp method. + /// If the glyph is inserted, the index of the new glyph in the sheet is returned. This index can be used to get the glyph's coordinates from the sheet coord buffer. See IFW1GlyphSheet::GetCoordBuffer and IFW1GlyphSheet::GetGlyphCoords.
+ /// If the method fails to insert the glyph, the returned value is 0xFFFFFFFF.
+ /// A pointer to an FW1_GLYPHMETRICS structure, specifying the metrics of the glyph to be inserted. + /// A pointer to image data. + /// The number of bytes in a row of image data. + /// The number of bytes between successive pixels. + virtual UINT STDMETHODCALLTYPE InsertGlyph( + __in const FW1_GLYPHMETRICS *pGlyphMetrics, + __in const void *pGlyphData, + __in UINT RowPitch, + __in UINT PixelStride + ) = 0; + + /// Close the sheet for additional glyphs. + /// After calling this method any subsequent attempts to insert new glyphs into the sheet will fail. + /// Calling this method can save some memory as the RAM copy of the texture can be released after the next call to IFW1GlyphSheet::Flush. + /// No return value. + virtual void STDMETHODCALLTYPE CloseSheet( + ) = 0; + + /// Flush any new glyphs to the internal D3D11 buffers. + /// When glyphs are inserted into the sheet only the CPU-memory resources are updated. + /// In order for these to be available for use by the GPU, they must be flushed to the device using a device-context. + /// No return value. + /// The context to use when updating device resources. + virtual void STDMETHODCALLTYPE Flush( + __in ID3D11DeviceContext *pContext + ) = 0; +}; + +/// A glyph-atlas is a collection of glyph-sheets. +/// +MIDL_INTERFACE("A31EB6A2-7458-4e24-82B3-945A95623B1F") IFW1GlyphAtlas : public IFW1Object { + /// Get the ID3D11Device the atlas is created on. + /// + /// Standard HRESULT error code. + /// Address of a pointer to an ID3D11Device. + virtual HRESULT STDMETHODCALLTYPE GetDevice( + __out ID3D11Device **ppDevice + ) = 0; + + /// Get the total number of glyphs in all the atlas' sheets. + /// + /// The total number of glyphs in the atlas. + virtual UINT STDMETHODCALLTYPE GetTotalGlyphCount( + ) = 0; + + /// Get the number of texture sheets in the atlas. + /// + /// The number of sheets in the atlas. + virtual UINT STDMETHODCALLTYPE GetSheetCount( + ) = 0; + + /// Get a pointer to an IFW1GlyphSheet in the atlas. + /// + /// Standard HRESULT error code. + /// The index of the sheet to be obtained. + /// Address of a pointer to an IFW1GlyphSheet. + virtual HRESULT STDMETHODCALLTYPE GetSheet( + __in UINT SheetIndex, + __out IFW1GlyphSheet **ppGlyphSheet + ) = 0; + + /// Get a pointer to a sheet's glyph-coord buffer. + /// + /// If SheetIndex is valid, returns a pointer to a coord buffer. See IFW1GlyphSheet::GetGlyphCoords. + /// The index of the sheet which coord buffer is to be obtained. + virtual const FW1_GLYPHCOORDS* STDMETHODCALLTYPE GetGlyphCoords( + __in UINT SheetIndex + ) = 0; + + /// Bind a sheet's shader resources on a device context. + /// + /// Standard HRESULT error code. + /// The context to set the shader resources on. + /// The index of the sheet to bind. + /// Flags that specify whether to set the geometry shader coord buffer. See IFW1GlyphSheet::BindSheet. + virtual HRESULT STDMETHODCALLTYPE BindSheet( + __in ID3D11DeviceContext *pContext, + __in UINT SheetIndex, + __in UINT Flags + ) = 0; + + /// Insert a glyph into the atlas. + /// The parameters for this method can be obtained as part of the FW1_GLYPHIMAGEDATA structure filled in by the IFW1DWriteRenderTarget::DrawGlyphTemp method. + /// If the glyph is inserted, the ID of the new glyph in the atlas is returned. + /// The ID is always ((SheetIndex << 16) | GlyphIndex), where SheetIndex is the index of the sheet texture the glyph is place in, and GlyphIndex is the index of the glyph in that sheet.
+ /// If the method fails to insert the glyph, the returned value is 0xFFFFFFFF.
+ /// A pointer to an FW1_GLYPHMETRICS structure, specifying the metrics of the glyph to be inserted. + /// A pointer to image data. + /// The number of bytes in a row of image data. + /// The number of bytes between successive pixels. + virtual UINT STDMETHODCALLTYPE InsertGlyph( + __in const FW1_GLYPHMETRICS *pGlyphMetrics, + __in const void *pGlyphData, + __in UINT RowPitch, + __in UINT PixelStride + ) = 0; + + /// Insert a sheet into the atlas. + /// This method is used internally whenever new glyphs no longer fits in existing sheets. The atlas will hold a reference to the sheet for the remainder of its lifetime. + /// On success, eturns the index of the sheet in the atlas after insertion.
If the method fails, 0xFFFFFFFF is returned.
+ /// A pointer ot the glyph sheet to insert. + virtual UINT STDMETHODCALLTYPE InsertSheet( + __in IFW1GlyphSheet *pGlyphSheet + ) = 0; + + /// Flush all new or internally updated sheets. + /// See IFW1GlyphSheet::Flush. + /// No return value. + /// The context to use when updating device resources. + virtual void STDMETHODCALLTYPE Flush( + __in ID3D11DeviceContext *pContext + ) = 0; +}; + +/// Collection of glyph-maps, mapping font/size/glyph information to an ID in a glyph atlas. +/// Whenever a glyph or glyphmap is queried from the glyph-provider, it will be dynamically inserted if it does not already exist. +MIDL_INTERFACE("F8360043-329D-4EC9-B0F8-ACB00FA77420") IFW1GlyphProvider : public IFW1Object { + /// Get the IFW1GlyphAtlas this glyph-provider references. + /// + /// Standard HRESULT error code. + /// Address of a pointer to an IFW1GlyphAtlas. + virtual HRESULT STDMETHODCALLTYPE GetGlyphAtlas( + __out IFW1GlyphAtlas **ppGlyphAtlas + ) = 0; + + /// Get the DirectWrite factory a glyph-provider references. + /// The DirectWrite factory is used internally to create render-targets needed to draw glyph-images that are put in the glyph-atlas. + /// Standard HRESULT error code. + /// Address of a pointer to an IDWriteFactory. + virtual HRESULT STDMETHODCALLTYPE GetDWriteFactory( + __out IDWriteFactory **ppDWriteFactory + ) = 0; + + /// Get the DirectWrite font-collection referenced by a glyph-provider. + /// The DirectWrite font collection is used internally only to match font-faces to unique names. + /// Since different IDWriteFontFace objects can reference the same font, a reliable method of identifying a font is required. + /// This is the only function of the font-collection in the scope of the glyph-provider. + /// A font-face not from the same collection can still be used when requesting glyphs, in which case it will only be identified by its pointer value. + /// Standard HRESULT error code. + /// Address of a pointer to an IDWriteFontCollection. + virtual HRESULT STDMETHODCALLTYPE GetDWriteFontCollection( + __out IDWriteFontCollection **ppFontCollection + ) = 0; + + /// Get a pointer identifying a glyph-map matching the specified font. + /// If the FW1_NONEWGLYPHS flag is not specified, new glyph-maps are created on demand. + /// The glyph-map returned from this method is not meaningful outside of the glyph provider internals, but is needed for subsequent calls to IFW1GlyphProvider::GetAtlasIdFromGlyphIndex. + /// A constant pointer identifying a glyph-map. + /// This pointer should only be used in subsequent calls to IFW1GlyphProvider::GetAtlasIdFromGlyphIndex, and remains valid for the lifetime of the IFW1GlyphProvider.
+ /// A NULL pointer may be returned, if using the FW1_NONEWGLYPHS flag and a matching glyph-map does not exist.
+ /// A DirectWrite font face. + /// The size of the font. + /// Can include zero or more of the following values, ORd together. Any additional values are ignored.
+ /// FW1_ALIASED - No anti-aliasing is used when drawing the glyphs.
+ /// FW1_NONEWGLYPHS - No new glyph-maps are created. + virtual const void* STDMETHODCALLTYPE GetGlyphMapFromFont( + __in IDWriteFontFace *pFontFace, + __in FLOAT FontSize, + __in UINT FontFlags + ) = 0; + + /// Get the ID of the specified glyph in the glyph-atlas. + /// If FW1_NONEWGLYPHS is not specified, any glyph not currently in the atlas will be inserted before the method returns. + /// The ID of the specified glyph in the glyph-atlas. + /// The ID is always ((SheetIndex << 16) | GlyphIndex), where SheetIndex is the index of the sheet texture the glyph is placed in, and GlyphIndex is the index of the glyph in that sheet.
+ /// If the specified glyph does not exist and can not be inserted on demand, the ID of a fallback glyph is returned.
+ /// A pointer identifying a glyph-map, previously obtained using IFW1GlyphProvider::GetGlyphMapFromFont. + /// If this parameter is NULL, the ID of the last-resort fallback glyph is returned, which will be zero. + /// The index of the glyph in the DirectWrite font face. + /// Glyph indices can be obtained from DirectWrite using IDWriteFontFace::GetGlyphIndices. + /// The DirectWrite font face that contains the glyph referenced by GlyphIndex. + /// Can include zero or more of the following values, ORd together. Any additional values are ignored.
+ /// FW1_NONEWGLYPHS - No new glyphs are inserted. + virtual UINT STDMETHODCALLTYPE GetAtlasIdFromGlyphIndex( + __in const void *pGlyphMap, + __in UINT16 GlyphIndex, + __in IDWriteFontFace *pFontFace, + __in UINT FontFlags + ) = 0; +}; + +/// Container for a DirectWrite render-target, used to draw glyph images that are to be inserted in a glyph atlas. +/// +MIDL_INTERFACE("A1EB4141-9A66-4097-A5B0-6FC84F8B162C") IFW1DWriteRenderTarget : public IFW1Object { + /// Draw a glyph-image. + /// The data returned in the FW1_GLYPHIMAGEDATA should only be read, and is valid until the next call to a method in the IFW1DWriteRenderTarget.
+ /// This method is not thread-safe.
+ /// Standard HRESULT error code. + /// The DirectWrite font face containing the glyph. + /// The index of the glyph in the font face. + /// The size of the font. + /// The DirectWrite rendering mode. See DirectWrite documentation. + /// The DirectWrite measuring mode. See DirectWrite documentation.. + /// A pointer to an FW1_GLYPHIMAGEDATA structure that will be filled in with the glyph image data on success. + virtual HRESULT STDMETHODCALLTYPE DrawGlyphTemp( + __in IDWriteFontFace *pFontFace, + __in UINT16 GlyphIndex, + __in FLOAT FontSize, + __in DWRITE_RENDERING_MODE RenderingMode, + __in DWRITE_MEASURING_MODE MeasuringMode, + __out FW1_GLYPHIMAGEDATA *pOutData + ) = 0; +}; + +/// An RGBA color. +/// An IFW1ColorRGBA object can be set as the drawing effect for a range in an IDWriteTextLayout, to override the default color of the text. +MIDL_INTERFACE("A0EA03A0-441D-49BE-9D2C-4AE27BB7A327") IFW1ColorRGBA : public IFW1Object { + /// Set the color. + /// + /// No return value. + /// The color to set, as 0xAaBbGgRr. + virtual void STDMETHODCALLTYPE SetColor( + __in UINT32 Color + ) = 0; + + /// Set the color. + /// + /// No return value. + /// The red component, in [0, 1]. + /// The green component, in [0, 1]. + /// The blue component, in [0, 1]. + /// The alpha component, in [0, 1]. + virtual void STDMETHODCALLTYPE SetColor( + __in FLOAT Red, + __in FLOAT Green, + __in FLOAT Blue, + __in FLOAT Alpha + ) = 0; + + /// Set the color. + /// + /// No return value. + /// Pointer to an array of four floats in [0, 1], specifying the red, green, blue and alpha components at indices 0 to 3. + virtual void STDMETHODCALLTYPE SetColor( + __in const FLOAT *pColor + ) = 0; + + /// Set the color. + /// + /// No return value. + /// Pointer to an array of four bytes in [0, 255], specifying the red, green, blue and alpha components at indices 0 to 3. + virtual void STDMETHODCALLTYPE SetColor( + __in const BYTE *pColor + ) = 0; + + /// Get the color. + /// + /// Returns the color, as 0xAaBbGgRr. + virtual UINT32 STDMETHODCALLTYPE GetColor32( + ) = 0; +}; + +/// A dynamic list of vertices. Note that this object is a simple array without synchronization and not safe to use simultaneously on more than one thread. +/// When rendering a string, a vertex is inserted into an IFW1TextGeometry object for each glyph. +/// The vertices in an IFW1TextGeometry can be drawn by the IFW1FontWrapper::DrawGeometry method.
+/// A pointer to the actual vertices can be obtained with the IFW1TextGeometry::GetGlyphVerticesTemp method.
+MIDL_INTERFACE("51E05736-6AFF-44A8-9745-77605C99E8F2") IFW1TextGeometry : public IFW1Object { + /// Clear any vertices currently contained in the geometry object. + /// This method is not thread-safe. + /// No return value. + virtual void STDMETHODCALLTYPE Clear( + ) = 0; + + /// Adds a vertex to the geometry. + /// The GlyphIndex member of the FW1_GLYPHVERTEX specified when inserting a vertex should be the atlas ID of the desired glyph, as ((SheetIndex << 16) | GlyphIndex). + /// See IFW1GlyphAtlas::InsertGlyph.
+ /// This method is not thread-safe.
+ /// No return value. + /// Pointer to an FW1_GLYPHVERTEX structure describing the vertex. + virtual void STDMETHODCALLTYPE AddGlyphVertex( + __in const FW1_GLYPHVERTEX *pVertex + ) = 0; + + /// Get the vertices in the geometry, sorted by glyph sheet. + /// When glyphs are inserted into the geometry they contain their glyph atlas ID. + /// The glyphs are internally sorted by glyph sheet, and glyphs returned by GetGlyphVerticesTemp contain the index of the glyph in its containing sheet, and not the atlas ID.
+ /// This method is not thread-safe.
+ /// An FW1_VERTEXDATA structure containing the glyph vertices. + /// The pointers in this structure are owned by the geometry object and should not be modified. + /// They are valid until the next call to a method in the IFW1TextGeometry. + virtual FW1_VERTEXDATA STDMETHODCALLTYPE GetGlyphVerticesTemp( + ) = 0; +}; + +/// A text-renderer converts DirectWrite text layouts into glyph-vertices. +/// +MIDL_INTERFACE("51E05736-6AFF-44A8-9745-77605C99E8F2") IFW1TextRenderer : public IFW1Object { + /// Get the IFW1GlyphProvider used by a text-renderer. + /// The glyph provider is used internally to get the atlas IDs for any glyphs needed when drawing a text layout. + /// Standard HRESULT error code. + /// Address of a pointer to an IFW1GlyphProvider. + virtual HRESULT STDMETHODCALLTYPE GetGlyphProvider( + __out IFW1GlyphProvider **ppGlyphProvider + ) = 0; + + /// Convert a text layout to vertices. + /// This method internally calls the IDWriteTextLayout::Draw method, and handles callbacks to convert the formatted text into vertices, which will be stored in the passed IFW1TextGeometry object. + /// This method is not thread-safe. + /// Standard HRESULT error code. + /// A DirectWrite text layout. See the DirectWrite documentation. + /// The X origin of the text. + /// The Y origin of the text. + /// The default text color, as 0xAaGgBbRr. + /// Can include zero or more of the following values, ORd together. Any additional values are ignored.
+ /// FW1_ALIASED - No anti-aliasing is used when drawing the glyphs.
+ /// FW1_NONEWGLYPHS - No new glyphs are inserted into the atlas. Not previously cached glyphs are replaced with a fallback glyph (usually an empty box).
+ /// FW1_CACHEONLY - All glyphs are queried from the glyph-provider and cached in the glyph-atlas, but no geometry is produced.
+ /// FW1_ANALYZEONLY - The text-layout is analyzed and glyph-maps are prepared, but the glyphs in the string are not cached and no geometry is produced.
+ /// + /// An IFW1TextGeometry object that the output vertices will be appended to. + virtual HRESULT STDMETHODCALLTYPE DrawTextLayout( + __in IDWriteTextLayout *pTextLayout, + __in FLOAT OriginX, + __in FLOAT OriginY, + __in UINT32 Color, + __in UINT Flags, + __in IFW1TextGeometry *pTextGeometry + ) = 0; +}; + +/// This interface contains all render states and shaders needed to draw glyphs. +/// +MIDL_INTERFACE("906928B6-79D8-4b42-8CE4-DC7D7046F206") IFW1GlyphRenderStates : public IFW1Object { + /// Get the ID3D11Device that all render states are created on. + /// + /// Standard HRESULT error code. + /// Address of a pointer to an ID3D11Device. + virtual HRESULT STDMETHODCALLTYPE GetDevice( + __out ID3D11Device **ppDevice + ) = 0; + + /// Set the internal states on a context. + /// + /// No return value. + /// The context to set the states on. + /// Can include zero or more of the following values, ORd together. Any additional values are ignored.
+ /// FW1_NOGEOMETRYSHADER - States are set up to draw indexed quads instead of constructing quads in the geometry shader.
+ /// FW1_CLIPRECT - Shaders will be set up to clip any drawn glyphs to the clip-rect set in IFW1GlyphRenderStates::UpdateShaderConstants. + /// + virtual void STDMETHODCALLTYPE SetStates( + __in ID3D11DeviceContext *pContext, + __in UINT Flags + ) = 0; + + /// Update the internal constant buffer. + /// + /// No return value. + /// The context to use to update the constant buffer. + /// A pointer to a rectangle to clip drawn glyphs to. + /// An array of 16 floats, representing a matrix which all glyph vertices will be multiplied with, in the geometry or vertex shader. + virtual void STDMETHODCALLTYPE UpdateShaderConstants( + __in ID3D11DeviceContext *pContext, + __in const FW1_RECTF *pClipRect, + __in const FLOAT *pTransformMatrix + ) = 0; + + /// Returns whether a geometry shader is available. + /// When an IFW1GlyphRenderStates object is created, it may attempt to create a geometry shader, depending on the parameters passed to IFW1Factory::CreateRenderStates. + /// If a geometry shader is not created, either because of the specified parameters or because the device feature level does not support geometry shaders, this method will return FALSE. + /// Returns TRUE if a geometry shader is available, and otherwise returns FALSE. + virtual BOOL STDMETHODCALLTYPE HasGeometryShader( + ) = 0; +}; + +/// A container for a dynamic vertex and index buffer, used to draw glyph vertices. +/// +MIDL_INTERFACE("E6CD7A32-5B59-463c-9B1B-D44074FF655B") IFW1GlyphVertexDrawer : public IFW1Object { + /// Get the ID3D11Device that the buffers are created on. + /// + /// Standard HRESULT error code. + /// Address of a pointer to an ID3D11Device. + virtual HRESULT STDMETHODCALLTYPE GetDevice( + __out ID3D11Device **ppDevice + ) = 0; + + /// Upload the specified vertices to the device buffers and draw them. + /// + /// Returns the index of the sheet in the atlas that was last bound to the device context during the operation. + /// The context to use to draw. + /// The glyph atlas containg the glyphs referenced by the vertices. + /// Pointer to an FW1_VERTEXDATA structure, containing vertices to be drawn, sorted by glyph sheet. + /// These are easiest obtained from an IFW1TextGeometry object. + /// Can include zero or more of the following values, ORd together. Any additional values are ignored.
+ /// FW1_NOGEOMETRYSHADER - Vertices are converted to quads on the fly on the CPU, instead of being sent directly to the device for the geometry shader.
+ /// FW1_BUFFERSPREPARED - The internal buffers are assumed to already be set on the device context from a previous call. (Avoids redundant state changes when drawing multiple times). + /// + /// If a sheet in the atlas is known to already be correctly set on the device context, specify its index in the atlas with this parameter, to avoid redundant state changes. + /// If no sheet is known to already be set, specify 0xFFFFFFFF, or another value greater than the number of sheets in the atlas. + /// + virtual UINT STDMETHODCALLTYPE DrawVertices( + __in ID3D11DeviceContext *pContext, + __in IFW1GlyphAtlas *pGlyphAtlas, + __in const FW1_VERTEXDATA *pVertexData, + __in UINT Flags, + __in UINT PreboundSheet + ) = 0; +}; + +/// The IFW1FontWrapper interface is the main interface used to draw text. +/// It holds references to all objects needed to format and convert text to vertices, as well as the D3D11 states and buffers needed to draw them. +/// Create a font-wrapper using IFW1Factory::CreateFontWrapper +MIDL_INTERFACE("83347A5C-B0B1-460e-A35C-427E8B85F9F4") IFW1FontWrapper : public IFW1Object { + /// Get the ID3D11Device that is used by the font-wrapper. + /// + /// Standard HRESULT error code. + /// Address of a pointer to an ID3D11Device. + virtual HRESULT STDMETHODCALLTYPE GetDevice( + __out ID3D11Device **ppDevice + ) = 0; + + /// Get the DirectWrite factory used by the font-wrapper. + /// The DirectWrite factory is used internally to create text-layouts when drawing strings using any of the DrawString methods. + /// Standard HRESULT error code. + /// Address of a pointer to an IDWriteFactory. + virtual HRESULT STDMETHODCALLTYPE GetDWriteFactory( + __out IDWriteFactory **ppDWriteFactory + ) = 0; + + /// Get the IFW1GlyphAtlas used to cache glyphs. + /// + /// Standard HRESULT error code. + /// Address of a pointer to an IFW1GlyphAtlas. + virtual HRESULT STDMETHODCALLTYPE GetGlyphAtlas( + __out IFW1GlyphAtlas **ppGlyphAtlas + ) = 0; + + /// Get the IFW1GlyphProvider used to map glyphs to atlas IDs. + /// + /// Standard HRESULT error code. + /// Address of a pointer to an IFW1GlyphProvider. + virtual HRESULT STDMETHODCALLTYPE GetGlyphProvider( + __out IFW1GlyphProvider **ppGlyphProvider + ) = 0; + + /// Get the IFW1GlyphRenderStates containing the render states needed to draw glyphs. + /// + /// Standard HRESULT error code. + /// Address of a pointer to an IFW1GlyphRenderStates. + virtual HRESULT STDMETHODCALLTYPE GetRenderStates( + __out IFW1GlyphRenderStates **ppRenderStates + ) = 0; + + /// Get the IFW1GlyphVertexDrawer used to draw glyph vertices. + /// + /// Standard HRESULT error code. + /// Address of a pointer to an IFW1GlyphVertexDrawer. + virtual HRESULT STDMETHODCALLTYPE GetVertexDrawer( + __out IFW1GlyphVertexDrawer **ppVertexDrawer + ) = 0; + + /// Draw a DirectWrite text layout. + /// Consult the DirectWrite documentation for details on how to construct a text-layout.
+ /// The pContext parameter can be NULL only if the FW1_NOFLUSH and either the FW1_ANALYZEONLY or the FW1_CACHEONLY flags are specified.
+ /// No return value. + /// The device context to draw on. + /// The text layout to draw. + /// The X origin of the text in the layout. + /// The Y origin of the text in the layout. + /// The default color of the text, as 0xAaBbGgRr. + /// See FW1_TEXT_FLAG. The alignment and word-wrapping flags have no meaning when drawing a preconstructed text layout. + virtual void STDMETHODCALLTYPE DrawTextLayout( + __in ID3D11DeviceContext *pContext, + __in IDWriteTextLayout *pTextLayout, + __in FLOAT OriginX, + __in FLOAT OriginY, + __in UINT32 Color, + __in UINT Flags + ) = 0; + + /// Draw a DirectWrite text layout. + /// Consult the DirectWrite documentation for details on how to construct a text-layout.
+ /// The pContext parameter can be NULL only if the FW1_NOFLUSH and either the FW1_ANALYZEONLY or the FW1_CACHEONLY flags are specified.
+ /// No return value. + /// The device context to draw on. + /// The text layout to draw. + /// The X origin of the text in the layout. + /// The Y origin of the text in the layout. + /// The default color of the text, as 0xAaBbGgRr. + /// A pointer to a rectangle to clip the text to if also using the FW1_CLIPRECT flag, or NULL to not clip. + /// An array of 16 floats, representing a matrix which the text will be transformed by. + /// See FW1_TEXT_FLAG. The alignment and word-wrapping flags have no meaning when drawing a preconstructed text layout. + virtual void STDMETHODCALLTYPE DrawTextLayout( + __in ID3D11DeviceContext *pContext, + __in IDWriteTextLayout *pTextLayout, + __in FLOAT OriginX, + __in FLOAT OriginY, + __in UINT32 Color, + __in const FW1_RECTF *pClipRect, + __in const FLOAT *pTransformMatrix, + __in UINT Flags + ) = 0; + + /// Draw a string. + /// The pContext parameter can be NULL only if the FW1_NOFLUSH and either the FW1_ANALYZEONLY or the FW1_CACHEONLY flags are specified. + /// No return value. + /// The device context to draw on. + /// The NULL-terminated string to draw. + /// The size of the font. + /// The X origin of the text. + /// The Y origin of the text . + /// The color of the text, as 0xAaBbGgRr. + /// See the FW1_TEXT_FLAG enumeration. + virtual void STDMETHODCALLTYPE DrawString( + __in ID3D11DeviceContext *pContext, + __in const WCHAR *pszString, + __in FLOAT FontSize, + __in FLOAT X, + __in FLOAT Y, + __in UINT32 Color, + __in UINT Flags + ) = 0; + + /// Draw a string. + /// The pContext parameter can be NULL only if the FW1_NOFLUSH and either the FW1_ANALYZEONLY or the FW1_CACHEONLY flags are specified. + /// No return value. + /// The device context to draw on. + /// The NULL-terminated string to draw. + /// The font family to use, such as Arial or Courier New. + /// The size of the font. + /// The X origin of the text. + /// The Y origin of the text . + /// The color of the text, as 0xAaBbGgRr. + /// See the FW1_TEXT_FLAG enumeration. + virtual void STDMETHODCALLTYPE DrawString( + __in ID3D11DeviceContext *pContext, + __in const WCHAR *pszString, + __in const WCHAR *pszFontFamily, + __in FLOAT FontSize, + __in FLOAT X, + __in FLOAT Y, + __in UINT32 Color, + __in UINT Flags + ) = 0; + + /// Draw a string. + /// The pContext parameter can be NULL only if the FW1_NOFLUSH and either the FW1_ANALYZEONLY or the FW1_CACHEONLY flags are specified. + /// No return value. + /// The device context to draw on. + /// The NULL-terminated string to draw. + /// The font family to use, such as Arial or Courier New. + /// The size of the font. + /// A pointer to a rectangle to format the text in. + /// The color of the text, as 0xAaBbGgRr. + /// A pointer to a rectangle to clip the text to if also using the FW1_CLIPRECT flag, or NULL to not clip. + /// An array of 16 floats, representing a matrix which the text will be transformed by, or NULL to draw in screen-space. + /// See the FW1_TEXT_FLAG enumeration. + virtual void STDMETHODCALLTYPE DrawString( + __in ID3D11DeviceContext *pContext, + __in const WCHAR *pszString, + __in const WCHAR *pszFontFamily, + __in FLOAT FontSize, + __in const FW1_RECTF *pLayoutRect, + __in UINT32 Color, + __in const FW1_RECTF *pClipRect, + __in const FLOAT *pTransformMatrix, + __in UINT Flags + ) = 0; + + /// Measure a string. + /// This function uses the IDWriteTextLayout::GetOverhangMetrics to obtain the size of the string. + /// The smallest rectangle that completely contains the string if drawn with DrawString and the same parameters as used with MeasureString. + /// The NULL-terminated string to measure. + /// The font family to use, such as Arial or Courier New. + /// The size of the font. + /// A pointer to a rectangle to format the text in. + /// See the FW1_TEXT_FLAG enumeration. + virtual FW1_RECTF STDMETHODCALLTYPE MeasureString( + __in const WCHAR *pszString, + __in const WCHAR *pszFontFamily, + __in FLOAT FontSize, + __in const FW1_RECTF *pLayoutRect, + __in UINT Flags + ) = 0; + + /// Analyze a string and generate geometry to draw it. + /// pTextGeometry can be NULL if the FW1_ANALYZEONLY or FW1_CACHEONLY flags are specified, as no actual geometry will be generated. + /// pContext can be NULL if the FW1_NOFLUSH flag is used, as any new glyphs will not be flushed to the device buffers. + /// No return value. + /// A device context to use to update device buffers when new glyphs are added to the glyph-atlas. + /// The NULL-terminated string to create geometry from. + /// The font family to use, such as Arial or Courier New. + /// The size of the font. + /// A pointer to a rectangle to format the text in. + /// The color of the text, as 0xAaBbGgRr. + /// See the FW1_TEXT_FLAG enumeration. + /// An IFW1TextGeometry object that the output vertices will be appended to. + virtual void STDMETHODCALLTYPE AnalyzeString( + __in ID3D11DeviceContext *pContext, + __in const WCHAR *pszString, + __in const WCHAR *pszFontFamily, + __in FLOAT FontSize, + __in const FW1_RECTF *pLayoutRect, + __in UINT32 Color, + __in UINT Flags, + __in IFW1TextGeometry *pTextGeometry + ) = 0; + + /// Analyze a text layout and generate geometry to draw it. + /// Consult the DirectWrite documentation for details on how to construct a text-layout. + /// pTextGeometry can be NULL if the FW1_ANALYZEONLY or FW1_CACHEONLY flags are specified, as no actual geometry will be generated. + /// pContext can be NULL if the FW1_NOFLUSH flag is used, as any new glyphs will not be flushed to the device buffers. + /// No return value. + /// A device context to use to update device buffers when new glyphs are added to the glyph-atlas. + /// The DirectWrite text layout to create geometry from. + /// The X origin of the text in the layout. + /// The Y origin of the text in the layout. + /// The default color of the text, as 0xAaBbGgRr. + /// See FW1_TEXT_FLAG. The alignment and word-wrapping flags have no meaning when using a preconstructed text layout. + /// An IFW1TextGeometry object that the output vertices will be appended to. + virtual void STDMETHODCALLTYPE AnalyzeTextLayout( + __in ID3D11DeviceContext *pContext, + __in IDWriteTextLayout *pTextLayout, + __in FLOAT OriginX, + __in FLOAT OriginY, + __in UINT32 Color, + __in UINT Flags, + __in IFW1TextGeometry *pTextGeometry + ) = 0; + + /// Draw geometry. + /// + /// No return value. + /// The device context to draw on. + /// The geometry to draw. + /// A pointer to a rectangle to clip the text to if also using the FW1_CLIPRECT flag, or NULL to not clip. This rect is in text-space, and clipping is performed prior to any transformation. + /// An array of 16 floats, representing a matrix which the text will be transformed by, or NULL to draw in screen-space. + /// See the FW1_TEXT_FLAG enumeration. + virtual void STDMETHODCALLTYPE DrawGeometry( + __in ID3D11DeviceContext *pContext, + __in IFW1TextGeometry *pGeometry, + __in const FW1_RECTF *pClipRect, + __in const FLOAT *pTransformMatrix, + __in UINT Flags + ) = 0; + + /// Flush any new glyphs to GPU resources. + /// This method calls IFW1GlyphAtlas::Flush to flush any newly cached glyphs. + /// This method is only needed if drawing text using the FW1_NOFLUSH flag and delaying flushing data to the device, as otherwise it is implicitly called whenever a string is drawn. See IFW1GlyphAtlas::Flush. + /// No return value. + /// The device context to use to update device resources. + virtual void STDMETHODCALLTYPE Flush( + __in ID3D11DeviceContext *pContext + ) = 0; +}; + +/// +/// Used to create all subsequent FW1 objects. +/// An IFW1Factory can be created using FW1CreateFactory. +/// +/// +/// Any and all FW1 objects are always created through a factory. All FW1 objects inherit from IFW1Object, and holds a reference to the factory that created them. +/// If an object in turn creates new objects, it uses the same factory that created the object itself. +/// For example, a glyph-atlas will ask the factory that created it to create new glyph-sheets as glyphs are added to the atlas. +/// +MIDL_INTERFACE("8004DB2B-B5F9-4420-A6A2-E17E15E4C336") IFW1Factory : public IUnknown { + public: + /// Create an IFW1FontWrapper object with default settings. + /// Standard HRESULT error code. + /// + /// The ID3D11Device the font-wrapper will be used with. + /// The default font-family to use when drawing strings. + /// Valid values include for example L"Arial" and L"Courier New", provided that the fonts are installed on the system. + /// Font-fallback will automatically choose a different font if the specified one is not available. + /// Address of a pointer to a font-wrapper (See IFW1FontWrapper). + virtual HRESULT STDMETHODCALLTYPE CreateFontWrapper( + __in ID3D11Device *pDevice, + __in LPCWSTR pszFontFamily, + __out IFW1FontWrapper **ppFontWrapper + ) = 0; + + /// Create an IFW1FontWrapper object. + /// + /// Standard HRESULT error code. + /// The ID3D11Device that the font-wrapper will be used with. + /// Pointer to an FW1_FONTWRAPPERCREATEPARAMS structure that describes the settings for the new font-wrapper. + /// Address of a pointer to a font-wrapper (See IFW1FontWrapper). + virtual HRESULT STDMETHODCALLTYPE CreateFontWrapper( + __in ID3D11Device *pDevice, + __in IDWriteFactory *pDWriteFactory, + __in const FW1_FONTWRAPPERCREATEPARAMS *pCreateParams, + __out IFW1FontWrapper **ppFontWrapper + ) = 0; + + /// Create an IFW1FontWrapper object. + /// + /// Standard HRESULT error code. + /// The ID3D11Device that the font-wrapper will be used with. + /// An IFW1GlyphAtlas that glyph-images will be stored in. + /// An IFW1GlyphProvider that handles fonts and glyphmaps. + /// An IFW1GlyphVertexDrawer that handles drawing glyph-vertices. + /// An IFW1GlyphRenderStates that handles all needed context states when drawing glyphs. + /// An IDWriteFactory that is used to create render-targets to draw glyphs with. + /// Pointer to an FW1_DWRITEFONTPARAMS that describes the default font. + /// Can be NULL if only drawing preconstructed DirectWrite text layouts. + /// Address of a pointer to a font-wrapper (See IFW1FontWrapper). + virtual HRESULT STDMETHODCALLTYPE CreateFontWrapper( + __in ID3D11Device *pDevice, + __in IFW1GlyphAtlas *pGlyphAtlas, + __in IFW1GlyphProvider *pGlyphProvider, + __in IFW1GlyphVertexDrawer *pGlyphVertexDrawer, + __in IFW1GlyphRenderStates *pGlyphRenderStates, + __in IDWriteFactory *pDWriteFactory, + __in const FW1_DWRITEFONTPARAMS *pDefaultFontParams, + __out IFW1FontWrapper **ppFontWrapper + ) = 0; + + /// Create an IFW1GlyphVertexDrawer object. + /// + /// Standard HRESULT error code. + /// The ID3D11Device that the vertex drawer will be used with. + /// The size in bytes of the dynamic vertex buffer. An index buffer will be created with a matching size. + /// Address of a pointer to a glyph-vertex drawer (See IFW1GlyphVertexDrawer). + virtual HRESULT STDMETHODCALLTYPE CreateGlyphVertexDrawer( + __in ID3D11Device *pDevice, + __in UINT VertexBufferSize, + __out IFW1GlyphVertexDrawer **ppGlyphVertexDrawer + ) = 0; + + /// Create an IFW1GlyphRenderStates object. + /// + /// Standard HRESULT error code. + /// The ID3D11Device that the render-states will be used with. + /// If TRUE, no geometry shader will be created. + /// If TRUE, a sampler state enabling anisotropic filtering will be created. + /// Address of a pointer to a glyph render-states object (See IFW1GlyphRenderStates). + virtual HRESULT STDMETHODCALLTYPE CreateGlyphRenderStates( + __in ID3D11Device *pDevice, + __in BOOL DisableGeometryShader, + __in BOOL AnisotropicFiltering, + __out IFW1GlyphRenderStates **ppGlyphRenderStates + ) = 0; + + /// Create an IFW1TextRenderer object. + /// + /// Standard HRESULT error code. + /// The IFW1GlyphProvider that provides glyph-information for the text-renderer. + /// Address of a pointer to a IFW1TextRenderer. + virtual HRESULT STDMETHODCALLTYPE CreateTextRenderer( + __in IFW1GlyphProvider *pGlyphProvider, + __out IFW1TextRenderer **ppTextRenderer + ) = 0; + + /// Create an IFW1TextGeometry object. + /// + /// Standard HRESULT error code. + /// Address of a pointer to an IFW1TextGeometry. + virtual HRESULT STDMETHODCALLTYPE CreateTextGeometry( + __out IFW1TextGeometry **ppTextGeometry + ) = 0; + + /// Create an IFW1GlyphProvider object. + /// + /// Standard HRESULT error code. + /// A glyph atlas to store glyph images in. + /// A DirectWrite factory, used to create glyph render targets. + /// A font collection used to identify fonts from DirectWrite font-face objects. + /// The maximum width of a single glyph. + /// The maximum height of a single glyph. + /// Address of a pointer to an IFW1GlyphProvider. + virtual HRESULT STDMETHODCALLTYPE CreateGlyphProvider( + __in IFW1GlyphAtlas *pGlyphAtlas, + __in IDWriteFactory *pDWriteFactory, + __in IDWriteFontCollection *pFontCollection, + __in UINT MaxGlyphWidth, + __in UINT MaxGlyphHeight, + __out IFW1GlyphProvider **ppGlyphProvider + ) = 0; + + /// Create an IFW1DWriteRenderTarget object. + /// + /// Standard HRESULT error code. + /// A DirectWrite factory used to create the internal render target. + /// The width of the render target. + /// The height of the render target. + /// Address of a pointer to an IFW1DWriteRenderTarget. + virtual HRESULT STDMETHODCALLTYPE CreateDWriteRenderTarget( + __in IDWriteFactory *pDWriteFactory, + __in UINT RenderTargetWidth, + __in UINT RenderTargetHeight, + __out IFW1DWriteRenderTarget **ppRenderTarget + ) = 0; + + /// Create an IFW1GlyphAtlas object. + /// + /// Standard HRESULT error code. + /// A D3D11 device used to create device resources. + /// Width of the atlas textures. + /// Height of the atlas textures. + /// If TRUE, create a D3D11 buffer with glyph coordinates for each sheet, for use with the geometry shader. + /// If FALSE, glyphs that are larger than the atlas textures will be rejected instead of partially inserted. + /// The maximum number of glyphs in a single sheet texture. + /// The number of mip levels for the textures. + /// The maximum number of sheet textures. + /// Address of a pointer to an IFW1GlyphAtlas. + virtual HRESULT STDMETHODCALLTYPE CreateGlyphAtlas( + __in ID3D11Device *pDevice, + __in UINT GlyphSheetWidth, + __in UINT GlyphSheetHeight, + __in BOOL HardwareCoordBuffer, + __in BOOL AllowOversizedGlyph, + __in UINT MaxGlyphCountPerSheet, + __in UINT MipLevels, + __in UINT MaxGlyphSheetCount, + __out IFW1GlyphAtlas **ppGlyphAtlas + ) = 0; + + /// Create an IFW1GlyphSheet object. + /// + /// Standard HRESULT error code. + /// A D3D11 device used to create device resources. + /// Width of the sheet texture. + /// Height of the sheet texture. + /// If TRUE, create a D3D11 buffer with glyph coordinates, for use with the geometry shader. + /// If FALSE, glyphs that are larger than the sheet texture will be rejected instead of partially inserted. + /// The maximum number of glyphs in the sheet. + /// The number of mip levels for the texture. + /// Address of a pointer to an IFW1GlyphSheet. + virtual HRESULT STDMETHODCALLTYPE CreateGlyphSheet( + __in ID3D11Device *pDevice, + __in UINT GlyphSheetWidth, + __in UINT GlyphSheetHeight, + __in BOOL HardwareCoordBuffer, + __in BOOL AllowOversizedGlyph, + __in UINT MaxGlyphCount, + __in UINT MipLevels, + __out IFW1GlyphSheet **ppGlyphSheet + ) = 0; + + /// Create an IFW1ColorRGBA object. + /// An IFW1ColorRGBA can be set as the drawing effect for a range in a DirectWrite text layout to override the default color. + /// Standard HRESULT error code. + /// The initial color, as 0xAaBbGgRr. + /// Address of a pointer to an IFW1ColorRGBA. + virtual HRESULT STDMETHODCALLTYPE CreateColor( + __in UINT32 Color, + __out IFW1ColorRGBA **ppColor + ) = 0; +}; + +#ifdef FW1_COMPILETODLL + extern "C" __declspec(dllexport) HRESULT STDMETHODCALLTYPE FW1CreateFactory( + __in UINT32 Version, + __out IFW1Factory **ppFactory + ); +#else + /// The FW1CreateFactory method creates an IFWFactory object, that can subsequently be used to create any and all FW1 objects. + /// + /// Standard HRESULT error code. + /// Set to FW1_VERSION. Is used to make sure the header matches the library version. + /// Address of a pointer to an IFW1Factory. + extern "C" HRESULT STDMETHODCALLTYPE FW1CreateFactory( + __in UINT32 Version, + __out IFW1Factory **ppFactory + ); +#endif + +typedef HRESULT (STDMETHODCALLTYPE * PFN_FW1CREATEFACTORY) (UINT32 Version, IFW1Factory **ppFactory); + + +#endif// IncludeGuard__FW1_FW1FontWrapper_h diff --git a/no_renderer/FW1FontWrapper/FW1Precompiled.cpp b/no_renderer/FW1FontWrapper/FW1Precompiled.cpp new file mode 100644 index 0000000..4098ef1 --- /dev/null +++ b/no_renderer/FW1FontWrapper/FW1Precompiled.cpp @@ -0,0 +1,4 @@ +// FW1Precompiled.cpp + +#include "FW1Precompiled.h" + diff --git a/no_renderer/FW1FontWrapper/FW1Precompiled.h b/no_renderer/FW1FontWrapper/FW1Precompiled.h new file mode 100644 index 0000000..f0fd35f --- /dev/null +++ b/no_renderer/FW1FontWrapper/FW1Precompiled.h @@ -0,0 +1,24 @@ +// FW1Precompiled.h + +#ifndef IncludeGuard__FW1_FW1Precompiled_h +#define IncludeGuard__FW1_FW1Precompiled_h + + +#define NOMINMAX +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FW1CompileSettings.h" +#include "FW1FontWrapper.h" + + +#endif// IncludeGuard__FW1_FW1Precompiled_h diff --git a/no_renderer/no_gui/no_gui.cpp b/no_renderer/no_gui/no_gui.cpp new file mode 100644 index 0000000..aeb658e --- /dev/null +++ b/no_renderer/no_gui/no_gui.cpp @@ -0,0 +1,388 @@ +#include "no_gui.h" + +bool no_gui::init(IDXGISwapChain* swapchain) +{ + HRESULT hr; + m_swap_chain = swapchain; + if (!m_swap_chain) + return false; + + m_swap_chain->GetDevice(__uuidof(m_device), (void**)&m_device); + m_device->GetImmediateContext(&m_device_context); + hr = m_device->CreateVertexShader(vs_blob, sizeof(vs_blob), NULL, &m_vertex_shader); + + D3D11_INPUT_ELEMENT_DESC layout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 } + }; + + hr = m_device->CreateInputLayout(layout, ARRAYSIZE(layout), vs_blob, sizeof(vs_blob), &m_input_layout); + hr = m_device->CreatePixelShader(ps_blob, sizeof(ps_blob), NULL, &m_pixel_shader); + + D3D11_BUFFER_DESC buffer_desc; + + buffer_desc.Usage = D3D11_USAGE_DYNAMIC; + buffer_desc.ByteWidth = 4 * sizeof(COLOR_VERTEX); + buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + buffer_desc.MiscFlags = 0; + + hr = m_device->CreateBuffer(&buffer_desc, NULL, &m_pvertex_buffer); + if (FAILED(hr)) + return false; + + D3D11_BLEND_DESC blend_state_desc; + ZeroMemory(&blend_state_desc, sizeof(blend_state_desc)); + blend_state_desc.AlphaToCoverageEnable = false; + blend_state_desc.RenderTarget[0].BlendEnable = true; + blend_state_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + blend_state_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blend_state_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + blend_state_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blend_state_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + blend_state_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blend_state_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + + hr = m_device->CreateBlendState(&blend_state_desc, &m_transparency); + if (FAILED(hr)) + return false; + + memset((void*)vs_blob, NULL, sizeof(vs_blob)); + memset((void*)ps_blob, NULL, sizeof(ps_blob)); + return true; +} + +void no_gui::reset() +{ + init(m_swap_chain); +} + +void no_gui::fill_rect(float x, float y, float w, float h, color color) +{ + if (!m_device_context) + return; + + int a = color.A & 0xff; + int r = color.R & 0xff; + int g = color.G & 0xff; + int b = color.B & 0xff; + + DXGI_SWAP_CHAIN_DESC swap_chain_desc; + memset(&swap_chain_desc, 0, sizeof(swap_chain_desc)); + + m_swap_chain->GetDesc(&swap_chain_desc); + float width = swap_chain_desc.BufferDesc.Width; + float height = swap_chain_desc.BufferDesc.Height; + + UINT numViewports = 1; + D3D11_VIEWPORT vp = { 0, 0, width, height, 1, 1 }; + m_device_context->RSSetViewports(numViewports, &vp); + + float x0 = x; + float y0 = y; + float x1 = x + w; + float y1 = y + h; + + float xx0 = 2.0f * (x0 - 0.5f) / vp.Width - 1.0f; + float yy0 = 1.0f - 2.0f * (y0 - 0.5f) / vp.Height; + float xx1 = 2.0f * (x1 - 0.5f) / vp.Width - 1.0f; + float yy1 = 1.0f - 2.0f * (y1 - 0.5f) / vp.Height; + + COLOR_VERTEX* v = NULL; + D3D11_MAPPED_SUBRESOURCE mapData; + + if (FAILED(m_device_context->Map(m_pvertex_buffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &mapData))) + return; + + v = (COLOR_VERTEX*)mapData.pData; + + v[0].Position.x = (float)x0; + v[0].Position.y = (float)y0; + v[0].Position.z = 0; + v[0].Color = vec4( + ((float)r / 255.0f), + ((float)g / 255.0f), + ((float)b / 255.0f), + ((float)a / 255.0f)); + + v[1].Position.x = (float)x1; + v[1].Position.y = (float)y1; + v[1].Position.z = 0; + v[1].Color = vec4( + ((float)r / 255.0f), + ((float)g / 255.0f), + ((float)b / 255.0f), + ((float)a / 255.0f)); + + v[0].Position.x = xx0; + v[0].Position.y = yy0; + v[0].Position.z = 0; + v[0].Color = vec4( + ((float)r / 255.0f), + ((float)g / 255.0f), + ((float)b / 255.0f), + ((float)a / 255.0f)); + + v[1].Position.x = xx1; + v[1].Position.y = yy0; + v[1].Position.z = 0; + v[1].Color = vec4( + ((float)r / 255.0f), + ((float)g / 255.0f), + ((float)b / 255.0f), + ((float)a / 255.0f)); + + v[2].Position.x = xx0; + v[2].Position.y = yy1; + v[2].Position.z = 0; + v[2].Color = vec4( + ((float)r / 255.0f), + ((float)g / 255.0f), + ((float)b / 255.0f), + ((float)a / 255.0f)); + + v[3].Position.x = xx1; + v[3].Position.y = yy1; + v[3].Position.z = 0; + v[3].Color = vec4( + ((float)r / 255.0f), + ((float)g / 255.0f), + ((float)b / 255.0f), + ((float)a / 255.0f)); + + + m_device_context->Unmap(m_pvertex_buffer, NULL); + + UINT Stride = sizeof(COLOR_VERTEX); + UINT Offset = 0; + + m_device_context->IASetVertexBuffers(0, 1, &m_pvertex_buffer, &Stride, &Offset); + m_device_context->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + m_device_context->IASetInputLayout(m_input_layout); + + m_device_context->VSSetShader(m_vertex_shader, 0, 0); + m_device_context->PSSetShader(m_pixel_shader, 0, 0); + m_device_context->GSSetShader(NULL, 0, 0); + m_device_context->Draw(4, 0); +} + +void no_gui::draw_string(std::string str, float fontSize, float x, float y, float r, float g, float b, float a) +{ + +} + +void no_gui::draw_line(float x1, float y1, float x2, float y2, color color) +{ + float blendFactor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + m_device_context->OMSetBlendState(m_transparency, blendFactor, 0xffffffff); + + if (m_device_context == NULL) { + return; + } + int a = color.A & 0xff; + int r = color.R & 0xff; + int g = color.G & 0xff; + int b = color.B & 0xff; + + UINT viewportNumber = 1; + + D3D11_VIEWPORT vp; + + m_device_context->RSGetViewports(&viewportNumber, &vp); + + float xx0 = 2.0f * (x1 - 0.5f) / vp.Width - 1.0f; + float yy0 = 1.0f - 2.0f * (y1 - 0.5f) / vp.Height; + float xx1 = 2.0f * (x2 - 0.5f) / vp.Width - 1.0f; + float yy1 = 1.0f - 2.0f * (y2 - 0.5f) / vp.Height; + + COLOR_VERTEX* v = NULL; + + D3D11_MAPPED_SUBRESOURCE mapData; + + if (FAILED(m_device_context->Map(m_pvertex_buffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &mapData))) + return; + + v = (COLOR_VERTEX*)mapData.pData; + v[0].Position.x = xx0; + v[0].Position.y = yy0; + + v[0].Position.z = 0; + v[0].Color = vec4( + ((float)r / 255.0f), + ((float)g / 255.0f), + ((float)b / 255.0f), + ((float)a / 255.0f)); + + v[1].Position.x = xx1; + v[1].Position.y = yy1; + v[1].Position.z = 0; + v[1].Color = vec4( + ((float)r / 255.0f), + ((float)g / 255.0f), + ((float)b / 255.0f), + ((float)a / 255.0f)); + + m_device_context->Unmap(m_pvertex_buffer, NULL); + UINT Stride = sizeof(COLOR_VERTEX); + UINT Offset = 0; + + m_device_context->IASetVertexBuffers(0, 1, &m_pvertex_buffer, &Stride, &Offset); + m_device_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP); + m_device_context->IASetInputLayout(m_input_layout); + + m_device_context->VSSetShader(m_vertex_shader, 0, 0); + m_device_context->PSSetShader(m_pixel_shader, 0, 0); + m_device_context->GSSetShader(NULL, 0, 0); + m_device_context->Draw(2, 0); +} + +void no_gui::draw_rect(float x, float y, float w, float h, color strokeColor) +{ + fill_rect(x, y, w, 1, strokeColor); + fill_rect(x, y + h - 1, w, 1, strokeColor); + fill_rect(x, y + 1, 1, h - 2 * 1, strokeColor); + fill_rect(x + w - 1, y + 1, 1, h - 2 * 1, strokeColor); +} + +void no_gui::draw_outlined_rect(const vec4& rect, const color& strokeColor, const color& color) +{ + fill_rect(rect.x, rect.y, rect.z, rect.w, color); + draw_rect(rect.x, rect.y, rect.z, rect.w, strokeColor); +} + +void no_gui::draw_corner_box(int x, int y, int w, int h, int borderPx, color& temp) +{ + fill_rect(x - (w / 2), (y - h + borderPx), w / 3, borderPx, temp); //top + fill_rect(x - (w / 2) + w - w / 3, (y - h + borderPx), w / 3, borderPx, temp); //top + fill_rect(x - (w / 2), (y - h + borderPx), borderPx, w / 3, temp); //left + fill_rect(x - (w / 2), (y - h + borderPx) + h - w / 3, borderPx, w / 3, temp); //left + fill_rect(x - (w / 2), y, w / 3, borderPx, temp); //bottom + fill_rect(x - (w / 2) + w - w / 3, y, w / 3, borderPx, temp); //bottom + fill_rect((x + w - borderPx) - (w / 2), (y - h + borderPx), borderPx, w / 3, temp); //right + fill_rect((x + w - borderPx) - (w / 2), (y - h + borderPx) + h - w / 3, borderPx, w / 3, temp); //right +} + +void no_gui::draw_border(int x, int y, int w, int h, int px, color& temp) +{ + fill_rect(x, (y + h - px), w, px, temp); + fill_rect(x, y, px, h, temp); + fill_rect(x, y, w, px, temp); + fill_rect((x + w - px), y, px, h, temp); +} + +void no_gui::draw_cross(float x, float y, float width, float height, const color& color) +{ + fill_rect(x - width, y - 0.5f, (width * 2.0f), 1.0f, color); + fill_rect(x - 0.5f, y - height, 1.0f, (height * 2.0f), color); +} + +void no_gui::draw_circle(float x0, float y0, float radius, const color& color, float thickness) +{ + int x = radius, y = 0; + int radius_error = 1 - x; + + while (x >= y) + { + fill_rect(x + x0, y + y0, thickness, thickness, color); + fill_rect(y + x0, x + y0, thickness, thickness, color); + fill_rect(-x + x0, y + y0, thickness, thickness, color); + fill_rect(-y + x0, x + y0, thickness, thickness, color); + fill_rect(-x + x0, -y + y0, thickness, thickness, color); + fill_rect(-y + x0, -x + y0, thickness, thickness, color); + fill_rect(x + x0, -y + y0, thickness, thickness, color); + fill_rect(y + x0, -x + y0, thickness, thickness, color); + y++; + + if (radius_error < 0) + radius_error += 2 * y + 1; + else + { + x--; + radius_error += 2 * (y - x + 1); + } + } +} + +void no_gui::draw_health_bar(int x, int y, float health, float max_health, int w, int h, bool is_shield) +{ + auto c_black = ::color(12, 12, 12, 228); + auto c_red = ::color(255, 0, 0, 255); + auto c_green = ::color(255, 0, 255, 0); + auto c_yellow = ::color(255, 255, 255, 0); + auto c_cyan = ::color(255, 0, 255, 255); + auto c_orange = ::color(255, 255, 153, 0); + + if (is_shield) + { + c_red = ::color(255, 102, 2, 209); + c_green = ::color(255, 19, 105, 244); + c_yellow = ::color(255, 13, 175, 229); + c_orange = ::color(255, 171, 13, 229); + } + + if (health > max_health) + health = max_health; + + FLOAT hp = health; + FLOAT factor = max_health / 4; + auto color = ::color(0.f, 0.f, 0.f, 0.f); + + if (hp <= factor) + color = c_red; + else if (hp <= factor * 2) + color = c_orange; + else if (hp <= factor * 3) + color = c_yellow; + else if (hp <= max_health) + color = c_green; + + fill_rect(x, y, w, h + 1, ::color(255, 0, 0, 0)); + UINT hw = (UINT)(((w - 2) * health) / max_health); + fill_rect(x + 1, y + 1, hw, h - 1, color); + +} + +HWND no_gui::get_window() +{ + return m_hwnd; +} + +float no_gui::get_width() +{ + return m_width; +} + +float no_gui::get_height() +{ + return m_height; +} + +void no_gui::begin_scene() +{ + m_swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&m_back_buffer); + ID3D11RenderTargetView* p_rtv; + m_device->CreateRenderTargetView(m_back_buffer, NULL, &p_rtv); + m_device_context->OMSetRenderTargets(1, &p_rtv, NULL); + + DXGI_SWAP_CHAIN_DESC swap_chain_desc; + memset(&swap_chain_desc, 0, sizeof(swap_chain_desc)); + m_swap_chain->GetDesc(&swap_chain_desc); + m_width = swap_chain_desc.BufferDesc.Width; + m_height = swap_chain_desc.BufferDesc.Height; + + m_restore_state = false; + if (SUCCEEDED(m_state_saver.save_current_state(m_device_context))) + m_restore_state = true; + m_device_context->IASetInputLayout(m_input_layout); +} + +void no_gui::end_scene() +{ + D3D11_TEXTURE2D_DESC backBufferDesc; + m_back_buffer->GetDesc(&backBufferDesc); + m_back_buffer->Release(); + + if (m_restore_state) + m_state_saver.restore_saved_state(); +} \ No newline at end of file diff --git a/no_renderer/no_gui/no_gui.h b/no_renderer/no_gui/no_gui.h new file mode 100644 index 0000000..fe7bd76 --- /dev/null +++ b/no_renderer/no_gui/no_gui.h @@ -0,0 +1,178 @@ +#pragma once +#include +#include +#include +#include + +#include "no_shaders.h" +#include "no_state_saver.h" +#include + +template inline void SAFE_DELETE(T*& p) +{ + if (p) + { + delete p; + p = NULL; + } +} + +template inline void SAFE_DELETE_ARRAY(T*& p) +{ + if (p) + { + delete[] p; + p = NULL; + } +} + +template inline void SAFE_RELEASE(T*& p) +{ + if (p) + { + p->Release(); + p = NULL; + } +} + +class vec3 +{ +public: + float x, y, z; + vec3(); + vec3(float, float, float); + + vec3 operator+(const vec3& v) { + return vec3{ x + v.x, y + v.y, z + v.z }; + } + + vec3 operator-(const vec3& v) { + return vec3{ x - v.x, y - v.y, z - v.z }; + } + + vec3 operator*(const float v) { + return vec3{ x * v, y * v, z * v }; + } + + vec3 operator/(const float fl) const { + return vec3(x / fl, y / fl, z / fl); + } + + inline float distance(vec3 v) + { + return float(sqrtf(powf(v.x - x, 2.0) + powf(v.y - y, 2.0) + powf(v.z - z, 2.0))); + } + + inline double Length() { + return sqrt(x * x + y * y + z * z); + } +}; + +inline vec3::vec3() +{ + x = y = z = 0.f; +} + +inline vec3::vec3(float _x, float _y, float _z) +{ + x = _x; + y = _y; + z = _z; +} +class vec4 +{ +public: + float x, y, z, w; + vec4(); + vec4(float, float, float, float); +}; + +inline vec4::vec4() +{ + x = y = z = w = 0.f; +} + +inline vec4::vec4(float _x, float _y, float _z, float _w) +{ + x = _x; + y = _y; + z = _z; + w = _w; +} +struct COLOR_VERTEX +{ + vec3 Position; + vec4 Color; +}; + +typedef unsigned char uchar; + +class color +{ +public: + uchar A, R, G, B; + + color() + { + A = R = G = B = 0; + } + + color(uchar A, uchar R, uchar G, uchar B) + { + this->A = A; + this->R = R; + this->G = G; + this->B = B; + } +}; + +enum _ALIGN : DWORD +{ + ALIGN_LEFT = 0, + ALIGN_RIGHT, + ALIGN_CENTER, +}; + + +class no_gui +{ +public: + + bool init(IDXGISwapChain* swap_chain); + void begin_scene(); + void end_scene(); + void reset(); + + void fill_rect(float x, float y, float w, float h, color color); + void draw_circle(float x0, float y0, float radius, const color& color, float thickness = 1.5f); + + void draw_string(std::string str, float fontSize, float x, float y, float r, float g, float b, float a); + + void draw_outlined_rect(const vec4& rect, const color& stroke_color, const color& color); + void draw_line(float x1, float y1, float x2, float y2, color color); + void draw_rect(float x, float y, float w, float h, color stroke_color); + void draw_corner_box(int x, int y, int w, int h, int border_px, color& temp); + void draw_border(int x, int y, int w, int h, int px, color& temp); + void draw_cross(float X, float Y, float Width, float Height, const color& d_color); + void draw_health_bar(int x, int y, float health, float max_health, int w, int h, bool is_shield = false); + + float get_width(); + float get_height(); + HWND get_window(); + +private: + IDXGISwapChain* m_swap_chain; + ID3D11Device* m_device; + ID3D11DeviceContext* m_device_context; + ID3D11InputLayout* m_input_layout; + ID3D11Buffer* m_pvertex_buffer; + no_state_saver m_state_saver; + ID3D11VertexShader* m_vertex_shader; + ID3D11PixelShader* m_pixel_shader; + ID3D11BlendState* m_transparency; + ID3D11Texture2D* m_back_buffer; + + float m_width, m_height; + HWND m_hwnd; + bool m_restore_state; +}; diff --git a/no_renderer/no_gui/no_shaders.h b/no_renderer/no_gui/no_shaders.h new file mode 100644 index 0000000..90b51d6 --- /dev/null +++ b/no_renderer/no_gui/no_shaders.h @@ -0,0 +1,124 @@ +#pragma once +// precompiled shaders +static const unsigned char vs_blob[] = { + 0x44, 0x58, 0x42, 0x43, 0x5f, 0x0b, 0x2c, 0x91, 0x23, 0xda, 0xe8, 0xae, + 0x94, 0x4b, 0x71, 0xfd, 0x64, 0x11, 0xb9, 0x13, 0x01, 0x00, 0x00, 0x00, + 0x10, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, + 0x94, 0x01, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe, 0xff, 0x00, 0x01, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, + 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, + 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, + 0x65, 0x72, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x00, 0x49, 0x53, 0x47, 0x4e, + 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, + 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, + 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, + 0x4f, 0x4e, 0x00, 0xab, 0x4f, 0x53, 0x47, 0x4e, 0x4c, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x43, 0x4f, 0x4c, 0x4f, + 0x52, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, + 0x4e, 0x00, 0xab, 0xab, 0x53, 0x48, 0x44, 0x52, 0x68, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x01, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, + 0xf2, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x03, + 0xf2, 0x10, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, + 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x04, + 0xf2, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x05, 0xf2, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x46, 0x1e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, + 0xf2, 0x20, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x1e, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, + 0x74, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const unsigned char ps_blob[] = { + 0x44, 0x58, 0x42, 0x43, 0x71, 0xee, 0xb8, 0x3b, 0xe2, 0x77, 0xf8, 0x55, + 0x47, 0x8a, 0x89, 0xf3, 0x78, 0x2f, 0x06, 0xe9, 0x01, 0x00, 0x00, 0x00, + 0xa0, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x00, 0x52, 0x44, 0x45, 0x46, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x00, 0x04, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, + 0x74, 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, + 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, + 0x65, 0x72, 0x20, 0x31, 0x30, 0x2e, 0x31, 0x00, 0x49, 0x53, 0x47, 0x4e, + 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, + 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0xab, 0xab, 0x4f, 0x53, 0x47, 0x4e, + 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x53, 0x56, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x00, 0xab, 0xab, + 0x53, 0x48, 0x44, 0x52, 0x38, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x62, 0x10, 0x00, 0x03, 0xf2, 0x10, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x03, 0xf2, 0x20, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x05, 0xf2, 0x20, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x1e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x00, 0x01, 0x53, 0x54, 0x41, 0x54, 0x74, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0 +}; + + +/* +static char shader[] = { +"Texture2D g_texture : register(t0);" +"SamplerState g_sampler : register(s1);" + +"struct VSOut" +"{" +" float4 Pos : SV_POSITION;" +" float4 Col : COLOR;" +" float2 Uv : TEXCOORD;" +"};" + +"struct VSInput" +"{" +" float4 Pos : POSITION;" +" float4 Col : COLOR;" +" float2 Uv : TEXCOORD;" +"};" + +"VSOut VS( VSInput Input )" +"{" +" VSOut Result;" +" Result.Col = Input.Col;" +" Result.Pos = Input.Pos;" +" Result.Uv = Input.Uv;" +" return Result;" +"}" + +"float4 PS( VSOut Input ) : SV_TARGET" +"{" +" if(Input.Uv.x == 0 && Input.Uv.y == 0)" +" return Input.Col;" + + "return g_texture.Sample( g_sampler, Input.Uv ) * Input.Col;" +"};" +};*/ \ No newline at end of file diff --git a/no_renderer/no_gui/no_state_saver.cpp b/no_renderer/no_gui/no_state_saver.cpp new file mode 100644 index 0000000..04c6cbe --- /dev/null +++ b/no_renderer/no_gui/no_state_saver.cpp @@ -0,0 +1,198 @@ +#include "no_gui.h" + +no_state_saver::no_state_saver() : + m_saved_state(false), + m_feature_level(D3D_FEATURE_LEVEL_11_0), + m_pcontext(NULL), + m_primitive_topology(D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED), + m_pinput_layout(NULL), + m_pblend_state(NULL), + m_sample_mask(0xffffffff), + m_pdepth_stencil_state(NULL), + m_stencilRef(0), + m_pRasterizerState(NULL), + m_pPSSRV(NULL), + m_pSamplerState(NULL), + m_pVS(NULL), + m_numVSClassInstances(0), + m_pVSConstantBuffer(NULL), + m_pGS(NULL), + m_numGSClassInstances(0), + m_pGSConstantBuffer(NULL), + m_pGSSRV(NULL), + m_pPS(NULL), + m_numPSClassInstances(0), + m_pHS(NULL), + m_numHSClassInstances(0), + m_pDS(NULL), + m_numDSClassInstances(0), + m_pVB(NULL), + m_vertexStride(0), + m_vertexOffset(0), + m_pIndexBuffer(NULL), + m_indexFormat(DXGI_FORMAT_UNKNOWN), + m_indexOffset(0) +{ + for (int i = 0; i < 4; ++i) + m_blend_factor[i] = 0.0f; + for (int i = 0; i < 256; ++i) + { + m_pVSClassInstances[i] = NULL; + m_pGSClassInstances[i] = NULL; + m_pPSClassInstances[i] = NULL; + m_pHSClassInstances[i] = NULL; + m_pDSClassInstances[i] = NULL; + } +} + +no_state_saver::~no_state_saver() +{ + release_saved_state(); +} + +HRESULT no_state_saver::save_current_state(ID3D11DeviceContext *pContext) +{ + if (m_saved_state) + release_saved_state(); + if (pContext == NULL) + return E_INVALIDARG; + + ID3D11Device *p_device; + pContext->GetDevice(&p_device); + if (p_device != NULL) { + m_feature_level = p_device->GetFeatureLevel(); + p_device->Release(); + } + + pContext->AddRef(); + m_pcontext = pContext; + + m_pcontext->IAGetPrimitiveTopology(&m_primitive_topology); + m_pcontext->IAGetInputLayout(&m_pinput_layout); + + m_pcontext->OMGetBlendState(&m_pblend_state, m_blend_factor, &m_sample_mask); + m_pcontext->OMGetDepthStencilState(&m_pdepth_stencil_state, &m_stencilRef); + + m_pcontext->RSGetState(&m_pRasterizerState); + + m_numVSClassInstances = 256; + m_pcontext->VSGetShader(&m_pVS, m_pVSClassInstances, &m_numVSClassInstances); + m_pcontext->VSGetConstantBuffers(0, 1, &m_pVSConstantBuffer); + + m_numPSClassInstances = 256; + m_pcontext->PSGetShader(&m_pPS, m_pPSClassInstances, &m_numPSClassInstances); + m_pcontext->PSGetShaderResources(0, 1, &m_pPSSRV); + pContext->PSGetSamplers(0, 1, &m_pSamplerState); + + if (m_feature_level >= D3D_FEATURE_LEVEL_10_0) + { + m_numGSClassInstances = 256; + m_pcontext->GSGetShader(&m_pGS, m_pGSClassInstances, &m_numGSClassInstances); + m_pcontext->GSGetConstantBuffers(0, 1, &m_pGSConstantBuffer); + + m_pcontext->GSGetShaderResources(0, 1, &m_pGSSRV); + + if (m_feature_level >= D3D_FEATURE_LEVEL_11_0) + { + m_numHSClassInstances = 256; + m_pcontext->HSGetShader(&m_pHS, m_pHSClassInstances, &m_numHSClassInstances); + + m_numDSClassInstances = 256; + m_pcontext->DSGetShader(&m_pDS, m_pDSClassInstances, &m_numDSClassInstances); + } + } + + m_pcontext->IAGetVertexBuffers(0, 1, &m_pVB, &m_vertexStride, &m_vertexOffset); + + m_pcontext->IAGetIndexBuffer(&m_pIndexBuffer, &m_indexFormat, &m_indexOffset); + + m_saved_state = true; + + return S_OK; +} + +HRESULT no_state_saver::restore_saved_state() +{ + if (!m_saved_state) + return E_FAIL; + + m_pcontext->IASetPrimitiveTopology(m_primitive_topology); + m_pcontext->IASetInputLayout(m_pinput_layout); + + m_pcontext->OMSetBlendState(m_pblend_state, m_blend_factor, m_sample_mask); + m_pcontext->OMSetDepthStencilState(m_pdepth_stencil_state, m_stencilRef); + + m_pcontext->RSSetState(m_pRasterizerState); + + m_pcontext->VSSetShader(m_pVS, m_pVSClassInstances, m_numVSClassInstances); + m_pcontext->VSSetConstantBuffers(0, 1, &m_pVSConstantBuffer); + + m_pcontext->PSSetShader(m_pPS, m_pPSClassInstances, m_numPSClassInstances); + m_pcontext->PSSetShaderResources(0, 1, &m_pPSSRV); + m_pcontext->PSSetSamplers(0, 1, &m_pSamplerState); + + if (m_feature_level >= D3D_FEATURE_LEVEL_10_0) + { + m_pcontext->GSSetShader(m_pGS, m_pGSClassInstances, m_numGSClassInstances); + m_pcontext->GSSetConstantBuffers(0, 1, &m_pGSConstantBuffer); + m_pcontext->GSSetShaderResources(0, 1, &m_pGSSRV); + + if (m_feature_level >= D3D_FEATURE_LEVEL_11_0) + { + m_pcontext->HSSetShader(m_pHS, m_pHSClassInstances, m_numHSClassInstances); + m_pcontext->DSSetShader(m_pDS, m_pDSClassInstances, m_numDSClassInstances); + } + } + + m_pcontext->IASetVertexBuffers(0, 1, &m_pVB, &m_vertexStride, &m_vertexOffset); + m_pcontext->IASetIndexBuffer(m_pIndexBuffer, m_indexFormat, m_indexOffset); + return S_OK; +} + +void no_state_saver::release_saved_state() +{ + m_primitive_topology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + SAFE_RELEASE(m_pinput_layout); + SAFE_RELEASE(m_pblend_state); + for (int i = 0; i < 4; ++i) + m_blend_factor[i] = 0.0f; + m_sample_mask = 0xffffffff; + SAFE_RELEASE(m_pdepth_stencil_state); + m_stencilRef = 0; + SAFE_RELEASE(m_pRasterizerState); + SAFE_RELEASE(m_pPSSRV); + SAFE_RELEASE(m_pSamplerState); + SAFE_RELEASE(m_pVS); + for (UINT i = 0; i < m_numVSClassInstances; ++i) + SAFE_RELEASE(m_pVSClassInstances[i]); + m_numVSClassInstances = 0; + SAFE_RELEASE(m_pVSConstantBuffer); + SAFE_RELEASE(m_pGS); + for (UINT i = 0; i < m_numGSClassInstances; ++i) + SAFE_RELEASE(m_pGSClassInstances[i]); + m_numGSClassInstances = 0; + SAFE_RELEASE(m_pGSConstantBuffer); + SAFE_RELEASE(m_pGSSRV); + SAFE_RELEASE(m_pPS); + for (UINT i = 0; i < m_numPSClassInstances; ++i) + SAFE_RELEASE(m_pPSClassInstances[i]); + m_numPSClassInstances = 0; + SAFE_RELEASE(m_pHS); + for (UINT i = 0; i < m_numHSClassInstances; ++i) + SAFE_RELEASE(m_pHSClassInstances[i]); + m_numHSClassInstances = 0; + SAFE_RELEASE(m_pDS); + for (UINT i = 0; i < m_numDSClassInstances; ++i) + SAFE_RELEASE(m_pDSClassInstances[i]); + m_numDSClassInstances = 0; + SAFE_RELEASE(m_pVB); + m_vertexStride = 0; + m_vertexOffset = 0; + SAFE_RELEASE(m_pIndexBuffer); + m_indexFormat = DXGI_FORMAT_UNKNOWN; + m_indexOffset = 0; + + SAFE_RELEASE(m_pcontext); + m_feature_level = D3D_FEATURE_LEVEL_11_0; + m_saved_state = false; +} \ No newline at end of file diff --git a/no_renderer/no_gui/no_state_saver.h b/no_renderer/no_gui/no_state_saver.h new file mode 100644 index 0000000..bd42b13 --- /dev/null +++ b/no_renderer/no_gui/no_state_saver.h @@ -0,0 +1,56 @@ +#pragma once +#include "no_gui.h" + +class no_state_saver +{ +private: + bool m_saved_state; + D3D_FEATURE_LEVEL m_feature_level; + ID3D11DeviceContext *m_pcontext; + D3D11_PRIMITIVE_TOPOLOGY m_primitive_topology; + ID3D11InputLayout *m_pinput_layout; + ID3D11BlendState *m_pblend_state; + float m_blend_factor[4]; + UINT m_sample_mask; + ID3D11DepthStencilState *m_pdepth_stencil_state; + UINT m_stencilRef; + ID3D11RasterizerState *m_pRasterizerState; + ID3D11ShaderResourceView *m_pPSSRV; + ID3D11SamplerState *m_pSamplerState; + ID3D11VertexShader *m_pVS; + ID3D11ClassInstance *m_pVSClassInstances[256]; + UINT m_numVSClassInstances; + ID3D11Buffer *m_pVSConstantBuffer; + ID3D11GeometryShader *m_pGS; + ID3D11ClassInstance *m_pGSClassInstances[256]; + UINT m_numGSClassInstances; + ID3D11Buffer *m_pGSConstantBuffer; + ID3D11ShaderResourceView *m_pGSSRV; + ID3D11PixelShader *m_pPS; + ID3D11ClassInstance *m_pPSClassInstances[256]; + UINT m_numPSClassInstances; + ID3D11HullShader *m_pHS; + ID3D11ClassInstance *m_pHSClassInstances[256]; + UINT m_numHSClassInstances; + ID3D11DomainShader *m_pDS; + ID3D11ClassInstance *m_pDSClassInstances[256]; + UINT m_numDSClassInstances; + ID3D11Buffer *m_pVB; + UINT m_vertexStride; + UINT m_vertexOffset; + ID3D11Buffer *m_pIndexBuffer; + DXGI_FORMAT m_indexFormat; + UINT m_indexOffset; + + no_state_saver(const no_state_saver&); + no_state_saver& operator=(const no_state_saver&); +public: + + no_state_saver(); + ~no_state_saver(); + + HRESULT save_current_state(ID3D11DeviceContext *p_context); + HRESULT restore_saved_state(); + void release_saved_state(); +}; + diff --git a/no_renderer/no_menu/no_menu.cpp b/no_renderer/no_menu/no_menu.cpp new file mode 100644 index 0000000..5cb5169 --- /dev/null +++ b/no_renderer/no_menu/no_menu.cpp @@ -0,0 +1,1018 @@ +#include "no_menu.h" +#include + +using namespace no_menu::globals; +no_menu::functions_t no_menu::functions; +no_menu::gui_window_context_t no_menu::globals::window_ctx; + +// ======================================================================== +bool no_menu::button(const char* id, const vec2 size) { + std::vector id_split = utils::hash::split_str(id, '#'); + + const unsigned long font = utils::misc::pop_font(); + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + const vec2 draw_pos{ window_ctx.position.x + cursor_pos.x, window_ctx.position.y + cursor_pos.y }; + + const bool active = window_ctx.blocking == utils::hash::hash(id); + + bool result = false; + if (const bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y, size.x, size.y); !active && hovered && utils::input::key_pressed(VK_LBUTTON)) { + window_ctx.blocking = utils::hash::hash(id); + } + else if (active && !utils::input::key_down(VK_LBUTTON)) { + window_ctx.blocking = 0; + result = hovered; + } + + int text_width, text_height; + functions.get_text_size(id_split[0].c_str(), text_width, text_height); + + window_ctx.render.emplace_back(no_menu_control_render_t{ {draw_pos.x + size.x / 2 - text_width / 2, draw_pos.y + size.y / 2 - text_height / 2}, no_menu_render_type::no_menu_text, global_colors.color_text, id_split[0], vec2{0, 0}, font }); + window_ctx.render.emplace_back(no_menu_control_render_t{ {draw_pos.x + 1, draw_pos.y + 1}, no_menu_render_type::no_menu_filled_rect, active ? global_colors.control_active_or_clicked : global_colors.control_idle, "", {size.x - 2, size.y - 2} }); + window_ctx.render.emplace_back(no_menu_control_render_t{ {draw_pos.x, draw_pos.y}, no_menu_render_type::no_menu_filled_rect, global_colors.control_outline, "", size }); + + utils::misc::push_cursor_pos(vec2{ cursor_pos.x + size.x + global_config.item_spacing, cursor_pos.y }); + utils::misc::push_cursor_pos(vec2{ cursor_pos.x, cursor_pos.y + size.y / 2 + global_config.item_spacing }); + + utils::misc::push_font(font); + + return result; +} +// ======================================================================== + + + + +void no_menu::MiniBox(const char* id) { + std::vector id_split = utils::hash::split_str(id, '#'); + + const unsigned long font = utils::misc::pop_font(); + + //const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + //const vec2 draw_pos{ window_ctx.position.x + cursor_pos.x, window_ctx.position.y + cursor_pos.y }; + + int text_width, text_height; + functions.get_text_size(id_split[0].c_str(), text_width, text_height); + + const vec2 cursor_position = vec2({ mouse_pos.x, mouse_pos.y }); + + //functions.draw_filled_rect(cursor_position.x + 15, cursor_position.y + 15, text_width + 6, text_height + 6, { 19, 19, 25, 255 }); + window_ctx.render.emplace_back(no_menu_control_render_t{ {cursor_position.x + 18, cursor_position.y + 18}, no_menu_render_type::no_menu_text, {255, 255, 255, 255}, id_split[0], vec2{0, 0}, font }); + + //utils::misc::push_cursor_pos(vec2{ cursor_pos.x + text_width + global_config.item_spacing, cursor_pos.y }); + //utils::misc::push_cursor_pos(vec2{ cursor_pos.x, cursor_pos.y + text_height / 2 + global_config.item_spacing }); + + utils::misc::push_font(font); +} + +bool no_menu::TextHoverable(const char* id, no_menu::color col) { + std::vector id_split = utils::hash::split_str(id, '#'); + + const unsigned long font = utils::misc::pop_font(); + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + const vec2 draw_pos{ window_ctx.position.x + cursor_pos.x, window_ctx.position.y + cursor_pos.y }; + + + int text_width, text_height; + functions.get_text_size(id_split[0].c_str(), text_width, text_height); + + const bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y, text_width, text_height); + + + + + + window_ctx.render.emplace_back(no_menu_control_render_t{ {draw_pos.x, draw_pos.y}, no_menu_render_type::no_menu_text, col, id_split[0], vec2{0, 0}, font }); + + utils::misc::push_cursor_pos(vec2{ cursor_pos.x + text_width + global_config.item_spacing, cursor_pos.y }); + utils::misc::push_cursor_pos(vec2{ cursor_pos.x, cursor_pos.y + text_height / 2 + global_config.item_spacing }); + + utils::misc::push_font(font); + + return hovered; +} + + + +// ======================================================================== +bool no_menu::Lineee(const vec2 size, const bool invisible) { + + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + + + if (invisible) { + const vec2 draw_pos{ window_ctx.position.x + cursor_pos.x, window_ctx.position.y + cursor_pos.y }; + window_ctx.render.emplace_back(no_menu_control_render_t{ {draw_pos.x + 1, draw_pos.y + 1}, no_menu_render_type::no_menu_filled_rect, global_colors.control_active_or_clicked, "", {size.x - 2, size.y - 2} }); + } + + + + utils::misc::push_cursor_pos(vec2{ cursor_pos.x + size.x + global_config.item_spacing, cursor_pos.y }); + utils::misc::push_cursor_pos(vec2{ cursor_pos.x, cursor_pos.y + size.y / 2 + 2 }); + + + return true; +} +// ======================================================================== + + + +// ======================================================================== +void no_menu::checkbox(const char *id, bool &value) { + std::vector id_split = utils::hash::split_str(id, '#'); + + const int control_height = 8; + const int control_width = 8; + + const unsigned long font = utils::misc::pop_font(); + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + const vec2 draw_pos{window_ctx.position.x + cursor_pos.x, window_ctx.position.y + cursor_pos.y}; + + int text_width, text_height; + functions.get_text_size(id_split[0].c_str(), text_width, text_height); + + const bool active = window_ctx.blocking == utils::hash::hash(id); + + if (const bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y, control_width + 6 + text_width, control_height); !active && hovered && utils::input::key_pressed(VK_LBUTTON)) { + window_ctx.blocking = utils::hash::hash(id); + } + else if (active && !utils::input::key_down(VK_LBUTTON)) { + window_ctx.blocking = 0; + value = !value; + } + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 14, draw_pos.y - 2}, no_menu_render_type::no_menu_text, value ? global_colors.color_text : global_colors.color_text_dimmer, id_split[0], vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 1, draw_pos.y + 1}, no_menu_render_type::no_menu_filled_rect, value ? global_colors.control_active_or_clicked : global_colors.control_idle, "", {control_width - 2, control_height - 2}}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y}, no_menu_render_type::no_menu_filled_rect, global_colors.control_outline, "", {control_width, control_height}}); + + utils::misc::push_cursor_pos(vec2{cursor_pos.x + 14 + text_width + global_config.item_spacing, cursor_pos.y}); + utils::misc::push_cursor_pos(vec2{cursor_pos.x, cursor_pos.y + global_config.item_spacing}); + + utils::misc::push_font(font); +} +// ======================================================================== + +// ======================================================================== +void no_menu::combobox(const char *id, std::vector items, int &value) { + std::vector id_split = utils::hash::split_str(id, '#'); + + const int control_width = 70; + const int control_height = 24; + + value = std::clamp(value, 0, static_cast(items.size()) - 1); + + const unsigned long font = utils::misc::pop_font(); + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + vec2 draw_pos{window_ctx.position.x + cursor_pos.x + 14, window_ctx.position.y + cursor_pos.y}; + + const bool inlined = id_split[0].empty(); + + if (!inlined) { + int text_width, text_height; + + functions.get_text_size(id_split[0].c_str(), text_width, text_height); + text_height = text_height + 4; + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y - 4}, no_menu_render_type::no_menu_text, global_colors.color_text, id_split[0], vec2{0, 0}, font}); + + draw_pos.y += text_height; + } + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + control_width - 10, draw_pos.y + 4}, no_menu_render_type::no_menu_text, global_colors.color_text, "+", vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 4, draw_pos.y + 4}, no_menu_render_type::no_menu_text, global_colors.color_text, items.at(value), vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 1, draw_pos.y + 1}, no_menu_render_type::no_menu_filled_rect, global_colors.control_idle, "", {control_width - 2, control_height - 2}}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y}, no_menu_render_type::no_menu_filled_rect, global_colors.control_outline, "", {control_width, control_height}}); + + utils::misc::push_cursor_pos(vec2{cursor_pos.x + control_width + global_config.item_spacing, cursor_pos.y}); + utils::misc::push_cursor_pos(vec2{cursor_pos.x, cursor_pos.y + control_height / 2 + global_config.item_spacing + (inlined ? 0 : 12)}); + + + if (const bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y, control_width, control_height); hovered && utils::input::key_pressed(VK_LBUTTON) && window_ctx.blocking == 0) { + window_ctx.blocking = utils::hash::hash(id); + } + else if (window_ctx.blocking == utils::hash::hash(id)) { + for (int i = 1; i <= items.size(); i++) { + bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y + (control_height - 1) * i, control_width, control_height); + + if (hovered && utils::input::key_pressed(VK_LBUTTON)) { + window_ctx.blocking = 0; + value = i - 1; + } + + if (!hovered && utils::input::key_pressed(VK_LBUTTON)) { + window_ctx.blocking = 0; + } + bool selected = value == i - 1; + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 4, draw_pos.y + (control_height - 1) * i + 4}, no_menu_render_type::no_menu_text, selected ? global_colors.control_active_or_clicked : global_colors.color_text, items.at(i - 1), vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 1, draw_pos.y + (19 * i) + 1}, no_menu_render_type::no_menu_filled_rect, hovered ? global_colors.color_combo_bg : global_colors.control_idle, "", {control_width - 2, control_height - 2 + 9}}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y + 19 * i}, no_menu_render_type::no_menu_filled_rect, global_colors.control_outline, "", {control_width, control_height + 9}}); + } + } + + utils::misc::push_font(font); +} + +// ======================================================================== +void no_menu::multi_combobox(const char *id, std::vector items) { + std::vector id_split = utils::hash::split_str(id, '#'); + + const int control_width = 100; + const int control_height = 20; + + const unsigned long font = utils::misc::pop_font(); + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + vec2 draw_pos{window_ctx.position.x + cursor_pos.x + 14, window_ctx.position.y + cursor_pos.y}; + + const bool inlined = id_split[0].empty(); + + if (!inlined) { + int text_width, text_height; + functions.get_text_size(id_split[0].c_str(), text_width, text_height); + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y - 4}, no_menu_render_type::no_menu_text, global_colors.color_text, id_split[0], vec2{0, 0}, font}); + + draw_pos.y += text_height; + } + + std::string value_str; + int text_width, text_height; + + for (auto &item_t : items) { + if (*item_t.value) { + if (value_str.length() > 0) + value_str += _(", "); + + value_str += item_t.name; + } + } + + functions.get_text_size(value_str.c_str(), text_width, text_height); + if (text_width > control_width - 18) { + value_str.resize(control_width / 10); + value_str += _(" ..."); + } + if (!value_str.length()) + value_str += _("None"); + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + control_width - 10, draw_pos.y + 4}, no_menu_render_type::no_menu_text, global_colors.color_text, "+", vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 4, draw_pos.y + 4}, no_menu_render_type::no_menu_text, global_colors.color_text, value_str, vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 1, draw_pos.y + 1}, no_menu_render_type::no_menu_filled_rect, global_colors.control_idle, "", {control_width - 2, control_height - 2}}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y}, no_menu_render_type::no_menu_filled_rect, global_colors.control_outline, "", {control_width, control_height}}); + + utils::misc::push_cursor_pos(vec2{cursor_pos.x + control_width + global_config.item_spacing, cursor_pos.y}); + utils::misc::push_cursor_pos(vec2{cursor_pos.x, cursor_pos.y + control_height / 2 + global_config.item_spacing + (inlined ? 0 : 12)}); + + + if (const bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y, control_width, control_height); hovered && utils::input::key_pressed(VK_LBUTTON) && window_ctx.blocking == 0) { + window_ctx.blocking = utils::hash::hash(id); + } + else if (window_ctx.blocking == utils::hash::hash(id)) { + for (int i = 1; i <= items.size(); i++) { + bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y + (control_height - 1) * i, control_width, control_height); + const bool outofbounds = utils::input::mouse_in_region(draw_pos.x, draw_pos.y + (control_height - 1), control_width, control_height * i); + if (hovered && utils::input::key_pressed(VK_LBUTTON)) { + window_ctx.blocking = utils::hash::hash(id); + *items[i - 1].value = !*items[i - 1].value; + } + if (!outofbounds && utils::input::key_pressed(VK_LBUTTON)) { + window_ctx.blocking = 0; + } + bool selected = *items[i - 1].value >= 1; + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 4, draw_pos.y + (control_height - 1) * i + 4}, no_menu_render_type::no_menu_text, selected ? global_colors.control_active_or_clicked : global_colors.color_text, items[i - 1].name.data(), vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 1, draw_pos.y + (19 * i) + 1}, no_menu_render_type::no_menu_filled_rect, hovered ? global_colors.color_combo_bg : global_colors.control_idle, "", {control_width - 2, control_height - 2}}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y + 19 * i}, no_menu_render_type::no_menu_filled_rect, global_colors.control_outline, "", {control_width, control_height}}); + } + } + + utils::misc::push_font(font); +} +// ======================================================================== + + +// ======================================================================== +void no_menu::begin_groupbox(std::string_view title, const vec2 size, const int flags) { + const unsigned long font = utils::misc::pop_font(); + + + + + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + const vec2 draw_pos{window_ctx.position.x + cursor_pos.x, window_ctx.position.y + cursor_pos.y}; + + int text_width, text_height; + + if (!title.empty()) + functions.get_text_size(title.data(), text_width, text_height); + + const int header_height = title.empty() ? 16 : text_height + 3; + + if (flags & no_menu_groupbox_flags_legacy_design) { + functions.draw_rect(draw_pos.x - 1, draw_pos.y - 1, size.x + 2, size.y + 2, global_colors.control_outline); + functions.draw_filled_rect(draw_pos.x, draw_pos.y, size.x, size.y, global_colors.color_groupbox_bg); + + if (!title.empty()) { + functions.draw_text(draw_pos.x + 4, draw_pos.y - 8, global_colors.color_text, false, title.data()); + } + } + else { + functions.draw_rect(draw_pos.x - 1, draw_pos.y - 1, size.x + 2, size.y + 2, global_colors.control_outline); + functions.draw_filled_rect(draw_pos.x, draw_pos.y, size.x, size.y, global_colors.color_groupbox_bg); + + functions.draw_filled_rect(draw_pos.x, draw_pos.y, size.x, header_height, global_colors.color_groupbox_header); + + if (!title.empty()) { + functions.draw_text(draw_pos.x + size.x / 2 - text_width / 2, draw_pos.y + 2, global_colors.color_text, false, title.data()); + } + } + + window_ctx.next_cursor_pos = vec2{cursor_pos.x, cursor_pos.y + size.y + 10}; + + utils::misc::push_cursor_pos(vec2{ cursor_pos.x + 8, cursor_pos.y + ((flags & no_menu_groupbox_flags_legacy_design) ? 0 : header_height) + 8 }); + + utils::misc::push_font(font); +} + +// ======================================================================== +void no_menu::end_groupbox() { + utils::misc::push_cursor_pos(window_ctx.next_cursor_pos); + window_ctx.next_cursor_pos = {}; +} +// ======================================================================== + + +// ======================================================================== +void no_menu::key_bind(const char *id, int &value) { + std::vector id_split = utils::hash::split_str(id, '#'); + + const int control_width = 80; + const int control_height = 20; + + value = std::clamp(value, 0, 255); + + const unsigned long font = utils::misc::pop_font(); + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + vec2 draw_pos{window_ctx.position.x + cursor_pos.x + 14, window_ctx.position.y + cursor_pos.y}; + + const bool inlined = id_split[0].empty(); + + if (!inlined) { + int text_width, text_height; + functions.get_text_size(id_split[0].c_str(), text_width, text_height); + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y - 4}, no_menu_render_type::no_menu_text, global_colors.color_text, id_split[0], vec2{0, 0}, font}); + + draw_pos.y += text_height; + } + + const bool active = window_ctx.blocking == utils::hash::hash(id); + + if (const bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y, control_width, control_height); hovered && utils::input::key_pressed(VK_LBUTTON) && window_ctx.blocking == 0) { + window_ctx.blocking = utils::hash::hash(id); + } + else if (active) { + for (int i = 0; i < 256; i++) { + if (utils::input::key_pressed(i)) { + if (keys_list[i] != _("Error")) + value = i; + + window_ctx.blocking = 0; + } + } + } + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 4, draw_pos.y + 4}, no_menu_render_type::no_menu_text, global_colors.color_text, active ? "Press any key" : keys_list[value].data(), vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 1, draw_pos.y + 1}, no_menu_render_type::no_menu_filled_rect, active ? global_colors.control_active_or_clicked : global_colors.control_idle, "", {control_width, control_height}}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y}, no_menu_render_type::no_menu_filled_rect, global_colors.control_outline, "", {control_width + 2, control_height + 2}}); + + utils::misc::push_cursor_pos(vec2{cursor_pos.x + control_width + global_config.item_spacing, cursor_pos.y}); + utils::misc::push_cursor_pos(vec2{cursor_pos.x, cursor_pos.y + control_height / 2 + global_config.item_spacing + (inlined ? 0 : 12)}); + + utils::misc::push_font(font); +} +// ======================================================================== + + + +// ======================================================================== +void no_menu::listbox(const char *id, std::vector items) { + std::vector id_split = utils::hash::split_str(id, '#'); + + const int control_width = 100; + const int control_height = 20; + + const unsigned long font = utils::misc::pop_font(); + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + vec2 draw_pos{window_ctx.position.x + cursor_pos.x, window_ctx.position.y + cursor_pos.y}; + + const bool inlined = id_split[0].empty(); + + if (!inlined) { + int text_width, text_height; + functions.get_text_size(id_split[0].c_str(), text_width, text_height); + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y - 4}, no_menu_render_type::no_menu_text, global_colors.color_text, id_split[0], vec2{0, 0}, font}); + + draw_pos.y += text_height; + } + + for (int i = 1; i <= items.size(); i++) { + const bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y + (control_height - 1) * (i - 1), control_width, control_height); + + if (hovered && utils::input::key_pressed(VK_LBUTTON)) { + window_ctx.blocking = 0; + *items[i - 1].value = !*items[i - 1].value; + } + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 4, draw_pos.y + (control_height - 1) * (i - 1) + 4}, no_menu_render_type::no_menu_text, *items[i - 1].value || hovered ? global_colors.control_active_or_clicked : global_colors.color_text, items[i - 1].name.data(), vec2{0, 0}, font}); + } + + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 1, draw_pos.y + 1}, no_menu_render_type::no_menu_filled_rect, global_colors.control_idle, "", {control_width - 2, static_cast(control_height * items.size() - 2)}}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y}, no_menu_render_type::no_menu_filled_rect, global_colors.control_outline, "", {control_width, static_cast(control_height * items.size())}}); + + utils::misc::push_cursor_pos(vec2{cursor_pos.x + control_width + global_config.item_spacing, cursor_pos.y}); + utils::misc::push_cursor_pos(vec2{cursor_pos.x, cursor_pos.y + control_height / 2 + global_config.item_spacing + (inlined ? 0 : 12) + control_height * (items.size() - 1)}); + + if (const bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y, control_width, control_height); hovered && utils::input::key_pressed(VK_LBUTTON) && window_ctx.blocking == 0) { + window_ctx.blocking = utils::hash::hash(id); + } + + utils::misc::push_font(font); +} +// ======================================================================== + +// ======================================================================== +void no_menu::slider_int(const char *id, const int min, const int max, int &value) { + std::vector id_split = utils::hash::split_str(id, '#'); + + const unsigned long font = utils::misc::pop_font(); + + const int control_width = 120; + const int control_height = 10; + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + vec2 draw_pos{window_ctx.position.x + cursor_pos.x + 14, window_ctx.position.y + cursor_pos.y}; + + const bool inlined = id_split[0].empty(); + + if (!inlined) { + int text_width, text_height; + functions.get_text_size(id_split[0].c_str(), text_width, text_height); + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y - 4}, no_menu_render_type::no_menu_text, global_colors.color_text, id_split[0], vec2{0, 0}, font}); + + draw_pos.y += text_height; + } + + if (window_ctx.blocking == 0 && utils::input::mouse_in_region(draw_pos.x - (control_height - 2), draw_pos.y, 8, 10) && utils::input::key_pressed(VK_LBUTTON)) + value = std::clamp(value - 1, min, max); + else if (window_ctx.blocking == 0 && utils::input::mouse_in_region(draw_pos.x + control_width, draw_pos.y, 8, 10) && utils::input::key_pressed(VK_LBUTTON)) + value = std::clamp(value + 1, min, max); + + if (const bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y, control_width, control_height); hovered && utils::input::key_pressed(VK_LBUTTON) && window_ctx.blocking == 0) { + window_ctx.blocking = utils::hash::hash(id); + } + else if (utils::input::key_down(VK_LBUTTON) && window_ctx.blocking == utils::hash::hash(id)) { + float value_unmapped = std::clamp(mouse_pos.x - draw_pos.x, 0.0f, static_cast(control_width)); + int value_mapped = static_cast(value_unmapped / control_width * (max - min) + min); + + value = value_mapped; + } + else if (!utils::input::key_down(VK_LBUTTON) && window_ctx.blocking == utils::hash::hash(id)) { + window_ctx.blocking = 0; + } + + const int dynamic_width = (static_cast(value) - min) / (max - min) * control_width - 2; + + int text_width, text_height; + std::string value_str = std::to_string(value); + functions.get_text_size(value_str.c_str(), text_width, text_height); + + int text_x = dynamic_width - text_width; + + if (text_x < 0) + text_x = 0; + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x - (control_height - 2), draw_pos.y - 2}, no_menu_render_type::no_menu_text, global_colors.color_text_dimmer, "-", vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + (control_width + 4), draw_pos.y - 2}, no_menu_render_type::no_menu_text, global_colors.color_text_dimmer, "+", vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + text_x, draw_pos.y}, no_menu_render_type::no_menu_text, global_colors.color_text, value_str, vec2{0, 0}, font}); + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 1, draw_pos.y + 1}, no_menu_render_type::no_menu_filled_rect, global_colors.color_slider, "", {static_cast(dynamic_width), control_height - 2}}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 1, draw_pos.y + 1}, no_menu_render_type::no_menu_filled_rect, global_colors.control_idle, "", {control_width - 2, control_height - 2}}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y}, no_menu_render_type::no_menu_filled_rect, global_colors.control_outline, "", {control_width, control_height}}); + + + utils::misc::push_cursor_pos(vec2{cursor_pos.x + control_width + 14 + global_config.item_spacing, cursor_pos.y}); + utils::misc::push_cursor_pos(vec2{cursor_pos.x, cursor_pos.y + control_height / 2 + global_config.item_spacing + (inlined ? 0 : 12)}); + + utils::misc::push_font(font); +} + +// ======================================================================== +void no_menu::slider_float(const char *id, const float min, const float max, float &value) { + std::vector id_split = utils::hash::split_str(id, '#'); + + const int control_width = 120; + const int control_height = 10; + + const unsigned long font = utils::misc::pop_font(); + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + vec2 draw_pos{window_ctx.position.x + cursor_pos.x + 14, window_ctx.position.y + cursor_pos.y}; + + const bool inlined = id_split[0].empty(); + + if (!inlined) { + int text_width, text_height; + functions.get_text_size(id_split[0].c_str(), text_width, text_height); + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y - 4}, no_menu_render_type::no_menu_text, global_colors.color_text, id_split[0], vec2{0, 0}, font}); + + draw_pos.y += text_height; + } + + if (window_ctx.blocking == 0 && utils::input::mouse_in_region(draw_pos.x - (control_height - 2), draw_pos.y, 8, 10) && utils::input::key_pressed(VK_LBUTTON)) + value = std::clamp(value - 1, min, max); + else if (window_ctx.blocking == 0 && utils::input::mouse_in_region(draw_pos.x + control_width, draw_pos.y, 8, 10) && utils::input::key_pressed(VK_LBUTTON)) + value = std::clamp(value + 1, min, max); + + if (const bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y, control_width, control_height); hovered && utils::input::key_pressed(VK_LBUTTON) && window_ctx.blocking == 0) { + window_ctx.blocking = utils::hash::hash(id); + } + else if (utils::input::key_down(VK_LBUTTON) && window_ctx.blocking == utils::hash::hash(id)) { + float value_unmapped = std::clamp(mouse_pos.x - draw_pos.x, 0.0f, static_cast(control_width)); + float value_mapped = static_cast((value_unmapped / static_cast(control_width)) * (max - min) + min); + + value = value_mapped; + } + else if (!utils::input::key_down(VK_LBUTTON) && window_ctx.blocking == utils::hash::hash(id)) { + window_ctx.blocking = 0; + } + + const float dynamic_width = (static_cast(value) - min) / (max - min) * control_width - 2; + + int text_width, text_height; + std::stringstream ss; + ss << std::fixed << std::setprecision(2) << value; + std::string value_str = ss.str(); + functions.get_text_size(value_str.c_str(), text_width, text_height); + + int text_x = dynamic_width - text_width; + + if (text_x < 0) + text_x = 0; + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x - (control_height - 2), draw_pos.y - 2}, no_menu_render_type::no_menu_text, global_colors.color_text_dimmer, "-", vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + (control_width + 4), draw_pos.y - 2}, no_menu_render_type::no_menu_text, global_colors.color_text_dimmer, "+", vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + text_x, draw_pos.y}, no_menu_render_type::no_menu_text, global_colors.color_text, value_str, vec2{0, 0}, font}); + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 1, draw_pos.y + 1}, no_menu_render_type::no_menu_filled_rect, global_colors.color_slider, "", {dynamic_width, control_height - 2}}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 1, draw_pos.y + 1}, no_menu_render_type::no_menu_filled_rect, global_colors.control_idle, "", {control_width - 2, control_height - 2}}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y}, no_menu_render_type::no_menu_filled_rect, global_colors.control_outline, "", {control_width, control_height}}); + + + utils::misc::push_cursor_pos(vec2{cursor_pos.x + control_width + 14 + global_config.item_spacing, cursor_pos.y}); + utils::misc::push_cursor_pos(vec2{cursor_pos.x, cursor_pos.y + control_height / 2 + global_config.item_spacing + (inlined ? 0 : 12)}); + + utils::misc::push_font(font); +} +// ======================================================================== + +// ======================================================================== +bool no_menu::clickable_text(const char *id) { + std::vector id_split = utils::hash::split_str(id, '#'); + + const unsigned long font = utils::misc::pop_font(); + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + const vec2 draw_pos{window_ctx.position.x + cursor_pos.x, window_ctx.position.y + cursor_pos.y}; + + int text_width, text_height; + functions.get_text_size(id_split[0].c_str(), text_width, text_height); + + const bool active = window_ctx.blocking == utils::hash::hash(id); + const bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y, text_width, text_height); + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y}, no_menu_render_type::no_menu_text, (hovered || window_ctx.blocking == utils::hash::hash(id)) ? global_colors.control_active_or_clicked : global_colors.color_text, id_split[0], vec2{0, 0}, font}); + + utils::misc::push_cursor_pos(vec2{cursor_pos.x + text_width + global_config.item_spacing, cursor_pos.y}); + utils::misc::push_cursor_pos(vec2{cursor_pos.x, cursor_pos.y + text_height / 2 + global_config.item_spacing}); + + bool result = false; + + if (!active && hovered && utils::input::key_pressed(VK_LBUTTON)) { + window_ctx.blocking = utils::hash::hash(id); + } + else if (active && !utils::input::key_down(VK_LBUTTON)) { + window_ctx.blocking = 0; + result = hovered; + } + + utils::misc::push_font(font); + + return result; +} + +// ======================================================================== +void no_menu::text(const char *text) { + const unsigned long font = utils::misc::pop_font(); + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + const vec2 draw_pos{window_ctx.position.x + cursor_pos.x, window_ctx.position.y + cursor_pos.y}; + + int text_width, text_height; + functions.get_text_size(text, text_width, text_height); + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y}, no_menu_render_type::no_menu_text, global_colors.color_text, text, vec2{0, 0}, font}); + + utils::misc::push_cursor_pos(vec2{cursor_pos.x + text_width + global_config.item_spacing, cursor_pos.y}); + utils::misc::push_cursor_pos(vec2{cursor_pos.x, cursor_pos.y + text_height / 2 + global_config.item_spacing}); + + utils::misc::push_font(font); +} +// ======================================================================== + +// ======================================================================== +void no_menu::text_input(const char *id, std::string &value, const int max_length, const int flags) { + std::vector id_split = utils::hash::split_str(id, '#'); + + const int control_width = 150; + const int control_height = 24; + + const unsigned long font = utils::misc::pop_font(); + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + vec2 draw_pos{window_ctx.position.x + cursor_pos.x + 14, window_ctx.position.y + cursor_pos.y}; + + const bool inlined = id_split[0].empty(); + + if (!inlined) { + int text_width, text_height; + functions.get_text_size(id_split[0].c_str(), text_width, text_height); + text_height = text_height + 2; + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y - 4}, no_menu_render_type::no_menu_text, global_colors.color_text, id_split[0], vec2{0, 0}, font}); + + draw_pos.y += text_height; + } + + const bool active = window_ctx.blocking == utils::hash::hash(id); + const bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y, control_width, control_height); + + if (hovered && utils::input::key_pressed(VK_LBUTTON) && !active) { + window_ctx.blocking = utils::hash::hash(id); + } + else if (active) { + if (utils::input::key_pressed(VK_ESCAPE) || utils::input::key_pressed(VK_RETURN) || (!hovered && utils::input::key_pressed(VK_LBUTTON))) { + window_ctx.blocking = 0; + } + else if (utils::input::key_pressed(VK_BACK) && !value.empty()) { + value.pop_back(); + } + else if (value.length() < max_length) { + for (int i = 32; i <= 222; i++) { + if ((i > 32 && i < 48) || (i > 57 && i < 65) || (i > 90 && i < 186)) + continue; + + if (i > 57 && i <= 90) { + if (utils::input::key_pressed(i)) + value += utils::input::key_down(VK_SHIFT) ? static_cast(i) : static_cast(i + 32); + } + else { + if (utils::input::key_pressed(i)) { + for (int j = 0; j < sizeof(special_characters); j++) { + if (special_characters[j].vk == i) + value += utils::input::key_down(VK_SHIFT) ? special_characters[j].shift : special_characters[j].regular; + } + } + } + } + } + } + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 4, draw_pos.y + 4}, no_menu_render_type::no_menu_text, global_colors.color_text, flags & no_menu_text_input_flags_password ? std::string(value.length(), '*').c_str() : value.c_str(), vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 1, draw_pos.y + 1}, no_menu_render_type::no_menu_filled_rect, active ? global_colors.control_active_or_clicked : global_colors.control_idle, "", {control_width - 2, control_height - 2}}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y}, no_menu_render_type::no_menu_filled_rect, global_colors.control_outline, "", {control_width, control_height}}); + + utils::misc::push_cursor_pos(vec2{cursor_pos.x + control_width + global_config.item_spacing, cursor_pos.y}); + utils::misc::push_cursor_pos(vec2{cursor_pos.x, cursor_pos.y + control_height / 2 + global_config.item_spacing + (inlined ? 0 : 12)}); + + utils::misc::push_font(font); +} +// ======================================================================== + +// ======================================================================== +void no_menu::toggle_button(const char *id, const vec2 size, bool &value) { + std::vector id_split = utils::hash::split_str(id, '#'); + + const unsigned long font = utils::misc::pop_font(); + + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + const vec2 draw_pos{window_ctx.position.x + cursor_pos.x, window_ctx.position.y + cursor_pos.y}; + + const bool active = window_ctx.blocking == utils::hash::hash(id); + + if (const bool hovered = utils::input::mouse_in_region(draw_pos.x, draw_pos.y, size.x, size.y); !active && hovered && utils::input::key_pressed(VK_LBUTTON)) { + window_ctx.blocking = utils::hash::hash(id); + } + else if (active && !utils::input::key_down(VK_LBUTTON)) { + window_ctx.blocking = 0; + value = !value; + } + + int text_width, text_height; + functions.get_text_size(id_split[0].c_str(), text_width, text_height); + + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + size.x / 2 - text_width / 2, draw_pos.y + size.y / 2 - text_height / 2}, no_menu_render_type::no_menu_text, global_colors.color_text, id_split[0], vec2{0, 0}, font}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x + 1, draw_pos.y + 1}, no_menu_render_type::no_menu_filled_rect, value ? global_colors.control_active_or_clicked : global_colors.control_idle, "", size}); + window_ctx.render.emplace_back(no_menu_control_render_t{{draw_pos.x, draw_pos.y}, no_menu_render_type::no_menu_filled_rect, global_colors.control_outline, "", {size.x + 2, size.y + 2}}); + + utils::misc::push_cursor_pos(vec2{cursor_pos.x + size.x + global_config.item_spacing, cursor_pos.y}); + utils::misc::push_cursor_pos(vec2{cursor_pos.x, cursor_pos.y + size.y / 2 + global_config.item_spacing}); + + utils::misc::push_font(font); +} +// ======================================================================== + +// ======================================================================== +bool no_menu::begin_window(std::string_view title, const vec2 windowsize, const int MenuToggleKey, const int flags) { + if (!input_loop_started) + throw std::exception(_("Input loop didnt start or didnt start properly."));; + + // window_ctx.position.x = 300; + // window_ctx.position.y = 300; + + + if (!(flags & no_menu_window_flags_always_open)) { + if (utils::input::key_pressed(MenuToggleKey)) + window_ctx.opened = !window_ctx.opened; + } + else + window_ctx.opened = true; + + if (const int prev_alpha = window_ctx.alpha; !(flags & no_menu_window_flags_no_ontoggle_animation)) { + const int fade_factor = static_cast(1.0f / 0.15f * functions.get_frametime() * 255); + window_ctx.alpha = std::clamp(window_ctx.alpha + (window_ctx.opened ? fade_factor : -fade_factor), 0, 255); + + if (window_ctx.alpha != prev_alpha) { + global_colors.window_border_inner_fill.a = window_ctx.alpha; + global_colors.window_border_fill.a = window_ctx.alpha; + global_colors.window_border_color.a = window_ctx.alpha; + global_colors.window_background.a = window_ctx.alpha; + + global_colors.control_outline.a = window_ctx.alpha; + global_colors.control_active_or_clicked.a = window_ctx.alpha; + global_colors.control_idle.a = window_ctx.alpha; + + global_colors.color_groupbox_bg.a = window_ctx.alpha; + global_colors.color_text.a = window_ctx.alpha; + global_colors.color_text_dimmer.a = window_ctx.alpha; + global_colors.color_slider.a = window_ctx.alpha; + } + } + + if (window_ctx.opened || window_ctx.alpha > 0) { + if (!(flags & no_menu_window_flags_no_move)) { + if ((flags & no_menu_window_flags_no_border ? utils::input::mouse_in_region(window_ctx.position.x + 9, window_ctx.position.y + 14, window_ctx.size.x - 18, 14) + : utils::input::mouse_in_region(window_ctx.position.x - 6, window_ctx.position.y - 10, window_ctx.size.x + 12, 16)) + && utils::input::key_pressed(VK_LBUTTON) && !window_ctx.dragging) { + window_ctx.dragging = true; + } + else if (utils::input::key_down(VK_LBUTTON) && window_ctx.dragging) { + const vec2 mouse_delta{mouse_pos.x - previous_mouse_pos.x, mouse_pos.y - previous_mouse_pos.y}; + const vec2 new_position{window_ctx.position.x + mouse_delta.x, window_ctx.position.y + mouse_delta.y}; + + window_ctx.position = new_position; + } + else if (!utils::input::key_down(VK_LBUTTON) && window_ctx.dragging) { + window_ctx.dragging = false; + } + } + + if (window_ctx.size.x < 1 && window_ctx.size.y < 1) + window_ctx.size = windowsize; + + if (!(flags & no_menu_window_flags_no_border)) { + functions.draw_filled_rect(window_ctx.position.x - 6, window_ctx.position.y - 10, window_ctx.size.x + 12, window_ctx.size.y + 16, global_colors.window_border_inner_fill); + functions.draw_filled_rect(window_ctx.position.x - 5, window_ctx.position.y - 9, window_ctx.size.x + 10, window_ctx.size.y + 14, global_colors.window_border_color); + functions.draw_filled_rect(window_ctx.position.x - 4, window_ctx.position.y - 8, window_ctx.size.x + 8, window_ctx.size.y + 12, global_colors.window_border_fill); + functions.draw_filled_rect(window_ctx.position.x, window_ctx.position.y + 7, window_ctx.size.x, window_ctx.size.y - 7, global_colors.window_border_color); + functions.draw_filled_rect(window_ctx.position.x + 1, window_ctx.position.y + 8, window_ctx.size.x - 2, window_ctx.size.y - 9, global_colors.window_border_inner_fill); + functions.draw_filled_rect(window_ctx.position.x + 8, window_ctx.position.y + 15, window_ctx.size.x - 16, window_ctx.size.y - 23, global_colors.window_border_color); + } + + if (!(flags & no_menu_window_flags_no_titlebar)) { + int text_width, text_height; + functions.get_text_size(title.data(), text_width, text_height); + functions.draw_text((window_ctx.position.x + window_ctx.size.x * 0.5) - text_width / 2, (window_ctx.position.y + (window_ctx.size.y * 0.010) - 6) - text_height / 2, global_colors.color_text, true, title.data()); + } + + + functions.draw_filled_rect(window_ctx.position.x + 9, window_ctx.position.y + 16, window_ctx.size.x - 18, window_ctx.size.y - 25, global_colors.window_background); + + + utils::misc::push_font(NULL); + utils::misc::push_cursor_pos(global_config.base_pos); + } + + return window_ctx.opened || window_ctx.alpha > 0; +} + +// ======================================================================== +void no_menu::end_window() { + for (int i = window_ctx.render.size() - 1; i >= 0; i--) { + switch (window_ctx.render[i].render_type) { + case no_menu_render_type::no_menu_line: + functions.draw_line(window_ctx.render[i].draw_position.x, window_ctx.render[i].draw_position.y, window_ctx.render[i].size.x, window_ctx.render[i].size.y, window_ctx.render[i].color); + break; + case no_menu_render_type::no_menu_rect: + functions.draw_rect(window_ctx.render[i].draw_position.x, window_ctx.render[i].draw_position.y, window_ctx.render[i].size.x, window_ctx.render[i].size.y, window_ctx.render[i].color); + break; + case no_menu_render_type::no_menu_filled_rect: + functions.draw_filled_rect(window_ctx.render[i].draw_position.x, window_ctx.render[i].draw_position.y, window_ctx.render[i].size.x, window_ctx.render[i].size.y, window_ctx.render[i].color); + break; + case no_menu_render_type::no_menu_text: + functions.draw_text(window_ctx.render[i].draw_position.x, window_ctx.render[i].draw_position.y, window_ctx.render[i].color, false, window_ctx.render[i].text.c_str()); + break; + } + } + + window_ctx.render.clear(); + + while (!window_ctx.cursor_pos.empty()) + window_ctx.cursor_pos.pop(); +} +// ======================================================================== + +// ======================================================================== +void no_menu::separator(int space, bool invisible){ + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + utils::misc::push_cursor_pos(vec2{cursor_pos.x, cursor_pos.y + space }); +} + +// ======================================================================== +void no_menu::next_column(const int pusher_x, const int pusher_y) { + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + vec2 new_cursor_pos{cursor_pos.x + pusher_x, global_config.base_pos.y + pusher_y}; + + if (window_ctx.next_cursor_pos.y != 0) + new_cursor_pos.y += 14; + + utils::misc::push_cursor_pos(new_cursor_pos); +} + +// ======================================================================== + +void no_menu::SetWidgetPosition(const int x, const int y) { + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + vec2 new_cursor_pos{ global_config.base_pos.x + x, global_config.base_pos.y + y }; + + if (window_ctx.next_cursor_pos.y != 0) + new_cursor_pos.y += 14; + + utils::misc::push_cursor_pos(new_cursor_pos); +} + +// ======================================================================== + +void no_menu::back_column(const int back_x, const int back_y) { + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + vec2 new_cursor_pos{ cursor_pos.x - back_x, global_config.base_pos.y + back_y }; + + if (window_ctx.next_cursor_pos.y != 0) + new_cursor_pos.y += 14; + + utils::misc::push_cursor_pos(new_cursor_pos); +} + +// ======================================================================== +void no_menu::same_line(const float x_axis) { + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + + if (x_axis != -1) + utils::misc::push_cursor_pos(vec2{global_config.base_pos.x + x_axis, cursor_pos.x}); +} + +// ======================================================================== +void no_menu::backup_line() { + const vec2 cursor_pos = utils::misc::pop_cursor_pos(); + + utils::misc::push_cursor_pos(vec2{window_ctx.next_cursor_pos.x, cursor_pos.y}); +} +// ======================================================================== + +// ======================================================================== +std::vector no_menu::utils::hash::split_str(const char *str, const char separator) { + std::vector output; + std::string substring; + std::istringstream stream{str}; + + while (std::getline(stream, substring, separator)) + output.push_back(substring); + + return output; +} + +// ======================================================================== +uint32_t no_menu::utils::hash::hash(const char *str, const uint32_t value) { + return *str ? hash(str + 1, (value ^ *str) * 0x1000193ull) : value; +} +// ======================================================================== + +// ======================================================================== +// Function for starting our input loop. +void no_menu::window_input(LPCSTR classname, LPCSTR windowname) { + + for (int i = 0; i < 256; i++) { + prev_key_state[i] = key_state[i]; + key_state[i] = functions.get_key_state_discord(i); + } + + POINT p_mouse_pos; + GetCursorPos(&p_mouse_pos); + ScreenToClient(FindWindowA(classname, windowname), &p_mouse_pos); + previous_mouse_pos = mouse_pos; + mouse_pos = vec2{static_cast(p_mouse_pos.x), static_cast(p_mouse_pos.y)}; + + if (!input_loop_started) + input_loop_started = true; +} + +// ======================================================================== +// Function for starting our input loop. +void no_menu::poll_input(HWND hwnd) { + if (!hwnd) + throw std::exception(_("No window from where input should be read from specified in function parameter.")); + + for (int i = 0; i < 256; i++) { + prev_key_state[i] = key_state[i]; + key_state[i] = functions.get_key_state_discord(i); + } + + POINT p_mouse_pos; + GetCursorPos(&p_mouse_pos); + ScreenToClient(hwnd, &p_mouse_pos); + previous_mouse_pos = mouse_pos; + + mouse_pos = vec2{static_cast(p_mouse_pos.x), static_cast(p_mouse_pos.y)}; + + if (!input_loop_started) + input_loop_started = true; +} + +// ======================================================================== +bool no_menu::utils::input::key_pressed(const int key) { + return key_state[key] && !prev_key_state[key]; +} + +// ======================================================================== +bool no_menu::utils::input::key_down(const int key) { + return key_state[key]; +} + +// ======================================================================== +bool no_menu::utils::input::key_released(const int key) { + return !key_state[key] && prev_key_state[key]; +} + +// ======================================================================== +// Check if mouse is hovered over specified region. +bool no_menu::utils::input::mouse_in_region(const int x, const int y, const int w, const int h) { + return mouse_pos.x > x && mouse_pos.y > y && mouse_pos.x < w + x && mouse_pos.y < h + y; +} +// ======================================================================== + +// ======================================================================== +// Push cursor position to the stack defined in window context. +void no_menu::utils::misc::push_cursor_pos(const vec2 pos) { + window_ctx.cursor_pos.push(pos); +} + +// ======================================================================== +// Pop cursor position from the stack defined in window context. +no_menu::vec2 no_menu::utils::misc::pop_cursor_pos() { + const vec2 pos = window_ctx.cursor_pos.top(); + window_ctx.cursor_pos.pop(); + return pos; +} + +// ======================================================================== +// Pop font from the stack defined in window context. +void no_menu::utils::misc::push_font(const unsigned long font) { + window_ctx.fonts.push(font); +} + +// ======================================================================== +// Push font to the stack defined in window context. +unsigned long no_menu::utils::misc::pop_font() { + const unsigned long font = window_ctx.fonts.top(); + window_ctx.fonts.pop(); + return font; +} +// ======================================================================== diff --git a/no_renderer/no_menu/no_menu.h b/no_renderer/no_menu/no_menu.h new file mode 100644 index 0000000..bf8cad4 --- /dev/null +++ b/no_renderer/no_menu/no_menu.h @@ -0,0 +1,303 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define no_menu_API __declspec(dllexport) + + +namespace no_menu_functions { + + +} + +namespace no_menu { + // Multi selectable item. + struct multi_select_item { + std::string_view name; + bool *value; + }; + // Two dimensional vector. + struct vec2 { + float x, y; + }; + // Color with 4 paremeters; red, green, blue and alpha. + struct color { + int r, g, b, a; + }; + + /// "Proxy" functions definitions. + using line_t = std::add_pointer_t; + using rect_t = std::add_pointer_t; + using filled_rect_t = std::add_pointer_t; + using text_t = std::add_pointer_t; + using get_text_size_t = std::add_pointer_t; + using get_frametime = std::add_pointer_t; + using get_key_state_discord_t = std::add_pointer_t; + + /// + + // "Proxy" functions stuff... + struct functions_t { + line_t draw_line; + rect_t draw_rect; + filled_rect_t draw_filled_rect; + text_t draw_text; + get_text_size_t get_text_size; + get_frametime get_frametime; + get_key_state_discord_t get_key_state_discord; + }; + extern functions_t functions; + + // Flags for window appereance and its behavior. + // ex: (no_menu_window_flags_no_border | no_menu_window_flags_no_titlebar) will cause window to be borderless and without title bar. + enum no_menu_window_flags { + no_menu_window_flags_none = 0, + no_menu_window_flags_no_border = 1 << 0, + no_menu_window_flags_no_titlebar = 1 << 1, + no_menu_window_flags_no_ontoggle_animation = 1 << 2, + no_menu_window_flags_no_move = 1 << 3, + no_menu_window_flags_always_open = 1 << 4, + }; + + // Flags for text input appereance. + // ex: (no_menu_text_input_flags_password) will convert text input (ex: "abcdef") to "******". + enum no_menu_text_input_flags { + no_menu_text_input_flags_none = 0, + no_menu_text_input_flags_password = 1 << 0 + }; + + // Flags for groupboxes appereance. + // ex: (no_menu_groupbox_flags_title_centered) will center align title of groupbox. + enum no_menu_groupbox_flags { + no_menu_groupbox_flags_none = 0, + no_menu_groupbox_flags_legacy_design = 1 << 0, + }; + + enum class no_menu_render_type { + no_menu_line = 1, + no_menu_rect, + no_menu_filled_rect, + no_menu_text + }; + + struct no_menu_control_render_t { + vec2 draw_position; + no_menu_render_type render_type; + color color; + std::string text; + vec2 size; + unsigned long font = 0; + }; + + struct gui_window_context_t { + uint32_t blocking; + std::stack cursor_pos; + std::stack fonts; + std::vector render; + vec2 position; + vec2 size; + vec2 next_cursor_pos; + bool dragging; + bool opened; + int alpha; + }; + + struct key_code_info { + int vk; + + char regular; + char shift; + }; + + namespace globals { + constexpr std::string_view keys_list[]{ + "Error", "Left Mouse", "Right Mouse", "Break", "Middle Mouse", "Mouse 4", "Mouse 5", + "Error", "Backspace", "TAB", "Error", "Error", "Error", "ENTER", "Error", "Error", "SHIFT", + "CTRL", "ALT", "PAUSE", "CAPS LOCK", "Error", "Error", "Error", "Error", "Error", "Error", + "Error", "Error", "Error", "Error", "Error", "SPACEBAR", "PG UP", "PG DOWN", "END", "HOME", "Left", + "Up", "Right", "Down", "Error", "Print", "Error", "Print Screen", "Insert", "Delete", "Error", "0", "1", + "2", "3", "4", "5", "6", "7", "8", "9", "Error", "Error", "Error", "Error", "Error", "Error", + "Error", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", + "V", "W", "X", "Y", "Z", "Left Windows", "Right Windows", "Error", "Error", "Error", "NUM 0", "NUM 1", + "NUM 2", "NUM 3", "NUM 4", "NUM 5", "NUM 6", "NUM 7", "NUM 8", "NUM 9", "*", "+", "_", "-", ".", "/", "F1", "F2", "F3", + "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "F19", "F20", "F21", + "F22", "F23", "F24", "Error", "Error", "Error", "Error", "Error", "Error", "Error", "Error", + "NUM LOCK", "SCROLL LOCK", "Error", "Error", "Error", "Error", "Error", "Error", "Error", + "Error", "Error", "Error", "Error", "Error", "Error", "Error", "LSHIFT", "RSHIFT", "LCONTROL", + "RCONTROL", "LMENU", "RMENU", "Error", "Error", "Error", "Error", "Error", "Error", "Error", + "Error", "Error", "Error", "Next Track", "Previous Track", "Stop", "Play/Pause", "Error", "Error", + "Error", "Error", "Error", "Error", ";", "+", ",", "-", ".", "/?", "~", "Error", "Error", + "Error", "Error", "Error", "Error", "Error", "Error", "Error", "Error", "Error", + "Error", "Error", "Error", "Error", "Error", "Error", "Error", "Error", "Error", + "Error", "Error", "Error", "Error", "Error", "Error", "[{", "\\|", "}]", "'\"", "Error", + "Error", "Error", "Error", "Error", "Error", "Error", "Error", "Error", "Error", + "Error", "Error", "Error", "Error", "Error", "Error", "Error", "Error", "Error", + "Error", "Error", "Error", "Error", "Error", "Error", "Error", "Error", "Error", + "Error", "Error" + }; + + static key_code_info special_characters[22] = { + {48, '0', ')'}, + {49, '1', '!'}, + {50, '2', '@'}, + {51, '3', '#'}, + {52, '4', '$'}, + {53, '5', '%'}, + {54, '6', '^'}, + {55, '7', '&'}, + {56, '8', '*'}, + {57, '9', '('}, + {32, ' ', ' '}, + {192, '`', '~'}, + {189, '-', '_'}, + {187, '=', '+'}, + {219, '[', '{'}, + {220, '\\', '|'}, + {221, ']', '}'}, + {186, ';', ':'}, + {222, '\'', '"'}, + {188, ',', '<'}, + {190, '.', '>'}, + {191, '/', '?'} + }; + + // Color definition. Can be changed at any time just simply by editing this struct. + static struct { + color window_border_inner_fill{60, 60, 60, 255}; + color window_border_fill{40, 40, 40, 255}; + color window_border_color{10, 10, 10, 255}; + color window_background{40, 40, 40, 255}; + + color control_outline{23, 23, 30, 255}; + color control_active_or_clicked{108, 92, 231, 255}; + color control_idle{62, 62, 72, 255}; + + color color_groupbox_bg{50, 50, 50, 255}; + color color_text{203, 203, 203, 255}; + color color_text_dimmer{99, 110, 114, 255}; + color color_slider{108, 92, 231, 255}; + color color_combo_bg{108, 92, 231, 255}; + color color_groupbox_header{26, 26, 26, 150}; + } global_colors; + + static struct { + // Base position of first drawn control (px). DO NOT change if its necessary + no_menu::vec2 base_pos{16, 23}; + // Spacing between items (px) + int item_spacing = 16; + // Key that will toggle menu visibility unless no_menu_window_flags_always_open is set + int menu_toggle_key = VK_INSERT; + } global_config; + + // Window definitions. + extern gui_window_context_t window_ctx; + + // "Proxy" functions stuff... + //inline no_menu::functions_t no_menu::functions; + + // Globals + static vec2 mouse_pos; + static vec2 previous_mouse_pos; + + // Input handling stuff + static bool key_state[256]; + static bool prev_key_state[256]; + + // Check for input polling. + static bool input_loop_started = false; + } + + // Start Input loop + no_menu_API void window_input(LPCSTR classname, LPCSTR windowname); + + no_menu_API void poll_input(HWND hwnd); + + namespace utils { + namespace input { + bool key_pressed(int key); + + bool key_down(int key); + + bool key_released(int key); + + bool mouse_in_region(int x, int y, int w, int h); + + } + + namespace hash { + std::vector split_str(const char *str, char separator); + + uint32_t hash(const char *str, uint32_t value = 0x811c9dc5); + } + + namespace misc { + no_menu_API void push_cursor_pos(vec2 pos); + + no_menu_API vec2 pop_cursor_pos(); + + no_menu_API void push_font(unsigned long font); + + no_menu_API unsigned long pop_font(); + } + + } + + no_menu_API bool begin_window(std::string_view title, vec2 default_size, int MenuToggleKey, int flags = 0); + + no_menu_API void end_window(); + + no_menu_API void begin_groupbox(std::string_view title, vec2 size, int flags = 0); + + no_menu_API void end_groupbox(); + + no_menu_API void checkbox(const char *id, bool &value); + + no_menu_API void toggle_button(const char *id, vec2 size, bool &value); + + no_menu_API bool button(const char* id, vec2 size); + + no_menu_API bool TextHoverable(const char* id, no_menu::color col); + + no_menu_API void MiniBox(const char* id); + + no_menu_API bool Lineee(vec2 size, bool invisible); + + no_menu_API void key_bind(const char *id, int &value); + + no_menu_API void text_input(const char *id, std::string &value, int max_length = 16, int flags = 0); + + no_menu_API void slider_int(const char *id, int min, int max, int &value); + + no_menu_API void slider_float(const char *id, float min, float max, float &value); + + no_menu_API void combobox(const char *, std::vector items, int &value); + + no_menu_API void multi_combobox(const char *id, std::vector items); + + no_menu_API void listbox(const char *id, std::vector items); + + no_menu_API bool clickable_text(const char *id); + + no_menu_API void text(const char *text); + + no_menu_API void separator(int space, bool invisible); + + no_menu_API void SetWidgetPosition(int x, int y); + + no_menu_API void next_column(int pusher_x = 174, int pusher_y = 14); + + no_menu_API void back_column(int back_x = 174, int back_y = 14); + + no_menu_API void same_line(float x_axis = -1); + + no_menu_API void backup_line(); + +} diff --git a/structs.h b/structs.h new file mode 100644 index 0000000..b0e55ee --- /dev/null +++ b/structs.h @@ -0,0 +1,28 @@ +#pragma once + +enum eDepthState +{ + ENABLED, + DISABLED, + READ_NO_WRITE, + NO_READ_NO_WRITE, + _DEPTH_COUNT +}; + +struct FVector2D +{ + FVector2D() : x(0.f), y(0.f) + { + + } + + FVector2D(float _x, float _y) : x(_x), y(_y) + { + + } + ~FVector2D() + { + + } + float x, y; +}; \ No newline at end of file