From 635576972024319c15141645d3304db8cd1d1e19 Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Mon, 8 Aug 2022 13:50:34 -0400 Subject: basic bezier path system added --- my_imgui_widgets.cpp | 293 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 260 insertions(+), 33 deletions(-) (limited to 'my_imgui_widgets.cpp') diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp index b4114e7..cb981c2 100644 --- a/my_imgui_widgets.cpp +++ b/my_imgui_widgets.cpp @@ -192,14 +192,27 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * } for (int h = 0; h < Layer->NumberOfEffects; h++) { effect *Effect = Layer->Effect[h]; - ImGui::Button("V"); ImGui::SameLine(); + ImGui::PushID(Effect); + // this is stupid + if (Effect->IsActive) + ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonHovered)); + else + ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_Button)); + if (ImGui::Button("V")) { + SwitchBool(Effect->IsActive); + State->UpdateFrame = true; + } + ImGui::SameLine(); + ImGui::PopStyleColor(); + ImGui::Button("R"); ImGui::SameLine(); ImGui::Text(Effect->Name); if (Effect->DisplayType == standard) { for (int i = 0; i < Effect->NumberOfProperties; i++) { property_channel *Property = &Effect->Property[i]; ImGui::PushID(Property); if (Property->VarType == type_real) - ImGui::DragScalar(Property->Name, ImGuiDataType_Float, &Property->CurrentValue.f, 0.005f, &Property->MaxVal.f, &Property->MaxVal.f, "%f"); + if (ImGui::DragScalar(Property->Name, ImGuiDataType_Float, &Property->CurrentValue.f, 0.005f, &Property->MaxVal.f, &Property->MaxVal.f, "%f")) + State->UpdateFrame = true; if (Property->VarType == type_color) if (ImGui::ColorEdit4("color 1", &Property->CurrentValue.f, ImGuiColorEditFlags_Float)) State->UpdateFrame = true; @@ -226,11 +239,76 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * ImGui::PopID(); } } else if (Effect->DisplayType == levels) { - real32 *Min = &Effect->Property[0].CurrentValue.f; - real32 *Mid = &Effect->Property[1].CurrentValue.f; - real32 *Max = &Effect->Property[2].CurrentValue.f; - ImGui::SliderLevels("f", Mid, Min, Max); + source *Source = Layer->Source; + layer_bitmap_info *BitmapInfo = &Layer->BitmapInfo; + + if (!BitmapInfo->HistogramVals) { + uint64 Size = Bitmap_CalcUnpackedBytes(Source->Info.Width, Source->Info.Height, Source->Info.BytesPerPixel); + BitmapInfo->HistogramVals = AllocateMemory(Memory, (sizeof(uint32) * 5 * 256), P_MiscCache); + Bitmap_CalcHistogram(BitmapInfo->HistogramVals, BitmapInfo->BitmapBuffer, Source->Info.BytesPerPixel, Size); + } + + char *LevelsButtons[5] = { "All", "Red", "Green", "Blue", "Alpha" }; + for (int i = 0; i < 5; i++) { + if (ImGui::Button(LevelsButtons[i])) { + BitmapInfo->LevelsSelector = i; + } + if (i != 4) { ImGui::SameLine(); } + } + + real32 *Min, *Mid, *Max; + if (BitmapInfo->LevelsSelector == 0) { + Min = &Effect->Property[0].CurrentValue.f; + Mid = &Effect->Property[1].CurrentValue.f; + Max = &Effect->Property[2].CurrentValue.f; + } else { + Min = &Effect->Property[3].CurrentValue.col.E[BitmapInfo->LevelsSelector - 1]; + Mid = &Effect->Property[4].CurrentValue.col.E[BitmapInfo->LevelsSelector - 1]; + Max = &Effect->Property[5].CurrentValue.col.E[BitmapInfo->LevelsSelector - 1]; + } + + if (BitmapInfo->LevelsSelector == 0) { + ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.6f, 0.6f, 0.6f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_PlotHistogramHovered, ImVec4(0.6f, 0.6f, 0.6f, 1.0f)); + } else if (BitmapInfo->LevelsSelector == 1) { + ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.9f, 0.6f, 0.6f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_PlotHistogramHovered, ImVec4(0.9f, 0.6f, 0.6f, 1.0f)); + } else if (BitmapInfo->LevelsSelector == 2) { + ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.6f, 0.9f, 0.6f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_PlotHistogramHovered, ImVec4(0.6f, 0.9f, 0.6f, 1.0f)); + } else if (BitmapInfo->LevelsSelector == 3) { + ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.6f, 0.6f, 0.9f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_PlotHistogramHovered, ImVec4(0.6f, 0.6f, 0.9f, 1.0f)); + } else if (BitmapInfo->LevelsSelector == 4) { + ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImVec4(0.9f, 0.9f, 0.9f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_PlotHistogramHovered, ImVec4(0.9f, 0.9f, 0.9f, 1.0f)); + } + + float *values = (float *)BitmapInfo->HistogramVals + 256*BitmapInfo->LevelsSelector; + int values_count = 256; + int values_offset = 0; + float scale_min = FLT_MIN; + float scale_max = FLT_MAX; + ImVec2 graph_size = ImVec2(0, 250); + int stride = sizeof(float); + + // The default histogram is good enough for what we need. + ImGui::PlotHistogram("##histo", values, values_count, values_offset, NULL, scale_min, scale_max, graph_size, stride); + // TODO(fox): Figure out the proper way to represent these IDs. + if (ImGui::SliderLevels("##one", "##two", "three", Mid, Min, Max)) + State->UpdateFrame = true; + + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + + if (State->UpdateFrame) { + uint64 Size = Bitmap_CalcUnpackedBytes(Source->Info.Width, Source->Info.Height, Source->Info.BytesPerPixel); + Bitmap_CalcHistogram(BitmapInfo->HistogramVals, BitmapInfo->BitmapBuffer, Source->Info.BytesPerPixel, Size); + } + + ImGui::Button("K"); } + ImGui::PopID(); } } else { char buf[256]; @@ -242,14 +320,12 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * ImGui::End(); } -static v2 -CalculateAnchorPointUV(project_layer *Layer, comp_buffer *Buffer); - static void ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer CompBuffer, ImGuiIO io, GLuint textureID) { - ImGui::Begin("Viewport"); + bool open = true; + ImGui::Begin("Viewport", &open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) UI->FocusedWindow = focus_viewport; @@ -272,6 +348,164 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer Comp draw_list->AddRectFilled(ViewportMin, ViewportMax, IM_COL32(50, 50, 50, 255)); draw_list->AddRect(ViewportMin, ViewportMax, IM_COL32(255, 255, 255, 255)); + // Actual composition texture + draw_list->PushClipRect(ViewportMin, ViewportMax, true); + draw_list->AddImage((void *)(intptr_t)textureID, ImVec2(UI->CompPos.x, UI->CompPos.y), + ImVec2(UI->CompPos.x + UI->CompZoom.x, UI->CompPos.y + UI->CompZoom.y)); + draw_list->PopClipRect(); + + // UI+interaction for layer + if (State->MostRecentlySelectedLayer > -1) { + project_layer *Layer = File.Layer[State->MostRecentlySelectedLayer]; + + // Anchor point + ImVec2 AUV = ImVec2(Layer->x.CurrentValue.f / CompBuffer.Width, Layer->y.CurrentValue.f / CompBuffer.Height); + ImVec2 ScreenAP = ImVec2(UI->CompPos.x + AUV.x * UI->CompZoom.x, UI->CompPos.y + AUV.y * UI->CompZoom.y); + draw_list->AddNgon(ScreenAP, 20, ImGui::GetColorU32(ImGuiCol_ScrollbarGrab), 8, 10.0f); + + // Mask points + if (Layer->NumberOfMasks) { + for (int i = 0; i < Layer->NumberOfMasks; i++) { + mask *Mask = &Layer->Mask[i]; + ImGui::PushID(i); + source *Source = Layer->Source; + + for (int p = 0; p < Mask->NumberOfPoints; p++) { + + mask_point *Point0 = &Mask->Point[p]; + mask_point *Point1 = &Mask->Point[p+1]; + if (p+1 == Mask->NumberOfPoints) + Point1 = &Mask->Point[0]; + + ImVec2 Point0_Pos = ImVec2(Point0->Pos.x, Point0->Pos.y); + ImVec2 Point0_Pos_Left = Point0_Pos + ImVec2(Point0->TangentLeft.x, Point0->TangentLeft.y); + ImVec2 Point0_Pos_Right = Point0_Pos + ImVec2(Point0->TangentRight.x, Point0->TangentRight.y); + + ImVec2 Point1_Pos = ImVec2(Point1->Pos.x, Point1->Pos.y); + ImVec2 Point1_Pos_Left = Point1_Pos + ImVec2(Point1->TangentLeft.x, Point1->TangentLeft.y); + ImVec2 Point1_Pos_Right = Point1_Pos + ImVec2(Point1->TangentRight.x, Point1->TangentRight.y); + + ImVec2 Point0_ScreenPos = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, V2(Point0_Pos)); + ImVec2 Point0_ScreenPos_Left = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, V2(Point0_Pos_Left)); + ImVec2 Point0_ScreenPos_Right = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, V2(Point0_Pos_Right)); + + ImVec2 Point1_ScreenPos = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, V2(Point1_Pos)); + ImVec2 Point1_ScreenPos_Left = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, V2(Point1_Pos_Left)); + ImVec2 Point1_ScreenPos_Right = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, V2(Point1_Pos_Right)); + + ImGui::PushID(p); + + ImU32 col = ImGui::GetColorU32(ImGuiCol_ScrollbarGrab); + + draw_list->AddNgon(Point0_ScreenPos, 10, col, 8, 5.0f); + draw_list->AddNgon(Point0_ScreenPos_Left, 10, col, 8, 5.0f); + draw_list->AddNgon(Point0_ScreenPos_Right, 10, col, 8, 5.0f); + + draw_list->AddLine(Point0_ScreenPos, Point0_ScreenPos_Left, col, 2.0f); + draw_list->AddLine(Point0_ScreenPos, Point0_ScreenPos_Right, col, 2.0f); + + ImU32 col2 = ImGui::GetColorU32(ImGuiCol_Button); + + + real32 PointSize = 40; + + + // Ratio of the point along the curve. See internal for more info. + float ratio; + + if (ImGui::BezierInteractive(Point0_ScreenPos, Point0_ScreenPos_Right, + Point1_ScreenPos_Left, Point1_ScreenPos, ratio)) + { + // Using a button like this may be kinda janky, but it gives us access + // to all of ButtonBehavior and the ID system without having to rewrite it. + ImGui::SetCursorScreenPos(io.MousePos - ImVec2(5,5)); + ImGui::Button("maskbezier", ImVec2(10, 10)); + + if(ImGui::IsItemHovered()) { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); + draw_list->AddNgon(io.MousePos, 2, col, 8, 5.0f); + ImVec2 RatioLeft = ImGui::RatioToPoint(Point0_ScreenPos, Point0_ScreenPos_Right, ratio); + ImVec2 RatioTop = ImGui::RatioToPoint(Point0_ScreenPos_Right, Point1_ScreenPos_Left, ratio); + ImVec2 RatioRight = ImGui::RatioToPoint(Point1_ScreenPos_Left, Point1_ScreenPos, ratio); + ImVec2 TangentLeft = ImGui::RatioToPoint(RatioLeft, RatioTop, ratio); + ImVec2 TangentRight = ImGui::RatioToPoint(RatioTop, RatioRight, ratio); + draw_list->AddLine(RatioLeft, RatioTop, col, 2.0f); + draw_list->AddLine(RatioRight, RatioTop, col, 2.0f); + draw_list->AddLine(TangentLeft, TangentRight, col, 2.0f); + } + if(ImGui::IsItemActivated() && io.KeyCtrl) { + ImVec2 Ratio0 = ImGui::RatioToPoint(Point0_Pos, Point0_Pos_Right, ratio); + ImVec2 RatioTop = ImGui::RatioToPoint(Point0_Pos_Right, Point1_Pos_Left, ratio); + ImVec2 Ratio1 = ImGui::RatioToPoint(Point1_Pos_Left, Point1_Pos, ratio); + ImVec2 TangentLeft = ImGui::RatioToPoint(Ratio0, RatioTop, ratio); + ImVec2 TangentRight = ImGui::RatioToPoint(RatioTop, Ratio1, ratio); + ImVec2 Point = ImGui::RatioToPoint(TangentLeft, TangentRight, ratio); + Mask_AddPoint(Mask, Point, Point - TangentLeft, Point - TangentRight, + Point0_Pos - Ratio0, Point1_Pos - Ratio1, p); + } + } + + DebugWatchVar("ratio", &ratio, d_float); + + // if (ImGui::TestLine(PointScreenPos[0], PointScreenPos[1])) { + // } + + // loops over point and handles + for (int b = 0; b < 3; b++) + { + ImGui::PushID(b); + if (b == 0) { + ImGui::SetCursorScreenPos(Point0_ScreenPos - ImVec2(PointSize/2, PointSize/2)); + } else if (b == 1) { + ImGui::SetCursorScreenPos(Point0_ScreenPos_Left - ImVec2(PointSize/2, PointSize/2)); + } else { + ImGui::SetCursorScreenPos(Point0_ScreenPos_Right - ImVec2(PointSize/2, PointSize/2)); + } + + ImGui::Button("##point", ImVec2(PointSize, PointSize)); + + if (ImGui::IsItemHovered()) { + ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); + } + if (ImGui::IsItemActive()) { + // TODO(fox): Combine this with the anchor point code. + ImVec2 MouseIncrement = io.MouseDelta * (ImVec2(CompBuffer.Width, CompBuffer.Height) / UI->CompZoom); + real32 Rad = (Layer->rotation.CurrentValue.f * (PI / 180)); + real32 s = Layer->scale.CurrentValue.f; + v2 XAxis = V2(cos(Rad), sin(Rad)) * (MouseIncrement.x / s); + v2 YAxis = V2(sin(Rad), -cos(Rad)) * (MouseIncrement.y / -s); + + if (b == 0) { + Point0->Pos.x += XAxis.x; + Point0->Pos.y -= XAxis.y; + Point0->Pos.x -= YAxis.x; + Point0->Pos.y += YAxis.y; + } else if (b == 1) { + Point0->TangentLeft.x += XAxis.x; + Point0->TangentLeft.y -= XAxis.y; + Point0->TangentLeft.x -= YAxis.x; + Point0->TangentLeft.y += YAxis.y; + } else { + Point0->TangentRight.x += XAxis.x; + Point0->TangentRight.y -= XAxis.y; + Point0->TangentRight.x -= YAxis.x; + Point0->TangentRight.y += YAxis.y; + } + } + ImGui::PopID(); + } + + + ImGui::PopID(); + } + ImGui::PopID(); + } + } + } + + // Interactions for dragging and zooming + ImGui::SetCursorScreenPos(ViewportMin); + ImGui::InvisibleButton("canvas", ViewportScale, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); bool32 IsHovered = ImGui::IsItemHovered(); bool32 IsActive = ImGui::IsItemActive(); @@ -300,10 +534,7 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer Comp UI->CompPos.x += io.MouseDelta.x; UI->CompPos.y += io.MouseDelta.y; } - // if (IsActive && ImGui::IsMouseDown(ImGuiMouseButton_Right)) - // { - // Debug.ToggleRenders = true; - // } + ImGui::OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonMiddle); if (ImGui::BeginPopup("context")) { if (ImGui::MenuItem("Scalar", NULL, false, InstructionMode != instruction_mode_scalar)) { InstructionMode = instruction_mode_scalar; State->UpdateFrame = true; } @@ -311,6 +542,7 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer Comp if (ImGui::MenuItem("AVX2", NULL, false, InstructionMode != instruction_mode_avx)) { InstructionMode = instruction_mode_avx; State->UpdateFrame = true; } ImGui::EndPopup(); } + if (IsActive && ImGui::IsMouseDragging(ImGuiMouseButton_Left, -1.0f) && ImGui::IsKeyDown(ImGuiKey_Z)) { real32 Distance = io.MouseDelta.x + io.MouseDelta.y; @@ -320,19 +552,6 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer Comp UI->CompPos.y -= Distance*UI->TempZoomRatio.y; } - draw_list->PushClipRect(ViewportMin, ViewportMax, true); - draw_list->AddImage((void *)(intptr_t)textureID, ImVec2(UI->CompPos.x, UI->CompPos.y), - ImVec2(UI->CompPos.x + UI->CompZoom.x, UI->CompPos.y + UI->CompZoom.y)); - - if (State->MostRecentlySelectedLayer > -1) { - project_layer *Layer = File.Layer[State->MostRecentlySelectedLayer]; - ImVec2 AUV = ImVec2(Layer->x.CurrentValue.f / CompBuffer.Width, Layer->y.CurrentValue.f / CompBuffer.Height); - ImVec2 ScreenAP = ImVec2(UI->CompPos.x + AUV.x * UI->CompZoom.x, UI->CompPos.y + AUV.y * UI->CompZoom.y); - draw_list->AddNgon(ScreenAP, 20, ImGui::GetColorU32(ImGuiCol_ScrollbarGrab), 8, 10.0f); - } - - draw_list->PopClipRect(); - ImGui::Text("%.1f", 100.0f * (UI->CompZoom.x / CompBuffer.Width)); if (State->MsgTime > 0) { ImGui::SameLine(); @@ -402,14 +621,21 @@ ImGui_File(project_data *File, project_state *State, memory *Memory, ui *UI, ImG } ImGui::Text("Sources:"); for (int i = 0; i < File->NumberOfSources; i++) { - ImGui::Text(File->Source[i].Path); + bool32 Test = false; + if (File->SourceSelected == i) + Test = true; + ImGui::Selectable(File->Source[i].Path, Test); + if (ImGui::IsItemClicked()) + File->SourceSelected = i; + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) + File->SourceSelected = i; ImGui::OpenPopupOnItemClick("sourcecontext", ImGuiPopupFlags_MouseButtonRight); - if (ImGui::BeginPopup("sourcecontext")) { - if (ImGui::MenuItem("Create layer from source")) { - Layer_CreateFromSource(File, State, Memory, &File->Source[i]); - } - ImGui::EndPopup(); + } + if (ImGui::BeginPopup("sourcecontext")) { + if (ImGui::MenuItem("Create layer from source")) { + Layer_CreateFromSource(File, State, Memory, &File->Source[File->SourceSelected]); } + ImGui::EndPopup(); } // static char Input[1024]; // ImGui::InputText("##sourceinput", Input, STRING_SIZE); @@ -427,6 +653,7 @@ ImGui_File(project_data *File, project_state *State, memory *Memory, ui *UI, ImG ImGui::Text("%s: %u", Debug.String[i], Debug.Val[i].u); } } + Debug = {}; #endif ImGui::End(); } -- cgit v1.2.3