404 lines
12 KiB
C++

#define STB_IMAGE_IMPLEMENTATION
#include "renderer.h"
bool init_renderer(Renderer *renderer, u32 width, u32 height) {
renderer->m_width = width;
renderer->m_height = height;
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
log(1, "%s error: failed to initialize GLAD\n", __FUNCTION__);
return false;
}
if (!GLAD_GL_VERSION_4_6) {
log(1, "%s error: failed to get at least OpenGL 4.6\n", __FUNCTION__);
return false;
}
{
bool success = init_frame_buffer(&renderer->frame_buffer, width, height);
if (!success) {
log(1, "%s error: could not init Framebuffer\n", __FUNCTION__);
return false;
}
log(1, "%s: framebuffer succesfully initialized\n", __FUNCTION__);
}
{
bool success = load_texture(&renderer->texture, "assets/textures/crate.png");
if (!success) {
log(1, "%s: texture loading failed\n", __FUNCTION__);
return false;
}
log(1, "%s: texture successfully loaded\n", __FUNCTION__);
}
{
bool success = init_vertex_buffer(&renderer->vertex_buffer);
if (!success) {
log(1, "%s: vertex buffer successfully created\n", __FUNCTION__);
return false;
}
}
{
bool success = init_uniform_buffer(&renderer->uniform_buffer);
if (!success) {
log(1, "%s: uniform buffer successfully created\n", __FUNCTION__);
return false;
}
}
{
bool success = load_shaders(&renderer->shader, "shaders/basic.vert", "shaders/basic.frag");
if (!success) {
log(1, "%s: basic shader loading failed\n", __FUNCTION__);
return false;
}
log(1, "%s: basic shaders succesfully loaded\n", __FUNCTION__);
}
{
bool success = load_shaders(&renderer->alt_shader, "shaders/alt.vert", "shaders/alt.frag");
if (!success) {
log(1, "%s: alt shader loading failed\n", __FUNCTION__);
return false;
}
log(1, "%s: alt shaders succesfully loaded\n", __FUNCTION__);
}
return true;
}
void set_renderer_size(Renderer *renderer, u32 width, u32 height) {
resize_frame_buffer(&renderer->frame_buffer, width, height);
glViewport(0, 0, width, height);
}
void draw_renderer(Renderer *renderer) {
bind_frame_buffer(&renderer->frame_buffer);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
Vector3 camera_position = Vector3(0.4f, 0.3f, 1.0f);
Vector3 camera_look_at_position = Vector3(0.0f, 0.0f, 0.0f);
Vector3 camera_up_vector = Vector3(0.0f, 1.0f, 0.0f);
renderer->projection_matrix = glm::perspective(glm::radians(90.0f), static_cast<f32>(renderer->m_width) / static_cast<f32>(renderer->m_height), 0.1f, 100.0f);
f32 dt = glfwGetTime();
Matrix4 model = Matrix4(1.0);
if (!renderer->use_alt_shader) {
use_shader(&renderer->shader);
model = glm::rotate(Matrix4(1.0f), dt, Vector3(0.0f, 0.0f, 1.0f));
} else {
use_shader(&renderer->alt_shader);
model = glm::rotate(Matrix4(1.0f), -dt, Vector3(0.0f, 0.0f, 1.0f));
}
renderer->view_matrix = glm::lookAt(camera_position, camera_look_at_position, camera_up_vector) * model;
upload_uniform_buffer_data(&renderer->uniform_buffer, renderer->view_matrix, renderer->projection_matrix);
bind_texture(&renderer->texture);
bind_vertex_buffer(&renderer->vertex_buffer);
draw_vertex_buffer(GL_TRIANGLES, 0, renderer->triangle_count * 3);
unbind_vertex_buffer();
unbind_texture();
unbind_frame_buffer(&renderer->frame_buffer);
draw_frame_buffer(&renderer->frame_buffer);
}
void upload_renderer_data(Renderer *renderer, Mesh *vertex_data) {
renderer->triangle_count = vertex_data->vertices.size() / 3;
upload_vertex_buffer_data(&renderer->vertex_buffer, vertex_data);
}
void cleanup_renderer(Renderer *renderer) {
cleanup_shader(&renderer->shader);
cleanup_shader(&renderer->alt_shader);
cleanup_texture(&renderer->texture);
cleanup_vertex_buffer(&renderer->vertex_buffer);
cleanup_frame_buffer(&renderer->frame_buffer);
}
/*
* Frame buffer
*/
bool init_frame_buffer(Frame_Buffer *frame_buffer, u32 width, u32 height) {
frame_buffer->width = width;
frame_buffer->height = height;
glGenFramebuffers(1, &frame_buffer->buffer);
glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer->buffer);
glEnable(GL_FRAMEBUFFER_SRGB);
glGenTextures(1, &frame_buffer->color_tex);
glBindTexture(GL_TEXTURE_2D, frame_buffer->color_tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, frame_buffer->color_tex, 0);
log(1, "%s: added color buffer\n", __FUNCTION__);
glGenRenderbuffers(1, &frame_buffer->depth_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, frame_buffer->depth_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, frame_buffer->depth_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
log(1, "%s: added depth render buffer\n", __FUNCTION__);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return check_frame_buffer_complete(frame_buffer);
}
bool check_frame_buffer_complete(Frame_Buffer *frame_buffer) {
glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer->buffer);
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (result != GL_FRAMEBUFFER_COMPLETE) {
log(1, "%s error: framebuffer is NOT complete\n", __FUNCTION__);
return false;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
log(1, "%s: framebuffer is complete\n", __FUNCTION__);
return true;
}
bool resize_frame_buffer(Frame_Buffer *frame_buffer, u32 width, u32 height) {
frame_buffer->width = width;
frame_buffer->height = height;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glDeleteTextures(1, &frame_buffer->color_tex);
glDeleteRenderbuffers(1, &frame_buffer->depth_buffer);
glDeleteFramebuffers(1, &frame_buffer->buffer);
return init_frame_buffer(frame_buffer, width, height);
}
void draw_frame_buffer(Frame_Buffer *frame_buffer) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, frame_buffer->buffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, frame_buffer->width, frame_buffer->height, 0, 0, frame_buffer->width, frame_buffer->height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
}
void bind_frame_buffer(Frame_Buffer *frame_buffer) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frame_buffer->buffer);
}
void unbind_frame_buffer(Frame_Buffer *frame_buffer) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
void cleanup_frame_buffer(Frame_Buffer *frame_buffer) {
unbind_frame_buffer(frame_buffer);
glDeleteTextures(1, &frame_buffer->color_tex);
glDeleteRenderbuffers(1, &frame_buffer->depth_buffer);
glDeleteFramebuffers(1, &frame_buffer->buffer);
}
/*
* Vertex buffer
*/
bool init_vertex_buffer(Vertex_Buffer *vertex_buffer) {
glGenVertexArrays(1, &vertex_buffer->vao);
glGenBuffers(1, &vertex_buffer->vbo);
glBindVertexArray(vertex_buffer->vao);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer->vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, position));
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, color));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*) offsetof(Vertex, uv));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
return true;
}
void cleanup_vertex_buffer(Vertex_Buffer *vertex_buffer) {
glDeleteBuffers(1, &vertex_buffer->vbo);
glDeleteVertexArrays(1, &vertex_buffer->vao);
}
void upload_vertex_buffer_data(Vertex_Buffer *vertex_buffer, Mesh *vertex_data) {
glBindVertexArray(vertex_buffer->vao);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer->vbo);
glBufferData(GL_ARRAY_BUFFER, vertex_data->vertices.size() * sizeof(Vertex), &vertex_data->vertices.at(0), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void bind_vertex_buffer(Vertex_Buffer *vertex_buffer) {
glBindVertexArray(vertex_buffer->vao);
}
void unbind_vertex_buffer() {
glBindVertexArray(0);
}
void draw_vertex_buffer(u32 mode, u32 start, u32 num) {
glDrawArrays(mode, start, num);
}
/*
* Uniform buffer
*/
bool init_uniform_buffer(Uniform_Buffer *uniform_buffer) {
glGenBuffers(1, &uniform_buffer->ubo_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, uniform_buffer->ubo_buffer);
glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(Matrix4), nullptr, GL_STATIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
return true;
}
void upload_uniform_buffer_data(Uniform_Buffer *uniform_buffer, Matrix4 view_matrix, Matrix4 projection_matrix) {
glBindBuffer(GL_UNIFORM_BUFFER, uniform_buffer->ubo_buffer);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(Matrix4), glm::value_ptr(view_matrix));
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(Matrix4), sizeof(Matrix4), glm::value_ptr(projection_matrix));
glBindBufferRange(GL_UNIFORM_BUFFER, 0, uniform_buffer->ubo_buffer, 0, 2 * sizeof(Matrix4));
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
void cleanup(Uniform_Buffer *uniform_buffer) {
glDeleteBuffers(1, &uniform_buffer->ubo_buffer);
}
/*
* Texture
*/
bool load_texture(Texture *texture, string filepath) {
texture->name = filepath;
stbi_set_flip_vertically_on_load(true);
u8* texture_data = stbi_load(filepath.c_str(), &texture->width, &texture->height, &texture->number_of_channels, 0);
if (!texture_data) {
stbi_image_free(texture_data);
return false;
}
glGenTextures(1, &texture->texture);
glBindTexture(GL_TEXTURE_2D, texture->texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(texture_data);
return true;
}
void bind_texture(Texture *texture) {
glBindTexture(GL_TEXTURE_2D, texture->texture);
}
void unbind_texture() {
glBindTexture(GL_TEXTURE_2D, 0);
}
void cleanup_texture(Texture *texture) {
glDeleteTextures(1, &texture->texture);
}
/*
* Shaders
*/
bool load_shaders(Shader *shader, string vertex_shader_filepath, string fragment_shader_filepath) {
u32 vertex_shader = load_shader(vertex_shader_filepath, GL_VERTEX_SHADER);
if (!vertex_shader) {
return false;
}
u32 fragment_shader = load_shader(fragment_shader_filepath, GL_FRAGMENT_SHADER);
if (!fragment_shader) {
return false;
}
shader->program = glCreateProgram();
glAttachShader(shader->program, vertex_shader);
glAttachShader(shader->program, fragment_shader);
glLinkProgram(shader->program);
s32 is_program_linked;
glGetProgramiv(shader->program, GL_LINK_STATUS, &is_program_linked);
if (!is_program_linked) {
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return false;
}
s32 ubo_index = glGetUniformBlockIndex(shader->program, "Matrices");
glUniformBlockBinding(shader->program, ubo_index, 0);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
return true;
}
void cleanup_shader(Shader *shader) {
glDeleteProgram(shader->program);
}
u32 load_shader(string filepath, u32 shader_type) {
string shader_as_text;
shader_as_text = load_file_to_string(filepath);
const char*shader_source = shader_as_text.c_str();
u32 shader = glCreateShader(shader_type);
glShaderSource(shader, 1, (const GLchar**) &shader_source, 0);
glCompileShader(shader);
s32 is_shader_compiled;
glGetShaderiv(shader, GL_COMPILE_STATUS, &is_shader_compiled);
if (!is_shader_compiled) {
return 0;
}
return shader;
}
void use_shader(Shader *shader) {
glUseProgram(shader->program);
}