summaryrefslogtreecommitdiff
path: root/src/imgui_ui_viewport.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/imgui_ui_viewport.cpp')
-rw-r--r--src/imgui_ui_viewport.cpp215
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;