rbdlsim/src/srender.h

1018 lines
26 KiB
C++

#ifndef SRENDER_H
#define SRENDER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdio.h>
#include "vectorial/simd4x4f.h"
typedef struct srndr srndr;
typedef struct srview srview;
typedef struct srcmdbuf srcmdbuf;
typedef union srvrtxdata srvrtxdata;
typedef struct srmeshdata srmeshdata;
extern GLuint* srDefaultVAId;
typedef enum {
SRndrCmdTypeFrame = 0,
SRndrCmdTypeGrid,
SRndrCmdTypeCube,
SRndrCmdTypeSphere,
SrndrCmdTypeMesh,
} SRndrCmdType;
//
// Simple Mesh Data
//
typedef struct srmeshdata {
int nvertices;
int nindices;
GLuint vao_id;
GLuint vb_id;
GLuint idb_id;
GLuint count;
GLenum mode;
} srmeshdata;
typedef struct srcmd {
simd4x4f mat;
simd4f color;
SRndrCmdType type;
srmeshdata* meshdata;
} 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);
//
// 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[3];
float uv[2];
GLubyte color[4];
};
} srvrtxdata;
inline srmeshdata* srmesh_create(
srvrtxdata* vrtxdata,
int nvertices,
GLuint* idxdata,
int nindices,
GLenum prim_mode,
GLuint count) {
srmeshdata* result = (srmeshdata*)calloc(sizeof(srmeshdata), 1);
result->nvertices = nvertices;
result->nindices = nindices;
result->mode = prim_mode;
result->count = count;
glGenVertexArrays(1, &result->vao_id);
glBindVertexArray(result->vao_id);
glGenBuffers(1, &result->vb_id);
glBindBuffer(GL_ARRAY_BUFFER, result->vb_id);
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));
glBufferData(
GL_ARRAY_BUFFER,
sizeof(srvrtxdata) * nvertices,
vrtxdata,
GL_DYNAMIC_DRAW);
glGenBuffers(1, &result->idb_id);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, result->idb_id);
for (int i = 0; i < nindices; i++) {
printf ("idx %2d: %d\n", i, idxdata[i]);
}
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
sizeof(GLuint) * nindices,
idxdata,
GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
return result;
}
inline void srmesh_destroy(srmeshdata* mesh) {
glDeleteVertexArrays(1, &mesh->vao_id);
glDeleteBuffers(1, &mesh->vb_id);
glDeleteBuffers(1, &mesh->idb_id);
free(mesh);
}
//
// srender Implementation
//
#ifdef SRENDER_IMPLEMENTATION
#include <assert.h>
#include <string.h>
#include "utils.h"
typedef struct srndr {
struct {
simd4f* pos;
simd4f* color;
GLuint num_points;
GLuint points_vbo_id;
} point_buf;
} 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 Buffer Object for all debug objects (coord frame, grid, cube, ...)
//
const GLint DEBUG_VBO_SIZE = 1024;
GLuint gDebugShapesVAId = 0;
GLuint gDebugShapesVBOId = 0;
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 z 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;
if (i == 5) {
grid_vertices[2 * i].g = 0;
grid_vertices[2 * i].r = 0;
grid_vertices[2 * i + 1].g = 0;
grid_vertices[2 * i + 1].r = 0;
}
}
// lines parallel to x 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;
if (i == 16) {
grid_vertices[2 * i].g = 0;
grid_vertices[2 * i].b = 0;
grid_vertices[2 * i + 1].g = 0;
grid_vertices[2 * i + 1].b = 0;
}
}
glBindBuffer(GL_ARRAY_BUFFER, gDebugShapesVBOId);
glBufferSubData(
GL_ARRAY_BUFFER,
dbg_vbuf_offset,
sizeof(union 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 = 24;
// clang-format off
srvrtxdata cube_vertices[24] = {
// +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) * gCubeMesh.nvertices,
cube_vertices);
dbg_vbuf_offset += sizeof(srvrtxdata) * gCubeMesh.nvertices;
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 = 24;
int sector_count = 24;
gUVSphereMesh.nvertices = (stack_count + 1) * (sector_count + 1);
gLog("UVsphere vertices: %d", gUVSphereMesh.nvertices);
srvrtxdata* uvsphere_vertices =
calloc(sizeof(srvrtxdata), gUVSphereMesh.nvertices);
float stack_step = M_PI / stack_count;
float sector_step = 2 * M_PI / sector_count;
int vert_index = 0;
for (int i = 0; i < stack_count + 1; i++) {
float phi = -M_PI * 0.5 + i * stack_step;
float y = sin(phi);
for (int j = 0; j < sector_count + 1; j++) {
float theta = -M_PI + j * sector_step;
float x = cos(theta) * cos(phi);
float z = -sin(theta) * cos(phi);
// gLog ("idx: %d # phi: %f, theta %f, p = %f, %f, %f", vert_index, phi * 180 / M_PI, theta * 180 / M_PI, x, y, z);
srvrtxdata* vertex = &uvsphere_vertices[vert_index++];
vertex->x = x * 0.5;
vertex->y = y * 0.5;
vertex->z = z * 0.5;
vertex->w = 1.0f;
vertex->nx = x;
vertex->ny = y;
vertex->nz = z;
vertex->s = (theta + M_PI) / (2.f * M_PI);
vertex->t = (phi + M_PI * 0.5) / M_PI;
vertex->r = 192;
vertex->g = 192;
vertex->b = 192;
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);
int indices_index = 0;
for (int i = 0; i < stack_count; i++) {
GLuint k1 = i * (sector_count + 1);
GLuint k2 = k1 + sector_count + 1;
for (int j = 0; j < sector_count; ++j, ++k1, ++k2) {
if (i != 0) {
uvsphere_indices[indices_index++] = k1;
uvsphere_indices[indices_index++] = k1 + 1;
uvsphere_indices[indices_index++] = k2 + 1;
}
if (i != stack_count - 1) {
uvsphere_indices[indices_index++] = k2 + 1;
uvsphere_indices[indices_index++] = k2;
uvsphere_indices[indices_index++] = k1;
}
}
}
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;
} else {
gLog("Resizing view to %d, %d", width, height);
}
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_run_mesh_command(const srcmd* cmd) {
glBindVertexArray(cmd->meshdata->vao_id);
glBindBuffer(GL_ARRAY_BUFFER, cmd->meshdata->vb_id);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cmd->meshdata->idb_id);
glDrawElements(
cmd->meshdata->mode,
cmd->meshdata->count,
GL_UNSIGNED_INT,
(void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_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);
glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
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;
case SrndrCmdTypeMesh:
srndr_run_mesh_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