From 0db1589dc66127c727ebf5699caf3098bdab22ce Mon Sep 17 00:00:00 2001 From: Martin Fouilleul Date: Fri, 1 Sep 2023 19:40:37 +0200 Subject: [PATCH] [canvas] remove degenerate point lines when encoding strokes --- sketches/canvas/build.bat | 1 + sketches/canvas/main.c | 195 ++++++++++------------ sketches/polygon/main.c | 192 ---------------------- sketches/{polygon => smiley}/build.bat | 3 +- sketches/{polygon => smiley}/build.sh | 4 +- sketches/smiley/main.c | 216 +++++++++++++++++++++++++ src/graphics/gl_canvas.c | 33 ++-- src/graphics/mtl_renderer.m | 5 + 8 files changed, 332 insertions(+), 317 deletions(-) delete mode 100644 sketches/polygon/main.c rename sketches/{polygon => smiley}/build.bat (91%) rename sketches/{polygon => smiley}/build.sh (84%) create mode 100644 sketches/smiley/main.c diff --git a/sketches/canvas/build.bat b/sketches/canvas/build.bat index 7d73c69..bdf2268 100644 --- a/sketches/canvas/build.bat +++ b/sketches/canvas/build.bat @@ -1,3 +1,4 @@ + set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers if not exist "bin" mkdir bin diff --git a/sketches/canvas/main.c b/sketches/canvas/main.c index bbf1bc9..e8ee1ad 100644 --- a/sketches/canvas/main.c +++ b/sketches/canvas/main.c @@ -10,44 +10,10 @@ #include #include #include - -#define _USE_MATH_DEFINES //NOTE: necessary for MSVC #include #include "orca.h" -oc_font create_font() -{ - //NOTE(martin): create font - oc_str8 fontPath = oc_path_executable_relative(oc_scratch(), OC_STR8("../../resources/OpenSansLatinSubset.ttf")); - char* fontPathCString = oc_str8_to_cstring(oc_scratch(), fontPath); - - FILE* fontFile = fopen(fontPathCString, "r"); - if(!fontFile) - { - oc_log_error("Could not load font file '%s': %s\n", fontPathCString, strerror(errno)); - return (oc_font_nil()); - } - unsigned char* fontData = 0; - fseek(fontFile, 0, SEEK_END); - u32 fontDataSize = ftell(fontFile); - rewind(fontFile); - fontData = (unsigned char*)malloc(fontDataSize); - fread(fontData, 1, fontDataSize, fontFile); - fclose(fontFile); - - oc_unicode_range ranges[5] = { OC_UNICODE_BASIC_LATIN, - OC_UNICODE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT, - OC_UNICODE_LATIN_EXTENDED_A, - OC_UNICODE_LATIN_EXTENDED_B, - OC_UNICODE_SPECIALS }; - - oc_font font = oc_font_create_from_memory(oc_str8_from_buffer(fontDataSize, (char*)fontData), 5, ranges); - free(fontData); - - return (font); -} - int main() { oc_init(); @@ -59,31 +25,29 @@ int main() //NOTE: create surface oc_surface surface = oc_surface_create_for_window(window, OC_CANVAS); + oc_surface_swap_interval(surface, 1); + if(oc_surface_is_nil(surface)) { oc_log_error("Error: couldn't create surface\n"); return (-1); } - oc_surface_swap_interval(surface, 0); + //TODO: create canvas oc_canvas canvas = oc_canvas_create(); if(oc_canvas_is_nil(canvas)) { - printf("Error: couldn't create canvas\n"); + oc_log_error("Error: couldn't create canvas\n"); return (-1); } - oc_font font = create_font(); - // start app oc_window_bring_to_front(window); oc_window_focus(window); - f32 x = 400, y = 300; - f32 speed = 0; - f32 dx = speed, dy = speed; f64 frameTime = 0; + f32 x = 0, y = 0; while(!oc_should_quit()) { @@ -103,25 +67,23 @@ int main() case OC_EVENT_KEYBOARD_KEY: { - if(event->key.action == OC_KEY_PRESS || event->key.action == OC_KEY_REPEAT) + if(event->key.action == OC_KEY_PRESS) { - f32 factor = (event->key.mods & OC_KEYMOD_SHIFT) ? 10 : 1; - if(event->key.code == OC_KEY_LEFT) { - x -= 0.3 * factor; + x -= 1; } - else if(event->key.code == OC_KEY_RIGHT) + if(event->key.code == OC_KEY_RIGHT) { - x += 0.3 * factor; + x += 1; } - else if(event->key.code == OC_KEY_UP) + if(event->key.code == OC_KEY_UP) { - y -= 0.3 * factor; + y -= 1; } - else if(event->key.code == OC_KEY_DOWN) + if(event->key.code == OC_KEY_DOWN) { - y += 0.3 * factor; + y += 1; } } } @@ -132,72 +94,92 @@ int main() } } - if(x - 200 < 0) - { - x = 200; - dx = speed; - } - if(x + 200 > contentRect.w) - { - x = contentRect.w - 200; - dx = -speed; - } - if(y - 200 < 0) - { - y = 200; - dy = speed; - } - if(y + 200 > contentRect.h) - { - y = contentRect.h - 200; - dy = -speed; - } - x += dx; - y += dy; + oc_surface_select(surface); // background oc_set_color_rgba(0, 1, 1, 1); oc_clear(); - oc_set_color_rgba(1, 0, 1, 1); - oc_rectangle_fill(0, 0, 100, 100); - - // head - oc_set_color_rgba(1, 1, 0, 1); - - oc_circle_fill(x, y, 200); - - // smile - f32 frown = frameTime > 0.033 ? -100 : 0; - - oc_set_color_rgba(0, 0, 0, 1); - oc_set_width(20); - oc_move_to(x - 100, y + 100); - oc_cubic_to(x - 50, y + 150 + frown, x + 50, y + 150 + frown, x + 100, y + 100); - oc_stroke(); - - // eyes - oc_ellipse_fill(x - 70, y - 50, 30, 50); - oc_ellipse_fill(x + 70, y - 50, 30, 50); - - // text - oc_set_color_rgba(0, 0, 1, 1); - oc_set_font(font); - oc_set_font_size(12); - oc_move_to(50, 600 - 50); - - oc_str8 text = oc_str8_pushf(oc_scratch(), - "Orca vector graphics test program (frame time = %fs, fps = %f)...", - frameTime, - 1. / frameTime); - oc_text_outlines(text); + oc_move_to(100, 100); + oc_line_to(150, 150); + oc_line_to(100, 200); + oc_line_to(50, 150); + oc_close_path(); + oc_set_color_rgba(1, 0, 0, 1); oc_fill(); + oc_move_to(200, 100); + oc_line_to(410, 100); + oc_line_to(410, 200); + oc_line_to(200, 200); + oc_close_path(); + oc_set_color_rgba(0, 1, 0, 1); + oc_fill(); + + oc_set_color_rgba(0, 0.5, 1, 0.5); + oc_rectangle_fill(120, 120, 200, 200); + + oc_set_color_rgba(1, 0, 0.5, 1); + oc_rectangle_fill(700, 500, 200, 200); + + oc_move_to(300, 300); + oc_quadratic_to(400, 500, 500, 300); + oc_close_path(); + oc_set_color_rgba(0, 0, 1, 1); + oc_fill(); + + oc_move_to(200, 450); + oc_cubic_to(200, 250, 400, 550, 400, 450); + oc_close_path(); + oc_set_color_rgba(1, 0.5, 0, 1); + oc_fill(); + + /* + oc_set_joint(OC_JOINT_NONE); + oc_set_max_joint_excursion(20); + + oc_set_cap(OC_CAP_SQUARE); + + oc_move_to(x+200, y+200); + oc_line_to(x+300, y+300); + oc_line_to(x+200, y+400); + oc_line_to(x+100, y+300); + oc_close_path(); + oc_set_color_rgba(1, 0, 0, 1); + // oc_set_width(2); + oc_stroke(); + + oc_move_to(400, 400); + oc_quadratic_to(600, 601, 800, 400); + oc_set_color_rgba(0, 0, 1, 1); + oc_stroke(); + + oc_move_to(x+400, y+300); + oc_cubic_to(x+400, y+100, x+600, y+400, x+600, y+300); + oc_close_path(); + oc_set_color_rgba(0, 0, 1, 1); + oc_stroke(); + + oc_set_color_rgba(1, 0, 0, 1); + oc_rounded_rectangle_fill(100, 100, 200, 300, 20); + + oc_move_to(x+8, y+8); + oc_line_to(x+33, y+8); + oc_line_to(x+33, y+19); + oc_line_to(x+8, y+19); + oc_close_path(); + oc_set_color_rgba(0, 0, 1, 1); + oc_fill(); +*/ + + oc_set_width(1); + oc_set_color_rgba(1, 0, 0, 1); + oc_rounded_rectangle_stroke(400, 400, 160, 160, 80); + oc_log_info("Orca vector graphics test program (frame time = %fs, fps = %f)...\n", frameTime, 1. / frameTime); - oc_surface_select(surface); oc_render(surface, canvas); oc_surface_present(surface); @@ -205,7 +187,6 @@ int main() frameTime = oc_clock_time(OC_CLOCK_MONOTONIC) - startTime; } - oc_font_destroy(font); oc_canvas_destroy(canvas); oc_surface_destroy(surface); oc_window_destroy(window); diff --git a/sketches/polygon/main.c b/sketches/polygon/main.c deleted file mode 100644 index 6d28207..0000000 --- a/sketches/polygon/main.c +++ /dev/null @@ -1,192 +0,0 @@ -/************************************************************/ /** -* -* @file: main.cpp -* @author: Martin Fouilleul -* @date: 30/07/2022 -* @revision: -* -*****************************************************************/ -#include -#include -#include -#include -#include - -#include "orca.h" - -int main() -{ - oc_init(); - - oc_rect windowRect = { .x = 100, .y = 100, .w = 810, .h = 610 }; - oc_window window = oc_window_create(windowRect, OC_STR8("test"), 0); - - oc_rect contentRect = oc_window_get_content_rect(window); - - //NOTE: create surface - oc_surface surface = oc_surface_create_for_window(window, OC_CANVAS); - oc_surface_swap_interval(surface, 1); - - if(oc_surface_is_nil(surface)) - { - oc_log_error("Error: couldn't create surface\n"); - return (-1); - } - - //TODO: create canvas - oc_canvas canvas = oc_canvas_create(); - - if(oc_canvas_is_nil(canvas)) - { - oc_log_error("Error: couldn't create canvas\n"); - return (-1); - } - - // start app - oc_window_bring_to_front(window); - oc_window_focus(window); - - f64 frameTime = 0; - f32 x = 0, y = 0; - - while(!oc_should_quit()) - { - f64 startTime = oc_clock_time(OC_CLOCK_MONOTONIC); - - oc_pump_events(0); - oc_event* event = 0; - while((event = oc_next_event(oc_scratch())) != 0) - { - switch(event->type) - { - case OC_EVENT_WINDOW_CLOSE: - { - oc_request_quit(); - } - break; - - case OC_EVENT_KEYBOARD_KEY: - { - if(event->key.action == OC_KEY_PRESS) - { - if(event->key.code == OC_KEY_LEFT) - { - x -= 1; - } - if(event->key.code == OC_KEY_RIGHT) - { - x += 1; - } - if(event->key.code == OC_KEY_UP) - { - y -= 1; - } - if(event->key.code == OC_KEY_DOWN) - { - y += 1; - } - } - } - break; - - default: - break; - } - } - - oc_surface_select(surface); - - // background - oc_set_color_rgba(0, 1, 1, 1); - oc_clear(); - - oc_move_to(100, 100); - oc_line_to(150, 150); - oc_line_to(100, 200); - oc_line_to(50, 150); - oc_close_path(); - oc_set_color_rgba(1, 0, 0, 1); - oc_fill(); - - oc_move_to(200, 100); - oc_line_to(410, 100); - oc_line_to(410, 200); - oc_line_to(200, 200); - oc_close_path(); - oc_set_color_rgba(0, 1, 0, 1); - oc_fill(); - - oc_set_color_rgba(0, 0.5, 1, 0.5); - oc_rectangle_fill(120, 120, 200, 200); - - oc_set_color_rgba(1, 0, 0.5, 1); - oc_rectangle_fill(700, 500, 200, 200); - - oc_move_to(300, 300); - oc_quadratic_to(400, 500, 500, 300); - oc_close_path(); - oc_set_color_rgba(0, 0, 1, 1); - oc_fill(); - - oc_move_to(200, 450); - oc_cubic_to(200, 250, 400, 550, 400, 450); - oc_close_path(); - oc_set_color_rgba(1, 0.5, 0, 1); - oc_fill(); - - /* - oc_set_joint(OC_JOINT_NONE); - oc_set_max_joint_excursion(20); - - oc_set_cap(OC_CAP_SQUARE); - - oc_move_to(x+200, y+200); - oc_line_to(x+300, y+300); - oc_line_to(x+200, y+400); - oc_line_to(x+100, y+300); - oc_close_path(); - oc_set_color_rgba(1, 0, 0, 1); - // oc_set_width(2); - oc_stroke(); - - oc_move_to(400, 400); - oc_quadratic_to(600, 601, 800, 400); - oc_set_color_rgba(0, 0, 1, 1); - oc_stroke(); - - oc_move_to(x+400, y+300); - oc_cubic_to(x+400, y+100, x+600, y+400, x+600, y+300); - oc_close_path(); - oc_set_color_rgba(0, 0, 1, 1); - oc_stroke(); - - oc_set_color_rgba(1, 0, 0, 1); - oc_rounded_rectangle_fill(100, 100, 200, 300, 20); - - oc_move_to(x+8, y+8); - oc_line_to(x+33, y+8); - oc_line_to(x+33, y+19); - oc_line_to(x+8, y+19); - oc_close_path(); - oc_set_color_rgba(0, 0, 1, 1); - oc_fill(); -*/ - oc_log_info("Orca vector graphics test program (frame time = %fs, fps = %f)...\n", - frameTime, - 1. / frameTime); - - oc_render(surface, canvas); - oc_surface_present(surface); - - oc_arena_clear(oc_scratch()); - frameTime = oc_clock_time(OC_CLOCK_MONOTONIC) - startTime; - } - - oc_canvas_destroy(canvas); - oc_surface_destroy(surface); - oc_window_destroy(window); - - oc_terminate(); - - return (0); -} diff --git a/sketches/polygon/build.bat b/sketches/smiley/build.bat similarity index 91% rename from sketches/polygon/build.bat rename to sketches/smiley/build.bat index ede0d52..0f832f1 100644 --- a/sketches/polygon/build.bat +++ b/sketches/smiley/build.bat @@ -1,6 +1,5 @@ - set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers if not exist "bin" mkdir bin -cl /we4013 /Zi /Zc:preprocessor /std:c11 /experimental:c11atomics %INCLUDES% main.c /link /LIBPATH:../../build/bin orca.dll.lib /out:bin/example_poly.exe +cl /we4013 /Zi /Zc:preprocessor /std:c11 /experimental:c11atomics %INCLUDES% main.c /link /LIBPATH:../../build/bin orca.dll.lib /out:bin/example_smiley.exe copy ..\..\build\bin\orca.dll bin diff --git a/sketches/polygon/build.sh b/sketches/smiley/build.sh similarity index 84% rename from sketches/polygon/build.sh rename to sketches/smiley/build.sh index 0eaebe2..5a12e7b 100755 --- a/sketches/polygon/build.sh +++ b/sketches/smiley/build.sh @@ -10,9 +10,9 @@ LIBS="-L$LIBDIR -lorca" FLAGS="-mmacos-version-min=10.15.4 -DOC_DEBUG -DLOG_COMPILE_DEBUG" mkdir -p $BINDIR -clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_polygon main.c +clang -g $FLAGS $LIBS $INCLUDES -o $BINDIR/example_smiley main.c cp $LIBDIR/liborca.dylib $BINDIR/ cp $LIBDIR/mtl_renderer.metallib $BINDIR/ -install_name_tool -add_rpath "@executable_path" $BINDIR/example_polygon +install_name_tool -add_rpath "@executable_path" $BINDIR/example_smiley diff --git a/sketches/smiley/main.c b/sketches/smiley/main.c new file mode 100644 index 0000000..bbf1bc9 --- /dev/null +++ b/sketches/smiley/main.c @@ -0,0 +1,216 @@ +/************************************************************/ /** +* +* @file: main.cpp +* @author: Martin Fouilleul +* @date: 30/07/2022 +* @revision: +* +*****************************************************************/ +#include +#include +#include +#include + +#define _USE_MATH_DEFINES //NOTE: necessary for MSVC +#include + +#include "orca.h" + +oc_font create_font() +{ + //NOTE(martin): create font + oc_str8 fontPath = oc_path_executable_relative(oc_scratch(), OC_STR8("../../resources/OpenSansLatinSubset.ttf")); + char* fontPathCString = oc_str8_to_cstring(oc_scratch(), fontPath); + + FILE* fontFile = fopen(fontPathCString, "r"); + if(!fontFile) + { + oc_log_error("Could not load font file '%s': %s\n", fontPathCString, strerror(errno)); + return (oc_font_nil()); + } + unsigned char* fontData = 0; + fseek(fontFile, 0, SEEK_END); + u32 fontDataSize = ftell(fontFile); + rewind(fontFile); + fontData = (unsigned char*)malloc(fontDataSize); + fread(fontData, 1, fontDataSize, fontFile); + fclose(fontFile); + + oc_unicode_range ranges[5] = { OC_UNICODE_BASIC_LATIN, + OC_UNICODE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT, + OC_UNICODE_LATIN_EXTENDED_A, + OC_UNICODE_LATIN_EXTENDED_B, + OC_UNICODE_SPECIALS }; + + oc_font font = oc_font_create_from_memory(oc_str8_from_buffer(fontDataSize, (char*)fontData), 5, ranges); + free(fontData); + + return (font); +} + +int main() +{ + oc_init(); + + oc_rect windowRect = { .x = 100, .y = 100, .w = 810, .h = 610 }; + oc_window window = oc_window_create(windowRect, OC_STR8("test"), 0); + + oc_rect contentRect = oc_window_get_content_rect(window); + + //NOTE: create surface + oc_surface surface = oc_surface_create_for_window(window, OC_CANVAS); + if(oc_surface_is_nil(surface)) + { + oc_log_error("Error: couldn't create surface\n"); + return (-1); + } + oc_surface_swap_interval(surface, 0); + + oc_canvas canvas = oc_canvas_create(); + + if(oc_canvas_is_nil(canvas)) + { + printf("Error: couldn't create canvas\n"); + return (-1); + } + + oc_font font = create_font(); + + // start app + oc_window_bring_to_front(window); + oc_window_focus(window); + + f32 x = 400, y = 300; + f32 speed = 0; + f32 dx = speed, dy = speed; + f64 frameTime = 0; + + while(!oc_should_quit()) + { + f64 startTime = oc_clock_time(OC_CLOCK_MONOTONIC); + + oc_pump_events(0); + oc_event* event = 0; + while((event = oc_next_event(oc_scratch())) != 0) + { + switch(event->type) + { + case OC_EVENT_WINDOW_CLOSE: + { + oc_request_quit(); + } + break; + + case OC_EVENT_KEYBOARD_KEY: + { + if(event->key.action == OC_KEY_PRESS || event->key.action == OC_KEY_REPEAT) + { + f32 factor = (event->key.mods & OC_KEYMOD_SHIFT) ? 10 : 1; + + if(event->key.code == OC_KEY_LEFT) + { + x -= 0.3 * factor; + } + else if(event->key.code == OC_KEY_RIGHT) + { + x += 0.3 * factor; + } + else if(event->key.code == OC_KEY_UP) + { + y -= 0.3 * factor; + } + else if(event->key.code == OC_KEY_DOWN) + { + y += 0.3 * factor; + } + } + } + break; + + default: + break; + } + } + + if(x - 200 < 0) + { + x = 200; + dx = speed; + } + if(x + 200 > contentRect.w) + { + x = contentRect.w - 200; + dx = -speed; + } + if(y - 200 < 0) + { + y = 200; + dy = speed; + } + if(y + 200 > contentRect.h) + { + y = contentRect.h - 200; + dy = -speed; + } + x += dx; + y += dy; + + // background + oc_set_color_rgba(0, 1, 1, 1); + oc_clear(); + + oc_set_color_rgba(1, 0, 1, 1); + oc_rectangle_fill(0, 0, 100, 100); + + // head + oc_set_color_rgba(1, 1, 0, 1); + + oc_circle_fill(x, y, 200); + + // smile + f32 frown = frameTime > 0.033 ? -100 : 0; + + oc_set_color_rgba(0, 0, 0, 1); + oc_set_width(20); + oc_move_to(x - 100, y + 100); + oc_cubic_to(x - 50, y + 150 + frown, x + 50, y + 150 + frown, x + 100, y + 100); + oc_stroke(); + + // eyes + oc_ellipse_fill(x - 70, y - 50, 30, 50); + oc_ellipse_fill(x + 70, y - 50, 30, 50); + + // text + oc_set_color_rgba(0, 0, 1, 1); + oc_set_font(font); + oc_set_font_size(12); + oc_move_to(50, 600 - 50); + + oc_str8 text = oc_str8_pushf(oc_scratch(), + "Orca vector graphics test program (frame time = %fs, fps = %f)...", + frameTime, + 1. / frameTime); + oc_text_outlines(text); + oc_fill(); + + oc_log_info("Orca vector graphics test program (frame time = %fs, fps = %f)...\n", + frameTime, + 1. / frameTime); + + oc_surface_select(surface); + oc_render(surface, canvas); + oc_surface_present(surface); + + oc_arena_clear(oc_scratch()); + frameTime = oc_clock_time(OC_CLOCK_MONOTONIC) - startTime; + } + + oc_font_destroy(font); + oc_canvas_destroy(canvas); + oc_surface_destroy(surface); + oc_window_destroy(window); + + oc_terminate(); + + return (0); +} diff --git a/src/graphics/gl_canvas.c b/src/graphics/gl_canvas.c index 831d27c..2e88522 100644 --- a/src/graphics/gl_canvas.c +++ b/src/graphics/gl_canvas.c @@ -1,10 +1,10 @@ -/************************************************************/ /** -* -* @file: gl_canvas.c -* @author: Martin Fouilleul -* @date: 29/01/2023 -* @revision: -* +/************************************************************/ /** +* +* @file: gl_canvas.c +* @author: Martin Fouilleul +* @date: 29/01/2023 +* @revision: +* *****************************************************************/ #include "gl_api.h" #include "glsl_shaders.h" @@ -393,10 +393,10 @@ void oc_gl_canvas_encode_path(oc_gl_canvas_backend* backend, oc_primitive* primi static bool oc_intersect_hull_legs(oc_vec2 p0, oc_vec2 p1, oc_vec2 p2, oc_vec2 p3, oc_vec2* intersection) { - /*NOTE: check intersection of lines (p0-p1) and (p2-p3) - - P = p0 + u(p1-p0) - P = p2 + w(p3-p2) + /*NOTE: check intersection of lines (p0-p1) and (p2-p3) + + P = p0 + u(p1-p0) + P = p2 + w(p3-p2) */ bool found = false; @@ -582,6 +582,11 @@ static void oc_cubic_split(oc_vec2 p[4], f32 t, oc_vec2 outLeft[4], oc_vec2 outR void oc_gl_encode_stroke_line(oc_gl_canvas_backend* backend, oc_vec2* p) { + if(p[0].x == p[1].x && p[0].y == p[1].y) + { + return; + } + f32 width = backend->primitive->attributes.width; oc_vec2 v = { p[1].x - p[0].x, p[1].y - p[0].y }; @@ -919,9 +924,9 @@ void oc_gl_stroke_joint(oc_gl_canvas_backend* backend, } //NOTE(martin): use the same code as hull offset to find mitter point... - /*NOTE(martin): let vector u = (n0+n1) and vector v = pIntersect - p1 - then v = u * (2*offset / norm(u)^2) - (this can be derived from writing the pythagoras theorems in the triangles of the joint) + /*NOTE(martin): let vector u = (n0+n1) and vector v = pIntersect - p1 + then v = u * (2*offset / norm(u)^2) + (this can be derived from writing the pythagoras theorems in the triangles of the joint) */ f32 halfW = 0.5 * attributes->width; oc_vec2 u = { n0.x + n1.x, n0.y + n1.y }; diff --git a/src/graphics/mtl_renderer.m b/src/graphics/mtl_renderer.m index 71e320d..e853c27 100644 --- a/src/graphics/mtl_renderer.m +++ b/src/graphics/mtl_renderer.m @@ -455,6 +455,11 @@ static void oc_cubic_split(oc_vec2 p[4], f32 t, oc_vec2 outLeft[4], oc_vec2 outR void oc_mtl_render_stroke_line(oc_mtl_canvas_backend* backend, oc_vec2* p) { + if(p[0].x == p[1].x && p[0].y == p[1].y) + { + return; + } + f32 width = backend->primitive->attributes.width; oc_vec2 v = { p[1].x - p[0].x, p[1].y - p[0].y };