summaryrefslogtreecommitdiff
path: root/src/imgui_ui_properties.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/imgui_ui_properties.cpp')
-rw-r--r--src/imgui_ui_properties.cpp441
1 files changed, 441 insertions, 0 deletions
diff --git a/src/imgui_ui_properties.cpp b/src/imgui_ui_properties.cpp
new file mode 100644
index 0000000..5fda218
--- /dev/null
+++ b/src/imgui_ui_properties.cpp
@@ -0,0 +1,441 @@
+static void
+ImGui_Properties_RGBASwitch(project_state *State, memory *Memory, ImGuiIO io, uint32 *Channel)
+{
+ char *Names[5] = {"All", "R", "G", "B", "A" };
+ if (ImGui::BeginListBox("RGB")) {
+ for (int i = 0; i < 5; i++) {
+ if (ImGui::Selectable(Names[i], (*Channel == i))) {
+ *Channel = i;
+ }
+ }
+ ImGui::EndListBox();
+ }
+}
+
+static void
+ImGui_Properties_Slider(project_state *State, memory *Memory, property_channel *Property, ImGuiIO &io, ImVec2 WindowMinAbs, ImVec2 WindowMaxAbs, memory_table_list Table)
+{
+ if (ImGui::IsItemActive()) {
+ State->UpdateFrame = true;
+ // ImGui_WarpMouse(State, io.MousePos, WindowMinAbs, WindowMaxAbs, 1);
+ }
+
+ if (ImGui::IsItemActivated()) {
+ State->Interact_Offset[0] = Property->CurrentValue;
+ State->Interact_Active = interact_type_slider_scrub;
+ }
+ if (ImGui::IsItemDeactivatedAfterEdit()) {
+ // Pressing Esc while dragging a slider conveniently stops the input in
+ // ImGui, so all we need to do is set it back:
+ if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
+ Property->CurrentValue = State->Interact_Offset[0];
+ } else if (!Property->Keyframe_Count) {
+ History_Entry_Commit(Memory, "Property interact");
+ real32 Temp = Property->CurrentValue;
+ Property->CurrentValue = State->Interact_Offset[0];
+ History_Action_Swap(Memory, Table, sizeof(Property->CurrentValue), &Property->CurrentValue);
+ Property->CurrentValue = Temp;
+ History_Entry_End(Memory);
+ }
+ State->Interact_Active = interact_type_none;
+ // State->UpdateFrame = true;
+ // State->Warp_X = 0;
+ // State->Warp_Y = 0;
+ }
+}
+
+
+static void
+ImGui_Properties_CurvesUI(project_state *State, memory *Memory, ImGuiIO io, block_effect *Effect, property_channel *PropertyStart, uint16 *SortedPointStart)
+{
+
+ real32 Padding = ImGui::GetFontSize()*6;
+ ImVec2 ViewportMin = ImGui::GetCursorScreenPos() + Padding/6;
+ ImVec2 ViewportScale = ImGui::GetContentRegionAvail();
+ ViewportScale.y = ViewportScale.x = ViewportScale.x - Padding; // square seems nice
+ ImVec2 ViewportMax = ViewportMin + ViewportScale;
+
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+ draw_list->AddRectFilled(ViewportMin, ViewportMax, IM_COL32(50, 50, 50, 255));
+ draw_list->AddRect(ViewportMin, ViewportMax, IM_COL32(255, 255, 255, 255));
+
+ real32 PointSize = 40;
+
+ ImU32 col = ImGui::GetColorU32(ImGuiCol_Text);
+ ImU32 col_light = ImGui::GetColorU32(ImGuiCol_TextDisabled);
+
+ ImVec2 Point_ScreenPos[4];
+
+ // ocd?
+ draw_list->PushClipRect(ViewportMin + 2, ViewportMax - 2, true);
+
+ for (real32 i = 0.25; i < 1.0; i += 0.25) {
+ ImVec2 Horizontal = ViewportMin + ViewportScale * ImVec2(0, i);
+ ImVec2 Vertical = ViewportMin + ViewportScale * ImVec2(i, 0);
+ draw_list->AddLine(Horizontal, Horizontal + ImVec2(ViewportScale.x, 0), col_light, 1.0f);
+ draw_list->AddLine(Vertical, Vertical + ImVec2(0, ViewportScale.y), col_light, 1.0f);
+ }
+
+ draw_list->PopClipRect();
+
+ uint32 *SelectedChannel = (uint32 *)&Effect->ExtraData[5];
+ real32 *Num = &Effect->ExtraData[*SelectedChannel];
+
+ v2 Pos = {};
+ bool32 AddPoint = 0;
+
+ for (uint32 i = 0; i < *(uint32 *)Num; i += 1) {
+
+ v2 Point_P1 = Effect_V2(Memory, Effect, SortedPointStart[i]);
+ v2 Point_P2 = Effect_V2(Memory, Effect, SortedPointStart[i + 1]);
+ v2 Point_P0 = (i != 0) ? Effect_V2(Memory, Effect, SortedPointStart[i - 1]) : V2(0, 0);
+ v2 Point_P3 = (i != (*Num - 2)) ? Effect_V2(Memory, Effect, SortedPointStart[i + 2]) : V2(1, 1);
+
+ ImVec2 Point_P0_ScreenPos = ViewportMin + (ImVec2(Point_P0.x, 1.0f - Point_P0.y) * ViewportScale);
+ ImVec2 Point_P1_ScreenPos = ViewportMin + (ImVec2(Point_P1.x, 1.0f - Point_P1.y) * ViewportScale);
+ ImVec2 Point_P2_ScreenPos = ViewportMin + (ImVec2(Point_P2.x, 1.0f - Point_P2.y) * ViewportScale);
+ ImVec2 Point_P3_ScreenPos = ViewportMin + (ImVec2(Point_P3.x, 1.0f - Point_P3.y) * ViewportScale);
+
+ ImGui::PushID(&PropertyStart[SortedPointStart[i]]);
+
+ draw_list->AddNgon(Point_P1_ScreenPos, 2, col, 8, 5.0f);
+
+ ImGui::SetCursorScreenPos(Point_P1_ScreenPos - ImVec2(PointSize/2, PointSize/2));
+ ImGui::InvisibleButton("##point", ImVec2(PointSize, PointSize), ImGuiButtonFlags_MouseButtonLeft);
+
+ if (ImGui::IsItemHovered()) {
+ ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
+ }
+
+ if (ImGui::IsItemActivated()) {
+ if (io.KeyCtrl && *Num != 2) {
+ History_Entry_Commit(Memory, "Curves delete point");
+ property_channel *Property_X = Effect_Property(Memory, Effect, SortedPointStart[i]);
+ History_Action_Swap(Memory, F_Properties, sizeof(Property_X->Identifier), &Property_X->Identifier);
+ Property_X->Identifier = -1;
+ property_channel *Property_Y = Effect_Property(Memory, Effect, SortedPointStart[i]+1);
+ History_Action_Swap(Memory, F_Properties, sizeof(Property_Y->Identifier), &Property_Y->Identifier);
+ Property_Y->Identifier = -1;
+ History_Action_Swap(Memory, F_Effects, sizeof(Effect->ExtraData[*SelectedChannel]), &Effect->ExtraData[*SelectedChannel]);
+ Effect->ExtraData[*SelectedChannel]--;
+ History_Entry_End(Memory);
+ }
+ }
+
+ if (ImGui::IsItemActive()) {
+ if (io.MouseDelta.x || io.MouseDelta.y) {
+ property_channel *Property_X = Effect_Property(Memory, Effect, SortedPointStart[i]);
+ property_channel *Property_Y = Effect_Property(Memory, Effect, SortedPointStart[i]+1);
+ v2 Point = V2(((io.MousePos - ViewportMin) / ViewportScale));
+ if (State->Interact_Active == interact_type_none) {
+ State->Interact_Active = interact_type_slider_scrub;
+ State->Interact_Offset[0] = Property_X->CurrentValue;
+ State->Interact_Offset[1] = Property_Y->CurrentValue;
+ }
+ Point.y = 1.0f - Point.y;
+ Point.x = Normalize(Point.x);
+ Point.y = Normalize(Point.y);
+ Property_X->CurrentValue = Point.x;
+ Property_Y->CurrentValue = Point.y;
+ State->UpdateFrame = true;
+ }
+ }
+
+ if (ImGui::IsItemDeactivated()) {
+ if (State->Interact_Active == interact_type_slider_scrub) {
+ History_Entry_Commit(Memory, "Curves change point pos");
+ property_channel *Property[2] = { Effect_Property(Memory, Effect, SortedPointStart[i]),
+ Effect_Property(Memory, Effect, SortedPointStart[i]+1) };
+ for (int a = 0; a < 2; a++)
+ {
+ real32 Temp = Property[a]->CurrentValue;
+ Property[a]->CurrentValue = State->Interact_Offset[a];
+ History_Action_Swap(Memory, F_Properties, sizeof(Property[a]->CurrentValue), &Property[a]->CurrentValue);
+ Property[a]->CurrentValue = Temp;
+ }
+ History_Entry_End(Memory);
+ State->Interact_Active = interact_type_none;
+ }
+ }
+
+ if (i == (*Num - 1)) {
+ ImGui::PopID();
+ break;
+ }
+
+ // Conversion from Catmull-Rom curves to Bezier curves for display,
+ // referencing https://pomax.github.io/bezierinfo/#catmullconv
+
+ ImVec2 bez_m1 = (Point_P2_ScreenPos - Point_P0_ScreenPos) / (6 * Tau);
+ ImVec2 bez_m2 = (Point_P3_ScreenPos - Point_P1_ScreenPos) / (6 * Tau);
+
+ ImVec2 Point_Bez[4];
+ Point_Bez[0] = Point_P1_ScreenPos;
+ Point_Bez[1] = Point_P1_ScreenPos + bez_m1;
+ Point_Bez[2] = Point_P2_ScreenPos - bez_m2;
+ Point_Bez[3] = Point_P2_ScreenPos;
+
+ draw_list->PushClipRect(ViewportMin, ViewportMax, true);
+
+ draw_list->AddBezierCubic(Point_Bez[0], Point_Bez[1], Point_Bez[2], Point_Bez[3], col, 1.0f, 0);
+
+ if (ImGui::BezierInteractive(Point_Bez[0], Point_Bez[1], Point_Bez[2], Point_Bez[3]) &&
+ io.MousePos.x > (Point_P1_ScreenPos.x + PointSize/2) &&
+ io.MousePos.x < (Point_P2_ScreenPos.x - PointSize/2))
+ {
+ ImGui::SetCursorScreenPos(io.MousePos - ImVec2(5,5));
+ ImGui::Button("pointclick", ImVec2(10, 10));
+ if (ImGui::IsItemActivated()) {
+ Pos = V2(((io.MousePos - ViewportMin) / ViewportScale));
+ Pos.y = 1.0f - Pos.y;
+ Pos.x = Normalize(Pos.x);
+ Pos.y = Normalize(Pos.y);
+ AddPoint = true;
+ }
+ }
+
+ if (i == 0)
+ draw_list->AddLine(ImVec2(ViewportMin.x, Point_Bez[0].y), Point_Bez[0], col, 1.0f);
+ if (i == (*Num - 2))
+ draw_list->AddLine(ImVec2(ViewportMax.x, Point_Bez[3].y), Point_Bez[3], col, 1.0f);
+
+ draw_list->PopClipRect();
+
+#if 0
+ for (int x = 0; x < 256; x++) {
+ v2 Point = V2((real32)x/256, LUT[*ChannelIndex][x]);
+ ImVec2 Point_ScreenPos = ViewportMin + (ImVec2(Point.x, 1.0f - Point.y) * ViewportScale);
+ draw_list->AddNgon(Point_ScreenPos, 1, col, 8, 5.0f);
+ }
+#endif
+
+ draw_list->AddNgon(Point_P1_ScreenPos, 2, col, 8, 5.0f);
+
+
+ ImGui::PopID();
+ }
+
+
+ if (AddPoint) {
+ int x = 0;
+ History_Entry_Commit(Memory, "Curves add point");
+ for (;;) {
+ if (x > MAX_PROPERTIES_PER_EFFECT)
+ break;
+ property_channel *Property_X = Effect_Property(Memory, Effect, x);
+ if (Property_X->Identifier == -1) {
+ History_Action_Swap(Memory, F_Properties, sizeof(Property_X->CurrentValue), &Property_X->CurrentValue);
+ Property_X->CurrentValue = Pos.x;
+ History_Action_Swap(Memory, F_Properties, sizeof(Property_X->Identifier), &Property_X->Identifier);
+ Property_X->Identifier = *SelectedChannel;
+ property_channel *Property_Y = Effect_Property(Memory, Effect, x+1);
+ Assert(Property_Y->Identifier == -1);
+ History_Action_Swap(Memory, F_Properties, sizeof(Property_Y->CurrentValue), &Property_Y->CurrentValue);
+ Property_Y->CurrentValue = Pos.y;
+ History_Action_Swap(Memory, F_Properties, sizeof(Property_Y->Identifier), &Property_Y->Identifier);
+ Property_Y->Identifier = *SelectedChannel;
+ x = MAX_PROPERTIES_PER_EFFECT;
+ }
+ x++;
+ }
+ History_Action_Swap(Memory, F_Effects, sizeof(Effect->ExtraData[*SelectedChannel]), &Effect->ExtraData[*SelectedChannel]);
+ Effect->ExtraData[*SelectedChannel]++;
+ AddPoint = false;
+ History_Entry_End(Memory);
+ }
+
+ // ImVec2 ButtonPos = ImGui::GetCursorScreenPos();
+ ImGui::SetCursorScreenPos(ViewportMin);
+
+ ImGui::InvisibleButton("canvas", ViewportScale, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
+ bool32 IsHovered = ImGui::IsItemHovered();
+ bool32 IsActive = ImGui::IsItemActive();
+ bool32 IsActivated = ImGui::IsItemActivated();
+ bool32 IsDeactivated = ImGui::IsItemDeactivated();
+
+ ImVec2 EndPos = ImGui::GetCursorScreenPos();
+
+ ImGui::SetCursorScreenPos(ViewportMin + ImVec2(ViewportScale.x + 20, 0));
+ ImGui_Properties_RGBASwitch(State, Memory, io, SelectedChannel);
+
+ ImGui::SetCursorScreenPos(EndPos);
+}
+
+static void
+ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray,
+ sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray)
+{
+ bool32 Display = 1;
+ block_layer *Layer = NULL;
+ sorted_layer_array *SortedLayer = NULL;
+ if (State->MostRecentlySelectedLayer > -1) {
+ Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, State->MostRecentlySelectedLayer, 0);
+ sorted_comp_array SortedCompStart = SortedCompArray[Layer->Block_Composition_Index];
+ sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, &SortedCompStart, Layer->Block_Composition_Index);
+ SortedLayer = &SortedLayerStart[State->MostRecentlySelectedLayer];
+ if (!Layer->Occupied)
+ Display = 0;
+ } else {
+ Display = 0;
+ }
+ if (Display) {
+ block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Layer->Block_String_Index);
+ char buf[256];
+ sprintf(buf, "Properties: %s###Properties", String->Char);
+ ImGui::Begin(buf);
+ if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
+ State->FocusedWindow = focus_properties;
+ ImVec2 WindowSize = ImGui::GetWindowSize();
+ ImVec2 WindowMinAbs = ImGui::GetWindowPos();
+ ImVec2 WindowMaxAbs = WindowMinAbs + WindowSize;
+ ImGui::Text("Transform");
+
+ sorted_property_array *InfoLocation = SortedPropertyStart + SortedLayer->SortedPropertyStart;
+ uint16 *ArrayLocation = SortedKeyframeArray + SortedLayer->SortedKeyframeStart;
+ int h = 0, c = 0, p = 0;
+ property_channel *Property = NULL;
+ block_effect *Effect = NULL;
+ while (Layer_LoopChannels(State, Memory, &InfoLocation, &ArrayLocation, Layer, &Property, &Effect, &h, &c, &p))
+ {
+ ImGui::PushID(Property);
+ if ((h - 1) < AmountOf(Layer->Property) && c == 0) {
+ if (ImGui::Button("K")) {
+ Property_AddKeyframe(Memory, F_Layers, Property, State->Frame_Current, ArrayLocation);
+ }
+ ImGui::SameLine();
+#if DEBUG
+ char size[64];
+ sprintf(size, "%s, %i", DefaultChannel[h-1], Property->Keyframe_Count);
+ char *Name = size;
+#else
+ char *Name = DefaultChannel[h-1];
+#endif
+ ImGui::DragScalar(Name, ImGuiDataType_Float, &Property->CurrentValue, Property->ScrubVal, &Property->MinVal, &Property->MaxVal, "%f");
+ ImGui_Properties_Slider(State, Memory, Property, io, WindowMinAbs, WindowMaxAbs, F_Layers);
+ } else {
+ Assert(Effect);
+ header_effect *EffectHeader = Effect_EntryFromID(State, Effect->ID);
+ header_property ChannelHeader = State->Property[EffectHeader->PropertyStartIndex + c - 1];
+#if DEBUG
+ char size[64];
+ sprintf(size, "%s, %i", ChannelHeader.Name, Property->Keyframe_Count);
+ char *Name = size;
+#else
+ char *Name = ChannelHeader.Name;
+#endif
+ if ((c - 1) == 0) {
+ uint16 EffectIdx = Layer->Block_Effect_Index[h - AmountOf(Layer->Property)];
+ ImGui::PushID(h);
+#if DEBUG
+ ImGui::Text("%s, %i", EffectHeader->Name, EffectIdx);
+#else
+ ImGui::Text(EffectHeader->Name);
+#endif
+ char T_VisibleIcon[4] = "o -";
+ char F_VisibleIcon[4] = "- -";
+ char *Icon = (Effect->IsToggled) ? T_VisibleIcon : F_VisibleIcon;
+
+ if (ImGui::Button(Icon)) {
+ History_Entry_Commit(Memory, "Toggle visibility");
+ History_Action_Swap(Memory, F_Effects, sizeof(Effect->IsToggled), &Effect->IsToggled);
+ Effect->IsToggled ^= 1;
+ History_Entry_End(Memory);
+ State->UpdateFrame = true;
+ }
+
+ ImGui::SameLine();
+ if (ImGui::Button("/\\")) {
+ if (EffectIdx != 0) {
+ }
+ }
+ ImGui::SameLine();
+ if (ImGui::Button("\\/")) {
+ }
+
+ ImGui::PopID();
+ }
+ if (EffectHeader->DisplayType == effect_display_type_standard) {
+ if (ChannelHeader.DisplayType == property_display_type_standard) {
+ if (ImGui::Button("K")) {
+ Property_AddKeyframe(Memory, F_Properties, Property, State->Frame_Current, ArrayLocation);
+ }
+ ImGui::SameLine();
+ ImGui::DragScalar(Name, ImGuiDataType_Float, &Property->CurrentValue, Property->ScrubVal, &Property->MinVal, &Property->MaxVal, "%f");
+ ImGui_Properties_Slider(State, Memory, Property, io, WindowMinAbs, WindowMaxAbs, F_Properties);
+ } else if (ChannelHeader.DisplayType == property_display_type_color) {
+ if (ImGui::Button("K")) {
+ Property_AddKeyframe(Memory, F_Properties, Property, State->Frame_Current, ArrayLocation);
+ }
+ ImGui::SameLine();
+ ImGui::DragScalar(Name, ImGuiDataType_Float, &Property->CurrentValue, Property->ScrubVal, &Property->MinVal, &Property->MaxVal, "%f");
+ ImGui_Properties_Slider(State, Memory, Property, io, WindowMinAbs, WindowMaxAbs, F_Properties);
+ // if (c == 3) {
+ // ImGui::ColorEdit4("col", Col, ImGuiColorEditFlags_Float);
+ // }
+ } else {
+ Assert(0);
+ }
+ } else if (EffectHeader->DisplayType == effect_display_type_curves) {
+#if DEBUG
+ ImGui::Text("Points (RGBA): %.02f, Points (indiv): %.02f, %.02f, %.02f, %.02f", Effect->ExtraData[0],
+ Effect->ExtraData[1], Effect->ExtraData[2], Effect->ExtraData[3], Effect->ExtraData[4]);
+#endif
+ if (Property->Identifier == -1) {
+ Effect_Curves_Init(Effect, Property);
+ }
+ uint16 SortedPointStart[MAX_PROPERTIES_PER_EFFECT/5];
+ uint32 VisibleChannel = *(uint32 *)&Effect->ExtraData[5];
+ Effect_Curves_Sort(Memory, Effect, SortedPointStart, VisibleChannel);
+ ImGui_Properties_CurvesUI(State, Memory, io, Effect, Property, SortedPointStart);
+ c = EffectHeader->Property_Count; // Causes this loop to only iterate once.
+ } else if (EffectHeader->DisplayType == effect_display_type_levels) {
+ ImGui::Text("Levels!");
+ uint32 VisibleChannel = *(uint32 *)&Effect->ExtraData[0];
+ real32 *P_Left = 0, *P_Mid = 0, *P_Right = 0;
+ if (VisibleChannel == 0) {
+ property_channel *Property0 = (property_channel *)Memory_Block_AddressAtIndex(Memory, F_Properties, Effect->Block_Property_Index[0]);
+ property_channel *Property1 = (property_channel *)Memory_Block_AddressAtIndex(Memory, F_Properties, Effect->Block_Property_Index[1]);
+ property_channel *Property2 = (property_channel *)Memory_Block_AddressAtIndex(Memory, F_Properties, Effect->Block_Property_Index[2]);
+ P_Left = &Property0->CurrentValue;
+ P_Mid = &Property1->CurrentValue;
+ P_Right = &Property2->CurrentValue;
+ } else {
+ property_channel *Property0 = (property_channel *)Memory_Block_AddressAtIndex(Memory, F_Properties, Effect->Block_Property_Index[3+(VisibleChannel-1)]);
+ property_channel *Property1 = (property_channel *)Memory_Block_AddressAtIndex(Memory, F_Properties, Effect->Block_Property_Index[7+(VisibleChannel-1)]);
+ property_channel *Property2 = (property_channel *)Memory_Block_AddressAtIndex(Memory, F_Properties, Effect->Block_Property_Index[11+(VisibleChannel-1)]);
+ P_Left = &Property0->CurrentValue;
+ P_Mid = &Property1->CurrentValue;
+ P_Right = &Property2->CurrentValue;
+ }
+ ImGui::SliderLevels("1", "2,", "3", (void *)P_Mid, (void *)P_Left, (void *)P_Right);
+ if (ImGui::IsItemActive()) {
+ State->UpdateFrame = true;
+ }
+ ImGui_Properties_RGBASwitch(State, Memory, io, (uint32 *)&Effect->ExtraData[0]);
+ c = EffectHeader->Property_Count;
+ } else {
+ Assert(0);
+ }
+ }
+ ImGui::PopID();
+ }
+ if (Layer->IsPrecomp) {
+ block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, Layer->Block_Source_Index);
+ ImGui::DragScalar("Width", ImGuiDataType_U16, &Comp->Width);
+ if (ImGui::IsItemActive()) {
+ State->UpdateFrame = true;
+ }
+ ImGui::DragScalar("Height", ImGuiDataType_U16, &Comp->Height);
+ if (ImGui::IsItemActive()) {
+ State->UpdateFrame = true;
+ }
+ }
+ ImGui::End();
+ } else {
+ ImGui::Begin("Properties: empty###Properties");
+ if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
+ State->FocusedWindow = focus_properties;
+ ImGui::End();
+ }
+}