From 2f164ae23bcd8a857081529189b484a1515f2834 Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Fri, 20 Jan 2023 10:10:54 -0500 Subject: youarelazy --- .gitignore | 2 + build.sh | 10 +- src/bezier.cpp | 121 +++++++- src/createcalls.cpp | 71 ++++- src/effects.cpp | 4 + src/effects_constructors.cpp | 6 +- src/effects_gl.cpp | 4 + src/effects_gl_shader.cpp | 4 + src/effects_software.cpp | 4 + src/ffmpeg_backend.cpp | 6 +- src/gl_calls.cpp | 149 +++++++++- src/imgui_helper.cpp | 4 + src/imgui_helper_internal.cpp | 5 +- src/imgui_ui.cpp | 32 +- src/imgui_ui_debug.cpp | 4 + src/imgui_ui_properties.cpp | 27 +- src/imgui_ui_stable_diffusion.cpp | 4 + src/imgui_ui_timeline.cpp | 4 + src/imgui_ui_viewport.cpp | 172 +++++++++-- src/include/all.h | 612 ++++++++++++++++++++++++++++++++++++++ src/include/defines.h | 2 + src/include/functions.h | 21 +- src/include/imgui_ops.h | 2 - src/include/layer.h | 2 +- src/include/main.h | 93 +++++- src/include/memory.h | 11 +- src/include/my_math.h | 16 +- src/io.cpp | 4 + src/layer.cpp | 175 ++++++++++- src/main.cpp | 338 +++++++++++++++------ src/memory.cpp | 16 +- src/nanovg.cpp | 4 + src/paint.cpp | 4 + src/prenderer.cpp | 16 +- src/sorted.cpp | 73 ++++- src/stable_diffusion.cpp | 6 +- src/strings.cpp | 4 + src/threading.cpp | 4 + src/undo.cpp | 56 +++- 39 files changed, 1861 insertions(+), 231 deletions(-) create mode 100644 src/include/all.h diff --git a/.gitignore b/.gitignore index 16374f3..7513e10 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ test test2 test3 test4 +tags +.cache diff --git a/build.sh b/build.sh index fff8475..f92c187 100755 --- a/build.sh +++ b/build.sh @@ -88,19 +88,19 @@ fi [[ -d bin ]] || mkdir bin -clang $IMGUI_FLAGS -Isrc/include -o bin/imgui_helper_internal.o src/imgui_helper_internal.cpp +clang $IMGUI_FLAGS -MJ bin/imguihelper.json -Isrc/include -o bin/imgui_helper_internal.o src/imgui_helper_internal.cpp if [[ "$IMGUI" == 1 ]]; then for i in $IMGUI_FILES do - clang $IMGUI_FLAGS -o bin/$i.o dependencies/src/imgui/$i.cpp + clang $IMGUI_FLAGS -MJ bin/$i.json -o bin/$i.o dependencies/src/imgui/$i.cpp done fi -clang dependencies/src/glad.c -Idependencies/include -I/usr/local/include -I/opt/local/include -c \ +clang dependencies/src/glad.c -MJ bin/glad.json -Idependencies/include -I/usr/local/include -I/opt/local/include -c \ $WARNING_FLAGS $OPTIMIZATION $ADDITIONAL_FLAGS -o bin/glad.o -clang src/main.cpp $WARNING_FLAGS $OPTIMIZATION $ADDITIONAL_FLAGS -o bin/real2d_"$ARCHNAME"_"$OSNAME" bin/*.o \ +clang src/main.cpp -MJ bin/main.json $WARNING_FLAGS $OPTIMIZATION $ADDITIONAL_FLAGS -o bin/real2d_"$ARCHNAME"_"$OSNAME" bin/*.o \ -Idependencies/include -Idependencies/include/imgui -Idependencies/src -Isrc/include \ -std=c++11 -lstdc++ \ $SDL_ARGS \ @@ -108,6 +108,8 @@ clang src/main.cpp $WARNING_FLAGS $OPTIMIZATION $ADDITIONAL_FLAGS -o bin/real2d -I . \ -lm $(pkg-config --cflags --libs $FFMPEG_LIBS) +# sed -e '1s/^/[\n/' -e '$s/,$/\n]/' bin/*.json > compile_commands.json + if [[ "$OSTYPE" =~ ^darwin ]]; then mkdir bin/real_"$ARCHNAME".app cp -r misc/mac_app_template/Contents bin/real_"$ARCHNAME".app 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]; @@ -609,6 +613,53 @@ Property_IsGraphSelected(memory *Memory, property_channel *Property, uint16 *Arr return 0; } +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) { @@ -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"; @@ -165,10 +176,132 @@ GL_DeleteHWBuffer(gl_effect_layer *Test) Test->Initialized = true; } +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 + +#include +#if WINDOWS +#include +#else +#include +#include +#endif + +#if ARM +#include +#include +#else +#include +#endif + +#include "imgui.h" +#include "imgui_impl_sdl.h" +#include "imgui_impl_opengl3.h" +#include +#if defined(IMGUI_IMPL_OPENGL_ES2) +#include +#else +#include +#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 +#include +#include +#include +#include +#include +} + + + +#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 - -#include -#if WINDOWS -#include -#else -#include -#include -#endif - -#if ARM -#include -#include -#else -#include -#endif - -#include "imgui.h" -#include "imgui_impl_sdl.h" -#include "imgui_impl_opengl3.h" -#include -#if defined(IMGUI_IMPL_OPENGL_ES2) -#include -#else -#include -#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 -#include -#include -#include -#include -#include -} - - -#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 #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; -- cgit v1.2.3