diff options
Diffstat (limited to 'src/imgui_ui_properties.cpp')
-rw-r--r-- | src/imgui_ui_properties.cpp | 441 |
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(); + } +} |