diff --git a/README.md b/README.md index c4609a3..637679f 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,7 @@ - ## TODO - Physics forces/torque etc + - Replace all renderer_check_gl calls with GL_CHECK macro - Fix lights type not being correctly saved/loaded from file - Physics Trimesh support - Debug physics mesh drawing @@ -365,3 +366,4 @@ * Implemented Getting/Modifying primitive physics shapes' values like length, radius etc * Update physics if entity position/rotation/scale etc are changed * Implemented Physics raycasting + * Implemented immediate mode renderer that can draw arbitrary points, lines and triangles diff --git a/assets/shaders/im_geom.frag b/assets/shaders/im_geom.frag new file mode 100644 index 0000000..763d770 --- /dev/null +++ b/assets/shaders/im_geom.frag @@ -0,0 +1,10 @@ +//include version.glsl + +in vec4 color; + +out vec4 frag_color; + +void main() +{ + frag_color = color; +} diff --git a/assets/shaders/im_geom.vert b/assets/shaders/im_geom.vert new file mode 100644 index 0000000..2d20b2e --- /dev/null +++ b/assets/shaders/im_geom.vert @@ -0,0 +1,14 @@ +//include version.glsl + +uniform mat4 mvp; + +in vec3 vPosition; +in vec4 vColor; + +out vec4 color; + +void main() +{ + gl_Position = mvp * vec4(vPosition, 1.0); + color = vColor; +} diff --git a/src/libsymmetry/game.c b/src/libsymmetry/game.c index 6acd0d9..20d098a 100644 --- a/src/libsymmetry/game.c +++ b/src/libsymmetry/game.c @@ -30,6 +30,7 @@ #include "../common/hashmap.h" #include "../common/variant.h" #include "../common/common.h" +#include "im_render.h" #define UNUSED(a) (void)a #ifndef _MSC_VER @@ -450,6 +451,76 @@ void debug(float dt) } platform->physics.cs_remove(ray); } + + // Immediate geometry test + vec3 im_position = { 0.f, 20.f, 0.f }; + vec3 im_scale = { 1.f, 1.f, 1.f }; + quat im_rot = { 0.f, 0.f, 0.f, 1.f }; + quat_identity(&im_rot); + im_begin(im_position, im_rot, im_scale, GL_LINES); + + im_color(0.f, 1.f, 0.f, 1.f); + im_pos(0.f, 0.f, 0.f); + im_pos(100.f, 100.f, 10.f); + + im_end(); + + im_position.x = -10; + im_begin(im_position, im_rot, im_scale, GL_TRIANGLES); + + //Front + im_pos(0.f, 0.f, 0.f); + im_pos(0.f, 20.f, 0.f); + im_pos(20.f, 20.f, 0.f); + im_pos(20.f, 20.f, 0.f); + im_pos(20.f, 0.f, 0.f); + im_pos( 0.f, 0.f, 0.f); + + //Back + im_pos(0.f, 0.f, 20.f); + im_pos(0.f, 20.f, 20.f); + im_pos(20.f, 20.f, 20.f); + im_pos(20.f, 20.f, 20.f); + im_pos(20.f, 0.f, 20.f); + im_pos( 0.f, 0.f, 20.f); + + //Left + im_pos(0.f, 0.f, 0.f); + im_pos(0.f, 0.f, 20.f); + im_pos(0.f, 20.f, 20.f); + im_pos(0.f, 20.f, 20.f); + im_pos(0.f, 20.f, 0.f); + im_pos(0.f, 0.f, 20.f); + + //Right + im_pos(20.f, 0.f, 0.f); + im_pos(20.f, 0.f, 20.f); + im_pos(20.f, 20.f, 20.f); + im_pos(20.f, 20.f, 20.f); + im_pos(20.f, 20.f, 0.f); + im_pos(20.f, 0.f, 20.f); + + im_end(); + + im_position.x = -30.f; + im_begin(im_position, im_rot, im_scale, GL_LINES); + im_color(1.f, 1.f, 0.f, 1.f); + + im_pos(0.f, 0.f, 0.f); + im_pos(0.f, 0.f, 10.f); + + im_pos(0.f, 0.f, 10.f); + im_pos(0.f, 10.f, 10.f); + + im_pos(0.f, 10.f, 10.f); + im_pos(0.f, 10.f, 0.f); + + im_pos(0.f, 10.f, 0.f); + im_pos(0.f, 0.f, 0.f); + + im_end(); + + } bool run(void) diff --git a/src/libsymmetry/gl_load.c b/src/libsymmetry/gl_load.c index 6cce5ac..4a94f2a 100644 --- a/src/libsymmetry/gl_load.c +++ b/src/libsymmetry/gl_load.c @@ -44,4 +44,27 @@ bool gl_load_extentions(void) #undef GLE #endif return success; -} +} + +void gl_check_error(const char * expression, unsigned int line, const char * file) +{ + int error = 1; + GLenum error_code = glGetError(); + const char* error_string = "No Error"; + switch(error_code) + { + case GL_INVALID_OPERATION: error_string = "Invalid Operation"; break; + case GL_NO_ERROR: error_string = "No Error"; break; + case GL_INVALID_ENUM: error_string = "Invalid ENUM"; break; + case GL_INVALID_VALUE: error_string = "Invalid Value"; break; + case GL_INVALID_FRAMEBUFFER_OPERATION: error_string = "Invalid FrameBuffer Operation"; break; + case GL_OUT_OF_MEMORY: error_string = "Out of Memory"; break; + } + + if(error_code != GL_NO_ERROR) + log_error("GL", "(%s:%d:%s) : %s", file, line, expression, error_string); + else + error = 0; + + return error; +} diff --git a/src/libsymmetry/gl_load.h b/src/libsymmetry/gl_load.h index aa2902c..535c194 100644 --- a/src/libsymmetry/gl_load.h +++ b/src/libsymmetry/gl_load.h @@ -61,8 +61,17 @@ SYMMETRY_GL_LIST #endif + +#ifdef GL_DEBUG + #define GL_CHECK(expression) do { gl_check(#expression, __LINE__, __FILE__)} while(false) +#else + #define GL_CHECK(expression) (expression) + +#endif + int gl_load_library(void); bool gl_load_extentions(void); +void gl_check_error(const char* expression, unsigned int line, const char* file); void gl_cleanup(void); #endif diff --git a/src/libsymmetry/im_render.c b/src/libsymmetry/im_render.c new file mode 100644 index 0000000..a82ffca --- /dev/null +++ b/src/libsymmetry/im_render.c @@ -0,0 +1,157 @@ +#include "im_render.h" +#include "entity.h" +#include "camera.h" +#include "gl_load.h" +#include "../common/array.h" +#include "../common/num_types.h" +#include "shader.h" +#include "../common/log.h" + +#define MAX_IM_VERTICES 4096 +#define MAX_IM_GEOMETRIES (MAX_IM_VERTICES / 2) + +static struct +{ + struct IM_Vertex vertices[MAX_IM_VERTICES]; + struct IM_Geom geometries[MAX_IM_GEOMETRIES]; + uint vao; + uint vbo; + int im_shader; + int curr_geom; + int curr_vertex; + vec4 default_color; +} +IM_State; + +static struct IM_Geom* active_geom = NULL; +static vec4 active_vertex_color = { 0.f, 0.f, 0.f, 0.f }; + +void im_init(void) +{ + glGenVertexArrays(1, &IM_State.vao); + glBindVertexArray(IM_State.vao); + + glGenBuffers(1, &IM_State.vbo); + glBindBuffer(GL_ARRAY_BUFFER, IM_State.vbo); + GL_CHECK(glBufferData(GL_ARRAY_BUFFER, sizeof(struct IM_Vertex) * MAX_IM_VERTICES, NULL, GL_STREAM_DRAW)); + + //Position + GL_CHECK(glVertexAttribPointer(ATTRIB_LOC_POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(struct IM_Vertex), 0)); + GL_CHECK(glEnableVertexAttribArray(ATTRIB_LOC_POSITION)); + + //Color + GL_CHECK(glVertexAttribPointer(ATTRIB_LOC_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(struct IM_Vertex), sizeof(vec3))); + GL_CHECK(glEnableVertexAttribArray(ATTRIB_LOC_COLOR)); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glBindVertexArray(0); + + memset(&IM_State.geometries[0], 0, sizeof(struct IM_Geom) * MAX_IM_GEOMETRIES); + memset(&IM_State.vertices[0], 0, sizeof(struct IM_Vertex) * MAX_IM_VERTICES); + IM_State.curr_geom = -1; + IM_State.curr_vertex = 0; + vec4_fill(&IM_State.default_color, 1.f, 0.f, 1.f, 1.f); + vec4_assign(&active_vertex_color, &IM_State.default_color); + + IM_State.im_shader = shader_create("im_geom.vert", "im_geom.frag"); +} + +void im_cleanup(void) +{ + shader_remove(IM_State.im_shader); + glDeleteBuffers(1, &IM_State.vbo); + glDeleteVertexArrays(1, &IM_State.vao); + + memset(&IM_State.geometries[0], 0, sizeof(struct IM_Geom) * MAX_IM_GEOMETRIES); + memset(&IM_State.vertices[0], 0, sizeof(struct IM_Vertex) * MAX_IM_VERTICES); + IM_State.vao = 0; + IM_State.vbo = 0; + IM_State.curr_geom = -1; + IM_State.curr_vertex = 0; + IM_State.im_shader = -1; +} + +void im_begin(vec3 position, quat rotation, vec3 scale, int draw_mode) +{ + if(active_geom) + { + log_error("im_begin", "im_begin called before im_end"); + return; + } + IM_State.curr_geom++; + active_geom = &IM_State.geometries[IM_State.curr_geom]; + active_geom->start_index = IM_State.curr_vertex; + active_geom->draw_mode = draw_mode; + vec3_assign(&active_geom->position, &position); + vec3_assign(&active_geom->scale, &scale); + quat_assign(&active_geom->rotation, &rotation); +} + +void im_pos(float x, float y, float z) +{ + vec3_fill(&IM_State.vertices[IM_State.curr_vertex].position, x, y, z); + vec4_assign(&IM_State.vertices[IM_State.curr_vertex].color, &active_vertex_color); + IM_State.curr_vertex++; +} + +void im_color(float r, float g, float b, float a) +{ + vec4_fill(&active_vertex_color, r, g, b, a); +} + +void im_end(void) +{ + active_geom->num_vertices = IM_State.curr_vertex - active_geom->start_index; + glBindBuffer(GL_ARRAY_BUFFER, IM_State.vbo); + glBufferSubData(GL_ARRAY_BUFFER, + sizeof(struct IM_Vertex) * active_geom->start_index, + sizeof(struct IM_Vertex) * active_geom->num_vertices, + &IM_State.vertices[active_geom->start_index]); + renderer_check_glerror("sprite_batch_end:glBufferSubData"); + glBindBuffer(GL_ARRAY_BUFFER, 0); + active_geom = NULL; + vec4_assign(&active_vertex_color, &IM_State.default_color); +} + +void im_render(struct Entity* active_viewer) +{ + if(IM_State.curr_geom == -1) + return; + + shader_bind(IM_State.im_shader); + { + static mat4 mvp, translation, rotation, scale; + + glBindVertexArray(IM_State.vao); + for(int i = 0; i <= IM_State.curr_geom; i++) + { + struct IM_Geom* geom = &IM_State.geometries[i]; + mat4_identity(&mvp); + + mat4_identity(&scale); + mat4_identity(&translation); + mat4_identity(&rotation); + + mat4_scale(&scale, geom->scale.x, geom->scale.y, geom->scale.z); + mat4_translate(&translation, geom->position.x, geom->position.y, geom->position.z); + mat4_from_quat(&rotation, &geom->rotation); + + mat4_mul(&mvp, &mvp, &translation); + mat4_mul(&mvp, &mvp, &rotation); + mat4_mul(&mvp, &mvp, &scale); + + mat4_mul(&mvp, &active_viewer->camera.view_proj_mat, &mvp); + + shader_set_uniform_mat4(IM_State.im_shader, "mvp", &mvp); + + glDrawArrays(geom->draw_mode, geom->start_index, geom->num_vertices); + } + glBindVertexArray(0); + + } + shader_unbind(); + + IM_State.curr_geom = -1; + IM_State.curr_vertex = 0; +} diff --git a/src/libsymmetry/im_render.h b/src/libsymmetry/im_render.h new file mode 100644 index 0000000..5660405 --- /dev/null +++ b/src/libsymmetry/im_render.h @@ -0,0 +1,32 @@ +#ifndef IM_RENDER_H +#define IM_RENDER_H + +#include "../common/linmath.h" + +struct IM_Vertex +{ + vec3 position; + vec4 color; +}; + +struct IM_Geom +{ + vec3 position; + quat rotation; + vec3 scale; + int start_index; + int num_vertices; + int draw_mode; +}; + +struct Entity; + +void im_init(void); +void im_cleanup(void); +void im_begin(vec3 position, quat rotation, vec3 scale, int draw_mode); +void im_pos(float x, float y, float z); +void im_color(float r, float g, float b, float a); // set active color +void im_end(void); +void im_render(struct Entity* active_viewer); + +#endif \ No newline at end of file diff --git a/src/libsymmetry/renderer.c b/src/libsymmetry/renderer.c index 4b1edb3..41258fb 100644 --- a/src/libsymmetry/renderer.c +++ b/src/libsymmetry/renderer.c @@ -19,6 +19,7 @@ #include "material.h" #include "editor.h" #include "sprite.h" +#include "im_render.h" #include "../common/variant.h" #include "../common/common.h" @@ -131,6 +132,8 @@ void renderer_init(void) { sprite_batch_create(sprite_batch, "sprite_map.tga", "sprite.vert", "sprite.frag", GL_TRIANGLES); } + + im_init(); } void renderer_draw(struct Entity* active_viewer) @@ -405,7 +408,9 @@ void renderer_draw(struct Entity* active_viewer) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } - shader_unbind(); + //Immediate mode geometry render + im_render(active_viewer); + /* Render 2D stuff */ shader_bind(sprite_batch->shader); @@ -416,7 +421,7 @@ void renderer_draw(struct Entity* active_viewer) struct Game_State* game_state = game_state_get(); platform->window.get_size(game_state->window, &width, &height); - mat4_ortho(&ortho_mat, 0, width, height, 0, -10.f, 10.f); + mat4_ortho(&ortho_mat, 0.f, (float)width, (float)height, 0.f, -10.f, 10.f); shader_set_uniform_mat4(sprite_batch->shader, "mvp", &ortho_mat); sprite_batch_render(sprite_batch); @@ -429,6 +434,7 @@ void renderer_draw(struct Entity* active_viewer) void renderer_cleanup(void) { + im_cleanup(); sprite_batch_remove(sprite_batch); free(sprite_batch); gui_cleanup(); @@ -480,15 +486,11 @@ int renderer_check_glerror(const char* context) error = 0; return error; -} - -void im_render_box(float position, float length, float width, float height) -{ -} - -struct Sprite_Batch * get_batch(void) -{ - return sprite_batch; +} + +struct Sprite_Batch * get_batch(void) +{ + return sprite_batch; } void renderer_debug_draw_enabled(bool enabled) diff --git a/src/libsymmetry/renderer.h b/src/libsymmetry/renderer.h index 134f86f..b73c304 100644 --- a/src/libsymmetry/renderer.h +++ b/src/libsymmetry/renderer.h @@ -43,8 +43,6 @@ void renderer_clearcolor_set(float r, float g, float b, float a); void renderer_debug_draw_enabled(bool enabled); int renderer_check_glerror(const char* context); -void im_render_box(float position, float length, float width, float height); - struct Sprite_Batch* get_batch(void); #endif