├── vmm.dll ├── vmm.lib ├── FTD3XX.dll ├── FTD3XX.lib ├── leechcore.dll ├── leechcore.lib ├── WZ.vcxproj.user ├── WZ.sln ├── imgui_impl_dx11.h ├── dma.h ├── vector.h ├── dma.cpp ├── WZ.vcxproj.filters ├── imgui_impl_win32.h ├── game.h ├── main.cpp ├── WZ.vcxproj ├── game_math.h ├── imconfig.h ├── imstb_rectpack.h ├── leechcore.h └── imstb_textedit.h /vmm.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyamuk0/wz-dma/HEAD/vmm.dll -------------------------------------------------------------------------------- /vmm.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyamuk0/wz-dma/HEAD/vmm.lib -------------------------------------------------------------------------------- /FTD3XX.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyamuk0/wz-dma/HEAD/FTD3XX.dll -------------------------------------------------------------------------------- /FTD3XX.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyamuk0/wz-dma/HEAD/FTD3XX.lib -------------------------------------------------------------------------------- /leechcore.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyamuk0/wz-dma/HEAD/leechcore.dll -------------------------------------------------------------------------------- /leechcore.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nyamuk0/wz-dma/HEAD/leechcore.lib -------------------------------------------------------------------------------- /WZ.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /WZ.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34018.315 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WZ", "WZ.vcxproj", "{2BEA2A73-224B-4E76-B257-7A3C35181D4F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {2BEA2A73-224B-4E76-B257-7A3C35181D4F}.Debug|x64.ActiveCfg = Debug|x64 17 | {2BEA2A73-224B-4E76-B257-7A3C35181D4F}.Debug|x64.Build.0 = Debug|x64 18 | {2BEA2A73-224B-4E76-B257-7A3C35181D4F}.Debug|x86.ActiveCfg = Debug|Win32 19 | {2BEA2A73-224B-4E76-B257-7A3C35181D4F}.Debug|x86.Build.0 = Debug|Win32 20 | {2BEA2A73-224B-4E76-B257-7A3C35181D4F}.Release|x64.ActiveCfg = Release|x64 21 | {2BEA2A73-224B-4E76-B257-7A3C35181D4F}.Release|x64.Build.0 = Release|x64 22 | {2BEA2A73-224B-4E76-B257-7A3C35181D4F}.Release|x86.ActiveCfg = Release|Win32 23 | {2BEA2A73-224B-4E76-B257-7A3C35181D4F}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {AEE91B0C-D0A2-4531-8A7B-C2D08E55DD38} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /imgui_impl_dx11.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for DirectX11 2 | // This needs to be used along with a Platform Backend (e.g. Win32) 3 | 4 | // Implemented features: 5 | // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! 6 | // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. 7 | 8 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 9 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 10 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 11 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 12 | 13 | #pragma once 14 | #include "imgui.h" // IMGUI_IMPL_API 15 | #ifndef IMGUI_DISABLE 16 | 17 | struct ID3D11Device; 18 | struct ID3D11DeviceContext; 19 | 20 | IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context); 21 | IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown(); 22 | IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame(); 23 | IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data); 24 | 25 | // Use if you want to reset your rendering device without losing Dear ImGui state. 26 | IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); 27 | IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); 28 | 29 | #endif // #ifndef IMGUI_DISABLE 30 | -------------------------------------------------------------------------------- /dma.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "vmmdll.h" 3 | #include "leechcore.h" 4 | #pragma comment(lib,"leechcore.lib") 5 | #pragma comment(lib,"vmm.lib") 6 | 7 | #define REMOTE_PROCESS_SHORT "cod.exe" 8 | #define REMOTE_PROCESS_LONG L"cod.exe" 9 | 10 | namespace DMA 11 | { 12 | extern VMM_HANDLE hVMM; 13 | extern bool Connected; 14 | extern uint32_t AttachedProcessId; 15 | extern uint64_t BaseAddress; 16 | extern uint64_t PebAddress; 17 | 18 | extern bool Connect(); 19 | extern void Disconnect(); 20 | extern bool AttachToProcessId(LPSTR szProcessName = const_cast(REMOTE_PROCESS_SHORT)); 21 | extern bool GetPEBAddress(uint32_t dwProcessId); 22 | 23 | template 24 | Var Read(U address, size_t uiSize, bool bFullReadRequired = true) 25 | { 26 | Var output{}; 27 | if (!AttachedProcessId || !Connected || !address) { 28 | return output; 29 | } 30 | 31 | uint32_t bytesRead = 0; 32 | uint32_t flags = VMMDLL_FLAG_NOCACHE | VMMDLL_FLAG_NOPAGING | VMMDLL_FLAG_ZEROPAD_ON_FAIL | VMMDLL_FLAG_NOPAGING_IO; 33 | 34 | BOOL bRetn = (VMMDLL_MemReadEx(DMA::hVMM, AttachedProcessId, (uint64_t)address, (uint8_t*)&output, uiSize, 35 | reinterpret_cast(&bytesRead), flags) && bytesRead != 0); 36 | 37 | if (!bRetn || (bFullReadRequired && bytesRead != uiSize)) { 38 | return output; 39 | } 40 | 41 | return output; 42 | } 43 | 44 | template 45 | uintptr_t ReadPtr(U address) 46 | { 47 | return Read(address, sizeof(uintptr_t), true); 48 | } 49 | } -------------------------------------------------------------------------------- /vector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #define M_PI 3.14159265358979323846264338327950288419716939937510 6 | 7 | class Vector2 8 | { 9 | public: 10 | float x; 11 | float y; 12 | 13 | inline bool is_Zero() { 14 | return (x == 0) && (y == 0); 15 | } 16 | }; 17 | 18 | 19 | struct FRotator 20 | { 21 | public: 22 | float Pitch; 23 | float Yaw; 24 | float Roll; 25 | }; 26 | 27 | 28 | 29 | class Vector3 30 | { 31 | public: 32 | Vector3() : x(0.f), y(0.f), z(0.f) 33 | { 34 | 35 | } 36 | 37 | Vector3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) 38 | { 39 | 40 | } 41 | ~Vector3() 42 | { 43 | 44 | } 45 | 46 | float x; 47 | float y; 48 | float z; 49 | 50 | inline float Dot(Vector3 v) 51 | { 52 | return x * v.x + y * v.y + z * v.z; 53 | } 54 | 55 | inline float Distance(Vector3 v) 56 | { 57 | return float(sqrtf(powf(v.x - x, 2.0) + powf(v.y - y, 2.0) + powf(v.z - z, 2.0))); 58 | } 59 | 60 | inline float Length() 61 | { 62 | return sqrt(x * x + y * y + z * z); 63 | } 64 | 65 | Vector3 operator+(Vector3 v) 66 | { 67 | return Vector3(x + v.x, y + v.y, z + v.z); 68 | } 69 | 70 | Vector3 operator-(Vector3 v) 71 | { 72 | return Vector3(x - v.x, y - v.y, z - v.z); 73 | } 74 | 75 | Vector3 operator*(float number) const 76 | { 77 | return Vector3(x * number, y * number, z * number); 78 | } 79 | }; 80 | 81 | struct FPlane : Vector3 82 | { 83 | float W = 0; 84 | 85 | 86 | Vector3 ToVector3() 87 | { 88 | Vector3 value; 89 | value.x = this->x; 90 | value.y = this->y; 91 | value.z = this->y; 92 | 93 | return value; 94 | } 95 | }; 96 | 97 | struct FQuat 98 | { 99 | float x; 100 | float y; 101 | float z; 102 | float w; 103 | }; 104 | 105 | struct FMatrix 106 | { 107 | FPlane XPlane; 108 | FPlane YPlane; 109 | FPlane ZPlane; 110 | FPlane WPlane; 111 | }; 112 | 113 | -------------------------------------------------------------------------------- /dma.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "vmmdll.h" 5 | #include "dma.h" 6 | 7 | VMM_HANDLE DMA::hVMM = nullptr; 8 | bool DMA::Connected = false; 9 | uint32_t DMA::AttachedProcessId = 0; 10 | uint64_t DMA::BaseAddress = 0; 11 | uint64_t DMA::PebAddress = 0; 12 | 13 | bool DMA::Connect() 14 | { 15 | if (DMA::Connected) 16 | return true; 17 | 18 | bool bReturnStatus = true; 19 | 20 | unsigned int iArgumentCount = 3; 21 | 22 | char args[3][50] = { "", "-device", "fpga" }; 23 | 24 | LPSTR argv[3]; 25 | for (int i = 0; i < 3; i++) { 26 | argv[i] = args[i]; 27 | } 28 | 29 | DMA::hVMM = VMMDLL_Initialize(iArgumentCount, argv); 30 | 31 | if (!DMA::hVMM) 32 | { 33 | MessageBoxA(nullptr, "Could not initialize the DMA device!", nullptr, 0); 34 | return false; 35 | } 36 | 37 | DMA::Connected = bReturnStatus; 38 | 39 | std::cout << "DMA: Connected" << std::endl; 40 | return bReturnStatus; 41 | } 42 | 43 | bool DMA::AttachToProcessId(LPSTR ProcessName) 44 | { 45 | if (!DMA::Connected) 46 | return false; 47 | 48 | if (VMMDLL_PidGetFromName(DMA::hVMM, ProcessName, reinterpret_cast(&DMA::AttachedProcessId)) == FALSE) 49 | return false; 50 | std::cout << "PID: " << DMA::AttachedProcessId << std::endl; 51 | 52 | DMA::BaseAddress = VMMDLL_ProcessGetModuleBase(DMA::hVMM, DMA::AttachedProcessId, const_cast(REMOTE_PROCESS_LONG)); 53 | std::cout << "Base: 0x" << std::hex << DMA::BaseAddress << std::dec << std::endl; 54 | 55 | return (AttachedProcessId != 0 && BaseAddress != 0); 56 | } 57 | 58 | void DMA::Disconnect() 59 | { 60 | DMA::Connected = false; 61 | 62 | DMA::AttachedProcessId = 0; 63 | DMA::BaseAddress = 0; 64 | 65 | VMMDLL_CloseAll(); 66 | } 67 | 68 | bool DMA::GetPEBAddress(uint32_t ProcessId) 69 | { 70 | VMMDLL_PROCESS_INFORMATION procInfo = { 0 }; 71 | SIZE_T cbProcInfo = sizeof(VMMDLL_PROCESS_INFORMATION); 72 | 73 | procInfo.magic = VMMDLL_PROCESS_INFORMATION_MAGIC; 74 | procInfo.wVersion = VMMDLL_PROCESS_INFORMATION_VERSION; 75 | procInfo.wSize = (WORD)cbProcInfo; 76 | 77 | if (!VMMDLL_ProcessGetInformation(DMA::hVMM, ProcessId, &procInfo, &cbProcInfo)) { 78 | std::cerr << "Failed to get process information for PID: " << ProcessId << std::endl; 79 | return false; 80 | } 81 | 82 | DMA::PebAddress = procInfo.win.vaPEB; 83 | std::cout << "PEB: 0x" << std::hex << DMA::PebAddress << std::dec << std::endl; 84 | return true; 85 | } 86 | 87 | -------------------------------------------------------------------------------- /WZ.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {a64a8fd4-bee0-41dd-beec-0647c60233db} 14 | 15 | 16 | {40d2d87c-76e4-4e48-82c4-67d7d6584873} 17 | 18 | 19 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 20 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 21 | 22 | 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files\imgui 32 | 33 | 34 | Source Files\imgui 35 | 36 | 37 | Source Files\imgui 38 | 39 | 40 | Source Files\imgui 41 | 42 | 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files\imgui 55 | 56 | 57 | Header Files\imgui 58 | 59 | 60 | Header Files\imgui 61 | 62 | 63 | Header Files\imgui 64 | 65 | 66 | Header Files\imgui 67 | 68 | 69 | Header Files\imgui 70 | 71 | 72 | Header Files\imgui 73 | 74 | 75 | Header Files\imgui 76 | 77 | 78 | Header Files 79 | 80 | 81 | Header Files 82 | 83 | 84 | -------------------------------------------------------------------------------- /imgui_impl_win32.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications) 2 | // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) 3 | 4 | // Implemented features: 5 | // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) 6 | // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. 7 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] 8 | // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 9 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. 10 | 11 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 12 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 13 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 14 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 15 | 16 | #pragma once 17 | #include "imgui.h" // IMGUI_IMPL_API 18 | #ifndef IMGUI_DISABLE 19 | 20 | IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd); 21 | IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd); 22 | IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); 23 | IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame(); 24 | 25 | // Win32 message handler your application need to call. 26 | // - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on from this helper. 27 | // - You should COPY the line below into your .cpp code to forward declare the function and then you can call it. 28 | // - Call from your application's message handler. Keep calling your message handler unless this function returns TRUE. 29 | 30 | #if 0 31 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 32 | #endif 33 | 34 | // DPI-related helpers (optional) 35 | // - Use to enable DPI awareness without having to create an application manifest. 36 | // - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps. 37 | // - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc. 38 | // but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime, 39 | // neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. 40 | IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness(); 41 | IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd 42 | IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor 43 | 44 | // Transparency related helpers (optional) [experimental] 45 | // - Use to enable alpha compositing transparency with the desktop. 46 | // - Use together with e.g. clearing your framebuffer with zero-alpha. 47 | IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd 48 | 49 | #endif // #ifndef IMGUI_DISABLE 50 | -------------------------------------------------------------------------------- /game.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "dma.h" 5 | #include "utilities.h" 6 | #include "game_math.h" 7 | 8 | inline auto is_user_in_game() -> bool 9 | { 10 | int ingame = DMA::Read(DMA::BaseAddress + offsets::game_mode, sizeof(ingame)); 11 | 12 | return ingame > 0; 13 | } 14 | 15 | inline auto player_count() -> int 16 | { 17 | int playercount = DMA::Read(DMA::BaseAddress + offsets::game_mode, sizeof(playercount)); 18 | 19 | return playercount; 20 | } 21 | 22 | inline auto local_player_index(QWORD client_info) -> int 23 | { 24 | auto index = DMA::ReadPtr(client_info + offsets::local_index); 25 | std::cout << "Index Ptr: 0x" << std::hex << index << std::dec << std::endl; 26 | int read_return = DMA::Read(index + offsets::local_index_pos, sizeof(read_return)); 27 | return read_return; 28 | } 29 | 30 | inline auto is_player_valid(QWORD player_address) -> bool 31 | { 32 | bool response = DMA::Read(player_address + offsets::player::valid, sizeof(response)); 33 | return response; 34 | } 35 | 36 | inline auto team_id(QWORD player_address) -> int 37 | { 38 | int team = DMA::Read(player_address + offsets::player::team, sizeof(team)); 39 | return team; 40 | } 41 | 42 | inline auto get_position(QWORD player_address) -> fvector 43 | { 44 | auto local_position = DMA::ReadPtr(player_address + offsets::player::pos); 45 | fvector final_pos = DMA::Read(local_position + 0x48, sizeof(final_pos)); 46 | return final_pos; 47 | } 48 | 49 | auto retrieve_camera_posistion() -> fvector 50 | { 51 | auto player_camera = DMA::ReadPtr(DMA::BaseAddress + offsets::camera_base); 52 | if (!player_camera) 53 | return {}; 54 | 55 | fvector received = DMA::Read(player_camera + offsets::camera_pos, sizeof(received)); 56 | return received; 57 | } 58 | auto get_angles() -> fvector2d 59 | { 60 | auto camera_angle = DMA::ReadPtr(DMA::BaseAddress + offsets::camera_base); 61 | if (!camera_angle) 62 | return {}; 63 | 64 | fvector2d received = DMA::Read(camera_angle + offsets::camera_pos + 0xC, sizeof(received)); 65 | return received; 66 | } 67 | 68 | auto retrieve_bone_position(const uintptr_t pointer, const int Bone) -> fvector 69 | { 70 | std::cout << "Address to Bone: 0x" << std::hex << pointer + ((uint64_t)Bone * 0x20) + 0x10 << std::dec << std::endl; 71 | fvector position = DMA::Read(pointer + ((uint64_t)Bone * 0x20) + 0x10, sizeof(position)); 72 | return position; 73 | } 74 | 75 | auto retrieve_bone_position_vec(const uintptr_t Client_Information) -> fvector 76 | { 77 | fvector information = DMA::Read(Client_Information + offsets::bone::bone_base, sizeof(information)); 78 | return information; 79 | } 80 | 81 | auto bone_pointer(uint64_t base, uint64_t index) -> uint64_t 82 | { 83 | std::cout << "Address to BonePtr: 0x" << std::hex << base + (index * offsets::bone::size) + offsets::bone::offset << std::dec << std::endl; 84 | auto bone = DMA::ReadPtr(base + (index * offsets::bone::size) + offsets::bone::offset); 85 | return bone; 86 | } 87 | 88 | auto world_to_screen(fvector world_location, fvector2d& out, fvector camera_pos, int screen_width, int screen_height, fvector2d fov, fvector matricies[3]) -> bool 89 | { 90 | // Local Calculation 91 | auto local = world_location - camera_pos; 92 | 93 | // Transformation Calculation 94 | auto trans = fvector{ 95 | local.Dot(matricies[1]), 96 | local.Dot(matricies[2]), 97 | local.Dot(matricies[0]) 98 | }; 99 | 100 | // Check trans.z 101 | if (trans.z < 0.01f) { 102 | return false; 103 | } 104 | 105 | // Screen Coordinates Calculation 106 | out.x = ((float)screen_width / 2.0) * (1.0 - (trans.x / fov.x / trans.z)); 107 | out.y = ((float)screen_height / 2.0) * (1.0 - (trans.y / fov.y / trans.z)); 108 | 109 | // Bounds Check 110 | if (out.x < 1 || out.y < 1 || (out.x > decrypt_refdef->ref_def_nn.width) || (out.y > decrypt_refdef->ref_def_nn.height)) { 111 | return false; 112 | } 113 | 114 | return true; 115 | } 116 | 117 | auto w2s(fvector world_position, fvector2d& screen_position) -> bool 118 | { 119 | return world_to_screen(world_position, screen_position, retrieve_camera_posistion(), decrypt_refdef->ref_def_nn.width, decrypt_refdef->ref_def_nn.height, decrypt_refdef->ref_def_nn.tan_half_fov, decrypt_refdef->ref_def_nn.axis); 120 | } 121 | 122 | auto units_to_m(float units) -> float { 123 | return units * 0.0254; 124 | } -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "dma.h" 5 | #include "game.h" 6 | 7 | int main() { 8 | if (!DMA::Connect()) { 9 | std::cout << "Failed to Connect" << std::endl; 10 | return 0; 11 | } 12 | if (!DMA::AttachToProcessId()) { 13 | std::cout << "Failed to Attach" << std::endl; 14 | return 0; 15 | } 16 | if (DMA::GetPEBAddress(DMA::AttachedProcessId) == false) { 17 | std::cout << "Failed to get PEB" << std::endl; 18 | return 0; 19 | } 20 | 21 | while (true) { 22 | if (is_user_in_game()) { 23 | int count = player_count(); 24 | //std::cout << "Player Count: " << count << std::endl; 25 | 26 | uint64_t clientInfo = decrypt_client_info(); 27 | if (clientInfo) { 28 | //std::cout << "Client Info: 0x" << std::hex << clientInfo << std::dec << std::endl; 29 | uint64_t clientBase = decrypt_client_base(clientInfo); 30 | //std::cout << "Client Base: 0x" << std::hex << clientBase << std::dec << std::endl; 31 | 32 | // Local Player 33 | int index = local_player_index(clientInfo); 34 | //std::cout << "Index: " << index << std::endl; 35 | uint64_t localPlayer = clientBase + (index * offsets::player::size); 36 | //std::cout << "Local Player: 0x" << std::hex << localPlayer << std::dec << std::endl; 37 | bool valid = is_player_valid(localPlayer); 38 | //std::cout << "Valid: " << std::boolalpha << valid << std::dec << std::endl; 39 | int teamId = team_id(localPlayer); 40 | //std::cout << "Team ID: " << teamId << std::endl; 41 | fvector pos = get_position(localPlayer); 42 | //std::cout << "Position: (" << pos.x << ", " << pos.y << ", " << pos.z << ")" << std::endl; 43 | 44 | // Ref Def 45 | uint64_t refDefPtr = decrypt_refdef->retrieve_ref_def(); 46 | //std::cout << "RefDef Address: 0x" << std::hex << refDefPtr << std::dec << std::endl; 47 | decrypt_refdef->ref_def_nn = DMA::Read(refDefPtr, sizeof(decrypt_refdef->ref_def_nn)); 48 | ref_def_t& ref_def = decrypt_refdef->ref_def_nn; // A reference for ease of use 49 | //std::cout << "x: " << ref_def.x << '\n'; 50 | //std::cout << "y: " << ref_def.y << '\n'; 51 | //std::cout << "width: " << ref_def.width << '\n'; 52 | //std::cout << "height: " << ref_def.height << '\n'; 53 | 54 | // Bone Base 55 | uint64_t boneBase = decrypt_bone_base(); 56 | //std::cout << "Bone Base: 0x" << std::hex << boneBase << std::dec << std::endl; 57 | //fvector bonePos = retrieve_bone_position_vec(clientInfo); 58 | //std::cout << "Bone Pos: (" << bonePos.x << ", " << bonePos.y << ", " << bonePos.z << ")" << std::endl; 59 | 60 | for (int i = 0; i < count; i++) 61 | { 62 | if (i == index) { 63 | continue; 64 | } 65 | 66 | uint64_t player = clientBase + (i * offsets::player::size); 67 | bool player_valid = is_player_valid(player); 68 | if (!player_valid) 69 | { 70 | continue; 71 | } 72 | 73 | fvector player_pos = get_position(player); 74 | if (player_pos.x == 0.0 && player_pos.y == 0.0 && player_pos.z == 0.0) { 75 | continue; 76 | } 77 | 78 | fvector2d player_screen = { 0, 0 }; 79 | if (w2s(player_pos, player_screen)) { 80 | auto player_distance = units_to_m(pos.distance_to(player_pos)); 81 | auto player_bone_index = get_bone_index(i); 82 | std::cout << "Bone Index: " << player_bone_index << std::endl; 83 | auto player_bone_ptr = bone_pointer(boneBase, player_bone_index); 84 | std::cout << "Bone Ptr: 0x" << std::hex << player_bone_ptr << std::dec << std::endl; 85 | 86 | auto player_bone_pos = retrieve_bone_position(player_bone_ptr, 7); 87 | std::cout << "Player" << i << " Bone Pos:" << " (" << player_bone_pos.x << ", " << player_bone_pos.y << ", " << player_bone_pos.z << ")" << std::endl; 88 | std::cout << "Player" << i << " Pos:" << " (" << player_pos.x << ", " << player_pos.y << ", " << player_pos.z << ")" << std::endl; 89 | 90 | // Getting wrong bone position, trying to figure out why 91 | break; 92 | } 93 | } 94 | } 95 | } 96 | 97 | Sleep(1000); 98 | } 99 | 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /WZ.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 17.0 23 | Win32Proj 24 | {2bea2a73-224b-4e76-b257-7a3c35181d4f} 25 | WZ 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | true 77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | Console 82 | true 83 | 84 | 85 | 86 | 87 | Level3 88 | true 89 | true 90 | true 91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | true 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | C:\Users\Administrator\source\repos\WZ\imgui;C:\Users\Administrator\source\repos\WZ\pcileech;%(AdditionalIncludeDirectories) 108 | stdcpp17 109 | 110 | 111 | Console 112 | true 113 | 114 | 115 | 116 | 117 | Level3 118 | true 119 | true 120 | true 121 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 122 | true 123 | MultiThreadedDLL 124 | stdcpp17 125 | 126 | 127 | Console 128 | true 129 | true 130 | true 131 | d3d11.lib;d3dcompiler.lib;dxgi.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) 132 | 133 | 134 | 135 | 136 | pch.h 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /game_math.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "vector.h" 3 | 4 | class fvector2d 5 | { 6 | public: 7 | float x; 8 | float y; 9 | 10 | inline bool is_Zero() { 11 | return (x == 0) && (y == 0); 12 | } 13 | }; 14 | 15 | class fvector 16 | { 17 | public: 18 | fvector() : x(0.f), y(0.f), z(0.f) 19 | { 20 | 21 | } 22 | 23 | fvector(float _x, float _y, float _z) : x(_x), y(_y), z(_z) 24 | { 25 | 26 | } 27 | ~fvector() 28 | { 29 | 30 | } 31 | 32 | float x; 33 | float y; 34 | float z; 35 | 36 | inline float Dot(fvector v) 37 | { 38 | return x * v.x + y * v.y + z * v.z; 39 | } 40 | 41 | inline float Distance(fvector v) 42 | { 43 | return float(sqrtf(powf(v.x - x, 2.0) + powf(v.y - y, 2.0) + powf(v.z - z, 2.0))); 44 | } 45 | float length(void) { 46 | auto sqr = [](float n) { 47 | return static_cast(n * n); 48 | }; 49 | 50 | return sqrt(sqr(x) + sqr(y) + sqr(z)); 51 | } 52 | 53 | float distance_to(const fvector& other) { 54 | fvector delta; 55 | delta.x = x - other.x; 56 | delta.y = y - other.y; 57 | delta.z = z - other.z; 58 | 59 | return delta.length(); 60 | } 61 | inline float Length() 62 | { 63 | return sqrt(x * x + y * y + z * z); 64 | } 65 | 66 | fvector operator+(fvector v) 67 | { 68 | return fvector(x + v.x, y + v.y, z + v.z); 69 | } 70 | 71 | fvector operator-(fvector v) 72 | { 73 | return fvector(x - v.x, y - v.y, z - v.z); 74 | } 75 | 76 | fvector operator*(float number) const 77 | { 78 | return fvector(x * number, y * number, z * number); 79 | } 80 | }; 81 | 82 | struct fplane : fvector 83 | { 84 | float W = 0; 85 | 86 | 87 | fvector ToVector3() 88 | { 89 | fvector value; 90 | value.x = this->x; 91 | value.y = this->y; 92 | value.z = this->y; 93 | 94 | return value; 95 | } 96 | }; 97 | 98 | struct fquat 99 | { 100 | float x; 101 | float y; 102 | float z; 103 | float w; 104 | }; 105 | 106 | struct fmatrix 107 | { 108 | fplane XPlane; 109 | fplane YPlane; 110 | fplane ZPlane; 111 | fplane WPlane; 112 | }; 113 | 114 | struct ftransform 115 | { 116 | fplane rot; 117 | fvector translation; 118 | char pad[8]; 119 | fvector scale; 120 | 121 | D3DMATRIX ToMatrixWithScale() 122 | { 123 | D3DMATRIX m; 124 | m._41 = translation.x; 125 | m._42 = translation.y; 126 | m._43 = translation.z; 127 | 128 | float x2 = rot.x + rot.x; 129 | float y2 = rot.y + rot.y; 130 | float z2 = rot.z + rot.z; 131 | 132 | float xx2 = rot.x * x2; 133 | float yy2 = rot.y * y2; 134 | float zz2 = rot.z * z2; 135 | m._11 = (1.0f - (yy2 + zz2)) * scale.x; 136 | m._22 = (1.0f - (xx2 + zz2)) * scale.y; 137 | m._33 = (1.0f - (xx2 + yy2)) * scale.z; 138 | 139 | float yz2 = rot.y * z2; 140 | float wx2 = rot.W * x2; 141 | m._32 = (yz2 - wx2) * scale.z; 142 | m._23 = (yz2 + wx2) * scale.y; 143 | 144 | float xy2 = rot.x * y2; 145 | float wz2 = rot.W * z2; 146 | m._21 = (xy2 - wz2) * scale.y; 147 | m._12 = (xy2 + wz2) * scale.x; 148 | 149 | float xz2 = rot.x * z2; 150 | float wy2 = rot.W * y2; 151 | m._31 = (xz2 + wy2) * scale.z; 152 | m._13 = (xz2 - wy2) * scale.x; 153 | 154 | m._14 = 0.0f; 155 | m._24 = 0.0f; 156 | m._34 = 0.0f; 157 | m._44 = 1.0f; 158 | 159 | return m; 160 | } 161 | }; 162 | 163 | D3DMATRIX MatrixMultiplication(D3DMATRIX pM1, D3DMATRIX pM2) 164 | { 165 | D3DMATRIX pOut; 166 | pOut._11 = pM1._11 * pM2._11 + pM1._12 * pM2._21 + pM1._13 * pM2._31 + pM1._14 * pM2._41; 167 | pOut._12 = pM1._11 * pM2._12 + pM1._12 * pM2._22 + pM1._13 * pM2._32 + pM1._14 * pM2._42; 168 | pOut._13 = pM1._11 * pM2._13 + pM1._12 * pM2._23 + pM1._13 * pM2._33 + pM1._14 * pM2._43; 169 | pOut._14 = pM1._11 * pM2._14 + pM1._12 * pM2._24 + pM1._13 * pM2._34 + pM1._14 * pM2._44; 170 | pOut._21 = pM1._21 * pM2._11 + pM1._22 * pM2._21 + pM1._23 * pM2._31 + pM1._24 * pM2._41; 171 | pOut._22 = pM1._21 * pM2._12 + pM1._22 * pM2._22 + pM1._23 * pM2._32 + pM1._24 * pM2._42; 172 | pOut._23 = pM1._21 * pM2._13 + pM1._22 * pM2._23 + pM1._23 * pM2._33 + pM1._24 * pM2._43; 173 | pOut._24 = pM1._21 * pM2._14 + pM1._22 * pM2._24 + pM1._23 * pM2._34 + pM1._24 * pM2._44; 174 | pOut._31 = pM1._31 * pM2._11 + pM1._32 * pM2._21 + pM1._33 * pM2._31 + pM1._34 * pM2._41; 175 | pOut._32 = pM1._31 * pM2._12 + pM1._32 * pM2._22 + pM1._33 * pM2._32 + pM1._34 * pM2._42; 176 | pOut._33 = pM1._31 * pM2._13 + pM1._32 * pM2._23 + pM1._33 * pM2._33 + pM1._34 * pM2._43; 177 | pOut._34 = pM1._31 * pM2._14 + pM1._32 * pM2._24 + pM1._33 * pM2._34 + pM1._34 * pM2._44; 178 | pOut._41 = pM1._41 * pM2._11 + pM1._42 * pM2._21 + pM1._43 * pM2._31 + pM1._44 * pM2._41; 179 | pOut._42 = pM1._41 * pM2._12 + pM1._42 * pM2._22 + pM1._43 * pM2._32 + pM1._44 * pM2._42; 180 | pOut._43 = pM1._41 * pM2._13 + pM1._42 * pM2._23 + pM1._43 * pM2._33 + pM1._44 * pM2._43; 181 | pOut._44 = pM1._41 * pM2._14 + pM1._42 * pM2._24 + pM1._43 * pM2._34 + pM1._44 * pM2._44; 182 | 183 | return pOut; 184 | } 185 | 186 | D3DMATRIX Matrix(fvector rot, fvector origin = fvector(0, 0, 0)) 187 | { 188 | float radPitch = (rot.x * float(M_PI) / 180.f); 189 | float radYaw = (rot.y * float(M_PI) / 180.f); 190 | float radRoll = (rot.z * float(M_PI) / 180.f); 191 | 192 | float SP = sinf(radPitch); 193 | float CP = cosf(radPitch); 194 | float SY = sinf(radYaw); 195 | float CY = cosf(radYaw); 196 | float SR = sinf(radRoll); 197 | float CR = cosf(radRoll); 198 | 199 | D3DMATRIX matrix; 200 | matrix.m[0][0] = CP * CY; 201 | matrix.m[0][1] = CP * SY; 202 | matrix.m[0][2] = SP; 203 | matrix.m[0][3] = 0.f; 204 | 205 | matrix.m[1][0] = SR * SP * CY - CR * SY; 206 | matrix.m[1][1] = SR * SP * SY + CR * CY; 207 | matrix.m[1][2] = -SR * CP; 208 | matrix.m[1][3] = 0.f; 209 | 210 | matrix.m[2][0] = -(CR * SP * CY + SR * SY); 211 | matrix.m[2][1] = CY * SR - CR * SP * SY; 212 | matrix.m[2][2] = CR * CP; 213 | matrix.m[2][3] = 0.f; 214 | 215 | matrix.m[3][0] = origin.x; 216 | matrix.m[3][1] = origin.y; 217 | matrix.m[3][2] = origin.z; 218 | matrix.m[3][3] = 1.f; 219 | 220 | return matrix; 221 | } 222 | 223 | class frotator 224 | { 225 | public: 226 | frotator() : Pitch(0.f), Yaw(0.f), Roll(0.f) 227 | { 228 | 229 | } 230 | 231 | frotator(float _Pitch, float _Yaw, float _Roll) : Pitch(_Pitch), Yaw(_Yaw), Roll(_Roll) 232 | { 233 | 234 | } 235 | ~frotator() 236 | { 237 | 238 | } 239 | 240 | float Pitch; 241 | float Yaw; 242 | float Roll; 243 | inline frotator get() { 244 | return frotator(Pitch, Yaw, Roll); 245 | } 246 | inline void set(float _Pitch, float _Yaw, float _Roll) { 247 | Pitch = _Pitch; 248 | Yaw = _Yaw; 249 | Roll = _Roll; 250 | } 251 | 252 | inline frotator Clamp() { 253 | frotator result = get(); 254 | if (result.Pitch > 180) 255 | result.Pitch -= 360; 256 | else if (result.Pitch < -180) 257 | result.Pitch += 360; 258 | if (result.Yaw > 180) 259 | result.Yaw -= 360; 260 | else if (result.Yaw < -180) 261 | result.Yaw += 360; 262 | if (result.Pitch < -89) 263 | result.Pitch = -89; 264 | if (result.Pitch > 89) 265 | result.Pitch = 89; 266 | while (result.Yaw < -180.0f) 267 | result.Yaw += 360.0f; 268 | while (result.Yaw > 180.0f) 269 | result.Yaw -= 360.0f; 270 | 271 | result.Roll = 0; 272 | return result; 273 | 274 | } 275 | float Length() { 276 | return sqrt(Pitch * Pitch + Yaw * Yaw + Roll * Roll); 277 | } 278 | 279 | frotator operator+(frotator angB) { return frotator(Pitch + angB.Pitch, Yaw + angB.Yaw, Roll + angB.Roll); } 280 | frotator operator-(frotator angB) { return frotator(Pitch - angB.Pitch, Yaw - angB.Yaw, Roll - angB.Roll); } 281 | frotator operator/(float flNum) { return frotator(Pitch / flNum, Yaw / flNum, Roll / flNum); } 282 | frotator operator*(float flNum) { return frotator(Pitch * flNum, Yaw * flNum, Roll * flNum); } 283 | bool operator==(frotator angB) { return Pitch == angB.Pitch && Yaw == angB.Yaw && Yaw == angB.Yaw; } 284 | bool operator!=(frotator angB) { return Pitch != angB.Pitch || Yaw != angB.Yaw || Yaw != angB.Yaw; } 285 | 286 | }; 287 | 288 | float __fastcall Atan2(float a1, float a2) 289 | { 290 | float result; 291 | 292 | result = 0.0; 293 | if (a2 != 0.0 || a1 != 0.0) 294 | return atan2(a1, a2); 295 | return result; 296 | } 297 | float __fastcall FMod(float a1, float a2) 298 | { 299 | if (fabs(a2) > 0.00000001) 300 | return fmod(a1, a2); 301 | else 302 | return 0.0; 303 | } 304 | 305 | float ClampAxis(float Angle) 306 | { 307 | Angle = FMod(Angle, (float)360.0); 308 | 309 | if (Angle < (float)0.0) 310 | { 311 | Angle += (float)360.0; 312 | } 313 | 314 | return Angle; 315 | } 316 | 317 | float NormalizeAxis(float Angle) 318 | { 319 | Angle = ClampAxis(Angle); 320 | 321 | if (Angle > (float)180.0) 322 | { 323 | Angle -= (float)360.0; 324 | } 325 | 326 | return Angle; 327 | } 328 | 329 | frotator rotator(fquat* F) 330 | { 331 | const float SingularityTest = F->z * F->x - F->w * F->y; 332 | const float YawY = 2.f * (F->w * F->z + F->x * F->y); 333 | const float YawX = (1.f - 2.f * ((F->y * F->y) + (F->z * F->z))); 334 | 335 | const float SINGULARITY_THRESHOLD = 0.4999995f; 336 | const float RAD_TO_DEG = 57.295776; 337 | float Pitch, Yaw, Roll; 338 | 339 | if (SingularityTest < -SINGULARITY_THRESHOLD) 340 | { 341 | Pitch = -90.f; 342 | Yaw = (Atan2(YawY, YawX) * RAD_TO_DEG); 343 | Roll = NormalizeAxis(-Yaw - (2.f * Atan2(F->x, F->w) * RAD_TO_DEG)); 344 | } 345 | else if (SingularityTest > SINGULARITY_THRESHOLD) 346 | { 347 | Pitch = 90.f; 348 | Yaw = (Atan2(YawY, YawX) * RAD_TO_DEG); 349 | Roll = NormalizeAxis(Yaw - (2.f * Atan2(F->x, F->w) * RAD_TO_DEG)); 350 | } 351 | else 352 | { 353 | Pitch = (asin(2.f * SingularityTest) * RAD_TO_DEG); 354 | Yaw = (Atan2(YawY, YawX) * RAD_TO_DEG); 355 | Roll = (Atan2(-2.f * (F->w * F->x + F->y * F->z), (1.f - 2.f * ((F->x * F->x) + (F->y * F->y)))) * RAD_TO_DEG); 356 | } 357 | 358 | frotator RotatorFromQuat = frotator{ Pitch, Yaw, Roll }; 359 | return RotatorFromQuat; 360 | } -------------------------------------------------------------------------------- /imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // DEAR IMGUI COMPILE-TIME OPTIONS 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) 7 | // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. 8 | //----------------------------------------------------------------------------- 9 | // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp 10 | // files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. 11 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 12 | // Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using. 13 | //----------------------------------------------------------------------------- 14 | 15 | #pragma once 16 | 17 | //---- Define assertion handler. Defaults to calling assert(). 18 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. 19 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 20 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 21 | 22 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows 23 | // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. 24 | // DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() 25 | // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. 26 | //#define IMGUI_API __declspec( dllexport ) 27 | //#define IMGUI_API __declspec( dllimport ) 28 | 29 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names. 30 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 31 | //#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions. 32 | 33 | //---- Disable all of Dear ImGui or don't implement standard windows/tools. 34 | // It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp. 35 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. 36 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. 37 | //#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88). 38 | 39 | //---- Don't implement some functions to reduce linkage requirements. 40 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) 41 | //#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) 42 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) 43 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME). 44 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). 45 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) 46 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. 47 | //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) 48 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. 49 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 50 | //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available 51 | 52 | //---- Include imgui_user.h at the end of imgui.h as a convenience 53 | //#define IMGUI_INCLUDE_IMGUI_USER_H 54 | 55 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 56 | //#define IMGUI_USE_BGRA_PACKED_COLOR 57 | 58 | //---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) 59 | //#define IMGUI_USE_WCHAR32 60 | 61 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 62 | // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. 63 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 64 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 65 | //#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined. 66 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 67 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 68 | //#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined. 69 | 70 | //---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) 71 | // Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h. 72 | //#define IMGUI_USE_STB_SPRINTF 73 | 74 | //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) 75 | // Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). 76 | // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. 77 | //#define IMGUI_ENABLE_FREETYPE 78 | 79 | //---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT) 80 | // Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided). 81 | // Only works in combination with IMGUI_ENABLE_FREETYPE. 82 | // (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) 83 | //#define IMGUI_ENABLE_FREETYPE_LUNASVG 84 | 85 | //---- Use stb_truetype to build and rasterize the font atlas (default) 86 | // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. 87 | //#define IMGUI_ENABLE_STB_TRUETYPE 88 | 89 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 90 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 91 | /* 92 | #define IM_VEC2_CLASS_EXTRA \ 93 | constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \ 94 | operator MyVec2() const { return MyVec2(x,y); } 95 | 96 | #define IM_VEC4_CLASS_EXTRA \ 97 | constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \ 98 | operator MyVec4() const { return MyVec4(x,y,z,w); } 99 | */ 100 | //---- ...Or use Dear ImGui's own very basic math operators. 101 | //#define IMGUI_DEFINE_MATH_OPERATORS 102 | 103 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. 104 | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). 105 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. 106 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 107 | //#define ImDrawIdx unsigned int 108 | 109 | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) 110 | //struct ImDrawList; 111 | //struct ImDrawCmd; 112 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 113 | //#define ImDrawCallback MyImDrawCallback 114 | 115 | //---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase) 116 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) 117 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 118 | //#define IM_DEBUG_BREAK __debugbreak() 119 | 120 | //---- Debug Tools: Enable slower asserts 121 | //#define IMGUI_DEBUG_PARANOID 122 | 123 | //---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files) 124 | /* 125 | namespace ImGui 126 | { 127 | void MyFunction(const char* name, MyMatrix44* mtx); 128 | } 129 | */ 130 | -------------------------------------------------------------------------------- /imstb_rectpack.h: -------------------------------------------------------------------------------- 1 | // [DEAR IMGUI] 2 | // This is a slightly modified version of stb_rect_pack.h 1.01. 3 | // Grep for [DEAR IMGUI] to find the changes. 4 | // 5 | // stb_rect_pack.h - v1.01 - public domain - rectangle packing 6 | // Sean Barrett 2014 7 | // 8 | // Useful for e.g. packing rectangular textures into an atlas. 9 | // Does not do rotation. 10 | // 11 | // Before #including, 12 | // 13 | // #define STB_RECT_PACK_IMPLEMENTATION 14 | // 15 | // in the file that you want to have the implementation. 16 | // 17 | // Not necessarily the awesomest packing method, but better than 18 | // the totally naive one in stb_truetype (which is primarily what 19 | // this is meant to replace). 20 | // 21 | // Has only had a few tests run, may have issues. 22 | // 23 | // More docs to come. 24 | // 25 | // No memory allocations; uses qsort() and assert() from stdlib. 26 | // Can override those by defining STBRP_SORT and STBRP_ASSERT. 27 | // 28 | // This library currently uses the Skyline Bottom-Left algorithm. 29 | // 30 | // Please note: better rectangle packers are welcome! Please 31 | // implement them to the same API, but with a different init 32 | // function. 33 | // 34 | // Credits 35 | // 36 | // Library 37 | // Sean Barrett 38 | // Minor features 39 | // Martins Mozeiko 40 | // github:IntellectualKitty 41 | // 42 | // Bugfixes / warning fixes 43 | // Jeremy Jaussaud 44 | // Fabian Giesen 45 | // 46 | // Version history: 47 | // 48 | // 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section 49 | // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles 50 | // 0.99 (2019-02-07) warning fixes 51 | // 0.11 (2017-03-03) return packing success/fail result 52 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings 53 | // 0.09 (2016-08-27) fix compiler warnings 54 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) 55 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) 56 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort 57 | // 0.05: added STBRP_ASSERT to allow replacing assert 58 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support 59 | // 0.01: initial release 60 | // 61 | // LICENSE 62 | // 63 | // See end of file for license information. 64 | 65 | ////////////////////////////////////////////////////////////////////////////// 66 | // 67 | // INCLUDE SECTION 68 | // 69 | 70 | #ifndef STB_INCLUDE_STB_RECT_PACK_H 71 | #define STB_INCLUDE_STB_RECT_PACK_H 72 | 73 | #define STB_RECT_PACK_VERSION 1 74 | 75 | #ifdef STBRP_STATIC 76 | #define STBRP_DEF static 77 | #else 78 | #define STBRP_DEF extern 79 | #endif 80 | 81 | #ifdef __cplusplus 82 | extern "C" { 83 | #endif 84 | 85 | typedef struct stbrp_context stbrp_context; 86 | typedef struct stbrp_node stbrp_node; 87 | typedef struct stbrp_rect stbrp_rect; 88 | 89 | typedef int stbrp_coord; 90 | 91 | #define STBRP__MAXVAL 0x7fffffff 92 | // Mostly for internal use, but this is the maximum supported coordinate value. 93 | 94 | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); 95 | // Assign packed locations to rectangles. The rectangles are of type 96 | // 'stbrp_rect' defined below, stored in the array 'rects', and there 97 | // are 'num_rects' many of them. 98 | // 99 | // Rectangles which are successfully packed have the 'was_packed' flag 100 | // set to a non-zero value and 'x' and 'y' store the minimum location 101 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left 102 | // if you imagine y increasing downwards). Rectangles which do not fit 103 | // have the 'was_packed' flag set to 0. 104 | // 105 | // You should not try to access the 'rects' array from another thread 106 | // while this function is running, as the function temporarily reorders 107 | // the array while it executes. 108 | // 109 | // To pack into another rectangle, you need to call stbrp_init_target 110 | // again. To continue packing into the same rectangle, you can call 111 | // this function again. Calling this multiple times with multiple rect 112 | // arrays will probably produce worse packing results than calling it 113 | // a single time with the full rectangle array, but the option is 114 | // available. 115 | // 116 | // The function returns 1 if all of the rectangles were successfully 117 | // packed and 0 otherwise. 118 | 119 | struct stbrp_rect 120 | { 121 | // reserved for your use: 122 | int id; 123 | 124 | // input: 125 | stbrp_coord w, h; 126 | 127 | // output: 128 | stbrp_coord x, y; 129 | int was_packed; // non-zero if valid packing 130 | 131 | }; // 16 bytes, nominally 132 | 133 | 134 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); 135 | // Initialize a rectangle packer to: 136 | // pack a rectangle that is 'width' by 'height' in dimensions 137 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long 138 | // 139 | // You must call this function every time you start packing into a new target. 140 | // 141 | // There is no "shutdown" function. The 'nodes' memory must stay valid for 142 | // the following stbrp_pack_rects() call (or calls), but can be freed after 143 | // the call (or calls) finish. 144 | // 145 | // Note: to guarantee best results, either: 146 | // 1. make sure 'num_nodes' >= 'width' 147 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' 148 | // 149 | // If you don't do either of the above things, widths will be quantized to multiples 150 | // of small integers to guarantee the algorithm doesn't run out of temporary storage. 151 | // 152 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm 153 | // may run out of temporary storage and be unable to pack some rectangles. 154 | 155 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); 156 | // Optionally call this function after init but before doing any packing to 157 | // change the handling of the out-of-temp-memory scenario, described above. 158 | // If you call init again, this will be reset to the default (false). 159 | 160 | 161 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); 162 | // Optionally select which packing heuristic the library should use. Different 163 | // heuristics will produce better/worse results for different data sets. 164 | // If you call init again, this will be reset to the default. 165 | 166 | enum 167 | { 168 | STBRP_HEURISTIC_Skyline_default=0, 169 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, 170 | STBRP_HEURISTIC_Skyline_BF_sortHeight 171 | }; 172 | 173 | 174 | ////////////////////////////////////////////////////////////////////////////// 175 | // 176 | // the details of the following structures don't matter to you, but they must 177 | // be visible so you can handle the memory allocations for them 178 | 179 | struct stbrp_node 180 | { 181 | stbrp_coord x,y; 182 | stbrp_node *next; 183 | }; 184 | 185 | struct stbrp_context 186 | { 187 | int width; 188 | int height; 189 | int align; 190 | int init_mode; 191 | int heuristic; 192 | int num_nodes; 193 | stbrp_node *active_head; 194 | stbrp_node *free_head; 195 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' 196 | }; 197 | 198 | #ifdef __cplusplus 199 | } 200 | #endif 201 | 202 | #endif 203 | 204 | ////////////////////////////////////////////////////////////////////////////// 205 | // 206 | // IMPLEMENTATION SECTION 207 | // 208 | 209 | #ifdef STB_RECT_PACK_IMPLEMENTATION 210 | #ifndef STBRP_SORT 211 | #include 212 | #define STBRP_SORT qsort 213 | #endif 214 | 215 | #ifndef STBRP_ASSERT 216 | #include 217 | #define STBRP_ASSERT assert 218 | #endif 219 | 220 | #ifdef _MSC_VER 221 | #define STBRP__NOTUSED(v) (void)(v) 222 | #define STBRP__CDECL __cdecl 223 | #else 224 | #define STBRP__NOTUSED(v) (void)sizeof(v) 225 | #define STBRP__CDECL 226 | #endif 227 | 228 | enum 229 | { 230 | STBRP__INIT_skyline = 1 231 | }; 232 | 233 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) 234 | { 235 | switch (context->init_mode) { 236 | case STBRP__INIT_skyline: 237 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); 238 | context->heuristic = heuristic; 239 | break; 240 | default: 241 | STBRP_ASSERT(0); 242 | } 243 | } 244 | 245 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) 246 | { 247 | if (allow_out_of_mem) 248 | // if it's ok to run out of memory, then don't bother aligning them; 249 | // this gives better packing, but may fail due to OOM (even though 250 | // the rectangles easily fit). @TODO a smarter approach would be to only 251 | // quantize once we've hit OOM, then we could get rid of this parameter. 252 | context->align = 1; 253 | else { 254 | // if it's not ok to run out of memory, then quantize the widths 255 | // so that num_nodes is always enough nodes. 256 | // 257 | // I.e. num_nodes * align >= width 258 | // align >= width / num_nodes 259 | // align = ceil(width/num_nodes) 260 | 261 | context->align = (context->width + context->num_nodes-1) / context->num_nodes; 262 | } 263 | } 264 | 265 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) 266 | { 267 | int i; 268 | 269 | for (i=0; i < num_nodes-1; ++i) 270 | nodes[i].next = &nodes[i+1]; 271 | nodes[i].next = NULL; 272 | context->init_mode = STBRP__INIT_skyline; 273 | context->heuristic = STBRP_HEURISTIC_Skyline_default; 274 | context->free_head = &nodes[0]; 275 | context->active_head = &context->extra[0]; 276 | context->width = width; 277 | context->height = height; 278 | context->num_nodes = num_nodes; 279 | stbrp_setup_allow_out_of_mem(context, 0); 280 | 281 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) 282 | context->extra[0].x = 0; 283 | context->extra[0].y = 0; 284 | context->extra[0].next = &context->extra[1]; 285 | context->extra[1].x = (stbrp_coord) width; 286 | context->extra[1].y = (1<<30); 287 | context->extra[1].next = NULL; 288 | } 289 | 290 | // find minimum y position if it starts at x1 291 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) 292 | { 293 | stbrp_node *node = first; 294 | int x1 = x0 + width; 295 | int min_y, visited_width, waste_area; 296 | 297 | STBRP__NOTUSED(c); 298 | 299 | STBRP_ASSERT(first->x <= x0); 300 | 301 | #if 0 302 | // skip in case we're past the node 303 | while (node->next->x <= x0) 304 | ++node; 305 | #else 306 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency 307 | #endif 308 | 309 | STBRP_ASSERT(node->x <= x0); 310 | 311 | min_y = 0; 312 | waste_area = 0; 313 | visited_width = 0; 314 | while (node->x < x1) { 315 | if (node->y > min_y) { 316 | // raise min_y higher. 317 | // we've accounted for all waste up to min_y, 318 | // but we'll now add more waste for everything we've visted 319 | waste_area += visited_width * (node->y - min_y); 320 | min_y = node->y; 321 | // the first time through, visited_width might be reduced 322 | if (node->x < x0) 323 | visited_width += node->next->x - x0; 324 | else 325 | visited_width += node->next->x - node->x; 326 | } else { 327 | // add waste area 328 | int under_width = node->next->x - node->x; 329 | if (under_width + visited_width > width) 330 | under_width = width - visited_width; 331 | waste_area += under_width * (min_y - node->y); 332 | visited_width += under_width; 333 | } 334 | node = node->next; 335 | } 336 | 337 | *pwaste = waste_area; 338 | return min_y; 339 | } 340 | 341 | typedef struct 342 | { 343 | int x,y; 344 | stbrp_node **prev_link; 345 | } stbrp__findresult; 346 | 347 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) 348 | { 349 | int best_waste = (1<<30), best_x, best_y = (1 << 30); 350 | stbrp__findresult fr; 351 | stbrp_node **prev, *node, *tail, **best = NULL; 352 | 353 | // align to multiple of c->align 354 | width = (width + c->align - 1); 355 | width -= width % c->align; 356 | STBRP_ASSERT(width % c->align == 0); 357 | 358 | // if it can't possibly fit, bail immediately 359 | if (width > c->width || height > c->height) { 360 | fr.prev_link = NULL; 361 | fr.x = fr.y = 0; 362 | return fr; 363 | } 364 | 365 | node = c->active_head; 366 | prev = &c->active_head; 367 | while (node->x + width <= c->width) { 368 | int y,waste; 369 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); 370 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL 371 | // bottom left 372 | if (y < best_y) { 373 | best_y = y; 374 | best = prev; 375 | } 376 | } else { 377 | // best-fit 378 | if (y + height <= c->height) { 379 | // can only use it if it first vertically 380 | if (y < best_y || (y == best_y && waste < best_waste)) { 381 | best_y = y; 382 | best_waste = waste; 383 | best = prev; 384 | } 385 | } 386 | } 387 | prev = &node->next; 388 | node = node->next; 389 | } 390 | 391 | best_x = (best == NULL) ? 0 : (*best)->x; 392 | 393 | // if doing best-fit (BF), we also have to try aligning right edge to each node position 394 | // 395 | // e.g, if fitting 396 | // 397 | // ____________________ 398 | // |____________________| 399 | // 400 | // into 401 | // 402 | // | | 403 | // | ____________| 404 | // |____________| 405 | // 406 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned 407 | // 408 | // This makes BF take about 2x the time 409 | 410 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { 411 | tail = c->active_head; 412 | node = c->active_head; 413 | prev = &c->active_head; 414 | // find first node that's admissible 415 | while (tail->x < width) 416 | tail = tail->next; 417 | while (tail) { 418 | int xpos = tail->x - width; 419 | int y,waste; 420 | STBRP_ASSERT(xpos >= 0); 421 | // find the left position that matches this 422 | while (node->next->x <= xpos) { 423 | prev = &node->next; 424 | node = node->next; 425 | } 426 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); 427 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); 428 | if (y + height <= c->height) { 429 | if (y <= best_y) { 430 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { 431 | best_x = xpos; 432 | //STBRP_ASSERT(y <= best_y); [DEAR IMGUI] 433 | best_y = y; 434 | best_waste = waste; 435 | best = prev; 436 | } 437 | } 438 | } 439 | tail = tail->next; 440 | } 441 | } 442 | 443 | fr.prev_link = best; 444 | fr.x = best_x; 445 | fr.y = best_y; 446 | return fr; 447 | } 448 | 449 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) 450 | { 451 | // find best position according to heuristic 452 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); 453 | stbrp_node *node, *cur; 454 | 455 | // bail if: 456 | // 1. it failed 457 | // 2. the best node doesn't fit (we don't always check this) 458 | // 3. we're out of memory 459 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { 460 | res.prev_link = NULL; 461 | return res; 462 | } 463 | 464 | // on success, create new node 465 | node = context->free_head; 466 | node->x = (stbrp_coord) res.x; 467 | node->y = (stbrp_coord) (res.y + height); 468 | 469 | context->free_head = node->next; 470 | 471 | // insert the new node into the right starting point, and 472 | // let 'cur' point to the remaining nodes needing to be 473 | // stiched back in 474 | 475 | cur = *res.prev_link; 476 | if (cur->x < res.x) { 477 | // preserve the existing one, so start testing with the next one 478 | stbrp_node *next = cur->next; 479 | cur->next = node; 480 | cur = next; 481 | } else { 482 | *res.prev_link = node; 483 | } 484 | 485 | // from here, traverse cur and free the nodes, until we get to one 486 | // that shouldn't be freed 487 | while (cur->next && cur->next->x <= res.x + width) { 488 | stbrp_node *next = cur->next; 489 | // move the current node to the free list 490 | cur->next = context->free_head; 491 | context->free_head = cur; 492 | cur = next; 493 | } 494 | 495 | // stitch the list back in 496 | node->next = cur; 497 | 498 | if (cur->x < res.x + width) 499 | cur->x = (stbrp_coord) (res.x + width); 500 | 501 | #ifdef _DEBUG 502 | cur = context->active_head; 503 | while (cur->x < context->width) { 504 | STBRP_ASSERT(cur->x < cur->next->x); 505 | cur = cur->next; 506 | } 507 | STBRP_ASSERT(cur->next == NULL); 508 | 509 | { 510 | int count=0; 511 | cur = context->active_head; 512 | while (cur) { 513 | cur = cur->next; 514 | ++count; 515 | } 516 | cur = context->free_head; 517 | while (cur) { 518 | cur = cur->next; 519 | ++count; 520 | } 521 | STBRP_ASSERT(count == context->num_nodes+2); 522 | } 523 | #endif 524 | 525 | return res; 526 | } 527 | 528 | static int STBRP__CDECL rect_height_compare(const void *a, const void *b) 529 | { 530 | const stbrp_rect *p = (const stbrp_rect *) a; 531 | const stbrp_rect *q = (const stbrp_rect *) b; 532 | if (p->h > q->h) 533 | return -1; 534 | if (p->h < q->h) 535 | return 1; 536 | return (p->w > q->w) ? -1 : (p->w < q->w); 537 | } 538 | 539 | static int STBRP__CDECL rect_original_order(const void *a, const void *b) 540 | { 541 | const stbrp_rect *p = (const stbrp_rect *) a; 542 | const stbrp_rect *q = (const stbrp_rect *) b; 543 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); 544 | } 545 | 546 | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) 547 | { 548 | int i, all_rects_packed = 1; 549 | 550 | // we use the 'was_packed' field internally to allow sorting/unsorting 551 | for (i=0; i < num_rects; ++i) { 552 | rects[i].was_packed = i; 553 | } 554 | 555 | // sort according to heuristic 556 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); 557 | 558 | for (i=0; i < num_rects; ++i) { 559 | if (rects[i].w == 0 || rects[i].h == 0) { 560 | rects[i].x = rects[i].y = 0; // empty rect needs no space 561 | } else { 562 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); 563 | if (fr.prev_link) { 564 | rects[i].x = (stbrp_coord) fr.x; 565 | rects[i].y = (stbrp_coord) fr.y; 566 | } else { 567 | rects[i].x = rects[i].y = STBRP__MAXVAL; 568 | } 569 | } 570 | } 571 | 572 | // unsort 573 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); 574 | 575 | // set was_packed flags and all_rects_packed status 576 | for (i=0; i < num_rects; ++i) { 577 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); 578 | if (!rects[i].was_packed) 579 | all_rects_packed = 0; 580 | } 581 | 582 | // return the all_rects_packed status 583 | return all_rects_packed; 584 | } 585 | #endif 586 | 587 | /* 588 | ------------------------------------------------------------------------------ 589 | This software is available under 2 licenses -- choose whichever you prefer. 590 | ------------------------------------------------------------------------------ 591 | ALTERNATIVE A - MIT License 592 | Copyright (c) 2017 Sean Barrett 593 | Permission is hereby granted, free of charge, to any person obtaining a copy of 594 | this software and associated documentation files (the "Software"), to deal in 595 | the Software without restriction, including without limitation the rights to 596 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 597 | of the Software, and to permit persons to whom the Software is furnished to do 598 | so, subject to the following conditions: 599 | The above copyright notice and this permission notice shall be included in all 600 | copies or substantial portions of the Software. 601 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 602 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 603 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 604 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 605 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 606 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 607 | SOFTWARE. 608 | ------------------------------------------------------------------------------ 609 | ALTERNATIVE B - Public Domain (www.unlicense.org) 610 | This is free and unencumbered software released into the public domain. 611 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 612 | software, either in source code form or as a compiled binary, for any purpose, 613 | commercial or non-commercial, and by any means. 614 | In jurisdictions that recognize copyright laws, the author or authors of this 615 | software dedicate any and all copyright interest in the software to the public 616 | domain. We make this dedication for the benefit of the public at large and to 617 | the detriment of our heirs and successors. We intend this dedication to be an 618 | overt act of relinquishment in perpetuity of all present and future rights to 619 | this software under copyright law. 620 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 621 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 622 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 623 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 624 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 625 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 626 | ------------------------------------------------------------------------------ 627 | */ 628 | -------------------------------------------------------------------------------- /leechcore.h: -------------------------------------------------------------------------------- 1 | // leechcore.h : external header of the LeechCore library. 2 | // 3 | // LeechCore is a library which abstracts away reading and writing to various 4 | // software and hardware acquisition sources. Sources ranges from memory dump 5 | // files to driver backed live memory to hardware (FPGA) DMA backed memory. 6 | // 7 | // LeechCore built-in device support may be extended with external plugin 8 | // device drivers placed as .dll or .so files in the same folder as LeechCore. 9 | // 10 | // For more information please consult the LeechCore information on Github: 11 | // - README: https://github.com/ufrisk/LeechCore 12 | // - GUIDE: https://github.com/ufrisk/LeechCore/wiki 13 | // 14 | // (c) Ulf Frisk, 2020-2023 15 | // Author: Ulf Frisk, pcileech@frizk.net 16 | // 17 | // Header Version: 2.15.0 18 | // 19 | 20 | #ifndef __LEECHCORE_H__ 21 | #define __LEECHCORE_H__ 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif /* __cplusplus */ 25 | 26 | //----------------------------------------------------------------------------- 27 | // OS COMPATIBILITY BELOW: 28 | //----------------------------------------------------------------------------- 29 | 30 | #ifdef _WIN32 31 | 32 | #include 33 | #define EXPORTED_FUNCTION __declspec(dllexport) 34 | typedef unsigned __int64 QWORD, *PQWORD; 35 | 36 | #endif /* _WIN32 */ 37 | #ifdef LINUX 38 | 39 | #include 40 | #include 41 | #define EXPORTED_FUNCTION __attribute__((visibility("default"))) 42 | typedef void VOID, *PVOID, *HANDLE, **PHANDLE, *HMODULE; 43 | typedef long long unsigned int QWORD, *PQWORD, ULONG64, *PULONG64; 44 | typedef size_t SIZE_T, *PSIZE_T; 45 | typedef uint64_t FILETIME, *PFILETIME; 46 | typedef uint32_t DWORD, *PDWORD, *LPDWORD, BOOL, *PBOOL, NTSTATUS; 47 | typedef uint16_t WORD, *PWORD; 48 | typedef uint8_t BYTE, *PBYTE, *LPBYTE, UCHAR; 49 | typedef char CHAR, *PCHAR, *LPSTR, *LPCSTR; 50 | typedef uint16_t WCHAR, *PWCHAR, *LPWSTR, *LPCWSTR; 51 | #define MAX_PATH 260 52 | #define _In_ 53 | #define _In_z_ 54 | #define _In_opt_ 55 | #define _In_reads_(x) 56 | #define _In_reads_opt_(x) 57 | #define _Inout_ 58 | #define _Inout_bytecount_(x) 59 | #define _Inout_opt_ 60 | #define _Inout_updates_opt_(x) 61 | #define _Out_ 62 | #define _Out_opt_ 63 | #define _Out_writes_(x) 64 | #define _Out_writes_bytes_opt_(x) 65 | #define _Out_writes_opt_(x) 66 | #define _Out_writes_to_(x,y) 67 | #define _When_(x,y) 68 | #define _Frees_ptr_opt_ 69 | #define _Post_ptr_invalid_ 70 | #define _Check_return_opt_ 71 | #define _Printf_format_string_ 72 | #define _Success_(x) 73 | 74 | #endif /* LINUX */ 75 | 76 | 77 | 78 | //----------------------------------------------------------------------------- 79 | // Create and Close LeechCore devices: 80 | // It's possible to create multiple LeechCore devices in parallel and also of 81 | // different types if the underlying device will allow this. LeechCore will 82 | // automatically take care of and abstract away any hardware/software issues 83 | // with regards to the underlying devices. 84 | // 85 | // For more information about supported devices please check out the LeechCore 86 | // guide at: https://github.com/ufrisk/LeechCore/wiki 87 | //----------------------------------------------------------------------------- 88 | 89 | #define LC_CONFIG_VERSION 0xc0fd0002 90 | #define LC_CONFIG_ERRORINFO_VERSION 0xc0fe0002 91 | 92 | #define LC_CONFIG_PRINTF_ENABLED 0x01 93 | #define LC_CONFIG_PRINTF_V 0x02 94 | #define LC_CONFIG_PRINTF_VV 0x04 95 | #define LC_CONFIG_PRINTF_VVV 0x08 96 | 97 | typedef struct LC_CONFIG { 98 | // below are set by caller 99 | DWORD dwVersion; // must equal LC_CREATE_VERSION 100 | DWORD dwPrintfVerbosity; // printf verbosity according to LC_PRINTF_* 101 | CHAR szDevice[MAX_PATH]; // device connection string - see wiki for additional info. 102 | CHAR szRemote[MAX_PATH]; // remote connection striLC_CONFIG_VERSIONng - see wiki for additional info. 103 | _Check_return_opt_ int(*pfn_printf_opt)(_In_z_ _Printf_format_string_ char const *const _Format, ...); 104 | // below are set by caller, updated by LeecCore 105 | QWORD paMax; // max physical address (disables any max address auto-detect). 106 | // below are set by LeechCore 107 | BOOL fVolatile; 108 | BOOL fWritable; 109 | BOOL fRemote; 110 | BOOL fRemoteDisableCompress; 111 | CHAR szDeviceName[MAX_PATH]; // device name - such as 'fpga' or 'file'. 112 | } LC_CONFIG, *PLC_CONFIG; 113 | 114 | typedef struct tdLC_CONFIG_ERRORINFO { 115 | DWORD dwVersion; // must equal LC_CONFIG_ERRORINFO_VERSION 116 | DWORD cbStruct; 117 | DWORD _FutureUse[16]; 118 | BOOL fUserInputRequest; 119 | DWORD cwszUserText; 120 | WCHAR wszUserText[]; 121 | } LC_CONFIG_ERRORINFO, *PLC_CONFIG_ERRORINFO, **PPLC_CONFIG_ERRORINFO; 122 | 123 | /* 124 | * Create a new LeechCore device according to the supplied configuration. 125 | * CALLER LcMemFree: ppLcCreateErrorInfo 126 | * -- pLcCreateConfig 127 | * -- ppLcCreateErrorInfo = ptr to receive function allocated struct with error 128 | * information upon function failure. This info may contain a user message 129 | * requesting user action as an example. Any returned struct should be 130 | * free'd by a call to LcMemFree(). 131 | * -- return 132 | */ 133 | EXPORTED_FUNCTION _Success_(return != NULL) 134 | HANDLE LcCreate( 135 | _Inout_ PLC_CONFIG pLcCreateConfig 136 | ); 137 | 138 | EXPORTED_FUNCTION _Success_(return != NULL) 139 | HANDLE LcCreateEx( 140 | _Inout_ PLC_CONFIG pLcCreateConfig, 141 | _Out_opt_ PPLC_CONFIG_ERRORINFO ppLcCreateErrorInfo 142 | ); 143 | 144 | /* 145 | * Close a LeechCore handle and free any resources no longer needed. 146 | */ 147 | EXPORTED_FUNCTION 148 | VOID LcClose( 149 | _In_opt_ _Post_ptr_invalid_ HANDLE hLC 150 | ); 151 | 152 | 153 | 154 | //----------------------------------------------------------------------------- 155 | // Read and Write memory from underlying device either using contiguous method 156 | // or more recommended scatter method. 157 | // 158 | // The MEM_SCATTER struct allows reading and writing of discontiguous memory 159 | // chunks which must adhere to the following rules: 160 | // - maximum size = 0x1000 (4096) bytes = recommended size. 161 | // - minimum size = 2 DWORDs (8 bytes). 162 | // - must be DWORD (4 byte) aligned. 163 | // - must never cross 0x1000 page boundary. 164 | // - max value of iStack = MEM_SCATTER_STACK_SIZE - 2. 165 | //----------------------------------------------------------------------------- 166 | 167 | #define MEM_SCATTER_VERSION 0xc0fe0002 168 | #define MEM_SCATTER_STACK_SIZE 12 169 | 170 | typedef struct tdMEM_SCATTER { 171 | DWORD version; // MEM_SCATTER_VERSION 172 | BOOL f; // TRUE = success data in pb, FALSE = fail or not yet read. 173 | QWORD qwA; // address of memory to read 174 | union { 175 | PBYTE pb; // buffer to hold memory contents 176 | QWORD _Filler; 177 | }; 178 | DWORD cb; // size of buffer to hold memory contents. 179 | DWORD iStack; // internal stack pointer 180 | QWORD vStack[MEM_SCATTER_STACK_SIZE]; // internal stack 181 | } MEM_SCATTER, *PMEM_SCATTER, **PPMEM_SCATTER; 182 | 183 | #define MEM_SCATTER_ADDR_INVALID ((QWORD)-1) 184 | #define MEM_SCATTER_ADDR_ISINVALID(pMEM) (pMEM->qwA == (QWORD)-1) 185 | #define MEM_SCATTER_ADDR_ISVALID(pMEM) (pMEM->qwA != (QWORD)-1) 186 | #define MEM_SCATTER_STACK_PUSH(pMEM, v) (pMEM->vStack[pMEM->iStack++] = (QWORD)(v)) 187 | #define MEM_SCATTER_STACK_PEEK(pMEM, i) (pMEM->vStack[pMEM->iStack - i]) 188 | #define MEM_SCATTER_STACK_SET(pMEM, i, v) (pMEM->vStack[pMEM->iStack - i] = (QWORD)(v)) 189 | #define MEM_SCATTER_STACK_ADD(pMEM, i, v) (pMEM->vStack[pMEM->iStack - i] += (QWORD)(v)) 190 | #define MEM_SCATTER_STACK_POP(pMEM) (pMEM->vStack[--pMEM->iStack]) 191 | 192 | /* 193 | * Free LeechCore allocated memory such as memory allocated by the 194 | * LcAllocScatter / LcCommand functions. 195 | * -- pv 196 | */ 197 | EXPORTED_FUNCTION 198 | VOID LcMemFree( 199 | _Frees_ptr_opt_ PVOID pv 200 | ); 201 | 202 | /* 203 | * Allocate and pre-initialize empty MEMs including a 0x1000 buffer for each 204 | * pMEM. The result should be freed by LcFree when its no longer needed. 205 | * -- cMEMs 206 | * -- pppMEMs = pointer to receive ppMEMs 207 | * -- return 208 | */ 209 | EXPORTED_FUNCTION _Success_(return) 210 | BOOL LcAllocScatter1( 211 | _In_ DWORD cMEMs, 212 | _Out_ PPMEM_SCATTER *pppMEMs 213 | ); 214 | 215 | /* 216 | * Allocate and pre-initialize empty MEMs excluding the 0x1000 buffer which 217 | * will be accounted towards the pbData buffer in a contiguous way. 218 | * The result should be freed by LcFree when its no longer needed. 219 | * -- cbData = size of pbData (must be cMEMs * 0x1000) 220 | * -- pbData = buffer used for MEM.pb 221 | * -- cMEMs 222 | * -- pppMEMs = pointer to receive ppMEMs 223 | * -- return 224 | */ 225 | EXPORTED_FUNCTION _Success_(return) 226 | BOOL LcAllocScatter2( 227 | _In_ DWORD cbData, 228 | _Inout_updates_opt_(cbData) PBYTE pbData, 229 | _In_ DWORD cMEMs, 230 | _Out_ PPMEM_SCATTER *pppMEMs 231 | ); 232 | 233 | /* 234 | * Allocate and pre-initialize empty MEMs excluding the 0x1000 buffer which 235 | * will be accounted towards the pbData buffer in a contiguous way. 236 | * -- pbDataFirstPage = optional buffer of first page 237 | * -- pbDataLastPage = optional buffer of last page 238 | * -- cbData = size of pbData 239 | * -- pbData = buffer used for MEM.pb except first/last if exists 240 | * -- cMEMs 241 | * -- pppMEMs = pointer to receive ppMEMs 242 | * -- return 243 | */ 244 | EXPORTED_FUNCTION _Success_(return) 245 | BOOL LcAllocScatter3( 246 | _Inout_updates_opt_(0x1000) PBYTE pbDataFirstPage, 247 | _Inout_updates_opt_(0x1000) PBYTE pbDataLastPage, 248 | _In_ DWORD cbData, 249 | _Inout_updates_opt_(cbData) PBYTE pbData, 250 | _In_ DWORD cMEMs, 251 | _Out_ PPMEM_SCATTER *pppMEMs 252 | ); 253 | 254 | /* 255 | * Read memory in a scattered non-contiguous way. This is recommended for reads. 256 | * -- hLC 257 | * -- cMEMs 258 | * -- ppMEMs 259 | */ 260 | EXPORTED_FUNCTION 261 | VOID LcReadScatter( 262 | _In_ HANDLE hLC, 263 | _In_ DWORD cMEMs, 264 | _Inout_ PPMEM_SCATTER ppMEMs 265 | ); 266 | 267 | /* 268 | * Read memory in a contiguous way. Note that if multiple memory segments are 269 | * to be read LcReadScatter() may be more efficient. 270 | * -- hLC, 271 | * -- pa 272 | * -- cb 273 | * -- pb 274 | * -- return 275 | */ 276 | EXPORTED_FUNCTION _Success_(return) 277 | BOOL LcRead( 278 | _In_ HANDLE hLC, 279 | _In_ QWORD pa, 280 | _In_ DWORD cb, 281 | _Out_writes_(cb) PBYTE pb 282 | ); 283 | 284 | /* 285 | * Write memory in a scattered non-contiguous way. 286 | * -- hLC 287 | * -- cMEMs 288 | * -- ppMEMs 289 | */ 290 | EXPORTED_FUNCTION 291 | VOID LcWriteScatter( 292 | _In_ HANDLE hLC, 293 | _In_ DWORD cMEMs, 294 | _Inout_ PPMEM_SCATTER ppMEMs 295 | ); 296 | 297 | /* 298 | * Write memory in a contiguous way. 299 | * -- hLC 300 | * -- pa 301 | * -- cb 302 | * -- pb 303 | * -- return 304 | */ 305 | EXPORTED_FUNCTION _Success_(return) 306 | BOOL LcWrite( 307 | _In_ HANDLE hLC, 308 | _In_ QWORD pa, 309 | _In_ DWORD cb, 310 | _In_reads_(cb) PBYTE pb 311 | ); 312 | 313 | 314 | 315 | //----------------------------------------------------------------------------- 316 | // Get/Set/Command functionality may be used to query and/or update LeechCore 317 | // or its devices in various ways. 318 | //----------------------------------------------------------------------------- 319 | 320 | /* 321 | * Set an option as defined by LC_OPT_*. (R option). 322 | * -- hLC 323 | * -- fOption = LC_OPT_* 324 | * -- cbData 325 | * -- pbData 326 | * -- pcbData 327 | */ 328 | EXPORTED_FUNCTION _Success_(return) 329 | BOOL LcGetOption( 330 | _In_ HANDLE hLC, 331 | _In_ QWORD fOption, 332 | _Out_ PQWORD pqwValue 333 | ); 334 | 335 | /* 336 | * Get an option as defined by LC_OPT_*. (W option). 337 | * -- hLC 338 | * -- fOption = LC_OPT_* 339 | * -- cbData 340 | * -- pbData 341 | */ 342 | EXPORTED_FUNCTION _Success_(return) 343 | BOOL LcSetOption( 344 | _In_ HANDLE hLC, 345 | _In_ QWORD fOption, 346 | _In_ QWORD qwValue 347 | ); 348 | 349 | /* 350 | * Execute a command and retrieve a result (if any) at the same time. 351 | * NB! If *ppbDataOut contains a memory allocation on exit this should be free'd 352 | * by calling LcMemFree(). 353 | * CALLER LcFreeMem: *ppbDataOut 354 | * -- hLC 355 | * -- fCommand = LC_CMD_* 356 | * -- cbDataIn 357 | * -- pbDataIn 358 | * -- ppbDataOut 359 | * -- pcbDataOut 360 | */ 361 | EXPORTED_FUNCTION _Success_(return) 362 | BOOL LcCommand( 363 | _In_ HANDLE hLC, 364 | _In_ QWORD fCommand, 365 | _In_ DWORD cbDataIn, 366 | _In_reads_opt_(cbDataIn) PBYTE pbDataIn, 367 | _Out_opt_ PBYTE *ppbDataOut, 368 | _Out_opt_ PDWORD pcbDataOut 369 | ); 370 | 371 | #define LC_OPT_CORE_PRINTF_ENABLE 0x4000000100000000 // RW 372 | #define LC_OPT_CORE_VERBOSE 0x4000000200000000 // RW 373 | #define LC_OPT_CORE_VERBOSE_EXTRA 0x4000000300000000 // RW 374 | #define LC_OPT_CORE_VERBOSE_EXTRA_TLP 0x4000000400000000 // RW 375 | #define LC_OPT_CORE_VERSION_MAJOR 0x4000000500000000 // R 376 | #define LC_OPT_CORE_VERSION_MINOR 0x4000000600000000 // R 377 | #define LC_OPT_CORE_VERSION_REVISION 0x4000000700000000 // R 378 | #define LC_OPT_CORE_ADDR_MAX 0x1000000800000000 // R 379 | #define LC_OPT_CORE_STATISTICS_CALL_COUNT 0x4000000900000000 // R [lo-dword: LC_STATISTICS_ID_*] 380 | #define LC_OPT_CORE_STATISTICS_CALL_TIME 0x4000000a00000000 // R [lo-dword: LC_STATISTICS_ID_*] 381 | #define LC_OPT_CORE_VOLATILE 0x1000000b00000000 // R 382 | #define LC_OPT_CORE_READONLY 0x1000000c00000000 // R 383 | 384 | #define LC_OPT_MEMORYINFO_VALID 0x0200000100000000 // R 385 | #define LC_OPT_MEMORYINFO_FLAG_32BIT 0x0200000300000000 // R 386 | #define LC_OPT_MEMORYINFO_FLAG_PAE 0x0200000400000000 // R 387 | #define LC_OPT_MEMORYINFO_OS_VERSION_MINOR 0x0200000500000000 // R 388 | #define LC_OPT_MEMORYINFO_OS_VERSION_MAJOR 0x0200000600000000 // R 389 | #define LC_OPT_MEMORYINFO_OS_DTB 0x0200000700000000 // R 390 | #define LC_OPT_MEMORYINFO_OS_PFN 0x0200000800000000 // R 391 | #define LC_OPT_MEMORYINFO_OS_PsLoadedModuleList 0x0200000900000000 // R 392 | #define LC_OPT_MEMORYINFO_OS_PsActiveProcessHead 0x0200000a00000000 // R 393 | #define LC_OPT_MEMORYINFO_OS_MACHINE_IMAGE_TP 0x0200000b00000000 // R 394 | #define LC_OPT_MEMORYINFO_OS_NUM_PROCESSORS 0x0200000c00000000 // R 395 | #define LC_OPT_MEMORYINFO_OS_SYSTEMTIME 0x0200000d00000000 // R 396 | #define LC_OPT_MEMORYINFO_OS_UPTIME 0x0200000e00000000 // R 397 | #define LC_OPT_MEMORYINFO_OS_KERNELBASE 0x0200000f00000000 // R 398 | #define LC_OPT_MEMORYINFO_OS_KERNELHINT 0x0200001000000000 // R 399 | #define LC_OPT_MEMORYINFO_OS_KdDebuggerDataBlock 0x0200001100000000 // R 400 | 401 | #define LC_OPT_FPGA_PROBE_MAXPAGES 0x0300000100000000 // RW 402 | #define LC_OPT_FPGA_MAX_SIZE_RX 0x0300000300000000 // RW 403 | #define LC_OPT_FPGA_MAX_SIZE_TX 0x0300000400000000 // RW 404 | #define LC_OPT_FPGA_DELAY_PROBE_READ 0x0300000500000000 // RW - uS 405 | #define LC_OPT_FPGA_DELAY_PROBE_WRITE 0x0300000600000000 // RW - uS 406 | #define LC_OPT_FPGA_DELAY_WRITE 0x0300000700000000 // RW - uS 407 | #define LC_OPT_FPGA_DELAY_READ 0x0300000800000000 // RW - uS 408 | #define LC_OPT_FPGA_RETRY_ON_ERROR 0x0300000900000000 // RW 409 | #define LC_OPT_FPGA_DEVICE_ID 0x0300008000000000 // RW - bus:dev:fn (ex: 04:00.0 == 0x0400). 410 | #define LC_OPT_FPGA_FPGA_ID 0x0300008100000000 // R 411 | #define LC_OPT_FPGA_VERSION_MAJOR 0x0300008200000000 // R 412 | #define LC_OPT_FPGA_VERSION_MINOR 0x0300008300000000 // R 413 | #define LC_OPT_FPGA_ALGO_TINY 0x0300008400000000 // RW - 1/0 use tiny 128-byte/tlp read algorithm. 414 | #define LC_OPT_FPGA_ALGO_SYNCHRONOUS 0x0300008500000000 // RW - 1/0 use synchronous (old) read algorithm. 415 | #define LC_OPT_FPGA_CFGSPACE_XILINX 0x0300008600000000 // RW - [lo-dword: register address in bytes] [bytes: 0-3: data, 4-7: byte_enable(if wr/set); top bit = cfg_mgmt_wr_rw1c_as_rw] 416 | #define LC_OPT_FPGA_TLP_READ_CB_WITHINFO 0x0300009000000000 // RW - 1/0 call TLP read callback with additional string info in szInfo 417 | #define LC_OPT_FPGA_TLP_READ_CB_FILTERCPL 0x0300009100000000 // RW - 1/0 call TLP read callback with memory read completions from read calls filtered 418 | #define LC_OPT_FPGA_TLP_READ_CB_BACKGROUND_THREAD 0x0300009200000000 // RW - 1/0 call TLP read callback auto-read with background thread [requires active callback function] 419 | 420 | #define LC_CMD_FPGA_WRITE_TLP 0x0000010100000000 // R - !!! DEPRECATED DO NOT USE !!! - USE LC_CMD_FPGA_TLP_WRITE_SINGLE! 421 | #define LC_CMD_FPGA_LISTEN_TLP 0x0000010200000000 // R - !!! DEPRECATED DO NOT USE !!! 422 | #define LC_CMD_FPGA_PCIECFGSPACE 0x0000010300000000 // R 423 | #define LC_CMD_FPGA_CFGREGPCIE 0x0000010400000000 // RW - [lo-dword: register address] 424 | #define LC_CMD_FPGA_CFGREGCFG 0x0000010500000000 // RW - [lo-dword: register address] 425 | #define LC_CMD_FPGA_CFGREGDRP 0x0000010600000000 // RW - [lo-dword: register address] 426 | #define LC_CMD_FPGA_CFGREGCFG_MARKWR 0x0000010700000000 // W - write with mask [lo-dword: register address] [bytes: 0-1: data, 2-3: mask] 427 | #define LC_CMD_FPGA_CFGREGPCIE_MARKWR 0x0000010800000000 // W - write with mask [lo-dword: register address] [bytes: 0-1: data, 2-3: mask] 428 | #define LC_CMD_FPGA_CFGREG_DEBUGPRINT 0x0000010a00000000 // N/A 429 | #define LC_CMD_FPGA_PROBE 0x0000010b00000000 // RW 430 | #define LC_CMD_FPGA_CFGSPACE_SHADOW_RD 0x0000010c00000000 // R 431 | #define LC_CMD_FPGA_CFGSPACE_SHADOW_WR 0x0000010d00000000 // W - [lo-dword: config space write base address] 432 | #define LC_CMD_FPGA_TLP_WRITE_SINGLE 0x0000011000000000 // R - write single tlp BYTE:s 433 | #define LC_CMD_FPGA_TLP_WRITE_MULTIPLE 0x0000011100000000 // R - write multiple LC_TLP:s 434 | #define LC_CMD_FPGA_TLP_TOSTRING 0x0000011200000000 // RW - convert single TLP to LPSTR; *pcbDataOut includes NULL terminator. 435 | #define LC_CMD_FPGA_TLP_READ_FUNCTION_CALLBACK 0x0000011300000000 // W - set/unset custom TLP read callback function and fetch TLPs (pbDataIn == PLC_TLP_CALLBACK). 436 | 437 | #define LC_CMD_FILE_DUMPHEADER_GET 0x0000020100000000 // R 438 | 439 | #define LC_CMD_STATISTICS_GET 0x4000010000000000 // R 440 | #define LC_CMD_MEMMAP_GET 0x4000020000000000 // R - MEMMAP as LPSTR 441 | #define LC_CMD_MEMMAP_SET 0x4000030000000000 // W - MEMMAP as LPSTR 442 | #define LC_CMD_MEMMAP_GET_STRUCT 0x4000040000000000 // R - MEMMAP as LC_MEMMAP_ENTRY[] 443 | #define LC_CMD_MEMMAP_SET_STRUCT 0x4000050000000000 // W - MEMMAP as LC_MEMMAP_ENTRY[] 444 | 445 | #define LC_CMD_AGENT_EXEC_PYTHON 0x8000000100000000 // RW - [lo-dword: optional timeout in ms] 446 | #define LC_CMD_AGENT_EXIT_PROCESS 0x8000000200000000 // - [lo-dword: process exit code] 447 | #define LC_CMD_AGENT_VFS_LIST 0x8000000300000000 // RW 448 | #define LC_CMD_AGENT_VFS_READ 0x8000000400000000 // RW 449 | #define LC_CMD_AGENT_VFS_WRITE 0x8000000500000000 // RW 450 | #define LC_CMD_AGENT_VFS_OPT_GET 0x8000000600000000 // RW 451 | #define LC_CMD_AGENT_VFS_OPT_SET 0x8000000700000000 // RW 452 | #define LC_CMD_AGENT_VFS_INITIALIZE 0x8000000800000000 // RW 453 | #define LC_CMD_AGENT_VFS_CONSOLE 0x8000000900000000 // RW 454 | 455 | #define LC_CMD_AGENT_VFS_REQ_VERSION 0xfeed0001 456 | #define LC_CMD_AGENT_VFS_RSP_VERSION 0xfeee0001 457 | 458 | #define LC_STATISTICS_VERSION 0xe1a10002 459 | #define LC_STATISTICS_ID_OPEN 0x00 460 | #define LC_STATISTICS_ID_READ 0x01 461 | #define LC_STATISTICS_ID_READSCATTER 0x02 462 | #define LC_STATISTICS_ID_WRITE 0x03 463 | #define LC_STATISTICS_ID_WRITESCATTER 0x04 464 | #define LC_STATISTICS_ID_GETOPTION 0x05 465 | #define LC_STATISTICS_ID_SETOPTION 0x06 466 | #define LC_STATISTICS_ID_COMMAND 0x07 467 | #define LC_STATISTICS_ID_MAX 0x07 468 | 469 | typedef struct tdLC_CMD_AGENT_VFS_REQ { 470 | DWORD dwVersion; 471 | DWORD _FutureUse; 472 | CHAR uszPathFile[2*MAX_PATH]; // file path to list/read/write 473 | union { 474 | QWORD qwOffset; // offset to read/write 475 | QWORD fOption; // option to get/set (qword data in *pb) 476 | }; 477 | DWORD dwLength; // length to read 478 | DWORD cb; 479 | BYTE pb[0]; 480 | } LC_CMD_AGENT_VFS_REQ, *PLC_CMD_AGENT_VFS_REQ; 481 | 482 | typedef struct tdLC_CMD_AGENT_VFS_RSP { 483 | DWORD dwVersion; 484 | DWORD dwStatus; // ntstatus of read/write 485 | DWORD cbReadWrite; // number of bytes read/written 486 | DWORD _FutureUse[2]; 487 | DWORD cb; 488 | BYTE pb[0]; 489 | } LC_CMD_AGENT_VFS_RSP, *PLC_CMD_AGENT_VFS_RSP; 490 | 491 | static LPCSTR LC_STATISTICS_NAME[] = { 492 | "LcOpen", 493 | "LcRead", 494 | "LcReadScatter", 495 | "LcWrite", 496 | "LcWriteScatter", 497 | "LcGetOption", 498 | "LcSetOption", 499 | "LcCommand", 500 | }; 501 | 502 | typedef struct tdLC_STATISTICS { 503 | DWORD dwVersion; 504 | DWORD _Reserved; 505 | QWORD qwFreq; 506 | struct { 507 | QWORD c; 508 | QWORD tm; // total time in qwFreq ticks 509 | } Call[LC_STATISTICS_ID_MAX + 1]; 510 | } LC_STATISTICS, *PLC_STATISTICS; 511 | 512 | typedef struct tdLC_MEMMAP_ENTRY { 513 | QWORD pa; 514 | QWORD cb; 515 | QWORD paRemap; 516 | } LC_MEMMAP_ENTRY, *PLC_MEMMAP_ENTRY; 517 | 518 | typedef struct tdLC_TLP { 519 | DWORD cb; 520 | DWORD _Reserved1; 521 | PBYTE pb; 522 | } LC_TLP, *PLC_TLP; 523 | 524 | /* 525 | * Custom FPGA-only callback function to be called whenever a TLP is received if 526 | * set by command LC_CMD_FPGA_TLP_READ_FUNCTION_CALLBACK. 527 | * NOTE! CALLBACK FUNCTION MUST NEVER CALL LEECHCORE DUE TO RISK OF DEADLOCK! 528 | */ 529 | typedef VOID(*PLC_TLP_READ_FUNCTION_CALLBACK)( 530 | _In_opt_ PVOID ctx, 531 | _In_ DWORD cbTlp, 532 | _In_ PBYTE pbTlp, 533 | _In_opt_ DWORD cbInfo, 534 | _In_opt_ LPSTR szInfo 535 | ); 536 | 537 | typedef struct tdLC_TLP_CALLBACK { 538 | PVOID ctx; 539 | PLC_TLP_READ_FUNCTION_CALLBACK pfn; 540 | } LC_TLP_CALLBACK, *PLC_TLP_CALLBACK; 541 | 542 | #ifdef __cplusplus 543 | } 544 | #endif /* __cplusplus */ 545 | #endif /* __LEECHCORE_H__ */ 546 | -------------------------------------------------------------------------------- /imstb_textedit.h: -------------------------------------------------------------------------------- 1 | // [DEAR IMGUI] 2 | // This is a slightly modified version of stb_textedit.h 1.14. 3 | // Those changes would need to be pushed into nothings/stb: 4 | // - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) 5 | // - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000) 6 | // Grep for [DEAR IMGUI] to find the changes. 7 | 8 | // stb_textedit.h - v1.14 - public domain - Sean Barrett 9 | // Development of this library was sponsored by RAD Game Tools 10 | // 11 | // This C header file implements the guts of a multi-line text-editing 12 | // widget; you implement display, word-wrapping, and low-level string 13 | // insertion/deletion, and stb_textedit will map user inputs into 14 | // insertions & deletions, plus updates to the cursor position, 15 | // selection state, and undo state. 16 | // 17 | // It is intended for use in games and other systems that need to build 18 | // their own custom widgets and which do not have heavy text-editing 19 | // requirements (this library is not recommended for use for editing large 20 | // texts, as its performance does not scale and it has limited undo). 21 | // 22 | // Non-trivial behaviors are modelled after Windows text controls. 23 | // 24 | // 25 | // LICENSE 26 | // 27 | // See end of file for license information. 28 | // 29 | // 30 | // DEPENDENCIES 31 | // 32 | // Uses the C runtime function 'memmove', which you can override 33 | // by defining STB_TEXTEDIT_memmove before the implementation. 34 | // Uses no other functions. Performs no runtime allocations. 35 | // 36 | // 37 | // VERSION HISTORY 38 | // 39 | // 1.14 (2021-07-11) page up/down, various fixes 40 | // 1.13 (2019-02-07) fix bug in undo size management 41 | // 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash 42 | // 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield 43 | // 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual 44 | // 1.9 (2016-08-27) customizable move-by-word 45 | // 1.8 (2016-04-02) better keyboard handling when mouse button is down 46 | // 1.7 (2015-09-13) change y range handling in case baseline is non-0 47 | // 1.6 (2015-04-15) allow STB_TEXTEDIT_memmove 48 | // 1.5 (2014-09-10) add support for secondary keys for OS X 49 | // 1.4 (2014-08-17) fix signed/unsigned warnings 50 | // 1.3 (2014-06-19) fix mouse clicking to round to nearest char boundary 51 | // 1.2 (2014-05-27) fix some RAD types that had crept into the new code 52 | // 1.1 (2013-12-15) move-by-word (requires STB_TEXTEDIT_IS_SPACE ) 53 | // 1.0 (2012-07-26) improve documentation, initial public release 54 | // 0.3 (2012-02-24) bugfixes, single-line mode; insert mode 55 | // 0.2 (2011-11-28) fixes to undo/redo 56 | // 0.1 (2010-07-08) initial version 57 | // 58 | // ADDITIONAL CONTRIBUTORS 59 | // 60 | // Ulf Winklemann: move-by-word in 1.1 61 | // Fabian Giesen: secondary key inputs in 1.5 62 | // Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6 63 | // Louis Schnellbach: page up/down in 1.14 64 | // 65 | // Bugfixes: 66 | // Scott Graham 67 | // Daniel Keller 68 | // Omar Cornut 69 | // Dan Thompson 70 | // 71 | // USAGE 72 | // 73 | // This file behaves differently depending on what symbols you define 74 | // before including it. 75 | // 76 | // 77 | // Header-file mode: 78 | // 79 | // If you do not define STB_TEXTEDIT_IMPLEMENTATION before including this, 80 | // it will operate in "header file" mode. In this mode, it declares a 81 | // single public symbol, STB_TexteditState, which encapsulates the current 82 | // state of a text widget (except for the string, which you will store 83 | // separately). 84 | // 85 | // To compile in this mode, you must define STB_TEXTEDIT_CHARTYPE to a 86 | // primitive type that defines a single character (e.g. char, wchar_t, etc). 87 | // 88 | // To save space or increase undo-ability, you can optionally define the 89 | // following things that are used by the undo system: 90 | // 91 | // STB_TEXTEDIT_POSITIONTYPE small int type encoding a valid cursor position 92 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 93 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer 94 | // 95 | // If you don't define these, they are set to permissive types and 96 | // moderate sizes. The undo system does no memory allocations, so 97 | // it grows STB_TexteditState by the worst-case storage which is (in bytes): 98 | // 99 | // [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATECOUNT 100 | // + sizeof(STB_TEXTEDIT_CHARTYPE) * STB_TEXTEDIT_UNDOCHARCOUNT 101 | // 102 | // 103 | // Implementation mode: 104 | // 105 | // If you define STB_TEXTEDIT_IMPLEMENTATION before including this, it 106 | // will compile the implementation of the text edit widget, depending 107 | // on a large number of symbols which must be defined before the include. 108 | // 109 | // The implementation is defined only as static functions. You will then 110 | // need to provide your own APIs in the same file which will access the 111 | // static functions. 112 | // 113 | // The basic concept is that you provide a "string" object which 114 | // behaves like an array of characters. stb_textedit uses indices to 115 | // refer to positions in the string, implicitly representing positions 116 | // in the displayed textedit. This is true for both plain text and 117 | // rich text; even with rich text stb_truetype interacts with your 118 | // code as if there was an array of all the displayed characters. 119 | // 120 | // Symbols that must be the same in header-file and implementation mode: 121 | // 122 | // STB_TEXTEDIT_CHARTYPE the character type 123 | // STB_TEXTEDIT_POSITIONTYPE small type that is a valid cursor position 124 | // STB_TEXTEDIT_UNDOSTATECOUNT the number of undo states to allow 125 | // STB_TEXTEDIT_UNDOCHARCOUNT the number of characters to store in the undo buffer 126 | // 127 | // Symbols you must define for implementation mode: 128 | // 129 | // STB_TEXTEDIT_STRING the type of object representing a string being edited, 130 | // typically this is a wrapper object with other data you need 131 | // 132 | // STB_TEXTEDIT_STRINGLEN(obj) the length of the string (ideally O(1)) 133 | // STB_TEXTEDIT_LAYOUTROW(&r,obj,n) returns the results of laying out a line of characters 134 | // starting from character #n (see discussion below) 135 | // STB_TEXTEDIT_GETWIDTH(obj,n,i) returns the pixel delta from the xpos of the i'th character 136 | // to the xpos of the i+1'th char for a line of characters 137 | // starting at character #n (i.e. accounts for kerning 138 | // with previous char) 139 | // STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character 140 | // (return type is int, -1 means not valid to insert) 141 | // STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based 142 | // STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize 143 | // as manually wordwrapping for end-of-line positioning 144 | // 145 | // STB_TEXTEDIT_DELETECHARS(obj,i,n) delete n characters starting at i 146 | // STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n) insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*) 147 | // 148 | // STB_TEXTEDIT_K_SHIFT a power of two that is or'd in to a keyboard input to represent the shift key 149 | // 150 | // STB_TEXTEDIT_K_LEFT keyboard input to move cursor left 151 | // STB_TEXTEDIT_K_RIGHT keyboard input to move cursor right 152 | // STB_TEXTEDIT_K_UP keyboard input to move cursor up 153 | // STB_TEXTEDIT_K_DOWN keyboard input to move cursor down 154 | // STB_TEXTEDIT_K_PGUP keyboard input to move cursor up a page 155 | // STB_TEXTEDIT_K_PGDOWN keyboard input to move cursor down a page 156 | // STB_TEXTEDIT_K_LINESTART keyboard input to move cursor to start of line // e.g. HOME 157 | // STB_TEXTEDIT_K_LINEEND keyboard input to move cursor to end of line // e.g. END 158 | // STB_TEXTEDIT_K_TEXTSTART keyboard input to move cursor to start of text // e.g. ctrl-HOME 159 | // STB_TEXTEDIT_K_TEXTEND keyboard input to move cursor to end of text // e.g. ctrl-END 160 | // STB_TEXTEDIT_K_DELETE keyboard input to delete selection or character under cursor 161 | // STB_TEXTEDIT_K_BACKSPACE keyboard input to delete selection or character left of cursor 162 | // STB_TEXTEDIT_K_UNDO keyboard input to perform undo 163 | // STB_TEXTEDIT_K_REDO keyboard input to perform redo 164 | // 165 | // Optional: 166 | // STB_TEXTEDIT_K_INSERT keyboard input to toggle insert mode 167 | // STB_TEXTEDIT_IS_SPACE(ch) true if character is whitespace (e.g. 'isspace'), 168 | // required for default WORDLEFT/WORDRIGHT handlers 169 | // STB_TEXTEDIT_MOVEWORDLEFT(obj,i) custom handler for WORDLEFT, returns index to move cursor to 170 | // STB_TEXTEDIT_MOVEWORDRIGHT(obj,i) custom handler for WORDRIGHT, returns index to move cursor to 171 | // STB_TEXTEDIT_K_WORDLEFT keyboard input to move cursor left one word // e.g. ctrl-LEFT 172 | // STB_TEXTEDIT_K_WORDRIGHT keyboard input to move cursor right one word // e.g. ctrl-RIGHT 173 | // STB_TEXTEDIT_K_LINESTART2 secondary keyboard input to move cursor to start of line 174 | // STB_TEXTEDIT_K_LINEEND2 secondary keyboard input to move cursor to end of line 175 | // STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text 176 | // STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text 177 | // 178 | // Keyboard input must be encoded as a single integer value; e.g. a character code 179 | // and some bitflags that represent shift states. to simplify the interface, SHIFT must 180 | // be a bitflag, so we can test the shifted state of cursor movements to allow selection, 181 | // i.e. (STB_TEXTEDIT_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow. 182 | // 183 | // You can encode other things, such as CONTROL or ALT, in additional bits, and 184 | // then test for their presence in e.g. STB_TEXTEDIT_K_WORDLEFT. For example, 185 | // my Windows implementations add an additional CONTROL bit, and an additional KEYDOWN 186 | // bit. Then all of the STB_TEXTEDIT_K_ values bitwise-or in the KEYDOWN bit, 187 | // and I pass both WM_KEYDOWN and WM_CHAR events to the "key" function in the 188 | // API below. The control keys will only match WM_KEYDOWN events because of the 189 | // keydown bit I add, and STB_TEXTEDIT_KEYTOTEXT only tests for the KEYDOWN 190 | // bit so it only decodes WM_CHAR events. 191 | // 192 | // STB_TEXTEDIT_LAYOUTROW returns information about the shape of one displayed 193 | // row of characters assuming they start on the i'th character--the width and 194 | // the height and the number of characters consumed. This allows this library 195 | // to traverse the entire layout incrementally. You need to compute word-wrapping 196 | // here. 197 | // 198 | // Each textfield keeps its own insert mode state, which is not how normal 199 | // applications work. To keep an app-wide insert mode, update/copy the 200 | // "insert_mode" field of STB_TexteditState before/after calling API functions. 201 | // 202 | // API 203 | // 204 | // void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) 205 | // 206 | // void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 207 | // void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 208 | // int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 209 | // int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) 210 | // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key) 211 | // 212 | // Each of these functions potentially updates the string and updates the 213 | // state. 214 | // 215 | // initialize_state: 216 | // set the textedit state to a known good default state when initially 217 | // constructing the textedit. 218 | // 219 | // click: 220 | // call this with the mouse x,y on a mouse down; it will update the cursor 221 | // and reset the selection start/end to the cursor point. the x,y must 222 | // be relative to the text widget, with (0,0) being the top left. 223 | // 224 | // drag: 225 | // call this with the mouse x,y on a mouse drag/up; it will update the 226 | // cursor and the selection end point 227 | // 228 | // cut: 229 | // call this to delete the current selection; returns true if there was 230 | // one. you should FIRST copy the current selection to the system paste buffer. 231 | // (To copy, just copy the current selection out of the string yourself.) 232 | // 233 | // paste: 234 | // call this to paste text at the current cursor point or over the current 235 | // selection if there is one. 236 | // 237 | // key: 238 | // call this for keyboard inputs sent to the textfield. you can use it 239 | // for "key down" events or for "translated" key events. if you need to 240 | // do both (as in Win32), or distinguish Unicode characters from control 241 | // inputs, set a high bit to distinguish the two; then you can define the 242 | // various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit 243 | // set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is 244 | // clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to 245 | // anything other type you wante before including. 246 | // 247 | // 248 | // When rendering, you can read the cursor position and selection state from 249 | // the STB_TexteditState. 250 | // 251 | // 252 | // Notes: 253 | // 254 | // This is designed to be usable in IMGUI, so it allows for the possibility of 255 | // running in an IMGUI that has NOT cached the multi-line layout. For this 256 | // reason, it provides an interface that is compatible with computing the 257 | // layout incrementally--we try to make sure we make as few passes through 258 | // as possible. (For example, to locate the mouse pointer in the text, we 259 | // could define functions that return the X and Y positions of characters 260 | // and binary search Y and then X, but if we're doing dynamic layout this 261 | // will run the layout algorithm many times, so instead we manually search 262 | // forward in one pass. Similar logic applies to e.g. up-arrow and 263 | // down-arrow movement.) 264 | // 265 | // If it's run in a widget that *has* cached the layout, then this is less 266 | // efficient, but it's not horrible on modern computers. But you wouldn't 267 | // want to edit million-line files with it. 268 | 269 | 270 | //////////////////////////////////////////////////////////////////////////// 271 | //////////////////////////////////////////////////////////////////////////// 272 | //// 273 | //// Header-file mode 274 | //// 275 | //// 276 | 277 | #ifndef INCLUDE_STB_TEXTEDIT_H 278 | #define INCLUDE_STB_TEXTEDIT_H 279 | 280 | //////////////////////////////////////////////////////////////////////// 281 | // 282 | // STB_TexteditState 283 | // 284 | // Definition of STB_TexteditState which you should store 285 | // per-textfield; it includes cursor position, selection state, 286 | // and undo state. 287 | // 288 | 289 | #ifndef STB_TEXTEDIT_UNDOSTATECOUNT 290 | #define STB_TEXTEDIT_UNDOSTATECOUNT 99 291 | #endif 292 | #ifndef STB_TEXTEDIT_UNDOCHARCOUNT 293 | #define STB_TEXTEDIT_UNDOCHARCOUNT 999 294 | #endif 295 | #ifndef STB_TEXTEDIT_CHARTYPE 296 | #define STB_TEXTEDIT_CHARTYPE int 297 | #endif 298 | #ifndef STB_TEXTEDIT_POSITIONTYPE 299 | #define STB_TEXTEDIT_POSITIONTYPE int 300 | #endif 301 | 302 | typedef struct 303 | { 304 | // private data 305 | STB_TEXTEDIT_POSITIONTYPE where; 306 | STB_TEXTEDIT_POSITIONTYPE insert_length; 307 | STB_TEXTEDIT_POSITIONTYPE delete_length; 308 | int char_storage; 309 | } StbUndoRecord; 310 | 311 | typedef struct 312 | { 313 | // private data 314 | StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT]; 315 | STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT]; 316 | short undo_point, redo_point; 317 | int undo_char_point, redo_char_point; 318 | } StbUndoState; 319 | 320 | typedef struct 321 | { 322 | ///////////////////// 323 | // 324 | // public data 325 | // 326 | 327 | int cursor; 328 | // position of the text cursor within the string 329 | 330 | int select_start; // selection start point 331 | int select_end; 332 | // selection start and end point in characters; if equal, no selection. 333 | // note that start may be less than or greater than end (e.g. when 334 | // dragging the mouse, start is where the initial click was, and you 335 | // can drag in either direction) 336 | 337 | unsigned char insert_mode; 338 | // each textfield keeps its own insert mode state. to keep an app-wide 339 | // insert mode, copy this value in/out of the app state 340 | 341 | int row_count_per_page; 342 | // page size in number of row. 343 | // this value MUST be set to >0 for pageup or pagedown in multilines documents. 344 | 345 | ///////////////////// 346 | // 347 | // private data 348 | // 349 | unsigned char cursor_at_end_of_line; // not implemented yet 350 | unsigned char initialized; 351 | unsigned char has_preferred_x; 352 | unsigned char single_line; 353 | unsigned char padding1, padding2, padding3; 354 | float preferred_x; // this determines where the cursor up/down tries to seek to along x 355 | StbUndoState undostate; 356 | } STB_TexteditState; 357 | 358 | 359 | //////////////////////////////////////////////////////////////////////// 360 | // 361 | // StbTexteditRow 362 | // 363 | // Result of layout query, used by stb_textedit to determine where 364 | // the text in each row is. 365 | 366 | // result of layout query 367 | typedef struct 368 | { 369 | float x0,x1; // starting x location, end x location (allows for align=right, etc) 370 | float baseline_y_delta; // position of baseline relative to previous row's baseline 371 | float ymin,ymax; // height of row above and below baseline 372 | int num_chars; 373 | } StbTexteditRow; 374 | #endif //INCLUDE_STB_TEXTEDIT_H 375 | 376 | 377 | //////////////////////////////////////////////////////////////////////////// 378 | //////////////////////////////////////////////////////////////////////////// 379 | //// 380 | //// Implementation mode 381 | //// 382 | //// 383 | 384 | 385 | // implementation isn't include-guarded, since it might have indirectly 386 | // included just the "header" portion 387 | #ifdef STB_TEXTEDIT_IMPLEMENTATION 388 | 389 | #ifndef STB_TEXTEDIT_memmove 390 | #include 391 | #define STB_TEXTEDIT_memmove memmove 392 | #endif 393 | 394 | 395 | ///////////////////////////////////////////////////////////////////////////// 396 | // 397 | // Mouse input handling 398 | // 399 | 400 | // traverse the layout to locate the nearest character to a display position 401 | static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y) 402 | { 403 | StbTexteditRow r; 404 | int n = STB_TEXTEDIT_STRINGLEN(str); 405 | float base_y = 0, prev_x; 406 | int i=0, k; 407 | 408 | r.x0 = r.x1 = 0; 409 | r.ymin = r.ymax = 0; 410 | r.num_chars = 0; 411 | 412 | // search rows to find one that straddles 'y' 413 | while (i < n) { 414 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 415 | if (r.num_chars <= 0) 416 | return n; 417 | 418 | if (i==0 && y < base_y + r.ymin) 419 | return 0; 420 | 421 | if (y < base_y + r.ymax) 422 | break; 423 | 424 | i += r.num_chars; 425 | base_y += r.baseline_y_delta; 426 | } 427 | 428 | // below all text, return 'after' last character 429 | if (i >= n) 430 | return n; 431 | 432 | // check if it's before the beginning of the line 433 | if (x < r.x0) 434 | return i; 435 | 436 | // check if it's before the end of the line 437 | if (x < r.x1) { 438 | // search characters in row for one that straddles 'x' 439 | prev_x = r.x0; 440 | for (k=0; k < r.num_chars; ++k) { 441 | float w = STB_TEXTEDIT_GETWIDTH(str, i, k); 442 | if (x < prev_x+w) { 443 | if (x < prev_x+w/2) 444 | return k+i; 445 | else 446 | return k+i+1; 447 | } 448 | prev_x += w; 449 | } 450 | // shouldn't happen, but if it does, fall through to end-of-line case 451 | } 452 | 453 | // if the last character is a newline, return that. otherwise return 'after' the last character 454 | if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE) 455 | return i+r.num_chars-1; 456 | else 457 | return i+r.num_chars; 458 | } 459 | 460 | // API click: on mouse down, move the cursor to the clicked location, and reset the selection 461 | static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 462 | { 463 | // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse 464 | // goes off the top or bottom of the text 465 | if( state->single_line ) 466 | { 467 | StbTexteditRow r; 468 | STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 469 | y = r.ymin; 470 | } 471 | 472 | state->cursor = stb_text_locate_coord(str, x, y); 473 | state->select_start = state->cursor; 474 | state->select_end = state->cursor; 475 | state->has_preferred_x = 0; 476 | } 477 | 478 | // API drag: on mouse drag, move the cursor and selection endpoint to the clicked location 479 | static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y) 480 | { 481 | int p = 0; 482 | 483 | // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse 484 | // goes off the top or bottom of the text 485 | if( state->single_line ) 486 | { 487 | StbTexteditRow r; 488 | STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 489 | y = r.ymin; 490 | } 491 | 492 | if (state->select_start == state->select_end) 493 | state->select_start = state->cursor; 494 | 495 | p = stb_text_locate_coord(str, x, y); 496 | state->cursor = state->select_end = p; 497 | } 498 | 499 | ///////////////////////////////////////////////////////////////////////////// 500 | // 501 | // Keyboard input handling 502 | // 503 | 504 | // forward declarations 505 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); 506 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state); 507 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length); 508 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length); 509 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length); 510 | 511 | typedef struct 512 | { 513 | float x,y; // position of n'th character 514 | float height; // height of line 515 | int first_char, length; // first char of row, and length 516 | int prev_first; // first char of previous row 517 | } StbFindState; 518 | 519 | // find the x/y location of a character, and remember info about the previous row in 520 | // case we get a move-up event (for page up, we'll have to rescan) 521 | static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line) 522 | { 523 | StbTexteditRow r; 524 | int prev_start = 0; 525 | int z = STB_TEXTEDIT_STRINGLEN(str); 526 | int i=0, first; 527 | 528 | if (n == z && single_line) { 529 | // special case if it's at the end (may not be needed?) 530 | STB_TEXTEDIT_LAYOUTROW(&r, str, 0); 531 | find->y = 0; 532 | find->first_char = 0; 533 | find->length = z; 534 | find->height = r.ymax - r.ymin; 535 | find->x = r.x1; 536 | return; 537 | } 538 | 539 | // search rows to find the one that straddles character n 540 | find->y = 0; 541 | 542 | for(;;) { 543 | STB_TEXTEDIT_LAYOUTROW(&r, str, i); 544 | if (n < i + r.num_chars) 545 | break; 546 | if (i + r.num_chars == z && z > 0 && STB_TEXTEDIT_GETCHAR(str, z - 1) != STB_TEXTEDIT_NEWLINE) // [DEAR IMGUI] special handling for last line 547 | break; // [DEAR IMGUI] 548 | prev_start = i; 549 | i += r.num_chars; 550 | find->y += r.baseline_y_delta; 551 | if (i == z) // [DEAR IMGUI] 552 | break; // [DEAR IMGUI] 553 | } 554 | 555 | find->first_char = first = i; 556 | find->length = r.num_chars; 557 | find->height = r.ymax - r.ymin; 558 | find->prev_first = prev_start; 559 | 560 | // now scan to find xpos 561 | find->x = r.x0; 562 | for (i=0; first+i < n; ++i) 563 | find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); 564 | } 565 | 566 | #define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end) 567 | 568 | // make the selection/cursor state valid if client altered the string 569 | static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 570 | { 571 | int n = STB_TEXTEDIT_STRINGLEN(str); 572 | if (STB_TEXT_HAS_SELECTION(state)) { 573 | if (state->select_start > n) state->select_start = n; 574 | if (state->select_end > n) state->select_end = n; 575 | // if clamping forced them to be equal, move the cursor to match 576 | if (state->select_start == state->select_end) 577 | state->cursor = state->select_start; 578 | } 579 | if (state->cursor > n) state->cursor = n; 580 | } 581 | 582 | // delete characters while updating undo 583 | static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len) 584 | { 585 | stb_text_makeundo_delete(str, state, where, len); 586 | STB_TEXTEDIT_DELETECHARS(str, where, len); 587 | state->has_preferred_x = 0; 588 | } 589 | 590 | // delete the section 591 | static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 592 | { 593 | stb_textedit_clamp(str, state); 594 | if (STB_TEXT_HAS_SELECTION(state)) { 595 | if (state->select_start < state->select_end) { 596 | stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start); 597 | state->select_end = state->cursor = state->select_start; 598 | } else { 599 | stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end); 600 | state->select_start = state->cursor = state->select_end; 601 | } 602 | state->has_preferred_x = 0; 603 | } 604 | } 605 | 606 | // canoncialize the selection so start <= end 607 | static void stb_textedit_sortselection(STB_TexteditState *state) 608 | { 609 | if (state->select_end < state->select_start) { 610 | int temp = state->select_end; 611 | state->select_end = state->select_start; 612 | state->select_start = temp; 613 | } 614 | } 615 | 616 | // move cursor to first character of selection 617 | static void stb_textedit_move_to_first(STB_TexteditState *state) 618 | { 619 | if (STB_TEXT_HAS_SELECTION(state)) { 620 | stb_textedit_sortselection(state); 621 | state->cursor = state->select_start; 622 | state->select_end = state->select_start; 623 | state->has_preferred_x = 0; 624 | } 625 | } 626 | 627 | // move cursor to last character of selection 628 | static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 629 | { 630 | if (STB_TEXT_HAS_SELECTION(state)) { 631 | stb_textedit_sortselection(state); 632 | stb_textedit_clamp(str, state); 633 | state->cursor = state->select_end; 634 | state->select_start = state->select_end; 635 | state->has_preferred_x = 0; 636 | } 637 | } 638 | 639 | #ifdef STB_TEXTEDIT_IS_SPACE 640 | static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx ) 641 | { 642 | return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1; 643 | } 644 | 645 | #ifndef STB_TEXTEDIT_MOVEWORDLEFT 646 | static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c ) 647 | { 648 | --c; // always move at least one character 649 | while( c >= 0 && !is_word_boundary( str, c ) ) 650 | --c; 651 | 652 | if( c < 0 ) 653 | c = 0; 654 | 655 | return c; 656 | } 657 | #define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous 658 | #endif 659 | 660 | #ifndef STB_TEXTEDIT_MOVEWORDRIGHT 661 | static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c ) 662 | { 663 | const int len = STB_TEXTEDIT_STRINGLEN(str); 664 | ++c; // always move at least one character 665 | while( c < len && !is_word_boundary( str, c ) ) 666 | ++c; 667 | 668 | if( c > len ) 669 | c = len; 670 | 671 | return c; 672 | } 673 | #define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next 674 | #endif 675 | 676 | #endif 677 | 678 | // update selection and cursor to match each other 679 | static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state) 680 | { 681 | if (!STB_TEXT_HAS_SELECTION(state)) 682 | state->select_start = state->select_end = state->cursor; 683 | else 684 | state->cursor = state->select_end; 685 | } 686 | 687 | // API cut: delete selection 688 | static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 689 | { 690 | if (STB_TEXT_HAS_SELECTION(state)) { 691 | stb_textedit_delete_selection(str,state); // implicitly clamps 692 | state->has_preferred_x = 0; 693 | return 1; 694 | } 695 | return 0; 696 | } 697 | 698 | // API paste: replace existing selection with passed-in text 699 | static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) 700 | { 701 | // if there's a selection, the paste should delete it 702 | stb_textedit_clamp(str, state); 703 | stb_textedit_delete_selection(str,state); 704 | // try to insert the characters 705 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) { 706 | stb_text_makeundo_insert(state, state->cursor, len); 707 | state->cursor += len; 708 | state->has_preferred_x = 0; 709 | return 1; 710 | } 711 | // note: paste failure will leave deleted selection, may be restored with an undo (see https://github.com/nothings/stb/issues/734 for details) 712 | return 0; 713 | } 714 | 715 | #ifndef STB_TEXTEDIT_KEYTYPE 716 | #define STB_TEXTEDIT_KEYTYPE int 717 | #endif 718 | 719 | // API key: process a keyboard input 720 | static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key) 721 | { 722 | retry: 723 | switch (key) { 724 | default: { 725 | int c = STB_TEXTEDIT_KEYTOTEXT(key); 726 | if (c > 0) { 727 | STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c; 728 | 729 | // can't add newline in single-line mode 730 | if (c == '\n' && state->single_line) 731 | break; 732 | 733 | if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { 734 | stb_text_makeundo_replace(str, state, state->cursor, 1, 1); 735 | STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); 736 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 737 | ++state->cursor; 738 | state->has_preferred_x = 0; 739 | } 740 | } else { 741 | stb_textedit_delete_selection(str,state); // implicitly clamps 742 | if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { 743 | stb_text_makeundo_insert(state, state->cursor, 1); 744 | ++state->cursor; 745 | state->has_preferred_x = 0; 746 | } 747 | } 748 | } 749 | break; 750 | } 751 | 752 | #ifdef STB_TEXTEDIT_K_INSERT 753 | case STB_TEXTEDIT_K_INSERT: 754 | state->insert_mode = !state->insert_mode; 755 | break; 756 | #endif 757 | 758 | case STB_TEXTEDIT_K_UNDO: 759 | stb_text_undo(str, state); 760 | state->has_preferred_x = 0; 761 | break; 762 | 763 | case STB_TEXTEDIT_K_REDO: 764 | stb_text_redo(str, state); 765 | state->has_preferred_x = 0; 766 | break; 767 | 768 | case STB_TEXTEDIT_K_LEFT: 769 | // if currently there's a selection, move cursor to start of selection 770 | if (STB_TEXT_HAS_SELECTION(state)) 771 | stb_textedit_move_to_first(state); 772 | else 773 | if (state->cursor > 0) 774 | --state->cursor; 775 | state->has_preferred_x = 0; 776 | break; 777 | 778 | case STB_TEXTEDIT_K_RIGHT: 779 | // if currently there's a selection, move cursor to end of selection 780 | if (STB_TEXT_HAS_SELECTION(state)) 781 | stb_textedit_move_to_last(str, state); 782 | else 783 | ++state->cursor; 784 | stb_textedit_clamp(str, state); 785 | state->has_preferred_x = 0; 786 | break; 787 | 788 | case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT: 789 | stb_textedit_clamp(str, state); 790 | stb_textedit_prep_selection_at_cursor(state); 791 | // move selection left 792 | if (state->select_end > 0) 793 | --state->select_end; 794 | state->cursor = state->select_end; 795 | state->has_preferred_x = 0; 796 | break; 797 | 798 | #ifdef STB_TEXTEDIT_MOVEWORDLEFT 799 | case STB_TEXTEDIT_K_WORDLEFT: 800 | if (STB_TEXT_HAS_SELECTION(state)) 801 | stb_textedit_move_to_first(state); 802 | else { 803 | state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 804 | stb_textedit_clamp( str, state ); 805 | } 806 | break; 807 | 808 | case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT: 809 | if( !STB_TEXT_HAS_SELECTION( state ) ) 810 | stb_textedit_prep_selection_at_cursor(state); 811 | 812 | state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor); 813 | state->select_end = state->cursor; 814 | 815 | stb_textedit_clamp( str, state ); 816 | break; 817 | #endif 818 | 819 | #ifdef STB_TEXTEDIT_MOVEWORDRIGHT 820 | case STB_TEXTEDIT_K_WORDRIGHT: 821 | if (STB_TEXT_HAS_SELECTION(state)) 822 | stb_textedit_move_to_last(str, state); 823 | else { 824 | state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 825 | stb_textedit_clamp( str, state ); 826 | } 827 | break; 828 | 829 | case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: 830 | if( !STB_TEXT_HAS_SELECTION( state ) ) 831 | stb_textedit_prep_selection_at_cursor(state); 832 | 833 | state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor); 834 | state->select_end = state->cursor; 835 | 836 | stb_textedit_clamp( str, state ); 837 | break; 838 | #endif 839 | 840 | case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: 841 | stb_textedit_prep_selection_at_cursor(state); 842 | // move selection right 843 | ++state->select_end; 844 | stb_textedit_clamp(str, state); 845 | state->cursor = state->select_end; 846 | state->has_preferred_x = 0; 847 | break; 848 | 849 | case STB_TEXTEDIT_K_DOWN: 850 | case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: 851 | case STB_TEXTEDIT_K_PGDOWN: 852 | case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: { 853 | StbFindState find; 854 | StbTexteditRow row; 855 | int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 856 | int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN; 857 | int row_count = is_page ? state->row_count_per_page : 1; 858 | 859 | if (!is_page && state->single_line) { 860 | // on windows, up&down in single-line behave like left&right 861 | key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT); 862 | goto retry; 863 | } 864 | 865 | if (sel) 866 | stb_textedit_prep_selection_at_cursor(state); 867 | else if (STB_TEXT_HAS_SELECTION(state)) 868 | stb_textedit_move_to_last(str, state); 869 | 870 | // compute current position of cursor point 871 | stb_textedit_clamp(str, state); 872 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 873 | 874 | for (j = 0; j < row_count; ++j) { 875 | float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; 876 | int start = find.first_char + find.length; 877 | 878 | if (find.length == 0) 879 | break; 880 | 881 | // [DEAR IMGUI] 882 | // going down while being on the last line shouldn't bring us to that line end 883 | if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE) 884 | break; 885 | 886 | // now find character position down a row 887 | state->cursor = start; 888 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 889 | x = row.x0; 890 | for (i=0; i < row.num_chars; ++i) { 891 | float dx = STB_TEXTEDIT_GETWIDTH(str, start, i); 892 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 893 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 894 | break; 895 | #endif 896 | x += dx; 897 | if (x > goal_x) 898 | break; 899 | ++state->cursor; 900 | } 901 | stb_textedit_clamp(str, state); 902 | 903 | state->has_preferred_x = 1; 904 | state->preferred_x = goal_x; 905 | 906 | if (sel) 907 | state->select_end = state->cursor; 908 | 909 | // go to next line 910 | find.first_char = find.first_char + find.length; 911 | find.length = row.num_chars; 912 | } 913 | break; 914 | } 915 | 916 | case STB_TEXTEDIT_K_UP: 917 | case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: 918 | case STB_TEXTEDIT_K_PGUP: 919 | case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: { 920 | StbFindState find; 921 | StbTexteditRow row; 922 | int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0; 923 | int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP; 924 | int row_count = is_page ? state->row_count_per_page : 1; 925 | 926 | if (!is_page && state->single_line) { 927 | // on windows, up&down become left&right 928 | key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT); 929 | goto retry; 930 | } 931 | 932 | if (sel) 933 | stb_textedit_prep_selection_at_cursor(state); 934 | else if (STB_TEXT_HAS_SELECTION(state)) 935 | stb_textedit_move_to_first(state); 936 | 937 | // compute current position of cursor point 938 | stb_textedit_clamp(str, state); 939 | stb_textedit_find_charpos(&find, str, state->cursor, state->single_line); 940 | 941 | for (j = 0; j < row_count; ++j) { 942 | float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x; 943 | 944 | // can only go up if there's a previous row 945 | if (find.prev_first == find.first_char) 946 | break; 947 | 948 | // now find character position up a row 949 | state->cursor = find.prev_first; 950 | STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); 951 | x = row.x0; 952 | for (i=0; i < row.num_chars; ++i) { 953 | float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i); 954 | #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE 955 | if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE) 956 | break; 957 | #endif 958 | x += dx; 959 | if (x > goal_x) 960 | break; 961 | ++state->cursor; 962 | } 963 | stb_textedit_clamp(str, state); 964 | 965 | state->has_preferred_x = 1; 966 | state->preferred_x = goal_x; 967 | 968 | if (sel) 969 | state->select_end = state->cursor; 970 | 971 | // go to previous line 972 | // (we need to scan previous line the hard way. maybe we could expose this as a new API function?) 973 | prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0; 974 | while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE) 975 | --prev_scan; 976 | find.first_char = find.prev_first; 977 | find.prev_first = prev_scan; 978 | } 979 | break; 980 | } 981 | 982 | case STB_TEXTEDIT_K_DELETE: 983 | case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT: 984 | if (STB_TEXT_HAS_SELECTION(state)) 985 | stb_textedit_delete_selection(str, state); 986 | else { 987 | int n = STB_TEXTEDIT_STRINGLEN(str); 988 | if (state->cursor < n) 989 | stb_textedit_delete(str, state, state->cursor, 1); 990 | } 991 | state->has_preferred_x = 0; 992 | break; 993 | 994 | case STB_TEXTEDIT_K_BACKSPACE: 995 | case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT: 996 | if (STB_TEXT_HAS_SELECTION(state)) 997 | stb_textedit_delete_selection(str, state); 998 | else { 999 | stb_textedit_clamp(str, state); 1000 | if (state->cursor > 0) { 1001 | stb_textedit_delete(str, state, state->cursor-1, 1); 1002 | --state->cursor; 1003 | } 1004 | } 1005 | state->has_preferred_x = 0; 1006 | break; 1007 | 1008 | #ifdef STB_TEXTEDIT_K_TEXTSTART2 1009 | case STB_TEXTEDIT_K_TEXTSTART2: 1010 | #endif 1011 | case STB_TEXTEDIT_K_TEXTSTART: 1012 | state->cursor = state->select_start = state->select_end = 0; 1013 | state->has_preferred_x = 0; 1014 | break; 1015 | 1016 | #ifdef STB_TEXTEDIT_K_TEXTEND2 1017 | case STB_TEXTEDIT_K_TEXTEND2: 1018 | #endif 1019 | case STB_TEXTEDIT_K_TEXTEND: 1020 | state->cursor = STB_TEXTEDIT_STRINGLEN(str); 1021 | state->select_start = state->select_end = 0; 1022 | state->has_preferred_x = 0; 1023 | break; 1024 | 1025 | #ifdef STB_TEXTEDIT_K_TEXTSTART2 1026 | case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT: 1027 | #endif 1028 | case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT: 1029 | stb_textedit_prep_selection_at_cursor(state); 1030 | state->cursor = state->select_end = 0; 1031 | state->has_preferred_x = 0; 1032 | break; 1033 | 1034 | #ifdef STB_TEXTEDIT_K_TEXTEND2 1035 | case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT: 1036 | #endif 1037 | case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT: 1038 | stb_textedit_prep_selection_at_cursor(state); 1039 | state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str); 1040 | state->has_preferred_x = 0; 1041 | break; 1042 | 1043 | 1044 | #ifdef STB_TEXTEDIT_K_LINESTART2 1045 | case STB_TEXTEDIT_K_LINESTART2: 1046 | #endif 1047 | case STB_TEXTEDIT_K_LINESTART: 1048 | stb_textedit_clamp(str, state); 1049 | stb_textedit_move_to_first(state); 1050 | if (state->single_line) 1051 | state->cursor = 0; 1052 | else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 1053 | --state->cursor; 1054 | state->has_preferred_x = 0; 1055 | break; 1056 | 1057 | #ifdef STB_TEXTEDIT_K_LINEEND2 1058 | case STB_TEXTEDIT_K_LINEEND2: 1059 | #endif 1060 | case STB_TEXTEDIT_K_LINEEND: { 1061 | int n = STB_TEXTEDIT_STRINGLEN(str); 1062 | stb_textedit_clamp(str, state); 1063 | stb_textedit_move_to_first(state); 1064 | if (state->single_line) 1065 | state->cursor = n; 1066 | else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1067 | ++state->cursor; 1068 | state->has_preferred_x = 0; 1069 | break; 1070 | } 1071 | 1072 | #ifdef STB_TEXTEDIT_K_LINESTART2 1073 | case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT: 1074 | #endif 1075 | case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT: 1076 | stb_textedit_clamp(str, state); 1077 | stb_textedit_prep_selection_at_cursor(state); 1078 | if (state->single_line) 1079 | state->cursor = 0; 1080 | else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) 1081 | --state->cursor; 1082 | state->select_end = state->cursor; 1083 | state->has_preferred_x = 0; 1084 | break; 1085 | 1086 | #ifdef STB_TEXTEDIT_K_LINEEND2 1087 | case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT: 1088 | #endif 1089 | case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: { 1090 | int n = STB_TEXTEDIT_STRINGLEN(str); 1091 | stb_textedit_clamp(str, state); 1092 | stb_textedit_prep_selection_at_cursor(state); 1093 | if (state->single_line) 1094 | state->cursor = n; 1095 | else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) 1096 | ++state->cursor; 1097 | state->select_end = state->cursor; 1098 | state->has_preferred_x = 0; 1099 | break; 1100 | } 1101 | } 1102 | } 1103 | 1104 | ///////////////////////////////////////////////////////////////////////////// 1105 | // 1106 | // Undo processing 1107 | // 1108 | // @OPTIMIZE: the undo/redo buffer should be circular 1109 | 1110 | static void stb_textedit_flush_redo(StbUndoState *state) 1111 | { 1112 | state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; 1113 | state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; 1114 | } 1115 | 1116 | // discard the oldest entry in the undo list 1117 | static void stb_textedit_discard_undo(StbUndoState *state) 1118 | { 1119 | if (state->undo_point > 0) { 1120 | // if the 0th undo state has characters, clean those up 1121 | if (state->undo_rec[0].char_storage >= 0) { 1122 | int n = state->undo_rec[0].insert_length, i; 1123 | // delete n characters from all other records 1124 | state->undo_char_point -= n; 1125 | STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE))); 1126 | for (i=0; i < state->undo_point; ++i) 1127 | if (state->undo_rec[i].char_storage >= 0) 1128 | state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it 1129 | } 1130 | --state->undo_point; 1131 | STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0]))); 1132 | } 1133 | } 1134 | 1135 | // discard the oldest entry in the redo list--it's bad if this 1136 | // ever happens, but because undo & redo have to store the actual 1137 | // characters in different cases, the redo character buffer can 1138 | // fill up even though the undo buffer didn't 1139 | static void stb_textedit_discard_redo(StbUndoState *state) 1140 | { 1141 | int k = STB_TEXTEDIT_UNDOSTATECOUNT-1; 1142 | 1143 | if (state->redo_point <= k) { 1144 | // if the k'th undo state has characters, clean those up 1145 | if (state->undo_rec[k].char_storage >= 0) { 1146 | int n = state->undo_rec[k].insert_length, i; 1147 | // move the remaining redo character data to the end of the buffer 1148 | state->redo_char_point += n; 1149 | STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE))); 1150 | // adjust the position of all the other records to account for above memmove 1151 | for (i=state->redo_point; i < k; ++i) 1152 | if (state->undo_rec[i].char_storage >= 0) 1153 | state->undo_rec[i].char_storage += n; 1154 | } 1155 | // now move all the redo records towards the end of the buffer; the first one is at 'redo_point' 1156 | // [DEAR IMGUI] 1157 | size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0])); 1158 | const char* buf_begin = (char*)state->undo_rec; (void)buf_begin; 1159 | const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end; 1160 | IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin); 1161 | IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end); 1162 | STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size); 1163 | 1164 | // now move redo_point to point to the new one 1165 | ++state->redo_point; 1166 | } 1167 | } 1168 | 1169 | static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numchars) 1170 | { 1171 | // any time we create a new undo record, we discard redo 1172 | stb_textedit_flush_redo(state); 1173 | 1174 | // if we have no free records, we have to make room, by sliding the 1175 | // existing records down 1176 | if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1177 | stb_textedit_discard_undo(state); 1178 | 1179 | // if the characters to store won't possibly fit in the buffer, we can't undo 1180 | if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) { 1181 | state->undo_point = 0; 1182 | state->undo_char_point = 0; 1183 | return NULL; 1184 | } 1185 | 1186 | // if we don't have enough free characters in the buffer, we have to make room 1187 | while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT) 1188 | stb_textedit_discard_undo(state); 1189 | 1190 | return &state->undo_rec[state->undo_point++]; 1191 | } 1192 | 1193 | static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len) 1194 | { 1195 | StbUndoRecord *r = stb_text_create_undo_record(state, insert_len); 1196 | if (r == NULL) 1197 | return NULL; 1198 | 1199 | r->where = pos; 1200 | r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len; 1201 | r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len; 1202 | 1203 | if (insert_len == 0) { 1204 | r->char_storage = -1; 1205 | return NULL; 1206 | } else { 1207 | r->char_storage = state->undo_char_point; 1208 | state->undo_char_point += insert_len; 1209 | return &state->undo_char[r->char_storage]; 1210 | } 1211 | } 1212 | 1213 | static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 1214 | { 1215 | StbUndoState *s = &state->undostate; 1216 | StbUndoRecord u, *r; 1217 | if (s->undo_point == 0) 1218 | return; 1219 | 1220 | // we need to do two things: apply the undo record, and create a redo record 1221 | u = s->undo_rec[s->undo_point-1]; 1222 | r = &s->undo_rec[s->redo_point-1]; 1223 | r->char_storage = -1; 1224 | 1225 | r->insert_length = u.delete_length; 1226 | r->delete_length = u.insert_length; 1227 | r->where = u.where; 1228 | 1229 | if (u.delete_length) { 1230 | // if the undo record says to delete characters, then the redo record will 1231 | // need to re-insert the characters that get deleted, so we need to store 1232 | // them. 1233 | 1234 | // there are three cases: 1235 | // there's enough room to store the characters 1236 | // characters stored for *redoing* don't leave room for redo 1237 | // characters stored for *undoing* don't leave room for redo 1238 | // if the last is true, we have to bail 1239 | 1240 | if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) { 1241 | // the undo records take up too much character space; there's no space to store the redo characters 1242 | r->insert_length = 0; 1243 | } else { 1244 | int i; 1245 | 1246 | // there's definitely room to store the characters eventually 1247 | while (s->undo_char_point + u.delete_length > s->redo_char_point) { 1248 | // should never happen: 1249 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1250 | return; 1251 | // there's currently not enough room, so discard a redo record 1252 | stb_textedit_discard_redo(s); 1253 | } 1254 | r = &s->undo_rec[s->redo_point-1]; 1255 | 1256 | r->char_storage = s->redo_char_point - u.delete_length; 1257 | s->redo_char_point = s->redo_char_point - u.delete_length; 1258 | 1259 | // now save the characters 1260 | for (i=0; i < u.delete_length; ++i) 1261 | s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i); 1262 | } 1263 | 1264 | // now we can carry out the deletion 1265 | STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length); 1266 | } 1267 | 1268 | // check type of recorded action: 1269 | if (u.insert_length) { 1270 | // easy case: was a deletion, so we need to insert n characters 1271 | STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length); 1272 | s->undo_char_point -= u.insert_length; 1273 | } 1274 | 1275 | state->cursor = u.where + u.insert_length; 1276 | 1277 | s->undo_point--; 1278 | s->redo_point--; 1279 | } 1280 | 1281 | static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) 1282 | { 1283 | StbUndoState *s = &state->undostate; 1284 | StbUndoRecord *u, r; 1285 | if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT) 1286 | return; 1287 | 1288 | // we need to do two things: apply the redo record, and create an undo record 1289 | u = &s->undo_rec[s->undo_point]; 1290 | r = s->undo_rec[s->redo_point]; 1291 | 1292 | // we KNOW there must be room for the undo record, because the redo record 1293 | // was derived from an undo record 1294 | 1295 | u->delete_length = r.insert_length; 1296 | u->insert_length = r.delete_length; 1297 | u->where = r.where; 1298 | u->char_storage = -1; 1299 | 1300 | if (r.delete_length) { 1301 | // the redo record requires us to delete characters, so the undo record 1302 | // needs to store the characters 1303 | 1304 | if (s->undo_char_point + u->insert_length > s->redo_char_point) { 1305 | u->insert_length = 0; 1306 | u->delete_length = 0; 1307 | } else { 1308 | int i; 1309 | u->char_storage = s->undo_char_point; 1310 | s->undo_char_point = s->undo_char_point + u->insert_length; 1311 | 1312 | // now save the characters 1313 | for (i=0; i < u->insert_length; ++i) 1314 | s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i); 1315 | } 1316 | 1317 | STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length); 1318 | } 1319 | 1320 | if (r.insert_length) { 1321 | // easy case: need to insert n characters 1322 | STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); 1323 | s->redo_char_point += r.insert_length; 1324 | } 1325 | 1326 | state->cursor = r.where + r.insert_length; 1327 | 1328 | s->undo_point++; 1329 | s->redo_point++; 1330 | } 1331 | 1332 | static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length) 1333 | { 1334 | stb_text_createundo(&state->undostate, where, 0, length); 1335 | } 1336 | 1337 | static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length) 1338 | { 1339 | int i; 1340 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0); 1341 | if (p) { 1342 | for (i=0; i < length; ++i) 1343 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1344 | } 1345 | } 1346 | 1347 | static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length) 1348 | { 1349 | int i; 1350 | STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length); 1351 | if (p) { 1352 | for (i=0; i < old_length; ++i) 1353 | p[i] = STB_TEXTEDIT_GETCHAR(str, where+i); 1354 | } 1355 | } 1356 | 1357 | // reset the state to default 1358 | static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_line) 1359 | { 1360 | state->undostate.undo_point = 0; 1361 | state->undostate.undo_char_point = 0; 1362 | state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT; 1363 | state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT; 1364 | state->select_end = state->select_start = 0; 1365 | state->cursor = 0; 1366 | state->has_preferred_x = 0; 1367 | state->preferred_x = 0; 1368 | state->cursor_at_end_of_line = 0; 1369 | state->initialized = 1; 1370 | state->single_line = (unsigned char) is_single_line; 1371 | state->insert_mode = 0; 1372 | state->row_count_per_page = 0; 1373 | } 1374 | 1375 | // API initialize 1376 | static void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line) 1377 | { 1378 | stb_textedit_clear_state(state, is_single_line); 1379 | } 1380 | 1381 | #if defined(__GNUC__) || defined(__clang__) 1382 | #pragma GCC diagnostic push 1383 | #pragma GCC diagnostic ignored "-Wcast-qual" 1384 | #endif 1385 | 1386 | static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len) 1387 | { 1388 | return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len); 1389 | } 1390 | 1391 | #if defined(__GNUC__) || defined(__clang__) 1392 | #pragma GCC diagnostic pop 1393 | #endif 1394 | 1395 | #endif//STB_TEXTEDIT_IMPLEMENTATION 1396 | 1397 | /* 1398 | ------------------------------------------------------------------------------ 1399 | This software is available under 2 licenses -- choose whichever you prefer. 1400 | ------------------------------------------------------------------------------ 1401 | ALTERNATIVE A - MIT License 1402 | Copyright (c) 2017 Sean Barrett 1403 | Permission is hereby granted, free of charge, to any person obtaining a copy of 1404 | this software and associated documentation files (the "Software"), to deal in 1405 | the Software without restriction, including without limitation the rights to 1406 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 1407 | of the Software, and to permit persons to whom the Software is furnished to do 1408 | so, subject to the following conditions: 1409 | The above copyright notice and this permission notice shall be included in all 1410 | copies or substantial portions of the Software. 1411 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1412 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1413 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1414 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1415 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1416 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1417 | SOFTWARE. 1418 | ------------------------------------------------------------------------------ 1419 | ALTERNATIVE B - Public Domain (www.unlicense.org) 1420 | This is free and unencumbered software released into the public domain. 1421 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 1422 | software, either in source code form or as a compiled binary, for any purpose, 1423 | commercial or non-commercial, and by any means. 1424 | In jurisdictions that recognize copyright laws, the author or authors of this 1425 | software dedicate any and all copyright interest in the software to the public 1426 | domain. We make this dedication for the benefit of the public at large and to 1427 | the detriment of our heirs and successors. We intend this dedication to be an 1428 | overt act of relinquishment in perpetuity of all present and future rights to 1429 | this software under copyright law. 1430 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1431 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1432 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1433 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 1434 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 1435 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1436 | ------------------------------------------------------------------------------ 1437 | */ 1438 | --------------------------------------------------------------------------------