From e9ecd9d52195fa14e1bd4aac8830007bf297f49e Mon Sep 17 00:00:00 2001 From: Martin Fouilleul Date: Wed, 22 Mar 2023 15:02:04 +0100 Subject: [PATCH] [mtl canvas] Fix artifacts on tiger that was due to epsilon comparison for cubics equation in draw kernel. Removed that (now do <= 0), but then we need to weed out false negatives for solid triangles. So we compute if the triangle is solid in the triangle kernel and store it in the mg_triangle_data struct for now. --- examples/tiger/main.c | 26 +++++++++++++------------- examples/tiger/svg2mg.py | 9 ++++++--- examples/tiger/tiger.c | 7 +++++++ src/mtl_shader.h | 3 ++- src/mtl_shader.metal | 16 ++++++++++------ 5 files changed, 38 insertions(+), 23 deletions(-) diff --git a/examples/tiger/main.c b/examples/tiger/main.c index 2d2df6a..44d1d62 100644 --- a/examples/tiger/main.c +++ b/examples/tiger/main.c @@ -65,7 +65,7 @@ int main() //NOTE: create surface mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT); - mg_surface_swap_interval(surface, 0); + mg_surface_swap_interval(surface, 1); //TODO: create canvas mg_canvas canvas = mg_canvas_create(surface); @@ -85,7 +85,7 @@ int main() bool tracked = false; vec2 trackPoint = {0}; f32 zoom = 1; - f32 startX = 0, startY = 0; + f32 startX = 300, startY = 200; f64 frameTime = 0; @@ -112,8 +112,8 @@ int main() { tracked = true; vec2 mousePos = mp_mouse_position(); - trackPoint.x = mousePos.x/zoom - startX; - trackPoint.y = mousePos.y/zoom - startY; + trackPoint.x = (mousePos.x - startX)/zoom; + trackPoint.y = (mousePos.y - startY)/zoom; } else { @@ -125,14 +125,14 @@ int main() case MP_EVENT_MOUSE_WHEEL: { vec2 mousePos = mp_mouse_position(); - f32 trackX = mousePos.x/zoom - startX; - f32 trackY = mousePos.y/zoom - startY; + f32 pinX = (mousePos.x - startX)/zoom; + f32 pinY = (mousePos.y - startY)/zoom; zoom *= 1 + event.move.deltaY * 0.01; - zoom = Clamp(zoom, 0.2, 10); + zoom = Clamp(zoom, 0.5, 5); - startX = mousePos.x/zoom - trackX; - startY = mousePos.y/zoom - trackY; + startX = mousePos.x - pinX*zoom; + startY = mousePos.y - pinY*zoom; } break; default: @@ -143,8 +143,8 @@ int main() if(tracked) { vec2 mousePos = mp_mouse_position(); - startX = mousePos.x/zoom - trackPoint.x; - startY = mousePos.y/zoom - trackPoint.y; + startX = mousePos.x - trackPoint.x*zoom; + startY = mousePos.y - trackPoint.y*zoom; } mg_surface_prepare(surface); @@ -152,8 +152,8 @@ int main() mg_set_color_rgba(1, 0, 1, 1); mg_clear(); - mg_matrix_push((mg_mat2x3){zoom, 0, 300+startX*zoom, - 0, zoom, 200+startY*zoom}); + mg_matrix_push((mg_mat2x3){zoom, 0, startX, + 0, zoom, startY}); draw_tiger(); diff --git a/examples/tiger/svg2mg.py b/examples/tiger/svg2mg.py index d22a82a..18aa62e 100644 --- a/examples/tiger/svg2mg.py +++ b/examples/tiger/svg2mg.py @@ -208,10 +208,13 @@ for g in tree.iter('{http://www.w3.org/2000/svg}g'): print("\tmg_set_color_rgba(" + f2s(r) + ", " + f2s(g) + ", " + f2s(b) + ", 1);") print("\tmg_fill();") - if stroke_width != None: - print("\tmg_set_width(" + stroke_width + ");"); - if stroke != None and stroke != "none": + + if stroke_width != None: + print("\tmg_set_width(" + stroke_width + ");"); + else: + print("\tmg_set_width(1);"); + (r, g, b) = parse_color(stroke) if fill != None: ctx.reset() diff --git a/examples/tiger/tiger.c b/examples/tiger/tiger.c index 9c76761..cd03d26 100644 --- a/examples/tiger/tiger.c +++ b/examples/tiger/tiger.c @@ -284,6 +284,7 @@ void draw_tiger() mg_close_path(); mg_set_color_rgba(1.000, 1.000, 1.000, 1); mg_fill(); + mg_set_width(1); mg_move_to(-129.830, 103.060); mg_cubic_to(-129.330, 109.110, -128.340, 115.680, -126.600, 118.800); mg_cubic_to(-126.600, 118.800, -130.200, 131.200, -121.400, 144.400); @@ -422,6 +423,7 @@ void draw_tiger() mg_close_path(); mg_set_color_rgba(0.800, 0.447, 0.149, 1); mg_fill(); + mg_set_width(1); mg_move_to(299.720, 80.245); mg_cubic_to(300.340, 80.426, 302.550, 81.550, 303.800, 83.200); mg_cubic_to(303.800, 83.200, 310.600, 94.000, 305.400, 75.600); @@ -909,6 +911,7 @@ void draw_tiger() mg_close_path(); mg_set_color_rgba(1.000, 0.447, 0.498, 1); mg_fill(); + mg_set_width(1); mg_move_to(-9.800, 174.400); mg_cubic_to(-9.800, 174.400, -12.600, 196.800, -9.400, 205.200); mg_cubic_to(-6.200, 213.600, -7.000, 215.600, -7.800, 219.600); @@ -3879,21 +3882,25 @@ void draw_tiger() mg_move_to(-89.250, 169.000); mg_move_to(-67.250, 173.750); + mg_set_width(1); mg_set_color_rgba(0.000, 0.000, 0.000, 1); mg_stroke(); mg_move_to(-39.000, 331.000); mg_cubic_to(-39.000, 331.000, -39.500, 327.500, -48.500, 338.000); + mg_set_width(1); mg_set_color_rgba(0.000, 0.000, 0.000, 1); mg_stroke(); mg_move_to(-33.500, 336.000); mg_cubic_to(-33.500, 336.000, -31.500, 329.500, -38.000, 334.000); + mg_set_width(1); mg_set_color_rgba(0.000, 0.000, 0.000, 1); mg_stroke(); mg_move_to(20.500, 344.500); mg_cubic_to(20.500, 344.500, 22.000, 333.500, 10.500, 346.500); + mg_set_width(1); mg_set_color_rgba(0.000, 0.000, 0.000, 1); mg_stroke(); diff --git a/src/mtl_shader.h b/src/mtl_shader.h index e1bea72..604488a 100644 --- a/src/mtl_shader.h +++ b/src/mtl_shader.h @@ -13,7 +13,7 @@ #define RENDERER_TILE_SIZE 16 #define RENDERER_MAX_TILES 65536 -#define RENDERER_TILE_BUFFER_COUNT 4*(1<<10) +#define RENDERER_TILE_BUFFER_COUNT 8*(1<<10) #define RENDERER_DEBUG_TILE_VISITED 0xf00d #define RENDERER_DEBUG_TILE_BUFFER_OVERFLOW 0xdead @@ -38,6 +38,7 @@ typedef struct mg_triangle_data matrix_float3x3 uvTransform; vector_float4 color; + bool full; vector_float4 cubic0; vector_float4 cubic1; vector_float4 cubic2; diff --git a/src/mtl_shader.metal b/src/mtl_shader.metal index 3a1bd82..73e9e56 100644 --- a/src/mtl_shader.metal +++ b/src/mtl_shader.metal @@ -158,6 +158,12 @@ kernel void TriangleKernel(constant mg_vertex* vertexBuffer [[buffer(0)]], triangleArray[gid].bias1 = is_top_left(p2, p0) ? -(1-cw)/2 : -(1+cw)/2; triangleArray[gid].bias2 = is_top_left(p0, p1) ? -(1-cw)/2 : -(1+cw)/2; + bool triangleFull = all( triangleArray[gid].cubic0 == float4(1, 1, 1, 1) + && triangleArray[gid].cubic1 == float4(1, 1, 1, 1) + && triangleArray[gid].cubic2 == float4(1, 1, 1, 1)); + + triangleArray[gid].full = triangleFull; + int4 coarseBox = int4(fbox)/RENDERER_TILE_SIZE; //NOTE: bucket triangle into tiles @@ -172,10 +178,6 @@ kernel void TriangleKernel(constant mg_vertex* vertexBuffer [[buffer(0)]], //NOTE(martin): it's important to do the computation with signed int, so that we can have negative xMax/yMax // otherwise all triangles on the left or below the x/y axis are attributed to tiles on row/column 0. - bool triangleFull = all( triangleArray[gid].cubic0 == float4(1, 1, 1, 1) - && triangleArray[gid].cubic1 == float4(1, 1, 1, 1) - && triangleArray[gid].cubic2 == float4(1, 1, 1, 1)); - int2 edges[3][2] = {{ip0, ip1}, {ip1, ip2}, {ip2, ip0}}; for(int y = yMin; y <= yMax; y++) @@ -450,6 +452,8 @@ kernel void RenderKernel(const device uint* tileCounters [[buffer(0)]], float4 cubic1 = triangle->cubic1; float4 cubic2 = triangle->cubic2; + bool fullTriangle = triangle->full; + int shapeIndex = triangle->shapeIndex; float4 color = triangle->color; color.rgb *= color.a; @@ -478,8 +482,8 @@ kernel void RenderKernel(const device uint* tileCounters [[buffer(0)]], { float4 cubic = (cubic0*w0 + cubic1*w1 + cubic2*w2)/(w0+w1+w2); - float eps = 0.0001; - if(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= eps) + if( fullTriangle + ||(cubic.w*(cubic.x*cubic.x*cubic.x - cubic.y*cubic.z) <= 0)) { if(shapeIndex == currentShapeIndex[sampleIndex]) {