summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFox Caminiti <fox@foxcam.net>2022-08-10 21:24:03 -0400
committerFox Caminiti <fox@foxcam.net>2022-08-10 21:24:03 -0400
commitbc5375149c0ecb416848a2d3657ea41ae97177b3 (patch)
tree8868395241d523bb96ea90d2846cd6ffefcae766
parentf1e12e108869c560d92eb8803e4b5104c7d8f85d (diff)
path rasterization started with opengl
-rw-r--r--bezier.cpp157
-rw-r--r--createcalls.cpp194
-rw-r--r--defines.h1
-rw-r--r--effects.cpp12
-rw-r--r--functions.h8
-rw-r--r--gl_calls.cpp134
-rw-r--r--main.cpp6
-rw-r--r--main.h37
-rw-r--r--my_imgui_internal_widgets.cpp104
-rw-r--r--my_imgui_internal_widgets.h5
-rw-r--r--my_imgui_widgets.cpp147
-rw-r--r--my_math.h22
12 files changed, 594 insertions, 233 deletions
diff --git a/bezier.cpp b/bezier.cpp
new file mode 100644
index 0000000..4e0cb5c
--- /dev/null
+++ b/bezier.cpp
@@ -0,0 +1,157 @@
+// 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);
+}
+
+// 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 ap = p - a;
+ v2 ab_dir = b - a;
+ real32 dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
+ if (dot < 0.0f) {
+ *ratio = 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) {
+ *ratio = 1.0f;
+ return b;
+ }
+ *ratio = dot / ab_len_sqr;
+ return a + ab_dir * dot / ab_len_sqr;
+}
+
+// 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.
+// The pow(0.5, level) represents the ratio of the next subdivision's leftmost
+// point (AKA the rightmost point of the current subdivision).
+
+// finds the point closest to p and also fills out its ratio along the curve
+static void Bezier_CubicClosestPointCasteljauStep(v2 p, v2 *p_closest, real32 ratio, real32 *r_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);
+ real32 added_ratio;
+ v2 p_line = Bezier_LineClosestPoint2(*p_last, p_current, p, &added_ratio);
+ real32 dist2 = LengthSq(p - p_line);
+ if (dist2 < *p_closest_dist2)
+ {
+ *p_closest = p_line;
+ *p_closest_dist2 = dist2;
+ *r_closest = ratio + pow(0.5, level)*added_ratio;
+ }
+ *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_CubicClosestPointCasteljauStep(p, p_closest, ratio, r_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
+ Bezier_CubicClosestPointCasteljauStep(p, p_closest, ratio + pow(0.5, level+1), r_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
+ }
+}
+
+// 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 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);
+ if (p_current.x < p_min->x) {
+ p_min->x = p_current.x;
+ }
+ if (p_current.y < p_min->y) {
+ p_min->y = p_current.y;
+ }
+ if (p_current.x > p_max->x) {
+ p_max->x = p_current.x;
+ }
+ if (p_current.y > p_max->y) {
+ p_max->y = p_current.y;
+ }
+ }
+ 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_CubicMinMaxCasteljauStep(p_min, p_max, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
+ Bezier_CubicMinMaxCasteljauStep(p_min, p_max, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
+ }
+}
+
+// return all points
+static void Bezier_CubicCalcPointsCasteljauStep(void *Data, uint32 *Increment, 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))
+ {
+ *((real32 *)Data + *Increment*3) = x4;
+ *((real32 *)Data + *Increment*3 + 1) = y4;
+ *((real32 *)Data + *Increment*3 + 2) = 0;
+ *Increment += 1;
+ }
+ 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_CubicCalcPointsCasteljauStep(Data, Increment, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
+ Bezier_CubicCalcPointsCasteljauStep(Data, Increment, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
+ }
+}
+
+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;
+}
+
+void Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 *Increment)
+{
+ real32 tess_tol = TESS_TOL;
+ void *Pointer = Data;
+ Bezier_CubicCalcPointsCasteljauStep(Pointer, Increment, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0);
+}
diff --git a/createcalls.cpp b/createcalls.cpp
index 5144cf0..4ddaa7e 100644
--- a/createcalls.cpp
+++ b/createcalls.cpp
@@ -180,6 +180,96 @@ STB_LoadStill(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory)
return Bitmap;
}
+static void
+Mask_RasterizePoints(mask *Mask)
+{
+ Mask->NumberOfVerts = 0;
+ for (int i = 0; i < Mask->NumberOfPoints; i++) {
+ mask_point Point0 = Mask->Point[i];
+ mask_point Point1 = Mask->Point[i+1];
+ if (i+1 == Mask->NumberOfPoints)
+ Point1 = Mask->Point[0];
+
+ if (Point0.HandleBezier || Point1.HandleBezier) {
+ Bezier_CubicCalcPoints(Point0.Pos, Point0.Pos + Point0.TangentRight, Point1.Pos + Point1.TangentLeft, Point1.Pos,
+ Mask->TriangulatedPointCache, &Mask->NumberOfVerts);
+ } else {
+ real32 *Data = (real32 *)Mask->TriangulatedPointCache + Mask->NumberOfVerts*3;
+ *(Data++) = Point0.Pos.x;
+ *(Data++) = Point0.Pos.y;
+ *(Data++) = 0;
+ Mask->NumberOfVerts += 1;
+ }
+ }
+}
+
+static void
+Mask_TriangulateAndRasterize(memory *Memory, project_layer *Layer, mask *Mask)
+{
+ if (!Mask->TriangulatedPointCache) {
+ Mask->TriangulatedPointCache = AllocateMemory(Memory, 50*1024, P_VectorPoints);
+ }
+ Mask_RasterizePoints(Mask);
+
+ gl_vertex_shader VertData;
+ gl_effect_layer Test = Layer->BitmapInfo.Test;
+
+ glBindFramebuffer(GL_FRAMEBUFFER, Test.FramebufferObject);
+
+ glEnable(GL_STENCIL_TEST);
+ glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+ glStencilFunc(GL_ALWAYS, 1, 0xFF); // always write
+ glStencilMask(0xff); // allow writing; ANDs any writes to the stencil buffer with this
+
+ glUseProgram(MaskShaderProgram);
+
+ // secondary VBO
+ glGenVertexArrays(1, &VertData.VertexArrayObject);
+ glBindVertexArray(VertData.VertexArrayObject);
+ glBindBuffer(GL_ARRAY_BUFFER, VertData.VertexBufferObject);
+ glBufferData(GL_ARRAY_BUFFER, Mask->NumberOfVerts*3*sizeof(real32), Mask->TriangulatedPointCache, GL_STREAM_DRAW);
+
+ // position attribute
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
+ glEnableVertexAttribArray(0);
+
+ int Scale = glGetUniformLocation(MaskShaderProgram, "CompDimensions");
+ glUniform3f(Scale, (real32)Layer->Source->Info.Width, (real32)Layer->Source->Info.Height, 0);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, Mask->NumberOfVerts);
+
+ glBindVertexArray(0);
+ glStencilFunc(GL_EQUAL, 1, 0xFF);
+ glStencilMask(0x00); // disables stencil writing
+
+ glBindRenderbuffer(GL_RENDERBUFFER, Test.Color_Renderbuffer);
+ glUseProgram(DefaultShaderProgram);
+
+ // // Switch to main buffer
+ glBindBuffer(GL_ARRAY_BUFFER, DefaultVerts.VertexBufferObject);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(DefaultVertices), DefaultVertices, GL_STATIC_DRAW);
+ // position attribute
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
+ glEnableVertexAttribArray(0);
+ // texture coordinate (note the last parameter's offset)
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
+ glEnableVertexAttribArray(1);
+
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
+
+ glDisable(GL_STENCIL_TEST);
+ glStencilMask(0xFF);
+ glStencilFunc(GL_ALWAYS, 0, 0xFF);
+
+ uint8 *Data = (uint8 *)Layer->BitmapInfo.BitmapBuffer;
+ glReadPixels(0, 0, Layer->Source->Info.Width, Layer->Source->Info.Height, GL_RGBA, GL_UNSIGNED_BYTE, &Data[0]);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
static void
Layer_UpdateBitmap(project_layer *Layer, memory *Memory, int32 CurrentFrame) {
@@ -199,7 +289,16 @@ Layer_UpdateBitmap(project_layer *Layer, memory *Memory, int32 CurrentFrame) {
void *DestBuffer = BitmapInfo->BitmapBuffer;
uint64 Size = Bitmap_CalcUnpackedBytes(Source->Info.Width, Source->Info.Height, Source->Info.BytesPerPixel);
Bitmap_CopyToPointer(Bitmap->Data, DestBuffer, BytesPerPixel, Size);
+
TestGL_InitTexture(&BitmapInfo->Test, DestBuffer, Width, Height);
+
+ if (Layer->NumberOfMasks) {
+ for (int i = 0; i < Layer->NumberOfMasks; i++) {
+ mask *Mask = &Layer->Mask[i];
+ Mask_TriangulateAndRasterize(Memory, Layer, Mask);
+ }
+ }
+
for (int i = 0; i < Layer->NumberOfEffects; i++)
{
if (Layer->Effect[i]->IsActive)
@@ -255,6 +354,25 @@ Layer_LocalToScreenSpace(project_layer *Layer, ui *UI, comp_buffer CompBuffer, v
return ImVec2(ScreenPoint.x, ScreenPoint.y);
}
+static v2
+Layer_ScreenSpaceToLocal(project_layer *Layer, ui *UI, comp_buffer CompBuffer, ImVec2 ViewportMin, ImVec2 Point)
+{
+ source *Source = Layer->Source;
+ v2 CompUV = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, Point);
+ v2 LayerUV = CompUVToLayerUV(Layer, &CompBuffer, CompUV);
+ return V2(LayerUV.x * Source->Info.Width, LayerUV.y * Source->Info.Height);
+}
+
+static void
+Mask_AddPointToLine(mask *Mask, uint16 Index, v2 Pos)
+{
+ for (int i = Mask->NumberOfPoints - 1; i > Index; i--) {
+ Mask->Point[i+1] = Mask->Point[i];
+ }
+ mask_point *PointToAdd = &Mask->Point[Index+1];
+ PointToAdd->Pos = Pos;
+ Mask->NumberOfPoints++;
+}
static void
Mask_PushPoint(mask *Mask, v2 Pos)
@@ -265,22 +383,31 @@ Mask_PushPoint(mask *Mask, v2 Pos)
}
static void
-Mask_AddPointToCurve(mask *Mask, ImVec2 Pos, ImVec2 TangentLeft, ImVec2 TangentRight,
- ImVec2 Ratio0, ImVec2 Ratio1, uint16 Index)
+Mask_AddPointToCurve(mask *Mask, uint16 Index, real32 ratio)
{
- mask_point *Point = &Mask->Point[Index];
- mask_point *NextPoint = &Mask->Point[Index+1];
+ mask_point *Point0 = &Mask->Point[Index];
+ mask_point *Point1 = &Mask->Point[Index+1];
+
+ v2 Point0_Pos_Right = Point0->Pos + Point0->TangentRight;
+ v2 Point1_Pos_Left = Point1->Pos + Point1->TangentLeft;
+ v2 Handle0_Half = Line_RatioToPoint(Point0->Pos, Point0_Pos_Right, ratio);
+ v2 Handle1_Half = Line_RatioToPoint(Point1_Pos_Left, Point1->Pos, ratio);
+ v2 Top_Half = Line_RatioToPoint(Point0_Pos_Right, Point1_Pos_Left, ratio);
+ v2 NewHandleLeft = Line_RatioToPoint(Handle0_Half, Top_Half, ratio);
+ v2 NewHandleRight = Line_RatioToPoint(Top_Half, Handle1_Half, ratio);
+ v2 NewPos = Line_RatioToPoint(NewHandleLeft, NewHandleRight, ratio);
- Point->TangentRight = -V2(Ratio0);
- NextPoint->TangentLeft = -V2(Ratio1);
+ Point0->TangentRight = -(Point0->Pos - Handle0_Half);
+ Point1->TangentLeft = -(Point1->Pos - Handle1_Half);
for (int i = Mask->NumberOfPoints - 1; i > Index; i--) {
Mask->Point[i+1] = Mask->Point[i];
}
mask_point *PointToAdd = &Mask->Point[Index+1];
- PointToAdd->Pos = {Pos.x, Pos.y};
- PointToAdd->TangentLeft = {-TangentLeft.x, -TangentLeft.y};
- PointToAdd->TangentRight = {-TangentRight.x, -TangentRight.y};
+
+ PointToAdd->Pos = NewPos;
+ PointToAdd->TangentLeft = -(NewPos - NewHandleLeft);
+ PointToAdd->TangentRight = -(NewPos - NewHandleRight);
Mask->NumberOfPoints++;
}
@@ -292,25 +419,36 @@ LoadTestFootage(project_data *File, project_state *State, memory *Memory)
source *Source = &File->Source[0];
Layer_CreateFromSource(File, State, Memory, Source);
SelectLayer(File->Layer[0], State, 0);
- AddEffect(File->Layer[0], Memory, 3);
-
- // mask *Mask = &File->Layer[0]->Mask[0];
- // File->Layer[0]->NumberOfMasks = 1;
- // Mask->Point[0].Pos = V2(200, 200);
- // Mask->Point[1].Pos = V2(1280, 0);
- // Mask->Point[2].Pos = V2(1280, 720);
- // Mask->Point[3].Pos = V2(0, 720);
-
- // Mask->Point[0].TangentLeft = V2(-50, 0);
- // Mask->Point[1].TangentLeft = V2(-50, 0);
- // Mask->Point[2].TangentLeft = V2(-50, 0);
- // Mask->Point[3].TangentLeft = V2(-50, 0);
-
- // Mask->Point[0].TangentRight = V2(50, 0);
- // Mask->Point[1].TangentRight = V2(50, 0);
- // Mask->Point[2].TangentRight = V2(50, 0);
- // Mask->Point[3].TangentRight = V2(50, 0);
- // Mask->NumberOfPoints = 4;
+ // AddEffect(File->Layer[0], Memory, 3);
+
+ mask *Mask = &File->Layer[0]->Mask[0];
+ File->Layer[0]->NumberOfMasks = 1;
+ Mask->Point[0].Pos = V2(200, 200);
+ Mask->Point[1].Pos = V2(200, 400);
+ Mask->Point[2].Pos = V2(200, 520);
+ Mask->Point[3].Pos = V2(1080, 520);
+ Mask->Point[4].Pos = V2(1080, 200);
+
+ Mask->Point[0].TangentLeft = V2(-50, 0);
+ Mask->Point[1].TangentLeft = V2(-50, 0);
+ Mask->Point[2].TangentLeft = V2(-50, 0);
+ Mask->Point[3].TangentLeft = V2(-50, 0);
+ Mask->Point[4].TangentLeft = V2(-50, 0);
+
+ Mask->Point[0].TangentRight = V2(50, 0);
+ Mask->Point[1].TangentRight = V2(50, 0);
+ Mask->Point[2].TangentRight = V2(50, 0);
+ Mask->Point[3].TangentRight = V2(50, 0);
+ Mask->Point[4].TangentRight = V2(50, 0);
+
+ Mask->Point[0].HandleBezier = true;
+ Mask->Point[1].HandleBezier = true;
+ Mask->Point[2].HandleBezier = true;
+ Mask->Point[3].HandleBezier = true;
+ Mask->Point[4].HandleBezier = true;
+
+
+ Mask->NumberOfPoints = 5;
// property_channel *Property = &File->Layer[0]->x;
// ManualKeyframeInsertF(Property, Memory, 1, 500);
diff --git a/defines.h b/defines.h
index 947a8f0..b87fc6d 100644
--- a/defines.h
+++ b/defines.h
@@ -21,6 +21,7 @@ typedef double real64;
#define NORMALIZED_REAL_MIN { 0.0f }
#define NORMALIZED_REAL_MAX { 1.0f }
+#define TESS_TOL 1.5f // Level of tesselation for bezier calculations; ImGui's default value
// All of these MIN/MAX values are arbitrarily chosen; they can probably be
// increased if the user requires it.
diff --git a/effects.cpp b/effects.cpp
index d006941..67f0887 100644
--- a/effects.cpp
+++ b/effects.cpp
@@ -201,7 +201,8 @@ Levels(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, property_c
Assert(&BitmapInfo->Test);
gl_effect_layer Test = BitmapInfo->Test;
- glBindRenderbuffer(GL_RENDERBUFFER, Test.RBO);
+ // glBindRenderbuffer(GL_RENDERBUFFER, Test.RBO);
+ /*
glUseProgram(TGL.ShaderProgram);
int vertexColorLocation = glGetUniformLocation(TGL.ShaderProgram, "Start");
@@ -216,6 +217,7 @@ Levels(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, property_c
glUniform4f(vertexColorLocation, Mid.r, Mid.g, Mid.b, Mid.a);
vertexColorLocation = glGetUniformLocation(TGL.ShaderProgram, "EndCol");
glUniform4f(vertexColorLocation, End.r, End.g, End.b, End.a);
+ */
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
@@ -233,13 +235,15 @@ GaussianBlur(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, prop
real32 Radius = Property[0].CurrentValue.f;
gl_effect_layer *Test = &BitmapInfo->Test;
- glBindRenderbuffer(GL_RENDERBUFFER, Test->RBO);
+ // glBindRenderbuffer(GL_RENDERBUFFER, Test->RBO);
+ /*
glUseProgram(TGL.ShaderProgram);
int vertexColorLocation = glGetUniformLocation(TGL.ShaderProgram, "Radius");
glUniform1f(vertexColorLocation, Radius + 1.60f);
vertexColorLocation = glGetUniformLocation(TGL.ShaderProgram, "Direction");
glUniform2f(vertexColorLocation, 1.0f, 0.0f);
+ */
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
@@ -250,11 +254,13 @@ GaussianBlur(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, prop
glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, &Data[0]);
TestGL_InitTexture(&BitmapInfo->Test, Data, Width, Height);
- glBindRenderbuffer(GL_RENDERBUFFER, Test->RBO);
+ // glBindRenderbuffer(GL_RENDERBUFFER, Test->RBO);
+ /*
glUseProgram(TGL.ShaderProgram);
vertexColorLocation = glGetUniformLocation(TGL.ShaderProgram, "Direction");
glUniform2f(vertexColorLocation, 0.0f, 1.0f);
+ */
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, &Data[0]);
diff --git a/functions.h b/functions.h
index 89f8955..81f18ee 100644
--- a/functions.h
+++ b/functions.h
@@ -23,4 +23,12 @@ static cached_bitmap * AV_LoadVideoFrame(source *Source, memory *Memory, int32 T
static cached_bitmap * Cache_CheckBitmap(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, int32 TimelineFrame);
static void TestGL_InitTexture(gl_effect_layer *Test, void *Data, uint16 Width, uint16 Height);
+static gl_effect TestGL_MaskInitVerts(mask Mask);
+static void TestGL_InitVerts();
+static gl_vertex_shader TestGL_MaskUploadVerts(project_layer *Layer, mask *Mask);
+
+static v2 Line_RatioToPoint(v2 a, v2 b, float ratio);
+static v2 ImGui_ScreenPointToCompUV(ImVec2 ViewportMin, ImVec2 CompPos, ImVec2 CompZoom, ImVec2 MousePos);
+
+void Bezier_CubicCalcPoints(v2 p1, v2 p2, v2 p3, v2 p4, void *Data, uint32 *Increment);
diff --git a/gl_calls.cpp b/gl_calls.cpp
index 85ce0b3..4474b44 100644
--- a/gl_calls.cpp
+++ b/gl_calls.cpp
@@ -1,4 +1,4 @@
-const char *vertexShaderSource = "#version 330 core\n"
+const char *DefaultVertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec2 aTexCoord;\n"
"out vec2 TexCoord;\n"
@@ -7,7 +7,26 @@ const char *vertexShaderSource = "#version 330 core\n"
" gl_Position = vec4(aPos, 1.0);\n"
" TexCoord = aTexCoord;\n"
"}\0";
-
+const char *MaskVertexShaderSource = "#version 330 core\n"
+"layout (location = 0) in vec3 aPos;\n"
+"layout (location = 1) in vec2 aTexCoord;\n"
+"out vec2 TexCoord;\n"
+"uniform vec3 CompDimensions;\n"
+"void main()\n"
+"{\n"
+" gl_Position = vec4(vec2(aPos.x / CompDimensions.x, aPos.y / CompDimensions.y) * 2 - 1.0f, 0.0f, 1.0);\n"
+" TexCoord = aTexCoord;\n"
+"}\0";
+const char *DefaultFragmentShaderSource = "#version 330 core\n"
+"out vec4 FragColor;\n"
+"in vec2 TexCoord;\n"
+"uniform sampler2D Texture;\n"
+"void main()\n"
+"{\n"
+"vec4 ColTest = texture(Texture, TexCoord);\n"
+"ColTest.r += 0.5f;\n"
+"FragColor = ColTest;\n"
+"}\0";
#if 0
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
@@ -30,7 +49,6 @@ const char *fragmentShaderSource = "#version 330 core\n"
"vec4 ValG = 1.0f / (End - Start) * (ColorG - Start);\n"
"FragColor = clamp(ValG, 0.0f, 1.0f);\n"
"}\0";
-#else
const char *fragmentShaderSource = "#version 330 core\n"
"uniform float Radius;\n"
"uniform vec2 Direction;\n"
@@ -57,78 +75,95 @@ const char *fragmentShaderSource = "#version 330 core\n"
#endif
-static void TestGL_InitShader() {
- TGL.VertexShader = glCreateShader(GL_VERTEX_SHADER);
+static void TestGL_InitDefaultShader() {
+ DefaultVertexShader = glCreateShader(GL_VERTEX_SHADER);
- // We have to compile our shaders before executing them.
- glShaderSource(TGL.VertexShader, 1, &vertexShaderSource, NULL);
- glCompileShader(TGL.VertexShader);
+ glShaderSource(DefaultVertexShader, 1, &DefaultVertexShaderSource, NULL);
+ glCompileShader(DefaultVertexShader);
int success;
char infoLog[512];
- glGetShaderiv(TGL.VertexShader, GL_COMPILE_STATUS, &success);
+ glGetShaderiv(DefaultVertexShader, GL_COMPILE_STATUS, &success);
if(!success)
{
- glGetShaderInfoLog(TGL.VertexShader, 512, NULL, infoLog);
+ glGetShaderInfoLog(DefaultVertexShader, 512, NULL, infoLog);
printf("Vertex shader fail:\n %s", infoLog);
}
- TGL.FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+ uint32 DefaultFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
- glShaderSource(TGL.FragmentShader, 1, &fragmentShaderSource, NULL);
- glCompileShader(TGL.FragmentShader);
+ glShaderSource(DefaultFragmentShader, 1, &DefaultFragmentShaderSource, NULL);
+ glCompileShader(DefaultFragmentShader);
- glGetShaderiv(TGL.FragmentShader, GL_COMPILE_STATUS, &success);
+ glGetShaderiv(DefaultFragmentShader, GL_COMPILE_STATUS, &success);
if(!success)
{
- glGetShaderInfoLog(TGL.FragmentShader, 512, NULL, infoLog);
+ glGetShaderInfoLog(DefaultFragmentShader, 512, NULL, infoLog);
printf("Fragment shader fail:\n %s", infoLog);
}
// Shader programs link both types of shaders together.
- TGL.ShaderProgram = glCreateProgram();
+ DefaultShaderProgram = glCreateProgram();
+
+ glAttachShader(DefaultShaderProgram, DefaultVertexShader);
+ glAttachShader(DefaultShaderProgram, DefaultFragmentShader);
+ glLinkProgram(DefaultShaderProgram);
+
+ glGetProgramiv(DefaultShaderProgram, GL_LINK_STATUS, &success);
+ if(!success) {
+ glGetProgramInfoLog(DefaultShaderProgram, 512, NULL, infoLog);
+ printf("Shader linkage fail:\n %s", infoLog);
+ }
+
+ uint32 MaskVertexShader = glCreateShader(GL_VERTEX_SHADER);
- glAttachShader(TGL.ShaderProgram, TGL.VertexShader);
- glAttachShader(TGL.ShaderProgram, TGL.FragmentShader);
- glLinkProgram(TGL.ShaderProgram);
+ glShaderSource(MaskVertexShader, 1, &MaskVertexShaderSource, NULL);
+ glCompileShader(MaskVertexShader);
- glGetProgramiv(TGL.ShaderProgram, GL_LINK_STATUS, &success);
+ glGetShaderiv(MaskVertexShader, GL_COMPILE_STATUS, &success);
if(!success) {
- glGetProgramInfoLog(TGL.ShaderProgram, 512, NULL, infoLog);
+ glGetProgramInfoLog(DefaultShaderProgram, 512, NULL, infoLog);
printf("Shader linkage fail:\n %s", infoLog);
}
- // The shaders are no longer needed by anything once they're linked.
- glDeleteShader(TGL.VertexShader);
- glDeleteShader(TGL.FragmentShader);
+ MaskShaderProgram = glCreateProgram();
+ glAttachShader(MaskShaderProgram, MaskVertexShader);
+ glAttachShader(MaskShaderProgram, DefaultFragmentShader);
+ glLinkProgram(MaskShaderProgram);
+
+ glGetProgramiv(MaskShaderProgram, GL_LINK_STATUS, &success);
+ if(!success) {
+ glGetProgramInfoLog(MaskShaderProgram, 512, NULL, infoLog);
+ printf("Shader linkage fail:\n %s", infoLog);
+ }
+
+ // Default vertex shader is still needed to link to other effects.
+ glDeleteShader(DefaultFragmentShader);
+ glDeleteShader(MaskVertexShader);
}
-static void TestGL_InitVerts() {
+static void TestGL_InitDefaultVerts() {
- float GLVertices[] = {
- 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
- 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
- -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
- -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
- };
unsigned int GLIndices[] = {
0, 1, 3,
1, 2, 3
};
// Indices!
- glGenBuffers(1, &TGL.EBO);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, TGL.EBO);
+ glGenVertexArrays(1, &DefaultVerts.VertexArrayObject);
+
+ glGenBuffers(1, &DefaultVerts.ElementBufferObject);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, DefaultVerts.ElementBufferObject);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLIndices), GLIndices,
GL_STATIC_DRAW);
- glGenBuffers(1, &TGL.VBO);
+ glGenBuffers(1, &DefaultVerts.VertexBufferObject);
// Our vertices need to be stored in this buffer.
- glBindBuffer(GL_ARRAY_BUFFER, TGL.VBO);
- glBufferData(GL_ARRAY_BUFFER, sizeof(GLVertices), GLVertices, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, DefaultVerts.VertexBufferObject);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(DefaultVertices), DefaultVertices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
@@ -150,21 +185,30 @@ TestGL_InitTexture(gl_effect_layer *Test, void *Data, uint16 Width, uint16 Heigh
glViewport(0, 0, Width, Height);
- glGenFramebuffers(1, &Test->FBO);
- glGenRenderbuffers(1, &Test->RBO);
+ glGenFramebuffers(1, &Test->FramebufferObject);
- glBindRenderbuffer(GL_RENDERBUFFER, Test->RBO);
+ glGenRenderbuffers(1, &Test->Color_Renderbuffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, Test->Color_Renderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, Width, Height);
- glBindFramebuffer(GL_FRAMEBUFFER, Test->FBO);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, Test->RBO);
+ GLuint Stencil_Renderbuffer = 0;
+ glGenRenderbuffers(1, &Stencil_Renderbuffer);
+ glBindRenderbuffer( GL_RENDERBUFFER, (GLuint)Stencil_Renderbuffer );
+ glRenderbufferStorage( GL_RENDERBUFFER, GL_STENCIL_INDEX8, Width, Height );
+
+ glBindFramebuffer(GL_FRAMEBUFFER, Test->FramebufferObject);
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, Test->Color_Renderbuffer);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, Stencil_Renderbuffer);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ printf("incomplete framebuffer");
+ Assert(0);
+ }
- // Non-POT textures with RGB instead of RGBA doesn't seem to work, but
- // since I don't plan on storing bitmaps that way (AVX2 is much more
- // efficient with RGBA) it doesn't really matter.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, Data);
- // glGenerateMipmap(GL_TEXTURE_2D);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
diff --git a/main.cpp b/main.cpp
index da67593..84d3559 100644
--- a/main.cpp
+++ b/main.cpp
@@ -62,6 +62,7 @@ SDL_sem *Semaphore;
#include "keyframes.cpp"
#include "layer.cpp"
#include "strings.cpp"
+#include "bezier.cpp"
#if THREADED
#include "threading.cpp"
#else
@@ -227,6 +228,7 @@ int main(int argc, char *argv[]) {
InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_AVInfo, "Image/video headers");
InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_SourceBitmapTable, "Source bitmap tables");
+ InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_VectorPoints, "Vector Points");
InitMemoryTable(&GlobalMemory, &Memory, 10 * 1024 * 1024, P_MiscCache, "Misc cache");
InitMemoryTable(&GlobalMemory, &Memory, 15 * 1024 * 1024, F_Layers, "Layers");
@@ -378,8 +380,8 @@ int main(int argc, char *argv[]) {
return -1;
}
- TestGL_InitShader();
- TestGL_InitVerts();
+ TestGL_InitDefaultShader();
+ TestGL_InitDefaultVerts();
LoadTestFootage(&File, &State, &Memory);
diff --git a/main.h b/main.h
index 8a6c7ca..e77042f 100644
--- a/main.h
+++ b/main.h
@@ -30,6 +30,7 @@ enum memory_table_list {
P_AVInfo,
P_SourceBitmapTable,
+ P_VectorPoints,
P_MiscCache, // don't put this in final
F_Layers,
@@ -127,23 +128,39 @@ enum blend_mode
blend_difference
};
-struct gl_vertex_shader {
-};
struct gl_effect {
- uint32 FragmentShader;
uint32 ShaderProgram;
- uint32 VertexShader;
- uint32 EBO;
- uint32 VBO;
};
-static gl_effect TGL;
+struct gl_vertex_shader {
+ uint32 VertexArrayObject;
+ uint32 VertexBufferObject;
+};
+
+struct default_gl_vertex_object {
+ uint32 VertexArrayObject;
+ uint32 VertexBufferObject;
+ uint32 ElementBufferObject;
+};
+
+static default_gl_vertex_object DefaultVerts;
+static uint32 DefaultVertexShader;
+static uint32 DefaultShaderProgram;
+static uint32 MaskShaderProgram;
+
+float DefaultVertices[] = {
+ 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
+ -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
+ -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
+};
+
struct gl_effect_layer {
GLuint Texture;
- GLuint FBO;
- GLuint RBO;
+ GLuint FramebufferObject;
+ uint32 Color_Renderbuffer;
};
static gl_vertex_shader GL_Vertices;
@@ -313,6 +330,8 @@ struct mask_point {
struct mask {
mask_point Point[16];
uint16 NumberOfPoints;
+ void *TriangulatedPointCache;
+ uint32 NumberOfVerts;
};
struct project_layer {
diff --git a/my_imgui_internal_widgets.cpp b/my_imgui_internal_widgets.cpp
index c654e36..705b898 100644
--- a/my_imgui_internal_widgets.cpp
+++ b/my_imgui_internal_widgets.cpp
@@ -164,95 +164,44 @@ bool ImGui::TestLine(ImVec2 p0, ImVec2 p1)
return Toggle;
}
-// Slightly modified version of the bezier closest point lookup code that
-// additionally outputs the ratio of the closest point along the curve for use
-// in constructing the handles of new points.
+// Currently not used anywhere outside of debug UI. I'll keep it in case
+// there's a place where doing this operation in UI space is useful. Note that
+// the version of this function in bezier.cpp differs in precision by about
+// 0.001.
-
-// The ratio here is just the dot product divided by the squared length.
-ImVec2 ImLineClosestPoint2(const ImVec2& a, const ImVec2& b, const ImVec2& p, float& ratio)
+ImVec2 ImGui::RatioToPoint(ImVec2 a, ImVec2 b, float ratio)
{
- ImVec2 ap = p - a;
ImVec2 ab_dir = b - a;
- float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
- if (dot < 0.0f) {
- ratio = 0.0f;
- return a;
- }
float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
- if (dot > ab_len_sqr) {
- ratio = 1.0f;
- return b;
- }
- ratio = dot / ab_len_sqr;
+ float dot = ratio*ab_len_sqr;
return a + ab_dir * dot / ab_len_sqr;
}
-// Function to convert a ratio back into a point for the bezier handles.
-ImVec2 ImGui::RatioToPoint(const ImVec2& a, const ImVec2& b, float ratio)
+// Returns true when cursor is close to the curve but not too close to the
+// beginning/end points. Basically just a wrapper for that ClosestPoint
+// function.
+bool ImGui::BezierInteractive(ImVec2 p0, ImVec2 p1, ImVec2 p2, ImVec2 p3)
{
- ImVec2 ab_dir = b - a;
- float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
- float dot = ratio*ab_len_sqr;
- return a + ab_dir * dot / ab_len_sqr;
-}
+ bool hovered = false;
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = GetCurrentWindow();
+ if (window->SkipItems)
+ return false;
-// 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.
-// The pow(0.5, level) represents the ratio of the next subdivision's leftmost
-// point (AKA the rightmost point of the current subdivision).
+ ImVec2 point = ImBezierCubicClosestPointCasteljau(p0, p1, p2, p3, g.IO.MousePos, GetStyle().CurveTessellationTol);
-static void ImBezierCubicClosestPointCasteljauStep2(const ImVec2& p, ImVec2& p_closest, float ratio, float& r_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
-{
- float dx = x4 - x1;
- float dy = y4 - y1;
- float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
- float 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))
- {
- ImVec2 p_current(x4, y4);
- float added_ratio;
- ImVec2 p_line = ImLineClosestPoint2(p_last, p_current, p, added_ratio);
- float dist2 = ImLengthSqr(p - p_line);
- if (dist2 < p_closest_dist2)
- {
- p_closest = p_line;
- p_closest_dist2 = dist2;
- r_closest = ratio + pow(0.5, level)*added_ratio;
- }
- p_last = p_current;
- }
- else if (level < 10)
+ if (abs(g.IO.MousePos.x - point.x) < 3 && abs(g.IO.MousePos.y - point.y) < 3 &&
+ abs(p0.x - point.x) > 3 && abs(p0.y - point.y) > 3 &&
+ abs(p1.x - point.x) > 3 && abs(p1.y - point.y) > 3)
{
- float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f;
- float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f;
- float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f;
- float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f;
- float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f;
- float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
- ImBezierCubicClosestPointCasteljauStep2(p, p_closest, ratio, r_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
- ImBezierCubicClosestPointCasteljauStep2(p, p_closest, ratio + pow(0.5, level+1), r_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
+ hovered = true;
}
-}
-ImVec2 ImBezierCubicClosestPointCasteljau2(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float& ratio, float tess_tol)
-{
- IM_ASSERT(tess_tol > 0.0f);
- ImVec2 p_last = p1;
- ImVec2 p_closest;
- float p_closest_dist2 = FLT_MAX;
- float r_closest;
- ImBezierCubicClosestPointCasteljauStep2(p, p_closest, 0, r_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);
- ratio = r_closest;
- return p_closest;
+ return hovered;
}
-// Returns true when cursor is close to the curve but not too close to the beginning/end points.
-bool ImGui::BezierInteractive(ImVec2 p0, ImVec2 p1, ImVec2 p2, ImVec2 p3, float& ratio)
+bool ImGui::LineInteractive(ImVec2 p0, ImVec2 p1)
{
bool hovered = false;
@@ -261,21 +210,14 @@ bool ImGui::BezierInteractive(ImVec2 p0, ImVec2 p1, ImVec2 p2, ImVec2 p3, float&
if (window->SkipItems)
return false;
- ImDrawList* draw_list = window->DrawList;
- ImU32 col = ImGui::GetColorU32(ImGuiCol_ScrollbarGrab);
-
- ImVec2 point = ImBezierCubicClosestPointCasteljau2(p0, p1, p2, p3, g.IO.MousePos, ratio, GetStyle().CurveTessellationTol);
-
+ ImVec2 point = ImLineClosestPoint(p0, p1, g.IO.MousePos);
if (abs(g.IO.MousePos.x - point.x) < 3 && abs(g.IO.MousePos.y - point.y) < 3 &&
abs(p0.x - point.x) > 3 && abs(p0.y - point.y) > 3 &&
abs(p1.x - point.x) > 3 && abs(p1.y - point.y) > 3)
{
- col = GetColorU32(ImGuiCol_Button);
hovered = true;
}
- draw_list->AddBezierCubic(p0, p1, p2, p3, col, 2.0f, 0);
-
return hovered;
}
diff --git a/my_imgui_internal_widgets.h b/my_imgui_internal_widgets.h
index 1e0a212..52fdc74 100644
--- a/my_imgui_internal_widgets.h
+++ b/my_imgui_internal_widgets.h
@@ -8,7 +8,8 @@
namespace ImGui {
IMGUI_API bool SliderLevels(const char* label, const char* label2, const char* label3, void* p_data, void* p_min, void* p_max);
IMGUI_API bool TestLine(ImVec2 P1, ImVec2 P2);
- IMGUI_API bool BezierInteractive(ImVec2 p0, ImVec2 p1, ImVec2 p2, ImVec2 p3, float& ratio);
- IMGUI_API ImVec2 RatioToPoint(const ImVec2& a, const ImVec2& b, float ratio);
+ IMGUI_API bool BezierInteractive(ImVec2 p0, ImVec2 p1, ImVec2 p2, ImVec2 p3);
+ IMGUI_API bool LineInteractive(ImVec2 p0, ImVec2 p1);
+ IMGUI_API ImVec2 RatioToPoint(ImVec2 a, ImVec2 b, float ratio);
}
diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp
index 6f785de..e334f63 100644
--- a/my_imgui_widgets.cpp
+++ b/my_imgui_widgets.cpp
@@ -71,14 +71,14 @@ ImGui_KeyframeDragging(project_data *File, project_state *State, ui *UI, propert
}
// Returns a normalized UV position of the composition
-static ImVec2
+static v2
ImGui_ScreenPointToCompUV(ImVec2 ViewportMin, ImVec2 CompPos, ImVec2 CompZoom, ImVec2 MousePos)
{
ImVec2 LocalMousePos = MousePos - ViewportMin;
ImVec2 LocalCompPos = CompPos - ViewportMin;
ImVec2 MouseScreenUV = LocalMousePos - LocalCompPos;
ImVec2 Result = MouseScreenUV / CompZoom;
- return Result;
+ return V2(Result);
}
static void
@@ -391,21 +391,24 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer Comp
if (p+1 == Mask->NumberOfPoints)
Point1 = &Mask->Point[0];
- ImVec2 Point0_Pos = ImVec2(Point0->Pos.x, Point0->Pos.y);
- ImVec2 Point0_Pos_Left = Point0_Pos + ImVec2(Point0->TangentLeft.x, Point0->TangentLeft.y);
- ImVec2 Point0_Pos_Right = Point0_Pos + ImVec2(Point0->TangentRight.x, Point0->TangentRight.y);
+ // NOTE(fox): I want to keep operations in local space under the v2 data
+ // type and operations in screen space under ImVec2.
+
+ v2 Point0_Pos = Point0->Pos;
+ v2 Point0_Pos_Left = Point0_Pos + Point0->TangentLeft;
+ v2 Point0_Pos_Right = Point0_Pos + Point0->TangentRight;
- ImVec2 Point1_Pos = ImVec2(Point1->Pos.x, Point1->Pos.y);
- ImVec2 Point1_Pos_Left = Point1_Pos + ImVec2(Point1->TangentLeft.x, Point1->TangentLeft.y);
- ImVec2 Point1_Pos_Right = Point1_Pos + ImVec2(Point1->TangentRight.x, Point1->TangentRight.y);
+ v2 Point1_Pos = Point1->Pos;
+ v2 Point1_Pos_Left = Point1_Pos + Point1->TangentLeft;
+ v2 Point1_Pos_Right = Point1_Pos + Point1->TangentRight;
- ImVec2 Point0_ScreenPos = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, V2(Point0_Pos));
- ImVec2 Point0_ScreenPos_Left = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, V2(Point0_Pos_Left));
- ImVec2 Point0_ScreenPos_Right = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, V2(Point0_Pos_Right));
+ ImVec2 Point0_ScreenPos = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, Point0_Pos);
+ ImVec2 Point0_ScreenPos_Left = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, Point0_Pos_Left);
+ ImVec2 Point0_ScreenPos_Right = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, Point0_Pos_Right);
- ImVec2 Point1_ScreenPos = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, V2(Point1_Pos));
- ImVec2 Point1_ScreenPos_Left = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, V2(Point1_Pos_Left));
- ImVec2 Point1_ScreenPos_Right = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, V2(Point1_Pos_Right));
+ ImVec2 Point1_ScreenPos = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, Point1_Pos);
+ ImVec2 Point1_ScreenPos_Left = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, Point1_Pos_Left);
+ ImVec2 Point1_ScreenPos_Right = Layer_LocalToScreenSpace(Layer, UI, CompBuffer, Point1_Pos_Right);
ImGui::PushID(p);
@@ -414,15 +417,19 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer Comp
// The handle itself
draw_list->AddNgon(Point0_ScreenPos, 10, col, 8, 5.0f);
- draw_list->AddNgon(Point0_ScreenPos_Left, 10, col, 8, 5.0f);
- draw_list->AddNgon(Point0_ScreenPos_Right, 10, col, 8, 5.0f);
- draw_list->AddLine(Point0_ScreenPos, Point0_ScreenPos_Left, col, 2.0f);
- draw_list->AddLine(Point0_ScreenPos, Point0_ScreenPos_Right, col, 2.0f);
+ // draw_list->AddNgon(Point0_ScreenPos_Left, 10, col, 8, 5.0f);
+ // draw_list->AddNgon(Point0_ScreenPos_Right, 10, col, 8, 5.0f);
+ // draw_list->AddLine(Point0_ScreenPos, Point0_ScreenPos_Left, col, 2.0f);
+ // draw_list->AddLine(Point0_ScreenPos, Point0_ScreenPos_Right, col, 2.0f);
- ImU32 col2 = ImGui::GetColorU32(ImGuiCol_Button);
+ int max = 1;
- for (int b = 0; b < 3; b++)
+ if (Point0->HandleBezier) {
+ max = 3;
+ }
+
+ for (int b = 0; b < max; b++)
{
ImGui::PushID(b);
if (b == 0) {
@@ -462,11 +469,11 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer Comp
Point0->TangentRight.x -= YAxis.x;
Point0->TangentRight.y += YAxis.y;
}
+ State->UpdateFrame = true;
}
ImGui::PopID();
}
-
// The bezier path
if (Mask->NumberOfPoints == 1) {
@@ -474,49 +481,63 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer Comp
continue;
}
- // Ratio of the point along the curve. See internal for more info.
- float ratio;
+ ImU32 col2 = ImGui::GetColorU32(ImGuiCol_Button);
- if (ImGui::BezierInteractive(Point0_ScreenPos, Point0_ScreenPos_Right,
- Point1_ScreenPos_Left, Point1_ScreenPos, ratio) &&
- State->Tool == tool_pen)
- {
- // Using a button like this may be kinda janky, but it gives us access
- // to all of ButtonBehavior and the ID system without having to rewrite it.
- ImGui::SetCursorScreenPos(io.MousePos - ImVec2(5,5));
- ImGui::Button("maskbezier", ImVec2(10, 10));
-
- if(ImGui::IsItemHovered()) {
- // ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll);
- draw_list->AddNgon(io.MousePos, 2, col, 8, 5.0f);
- ImVec2 RatioLeft = ImGui::RatioToPoint(Point0_ScreenPos, Point0_ScreenPos_Right, ratio);
- ImVec2 RatioTop = ImGui::RatioToPoint(Point0_ScreenPos_Right, Point1_ScreenPos_Left, ratio);
- ImVec2 RatioRight = ImGui::RatioToPoint(Point1_ScreenPos_Left, Point1_ScreenPos, ratio);
- ImVec2 TangentLeft = ImGui::RatioToPoint(RatioLeft, RatioTop, ratio);
- ImVec2 TangentRight = ImGui::RatioToPoint(RatioTop, RatioRight, ratio);
- draw_list->AddLine(RatioLeft, RatioTop, col, 2.0f);
- draw_list->AddLine(RatioRight, RatioTop, col, 2.0f);
- draw_list->AddLine(TangentLeft, TangentRight, col, 2.0f);
- }
- if(ImGui::IsItemActivated() && io.KeyCtrl) {
- ImVec2 Ratio0 = ImGui::RatioToPoint(Point0_Pos, Point0_Pos_Right, ratio);
- ImVec2 RatioTop = ImGui::RatioToPoint(Point0_Pos_Right, Point1_Pos_Left, ratio);
- ImVec2 Ratio1 = ImGui::RatioToPoint(Point1_Pos_Left, Point1_Pos, ratio);
- ImVec2 TangentLeft = ImGui::RatioToPoint(Ratio0, RatioTop, ratio);
- ImVec2 TangentRight = ImGui::RatioToPoint(RatioTop, Ratio1, ratio);
- ImVec2 Point = ImGui::RatioToPoint(TangentLeft, TangentRight, ratio);
- Mask_AddPointToCurve(Mask, Point, Point - TangentLeft, Point - TangentRight,
- Point0_Pos - Ratio0, Point1_Pos - Ratio1, p);
- }
+ if (Point0->HandleBezier || Point1->HandleBezier) {
+ draw_list->AddBezierCubic(Point0_ScreenPos, Point0_ScreenPos_Right,
+ Point1_ScreenPos_Left, Point1_ScreenPos, col2, 6.0f, 0);
+ } else {
+ draw_list->AddLine(Point0_ScreenPos, Point1_ScreenPos, col2, 6.0f);
}
- // DebugWatchVar("ratio", &ratio, d_float);
-
- // if (ImGui::TestLine(PointScreenPos[0], PointScreenPos[1])) {
- // }
+ if (Point0->HandleBezier && Point1->HandleBezier) {
+ if (ImGui::BezierInteractive(Point0_ScreenPos, Point0_ScreenPos_Right,
+ Point1_ScreenPos_Left, Point1_ScreenPos) &&
+ State->Tool == tool_pen)
+ {
+ // Using a button like this may be kinda janky, but it gives us access
+ // to all of ButtonBehavior and the ID system without having to write on top of ImGui's.
+ ImGui::SetCursorScreenPos(io.MousePos - ImVec2(5,5));
+ ImGui::Button("maskbezier", ImVec2(10, 10));
+ if (ImGui::IsItemHovered()) {
+#if DEBUG
+ v2 LayerPoint = Layer_ScreenSpaceToLocal(Layer, UI, CompBuffer, ViewportMin, io.MousePos);
+ real32 ratio = Bezier_CubicRatioOfPoint(Point0_Pos, Point0_Pos_Right, Point1_Pos_Left, Point1_Pos, LayerPoint);
+ draw_list->AddNgon(io.MousePos, 2, col, 8, 5.0f);
+ ImVec2 RatioLeft = ImGui::RatioToPoint(Point0_ScreenPos, Point0_ScreenPos_Right, ratio);
+ ImVec2 RatioRight = ImGui::RatioToPoint(Point1_ScreenPos_Left, Point1_ScreenPos, ratio);
+ ImVec2 RatioTop = ImGui::RatioToPoint(Point0_ScreenPos_Right, Point1_ScreenPos_Left, ratio);
+ ImVec2 TangentLeft = ImGui::RatioToPoint(RatioLeft, RatioTop, ratio);
+ ImVec2 TangentRight = ImGui::RatioToPoint(RatioTop, RatioRight, ratio);
+ draw_list->AddLine(RatioLeft, RatioTop, col, 2.0f);
+ draw_list->AddLine(RatioRight, RatioTop, col, 2.0f);
+ draw_list->AddLine(TangentLeft, TangentRight, col, 2.0f);
+#endif
+ }
+ if (ImGui::IsItemActivated() && io.KeyCtrl) {
+ v2 LayerPoint = Layer_ScreenSpaceToLocal(Layer, UI, CompBuffer, ViewportMin, io.MousePos);
+ real32 ratio = Bezier_CubicRatioOfPoint(Point0_Pos, Point0_Pos_Right, Point1_Pos_Left, Point1_Pos, LayerPoint);
+ Mask_AddPointToCurve(Mask, p, ratio);
+ }
+ }
+ } else {
+ if (ImGui::LineInteractive(Point0_ScreenPos, Point1_ScreenPos) &&
+ State->Tool == tool_pen)
+ {
+ ImGui::SetCursorScreenPos(io.MousePos - ImVec2(5,5));
+ ImGui::Button("maskline", ImVec2(10, 10));
+ if (ImGui::IsItemHovered()) {
+ draw_list->AddNgon(io.MousePos, 2, col, 8, 5.0f);
+ }
+ if (ImGui::IsItemActivated() && io.KeyCtrl) {
+ v2 LayerPoint = Layer_ScreenSpaceToLocal(Layer, UI, CompBuffer, ViewportMin, io.MousePos);
+ Mask_AddPointToLine(Mask, p, LayerPoint);
+ }
+ }
+ }
ImGui::PopID();
}
ImGui::PopID();
@@ -543,6 +564,7 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer Comp
bool32 IsActive = ImGui::IsItemActive();
bool32 IsActivated = ImGui::IsItemActivated();
+ /*
if (State->MostRecentlySelectedLayer > -1)
{
project_layer *Layer = File.Layer[State->MostRecentlySelectedLayer];
@@ -555,15 +577,13 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer Comp
if (State->Pen.IsActive && !ImGui::IsKeyDown(ImGuiKey_Z)) {
if (IsActivated) {
- v2 CompUV = V2(ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos));
- v2 LayerUV = CompUVToLayerUV(Layer, &CompBuffer, CompUV);
- v2 LayerPos = LayerUV * V2(Layer->Source->Info.Width, Layer->Source->Info.Height);
+ v2 LayerPos = Layer_ScreenSpaceToLocal(Layer, UI, CompBuffer, ViewportMin, io.MousePos);
Mask_PushPoint(&Layer->Mask[Layer->NumberOfMasks-1], LayerPos);
}
if (IsActive) {
mask *Mask = &Layer->Mask[Layer->NumberOfMasks-1];
mask_point *CurrentPoint = &Mask->Point[Mask->NumberOfPoints-1];
- v2 CompUV = V2(ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos));
+ v2 CompUV = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos);
v2 LayerUV = CompUVToLayerUV(Layer, &CompBuffer, CompUV);
v2 LayerPos = LayerUV * V2(Layer->Source->Info.Width, Layer->Source->Info.Height);
v2 OffsetPos = CurrentPoint->Pos - LayerPos;
@@ -575,11 +595,12 @@ ImGui_Viewport(project_data File, project_state *State, ui *UI, comp_buffer Comp
}
}
}
+ */
if (IsHovered && IsActivated && ImGui::IsMouseDown(ImGuiMouseButton_Left))
{
// Point to zoom in on if Z is held
- UI->TempZoomRatio = V2(ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos));
+ UI->TempZoomRatio = ImGui_ScreenPointToCompUV(ViewportMin, UI->CompPos, UI->CompZoom, io.MousePos);
DebugWatchVar("MouseScreenUV", &UI->TempZoomRatio.x, d_float);
DebugWatchVar("MouseScreenUV", &UI->TempZoomRatio.y, d_float);
diff --git a/my_math.h b/my_math.h
index b95e71d..cf491f1 100644
--- a/my_math.h
+++ b/my_math.h
@@ -46,6 +46,16 @@ inline v2 V2(real32 x, real32 y)
return(Result);
}
+inline v2 V2(real32 x)
+{
+ v2 Result;
+
+ Result.x = x;
+ Result.y = x;
+
+ return(Result);
+}
+
inline v2 V2(ImVec2 A)
{
v2 Result;
@@ -186,6 +196,18 @@ v2i operator+(v2i A, v2i B)
return(Result);
}
+v2 operator/(v2 A, real32 B)
+{
+ v2 Result;
+
+ Result.x = A.x / B;
+ Result.y = A.y / B;
+
+ return Result;
+}
+
+
+
v4 operator+(v4 A, v4 B)
{
v4 Result;