Skip to content

Commit

Permalink
add curve demo pane
Browse files Browse the repository at this point in the history
add a helper "HelpManipulateControlPoint" for control point manipulation
  • Loading branch information
aiekick committed Dec 21, 2020
1 parent 2e48c2d commit 09ddc92
Showing 1 changed file with 122 additions and 0 deletions.
122 changes: 122 additions & 0 deletions imgui_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,55 @@ static void HelpMarker(const char* desc)
}
}

// Helper to interact with a control point
// mouse left click/move for move the control point
static ImVec2 HelpManipulateControlPoint(const int point_index, ImVec2& point_coords, const float point_radius, const ImVec4 canvas)
{
static int selected_control_point = -1;

// current point control
ImVec2 point = ImVec2(canvas.x + point_coords.x * canvas.z, canvas.y + point_coords.y * canvas.w);

bool hovered = false;
if (ImGui::IsItemHovered())
{
if (ImGui::IsMouseHoveringRect(
ImVec2(point.x - point_radius * 0.5f, point.y - point_radius * 0.5f),
ImVec2(point.x + point_radius * 0.5f, point.y + point_radius * 0.5f)))
{
hovered = true;

// select if active and no point was selected before
// for have only one point movable at same time
if (selected_control_point < 0 && ImGui::IsItemActive())
selected_control_point = point_index;
}
}

ImDrawList* draw_list = ImGui::GetWindowDrawList();
// draw point background color
draw_list->AddCircleFilled(point, point_radius,
(selected_control_point == point_index) ? IM_COL32(0, 0, 255, 255) :
(hovered) ? IM_COL32(0, 127, 127, 255) : IM_COL32(255, 0, 0, 255));
// draw point edge
draw_list->AddCircle(point, point_radius, IM_COL32(255, 255, 255, 255), 0, 2.0f);

// unselect point
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left))
selected_control_point = -1;

// move point, will be updated on next frame
if (selected_control_point == point_index &&
ImGui::IsMouseDragging(ImGuiMouseButton_Left, 0.0f))
{
ImGuiIO& io = ImGui::GetIO();
point_coords.x += io.MouseDelta.x / (canvas.z + 1e-5f);
point_coords.y += io.MouseDelta.y / (canvas.w + 1e-5f);
}

return point;
}

// Helper to display basic user controls.
void ImGui::ShowUserGuide()
{
Expand Down Expand Up @@ -7106,6 +7155,79 @@ static void ShowExampleAppCustomRendering(bool* p_open)
ImGui::EndTabItem();
}

if (ImGui::BeginTabItem("Curves"))
{
static ImVec2 bezier_control_points[4] = { ImVec2(0.12, 0.82), ImVec2(0.34, 0.21), ImVec2(0.90, 0.41), ImVec2(0.56, 0.82) }; // ratio of canvas size
static float control_point_radius = 10.0f;
static int curve_type = 0; // 0 quadratic, 1 cubic
static bool curve_segments_override = false;
static int curve_segments_override_v = 8;

ImGui::RadioButton("Quad Bezier", &curve_type, 0);
ImGui::SameLine(); HelpMarker("a Quad bezier have 3 control points;");
ImGui::SameLine(); ImGui::RadioButton("Cubic Bezier", &curve_type, 1);
ImGui::SameLine(); HelpMarker("a Cubic bezier have 4 control points;");
ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override);
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
if (ImGui::SliderInt("Curves segments", &curve_segments_override_v, 3, 40))
curve_segments_override = true;

ImGui::Text("Mouse Left : move control points");

// canvas from last tab
// Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive()
ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f;
ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);

// Draw border and background color
ImGuiIO& io = ImGui::GetIO();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));

// This will catch our interactions, only left button, no scrolling on this one
ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft);
ImVec4 canvas_rc = ImVec4(canvas_p0.x, canvas_p0.y, canvas_p1.x - canvas_p0.x, canvas_p1.y - canvas_p0.y);

draw_list->PushClipRect(canvas_p0, canvas_p1, true); // canvas clipping
{
draw_list->ChannelsSplit(2); // split channels

// calc and render control point in top layer
draw_list->ChannelsSetCurrent(1);
ImVec2 cp[4]; // control point
for (int i = 0; i < 3 + curve_type; i++) // 3 when curve is quadratic, 4 when curve is cubic
{
cp[i] = HelpManipulateControlPoint(i, bezier_control_points[i], control_point_radius, canvas_rc);
}

// render curve and edges in bottom layer
draw_list->ChannelsSetCurrent(0);
const ImU32 curve_color = IM_COL32(255, 255, 0, 255);
const int curve_segments = curve_segments_override ? curve_segments_override_v : 0;
if (curve_type) // bezier cubic
{
draw_list->AddBezierCubic(cp[0], cp[1], cp[2], cp[3], curve_color, 2.0f, curve_segments); // curve
draw_list->AddLine(cp[0], cp[1], IM_COL32(255, 255, 255, 255), 1.5f); // edge from control point 0 to 1
draw_list->AddLine(cp[2], cp[3], IM_COL32(255, 255, 255, 255), 1.5f); // edge from control point 2 to 3
}
else // bezier quadratic
{
draw_list->AddBezierQuadratic(cp[0], cp[1], cp[2], curve_color, 2.0f, curve_segments); // curve
draw_list->AddLine(cp[0], cp[1], IM_COL32(255, 255, 255, 255), 1.5f); // edge from control point 0 to 1
draw_list->AddLine(cp[1], cp[2], IM_COL32(255, 255, 255, 255), 1.5f); // edge from control point 2 to 3
}

draw_list->ChannelsMerge(); // merge channels
}
draw_list->PopClipRect();

ImGui::EndTabItem();
}

ImGui::EndTabBar();
}

Expand Down

0 comments on commit 09ddc92

Please sign in to comment.