Switched to fixed point in gles triangle rasterization, and fixed wrong offset curve check collapsing the internal control points
This commit is contained in:
parent
e0300e9e3c
commit
0796b2cbcd
|
@ -41,7 +41,7 @@ int main()
|
||||||
mp_window_bring_to_front(window);
|
mp_window_bring_to_front(window);
|
||||||
mp_window_focus(window);
|
mp_window_focus(window);
|
||||||
|
|
||||||
f32 dx = 17.000029, dy = 0;
|
f32 dx = 0, dy = 0;
|
||||||
|
|
||||||
while(!mp_should_quit())
|
while(!mp_should_quit())
|
||||||
{
|
{
|
||||||
|
@ -67,30 +67,27 @@ int main()
|
||||||
|
|
||||||
case MP_EVENT_KEYBOARD_KEY:
|
case MP_EVENT_KEYBOARD_KEY:
|
||||||
{
|
{
|
||||||
printf("key %i: %s\n",
|
|
||||||
event.key.code,
|
|
||||||
event.key.action == MP_KEY_PRESS ? "press" : (event.key.action == MP_KEY_RELEASE ? "release" : "repeat"));
|
|
||||||
if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT)
|
if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT)
|
||||||
{
|
{
|
||||||
if(event.key.code == MP_KEY_LEFT)
|
if(event.key.code == MP_KEY_LEFT)
|
||||||
{
|
{
|
||||||
printf("left\n");
|
printf("left\n");
|
||||||
dx-=0.1;
|
dx-=1.1;
|
||||||
}
|
}
|
||||||
else if(event.key.code == MP_KEY_RIGHT)
|
else if(event.key.code == MP_KEY_RIGHT)
|
||||||
{
|
{
|
||||||
printf("right\n");
|
printf("right\n");
|
||||||
dx+=0.1;
|
dx+=1.1;
|
||||||
}
|
}
|
||||||
else if(event.key.code == MP_KEY_UP)
|
else if(event.key.code == MP_KEY_UP)
|
||||||
{
|
{
|
||||||
printf("up\n");
|
printf("up\n");
|
||||||
dy+=0.1;
|
dy+=1.1;
|
||||||
}
|
}
|
||||||
else if(event.key.code == MP_KEY_DOWN)
|
else if(event.key.code == MP_KEY_DOWN)
|
||||||
{
|
{
|
||||||
printf("down\n");
|
printf("down\n");
|
||||||
dy-=0.1;
|
dy-=1.1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
@ -102,12 +99,10 @@ int main()
|
||||||
|
|
||||||
mg_surface_prepare(surface);
|
mg_surface_prepare(surface);
|
||||||
|
|
||||||
printf("dx = %f, dy = %f\n", dx, dy);
|
|
||||||
|
|
||||||
// background
|
// background
|
||||||
mg_set_color_rgba(1, 0, 1, 1);
|
mg_set_color_rgba(1, 0, 1, 1);
|
||||||
mg_clear();
|
mg_clear();
|
||||||
/*
|
|
||||||
// head
|
// head
|
||||||
mg_set_color_rgba(1, 1, 0, 1);
|
mg_set_color_rgba(1, 1, 0, 1);
|
||||||
mg_circle_fill(dx+400, dy+300, 200);
|
mg_circle_fill(dx+400, dy+300, 200);
|
||||||
|
@ -123,8 +118,6 @@ int main()
|
||||||
// eyes
|
// eyes
|
||||||
mg_ellipse_fill(dx+330, dy+350, 30, 50);
|
mg_ellipse_fill(dx+330, dy+350, 30, 50);
|
||||||
mg_ellipse_fill(dx+470, dy+350, 30, 50);
|
mg_ellipse_fill(dx+470, dy+350, 30, 50);
|
||||||
*/
|
|
||||||
mg_rectangle_fill((int)(dx + 200), 200, (int)(dy+300), (int)(dy+300));
|
|
||||||
|
|
||||||
mg_flush();
|
mg_flush();
|
||||||
mg_surface_present(surface);
|
mg_surface_present(surface);
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
https://fgiesen.wordpress.com/2013/02/08/triangle-rasterization-in-practice/
|
||||||
|
|
||||||
|
https://github.com/rygorous/trirast/blob/master/main.cpp
|
||||||
|
|
||||||
|
https://joshbeam.com/articles/triangle_rasterization/
|
||||||
|
|
||||||
|
https://nlguillemot.wordpress.com/2016/07/10/rasterizer-notes/
|
||||||
|
|
||||||
|
https://web.archive.org/web/20120625103536/http://devmaster.net/forums/topic/1145-advanced-rasterization/
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* file: gles_canvas_shaders.h
|
* file: gles_canvas_shaders.h
|
||||||
* note: string literals auto-generated by embed_text.py
|
* note: string literals auto-generated by embed_text.py
|
||||||
* date: 01/022023
|
* date: 02/022023
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
#ifndef __GLES_CANVAS_SHADERS_H__
|
#ifndef __GLES_CANVAS_SHADERS_H__
|
||||||
|
@ -36,32 +36,25 @@ const char* gles_canvas_fragment =
|
||||||
"layout(location = 0) uniform int indexCount;\n"
|
"layout(location = 0) uniform int indexCount;\n"
|
||||||
"layout(location = 0) out vec4 fragColor;\n"
|
"layout(location = 0) out vec4 fragColor;\n"
|
||||||
"\n"
|
"\n"
|
||||||
"bool is_top_left(vec2 a, vec2 b)\n"
|
"bool is_top_left(ivec2 a, ivec2 b)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" return( (a.y == b.y && b.x < a.x)\n"
|
" return( (a.y == b.y && b.x < a.x)\n"
|
||||||
" ||(b.y < a.y));\n"
|
" ||(b.y < a.y));\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"float orient2d(vec2 a, vec2 b, vec2 c)\n"
|
"int orient2d(ivec2 a, ivec2 b, ivec2 p)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" //////////////////////////////////////////////////////////////////////////////////////////\n"
|
" return((b.x-a.x)*(p.y-a.y) - (b.y-a.y)*(p.x-a.x));\n"
|
||||||
" //TODO(martin): FIX this. This is a **horrible** quick hack to fix the precision issues\n"
|
|
||||||
" // arising when a, b, and c are close. But it degrades when a, c, and c\n"
|
|
||||||
" // are big. The proper solution is to change the expression to avoid\n"
|
|
||||||
" // precision loss but I'm too busy/lazy to do it now.\n"
|
|
||||||
" //////////////////////////////////////////////////////////////////////////////////////////\n"
|
|
||||||
" a *= 10.;\n"
|
|
||||||
" b *= 10.;\n"
|
|
||||||
" c *= 10.;\n"
|
|
||||||
" return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));\n"
|
|
||||||
"}\n"
|
"}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"void main()\n"
|
"void main()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
" float subPixelFactor = 16.;\n"
|
||||||
|
"\n"
|
||||||
" vec4 pixelColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
" vec4 pixelColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
|
||||||
" vec4 currentColor = vec4(0., 0., 0., 1.0);\n"
|
" vec4 currentColor = vec4(0., 0., 0., 1.0);\n"
|
||||||
"\n"
|
"\n"
|
||||||
" vec2 samplePoint = gl_FragCoord.xy;\n"
|
" ivec2 samplePoint = ivec2(gl_FragCoord.xy * subPixelFactor + vec2(0.5, 0.5));\n"
|
||||||
"\n"
|
"\n"
|
||||||
" int currentZIndex = -1;\n"
|
" int currentZIndex = -1;\n"
|
||||||
" int flipCount = 0;\n"
|
" int flipCount = 0;\n"
|
||||||
|
@ -73,22 +66,22 @@ const char* gles_canvas_fragment =
|
||||||
" uint i1 = indexBuffer.elements[i+1];\n"
|
" uint i1 = indexBuffer.elements[i+1];\n"
|
||||||
" uint i2 = indexBuffer.elements[i+2];\n"
|
" uint i2 = indexBuffer.elements[i+2];\n"
|
||||||
"\n"
|
"\n"
|
||||||
" vec2 p0 = vertexBuffer.elements[i0].pos;\n"
|
" ivec2 p0 = ivec2(vertexBuffer.elements[i0].pos * subPixelFactor + vec2(0.5, 0.5));\n"
|
||||||
" vec2 p1 = vertexBuffer.elements[i1].pos;\n"
|
" ivec2 p1 = ivec2(vertexBuffer.elements[i1].pos * subPixelFactor + vec2(0.5, 0.5));\n"
|
||||||
" vec2 p2 = vertexBuffer.elements[i2].pos;\n"
|
" ivec2 p2 = ivec2(vertexBuffer.elements[i2].pos * subPixelFactor + vec2(0.5, 0.5));\n"
|
||||||
"\n"
|
"\n"
|
||||||
" int zIndex = vertexBuffer.elements[i0].zIndex;\n"
|
" int zIndex = vertexBuffer.elements[i0].zIndex;\n"
|
||||||
" vec4 color = vertexBuffer.elements[i0].color;\n"
|
" vec4 color = vertexBuffer.elements[i0].color;\n"
|
||||||
"\n"
|
"\n"
|
||||||
" //NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge\n"
|
" //NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge\n"
|
||||||
" float cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;\n"
|
" int cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;\n"
|
||||||
" if(cw < 0.)\n"
|
" if(cw < 0)\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" uint tmpIndex = i1;\n"
|
" uint tmpIndex = i1;\n"
|
||||||
" i1 = i2;\n"
|
" i1 = i2;\n"
|
||||||
" i2 = tmpIndex;\n"
|
" i2 = tmpIndex;\n"
|
||||||
"\n"
|
"\n"
|
||||||
" vec2 tmpPoint = p1;\n"
|
" ivec2 tmpPoint = p1;\n"
|
||||||
" p1 = p2;\n"
|
" p1 = p2;\n"
|
||||||
" p2 = tmpPoint;\n"
|
" p2 = tmpPoint;\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
|
@ -101,14 +94,13 @@ const char* gles_canvas_fragment =
|
||||||
" int bias1 = is_top_left(p2, p0) ? 0 : -1;\n"
|
" int bias1 = is_top_left(p2, p0) ? 0 : -1;\n"
|
||||||
" int bias2 = is_top_left(p0, p1) ? 0 : -1;\n"
|
" int bias2 = is_top_left(p0, p1) ? 0 : -1;\n"
|
||||||
"\n"
|
"\n"
|
||||||
" float w0 = orient2d(p1, p2, samplePoint);\n"
|
" int w0 = orient2d(p1, p2, samplePoint);\n"
|
||||||
" float w1 = orient2d(p2, p0, samplePoint);\n"
|
" int w1 = orient2d(p2, p0, samplePoint);\n"
|
||||||
" float w2 = orient2d(p0, p1, samplePoint);\n"
|
" int w2 = orient2d(p0, p1, samplePoint);\n"
|
||||||
"\n"
|
"\n"
|
||||||
" if((int(w0)+bias0) >= 0 && (int(w1)+bias1) >= 0 && (int(w2)+bias2) >= 0)\n"
|
" if((w0+bias0) >= 0 && (w1+bias1) >= 0 && (w2+bias2) >= 0)\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" //TODO check cubic\n"
|
" vec4 cubic = (cubic0*float(w0) + cubic1*float(w1) + cubic2*float(w2))/(float(w0)+float(w1)+float(w2));\n"
|
||||||
" vec4 cubic = (cubic0*w0 + cubic1*w1 + cubic2*w2)/(w0+w1+w2);\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
" float eps = 0.0001;\n"
|
" float eps = 0.0001;\n"
|
||||||
" if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)\n"
|
" if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)\n"
|
||||||
|
|
|
@ -23,32 +23,25 @@ layout(binding = 1) buffer indexBufferSSBO {
|
||||||
layout(location = 0) uniform int indexCount;
|
layout(location = 0) uniform int indexCount;
|
||||||
layout(location = 0) out vec4 fragColor;
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
bool is_top_left(vec2 a, vec2 b)
|
bool is_top_left(ivec2 a, ivec2 b)
|
||||||
{
|
{
|
||||||
return( (a.y == b.y && b.x < a.x)
|
return( (a.y == b.y && b.x < a.x)
|
||||||
||(b.y < a.y));
|
||(b.y < a.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
float orient2d(vec2 a, vec2 b, vec2 c)
|
int orient2d(ivec2 a, ivec2 b, ivec2 p)
|
||||||
{
|
{
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
return((b.x-a.x)*(p.y-a.y) - (b.y-a.y)*(p.x-a.x));
|
||||||
//TODO(martin): FIX this. This is a **horrible** quick hack to fix the precision issues
|
|
||||||
// arising when a, b, and c are close. But it degrades when a, c, and c
|
|
||||||
// are big. The proper solution is to change the expression to avoid
|
|
||||||
// precision loss but I'm too busy/lazy to do it now.
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
a *= 10.;
|
|
||||||
b *= 10.;
|
|
||||||
c *= 10.;
|
|
||||||
return((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
float subPixelFactor = 16.;
|
||||||
|
|
||||||
vec4 pixelColor = vec4(0.0, 1.0, 0.0, 1.0);
|
vec4 pixelColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||||
vec4 currentColor = vec4(0., 0., 0., 1.0);
|
vec4 currentColor = vec4(0., 0., 0., 1.0);
|
||||||
|
|
||||||
vec2 samplePoint = gl_FragCoord.xy;
|
ivec2 samplePoint = ivec2(gl_FragCoord.xy * subPixelFactor + vec2(0.5, 0.5));
|
||||||
|
|
||||||
int currentZIndex = -1;
|
int currentZIndex = -1;
|
||||||
int flipCount = 0;
|
int flipCount = 0;
|
||||||
|
@ -60,22 +53,22 @@ void main()
|
||||||
uint i1 = indexBuffer.elements[i+1];
|
uint i1 = indexBuffer.elements[i+1];
|
||||||
uint i2 = indexBuffer.elements[i+2];
|
uint i2 = indexBuffer.elements[i+2];
|
||||||
|
|
||||||
vec2 p0 = vertexBuffer.elements[i0].pos;
|
ivec2 p0 = ivec2(vertexBuffer.elements[i0].pos * subPixelFactor + vec2(0.5, 0.5));
|
||||||
vec2 p1 = vertexBuffer.elements[i1].pos;
|
ivec2 p1 = ivec2(vertexBuffer.elements[i1].pos * subPixelFactor + vec2(0.5, 0.5));
|
||||||
vec2 p2 = vertexBuffer.elements[i2].pos;
|
ivec2 p2 = ivec2(vertexBuffer.elements[i2].pos * subPixelFactor + vec2(0.5, 0.5));
|
||||||
|
|
||||||
int zIndex = vertexBuffer.elements[i0].zIndex;
|
int zIndex = vertexBuffer.elements[i0].zIndex;
|
||||||
vec4 color = vertexBuffer.elements[i0].color;
|
vec4 color = vertexBuffer.elements[i0].color;
|
||||||
|
|
||||||
//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
|
//NOTE(martin): reorder triangle counter-clockwise and compute bias for each edge
|
||||||
float cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;
|
int cw = (p1 - p0).x*(p2 - p0).y - (p1 - p0).y*(p2 - p0).x;
|
||||||
if(cw < 0.)
|
if(cw < 0)
|
||||||
{
|
{
|
||||||
uint tmpIndex = i1;
|
uint tmpIndex = i1;
|
||||||
i1 = i2;
|
i1 = i2;
|
||||||
i2 = tmpIndex;
|
i2 = tmpIndex;
|
||||||
|
|
||||||
vec2 tmpPoint = p1;
|
ivec2 tmpPoint = p1;
|
||||||
p1 = p2;
|
p1 = p2;
|
||||||
p2 = tmpPoint;
|
p2 = tmpPoint;
|
||||||
}
|
}
|
||||||
|
@ -88,14 +81,13 @@ void main()
|
||||||
int bias1 = is_top_left(p2, p0) ? 0 : -1;
|
int bias1 = is_top_left(p2, p0) ? 0 : -1;
|
||||||
int bias2 = is_top_left(p0, p1) ? 0 : -1;
|
int bias2 = is_top_left(p0, p1) ? 0 : -1;
|
||||||
|
|
||||||
float w0 = orient2d(p1, p2, samplePoint);
|
int w0 = orient2d(p1, p2, samplePoint);
|
||||||
float w1 = orient2d(p2, p0, samplePoint);
|
int w1 = orient2d(p2, p0, samplePoint);
|
||||||
float w2 = orient2d(p0, p1, samplePoint);
|
int w2 = orient2d(p0, p1, samplePoint);
|
||||||
|
|
||||||
if((int(w0)+bias0) >= 0 && (int(w1)+bias1) >= 0 && (int(w2)+bias2) >= 0)
|
if((w0+bias0) >= 0 && (w1+bias1) >= 0 && (w2+bias2) >= 0)
|
||||||
{
|
{
|
||||||
//TODO check cubic
|
vec4 cubic = (cubic0*float(w0) + cubic1*float(w1) + cubic2*float(w2))/(float(w0)+float(w1)+float(w2));
|
||||||
vec4 cubic = (cubic0*w0 + cubic1*w1 + cubic2*w2)/(w0+w1+w2);
|
|
||||||
|
|
||||||
float eps = 0.0001;
|
float eps = 0.0001;
|
||||||
if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)
|
if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps)
|
||||||
|
|
|
@ -1154,7 +1154,7 @@ void mg_offset_hull(int count, vec2* p, vec2* result, f32 offset)
|
||||||
{
|
{
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
//WARN: quick fix for coincident middle control points
|
//WARN: quick fix for coincident middle control points
|
||||||
if(count == 4 && (p[1].x - p[2].x < 0.01) && (p[1].y - p[2].y < 0.01))
|
if(count == 4 && (fabs(p[1].x - p[2].x) < 0.01) && (fabs(p[1].y - p[2].y) < 0.01))
|
||||||
{
|
{
|
||||||
vec2 hull3[3] = {p[0], p[1], p[3]};
|
vec2 hull3[3] = {p[0], p[1], p[3]};
|
||||||
vec2 result3[3];
|
vec2 result3[3];
|
||||||
|
@ -1284,6 +1284,7 @@ void mg_render_stroke_quadratic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, m
|
||||||
//
|
//
|
||||||
// we compute the maximum overshoot outside these bounds and split the curve at the corresponding parameter
|
// we compute the maximum overshoot outside these bounds and split the curve at the corresponding parameter
|
||||||
|
|
||||||
|
//TODO: maybe refactor by using tolerance in the _check_, not in the computation of the overshoot
|
||||||
f32 tolerance = minimum(attributes->tolerance, 0.5 * attributes->width);
|
f32 tolerance = minimum(attributes->tolerance, 0.5 * attributes->width);
|
||||||
f32 d2LowBound = Square(0.5 * attributes->width - attributes->tolerance);
|
f32 d2LowBound = Square(0.5 * attributes->width - attributes->tolerance);
|
||||||
f32 d2HighBound = Square(0.5 * attributes->width + attributes->tolerance);
|
f32 d2HighBound = Square(0.5 * attributes->width + attributes->tolerance);
|
||||||
|
@ -1316,7 +1317,6 @@ void mg_render_stroke_quadratic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, m
|
||||||
|
|
||||||
if(maxOvershoot > 0)
|
if(maxOvershoot > 0)
|
||||||
{
|
{
|
||||||
//TODO(martin): split at maxErrorParameter and recurse
|
|
||||||
vec2 splitLeft[3];
|
vec2 splitLeft[3];
|
||||||
vec2 splitRight[3];
|
vec2 splitRight[3];
|
||||||
mg_quadratic_split(p, maxOvershootParameter, splitLeft, splitRight);
|
mg_quadratic_split(p, maxOvershootParameter, splitLeft, splitRight);
|
||||||
|
@ -1442,6 +1442,7 @@ void mg_render_stroke_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_at
|
||||||
//
|
//
|
||||||
// we compute the maximum overshoot outside these bounds and split the curve at the corresponding parameter
|
// we compute the maximum overshoot outside these bounds and split the curve at the corresponding parameter
|
||||||
|
|
||||||
|
//TODO: maybe refactor by using tolerance in the _check_, not in the computation of the overshoot
|
||||||
f32 tolerance = minimum(attributes->tolerance, 0.5 * attributes->width);
|
f32 tolerance = minimum(attributes->tolerance, 0.5 * attributes->width);
|
||||||
f32 d2LowBound = Square(0.5 * attributes->width - attributes->tolerance);
|
f32 d2LowBound = Square(0.5 * attributes->width - attributes->tolerance);
|
||||||
f32 d2HighBound = Square(0.5 * attributes->width + attributes->tolerance);
|
f32 d2HighBound = Square(0.5 * attributes->width + attributes->tolerance);
|
||||||
|
@ -1474,17 +1475,17 @@ void mg_render_stroke_cubic(mg_canvas_data* canvas, vec2 p[4], u32 zIndex, mg_at
|
||||||
|
|
||||||
if(maxOvershoot > 0)
|
if(maxOvershoot > 0)
|
||||||
{
|
{
|
||||||
//TODO(martin): split at maxErrorParameter and recurse
|
|
||||||
vec2 splitLeft[4];
|
vec2 splitLeft[4];
|
||||||
vec2 splitRight[4];
|
vec2 splitRight[4];
|
||||||
mg_cubic_split(p, maxOvershootParameter, splitLeft, splitRight);
|
mg_cubic_split(p, maxOvershootParameter, splitLeft, splitRight);
|
||||||
mg_render_stroke_cubic(canvas, splitLeft, zIndex, attributes);
|
mg_render_stroke_cubic(canvas, splitLeft, zIndex, attributes);
|
||||||
mg_render_stroke_cubic(canvas, splitRight, zIndex, attributes);
|
mg_render_stroke_cubic(canvas, splitRight, zIndex, attributes);
|
||||||
|
|
||||||
|
//TODO: render joint between the split curves
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//NOTE(martin): push the actual fill commands for the offset contour
|
//NOTE(martin): push the actual fill commands for the offset contour
|
||||||
|
|
||||||
u32 zIndex = mg_get_next_z_index(canvas);
|
u32 zIndex = mg_get_next_z_index(canvas);
|
||||||
|
|
||||||
mg_render_fill_cubic(canvas, positiveOffsetHull, zIndex, attributes->color);
|
mg_render_fill_cubic(canvas, positiveOffsetHull, zIndex, attributes->color);
|
||||||
|
|
18
todo.txt
18
todo.txt
|
@ -14,9 +14,21 @@
|
||||||
[ ] Cleanup graphics backend compile-time/runtime selection
|
[ ] Cleanup graphics backend compile-time/runtime selection
|
||||||
[ ] Cleanup graphics resource handles
|
[ ] Cleanup graphics resource handles
|
||||||
|
|
||||||
[>>] OpenGL surface on OSX
|
[.] GLES 3.0 surface on OSX
|
||||||
[>>] Port vector graphics to OpenGL on OSX
|
[x] GLES 3.1 surface on Win32
|
||||||
[>] Check OpenGL vector graphics on win32
|
[.] GLES vector graphics on win32
|
||||||
|
[x] Fix triangle rasterization precision issues
|
||||||
|
-> we do not want to snap vertex coordinates to integers though, but use fixed point with 4 or 8 bits of subpixel precision
|
||||||
|
-> convert verts pos to fixed point
|
||||||
|
-> do orient2d in fixed point
|
||||||
|
[!] Check precision/possible overflow when using barycentric coords
|
||||||
|
|
||||||
|
[>>] Investigate cubics flipping when curves are disabled
|
||||||
|
[>>] Investigate bad curve splitting on the right?
|
||||||
|
[ ] Multi-sampling
|
||||||
|
|
||||||
|
[>] Avoid first useless (degenerate) triangle on every path
|
||||||
|
|
||||||
[ ] Implement surfaces with child windows on win32
|
[ ] Implement surfaces with child windows on win32
|
||||||
[/] Maybe implement compositing directly in d3d and opengl compat extension...
|
[/] Maybe implement compositing directly in d3d and opengl compat extension...
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue