summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bezier.cpp4
-rw-r--r--src/gl_calls.cpp139
-rw-r--r--src/imgui_ui.cpp1
-rw-r--r--src/imgui_ui_properties.cpp21
-rw-r--r--src/imgui_ui_viewport.cpp211
-rw-r--r--src/include/debug.h2
-rw-r--r--src/include/functions.h8
-rw-r--r--src/include/layer.h2
-rw-r--r--src/include/main.h9
-rw-r--r--src/include/nanovg.h29
-rw-r--r--src/layer.cpp46
-rw-r--r--src/main.cpp5
-rw-r--r--src/nanovg.cpp188
-rw-r--r--src/prenderer.cpp46
14 files changed, 492 insertions, 219 deletions
diff --git a/src/bezier.cpp b/src/bezier.cpp
index 420cae1..6bb1541 100644
--- a/src/bezier.cpp
+++ b/src/bezier.cpp
@@ -171,13 +171,13 @@ static void Bezier_CubicCalcPointsCasteljauStep(void *Data, uint32 Size, uint32
}
}
-uint32 Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 Size)
+void * Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 Size)
{
uint32 Increment = 0;
real32 tess_tol = TESS_TOL;
void *Pointer = Data;
Bezier_CubicCalcPointsCasteljauStep(Pointer, Size, &Increment, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0);
- return Increment;
+ return ((uint8 *)Data + (Increment * Size));
}
diff --git a/src/gl_calls.cpp b/src/gl_calls.cpp
index dbc0784..a1938be 100644
--- a/src/gl_calls.cpp
+++ b/src/gl_calls.cpp
@@ -20,8 +20,8 @@ const char *DefaultVertexShaderSource = "#version 330 core\n"
" vec2 YRotation = vec2(sin(Rad), -cos(Rad));\n"
" vec2 XAxis = (Point.x - (Anchor.x * LayerDimensions.x)) * Scale * XRotation;\n"
" vec2 YAxis = (Point.y - (Anchor.y * LayerDimensions.y)) * -Scale * YRotation;\n"
-" vec2 LocalPoint = Pos + vec2(XAxis + YAxis);\n"
-" gl_Position = vec4(vec2(LocalPoint.x / CompDimensions.x, LocalPoint.y / CompDimensions.y) * 2 - 1.0f, 0.0f, 1.0);\n"
+" vec2 CompPoint = Pos + vec2(XAxis + YAxis);\n"
+" gl_Position = vec4(vec2(CompPoint.x / CompDimensions.x, CompPoint.y / CompDimensions.y) * 2 - 1.0f, 0.0f, 1.0);\n"
"}\n"
" TexCoord = aTexCoord;\n"
"}\0";
@@ -167,8 +167,9 @@ GL_DeleteHWBuffer(gl_effect_layer *Test)
static void
GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *StrokeData, void *FillData, uint32 StrokeCount, uint32 FillCount,
- layer_transforms T, int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, int L_Width, int L_Height, v4 Col, int RenderMode)
+ layer_transforms T, int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, int L_Width, int L_Height, v4 StrokeCol, v4 FillCol, int RenderMode)
{
+ int Uniform = 0;
glBindTexture(GL_TEXTURE_2D, TestL->Texture);
int ByteFlag = (BytesPerPixel == 4) ? GL_RGBA : GL_RGBA16;
int ByteFlag2 = (BytesPerPixel == 4) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
@@ -191,10 +192,6 @@ GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *StrokeDa
glUseProgram(DefaultShaderProgram);
- int Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode");
- glUniform1i(Uniform, 1);
- Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode");
- glUniform1i(Uniform, 1);
Uniform = glGetUniformLocation(DefaultShaderProgram, "CompDimensions");
glUniform3f(Uniform, Width, Height, 0);
Uniform = glGetUniformLocation(DefaultShaderProgram, "LayerDimensions");
@@ -209,90 +206,80 @@ GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *StrokeDa
Uniform = glGetUniformLocation(DefaultShaderProgram, "Scale");
glUniform1f(Uniform, T.scale);
-#if 0
- void *PointData = NULL;
- int PointCount = 0;
- if (RenderMode == 0) {
- PointData = FillData;
- PointCount = FillCount;
- } else {
- PointData = StrokeData;
- PointCount = StrokeCount;
- }
- glBindBuffer(GL_ARRAY_BUFFER, ShapeVerts.VertexBufferObject);
- glBufferData(GL_ARRAY_BUFFER, sizeof(real32) * 4 * PointCount, PointData, GL_STATIC_DRAW);
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
- glEnableVertexAttribArray(1);
-
- // stencil buffer
- glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP);
- glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP);
- glDisable(GL_CULL_FACE);
-
- if (RenderMode == 0) {
- glDrawArrays(GL_TRIANGLE_FAN, 0, PointCount);
- } else {
- glDrawArrays(GL_TRIANGLE_STRIP, 0, PointCount);
- }
-
- // stencil buffer
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-#else
- glBindBuffer(GL_ARRAY_BUFFER, ShapeVerts.VertexBufferObject);
- glBufferData(GL_ARRAY_BUFFER, sizeof(real32) * 4 * FillCount, FillData, GL_STATIC_DRAW);
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
-
- glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP);
- glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP);
- glDisable(GL_CULL_FACE);
-
- glDrawArrays(GL_TRIANGLE_FAN, 0, FillCount);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode");
+ glUniform1i(Uniform, 1);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode");
+ glUniform1i(Uniform, 1);
- glBindBuffer(GL_ARRAY_BUFFER, ShapeVerts.VertexBufferObject);
- glBufferData(GL_ARRAY_BUFFER, sizeof(real32) * 4 * StrokeCount, StrokeData, GL_STATIC_DRAW);
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
+ // fill
+ // vertices
+ glBindBuffer(GL_ARRAY_BUFFER, ShapeVerts.VertexBufferObject);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(real32) * 4 * FillCount, FillData, GL_STATIC_DRAW);
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
- glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP);
- glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP);
- glDisable(GL_CULL_FACE);
+ // stencil buffer
+ glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP);
+ glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP);
+ glDisable(GL_CULL_FACE);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, StrokeCount);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, FillCount);
+ //
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-#endif
-
- // default verts
glBindVertexArray(0);
+
Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode");
glUniform1i(Uniform, 0);
Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode");
glUniform1i(Uniform, 1);
Uniform = glGetUniformLocation(DefaultShaderProgram, "InputCol");
- glUniform3f(Uniform, Col.r, Col.g, Col.b);
- glBindBuffer(GL_ARRAY_BUFFER, DefaultVerts.VertexBufferObject);
- glBufferData(GL_ARRAY_BUFFER, sizeof(GL_DefaultVertices), GL_DefaultVertices, GL_STATIC_DRAW);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
- glEnableVertexAttribArray(0);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
- glEnableVertexAttribArray(1);
-
- // stencil buffer
- glStencilFunc(GL_NOTEQUAL, 0, 0xFF);
- glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
-
- glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_INT, 0);
-
- // stencil buffer
+ glUniform3f(Uniform, FillCol.r, FillCol.g, FillCol.b);
+
+ // stencil for fill
+ //
+ // vertices
+ glBindBuffer(GL_ARRAY_BUFFER, DefaultVerts.VertexBufferObject);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(GL_DefaultVertices), GL_DefaultVertices, GL_STATIC_DRAW);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
+ glEnableVertexAttribArray(1);
+
+ // stencil buffer
+ glStencilFunc(GL_NOTEQUAL, 0, 0xFF);
+ glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
+
+ glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_INT, 0);
+ //
+
+ // stencil buffer not needed
glDisable(GL_STENCIL_TEST);
glStencilMask(0xFF);
glStencilFunc(GL_ALWAYS, 0, 0xFF);
+ glBindVertexArray(0);
+
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode");
+ glUniform1i(Uniform, 1);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode");
+ glUniform1i(Uniform, 1);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "InputCol");
+ glUniform3f(Uniform, StrokeCol.r, StrokeCol.g, StrokeCol.b);
+
+ // stroke
+ //
+ glBindBuffer(GL_ARRAY_BUFFER, ShapeVerts.VertexBufferObject);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(real32) * 4 * StrokeCount, StrokeData, GL_STATIC_DRAW);
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
+ glEnableVertexAttribArray(1);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, StrokeCount);
+ //
+
glBindFramebuffer(GL_READ_FRAMEBUFFER, TestM->FramebufferObject);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, TestL->FramebufferObject);
glBlitFramebuffer(0, 0, Width, Height, 0, 0, Width, Height,
diff --git a/src/imgui_ui.cpp b/src/imgui_ui.cpp
index c545e80..50d25a4 100644
--- a/src/imgui_ui.cpp
+++ b/src/imgui_ui.cpp
@@ -116,7 +116,6 @@ ImGui_File(project_data *File, project_state *State, memory *Memory, ImGuiIO io,
ImGui::End();
}
-
static void
ImGui_ColorPanel(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io)
{
diff --git a/src/imgui_ui_properties.cpp b/src/imgui_ui_properties.cpp
index d89f2f0..6f949c8 100644
--- a/src/imgui_ui_properties.cpp
+++ b/src/imgui_ui_properties.cpp
@@ -443,6 +443,27 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory *
}
ImGui::EndListBox();
}
+ char *Names2[3] = { "Butt", "Round", "Square" };
+ nvg_line_cap CapVals[3] = { NVG_BUTT, NVG_ROUND, NVG_SQUARE };
+ if (ImGui::BeginListBox("Path cap type")) {
+ for (int i = 0; i < 2; i++) {
+ if (ImGui::Selectable(Names2[i], (Opt->LineCapType == CapVals[i]))) {
+ Opt->LineCapType = CapVals[i];
+ }
+ }
+ ImGui::EndListBox();
+ }
+ char *Names3[3] = { "Miter", "Round", "Bevel" };
+ nvg_line_cap JoinVals[3] = { NVG_MITER, NVG_ROUND, NVG_BEVEL };
+ if (ImGui::BeginListBox("Path join type")) {
+ for (int i = 0; i < 2; i++) {
+ if (ImGui::Selectable(Names3[i], (Opt->LineJoinType == JoinVals[i]))) {
+ Opt->Visibility = i;
+ Opt->LineJoinType = JoinVals[i];
+ }
+ }
+ ImGui::EndListBox();
+ }
ImGui::ColorEdit4("Fill color", (real32 *)&Opt->FillCol, ImGuiColorEditFlags_Float);
ImGui::ColorEdit4("Stroke color", (real32 *)&Opt->StrokeCol, ImGuiColorEditFlags_Float);
real32 StrokeWidthMin = 0;
diff --git a/src/imgui_ui_viewport.cpp b/src/imgui_ui_viewport.cpp
index 9563d63..fae7bd4 100644
--- a/src/imgui_ui_viewport.cpp
+++ b/src/imgui_ui_viewport.cpp
@@ -32,7 +32,7 @@ ImGui_Viewport_Toolbar(project_state *State, ImDrawList *draw_list)
}
static void
-ImGui_Viewport_ShapeUI(project_state *State, memory *Memory, ui *UI, shape_layer *Shape, block_composition *MainComp, ImDrawList *draw_list)
+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)
{
if (Shape->Point_Count) {
uint32 wcol = IM_COL32(00, 00, 80, 255);
@@ -48,33 +48,166 @@ ImGui_Viewport_ShapeUI(project_state *State, memory *Memory, ui *UI, shape_layer
ImVec2 ScreenPoint_0[3];
ImVec2 ScreenPoint_1[3];
+ if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
+ Point_1->IsSelected = false;
+ }
+
for (int i = 0; i < 3; i++) {
ImVec2 Point = (i == 0) ? ImVec2_(Point_0->Pos[0]) : ImVec2_(Point_0->Pos[0] + Point_0->Pos[i]);
+ if (Layer != NULL) {
+ layer_transforms T = Layer_GetTransforms(Layer);
+ Point = ImVec2_(TransformPoint(T, Width, Height, *(v2 *)&Point));
+ }
+ if (State->Interact_Active == interact_type_keyframe_move && Point_0->IsSelected) {
+ Point.x += State->Interact_Offset[0];
+ Point.y += State->Interact_Offset[1];
+ }
ImVec2 Point_Ratio = Point / CompDimensions;
ScreenPoint_0[i] = UI->CompPos + Point_Ratio * UI->CompZoom;
}
for (int i = 0; i < 3; i++) {
ImVec2 Point = (i == 0) ? ImVec2_(Point_1->Pos[0]) : ImVec2_(Point_1->Pos[0] + Point_1->Pos[i]);
+ if (Layer != NULL) {
+ layer_transforms T = Layer_GetTransforms(Layer);
+ Point = ImVec2_(TransformPoint(T, Width, Height, *(v2 *)&Point));
+ }
+ if (State->Interact_Active == interact_type_keyframe_move && Point_1->IsSelected) {
+ Point.x += State->Interact_Offset[0];
+ Point.y += State->Interact_Offset[1];
+ }
ImVec2 Point_Ratio = Point / CompDimensions;
ScreenPoint_1[i] = UI->CompPos + Point_Ratio * UI->CompZoom;
}
if (Point_1->Type == interpolation_type_bezier)
draw_list->AddLine(ScreenPoint_0[1], ScreenPoint_0[2], wcol, 2.0f);
- draw_list->AddNgon(ScreenPoint_0[0], 2, wcol, 8, 2.0f);
+ ImU32 PointCol = (Point_1->IsSelected) ? ImColor(0.8f, 0.5f, 0.0f, 1.0f) : ImColor(0.1f, 0.1f, 0.1f, 1.0f);
ImGui::PushID(i);
for (int a = 0; a < 3; a++) {
ImGui::PushID(a);
- ImGui::SetCursorScreenPos(ScreenPoint_1[a]);
- if (ImGui::Button("##bezhandle")) {
- if (a == 0 && i == 0) {
+ real32 FontSize = ImGui::GetFontSize();
+ ImGui::SetCursorScreenPos(ScreenPoint_1[a] - ImVec2(FontSize / 2, FontSize / 2));
+ ImGui::InvisibleButton("##bezhandle", ImVec2(FontSize, FontSize), ImGuiMouseButton_Left);
+ bool32 IsHovered = ImGui::IsItemHovered();
+ bool32 IsItemActive = ImGui::IsItemActive();
+ bool32 IsItemActivated = ImGui::IsItemActivated();
+ bool32 IsItemDeactivated = ImGui::IsItemDeactivated();
+ bool32 LeftClick = ImGui::IsMouseDown(ImGuiMouseButton_Left);
+ bool32 RightClick = ImGui::IsMouseDown(ImGuiMouseButton_Right);
+ if (IsHovered) {
+ PointCol = ImColor(1.0f, 0.8f, 0.8f, 1.0f);
+ ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
+ }
+ if (IsItemActivated) {
+ Point_1->IsSelected = 1;
+ }
+ if (IsItemActive) {
+ if (State->Interact_Active == interact_type_none) {
+ State->Interact_Offset[2] = io.MousePos.x;
+ State->Interact_Offset[3] = io.MousePos.y;
+ State->Interact_Active = interact_type_keyframe_move;
+ } else {
+ Assert(State->Interact_Active == interact_type_keyframe_move);
+ ImVec2 DragDelta = io.MousePos - ImVec2(State->Interact_Offset[2], State->Interact_Offset[3]);
+ if (io.MouseDelta.x || io.MouseDelta.y) {
+ State->UpdateFrame = true;
+ }
+ if (State->Interact_Active == interact_type_keyframe_move) {
+ State->Interact_Offset[0] = DragDelta.x * (MainComp->Width / UI->CompZoom.x);
+ State->Interact_Offset[1] = DragDelta.y * (MainComp->Height / UI->CompZoom.y);
+ }
+ }
+ }
+ if (IsItemDeactivated) {
+ if (Layer == NULL && a == 0 && i == 0 && Shape->IsClosed == false) {
History_Entry_Commit(Memory, "Close shape");
History_Action_Swap(Memory, F_File, sizeof(Shape->IsClosed), &Shape->IsClosed);
Shape->IsClosed = true;
History_Entry_End(Memory);
+ } else if (Layer != NULL) {
+ layer_transforms T = Layer_GetTransforms(Layer);
+ History_Entry_Commit(Memory, "Move point");
+ void *Data = Memory_PushScratch(Memory, sizeof(nvg_point) * 128);
+ v2 Min_Old = {}, Max_Old = {};
+ NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, State, T, 0, 0, Width, Height, 0, &Min_Old, &Max_Old);
+ v2 TestMin = Min_Old, TestMax = Max_Old;
+ for (int p = 0; p < Shape->Point_Count; p++) {
+ bezier_point *Point = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, p, 1);
+ if (Point->IsSelected) {
+ v2 *Pos = &Point->Pos[Point->IsSelected-1];
+ History_Action_Swap(Memory, F_Bezier, sizeof(*Pos), Pos);
+ Pos->x += State->Interact_Offset[0];
+ Pos->y += State->Interact_Offset[1];
+ if (Pos->x < TestMin.x) {
+ TestMin.x = Pos->x;
+ }
+ if (Pos->y < TestMin.y) {
+ TestMin.y = Pos->y;
+ }
+ if (Pos->x > TestMax.x) {
+ TestMax.x = Pos->x;
+ }
+ if (Pos->y > TestMax.y) {
+ TestMax.y = Pos->y;
+ }
+ }
+ }
+ v2 MinDiff = TestMin - Min_Old;
+ v2 MaxDiff = TestMax - Max_Old;
+ for (int p = 0; p < Shape->Point_Count; p++) {
+ bezier_point *Point = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, p, 1);
+ v2 *Pos = &Point->Pos[0];
+ History_Action_Swap(Memory, F_Bezier, sizeof(*Pos), Pos);
+ if (MinDiff.x)
+ Pos->x -= State->Interact_Offset[0];
+ if (MinDiff.y)
+ Pos->y -= State->Interact_Offset[1];
+ if (MaxDiff.x)
+ // Pos->x -= State->Interact_Offset[0];
+ if (MaxDiff.y)
+ // Pos->y += State->Interact_Offset[1];
+ int FU = 0;
+ }
+ State->Interact_Active = interact_type_none;
+ v2 Min_New = {}, Max_New = {};
+ NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, State, T, Shape->Width, Shape->Height, Width, Height, 1, &Min_New, &Max_New);
+
+ Memory_PopScratch(Memory, sizeof(nvg_point) * 128);
+
+ int Width_Old = Max_Old.x - Min_Old.x;
+ int Width_New = Max_New.x - Min_New.x;
+ int Height_New = Max_New.y - Min_New.y;
+ if (MinDiff.x) {
+ History_Action_Swap(Memory, F_Layers, sizeof(Layer->ax.CurrentValue), &Layer->ax.CurrentValue);
+ Layer->ax.CurrentValue -= (real32)(State->Interact_Offset[0]) * (1.0f - Layer->ax.CurrentValue) / Width_New;
+ } if (MinDiff.y) {
+ History_Action_Swap(Memory, F_Layers, sizeof(Layer->ay.CurrentValue), &Layer->ay.CurrentValue);
+ Layer->ay.CurrentValue -= (real32)(State->Interact_Offset[1]) * (1.0f - Layer->ay.CurrentValue) / Height_New;
+ } if (MaxDiff.x) {
+ History_Action_Swap(Memory, F_Layers, sizeof(Layer->ax.CurrentValue), &Layer->ax.CurrentValue);
+ Layer->ax.CurrentValue -= (real32)(State->Interact_Offset[0]) * (Layer->ax.CurrentValue) / Width_New;
+ } if (MaxDiff.y) {
+ History_Action_Swap(Memory, F_Layers, sizeof(Layer->ay.CurrentValue), &Layer->ay.CurrentValue);
+ Layer->ay.CurrentValue -= (real32)(State->Interact_Offset[1]) * (Layer->ay.CurrentValue) / Height_New;
+ }
+ /*
+ if (Min_New.y < Min_Old.y) {
+ Layer->y.CurrentValue += Min_New.y - Min_Old.y;
+ }
+ if (Max_New.x > Max_Old.x) {
+ Layer->x.CurrentValue += Max_New.x - Max_Old.x;
+ }
+ if (Max_New.y > Max_Old.y) {
+ Layer->y.CurrentValue += Max_New.y - Max_Old.y;
+ }
+ */
+ Shape->Width = Width_New;
+ Shape->Height = Height_New;
+ History_Entry_End(Memory);
}
}
+ draw_list->AddNgon(ScreenPoint_1[a], 4, PointCol, 8, 5.0f);
ImGui::PopID();
}
ImGui::PopID();
@@ -141,7 +274,7 @@ ImGui_Viewport_BrushUI(project_state *State, memory *Memory, ImVec2 ViewportMin,
}
static void
-ImGui_Viewport_TransformUI(project_data *File, project_state *State, memory *Memory, ui *UI, ImDrawList *draw_list, ImGuiIO &io,
+ImGui_Viewport_TransformUI(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO &io, ImDrawList *draw_list,
interact_transform *Interact, ImVec2 ViewportMin, uint32 CompWidth, uint32 CompHeight, uint16 *SortedKeyframeArray)
{
v2 InteractMin = Interact->Min + Interact->Position;
@@ -419,7 +552,7 @@ ImGui_Viewport_TransformUI(project_data *File, project_state *State, memory *Mem
}
static void
-ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImDrawList *draw_list, block_composition *MainComp, uint32 CompIndex, block_layer *ParentLayer[4], uint32 Recursions,
+ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImGuiIO &io, ImDrawList *draw_list, block_composition *MainComp, uint32 CompIndex, block_layer *ParentLayer[4], uint32 Recursions,
sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray)
{
sorted_comp_array *SortedCompStart = &SortedCompArray[CompIndex];
@@ -432,7 +565,7 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImD
block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical);
if (Layer->IsPrecomp) {
ParentLayer[Recursions] = Layer;
- ImGui_Viewport_SelectedLayerUI(State, Memory, UI, draw_list, MainComp, Layer->Block_Source_Index, ParentLayer, Recursions + 1, SortedCompArray, SortedLayerArray);
+ ImGui_Viewport_SelectedLayerUI(State, Memory, UI, io, draw_list, MainComp, Layer->Block_Source_Index, ParentLayer, Recursions + 1, SortedCompArray, SortedLayerArray);
}
if (Layer->IsSelected) {
uint32 Width = 0, Height = 0;
@@ -443,13 +576,22 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImD
Width = Comp->Width;
Height = Comp->Height;
} else if (Layer->IsShapeLayer) {
+#if DEBUG
block_bezier *Bezier = (block_bezier *)Memory_Block_AddressAtIndex(Memory, F_Bezier, Layer->Shape.Block_Bezier_Index[0]);
Data = Memory_PushScratch(Memory, sizeof(nvg_point) * 128);
int L_Width = 0, L_Height = 0;
Assert(Layer->Shape.Contiguous);
- NumberOfVerts = NVG_FlattenPath(Memory, &Layer->Shape, (nvg_point *)Data, &L_Width, &L_Height);
- Width = L_Width;
- Height = L_Height;
+
+ v2 Min = {}, Max = {};
+ layer_transforms T = Layer_GetTransforms(Layer);
+ if (State->Interact_Active == interact_type_keyframe_move) {
+ NVG_FlattenPath(Memory, &Layer->Shape, (nvg_point *)Data, State, T, 0, 0, Width, Height, 0, &Min, &Max);
+ }
+ NumberOfVerts = NVG_FlattenPath(Memory, &Layer->Shape, (nvg_point *)Data,
+ State, T, Layer->Shape.Width, Layer->Shape.Height, Width, Height, 1, &Min, &Max);
+#endif
+ Width = Layer->Shape.Width;
+ Height = Layer->Shape.Height;
} else {
block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
Width = Source->Width;
@@ -463,41 +605,12 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImD
}
if (Layer->IsShapeLayer) {
- /*
- block_bezier *Bezier = (block_bezier *)Memory_Block_AddressAtIndex(Memory, F_Bezier, Layer->Shape.Block_Bezier_Index[0]);
- for (int i = 0; i < Layer->Shape.Point_Count; i++) {
- bezier_point Point = Bezier->Point[i];
- v2 Pos = TransformPoint(T, Width, Height, Point.Pos[0]);
- v2 CompUV = Pos / V2(MainComp->Width, MainComp->Height);
- ImVec2 ScreenPoint = ImVec2(UI->CompPos.x + CompUV.x * UI->CompZoom.x,
- UI->CompPos.y + CompUV.y * UI->CompZoom.y);
- draw_list->AddNgon(ScreenPoint, 10, IM_COL32(10, 10, 10, 255), 8, 9.0f);
- }
- for (int i = 1; i < Layer->Shape.Point_Count; i++) {
- if (Bezier->Point[i].Type == interpolation_type_bezier) {
- v2 L_Pos[4] = { Bezier->Point[i-1].Pos[0], Bezier->Point[i-1].Pos[2], Bezier->Point[i].Pos[1], Bezier->Point[i].Pos[0] };
- L_Pos[1] = L_Pos[1] + L_Pos[0];
- L_Pos[2] = L_Pos[2] + L_Pos[3];
- ImVec2 ScreenPoint[4];
- for (int i = 0; i < 4; i++) {
- v2 Pos = TransformPoint(T, Width, Height, L_Pos[i]);
- v2 CompUV = Pos / V2(MainComp->Width, MainComp->Height);
- ScreenPoint[i] = ImVec2(UI->CompPos.x + CompUV.x * UI->CompZoom.x,
- UI->CompPos.y + CompUV.y * UI->CompZoom.y);
- }
- draw_list->AddNgon(ScreenPoint[0], 10, IM_COL32(10, 10, 10, 255), 8, 2.0f);
- draw_list->AddNgon(ScreenPoint[3], 10, IM_COL32(10, 10, 10, 255), 8, 2.0f);
- draw_list->AddBezierCubic(ScreenPoint[0],ScreenPoint[1],ScreenPoint[2],ScreenPoint[3], IM_COL32(10, 10, 10, 255), 1.0f, 0);
- } else {
- }
- }
- */
- ImGui_Viewport_ShapeUI(State, Memory, UI, &Layer->Shape, MainComp, draw_list);
+ ImGui_Viewport_ShapeUI(State, Memory, UI, io, Layer, Width, Height, &Layer->Shape, MainComp, draw_list);
+ // point visualization
+#if DEBUG
void *Data2 = Memory_PushScratch(Memory, sizeof(real32) * 3 * 256);
- uint32 GL_PointCount = NVG_ExpandStroke(Memory, NumberOfVerts, Layer->Shape.Opt.StrokeWidth, Layer->Shape.IsClosed, (nvg_point *)Data, (real32 *)Data2);
-
- // test code
+ uint32 GL_PointCount = NVG_ExpandStroke(Memory, NumberOfVerts, Layer->Shape.Opt.StrokeWidth, Layer->Shape.Opt.LineCapType, Layer->Shape.Opt.LineJoinType, Layer->Shape.IsClosed, (nvg_point *)Data, (real32 *)Data2);
for (int i = 0; i < NumberOfVerts; i++) {
nvg_point Point = *((nvg_point *)Data + i);
@@ -516,8 +629,10 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImD
UI->CompPos.y + CompUV.y * UI->CompZoom.y);
draw_list->AddNgon(ScreenPoint, 2, IM_COL32(80, 80, 10, 255), 8, 2.0f);
}
+
Memory_PopScratch(Memory, sizeof(real32) * 3 * 256);
Memory_PopScratch(Memory, sizeof(nvg_point) * 128);
+#endif
}
v2 BoundingPoint[5] = { V2(Width*Layer->ax.CurrentValue, Height*Layer->ay.CurrentValue), V2(0, 0), V2(Width, 0), V2(0, Height), V2(Width, Height) };
@@ -613,15 +728,15 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
if (State->MostRecentlySelectedLayer > -1)
{
block_layer *ParentLayer[4];
- ImGui_Viewport_SelectedLayerUI(State, Memory, UI, draw_list, MainComp, File->PrincipalCompIndex, ParentLayer, 0, SortedCompArray, SortedLayerArray);
+ ImGui_Viewport_SelectedLayerUI(State, Memory, UI, io, draw_list, MainComp, File->PrincipalCompIndex, ParentLayer, 0, SortedCompArray, SortedLayerArray);
if (State->Interact_Active == interact_type_viewport_transform) {
- ImGui_Viewport_TransformUI(File, State, Memory, UI, draw_list, io, (interact_transform *)&State->Interact_Offset[0], ViewportMin, MainComp->Width, MainComp->Height, SortedKeyframeArray);
+ ImGui_Viewport_TransformUI(File, State, Memory, UI, io, draw_list, (interact_transform *)&State->Interact_Offset[0], ViewportMin, MainComp->Width, MainComp->Height, SortedKeyframeArray);
}
}
shape_layer *Shape = &UI->Shape;
- if (State->Tool == tool_pen && State->Interact_Active == interact_type_none && State->MostRecentlySelectedLayer == -1)
- ImGui_Viewport_ShapeUI(State, Memory, UI, Shape, MainComp, draw_list);
+ if (State->Tool == tool_pen && State->MostRecentlySelectedLayer == -1)
+ ImGui_Viewport_ShapeUI(State, Memory, UI, io, NULL, 0, 0, Shape, MainComp, draw_list);
// Interactions for dragging and zooming
ImGui::SetCursorScreenPos(ViewportMin);
diff --git a/src/include/debug.h b/src/include/debug.h
index e1d8ccc..3ddbdc8 100644
--- a/src/include/debug.h
+++ b/src/include/debug.h
@@ -27,7 +27,7 @@ struct debug_temp
struct project_debug
{
debug_temp Temp;
- bool32 ToggleWindow = 1;
+ bool32 ToggleWindow = 0;
bool32 ReloadUI = true;
bool32 NoThreading = 0;
bool32 DisableAlpha = 0;
diff --git a/src/include/functions.h b/src/include/functions.h
index e7b5e44..32737ea 100644
--- a/src/include/functions.h
+++ b/src/include/functions.h
@@ -18,11 +18,15 @@ static void Bezier_Interact_Evaluate(project_state *State, bezier_poin
static void Bezier_Add(memory *Memory, memory_table_list TableName, property_channel *Property, bezier_point PointData, uint16 *ArrayLocation);
static void Bezier_Add(memory *Memory, memory_table_list TableName, uint16 *Block_Bezier_Index, uint16 *Block_Bezier_Count, uint16 *PointCount, bezier_point PointData);
-uint32 Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 Size);
+void * Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 Size);
+
+static layer_transforms Transform_Inverse(layer_transforms T);
+
+static v2 T_CompPosToLayerPos(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, real32 X, real32 Y);
static void GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *StrokeData, void *FillData, uint32 StrokeCount, uint32 FillCount,
- layer_transforms T, int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, int L_Width, int L_Height, v4 Col, int RenderMode);
+ layer_transforms T, int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, int L_Width, int L_Height, v4 FillCol, v4 StrokeCol, int RenderMode);
static void ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, sorted_file Sorted);
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);
diff --git a/src/include/layer.h b/src/include/layer.h
index 85d980d..bf32aca 100644
--- a/src/include/layer.h
+++ b/src/include/layer.h
@@ -12,7 +12,7 @@ Layer_GetTopOffset(project_data *File, memory *Memory);
static void
Layer_UpdateMasksEffects(project_state *State, block_layer *Layer, memory *Memory, void *EffectBitmapAddress,
- int Width, int Height, int BytesPerPixel);
+ int Width, int Height, int BytesPerPixel, int CompWidth, int CompHeight);
static void
Layer_ToggleChannel(project_data *File, memory *Memory, int32 a);
diff --git a/src/include/main.h b/src/include/main.h
index a39fe45..db384ce 100644
--- a/src/include/main.h
+++ b/src/include/main.h
@@ -183,11 +183,14 @@ struct sorted_file
uint64 Source_SortSize;
};
+
struct shape_options {
int Visibility;
v4 FillCol = {1, 1, 1, 1};
- v4 StrokeCol = {1, 1, 1, 1};
- float StrokeWidth = 50;
+ v4 StrokeCol = {0, 1, 0, 1};
+ float StrokeWidth = 10;
+ nvg_line_cap LineJoinType = NVG_ROUND;
+ nvg_line_cap LineCapType = NVG_ROUND;
};
struct shape_layer {
@@ -196,6 +199,8 @@ struct shape_layer {
uint16 Point_Count;
bool32 IsClosed;
bool32 Contiguous = 1; // No points have been deleted/added, so sorting isn't needed.
+ // NOTE(fox): This is kinda lazily done atm, there may be situations where
+ // this isn't the correct value.
int Width;
int Height;
shape_options Opt;
diff --git a/src/include/nanovg.h b/src/include/nanovg.h
new file mode 100644
index 0000000..c6df6b4
--- /dev/null
+++ b/src/include/nanovg.h
@@ -0,0 +1,29 @@
+
+enum nvg_line_cap {
+ NVG_BUTT,
+ NVG_ROUND, // join and line type
+ NVG_SQUARE,
+ NVG_BEVEL, // join type
+ NVG_MITER, // join type
+};
+
+enum nvg_point_flags
+{
+ NVG_PT_CORNER = 0x01,
+ NVG_PT_LEFT = 0x02,
+ NVG_PT_BEVEL = 0x04,
+ NVG_PR_INNERBEVEL = 0x08,
+};
+
+struct nvg_point
+{
+ real32 x;
+ real32 y;
+ real32 dx;
+ real32 dy;
+ real32 Length;
+ real32 dmx;
+ real32 dmy;
+ uint8 Flags;
+};
+
diff --git a/src/layer.cpp b/src/layer.cpp
index 93db19d..7d40310 100644
--- a/src/layer.cpp
+++ b/src/layer.cpp
@@ -94,7 +94,7 @@ Layer_GetTopOffset(project_data *File, memory *Memory)
static void
Layer_UpdateMasksEffects(project_state *State, block_layer *Layer, memory *Memory, void *EffectBitmapAddress,
- int Width, int Height, int BytesPerPixel, int *L_Width, int *L_Height)
+ int Width, int Height, int BytesPerPixel)
{
uint64 Size = Width*Height*BytesPerPixel;
@@ -109,15 +109,24 @@ Layer_UpdateMasksEffects(project_state *State, block_layer *Layer, memory *Memor
if (Layer->IsShapeLayer) {
shape_layer *Shape = &Layer->Shape;
void *Data = Memory_PushScratch(Memory, sizeof(nvg_point) * 128);
- uint32 NumberOfVerts = NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, L_Width, L_Height);
+ Arbitrary_Zero((uint8 *)Data, sizeof(nvg_point) * 128);
+ layer_transforms T = Layer_GetTransforms(Layer);
+ v2 Min = {}, Max = {};
+ if (State->Interact_Active == interact_type_keyframe_move) {
+ NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, State, T, 0, 0, Width, Height, 0, &Min, &Max);
+ Shape->Width = Max.x - Min.x;
+ Shape->Height = Max.y - Min.y;
+ }
+ uint32 NumberOfVerts = NVG_FlattenPath(Memory, Shape, (nvg_point *)Data,
+ State, T, Shape->Width, Shape->Height, Width, Height, 1, &Min, &Max);
void *Data_Stroke = Memory_PushScratch(Memory, sizeof(real32) * 4 * 256);
- uint32 StrokeCount = NVG_ExpandStroke(Memory, NumberOfVerts, Shape->Opt.StrokeWidth, Shape->IsClosed, (nvg_point *)Data, (real32 *)Data_Stroke);
+ uint32 StrokeCount = NVG_ExpandStroke(Memory, NumberOfVerts, Shape->Opt.StrokeWidth, Shape->Opt.LineCapType, Shape->Opt.LineJoinType, Shape->IsClosed, (nvg_point *)Data, (real32 *)Data_Stroke);
void *Data_Fill = Memory_PushScratch(Memory, sizeof(real32) * 4 * NumberOfVerts);
NVG_ExpandFill(Memory, NumberOfVerts, (nvg_point *)Data, (real32 *)Data_Fill);
- layer_transforms T = Layer_GetTransforms(Layer);
GL_RasterizeShape(&TestL, &TestM, Data_Stroke, Data_Fill, StrokeCount, NumberOfVerts, T,
- Width, Height, BytesPerPixel, EffectBitmapAddress, *L_Width, *L_Height, Layer->Shape.Opt.StrokeCol, Shape->Opt.Visibility);
+ Width, Height, BytesPerPixel, EffectBitmapAddress, Shape->Width, Shape->Height,
+ Shape->Opt.StrokeCol, Shape->Opt.FillCol, Shape->Opt.Visibility);
Memory_PopScratch(Memory, sizeof(real32) * 4 * NumberOfVerts);
Memory_PopScratch(Memory, sizeof(real32) * 4 * 256);
@@ -309,6 +318,23 @@ Layer_Select_Traverse(uint16 PrincipalCompIndex, memory *Memory, project_state *
}
}
+static void
+Layer_GetDimensions(memory *Memory, block_layer *Layer, int *Width, int *Height)
+{
+ if (Layer->IsPrecomp) {
+ block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, Layer->Block_Source_Index);
+ *Width = Comp->Width;
+ *Height = Comp->Height;
+ } else if (Layer->IsShapeLayer) {
+ *Width = Layer->Shape.Width;
+ *Height = Layer->Shape.Height;
+ } else {
+ block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
+ *Width = Source->Width;
+ *Height = Source->Height;
+ }
+}
+
static v2
Layer_TraverseForPoint(project_data *File, project_state *State, memory *Memory, v2 PrincipalCompUV, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray)
{
@@ -352,9 +378,10 @@ Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_ar
sorted_layer_array SortEntry = SortedLayerStart[i];
uint32 Index_Physical = SortEntry.Block_Layer_Index;
block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical);
- block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
+ int Width, Height;
+ Layer_GetDimensions(Memory, Layer, &Width, &Height);
layer_transforms T = Layer_GetTransforms(Layer);
- v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Source->Width, Source->Height, State->LastClickedPoint);
+ v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Width, Height, State->LastClickedPoint);
if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && Layer->IsSelected)
{
SelectionCount++;
@@ -366,9 +393,10 @@ Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_ar
sorted_layer_array SortEntry = SortedLayerStart[i];
uint32 Index_Physical = SortEntry.Block_Layer_Index;
block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, Index_Physical);
- block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
+ int Width, Height;
+ Layer_GetDimensions(Memory, Layer, &Width, &Height);
layer_transforms T = Layer_GetTransforms(Layer);
- v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Source->Width, Source->Height, State->LastClickedPoint);
+ v2 UV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Width, Height, State->LastClickedPoint);
if (UV.x <= 1.0f && UV.x >= 0.0f && UV.y <= 1.0f && UV.y >= 0.0f && !Layer->IsSelected)
{
if (SelectionCount == 1) {
diff --git a/src/main.cpp b/src/main.cpp
index 27a985e..e9cbf32 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -54,6 +54,7 @@ extern "C" {
#include "stable_diffusion.h"
#endif
#include "memory.h"
+#include "nanovg.h"
#include "main.h"
#include "ffmpeg_backend.h"
@@ -441,7 +442,9 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, sorted_fil
}
if (Layer->IsShapeLayer) {
- Layer_UpdateMasksEffects(State, Layer, Memory, RenderAddress, Comp->Width, Comp->Height, Comp->BytesPerPixel, &Width, &Height);
+ Layer_UpdateMasksEffects(State, Layer, Memory, RenderAddress, Comp->Width, Comp->Height, Comp->BytesPerPixel);
+ Width = Layer->Shape.Width;
+ Height = Layer->Shape.Height;
rectangle RenderRegion = { 0, 0, Comp->Width, Comp->Height };
direct_info Info = { (real32)Comp->Width, (real32)Comp->Height, (real32)Comp->BytesPerPixel, (real32)Comp->Width * Comp->BytesPerPixel,
Bitmap_ByteInfo(Comp->BytesPerPixel), UI->Color.a, blend_normal,
diff --git a/src/nanovg.cpp b/src/nanovg.cpp
index 5627b5f..1fb59ee 100644
--- a/src/nanovg.cpp
+++ b/src/nanovg.cpp
@@ -1,23 +1,23 @@
-enum nvg_point_flags
-{
- NVG_PT_CORNER = 0x01,
- NVG_PT_LEFT = 0x02,
- NVG_PT_BEVEL = 0x04,
- NVG_PR_INNERBEVEL = 0x08,
-};
+// nanovg code adapted by me for my data structures, I'm primarily using the
+// functions related to shape/path triangulation.
-struct nvg_point
-{
- real32 x;
- real32 y;
- real32 dx;
- real32 dy;
- real32 Length;
- real32 dmx;
- real32 dmy;
- uint8 Flags;
-};
+// Copyright (c) 2013 Mikko Mononen memon@inside.org
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+//
static real32
NVG_Normalize(real32 *x, float* y)
@@ -87,7 +87,30 @@ static real32 * NVG_RoundJoin(nvg_point *Point, nvg_point *NextPoint, real32 *St
StrokeData = NVG_Point(StrokeData, lx1, ly1, 0, 0);
StrokeData = NVG_Point(StrokeData, NextPoint->x - dlx1*rw, NextPoint->y - dly1*rw, 0, 0);
- }
+ } else {
+ float rx0,ry0,rx1,ry1,a0,a1;
+ NVG_ChooseBevel(NextPoint->Flags & NVG_PR_INNERBEVEL, Point, NextPoint, -rw, &rx0,&ry0, &rx1,&ry1);
+ a0 = atan2f(dly0, dlx0);
+ a1 = atan2f(dly1, dlx1);
+ if (a1 < a0) a1 += PI*2;
+
+ StrokeData = NVG_Point(StrokeData, NextPoint->x + dlx0*rw, NextPoint->y + dly0*rw, 0, 0);
+ StrokeData = NVG_Point(StrokeData, rx0, ry0, 0, 0);
+
+ n = NVG_Clampi((int)ceilf(((a1 - a0) / PI) * ncap), 2, ncap);
+ for (i = 0; i < n; i++) {
+ float u = i/(float)(n-1);
+ float a = a0 + u*(a1-a0);
+ float lx = NextPoint->x + cosf(a) * lw;
+ float ly = NextPoint->y + sinf(a) * lw;
+ StrokeData = NVG_Point(StrokeData, lx, ly, 0, 0);
+ StrokeData = NVG_Point(StrokeData, NextPoint->x, NextPoint->y, 0, 0);
+ }
+
+ StrokeData = NVG_Point(StrokeData, NextPoint->x + dlx1*rw, NextPoint->y + dly1*rw, 0, 0);
+ StrokeData = NVG_Point(StrokeData, rx1, ry1, 0, 0);
+ }
+
return StrokeData;
}
@@ -125,71 +148,100 @@ static real32 * NVG_RoundCap(nvg_point * Point, real32 *StrokeData,
return StrokeData;
}
+static real32 * NVG_ButtCap(nvg_point *Point, real32 *StrokeData,
+ float dx, float dy, float w, float d,
+ float u0, float u1, int Mode)
+{
+ float px = (Mode == 0) ? Point->x - dx*d : Point->x + dx*d;
+ float py = (Mode == 0) ? Point->y - dy*d : Point->y + dy*d;
+ float dlx = dy;
+ float dly = -dx;
+ if (Mode == 0) {
+ StrokeData = NVG_Point(StrokeData, px + dlx*w - dx, py + dly*w - dy, 0, 0);
+ StrokeData = NVG_Point(StrokeData, px - dlx*w - dx, py - dly*w - dy, 0, 0);
+ StrokeData = NVG_Point(StrokeData, px + dlx*w, py + dly*w, 0, 0);
+ StrokeData = NVG_Point(StrokeData, px - dlx*w, py - dly*w, 0, 0);
+ } else {
+ StrokeData = NVG_Point(StrokeData, px + dlx*w, py + dly*w, 0, 0);
+ StrokeData = NVG_Point(StrokeData, px - dlx*w, py - dly*w, 0, 0);
+ StrokeData = NVG_Point(StrokeData, px + dlx*w + dx, py + dly*w + dy, 0, 0);
+ StrokeData = NVG_Point(StrokeData, px - dlx*w + dx, py - dly*w + dy, 0, 0);
+ }
+ return StrokeData;
+}
+
// NOTE(fox): We only have to care about winding if we want to do HW accelerated
// shape subtraction with the stencil buffer (I think).
+// All the extra inputs on the second line are for when we need to take
+// interactive mode into account. Since undoing a transform requires knowledge
+// of the shape's size (does it?), the code needs to be ran twice, controlled
+// with the Interact bool.
static uint32
-NVG_FlattenPath(memory *Memory, shape_layer *Shape, nvg_point *PointData, int *Width, int *Height)
+NVG_FlattenPath(memory *Memory, shape_layer *Shape, nvg_point *PointData,
+ project_state *State, layer_transforms T, int Width, int Height,
+ int CompWidth, int CompHeight, bool32 Interact, v2 *Min, v2 *Max)
{
- uint32 NumberOfVerts = 0;
nvg_point *PointPlayhead = PointData;
for (int i = 0; i < Shape->Point_Count; i++) {
bezier_point *Point = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i, 1);
-#if 0
if (i == 0 || Point->Type == interpolation_type_linear) {
- *(v2 *)PointPlayhead = Point->Pos[0];
- if (i != 0 && i != (Shape->Point_Count - 1)) {
+ v2 Pos = Point->Pos[0];
+ if (State->Interact_Active == interact_type_keyframe_move && Point->IsSelected && Interact != 0) {
+ Pos = TransformPoint(T, Width, Height, Pos);
+ Pos.x += State->Interact_Offset[0];
+ Pos.y += State->Interact_Offset[1];
+ Pos = T_CompPosToLayerPos(T, CompWidth, CompHeight, Width, Height, Pos.x, Pos.y);
+ }
+ *(v2 *)PointPlayhead = Pos;
+ if (Shape->IsClosed || (i != 0 && i != (Shape->Point_Count - 1))) {
PointPlayhead->Flags |= NVG_PT_CORNER;
}
PointPlayhead++;
- NumberOfVerts++;
} else if (Point->Type == interpolation_type_bezier) {
bezier_point *Point_1 = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i-1, 1);
- v2 Pos[4] = { Point->Pos[0], Point->Pos[1], Point_1->Pos[2], Point_1->Pos[0] };
- Pos[1] = Pos[1] + Pos[0];
- Pos[2] = Pos[2] + Pos[3];
- NumberOfVerts += Bezier_CubicCalcPoints(Pos[3], Pos[2], Pos[1], Pos[0], PointPlayhead, sizeof(nvg_point));
+ v2 Pos[2] = { Point_1->Pos[0], Point->Pos[0] };
+ if (State->Interact_Active == interact_type_keyframe_move && Point->IsSelected && Width != 0) {
+ for (int i = 0; i < 2; i++) {
+ Pos[i] = TransformPoint(T, Width, Height, Pos[i]);
+ Pos[i].x += State->Interact_Offset[0];
+ Pos[i].y += State->Interact_Offset[1];
+ Pos[i] = T_CompPosToLayerPos(T, CompWidth, CompHeight, Width, Height, Pos[i].x, Pos[i].y);
+ }
+ }
+ PointPlayhead = (nvg_point *)Bezier_CubicCalcPoints(Pos[0], Pos[0] + Point_1->Pos[1], Pos[1] + Point->Pos[2], Pos[1], PointPlayhead, sizeof(nvg_point));
// The point at the end is also returned, so we remove it.
- NumberOfVerts--;
- PointPlayhead--;
+ if (i != (Shape->Point_Count - 1))
+ PointPlayhead--;
} else {
Assert(0);
}
-#else
- *(v2 *)PointPlayhead = Point->Pos[0];
- if (i != 0 && i != (Shape->Point_Count - 1)) {
- PointPlayhead->Flags |= NVG_PT_CORNER;
- }
- PointPlayhead++;
- NumberOfVerts++;
-#endif
}
+ int NumberOfVerts = PointPlayhead - PointData;
nvg_point *Point = &PointData[NumberOfVerts - 1];
nvg_point *NextPoint = PointData;
- v2 Min = V2(10000, 10000);
- v2 Max = V2(-10000, -10000);
+ *Min = V2(10000, 10000);
+ *Max = V2(-10000, -10000);
for (int i = 0; i < NumberOfVerts; i++) {
Point->dx = NextPoint->x - Point->x;
Point->dy = NextPoint->y - Point->y;
Point->Length = NVG_Normalize(&Point->dx, &Point->dy);
- if (Point->x > Max.x)
- Max.x = Point->x;
- if (Point->x < Min.x)
- Min.x = Point->x;
- if (Point->y > Max.y)
- Max.y = Point->y;
- if (Point->y < Min.y)
- Min.y = Point->y;
+ if (Point->x > Max->x)
+ Max->x = Point->x;
+ if (Point->x < Min->x)
+ Min->x = Point->x;
+ if (Point->y > Max->y)
+ Max->y = Point->y;
+ if (Point->y < Min->y)
+ Min->y = Point->y;
Point = NextPoint++;
}
- *Width = Max.x - Min.x;
- *Height = Max.y - Min.y;
return NumberOfVerts;
}
real32 MiterLimit = 2.4f;
static uint32
-NVG_ExpandStroke(void *Memory, int NumberOfVerts, real32 StartWidth, bool32 IsClosed, nvg_point *PointData, real32 *StrokeData)
+NVG_ExpandStroke(void *Memory, int NumberOfVerts, real32 StartWidth, nvg_line_cap LineCap, nvg_line_cap LineJoin, bool32 IsClosed, nvg_point *PointData, real32 *StrokeData)
{
real32 Width = StartWidth * 0.5;
int ncap = 12;
@@ -205,7 +257,11 @@ NVG_ExpandStroke(void *Memory, int NumberOfVerts, real32 StartWidth, bool32 IsCl
NextPoint = &PointData[1];
Start = 1;
LoopAmount = NumberOfVerts - 1;
- StrokeData = NVG_RoundCap(Point, StrokeData, Point->dx, Point->dy, Width, ncap, 0.5, 0.5, 0);
+ if (LineCap == NVG_ROUND) {
+ StrokeData = NVG_RoundCap(Point, StrokeData, Point->dx, Point->dy, Width, ncap, 0.5, 0.5, 0);
+ } else {
+ StrokeData = NVG_ButtCap(Point, StrokeData, Point->dx, Point->dy, Width, Width-1, 0.5, 0.5, 0);
+ }
}
for (int i = Start; i < LoopAmount; i++) {
@@ -229,6 +285,9 @@ NVG_ExpandStroke(void *Memory, int NumberOfVerts, real32 StartWidth, bool32 IsCl
NextPoint->dmy *= scale;
}
+ // Clear flags, but keep the corner.
+ NextPoint->Flags = (NextPoint->Flags & NVG_PT_CORNER) ? NVG_PT_CORNER : 0;
+
// Keep track of left turns.
cross = NextPoint->dx * Point->dy - Point->dx * NextPoint->dy;
if (cross > 0.0f) {
@@ -236,21 +295,22 @@ NVG_ExpandStroke(void *Memory, int NumberOfVerts, real32 StartWidth, bool32 IsCl
}
// Calculate if we should use bevel or miter for inner join.
- // limit = nvg__maxf(1.01f, nvg__minf(p0->len, p1->len) * iw);
- // if ((dmr2 * limit*limit) < 1.0f)
- // p1->flags |= NVG_PR_INNERBEVEL;
+ float iw = (Width > 0.0f) ? 1.0f / Width : 0.0f;
+ limit = Max(1.01f, Min(Point->Length, NextPoint->Length) * iw);
+ if ((dmr2 * limit*limit) < 1.0f)
+ NextPoint->Flags |= NVG_PR_INNERBEVEL;
// Check to see if the corner needs to be beveled.
if (NextPoint->Flags & NVG_PT_CORNER) {
- // if ((dmr2 * MiterLimit*MiterLimit) < 1.0f) r // || lineJoin == NVG_BEVEL || lineJoin == NVG_ROUND) {
- // NextPoint->Flags |= NVG_PT_BEVEL;
- // }
+ if (((dmr2 * MiterLimit*MiterLimit) < 1.0f) || LineJoin == NVG_BEVEL || LineJoin == NVG_ROUND) {
+ NextPoint->Flags |= NVG_PT_BEVEL;
+ }
}
if ((NextPoint->Flags & (NVG_PT_BEVEL | NVG_PR_INNERBEVEL)) != 0) {
- // if (lineJoin == NVG_ROUND) {
+ if (LineJoin == NVG_ROUND) {
StrokeData = NVG_RoundJoin(Point, NextPoint, StrokeData, Width, Width, 0.5, 0.5, ncap);
- // }
+ }
} else {
StrokeData = NVG_Point(StrokeData, NextPoint->x + (NextPoint->dmx * Width), NextPoint->y + (NextPoint->dmy * Width), 0, 0);
StrokeData = NVG_Point(StrokeData, NextPoint->x - (NextPoint->dmx * Width), NextPoint->y - (NextPoint->dmy * Width), 0, 0);
@@ -260,7 +320,11 @@ NVG_ExpandStroke(void *Memory, int NumberOfVerts, real32 StartWidth, bool32 IsCl
}
if (!IsClosed) {
- StrokeData = NVG_RoundCap(NextPoint, StrokeData, Point->dx, Point->dy, Width, ncap, 0.5, 0.5, 1);
+ if (LineCap == NVG_ROUND) {
+ StrokeData = NVG_RoundCap(NextPoint, StrokeData, Point->dx, Point->dy, Width, ncap, 0.5, 0.5, 1);
+ } else {
+ StrokeData = NVG_ButtCap(NextPoint, StrokeData, Point->dx, Point->dy, Width, Width-1, 0.5, 0.5, 1);
+ }
} else {
StrokeData = NVG_Point(StrokeData, StartingStrokeData[0], StartingStrokeData[1], 0, 0);
StrokeData = NVG_Point(StrokeData, StartingStrokeData[4], StartingStrokeData[5], 0, 0);
diff --git a/src/prenderer.cpp b/src/prenderer.cpp
index 54b19cf..fc6edd4 100644
--- a/src/prenderer.cpp
+++ b/src/prenderer.cpp
@@ -1,4 +1,24 @@
static v2
+T_CompPosToLayerPos(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, real32 X, real32 Y)
+{
+ real32 Rad = (T.rotation* (PI / 180));
+ v2 XAxis = (SourceWidth * T.scale)*V2(cos(Rad), sin(Rad));
+ v2 YAxis = (SourceHeight * -T.scale)*V2(sin(Rad), -cos(Rad));
+
+ v2 Pos = {T.x, T.y};
+ v2 Origin = Pos - (XAxis * T.ax) - (YAxis * T.ay);
+
+ v2 XAxisPerp = (1.0f / LengthSq(XAxis))*XAxis;
+ v2 YAxisPerp = (1.0f / LengthSq(YAxis))*YAxis;
+
+ real32 StartVectorX = X - Origin.x;
+ real32 StartVectorY = Y - Origin.y;
+ real32 LayerU = (StartVectorX * XAxisPerp.x) + (StartVectorY * XAxisPerp.y);
+ real32 LayerV = (StartVectorX * YAxisPerp.x) + (StartVectorY * YAxisPerp.y);
+ return V2(LayerU * SourceWidth, LayerV * SourceHeight);
+}
+
+static v2
T_CompUVToLayerUV(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, v2 CompUV)
{
real32 X = CompUV.x*FileWidth;
@@ -37,20 +57,6 @@ Transform_ScreenSpaceToLocal(layer_transforms T, uint32 FileWidth, uint32 FileHe
return V2(LayerUV.x * SourceWidth, LayerUV.y * SourceHeight);
}
-static void
-Layer_GetDimensions(memory *Memory, block_layer *Layer, int *Width, int *Height)
-{
- if (!Layer->IsPrecomp) {
- block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index);
- *Width = Source->Width;
- *Height = Source->Height;
- } else {
- block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, Layer->Block_Source_Index);
- *Width = Comp->Width;
- *Height = Comp->Height;
- }
-}
-
// Transform given data based on state's Interact data.
static void
Transform_ApplyInteractive(interact_transform Interact, real32 *OutputX, real32 *OutputY, real32 *OutputRotation, real32 *OutputScale)
@@ -220,6 +226,7 @@ Interact_Transform_Begin(project_data *File, memory *Memory, project_state *Stat
*/
}
+
static v2
TransformPoint(layer_transforms T, real32 Width, real32 Height, v2 Point)
{
@@ -230,6 +237,17 @@ TransformPoint(layer_transforms T, real32 Width, real32 Height, v2 Point)
return V2(T.x + LocalPoint.x, T.y + LocalPoint.y);
}
+static layer_transforms
+Transform_Inverse(layer_transforms T)
+{
+ T.x = -T.x;
+ T.y = -T.y;
+ T.ax = -T.ax;
+ T.ay = -T.ay;
+ T.rotation = T.rotation;
+ T.scale = 1.0f;
+ return T;
+}
static ImVec2
Layer_LocalToScreenSpace(project_state *State, memory *Memory, block_layer *Layer, ui *UI, uint32 PrincipalCompIndex, v2 Point)