mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
imgui: update imgui to v1.92.7, update dx9 backend to latest (#605)
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2014-2023 Omar Cornut
|
Copyright (c) 2014-2026 Omar Cornut
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
+645
-269
@@ -1,16 +1,37 @@
|
|||||||
// dear imgui: Renderer for DirectX9
|
// dear imgui: Renderer Backend for DirectX9
|
||||||
// This needs to be used along with a Platform Binding (e.g. Win32)
|
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||||
|
|
||||||
// Implemented features:
|
// Implemented features:
|
||||||
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
|
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
|
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||||
|
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||||
|
// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9.
|
||||||
|
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||||
|
|
||||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
// https://github.com/ocornut/imgui
|
// Learn about Dear ImGui:
|
||||||
|
// - FAQ https://dearimgui.com/faq
|
||||||
|
// - Getting Started https://dearimgui.com/getting-started
|
||||||
|
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||||
|
// - Introduction, links and more at the top of imgui.cpp
|
||||||
|
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
// (minor and older changes stripped away, please see git history for details)
|
// (minor and older changes stripped away, please see git history for details)
|
||||||
|
// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||||
|
// 2026-03-19: Fixed issue in ImGui_ImplDX9_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310)
|
||||||
|
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
|
||||||
|
// 2025-06-11: DirectX9: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
|
||||||
|
// 2024-10-07: DirectX9: Changed default texture sampler to Clamp instead of Repeat/Wrap.
|
||||||
|
// 2024-02-12: DirectX9: Using RGBA format when supported by the driver to avoid CPU side conversion. (#6575)
|
||||||
|
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
|
||||||
|
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||||
|
// 2021-06-25: DirectX9: Explicitly disable texture state stages after >= 1.
|
||||||
|
// 2021-05-19: DirectX9: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
|
||||||
|
// 2021-04-23: DirectX9: Explicitly setting up more graphics states to increase compatibility with unusual non-default states.
|
||||||
|
// 2021-03-18: DirectX9: Calling IDirect3DStateBlock9::Capture() after CreateStateBlock() as a workaround for state restoring issues (see #3857).
|
||||||
|
// 2021-03-03: DirectX9: Added support for IMGUI_USE_BGRA_PACKED_COLOR in user's imconfig file.
|
||||||
|
// 2021-02-18: DirectX9: Change blending equation to preserve alpha in output buffer.
|
||||||
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||||
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||||
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
|
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
|
||||||
@@ -22,160 +43,154 @@
|
|||||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
|
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
|
||||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||||
|
|
||||||
#include "imgui_impl_dx9.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
// DirectX
|
|
||||||
#include <d3d9.h>
|
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
#ifndef IMGUI_DISABLE
|
||||||
|
#include "imgui_impl_dx9.h"
|
||||||
|
|
||||||
// allow std::min use
|
// allow std::min use
|
||||||
#ifdef min
|
#ifdef min
|
||||||
#undef min
|
#undef min
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// DirectX data
|
// DirectX
|
||||||
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
|
#include <d3d9.h>
|
||||||
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
|
|
||||||
static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;
|
|
||||||
static LPDIRECT3DTEXTURE9 g_FontTexture = NULL;
|
|
||||||
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
|
||||||
|
|
||||||
|
// Clang/GCC warnings with -Weverything
|
||||||
|
#if defined(__clang__)
|
||||||
|
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
|
||||||
|
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// DirectX data
|
||||||
|
struct ImGui_ImplDX9_Data
|
||||||
|
{
|
||||||
|
LPDIRECT3DDEVICE9 pd3dDevice;
|
||||||
|
LPDIRECT3DVERTEXBUFFER9 pVB;
|
||||||
|
LPDIRECT3DINDEXBUFFER9 pIB;
|
||||||
|
int VertexBufferSize;
|
||||||
|
int IndexBufferSize;
|
||||||
|
bool HasRgbaSupport;
|
||||||
|
|
||||||
|
ImGui_ImplDX9_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CUSTOMVERTEX
|
||||||
|
{
|
||||||
|
float pos[3];
|
||||||
|
D3DCOLOR col;
|
||||||
|
float uv[2];
|
||||||
|
};
|
||||||
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
|
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
|
||||||
|
|
||||||
// Render function.
|
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
|
#define IMGUI_COL_TO_DX9_ARGB(_COL) (_COL)
|
||||||
void ImGui_ImplDX9_RenderDrawData(ImDrawData *draw_data) {
|
#else
|
||||||
|
#define IMGUI_COL_TO_DX9_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16))
|
||||||
|
#endif
|
||||||
|
|
||||||
// Avoid rendering when minimized
|
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
||||||
return;
|
static ImGui_ImplDX9_Data* ImGui_ImplDX9_GetBackendData()
|
||||||
|
{
|
||||||
|
return ImGui::GetCurrentContext() ? (ImGui_ImplDX9_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Create and grow buffers if needed
|
// Forward Declarations
|
||||||
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) {
|
static void ImGui_ImplDX9_InitMultiViewportSupport();
|
||||||
if (g_pVB) {
|
static void ImGui_ImplDX9_ShutdownMultiViewportSupport();
|
||||||
g_pVB->Release();
|
static void ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows();
|
||||||
g_pVB = NULL;
|
static void ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows();
|
||||||
}
|
|
||||||
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
|
||||||
if (g_pd3dDevice->CreateVertexBuffer(g_VertexBufferSize * sizeof(ImDrawVert),
|
|
||||||
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX,
|
|
||||||
D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount) {
|
|
||||||
if (g_pIB) {
|
|
||||||
g_pIB->Release();
|
|
||||||
g_pIB = NULL;
|
|
||||||
}
|
|
||||||
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
|
||||||
if (g_pd3dDevice->CreateIndexBuffer(g_IndexBufferSize * sizeof(ImDrawIdx),
|
|
||||||
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
|
|
||||||
sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32,
|
|
||||||
D3DPOOL_DEFAULT, &g_pIB, NULL) < 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Backup the DX9 state
|
struct render_state_t {
|
||||||
IDirect3DStateBlock9 *d3d9_state_block = NULL;
|
IDirect3DSurface9 *back_buffer;
|
||||||
if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
|
IDirect3DSurface9 *depth_stencil;
|
||||||
return;
|
IDirect3DSurface9 *render_targets[8];
|
||||||
|
D3DCAPS9 caps;
|
||||||
|
};
|
||||||
|
|
||||||
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
|
// Functions
|
||||||
D3DMATRIX last_world, last_view, last_projection;
|
static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data, struct render_state_t *render_state)
|
||||||
g_pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
|
{
|
||||||
g_pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
|
|
||||||
|
|
||||||
// Copy all vertices into a single contiguous buffer
|
|
||||||
ImDrawVert *vtx_dst;
|
|
||||||
ImDrawIdx *idx_dst;
|
|
||||||
if (g_pVB->Lock(0, (UINT) (draw_data->TotalVtxCount * sizeof(ImDrawVert)), (void **) &vtx_dst,
|
|
||||||
D3DLOCK_DISCARD) < 0)
|
|
||||||
return;
|
|
||||||
if (g_pIB->Lock(0, (UINT) (draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void **) &idx_dst,
|
|
||||||
D3DLOCK_DISCARD) < 0)
|
|
||||||
return;
|
|
||||||
for (int n = 0; n < draw_data->CmdListsCount; n++) {
|
|
||||||
const ImDrawList *cmd_list = draw_data->CmdLists[n];
|
|
||||||
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
|
||||||
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
|
||||||
vtx_dst += cmd_list->VtxBuffer.Size;
|
|
||||||
idx_dst += cmd_list->IdxBuffer.Size;
|
|
||||||
}
|
|
||||||
g_pVB->Unlock();
|
|
||||||
g_pIB->Unlock();
|
|
||||||
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(ImDrawVert));
|
|
||||||
g_pd3dDevice->SetIndices(g_pIB);
|
|
||||||
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
|
|
||||||
|
|
||||||
// Setup viewport
|
// Setup viewport
|
||||||
D3DVIEWPORT9 vp;
|
D3DVIEWPORT9 vp;
|
||||||
vp.X = vp.Y = 0;
|
vp.X = vp.Y = 0;
|
||||||
vp.Width = (DWORD) draw_data->DisplaySize.x;
|
vp.Width = (DWORD)draw_data->DisplaySize.x;
|
||||||
vp.Height = (DWORD) draw_data->DisplaySize.y;
|
vp.Height = (DWORD)draw_data->DisplaySize.y;
|
||||||
vp.MinZ = 0.0f;
|
vp.MinZ = 0.0f;
|
||||||
vp.MaxZ = 1.0f;
|
vp.MaxZ = 1.0f;
|
||||||
g_pd3dDevice->SetViewport(&vp);
|
|
||||||
|
|
||||||
g_pd3dDevice->SetPixelShader(nullptr);
|
LPDIRECT3DDEVICE9 device = bd->pd3dDevice;
|
||||||
g_pd3dDevice->SetVertexShader(nullptr);
|
device->SetViewport(&vp);
|
||||||
|
|
||||||
D3DCAPS9 caps {};
|
// spice ldj
|
||||||
if (FAILED(g_pd3dDevice->GetDeviceCaps(&caps))) {
|
{
|
||||||
caps.NumSimultaneousRTs = 0UL;
|
if (FAILED(device->GetDeviceCaps(&render_state->caps))) {
|
||||||
}
|
render_state->caps.NumSimultaneousRTs = 0UL;
|
||||||
|
}
|
||||||
|
|
||||||
IDirect3DSurface9 *back_buffer = nullptr;
|
// save all previous render target state
|
||||||
IDirect3DSurface9 *depth_stencil = nullptr;
|
for (size_t target = 0; target < std::min(8UL, render_state->caps.NumSimultaneousRTs); target++) {
|
||||||
IDirect3DSurface9 *render_targets[8];
|
if (FAILED(device->GetRenderTarget(target, &render_state->render_targets[target]))) {
|
||||||
|
render_state->render_targets[target] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// save all previous render target state
|
// get the previous depth stencil
|
||||||
for (size_t target = 0; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
|
if (FAILED(device->GetDepthStencilSurface(&render_state->depth_stencil))) {
|
||||||
if (FAILED(g_pd3dDevice->GetRenderTarget(target, &render_targets[target]))) {
|
render_state->depth_stencil = nullptr;
|
||||||
render_targets[target] = nullptr;
|
}
|
||||||
|
|
||||||
|
// set the back buffer as the current render target
|
||||||
|
if (SUCCEEDED(device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &render_state->back_buffer))) {
|
||||||
|
device->SetRenderTarget(0, render_state->back_buffer);
|
||||||
|
device->SetDepthStencilSurface(nullptr);
|
||||||
|
|
||||||
|
for (size_t target = 1; target < std::min(8UL, render_state->caps.NumSimultaneousRTs); target++) {
|
||||||
|
device->SetRenderTarget(target, nullptr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
render_state->back_buffer = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the previous depth stencil
|
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling.
|
||||||
if (FAILED(g_pd3dDevice->GetDepthStencilSurface(&depth_stencil))) {
|
device->SetPixelShader(nullptr);
|
||||||
depth_stencil = nullptr;
|
device->SetVertexShader(nullptr);
|
||||||
}
|
device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
|
||||||
|
device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
||||||
// set the back buffer as the current render target
|
device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
|
||||||
if (SUCCEEDED(g_pd3dDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back_buffer))) {
|
device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
|
||||||
g_pd3dDevice->SetRenderTarget(0, back_buffer);
|
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||||
g_pd3dDevice->SetDepthStencilSurface(nullptr);
|
device->SetRenderState(D3DRS_ZENABLE, FALSE);
|
||||||
|
device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
|
||||||
for (size_t target = 1; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
|
device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
||||||
g_pd3dDevice->SetRenderTarget(target, nullptr);
|
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||||
}
|
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||||
} else {
|
device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
|
||||||
back_buffer = nullptr;
|
device->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
|
||||||
}
|
device->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
|
||||||
|
device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
|
||||||
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient)
|
device->SetRenderState(D3DRS_FOGENABLE, FALSE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
device->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, false);
|
device->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false);
|
device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
|
device->SetRenderState(D3DRS_CLIPPING, TRUE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, false);
|
device->SetRenderState(D3DRS_LIGHTING, FALSE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, true);
|
device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||||
g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, false);
|
device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
|
||||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
|
||||||
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
|
||||||
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
|
||||||
|
|
||||||
// Setup orthographic projection matrix
|
// Setup orthographic projection matrix
|
||||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||||
@@ -185,176 +200,537 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData *draw_data) {
|
|||||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
|
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
|
||||||
float T = draw_data->DisplayPos.y + 0.5f;
|
float T = draw_data->DisplayPos.y + 0.5f;
|
||||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
|
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
|
||||||
D3DMATRIX mat_identity = {{{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}};
|
D3DMATRIX mat_identity = { { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } } };
|
||||||
D3DMATRIX mat_projection =
|
D3DMATRIX mat_projection =
|
||||||
{{{
|
{ { {
|
||||||
2.0f / (R - L), 0.0f, 0.0f, 0.0f,
|
2.0f/(R-L), 0.0f, 0.0f, 0.0f,
|
||||||
0.0f, 2.0f / (T - B), 0.0f, 0.0f,
|
0.0f, 2.0f/(T-B), 0.0f, 0.0f,
|
||||||
0.0f, 0.0f, 0.5f, 0.0f,
|
0.0f, 0.0f, 0.5f, 0.0f,
|
||||||
(L + R) / (L - R), (T + B) / (B - T), 0.5f, 1.0f
|
(L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f
|
||||||
}}};
|
} } };
|
||||||
g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
|
device->SetTransform(D3DTS_WORLD, &mat_identity);
|
||||||
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
|
device->SetTransform(D3DTS_VIEW, &mat_identity);
|
||||||
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
|
device->SetTransform(D3DTS_PROJECTION, &mat_projection);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render function.
|
||||||
|
void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
||||||
|
{
|
||||||
|
// Avoid rendering when minimized
|
||||||
|
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
LPDIRECT3DDEVICE9 device = bd->pd3dDevice;
|
||||||
|
|
||||||
|
// Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
|
||||||
|
// (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates).
|
||||||
|
if (draw_data->Textures != nullptr)
|
||||||
|
for (ImTextureData* tex : *draw_data->Textures)
|
||||||
|
if (tex->Status != ImTextureStatus_OK)
|
||||||
|
ImGui_ImplDX9_UpdateTexture(tex);
|
||||||
|
|
||||||
|
// Create and grow buffers if needed
|
||||||
|
if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
|
||||||
|
{
|
||||||
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
|
||||||
|
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||||
|
if (device->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, nullptr) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
|
||||||
|
{
|
||||||
|
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
|
||||||
|
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||||
|
if (device->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup the DX9 state
|
||||||
|
IDirect3DStateBlock9* state_block = nullptr;
|
||||||
|
if (device->CreateStateBlock(D3DSBT_ALL, &state_block) < 0)
|
||||||
|
return;
|
||||||
|
if (state_block->Capture() < 0)
|
||||||
|
{
|
||||||
|
state_block->Release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
|
||||||
|
D3DMATRIX last_world, last_view, last_projection;
|
||||||
|
device->GetTransform(D3DTS_WORLD, &last_world);
|
||||||
|
device->GetTransform(D3DTS_VIEW, &last_view);
|
||||||
|
device->GetTransform(D3DTS_PROJECTION, &last_projection);
|
||||||
|
|
||||||
|
// Allocate buffers
|
||||||
|
CUSTOMVERTEX* vtx_dst;
|
||||||
|
ImDrawIdx* idx_dst;
|
||||||
|
if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
|
||||||
|
{
|
||||||
|
state_block->Release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
|
||||||
|
{
|
||||||
|
bd->pVB->Unlock();
|
||||||
|
state_block->Release();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format.
|
||||||
|
// FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and
|
||||||
|
// 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
// 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
|
||||||
|
for (const ImDrawList* draw_list : draw_data->CmdLists)
|
||||||
|
{
|
||||||
|
const ImDrawVert* vtx_src = draw_list->VtxBuffer.Data;
|
||||||
|
for (int i = 0; i < draw_list->VtxBuffer.Size; i++)
|
||||||
|
{
|
||||||
|
vtx_dst->pos[0] = vtx_src->pos.x;
|
||||||
|
vtx_dst->pos[1] = vtx_src->pos.y;
|
||||||
|
vtx_dst->pos[2] = 0.0f;
|
||||||
|
vtx_dst->col = IMGUI_COL_TO_DX9_ARGB(vtx_src->col);
|
||||||
|
vtx_dst->uv[0] = vtx_src->uv.x;
|
||||||
|
vtx_dst->uv[1] = vtx_src->uv.y;
|
||||||
|
vtx_dst++;
|
||||||
|
vtx_src++;
|
||||||
|
}
|
||||||
|
memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||||
|
idx_dst += draw_list->IdxBuffer.Size;
|
||||||
|
}
|
||||||
|
bd->pVB->Unlock();
|
||||||
|
bd->pIB->Unlock();
|
||||||
|
device->SetStreamSource(0, bd->pVB, 0, sizeof(CUSTOMVERTEX));
|
||||||
|
device->SetIndices(bd->pIB);
|
||||||
|
device->SetFVF(D3DFVF_CUSTOMVERTEX);
|
||||||
|
|
||||||
|
// Setup desired DX state
|
||||||
|
struct render_state_t render_state = {};
|
||||||
|
ImGui_ImplDX9_SetupRenderState(draw_data, &render_state);
|
||||||
|
|
||||||
// Render command lists
|
// Render command lists
|
||||||
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||||
int global_vtx_offset = 0;
|
int global_vtx_offset = 0;
|
||||||
int global_idx_offset = 0;
|
int global_idx_offset = 0;
|
||||||
ImVec2 clip_off = draw_data->DisplayPos;
|
ImVec2 clip_off = draw_data->DisplayPos;
|
||||||
for (int n = 0; n < draw_data->CmdListsCount; n++) {
|
for (const ImDrawList* draw_list : draw_data->CmdLists)
|
||||||
const ImDrawList *cmd_list = draw_data->CmdLists[n];
|
{
|
||||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
|
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
|
||||||
const ImDrawCmd *pcmd = &cmd_list->CmdBuffer[cmd_i];
|
{
|
||||||
if (pcmd->UserCallback != NULL) {
|
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
|
||||||
pcmd->UserCallback(cmd_list, pcmd);
|
if (pcmd->UserCallback != nullptr)
|
||||||
} else {
|
{
|
||||||
const RECT r = {(LONG) (pcmd->ClipRect.x - clip_off.x), (LONG) (pcmd->ClipRect.y - clip_off.y),
|
// User callback, registered via ImDrawList::AddCallback()
|
||||||
(LONG) (pcmd->ClipRect.z - clip_off.x), (LONG) (pcmd->ClipRect.w - clip_off.y)};
|
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
||||||
auto texture = reinterpret_cast<IDirect3DBaseTexture9 *>(pcmd->TextureId);
|
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
|
||||||
g_pd3dDevice->SetTexture(0, texture);
|
ImGui_ImplDX9_SetupRenderState(draw_data, &render_state);
|
||||||
g_pd3dDevice->SetScissorRect(&r);
|
else
|
||||||
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
|
pcmd->UserCallback(draw_list, pcmd);
|
||||||
pcmd->VtxOffset + global_vtx_offset, 0,
|
}
|
||||||
(UINT) cmd_list->VtxBuffer.Size,
|
else
|
||||||
pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
|
{
|
||||||
|
// Project scissor/clipping rectangles into framebuffer space
|
||||||
|
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
|
||||||
|
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
|
||||||
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Apply scissor/clipping rectangle
|
||||||
|
const RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
|
||||||
|
device->SetScissorRect(&r);
|
||||||
|
|
||||||
|
// Bind texture, Draw
|
||||||
|
const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID();
|
||||||
|
device->SetTexture(0, texture);
|
||||||
|
device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)draw_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
global_idx_offset += cmd_list->IdxBuffer.Size;
|
global_idx_offset += draw_list->IdxBuffer.Size;
|
||||||
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
global_vtx_offset += draw_list->VtxBuffer.Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (back_buffer) {
|
// When using multi-viewports, it appears that there's an odd logic in DirectX9 which prevent subsequent windows
|
||||||
back_buffer->Release();
|
// from rendering until the first window submits at least one draw call, even once. That's our workaround. (see #2560)
|
||||||
back_buffer = nullptr;
|
if (global_vtx_offset == 0)
|
||||||
}
|
bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
// restore previous depth stencil
|
// spice ldj
|
||||||
if (depth_stencil) {
|
{
|
||||||
g_pd3dDevice->SetDepthStencilSurface(depth_stencil);
|
if (render_state.back_buffer) {
|
||||||
depth_stencil->Release();
|
render_state.back_buffer->Release();
|
||||||
depth_stencil = nullptr;
|
render_state.back_buffer = nullptr;
|
||||||
}
|
}
|
||||||
|
// restore previous depth stencil
|
||||||
|
if (render_state.depth_stencil) {
|
||||||
|
device->SetDepthStencilSurface(render_state.depth_stencil);
|
||||||
|
render_state.depth_stencil->Release();
|
||||||
|
render_state.depth_stencil = nullptr;
|
||||||
|
}
|
||||||
|
// restore all render target state
|
||||||
|
for (size_t target = 0; target < std::min(8UL, render_state.caps.NumSimultaneousRTs); target++) {
|
||||||
|
auto render_target = render_state.render_targets[target];
|
||||||
|
|
||||||
// restore all render target state
|
if (render_target) {
|
||||||
for (size_t target = 0; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
|
device->SetRenderTarget(target, render_target);
|
||||||
auto render_target = render_targets[target];
|
render_target->Release();
|
||||||
|
}
|
||||||
if (render_target) {
|
|
||||||
g_pd3dDevice->SetRenderTarget(target, render_target);
|
|
||||||
render_target->Release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore the DX9 transform
|
// Restore the DX9 transform
|
||||||
g_pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
|
device->SetTransform(D3DTS_WORLD, &last_world);
|
||||||
g_pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
|
device->SetTransform(D3DTS_VIEW, &last_view);
|
||||||
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
|
device->SetTransform(D3DTS_PROJECTION, &last_projection);
|
||||||
|
|
||||||
// restore the DX9 state
|
// Restore the DX9 state
|
||||||
d3d9_state_block->Apply();
|
state_block->Apply();
|
||||||
d3d9_state_block->Release();
|
state_block->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplDX9_Init(IDirect3DDevice9 *device) {
|
static bool ImGui_ImplDX9_CheckFormatSupport(LPDIRECT3DDEVICE9 pDevice, D3DFORMAT format)
|
||||||
|
{
|
||||||
|
LPDIRECT3D9 pd3d = nullptr;
|
||||||
|
if (pDevice->GetDirect3D(&pd3d) != D3D_OK)
|
||||||
|
return false;
|
||||||
|
D3DDEVICE_CREATION_PARAMETERS param = {};
|
||||||
|
D3DDISPLAYMODE mode = {};
|
||||||
|
if (pDevice->GetCreationParameters(¶m) != D3D_OK || pDevice->GetDisplayMode(0, &mode) != D3D_OK)
|
||||||
|
{
|
||||||
|
pd3d->Release();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Font texture should support linear filter, color blend and write to render-target
|
||||||
|
bool support = (pd3d->CheckDeviceFormat(param.AdapterOrdinal, param.DeviceType, mode.Format, D3DUSAGE_DYNAMIC | D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, format)) == D3D_OK;
|
||||||
|
pd3d->Release();
|
||||||
|
return support;
|
||||||
|
}
|
||||||
|
|
||||||
// Setup back-end capabilities flags
|
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
|
||||||
auto &io = ImGui::GetIO();
|
{
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||||
|
|
||||||
|
// Setup backend capabilities flags
|
||||||
|
ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)();
|
||||||
|
io.BackendRendererUserData = (void*)bd;
|
||||||
io.BackendRendererName = "imgui_impl_dx9";
|
io.BackendRendererName = "imgui_impl_dx9";
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||||
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||||
|
|
||||||
// We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
|
platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = 4096;
|
||||||
|
|
||||||
|
bd->pd3dDevice = device;
|
||||||
|
bd->pd3dDevice->AddRef();
|
||||||
|
bd->HasRgbaSupport = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8);
|
||||||
|
|
||||||
|
ImGui_ImplDX9_InitMultiViewportSupport();
|
||||||
|
|
||||||
g_pd3dDevice = device;
|
|
||||||
g_pd3dDevice->AddRef();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplDX9_Shutdown() {
|
void ImGui_ImplDX9_Shutdown()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
|
|
||||||
|
ImGui_ImplDX9_ShutdownMultiViewportSupport();
|
||||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||||
|
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
|
||||||
|
|
||||||
if (g_pd3dDevice) {
|
io.BackendRendererName = nullptr;
|
||||||
g_pd3dDevice->Release();
|
io.BackendRendererUserData = nullptr;
|
||||||
g_pd3dDevice = NULL;
|
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
|
||||||
|
platform_io.ClearRendererHandlers();
|
||||||
|
IM_DELETE(bd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices)
|
||||||
|
static void ImGui_ImplDX9_CopyTextureRegion(bool tex_use_colors, const ImU32* src, int src_pitch, ImU32* dst, int dst_pitch, int w, int h)
|
||||||
|
{
|
||||||
|
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
const bool convert_rgba_to_bgra = (!bd->HasRgbaSupport && tex_use_colors);
|
||||||
|
#else
|
||||||
|
const bool convert_rgba_to_bgra = false;
|
||||||
|
IM_UNUSED(tex_use_colors);
|
||||||
|
#endif
|
||||||
|
for (int y = 0; y < h; y++)
|
||||||
|
{
|
||||||
|
const ImU32* src_p = (const ImU32*)(const void*)((const unsigned char*)src + src_pitch * y);
|
||||||
|
ImU32* dst_p = (ImU32*)(void*)((unsigned char*)dst + dst_pitch * y);
|
||||||
|
if (convert_rgba_to_bgra)
|
||||||
|
for (int x = w; x > 0; x--, src_p++, dst_p++) // Convert copy
|
||||||
|
*dst_p = IMGUI_COL_TO_DX9_ARGB(*src_p);
|
||||||
|
else
|
||||||
|
memcpy(dst_p, src_p, w * 4); // Raw copy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ImGui_ImplDX9_CreateFontsTexture() {
|
void ImGui_ImplDX9_UpdateTexture(ImTextureData* tex)
|
||||||
// Build texture atlas
|
{
|
||||||
ImGuiIO &io = ImGui::GetIO();
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
unsigned char *pixels;
|
|
||||||
int width, height, bytes_per_pixel;
|
|
||||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
|
|
||||||
|
|
||||||
// Upload texture to graphics system
|
if (tex->Status == ImTextureStatus_WantCreate)
|
||||||
g_FontTexture = NULL;
|
{
|
||||||
if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8,
|
// Create and upload new texture to graphics system
|
||||||
D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0)
|
//IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
|
||||||
return false;
|
IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
|
||||||
D3DLOCKED_RECT tex_locked_rect;
|
IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
|
||||||
if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
|
LPDIRECT3DTEXTURE9 dx_tex = nullptr;
|
||||||
return false;
|
HRESULT hr = bd->pd3dDevice->CreateTexture(tex->Width, tex->Height, 1, D3DUSAGE_DYNAMIC, bd->HasRgbaSupport ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &dx_tex, nullptr);
|
||||||
for (int y = 0; y < height; y++)
|
if (hr < 0)
|
||||||
memcpy((unsigned char *) tex_locked_rect.pBits + tex_locked_rect.Pitch * y,
|
{
|
||||||
pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel));
|
IM_ASSERT(hr >= 0 && "Backend failed to create texture!");
|
||||||
g_FontTexture->UnlockRect(0);
|
return;
|
||||||
|
|
||||||
// Store our identifier
|
|
||||||
io.Fonts->TexID = (ImTextureID) g_FontTexture;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ImGui_ImplDX9_CreateDeviceObjects() {
|
|
||||||
if (!g_pd3dDevice) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return ImGui_ImplDX9_CreateFontsTexture();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui_ImplDX9_InvalidateDeviceObjects() {
|
|
||||||
if (!g_pd3dDevice)
|
|
||||||
return;
|
|
||||||
if (g_pVB) {
|
|
||||||
g_pVB->Release();
|
|
||||||
g_pVB = NULL;
|
|
||||||
}
|
|
||||||
if (g_pIB) {
|
|
||||||
g_pIB->Release();
|
|
||||||
g_pIB = NULL;
|
|
||||||
}
|
|
||||||
if (g_FontTexture) {
|
|
||||||
g_FontTexture->Release();
|
|
||||||
g_FontTexture = NULL;
|
|
||||||
ImGui::GetIO().Fonts->TexID = 0;
|
|
||||||
} // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui_ImplDX9_NewFrame() {
|
|
||||||
if (!g_FontTexture) {
|
|
||||||
ImGui_ImplDX9_CreateDeviceObjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
IDirect3DSwapChain9 *swap_chain = nullptr;
|
|
||||||
if (SUCCEEDED(g_pd3dDevice->GetSwapChain(0, &swap_chain))) {
|
|
||||||
auto &io = ImGui::GetIO();
|
|
||||||
|
|
||||||
D3DPRESENT_PARAMETERS present_params {};
|
|
||||||
|
|
||||||
if (SUCCEEDED(swap_chain->GetPresentParameters(&present_params))) {
|
|
||||||
if (present_params.BackBufferWidth != 0 && present_params.BackBufferHeight != 0) {
|
|
||||||
io.DisplaySize.x = static_cast<float>(present_params.BackBufferWidth);
|
|
||||||
io.DisplaySize.y = static_cast<float>(present_params.BackBufferHeight);
|
|
||||||
} else {
|
|
||||||
RECT rect {};
|
|
||||||
GetClientRect(present_params.hDeviceWindow, &rect);
|
|
||||||
|
|
||||||
io.DisplaySize.x = static_cast<float>(rect.right - rect.left);
|
|
||||||
io.DisplaySize.y = static_cast<float>(rect.bottom - rect.top);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
swap_chain->Release();
|
D3DLOCKED_RECT locked_rect;
|
||||||
|
if (dx_tex->LockRect(0, &locked_rect, nullptr, 0) == D3D_OK)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_CopyTextureRegion(tex->UseColors, (ImU32*)tex->GetPixels(), tex->Width * 4, (ImU32*)locked_rect.pBits, (ImU32)locked_rect.Pitch, tex->Width, tex->Height);
|
||||||
|
dx_tex->UnlockRect(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store identifiers
|
||||||
|
tex->SetTexID((ImTextureID)(intptr_t)dx_tex);
|
||||||
|
tex->SetStatus(ImTextureStatus_OK);
|
||||||
|
}
|
||||||
|
else if (tex->Status == ImTextureStatus_WantUpdates)
|
||||||
|
{
|
||||||
|
// Update selected blocks. We only ever write to textures regions which have never been used before!
|
||||||
|
// This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region.
|
||||||
|
LPDIRECT3DTEXTURE9 backend_tex = (LPDIRECT3DTEXTURE9)(intptr_t)tex->TexID;
|
||||||
|
RECT update_rect = { (LONG)tex->UpdateRect.x, (LONG)tex->UpdateRect.y, (LONG)(tex->UpdateRect.x + tex->UpdateRect.w), (LONG)(tex->UpdateRect.y + tex->UpdateRect.h) };
|
||||||
|
D3DLOCKED_RECT locked_rect;
|
||||||
|
if (backend_tex->LockRect(0, &locked_rect, &update_rect, 0) == D3D_OK)
|
||||||
|
for (ImTextureRect& r : tex->Updates)
|
||||||
|
ImGui_ImplDX9_CopyTextureRegion(tex->UseColors, (ImU32*)tex->GetPixelsAt(r.x, r.y), tex->Width * 4,
|
||||||
|
(ImU32*)locked_rect.pBits + (r.x - update_rect.left) + (r.y - update_rect.top) * (locked_rect.Pitch / 4), (int)locked_rect.Pitch, r.w, r.h);
|
||||||
|
backend_tex->UnlockRect(0);
|
||||||
|
tex->SetStatus(ImTextureStatus_OK);
|
||||||
|
}
|
||||||
|
else if (tex->Status == ImTextureStatus_WantDestroy)
|
||||||
|
{
|
||||||
|
if (tex->TexID != ImTextureID_Invalid)
|
||||||
|
if (LPDIRECT3DTEXTURE9 backend_tex = (LPDIRECT3DTEXTURE9)tex->TexID)
|
||||||
|
{
|
||||||
|
IM_ASSERT(tex->TexID == (ImTextureID)(intptr_t)backend_tex);
|
||||||
|
backend_tex->Release();
|
||||||
|
|
||||||
|
// Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
|
||||||
|
tex->SetTexID(ImTextureID_Invalid);
|
||||||
|
}
|
||||||
|
tex->SetStatus(ImTextureStatus_Destroyed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ImGui_ImplDX9_CreateDeviceObjects()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
if (!bd || !bd->pd3dDevice)
|
||||||
|
return false;
|
||||||
|
ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX9_InvalidateDeviceObjects()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
if (!bd || !bd->pd3dDevice)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Destroy all textures
|
||||||
|
for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
|
||||||
|
if (tex->RefCount == 1)
|
||||||
|
{
|
||||||
|
tex->SetStatus(ImTextureStatus_WantDestroy);
|
||||||
|
ImGui_ImplDX9_UpdateTexture(tex);
|
||||||
|
}
|
||||||
|
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
|
||||||
|
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
|
||||||
|
ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_ImplDX9_NewFrame()
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX9_Init()?");
|
||||||
|
// IM_UNUSED(bd);
|
||||||
|
|
||||||
|
// spice ldj
|
||||||
|
{
|
||||||
|
IDirect3DSwapChain9 *swap_chain = nullptr;
|
||||||
|
if (SUCCEEDED(bd->pd3dDevice->GetSwapChain(0, &swap_chain))) {
|
||||||
|
auto &io = ImGui::GetIO();
|
||||||
|
|
||||||
|
D3DPRESENT_PARAMETERS present_params {};
|
||||||
|
|
||||||
|
if (SUCCEEDED(swap_chain->GetPresentParameters(&present_params))) {
|
||||||
|
if (present_params.BackBufferWidth != 0 && present_params.BackBufferHeight != 0) {
|
||||||
|
io.DisplaySize.x = static_cast<float>(present_params.BackBufferWidth);
|
||||||
|
io.DisplaySize.y = static_cast<float>(present_params.BackBufferHeight);
|
||||||
|
} else {
|
||||||
|
RECT rect {};
|
||||||
|
GetClientRect(present_params.hDeviceWindow, &rect);
|
||||||
|
|
||||||
|
io.DisplaySize.x = static_cast<float>(rect.right - rect.left);
|
||||||
|
io.DisplaySize.y = static_cast<float>(rect.bottom - rect.top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swap_chain->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||||
|
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||||
|
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||||
|
//--------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||||
|
struct ImGui_ImplDX9_ViewportData
|
||||||
|
{
|
||||||
|
IDirect3DSwapChain9* SwapChain;
|
||||||
|
D3DPRESENT_PARAMETERS d3dpp;
|
||||||
|
|
||||||
|
ImGui_ImplDX9_ViewportData() { SwapChain = nullptr; ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS)); }
|
||||||
|
~ImGui_ImplDX9_ViewportData() { IM_ASSERT(SwapChain == nullptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ImGui_ImplDX9_CreateWindow(ImGuiViewport* viewport)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
ImGui_ImplDX9_ViewportData* vd = IM_NEW(ImGui_ImplDX9_ViewportData)();
|
||||||
|
viewport->RendererUserData = vd;
|
||||||
|
|
||||||
|
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID).
|
||||||
|
// Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND.
|
||||||
|
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
||||||
|
IM_ASSERT(hwnd != 0);
|
||||||
|
|
||||||
|
ZeroMemory(&vd->d3dpp, sizeof(D3DPRESENT_PARAMETERS));
|
||||||
|
vd->d3dpp.Windowed = TRUE;
|
||||||
|
vd->d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||||
|
vd->d3dpp.BackBufferWidth = (UINT)viewport->Size.x;
|
||||||
|
vd->d3dpp.BackBufferHeight = (UINT)viewport->Size.y;
|
||||||
|
vd->d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
|
||||||
|
vd->d3dpp.hDeviceWindow = hwnd;
|
||||||
|
vd->d3dpp.EnableAutoDepthStencil = FALSE;
|
||||||
|
vd->d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
|
||||||
|
vd->d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Present without vsync
|
||||||
|
|
||||||
|
HRESULT hr = bd->pd3dDevice->CreateAdditionalSwapChain(&vd->d3dpp, &vd->SwapChain); IM_UNUSED(hr);
|
||||||
|
IM_ASSERT(hr == D3D_OK);
|
||||||
|
IM_ASSERT(vd->SwapChain != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplDX9_DestroyWindow(ImGuiViewport* viewport)
|
||||||
|
{
|
||||||
|
// The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it.
|
||||||
|
if (ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData)
|
||||||
|
{
|
||||||
|
if (vd->SwapChain)
|
||||||
|
vd->SwapChain->Release();
|
||||||
|
vd->SwapChain = nullptr;
|
||||||
|
ZeroMemory(&vd->d3dpp, sizeof(D3DPRESENT_PARAMETERS));
|
||||||
|
IM_DELETE(vd);
|
||||||
|
}
|
||||||
|
viewport->RendererUserData = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplDX9_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData;
|
||||||
|
if (vd->SwapChain)
|
||||||
|
{
|
||||||
|
vd->SwapChain->Release();
|
||||||
|
vd->SwapChain = nullptr;
|
||||||
|
vd->d3dpp.BackBufferWidth = (UINT)size.x;
|
||||||
|
vd->d3dpp.BackBufferHeight = (UINT)size.y;
|
||||||
|
HRESULT hr = bd->pd3dDevice->CreateAdditionalSwapChain(&vd->d3dpp, &vd->SwapChain); IM_UNUSED(hr);
|
||||||
|
IM_ASSERT(hr == D3D_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplDX9_RenderWindow(ImGuiViewport* viewport, void*)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||||
|
ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData;
|
||||||
|
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
LPDIRECT3DSURFACE9 render_target = nullptr;
|
||||||
|
LPDIRECT3DSURFACE9 last_render_target = nullptr;
|
||||||
|
LPDIRECT3DSURFACE9 last_depth_stencil = nullptr;
|
||||||
|
vd->SwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &render_target);
|
||||||
|
bd->pd3dDevice->GetRenderTarget(0, &last_render_target);
|
||||||
|
bd->pd3dDevice->GetDepthStencilSurface(&last_depth_stencil);
|
||||||
|
bd->pd3dDevice->SetRenderTarget(0, render_target);
|
||||||
|
bd->pd3dDevice->SetDepthStencilSurface(nullptr);
|
||||||
|
|
||||||
|
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||||
|
{
|
||||||
|
D3DCOLOR clear_col_dx = D3DCOLOR_RGBA((int)(clear_color.x*255.0f), (int)(clear_color.y*255.0f), (int)(clear_color.z*255.0f), (int)(clear_color.w*255.0f));
|
||||||
|
bd->pd3dDevice->Clear(0, nullptr, D3DCLEAR_TARGET, clear_col_dx, 1.0f, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui_ImplDX9_RenderDrawData(viewport->DrawData);
|
||||||
|
|
||||||
|
// Restore render target
|
||||||
|
bd->pd3dDevice->SetRenderTarget(0, last_render_target);
|
||||||
|
bd->pd3dDevice->SetDepthStencilSurface(last_depth_stencil);
|
||||||
|
render_target->Release();
|
||||||
|
last_render_target->Release();
|
||||||
|
if (last_depth_stencil) last_depth_stencil->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplDX9_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||||
|
{
|
||||||
|
ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData;
|
||||||
|
HRESULT hr = vd->SwapChain->Present(nullptr, nullptr, vd->d3dpp.hDeviceWindow, nullptr, 0);
|
||||||
|
// Let main application handle D3DERR_DEVICELOST by resetting the device.
|
||||||
|
IM_ASSERT(SUCCEEDED(hr) || hr == D3DERR_DEVICELOST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplDX9_InitMultiViewportSupport()
|
||||||
|
{
|
||||||
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
|
platform_io.Renderer_CreateWindow = ImGui_ImplDX9_CreateWindow;
|
||||||
|
platform_io.Renderer_DestroyWindow = ImGui_ImplDX9_DestroyWindow;
|
||||||
|
platform_io.Renderer_SetWindowSize = ImGui_ImplDX9_SetWindowSize;
|
||||||
|
platform_io.Renderer_RenderWindow = ImGui_ImplDX9_RenderWindow;
|
||||||
|
platform_io.Renderer_SwapBuffers = ImGui_ImplDX9_SwapBuffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplDX9_ShutdownMultiViewportSupport()
|
||||||
|
{
|
||||||
|
ImGui::DestroyPlatformWindows();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows()
|
||||||
|
{
|
||||||
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
|
for (int i = 1; i < platform_io.Viewports.Size; i++)
|
||||||
|
if (!platform_io.Viewports[i]->RendererUserData)
|
||||||
|
ImGui_ImplDX9_CreateWindow(platform_io.Viewports[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows()
|
||||||
|
{
|
||||||
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
|
for (int i = 1; i < platform_io.Viewports.Size; i++)
|
||||||
|
if (platform_io.Viewports[i]->RendererUserData)
|
||||||
|
ImGui_ImplDX9_DestroyWindow(platform_io.Viewports[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
|
|||||||
+25
-12
@@ -1,25 +1,38 @@
|
|||||||
// dear imgui: Renderer for DirectX9
|
// dear imgui: Renderer Backend for DirectX9
|
||||||
// This needs to be used along with a Platform Binding (e.g. Win32)
|
// This needs to be used along with a Platform Backend (e.g. Win32)
|
||||||
|
|
||||||
// Implemented features:
|
// Implemented features:
|
||||||
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
|
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
|
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||||
|
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||||
|
// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9.
|
||||||
|
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||||
|
|
||||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||||
// https://github.com/ocornut/imgui
|
// Learn about Dear ImGui:
|
||||||
|
// - FAQ https://dearimgui.com/faq
|
||||||
|
// - Getting Started https://dearimgui.com/getting-started
|
||||||
|
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
|
||||||
|
// - Introduction, links and more at the top of imgui.cpp
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "imgui.h" // IMGUI_IMPL_API
|
||||||
#include "imgui.h"
|
#ifndef IMGUI_DISABLE
|
||||||
|
|
||||||
struct IDirect3DDevice9;
|
struct IDirect3DDevice9;
|
||||||
|
|
||||||
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9 *device);
|
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
|
||||||
|
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device);
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
|
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
|
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData *draw_data);
|
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data);
|
||||||
|
|
||||||
// Use if you want to reset your rendering device without losing ImGui state.
|
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||||
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
|
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
|
||||||
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
|
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||||
|
|
||||||
|
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplDX9_UpdateTexture(ImTextureData* tex);
|
||||||
|
|
||||||
|
#endif // #ifndef IMGUI_DISABLE
|
||||||
|
|||||||
+13
-5
@@ -15,7 +15,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
//---- Define assertion handler. Defaults to calling assert().
|
//---- Define assertion handler. Defaults to calling assert().
|
||||||
// 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.
|
// - 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.
|
||||||
|
// - Compiling with NDEBUG will usually strip out assert() to nothing, which is NOT recommended because we use asserts to notify of programmer mistakes.
|
||||||
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||||
#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||||
|
|
||||||
@@ -29,7 +30,6 @@
|
|||||||
|
|
||||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
||||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS.
|
|
||||||
|
|
||||||
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||||
// 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.
|
// 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.
|
||||||
@@ -49,6 +49,7 @@
|
|||||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||||
//#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.
|
//#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.
|
||||||
#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().
|
#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().
|
||||||
|
//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded fonts (ProggyClean/ProggyForever), remove ~9 KB + ~14 KB from output binary. AddFontDefaultXXX() functions will assert.
|
||||||
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||||
|
|
||||||
//---- Enable Test Engine / Automation features.
|
//---- Enable Test Engine / Automation features.
|
||||||
@@ -59,12 +60,15 @@
|
|||||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||||
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
|
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
|
||||||
|
|
||||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
//---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support.
|
||||||
#define IMGUI_USE_BGRA_PACKED_COLOR
|
#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||||
|
|
||||||
//---- Performance optimization for DX9
|
//---- Performance optimization for DX9
|
||||||
#define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
|
#define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
|
||||||
|
|
||||||
|
//---- Use legacy CRC32-adler tables (used before 1.91.6), in order to preserve old .ini data that you cannot afford to invalidate.
|
||||||
|
//#define IMGUI_USE_LEGACY_CRC32_ADLER
|
||||||
|
|
||||||
//---- 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...)
|
//---- 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...)
|
||||||
//#define IMGUI_USE_WCHAR32
|
//#define IMGUI_USE_WCHAR32
|
||||||
|
|
||||||
@@ -83,13 +87,13 @@
|
|||||||
|
|
||||||
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
|
||||||
// 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).
|
// 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).
|
||||||
|
// Note that imgui_freetype.cpp may be used _without_ this define, if you manually call ImFontAtlas::SetFontLoader(). The define is simply a convenience.
|
||||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||||
//#define IMGUI_ENABLE_FREETYPE
|
//#define IMGUI_ENABLE_FREETYPE
|
||||||
|
|
||||||
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
|
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
|
||||||
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||||
// - lunasvg is currently easier to acquire/install, as e.g. it is part of vcpkg.
|
// - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions.
|
||||||
// - plutosvg will support more fonts and may load them faster. It currently requires to be built manually but it is fairly easy. See misc/freetype/README for instructions.
|
|
||||||
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
|
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
|
||||||
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||||
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
|
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
|
||||||
@@ -130,6 +134,10 @@
|
|||||||
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||||
//#define IM_DEBUG_BREAK __debugbreak()
|
//#define IM_DEBUG_BREAK __debugbreak()
|
||||||
|
|
||||||
|
//---- Debug Tools: Enable highlight ID conflicts _before_ hovering items. When io.ConfigDebugHighlightIdConflicts is set.
|
||||||
|
// (THIS WILL SLOW DOWN DEAR IMGUI. Only use occasionally and disable after use)
|
||||||
|
//#define IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS
|
||||||
|
|
||||||
//---- Debug Tools: Enable slower asserts
|
//---- Debug Tools: Enable slower asserts
|
||||||
//#define IMGUI_DEBUG_PARANOID
|
//#define IMGUI_DEBUG_PARANOID
|
||||||
|
|
||||||
|
|||||||
Vendored
+3439
-1953
File diff suppressed because it is too large
Load Diff
Vendored
+1022
-516
File diff suppressed because it is too large
Load Diff
+2825
-2079
File diff suppressed because it is too large
Load Diff
+3216
-1153
File diff suppressed because it is too large
Load Diff
+780
-340
File diff suppressed because it is too large
Load Diff
+352
-176
File diff suppressed because it is too large
Load Diff
+1497
-961
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -315,7 +315,7 @@ static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0
|
|||||||
if (node->y > min_y) {
|
if (node->y > min_y) {
|
||||||
// raise min_y higher.
|
// raise min_y higher.
|
||||||
// we've accounted for all waste up to min_y,
|
// we've accounted for all waste up to min_y,
|
||||||
// but we'll now add more waste for everything we've visted
|
// but we'll now add more waste for everything we've visited
|
||||||
waste_area += visited_width * (node->y - min_y);
|
waste_area += visited_width * (node->y - min_y);
|
||||||
min_y = node->y;
|
min_y = node->y;
|
||||||
// the first time through, visited_width might be reduced
|
// the first time through, visited_width might be reduced
|
||||||
@@ -470,7 +470,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i
|
|||||||
|
|
||||||
// insert the new node into the right starting point, and
|
// insert the new node into the right starting point, and
|
||||||
// let 'cur' point to the remaining nodes needing to be
|
// let 'cur' point to the remaining nodes needing to be
|
||||||
// stiched back in
|
// stitched back in
|
||||||
|
|
||||||
cur = *res.prev_link;
|
cur = *res.prev_link;
|
||||||
if (cur->x < res.x) {
|
if (cur->x < res.x) {
|
||||||
|
|||||||
+113
-55
@@ -5,7 +5,8 @@
|
|||||||
// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783)
|
// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783)
|
||||||
// - Added name to struct or it may be forward declared in our code.
|
// - Added name to struct or it may be forward declared in our code.
|
||||||
// - Added UTF-8 support (see https://github.com/nothings/stb/issues/188 + https://github.com/ocornut/imgui/pull/7925)
|
// - Added UTF-8 support (see https://github.com/nothings/stb/issues/188 + https://github.com/ocornut/imgui/pull/7925)
|
||||||
// Grep for [DEAR IMGUI] to find the changes.
|
// - Changed STB_TEXTEDIT_INSERTCHARS() to return inserted count (instead of 0/1 bool), allowing partial insertion.
|
||||||
|
// Grep for [DEAR IMGUI] to find some changes.
|
||||||
// - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_*
|
// - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_*
|
||||||
|
|
||||||
// stb_textedit.h - v1.14 - public domain - Sean Barrett
|
// stb_textedit.h - v1.14 - public domain - Sean Barrett
|
||||||
@@ -39,6 +40,7 @@
|
|||||||
//
|
//
|
||||||
// VERSION HISTORY
|
// VERSION HISTORY
|
||||||
//
|
//
|
||||||
|
// !!!! (2025-10-23) changed STB_TEXTEDIT_INSERTCHARS() to return inserted count (instead of 0/1 bool), allowing partial insertion.
|
||||||
// 1.14 (2021-07-11) page up/down, various fixes
|
// 1.14 (2021-07-11) page up/down, various fixes
|
||||||
// 1.13 (2019-02-07) fix bug in undo size management
|
// 1.13 (2019-02-07) fix bug in undo size management
|
||||||
// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash
|
// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash
|
||||||
@@ -141,12 +143,14 @@
|
|||||||
// with previous char)
|
// with previous char)
|
||||||
// STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character
|
// STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character
|
||||||
// (return type is int, -1 means not valid to insert)
|
// (return type is int, -1 means not valid to insert)
|
||||||
|
// (not supported if you want to use UTF-8, see below)
|
||||||
// STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based
|
// STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based
|
||||||
// STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize
|
// STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize
|
||||||
// as manually wordwrapping for end-of-line positioning
|
// as manually wordwrapping for end-of-line positioning
|
||||||
//
|
//
|
||||||
// STB_TEXTEDIT_DELETECHARS(obj,i,n) delete n characters starting at i
|
// STB_TEXTEDIT_DELETECHARS(obj,i,n) delete n characters starting at i
|
||||||
// STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n) insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*)
|
// STB_TEXTEDIT_INSERTCHARS(obj,i,c*,n) try to insert n characters at i (pointed to by STB_TEXTEDIT_CHARTYPE*)
|
||||||
|
// returns number of characters actually inserted. [DEAR IMGUI]
|
||||||
//
|
//
|
||||||
// STB_TEXTEDIT_K_SHIFT a power of two that is or'd in to a keyboard input to represent the shift key
|
// STB_TEXTEDIT_K_SHIFT a power of two that is or'd in to a keyboard input to represent the shift key
|
||||||
//
|
//
|
||||||
@@ -178,6 +182,13 @@
|
|||||||
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
|
// STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text
|
||||||
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
|
// STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text
|
||||||
//
|
//
|
||||||
|
// To support UTF-8:
|
||||||
|
//
|
||||||
|
// STB_TEXTEDIT_GETPREVCHARINDEX returns index of previous character
|
||||||
|
// STB_TEXTEDIT_GETNEXTCHARINDEX returns index of next character
|
||||||
|
// Do NOT define STB_TEXTEDIT_KEYTOTEXT.
|
||||||
|
// Instead, call stb_textedit_text() directly for text contents.
|
||||||
|
//
|
||||||
// Keyboard input must be encoded as a single integer value; e.g. a character code
|
// Keyboard input must be encoded as a single integer value; e.g. a character code
|
||||||
// and some bitflags that represent shift states. to simplify the interface, SHIFT must
|
// and some bitflags that represent shift states. to simplify the interface, SHIFT must
|
||||||
// be a bitflag, so we can test the shifted state of cursor movements to allow selection,
|
// be a bitflag, so we can test the shifted state of cursor movements to allow selection,
|
||||||
@@ -250,8 +261,10 @@
|
|||||||
// if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are
|
// if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are
|
||||||
// transformed into text and stb_textedit_text() is automatically called.
|
// transformed into text and stb_textedit_text() is automatically called.
|
||||||
//
|
//
|
||||||
// text: [DEAR IMGUI] added 2024-09
|
// text: (added 2025)
|
||||||
// call this to text inputs sent to the textfield.
|
// call this to directly send text input the textfield, which is required
|
||||||
|
// for UTF-8 support, because stb_textedit_key() + STB_TEXTEDIT_KEYTOTEXT()
|
||||||
|
// cannot infer text length.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// When rendering, you can read the cursor position and selection state from
|
// When rendering, you can read the cursor position and selection state from
|
||||||
@@ -400,6 +413,16 @@ typedef struct
|
|||||||
#define IMSTB_TEXTEDIT_memmove memmove
|
#define IMSTB_TEXTEDIT_memmove memmove
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// [DEAR IMGUI]
|
||||||
|
// Functions must be implemented for UTF8 support
|
||||||
|
// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit.
|
||||||
|
// There is not necessarily a '[DEAR IMGUI]' at the usage sites.
|
||||||
|
#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX
|
||||||
|
#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(OBJ, IDX) ((IDX) - 1)
|
||||||
|
#endif
|
||||||
|
#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX
|
||||||
|
#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(OBJ, IDX) ((IDX) + 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@@ -407,7 +430,7 @@ typedef struct
|
|||||||
//
|
//
|
||||||
|
|
||||||
// traverse the layout to locate the nearest character to a display position
|
// traverse the layout to locate the nearest character to a display position
|
||||||
static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
|
static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y, int* out_side_on_line)
|
||||||
{
|
{
|
||||||
StbTexteditRow r;
|
StbTexteditRow r;
|
||||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||||
@@ -417,6 +440,7 @@ static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
|
|||||||
r.x0 = r.x1 = 0;
|
r.x0 = r.x1 = 0;
|
||||||
r.ymin = r.ymax = 0;
|
r.ymin = r.ymax = 0;
|
||||||
r.num_chars = 0;
|
r.num_chars = 0;
|
||||||
|
*out_side_on_line = 0;
|
||||||
|
|
||||||
// search rows to find one that straddles 'y'
|
// search rows to find one that straddles 'y'
|
||||||
while (i < n) {
|
while (i < n) {
|
||||||
@@ -436,7 +460,10 @@ static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
|
|||||||
|
|
||||||
// below all text, return 'after' last character
|
// below all text, return 'after' last character
|
||||||
if (i >= n)
|
if (i >= n)
|
||||||
|
{
|
||||||
|
*out_side_on_line = 1;
|
||||||
return n;
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
// check if it's before the beginning of the line
|
// check if it's before the beginning of the line
|
||||||
if (x < r.x0)
|
if (x < r.x0)
|
||||||
@@ -449,6 +476,7 @@ static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
|
|||||||
for (k=0; k < r.num_chars; k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k) - i) {
|
for (k=0; k < r.num_chars; k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k) - i) {
|
||||||
float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
|
float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
|
||||||
if (x < prev_x+w) {
|
if (x < prev_x+w) {
|
||||||
|
*out_side_on_line = (k == 0) ? 0 : 1;
|
||||||
if (x < prev_x+w/2)
|
if (x < prev_x+w/2)
|
||||||
return k+i;
|
return k+i;
|
||||||
else
|
else
|
||||||
@@ -460,6 +488,7 @@ static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if the last character is a newline, return that. otherwise return 'after' the last character
|
// if the last character is a newline, return that. otherwise return 'after' the last character
|
||||||
|
*out_side_on_line = 1;
|
||||||
if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE)
|
if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE)
|
||||||
return i+r.num_chars-1;
|
return i+r.num_chars-1;
|
||||||
else
|
else
|
||||||
@@ -471,6 +500,7 @@ static void stb_textedit_click(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *st
|
|||||||
{
|
{
|
||||||
// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
|
// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
|
||||||
// goes off the top or bottom of the text
|
// goes off the top or bottom of the text
|
||||||
|
int side_on_line;
|
||||||
if( state->single_line )
|
if( state->single_line )
|
||||||
{
|
{
|
||||||
StbTexteditRow r;
|
StbTexteditRow r;
|
||||||
@@ -478,16 +508,18 @@ static void stb_textedit_click(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *st
|
|||||||
y = r.ymin;
|
y = r.ymin;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->cursor = stb_text_locate_coord(str, x, y);
|
state->cursor = stb_text_locate_coord(str, x, y, &side_on_line);
|
||||||
state->select_start = state->cursor;
|
state->select_start = state->cursor;
|
||||||
state->select_end = state->cursor;
|
state->select_end = state->cursor;
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
|
str->LastMoveDirectionLR = (ImS8)(side_on_line ? ImGuiDir_Right : ImGuiDir_Left);
|
||||||
}
|
}
|
||||||
|
|
||||||
// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location
|
// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location
|
||||||
static void stb_textedit_drag(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
static void stb_textedit_drag(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
||||||
{
|
{
|
||||||
int p = 0;
|
int p = 0;
|
||||||
|
int side_on_line;
|
||||||
|
|
||||||
// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
|
// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
|
||||||
// goes off the top or bottom of the text
|
// goes off the top or bottom of the text
|
||||||
@@ -501,8 +533,9 @@ static void stb_textedit_drag(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *sta
|
|||||||
if (state->select_start == state->select_end)
|
if (state->select_start == state->select_end)
|
||||||
state->select_start = state->cursor;
|
state->select_start = state->cursor;
|
||||||
|
|
||||||
p = stb_text_locate_coord(str, x, y);
|
p = stb_text_locate_coord(str, x, y, &side_on_line);
|
||||||
state->cursor = state->select_end = p;
|
state->cursor = state->select_end = p;
|
||||||
|
str->LastMoveDirectionLR = (ImS8)(side_on_line ? ImGuiDir_Right : ImGuiDir_Left);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -552,6 +585,8 @@ static void stb_textedit_find_charpos(StbFindState *find, IMSTB_TEXTEDIT_STRING
|
|||||||
STB_TEXTEDIT_LAYOUTROW(&r, str, i);
|
STB_TEXTEDIT_LAYOUTROW(&r, str, i);
|
||||||
if (n < i + r.num_chars)
|
if (n < i + r.num_chars)
|
||||||
break;
|
break;
|
||||||
|
if (str->LastMoveDirectionLR == ImGuiDir_Right && str->Stb->cursor > 0 && str->Stb->cursor == i + r.num_chars && STB_TEXTEDIT_GETCHAR(str, i + r.num_chars - 1) != STB_TEXTEDIT_NEWLINE) // [DEAR IMGUI] Wrapping point handling
|
||||||
|
break;
|
||||||
if (i + r.num_chars == z && z > 0 && STB_TEXTEDIT_GETCHAR(str, z - 1) != STB_TEXTEDIT_NEWLINE) // [DEAR IMGUI] special handling for last line
|
if (i + r.num_chars == z && z > 0 && STB_TEXTEDIT_GETCHAR(str, z - 1) != STB_TEXTEDIT_NEWLINE) // [DEAR IMGUI] special handling for last line
|
||||||
break; // [DEAR IMGUI]
|
break; // [DEAR IMGUI]
|
||||||
prev_start = i;
|
prev_start = i;
|
||||||
@@ -648,15 +683,33 @@ static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str, STB_TexteditSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// [DEAR IMGUI]
|
// [DEAR IMGUI] Extracted this function so we can more easily add support for word-wrapping.
|
||||||
// Functions must be implemented for UTF8 support
|
#ifndef STB_TEXTEDIT_MOVELINESTART
|
||||||
// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit.
|
static int stb_textedit_move_line_start(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int cursor)
|
||||||
// There is not necessarily a '[DEAR IMGUI]' at the usage sites.
|
{
|
||||||
#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX
|
if (state->single_line)
|
||||||
#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx) (idx - 1)
|
return 0;
|
||||||
|
while (cursor > 0) {
|
||||||
|
int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, cursor);
|
||||||
|
if (STB_TEXTEDIT_GETCHAR(str, prev) == STB_TEXTEDIT_NEWLINE)
|
||||||
|
break;
|
||||||
|
cursor = prev;
|
||||||
|
}
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
#define STB_TEXTEDIT_MOVELINESTART stb_textedit_move_line_start
|
||||||
#endif
|
#endif
|
||||||
#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX
|
#ifndef STB_TEXTEDIT_MOVELINEEND
|
||||||
#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx) (idx + 1)
|
static int stb_textedit_move_line_end(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int cursor)
|
||||||
|
{
|
||||||
|
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||||
|
if (state->single_line)
|
||||||
|
return n;
|
||||||
|
while (cursor < n && STB_TEXTEDIT_GETCHAR(str, cursor) != STB_TEXTEDIT_NEWLINE)
|
||||||
|
cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, cursor);
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
#define STB_TEXTEDIT_MOVELINEEND stb_textedit_move_line_end
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef STB_TEXTEDIT_IS_SPACE
|
#ifdef STB_TEXTEDIT_IS_SPACE
|
||||||
@@ -668,9 +721,9 @@ static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx )
|
|||||||
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
|
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
|
||||||
static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c )
|
static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c )
|
||||||
{
|
{
|
||||||
--c; // always move at least one character
|
c = IMSTB_TEXTEDIT_GETPREVCHARINDEX( str, c ); // always move at least one character
|
||||||
while( c >= 0 && !is_word_boundary( str, c ) )
|
while (c >= 0 && !is_word_boundary(str, c))
|
||||||
--c;
|
c = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, c);
|
||||||
|
|
||||||
if( c < 0 )
|
if( c < 0 )
|
||||||
c = 0;
|
c = 0;
|
||||||
@@ -684,9 +737,9 @@ static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c
|
|||||||
static int stb_textedit_move_to_word_next( IMSTB_TEXTEDIT_STRING *str, int c )
|
static int stb_textedit_move_to_word_next( IMSTB_TEXTEDIT_STRING *str, int c )
|
||||||
{
|
{
|
||||||
const int len = STB_TEXTEDIT_STRINGLEN(str);
|
const int len = STB_TEXTEDIT_STRINGLEN(str);
|
||||||
++c; // always move at least one character
|
c = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, c); // always move at least one character
|
||||||
while( c < len && !is_word_boundary( str, c ) )
|
while( c < len && !is_word_boundary( str, c ) )
|
||||||
++c;
|
c = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, c);
|
||||||
|
|
||||||
if( c > len )
|
if( c > len )
|
||||||
c = len;
|
c = len;
|
||||||
@@ -725,7 +778,8 @@ static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditS
|
|||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
stb_textedit_delete_selection(str,state);
|
stb_textedit_delete_selection(str,state);
|
||||||
// try to insert the characters
|
// try to insert the characters
|
||||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) {
|
len = STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len);
|
||||||
|
if (len) {
|
||||||
stb_text_makeundo_insert(state, state->cursor, len);
|
stb_text_makeundo_insert(state, state->cursor, len);
|
||||||
state->cursor += len;
|
state->cursor += len;
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
@@ -739,6 +793,7 @@ static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditS
|
|||||||
#define STB_TEXTEDIT_KEYTYPE int
|
#define STB_TEXTEDIT_KEYTYPE int
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// API key: process text input
|
||||||
// [DEAR IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility.
|
// [DEAR IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility.
|
||||||
static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len)
|
static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len)
|
||||||
{
|
{
|
||||||
@@ -749,14 +804,15 @@ static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* sta
|
|||||||
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
|
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
|
||||||
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
|
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
|
||||||
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
|
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
|
||||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
|
text_len = STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len);
|
||||||
|
if (text_len) {
|
||||||
state->cursor += text_len;
|
state->cursor += text_len;
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
stb_textedit_delete_selection(str, state); // implicitly clamps
|
stb_textedit_delete_selection(str, state); // implicitly clamps
|
||||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
|
text_len = STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len);
|
||||||
|
if (text_len) {
|
||||||
stb_text_makeundo_insert(state, state->cursor, text_len);
|
stb_text_makeundo_insert(state, state->cursor, text_len);
|
||||||
state->cursor += text_len;
|
state->cursor += text_len;
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
@@ -771,6 +827,7 @@ retry:
|
|||||||
switch (key) {
|
switch (key) {
|
||||||
default: {
|
default: {
|
||||||
#ifdef STB_TEXTEDIT_KEYTOTEXT
|
#ifdef STB_TEXTEDIT_KEYTOTEXT
|
||||||
|
// This is not suitable for UTF-8 support.
|
||||||
int c = STB_TEXTEDIT_KEYTOTEXT(key);
|
int c = STB_TEXTEDIT_KEYTOTEXT(key);
|
||||||
if (c > 0) {
|
if (c > 0) {
|
||||||
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
|
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
|
||||||
@@ -911,15 +968,16 @@ retry:
|
|||||||
|
|
||||||
// [DEAR IMGUI]
|
// [DEAR IMGUI]
|
||||||
// going down while being on the last line shouldn't bring us to that line end
|
// going down while being on the last line shouldn't bring us to that line end
|
||||||
if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
|
//if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
|
||||||
break;
|
// break;
|
||||||
|
|
||||||
// now find character position down a row
|
// now find character position down a row
|
||||||
state->cursor = start;
|
state->cursor = start;
|
||||||
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
|
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
|
||||||
x = row.x0;
|
x = row.x0;
|
||||||
for (i=0; i < row.num_chars; ++i) {
|
for (i=0; i < row.num_chars; ) {
|
||||||
float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
|
float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
|
||||||
|
int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
||||||
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||||
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||||
break;
|
break;
|
||||||
@@ -927,10 +985,13 @@ retry:
|
|||||||
x += dx;
|
x += dx;
|
||||||
if (x > goal_x)
|
if (x > goal_x)
|
||||||
break;
|
break;
|
||||||
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
i += next - state->cursor;
|
||||||
|
state->cursor = next;
|
||||||
}
|
}
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
|
|
||||||
|
if (state->cursor == find.first_char + find.length)
|
||||||
|
str->LastMoveDirectionLR = ImGuiDir_Left;
|
||||||
state->has_preferred_x = 1;
|
state->has_preferred_x = 1;
|
||||||
state->preferred_x = goal_x;
|
state->preferred_x = goal_x;
|
||||||
|
|
||||||
@@ -980,8 +1041,9 @@ retry:
|
|||||||
state->cursor = find.prev_first;
|
state->cursor = find.prev_first;
|
||||||
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
|
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
|
||||||
x = row.x0;
|
x = row.x0;
|
||||||
for (i=0; i < row.num_chars; ++i) {
|
for (i=0; i < row.num_chars; ) {
|
||||||
float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
|
float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
|
||||||
|
int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
||||||
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||||
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||||
break;
|
break;
|
||||||
@@ -989,10 +1051,15 @@ retry:
|
|||||||
x += dx;
|
x += dx;
|
||||||
if (x > goal_x)
|
if (x > goal_x)
|
||||||
break;
|
break;
|
||||||
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
i += next - state->cursor;
|
||||||
|
state->cursor = next;
|
||||||
}
|
}
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
|
|
||||||
|
if (state->cursor == find.first_char)
|
||||||
|
str->LastMoveDirectionLR = ImGuiDir_Right;
|
||||||
|
else if (state->cursor == find.prev_first)
|
||||||
|
str->LastMoveDirectionLR = ImGuiDir_Left;
|
||||||
state->has_preferred_x = 1;
|
state->has_preferred_x = 1;
|
||||||
state->preferred_x = goal_x;
|
state->preferred_x = goal_x;
|
||||||
|
|
||||||
@@ -1002,10 +1069,15 @@ retry:
|
|||||||
// go to previous line
|
// go to previous line
|
||||||
// (we need to scan previous line the hard way. maybe we could expose this as a new API function?)
|
// (we need to scan previous line the hard way. maybe we could expose this as a new API function?)
|
||||||
prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
|
prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
|
||||||
while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)
|
while (prev_scan > 0)
|
||||||
--prev_scan;
|
{
|
||||||
|
int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, prev_scan);
|
||||||
|
if (STB_TEXTEDIT_GETCHAR(str, prev) == STB_TEXTEDIT_NEWLINE)
|
||||||
|
break;
|
||||||
|
prev_scan = prev;
|
||||||
|
}
|
||||||
find.first_char = find.prev_first;
|
find.first_char = find.prev_first;
|
||||||
find.prev_first = prev_scan;
|
find.prev_first = STB_TEXTEDIT_MOVELINESTART(str, state, prev_scan);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1079,10 +1151,7 @@ retry:
|
|||||||
case STB_TEXTEDIT_K_LINESTART:
|
case STB_TEXTEDIT_K_LINESTART:
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
stb_textedit_move_to_first(state);
|
stb_textedit_move_to_first(state);
|
||||||
if (state->single_line)
|
state->cursor = STB_TEXTEDIT_MOVELINESTART(str, state, state->cursor);
|
||||||
state->cursor = 0;
|
|
||||||
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
|
|
||||||
--state->cursor;
|
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1090,13 +1159,9 @@ retry:
|
|||||||
case STB_TEXTEDIT_K_LINEEND2:
|
case STB_TEXTEDIT_K_LINEEND2:
|
||||||
#endif
|
#endif
|
||||||
case STB_TEXTEDIT_K_LINEEND: {
|
case STB_TEXTEDIT_K_LINEEND: {
|
||||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
stb_textedit_move_to_first(state);
|
stb_textedit_move_to_last(str, state);
|
||||||
if (state->single_line)
|
state->cursor = STB_TEXTEDIT_MOVELINEEND(str, state, state->cursor);
|
||||||
state->cursor = n;
|
|
||||||
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
|
|
||||||
++state->cursor;
|
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1107,10 +1172,7 @@ retry:
|
|||||||
case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
|
case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
stb_textedit_prep_selection_at_cursor(state);
|
stb_textedit_prep_selection_at_cursor(state);
|
||||||
if (state->single_line)
|
state->cursor = STB_TEXTEDIT_MOVELINESTART(str, state, state->cursor);
|
||||||
state->cursor = 0;
|
|
||||||
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
|
|
||||||
--state->cursor;
|
|
||||||
state->select_end = state->cursor;
|
state->select_end = state->cursor;
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
break;
|
break;
|
||||||
@@ -1119,13 +1181,9 @@ retry:
|
|||||||
case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
|
case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
|
||||||
#endif
|
#endif
|
||||||
case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
|
case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
|
||||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
stb_textedit_prep_selection_at_cursor(state);
|
stb_textedit_prep_selection_at_cursor(state);
|
||||||
if (state->single_line)
|
state->cursor = STB_TEXTEDIT_MOVELINEEND(str, state, state->cursor);
|
||||||
state->cursor = n;
|
|
||||||
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
|
|
||||||
++state->cursor;
|
|
||||||
state->select_end = state->cursor;
|
state->select_end = state->cursor;
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
break;
|
break;
|
||||||
@@ -1300,7 +1358,7 @@ static void stb_text_undo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
|||||||
// check type of recorded action:
|
// check type of recorded action:
|
||||||
if (u.insert_length) {
|
if (u.insert_length) {
|
||||||
// easy case: was a deletion, so we need to insert n characters
|
// easy case: was a deletion, so we need to insert n characters
|
||||||
STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length);
|
u.insert_length = STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length);
|
||||||
s->undo_char_point -= u.insert_length;
|
s->undo_char_point -= u.insert_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1351,7 +1409,7 @@ static void stb_text_redo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
|||||||
|
|
||||||
if (r.insert_length) {
|
if (r.insert_length) {
|
||||||
// easy case: need to insert n characters
|
// easy case: need to insert n characters
|
||||||
STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length);
|
r.insert_length = STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length);
|
||||||
s->redo_char_point += r.insert_length;
|
s->redo_char_point += r.insert_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -886,7 +886,7 @@ STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, fl
|
|||||||
// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
|
// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
|
||||||
|
|
||||||
STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
|
STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
|
||||||
// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel
|
// the same as stbtt_GetCodepointBitmap, but you can specify a subpixel
|
||||||
// shift for the character
|
// shift for the character
|
||||||
|
|
||||||
STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);
|
STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);
|
||||||
@@ -4516,8 +4516,8 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
|
|||||||
q2[0] = (float)x2;
|
q2[0] = (float)x2;
|
||||||
q2[1] = (float)y2;
|
q2[1] = (float)y2;
|
||||||
if (equal(q0,q1) || equal(q1,q2)) {
|
if (equal(q0,q1) || equal(q1,q2)) {
|
||||||
x0 = (int)verts[i-1].x;
|
x0 = (int)verts[i-1].x; //-V1048
|
||||||
y0 = (int)verts[i-1].y;
|
y0 = (int)verts[i-1].y; //-V1048
|
||||||
x1 = (int)verts[i ].x;
|
x1 = (int)verts[i ].x;
|
||||||
y1 = (int)verts[i ].y;
|
y1 = (int)verts[i ].y;
|
||||||
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
|
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
|
||||||
|
|||||||
@@ -501,7 +501,7 @@ void paint_draw_cmd(
|
|||||||
const SwOptions& options,
|
const SwOptions& options,
|
||||||
Stats* stats)
|
Stats* stats)
|
||||||
{
|
{
|
||||||
const auto texture = reinterpret_cast<const Texture*>(pcmd.TextureId);
|
const auto texture = reinterpret_cast<const Texture*>(pcmd.GetTexID());
|
||||||
const auto offset = pcmd.IdxOffset;
|
const auto offset = pcmd.IdxOffset;
|
||||||
|
|
||||||
// ImGui uses the first pixel for "white".
|
// ImGui uses the first pixel for "white".
|
||||||
@@ -678,7 +678,7 @@ void bind_imgui_painting()
|
|||||||
int font_width, font_height;
|
int font_width, font_height;
|
||||||
io.Fonts->GetTexDataAsAlpha8(&tex_data, &font_width, &font_height);
|
io.Fonts->GetTexDataAsAlpha8(&tex_data, &font_width, &font_height);
|
||||||
const auto texture = new Texture{tex_data, font_width, font_height};
|
const auto texture = new Texture{tex_data, font_width, font_height};
|
||||||
io.Fonts->TexID = reinterpret_cast<ImTextureID>(texture);
|
io.Fonts->SetTexID(reinterpret_cast<ImTextureID>(texture));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Stats s_stats; // TODO: pass as an argument?
|
static Stats s_stats; // TODO: pass as an argument?
|
||||||
@@ -700,7 +700,7 @@ void paint_imgui(uint32_t* pixels, int width_pixels, int height_pixels, const Sw
|
|||||||
void unbind_imgui_painting()
|
void unbind_imgui_painting()
|
||||||
{
|
{
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
delete reinterpret_cast<Texture*>(io.Fonts->TexID);
|
delete reinterpret_cast<Texture*>(io.Fonts->TexID.GetTexID());
|
||||||
io.Fonts = nullptr;
|
io.Fonts = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ void overlay::SpiceOverlay::init() {
|
|||||||
if (UI_SCALE_PERCENT.has_value()) {
|
if (UI_SCALE_PERCENT.has_value()) {
|
||||||
const auto scale = static_cast<float>(UI_SCALE_PERCENT.value()) / 100.f;
|
const auto scale = static_cast<float>(UI_SCALE_PERCENT.value()) / 100.f;
|
||||||
ImGui::GetStyle().ScaleAllSizes(scale);
|
ImGui::GetStyle().ScaleAllSizes(scale);
|
||||||
ImGui::GetIO().FontGlobalScale = scale;
|
ImGui::GetStyle().FontScaleMain = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
// based on CrimsonVesuvius theme from
|
// based on CrimsonVesuvius theme from
|
||||||
@@ -283,7 +283,7 @@ void overlay::SpiceOverlay::init() {
|
|||||||
io.FontAllowUserScaling = true;
|
io.FontAllowUserScaling = true;
|
||||||
|
|
||||||
// add default font
|
// add default font
|
||||||
io.Fonts->AddFontDefault();
|
io.Fonts->AddFontDefaultBitmap();
|
||||||
|
|
||||||
// add fallback fonts for missing glyph ranges
|
// add fallback fonts for missing glyph ranges
|
||||||
ImFontConfig config {};
|
ImFontConfig config {};
|
||||||
|
|||||||
@@ -2196,9 +2196,8 @@ namespace overlay::windows {
|
|||||||
auto analog_device_changed = ImGui::Combo(
|
auto analog_device_changed = ImGui::Combo(
|
||||||
"Device",
|
"Device",
|
||||||
&this->analogs_devices_selected,
|
&this->analogs_devices_selected,
|
||||||
[](void* data, int i, const char **item) {
|
[](void* data, int i) {
|
||||||
*item = ((std::vector<rawinput::Device*>*) data)->at(i)->desc.c_str();
|
return ((std::vector<rawinput::Device*>*) data)->at(i)->desc.c_str();
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
&this->analogs_devices, (int) this->analogs_devices.size());
|
&this->analogs_devices, (int) this->analogs_devices.size());
|
||||||
|
|
||||||
@@ -2317,9 +2316,8 @@ namespace overlay::windows {
|
|||||||
// controls
|
// controls
|
||||||
ImGui::Combo("Control",
|
ImGui::Combo("Control",
|
||||||
&this->analogs_devices_control_selected,
|
&this->analogs_devices_control_selected,
|
||||||
[](void* data, int i, const char **item) {
|
[](void* data, int i) {
|
||||||
*item = ((std::vector<std::string>*) data)->at(i).c_str();
|
return ((std::vector<std::string>*) data)->at(i).c_str();
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
&control_names, control_names.size());
|
&control_names, control_names.size());
|
||||||
|
|
||||||
@@ -2957,9 +2955,8 @@ namespace overlay::windows {
|
|||||||
bool control_changed = false;
|
bool control_changed = false;
|
||||||
if (ImGui::Combo("Device",
|
if (ImGui::Combo("Device",
|
||||||
&this->lights_devices_selected,
|
&this->lights_devices_selected,
|
||||||
[] (void* data, int i, const char **item) {
|
[] (void* data, int i) {
|
||||||
*item = ((std::vector<rawinput::Device*>*) data)->at(i)->desc.c_str();
|
return ((std::vector<rawinput::Device*>*) data)->at(i)->desc.c_str();
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
&this->lights_devices, (int) this->lights_devices.size())) {
|
&this->lights_devices, (int) this->lights_devices.size())) {
|
||||||
this->lights_devices_control_selected = 0;
|
this->lights_devices_control_selected = 0;
|
||||||
@@ -3054,9 +3051,8 @@ namespace overlay::windows {
|
|||||||
// controls
|
// controls
|
||||||
if (ImGui::Combo("Light Control",
|
if (ImGui::Combo("Light Control",
|
||||||
&this->lights_devices_control_selected,
|
&this->lights_devices_control_selected,
|
||||||
[] (void* data, int i, const char **item) {
|
[] (void* data, int i) {
|
||||||
*item = ((std::vector<std::string> *) data)->at(i).c_str();
|
return ((std::vector<std::string> *) data)->at(i).c_str();
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
&control_names, control_names.size())) {
|
&control_names, control_names.size())) {
|
||||||
control_changed = true;
|
control_changed = true;
|
||||||
@@ -3137,10 +3133,9 @@ namespace overlay::windows {
|
|||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
bool device_changed = ImGui::Combo("##AutoMatchDevice",
|
bool device_changed = ImGui::Combo("##AutoMatchDevice",
|
||||||
&this->auto_match_device_selected,
|
&this->auto_match_device_selected,
|
||||||
[] (void* data, int i, const char **item) {
|
[] (void* data, int i) {
|
||||||
auto *devs = (std::vector<rawinput::Device*>*) data;
|
auto *devs = (std::vector<rawinput::Device*>*) data;
|
||||||
*item = devs->at(i)->desc.c_str();
|
return devs->at(i)->desc.c_str();
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
&this->auto_match_devices,
|
&this->auto_match_devices,
|
||||||
(int) this->auto_match_devices.size());
|
(int) this->auto_match_devices.size());
|
||||||
|
|||||||
Reference in New Issue
Block a user