diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 11f6cd704..4ec8699c9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -137,6 +137,7 @@ HOW TO UPDATE? Thickness=2.0f blurry sharp sharp sharp sharp Thickness=3.0f sharp sharp sharp blurry sharp ------------------------------------------------------------------------ +- Added ImDrawList::PushDrawFlag()/PopDrawFlag() to alter certain flags for a scope. - (Breaking) AddRect, AddCircle, AddNgon, AddEllipse: defaulting to "inside" stroke. - All closed shapes with thickness=1.0f will appear identical. - The difference for thickness>1.0f shapes may be minimal since very large strokes diff --git a/imgui.cpp b/imgui.cpp index cf9d18328..4cceb89e5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -23582,10 +23582,9 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, con Selectable(buf, false); if (fg_draw_list && IsItemHovered()) { - ImDrawFlags backup_flags = fg_draw_list->Flags; - fg_draw_list->Flags &= ~ImDrawFlags_AALines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + fg_draw_list->PushDrawFlag(ImDrawFlags_AALines, false); // Disable AA on triangle outlines is more readable for very large and thin triangles. fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), 1.0f, ImDrawFlags_Closed); - fg_draw_list->Flags = backup_flags; + fg_draw_list->PopDrawFlag(); } } TreePop(); @@ -23601,8 +23600,7 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co // Draw wire-frame version of all triangles ImRect clip_rect = draw_cmd->ClipRect; ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); - ImDrawFlags backup_flags = out_draw_list->Flags; - out_draw_list->Flags &= ~ImDrawFlags_AALines; // Disable AA on triangle outlines is more readable for very large and thin triangles. + out_draw_list->PushDrawFlag(ImDrawFlags_AALines, false); // Disable AA on triangle outlines is more readable for very large and thin triangles. for (unsigned int idx_n = draw_cmd->IdxOffset, idx_end = draw_cmd->IdxOffset + draw_cmd->ElemCount; idx_n < idx_end; ) { ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL; // We don't hold on those pointers past iterations as ->AddPolyline() may invalidate them if out_draw_list==draw_list @@ -23620,7 +23618,7 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co out_draw_list->AddRect(ImTrunc(clip_rect.Min), ImTrunc(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU out_draw_list->AddRect(ImTrunc(vtxs_rect.Min), ImTrunc(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles } - out_draw_list->Flags = backup_flags; + out_draw_list->PopDrawFlag(); } // [DEBUG] Compute mask of inputs with the same codepoint. diff --git a/imgui.h b/imgui.h index a6460850e..d80ef0d54 100644 --- a/imgui.h +++ b/imgui.h @@ -3001,6 +3001,19 @@ struct ImGuiStorage #endif }; +// [Internal] Used for small stacks. Do not use. +template +struct ImSmallStack_ +{ + T LocalData[Capacity]; // FIXME: should evolve into using heap, e.g union {} with T* HeapData + add SZ_T Capacity. + SZ_T Size = 0; + + inline void clear() { Size = 0; } + inline T& back() { IM_ASSERT(Size > 0); return LocalData[Size - 1]; } + inline void push_back(const T& v) { IM_ASSERT(Size < Capacity); memcpy(&LocalData[Size], &v, sizeof(v)); Size++; } + inline void pop_back() { IM_ASSERT(Size > 0); Size--; } +}; + // Flags for ImGuiListClipper (currently not fully exposed in function calls: a future refactor will likely add this to ImGuiListClipper::Begin function equivalent) enum ImGuiListClipperFlags_ { @@ -3416,9 +3429,8 @@ enum ImDrawFlags_ // About usage of flags: // - "Prim" column: 'OK' = flag can be used to configure an individual AddXXX() call. - // - "Scope" column: 'OK' = initialized by ImGui based on Style options (e.g. whether anti-aliased is enabled). + // - "Scope" column: 'OK' = initialized by ImGui based on Style options (e.g. whether anti-aliased is enabled) + may be modified using ImDrawList::PushDrawFlag(). // OK(0)/OK(1) indicates whether this flag is set in the default ImGui Style settings. - // (flag will be possible to alter in a scope using PushDrawFlags()). // - Rounding default to ImDrawFlags_RoundCornersAll when 'rounding > 0'. // - So you only need to use the _RoundCorners flags if you want a special configuration (e.g. a rectangle with one rounded corner). @@ -3468,7 +3480,7 @@ enum ImDrawFlags_ ImDrawFlags_UseVtxOffset = 1 << 23, // -- OK(1) // Can emit 'VtxOffset > 0' to allow large meshes with 16-bit ImDrawIdx. Used by default when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled by the backend. // [Internal] - ImDrawFlags_AllowedInScope_ = ImDrawFlags_AAFill | ImDrawFlags_AALines | ImDrawFlags_AALineEnds | ImDrawFlags_StrokeLegacy | ImDrawFlags_TextNoPixelSnap | ImDrawFlags_UseTexForRoundCorners | ImDrawFlags_UseTexForStrokeLegacy | ImDrawFlags_UseVtxOffset, // [Internal] Values allowed in scope e.g. incoming PushDrawFlags() stack. + ImDrawFlags_AllowedInScope_ = ImDrawFlags_AAFill | ImDrawFlags_AALines | ImDrawFlags_AALineEnds | ImDrawFlags_StrokeLegacy | ImDrawFlags_TextNoPixelSnap | ImDrawFlags_UseTexForRoundCorners | ImDrawFlags_UseTexForStrokeLegacy | ImDrawFlags_UseVtxOffset, // [Internal] Values allowed in PushDrawFlag() scope. ImDrawFlags_RoundCornersMask_ = ImDrawFlags_RoundCornersAll | ImDrawFlags_RoundCornersNone, // [Internal] ImDrawFlags_StrokeMask_ = 0x07 << 17, // [Internal] ImDrawFlags_InvalidMask_ = ~0x7FFFFFF0, // [Internal] == 0x8000000F. Reserved to detect misuses. @@ -3489,7 +3501,7 @@ struct ImDrawList ImVector CmdBuffer; // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback. ImVector IdxBuffer; // Index buffer. Each command consume ImDrawCmd::ElemCount of those ImVector VtxBuffer; // Vertex buffer. - ImDrawFlags Flags; // Current flags for drawing primitives. You may poke into these to adjust anti-aliasing settings per-primitive. Will be exposed as PushDrawFlags(). + ImDrawFlags Flags; // Current flags for drawing primitives. You may poke into these to adjust anti-aliasing settings per-primitive. Alter with PushDrawFlag(). // [Internal, used while building lists] unsigned int _VtxCurrentIdx; // [Internal] generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0. @@ -3502,6 +3514,7 @@ struct ImDrawList ImVector _ClipRectStack; // [Internal] ImVector _TextureStack; // [Internal] ImVector _CallbacksDataBuf; // [Internal] + ImSmallStack_ _DrawFlagsStack;// [Internal] float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content float _InvFringeScale; // [internal] 1.0 / _FringeScale // FIXME: Consider renaming to _PixelDensity. bool _FringeScaleIsInteger; // [Internal] true if 1/_FringeScale is a whole number, used to select fast path for rendering @@ -3517,6 +3530,8 @@ struct ImDrawList IMGUI_API void PopClipRect(); IMGUI_API void PushTexture(ImTextureRef tex_ref); IMGUI_API void PopTexture(); + IMGUI_API void PushDrawFlag(ImDrawFlags flags, bool enabled); // [BETA] Please notify me if you are using this. + IMGUI_API void PopDrawFlag(); inline ImVec2 GetClipRectMin() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.x, cr.y); } inline ImVec2 GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); } @@ -3658,7 +3673,6 @@ struct ImDrawList IMGUI_API void _AddRectTinyRounding(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, float thickness, ImDrawFlags flags); IMGUI_API void _SelectFringeTexture(float screen_thickness, ImVec4* out_tex_uvs, float* out_fringe); IMGUI_API float _CalculateCenterBiasedOffset(float thickness); - }; // All draw data to render a Dear ImGui frame diff --git a/imgui_demo.cpp b/imgui_demo.cpp index df5b16d8d..2b4eb408e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -10488,8 +10488,8 @@ static void ShowExampleAppCustomRendering(bool* p_open) ImGui::PopID(); ImGui::Spacing(); - ImDrawFlags backup_draw_list_flags = draw_list->Flags; - draw_list->Flags = (draw_list->Flags & ~ImDrawFlags_AllowedInScope_) | scope_flags; // Equivalent to an hypothetical PushDrawFlags() API + draw_list->PushDrawFlag(ImDrawFlags_AllowedInScope_, false); // Reset all existing (very unusual: done for this demo) + draw_list->PushDrawFlag(scope_flags, true); const ImDrawFlags flags = prim_stroke_flags | prim_other_flags; const ImDrawFlags fill_flags = flags & (ImDrawFlags_AAFill | ImDrawFlags_UseTexForRoundCorners); @@ -10622,11 +10622,12 @@ static void ShowExampleAppCustomRendering(bool* p_open) } ImGui::Dummy(ImVec2((sz + spacing) * 15.0f, (sz + spacing) * 4.0f)); + draw_list->PopDrawFlag(); + draw_list->PopDrawFlag(); + ImGui::PopItemFlag(); ImGui::PopItemWidth(); ImGui::EndTabItem(); - - draw_list->Flags = backup_draw_list_flags; } if (ImGui::BeginTabItem("Canvas")) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 926c3220e..e1e3ed8fd 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -476,6 +476,7 @@ void ImDrawList::_ResetForNewFrame() _ClipRectStack.resize(0); _TextureStack.resize(0); _CallbacksDataBuf.resize(0); + _DrawFlagsStack.clear(); _Path.resize(0); _Splitter.Clear(); CmdBuffer.push_back(ImDrawCmd()); @@ -494,6 +495,7 @@ void ImDrawList::_ClearFreeMemory() _ClipRectStack.clear(); _TextureStack.clear(); _CallbacksDataBuf.clear(); + _DrawFlagsStack.clear(); _Path.clear(); _Splitter.ClearFreeMemory(); } @@ -717,6 +719,24 @@ void ImDrawList::PopTexture() _OnChangedTexture(); } +// IMPORTANT: currently limited to 3 deep +void ImDrawList::PushDrawFlag(ImDrawFlags flags, bool enabled) +{ + IM_ASSERT((flags & ~ImDrawFlags_AllowedInScope_) == 0); + _DrawFlagsStack.push_back(Flags); + if (enabled) + Flags |= flags; + else + Flags &= ~flags; +} + +void ImDrawList::PopDrawFlag() +{ + IM_ASSERT_USER_ERROR_RET(_DrawFlagsStack.Size > 0, "Calling PopDrawFlags() too many times!"); + Flags = _DrawFlagsStack.back(); + _DrawFlagsStack.pop_back(); +} + // This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTexture()/PopTexture(). void ImDrawList::_SetTexture(ImTextureRef tex_ref) { @@ -3144,7 +3164,7 @@ void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_ radius = ImMax(0.01f, radius); - // Check overestimate first before testing details. + // Check overestimate first before testing details (+1.0f is intended, not FringeScale) if (radius < (thickness * 2.0f + 1.0f)) { const float unit_apothem = ImCos(IM_PI / (float)num_segments); @@ -5349,7 +5369,7 @@ static void ImFontAtlasBuildUpdateTexDataCorners(ImFontAtlas* atlas) const int pitch = tex->Width; for (int ly = 0; ly < h; ly++) { - for (int lx = 0; lx < h; lx++) + for (int lx = 0; lx < w; lx++) write_ptr[lx] = SampleCorner((float)lx + 0.5f, (float)ly + 0.5f, line_normals, line_distances, num_lines) & DEBUG_TEX_CORNER_U8(lx, h); write_ptr += pitch; } @@ -5360,7 +5380,7 @@ static void ImFontAtlasBuildUpdateTexDataCorners(ImFontAtlas* atlas) const int pitch = tex->Width; for (int ly = 0; ly < h; ly++) { - for (int lx = 0; lx < h; lx++) + for (int lx = 0; lx < w; lx++) write_ptr[lx] = IM_COL32(255, 255, 255, SampleCorner((float)lx + 0.5f, (float)ly + 0.5f, line_normals, line_distances, num_lines)) & DEBUG_TEX_CORNER_U32(lx, h); write_ptr += pitch; }