added graphics.rectangle and graphics.set_color
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 2 Nov 2021 18:26:10 +0000 (13:26 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 2 Nov 2021 18:26:10 +0000 (13:26 -0500)
Makefile
include/gfx.h
include/heartbreak.h
include/utils.h
src/gfx.c
src/heartbreak.c
src/heartbreak_graphics.c
src/heartbreak_system.c
src/utils.c
tests/simp.onyx

index d1a06d95219e1d3ae01a1e5362e83e2f37d3e5bc..4c645d048f2c680bcac1c65efeed41dbec926876 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ INCLUDES=-I./include -I./lib/linux_x86_64/include
 LIBS=-L./lib/linux_x86_64/lib -lwasmer -Wl,-rpath=./lib/linux_x86_64/lib -lglfw -lGL -lm
 TARGET=./bin/heartbreak
 
-OBJECT_FILES=./build/heartbreak.o ./build/utils.o ./build/heartbreak_system.o ./build/heartbreak_graphics.o ./build/heartbreak_input.o ./build/heartbreak_window.o
+OBJECT_FILES=./build/heartbreak.o ./build/utils.o ./build/gfx.o ./build/heartbreak_system.o ./build/heartbreak_graphics.o ./build/heartbreak_input.o ./build/heartbreak_window.o
 
 build/%.o: src/%.c
        $(CC) $(FLAGS) $(INCLUDES) -o $@ $(LIBS) -c $<
index 2e17a0466a34133b913c551518ba66401b876fab..2585c1ae70f96e9167ce117fa0bcebb75d827ad7 100644 (file)
@@ -20,10 +20,14 @@ typedef struct Shader {
 
 Shader gfx_shader_make_from_source(const char* vertex_src, const char* fragment_src);
 
+typedef struct ImmediateColor {
+    f32 r, g, b, a;
+} ImmediateColor;
+
 typedef struct ImmediateVertex {
     f32 x, y;
-    f32 r, g, b, a;
     f32 u, v;
+    ImmediateColor color;    
 } ImmediateVertex;
 
 #define VERTEX_DATA_MAX_COUNT 1020
@@ -33,6 +37,8 @@ typedef struct ImmediateRenderer {
     ImmediateVertex* vertex_data;
     u32              vertex_count;
 
+    ImmediateColor   current_color;
+
     GLint vertex_array;
     GLint vertex_buffer;
 
@@ -40,5 +46,13 @@ typedef struct ImmediateRenderer {
 } ImmediateRenderer;
 
 void gfx_immediate_renderer_init(ImmediateRenderer *ir);
+void gfx_immediate_renderer_flush(ImmediateRenderer *ir);
+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,
+    f32 x1, f32 y1, f32 u1, f32 v1,
+    f32 x2, f32 y2, f32 u2, f32 v2,
+    f32 x3, f32 y3, f32 u3, f32 v3);
+void gfx_immediate_renderer_update_window_size(ImmediateRenderer *ir, f32 width, f32 height);
 
 #endif
\ No newline at end of file
index ce5c4636b4d90dcf0c4c973dea0f2536b9146a6d..8cf4b59336c7a05a9fde5c2b1e1cddba1c56a2f3 100644 (file)
@@ -4,12 +4,15 @@
 #include "bh.h"
 #include "wasm.h"
 #include "wasmer.h"
+
 #include <GLFW/glfw3.h>
+#include "gfx.h"
 
 //
 // Global OpenGL / GLFW things
 //
 extern GLFWwindow* glfw_window;
+extern ImmediateRenderer renderer;
 
 
 //
index 927742114f4c7b157768569361572ef8dd240ef7..c0734e1db47170d9b5124cf7f9fabd1d10526109 100644 (file)
@@ -4,6 +4,12 @@
 #include "wasm.h"
 #include "bh.h"
 
+
+#ifndef offsetof
+#define offsetof(T, m) ((void *) &((T*)NULL)->(m))
+#endif
+
+
 //
 // Wasm-C-API Utilities
 // Things I think should come with the Wasm-C-API but don't
index 39c5776670efbba5be1799dae2e7e327bd85a6b5..9d1ea2c400a85886f07bf27a65e9f6857b51159e 100644 (file)
--- a/src/gfx.c
+++ b/src/gfx.c
@@ -1,9 +1,11 @@
 #include "gfx.h"
+#include "utils.h"
 
 static const char* SIMPLE_SHADER_VERTEX = "#version 300 es\n"
+"precision mediump float;\n"
 "layout(location = 0) in vec2 a_vertex;\n"
-"layout(location = 1) in vec4 a_color;\n"
-"layout(location = 2) in vec2 a_texture;\n"
+"layout(location = 1) in vec2 a_texture;\n"
+"layout(location = 2) in vec4 a_color;\n"
 "\n"
 "uniform mat4 u_view;\n"
 "uniform mat4 u_world;\n"
@@ -19,11 +21,11 @@ static const char* SIMPLE_SHADER_VERTEX = "#version 300 es\n"
 
 static const char* SIMPLE_SHADER_FRAGMENT = "#version 300 es\n"
 "precision mediump float;\n"
-"uniform sample2D u_texture;\n"
-"\n"
 "in vec4 v_color;\n"
 "in vec2 v_texture;\n"
 "\n"
+"uniform sampler2D u_texture;\n"
+"\n"
 "out vec4 fragColor;\n"
 "\n"
 "void main() {\n"
@@ -33,7 +35,7 @@ static const char* SIMPLE_SHADER_FRAGMENT = "#version 300 es\n"
 static b32 compile_shader(GLuint shader_type, const char *src, GLuint *out_shader) {
     GLuint s = glCreateShader(shader_type);
 
-    glShaderSource(s, 1, src, NULL);
+    glShaderSource(s, 1, (const char * const *) &src, NULL);
     glCompileShader(s);
 
     GLint successful;
@@ -62,7 +64,7 @@ static GLuint link_program(GLuint vertex_shader, GLuint fragment_shader) {
     if (successful != GL_TRUE) {
         GLsizei log_length = 0;
         GLchar program_log[1024];
-        glGetShaderInfoLog(s, 1023, &log_length, program_log);
+        glGetProgramInfoLog(program, 1023, &log_length, program_log);
 
         bh_printf("Error linking program:\n%s\n", program_log);
         return -1;
@@ -81,7 +83,7 @@ Shader gfx_shader_make_from_source(const char *vertex_src, const char *fragment_
     Shader shader;
     shader.program = program;
     
-    shader.position_loc = glGetAttribLocation(program, "a_position");
+    shader.position_loc = glGetAttribLocation(program, "a_vertex");
     shader.color_loc    = glGetAttribLocation(program, "a_color");
     shader.texture_loc  = glGetAttribLocation(program, "a_texture");
 
@@ -94,7 +96,7 @@ Shader gfx_shader_make_from_source(const char *vertex_src, const char *fragment_
 
 void gfx_immediate_renderer_init(ImmediateRenderer *ir) {
     ir->vertex_allocator = bh_heap_allocator();
-    ir->vertex_data      = bh_alloc(ir->vertex_allocator, sizeof(ImmediateVertex) * VERTEX_DATA_MAX_COUN);
+    ir->vertex_data      = bh_alloc(ir->vertex_allocator, sizeof(ImmediateVertex) * VERTEX_DATA_MAX_COUNT);
     ir->vertex_count     = 0;
 
     ir->simple_shader = gfx_shader_make_from_source(SIMPLE_SHADER_VERTEX, SIMPLE_SHADER_FRAGMENT);
@@ -106,5 +108,84 @@ void gfx_immediate_renderer_init(ImmediateRenderer *ir) {
     glBindBuffer(GL_ARRAY_BUFFER, ir->vertex_buffer);
     glBufferData(GL_ARRAY_BUFFER, sizeof(ImmediateVertex) * VERTEX_DATA_MAX_COUNT, NULL, GL_STREAM_DRAW);
 
+    glEnableVertexAttribArray(ir->simple_shader.position_loc);
+    glEnableVertexAttribArray(ir->simple_shader.texture_loc);
+    glEnableVertexAttribArray(ir->simple_shader.color_loc);
+
+    glVertexAttribPointer(ir->simple_shader.position_loc, 2, GL_FLOAT, false, sizeof(ImmediateVertex), (void*) offsetof(ImmediateVertex, x));
+    glVertexAttribPointer(ir->simple_shader.texture_loc,  2, GL_FLOAT, false, sizeof(ImmediateVertex), (void*) offsetof(ImmediateVertex, u));
+    glVertexAttribPointer(ir->simple_shader.color_loc,    4, GL_FLOAT, false, sizeof(ImmediateVertex), (void*) offsetof(ImmediateVertex, color));
+    glBindBuffer(GL_ARRAY_BUFFER, -1);
+
+    glBindVertexArray(-1);
+
+    glUseProgram(ir->simple_shader.program);
+
+    static const f32 identity_matrix[] = {
+        1,0,0,0,
+        0,1,0,0,
+        0,0,1,0,
+        0,0,0,1
+    };
+
+    glUniformMatrix4fv(ir->simple_shader.view_uniform,  1, 0, identity_matrix);
+    glUniformMatrix4fv(ir->simple_shader.world_uniform, 1, 0, identity_matrix);
+
+    ir->current_color = (ImmediateColor) { 1, 1, 1, 1 };
+}
+
+void gfx_immediate_renderer_flush(ImmediateRenderer *ir) {
+    glBindBuffer(GL_ARRAY_BUFFER, ir->vertex_buffer);
+    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(ImmediateVertex) * ir->vertex_count, ir->vertex_data);
+    glBindBuffer(GL_ARRAY_BUFFER, -1);
+
+    glUseProgram(ir->simple_shader.program);
+    glBindVertexArray(ir->vertex_array);
+    glDrawArrays(GL_TRIANGLES, 0, ir->vertex_count);
     glBindVertexArray(-1);
+
+    ir->vertex_count = 0;
+}
+
+void gfx_immediate_renderer_set_color(ImmediateRenderer *ir, ImmediateColor color) {
+    ir->current_color = color;
+}
+
+void gfx_immediate_renderer_push_vertex(ImmediateRenderer *ir, f32 x, f32 y, f32 u, f32 v) {
+    ir->vertex_data[ir->vertex_count++] = (ImmediateVertex) { x, y, u, v, ir->current_color };
+}
+
+void gfx_immediate_renderer_push_triangle(ImmediateRenderer *ir,
+    f32 x1, f32 y1, f32 u1, f32 v1,
+    f32 x2, f32 y2, f32 u2, f32 v2,
+    f32 x3, f32 y3, f32 u3, f32 v3) {
+
+    if (ir->vertex_count - 3 >= VERTEX_DATA_MAX_COUNT) {
+        gfx_immediate_renderer_flush(ir);
+    }
+
+    assert(ir->vertex_count % 3 == 0); // Must be aligned to a triangle
+
+    ir->vertex_data[ir->vertex_count + 0] = (ImmediateVertex) { x1, y1, u1, v1, ir->current_color };
+    ir->vertex_data[ir->vertex_count + 1] = (ImmediateVertex) { x2, y2, u2, v2, ir->current_color };
+    ir->vertex_data[ir->vertex_count + 2] = (ImmediateVertex) { x3, y3, u3, v3, ir->current_color };
+    ir->vertex_count += 3;
+}
+
+void gfx_immediate_renderer_update_window_size(ImmediateRenderer *ir, f32 width, f32 height) {
+    f32 left = 0;
+    f32 right = width;
+    f32 top = 0;
+    f32 bottom = height;
+    f32 far = 100.0;
+    f32 near = 0.0;
+
+    f32 camera_matrix[] = {
+        2 / (right - left), 0, 0, 0,
+        0, 2 / (top - bottom), 0, 0,
+        0, 0, -2 / (far - near), 0,
+        -(right + left) / (right - left), -(top + bottom) / (top - bottom), -(far + near) / (far - near), 1,
+    };
+
+    glUniformMatrix4fv(ir->simple_shader.view_uniform, 1, false, camera_matrix);
 }
\ No newline at end of file
index acc952bc191fc9cc53712fb5577f86193b5f6411..7b8449bb82f3a44a48471d1bf5f13a8c2aabad1d 100644 (file)
@@ -4,6 +4,7 @@
 #include "bh.h"
 #include "utils.h"
 #include "heartbreak.h"
+#include "gfx.h"
 
 #include "wasm.h"
 #include "wasmer.h"
@@ -11,6 +12,7 @@
 #include <GLFW/glfw3.h>
 
 GLFWwindow* glfw_window = NULL;
+ImmediateRenderer renderer;
 
 void build_heartbreak_imports(WasmFuncDefinition** out_wfds, i32* out_count) {
     static WasmFuncDefinition* modules[] = {
@@ -92,7 +94,7 @@ void run_wasm_file(bh_buffer wasm_bytes) {
     build_heartbreak_imports(&defs, &defs_count);
 
     wasm_name_t heartbreak_name;
-    wasm_name_new_from_string(&heartbreak_name, "heartbreak");
+    wasm_name_new_from_string(&heartbreak_name, "heartbreak"); // @Free
 
     wasm_importtype_vec_t module_imports;    // @Free
     wasm_module_imports(module, &module_imports);
index 7a71b3c74d834b1805930e1a0592bed205625b9b..b255f8637b7abfb86a21f99a99fd4970456290b5 100644 (file)
@@ -19,11 +19,30 @@ HEARTBREAK_DEF(clear, (), ()) {
 }
 
 HEARTBREAK_DEF(set_color, (WASM_F32,WASM_F32,WASM_F32,WASM_F32), ()) {
-
+    ImmediateColor c;
+    c.r = params->data[0].of.f32;
+    c.g = params->data[1].of.f32;
+    c.b = params->data[2].of.f32;
+    c.a = params->data[3].of.f32;
+    gfx_immediate_renderer_set_color(&renderer, c);
     return NULL;
 }
 
 HEARTBREAK_DEF(rectangle, (WASM_I32,WASM_F32,WASM_F32,WASM_F32,WASM_F32), ()) {
+    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);
+
+    gfx_immediate_renderer_push_triangle(&renderer,
+        x, y, 0, 0,
+        x + w, y + h, 0, 0,
+        x, y + h, 0, 0);
 
     return NULL;
 }
index f91b25f30d2590e7c8b4ce4363ee84fb73c643bc..a0a386168fddd54a47a68afb521f68b2a5c37ed5 100644 (file)
@@ -1,4 +1,5 @@
 #include "heartbreak.h"
+#include "gfx.h"
 
 #define HEARTBREAK_MODULE_NAME system
 
@@ -9,8 +10,6 @@ HEARTBREAK_DEF(init, (), (WASM_I32)) {
         return NULL;
     }
 
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
-    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
     glfw_window = glfwCreateWindow(800, 600, "Heartbreak", NULL, NULL);
     if (!glfw_window) {
         bh_printf("Failed to create GLFW window.\n");
@@ -18,8 +17,19 @@ HEARTBREAK_DEF(init, (), (WASM_I32)) {
         return NULL;
     }
 
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
     glfwMakeContextCurrent(glfw_window);
 
+    glfwSwapInterval(1);
+
+    gfx_immediate_renderer_init(&renderer);
+
+    i32 width, height;
+    glfwGetWindowSize(glfw_window, &width, &height);
+    glViewport(0, 0, width, height);
+    gfx_immediate_renderer_update_window_size(&renderer, (f32) width, (f32) height);
+
     results->data[0] = WASM_I32_VAL(1);
     return NULL;
 }
@@ -34,6 +44,8 @@ HEARTBREAK_DEF(destroy, (), ()) {
 // main loop. This function also returns if the application should stay running.
 //
 HEARTBREAK_DEF(end_frame, (), (WASM_I32)) {
+    gfx_immediate_renderer_flush(&renderer);
+
     glfwSwapBuffers(glfw_window);
     glfwPollEvents();
 
index bc8b03fbc619999e4f07498d8a64c51858fd1ede..5647b481021ba6bb2aaf14c72490301135852b28 100644 (file)
@@ -31,6 +31,8 @@ wasm_extern_t* wasm_extern_lookup_by_name(wasm_module_t* module, wasm_instance_t
         }
     }
 
+    if (idx == -1) return NULL;
+
     wasm_extern_vec_t exports;
     wasm_instance_exports(instance, &exports);
 
index 602717be26a331207f23a1ef32ba0c1fedc0286a..7181bcb15199a061c71d970e86f0784216785072 100644 (file)
@@ -9,7 +9,7 @@ init :: () {
     h := hb.window.getHeight();
     printf("The window is {}x{}\n", w, h);
 
-    hb.window.setDimensions(1200, 900);
+    // hb.window.setDimensions(1200, 900);
 }
 
 t: f32 = 0;
@@ -31,6 +31,10 @@ 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.setColor(1, 1, 1);
+    hb.graphics.rectangle(.Fill, 700, 500, 100, 100);
 }
 
 main :: (_) => hb.run(.{ init, update, draw });
\ No newline at end of file