summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bezier.cpp121
-rw-r--r--src/createcalls.cpp71
-rw-r--r--src/effects.cpp4
-rw-r--r--src/effects_constructors.cpp6
-rw-r--r--src/effects_gl.cpp4
-rw-r--r--src/effects_gl_shader.cpp4
-rw-r--r--src/effects_software.cpp4
-rw-r--r--src/ffmpeg_backend.cpp6
-rw-r--r--src/gl_calls.cpp149
-rw-r--r--src/imgui_helper.cpp4
-rw-r--r--src/imgui_helper_internal.cpp5
-rw-r--r--src/imgui_ui.cpp32
-rw-r--r--src/imgui_ui_debug.cpp4
-rw-r--r--src/imgui_ui_properties.cpp27
-rw-r--r--src/imgui_ui_stable_diffusion.cpp4
-rw-r--r--src/imgui_ui_timeline.cpp4
-rw-r--r--src/imgui_ui_viewport.cpp172
-rw-r--r--src/include/all.h612
-rw-r--r--src/include/defines.h2
-rw-r--r--src/include/functions.h21
-rw-r--r--src/include/imgui_ops.h2
-rw-r--r--src/include/layer.h2
-rw-r--r--src/include/main.h93
-rw-r--r--src/include/memory.h11
-rw-r--r--src/include/my_math.h16
-rw-r--r--src/io.cpp4
-rw-r--r--src/layer.cpp175
-rw-r--r--src/main.cpp338
-rw-r--r--src/memory.cpp16
-rw-r--r--src/nanovg.cpp4
-rw-r--r--src/paint.cpp4
-rw-r--r--src/prenderer.cpp16
-rw-r--r--src/sorted.cpp73
-rw-r--r--src/stable_diffusion.cpp6
-rw-r--r--src/strings.cpp4
-rw-r--r--src/threading.cpp4
-rw-r--r--src/undo.cpp56
37 files changed, 1853 insertions, 227 deletions
diff --git a/src/bezier.cpp b/src/bezier.cpp
index b90e146..5916c42 100644
--- a/src/bezier.cpp
+++ b/src/bezier.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static real32
Bezier_SolveYForX(v2 Point_P0, v2 Point_P1, v2 Point_P2, v2 Point_P3, real32 TargetX) {
@@ -46,6 +50,11 @@ Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData,
bezier_point *PointStart = PointData;
for (int i = 0; i < Shape->Point_Count; i++) {
bezier_point Point = *Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i, 1);
+ if (Width != 0 && Height != 0) {
+ for (int a = 0; a < 3; a++) {
+ Point.Pos[a] = Point.Pos[a] * V2(Width, Height);
+ }
+ }
if (State->Interact_Active == interact_type_keyframe_move && Interact && Point.IsSelected) {
v2 Pos = Point.Pos[0];
Pos = TransformPoint(T, Width, Height, Pos);
@@ -64,6 +73,10 @@ Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData,
bezier_point *Point_Next = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, Index_Next, 1);
v2 Pos_Prev = Point_Prev->Pos[0];
v2 Pos_Next = Point_Next->Pos[0];
+ if (Width != 0 && Height != 0) {
+ Pos_Prev = Pos_Prev * V2(Width, Height);
+ Pos_Next = Pos_Next * V2(Width, Height);
+ }
// TODO(fox): debloat
if (State->Interact_Active == interact_type_keyframe_move && Interact && Point_Prev->IsSelected) {
v2 Pos = Pos_Prev;
@@ -255,21 +268,38 @@ void * Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 Siz
return ((uint8 *)Data + (Increment * Size));
}
+v2 Bezier_LineDist(v2 a, v2 b, v2 p)
+{
+ v2 ap = p - a;
+ v2 ab_dir = b - a;
+ real32 dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
+ if (dot < 0.0f) {
+ return a;
+ }
+ real32 ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
+ if (dot > ab_len_sqr) {
+ return b;
+ }
+ return p - (a + ab_dir * dot / ab_len_sqr);
+}
-#if 0
-// A modified version of the bezier code in ImGui with extra features for bitmap and path interaction.
-
-// Function to convert a ratio back into a point for the bezier handles.
-v2 Line_RatioToPoint(v2 a, v2 b, real32 ratio)
+v2 Bezier_LineClosestPoint(v2 a, v2 b, v2 p)
{
+ v2 ap = p - a;
v2 ab_dir = b - a;
+ real32 dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
+ if (dot < 0.0f) {
+ return a;
+ }
real32 ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
- real32 dot = ratio*ab_len_sqr;
- return a + ab_dir * dot / V2(ab_len_sqr);
+ if (dot > ab_len_sqr) {
+ return b;
+ }
+ return a + ab_dir * dot / ab_len_sqr;
}
// The ratio here is just the dot product divided by the squared length.
-v2 Bezier_LineClosestPoint2(v2 a, v2 b, v2 p, real32 *ratio)
+v2 Bezier_LineClosestPointR(v2 a, v2 b, v2 p, real32 *ratio)
{
v2 ap = p - a;
v2 ab_dir = b - a;
@@ -287,6 +317,54 @@ v2 Bezier_LineClosestPoint2(v2 a, v2 b, v2 p, real32 *ratio)
return a + ab_dir * dot / ab_len_sqr;
}
+static void Bezier_CubicBoxCasteljauStep(v2 Min, v2 Max, v2 *p_closest, v2 *p_last, real32 *p_closest_dist2,
+ real32 x1, real32 y1, real32 x2, real32 y2, real32 x3, real32 y3, real32 x4, real32 y4, real32 tess_tol, int level)
+{
+ real32 dx = x4 - x1;
+ real32 dy = y4 - y1;
+ real32 d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
+ real32 d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
+ d2 = (d2 >= 0) ? d2 : -d2;
+ d3 = (d3 >= 0) ? d3 : -d3;
+ if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
+ {
+ v2 p_current = V2(x4, y4);
+ v2 p[4] = { Min, Max, V2(Min.x, Max.y), V2(Max.y, Min.x) };
+ for (int i = 0; i < 4; i++) {
+ v2 p_line = Bezier_LineClosestPoint(*p_last, p_current, p[i]);
+ real32 dist2 = LengthSq(p[i] - p_line);
+ if (dist2 < p_closest_dist2[i])
+ {
+ p_closest[i] = p_line;
+ p_closest_dist2[i] = dist2;
+ }
+ }
+ *p_last = p_current;
+ }
+ else if (level < 10)
+ {
+ real32 x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f;
+ real32 x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f;
+ real32 x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f;
+ real32 x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f;
+ real32 x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f;
+ real32 x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
+ Bezier_CubicBoxCasteljauStep(Min, Max, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
+ Bezier_CubicBoxCasteljauStep(Min, Max, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
+ }
+}
+
+static void
+Bezier_BoxTest(v2 p1, v2 p2, v2 p3, v2 p4, v2 Min, v2 Max, v2 *p_closest)
+{
+ real32 tess_tol = TESS_TOL;
+ v2 p_last = p1;
+ real32 p_closest_dist2[4] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
+ Bezier_CubicBoxCasteljauStep(Min, Max, p_closest, &p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0);
+}
+
+
+#if 0
// Following the algorithm, we take the ratio from the _leftmost_ point in each
// subdivision of the cubic spline until we're within tess_tol, and then we
// interpolate it with the subdivision's rightmost point in the ClosestPoint call.
@@ -307,7 +385,7 @@ static void Bezier_CubicClosestPointCasteljauStep(v2 p, v2 *p_closest, real32 ra
{
v2 p_current = V2(x4, y4);
real32 added_ratio;
- v2 p_line = Bezier_LineClosestPoint2(*p_last, p_current, p, &added_ratio);
+ v2 p_line = Bezier_LineClosestPoint(*p_last, p_current, p, &added_ratio);
real32 dist2 = LengthSq(p - p_line);
if (dist2 < *p_closest_dist2)
{
@@ -330,6 +408,31 @@ static void Bezier_CubicClosestPointCasteljauStep(v2 p, v2 *p_closest, real32 ra
}
}
+real32 Bezier_CubicRatioOfPoint(v2 p1, v2 p2, v2 p3, v2 p4, v2 p)
+{
+ real32 tess_tol = TESS_TOL;
+ v2 p_last = p1;
+ v2 p_closest;
+ real32 p_closest_dist2 = FLT_MAX;
+ real32 ratio = 0;
+ Bezier_CubicClosestPointCasteljauStep(p, &p_closest, 0, &ratio, &p_last, &p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0);
+ return ratio;
+}
+#endif
+
+
+#if 0
+// A modified version of the bezier code in ImGui with extra features for bitmap and path interaction.
+
+// Function to convert a ratio back into a point for the bezier handles.
+v2 Line_RatioToPoint(v2 a, v2 b, real32 ratio)
+{
+ v2 ab_dir = b - a;
+ real32 ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
+ real32 dot = ratio*ab_len_sqr;
+ return a + ab_dir * dot / V2(ab_len_sqr);
+}
+
// finds the min/max bounds of the curve
static void Bezier_CubicMinMaxCasteljauStep(v2 *p_min, v2 *p_max, real32 x1, real32 y1, real32 x2, real32 y2, real32 x3, real32 y3, real32 x4, real32 y4, real32 tess_tol, int level)
{
diff --git a/src/createcalls.cpp b/src/createcalls.cpp
index 4334dc8..2a344a0 100644
--- a/src/createcalls.cpp
+++ b/src/createcalls.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static void
PostMsg(project_state *State, char *msg)
{
@@ -459,7 +463,7 @@ void Property_MinMax_X(memory *Memory, project_state *State, property_channel *P
*Max = LastPointPos[0].x;
}
void Property_MinMax_Y(memory *Memory, project_state *State, property_channel *Property,
- sorted_property_array *PropertyStart, real32 *Min, real32 *Max, bool32 Evaluate = 1)
+ sorted_property_array *PropertyStart, real32 *Min, real32 *Max, bool32 Evaluate)
{
if (Evaluate) {
v2 MinYPointPos[3];
@@ -610,6 +614,53 @@ Property_IsGraphSelected(memory *Memory, property_channel *Property, uint16 *Arr
}
static void
+Project_Layer_Duplicate(project_data *File, project_state *State, memory *Memory,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, v2 Offset, bool32 FakeOnly)
+{
+ for (int c = 0; c < File->Comp_Count; c++) {
+ sorted_comp_array SortedCompStart = SortedCompArray[c];
+ sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, c);
+ int LayerCount = SortedCompStart.LayerCount + SortedCompStart.FakeLayerCount;
+ int Increment = 0;
+ for (int i = 0; i < LayerCount; i++)
+ {
+ 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);
+ if ((FakeOnly && SortEntry.IsFake) || (!FakeOnly && Layer->IsSelected))
+ {
+ if (!FakeOnly)
+ Layer->IsSelected = false;
+
+ block_layer *NewLayer = (block_layer *)Memory_Block_AllocateAddress(Memory, F_Layers);
+ History_Action_Block_Swap(Memory, F_Layers, NewLayer);
+ *NewLayer = *Layer;
+ NewLayer->IsSelected = true;
+
+ Assert(!NewLayer->x.Keyframe_Count);
+ Assert(!NewLayer->y.Keyframe_Count);
+ NewLayer->x.CurrentValue += Offset.x;
+ NewLayer->y.CurrentValue += Offset.y;
+
+ NewLayer->Block_String_Index = Memory_Block_AllocateNew(Memory, F_Strings);
+ block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, NewLayer->Block_String_Index, 0);
+ sprintf(String->Char, "Layer %i", File->Layer_Count + 1); // CSbros...
+ History_Action_Swap(Memory, F_Strings, sizeof(String->Occupied), &String->Occupied);
+ String->Occupied = 1;
+
+ History_Action_Swap(Memory, F_File, sizeof(File->Layer_Count), &File->Layer_Count);
+ File->Layer_Count++;
+
+ Increment++;
+ } else {
+ // History_Action_Swap(Memory, F_File, sizeof(Layer->Vertical_Offset), &Layer->Vertical_Offset);
+ Layer->IsSelected = false;
+ }
+ }
+ }
+}
+
+static void
Project_ShapeLayer_New(project_data *File, project_state *State, memory *Memory)
{
int TopOffset = Layer_GetTopOffset(File, Memory);
@@ -635,6 +686,13 @@ Project_ShapeLayer_New(project_data *File, project_state *State, memory *Memory)
Memory_PopScratch(Memory, sizeof(nvg_point) * 128);
Shape->Width = Max.x - Min.x;
Shape->Height = Max.y - Min.y;
+ for (int i = 0; i < Shape->Point_Count; i++) {
+ bezier_point *Point = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i, 1);
+ for (int a = 0; a < 3; a++) {
+ Point->Pos[a] = (Point->Pos[a] - Min) / V2(Shape->Width, Shape->Height);
+ }
+ }
+
Layer->x.CurrentValue = Min.x + (Shape->Width / 2);
Layer->y.CurrentValue = Min.y + (Shape->Height / 2);
@@ -657,10 +715,6 @@ Project_ShapeLayer_New(project_data *File, project_state *State, memory *Memory)
Layer->x.CurrentValue = Min.x + (ShapeSize.x / 2);
Layer->y.CurrentValue = Min.y + (ShapeSize.y / 2);
*/
- for (int i = 0; i < Shape->Point_Count; i++) {
- bezier_point *Point = Bezier_LookupAddress(Memory, Shape->Block_Bezier_Index, i, 1);
- Point->Pos[0] = Point->Pos[0] - Min;
- }
History_Action_Swap(Memory, F_Layers, sizeof(Layer->Shape), &Layer->Shape);
Layer->Shape = File->UI.Shape;
@@ -723,6 +777,13 @@ void Source_UICreateButton(project_data *File, project_state *State, memory *Mem
Layer->Vertical_Offset = TopOffset-1;
Layer->Frame_Start = Comp->Frame_Start;
Layer->Frame_End = Comp->Frame_End;
+ if (Source->HasVideo) {
+ av_info *AV = (av_info *)Memory_Block_AllocateAddress(Memory, P_AVInfo);
+ AV->Occupied = 1;
+ AV->Block_Source_Index = Layer->Block_Source_Index;
+ AV_Init(Source, AV, Memory);
+ State->AVCount++;
+ }
}
State->UpdateFrame = true;
}
diff --git a/src/effects.cpp b/src/effects.cpp
index 1aacddb..23a4fb2 100644
--- a/src/effects.cpp
+++ b/src/effects.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
#include "effects_software.cpp"
#include "effects_gl.cpp"
diff --git a/src/effects_constructors.cpp b/src/effects_constructors.cpp
index 406cb08..4b87036 100644
--- a/src/effects_constructors.cpp
+++ b/src/effects_constructors.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static void
Effect_AddEntry(project_state *State, char *Name, char *ID, void (*func)(real32 *, int, int, int, void *, uint16), const char *GL_Shader, effect_display_type DisplayType = effect_display_type_standard)
{
@@ -20,7 +24,7 @@ Effect_EndEntry(project_state *State)
}
static void
-Effect_AddProperty_Real(project_state *State, char *Name, real32 DefaultValue, real32 MinVal = -999999, real32 MaxVal = 999999, property_display_type DisplayType = property_display_type_standard)
+Effect_AddProperty_Real(project_state *State, char *Name, real32 DefaultValue, real32 MinVal, real32 MaxVal, property_display_type DisplayType)
{
header_effect *Effect = &State->Effect[State->Playhead_Effect];
Effect->Property_Count++;
diff --git a/src/effects_gl.cpp b/src/effects_gl.cpp
index c3ff444..64a0758 100644
--- a/src/effects_gl.cpp
+++ b/src/effects_gl.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
void GL_UpdateTexture(gl_effect_layer *Test, void *Data, uint16 Width, uint16 Height, uint16 BytesPerPixel, bool32 Multisample);
static uint16 Effect_GL_InitShader(const char *Effect);
static void GL_BindDefaultVertexArrays();
diff --git a/src/effects_gl_shader.cpp b/src/effects_gl_shader.cpp
index b2e1fc1..283714c 100644
--- a/src/effects_gl_shader.cpp
+++ b/src/effects_gl_shader.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
const char *GLShader_Levels = "#version 330 core\n"
"out vec4 FragColor;\n"
"in vec2 TexCoord;\n"
diff --git a/src/effects_software.cpp b/src/effects_software.cpp
index 2fde6b9..a5c0296 100644
--- a/src/effects_software.cpp
+++ b/src/effects_software.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static void
Effect_Software_DrawColor(int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, v4 Color, blend_mode BlendMode)
diff --git a/src/ffmpeg_backend.cpp b/src/ffmpeg_backend.cpp
index a104714..510188b 100644
--- a/src/ffmpeg_backend.cpp
+++ b/src/ffmpeg_backend.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
// workaround to make libav error printing work
#ifdef av_err2str
#undef av_err2str
@@ -9,7 +13,7 @@ av_always_inline std::string av_err2string(int errnum) {
#define av_err2str(err) av_err2string(err).c_str()
#endif // av_err2str
-bool32 AV_TryFrame(av_info *AV, AVCodecContext *CodecContext, int32 *err, bool32 *EndOfFile, int StreamIndex = -1)
+bool32 AV_TryFrame(av_info *AV, AVCodecContext *CodecContext, int32 *err, bool32 *EndOfFile, int StreamIndex)
{
*err = av_read_frame(AV->FileFormatContext, AV->Packet);
bool32 CheckForStream = (StreamIndex != -1) ? (AV->Packet->stream_index == StreamIndex) : 1;
diff --git a/src/gl_calls.cpp b/src/gl_calls.cpp
index 3db9e6a..0fe2a31 100644
--- a/src/gl_calls.cpp
+++ b/src/gl_calls.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
#include "gl_calls.h"
const char *DefaultVertexShaderSource = "#version 330 core\n"
@@ -5,9 +9,12 @@ const char *DefaultVertexShaderSource = "#version 330 core\n"
"layout (location = 1) in vec2 aTexCoord;\n"
"out vec2 TexCoord;\n"
"uniform int VertexMode;\n"
-"uniform vec3 CompDimensions;\n"
+"uniform vec2 CompDimensions;\n"
"uniform vec2 LayerDimensions;\n"
+"uniform vec2 ScreenDimensions;\n"
"uniform vec2 Pos;\n"
+"uniform vec2 UIOffset;\n"
+"uniform vec2 UIZoom;\n"
"uniform vec2 Anchor;\n"
"uniform float Rad;\n"
"uniform float Scale;\n"
@@ -21,7 +28,11 @@ const char *DefaultVertexShaderSource = "#version 330 core\n"
" vec2 XAxis = (Point.x - (Anchor.x * LayerDimensions.x)) * Scale * XRotation;\n"
" vec2 YAxis = (Point.y - (Anchor.y * LayerDimensions.y)) * -Scale * YRotation;\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"
+" vec2 CompUV = CompPoint / CompDimensions;\n"
+" vec2 ScreenPoint = UIOffset + (CompUV * UIZoom);\n"
+" vec2 ScreenUV = ScreenPoint / ScreenDimensions;\n"
+" vec2 GL_Space = ScreenUV * 2 - vec2(1.0f, 1.0f);\n"
+" gl_Position = vec4(vec2(GL_Space.x, -GL_Space.y), 0.0f, 1.0);\n"
"}\n"
" TexCoord = aTexCoord;\n"
"}\0";
@@ -166,9 +177,131 @@ GL_DeleteHWBuffer(gl_effect_layer *Test)
}
static void
+GL_RasterizeShape2(gl_effect_layer *TestM, void *StrokeData, void *FillData, uint32 StrokeCount, uint32 FillCount,
+ layer_transforms T, int Width, int Height, int BytesPerPixel,
+ int L_Width, int L_Height,v4 StrokeCol, v4 FillCol, int RenderMode, int Vector,
+ ImVec2 ViewportSize, ImVec2 UIPos, ImVec2 UIZoom)
+{
+ int Uniform = 0;
+
+ // stencil buffer
+ glEnable(GL_STENCIL_TEST);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glStencilFunc(GL_ALWAYS, 0, 0xFF);
+ glStencilMask(0xff);
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "CompDimensions");
+ glUniform2f(Uniform, Width, Height);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "LayerDimensions");
+ glUniform2f(Uniform, L_Width, L_Height);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "ScreenDimensions");
+ glUniform2f(Uniform, ViewportSize.x, ViewportSize.y);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "UIOffset");
+ glUniform2f(Uniform, UIPos.x, UIPos.y);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "UIZoom");
+ glUniform2f(Uniform, UIZoom.x, UIZoom.y);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "Pos");
+ glUniform2f(Uniform, T.x, T.y);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "Anchor");
+ glUniform2f(Uniform, T.ax, T.ay);
+ real32 Rad = (T.rotation * (PI / 180));
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "Rad");
+ glUniform1f(Uniform, Rad);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "Scale");
+ glUniform1f(Uniform, T.scale);
+
+ if (RenderMode == 0 || RenderMode == 1)
+ {
+
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode");
+ glUniform1i(Uniform, 1);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode");
+ glUniform1i(Uniform, 1);
+
+ // 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)));
+
+ // 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_FAN, 0, FillCount);
+ //
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glBindVertexArray(0);
+
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "VertexMode");
+ glUniform1i(Uniform, 0);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "FragmentMode");
+ glUniform1i(Uniform, 1);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "InputCol");
+ 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);
+ //
+ } else {
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+
+ // stencil buffer not needed
+ glDisable(GL_STENCIL_TEST);
+ glStencilMask(0xFF);
+ glStencilFunc(GL_ALWAYS, 0, 0xFF);
+
+ glBindVertexArray(0);
+
+ if (RenderMode == 0 || RenderMode == 2) {
+ 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);
+ //
+ }
+}
+
+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 StrokeCol, v4 FillCol, 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 Vector,
+ ImVec2 ViewportSize, ImVec2 UIZoom, ImVec2 UIPos)
{
+#if 0
int Uniform = 0;
glBindTexture(GL_TEXTURE_2D, TestL->Texture);
int ByteFlag = (BytesPerPixel == 4) ? GL_RGBA : GL_RGBA16;
@@ -176,7 +309,8 @@ GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *StrokeDa
glTexImage2D(GL_TEXTURE_2D, 0, ByteFlag, Width, Height, 0, GL_RGBA,
ByteFlag2, EffectBitmapAddress);
- GL_UpdateTexture(TestL, EffectBitmapAddress, Width, Height, BytesPerPixel, 0);
+ if (!Vector)
+ GL_UpdateTexture(TestL, EffectBitmapAddress, Width, Height, BytesPerPixel, 0);
GL_UpdateTexture(TestM, EffectBitmapAddress, Width, Height, BytesPerPixel, 1);
glBindFramebuffer(GL_FRAMEBUFFER, TestM->FramebufferObject);
@@ -196,8 +330,14 @@ GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *StrokeDa
glUniform3f(Uniform, Width, Height, 0);
Uniform = glGetUniformLocation(DefaultShaderProgram, "LayerDimensions");
glUniform2f(Uniform, L_Width, L_Height);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "ScreenDimensions");
+ glUniform2f(Uniform, ViewportSize.x, ViewportSize.y);
Uniform = glGetUniformLocation(DefaultShaderProgram, "Pos");
glUniform2f(Uniform, T.x, T.y);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "CompOffset");
+ glUniform2f(Uniform, UIPos.x, UIPos.y);
+ Uniform = glGetUniformLocation(DefaultShaderProgram, "CompZoom");
+ glUniform2f(Uniform, UIZoom.x, UIZoom.y);
Uniform = glGetUniformLocation(DefaultShaderProgram, "Anchor");
glUniform2f(Uniform, T.ax, T.ay);
real32 Rad = (T.rotation * (PI / 180));
@@ -297,6 +437,7 @@ GL_RasterizeShape(gl_effect_layer *TestL, gl_effect_layer *TestM, void *StrokeDa
glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, EffectBitmapAddress);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
+#endif
}
void
diff --git a/src/imgui_helper.cpp b/src/imgui_helper.cpp
index dc120e1..3c771e9 100644
--- a/src/imgui_helper.cpp
+++ b/src/imgui_helper.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
// Widgets not directly related to drawing UI.
// Returns a normalized UV position of the composition
diff --git a/src/imgui_helper_internal.cpp b/src/imgui_helper_internal.cpp
index 184930e..7d6944b 100644
--- a/src/imgui_helper_internal.cpp
+++ b/src/imgui_helper_internal.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
#include "imgui_internal_widgets.h"
#include "imgui.h"
@@ -6,7 +10,6 @@
#endif
#include "imgui_internal.h"
-
// NOTE(fox): This API will change in the future!
void ImGui::MyWindowSetup(ImGuiID id)
{
diff --git a/src/imgui_ui.cpp b/src/imgui_ui.cpp
index 0a7f310..380aaf2 100644
--- a/src/imgui_ui.cpp
+++ b/src/imgui_ui.cpp
@@ -1,19 +1,5 @@
-
-#include "imgui_internal_widgets.h"
-
-#include "imgui_ops.h"
-
-#include "imgui_helper.cpp"
-
-#include "imgui_ui_properties.cpp"
-#include "imgui_ui_timeline.cpp"
-#include "imgui_ui_viewport.cpp"
-
-#if DEBUG
-#include "imgui_ui_debug.cpp"
-#endif
-#if STABLE
-#include "imgui_ui_stable_diffusion.cpp"
+#if SPECIAL
+#include "main.h"
#endif
static void
@@ -21,6 +7,7 @@ ImGui_File(project_data *File, project_state *State, memory *Memory, ImGuiIO io,
sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray)
{
ImGui::Begin("Files");
+ ImGui::Text("%s: %hu", "Layers", File->Layer_Count);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
@@ -421,7 +408,14 @@ ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Me
State->Tool = tool_brush;
}
if (ImGui::IsKeyPressed(ImGuiKey_D)) {
- State->Tool = tool_pen;
+ if (io.KeyShift && State->Interact_Active == interact_type_none) {
+ History_Entry_Commit(Memory, "Duplicate layers");
+ v2 Offset = V2(State->Interact_Dup_Previous[0], State->Interact_Dup_Previous[1]);
+ Project_Layer_Duplicate(File, State, Memory, Sorted.CompArray, Sorted.LayerArray, Offset, 0);
+ History_Entry_End(Memory);
+ } else {
+ State->Tool = tool_pen;
+ }
}
// NOTE(fox): File data not tracked on undo tree!
if (ImGui::IsKeyPressed(ImGuiKey_N)) {
@@ -653,6 +647,10 @@ ImGui_Menu(project_data *File, project_state *State, ui *UI, memory *Memory, ImG
}
if (ImGui::BeginMenu("Window"))
{
+ if (ImGui::Selectable("Standard view", UI->Mode == 0))
+ UI->Mode = 0;
+ if (ImGui::Selectable("Vector view", UI->Mode == 1))
+ UI->Mode = 1;
#if STABLE
if (ImGui::Selectable("Stable Diffusion tools", UI->StableEnabled))
UI->StableEnabled ^= 1;
diff --git a/src/imgui_ui_debug.cpp b/src/imgui_ui_debug.cpp
index 8c63ff3..04adce6 100644
--- a/src/imgui_ui_debug.cpp
+++ b/src/imgui_ui_debug.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static void
ImGui_DebugMemoryViewer(memory *Memory, project_state *State)
{
diff --git a/src/imgui_ui_properties.cpp b/src/imgui_ui_properties.cpp
index 83adcf1..341045e 100644
--- a/src/imgui_ui_properties.cpp
+++ b/src/imgui_ui_properties.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static void
ImGui_Properties_RGBASwitch(project_state *State, memory *Memory, ImGuiIO io, uint32 *Channel)
{
@@ -50,7 +54,7 @@ ImGui_Properties_CurvesUI(project_state *State, memory *Memory, ImGuiIO io, bloc
{
real32 Padding = ImGui::GetFontSize()*6;
- ImVec2 ViewportMin = ImGui::GetCursorScreenPos() + Padding/6;
+ ImVec2 ViewportMin = ImGui::GetCursorScreenPos() + ImVec2(Padding/6,Padding/6);
ImVec2 ViewportScale = ImGui::GetContentRegionAvail();
ViewportScale.y = ViewportScale.x = ViewportScale.x - Padding; // square seems nice
ImVec2 ViewportMax = ViewportMin + ViewportScale;
@@ -296,10 +300,15 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory *
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))
+ int MainProperties = AmountOf(Layer->Property);
+ // don't display time offset for shape layers
+ if (Layer->IsShapeLayer) {
+ MainProperties -= 1;
+ }
+ while (Layer_LoopChannels(State, Memory, &InfoLocation, &ArrayLocation, Layer, &Property, &Effect, &h, &c, &p, MainProperties))
{
ImGui::PushID(Property);
- if ((h - 1) < AmountOf(Layer->Property) && c == 0) {
+ if ((h - 1) < MainProperties && c == 0) {
if (ImGui::Button("K")) {
Property_AddKeyframe(Memory, F_Layers, Property, State->Frame_Current - Layer->Frame_Offset, ArrayLocation);
}
@@ -432,8 +441,19 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory *
}
}
if (Layer->IsShapeLayer) {
+ shape_layer *Shape = &Layer->Shape;
shape_options *Opt = &Layer->Shape.Opt;
// TODO(fox): Combine with RGBA function?
+ ImGui::DragScalar("Shape width", ImGuiDataType_Float, &Shape->Width);
+ if (ImGui::IsItemActive()) {
+ Memory->PurgeCache = true;
+ State->UpdateFrame = true;
+ }
+ ImGui::DragScalar("Shape height ", ImGuiDataType_Float, &Shape->Height);
+ if (ImGui::IsItemActive()) {
+ Memory->PurgeCache = true;
+ State->UpdateFrame = true;
+ }
char *Names[3] = { "Fill and stroke", "Fill only", "Stroke only" };
if (ImGui::BeginListBox("Shape render type")) {
for (int i = 0; i < 3; i++) {
@@ -462,7 +482,6 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory *
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];
Memory->PurgeCache = true;
State->UpdateFrame = true;
diff --git a/src/imgui_ui_stable_diffusion.cpp b/src/imgui_ui_stable_diffusion.cpp
index e6ef8cc..9f2963a 100644
--- a/src/imgui_ui_stable_diffusion.cpp
+++ b/src/imgui_ui_stable_diffusion.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static void
ImGui_SD_Thumbnail(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io,
sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 *SourceArray, uint16 SourceCount)
diff --git a/src/imgui_ui_timeline.cpp b/src/imgui_ui_timeline.cpp
index 3a5eca0..c8ebcc4 100644
--- a/src/imgui_ui_timeline.cpp
+++ b/src/imgui_ui_timeline.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static void
ImGui_Timeline_BGElements(project_data *File, project_state *State, memory *Memory, ui *UI, ImDrawList *draw_list, ImVec2 TimelineSizeWithBorder, ImVec2 TimelineAbsolutePos, block_composition MainComp,
ImVec2 TimelineZoomSize, ImVec2 TimelineMoveSize)
diff --git a/src/imgui_ui_viewport.cpp b/src/imgui_ui_viewport.cpp
index beb7c8f..eb48159 100644
--- a/src/imgui_ui_viewport.cpp
+++ b/src/imgui_ui_viewport.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static void
ImGui_Viewport_Toolbar(project_state *State, ImDrawList *draw_list)
@@ -473,10 +477,10 @@ ImGui_Viewport_TransformUI(project_data *File, project_state *State, memory *Mem
}
}
} else {
- History_Action_Swap(Memory, F_File, sizeof(Layer->x.CurrentValue), &Layer->x.CurrentValue);
- History_Action_Swap(Memory, F_File, sizeof(Layer->y.CurrentValue), &Layer->y.CurrentValue);
- History_Action_Swap(Memory, F_File, sizeof(Layer->scale.CurrentValue), &Layer->scale.CurrentValue);
- History_Action_Swap(Memory, F_File, sizeof(Layer->rotation.CurrentValue), &Layer->rotation.CurrentValue);
+ 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(*(interact_transform *)&State->Interact_Offset[0], &Layer->x.CurrentValue, &Layer->y.CurrentValue, &Layer->rotation.CurrentValue, &Layer->scale.CurrentValue);
}
}
@@ -502,7 +506,8 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImG
sorted_comp_array *SortedCompStart = &SortedCompArray[CompIndex];
sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, CompIndex);
ImU32 wcol = ImGui::GetColorU32(ImGuiCol_Text);
- for (int i = 0; i < SortedCompStart->LayerCount; i++)
+ int LayerCount = SortedCompStart->LayerCount + SortedCompStart->FakeLayerCount;
+ for (int i = 0; i < LayerCount; i++)
{
sorted_layer_array SortEntry = SortedLayerStart[i];
uint32 Index_Physical = SortEntry.Block_Layer_Index;
@@ -511,7 +516,8 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImG
ParentLayer[Recursions] = Layer;
ImGui_Viewport_SelectedLayerUI(State, Memory, UI, io, draw_list, MainComp, Layer->Block_Source_Index, ParentLayer, Recursions + 1, SortedCompArray, SortedLayerArray);
}
- if (Layer->IsSelected) {
+ // if (Layer->IsSelected) {
+ if (1) {
uint32 Width = 0, Height = 0;
void *Data;
uint32 NumberOfVerts;
@@ -520,7 +526,7 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImG
Width = Comp->Width;
Height = Comp->Height;
} else if (Layer->IsShapeLayer) {
-#if DEBUG
+#if 0
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;
@@ -528,9 +534,6 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImG
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
@@ -547,12 +550,17 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImG
if (State->Interact_Active == interact_type_viewport_transform && Layer->IsSelected == 1) {
Transform_ApplyInteractive(*(interact_transform *)&State->Interact_Offset[0], &T.x, &T.y, &T.rotation, &T.scale);
}
+ if (State->Interact_Active == interact_type_viewport_duplicate && SortEntry.IsFake) {
+ Assert(Layer->IsSelected);
+ T.x += State->Interact_Offset[0];
+ T.y += State->Interact_Offset[1];
+ }
if (Layer->IsShapeLayer) {
ImGui_Viewport_ShapeUI(State, Memory, UI, io, Layer, Width, Height, &Layer->Shape, MainComp, draw_list);
// point visualization
-#if DEBUG
+#if 0
void *Data2 = Memory_PushScratch(Memory, sizeof(real32) * 3 * 256);
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);
@@ -620,7 +628,7 @@ ImGui_Viewport_SelectedLayerUI(project_state *State, memory *Memory, ui *UI, ImG
static void
ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, GLuint textureID,
- sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 *SortedKeyframeArray)
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray)
{
bool open = true;
ImGui::Begin("Viewport", &open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
@@ -651,9 +659,14 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
ImVec2 CompPosMax = ImVec2(UI->CompPos.x + UI->CompZoom.x, UI->CompPos.y + UI->CompZoom.y);
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));
- draw_list->AddRect(CompPosMin, CompPosMax, IM_COL32(255, 255, 255, 55));
+ uint32 BGCOL = IM_COL32(50, 50, 50, 255);
+ uint32 OUTLINE = IM_COL32(255, 255, 255, 255);
+ if (UI->Mode == 1) {
+ // BGCOL = IM_COL32(0, 0, 0, 255);
+ OUTLINE = IM_COL32(255,255,255, 255);
+ }
+ draw_list->AddRectFilled(ViewportMin, ViewportMax, BGCOL);
+ draw_list->AddRect(ViewportMin, ViewportMax, IM_COL32(255,255,255, 255));
real32 FontSize = ImGui::GetFontSize();
ImGui::SetCursorScreenPos(ImVec2(ViewportMax.x - FontSize*2, ViewportMin.y + ViewportScale.y - FontSize*3.0));
@@ -665,11 +678,20 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
// Actual composition texture
draw_list->PushClipRect(ViewportMin, ViewportMax, true);
- draw_list->AddImage((void *)(intptr_t)textureID, CompPosMin, CompPosMax);
+ if (UI->Mode == 0) {
+ 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,
+ SortedPropertyStart, SortedKeyframeArray, File->PrincipalCompIndex, State->Frame_Current);
+ draw_list->AddRect(CompPosMin, CompPosMax, OUTLINE);
+ }
draw_list->PopClipRect();
+
// UI+interaction for layer
- if (State->MostRecentlySelectedLayer > -1)
+ // if (State->MostRecentlySelectedLayer > -1)
{
block_layer *ParentLayer[4];
ImGui_Viewport_SelectedLayerUI(State, Memory, UI, io, draw_list, MainComp, File->PrincipalCompIndex, ParentLayer, 0, SortedCompArray, SortedLayerArray);
@@ -679,7 +701,7 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
}
shape_layer *Shape = &UI->Shape;
- if ((State->Tool == tool_pen || State->Tool == tool_square) && State->MostRecentlySelectedLayer == -1)
+ 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
@@ -726,15 +748,41 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
}
// Layer selection
if (State->Tool == tool_default && State->Interact_Active == interact_type_none) {
- int32 Selection = Layer_TestSelection(Memory, State, UI, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex);
- if (!io.KeyShift && State->Interact_Active == interact_type_none)
- Layer_DeselectAll(File, State, Memory);
- if (Selection != -1)
- Layer_Select(Memory, State, Selection);
+ if (io.KeyAlt) {
+ } else {
+ int32 Selection = Layer_TestSelection(Memory, State, UI, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex);
+ if (!io.KeyShift && State->Interact_Active == interact_type_none)
+ Layer_DeselectAll(File, State, Memory);
+ if (Selection != -1)
+ Layer_Select(Memory, State, Selection);
+ }
}
}
}
+ if (IsActive && !ImGui::IsMouseDown(ImGuiMouseButton_Right) && !io.KeyCtrl && !io.KeyAlt)
+ {
+ v2 CompUV = State->LastClickedPoint;
+ ImVec2 ScreenPointStart = ImVec2(UI->CompPos.x + CompUV.x * UI->CompZoom.x,
+ UI->CompPos.y + CompUV.y * UI->CompZoom.y);
+ uint32 fcol = IM_COL32(00, 00, 255, 50);
+ uint32 wcol = IM_COL32(128, 128, 255, 255);
+ ImVec2 Vector = io.MousePos - ScreenPointStart;
+ ImVec2 MousePos = io.MousePos;
+ if (State->Tool == tool_default && State->Interact_Active == interact_type_none) {
+ draw_list->AddRectFilled(ScreenPointStart, MousePos, fcol, 2.0f);
+ draw_list->AddRect(ScreenPointStart, MousePos, wcol, 2.0f);
+ }
+ if (io.MouseDelta.x || io.MouseDelta.y) {
+ Layer_DeselectAll(File, State, Memory);
+ v2 LocalMaxUV = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, MousePos);
+ v2 LocalMinPos = State->LastClickedPoint * V2(MainComp->Width, MainComp->Height);
+ v2 LocalMaxPos = LocalMaxUV * V2(MainComp->Width, MainComp->Height);
+ Layer_TestBoxSelect(Memory, State, UI, SortedCompArray, SortedLayerArray, File->PrincipalCompIndex,
+ LocalMinPos, LocalMaxPos);
+ }
+ }
+
/*
if (State->Interact_Active == interact_type_viewport_transform) {
interact_transform *Interact = (interact_transform *)&State->Interact_Offset[0];
@@ -785,7 +833,6 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
v2 CompUV = State->LastClickedPoint;
ImVec2 ScreenPoint = ImVec2(UI->CompPos.x + CompUV.x * UI->CompZoom.x,
UI->CompPos.y + CompUV.y * UI->CompZoom.y);
- shape_layer *Shape = &UI->Shape;
if (Shape->Point_Count > 1) {
ImGui::OpenPopupOnItemClick("shapecreate", ImGuiPopupFlags_MouseButtonRight);
}
@@ -796,9 +843,6 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
ImGui::EndPopup();
}
if (!Shape->IsClosed) {
- if (IsHovered && IsActivated && !ImGui::IsMouseDown(ImGuiMouseButton_Right))
- {
- }
ImVec2 Vector = io.MousePos - ScreenPoint;
uint32 wcol = IM_COL32(00, 00, 80, 255);
if (IsActive && !OtherActions) {
@@ -819,6 +863,53 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
}
}
+ if (State->Tool == tool_slide && State->Interact_Active == interact_type_none && !OtherActions) {
+ real32 Delta = io.MouseDelta.x + io.MouseDelta.y;
+ if (Delta && IsActive) {
+ State->Interact_Active = interact_type_viewport_slide;
+ }
+ }
+
+ if (State->Interact_Active == interact_type_viewport_slide) {
+ if (IsDeactivated) {
+ Assert(0);
+ } else {
+ Assert(IsActive);
+ v2 MouseCompPos = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos);
+ v2 DragDelta = MouseCompPos - State->LastClickedPoint;
+ State->Interact_Offset[0] = DragDelta.x * MainComp->Width;
+ State->Interact_Offset[1] = DragDelta.y * MainComp->Height;
+ }
+ }
+
+ if (State->Tool == tool_rectangle && State->Interact_Active == interact_type_none) {
+ v2 CompUV = State->LastClickedPoint;
+ ImVec2 ScreenPointStart = ImVec2(UI->CompPos.x + CompUV.x * UI->CompZoom.x,
+ UI->CompPos.y + CompUV.y * UI->CompZoom.y);
+ uint32 wcol = IM_COL32(00, 00, 255, 255);
+ ImVec2 Vector = io.MousePos - ScreenPointStart;
+ ImVec2 MousePos = io.MousePos;
+ if (io.KeyShift) {
+ MousePos = ScreenPointStart + ImVec2(Vector.x, Vector.x);
+ }
+ if (IsActive && !OtherActions) {
+ draw_list->AddRect(ScreenPointStart, MousePos, wcol, 2.0f);
+ }
+ if (Shape->Point_Count == 0 && IsDeactivated && !OtherActions && !ImGui::IsMouseReleased(ImGuiMouseButton_Right)) {
+ ImVec2 ScreenPoint[4] = { ScreenPointStart, ImVec2(ScreenPointStart.x, MousePos.y), MousePos, ImVec2(MousePos.x, ScreenPointStart.y) };
+ History_Entry_Commit(Memory, "Add rectangle");
+ for (int i = 0; i < 4; i++) {
+ v2 CompPoint = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, ScreenPoint[i]);
+ CompPoint = CompPoint * V2(MainComp->Width, MainComp->Height);
+ bezier_point PointData = { 1, { CompPoint, V2(0, 0), V2(0, 0) }, interpolation_type_linear, 0 };
+ Bezier_Add(Memory, F_File, Shape->Block_Bezier_Index, &Shape->Block_Bezier_Count, &Shape->Point_Count, PointData);
+ }
+ Shape->IsClosed = true;
+ History_Entry_End(Memory);
+ State->HotkeyInput = hotkey_newlayer_shape;
+ }
+ }
+
if (ImGui::IsKeyDown(ImGuiKey_Z) && ImGui::IsWindowHovered()) {
if (IsActive)
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll);
@@ -833,16 +924,39 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory,
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
Distance = 200;
}
- if (Distance && ImGui::IsKeyDown(ImGuiKey_Z))
- {
+ if (Distance && ImGui::IsKeyDown(ImGuiKey_Z)) {
if (io.KeyShift)
Distance *= -1;
UI->CompZoom.x += (Distance)*(real32)MainComp->Width/MainComp->Height;
UI->CompZoom.y += (Distance);
UI->CompPos.x -= ((Distance)*(real32)MainComp->Width/MainComp->Height)*State->LastClickedPoint.x;
UI->CompPos.y -= Distance*State->LastClickedPoint.y;
+ } else if (Distance && io.KeyAlt) {
+ State->Interact_Active = interact_type_viewport_duplicate;
+ }
+
+ if (State->Interact_Active == interact_type_viewport_duplicate) {
+ if (IsDeactivated) {
+ History_Entry_Commit(Memory, "Duplicate layers");
+ State->Interact_Active = interact_type_none;
+ State->Interact_Modifier = 0;
+ v2 Offset = V2(State->Interact_Offset[0], State->Interact_Offset[1]);
+ Project_Layer_Duplicate(File, State, Memory, SortedCompArray, SortedLayerArray, Offset, 1);
+ State->Interact_Dup_Previous[0] = State->Interact_Offset[0];
+ State->Interact_Dup_Previous[1] = State->Interact_Offset[1];
+ State->Interact_Offset[0] = 0;
+ State->Interact_Offset[1] = 0;
+ History_Entry_End(Memory);
+ } else {
+ Assert(IsActive);
+ v2 MouseCompPos = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos);
+ v2 DragDelta = MouseCompPos - State->LastClickedPoint;
+ State->Interact_Offset[0] = DragDelta.x * MainComp->Width;
+ State->Interact_Offset[1] = DragDelta.y * MainComp->Height;
+ }
}
+
ImGui::SetCursorScreenPos(ImVec2(ViewportMin.x, ViewportMin.y + ViewportScale.y - FontSize*1.5));
ImGui::Text("%.1f", 100.0f * (UI->CompZoom.x / MainComp->Width));
diff --git a/src/include/all.h b/src/include/all.h
new file mode 100644
index 0000000..8bafd30
--- /dev/null
+++ b/src/include/all.h
@@ -0,0 +1,612 @@
+// TODO(fox);: Incorporate sorting for non-continuous shapes.
+static uint32
+Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData,
+ project_state *State, layer_transforms T, int Width, int Height,
+ int CompWidth, int CompHeight, bool32 Interact);
+
+static bezier_point *
+Bezier_LookupAddress(memory *Memory, uint16 *Block_Bezier_Index, uint16 Index, bool32 AssertExists = 1);
+
+static bezier_point *
+Bezier_LookupAddress(memory *Memory, property_channel *Property, uint16 Index, bool32 AssertExists = 1);
+
+static void
+Bezier_Interact_Evaluate(project_state *State, bezier_point *PointAddress, v2 *Pos, real32 GraphZoomHeight = 1, real32 Y_Increment = 1);
+
+static void
+Bezier_Add(memory *Memory, memory_table_list TableName, uint16 *Block_Bezier_Index, uint16 *Block_Bezier_Count,
+ uint16 *PointCount, bezier_point PointData);
+
+static void
+Bezier_Add(memory *Memory, memory_table_list TableName, property_channel *Property, bezier_point PointData, uint16 *ArrayLocation);
+
+// return all points
+static void Bezier_CubicCalcPointsCasteljauStep(void *Data, uint32 Size, uint32 *Increment, real32 x1, real32 y1, real32 x2, real32 y2, real32 x3, real32 y3, real32 x4, real32 y4, real32 tess_tol, int level);
+
+void * Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 Size);
+
+v2 Bezier_LineDist(v2 a, v2 b, v2 p);
+
+v2 Bezier_LineClosestPoint(v2 a, v2 b, v2 p);
+
+// The ratio here is just the dot product divided by the squared length.
+v2 Bezier_LineClosestPointR(v2 a, v2 b, v2 p, real32 *ratio);
+
+static void Bezier_CubicBoxCasteljauStep(v2 Min, v2 Max, v2 *p_closest, v2 *p_last, real32 *p_closest_dist2,
+ real32 x1, real32 y1, real32 x2, real32 y2, real32 x3, real32 y3, real32 x4, real32 y4, real32 tess_tol, int level);
+
+static void
+Bezier_BoxTest(v2 p1, v2 p2, v2 p3, v2 p4, v2 Min, v2 Max, v2 *p_closest);
+
+real32 Bezier_CubicRatioOfPoint(v2 p1, v2 p2, v2 p3, v2 p4, v2 p);
+
+// finds the min/max bounds of the curve
+static void Bezier_CubicMinMaxCasteljauStep(v2 *p_min, v2 *p_max, real32 x1, real32 y1, real32 x2, real32 y2, real32 x3, real32 y3, real32 x4, real32 y4, real32 tess_tol, int level);
+
+real32 Bezier_CubicRatioOfPoint(v2 p1, v2 p2, v2 p3, v2 p4, v2 p);
+
+static bool32
+File_Open(project_data *File, project_state *State, memory *Memory, char *Filename);
+
+static bool32
+IO_Save(project_data *File, project_state *State, memory *Memory, char *Filename);
+
+static void
+File_SaveAs(project_data *File, project_state *State, memory *Memory, char *Filename);
+
+static void
+Playhead_Increment(int32 *Frame_Current, int32 Frame_Start, int32 Frame_End, int32 Increment);
+
+static uint16
+Source_Generate_Blank(project_data *File, project_state *State, memory *Memory, uint16 Width, uint16 Height, uint16 BytesPerPixel);
+
+static void
+Source_Delete(project_data *File, memory *Memory, uint32 Index);
+
+static int16
+Source_Generate(project_data *File, project_state *State, memory *Memory, void *TempString);
+
+
+static void
+Property_AddKeyframe(memory *Memory, memory_table_list TableName, property_channel *Property, int Frame, uint16 *ArrayLocation);
+
+static block_composition *
+Precomp_Init(project_data *File, memory *Memory);
+
+static uint32
+Effect_Init(project_state *State, memory *Memory, uint32 EffectEntryIndex, int EffectCount);
+
+static void
+Effect_Add(project_data *File, project_state *State, memory *Memory, uint32 EffectEntryIndex);
+
+void Source_DeselectAll(project_data *File, memory *Memory);
+
+// NOTE(fox);: This won't work with precomps!
+
+void Clipboard_Paste(project_data *File, project_state *State, memory *Memory, sorted_comp_array *SortedCompStart, sorted_layer_array *SortedLayerStart, uint16 *SortedKeyframeArray);
+
+void Clipboard_Store(project_data *File, project_state *State, memory *Memory, sorted_comp_array *SortedCompStart, sorted_layer_array *SortedLayerStart, sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray);
+
+void Property_MinMax_X(memory *Memory, project_state *State, property_channel *Property,
+ uint16 *ArrayLocation, real32 *Min, real32 *Max);
+void Property_MinMax_Y(memory *Memory, project_state *State, property_channel *Property,
+ sorted_property_array *PropertyStart, real32 *Min, real32 *Max, bool32 Evaluate = 1);
+
+inline property_channel *
+Effect_Property(memory *Memory, block_effect *Effect, int Offset);
+
+inline v2 Effect_V2(memory *Memory, block_effect *Effect, int Offset);
+
+// TODO(fox);: Merge with other sorting code.
+void Effect_Curves_Sort(memory *Memory, block_effect *Effect, uint16 *SortedPointStart, uint16 Which);
+
+static void
+Interact_Evaluate_Layer(memory *Memory, project_state *State, uint16 Layer_Index_Physical, sorted_comp_array SortedCompStart, sorted_layer_array *SortedLayerStart,
+ int32 *Frame_Start, int32 *Frame_End, int *Frame_Offset);
+
+void File_DeselectAllKeyframes(project_data *File, project_state *State, memory *Memory,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray,
+ sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray);
+
+
+static void
+Project_Layer_Delete(project_data *File, project_state *State, memory *Memory);
+
+static bool32
+Property_IsGraphSelected(memory *Memory, property_channel *Property, uint16 *ArrayLocation);
+
+static void
+Project_Layer_Duplicate(project_data *File, project_state *State, memory *Memory,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, v2 Offset, bool32 FakeOnly);
+
+static void
+Project_ShapeLayer_New(project_data *File, project_state *State, memory *Memory);
+
+static void
+Project_PaintLayer_New(project_data *File, project_state *State, memory *Memory);
+
+void Source_UICreateButton(project_data *File, project_state *State, memory *Memory);
+
+void Precomp_UIDuplicate(project_data *File, project_state *State, memory *Memory, uint16 CompIndex,
+ sorted_comp_array SortedCompStart, sorted_layer_array *SortedLayerStart);
+
+void Precomp_UIDelete(project_data *File, project_state *State, memory *Memory, uint16 CompIndex,
+ sorted_comp_array SortedCompStart, sorted_layer_array *SortedLayerStart);
+
+void Precomp_UICreateButton(project_data *File, project_state *State, memory *Memory, uint16 CompIndex,
+ sorted_comp_array SortedCompStart, sorted_layer_array *SortedLayerStart);
+
+// TODO(fox);: Make separate full-size bitmap that gets scaled on the GPU instead of this
+static void
+State_BindBrushTexture(memory *Memory, brush_state *Brush, uint32 BytesPerPixel);
+
+static void
+Brush_CalcBitmapAlphaFromSize(memory *Memory, brush_state *Brush, uint32 BytesPerPixel);
+
+// Imported bitmaps are stored in linear, and all ops are also done in linear.
+static void
+Bitmap_SRGBToLinear(void *Buffer, uint16 Width, uint16 Height, uint16 BytesPerPixel, bool32 ToLinear);
+
+static void
+Brush_Info(brush_info *B, brush_state *Brush, block_source *Source, void *SourceBuffer, v2 LayerPos, v4 Color);
+
+void Bitmap_SwapData(uint8 *Address_0, uint8 *Address_1, uint64 Size, uint16 BytesPerPixel);
+
+static void
+PaintTest(brush_info B, void *CacheBuffer, rectangle RenderRegion);
+
+static void
+RenderQueue_AddBrush(project_state *State, v2 LayerPos);
+
+static void
+RenderQueue_AddBlit(project_state *State);
+
+static void
+Effect_GaussianBlur(real32 *Data, int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, uint16 ShaderProgram);
+
+static void
+Effect_Curves_Init(block_effect *Effect, property_channel *Property);
+
+static void
+Effect_Levels(real32 *Data, int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, uint16 ShaderProgram);
+
+static void
+Effect_Curves(real32 *Data, int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, uint16 ShaderProgram);
+
+static void
+Effect_EndEntry(project_state *State);
+
+static void
+Effect_AddProperty_Real(project_state *State, char *Name, real32 DefaultValue, real32 MinVal = -999999, real32 MaxVal = 999999, property_display_type DisplayType = property_display_type_standard);
+
+static void
+Effect_AddProperty_Col(project_state *State, char *Name, v4 DefaultValue);
+
+static void
+Effect_AddProperty_Blendmode(project_state *State, char *Name, blend_mode DefaultValue);
+
+static header_effect*
+Effect_EntryFromID(project_state *State, char *ID);
+
+static void
+Effect_InitEntries(project_state *State);
+
+void Effect_GL_DrawColor(int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress,
+ uint16 ShaderProgram, v4 Color);
+
+void Effect_GL_GaussianBlur(int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress,
+ uint16 ShaderProgram, real32 Radius);
+
+void Effect_GL_Levels(int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress,
+ uint16 ShaderProgram, real32 Min, real32 Mid, real32 Max, v4 ColMin, v4 ColMid, v4 ColMax);
+static void
+CurvesSolver(real32 *LUT, v2 Point_P1, v2 Point_P2, v2 m1, v2 m2, int i);
+
+static void
+Effect_Software_Curves(int Width, int Height, int BytesPerPixel, void *EffectBitmapAddress, v2 *PointData, real32 PointCount, v4 PointCount_Col);
+
+bool32 AV_TryFrame(av_info *AV, AVCodecContext *CodecContext, int32 *err, bool32 *EndOfFile, int StreamIndex = -1);
+
+// Widgets not involving drawing UI.
+
+static v2 ImGui_ScreenPointToCompUV(ImVec2 ViewportMin, ImVec2 CompPos, ImVec2 CompZoom, ImVec2 MousePos);
+static void ImGui_WarpMouseFinish(project_state *State, ImVec2 MousePos);
+static ImVec2 ImGui_Brush_CalcMousePos(project_state *State, ImGuiIO &io, ImVec2 MouseDelta, int32 i, real32 DeltaDistance, real32 DeltaSlope);
+static bool32 ImGui_TestBoxSelection_Point(ImVec2 Pos, ImGuiIO &io, bool32 *Test);
+
+static void
+Layer_TestBoxSelect(memory *Memory, project_state *State, ui *UI, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray,
+ uint16 PrincipalIndex, v2 MinPos, v2 MaxPos);
+
+void AV_IsFileSupported(char *filename, bool32 *IsVideo, bool32 *HasAudio);
+
+void AV_Dealloc(av_info *AV);
+
+void AV_InitStream(av_stream_info *Stream);
+
+// The duration isn't always reported in AVStream, but seeking towards the end
+// and advancing until we hit EOF seems to be accurate.
+void AV_GetDuration(av_info *AV, av_stream_info *Stream, uint64 *Duration, real32 *SecondCount);
+
+
+void AV_Init(block_source *Source, av_info *AV, memory *Memory);
+
+uint32 AV_AudioTest(av_info *AV, void *Data, uint32 Size, real32 FPS, int32 InitialFrameToSeek);
+
+void AV_SeekAudio(av_info *AV, real32 FPS, int32 FrameToSeek);
+
+
+void AV_LoadVideoFrame(memory *Memory, block_source *Source, av_info *AV, int32 FrameToSeek, void *Buffer);
+
+void
+GL_GenAndBindTexture(GLuint *GLTexture, int Width, int Height, int BytesPerPixel, void *BufferAddress);
+
+static void
+GL_BindDefaultVertexArrays();
+
+void
+GL_InitHWBuffer(gl_effect_layer *Test);
+
+void
+GL_DeleteHWBuffer(gl_effect_layer *Test);
+
+void
+GL_UpdateTexture(gl_effect_layer *Test, void *Data, uint16 Width, uint16 Height, uint16 BytesPerPixel, bool32 Multisample);
+
+static uint16
+Effect_GL_InitShader(const char *FragmentShaderEffectSource);
+
+static void
+ImGui_WarpMouse(project_state *State, ImVec2 MousePos, ImVec2 Min, ImVec2 Max, int Direction = 3);
+
+static bool32
+ImGui_TestBoxSelection_Point(ImVec2 Pos, ImGuiIO &io, bool32 *Test);
+
+static void
+ImGui_ColorPanel(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io);
+
+static void
+ImGui_KeybindUI(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io);
+
+static void
+ImGui_Popups(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io);
+
+static void
+ImGui_ProcessInputs(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, sorted_file Sorted);
+
+static void
+ImGui_Menu(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io);
+
+static void
+ImGui_EffectsPanel(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io);
+
+static void
+ImGui_DebugRenderQueue(project_state *State);
+
+static void
+ImGui_DebugUndoTree(memory *Memory, project_state *State);
+
+static void
+ImGui_Properties_Slider(project_state *State, memory *Memory, property_channel *Property, ImGuiIO &io, ImVec2 WindowMinAbs, ImVec2 WindowMaxAbs, memory_table_list Table);
+
+
+static void
+ImGui_Properties_CurvesUI(project_state *State, memory *Memory, ImGuiIO io, block_effect *Effect, property_channel *PropertyStart, uint16 *SortedPointStart);
+
+static void
+ImGui_SD_Prompt(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray);
+
+static void
+ImGui_Timeline_HorizontalIncrementDraw(project_state *State, ui *UI, ImDrawList *draw_list, ImVec2 TimelineSizeWithBorder, ImVec2 TimelineAbsolutePos, block_composition MainComp,
+ ImVec2 TimelineZoomSize, ImVec2 TimelineMoveSize);
+
+static void
+ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray);
+
+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);
+
+
+static void
+ImGui_Viewport_BrushUI(project_state *State, memory *Memory, ImVec2 ViewportMin, ImVec2 ViewportMax, ImVec2 CompZoom, ImGuiIO io, uint16 Width, uint16 Height);
+
+static void
+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);
+
+static void
+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);
+
+static void
+ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, GLuint textureID,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray);
+
+static void
+IO_ReadFromStream(void *Address, uint64 SizeToRead, SDL_RWops *File);
+
+// lots of cleanup...
+static void
+Layer_Delete(project_data *File, project_state *State, memory *Memory, uint32 Index);
+
+static int
+Layer_GetTopOffset(project_data *File, memory *Memory);
+
+static void
+Layer_ToggleChannel(project_data *File, memory *Memory, int32 a);
+
+static void
+Layer_Select(memory *Memory, project_state *State, int32 i);
+
+static void
+Layer_Select_RecurseUp(memory *Memory, project_state *State, int32 i, int16 RecursionIdx[MAX_PRECOMP_RECURSIONS], uint32 Recursions);
+
+static void
+Layer_Select_Traverse(uint16 PrincipalCompIndex, memory *Memory, project_state *State, int32 IndexToFind, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray,
+ int16 RecursionIdx[MAX_PRECOMP_RECURSIONS], int32 *Recursions);
+
+static void
+Layer_GetDimensions(memory *Memory, block_layer *Layer, int *Width, int *Height);
+
+static v2
+Layer_TraverseForPoint(project_data *File, project_state *State, memory *Memory, v2 PrincipalCompUV, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray);
+
+// TODO(fox);: Precomps?
+static int32
+Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 PrincipalIndex);
+
+static bool32
+Shape_TestBoxSelect(v2 Min, v2 Max, bezier_point *BezierPointData, uint32 BezierCount);
+
+static bool32
+Transform_TestBox(block_layer *Layer, uint32 Width, uint32 Height, v2 Min, v2 Max);
+
+static void
+Interact_Transform_Begin(project_data *File, memory *Memory, project_state *State, ImVec2 OGPos,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray);
+
+static void
+Layer_RecursiveDeselect(memory *Memory, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 TargetIndex, uint16 PrincipalIndex);
+
+static void
+Main_InputTest(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID);
+
+static void
+Render_Main(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID,
+ void *Data, void *OutputBuffer, render_type RenderType, rectangle RenderRegion);
+
+static void
+Layer_UpdateAllKeyframes(project_data *File, project_state *State, memory *Memory, block_layer *Layer, uint16 Index_Physical,
+ sorted_property_array *SortedProperty, uint16 *SortedKeyframe, uint16 Frame_Current);
+
+static av_info *
+AV_Retrieve(project_state *State, memory *Memory, uint32 SourceIndex);
+
+struct gl_data;
+struct gl_viewport_data;
+
+static void
+GL_Test(const ImDrawList* parent_list, const ImDrawCmd* cmd);
+
+static void
+Render_Paint(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID, ImGuiIO io, v2 LayerPos);
+
+static void
+Render_Blit(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID, ImGuiIO io, v2 LayerPos);
+
+static void
+Main_Renderer(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID, ImGuiIO io);
+
+static uint32
+Memory_Block_AllocateNew(memory *Memory, memory_table_list TableName);
+
+static void *
+Memory_Block_AddressAtIndex(memory *Memory, memory_table_list TableName, uint32 Index, bool32 AssertExists = 1);
+
+static uint16
+Memory_Block_LazyIndexAtAddress(memory *Memory, memory_table_list TableName, void *Address);
+
+
+static void *
+Memory_Block_AllocateAddress(memory *Memory, memory_table_list TableName);
+
+// IMPORTANT(fox);: All block data structs have to start with a uint8 Occupied variable!
+static bool32
+Block_Loop(memory *Memory, memory_table_list TableName, uint32 TotalCount, int *HasIncremented, int *CurrentCount, int *Index);
+
+static bool32
+Block_Loop(memory *Memory, property_channel *Property, uint32 TotalCount, int *HasIncremented, int *CurrentCount, int *Index);
+
+static uint32
+Memory_Block_PrincipalBitmap_AllocateNew(project_data *File, project_state *State, memory *Memory);
+
+static uint32
+Memory_Block_Bitmap_AllocateNew(project_state *State, memory *Memory, cache_entry Entry, uint64 NewSize);
+static void
+Memory_Cache_Purge(project_data *File, project_state *State, memory *Memory, int32 SingleFrame = -1);
+
+static cache_entry *
+Memory_Cache_Search(project_state *State, memory *Memory, cache_entry_type Type, uint32 TypeInfo, uint32 TypeInfo_Sub);
+
+static void *
+Memory_Block_Bitmap_AddressAtIndex(memory *Memory, uint32 Index);
+
+static void *
+Memory_AddressAtOffset(memory *Memory, memory_table_list TableName, uint64 Offset);
+
+void Memory_Copy(uint8 *Address_Write, uint8 *Address_Read, uint64 Size);
+
+void Memory_Fill(uint8 *Address_Write, uint8 *Address_Read, uint64 WriteSize, uint64 ReadSize);
+
+void Arbitrary_Zero(uint8 *Address_Write, uint64 Size);
+
+void Arbitrary_SwapData(memory *Memory, uint8 *Address_0, uint8 *Address_1, uint64 Size);
+
+
+static void
+Arbitrary_ShiftData(uint8 *Address_Start, uint8 *Address_End, uint64 ShiftAmount, int32 Direction);
+
+static uint64
+Data_Compress(memory *Memory, void *DataSource, uint64 DataSize, void *DataBuffer, uint64 DataBufferSize, int CompressionLevel);
+
+static void
+Data_Decompress(memory *Memory, void *CompressedLocation, uint64 CompressedSize, void *BitmapLocation, uint64 ExpectedSize);
+
+static real32 *
+NVG_Point(real32 *StrokeData, real32 x, real32 y, real32 u, real32 v);
+
+static void NVG_ChooseBevel(int bevel, nvg_point *p0, nvg_point *p1, float w,
+ float* x0, float* y0, float* x1, float* y1);
+
+static real32 * NVG_RoundCap(nvg_point * Point, real32 *StrokeData,
+ float dx, float dy, float w, int ncap,
+ float u0, float u1, int Mode);
+
+static real32 * NVG_ButtCap(nvg_point *Point, real32 *StrokeData,
+ float dx, float dy, float w, float d,
+ float u0, float u1, int Mode);
+
+static void
+NVG_ExpandFill(void *Memory, int NumberOfVerts, nvg_point *PointData, real32 *FillData);
+
+static v2
+T_CompUVToLayerUV(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, v2 CompUV);
+
+static v2
+T_CompPosToLayerPos(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, real32 X, real32 Y);
+
+static void
+Render_UI(project_data *File, project_state *State, memory *Memory, ui *UI, ImDrawList *draw_list,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray,
+ sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray, uint32 CompIndex, int32 Frame_Current);
+
+static v2
+Transform_ScreenSpaceToLocal(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight,
+ ImVec2 CompPos, ImVec2 CompZoom, ImVec2 ViewportMin, ImVec2 Point);
+
+// Transform given data based on state's Interact data.
+static void
+Transform_ApplyInteractive(interact_transform Interact, real32 *OutputX, real32 *OutputY, real32 *OutputRotation, real32 *OutputScale);
+
+static void
+Transform_IterateOuterBounds(block_layer *Layer, uint32 Width, uint32 Height, real32 *MinX, real32 *MinY, real32 *MaxX, real32 *MaxY);
+static void
+Transform_Recurse(project_state *State, memory *Memory, block_composition *MainComp, uint32 CompIndex, block_layer *ParentLayer[4], uint32 Recursions,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray,
+ real32 *MinX, real32 *MinY, real32 *MaxX, real32 *MaxY);
+
+
+static v2
+TransformPoint(layer_transforms T, real32 Width, real32 Height, v2 Point);
+
+static layer_transforms
+Transform_Inverse(layer_transforms T);
+
+static ImVec2
+Layer_LocalToScreenSpace(project_state *State, memory *Memory, block_layer *Layer, ui *UI, uint32 PrincipalCompIndex, v2 Point);
+
+static void
+Renderer_Start(void *Data, void *OutputBuffer, render_type RenderType, rectangle RenderRegion);
+
+static void
+Renderer_Check(bool32 *Test, render_type RenderType);
+
+static void
+Fallback_RenderLayer(transform_info T, void *OutputBuffer, rectangle RenderRegion);
+
+inline uint16 *
+Property_GetSortedArray(uint16 *SortedKeyframeArray, int i, int h);
+
+static sorted_layer_array *
+Sorted_GetLayerStart(sorted_layer_array *LayerArrayStart, sorted_comp_array *SortedCompStart, uint32 TargetComp);
+
+static void
+Layer_Sort_CheckPrev(memory *Memory, int i, int Direction, sorted_layer_array *SortedLayerStart, sorted_comp_array SortedCompStart, int *EntriesPassed, sorted_layer_array *LayerEntry, bool32 AltMethod);
+
+void LayerProperty_SortAll(project_data *File, project_state *State, memory *Memory, sorted_layer_array *LayerArrayStart,
+ sorted_comp_array *CompStart, sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray,
+ uint32 CompCount);
+
+static void
+TempSource_SortAll(project_data *File, project_state *State, memory *Memory, uint16 *SourceArrayStart, uint16 *TempSourceCount);
+
+
+static sorted_file
+File_Sort_Push(project_data *File, project_state *State, memory *Memory);
+
+static void
+File_Sort_Pop(memory *Memory, uint64 Layer_SortSize, uint64 Property_SortSize, uint64 Source_SortSize);
+
+#if STABLE
+struct curl_data;
+
+static size_t dumbcurlcallback(void *data, size_t size, size_t nmemb, void *userp);
+
+static void
+SD_JSONToSource(project_data *File, project_state *State, memory *Memory, void *JSONResponse, int Height, int Width);
+
+static void
+SD_ParseProgress(project_state *State, char *JSONInfo);
+
+static void
+SD_AssembleJSON(sd_state *SD, char *JSONPayload, void *Base64Bitmap = NULL);
+
+struct curl_state;
+
+static void
+Curl_Free(curl_state *Handle);
+
+static void
+Curl_StopAll(project_state *State, curl_state *ProgHandle, curl_state *MainHandle);
+
+static int
+Curl_Check(curl_state *Handle);
+
+static void
+Curl_Prog_Init(curl_state *C, void *OutputData);
+
+static void
+Curl_Main(project_data *File, project_state *State, memory *Memory, curl_state *MainHandle, curl_state *ProgHandle);
+#endif
+
+static void
+CopyStrings(void *Dest, void *Data);
+
+static uint16
+String_AddToFile(memory *Memory, char *Char);
+
+static bool32
+String_Compare(char *String1, char *String2, uint32 Length);
+
+static uint32
+String_Length(char *Char);
+
+static void
+String_Copy(char *String1, char *String2, uint32 Length);
+
+static void
+String_Append(char *String1, char *String2, uint32 Length);
+
+static void
+String_PathToLayerName(char *Path, char *Dest);
+
+static int
+TestThread(void *ptr);
+
+static bool32
+Threading_IsActive(render_type RenderType);
+
+static void
+Threading_BitmapOp(void *Data, void *OutputBuffer, render_type RenderType, rectangle InitialRenderRegion);
+
+static uint64
+History_GetActionSize(history_entry_list *History, int i);
+
+void History_Entry_Commit(memory *Memory, char *Name);
+void History_Entry_End(memory *Memory);
+static void History_Action_Shift(memory *Memory, memory_table_list TableName,
+ void *Address0, void *Address1, uint64 Amount, int16 Direction);
+static void History_Action_Block_Swap(memory *Memory, memory_table_list TableName, void *Address_Data);
+static void History_Action_Swap(memory *Memory, memory_table_list TableName, uint64 Size, void *Address_Data);
diff --git a/src/include/defines.h b/src/include/defines.h
index 1d4e147..2100c07 100644
--- a/src/include/defines.h
+++ b/src/include/defines.h
@@ -31,6 +31,8 @@ typedef uint64 ptrsize; // is there a compiler variable for 32 vs 64 bit like
#define MAX_LAYERS 2048
#define MAX_EFFECTS 32
#define MAX_SOURCES 1024
+#define MAX_HISTORY_ENTRIES 1024
+#define MAX_HISTORY_ACTIONS 4096
#define MAX_COMPS 1024
#define MAX_PRECOMP_RECURSIONS 4
#define MAX_MASKS 8
diff --git a/src/include/functions.h b/src/include/functions.h
index 2c18f85..4ded552 100644
--- a/src/include/functions.h
+++ b/src/include/functions.h
@@ -6,6 +6,7 @@ static void Arbitrary_Zero(uint8 *Address_Write, uint64 Size);
static void Arbitrary_SwapData(memory *Memory, uint8 *Address_0, uint8 *Address_1, uint64 Size);
static void Arbitrary_ShiftData(uint8 *Address_Start, uint8 *Address_End, uint64 ShiftAmount, int32 Direction);
+void AV_Init(block_source *Source, av_info *AV, memory *Memory);
// Rudimentary guess-until-correct solver for bezier curves, used to evaluate
// the keyframe graph. Similar to the Catmull-Rom solver in CurvesSolver().
@@ -18,6 +19,19 @@ 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);
+static void
+Render_UI(project_data *File, project_state *State, memory *Memory, ui *UI, ImDrawList *draw_list,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray,
+ sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray, uint32 CompIndex, int32 Frame_Current);
+
+static void *
+Memory_Block_AddressAtIndex(memory *Memory, memory_table_list TableName, uint32 Index, bool32 AssertExists = 1);
+
+static bool32
+Block_Loop(memory *Memory, memory_table_list TableName, uint32 TotalCount, int *HasIncremented, int *CurrentCount, int *Index);
+
+static void
+File_SaveAs(project_data *File, project_state *State, memory *Memory, char *Filename);
static uint32
Bezier_Shape_Sort(memory *Memory, shape_layer *Shape, bezier_point *PointData,
@@ -31,12 +45,11 @@ 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 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);
-static void ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, GLuint textureID, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 *SortedKeyframeArray);
+static void
+ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io, GLuint textureID,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray);
static void ImGui_Timeline(project_data *File, project_state *State, memory *Memory, ui *UI, ImGuiIO io, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray);
static void ImGui_File(project_data *File, project_state *State, memory *Memory, ImGuiIO io, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray);
diff --git a/src/include/imgui_ops.h b/src/include/imgui_ops.h
index 6089f94..2d1c1bc 100644
--- a/src/include/imgui_ops.h
+++ b/src/include/imgui_ops.h
@@ -1,5 +1,3 @@
-
-
ImVec2 operator+(ImVec2 A, ImVec2 B)
{
ImVec2 Result;
diff --git a/src/include/layer.h b/src/include/layer.h
index bf32aca..2b83a79 100644
--- a/src/include/layer.h
+++ b/src/include/layer.h
@@ -28,7 +28,7 @@ Layer_DeselectAll(project_data *File, project_state *State, memory *Memory);
static bool32
Layer_LoopChannels(project_state *State, memory *Memory, sorted_property_array **SortedProperty, uint16 **SortedKeyframe, block_layer *Layer,
- property_channel **Property, block_effect **EffectOut, int *h, int *c, int *p);
+ property_channel **Property, block_effect **EffectOut, int *h, int *c, int *p, int LoopNumber = 8);
static void
Layer_ToggleAllChannels(project_state *State, memory *Memory, block_layer *Layer,
diff --git a/src/include/main.h b/src/include/main.h
index 7d3299e..6c9caca 100644
--- a/src/include/main.h
+++ b/src/include/main.h
@@ -1,3 +1,62 @@
+#include <glad.h>
+
+#include <stdio.h>
+#if WINDOWS
+#include <windows.h>
+#else
+#include <sys/mman.h>
+#include <unistd.h>
+#endif
+
+#if ARM
+#include <arm_neon.h>
+#include <arm_sve.h>
+#else
+#include <smmintrin.h>
+#endif
+
+#include "imgui.h"
+#include "imgui_impl_sdl.h"
+#include "imgui_impl_opengl3.h"
+#include <SDL.h>
+#if defined(IMGUI_IMPL_OPENGL_ES2)
+#include <SDL_opengles2.h>
+#else
+#include <SDL_opengl.h>
+#endif
+
+#define STB_IMAGE_IMPLEMENTATION
+#define STBI_FAILURE_USERMSG
+#include "stb_image.h"
+
+#define STB_IMAGE_WRITE_IMPLEMENTATION
+#include "stb_image_write.h"
+
+// TODO(fox): Used for thumbnails. The renderer could be expanded to do this
+// much more efficiently.
+#define STB_IMAGE_RESIZE_IMPLEMENTATION
+#include "stb_image_resize.h"
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavformat/avio.h>
+#include <libavutil/avutil.h>
+#include <libswscale/swscale.h>
+#include <libswresample/swresample.h>
+}
+
+
+
+#include "defines.h"
+#include "my_math.h"
+#include "structs.h"
+#if STABLE
+#include "stable_diffusion.h"
+#endif
+#include "memory.h"
+#include "nanovg.h"
+
enum instruction_mode {
instruction_mode_scalar,
#if ARM
@@ -156,6 +215,7 @@ struct sorted_property_array
struct sorted_comp_array
{
uint32 LayerCount;
+ uint32 FakeLayerCount;
uint32 CurrentSortIndex; // Used intermediately in the sorting algorithm
real32 DisplaySize;
};
@@ -163,6 +223,7 @@ struct sorted_comp_array
struct sorted_layer_array
{
uint16 Block_Layer_Index;
+ bool32 IsFake;
real32 SortedOffset;
real32 DisplayOffset;
uint16 Sorted_Effect_Index[MAX_EFFECTS];
@@ -187,8 +248,8 @@ struct sorted_file
struct shape_options {
int Visibility;
v4 FillCol = {1, 1, 1, 1};
- v4 StrokeCol = {0, 1, 0, 1};
- float StrokeWidth = 25;
+ v4 StrokeCol = {1, 0, 0, 1};
+ float StrokeWidth = 10;
nvg_line_cap LineJoinType = NVG_ROUND;
nvg_line_cap LineCapType = NVG_ROUND;
real32 Roundness;
@@ -200,10 +261,10 @@ 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;
+ // NOTE(fox): Point vals are normalized based on whatever these values are!
+ // They get set once the shape becomes a shape layer!
+ real32 Width;
+ real32 Height;
shape_options Opt;
};
@@ -239,6 +300,8 @@ enum interact_type
interact_type_layer_move,
interact_type_layer_timeadjust,
interact_type_viewport_transform,
+ interact_type_viewport_duplicate,
+ interact_type_viewport_slide,
interact_type_keyframe_move,
interact_type_keyframe_scale,
interact_type_keyframe_rotate,
@@ -249,16 +312,18 @@ char *ToolName[] {
"Move",
"Crop",
"Brush",
+ "Slide",
"Pen",
- "Square"
+ "Rectangle"
};
enum tool {
tool_default,
tool_crop,
tool_brush,
+ tool_slide,
tool_pen,
- tool_square,
+ tool_rectangle,
tool_count
};
@@ -413,6 +478,7 @@ struct project_state
interact_type Interact_Active;
int32 Interact_Modifier;
real32 Interact_Offset[12];
+ real32 Interact_Dup_Previous[2];
void *Interact_Address;
// NOTE(fox): We need to keep track of when the user changes the CurrentValue of a
@@ -459,6 +525,8 @@ struct ui
ImVec2 CompZoom; // In screen pixels, not percentage.
ImVec2 CompPos;
+ int Mode = 1;
+
// Under 1 is zoomed in!
ImVec2 TimelinePercentZoomed;
ImVec2 TimelinePercentOffset;
@@ -730,3 +798,12 @@ struct render_entry {
rectangle RenderRegion;
};
+
+#include "ffmpeg_backend.h"
+#include "layer.h"
+#include "debug.h"
+#include "all.h"
+
+#include "imgui_internal_widgets.h"
+
+#include "imgui_ops.h"
diff --git a/src/include/memory.h b/src/include/memory.h
index dab6ed4..e6b7676 100644
--- a/src/include/memory.h
+++ b/src/include/memory.h
@@ -15,9 +15,12 @@ enum memory_table_list {
F_PrincipalBitmaps,
B_Thumbnails,
+ B_PointData,
B_ScratchSpace,
B_CacheEntries,
B_CachedBitmaps,
+
+ M_Count
};
struct memory_table {
@@ -53,15 +56,17 @@ struct history_entry {
uint16 NumberOfActions;
};
+
+
struct history_entry_list {
- history_entry Entry[256];
- history_action Action[1024];
+ history_entry Entry[MAX_HISTORY_ENTRIES];
+ history_action Action[MAX_HISTORY_ACTIONS];
uint16 NumberOfEntries;
uint16 EntryPlayhead;
};
struct memory {
- memory_table Slot[16];
+ memory_table Slot[M_Count];
history_entry_list History;
uint64 ScratchPos;
uint32 EntryCount;
diff --git a/src/include/my_math.h b/src/include/my_math.h
index 72c6b99..2a54f4d 100644
--- a/src/include/my_math.h
+++ b/src/include/my_math.h
@@ -361,16 +361,6 @@ v2i operator-(v2i A, int16 B)
return(Result);
}
-v2i operator+(v2i A, int16 B)
-{
- v2i Result;
-
- Result.x = A.x + B;
- Result.y = A.y + B;
-
- return(Result);
-}
-
v2 operator*(real32 A, v2 B)
{
v2 Result;
@@ -580,6 +570,12 @@ LengthSq(v2 A)
return Result;
}
+inline real32
+Length(v2 A)
+{
+ return sqrt(Inner(A, A));
+}
+
inline uint32
Floor(uint32 A, uint32 B)
{
diff --git a/src/io.cpp b/src/io.cpp
index 50ffbcf..488d2bd 100644
--- a/src/io.cpp
+++ b/src/io.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static void
IO_WriteToStream(void *Address, uint64 FileSize, SDL_RWops *TestFile)
{
diff --git a/src/layer.cpp b/src/layer.cpp
index b27935b..8bf6bef 100644
--- a/src/layer.cpp
+++ b/src/layer.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static property_channel
Property_InitFloat(real32 Val, real32 ScrubVal, real32 MinVal = PROPERTY_REAL_MIN, real32 MaxVal = PROPERTY_REAL_MAX, bool32 AlwaysInteger = 0);
@@ -17,7 +21,7 @@ Layer_Init(project_data *File, memory *Memory)
Layer->Block_String_Index = Memory_Block_AllocateNew(Memory, F_Strings);
block_string *String = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Layer->Block_String_Index, 0);
sprintf(String->Char, "Layer %i", File->Layer_Count + 1); // CSbros...
- History_Action_Swap(Memory, F_File, sizeof(String->Occupied), &String->Occupied);
+ History_Action_Swap(Memory, F_Strings, sizeof(String->Occupied), &String->Occupied);
String->Occupied = 1;
Layer->x = Property_InitFloat(0.0f, 1.0f);
@@ -112,22 +116,17 @@ Layer_UpdateMasksEffects(project_state *State, block_layer *Layer, memory *Memor
Arbitrary_Zero((uint8 *)Data, sizeof(nvg_point) * 128);
layer_transforms T = Layer_GetTransforms(Layer);
v2 Min = {}, Max = {};
- int ShapeWidth = 0, ShapeHeight = 0;
- if (State->Interact_Active == interact_type_keyframe_move) {
- NVG_FlattenPath(Memory, Shape, (nvg_point *)Data, State, T, 0, 0, Width, Height, 0, &Min, &Max);
- ShapeWidth = Max.x - Min.x;
- ShapeHeight = Max.y - Min.y;
- }
uint32 NumberOfVerts = NVG_FlattenPath(Memory, Shape, (nvg_point *)Data,
- State, T, ShapeWidth, ShapeHeight, Width, Height, 1, &Min, &Max);
+ 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->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);
- GL_RasterizeShape(&TestL, &TestM, Data_Stroke, Data_Fill, StrokeCount, NumberOfVerts, T,
- Width, Height, BytesPerPixel, EffectBitmapAddress, Shape->Width, Shape->Height,
- Shape->Opt.StrokeCol, Shape->Opt.FillCol, Shape->Opt.Visibility);
+ Assert(0);
+ // GL_RasterizeShape(&TestL, &TestM, Data_Stroke, Data_Fill, StrokeCount, NumberOfVerts, T,
+ // 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);
@@ -215,17 +214,18 @@ Layer_DeselectAll(project_data *File, project_state *State, memory *Memory) {
State->MostRecentlySelectedLayer = -1;
}
+// TODO(fox): This function will be replaced once properties are reworked.
// h: index of the total amount of properties and effects
// c: index of the amount of properties in a given effect
// p: prior property's keyframe count, so we can increment the sorted keyframe array properly
static bool32
Layer_LoopChannels(project_state *State, memory *Memory, sorted_property_array **SortedProperty, uint16 **SortedKeyframe, block_layer *Layer,
- property_channel **Property, block_effect **EffectOut, int *h, int *c, int *p)
+ property_channel **Property, block_effect **EffectOut, int *h, int *c, int *p, int LoopNumber)
{
- uint32 Amount = AmountOf(Layer->Property) + Layer->Block_Effect_Count;
+ uint32 Amount = LoopNumber + Layer->Block_Effect_Count;
// Assert(Layer->Block_Effect_Count < 2);
while (*h < Amount) {
- if (*h < AmountOf(Layer->Property) && *c == 0) {
+ if (*h < LoopNumber && *c == 0) {
*Property = &Layer->Property[*h];
if (*h != 0) {
*SortedProperty += 1;
@@ -367,6 +367,7 @@ Layer_TraverseForPoint(project_data *File, project_state *State, memory *Memory,
return PointUV * V2(InnerWidth, InnerHeight);
}
+// TODO(fox): Precomps?
static int32
Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 PrincipalIndex)
{
@@ -420,6 +421,152 @@ Layer_TestSelection(memory *Memory, project_state *State, ui *UI, sorted_comp_ar
return LayerIndex;
}
+static bool32
+Shape_TestBoxSelect(v2 Min, v2 Max, bezier_point *BezierPointData, uint32 BezierCount)
+{
+ v2 StartMin = V2(1000, 1000);
+ v2 StartMax = V2(-1000, -1000);
+ v2 ClosestPoint[4] = { StartMin, StartMax, V2(StartMin.x, StartMax.y), V2(StartMax.y, StartMin.x) };
+
+ for (int i = 0; i < BezierCount; i++) {
+ bezier_point *Point = &BezierPointData[i];
+ if (i == 0 || Point->Type == interpolation_type_linear) {
+ if ((Point->Pos[0].x > Min.x) && (Point->Pos[0].x < Max.x) &&
+ (Point->Pos[0].x > Min.y) && (Point->Pos[0].x < Max.y))
+ Assert(0);
+ } else if (Point->Type == interpolation_type_bezier) {
+ Assert(0);
+ /*
+ bezier_point *Point_1 = &BezierPointData[i-1];
+ v2 Pos[2] = { Point_1->Pos[0], Point->Pos[0] };
+ PointPlayhead = (nvg_point *)Bezier_CubicCalcPoints(Pos[0], Pos[0] + Point_1->Pos[1], Pos[1] + Point->Pos[2], Pos[1], PointPlayhead, sizeof(nvg_point));
+ */
+ } else {
+ Assert(0);
+ }
+ }
+ return false;
+}
+
+// v2 Bezier_LineClose
+
+// stPoint(v2 a, v2 b, v2 p);
+
+
+// char get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y,
+// float p2_x, float p2_y, float p3_x, float p3_y, float *i_x, float *i_y)
+#if 0
+char T_TestLine(v2 Point[4])
+{
+ /*
+ float s1_x, s1_y, s2_x, s2_y;
+
+ s1_x = p1_x - p0_x;
+ s1_y = p1_y - p0_y;
+ s2_x = p3_x - p2_x;
+ s2_y = p3_y - p2_y;
+ */
+
+ v2 Vector0 = Point[1] - Point[0];
+ v2 Vector1 = Point[3] - Point[2];
+
+ Vector1 * (Point[0] - Point[2]) /
+ Side0 = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y))
+
+ float s, t;
+ s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
+ t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
+
+ if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
+ {
+ // Collision detected
+ if (i_x != NULL)
+ *i_x = p0_x + (t * s1_x);
+ if (i_y != NULL)
+ *i_y = p0_y + (t * s1_y);
+ return 1;
+ }
+
+ return 0; // No collision
+}
+#endif
+
+static bool32
+Transform_TestBox(block_layer *Layer, uint32 Width, uint32 Height, v2 Min, v2 Max)
+{
+ real32 Rad = (Layer->rotation.CurrentValue * (PI / 180));
+ real32 s = Layer->scale.CurrentValue;
+
+ v2 XAxis = (Width * s)*V2(cos(Rad), sin(Rad));
+ v2 YAxis = (Height * -s)*V2(sin(Rad), -cos(Rad));
+
+ real32 AnchorX = Layer->ax.CurrentValue;
+ real32 AnchorY = Layer->ay.CurrentValue;
+
+ v2 Pos = {Layer->x.CurrentValue, Layer->y.CurrentValue};
+ v2 Origin = Pos - (XAxis * AnchorX) - (YAxis * AnchorY);
+
+ real32 XLengthSq = 1.0f / LengthSq(XAxis);
+ real32 YLengthSq = 1.0f / LengthSq(YAxis);
+
+ v2 Box[4] = { Min, V2(Min.x, Max.y), Max, V2(Max.x, Min.y) };
+ v2 Point[4] = {Origin, Origin + YAxis, Origin + XAxis + YAxis, Origin + XAxis };
+ if (Length((Max - Min)) < 2.0f)
+ return false;
+ v2 *P1_B = &Box[3];
+ v2 *P2_B = &Box[0];
+ for (int x = 0; x < 4; x++) {
+ v2 *P1 = &Point[3];
+ v2 *P2 = &Point[0];
+ for (int i = 0; i < 4; i++) {
+ // v2 ClosestLayer = Bezier_LineClosestPoint(*P1, *P2, *P1_B);
+ // v2 ClosestBox = Bezier_LineClosestPoint(*P1_B, *P2_B, *P1);
+ // if (abs(ClosestLayer.x - ClosestBox.x) < 1.0f &&
+ // abs(ClosestLayer.y - ClosestBox.y) < 1.0f)
+ // return true;
+ // P1 = P2++;
+ }
+ P1_B = P2_B++;
+ }
+ return false;
+}
+
+
+static void
+Layer_TestBoxSelect(memory *Memory, project_state *State, ui *UI, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray,
+ uint16 PrincipalIndex, v2 MinPos, v2 MaxPos)
+{
+ block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, PrincipalIndex);
+ sorted_comp_array SortedCompStart = SortedCompArray[PrincipalIndex];
+ sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, PrincipalIndex);
+ for (int i = SortedCompStart.LayerCount - 1; i >= 0; i--) {
+ 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);
+ if (Layer->IsShapeLayer) {
+ shape_layer *Shape = &Layer->Shape;
+ int Width = Shape->Width, Height = Shape->Height;
+ layer_transforms T = Layer_GetTransforms(Layer);
+ v2 MinUV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Width, Height, MinPos);
+ v2 MaxUV = T_CompUVToLayerUV(T, Comp->Width, Comp->Height, Width, Height, MaxPos);
+
+ bezier_point *BezierPointData = (bezier_point *)Memory_PushScratch(Memory, sizeof(bezier_point) * 128);
+ uint32 BezierCount = Bezier_Shape_Sort(Memory, Shape, BezierPointData,
+ State, T, Width, Height,
+ Comp->Width, Comp->Height, 0);
+
+ Shape_TestBoxSelect(MinPos, MaxPos, BezierPointData, BezierCount);
+
+ Memory_PopScratch(Memory, sizeof(bezier_point) * 128);
+ } else {
+ int Width, Height;
+ Layer_GetDimensions(Memory, Layer, &Width, &Height);
+ if (Transform_TestBox(Layer, Width, Height, MinPos, MaxPos))
+ Layer->IsSelected = true;
+ }
+ }
+}
+
static void
Layer_RecursiveDeselect(memory *Memory, sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray, uint16 TargetIndex, uint16 PrincipalIndex)
{
diff --git a/src/main.cpp b/src/main.cpp
index e9cbf32..82f0153 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,66 +1,4 @@
-#include <glad.h>
-
-#include <stdio.h>
-#if WINDOWS
-#include <windows.h>
-#else
-#include <sys/mman.h>
-#include <unistd.h>
-#endif
-
-#if ARM
-#include <arm_neon.h>
-#include <arm_sve.h>
-#else
-#include <smmintrin.h>
-#endif
-
-#include "imgui.h"
-#include "imgui_impl_sdl.h"
-#include "imgui_impl_opengl3.h"
-#include <SDL.h>
-#if defined(IMGUI_IMPL_OPENGL_ES2)
-#include <SDL_opengles2.h>
-#else
-#include <SDL_opengl.h>
-#endif
-
-#define STB_IMAGE_IMPLEMENTATION
-#define STBI_FAILURE_USERMSG
-#include "stb_image.h"
-
-#define STB_IMAGE_WRITE_IMPLEMENTATION
-#include "stb_image_write.h"
-
-// TODO(fox): Used for thumbnails. The renderer could be expanded to do this
-// much more efficiently.
-#define STB_IMAGE_RESIZE_IMPLEMENTATION
-#include "stb_image_resize.h"
-
-extern "C" {
-#include <libavcodec/avcodec.h>
-#include <libavformat/avformat.h>
-#include <libavformat/avio.h>
-#include <libavutil/avutil.h>
-#include <libswscale/swscale.h>
-#include <libswresample/swresample.h>
-}
-
-
-#include "defines.h"
-#include "my_math.h"
-#include "structs.h"
-#if STABLE
-#include "stable_diffusion.h"
-#endif
-#include "memory.h"
-#include "nanovg.h"
#include "main.h"
-#include "ffmpeg_backend.h"
-
-#include "layer.h"
-#include "debug.h"
-#include "functions.h"
SDL_Thread *Thread[8];
SDL_sem *Semaphore;
@@ -82,6 +20,8 @@ uint32 BitmapFill = 0x00000001;
#include <curl/curl.h>
#endif
+#if SPECIAL
+#else
#include "memory.cpp"
#include "undo.cpp"
#include "io.cpp"
@@ -95,13 +35,26 @@ uint32 BitmapFill = 0x00000001;
#include "stable_diffusion.cpp"
#endif
#include "ffmpeg_backend.cpp"
+
+#include "imgui_helper.cpp"
+#include "imgui_ui_properties.cpp"
+#include "imgui_ui_timeline.cpp"
+#include "imgui_ui_viewport.cpp"
+#if DEBUG
+#include "imgui_ui_debug.cpp"
+#endif
+#if STABLE
+#include "imgui_ui_stable_diffusion.cpp"
+#endif
#include "imgui_ui.cpp"
+
#include "prenderer.cpp"
#include "gl_calls.cpp"
#include "bezier.cpp"
#include "effects_gl_shader.cpp"
#include "effects.cpp"
#include "effects_constructors.cpp"
+#endif
static void
Main_RenderUI(ImGuiIO io, ImVec4 clear_color, SDL_Window *window)
@@ -173,12 +126,17 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, sorted_
}
#endif
- ImGui_Viewport(File, State, UI, Memory, io, textureID, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyArray);
+ ImGui_Viewport(File, State, UI, Memory, io, textureID, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyStart, Sorted.PropertyArray);
ImGui_Timeline(File, State, Memory, UI, io, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyStart, Sorted.PropertyArray);
+
+ if (File->UI.Mode == 0) {
+ ImGui_EffectsPanel(File, State, Memory, UI, io);
+ } else {
+ }
ImGui_PropertiesPanel(File, State, UI, Memory, io, Sorted.CompArray, Sorted.LayerArray, Sorted.PropertyStart, Sorted.PropertyArray);
ImGui_File(File, State, Memory, io, Sorted.CompArray, Sorted.LayerArray);
ImGui_ColorPanel(File, State, UI, Memory, io);
- ImGui_EffectsPanel(File, State, Memory, UI, io);
+
#if STABLE
if (UI->StableEnabled) {
ImGui_SD_Prompt(File, State, UI, Memory, io, Sorted.CompArray, Sorted.LayerArray);
@@ -207,7 +165,7 @@ Render_Main(project_data *File, project_state *State, memory *Memory, sorted_fil
bool32 IsRendering = true;
Renderer_Start(Data, OutputBuffer, RenderType, RenderRegion);
while (IsRendering) {
- Main_InputTest(File, State, Memory, Sorted, UI, window, textureID);
+ // Main_InputTest(File, State, Memory, Sorted, UI, window, textureID);
// ImGuiIO& io = ImGui::GetIO();
// Main_RenderUI(io, ImVec4(0.45f, 0.55f, 0.60f, 1.00f), window);
Renderer_Check(&IsRendering, RenderType);
@@ -282,11 +240,137 @@ AV_Retrieve(project_state *State, memory *Memory, uint32 SourceIndex)
return AV;
}
-static void *
-Render_Comp(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID, ImGuiIO io,
+static void
+Render_SortKeyframes(project_data *File, project_state *State, memory *Memory,
+ sorted_comp_array *SortedCompStart, sorted_layer_array *SortedLayerStart,
sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray,
- sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray, uint32 CompIndex, int32 Frame_Current)
+ sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray, int Frame_Current)
+{
+ for (int i = 0; i < SortedCompStart->LayerCount; i++) {
+ 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);
+
+ int32 Frame_Start = Layer->Frame_Start;
+ int32 Frame_End = Layer->Frame_End;
+ int32 Frame_Offset = Layer->Frame_Offset;
+ if (Layer->IsSelected)
+ Interact_Evaluate_Layer(Memory, State, Index_Physical, *SortedCompStart, SortedLayerStart, &Frame_Start, &Frame_End, &Frame_Offset);
+ int32 Frame_Start_Abs = Frame_Start + Frame_Offset;
+ int32 Frame_End_Abs = Frame_End + Frame_Offset;
+ int FrameToSeek = State->Frame_Current - Frame_Start_Abs;
+
+ if (Frame_Start_Abs <= Frame_Current &&
+ Frame_End_Abs > Frame_Current && Layer->IsVisible)
+ {
+ if (State->UpdateKeyframes) {
+ sorted_property_array *SortedLayerProperties = SortedPropertyStart + SortEntry.SortedPropertyStart;
+ uint16 *SortedLayerKeyframes = SortedKeyframeArray + SortEntry.SortedKeyframeStart;
+ Layer_UpdateAllKeyframes(File, State, Memory, Layer, Index_Physical, SortedLayerProperties, SortedLayerKeyframes, Frame_Current);
+ }
+ }
+ }
+}
+
+/*
+struct render_entry_data
+{
+ int LayerCount;
+ int Width;
+ int Height;
+ int BytesPerPixel;
+ blend_mode BlendMode;
+};
+
+struct render_layer_data
{
+ layer_transforms T;
+ int Width;
+ int Height;
+ // AV-specific
+ int BytesPerPixel;
+ void *Buffer;
+ // shape-specific
+ void *Stroke_Data;
+ uint32 Stroke_Count;
+ v4 Stroke_Col;
+ void *Fill_Data;
+ uint32 Fill_Count;
+ v4 Fill_Col;
+};
+*/
+
+struct gl_data
+{
+ void *StrokeData;
+ uint32 StrokeCount;
+ v4 StrokeCol;
+ void *FillData;
+ uint32 FillCount;
+ v4 FillCol;
+ layer_transforms T;
+ real32 Width;
+ real32 Height;
+ int RenderMode;
+};
+
+struct gl_viewport_data
+{
+ ImVec2 ViewportSize;
+ int Width;
+ int Height;
+ int BytesPerPixel;
+ ImVec2 UIPos;
+ ImVec2 UIZoom;
+ real32 UIScale;
+ gl_data *LayerEntry[MAX_LAYERS];
+ int LayerCount;
+};
+
+static void
+GL_Test(const ImDrawList* parent_list, const ImDrawCmd* cmd)
+{
+ gl_viewport_data *RenderData = (gl_viewport_data *)cmd->UserCallbackData;
+ gl_effect_layer MSBuffer = {};
+
+ int A[4] = {};
+ glGetIntegerv(GL_VIEWPORT, A);
+
+ GL_UpdateTexture(&MSBuffer, NULL, A[2], A[3], RenderData->BytesPerPixel, 1);
+ glBindFramebuffer(GL_FRAMEBUFFER, MSBuffer.FramebufferObject);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glUseProgram(DefaultShaderProgram);
+
+ // for (int i = 0; i < 1; i++) {
+ for (int i = 0; i < RenderData->LayerCount; i++) {
+ gl_data *Data = RenderData->LayerEntry[i];
+ GL_RasterizeShape2(&MSBuffer, Data->StrokeData, Data->FillData, Data->StrokeCount, Data->FillCount,
+ Data->T, RenderData->Width, RenderData->Height, RenderData->BytesPerPixel,
+ Data->Width, Data->Height, Data->StrokeCol, Data->FillCol, Data->RenderMode, 0,
+ RenderData->ViewportSize, RenderData->UIPos, RenderData->UIZoom);
+ }
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, MSBuffer.FramebufferObject);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ // The multisample framebuffer allows us to conveniently clip to the comp bounds.
+ ImVec2 MinPos(RenderData->UIPos.x, A[3] - RenderData->UIPos.y - RenderData->UIZoom.y);
+ ImVec2 MaxPos = MinPos + RenderData->UIZoom;
+ glBlitFramebuffer(MinPos.x, MinPos.y, MaxPos.x, MaxPos.y,
+ MinPos.x, MinPos.y, MaxPos.x, MaxPos.y,
+ GL_COLOR_BUFFER_BIT, GL_LINEAR);
+
+ GL_DeleteHWBuffer(&MSBuffer);
+}
+
+static void
+Render_UI(project_data *File, project_state *State, memory *Memory, ui *UI, ImDrawList *draw_list,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray,
+ sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray, uint32 CompIndex, int32 Frame_Current)
+{
+
block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex);
cache_entry *Entry_Main = Memory_Cache_Search(State, Memory, cache_entry_type_comp, CompIndex, Frame_Current);
void *CompBuffer = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry_Main->Block_StartIndex);
@@ -295,16 +379,27 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, sorted_fil
sorted_comp_array *SortedCompStart = &SortedCompArray[CompIndex];
sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, CompIndex);
- // NOTE(fox): We have to re-evalute keyframes even when the frame is
- // cached, since we aren't caching the values and the UI needs to have
- // them. Make sure that the cache is always purged if keyframes are
- // updated.
+ Render_SortKeyframes(File, State, Memory, SortedCompStart, SortedLayerStart, SortedCompArray, SortedLayerArray, SortedPropertyStart, SortedKeyframeArray, Frame_Current);
- for (int i = 0; i < SortedCompStart->LayerCount; i++) {
+ uint8 *StartAddress = (uint8 *)Memory->Slot[B_PointData].Address;
+ Arbitrary_Zero(StartAddress, Memory->Slot[B_PointData].Size);
+
+
+ gl_viewport_data *RenderData = (gl_viewport_data *)StartAddress;
+ StartAddress += sizeof(gl_viewport_data);
+ *RenderData = { ImGui::GetMainViewport()->Size,
+ Comp->Width, Comp->Height, Comp->BytesPerPixel,
+ UI->CompPos, UI->CompZoom, UI->CompZoom.x / Comp->Width, {} };
+
+ int LayerCount = SortedCompStart->LayerCount + SortedCompStart->FakeLayerCount;
+ for (int i = 0; i < LayerCount; i++)
+ {
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);
-
+ if (!Layer->IsShapeLayer) {
+ continue;
+ }
int32 Frame_Start = Layer->Frame_Start;
int32 Frame_End = Layer->Frame_End;
int32 Frame_Offset = Layer->Frame_Offset;
@@ -317,14 +412,76 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, sorted_fil
if (Frame_Start_Abs <= Frame_Current &&
Frame_End_Abs > Frame_Current && Layer->IsVisible)
{
- if (State->UpdateKeyframes) {
- sorted_property_array *SortedLayerProperties = SortedPropertyStart + SortEntry.SortedPropertyStart;
- uint16 *SortedLayerKeyframes = SortedKeyframeArray + SortEntry.SortedKeyframeStart;
- Layer_UpdateAllKeyframes(File, State, Memory, Layer, Index_Physical, SortedLayerProperties, SortedLayerKeyframes, Frame_Current);
+ shape_layer *Shape = &Layer->Shape;
+ void *Data = StartAddress;
+
+ layer_transforms T = Layer_GetTransforms(Layer);
+ if (State->Interact_Active == interact_type_viewport_transform && Layer->IsSelected == 1) {
+ Transform_ApplyInteractive(*(interact_transform *)&State->Interact_Offset[0], &T.x, &T.y, &T.rotation, &T.scale);
+ }
+ if (State->Interact_Active == interact_type_viewport_slide && Layer->IsSelected == 1) {
+ // Transform_ApplySlide((v2 *)&State->Interact_Offset[0], &T);
+ }
+ if (State->Interact_Active == interact_type_viewport_duplicate && SortEntry.IsFake) {
+ Assert(Layer->IsSelected);
+ T.x += State->Interact_Offset[0];
+ T.y += State->Interact_Offset[1];
}
+
+ v2 Min = {}, Max = {};
+ uint32 NumberOfVerts = NVG_FlattenPath(Memory, Shape, (nvg_point *)Data,
+ State, T, Shape->Width, Shape->Height, Comp->Width, Comp->Height, 1, &Min, &Max);
+ StartAddress += NumberOfVerts * sizeof(nvg_point);
+ void *Data_Stroke = StartAddress;
+ uint32 StrokeCount = NVG_ExpandStroke(Memory, NumberOfVerts, Shape->Opt.StrokeWidth, Shape->Opt.LineCapType, Shape->Opt.LineJoinType, Shape->IsClosed, (nvg_point *)Data, (real32 *)Data_Stroke);
+ StartAddress += StrokeCount * sizeof(real32) * 4;
+ void *Data_Fill = StartAddress;
+ NVG_ExpandFill(Memory, NumberOfVerts, (nvg_point *)Data, (real32 *)Data_Fill);
+ StartAddress += NumberOfVerts * sizeof(real32) * 4;
+
+ // zero to set the framebuffer to main
+ gl_effect_layer TestL = {};
+ void *EffectBitmapAddress = NULL;
+
+ gl_data *GL_Data = RenderData->LayerEntry[RenderData->LayerCount] = (gl_data *)StartAddress;
+ RenderData->LayerCount++;
+ StartAddress += sizeof(gl_data);
+
+ int Visibility = (Shape->Opt.StrokeWidth > 0.0f) ? Shape->Opt.Visibility : 1;
+ *GL_Data = { Data_Stroke, StrokeCount, Shape->Opt.StrokeCol,
+ Data_Fill, NumberOfVerts, Shape->Opt.FillCol,
+ T, Shape->Width, Shape->Height, Visibility };
}
}
+ Assert((StartAddress - (uint8 *)Memory->Slot[B_PointData].Address) < Memory->Slot[B_PointData].Size);
+
+ ImDrawCallback CustomRenderer = GL_Test;
+ draw_list->AddCallback(CustomRenderer, (void *)RenderData);
+
+ draw_list->AddCallback(ImDrawCallback_ResetRenderState, NULL);
+}
+
+static void *
+Render_Comp(project_data *File, project_state *State, memory *Memory, sorted_file Sorted, ui *UI, SDL_Window *window, GLuint textureID, ImGuiIO io,
+ sorted_comp_array *SortedCompArray, sorted_layer_array *SortedLayerArray,
+ sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray, uint32 CompIndex, int32 Frame_Current)
+{
+ block_composition *Comp = (block_composition *)Memory_Block_AddressAtIndex(Memory, F_Precomps, CompIndex);
+ cache_entry *Entry_Main = Memory_Cache_Search(State, Memory, cache_entry_type_comp, CompIndex, Frame_Current);
+ void *CompBuffer = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry_Main->Block_StartIndex);
+ uint64 Size = Comp->Width * Comp->Height * Comp->BytesPerPixel;
+
+ sorted_comp_array *SortedCompStart = &SortedCompArray[CompIndex];
+ sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(SortedLayerArray, SortedCompArray, CompIndex);
+
+ // NOTE(fox): We have to re-evalute keyframes even when the frame is
+ // cached, since we aren't caching the values and the UI needs to have
+ // them. Make sure that the cache is always purged if keyframes are
+ // updated.
+
+ Render_SortKeyframes(File, State, Memory, SortedCompStart, SortedLayerStart, SortedCompArray, SortedLayerArray, SortedPropertyStart, SortedKeyframeArray, Frame_Current);
+
if (Entry_Main->IsCached)
return CompBuffer;
@@ -533,7 +690,6 @@ Main_Renderer(project_data *File, project_state *State, memory *Memory, sorted_f
int ByteFlag2 = (MainComp->BytesPerPixel == 4) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
if (State->FirstFrame) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MainComp->Width, MainComp->Height, 0, GL_RGBA, ByteFlag2, MainCompBuffer);
- State->FirstFrame = false;
}
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, MainComp->Width, MainComp->Height, GL_RGBA, ByteFlag2, MainCompBuffer);
@@ -543,8 +699,6 @@ Main_Renderer(project_data *File, project_state *State, memory *Memory, sorted_f
State->UpdateKeyframes = false;
}
-static int pp = -2;
-
int main(int argc, char *argv[]) {
global_memory GlobalMemory = {};
@@ -557,10 +711,10 @@ int main(int argc, char *argv[]) {
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else
GlobalMemory.Address = mmap(0, GlobalMemory.Size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1,
- 0);
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ -1,
+ 0);
#endif
// 1 meg per block
@@ -569,7 +723,7 @@ int main(int argc, char *argv[]) {
memory Memory = {};
Memory_InitTable(&GlobalMemory, &Memory, 1 * 1024 * 1024, P_AVInfo, "FFmpeg state", sizeof(av_info));
- Memory_InitTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_UndoBuffer, "Undo buffer");
+ Memory_InitTable(&GlobalMemory, &Memory, 1 * 1024 * 1024, P_UndoBuffer, "Undo buffer");
Memory_InitTable(&GlobalMemory, &Memory, 40 * 1024 * 1024, P_MiscCache, "Misc persistent");
Memory_InitTable(&GlobalMemory, &Memory, sizeof(project_data), F_File, "File", sizeof(project_data));
@@ -583,10 +737,13 @@ int main(int argc, char *argv[]) {
Memory_InitTable(&GlobalMemory, &Memory, (uint64)100 * 1024 * 1024, F_PrincipalBitmaps, "Principal bitmap data", BitmapBlockSize);
Memory_InitTable(&GlobalMemory, &Memory, (uint64)5 * 1024 * 1024, B_Thumbnails, "Thumbnails");
- Memory_InitTable(&GlobalMemory, &Memory, (uint64)64 * 1024 * 1024, B_ScratchSpace, "Scratch");
+ Memory_InitTable(&GlobalMemory, &Memory, (uint64)5 * 1024 * 1024, B_PointData, "Point data");
+ Memory_InitTable(&GlobalMemory, &Memory, (uint64)128 * 1024 * 1024, B_ScratchSpace, "Scratch");
// Memory_InitTable(&GlobalMemory, &Memory, (uint64)1 * 1024 * 1024, B_CacheEntries, "Cache entries", sizeof(cache_entry));
Memory_InitTable(&GlobalMemory, &Memory, (uint64)700 * 1024 * 1024, B_CachedBitmaps, "Cached bitmap buffer");
+ uint8 *Test = (uint8 *)Memory.Slot[B_ScratchSpace].Address + Memory.Slot[B_ScratchSpace].Size + 2;
+ *Test = 30;
#if ARM
InstructionMode = instruction_mode_neon;
@@ -967,6 +1124,7 @@ int main(int argc, char *argv[]) {
}
}
+#if 0
if (State->UpdateFrame) {
// Default queue item type simply calls the renderer on the current
// frame, so no additional info is needed
@@ -980,7 +1138,7 @@ int main(int argc, char *argv[]) {
Memory_Cache_Purge(File, State, &Memory, State->Frame_Current);
}
// Assert(pp != State->Frame_Current);
- pp = State->Frame_Current;
+ // pp = State->Frame_Current;
Main_Renderer(File, State, &Memory, Sorted, &File->UI, window, textureID, io);
} else if (Item.Type == 1) {
Assert(State->Interact_Active == interact_type_brush);
@@ -995,6 +1153,7 @@ int main(int argc, char *argv[]) {
State->Queue.CurrentIdx = 0;
State->Queue.Playhead = 0;
Arbitrary_Zero((uint8 *)State->Queue.Item, sizeof(State->Queue.Item));
+#endif
File_Sort_Pop(&Memory, Sorted.Layer_SortSize, Sorted.Property_SortSize, Sorted.Source_SortSize);
@@ -1019,6 +1178,9 @@ int main(int argc, char *argv[]) {
if (State->Initializing)
State->Initializing--;
+ if (State->FirstFrame)
+ State->FirstFrame = false;
+
uint64 PerfEnd = SDL_GetPerformanceCounter();
uint64 PerfTime = PerfEnd - PerfStart;
real64 FrameMS = (1000.0f * (real64)PerfTime) / (real64)PerfFrequency;
diff --git a/src/memory.cpp b/src/memory.cpp
index ca64745..7454a2a 100644
--- a/src/memory.cpp
+++ b/src/memory.cpp
@@ -1,9 +1,13 @@
+#if SPECIAL
+#include "main.h"
+#endif
static void
Memory_InitTable(global_memory *GlobalMemory, memory *Memory, uint64 Size, memory_table_list TableName, char *Name, uint64 Block_ElementSize = 0) {
memory_table *Table = &Memory->Slot[TableName];
Table->Name = Name;
Table->Address = (ptrsize *)((uint8 *)GlobalMemory->Address + GlobalMemory->CurrentPosition);
+ // Table->Address = malloc(Size);
Table->Size = Size;
Table->Block_ElementSize = Block_ElementSize;
GlobalMemory->CurrentPosition += Size;
@@ -21,19 +25,21 @@ Memory_Block_AllocateNew(memory *Memory, memory_table_list TableName)
Address_Playhead += Table->Block_ElementSize;
Index++;
}
+ Assert((Address_Playhead - (uint8 *)Table->Address) < Table->Size);
Arbitrary_Zero(Address_Playhead, Table->Block_ElementSize);
return Index;
}
static void *
-Memory_Block_AddressAtIndex(memory *Memory, memory_table_list TableName, uint32 Index, bool32 AssertExists = 1)
+Memory_Block_AddressAtIndex(memory *Memory, memory_table_list TableName, uint32 Index, bool32 AssertExists)
{
memory_table *Table = &Memory->Slot[TableName];
Assert(Table->Block_ElementSize != 0);
uint8 *Address = (uint8 *)Table->Address + (Table->Block_ElementSize * Index);
if (AssertExists)
Assert(*Address != 0);
+ Assert((Address - (uint8 *)Table->Address) < Table->Size);
return (void *)Address;
}
@@ -44,6 +50,7 @@ Memory_Block_LazyIndexAtAddress(memory *Memory, memory_table_list TableName, voi
return ((uint8 *)Address - (uint8 *)Table->Address) / Table->Block_ElementSize;
}
+
static void *
Memory_Block_AllocateAddress(memory *Memory, memory_table_list TableName)
{
@@ -179,11 +186,12 @@ Memory_Block_Bitmap_AllocateNew(project_state *State, memory *Memory, cache_entr
}
static void
-Memory_Cache_Purge(project_data *File, project_state *State, memory *Memory, int32 SingleFrame = -1)
+Memory_Cache_Purge(project_data *File, project_state *State, memory *Memory, int32 SingleFrame)
{
cache_entry *EntryArray = State->Render.Entry;
int c = 0;
int count = Memory->EntryCount;
+ Assert(Memory->EntryCount < 10000);
while (count != 0) {
bool32 ExtraCheck = (SingleFrame == -1) ? 1 : EntryArray[c].TypeInfo_Sub == SingleFrame;
if (EntryArray[c].Type == cache_entry_type_comp &&
@@ -236,6 +244,8 @@ Memory_PushScratch(memory *Memory, uint64 Size) {
uint8 *Address = ((uint8 *)Table->Address + Memory->ScratchPos);
Memory->ScratchPos += Size;
#if DEBUG
+ Assert(Memory->ScratchPos > 0);
+ Assert(Memory->ScratchPos < Table->Size);
Debug.ScratchSize[Debug.ScratchState] = Size;
Debug.ScratchState++;
#endif
@@ -245,6 +255,7 @@ Memory_PushScratch(memory *Memory, uint64 Size) {
static void
Memory_PopScratch(memory *Memory, uint64 Size) {
memory_table *Table = &Memory->Slot[B_ScratchSpace];
+ Assert(Memory->ScratchPos >= Size);
Memory->ScratchPos -= Size;
#if DEBUG
Debug.ScratchState--;
@@ -256,6 +267,7 @@ static void *
Memory_AddressAtOffset(memory *Memory, memory_table_list TableName, uint64 Offset)
{
memory_table *Table = &Memory->Slot[TableName];
+ Assert(Offset < Table->Size);
return (void *)((uint8 *)Table->Address + Offset);
}
diff --git a/src/nanovg.cpp b/src/nanovg.cpp
index 22d8621..b7b426f 100644
--- a/src/nanovg.cpp
+++ b/src/nanovg.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
// nanovg code adapted by me for my data structures, I'm primarily using the
// functions related to shape/path triangulation.
diff --git a/src/paint.cpp b/src/paint.cpp
index f3170e5..9362504 100644
--- a/src/paint.cpp
+++ b/src/paint.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static void
SlidingBrush(pixel_buffer *Buffer, v2i Pos, brush_tool Brush)
diff --git a/src/prenderer.cpp b/src/prenderer.cpp
index fc6edd4..08cdadf 100644
--- a/src/prenderer.cpp
+++ b/src/prenderer.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static v2
T_CompPosToLayerPos(layer_transforms T, uint32 FileWidth, uint32 FileHeight, uint32 SourceWidth, uint32 SourceHeight, real32 X, real32 Y)
{
@@ -126,16 +130,8 @@ Transform_Recurse(project_state *State, memory *Memory, block_composition *MainC
MinX, MinY, MaxX, MaxY);
}
if (Layer->IsSelected) {
- uint32 Width = 0, Height = 0;
- 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;
- }
+ int Width = 0, Height = 0;
+ Layer_GetDimensions(Memory, Layer, &Width, &Height);
v2 Point[5] = { V2(Width*Layer->ax.CurrentValue, Height*Layer->ay.CurrentValue), V2(0, 0), V2(Width, 0), V2(0, Height), V2(Width, Height) };
diff --git a/src/sorted.cpp b/src/sorted.cpp
index 46b9549..08d9d3b 100644
--- a/src/sorted.cpp
+++ b/src/sorted.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
inline sorted_property_array *
Property_GetSortedInfo(sorted_property_array *SortedPropertyStart, int i, int h)
@@ -17,7 +21,7 @@ Sorted_GetLayerStart(sorted_layer_array *LayerArrayStart, sorted_comp_array *Sor
{
uint32 LayerOffset = 0; int s = 0;
while (s < TargetComp) {
- LayerOffset += SortedCompStart[s].LayerCount;
+ LayerOffset += SortedCompStart[s].LayerCount + SortedCompStart[s].FakeLayerCount;
s++;
}
return LayerArrayStart + LayerOffset;
@@ -80,7 +84,8 @@ Layer_Sort_DisplayOffset(project_state *State, memory *Memory,
sorted_comp_array *SortedCompStart, sorted_layer_array *SortedLayerStart)
{
int32 DisplayOffset = 0;
- for (int i = SortedCompStart->LayerCount - 1; i >= 0; i--)
+ int LayerCount = SortedCompStart->LayerCount + SortedCompStart->FakeLayerCount;
+ for (int i = LayerCount - 1; i >= 0; i--)
{
sorted_layer_array *SortEntry = &SortedLayerStart[i];
SortEntry->DisplayOffset = DisplayOffset;
@@ -107,7 +112,7 @@ Layer_Sort_DisplayOffset(project_state *State, memory *Memory,
DisplayOffset += InnerCompOffset;
}
}
- if (SortedCompStart->LayerCount > 1) {
+ if (LayerCount > 1) {
sorted_layer_array LayerEntry_Top = SortedLayerStart[SortedCompStart->LayerCount - 1];
sorted_layer_array LayerEntry_Bottom = SortedLayerStart[0];
real32 SmallestY = LayerEntry_Top.SortedOffset;
@@ -155,7 +160,11 @@ Layer_SortAll(project_state *State, memory *Memory,
while (Block_Loop(Memory, F_Layers, LayerCount, &h, &c, &i)) {
block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
Assert(Layer->Block_Composition_Index < CompCount);
- CompArrayStart[Layer->Block_Composition_Index].LayerCount++;
+ sorted_comp_array *SortedCompStart = &CompArrayStart[Layer->Block_Composition_Index];
+ SortedCompStart->LayerCount++;
+ if (State->Interact_Active == interact_type_viewport_duplicate && Layer->IsSelected) {
+ SortedCompStart->FakeLayerCount++;
+ }
}
h = 0, c = 0, i = 0;
while (Block_Loop(Memory, F_Layers, LayerCount, &h, &c, &i)) {
@@ -220,12 +229,38 @@ Layer_SortAll(project_state *State, memory *Memory,
}
}
}
+ else if (State->Interact_Active == interact_type_viewport_duplicate) {
+ for (uint32 c = 0; c < CompCount; c++) {
+ sorted_comp_array *SortedCompStart = &CompArrayStart[c];
+ if (!SortedCompStart->LayerCount)
+ continue;
+ sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(LayerArrayStart, CompArrayStart, c);
+ int i = 0;
+ int FauxIncrement = 0;
+ while (i < SortedCompStart->LayerCount) {
+ int Idx = i + FauxIncrement;
+ sorted_layer_array *LayerEntry = &SortedLayerStart[Idx];
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, LayerEntry->Block_Layer_Index);
+ if (Layer->IsSelected) {
+ uint8 *Address_Start = (uint8 *)(LayerEntry);
+ uint8 *Address_End = (uint8 *)(&SortedLayerStart[SortedCompStart->LayerCount + FauxIncrement]) - 1;
+ Assert(SortedCompStart->CurrentSortIndex != (SortedCompStart->LayerCount + SortedCompStart->FakeLayerCount));
+ Arbitrary_ShiftData(Address_Start, Address_End, sizeof(sorted_layer_array), 1);
+ sorted_layer_array *FakeLayerEntry = LayerEntry + 1;
+ Assert(FakeLayerEntry->Block_Layer_Index == LayerEntry->Block_Layer_Index);
+ FakeLayerEntry->IsFake = true;
+ FauxIncrement++;
+ }
+ i++;
+ }
+ }
+ }
}
// NOTE(fox): We could be slightly more efficient and just allocate redundant data
// instead of having another loop.
void LayerProperty_Count(project_data *File, project_state *State, memory *Memory, sorted_layer_array *LayerArrayStart,
- sorted_comp_array *CompStart, uint32 LayerCount, uint32 CompCount,
+ sorted_comp_array *CompStart, uint32 CompCount,
uint32 *TotalPropertyCount, uint32 *TotalKeyframeCount)
{
uint32 SortedPropertyPlayhead = 0;
@@ -233,8 +268,11 @@ void LayerProperty_Count(project_data *File, project_state *State, memory *Memor
for (int c = 0; c < CompCount; c++) {
sorted_comp_array SortedCompStart = CompStart[c];
sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(LayerArrayStart, CompStart, c);
- for (int i = 0; i < SortedCompStart.LayerCount; i++) {
+ int LayerCount = SortedCompStart.LayerCount + SortedCompStart.FakeLayerCount;
+ for (int i = 0; i < LayerCount; i++) {
sorted_layer_array *SortedLayer = &SortedLayerStart[i];
+ if (SortedLayer->IsFake)
+ continue;
block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, SortedLayer->Block_Layer_Index);
SortedLayer->SortedPropertyStart = SortedPropertyPlayhead;
SortedLayer->SortedKeyframeStart = SortedKeyframePlayhead;
@@ -265,15 +303,18 @@ void LayerProperty_Count(project_data *File, project_state *State, memory *Memor
void LayerProperty_SortAll(project_data *File, project_state *State, memory *Memory, sorted_layer_array *LayerArrayStart,
sorted_comp_array *CompStart, sorted_property_array *SortedPropertyStart, uint16 *SortedKeyframeArray,
- uint32 LayerCount, uint32 CompCount)
+ uint32 CompCount)
{
uint32 SortedPropertyPlayhead = 0;
uint32 SortedKeyframePlayhead = 0;
for (int c = 0; c < CompCount; c++) {
sorted_comp_array SortedCompStart = CompStart[c];
sorted_layer_array *SortedLayerStart = Sorted_GetLayerStart(LayerArrayStart, CompStart, c);
- for (int i = 0; i < SortedCompStart.LayerCount; i++) {
+ int LayerCount = SortedCompStart.LayerCount + SortedCompStart.FakeLayerCount;
+ for (int i = 0; i < LayerCount; i++) {
sorted_layer_array *SortedLayer = &SortedLayerStart[i];
+ if (SortedLayer->IsFake)
+ continue;
block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, SortedLayer->Block_Layer_Index);
SortedLayer->SortedPropertyStart = SortedPropertyPlayhead;
SortedLayer->SortedKeyframeStart = SortedKeyframePlayhead;
@@ -341,8 +382,18 @@ static sorted_file
File_Sort_Push(project_data *File, project_state *State, memory *Memory)
{
sorted_file Sorted = {0};
+
+ int ExtraLayers = 0;
+ if (State->Interact_Active == interact_type_viewport_duplicate) {
+ int h = 0, c = 0, i = 0;
+ while (Block_Loop(Memory, F_Layers, File->Layer_Count, &h, &c, &i)) {
+ block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, i);
+ Assert(Layer->Block_Composition_Index < File->Comp_Count);
+ ExtraLayers++;
+ }
+ }
Sorted.Layer_SortSize = (sizeof(sorted_comp_array) * File->Comp_Count) +
- (sizeof(sorted_layer_array) * File->Layer_Count);
+ (sizeof(sorted_layer_array) * (File->Layer_Count + ExtraLayers));
void *Layer_SortedArray = Memory_PushScratch(Memory, Sorted.Layer_SortSize);
Arbitrary_Zero((uint8 *)Layer_SortedArray, Sorted.Layer_SortSize);
Sorted.CompArray = (sorted_comp_array *)Layer_SortedArray;
@@ -361,7 +412,7 @@ File_Sort_Push(project_data *File, project_state *State, memory *Memory)
uint32 TotalPropertyCount = 0;
uint32 TotalKeyframeCount = 0;
- LayerProperty_Count(File, State, Memory, Sorted.LayerArray, Sorted.CompArray, File->Layer_Count, File->Comp_Count, &TotalPropertyCount, &TotalKeyframeCount);
+ LayerProperty_Count(File, State, Memory, Sorted.LayerArray, Sorted.CompArray, File->Comp_Count, &TotalPropertyCount, &TotalKeyframeCount);
uint64 PropertyStartSize = TotalPropertyCount * sizeof(sorted_property_array);
uint64 PropertyArraySize = TotalKeyframeCount * sizeof(uint16);
Sorted.Property_SortSize = PropertyArraySize + PropertyStartSize;
@@ -370,7 +421,7 @@ File_Sort_Push(project_data *File, project_state *State, memory *Memory)
Sorted.PropertyStart = (sorted_property_array *)Property_SortedArray;
Sorted.PropertyArray = (uint16 *)((uint8 *)Property_SortedArray + PropertyStartSize);
- LayerProperty_SortAll(File, State, Memory, Sorted.LayerArray, Sorted.CompArray, Sorted.PropertyStart, Sorted.PropertyArray, File->Layer_Count, File->Comp_Count);
+ LayerProperty_SortAll(File, State, Memory, Sorted.LayerArray, Sorted.CompArray, Sorted.PropertyStart, Sorted.PropertyArray, File->Comp_Count);
sorted_comp_array *MainSortedCompStart = &Sorted.CompArray[File->PrincipalCompIndex];
sorted_layer_array *MainSortedLayerStart = Sorted_GetLayerStart(Sorted.LayerArray, Sorted.CompArray, File->PrincipalCompIndex);
diff --git a/src/stable_diffusion.cpp b/src/stable_diffusion.cpp
index 4da327d..c047594 100644
--- a/src/stable_diffusion.cpp
+++ b/src/stable_diffusion.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
struct curl_data {
char *response;
size_t size;
@@ -118,7 +122,7 @@ JSON_AppendParam_String(char *String, uint64 *i, char *P1, char *P2)
}
static void
-SD_AssembleJSON(sd_state *SD, char *JSONPayload, void *Base64Bitmap = NULL)
+SD_AssembleJSON(sd_state *SD, char *JSONPayload, void *Base64Bitmap)
{
Arbitrary_Zero((uint8 *)JSONPayload, 1024);
// char CurlCommand[1024];
diff --git a/src/strings.cpp b/src/strings.cpp
index d2acc03..e6c3ec5 100644
--- a/src/strings.cpp
+++ b/src/strings.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static bool32 Hacko = false;
static int32 EffectSel = -1;
diff --git a/src/threading.cpp b/src/threading.cpp
index 5a42ea7..3c034c0 100644
--- a/src/threading.cpp
+++ b/src/threading.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
static void
RenderLayers(render_entry Entry);
diff --git a/src/undo.cpp b/src/undo.cpp
index ec85530..38c22ef 100644
--- a/src/undo.cpp
+++ b/src/undo.cpp
@@ -1,3 +1,7 @@
+#if SPECIAL
+#include "main.h"
+#endif
+
struct history_info {
uint16 ActionCount_Total;
uint16 ActionCount_EndOfPlayhead;
@@ -11,7 +15,7 @@ struct history_info {
};
static uint64
-History_GetActionSize(history_entry_list *History, int i, uint16 ActionCount_EndOfPlayhead)
+History_GetActionSize(history_entry_list *History, int i)
{
history_action *Action = &History->Action[i];
if (Action->Type == action_type_swap || Action->Type == action_type_swap_bitmap)
@@ -44,7 +48,7 @@ History_GetTreeInfo(history_entry_list *History, uint16 SampleIndex)
for (int i = 0; i < Info.ActionCount_Total; i++)
{
- uint64 Size = History_GetActionSize(History, i, Info.ActionCount_EndOfPlayhead);
+ uint64 Size = History_GetActionSize(History, i);
Info.ActionOffset_Total += Size;
if (i < Info.ActionCount_EndOfPlayhead)
Info.ActionOffset_EndOfPlayhead += Size;
@@ -202,6 +206,9 @@ void History_Entry_Commit(memory *Memory, char *Name)
history_entry *Entry = &History->Entry[History->EntryPlayhead];
Entry->Name = Name;
Entry->NumberOfActions = 0;
+ if (History->NumberOfEntries > MAX_HISTORY_ENTRIES) {
+ Assert(0);
+ }
// Effectively deletes entries in front if we're beginning out of an undo.
if (History->NumberOfEntries != History->EntryPlayhead)
History->NumberOfEntries = History->EntryPlayhead;
@@ -223,6 +230,42 @@ void History_Entry_End(memory *Memory)
#endif
}
+static void
+History_Purge(memory *Memory, history_entry_list *History, uint64 ActionCount_Total, uint64 ActionOffset_Total, uint64 PurgeSize)
+{
+ int Size = 0;
+ int EntryIndex = 0;
+ int ActionIndex = 0;
+ int ActionCount = 0;
+ while (Size < PurgeSize) {
+ history_entry *Entry = &History->Entry[EntryIndex];
+ ActionCount += Entry->NumberOfActions;
+ while (ActionIndex < ActionCount) {
+ Size += History_GetActionSize(History, ActionIndex);
+ ActionIndex++;
+ }
+ EntryIndex++;
+ }
+ int EntryCount = (EntryIndex + 1);
+ {
+ uint8 *Address_Start = (uint8 *)Memory_AddressAtOffset(Memory, P_UndoBuffer, Size);
+ uint8 *Address_End = (uint8 *)Memory_AddressAtOffset(Memory, P_UndoBuffer, ActionOffset_Total);
+ Arbitrary_ShiftData(Address_Start, Address_End, Size, -1);
+ }
+ {
+ uint8 *Address_Start = (uint8 *)&History->Entry[EntryCount];
+ uint8 *Address_End = (uint8 *)&History->Entry[History->NumberOfEntries];
+ Arbitrary_ShiftData(Address_Start, Address_End, sizeof(history_entry) * EntryCount, -1);
+ }
+ {
+ uint8 *Address_Start = (uint8 *)&History->Action[ActionCount];
+ uint8 *Address_End = (uint8 *)&History->Action[ActionCount_Total];
+ Arbitrary_ShiftData(Address_Start, Address_End, sizeof(history_action) * ActionCount, -1);
+ }
+ History->NumberOfEntries -= EntryCount;
+ History->EntryPlayhead -= EntryCount;
+}
+
// NOTE(fox): Shift is the only action that additionally changes the data after
// the info is put on the tree, since it's always the same function used.
@@ -233,6 +276,15 @@ static void History_Action_Add(memory *Memory, history_action ActionData, void *
history_info Info = History_GetTreeInfo(History, History->EntryPlayhead - 1);
+ if ((Info.ActionOffset_EndOfPlayhead + ActionData.Size) > Memory->Slot[P_UndoBuffer].Size) {
+ History_Purge(Memory, History, Info.ActionCount_Total, Info.ActionOffset_Total, ActionData.Size * 4);
+ Entry = &History->Entry[History->EntryPlayhead - 1];
+ Info = History_GetTreeInfo(History, History->EntryPlayhead - 1);
+ }
+ if (Info.ActionCount_Total > MAX_HISTORY_ACTIONS) {
+ Assert(0);
+ }
+
history_action *Action = &History->Action[Info.ActionCount_Total];
*Action = ActionData;