From 0c77b3a2307b43d9a2f0c43468766bd5924336f3 Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Sat, 24 Oct 2020 11:05:31 +0200 Subject: [PATCH] Transformed srender to a single header library, added srcmdbuf_add(cmd); --- src/srender.c | 578 +---------------------------------------------- src/srender.h | 606 +++++++++++++++++++++++++++++++++++++++++++++++++- src/vissim.cc | 16 +- 3 files changed, 616 insertions(+), 584 deletions(-) diff --git a/src/srender.c b/src/srender.c index edec532..20ed4ed 100644 --- a/src/srender.c +++ b/src/srender.c @@ -2,580 +2,8 @@ #include // clang-format on +#define SRENDER_IMPLEMENTATION + #include "srender.h" +#undef SRENDER_IMPLEMENTATION -#include "utils.h" - -#include -#include - -typedef struct srndr { -} srndr; - -typedef struct srview { - GLuint width; - GLuint height; - - GLuint mFrameBufferId; - GLuint mColorTexture; - GLuint mDepthTexture; - - simd4x4f proj; - simd4x4f view; -} srview; - -typedef struct srcmdbuf { - int nbufsize; - int ncmds; - srcmd* cmds; -} srcmdbuf; - -// -// Vertex Data -// -typedef union srvrtxdata { - struct { - float x, y, z, w; - float nx, ny, nz; - float s, t; - GLubyte r, g, b, a; - }; - struct { - float pos[4]; - float n[4]; - float uv[2]; - GLubyte color[4]; - }; -} srvrtxdata; - -// -// Vertex Buffer Object for all debug objects (coord frame, grid, cube, ...) -// -const GLint DEBUG_VBO_SIZE = 1024; -GLuint gDebugShapesVBOId = 0; -GLuint gDebugShapesVAId = 0; - -// -// Simple Mesh Data -// -typedef struct srmeshdata { - int nvertices; - int nindices; - - GLuint vao_id; - GLuint vb_id; - GLuint idb_id; - - GLuint count; - GLenum mode; -} srmeshdata; - -static srmeshdata gCoordFrameMesh = {0}; -static srmeshdata gGridMesh = {0}; - -typedef struct srshader { - const char* vert_fname; - const char* frag_fname; - - GLuint program_id; - GLuint vert_shader_id; - GLuint frag_shader_id; -} srshader; - -static srshader gDefaultShader = - {"default_vert.glsl", "default_frag.glsl", 0, 0, 0}; - -bool srshader_compile(GLuint shader_id, const char* shader_src) { - glShaderSource(shader_id, 1, &shader_src, 0); - glCompileShader(shader_id); - - // Check Vertex Shader - GLint result = GL_FALSE; - int log_length = 0; - glGetShaderiv(shader_id, GL_COMPILE_STATUS, &result); - glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &log_length); - if (log_length > 0) { - char* err_msg = calloc(log_length, sizeof(char)); - assert(err_msg); - glGetShaderInfoLog(shader_id, log_length, NULL, err_msg); - gLog("%s", err_msg); - free(err_msg); - - return false; - } - - return true; -} - -bool srshader_load( - srshader* shader, - const char* vert_src, - const char* frag_src) { - shader->vert_shader_id = glCreateShader(GL_VERTEX_SHADER); - if (!srshader_compile(shader->vert_shader_id, vert_src)) { - gLog("Error compiling vertex shader!"); - return false; - } - - shader->frag_shader_id = glCreateShader(GL_FRAGMENT_SHADER); - if (!srshader_compile(shader->frag_shader_id, frag_src)) { - gLog("Error compiling fragment shader!"); - return false; - } - - shader->program_id = glCreateProgram(); - glAttachShader(shader->program_id, shader->vert_shader_id); - glAttachShader(shader->program_id, shader->frag_shader_id); - - // Bind attribute locations - glBindAttribLocation(shader->program_id, 0, "inCoord"); - glBindAttribLocation(shader->program_id, 1, "inNormal"); - glBindAttribLocation(shader->program_id, 2, "inUV"); - glBindAttribLocation(shader->program_id, 3, "inColor"); - - glLinkProgram(shader->program_id); - - GLint result = GL_FALSE; - int log_length = 0; - glGetProgramiv(shader->program_id, GL_LINK_STATUS, &result); - glGetProgramiv(shader->program_id, GL_INFO_LOG_LENGTH, &log_length); - if (log_length > 0) { - char* err_msg = calloc(log_length, sizeof(char)); - assert(err_msg); - glGetProgramInfoLog(shader->program_id, log_length, NULL, err_msg); - gLog("%s", err_msg); - free(err_msg); - gLog("Error linking shader program!"); - - return false; - } - - return true; -} - -bool try_read_file(const char* dir, const char* filename, char** buf) { - assert(*buf == NULL); - - int path_len = strlen(dir) + strlen(filename) + 1; - char* path_buffer = calloc(path_len, sizeof(char)); - snprintf(path_buffer, path_len, "%s%s", dir, filename); - long file_length = 0; - - FILE* file = NULL; - file = fopen(path_buffer, "rb"); - if (file) { - fseek(file, 0, SEEK_END); - file_length = ftell(file); - fseek(file, 0, SEEK_SET); - *buf = calloc(file_length, sizeof(char)); - assert(*buf); - fread(*buf, 1, file_length, file); - fclose(file); - - return true; - } - - return false; -} - -void init_shaders() { - static const char* shader_search_paths[] = { - "./data/shaders/", - "../data/shaders/", - NULL}; - - bool found = false; - int search_index = 0; - char* frag_buffer = NULL; - char* vert_buffer = NULL; - - while (shader_search_paths[search_index] != NULL) { - const char* dir = shader_search_paths[search_index]; - static char path_buf[1024]; - long length; - - if (vert_buffer == NULL) { - try_read_file(dir, gDefaultShader.vert_fname, &vert_buffer); - } - if (frag_buffer == NULL) { - try_read_file(dir, gDefaultShader.frag_fname, &frag_buffer); - } - - if ((vert_buffer != NULL) && (frag_buffer != NULL)) { - srshader_load(&gDefaultShader, vert_buffer, frag_buffer); - - free(vert_buffer); - vert_buffer = NULL; - free(frag_buffer); - frag_buffer = NULL; - break; - } - - search_index++; - } - - if (gDefaultShader.program_id == 0) { - gLog("Error: could not load default shader!"); - } -} - -void init_debug_meshes() { - assert(gCoordFrameMesh.nvertices == 0); - - glGenVertexArrays(1, &gDebugShapesVAId); - glBindVertexArray(gDebugShapesVAId); - - glGenBuffers(1, &gDebugShapesVBOId); - glBindBuffer(GL_ARRAY_BUFFER, gDebugShapesVBOId); - glBufferData(GL_ARRAY_BUFFER, sizeof(union srvrtxdata) * DEBUG_VBO_SIZE, NULL, GL_STATIC_DRAW); - - GLintptr dbg_vbuf_offset = 0; - - glEnableVertexAttribArray(0); - glVertexAttribPointer( - 0, - 4, - GL_FLOAT, - GL_FALSE, - (sizeof(srvrtxdata)), - (void*)0); - - glEnableVertexAttribArray(1); - glVertexAttribPointer( - 1, - 3, - GL_FLOAT, - GL_FALSE, - (sizeof(srvrtxdata)), - (void*)(sizeof(float) * 4)); - - // Attribute 2: texture coordinates - glEnableVertexAttribArray(2); - glVertexAttribPointer( - 2, - 2, - GL_FLOAT, - GL_FALSE, - (sizeof(srvrtxdata)), - (void*)(sizeof(float) * 7)); - // Attribute 3: color - glEnableVertexAttribArray(3); - glVertexAttribPointer( - 3, - 4, - GL_UNSIGNED_BYTE, - GL_TRUE, - (sizeof(srvrtxdata)), - (void*)(sizeof(float) * 9)); - - // - // Coordinate Frame - // - gCoordFrameMesh.vao_id = gDebugShapesVAId; - gCoordFrameMesh.vb_id = gDebugShapesVBOId; - gCoordFrameMesh.nvertices = 6; - - srvrtxdata coord_frame_vertices[] = { - {0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 255, 0, 0, 255}, - {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 255, 0, 0, 255}, - - {0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, 255, 0, 255}, - {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, 255, 0, 255}, - - {0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, 0, 255, 255}, - {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, 0, 255, 255}}; - GLuint coord_frame_indices[] = {0, 1, 2, 3, 4, 5}; - - glBufferSubData( - GL_ARRAY_BUFFER, - dbg_vbuf_offset, - sizeof(coord_frame_vertices), - coord_frame_vertices); - dbg_vbuf_offset = sizeof (coord_frame_vertices); - - glGenBuffers(1, &gCoordFrameMesh.idb_id); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gCoordFrameMesh.idb_id); - glBufferData( - GL_ELEMENT_ARRAY_BUFFER, - sizeof(coord_frame_indices), - coord_frame_indices, - GL_STATIC_DRAW); - - gCoordFrameMesh.mode = GL_LINES; - gCoordFrameMesh.count = 6; - - // - // Coordinate Frame - // - gGridMesh.vao_id = gDebugShapesVAId; - gGridMesh.vb_id = gDebugShapesVBOId; - gGridMesh.nvertices = 44; - - srvrtxdata* grid_vertices = calloc(44, sizeof(srvrtxdata)); - srvrtxdata grid_def_vertex = { - 0.f, 0.f, 0.f, 1.f, - 0.f, 1.f, 0.f, - 0.f, 0.f, - 255, 255, 255, 255 - }; - // lines along parallel to x axis - for (int i = 0; i <= 10; i++) { - memcpy (&grid_vertices[2*i], &grid_def_vertex, sizeof(srvrtxdata)); - memcpy (&grid_vertices[2*i + 1], &grid_def_vertex, sizeof(srvrtxdata)); - grid_vertices[2 * i].pos[0] = -5.0f + i * 1.0f; - grid_vertices[2 * i].pos[2] = 5.0f; - grid_vertices[2 * i + 1].pos[0] = -5.0f + i * 1.0f; - grid_vertices[2 * i + 1].pos[2] = -5.0f; - } - // lines parallel to z axis - for (int i = 11; i <= 21; i++) { - memcpy (&grid_vertices[2*i], &grid_def_vertex, sizeof(srvrtxdata)); - memcpy (&grid_vertices[2*i + 1], &grid_def_vertex, sizeof(srvrtxdata)); - grid_vertices[2 * i].pos[0] = -5.0f; - grid_vertices[2 * i].pos[2] = -5.0f + (i - 11) * 1.0f; - grid_vertices[2 * i + 1].pos[0] = 5.0f; - grid_vertices[2 * i + 1].pos[2] = -5.0f + (i - 11) * 1.0f; - } - - glBindBuffer(GL_ARRAY_BUFFER, gDebugShapesVBOId); - glBufferSubData( - GL_ARRAY_BUFFER, - dbg_vbuf_offset, - sizeof(srvrtxdata) * 44, - grid_vertices); - dbg_vbuf_offset += sizeof (srvrtxdata) * 44; - - free(grid_vertices); - - GLuint grid_indices[44]; - for (int i = 0; i < 22; i++) { - grid_indices[2 * i] = 2*i + 6; - grid_indices[2 * i + 1] = (2*i+1) + 6; - } - - glGenBuffers(1, &gGridMesh.idb_id); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gGridMesh.idb_id); - glBufferData( - GL_ELEMENT_ARRAY_BUFFER, - sizeof(grid_indices), - grid_indices, - GL_STATIC_DRAW); - - gGridMesh.mode = GL_LINES; - gGridMesh.count = 44; - - glBindVertexArray(0); -}; - -// -// Renderer -// -srndr* srndr_create() { - srndr* result = calloc(1, sizeof(srndr)); - - init_shaders(); - init_debug_meshes(); - - return result; -} - -void srndr_destroy(srndr* sr) { free(sr); } - -// -// View -// -void srview_get_output_texture(srview* sv, GLuint* texture) { - *texture = sv->mColorTexture; -} - -void srview_set_proj(srview* sv, simd4x4f proj) { sv->proj = proj; } - -void srview_set_view(srview* sv, simd4x4f view) { sv->view = view; } - -void srview_update_framebuffer(srview* sv) { - glGenFramebuffers(1, &sv->mFrameBufferId); - glBindFramebuffer(GL_FRAMEBUFFER, sv->mFrameBufferId); - - // Color Texture - glGenTextures(1, &sv->mColorTexture); - glBindTexture(GL_TEXTURE_2D, sv->mColorTexture); - - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_RGB, - sv->width, - sv->height, - 0, - GL_RGB, - GL_UNSIGNED_BYTE, - 0); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - sv->mColorTexture, - 0); - - // Depth Texture - glGenTextures(1, &sv->mDepthTexture); - glBindTexture(GL_TEXTURE_2D, sv->mDepthTexture); - - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_DEPTH_COMPONENT, - sv->width, - sv->height, - 0, - GL_DEPTH_COMPONENT, - GL_FLOAT, - 0); - - // Set parameters so that we can set a shadow2DSampler - glTexParameteri( - GL_TEXTURE_2D, - GL_TEXTURE_COMPARE_MODE, - GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - float border_color[] = {1.0f, 1.0f, 1.0f, 1.0f}; - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); - - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, - sv->mDepthTexture, - 0); -} - -void srview_cleanup_framebuffer(srview* sv) { - if (glIsFramebuffer(sv->mFrameBufferId)) { - glDeleteFramebuffers(1, &sv->mFrameBufferId); - } - - if (sv->mColorTexture != -1) { - glDeleteTextures(1, &sv->mColorTexture); - sv->mColorTexture = -1; - } - - if (sv->mDepthTexture != -1) { - glDeleteTextures(1, &sv->mDepthTexture); - sv->mDepthTexture = -1; - } -} - -void srview_set_size(srview* sv, int width, int height) { - if (sv->width == width && sv->height == height) { - return; - } - - sv->width = width; - sv->height = height; - - srview_cleanup_framebuffer(sv); - srview_update_framebuffer(sv); -} - -srview* srview_create() { - srview* result = calloc(1, sizeof(srview)); - - return result; -} - -void srview_destroy(srview* sv) { - srview_cleanup_framebuffer(sv); - - free(sv); -} - -void srndr_run_frame_command(const srcmd* cmd) { - glBindVertexArray(gCoordFrameMesh.vao_id); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gCoordFrameMesh.idb_id); - glDrawElements(gCoordFrameMesh.mode, gCoordFrameMesh.count, GL_UNSIGNED_INT, (void*)0); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -void srndr_run_grid_command(const srcmd* cmd) { - glBindVertexArray(gGridMesh.vao_id); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gGridMesh.idb_id); - glDrawElements(gGridMesh.mode, gGridMesh.count, GL_UNSIGNED_INT, (void*)0); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); -} - -void srndr_render(srndr* srndr, srview* sview, srcmdbuf* scmdbuf) { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, sview->mFrameBufferId); - - glViewport(0, 0, sview->width, sview->height); - glClearColor(0.1f, 0.1f, 0.1f, 0.1f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glUseProgram(gDefaultShader.program_id); - GLint view_mat_loc = - glGetUniformLocation(gDefaultShader.program_id, "uViewMatrix"); - assert(view_mat_loc != -1); - glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, &sview->view); - - GLint proj_mat_loc = - glGetUniformLocation(gDefaultShader.program_id, "uProjectionMatrix"); - assert(proj_mat_loc != -1); - glUniformMatrix4fv(proj_mat_loc, 1, GL_FALSE, &sview->proj); - - GLint model_mat_loc = - glGetUniformLocation(gDefaultShader.program_id, "uModelMatrix"); - assert(model_mat_loc != -1); - - for (int i = 0; i < scmdbuf->ncmds; i++) { - const srcmd* cmd = &scmdbuf->cmds[i]; - glUniformMatrix4fv(model_mat_loc, 1, GL_FALSE, &cmd->mat); - - switch (cmd->type) { - case SRndrCmdTypeFrame: - srndr_run_frame_command(cmd); - break; - case SRndrCmdTypeGrid: - srndr_run_grid_command(cmd); - break; - default: - gLog("Invalid command type %d at index %d", cmd->type, i); - break; - } - } - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -} - -// -// Render Commands -// -srcmdbuf* srcmdbuf_create(unsigned int size_max) { - srcmdbuf* result = malloc(sizeof(srcmdbuf)); - result->nbufsize = size_max; - result->ncmds = 0; - result->cmds = calloc(sizeof(srcmd), size_max); - - return result; -} - -void srcmdbuf_clear(srcmdbuf* cmdbuf) { cmdbuf->ncmds = 0; } - -srcmd* srcmd_create(srcmdbuf* cmdbuf) { - if (cmdbuf->ncmds == cmdbuf->nbufsize) { - gLog("Warning: number of render commands maxed out!"); - return NULL; - } - return &(cmdbuf->cmds[cmdbuf->ncmds++]); -} diff --git a/src/srender.h b/src/srender.h index a4277b0..9947afc 100644 --- a/src/srender.h +++ b/src/srender.h @@ -5,6 +5,7 @@ extern "C" { #endif +#include #include "vectorial/simd4x4f.h" typedef struct srndr srndr; @@ -45,14 +46,617 @@ void srview_get_output_texture(srview* sv, GLuint* texture); // // Command Buffer and Commands // +void srcmd_clear (srcmd *cmd); + srcmdbuf* srcmdbuf_create(unsigned int size_max); void srcmdbuf_clear(srcmdbuf* cmdbuf); +bool srcmdbuf_add(srcmdbuf* cmdbuf, srcmd *cmd); srcmd* srcmd_create(srcmdbuf* cmdbuf); void srndr_render(srndr* srndr, srview* sview, srcmdbuf* scmdbuf); +// +// srender Implementation +// + +#ifdef SRENDER_IMPLEMENTATION + +#include "utils.h" + +#include +#include + +typedef struct srndr { +} srndr; + +typedef struct srview { + GLuint width; + GLuint height; + + GLuint mFrameBufferId; + GLuint mColorTexture; + GLuint mDepthTexture; + + simd4x4f proj; + simd4x4f view; +} srview; + +typedef struct srcmdbuf { + int nbufsize; + int ncmds; + srcmd* cmds; +} srcmdbuf; + +// +// Vertex Data +// +typedef union srvrtxdata { + struct { + float x, y, z, w; + float nx, ny, nz; + float s, t; + GLubyte r, g, b, a; + }; + struct { + float pos[4]; + float n[4]; + float uv[2]; + GLubyte color[4]; + }; +} srvrtxdata; + +// +// Vertex Buffer Object for all debug objects (coord frame, grid, cube, ...) +// +const GLint DEBUG_VBO_SIZE = 1024; +GLuint gDebugShapesVBOId = 0; +GLuint gDebugShapesVAId = 0; + +// +// Simple Mesh Data +// +typedef struct srmeshdata { + int nvertices; + int nindices; + + GLuint vao_id; + GLuint vb_id; + GLuint idb_id; + + GLuint count; + GLenum mode; +} srmeshdata; + +static srmeshdata gCoordFrameMesh = {0}; +static srmeshdata gGridMesh = {0}; + +typedef struct srshader { + const char* vert_fname; + const char* frag_fname; + + GLuint program_id; + GLuint vert_shader_id; + GLuint frag_shader_id; +} srshader; + +static srshader gDefaultShader = + {"default_vert.glsl", "default_frag.glsl", 0, 0, 0}; + +bool srshader_compile(GLuint shader_id, const char* shader_src) { + glShaderSource(shader_id, 1, &shader_src, 0); + glCompileShader(shader_id); + + // Check Vertex Shader + GLint result = GL_FALSE; + int log_length = 0; + glGetShaderiv(shader_id, GL_COMPILE_STATUS, &result); + glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &log_length); + if (log_length > 0) { + char* err_msg = calloc(log_length, sizeof(char)); + assert(err_msg); + glGetShaderInfoLog(shader_id, log_length, NULL, err_msg); + gLog("%s", err_msg); + free(err_msg); + + return false; + } + + return true; +} + +bool srshader_load( + srshader* shader, + const char* vert_src, + const char* frag_src) { + shader->vert_shader_id = glCreateShader(GL_VERTEX_SHADER); + if (!srshader_compile(shader->vert_shader_id, vert_src)) { + gLog("Error compiling vertex shader!"); + return false; + } + + shader->frag_shader_id = glCreateShader(GL_FRAGMENT_SHADER); + if (!srshader_compile(shader->frag_shader_id, frag_src)) { + gLog("Error compiling fragment shader!"); + return false; + } + + shader->program_id = glCreateProgram(); + glAttachShader(shader->program_id, shader->vert_shader_id); + glAttachShader(shader->program_id, shader->frag_shader_id); + + // Bind attribute locations + glBindAttribLocation(shader->program_id, 0, "inCoord"); + glBindAttribLocation(shader->program_id, 1, "inNormal"); + glBindAttribLocation(shader->program_id, 2, "inUV"); + glBindAttribLocation(shader->program_id, 3, "inColor"); + + glLinkProgram(shader->program_id); + + GLint result = GL_FALSE; + int log_length = 0; + glGetProgramiv(shader->program_id, GL_LINK_STATUS, &result); + glGetProgramiv(shader->program_id, GL_INFO_LOG_LENGTH, &log_length); + if (log_length > 0) { + char* err_msg = calloc(log_length, sizeof(char)); + assert(err_msg); + glGetProgramInfoLog(shader->program_id, log_length, NULL, err_msg); + gLog("%s", err_msg); + free(err_msg); + gLog("Error linking shader program!"); + + return false; + } + + return true; +} + +bool try_read_file(const char* dir, const char* filename, char** buf) { + assert(*buf == NULL); + + int path_len = strlen(dir) + strlen(filename) + 1; + char* path_buffer = calloc(path_len, sizeof(char)); + snprintf(path_buffer, path_len, "%s%s", dir, filename); + long file_length = 0; + + FILE* file = NULL; + file = fopen(path_buffer, "rb"); + if (file) { + fseek(file, 0, SEEK_END); + file_length = ftell(file); + fseek(file, 0, SEEK_SET); + *buf = calloc(file_length, sizeof(char)); + assert(*buf); + fread(*buf, 1, file_length, file); + fclose(file); + + return true; + } + + return false; +} + +void init_shaders() { + static const char* shader_search_paths[] = { + "./data/shaders/", + "../data/shaders/", + NULL}; + + bool found = false; + int search_index = 0; + char* frag_buffer = NULL; + char* vert_buffer = NULL; + + while (shader_search_paths[search_index] != NULL) { + const char* dir = shader_search_paths[search_index]; + static char path_buf[1024]; + long length; + + if (vert_buffer == NULL) { + try_read_file(dir, gDefaultShader.vert_fname, &vert_buffer); + } + if (frag_buffer == NULL) { + try_read_file(dir, gDefaultShader.frag_fname, &frag_buffer); + } + + if ((vert_buffer != NULL) && (frag_buffer != NULL)) { + srshader_load(&gDefaultShader, vert_buffer, frag_buffer); + + free(vert_buffer); + vert_buffer = NULL; + free(frag_buffer); + frag_buffer = NULL; + break; + } + + search_index++; + } + + if (gDefaultShader.program_id == 0) { + gLog("Error: could not load default shader!"); + } +} + +void init_debug_meshes() { + assert(gCoordFrameMesh.nvertices == 0); + + glGenVertexArrays(1, &gDebugShapesVAId); + glBindVertexArray(gDebugShapesVAId); + + glGenBuffers(1, &gDebugShapesVBOId); + glBindBuffer(GL_ARRAY_BUFFER, gDebugShapesVBOId); + glBufferData(GL_ARRAY_BUFFER, sizeof(union srvrtxdata) * DEBUG_VBO_SIZE, NULL, GL_STATIC_DRAW); + + GLintptr dbg_vbuf_offset = 0; + + glEnableVertexAttribArray(0); + glVertexAttribPointer( + 0, + 4, + GL_FLOAT, + GL_FALSE, + (sizeof(srvrtxdata)), + (void*)0); + + glEnableVertexAttribArray(1); + glVertexAttribPointer( + 1, + 3, + GL_FLOAT, + GL_FALSE, + (sizeof(srvrtxdata)), + (void*)(sizeof(float) * 4)); + + // Attribute 2: texture coordinates + glEnableVertexAttribArray(2); + glVertexAttribPointer( + 2, + 2, + GL_FLOAT, + GL_FALSE, + (sizeof(srvrtxdata)), + (void*)(sizeof(float) * 7)); + // Attribute 3: color + glEnableVertexAttribArray(3); + glVertexAttribPointer( + 3, + 4, + GL_UNSIGNED_BYTE, + GL_TRUE, + (sizeof(srvrtxdata)), + (void*)(sizeof(float) * 9)); + + // + // Coordinate Frame + // + gCoordFrameMesh.vao_id = gDebugShapesVAId; + gCoordFrameMesh.vb_id = gDebugShapesVBOId; + gCoordFrameMesh.nvertices = 6; + + srvrtxdata coord_frame_vertices[] = { + {0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 255, 0, 0, 255}, + {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 255, 0, 0, 255}, + + {0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, 255, 0, 255}, + {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, 255, 0, 255}, + + {0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, 0, 255, 255}, + {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, 0, 255, 255}}; + GLuint coord_frame_indices[] = {0, 1, 2, 3, 4, 5}; + + glBufferSubData( + GL_ARRAY_BUFFER, + dbg_vbuf_offset, + sizeof(coord_frame_vertices), + coord_frame_vertices); + dbg_vbuf_offset = sizeof (coord_frame_vertices); + + glGenBuffers(1, &gCoordFrameMesh.idb_id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gCoordFrameMesh.idb_id); + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, + sizeof(coord_frame_indices), + coord_frame_indices, + GL_STATIC_DRAW); + + gCoordFrameMesh.mode = GL_LINES; + gCoordFrameMesh.count = 6; + + // + // Coordinate Frame + // + gGridMesh.vao_id = gDebugShapesVAId; + gGridMesh.vb_id = gDebugShapesVBOId; + gGridMesh.nvertices = 44; + + srvrtxdata* grid_vertices = calloc(44, sizeof(srvrtxdata)); + srvrtxdata grid_def_vertex = { + 0.f, 0.f, 0.f, 1.f, + 0.f, 1.f, 0.f, + 0.f, 0.f, + 255, 255, 255, 255 + }; + // lines along parallel to x axis + for (int i = 0; i <= 10; i++) { + memcpy (&grid_vertices[2*i], &grid_def_vertex, sizeof(srvrtxdata)); + memcpy (&grid_vertices[2*i + 1], &grid_def_vertex, sizeof(srvrtxdata)); + grid_vertices[2 * i].pos[0] = -5.0f + i * 1.0f; + grid_vertices[2 * i].pos[2] = 5.0f; + grid_vertices[2 * i + 1].pos[0] = -5.0f + i * 1.0f; + grid_vertices[2 * i + 1].pos[2] = -5.0f; + } + // lines parallel to z axis + for (int i = 11; i <= 21; i++) { + memcpy (&grid_vertices[2*i], &grid_def_vertex, sizeof(srvrtxdata)); + memcpy (&grid_vertices[2*i + 1], &grid_def_vertex, sizeof(srvrtxdata)); + grid_vertices[2 * i].pos[0] = -5.0f; + grid_vertices[2 * i].pos[2] = -5.0f + (i - 11) * 1.0f; + grid_vertices[2 * i + 1].pos[0] = 5.0f; + grid_vertices[2 * i + 1].pos[2] = -5.0f + (i - 11) * 1.0f; + } + + glBindBuffer(GL_ARRAY_BUFFER, gDebugShapesVBOId); + glBufferSubData( + GL_ARRAY_BUFFER, + dbg_vbuf_offset, + sizeof(srvrtxdata) * 44, + grid_vertices); + dbg_vbuf_offset += sizeof (srvrtxdata) * 44; + + free(grid_vertices); + + GLuint grid_indices[44]; + for (int i = 0; i < 22; i++) { + grid_indices[2 * i] = 2*i + 6; + grid_indices[2 * i + 1] = (2*i+1) + 6; + } + + glGenBuffers(1, &gGridMesh.idb_id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gGridMesh.idb_id); + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, + sizeof(grid_indices), + grid_indices, + GL_STATIC_DRAW); + + gGridMesh.mode = GL_LINES; + gGridMesh.count = 44; + + glBindVertexArray(0); +}; + +// +// Renderer +// +srndr* srndr_create() { + srndr* result = calloc(1, sizeof(srndr)); + + init_shaders(); + init_debug_meshes(); + + return result; +} + +void srndr_destroy(srndr* sr) { free(sr); } + +// +// View +// +void srview_get_output_texture(srview* sv, GLuint* texture) { + *texture = sv->mColorTexture; +} + +void srview_set_proj(srview* sv, simd4x4f proj) { sv->proj = proj; } + +void srview_set_view(srview* sv, simd4x4f view) { sv->view = view; } + +void srview_update_framebuffer(srview* sv) { + glGenFramebuffers(1, &sv->mFrameBufferId); + glBindFramebuffer(GL_FRAMEBUFFER, sv->mFrameBufferId); + + // Color Texture + glGenTextures(1, &sv->mColorTexture); + glBindTexture(GL_TEXTURE_2D, sv->mColorTexture); + + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGB, + sv->width, + sv->height, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + sv->mColorTexture, + 0); + + // Depth Texture + glGenTextures(1, &sv->mDepthTexture); + glBindTexture(GL_TEXTURE_2D, sv->mDepthTexture); + + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_DEPTH_COMPONENT, + sv->width, + sv->height, + 0, + GL_DEPTH_COMPONENT, + GL_FLOAT, + 0); + + // Set parameters so that we can set a shadow2DSampler + glTexParameteri( + GL_TEXTURE_2D, + GL_TEXTURE_COMPARE_MODE, + GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + float border_color[] = {1.0f, 1.0f, 1.0f, 1.0f}; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color); + + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, + sv->mDepthTexture, + 0); +} + +void srview_cleanup_framebuffer(srview* sv) { + if (glIsFramebuffer(sv->mFrameBufferId)) { + glDeleteFramebuffers(1, &sv->mFrameBufferId); + } + + if (sv->mColorTexture != -1) { + glDeleteTextures(1, &sv->mColorTexture); + sv->mColorTexture = -1; + } + + if (sv->mDepthTexture != -1) { + glDeleteTextures(1, &sv->mDepthTexture); + sv->mDepthTexture = -1; + } +} + +void srview_set_size(srview* sv, int width, int height) { + if (sv->width == width && sv->height == height) { + return; + } + + sv->width = width; + sv->height = height; + + srview_cleanup_framebuffer(sv); + srview_update_framebuffer(sv); +} + +srview* srview_create() { + srview* result = calloc(1, sizeof(srview)); + + return result; +} + +void srview_destroy(srview* sv) { + srview_cleanup_framebuffer(sv); + + free(sv); +} + +void srndr_run_frame_command(const srcmd* cmd) { + glBindVertexArray(gCoordFrameMesh.vao_id); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gCoordFrameMesh.idb_id); + glDrawElements(gCoordFrameMesh.mode, gCoordFrameMesh.count, GL_UNSIGNED_INT, (void*)0); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} + +void srndr_run_grid_command(const srcmd* cmd) { + glBindVertexArray(gGridMesh.vao_id); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gGridMesh.idb_id); + glDrawElements(gGridMesh.mode, gGridMesh.count, GL_UNSIGNED_INT, (void*)0); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} + +void srndr_render(srndr* srndr, srview* sview, srcmdbuf* scmdbuf) { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, sview->mFrameBufferId); + + glViewport(0, 0, sview->width, sview->height); + glClearColor(0.1f, 0.1f, 0.1f, 0.1f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glUseProgram(gDefaultShader.program_id); + GLint view_mat_loc = + glGetUniformLocation(gDefaultShader.program_id, "uViewMatrix"); + assert(view_mat_loc != -1); + glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, &sview->view); + + GLint proj_mat_loc = + glGetUniformLocation(gDefaultShader.program_id, "uProjectionMatrix"); + assert(proj_mat_loc != -1); + glUniformMatrix4fv(proj_mat_loc, 1, GL_FALSE, &sview->proj); + + GLint model_mat_loc = + glGetUniformLocation(gDefaultShader.program_id, "uModelMatrix"); + assert(model_mat_loc != -1); + + for (int i = 0; i < scmdbuf->ncmds; i++) { + const srcmd* cmd = &scmdbuf->cmds[i]; + glUniformMatrix4fv(model_mat_loc, 1, GL_FALSE, &cmd->mat); + + switch (cmd->type) { + case SRndrCmdTypeFrame: + srndr_run_frame_command(cmd); + break; + case SRndrCmdTypeGrid: + srndr_run_grid_command(cmd); + break; + default: + gLog("Invalid command type %d at index %d", cmd->type, i); + break; + } + } + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +} + +// +// Render Commands +// +void srcmd_clear (srcmd *cmd) { + cmd->color = simd4f_create(1.f, 1.f, 1.f, 1.f); + cmd->type = SRndrCmdTypeFrame; + simd4x4f_identity(&cmd->mat); +} + +srcmdbuf* srcmdbuf_create(unsigned int size_max) { + srcmdbuf* result = malloc(sizeof(srcmdbuf)); + result->nbufsize = size_max; + result->ncmds = 0; + result->cmds = calloc(sizeof(srcmd), size_max); + + return result; +} + +void srcmdbuf_clear(srcmdbuf* cmdbuf) { cmdbuf->ncmds = 0; } + +bool srcmdbuf_add(srcmdbuf* cmdbuf, srcmd *cmd) { + srcmd *buf_cmd = srcmd_create(cmdbuf); + + if (!buf_cmd) { + return false; + } + + *buf_cmd = *cmd; +} + +srcmd* srcmd_create(srcmdbuf* cmdbuf) { + if (cmdbuf->ncmds == cmdbuf->nbufsize) { + gLog("Warning: number of render commands maxed out!"); + return NULL; + } + return &(cmdbuf->cmds[cmdbuf->ncmds++]); +} + +#endif // SRENDER_IMPLEMENTATION + #ifdef __cplusplus } #endif -#endif +#endif // SRENDER_H diff --git a/src/vissim.cc b/src/vissim.cc index aa52844..1ed3e20 100644 --- a/src/vissim.cc +++ b/src/vissim.cc @@ -187,15 +187,15 @@ void DoRender() { // Populate render commands srcmdbuf_clear(gRndrCmds); - srcmd* cmd = srcmd_create(gRndrCmds); - cmd->type = SRndrCmdTypeFrame; - simd4x4f_identity(&cmd->mat); - cmd->color = simd4f_create(1.f, 1.f, 1.f, 1.f); - cmd = srcmd_create(gRndrCmds); - cmd->type = SRndrCmdTypeGrid; - simd4x4f_identity(&cmd->mat); - cmd->color = simd4f_create(1.f, 1.f, 1.f, 1.f); + srcmd rcmd; + srcmd_clear(&rcmd); + + rcmd.type = SRndrCmdTypeFrame; + srcmdbuf_add(gRndrCmds, &rcmd); + + rcmd.type = SRndrCmdTypeGrid; + srcmdbuf_add(gRndrCmds, &rcmd); // Perform the actual render srndr_render(gRndr, gView, gRndrCmds);