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