Merge pull request #22287 from hrydgard/imgui-1.92

Update the Dear ImGui dependency to 1.92
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-09-14 11:06:50 -06:00
commit fa284ad087
22 files changed
+15067 -7596

No files matched your search

+23
View File
@@ -112,6 +112,7 @@ public:
void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;
void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) override;
void UpdateTextureRegions(Texture *texture, int level, const TextureRegionUpdate *regions, int numRegions) override;
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, Aspect aspects, const char *tag) override;
bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, Aspect aspects, FBBlitFilter filter, const char *tag) override;
@@ -890,6 +891,7 @@ public:
bool CreateStagingTexture(ID3D11Device *device);
void UpdateTextureLevels(ID3D11DeviceContext *context, ID3D11Device *device, Texture *texture, const uint8_t *const *data, TextureCallback initDataCallback, int numLevels);
void UpdateTextureRegions(ID3D11DeviceContext *context, int level, const TextureRegionUpdate *regions, int numRegions);
ID3D11ShaderResourceView *View() { return view_.Get(); }
@@ -1051,6 +1053,22 @@ void D3D11Texture::UpdateTextureLevels(ID3D11DeviceContext *context, ID3D11Devic
stagingTex_.Reset();
}
void D3D11Texture::UpdateTextureRegions(ID3D11DeviceContext *context, int level, const TextureRegionUpdate *regions, int numRegions) {
const UINT pixelSize = (UINT)DataFormatSizeInBytes(format_);
for (int i = 0; i < numRegions; i++) {
const TextureRegionUpdate &region = regions[i];
D3D11_BOX box{};
box.left = region.x;
box.top = region.y;
box.front = 0;
box.right = region.x + region.w;
box.bottom = region.y + region.h;
box.back = 1;
const UINT srcStride = region.byteStride ? (UINT)region.byteStride : region.w * pixelSize;
context->UpdateSubresource(tex_.Get(), level, &box, region.data, srcStride, 0);
}
}
Texture *D3D11DrawContext::CreateTexture(const TextureDesc &desc) {
if (!(GetDataFormatSupport(desc.format) & FMT_TEXTURE)) {
// D3D11 does not support this format as a texture format.
@@ -1077,6 +1095,11 @@ void D3D11DrawContext::UpdateTextureLevels(Texture *texture, const uint8_t **dat
tex->UpdateTextureLevels(context_.Get(), device_.Get(), texture, data, initDataCallback, numLevels);
}
void D3D11DrawContext::UpdateTextureRegions(Texture *texture, int level, const TextureRegionUpdate *regions, int numRegions) {
D3D11Texture *tex = (D3D11Texture *)texture;
tex->UpdateTextureRegions(context_.Get(), level, regions, numRegions);
}
ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const char *tag) {
if (language != ShaderLanguage::HLSL_D3D11) {
ERROR_LOG(Log::G3D, "Unsupported shader language");
+34
View File
@@ -130,6 +130,15 @@ void GLQueueRunner::RunInitSteps(const FastVec<GLRInitStep> &steps, bool skipGLC
}
break;
}
case GLRInitStepType::TEXTURE_SUBIMAGE:
{
if (step.texture_subimage.allocType == GLRAllocType::ALIGNED) {
FreeAlignedMemory(step.texture_subimage.data);
} else if (step.texture_subimage.allocType == GLRAllocType::NEW) {
delete[] step.texture_subimage.data;
}
break;
}
case GLRInitStepType::CREATE_PROGRAM:
{
WARN_LOG(Log::G3D, "CREATE_PROGRAM found with skipGLCalls, not good");
@@ -400,6 +409,31 @@ void GLQueueRunner::RunInitSteps(const FastVec<GLRInitStep> &steps, bool skipGLC
CHECK_GL_ERROR_IF_DEBUG();
break;
}
case GLRInitStepType::TEXTURE_SUBIMAGE:
{
GLRTexture *tex = step.texture_subimage.texture;
CHECK_GL_ERROR_IF_DEBUG();
if (boundTexture != tex->texture) {
glBindTexture(tex->target, tex->texture);
boundTexture = tex->texture;
}
_assert_(tex->target == GL_TEXTURE_2D);
_assert_(step.texture_subimage.data != nullptr);
GLenum internalFormat, format, type;
int alignment;
Thin3DFormatToGLFormatAndType(step.texture_subimage.format, internalFormat, format, type, alignment);
glTexSubImage2D(tex->target, step.texture_subimage.level,
step.texture_subimage.x, step.texture_subimage.y,
step.texture_subimage.width, step.texture_subimage.height,
format, type, step.texture_subimage.data);
if (step.texture_subimage.allocType == GLRAllocType::ALIGNED) {
FreeAlignedMemory(step.texture_subimage.data);
} else if (step.texture_subimage.allocType == GLRAllocType::NEW) {
delete[] step.texture_subimage.data;
}
CHECK_GL_ERROR_IF_DEBUG();
break;
}
case GLRInitStepType::TEXTURE_FINALIZE:
{
CHECK_GL_ERROR_IF_DEBUG();
+12
View File
@@ -214,6 +214,7 @@ enum class GLRInitStepType : uint8_t {
CREATE_FRAMEBUFFER,
TEXTURE_IMAGE,
TEXTURE_SUBIMAGE,
TEXTURE_FINALIZE,
BUFFER_SUBDATA,
};
@@ -266,6 +267,17 @@ struct GLRInitStep {
bool linearFilter;
uint8_t *data; // owned, delete[]-d
} texture_image;
struct {
GLRTexture *texture;
Draw::DataFormat format;
int level;
uint16_t x;
uint16_t y;
uint16_t width;
uint16_t height;
GLRAllocType allocType;
uint8_t *data; // owned, delete[]-d
} texture_subimage;
struct {
GLRTexture *texture;
int loadedLevels;
+17
View File
@@ -444,6 +444,23 @@ public:
step.texture_image.linearFilter = linearFilter;
}
// Takes ownership over the data pointer and delete[]-s it. Runs as an init step, so unlike
// TextureSubImage below, it doesn't have to happen inside a render pass.
void TextureSubImageInit(GLRTexture *texture, int level, int x, int y, int width, int height, Draw::DataFormat format, uint8_t *data, GLRAllocType allocType = GLRAllocType::NEW) {
std::lock_guard<std::mutex> lock(initStepsMutex_);
GLRInitStep &step = initSteps_.push_uninitialized();
step.stepType = GLRInitStepType::TEXTURE_SUBIMAGE;
step.texture_subimage.texture = texture;
step.texture_subimage.data = data;
step.texture_subimage.format = format;
step.texture_subimage.level = level;
step.texture_subimage.x = x;
step.texture_subimage.y = y;
step.texture_subimage.width = width;
step.texture_subimage.height = height;
step.texture_subimage.allocType = allocType;
}
void TextureSubImage(int slot, GLRTexture *texture, int level, int x, int y, int width, int height, Draw::DataFormat format, uint8_t *data, GLRAllocType allocType = GLRAllocType::NEW) {
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
GLRRenderData _data(GLRRenderCommand::TEXTURE_SUBIMAGE);
+24
View File
@@ -377,6 +377,7 @@ public:
void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;
void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) override;
void UpdateTextureRegions(Texture *texture, int level, const TextureRegionUpdate *regions, int numRegions) override;
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, Aspect aspects, const char *tag) override;
bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, Aspect aspects, FBBlitFilter filter, const char *tag) override;
@@ -860,6 +861,7 @@ public:
}
void UpdateTextureLevels(GLRenderManager *render, const uint8_t *const *data, int numLevels, TextureCallback initDataCallback);
void UpdateTextureRegions(GLRenderManager *render, int level, const TextureRegionUpdate *regions, int numRegions);
private:
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data, TextureCallback initDataCallback);
@@ -920,6 +922,23 @@ void OpenGLTexture::UpdateTextureLevels(GLRenderManager *render, const uint8_t *
render->FinalizeTexture(tex_, mipLevels_, genMips);
}
void OpenGLTexture::UpdateTextureRegions(GLRenderManager *render, int level, const TextureRegionUpdate *regions, int numRegions) {
const int pixelSize = (int)DataFormatSizeInBytes(format_);
for (int i = 0; i < numRegions; i++) {
const TextureRegionUpdate &region = regions[i];
_dbg_assert_(region.w > 0 && region.h > 0);
const int srcStride = region.byteStride ? region.byteStride : region.w * pixelSize;
const int dstStride = region.w * pixelSize;
// glTexSubImage2D could take the stride through GL_UNPACK_ROW_LENGTH, but that's not in GLES2,
// and the queue runner owns the data anyway, so just pack it here.
uint8_t *texData = new uint8_t[(size_t)dstStride * region.h];
for (int y = 0; y < region.h; y++) {
memcpy(texData + (size_t)dstStride * y, region.data + (size_t)srcStride * y, dstStride);
}
render->TextureSubImageInit(tex_, level, region.x, region.y, region.w, region.h, format_, texData);
}
}
OpenGLTexture::~OpenGLTexture() {
if (tex_) {
render_->DeleteTexture(tex_);
@@ -1045,6 +1064,11 @@ void OpenGLContext::UpdateTextureLevels(Texture *texture, const uint8_t **data,
tex->UpdateTextureLevels(&renderManager_, data, numLevels, initDataCallback);
}
void OpenGLContext::UpdateTextureRegions(Texture *texture, int level, const TextureRegionUpdate *regions, int numRegions) {
OpenGLTexture *tex = (OpenGLTexture *)texture;
tex->UpdateTextureRegions(&renderManager_, level, regions, numRegions);
}
DepthStencilState *OpenGLContext::CreateDepthStencilState(const DepthStencilStateDesc &desc) {
OpenGLDepthStencilState *ds = new OpenGLDepthStencilState();
ds->depthTestEnabled = desc.depthTestEnabled;
+8 -4
View File
@@ -170,15 +170,19 @@ bool VulkanTexture::CreateDirect(int w, int h, int depth, int numMips, VkFormat
}
void VulkanTexture::CopyBufferToMipLevel(VkCommandBuffer cmd, TextureCopyBatch *copyBatch, int mip, int mipWidth, int mipHeight, int depthLayer, VkBuffer buffer, uint32_t offset, size_t rowLength) {
CopyBufferToMipLevelRegion(cmd, copyBatch, mip, 0, 0, mipWidth, mipHeight, depthLayer, buffer, offset, rowLength);
}
void VulkanTexture::CopyBufferToMipLevelRegion(VkCommandBuffer cmd, TextureCopyBatch *copyBatch, int mip, int x, int y, int w, int h, int depthLayer, VkBuffer buffer, uint32_t offset, size_t rowLength) {
VkBufferImageCopy &copy_region = copyBatch->copies.push_uninitialized();
copy_region.bufferOffset = offset;
copy_region.bufferRowLength = (uint32_t)rowLength;
copy_region.bufferImageHeight = 0; // 2D
copy_region.imageOffset.x = 0;
copy_region.imageOffset.y = 0;
copy_region.imageOffset.x = x;
copy_region.imageOffset.y = y;
copy_region.imageOffset.z = depthLayer;
copy_region.imageExtent.width = mipWidth;
copy_region.imageExtent.height = mipHeight;
copy_region.imageExtent.width = w;
copy_region.imageExtent.height = h;
copy_region.imageExtent.depth = 1;
copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy_region.imageSubresource.mipLevel = mip;
+2
View File
@@ -36,6 +36,8 @@ public:
// Can also be used to copy individual levels of a 3D texture.
// If possible, will just add to the batch instead of submitting a copy.
void CopyBufferToMipLevel(VkCommandBuffer cmd, TextureCopyBatch *copyBatch, int mip, int mipWidth, int mipHeight, int depthLayer, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels
// Same, but only covers a rectangle of the mip level instead of all of it.
void CopyBufferToMipLevelRegion(VkCommandBuffer cmd, TextureCopyBatch *copyBatch, int mip, int x, int y, int w, int h, int depthLayer, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels
void FinishCopyBatch(VkCommandBuffer cmd, TextureCopyBatch *copyBatch);
void GenerateMips(VkCommandBuffer cmd, int firstMipToGenerate, bool fromCompute);
+50
View File
@@ -332,6 +332,7 @@ public:
}
bool Create(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, VulkanPushPool *pushBuffer, const TextureDesc &desc);
void Update(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, VulkanPushPool *pushBuffer, const uint8_t *const *data, TextureCallback callback, int numLevels);
void UpdateRegions(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, VulkanPushPool *pushBuffer, int level, const TextureRegionUpdate *regions, int numRegions);
~VKTexture() {
Destroy();
@@ -449,6 +450,7 @@ public:
void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;
void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) override;
void UpdateTextureRegions(Texture *texture, int level, const TextureRegionUpdate *regions, int numRegions) override;
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, Aspect aspects, const char *tag) override;
bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, Aspect aspects, FBBlitFilter filter, const char *tag) override;
@@ -860,6 +862,37 @@ void VKTexture::Update(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, Vu
vkTex_->RestoreAfterTransferDst(numLevels, postBarriers);
}
void VKTexture::UpdateRegions(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, VulkanPushPool *pushBuffer, int level, const TextureRegionUpdate *regions, int numRegions) {
VkFormat vulkanFormat = DataFormatToVulkan(format_);
int bpp = GetBpp(vulkanFormat);
_dbg_assert_(bpp != 0);
const int bytesPerPixel = bpp / 8;
// Only the level we're writing needs to change layout, the others stay sampleable.
vkTex_->PrepareForTransferDst(cmd, level + 1);
TextureCopyBatch batch;
batch.reserve(numRegions);
for (int i = 0; i < numRegions; i++) {
const TextureRegionUpdate &region = regions[i];
_dbg_assert_(region.w > 0 && region.h > 0);
const int srcStride = region.byteStride ? region.byteStride : region.w * bytesPerPixel;
const int dstStride = region.w * bytesPerPixel;
uint32_t offset;
VkBuffer buf;
uint8_t *dest = (uint8_t *)pushBuffer->Allocate((size_t)dstStride * region.h, 16, &buf, &offset);
_assert_(dest != nullptr);
for (int y = 0; y < region.h; y++) {
memcpy(dest + (size_t)dstStride * y, region.data + (size_t)srcStride * y, dstStride);
}
vkTex_->CopyBufferToMipLevelRegion(cmd, &batch, level, region.x, region.y, region.w, region.h, 0, buf, offset, region.w);
}
vkTex_->FinishCopyBatch(cmd, &batch);
vkTex_->RestoreAfterTransferDst(level + 1, postBarriers);
}
void VKTexture::UpdateInternal(VkCommandBuffer cmd, VulkanPushPool *pushBuffer, const uint8_t * const *data, TextureCallback initDataCallback, int numLevels) {
int w = width_;
int h = height_;
@@ -1401,6 +1434,23 @@ void VKContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, Text
tex->Update(initCmd, &renderManager_.PostInitBarrier(), push_, data, initDataCallback, numLevels);
}
void VKContext::UpdateTextureRegions(Texture *texture, int level, const TextureRegionUpdate *regions, int numRegions) {
if (numRegions <= 0) {
return;
}
VkCommandBuffer initCmd = renderManager_.GetInitCmd();
if (!push_ || !initCmd) {
// Too early! Fail.
ERROR_LOG(Log::G3D, "Can't update textures before the first frame has started.");
return;
}
VKTexture *tex = (VKTexture *)texture;
_dbg_assert_(level < tex->NumLevels());
tex->UpdateRegions(initCmd, &renderManager_.PostInitBarrier(), push_, level, regions, numRegions);
}
static inline void CopySide(VkStencilOpState &dest, const StencilSetup &src) {
dest.compareOp = compToVK[(int)src.compareOp];
dest.failOp = stencilOpToVK[(int)src.failOp];
+16
View File
@@ -669,6 +669,18 @@ struct TextureDesc {
TextureCallback initDataCallback;
};
// A rectangular piece of a single mip level, for DrawContext::UpdateTextureRegions.
struct TextureRegionUpdate {
int x;
int y;
int w;
int h;
// Points at the top left pixel of the region. Does not take ownership.
const uint8_t *data;
// Distance between rows in data, in bytes. 0 means tightly packed, that is w pixels.
int byteStride;
};
enum class RPAction {
KEEP = 0,
CLEAR = 1,
@@ -790,6 +802,10 @@ public:
// while in Vulkan this might cause various strangeness like image corruption.
virtual void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) = 0;
// Replaces a set of rectangular regions of a single mip level, leaving the rest of the texture alone.
// Same in-flight caveat as UpdateTextureLevels. The regions must not overlap each other.
virtual void UpdateTextureRegions(Texture *texture, int level, const TextureRegionUpdate *regions, int numRegions) = 0;
virtual void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, Aspect aspects, const char *tag) = 0;
virtual bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, Aspect aspects, FBBlitFilter filter, const char *tag) = 0;
+2 -2
View File
@@ -375,8 +375,8 @@ void runImDebugger(Draw::DrawContext *draw) {
{node->Pos.x + node->Size.x, node->Pos.y + node->Size.y},
IM_COL32(255, 255, 255, 90),
0.f,
ImDrawFlags_None,
1.f
1.f,
ImDrawFlags_None
);
}
imDebugger_->Frame(currentDebugMIPS, gpu, draw);
+29 -10
View File
@@ -15,20 +15,21 @@
#pragma once
//---- 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) ((void)(_EXPR)) // Disable asserts
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
//#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport )
// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export
//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import
//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden
//---- 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_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.
// 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.
@@ -42,21 +43,32 @@
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_TIME_FUNCTIONS // Don't setup default platform_io.Platform_SessionDate value using time(), localtime_r().
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
//#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_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_DEFAULT_FONT_BITMAP // Disable default embedded bitmap font (ProggyClean). Remove ~9 KB from output binary. AddFontDefaultBitmap() will assert.
//#define IMGUI_DISABLE_DEFAULT_FONT_VECTOR // Disable default embedded vector font (ProggyForever), Remove ~14 KB from output binary. AddFontDefaultVector() will assert.
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
//---- Enable Test Engine / Automation features.
//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_imconfig.h", see Test Engine for details.
//---- Include imgui_user.h at the end of imgui.h as a convenience
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
//#define IMGUI_INCLUDE_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
//---- 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...)
//#define IMGUI_USE_WCHAR32
@@ -75,13 +87,16 @@
//---- 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).
// 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'.
//#define IMGUI_ENABLE_FREETYPE
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
// Only works in combination with IMGUI_ENABLE_FREETYPE.
// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
// - 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.
// - 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)
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
//---- Use stb_truetype to build and rasterize the font atlas (default)
@@ -119,6 +134,10 @@
//#define IM_DEBUG_BREAK IM_ASSERT(0)
//#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
//#define IMGUI_DEBUG_PARANOID
+3777 -1895
View File
File diff suppressed because it is too large. Load diff
+1118 -523
View File
File diff suppressed because it is too large. Load diff
+3043 -2104
View File
File diff suppressed because it is too large. Load diff
+3127 -1114
View File
File diff suppressed because it is too large. Load diff
+132 -35
View File
@@ -33,11 +33,16 @@ struct RegisteredTexture {
struct BackendData {
Draw::SamplerState *fontSampler = nullptr;
Draw::Texture *fontImage = nullptr;
Draw::Pipeline *pipelines[(int)ImGuiPipeline::Count]{};
std::vector<RegisteredTexture> tempTextures;
// Textures imgui asked us to create (since 1.92 the font atlas is one of these, and there can
// be more than one as it grows). Indexed by ImTextureID - 1, so entries can go null on destroy
// without shifting the rest. Slots are reused.
std::vector<Draw::Texture *> imguiTextures;
};
// ImTextureID layout: 0 is ImTextureID_Invalid, 1..TEX_ID_OFFSET-1 index imguiTextures, and
// TEX_ID_OFFSET and up index the per-frame tempTextures.
#define TEX_ID_OFFSET 256
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
@@ -47,6 +52,91 @@ static BackendData *ImGui_ImplThin3d_GetBackendData() {
return ImGui::GetCurrentContext() ? (BackendData *)ImGui::GetIO().BackendRendererUserData : nullptr;
}
// Since 1.92 imgui owns its textures (the font atlas, and any more it needs as glyphs get
// rasterized on demand) and asks the backend to create, refresh and destroy them. An update comes
// with a list of dirty rectangles, which we hand to thin3d as sub-rectangle uploads so a single new
// glyph doesn't cost a re-upload of the whole atlas.
static void ImGui_ImplThin3d_UpdateTexture(Draw::DrawContext *draw, ImTextureData *tex) {
BackendData *bd = ImGui_ImplThin3d_GetBackendData();
switch (tex->Status) {
case ImTextureStatus_WantCreate:
{
_dbg_assert_(tex->Format == ImTextureFormat_RGBA32 && tex->BytesPerPixel == 4);
Draw::TextureDesc desc{};
desc.width = tex->Width;
desc.height = tex->Height;
desc.mipLevels = 1;
desc.format = Draw::DataFormat::R8G8B8A8_UNORM;
desc.type = Draw::TextureType::LINEAR2D;
desc.swizzle = Draw::TextureSwizzle::DEFAULT;
desc.depth = 1;
desc.tag = "imgui-texture";
desc.initData.push_back((const uint8_t *)tex->GetPixels());
Draw::Texture *created = draw->CreateTexture(desc);
if (!created) {
ERROR_LOG(Log::System, "imgui: failed to create a %dx%d texture", tex->Width, tex->Height);
return;
}
// Reuse a slot freed by an earlier destroy, so a long session doesn't grow the vector.
size_t index = 0;
while (index < bd->imguiTextures.size() && bd->imguiTextures[index]) {
index++;
}
if (index == bd->imguiTextures.size()) {
bd->imguiTextures.push_back(created);
} else {
bd->imguiTextures[index] = created;
}
_dbg_assert_(index + 1 < TEX_ID_OFFSET);
tex->SetTexID((ImTextureID)(index + 1));
tex->SetStatus(ImTextureStatus_OK);
break;
}
case ImTextureStatus_WantUpdates:
{
const size_t index = (size_t)tex->GetTexID() - 1;
if (index >= bd->imguiTextures.size() || !bd->imguiTextures[index]) {
ERROR_LOG(Log::System, "imgui: asked to update texture %d, which we don't have", (int)tex->GetTexID());
return;
}
std::vector<Draw::TextureRegionUpdate> regions;
regions.reserve(tex->Updates.Size);
for (const ImTextureRect &rect : tex->Updates) {
Draw::TextureRegionUpdate region;
region.x = rect.x;
region.y = rect.y;
region.w = rect.w;
region.h = rect.h;
region.data = (const uint8_t *)tex->GetPixelsAt(rect.x, rect.y);
region.byteStride = tex->GetPitch();
regions.push_back(region);
}
if (!regions.empty()) {
draw->UpdateTextureRegions(bd->imguiTextures[index], 0, regions.data(), (int)regions.size());
}
tex->SetStatus(ImTextureStatus_OK);
break;
}
case ImTextureStatus_WantDestroy:
{
const size_t index = (size_t)tex->GetTexID() - 1;
if (index < bd->imguiTextures.size() && bd->imguiTextures[index]) {
bd->imguiTextures[index]->Release();
bd->imguiTextures[index] = nullptr;
}
tex->SetTexID(ImTextureID_Invalid);
tex->SetStatus(ImTextureStatus_Destroyed);
break;
}
default:
break;
}
}
// Render function
void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *draw) {
if (!draw_data) {
@@ -61,6 +151,16 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d
}
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
// Create/refresh/destroy whatever imgui needs before we start referring to the textures.
if (draw_data->Textures != nullptr) {
for (ImTextureData *tex : *draw_data->Textures) {
if (tex->Status != ImTextureStatus_OK) {
ImGui_ImplThin3d_UpdateTexture(draw, tex);
}
}
}
draw->BindSamplerStates(0, 1, &bd->fontSampler);
// Setup viewport
@@ -96,7 +196,7 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d
Draw::Aspect boundAspect = Draw::Aspect::COLOR_BIT;
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++) {
for (int n = 0; n < draw_data->CmdLists.Size; n++) {
const ImDrawList* cmd_list = draw_data->CmdLists[n];
draws.clear();
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
@@ -105,15 +205,22 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d
_dbg_assert_(pcmd->UserCallback == nullptr);
// Update the texture pointers.
if (!pcmd->TextureId) {
// Default
boundTexture = bd->fontImage;
const ImTextureID texId = pcmd->GetTexID();
if (texId < TEX_ID_OFFSET) {
// One of imgui's own textures - the font atlas, most of the time.
const size_t index = (size_t)texId - 1;
if (texId == ImTextureID_Invalid || index >= bd->imguiTextures.size() || !bd->imguiTextures[index]) {
WARN_LOG(Log::System, "Missing imgui texture %d", (int)texId);
continue;
}
boundTexture = bd->imguiTextures[index];
boundNativeTexture = nullptr;
boundFBAsTexture = nullptr;
boundAspect = Draw::Aspect::COLOR_BIT;
boundPipeline = bd->pipelines[0];
boundSampler = bd->fontSampler;
} else {
size_t index = (size_t)pcmd->TextureId - TEX_ID_OFFSET;
size_t index = (size_t)texId - TEX_ID_OFFSET;
if (index >= bd->tempTextures.size()) {
WARN_LOG(Log::System, "Missing temp texture %d (out of %d)", (int)index, (int)bd->tempTextures.size());
continue;
@@ -245,40 +352,27 @@ bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) {
rasterNoCull->Release();
}
if (!bd->fontImage) {
ImGuiIO& io = ImGui::GetIO();
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
size_t upload_size = width * height * 4 * sizeof(char);
Draw::TextureDesc desc{};
desc.width = width;
desc.height = height;
desc.mipLevels = 1;
desc.format = Draw::DataFormat::R8G8B8A8_UNORM;
desc.type = Draw::TextureType::LINEAR2D;
desc.swizzle = Draw::TextureSwizzle::DEFAULT;
desc.depth = 1;
desc.tag = "imgui-font";
desc.initData.push_back((const uint8_t *)pixels);
bd->fontImage = draw->CreateTexture(desc);
io.Fonts->SetTexID(0);
}
// The font atlas isn't built here any more - since 1.92 imgui hands us its textures through
// ImGui_ImplThin3d_UpdateTexture as it needs them.
return true;
}
void ImGui_ImplThin3d_DestroyDeviceObjects() {
ImGuiIO& io = ImGui::GetIO();
BackendData* bd = ImGui_ImplThin3d_GetBackendData();
if (bd->fontImage) {
bd->fontImage->Release();
bd->fontImage = nullptr;
io.Fonts->SetTexID(0);
// Hand imgui's textures back. Setting the status to Destroyed lets it ask for them again if
// the backend comes back up, which is what happens on a device loss or a backend switch.
for (ImTextureData *tex : ImGui::GetPlatformIO().Textures) {
if (tex->RefCount == 1) {
const size_t index = (size_t)tex->GetTexID() - 1;
if (tex->GetTexID() != ImTextureID_Invalid && index < bd->imguiTextures.size() && bd->imguiTextures[index]) {
bd->imguiTextures[index]->Release();
bd->imguiTextures[index] = nullptr;
}
tex->SetTexID(ImTextureID_Invalid);
tex->SetStatus(ImTextureStatus_Destroyed);
}
}
bd->imguiTextures.clear();
for (int i = 0; i < ARRAY_SIZE(bd->pipelines); i++) {
if (bd->pipelines[i]) {
bd->pipelines[i]->Release();
@@ -323,12 +417,15 @@ bool ImGui_ImplThin3d_Init(Draw::DrawContext *draw,
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_thin3d";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We create/update/destroy imgui's textures on request - see ImGui_ImplThin3d_UpdateTexture.
ImGui_ImplThin3d_CreateDeviceObjects(draw);
return true;
}
void ImGui_PushFixedFont() {
ImGui::PushFont(g_fixedFont);
// LegacySize is the size the font was added at, which is what PushFont used before 1.92 made
// the size an explicit parameter.
ImGui::PushFont(g_fixedFont, g_fixedFont->LegacySize);
}
void ImGui_PopFont() {
+951 -424
View File
File diff suppressed because it is too large. Load diff
+782 -345
View File
File diff suppressed because it is too large. Load diff
+1802 -1080
View File
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -315,7 +315,7 @@ static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0
if (node->y > min_y) {
// raise min_y higher.
// 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);
min_y = node->y;
// 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
// let 'cur' point to the remaining nodes needing to be
// stiched back in
// stitched back in
cur = *res.prev_link;
if (cur->x < res.x) {
+113 -55
View File
@@ -5,7 +5,8 @@
// - 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 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_*
// stb_textedit.h - v1.14 - public domain - Sean Barrett
@@ -39,6 +40,7 @@
//
// 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.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
@@ -141,12 +143,14 @@
// with previous char)
// STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character
// (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_NEWLINE the character returned by _GETCHAR() we recognize
// as manually wordwrapping for end-of-line positioning
//
// 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
//
@@ -178,6 +182,13 @@
// 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
//
// 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
// 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,
@@ -250,8 +261,10 @@
// if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are
// transformed into text and stb_textedit_text() is automatically called.
//
// text: [DEAR IMGUI] added 2024-09
// call this to text inputs sent to the textfield.
// text: (added 2025)
// 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
@@ -400,6 +413,16 @@ typedef struct
#define IMSTB_TEXTEDIT_memmove memmove
#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
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;
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.ymin = r.ymax = 0;
r.num_chars = 0;
*out_side_on_line = 0;
// search rows to find one that straddles 'y'
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
if (i >= n)
{
*out_side_on_line = 1;
return n;
}
// check if it's before the beginning of the line
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) {
float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
if (x < prev_x+w) {
*out_side_on_line = (k == 0) ? 0 : 1;
if (x < prev_x+w/2)
return k+i;
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
*out_side_on_line = 1;
if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE)
return i+r.num_chars-1;
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
// goes off the top or bottom of the text
int side_on_line;
if( state->single_line )
{
StbTexteditRow r;
@@ -478,16 +508,18 @@ static void stb_textedit_click(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *st
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_end = state->cursor;
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
static void stb_textedit_drag(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
{
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
// 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)
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;
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);
if (n < i + r.num_chars)
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
break; // [DEAR IMGUI]
prev_start = i;
@@ -648,15 +683,33 @@ static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str, STB_TexteditSt
}
}
// [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)
// [DEAR IMGUI] Extracted this function so we can more easily add support for word-wrapping.
#ifndef STB_TEXTEDIT_MOVELINESTART
static int stb_textedit_move_line_start(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int cursor)
{
if (state->single_line)
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
#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX
#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx) (idx + 1)
#ifndef STB_TEXTEDIT_MOVELINEEND
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
#ifdef STB_TEXTEDIT_IS_SPACE
@@ -668,9 +721,9 @@ static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx )
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c )
{
--c; // always move at least one character
while( c >= 0 && !is_word_boundary( str, c ) )
--c;
c = IMSTB_TEXTEDIT_GETPREVCHARINDEX( str, c ); // always move at least one character
while (c >= 0 && !is_word_boundary(str, c))
c = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, c);
if( 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 )
{
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 ) )
++c;
c = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, c);
if( 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_delete_selection(str,state);
// 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);
state->cursor += len;
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
#endif
// API key: process text input
// [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)
{
@@ -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)) {
stb_text_makeundo_replace(str, state, state->cursor, 1, 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->has_preferred_x = 0;
}
}
else {
} else {
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);
state->cursor += text_len;
state->has_preferred_x = 0;
@@ -771,6 +827,7 @@ retry:
switch (key) {
default: {
#ifdef STB_TEXTEDIT_KEYTOTEXT
// This is not suitable for UTF-8 support.
int c = STB_TEXTEDIT_KEYTOTEXT(key);
if (c > 0) {
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
@@ -911,15 +968,16 @@ retry:
// [DEAR IMGUI]
// 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)
break;
//if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
// break;
// now find character position down a row
state->cursor = start;
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
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);
int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
break;
@@ -927,10 +985,13 @@ retry:
x += dx;
if (x > goal_x)
break;
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
i += next - state->cursor;
state->cursor = next;
}
stb_textedit_clamp(str, state);
if (state->cursor == find.first_char + find.length)
str->LastMoveDirectionLR = ImGuiDir_Left;
state->has_preferred_x = 1;
state->preferred_x = goal_x;
@@ -980,8 +1041,9 @@ retry:
state->cursor = find.prev_first;
STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
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);
int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
break;
@@ -989,10 +1051,15 @@ retry:
x += dx;
if (x > goal_x)
break;
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
i += next - state->cursor;
state->cursor = next;
}
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->preferred_x = goal_x;
@@ -1002,10 +1069,15 @@ retry:
// go to previous line
// (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;
while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)
--prev_scan;
while (prev_scan > 0)
{
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.prev_first = prev_scan;
find.prev_first = STB_TEXTEDIT_MOVELINESTART(str, state, prev_scan);
}
break;
}
@@ -1079,10 +1151,7 @@ retry:
case STB_TEXTEDIT_K_LINESTART:
stb_textedit_clamp(str, state);
stb_textedit_move_to_first(state);
if (state->single_line)
state->cursor = 0;
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
--state->cursor;
state->cursor = STB_TEXTEDIT_MOVELINESTART(str, state, state->cursor);
state->has_preferred_x = 0;
break;
@@ -1090,13 +1159,9 @@ retry:
case STB_TEXTEDIT_K_LINEEND2:
#endif
case STB_TEXTEDIT_K_LINEEND: {
int n = STB_TEXTEDIT_STRINGLEN(str);
stb_textedit_clamp(str, state);
stb_textedit_move_to_first(state);
if (state->single_line)
state->cursor = n;
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
++state->cursor;
stb_textedit_move_to_last(str, state);
state->cursor = STB_TEXTEDIT_MOVELINEEND(str, state, state->cursor);
state->has_preferred_x = 0;
break;
}
@@ -1107,10 +1172,7 @@ retry:
case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
stb_textedit_clamp(str, state);
stb_textedit_prep_selection_at_cursor(state);
if (state->single_line)
state->cursor = 0;
else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
--state->cursor;
state->cursor = STB_TEXTEDIT_MOVELINESTART(str, state, state->cursor);
state->select_end = state->cursor;
state->has_preferred_x = 0;
break;
@@ -1119,13 +1181,9 @@ retry:
case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
#endif
case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
int n = STB_TEXTEDIT_STRINGLEN(str);
stb_textedit_clamp(str, state);
stb_textedit_prep_selection_at_cursor(state);
if (state->single_line)
state->cursor = n;
else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
++state->cursor;
state->cursor = STB_TEXTEDIT_MOVELINEEND(str, state, state->cursor);
state->select_end = state->cursor;
state->has_preferred_x = 0;
break;
@@ -1300,7 +1358,7 @@ static void stb_text_undo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
// check type of recorded action:
if (u.insert_length) {
// 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;
}
@@ -1351,7 +1409,7 @@ static void stb_text_redo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
if (r.insert_length) {
// 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;
}
+3 -3
View File
@@ -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
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
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[1] = (float)y2;
if (equal(q0,q1) || equal(q1,q2)) {
x0 = (int)verts[i-1].x;
y0 = (int)verts[i-1].y;
x0 = (int)verts[i-1].x; //-V1048
y0 = (int)verts[i-1].y; //-V1048
x1 = (int)verts[i ].x;
y1 = (int)verts[i ].y;
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {