[wip, win32, canvas] quadratics
This commit is contained in:
parent
899ad4c030
commit
01aa4f838f
|
@ -117,16 +117,18 @@ int main()
|
||||||
mg_set_color_rgba(0, 1, 0, 1);
|
mg_set_color_rgba(0, 1, 0, 1);
|
||||||
mg_fill();
|
mg_fill();
|
||||||
|
|
||||||
mg_set_color_rgba(0, 1, 1, 1);
|
mg_set_color_rgba(0, 1, 1, 0.5);
|
||||||
mg_rectangle_fill(120, 120, 200, 200);
|
mg_rectangle_fill(120, 120, 200, 200);
|
||||||
|
|
||||||
/*
|
mg_set_color_rgba(1, 0, 0.5, 1);
|
||||||
mg_move_to(400, 400);
|
mg_rectangle_fill(700, 500, 200, 200);
|
||||||
mg_quadratic_to(600, 601, 800, 400);
|
|
||||||
|
mg_move_to(300, 300);
|
||||||
|
mg_quadratic_to(400, 500, 500, 300);
|
||||||
mg_close_path();
|
mg_close_path();
|
||||||
mg_set_color_rgba(0, 0, 1, 1);
|
mg_set_color_rgba(0, 0, 1, 1);
|
||||||
mg_fill();
|
mg_fill();
|
||||||
|
/*
|
||||||
mg_move_to(2*400, 2*400);
|
mg_move_to(2*400, 2*400);
|
||||||
mg_cubic_to(2*400, 2*200, 2*600, 2*500, 2*600, 2*400);
|
mg_cubic_to(2*400, 2*200, 2*600, 2*500, 2*600, 2*400);
|
||||||
mg_close_path();
|
mg_close_path();
|
||||||
|
|
|
@ -72,3 +72,99 @@ struct mg_gl_tile_queue
|
||||||
int first;
|
int first;
|
||||||
int last;
|
int last;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
float ccw(vec2 a, vec2 b, vec2 c)
|
||||||
|
{
|
||||||
|
return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
|
||||||
|
}
|
||||||
|
|
||||||
|
int side_of_segment(vec2 p, mg_gl_segment seg)
|
||||||
|
{
|
||||||
|
int side = 0;
|
||||||
|
if(p.y > seg.box.w || p.y <= seg.box.y)
|
||||||
|
{
|
||||||
|
if(p.x > seg.box.x && p.x <= seg.box.z)
|
||||||
|
{
|
||||||
|
if(p.y > seg.box.w)
|
||||||
|
{
|
||||||
|
side = (seg.config == MG_GL_TL || seg.config == MG_GL_BR)? -1 : 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
side = (seg.config == MG_GL_TL || seg.config == MG_GL_BR)? 1 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(p.x > seg.box.z)
|
||||||
|
{
|
||||||
|
side = 1;
|
||||||
|
}
|
||||||
|
else if(p.x <= seg.box.x)
|
||||||
|
{
|
||||||
|
side = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vec2 a, b, c;
|
||||||
|
switch(seg.config)
|
||||||
|
{
|
||||||
|
case MG_GL_TL:
|
||||||
|
a = seg.box.xy;
|
||||||
|
b = seg.box.zw;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MG_GL_BR:
|
||||||
|
a = seg.box.zw;
|
||||||
|
b = seg.box.xy;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MG_GL_TR:
|
||||||
|
a = seg.box.xw;
|
||||||
|
b = seg.box.zy;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MG_GL_BL:
|
||||||
|
a = seg.box.zy;
|
||||||
|
b = seg.box.xw;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c = seg.hullVertex;
|
||||||
|
|
||||||
|
if(ccw(a, b, p) < 0)
|
||||||
|
{
|
||||||
|
// other side of the diagonal
|
||||||
|
side = (seg.config == MG_GL_BR || seg.config == MG_GL_TR) ? -1 : 1;
|
||||||
|
}
|
||||||
|
else if(ccw(b, c, p) < 0 || ccw(c, a, p) < 0)
|
||||||
|
{
|
||||||
|
// same side of the diagonal, but outside curve hull
|
||||||
|
side = (seg.config == MG_GL_BL || seg.config == MG_GL_TL) ? -1 : 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// inside curve hull
|
||||||
|
switch(seg.kind)
|
||||||
|
{
|
||||||
|
case MG_GL_LINE:
|
||||||
|
side = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MG_GL_QUADRATIC:
|
||||||
|
{
|
||||||
|
vec3 ph = {p.x, p.y, 1};
|
||||||
|
vec3 klm = seg.implicitMatrix * ph;
|
||||||
|
side = ((klm.x*klm.x - klm.y)*klm.z < 0)? -1 : 1;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case MG_GL_CUBIC:
|
||||||
|
{
|
||||||
|
vec3 ph = {p.x, p.y, 1};
|
||||||
|
vec3 klm = seg.implicitMatrix * ph;
|
||||||
|
side = (seg.sign*(klm.x*klm.x*klm.x - klm.y*klm.z) < 0)? -1 : 1;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(side);
|
||||||
|
}
|
||||||
|
|
|
@ -33,101 +33,6 @@ layout(location = 0) uniform float scale;
|
||||||
|
|
||||||
layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;
|
layout(rgba8, binding = 0) uniform restrict writeonly image2D outTexture;
|
||||||
|
|
||||||
float ccw(vec2 a, vec2 b, vec2 c)
|
|
||||||
{
|
|
||||||
return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
|
|
||||||
}
|
|
||||||
|
|
||||||
int side_of_segment(vec2 p, mg_gl_segment seg)
|
|
||||||
{
|
|
||||||
int side = 0;
|
|
||||||
if(p.y > seg.box.w || p.y <= seg.box.y)
|
|
||||||
{
|
|
||||||
if(p.x > seg.box.x && p.x <= seg.box.z)
|
|
||||||
{
|
|
||||||
if(p.y > seg.box.w)
|
|
||||||
{
|
|
||||||
side = (seg.config == MG_GL_TL || seg.config == MG_GL_BR)? -1 : 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
side = (seg.config == MG_GL_TL || seg.config == MG_GL_BR)? 1 : -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(p.x > seg.box.z)
|
|
||||||
{
|
|
||||||
side = 1;
|
|
||||||
}
|
|
||||||
else if(p.x <= seg.box.x)
|
|
||||||
{
|
|
||||||
side = -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vec2 a, b, c;
|
|
||||||
switch(seg.config)
|
|
||||||
{
|
|
||||||
case MG_GL_TL:
|
|
||||||
a = seg.box.xy;
|
|
||||||
b = seg.box.zw;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MG_GL_BR:
|
|
||||||
a = seg.box.zw;
|
|
||||||
b = seg.box.xy;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MG_GL_TR:
|
|
||||||
a = seg.box.xw;
|
|
||||||
b = seg.box.zy;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MG_GL_BL:
|
|
||||||
a = seg.box.zy;
|
|
||||||
b = seg.box.xw;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
c = seg.hullVertex;
|
|
||||||
|
|
||||||
if(ccw(a, b, p) < 0)
|
|
||||||
{
|
|
||||||
// other side of the diagonal
|
|
||||||
side = (seg.config == MG_GL_BR || seg.config == MG_GL_TR) ? -1 : 1;
|
|
||||||
}
|
|
||||||
else if(ccw(b, c, p) < 0 || ccw(c, a, p) < 0)
|
|
||||||
{
|
|
||||||
// same side of the diagonal, but outside curve hull
|
|
||||||
side = (seg.config == MG_GL_BL || seg.config == MG_GL_TL) ? -1 : 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// inside curve hull
|
|
||||||
switch(seg.kind)
|
|
||||||
{
|
|
||||||
case MG_GL_LINE:
|
|
||||||
side = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MG_GL_QUADRATIC:
|
|
||||||
{
|
|
||||||
vec3 ph = {p.x, p.y, 1};
|
|
||||||
vec3 klm = seg.implicitMatrix * ph;
|
|
||||||
side = ((klm.x*klm.x - klm.y)*klm.z < 0)? -1 : 1;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case MG_GL_CUBIC:
|
|
||||||
{
|
|
||||||
vec3 ph = {p.x, p.y, 1};
|
|
||||||
vec3 klm = seg.implicitMatrix * ph;
|
|
||||||
side = (seg.sign*(klm.x*klm.x*klm.x - klm.y*klm.z) < 0)? -1 : 1;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(side);
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
uvec2 nTiles = gl_NumWorkGroups.xy;
|
uvec2 nTiles = gl_NumWorkGroups.xy;
|
||||||
|
|
|
@ -42,161 +42,6 @@ layout(binding = 6) restrict buffer tileOpBufferSSBO
|
||||||
layout(location = 0) uniform float scale;
|
layout(location = 0) uniform float scale;
|
||||||
layout(location = 1) uniform uint tileSize;
|
layout(location = 1) uniform uint tileSize;
|
||||||
|
|
||||||
int push_segment(in vec2 p[4], int kind, int pathIndex)
|
|
||||||
{
|
|
||||||
int segIndex = atomicAdd(segmentCountBuffer.elements[0], 1);
|
|
||||||
|
|
||||||
vec2 s = p[0];
|
|
||||||
vec2 c = p[0];
|
|
||||||
vec2 e = p[1];
|
|
||||||
|
|
||||||
bool goingUp = e.y >= s.y;
|
|
||||||
bool goingRight = e.x >= s.x;
|
|
||||||
|
|
||||||
vec4 box = vec4(min(s.x, e.x),
|
|
||||||
min(s.y, e.y),
|
|
||||||
max(s.x, e.x),
|
|
||||||
max(s.y, e.y));
|
|
||||||
|
|
||||||
segmentBuffer.elements[segIndex].kind = kind;
|
|
||||||
segmentBuffer.elements[segIndex].pathIndex = pathIndex;
|
|
||||||
segmentBuffer.elements[segIndex].windingIncrement = goingUp ? 1 : -1;
|
|
||||||
segmentBuffer.elements[segIndex].box = box;
|
|
||||||
|
|
||||||
float dx = c.x - box.x;
|
|
||||||
float dy = c.y - box.y;
|
|
||||||
float alpha = (box.w - box.y)/(box.z - box.x);
|
|
||||||
float ofs = box.w - box.y;
|
|
||||||
|
|
||||||
if(goingUp == goingRight)
|
|
||||||
{
|
|
||||||
if(kind == MG_GL_LINE)
|
|
||||||
{
|
|
||||||
segmentBuffer.elements[segIndex].config = MG_GL_BR;
|
|
||||||
}
|
|
||||||
else if(dy > alpha*dx)
|
|
||||||
{
|
|
||||||
segmentBuffer.elements[segIndex].config = MG_GL_TL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
segmentBuffer.elements[segIndex].config = MG_GL_BR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(kind == MG_GL_LINE)
|
|
||||||
{
|
|
||||||
segmentBuffer.elements[segIndex].config = MG_GL_TR;
|
|
||||||
}
|
|
||||||
else if(dy < ofs - alpha*dx)
|
|
||||||
{
|
|
||||||
segmentBuffer.elements[segIndex].config = MG_GL_BL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
segmentBuffer.elements[segIndex].config = MG_GL_TR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return(segIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
float ccw(vec2 a, vec2 b, vec2 c)
|
|
||||||
{
|
|
||||||
return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
|
|
||||||
}
|
|
||||||
|
|
||||||
int side_of_segment(vec2 p, mg_gl_segment seg)
|
|
||||||
{
|
|
||||||
int side = 0;
|
|
||||||
if(p.y > seg.box.w || p.y <= seg.box.y)
|
|
||||||
{
|
|
||||||
if(p.x > seg.box.x && p.x <= seg.box.z)
|
|
||||||
{
|
|
||||||
if(p.y > seg.box.w)
|
|
||||||
{
|
|
||||||
side = (seg.config == MG_GL_TL || seg.config == MG_GL_BR)? -1 : 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
side = (seg.config == MG_GL_TL || seg.config == MG_GL_BR)? 1 : -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(p.x > seg.box.z)
|
|
||||||
{
|
|
||||||
side = 1;
|
|
||||||
}
|
|
||||||
else if(p.x <= seg.box.x)
|
|
||||||
{
|
|
||||||
side = -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vec2 a, b, c;
|
|
||||||
switch(seg.config)
|
|
||||||
{
|
|
||||||
case MG_GL_TL:
|
|
||||||
a = seg.box.xy;
|
|
||||||
b = seg.box.zw;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MG_GL_BR:
|
|
||||||
a = seg.box.zw;
|
|
||||||
b = seg.box.xy;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MG_GL_TR:
|
|
||||||
a = seg.box.xw;
|
|
||||||
b = seg.box.zy;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MG_GL_BL:
|
|
||||||
a = seg.box.zy;
|
|
||||||
b = seg.box.xw;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
c = seg.hullVertex;
|
|
||||||
|
|
||||||
if(ccw(a, b, p) < 0)
|
|
||||||
{
|
|
||||||
// other side of the diagonal
|
|
||||||
side = (seg.config == MG_GL_BR || seg.config == MG_GL_TR) ? -1 : 1;
|
|
||||||
}
|
|
||||||
else if(ccw(b, c, p) < 0 || ccw(c, a, p) < 0)
|
|
||||||
{
|
|
||||||
// same side of the diagonal, but outside curve hull
|
|
||||||
side = (seg.config == MG_GL_BL || seg.config == MG_GL_TL) ? -1 : 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// inside curve hull
|
|
||||||
switch(seg.kind)
|
|
||||||
{
|
|
||||||
case MG_GL_LINE:
|
|
||||||
side = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MG_GL_QUADRATIC:
|
|
||||||
{
|
|
||||||
vec3 ph = {p.x, p.y, 1};
|
|
||||||
vec3 klm = seg.implicitMatrix * ph;
|
|
||||||
side = ((klm.x*klm.x - klm.y)*klm.z < 0)? -1 : 1;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case MG_GL_CUBIC:
|
|
||||||
{
|
|
||||||
vec3 ph = {p.x, p.y, 1};
|
|
||||||
vec3 klm = seg.implicitMatrix * ph;
|
|
||||||
side = (seg.sign*(klm.x*klm.x*klm.x - klm.y*klm.z) < 0)? -1 : 1;
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(side);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bin_to_tiles(int segIndex)
|
void bin_to_tiles(int segIndex)
|
||||||
{
|
{
|
||||||
//NOTE: add segment index to the queues of tiles it overlaps with
|
//NOTE: add segment index to the queues of tiles it overlaps with
|
||||||
|
@ -288,6 +133,98 @@ void bin_to_tiles(int segIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int push_segment(in vec2 p[4], int kind, int pathIndex)
|
||||||
|
{
|
||||||
|
int segIndex = atomicAdd(segmentCountBuffer.elements[0], 1);
|
||||||
|
|
||||||
|
vec2 s, c, e;
|
||||||
|
|
||||||
|
switch(kind)
|
||||||
|
{
|
||||||
|
case MG_GL_LINE:
|
||||||
|
s = p[0];
|
||||||
|
c = p[0];
|
||||||
|
e = p[1];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MG_GL_QUADRATIC:
|
||||||
|
s = p[0];
|
||||||
|
c = p[1];
|
||||||
|
e = p[2];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MG_GL_CUBIC:
|
||||||
|
{
|
||||||
|
s = p[0];
|
||||||
|
float sqrNorm0 = dot(p[1]-p[0], p[1]-p[0]);
|
||||||
|
float sqrNorm1 = dot(p[3]-p[2], p[3]-p[2]);
|
||||||
|
if(sqrNorm0 < sqrNorm1)
|
||||||
|
{
|
||||||
|
c = p[2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c = p[1];
|
||||||
|
}
|
||||||
|
e = p[3];
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool goingUp = e.y >= s.y;
|
||||||
|
bool goingRight = e.x >= s.x;
|
||||||
|
|
||||||
|
vec4 box = vec4(min(s.x, e.x),
|
||||||
|
min(s.y, e.y),
|
||||||
|
max(s.x, e.x),
|
||||||
|
max(s.y, e.y));
|
||||||
|
|
||||||
|
segmentBuffer.elements[segIndex].kind = kind;
|
||||||
|
segmentBuffer.elements[segIndex].pathIndex = pathIndex;
|
||||||
|
segmentBuffer.elements[segIndex].windingIncrement = goingUp ? 1 : -1;
|
||||||
|
segmentBuffer.elements[segIndex].box = box;
|
||||||
|
|
||||||
|
float dx = c.x - box.x;
|
||||||
|
float dy = c.y - box.y;
|
||||||
|
float alpha = (box.w - box.y)/(box.z - box.x);
|
||||||
|
float ofs = box.w - box.y;
|
||||||
|
|
||||||
|
if(goingUp == goingRight)
|
||||||
|
{
|
||||||
|
if(kind == MG_GL_LINE)
|
||||||
|
{
|
||||||
|
segmentBuffer.elements[segIndex].config = MG_GL_BR;
|
||||||
|
}
|
||||||
|
else if(dy > alpha*dx)
|
||||||
|
{
|
||||||
|
segmentBuffer.elements[segIndex].config = MG_GL_TL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
segmentBuffer.elements[segIndex].config = MG_GL_BR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(kind == MG_GL_LINE)
|
||||||
|
{
|
||||||
|
segmentBuffer.elements[segIndex].config = MG_GL_TR;
|
||||||
|
}
|
||||||
|
else if(dy < ofs - alpha*dx)
|
||||||
|
{
|
||||||
|
segmentBuffer.elements[segIndex].config = MG_GL_BL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
segmentBuffer.elements[segIndex].config = MG_GL_TR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(segIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define square(x) ((x)*(x))
|
||||||
|
#define cube(x) ((x)*(x)*(x))
|
||||||
|
|
||||||
void line_setup(vec2 p[4], int pathIndex)
|
void line_setup(vec2 p[4], int pathIndex)
|
||||||
{
|
{
|
||||||
int segIndex = push_segment(p, MG_GL_LINE, pathIndex);
|
int segIndex = push_segment(p, MG_GL_LINE, pathIndex);
|
||||||
|
@ -296,6 +233,107 @@ void line_setup(vec2 p[4], int pathIndex)
|
||||||
bin_to_tiles(segIndex);
|
bin_to_tiles(segIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec2 quadratic_blossom(vec2 p[4], float u, float v)
|
||||||
|
{
|
||||||
|
vec2 b10 = u*p[1] + (1-u)*p[0];
|
||||||
|
vec2 b11 = u*p[2] + (1-u)*p[1];
|
||||||
|
vec2 b20 = v*b11 + (1-v)*b10;
|
||||||
|
return(b20);
|
||||||
|
}
|
||||||
|
|
||||||
|
void quadratic_slice(vec2 p[4], float s0, float s1, out vec2 sp[4])
|
||||||
|
{
|
||||||
|
/*NOTE: using blossoms to compute sub-curve control points ensure that the fourth point
|
||||||
|
of sub-curve (s0, s1) and the first point of sub-curve (s1, s3) match.
|
||||||
|
However, due to numerical errors, the evaluation of B(s=0) might not be equal to
|
||||||
|
p[0] (and likewise, B(s=1) might not equal p[3]).
|
||||||
|
We handle that case explicitly to ensure that we don't create gaps in the paths.
|
||||||
|
*/
|
||||||
|
sp[0] = (s0 == 0) ? p[0] : quadratic_blossom(p, s0, s0);
|
||||||
|
sp[1] = quadratic_blossom(p, s0, s1);
|
||||||
|
sp[2] = (s1 == 1) ? p[2] : quadratic_blossom(p, s1, s1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int quadratic_monotonize(vec2 p[4], out float splits[4])
|
||||||
|
{
|
||||||
|
//NOTE: compute split points
|
||||||
|
int count = 0;
|
||||||
|
splits[0] = 0;
|
||||||
|
count++;
|
||||||
|
|
||||||
|
vec2 r = (p[0] - p[1])/(p[2] - 2*p[1] + p[0]);
|
||||||
|
if(r.x > r.y)
|
||||||
|
{
|
||||||
|
float tmp = r.x;
|
||||||
|
r.x = r.y;
|
||||||
|
r.y = tmp;
|
||||||
|
}
|
||||||
|
if(r.x > 0 && r.x < 1)
|
||||||
|
{
|
||||||
|
splits[count] = r.x;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if(r.y > 0 && r.y < 1)
|
||||||
|
{
|
||||||
|
splits[count] = r.y;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
splits[count] = 1;
|
||||||
|
count++;
|
||||||
|
return(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
mat3 barycentric_matrix(vec2 v0, vec2 v1, vec2 v2)
|
||||||
|
{
|
||||||
|
float det = v0.x*(v1.y-v2.y) + v1.x*(v2.y-v0.y) + v2.x*(v0.y - v1.y);
|
||||||
|
mat3 B = {{v1.y - v2.y, v2.y-v0.y, v0.y-v1.y},
|
||||||
|
{v2.x - v1.x, v0.x-v2.x, v1.x-v0.x},
|
||||||
|
{v1.x*v2.y-v2.x*v1.y, v2.x*v0.y-v0.x*v2.y, v0.x*v1.y-v1.x*v0.y}};
|
||||||
|
B *= (1/det);
|
||||||
|
return(B);
|
||||||
|
}
|
||||||
|
|
||||||
|
void quadratic_emit(vec2 p[4], int pathIndex)
|
||||||
|
{
|
||||||
|
int segIndex = push_segment(p, MG_GL_QUADRATIC, pathIndex);
|
||||||
|
|
||||||
|
//NOTE: compute implicit equation matrix
|
||||||
|
float det = p[0].x*(p[1].y-p[2].y) + p[1].x*(p[2].y-p[0].y) + p[2].x*(p[0].y - p[1].y);
|
||||||
|
|
||||||
|
float a = p[0].y - p[1].y + 0.5*(p[2].y - p[0].y);
|
||||||
|
float b = p[1].x - p[0].x + 0.5*(p[0].x - p[2].x);
|
||||||
|
float c = p[0].x*p[1].y - p[1].x*p[0].y + 0.5*(p[2].x*p[0].y - p[0].x*p[2].y);
|
||||||
|
float d = p[0].y - p[1].y;
|
||||||
|
float e = p[1].x - p[0].x;
|
||||||
|
float f = p[0].x*p[1].y - p[1].x*p[0].y;
|
||||||
|
|
||||||
|
float flip = ( segmentBuffer.elements[segIndex].config == MG_GL_TL
|
||||||
|
|| segmentBuffer.elements[segIndex].config == MG_GL_BL)? -1 : 1;
|
||||||
|
|
||||||
|
float g = flip*(p[2].x*(p[0].y - p[1].y) + p[0].x*(p[1].y - p[2].y) + p[1].x*(p[2].y - p[0].y));
|
||||||
|
|
||||||
|
segmentBuffer.elements[segIndex].implicitMatrix = (1/det)*mat3(a, d, 0.,
|
||||||
|
b, e, 0.,
|
||||||
|
c, f, g);
|
||||||
|
segmentBuffer.elements[segIndex].hullVertex = p[1];
|
||||||
|
|
||||||
|
bin_to_tiles(segIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void quadratic_setup(vec2 p[4], int pathIndex)
|
||||||
|
{
|
||||||
|
float splits[4];
|
||||||
|
int splitCount = quadratic_monotonize(p, splits);
|
||||||
|
|
||||||
|
//NOTE: produce bézier curve for each consecutive pair of roots
|
||||||
|
for(int sliceIndex=0; sliceIndex<splitCount-1; sliceIndex++)
|
||||||
|
{
|
||||||
|
vec2 sp[4];
|
||||||
|
quadratic_slice(p, splits[sliceIndex], splits[sliceIndex+1], sp);
|
||||||
|
quadratic_emit(sp, pathIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
int eltIndex = int(gl_WorkGroupID.x);
|
int eltIndex = int(gl_WorkGroupID.x);
|
||||||
|
@ -310,6 +348,12 @@ void main()
|
||||||
line_setup(p, elt.pathIndex);
|
line_setup(p, elt.pathIndex);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case MG_GL_QUADRATIC:
|
||||||
|
{
|
||||||
|
vec2 p[4] = {elt.p[0]*scale, elt.p[1]*scale, elt.p[2]*scale, vec2(0)};
|
||||||
|
quadratic_setup(p, elt.pathIndex);
|
||||||
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue