From: Brendan Hansen Date: Tue, 2 Nov 2021 18:26:10 +0000 (-0500) Subject: added graphics.rectangle and graphics.set_color X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=57c73c99ffd6a66a36f5379d10be1f2e139b02bd;p=heartbreak.git added graphics.rectangle and graphics.set_color --- diff --git a/Makefile b/Makefile index d1a06d9..4c645d0 100644 --- 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 $< diff --git a/include/gfx.h b/include/gfx.h index 2e17a04..2585c1a 100644 --- a/include/gfx.h +++ b/include/gfx.h @@ -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 diff --git a/include/heartbreak.h b/include/heartbreak.h index ce5c463..8cf4b59 100644 --- a/include/heartbreak.h +++ b/include/heartbreak.h @@ -4,12 +4,15 @@ #include "bh.h" #include "wasm.h" #include "wasmer.h" + #include +#include "gfx.h" // // Global OpenGL / GLFW things // extern GLFWwindow* glfw_window; +extern ImmediateRenderer renderer; // diff --git a/include/utils.h b/include/utils.h index 9277421..c0734e1 100644 --- a/include/utils.h +++ b/include/utils.h @@ -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 diff --git a/src/gfx.c b/src/gfx.c index 39c5776..9d1ea2c 100644 --- 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 diff --git a/src/heartbreak.c b/src/heartbreak.c index acc952b..7b8449b 100644 --- a/src/heartbreak.c +++ b/src/heartbreak.c @@ -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 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); diff --git a/src/heartbreak_graphics.c b/src/heartbreak_graphics.c index 7a71b3c..b255f86 100644 --- a/src/heartbreak_graphics.c +++ b/src/heartbreak_graphics.c @@ -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; } diff --git a/src/heartbreak_system.c b/src/heartbreak_system.c index f91b25f..a0a3861 100644 --- a/src/heartbreak_system.c +++ b/src/heartbreak_system.c @@ -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(); diff --git a/src/utils.c b/src/utils.c index bc8b03f..5647b48 100644 --- a/src/utils.c +++ b/src/utils.c @@ -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); diff --git a/tests/simp.onyx b/tests/simp.onyx index 602717b..7181bcb 100644 --- a/tests/simp.onyx +++ b/tests/simp.onyx @@ -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