/Engine/imgui/imgui_draw.cpp
C++ | 1249 lines | 1027 code | 145 blank | 77 comment | 208 complexity | dd4b4e53bfce7a3bec20223087cf64f3 MD5 | raw file
- // dear imgui, v1.50 WIP
- // (drawing and font code)
- // Contains implementation for
- // - ImDrawList
- // - ImDrawData
- // - ImFontAtlas
- // - ImFont
- // - Default font data
- #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
- #define _CRT_SECURE_NO_WARNINGS
- #endif
- #include "imgui.h"
- #define IMGUI_DEFINE_MATH_OPERATORS
- #define IMGUI_DEFINE_PLACEMENT_NEW
- #include "imgui_internal.h"
- #include <stdio.h> // vsnprintf, sscanf, printf
- #if !defined(alloca)
- #ifdef _WIN32
- #include <malloc.h> // alloca
- #elif (defined(__FreeBSD__) || defined(FreeBSD_kernel) || defined(__DragonFly__)) && !defined(__GLIBC__)
- #include <stdlib.h> // alloca. FreeBSD uses stdlib.h unless GLIBC
- #else
- #include <alloca.h> // alloca
- #endif
- #endif
- #ifdef _MSC_VER
- #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
- #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
- #define snprintf _snprintf
- #endif
- #ifdef __clang__
- #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
- #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
- #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
- #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
- #if __has_warning("-Wreserved-id-macro")
- #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier //
- #endif
- #elif defined(__GNUC__)
- #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
- #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
- #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
- #endif
- //-------------------------------------------------------------------------
- // STB libraries implementation
- //-------------------------------------------------------------------------
- //#define IMGUI_STB_NAMESPACE ImGuiStb
- //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
- //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
- #ifdef IMGUI_STB_NAMESPACE
- namespace IMGUI_STB_NAMESPACE
- {
- #endif
- #ifdef _MSC_VER
- #pragma warning (push)
- #pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration
- #endif
- #ifdef __clang__
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
- #pragma clang diagnostic ignored "-Wunused-function"
- #pragma clang diagnostic ignored "-Wmissing-prototypes"
- #endif
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits]
- #endif
- #define STBRP_ASSERT(x) IM_ASSERT(x)
- #ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
- #define STBRP_STATIC
- #define STB_RECT_PACK_IMPLEMENTATION
- #endif
- #include "stb_rect_pack.h"
- #define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x))
- #define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x))
- #define STBTT_assert(x) IM_ASSERT(x)
- #ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
- #define STBTT_STATIC
- #define STB_TRUETYPE_IMPLEMENTATION
- #else
- #define STBTT_DEF extern
- #endif
- #include "stb_truetype.h"
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
- #ifdef __clang__
- #pragma clang diagnostic pop
- #endif
- #ifdef _MSC_VER
- #pragma warning (pop)
- #endif
- #ifdef IMGUI_STB_NAMESPACE
- } // namespace ImGuiStb
- using namespace IMGUI_STB_NAMESPACE;
- #endif
- //-----------------------------------------------------------------------------
- // ImDrawList
- //-----------------------------------------------------------------------------
- static const ImVec4 GNullClipRect(-8192.0f, -8192.0f, +8192.0f, +8192.0f); // Large values that are easy to encode in a few bits+shift
- void ImDrawList::Clear()
- {
- CmdBuffer.resize(0);
- IdxBuffer.resize(0);
- VtxBuffer.resize(0);
- _VtxCurrentIdx = 0;
- _VtxWritePtr = NULL;
- _IdxWritePtr = NULL;
- _ClipRectStack.resize(0);
- _TextureIdStack.resize(0);
- _Path.resize(0);
- _ChannelsCurrent = 0;
- _ChannelsCount = 1;
- // NB: Do not clear channels so our allocations are re-used after the first frame.
- }
- void ImDrawList::ClearFreeMemory()
- {
- CmdBuffer.clear();
- IdxBuffer.clear();
- VtxBuffer.clear();
- _VtxCurrentIdx = 0;
- _VtxWritePtr = NULL;
- _IdxWritePtr = NULL;
- _ClipRectStack.clear();
- _TextureIdStack.clear();
- _Path.clear();
- _ChannelsCurrent = 0;
- _ChannelsCount = 1;
- for (int i = 0; i < _Channels.Size; i++)
- {
- if (i == 0) memset(&_Channels[0], 0, sizeof(_Channels[0])); // channel 0 is a copy of CmdBuffer/IdxBuffer, don't destruct again
- _Channels[i].CmdBuffer.clear();
- _Channels[i].IdxBuffer.clear();
- }
- _Channels.clear();
- }
- // Use macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug mode
- #define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1] : GNullClipRect)
- #define GetCurrentTextureId() (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : NULL)
- void ImDrawList::AddDrawCmd()
- {
- ImDrawCmd draw_cmd;
- draw_cmd.ClipRect = GetCurrentClipRect();
- draw_cmd.TextureId = GetCurrentTextureId();
- IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);
- CmdBuffer.push_back(draw_cmd);
- }
- void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
- {
- ImDrawCmd* current_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
- if (!current_cmd || current_cmd->ElemCount != 0 || current_cmd->UserCallback != NULL)
- {
- AddDrawCmd();
- current_cmd = &CmdBuffer.back();
- }
- current_cmd->UserCallback = callback;
- current_cmd->UserCallbackData = callback_data;
- AddDrawCmd(); // Force a new command after us (see comment below)
- }
- // Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack.
- // The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only.
- void ImDrawList::UpdateClipRect()
- {
- // If current command is used with different settings we need to add a new command
- const ImVec4 curr_clip_rect = GetCurrentClipRect();
- ImDrawCmd* curr_cmd = CmdBuffer.Size > 0 ? &CmdBuffer.Data[CmdBuffer.Size-1] : NULL;
- if (!curr_cmd || (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL)
- {
- AddDrawCmd();
- return;
- }
- // Try to merge with previous command if it matches, else use current command
- ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL;
- if (curr_cmd->ElemCount == 0 && prev_cmd && memcmp(&prev_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) == 0 && prev_cmd->TextureId == GetCurrentTextureId() && prev_cmd->UserCallback == NULL)
- CmdBuffer.pop_back();
- else
- curr_cmd->ClipRect = curr_clip_rect;
- }
- void ImDrawList::UpdateTextureID()
- {
- // If current command is used with different settings we need to add a new command
- const ImTextureID curr_texture_id = GetCurrentTextureId();
- ImDrawCmd* curr_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
- if (!curr_cmd || (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != curr_texture_id) || curr_cmd->UserCallback != NULL)
- {
- AddDrawCmd();
- return;
- }
- // Try to merge with previous command if it matches, else use current command
- ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL;
- if (prev_cmd && prev_cmd->TextureId == curr_texture_id && memcmp(&prev_cmd->ClipRect, &GetCurrentClipRect(), sizeof(ImVec4)) == 0 && prev_cmd->UserCallback == NULL)
- CmdBuffer.pop_back();
- else
- curr_cmd->TextureId = curr_texture_id;
- }
- #undef GetCurrentClipRect
- #undef GetCurrentTextureId
- // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
- void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect)
- {
- ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
- if (intersect_with_current_clip_rect && _ClipRectStack.Size)
- {
- ImVec4 current = _ClipRectStack.Data[_ClipRectStack.Size-1];
- if (cr.x < current.x) cr.x = current.x;
- if (cr.y < current.y) cr.y = current.y;
- if (cr.z > current.z) cr.z = current.z;
- if (cr.w > current.w) cr.w = current.w;
- }
- cr.z = ImMax(cr.x, cr.z);
- cr.w = ImMax(cr.y, cr.w);
- _ClipRectStack.push_back(cr);
- UpdateClipRect();
- }
- void ImDrawList::PushClipRectFullScreen()
- {
- PushClipRect(ImVec2(GNullClipRect.x, GNullClipRect.y), ImVec2(GNullClipRect.z, GNullClipRect.w));
- //PushClipRect(GetVisibleRect()); // FIXME-OPT: This would be more correct but we're not supposed to access ImGuiContext from here?
- }
- void ImDrawList::PopClipRect()
- {
- IM_ASSERT(_ClipRectStack.Size > 0);
- _ClipRectStack.pop_back();
- UpdateClipRect();
- }
- void ImDrawList::PushTextureID(const ImTextureID& texture_id)
- {
- _TextureIdStack.push_back(texture_id);
- UpdateTextureID();
- }
- void ImDrawList::PopTextureID()
- {
- IM_ASSERT(_TextureIdStack.Size > 0);
- _TextureIdStack.pop_back();
- UpdateTextureID();
- }
- void ImDrawList::ChannelsSplit(int channels_count)
- {
- IM_ASSERT(_ChannelsCurrent == 0 && _ChannelsCount == 1);
- int old_channels_count = _Channels.Size;
- if (old_channels_count < channels_count)
- _Channels.resize(channels_count);
- _ChannelsCount = channels_count;
- // _Channels[] (24 bytes each) hold storage that we'll swap with this->_CmdBuffer/_IdxBuffer
- // The content of _Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to.
- // When we switch to the next channel, we'll copy _CmdBuffer/_IdxBuffer into _Channels[0] and then _Channels[1] into _CmdBuffer/_IdxBuffer
- memset(&_Channels[0], 0, sizeof(ImDrawChannel));
- for (int i = 1; i < channels_count; i++)
- {
- if (i >= old_channels_count)
- {
- IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel();
- }
- else
- {
- _Channels[i].CmdBuffer.resize(0);
- _Channels[i].IdxBuffer.resize(0);
- }
- if (_Channels[i].CmdBuffer.Size == 0)
- {
- ImDrawCmd draw_cmd;
- draw_cmd.ClipRect = _ClipRectStack.back();
- draw_cmd.TextureId = _TextureIdStack.back();
- _Channels[i].CmdBuffer.push_back(draw_cmd);
- }
- }
- }
- void ImDrawList::ChannelsMerge()
- {
- // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use.
- if (_ChannelsCount <= 1)
- return;
- ChannelsSetCurrent(0);
- if (CmdBuffer.Size && CmdBuffer.back().ElemCount == 0)
- CmdBuffer.pop_back();
- int new_cmd_buffer_count = 0, new_idx_buffer_count = 0;
- for (int i = 1; i < _ChannelsCount; i++)
- {
- ImDrawChannel& ch = _Channels[i];
- if (ch.CmdBuffer.Size && ch.CmdBuffer.back().ElemCount == 0)
- ch.CmdBuffer.pop_back();
- new_cmd_buffer_count += ch.CmdBuffer.Size;
- new_idx_buffer_count += ch.IdxBuffer.Size;
- }
- CmdBuffer.resize(CmdBuffer.Size + new_cmd_buffer_count);
- IdxBuffer.resize(IdxBuffer.Size + new_idx_buffer_count);
- ImDrawCmd* cmd_write = CmdBuffer.Data + CmdBuffer.Size - new_cmd_buffer_count;
- _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size - new_idx_buffer_count;
- for (int i = 1; i < _ChannelsCount; i++)
- {
- ImDrawChannel& ch = _Channels[i];
- if (int sz = ch.CmdBuffer.Size) { memcpy(cmd_write, ch.CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; }
- if (int sz = ch.IdxBuffer.Size) { memcpy(_IdxWritePtr, ch.IdxBuffer.Data, sz * sizeof(ImDrawIdx)); _IdxWritePtr += sz; }
- }
- AddDrawCmd();
- _ChannelsCount = 1;
- }
- void ImDrawList::ChannelsSetCurrent(int idx)
- {
- IM_ASSERT(idx < _ChannelsCount);
- if (_ChannelsCurrent == idx) return;
- memcpy(&_Channels.Data[_ChannelsCurrent].CmdBuffer, &CmdBuffer, sizeof(CmdBuffer)); // copy 12 bytes, four times
- memcpy(&_Channels.Data[_ChannelsCurrent].IdxBuffer, &IdxBuffer, sizeof(IdxBuffer));
- _ChannelsCurrent = idx;
- memcpy(&CmdBuffer, &_Channels.Data[_ChannelsCurrent].CmdBuffer, sizeof(CmdBuffer));
- memcpy(&IdxBuffer, &_Channels.Data[_ChannelsCurrent].IdxBuffer, sizeof(IdxBuffer));
- _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size;
- }
- // NB: this can be called with negative count for removing primitives (as long as the result does not underflow)
- void ImDrawList::PrimReserve(int idx_count, int vtx_count)
- {
- ImDrawCmd& draw_cmd = CmdBuffer.Data[CmdBuffer.Size-1];
- draw_cmd.ElemCount += idx_count;
- int vtx_buffer_size = VtxBuffer.Size;
- VtxBuffer.resize(vtx_buffer_size + vtx_count);
- _VtxWritePtr = VtxBuffer.Data + vtx_buffer_size;
- int idx_buffer_size = IdxBuffer.Size;
- IdxBuffer.resize(idx_buffer_size + idx_count);
- _IdxWritePtr = IdxBuffer.Data + idx_buffer_size;
- }
- // Fully unrolled with inline call to keep our debug builds decently fast.
- void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)
- {
- ImVec2 b(c.x, a.y), d(a.x, c.y), uv(GImGui->FontTexUvWhitePixel);
- ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
- _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
- _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
- _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
- _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
- _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
- _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;
- _VtxWritePtr += 4;
- _VtxCurrentIdx += 4;
- _IdxWritePtr += 6;
- }
- void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col)
- {
- ImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y);
- ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
- _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
- _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
- _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
- _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
- _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
- _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
- _VtxWritePtr += 4;
- _VtxCurrentIdx += 4;
- _IdxWritePtr += 6;
- }
- void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col)
- {
- ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
- _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
- _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
- _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
- _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
- _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
- _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
- _VtxWritePtr += 4;
- _VtxCurrentIdx += 4;
- _IdxWritePtr += 6;
- }
- // TODO: Thickness anti-aliased lines cap are missing their AA fringe.
- void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness, bool anti_aliased)
- {
- if (points_count < 2)
- return;
- const ImVec2 uv = GImGui->FontTexUvWhitePixel;
- anti_aliased &= GImGui->Style.AntiAliasedLines;
- //if (ImGui::GetIO().KeyCtrl) anti_aliased = false; // Debug
- int count = points_count;
- if (!closed)
- count = points_count-1;
- const bool thick_line = thickness > 1.0f;
- if (anti_aliased)
- {
- // Anti-aliased stroke
- const float AA_SIZE = 1.0f;
- const ImU32 col_trans = col & IM_COL32(255,255,255,0);
- const int idx_count = thick_line ? count*18 : count*12;
- const int vtx_count = thick_line ? points_count*4 : points_count*3;
- PrimReserve(idx_count, vtx_count);
- // Temporary buffer
- ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2));
- ImVec2* temp_points = temp_normals + points_count;
- for (int i1 = 0; i1 < count; i1++)
- {
- const int i2 = (i1+1) == points_count ? 0 : i1+1;
- ImVec2 diff = points[i2] - points[i1];
- diff *= ImInvLength(diff, 1.0f);
- temp_normals[i1].x = diff.y;
- temp_normals[i1].y = -diff.x;
- }
- if (!closed)
- temp_normals[points_count-1] = temp_normals[points_count-2];
- if (!thick_line)
- {
- if (!closed)
- {
- temp_points[0] = points[0] + temp_normals[0] * AA_SIZE;
- temp_points[1] = points[0] - temp_normals[0] * AA_SIZE;
- temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * AA_SIZE;
- temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * AA_SIZE;
- }
- // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
- unsigned int idx1 = _VtxCurrentIdx;
- for (int i1 = 0; i1 < count; i1++)
- {
- const int i2 = (i1+1) == points_count ? 0 : i1+1;
- unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3;
- // Average normals
- ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
- float dmr2 = dm.x*dm.x + dm.y*dm.y;
- if (dmr2 > 0.000001f)
- {
- float scale = 1.0f / dmr2;
- if (scale > 100.0f) scale = 100.0f;
- dm *= scale;
- }
- dm *= AA_SIZE;
- temp_points[i2*2+0] = points[i2] + dm;
- temp_points[i2*2+1] = points[i2] - dm;
- // Add indexes
- _IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
- _IdxWritePtr[3] = (ImDrawIdx)(idx1+2); _IdxWritePtr[4] = (ImDrawIdx)(idx2+2); _IdxWritePtr[5] = (ImDrawIdx)(idx2+0);
- _IdxWritePtr[6] = (ImDrawIdx)(idx2+1); _IdxWritePtr[7] = (ImDrawIdx)(idx1+1); _IdxWritePtr[8] = (ImDrawIdx)(idx1+0);
- _IdxWritePtr[9] = (ImDrawIdx)(idx1+0); _IdxWritePtr[10]= (ImDrawIdx)(idx2+0); _IdxWritePtr[11]= (ImDrawIdx)(idx2+1);
- _IdxWritePtr += 12;
- idx1 = idx2;
- }
- // Add vertexes
- for (int i = 0; i < points_count; i++)
- {
- _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
- _VtxWritePtr[1].pos = temp_points[i*2+0]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans;
- _VtxWritePtr[2].pos = temp_points[i*2+1]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col_trans;
- _VtxWritePtr += 3;
- }
- }
- else
- {
- const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
- if (!closed)
- {
- temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE);
- temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness);
- temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness);
- temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE);
- temp_points[(points_count-1)*4+0] = points[points_count-1] + temp_normals[points_count-1] * (half_inner_thickness + AA_SIZE);
- temp_points[(points_count-1)*4+1] = points[points_count-1] + temp_normals[points_count-1] * (half_inner_thickness);
- temp_points[(points_count-1)*4+2] = points[points_count-1] - temp_normals[points_count-1] * (half_inner_thickness);
- temp_points[(points_count-1)*4+3] = points[points_count-1] - temp_normals[points_count-1] * (half_inner_thickness + AA_SIZE);
- }
- // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
- unsigned int idx1 = _VtxCurrentIdx;
- for (int i1 = 0; i1 < count; i1++)
- {
- const int i2 = (i1+1) == points_count ? 0 : i1+1;
- unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4;
- // Average normals
- ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
- float dmr2 = dm.x*dm.x + dm.y*dm.y;
- if (dmr2 > 0.000001f)
- {
- float scale = 1.0f / dmr2;
- if (scale > 100.0f) scale = 100.0f;
- dm *= scale;
- }
- ImVec2 dm_out = dm * (half_inner_thickness + AA_SIZE);
- ImVec2 dm_in = dm * half_inner_thickness;
- temp_points[i2*4+0] = points[i2] + dm_out;
- temp_points[i2*4+1] = points[i2] + dm_in;
- temp_points[i2*4+2] = points[i2] - dm_in;
- temp_points[i2*4+3] = points[i2] - dm_out;
- // Add indexes
- _IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
- _IdxWritePtr[3] = (ImDrawIdx)(idx1+2); _IdxWritePtr[4] = (ImDrawIdx)(idx2+2); _IdxWritePtr[5] = (ImDrawIdx)(idx2+1);
- _IdxWritePtr[6] = (ImDrawIdx)(idx2+1); _IdxWritePtr[7] = (ImDrawIdx)(idx1+1); _IdxWritePtr[8] = (ImDrawIdx)(idx1+0);
- _IdxWritePtr[9] = (ImDrawIdx)(idx1+0); _IdxWritePtr[10] = (ImDrawIdx)(idx2+0); _IdxWritePtr[11] = (ImDrawIdx)(idx2+1);
- _IdxWritePtr[12] = (ImDrawIdx)(idx2+2); _IdxWritePtr[13] = (ImDrawIdx)(idx1+2); _IdxWritePtr[14] = (ImDrawIdx)(idx1+3);
- _IdxWritePtr[15] = (ImDrawIdx)(idx1+3); _IdxWritePtr[16] = (ImDrawIdx)(idx2+3); _IdxWritePtr[17] = (ImDrawIdx)(idx2+2);
- _IdxWritePtr += 18;
- idx1 = idx2;
- }
- // Add vertexes
- for (int i = 0; i < points_count; i++)
- {
- _VtxWritePtr[0].pos = temp_points[i*4+0]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col_trans;
- _VtxWritePtr[1].pos = temp_points[i*4+1]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
- _VtxWritePtr[2].pos = temp_points[i*4+2]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
- _VtxWritePtr[3].pos = temp_points[i*4+3]; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col_trans;
- _VtxWritePtr += 4;
- }
- }
- _VtxCurrentIdx += (ImDrawIdx)vtx_count;
- }
- else
- {
- // Non Anti-aliased Stroke
- const int idx_count = count*6;
- const int vtx_count = count*4; // FIXME-OPT: Not sharing edges
- PrimReserve(idx_count, vtx_count);
- for (int i1 = 0; i1 < count; i1++)
- {
- const int i2 = (i1+1) == points_count ? 0 : i1+1;
- const ImVec2& p1 = points[i1];
- const ImVec2& p2 = points[i2];
- ImVec2 diff = p2 - p1;
- diff *= ImInvLength(diff, 1.0f);
- const float dx = diff.x * (thickness * 0.5f);
- const float dy = diff.y * (thickness * 0.5f);
- _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
- _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
- _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
- _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;
- _VtxWritePtr += 4;
- _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx+1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx+2);
- _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx+2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx+3);
- _IdxWritePtr += 6;
- _VtxCurrentIdx += 4;
- }
- }
- }
- void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col, bool anti_aliased)
- {
- const ImVec2 uv = GImGui->FontTexUvWhitePixel;
- anti_aliased &= GImGui->Style.AntiAliasedShapes;
- //if (ImGui::GetIO().KeyCtrl) anti_aliased = false; // Debug
- if (anti_aliased)
- {
- // Anti-aliased Fill
- const float AA_SIZE = 1.0f;
- const ImU32 col_trans = col & IM_COL32(255,255,255,0);
- const int idx_count = (points_count-2)*3 + points_count*6;
- const int vtx_count = (points_count*2);
- PrimReserve(idx_count, vtx_count);
- // Add indexes for fill
- unsigned int vtx_inner_idx = _VtxCurrentIdx;
- unsigned int vtx_outer_idx = _VtxCurrentIdx+1;
- for (int i = 2; i < points_count; i++)
- {
- _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx+((i-1)<<1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx+(i<<1));
- _IdxWritePtr += 3;
- }
- // Compute normals
- ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2));
- for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
- {
- const ImVec2& p0 = points[i0];
- const ImVec2& p1 = points[i1];
- ImVec2 diff = p1 - p0;
- diff *= ImInvLength(diff, 1.0f);
- temp_normals[i0].x = diff.y;
- temp_normals[i0].y = -diff.x;
- }
- for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++)
- {
- // Average normals
- const ImVec2& n0 = temp_normals[i0];
- const ImVec2& n1 = temp_normals[i1];
- ImVec2 dm = (n0 + n1) * 0.5f;
- float dmr2 = dm.x*dm.x + dm.y*dm.y;
- if (dmr2 > 0.000001f)
- {
- float scale = 1.0f / dmr2;
- if (scale > 100.0f) scale = 100.0f;
- dm *= scale;
- }
- dm *= AA_SIZE * 0.5f;
- // Add vertices
- _VtxWritePtr[0].pos = (points[i1] - dm); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner
- _VtxWritePtr[1].pos = (points[i1] + dm); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer
- _VtxWritePtr += 2;
- // Add indexes for fringes
- _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx+(i1<<1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx+(i0<<1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx+(i0<<1));
- _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx+(i0<<1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx+(i1<<1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx+(i1<<1));
- _IdxWritePtr += 6;
- }
- _VtxCurrentIdx += (ImDrawIdx)vtx_count;
- }
- else
- {
- // Non Anti-aliased Fill
- const int idx_count = (points_count-2)*3;
- const int vtx_count = points_count;
- PrimReserve(idx_count, vtx_count);
- for (int i = 0; i < vtx_count; i++)
- {
- _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
- _VtxWritePtr++;
- }
- for (int i = 2; i < points_count; i++)
- {
- _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx+i-1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx+i);
- _IdxWritePtr += 3;
- }
- _VtxCurrentIdx += (ImDrawIdx)vtx_count;
- }
- }
- void ImDrawList::PathArcToFast(const ImVec2& centre, float radius, int amin, int amax)
- {
- static ImVec2 circle_vtx[12];
- static bool circle_vtx_builds = false;
- const int circle_vtx_count = IM_ARRAYSIZE(circle_vtx);
- if (!circle_vtx_builds)
- {
- for (int i = 0; i < circle_vtx_count; i++)
- {
- const float a = ((float)i / (float)circle_vtx_count) * 2*IM_PI;
- circle_vtx[i].x = cosf(a);
- circle_vtx[i].y = sinf(a);
- }
- circle_vtx_builds = true;
- }
- if (amin > amax) return;
- if (radius == 0.0f)
- {
- _Path.push_back(centre);
- }
- else
- {
- _Path.reserve(_Path.Size + (amax - amin + 1));
- for (int a = amin; a <= amax; a++)
- {
- const ImVec2& c = circle_vtx[a % circle_vtx_count];
- _Path.push_back(ImVec2(centre.x + c.x * radius, centre.y + c.y * radius));
- }
- }
- }
- void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float amin, float amax, int num_segments)
- {
- if (radius == 0.0f)
- _Path.push_back(centre);
- _Path.reserve(_Path.Size + (num_segments + 1));
- for (int i = 0; i <= num_segments; i++)
- {
- const float a = amin + ((float)i / (float)num_segments) * (amax - amin);
- _Path.push_back(ImVec2(centre.x + cosf(a) * radius, centre.y + sinf(a) * radius));
- }
- }
- static void PathBezierToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
- {
- float dx = x4 - x1;
- float dy = y4 - y1;
- float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
- float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
- d2 = (d2 >= 0) ? d2 : -d2;
- d3 = (d3 >= 0) ? d3 : -d3;
- if ((d2+d3) * (d2+d3) < tess_tol * (dx*dx + dy*dy))
- {
- path->push_back(ImVec2(x4, y4));
- }
- else if (level < 10)
- {
- float x12 = (x1+x2)*0.5f, y12 = (y1+y2)*0.5f;
- float x23 = (x2+x3)*0.5f, y23 = (y2+y3)*0.5f;
- float x34 = (x3+x4)*0.5f, y34 = (y3+y4)*0.5f;
- float x123 = (x12+x23)*0.5f, y123 = (y12+y23)*0.5f;
- float x234 = (x23+x34)*0.5f, y234 = (y23+y34)*0.5f;
- float x1234 = (x123+x234)*0.5f, y1234 = (y123+y234)*0.5f;
- PathBezierToCasteljau(path, x1,y1, x12,y12, x123,y123, x1234,y1234, tess_tol, level+1);
- PathBezierToCasteljau(path, x1234,y1234, x234,y234, x34,y34, x4,y4, tess_tol, level+1);
- }
- }
- void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments)
- {
- ImVec2 p1 = _Path.back();
- if (num_segments == 0)
- {
- // Auto-tessellated
- PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, GImGui->Style.CurveTessellationTol, 0);
- }
- else
- {
- float t_step = 1.0f / (float)num_segments;
- for (int i_step = 1; i_step <= num_segments; i_step++)
- {
- float t = t_step * i_step;
- float u = 1.0f - t;
- float w1 = u*u*u;
- float w2 = 3*u*u*t;
- float w3 = 3*u*t*t;
- float w4 = t*t*t;
- _Path.push_back(ImVec2(w1*p1.x + w2*p2.x + w3*p3.x + w4*p4.x, w1*p1.y + w2*p2.y + w3*p3.y + w4*p4.y));
- }
- }
- }
- void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, int rounding_corners)
- {
- float r = rounding;
- r = ImMin(r, fabsf(b.x-a.x) * ( ((rounding_corners&(1|2))==(1|2)) || ((rounding_corners&(4|8))==(4|8)) ? 0.5f : 1.0f ) - 1.0f);
- r = ImMin(r, fabsf(b.y-a.y) * ( ((rounding_corners&(1|8))==(1|8)) || ((rounding_corners&(2|4))==(2|4)) ? 0.5f : 1.0f ) - 1.0f);
- if (r <= 0.0f || rounding_corners == 0)
- {
- PathLineTo(a);
- PathLineTo(ImVec2(b.x,a.y));
- PathLineTo(b);
- PathLineTo(ImVec2(a.x,b.y));
- }
- else
- {
- const float r0 = (rounding_corners & 1) ? r : 0.0f;
- const float r1 = (rounding_corners & 2) ? r : 0.0f;
- const float r2 = (rounding_corners & 4) ? r : 0.0f;
- const float r3 = (rounding_corners & 8) ? r : 0.0f;
- PathArcToFast(ImVec2(a.x+r0,a.y+r0), r0, 6, 9);
- PathArcToFast(ImVec2(b.x-r1,a.y+r1), r1, 9, 12);
- PathArcToFast(ImVec2(b.x-r2,b.y-r2), r2, 0, 3);
- PathArcToFast(ImVec2(a.x+r3,b.y-r3), r3, 3, 6);
- }
- }
- void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness)
- {
- if ((col & IM_COL32_A_MASK) == 0)
- return;
- PathLineTo(a + ImVec2(0.5f,0.5f));
- PathLineTo(b + ImVec2(0.5f,0.5f));
- PathStroke(col, false, thickness);
- }
- // a: upper-left, b: lower-right. we don't render 1 px sized rectangles properly.
- void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags, float thickness)
- {
- if ((col & IM_COL32_A_MASK) == 0)
- return;
- PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.5f,0.5f), rounding, rounding_corners_flags);
- PathStroke(col, true, thickness);
- }
- void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags)
- {
- if ((col & IM_COL32_A_MASK) == 0)
- return;
- if (rounding > 0.0f)
- {
- PathRect(a, b, rounding, rounding_corners_flags);
- PathFill(col);
- }
- else
- {
- PrimReserve(6, 4);
- PrimRect(a, b, col);
- }
- }
- void ImDrawList::AddRectFilledMultiColor(const ImVec2& a, const ImVec2& c, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left)
- {
- if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0)
- return;
- const ImVec2 uv = GImGui->FontTexUvWhitePixel;
- PrimReserve(6, 4);
- PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2));
- PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+3));
- PrimWriteVtx(a, uv, col_upr_left);
- PrimWriteVtx(ImVec2(c.x, a.y), uv, col_upr_right);
- PrimWriteVtx(c, uv, col_bot_right);
- PrimWriteVtx(ImVec2(a.x, c.y), uv, col_bot_left);
- }
- void ImDrawList::AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness)
- {
- if ((col & IM_COL32_A_MASK) == 0)
- return;
- PathLineTo(a);
- PathLineTo(b);
- PathLineTo(c);
- PathLineTo(d);
- PathStroke(col, true, thickness);
- }
- void ImDrawList::AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col)
- {
- if ((col & IM_COL32_A_MASK) == 0)
- return;
- PathLineTo(a);
- PathLineTo(b);
- PathLineTo(c);
- PathLineTo(d);
- PathFill(col);
- }
- void ImDrawList::AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness)
- {
- if ((col & IM_COL32_A_MASK) == 0)
- return;
- PathLineTo(a);
- PathLineTo(b);
- PathLineTo(c);
- PathStroke(col, true, thickness);
- }
- void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col)
- {
- if ((col & IM_COL32_A_MASK) == 0)
- return;
- PathLineTo(a);
- PathLineTo(b);
- PathLineTo(c);
- PathFill(col);
- }
- void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness)
- {
- if ((col & IM_COL32_A_MASK) == 0)
- return;
- const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
- PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments);
- PathStroke(col, true, thickness);
- }
- void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments)
- {
- if ((col & IM_COL32_A_MASK) == 0)
- return;
- const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
- PathArcTo(centre, radius, 0.0f, a_max, num_segments);
- PathFill(col);
- }
- void ImDrawList::AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments)
- {
- if ((col & IM_COL32_A_MASK) == 0)
- return;
- PathLineTo(pos0);
- PathBezierCurveTo(cp0, cp1, pos1, num_segments);
- PathStroke(col, false, thickness);
- }
- void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect)
- {
- if ((col & IM_COL32_A_MASK) == 0)
- return;
- if (text_end == NULL)
- text_end = text_begin + strlen(text_begin);
- if (text_begin == text_end)
- return;
- // Note: This is one of the few instance of breaking the encapsulation of ImDrawList, as we pull this from ImGui state, but it is just SO useful.
- // Might just move Font/FontSize to ImDrawList?
- if (font == NULL)
- font = GImGui->Font;
- if (font_size == 0.0f)
- font_size = GImGui->FontSize;
- IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
- ImVec4 clip_rect = _ClipRectStack.back();
- if (cpu_fine_clip_rect)
- {
- clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
- clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
- clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
- clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
- }
- font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);
- }
- void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)
- {
- AddText(GImGui->Font, GImGui->FontSize, pos, col, text_begin, text_end);
- }
- void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv0, const ImVec2& uv1, ImU32 col)
- {
- if ((col & IM_COL32_A_MASK) == 0)
- return;
- // FIXME-OPT: This is wasting draw calls.
- const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
- if (push_texture_id)
- PushTextureID(user_texture_id);
- PrimReserve(6, 4);
- PrimRectUV(a, b, uv0, uv1, col);
- if (push_texture_id)
- PopTextureID();
- }
- //-----------------------------------------------------------------------------
- // ImDrawData
- //-----------------------------------------------------------------------------
- // For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering!
- void ImDrawData::DeIndexAllBuffers()
- {
- ImVector<ImDrawVert> new_vtx_buffer;
- TotalVtxCount = TotalIdxCount = 0;
- for (int i = 0; i < CmdListsCount; i++)
- {
- ImDrawList* cmd_list = CmdLists[i];
- if (cmd_list->IdxBuffer.empty())
- continue;
- new_vtx_buffer.resize(cmd_list->IdxBuffer.Size);
- for (int j = 0; j < cmd_list->IdxBuffer.Size; j++)
- new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]];
- cmd_list->VtxBuffer.swap(new_vtx_buffer);
- cmd_list->IdxBuffer.resize(0);
- TotalVtxCount += cmd_list->VtxBuffer.Size;
- }
- }
- // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than ImGui expects, or if there is a difference between your window resolution and framebuffer resolution.
- void ImDrawData::ScaleClipRects(const ImVec2& scale)
- {
- for (int i = 0; i < CmdListsCount; i++)
- {
- ImDrawList* cmd_list = CmdLists[i];
- for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
- {
- ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i];
- cmd->ClipRect = ImVec4(cmd->ClipRect.x * scale.x, cmd->ClipRect.y * scale.y, cmd->ClipRect.z * scale.x, cmd->ClipRect.w * scale.y);
- }
- }
- }
- //-----------------------------------------------------------------------------
- // ImFontAtlas
- //-----------------------------------------------------------------------------
- ImFontConfig::ImFontConfig()
- {
- FontData = NULL;
- FontDataSize = 0;
- FontDataOwnedByAtlas = true;
- FontNo = 0;
- SizePixels = 0.0f;
- OversampleH = 3;
- OversampleV = 1;
- PixelSnapH = false;
- GlyphExtraSpacing = ImVec2(0.0f, 0.0f);
- GlyphRanges = NULL;
- MergeMode = false;
- MergeGlyphCenterV = false;
- DstFont = NULL;
- memset(Name, 0, sizeof(Name));
- }
- ImFontAtlas::ImFontAtlas()
- {
- TexID = NULL;
- TexPixelsAlpha8 = NULL;
- TexPixelsRGBA32 = NULL;
- TexWidth = TexHeight = TexDesiredWidth = 0;
- TexUvWhitePixel = ImVec2(0, 0);
- }
- ImFontAtlas::~ImFontAtlas()
- {
- Clear();
- }
- void ImFontAtlas::ClearInputData()
- {
- for (int i = 0; i < ConfigData.Size; i++)
- if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas)
- {
- ImGui::MemFree(ConfigData[i].FontData);
- ConfigData[i].FontData = NULL;
- }
- // When clearing this we lose access to the font name and other information used to build the font.
- for (int i = 0; i < Fonts.Size; i++)
- if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size)
- {
- Fonts[i]->ConfigData = NULL;
- Fonts[i]->ConfigDataCount = 0;
- }
- ConfigData.clear();
- }
- void ImFontAtlas::ClearTexData()
- {
- if (TexPixelsAlpha8)
- ImGui::MemFree(TexPixelsAlpha8);
- if (TexPixelsRGBA32)
- ImGui::MemFree(TexPixelsRGBA32);
- TexPixelsAlpha8 = NULL;
- TexPixelsRGBA32 = NULL;
- }
- void ImFontAtlas::ClearFonts()
- {
- for (int i = 0; i < Fonts.Size; i++)
- {
- Fonts[i]->~ImFont();
- ImGui::MemFree(Fonts[i]);
- }
- Fonts.clear();
- }
- void ImFontAtlas::Clear()
- {
- ClearInputData();
- ClearTexData();
- ClearFonts();
- }
- void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
- {
- // Build atlas on demand
- if (TexPixelsAlpha8 == NULL)
- {
- if (ConfigData.empty())
- AddFontDefault();
- Build();
- }
- *out_pixels = TexPixelsAlpha8;
- if (out_width) *out_width = TexWidth;
- if (out_height) *out_height = TexHeight;
- if (out_bytes_per_pixel) *out_bytes_per_pixel = 1;
- }
- void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
- {
- // Convert to RGBA32 format on demand
- // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp
- if (!TexPixelsRGBA32)
- {
- unsigned char* pixels;
- GetTexDataAsAlpha8(&pixels, NULL, NULL);
- TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)(TexWidth * TexHeight * 4));
- const unsigned char* src = pixels;
- unsigned int* dst = TexPixelsRGBA32;
- for (int n = TexWidth * TexHeight; n > 0; n--)
- *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++));
- }
- *out_pixels = (unsigned char*)TexPixelsRGBA32;
- if (out_width) *out_width = TexWidth;
- if (out_height) *out_height = TexHeight;
- if (out_bytes_per_pixel) *out_bytes_per_pixel = 4;
- }
- ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
- {
- IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0);
- IM_ASSERT(font_cfg->SizePixels > 0.0f);
- // Create new font
- if (!font_cfg->MergeMode)
- {
- ImFont* font = (ImFont*)ImGui::MemAlloc(sizeof(ImFont));
- IM_PLACEMENT_NEW(font) ImFont();
- Fonts.push_back(font);
- }
- ConfigData.push_back(*font_cfg);
- ImFontConfig& new_font_cfg = ConfigData.back();
- if (!new_font_cfg.DstFont)
- new_font_cfg.DstFont = Fonts.back();
- if (!new_font_cfg.FontDataOwnedByAtlas)
- {
- new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize);
- new_font_cfg.FontDataOwnedByAtlas = true;
- memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
- }
- // Invalidate texture
- ClearTexData();
- return new_font_cfg.DstFont;
- }
- // Default font TTF is compressed with stb_compress then base85 encoded (see extra_fonts/binary_to_compressed_c.cpp for encoder)
- static unsigned int stb_decompress_length(unsigned char *input);
- static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsigned int length);
- static const char* GetDefaultCompressedFontDataTTFBase85();
- static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; }
- static void Decode85(const unsigned char* src, unsigned char* dst)
- {
- while (*src)
- {
- unsigned int tmp = Decode85Byte(src[0]) + 85*(Decode85Byte(src[1]) + 85*(Decode85Byte(src[2]) + 85*(Decode85Byte(src[3]) + 85*Decode85Byte(src[4]))));
- dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF); // We can't assume little-endianness.
- src += 5;
- dst += 4;
- }
- }
- // Load embedded ProggyClean.ttf at size 13, disable oversampling
- ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
- {
- ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
- if (!font_cfg_template)
- {
- font_cfg.OversampleH = font_cfg.OversampleV = 1;
- font_cfg.PixelSnapH = true;
- }
- if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "<default>");
- const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
- ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, 13.0f, &font_cfg, GetGlyphRangesDefault());
- return font;
- }
- ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
- {
- int data_size = 0;
- void* data = ImLoadFileToMemory(filename, "rb", &data_size, 0);
- if (!data)
- {
- IM_ASSERT(0); // Could not load file.
- return NULL;
- }
- ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
- if (font_cfg.Name[0] == '\0')
- {
- // Store a short copy of filename into into the font name for convenience
- const char* p;
- for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
- snprintf(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s", p);
- }
- return AddFontFromMemoryTTF(data, data_size, size_pixels, &font_cfg, glyph_ranges);
- }
- // NBM Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().
- ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
- {
- ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
- IM_ASSERT(font_cfg.FontData == NULL);
- font_cfg.FontData = ttf_data;
- font_cfg.FontDataSize = ttf_size;
- font_cfg.SizePixels = size_pixels;
- if (glyph_ranges)
- font_cfg.GlyphRanges = glyph_ranges;
- return AddFont(&font_cfg);
- }
- ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
- {
- const unsigned int buf_decompressed_size = stb_decompress_length((unsigned char*)compressed_ttf_data);
- unsigned char* buf_decompressed_data = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
- stb_decompress(buf_decompressed_data, (unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
- ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
- IM_ASSERT(font_cfg.FontData == NULL);
- font_cfg.FontDataOwnedByAtlas = true;
- return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges);
- }
- ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
- {
- int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
- void* compressed_ttf = ImGui::MemAlloc((size_t)compressed_ttf_size);
- Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
- ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
- ImGui::MemFree(compressed_ttf);
- return font;
- }
- bool ImFontAt