#ifndef SRENDER_H #define SRENDER_H #ifdef __cplusplus extern "C" { #endif #include #include "vectorial/simd4x4f.h" typedef struct srndr srndr; typedef struct srview srview; typedef struct srcmdbuf srcmdbuf; typedef enum { SRndrCmdTypeFrame = 0, SRndrCmdTypeGrid, SRndrCmdTypeCube, SRndrCmdTypeSphere } SRndrCmdType; typedef struct srcmd { simd4x4f mat; simd4f color; SRndrCmdType type; } srcmd; // // Renderer // srndr* srndr_create(); void srndr_destroy(srndr* sr); // // View // srview* srview_create(); void srview_destroy(srview* sv); void srview_set_proj(srview* sv, simd4x4f proj); void srview_set_view(srview* sv, simd4x4f view); void srview_set_size(srview* sv, int width, int height); 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 #include #include "utils.h" 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}; static srmeshdata gCubeMesh = {0}; static srmeshdata gUVSphereMesh = {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[44]; 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; 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; // // Cube // gCubeMesh.vao_id = gDebugShapesVAId; gCubeMesh.vb_id = gDebugShapesVBOId; gCubeMesh.nvertices = 48; // clang-format off srvrtxdata cube_vertices[48] = { // +x { 0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 255, 0, 0, 255}, { 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 255, 0, 0, 255}, { 0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 255, 0, 0, 255}, { 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 255, 0, 0, 255}, // +y {-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0, 255, 0, 255}, { 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0, 255, 0, 255}, { 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0, 255, 0, 255}, {-0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0, 255, 0, 255}, // +z {-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0, 0, 255, 255}, { 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0, 0, 255, 255}, { 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0, 0, 255, 255}, {-0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0, 0, 255, 255}, // -x {-0.5f, -0.5f, -0.5f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 128, 0, 0, 255}, {-0.5f, -0.5f, 0.5f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 128, 0, 0, 255}, {-0.5f, 0.5f, 0.5f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 128, 0, 0, 255}, {-0.5f, 0.5f, -0.5f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 128, 0, 0, 255}, // -y { 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0, 128, 0, 255}, {-0.5f, -0.5f, 0.5f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0, 128, 0, 255}, {-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0, 128, 0, 255}, { 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0, 128, 0, 255}, // -z { 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0, 0, 128, 255}, {-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0, 0, 128, 255}, {-0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0, 0, 128, 255}, { 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0, 0, 128, 255} }; // clang-format on glBindBuffer(GL_ARRAY_BUFFER, gDebugShapesVBOId); glBufferSubData( GL_ARRAY_BUFFER, dbg_vbuf_offset, sizeof(srvrtxdata) * 24, cube_vertices); dbg_vbuf_offset += sizeof(srvrtxdata) * 24; GLuint cube_indices[] = { // clang-format off 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23 // clang-format on }; for (int i = 0; i < 36; i++) { cube_indices[i] += gCoordFrameMesh.nvertices + gGridMesh.nvertices; } glGenBuffers(1, &gCubeMesh.idb_id); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gCubeMesh.idb_id); glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(cube_indices), cube_indices, GL_STATIC_DRAW); gCubeMesh.mode = GL_TRIANGLES; gCubeMesh.count = 36; // // UVSphere // gUVSphereMesh.vao_id = gDebugShapesVAId; gUVSphereMesh.vb_id = gDebugShapesVBOId; // loosely based on http://www.songho.ca/opengl/gl_sphere.html int stack_count = 4; int sector_count = 4; gUVSphereMesh.nvertices = (stack_count + 1) * (sector_count + 1); gLog("UVsphere vertices: %d", gUVSphereMesh.nvertices); srvrtxdata* uvsphere_vertices = calloc(sizeof(srvrtxdata), gUVSphereMesh.nvertices); float sector_step = 2.f * M_PI / sector_count; float stack_step = M_PI / stack_count; float sector_angle, stack_angle; for (int i = 0; i <= stack_count; ++i) { stack_angle = M_PI / 2 - i * stack_step; // starting from pi/2 to -pi/2 float xy = cosf(stack_angle); // r * cos(u) float z = sinf(stack_angle); // r * sin(u) // add (sector_count+1) vertices per stack // the first and last vertices have same position and normal, but different tex coords for (int j = 0; j <= sector_count; ++j) { int vertex_index = (i * (sector_count + 1)) + j; gLog("vertex_index %d", vertex_index); srvrtxdata* vertex = &uvsphere_vertices[vertex_index]; sector_angle = j * sector_step; // starting from 0 to 2pi // vertex position (x, y, z) vertex->x = xy * cosf(sector_angle); // r * cos(u) * cos(v) vertex->y = xy * sinf(sector_angle); // r * cos(u) * sin(v) vertex->z = z; vertex->w = 1.f; // normalized vertex normal (nx, ny, nz) vertex->nx = vertex->x; vertex->ny = vertex->y; vertex->nz = vertex->z; // vertex tex coord (s, t) range between [0, 1] vertex->s = (float)j / sector_count; vertex->t = (float)i / stack_count; vertex->r = 128; vertex->g = 128; vertex->b = 128; vertex->a = 255; } } glBindBuffer(GL_ARRAY_BUFFER, gDebugShapesVBOId); glBufferSubData( GL_ARRAY_BUFFER, dbg_vbuf_offset, sizeof(srvrtxdata) * gUVSphereMesh.nvertices, uvsphere_vertices); dbg_vbuf_offset += sizeof(srvrtxdata) * gUVSphereMesh.nvertices; free(uvsphere_vertices); gUVSphereMesh.nindices = stack_count * sector_count * 3 * 2 - sector_count * 2 * 3; GLuint* uvsphere_indices = calloc(sizeof(GLuint), gUVSphereMesh.nindices); gLog("nindices = %d", gUVSphereMesh.nindices); // generate CCW index list of sphere triangles int k1, k2; GLuint tri_index = 0; for (int i = 0; i < stack_count; ++i) { k1 = i * (sector_count + 1); // beginning of current stack k2 = k1 + sector_count + 1; // beginning of next stack for (int j = 0; j < sector_count; ++j, ++k1, ++k2) { // 2 triangles per sector excluding first and last stacks // k1 => k2 => k1+1 if (i != 0) { uvsphere_indices[++tri_index] = k1; uvsphere_indices[++tri_index] = k2; uvsphere_indices[++tri_index] = k1 + 1; } // k1+1 => k2 => k2+1 if (i != (stack_count - 1)) { uvsphere_indices[++tri_index] = k1 + 1; uvsphere_indices[++tri_index] = k2; uvsphere_indices[++tri_index] = k2 + 1; } gLog("tri_index = %d", tri_index); } } for (int i = 0; i < gUVSphereMesh.nindices; i++) { uvsphere_indices[i] += gCoordFrameMesh.nvertices + gGridMesh.nvertices + gCubeMesh.nvertices; } glGenBuffers(1, &gUVSphereMesh.idb_id); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gUVSphereMesh.idb_id); glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * gUVSphereMesh.nindices, uvsphere_indices, GL_STATIC_DRAW); free(uvsphere_indices); gUVSphereMesh.mode = GL_TRIANGLES; gUVSphereMesh.count = gUVSphereMesh.nindices; 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_run_cube_command(const srcmd* cmd) { glBindVertexArray(gCubeMesh.vao_id); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gCubeMesh.idb_id); glDrawElements(gCubeMesh.mode, gCubeMesh.count, GL_UNSIGNED_INT, (void*)0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } void srndr_run_sphere_command(const srcmd* cmd) { glBindVertexArray(gCubeMesh.vao_id); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gUVSphereMesh.idb_id); glDrawElements( gUVSphereMesh.mode, gUVSphereMesh.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); glEnable(GL_DEPTH_TEST); // glEnable(GL_CULL_FACE); // glCullFace(GL_BACK); 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; case SRndrCmdTypeCube: srndr_run_cube_command(cmd); break; case SRndrCmdTypeSphere: srndr_run_sphere_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 // SRENDER_H