added drawing line primitives
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 8 Nov 2021 02:23:57 +0000 (20:23 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 8 Nov 2021 02:23:57 +0000 (20:23 -0600)
include/gfx.h
src/gfx.c
src/heartbreak_graphics.c
src/heartbreak_system.c
tests/simp.onyx

index 712880fd6f3905dca0364e6bdad625870e3870f0..44075f057bedc810efcfc151a3f6cf921bdbc95d 100644 (file)
@@ -51,6 +51,11 @@ typedef struct ImmediateColor {
     f32 r, g, b, a;
 } ImmediateColor;
 
+typedef enum ImmediateMode {
+    IMMEDIATE_MODE_TRIANGLES = 1,
+    IMMEDIATE_MODE_LINES     = 2,
+} ImmediateMode;
+
 typedef struct ImmediateVertex {
     f32 x, y;
     f32 u, v;
@@ -66,6 +71,7 @@ typedef struct ImmediateRenderer {
     u32              tris_vertex_count;
 
     ImmediateColor   current_color;
+    ImmediateMode    current_mode;
 
     Shader tris_shader;
     GLint tris_vertex_array;
@@ -86,6 +92,7 @@ typedef struct ImmediateRenderer {
 
 void gfx_immediate_renderer_init(ImmediateRenderer *ir, bh_allocator allocator);
 void gfx_immediate_renderer_flush(ImmediateRenderer *ir);
+void gfx_immediate_renderer_set_primitive_mode(ImmediateRenderer *ir, ImmediateMode mode);
 void gfx_immediate_renderer_set_color(ImmediateRenderer *ir, ImmediateColor color);
 void gfx_immediate_renderer_push_vertex(ImmediateRenderer *ir, f32 x, f32 y, f32 u, f32 v);
 void gfx_immediate_renderer_push_triangle(ImmediateRenderer *ir,
index 3c0ee21fb454cfcbfc197498bcf95ef7cf3bf77d..3a36e16fbcd1a1a421a4b3f8e1870d6d6c914f09 100644 (file)
--- a/src/gfx.c
+++ b/src/gfx.c
@@ -256,6 +256,7 @@ void gfx_immediate_renderer_init(ImmediateRenderer *ir, bh_allocator allocator)
 
     gfx_image_unbind(ir);
 
+    ir->current_mode  = IMMEDIATE_MODE_TRIANGLES;
     ir->current_color = (ImmediateColor) { 1, 1, 1, 1 };
     ir->world_transform_dirty = 1;
 
@@ -271,14 +272,29 @@ void gfx_immediate_renderer_flush(ImmediateRenderer *ir) {
 
     gfx_immediate_renderer_update_world_transform(ir);
 
+    static const GLint primitives[] = {
+        0,
+        GL_TRIANGLES,
+        GL_LINES,
+    };
+    GLint primitive = primitives[ir->current_mode];
+
     glUseProgram(ir->tris_shader.program);
     glBindVertexArray(ir->tris_vertex_array);
-    glDrawArrays(GL_TRIANGLES, 0, ir->tris_vertex_count);
+    glDrawArrays(primitive, 0, ir->tris_vertex_count);
     glBindVertexArray(-1);
 
     ir->tris_vertex_count = 0;
 }
 
+void gfx_immediate_renderer_set_primitive_mode(ImmediateRenderer *ir, ImmediateMode mode) {
+    if (ir->current_mode != mode && ir->tris_vertex_count > 0) {
+        gfx_immediate_renderer_flush(ir);
+    }
+
+    ir->current_mode = mode;
+}
+
 void gfx_immediate_renderer_set_color(ImmediateRenderer *ir, ImmediateColor color) {
     ir->current_color = color;
 
index 6d85b11e4881136212d00fc5d8a10c765811ec2c..3212b41bc1a4381b9b03529a0a55d22a74d41062 100644 (file)
@@ -33,117 +33,219 @@ HEARTBREAK_DEF(set_color, (WASM_F32,WASM_F32,WASM_F32,WASM_F32), ()) {
 
 HEARTBREAK_DEF(rectangle, (WASM_I32,WASM_F32,WASM_F32,WASM_F32,WASM_F32), ()) {
     gfx_image_unbind(&renderer);
-    // @TODO: Use fill mode
+
+    i32 mode = params->data[0].of.i32;
+    if (mode == 1) gfx_immediate_renderer_set_primitive_mode(&renderer, IMMEDIATE_MODE_TRIANGLES);
+    if (mode == 2) gfx_immediate_renderer_set_primitive_mode(&renderer, IMMEDIATE_MODE_LINES);
 
     f32 x = params->data[1].of.f32;
     f32 y = params->data[2].of.f32;
     f32 w = params->data[3].of.f32;
     f32 h = params->data[4].of.f32;
 
-    gfx_immediate_renderer_push_triangle(&renderer,
-        x, y, 0, 0,
-        x + w, y, 0, 0,
-        x + w, y + h, 0, 0);
+    if (mode == 1) {
+        gfx_immediate_renderer_push_triangle(&renderer,
+            x, y, 0, 0,
+            x + w, y, 0, 0,
+            x + w, y + h, 0, 0);
 
-    gfx_immediate_renderer_push_triangle(&renderer,
-        x, y, 0, 0,
-        x + w, y + h, 0, 0,
-        x, y + h, 0, 0);
+        gfx_immediate_renderer_push_triangle(&renderer,
+            x, y, 0, 0,
+            x + w, y + h, 0, 0,
+            x, y + h, 0, 0);
+
+    } else if (mode == 2) {
+        gfx_immediate_renderer_push_vertex(&renderer, x, y, 0, 0);
+        gfx_immediate_renderer_push_vertex(&renderer, x + w, y, 0, 0);
+        gfx_immediate_renderer_push_vertex(&renderer, x + w, y, 0, 0);
+        gfx_immediate_renderer_push_vertex(&renderer, x + w, y + h, 0, 0);
+        gfx_immediate_renderer_push_vertex(&renderer, x + w, y + h, 0, 0);
+        gfx_immediate_renderer_push_vertex(&renderer, x, y + h, 0, 0);
+        gfx_immediate_renderer_push_vertex(&renderer, x, y + h, 0, 0);
+        gfx_immediate_renderer_push_vertex(&renderer, x, y, 0, 0);
+    }
 
     return NULL;
 }
 
 HEARTBREAK_DEF(circle, (WASM_I32, WASM_F32, WASM_F32, WASM_F32, WASM_I32), ()) {
     gfx_image_unbind(&renderer);
-    // @TODO: Use fill mode
 
-    f32 x = params->data[1].of.f32;
-    f32 y = params->data[2].of.f32;
-    f32 r = params->data[3].of.f32;
-    i32 segments = params->data[4].of.i32;
+    i32 mode = params->data[0].of.i32;
+    if (mode == 1) {
+        gfx_immediate_renderer_set_primitive_mode(&renderer, IMMEDIATE_MODE_TRIANGLES);
 
-    f32 cx1 = x + r;
-    f32 cy1 = y;
-    f32 cx2 = x + cos(PI * 2 / segments) * r;
-    f32 cy2 = y + sin(PI * 2 / segments) * r;
-    f32 cx3, cy3;
+        f32 x = params->data[1].of.f32;
+        f32 y = params->data[2].of.f32;
+        f32 r = params->data[3].of.f32;
+        i32 segments = params->data[4].of.i32;
 
-    fori (i, 2, segments) {
-        cx3 = x + cos(i * PI * 2 / segments) * r;
-        cy3 = y + sin(i * PI * 2 / segments) * r;
+        f32 cx1 = x + r;
+        f32 cy1 = y;
+        f32 cx2 = x + cos(PI * 2 / segments) * r;
+        f32 cy2 = y + sin(PI * 2 / segments) * r;
+        f32 cx3, cy3;
 
-        gfx_immediate_renderer_push_triangle(&renderer,
-            cx1, cy1, 0, 0,
-            cx2, cy2, 0, 0,
-            cx3, cy3, 0, 0);
+        fori (i, 2, segments) {
+            cx3 = x + cos(i * PI * 2 / segments) * r;
+            cy3 = y + sin(i * PI * 2 / segments) * r;
 
-        cx2 = cx3;
-        cy2 = cy3;
-    }
+            gfx_immediate_renderer_push_triangle(&renderer,
+                cx1, cy1, 0, 0,
+                cx2, cy2, 0, 0,
+                cx3, cy3, 0, 0);
 
-    return NULL;
-}
+            cx2 = cx3;
+            cy2 = cy3;
+        }
 
-HEARTBREAK_DEF(ellipse, (WASM_I32, WASM_F32, WASM_F32, WASM_F32, WASM_F32, WASM_I32), ()) {
-    gfx_image_unbind(&renderer);
-    // @TODO: Use fill mode
+    } else if (mode == 2) {
+        gfx_immediate_renderer_set_primitive_mode(&renderer, IMMEDIATE_MODE_LINES);
 
-    f32 x = params->data[1].of.f32;
-    f32 y = params->data[2].of.f32;
-    f32 r1 = params->data[3].of.f32;
-    f32 r2 = params->data[4].of.f32;
-    i32 segments = params->data[5].of.i32;
+        f32 x = params->data[1].of.f32;
+        f32 y = params->data[2].of.f32;
+        f32 r = params->data[3].of.f32;
+        i32 segments = params->data[4].of.i32;
 
-    f32 cx1 = x + r1;
-    f32 cy1 = y;
-    f32 cx2 = x + cos(PI * 2 / segments) * r1;
-    f32 cy2 = y + sin(PI * 2 / segments) * r2;
-    f32 cx3, cy3;
+        f32 cx1 = x + r;
+        f32 cy1 = y;
+        f32 cx2, cy2;
 
-    fori (i, 2, segments) {
-        cx3 = x + cos(i * PI * 2 / segments) * r1;
-        cy3 = y + sin(i * PI * 2 / segments) * r2;
+        fori (i, 1, segments + 1) {
+            cx2 = x + cos(i * PI * 2 / segments) * r;
+            cy2 = y + sin(i * PI * 2 / segments) * r;
 
-        gfx_immediate_renderer_push_triangle(&renderer,
-            cx1, cy1, 0, 0,
-            cx2, cy2, 0, 0,
-            cx3, cy3, 0, 0);
+            gfx_immediate_renderer_push_vertex(&renderer, cx1, cy1, 0, 0);
+            gfx_immediate_renderer_push_vertex(&renderer, cx2, cy2, 0, 0);
 
-        cx2 = cx3;
-        cy2 = cy3;
+            cx1 = cx2;
+            cy1 = cy2;
+        }
     }
 
     return NULL;
 }
 
-HEARTBREAK_DEF(arc, (WASM_I32, WASM_F32, WASM_F32, WASM_F32, WASM_F32, WASM_F32, WASM_I32), ()) {
+HEARTBREAK_DEF(ellipse, (WASM_I32, WASM_F32, WASM_F32, WASM_F32, WASM_F32, WASM_I32), ()) {
     gfx_image_unbind(&renderer);
-    // @TODO: Use fill mode
 
-    f32 x = params->data[1].of.f32;
-    f32 y = params->data[2].of.f32;
-    f32 r = params->data[3].of.f32;
-    f32 a1 = params->data[4].of.f32;
-    f32 a2 = params->data[5].of.f32;
-    f32 segments = params->data[6].of.i32;
-
-    f32 cx1 = x;
-    f32 cy1 = y;
-    f32 cx2 = x + cos(a1 + 0 * (a2 - a1) / segments) * r;
-    f32 cy2 = y + sin(a1 + 0 * (a2 - a1) / segments) * r;
-    f32 cx3, cy3;
+    i32 mode = params->data[0].of.i32;
+    if (mode == 1) {
+        gfx_immediate_renderer_set_primitive_mode(&renderer, IMMEDIATE_MODE_TRIANGLES);
+        f32 x = params->data[1].of.f32;
+        f32 y = params->data[2].of.f32;
+        f32 r1 = params->data[3].of.f32;
+        f32 r2 = params->data[4].of.f32;
+        i32 segments = params->data[5].of.i32;
+
+        f32 cx1 = x + r1;
+        f32 cy1 = y;
+        f32 cx2 = x + cos(PI * 2 / segments) * r1;
+        f32 cy2 = y + sin(PI * 2 / segments) * r2;
+        f32 cx3, cy3;
+
+        fori (i, 2, segments) {
+            cx3 = x + cos(i * PI * 2 / segments) * r1;
+            cy3 = y + sin(i * PI * 2 / segments) * r2;
+
+            gfx_immediate_renderer_push_triangle(&renderer,
+                cx1, cy1, 0, 0,
+                cx2, cy2, 0, 0,
+                cx3, cy3, 0, 0);
+
+            cx2 = cx3;
+            cy2 = cy3;
+        }
+
+    } else if (mode == 2) {
+        gfx_immediate_renderer_set_primitive_mode(&renderer, IMMEDIATE_MODE_LINES);
+        f32 x = params->data[1].of.f32;
+        f32 y = params->data[2].of.f32;
+        f32 r1 = params->data[3].of.f32;
+        f32 r2 = params->data[4].of.f32;
+        i32 segments = params->data[5].of.i32;
+
+        f32 cx1 = x + r1;
+        f32 cy1 = y;
+        f32 cx2, cy2;
+
+        fori (i, 1, segments + 1) {
+            cx2 = x + cos(i * PI * 2 / segments) * r1;
+            cy2 = y + sin(i * PI * 2 / segments) * r2;
+
+            gfx_immediate_renderer_push_vertex(&renderer, cx1, cy1, 0, 0);
+            gfx_immediate_renderer_push_vertex(&renderer, cx2, cy2, 0, 0);
+
+            cx1 = cx2;
+            cy1 = cy2;
+        }
+    }
 
-    fori (i, 1, segments + 1) {
-        cx3 = x + cos(a1 + i * (a2 - a1) / segments) * r;
-        cy3 = y + sin(a1 + i * (a2 - a1) / segments) * r;
+    return NULL;
+}
 
-        gfx_immediate_renderer_push_triangle(&renderer,
-            cx1, cy1, 0, 0,
-            cx2, cy2, 0, 0,
-            cx3, cy3, 0, 0);
+HEARTBREAK_DEF(arc, (WASM_I32, WASM_F32, WASM_F32, WASM_F32, WASM_F32, WASM_F32, WASM_I32), ()) {
+    gfx_image_unbind(&renderer);
 
-        cx2 = cx3;
-        cy2 = cy3;
+    i32 mode = params->data[0].of.i32;
+    if (mode == 1) {
+        gfx_immediate_renderer_set_primitive_mode(&renderer, IMMEDIATE_MODE_TRIANGLES);
+        f32 x = params->data[1].of.f32;
+        f32 y = params->data[2].of.f32;
+        f32 r = params->data[3].of.f32;
+        f32 a1 = params->data[4].of.f32;
+        f32 a2 = params->data[5].of.f32;
+        f32 segments = params->data[6].of.i32;
+
+        f32 cx1 = x;
+        f32 cy1 = y;
+        f32 cx2 = x + cos(a1 + 0 * (a2 - a1) / segments) * r;
+        f32 cy2 = y + sin(a1 + 0 * (a2 - a1) / segments) * r;
+        f32 cx3, cy3;
+
+        fori (i, 1, segments + 1) {
+            cx3 = x + cos(a1 + i * (a2 - a1) / segments) * r;
+            cy3 = y + sin(a1 + i * (a2 - a1) / segments) * r;
+
+            gfx_immediate_renderer_push_triangle(&renderer,
+                cx1, cy1, 0, 0,
+                cx2, cy2, 0, 0,
+                cx3, cy3, 0, 0);
+
+            cx2 = cx3;
+            cy2 = cy3;
+        }
+
+    } else if (mode == 2) {
+        gfx_immediate_renderer_set_primitive_mode(&renderer, IMMEDIATE_MODE_LINES);
+
+        f32 x = params->data[1].of.f32;
+        f32 y = params->data[2].of.f32;
+        f32 r = params->data[3].of.f32;
+        f32 a1 = params->data[4].of.f32;
+        f32 a2 = params->data[5].of.f32;
+        f32 segments = params->data[6].of.i32;
+
+        f32 cx1 = x + cos(a1 + 0 * (a2 - a1) / segments) * r;
+        f32 cy1 = y + sin(a1 + 0 * (a2 - a1) / segments) * r;
+        f32 cx2, cy2;
+
+        gfx_immediate_renderer_push_vertex(&renderer,   x,   y, 0, 0);
+        gfx_immediate_renderer_push_vertex(&renderer, cx1, cy1, 0, 0);
+
+        fori (i, 1, segments + 1) {
+            cx2 = x + cos(a1 + i * (a2 - a1) / segments) * r;
+            cy2 = y + sin(a1 + i * (a2 - a1) / segments) * r;
+
+            gfx_immediate_renderer_push_vertex(&renderer, cx1, cy1, 0, 0);
+            gfx_immediate_renderer_push_vertex(&renderer, cx2, cy2, 0, 0);
+
+            cx1 = cx2;
+            cy1 = cy2;
+        }
+
+        gfx_immediate_renderer_push_vertex(&renderer,   x,   y, 0, 0);
+        gfx_immediate_renderer_push_vertex(&renderer, cx1, cy1, 0, 0);
     }
 
     return NULL;
@@ -233,6 +335,7 @@ HEARTBREAK_DEF(image_draw, (WASM_I64, WASM_F32, WASM_F32, WASM_F32, WASM_F32), (
     if (w < 0) w = img->width;
     if (h < 0) h = img->height;
 
+    gfx_immediate_renderer_set_primitive_mode(&renderer, IMMEDIATE_MODE_TRIANGLES);
     gfx_image_bind(&renderer, img, 0);
 
     gfx_immediate_renderer_push_triangle(&renderer,
index 0967775b3d388d473e8c2440a62830c5833268b6..5465e62a3c80e69aff929d1237ce6f3de66aefa9 100644 (file)
         HB_EVENT(wheelmoved, (WASM_F32, WASM_F32))  \
         HB_EVENT(resize,     (WASM_I32, WASM_I32))  \
 
-#define HB_EVENT(name, pt) static wasm_func_t *__heartbreak_event_##name;
-HEARTBREAK_EVENTS
-#undef  HB_EVENT
-
 typedef struct HeartbreakEventType {
     const char*       name;
-    wasm_func_t**     func;
+    wasm_func_t*      func;
     WasmValkindBuffer params;
 } HeartbreakEventType;
 
-#define HB_EVENT(name, pt) static HeartbreakEventType __heartbreak_event_type_##name = { #name, &__heartbreak_event_##name, _VALS pt };
+#define HB_EVENT(name, pt) static HeartbreakEventType __heartbreak_event_type_##name = { #name, NULL, _VALS pt };
 HEARTBREAK_EVENTS
 #undef  HB_EVENT
 
 #define HEARTBREAK_EVENT_CALL(name, ...) __heartbreak_event_call(&__heartbreak_event_type_##name, __VA_ARGS__);
 
 void __heartbreak_event_call(HeartbreakEventType *ev, ...) {
-    if (*ev->func == NULL) return;
+    if (ev->func == NULL) return;
 
     va_list args;
     va_start(args, ev);
@@ -49,7 +45,7 @@ void __heartbreak_event_call(HeartbreakEventType *ev, ...) {
         }
     }
 
-    const wasm_trap_t* trap = wasm_func_call(*ev->func, &wasm_args, &wasm_results);
+    const wasm_trap_t* trap = wasm_func_call(ev->func, &wasm_args, &wasm_results);
     if (trap) {
         wasm_message_t msg;
         wasm_trap_message(trap, &msg);
@@ -96,8 +92,8 @@ static void __glfw_scroll_callback(GLFWwindow *w, f64 xoff, f64 yoff) {
 }
 
 typedef struct HeartbreakEventLink {
-    const char   *name;
-    wasm_func_t **func;
+    const char          *name;
+    HeartbreakEventType *ev;
 } HeartbreakEventLink;
 
 HEARTBREAK_DEF(init, (), (WASM_I32)) {
@@ -136,7 +132,7 @@ HEARTBREAK_DEF(init, (), (WASM_I32)) {
     glfwGetWindowSize(glfw_window, &width, &height);
     gfx_immediate_renderer_update_window_size(&renderer, (f32) width, (f32) height);
 
-    #define HB_EVENT(name, pt) { "__heartbreak_" #name, &__heartbreak_event_##name },
+    #define HB_EVENT(name, pt) { "__heartbreak_" #name, &__heartbreak_event_type_##name },
     static HeartbreakEventLink events[] = {
         HEARTBREAK_EVENTS
         { NULL }
@@ -147,7 +143,7 @@ HEARTBREAK_DEF(init, (), (WASM_I32)) {
     HeartbreakEventLink* ev = events;
     while (ev->name) {
         tmp_extern = wasm_extern_lookup_by_name(wasm_module, wasm_instance, ev->name);
-        if (tmp_extern) *ev->func = wasm_extern_as_func(tmp_extern);
+        if (tmp_extern) ev->ev->func = wasm_extern_as_func(tmp_extern);
         ev++;
     }
 
index c32bf464d43bd04b61682e3cbf617496e79195b3..4c8020b9bd65fa9223b6dd5e94787e09e9feb59e 100644 (file)
@@ -81,7 +81,7 @@ draw :: () {
     hb.graphics.setColor(0, 1, 0);
     hb.graphics.rectangle(.Fill, 0, 0, 100, 100);
     hb.graphics.setColor(1, 1, 0);
-    hb.graphics.rectangle(.Fill, 100, 100, 200, 100);
+    hb.graphics.rectangle(.Line, 100, 100, 200, 100);
 
     mx, my := hb.input.mouseGetPos();
     hb.graphics.push();
@@ -89,7 +89,7 @@ draw :: () {
     hb.graphics.rotate(t);
     hb.graphics.translate(~~ mx, ~~ my);
     hb.graphics.setColor(1, 0, 0);
-    hb.graphics.ellipse(.Fill, 0, 0, 25, 15 + 10 * math.sin(t));
+    hb.graphics.ellipse(.Line, 0, 0, 25, 15 + 10 * math.sin(t));
     hb.graphics.pop();
 
     hb.graphics.setColor(1, 1, 1, 1);
@@ -106,8 +106,11 @@ draw :: () {
     hb.graphics.rectangle(.Fill, w - 100, h - 100, 100, 100);
 
     hb.graphics.setColor(0, 0, 1);
-    hb.graphics.arc(.Fill, 300, 300, 100, math.PI / 4, math.PI * 7 / 4);
+    hb.graphics.arc(.Line, 300, 300, 100, math.PI / 4, math.PI * 7 / 4);
 
     hb.graphics.setColor(0, 1, 1);
-    hb.graphics.print("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+`~[{}]\|<,>./?'\";:", 100, 100, 200 + math.sin(t) * 100);
+    hb.graphics.print("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+`~[{}]\|<,>./?'\";:", 400, 100, 200 + math.sin(t) * 100);
+
+    hb.graphics.setColor(1, 1, 1);
+    hb.graphics.circle(.Line, 200, 500, 100, 100);
 }