├── 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 |
--------------------------------------------------------------------------------