diff options
Diffstat (limited to 'src/imgui_ui_viewport.cpp')
-rw-r--r-- | src/imgui_ui_viewport.cpp | 215 |
1 files changed, 130 insertions, 85 deletions
diff --git a/src/imgui_ui_viewport.cpp b/src/imgui_ui_viewport.cpp index 749999d..6503e6f 100644 --- a/src/imgui_ui_viewport.cpp +++ b/src/imgui_ui_viewport.cpp @@ -38,6 +38,7 @@ ImGui_Viewport_Toolbar(project_state *State, ImDrawList *draw_list) static void ImGui_Viewport_ShapeUI(project_state *State, memory *Memory, ui *UI, ImGuiIO &io, block_layer *Layer, int Width, int Height, shape_layer *Shape, block_composition *MainComp, ImDrawList *draw_list) { + memory_table_list TableName = (Layer == NULL) ? F_File : F_Layers; if (Shape->Point_Count) { uint32 wcol = IM_COL32(00, 00, 80, 255); v2 CompUV = State->LastClickedPoint; @@ -132,9 +133,7 @@ ImGui_Viewport_ShapeUI(project_state *State, memory *Memory, ui *UI, ImGuiIO &io if (IsItemDeactivated) { if (Layer == NULL && a == 0 && i == 0 && Shape->IsClosed == false) { History_Entry_Commit(Memory, "Close shape"); - Assert(0); - // which one?? - History_Action_Swap(Memory, F_File, sizeof(Shape->IsClosed), &Shape->IsClosed); + History_Action_Swap(Memory, TableName, sizeof(Shape->IsClosed), &Shape->IsClosed); Shape->IsClosed = true; History_Entry_End(Memory); } else if (Layer != NULL) { @@ -388,33 +387,26 @@ ImGui_Viewport_TransformUI2(project_data *File, project_state *State, memory *Me layer_transforms BoxTransforms = { NewCenter.x, NewCenter.y, 0.5, 0.5, (real32)(Rad / (PI / 180)), Scale }; v2 LayerPoint = Transform_ScreenSpaceToLocal(BoxTransforms, CompWidth, CompHeight, BoxLength.x, BoxLength.y, UI->CompPos, UI->CompZoom, ViewportMin, io.MousePos); - - // for (int i = 0; i < 4; i++) { - // v2 Anchor = TransformPoint(BoxTransforms, BoxLength.x, BoxLength.y, BoxLength * Mid_Local[i]); - // Mid_P[i] = IV2(Anchor)*CompScale + UI->CompPos; - // } - real32 U = LayerPoint.x / BoxLength.x; real32 V = LayerPoint.y / BoxLength.y; - // DebugWatchVar("U", &U, d_float); - // DebugWatchVar("V", &V, d_float); - ImVec2 ScaleHandleSize(50, 50); + real32 HandleSize = ImGui::GetFontSize() * 2; + ImVec2 ScaleHandleSize(HandleSize, HandleSize); bool32 OtherActions = ImGui::IsKeyDown(ImGuiKey_Z); - // First do the halfway scale points, since they don't need UVs considered: + uint32 Col[4] = { IM_COL32(255, 0, 0, 255), IM_COL32(0, 255, 0, 255), IM_COL32(0, 0, 255, 255), IM_COL32(255, 255, 255, 255) }; + + // TODO(fox): Combine halfway and corner scale code? for (int i = 0; i < 4; i++) { ImGui::SetCursorScreenPos(Mid_P[i] - ScaleHandleSize/2); ImGui::PushID(i); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::ColorConvertFloat4ToU32(ImVec4(0.6f, 0.0f, 0.3f, 1.0f))); ImGui::InvisibleButton("##ScaleMids", ScaleHandleSize); - ImGui::PopStyleColor(); ImGui_DrawCenteredRect(draw_list, Mid_P[i], 12, IM_COL32(20, 20, 20, 255)); ImGui_DrawCenteredRect(draw_list, Mid_P[i], 10, IM_COL32(20, 20, 220, 255)); - ImGui_DrawCenteredRect(draw_list, Mid_P[i], 6, IM_COL32(255, 255, 225, 50)); + ImGui_DrawCenteredRect(draw_list, Mid_P[i], 6, Col[i]); if (ImGui::GetMouseCursor() != ImGuiMouseCursor_None && ImGui::IsItemHovered() && !OtherActions) { @@ -428,59 +420,58 @@ ImGui_Viewport_TransformUI2(project_data *File, project_state *State, memory *Me if (State->InteractTransformMode == 1 && ImGui::IsItemActive()) { - uint32 side = i; - v2 Dir = {}; - if (i == 0) { - Dir = V2(1, -1); - } else if (i == 1) { - Dir = V2(-1, -1); - } else if (i == 2) { - Dir = V2(-1, 0); - } else if (i == 3) { - Dir = V2(1, 0); - } else { - Assert(0); - } - - // InteractMin + V2(BoxLength.x * 0.5, 0), InteractMin + V2(0, BoxLength.y * 0.5), - // InteractMax - V2(BoxLength.x * 0.5, 0), InteractMax - V2(0, BoxLength.y * 0.5) }; - + // real32 NegRad = Rad - (90 * (PI / 180)); ImVec2 LengthVec = (io.MousePos - io.MouseClickedPos[0]) / CompScale; real32 NegRad = -Rad; - v2 UnrotatedLengthVec = {}; - { - v2 XAxis = (LengthVec.x * 1.0f)*V2(cos(NegRad), sin(NegRad)); - v2 YAxis = (LengthVec.y * -1.0f)*V2(sin(NegRad), -cos(NegRad)); - UnrotatedLengthVec = XAxis + YAxis; - } - - real32 Length = UnrotatedLengthVec.x * Dir.x; - real32 BoxAxis = BoxLength.x; - Interact->Scale = 1.0f + Length / BoxAxis; - v2 MovePos = V2((Length / 2), -(Length / 2) * (BoxLength.y / BoxLength.x)); - v2 XAxis = (MovePos.x * Dir.x)*V2(cos(Rad), sin(Rad)); - v2 YAxis = (MovePos.y * Dir.y)*V2(sin(Rad), -cos(Rad)); - v2 Pos = XAxis + YAxis; + v2 XAxis = (LengthVec.x * 1.0f)*V2(cos(NegRad), sin(NegRad)); + v2 YAxis = (LengthVec.y * -1.0f)*V2(sin(NegRad), -cos(NegRad)); + v2 UnrotatedLengthVec = XAxis + YAxis; - Interact->Position.x = Pos.x; - Interact->Position.y = Pos.y; -#if 0 + v2 Dir = {}; if (i == 0) { - Interact->Position.x = Pos.x; - Interact->Position.y = Pos.y; + Dir = V2(-1, 1); } else if (i == 1) { - Interact->Position.x = Pos.x; - Interact->Position.y = Pos.y; + Dir = V2(1, 1); } else if (i == 2) { - Interact->Position.x = Pos.x; - Interact->Position.y = Pos.y; + Dir = V2(1, -1); } else if (i == 3) { - Interact->Position.x = Pos.x; - Interact->Position.y = Pos.y; + Dir = V2(-1, -1); + } else { + Assert(0); } -#endif + if (i == 1 || i == 3) { + real32 Length = UnrotatedLengthVec.x * Dir.x; + real32 BoxAxis = BoxLength.x; + Interact->Scale = 1.0f + -Length / BoxAxis; + v2 MovePos = V2((Length / 2), 0); + v2 XAxis = (MovePos.x * Dir.x)*V2(cos(Rad), sin(Rad)); + v2 YAxis = (MovePos.y * Dir.y)*V2(sin(Rad), -cos(Rad)); + v2 Pos = XAxis + YAxis; + if (!io.KeyCtrl) { + Interact->Position.x = Pos.x; + Interact->Position.y = Pos.y; + } else { + Interact->Position.x = 0; + Interact->Position.y = 0; + } + } else { + real32 Length = UnrotatedLengthVec.y * Dir.x; + real32 BoxAxis = BoxLength.y; + Interact->Scale = 1.0f + -Length / BoxAxis; + v2 MovePos = V2(0, (Length / 2)); + v2 XAxis = (MovePos.x * Dir.x)*V2(cos(Rad), sin(Rad)); + v2 YAxis = (MovePos.y * Dir.y)*V2(sin(Rad), -cos(Rad)); + v2 Pos = XAxis + YAxis; + if (!io.KeyCtrl) { + Interact->Position.x = Pos.x; + Interact->Position.y = Pos.y; + } else { + Interact->Position.x = 0; + Interact->Position.y = 0; + } + } } ImGui::PopID(); @@ -494,7 +485,6 @@ ImGui_Viewport_TransformUI2(project_data *File, project_state *State, memory *Me InBounds = true; } - uint32 Col[4] = { IM_COL32(255, 0, 0, 255), IM_COL32(0, 255, 0, 255), IM_COL32(0, 0, 255, 255), IM_COL32(255, 255, 255, 255) }; for (int i = 0; i < 4; i++) { ImGui::SetCursorScreenPos(P[i] - ScaleHandleSize/2); ImGui::PushID(i); @@ -542,6 +532,8 @@ ImGui_Viewport_TransformUI2(project_data *File, project_state *State, memory *Me Assert(0); } + // Determine whether to use the unrotated X or Y axis based on + // where the mouse is. Makes the box corner always 'stick' to the mouse. v2 Vector0 = V2(BoxLength.x, BoxLength.y); real32 Dot = Inner(V2(-Vector0.y * Dir.x, Vector0.x * Dir.y), UnrotatedLengthVec); bool32 Test = (Dot < 0.0f) ? 0 : 1; @@ -554,8 +546,13 @@ ImGui_Viewport_TransformUI2(project_data *File, project_state *State, memory *Me v2 XAxis = (MovePos.x * Dir.x)*V2(cos(Rad), sin(Rad)); v2 YAxis = (MovePos.y * Dir.y)*V2(sin(Rad), -cos(Rad)); v2 Pos = XAxis + YAxis; - Interact->Position.x = Pos.x; - Interact->Position.y = Pos.y; + if (!io.KeyCtrl) { + Interact->Position.x = Pos.x; + Interact->Position.y = Pos.y; + } else { + Interact->Position.x = 0; + Interact->Position.y = 0; + } } else { real32 Mult = (i == 1 || i == 3) ? -1 : 1; real32 Length = UnrotatedLengthVec.y * Mult * Dir.x; @@ -565,8 +562,13 @@ ImGui_Viewport_TransformUI2(project_data *File, project_state *State, memory *Me v2 XAxis = (MovePos.x * Dir.x)*V2(cos(Rad), sin(Rad)); v2 YAxis = (MovePos.y * Dir.y)*V2(sin(Rad), -cos(Rad)); v2 Pos = XAxis + YAxis; - Interact->Position.x = Pos.x; - Interact->Position.y = Pos.y; + if (!io.KeyCtrl) { + Interact->Position.x = Pos.x; + Interact->Position.y = Pos.y; + } else { + Interact->Position.x = 0; + Interact->Position.y = 0; + } } } @@ -623,27 +625,40 @@ ImGui_Viewport_TransformUI2(project_data *File, project_state *State, memory *Me State->UpdateFrame = true; if (!ImGui::IsMouseDown(ImGuiMouseButton_Left)) { - Assert(State->Interact_Active == interact_type_viewport_transform_gizmo); - int h = 0, c = 0, i = 0; - History_Entry_Commit(Memory, "Transform layers"); - while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) { - block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i); - if (Layer->IsSelected == 1) { - History_Action_Swap(Memory, F_Layers, sizeof(Layer->x.CurrentValue), &Layer->x.CurrentValue); - History_Action_Swap(Memory, F_Layers, sizeof(Layer->y.CurrentValue), &Layer->y.CurrentValue); - History_Action_Swap(Memory, F_Layers, sizeof(Layer->scale.CurrentValue), &Layer->scale.CurrentValue); - History_Action_Swap(Memory, F_Layers, sizeof(Layer->rotation.CurrentValue), &Layer->rotation.CurrentValue); - Transform_ApplyInteractive(State->Interact_Transform, &Layer->x.CurrentValue, &Layer->y.CurrentValue, &Layer->rotation.CurrentValue, &Layer->scale.CurrentValue); + // A mouse release without any delta usually means the user wants + // to initiate a layer seelect. + ImVec2 LengthVec = (io.MousePos - io.MouseClickedPos[0]); + if (fabsf(LengthVec.x) + fabsf(LengthVec.y) > 2) { + Assert(State->Interact_Active == interact_type_viewport_transform_gizmo); + int h = 0, c = 0, i = 0; + History_Entry_Commit(Memory, "Transform layers"); + while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) { + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i); + if (Layer->IsSelected == 1) { + History_Action_Swap(Memory, F_Layers, sizeof(Layer->x.CurrentValue), &Layer->x.CurrentValue); + History_Action_Swap(Memory, F_Layers, sizeof(Layer->y.CurrentValue), &Layer->y.CurrentValue); + History_Action_Swap(Memory, F_Layers, sizeof(Layer->scale.CurrentValue), &Layer->scale.CurrentValue); + History_Action_Swap(Memory, F_Layers, sizeof(Layer->rotation.CurrentValue), &Layer->rotation.CurrentValue); + Transform_ApplyInteractive(State->Interact_Transform, &Layer->x.CurrentValue, &Layer->y.CurrentValue, &Layer->rotation.CurrentValue, &Layer->scale.CurrentValue); + } } + History_Entry_End(Memory); + State->UpdateFrame = true; + State->UncommitedKeyframe = 1; + } else { + int32 Selection = Layer_TestSelection(Memory, State, UI, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex, io.KeyShift); + Assert(State->Tool == tool_default); + if (!io.KeyShift) { + Layer_DeselectAll(File, State, Memory); + State->Interact_Transform = {}; + } + if (Selection != -1) + Layer_Select(Memory, State, Selection); } - History_Entry_End(Memory); State->Interact_Active = interact_type_none; State->Interact_Transform = {}; - State->UpdateFrame = true; State->InteractTransformMode = 0; State->Interact_Modifier = 0; - State->UncommitedKeyframe = 1; - State->UpdateFrame = true; } } @@ -1077,6 +1092,10 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, if (ImGui::IsWindowHovered(ImGuiFocusedFlags_ChildWindows)) { State->FocusedWindow = focus_viewport; + // normal people won't use this... + if (ImGui::IsKeyPressed(ImGuiKey_Escape)) { + Layer_DeselectAll(File, State, Memory); + } } block_composition *MainComp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex); @@ -1123,9 +1142,21 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, draw_list->AddRect(CompPosMin, CompPosMax, OUTLINE); draw_list->AddImage((void *)(intptr_t)textureID, CompPosMin, CompPosMax); } else { - Render_UI(File, State, Memory, UI, draw_list, - SortedCompArray, SortedLayerArray, + block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, File->PrincipalCompIndex); + uint8 *StartAddress = (uint8 *)Memory->Slot[B_PointData].Address; + uint8 *Data = StartAddress; + Arbitrary_Zero(Data, Memory->Slot[B_PointData].Size); + gl_viewport_data *RenderData = (gl_viewport_data *)Data; + Data += sizeof(gl_viewport_data); + *RenderData = { ImGui::GetMainViewport()->Size, + Comp->Width, Comp->Height, Comp->BytesPerPixel, + UI->CompPos, UI->CompZoom, UI->CompZoom.x / Comp->Width, {} }; + layer_transforms ExtraT = {}; + Render_UI(File, State, Memory, UI, draw_list, Data, RenderData, + SortedCompArray, SortedLayerArray, &ExtraT, SortedPropertyStart, SortedKeyframeArray, File->PrincipalCompIndex, State->Frame_Current); + draw_list->AddCallback(GL_Test, (void *)StartAddress); + draw_list->AddCallback(ImDrawCallback_ResetRenderState, NULL); draw_list->AddRect(CompPosMin, CompPosMax, OUTLINE); } draw_list->PopClipRect(); @@ -1200,6 +1231,12 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, bool32 OtherActions = ImGui::IsKeyDown(ImGuiKey_Z) || ImGui::IsMouseDown(ImGuiMouseButton_Right); + // If there's any sort of drag before the user lets go of the mouse, they + // either want to use the bounding box or drag an object that isn't + // currently selected, so we need to select it now instead of on mouse + // release. This requires a state override (Interact_OutOfDrag) to force + // the deselection code to not be called on mouse release. + if (IsActive && !OtherActions && !io.KeyCtrl && !io.KeyAlt) { ImVec2 ClickedPos = io.MouseClickedPos[0]; @@ -1215,9 +1252,10 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, BoxMax.y = (MousePos.y > ClickedPos.y) ? MousePos.y : ClickedPos.y; if (io.MouseDelta.x || io.MouseDelta.y) { if (State->Tool == tool_default && State->Interact_Active == interact_type_none) { - int32 Selection = Layer_TestSelection(Memory, State, UI, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex); + int32 Selection = Layer_TestSelection(Memory, State, UI, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex, io.KeyShift); if (!State->InteractTransformMode && Selection != -1) { - Layer_DeselectAll(File, State, Memory); + if (!io.KeyShift) + Layer_DeselectAll(File, State, Memory); Layer_Select(Memory, State, Selection); State->Interact_Active = interact_type_viewport_transform_gizmo; State->Interact_OutOfDrag = true; @@ -1252,7 +1290,7 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, State->Interact_OutOfDrag = 0; } else { // Layer selection - int32 Selection = Layer_TestSelection(Memory, State, UI, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex); + int32 Selection = Layer_TestSelection(Memory, State, UI, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex, io.KeyShift); if (State->Tool == tool_default && State->Interact_Active == interact_type_none) { if (!io.KeyShift && State->Interact_Active == interact_type_none) { Layer_DeselectAll(File, State, Memory); @@ -1295,7 +1333,7 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, ImVec2 MouseDelta = io.MouseDelta; real32 Delta = MouseDelta.x + MouseDelta.y; v2 PrincipalCompUV = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos); - v2 LayerPos = Layer_TraverseForPoint(File, State, Memory, PrincipalCompUV, SortedCompArray, SortedLayerArray); + v2 LayerPos = Layer_TraverseForPoint(File, State, Memory, PrincipalCompUV, SortedCompArray, SortedLayerArray, State->Brush.LayerToPaint_Index); if (IsActivated) { RenderQueue_AddBrush(State, LayerPos); } else if (Delta != 0.0f) { @@ -1423,6 +1461,13 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, if (State->Interact_Active == interact_type_viewport_duplicate) { if (IsDeactivated) { + // NOTE(fox): Normally calling functions that add/delete things + // shouldn't be done here since they affect sorting and can lead to + // access of invalid data, but since the duplicate state already + // pre-modifies the sort data to be correct, it's safe to call it + // here. + // UI bugs can form if code prior to this and code after this + // depend on the IsFake flag! History_Entry_Commit(Memory, "Duplicate layers"); State->Interact_Active = interact_type_none; State->Interact_Modifier = 0; |