System info & network
This commit is contained in:
382
code/render/2d.cpp
Normal file
382
code/render/2d.cpp
Normal file
@@ -0,0 +1,382 @@
|
||||
#include "2d.h"
|
||||
#include "state.h"
|
||||
#include "../debug/logger.h"
|
||||
|
||||
static const u32 PIXELS_PER_SEGMENT = 3;
|
||||
|
||||
// Internal use functions
|
||||
static void set_texture_in_shader(r_shader *shader, r_texture *texture, v4 color = {1,1,1,1}, u32 texture_index = 0);
|
||||
|
||||
// Immediate functions
|
||||
void r_2d_immediate_segment(v2 a, v2 b, v4 a_color, v4 b_color, f32 thickness)
|
||||
{
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
// Shader
|
||||
glUseProgram(r_render_state.shader_2d.id);
|
||||
glUniform1i(r_render_state.shader_2d.has_texture[0], 0);
|
||||
|
||||
// Vertex buffer data
|
||||
GLuint gl_VAO, gl_VBO;
|
||||
glGenVertexArrays(1, &gl_VAO);
|
||||
glBindVertexArray(gl_VAO);
|
||||
glGenBuffers(1, &gl_VBO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gl_VBO);
|
||||
|
||||
f32 data[12] = { a.x, a.y, b.x, b.y, a_color.r, a_color.g, a_color.b, a_color.a, b_color.r, b_color.g, b_color.b, b_color.a };
|
||||
glBufferData(GL_ARRAY_BUFFER, 2*sizeof(v2)+2*sizeof(v4), data, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(v2), (void*)0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(v4), (void*)(2*sizeof(v2)));
|
||||
|
||||
// Draw
|
||||
glLineWidth(thickness);
|
||||
glDrawArrays(GL_LINES, 0, 2);
|
||||
|
||||
// Deinit
|
||||
glDeleteBuffers(1, &gl_VBO);
|
||||
glDeleteVertexArrays(1, &gl_VAO);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void r_2d_immediate_polygonal_chain(u64 count, v2 *vertices, v4 color, f32 thickness)
|
||||
{
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
// Shader
|
||||
glUseProgram(r_render_state.shader_2d.id);
|
||||
glUniform1i(r_render_state.shader_2d.has_texture[0], 0);
|
||||
|
||||
// Vertex buffer data
|
||||
GLuint gl_VAO, gl_VBO;
|
||||
glGenVertexArrays(1, &gl_VAO);
|
||||
glBindVertexArray(gl_VAO);
|
||||
glGenBuffers(1, &gl_VBO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gl_VBO);
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, count*sizeof(v2), vertices, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(v2), (void*)0);
|
||||
//glDisableVertexAttribArray(1);
|
||||
glVertexAttrib4f(1, color.r, color.g, color.b, color.a);
|
||||
|
||||
// Draw
|
||||
glLineWidth(thickness);
|
||||
glDrawArrays(GL_LINE_STRIP, 0, count);
|
||||
|
||||
// Deinit
|
||||
glDeleteBuffers(1, &gl_VBO);
|
||||
glDeleteVertexArrays(1, &gl_VAO);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void r_2d_immediate_triangle(v2 a, v2 b, v2 c, v4 a_color, v4 b_color, v4 c_color, v2 a_uv, v2 b_uv, v2 c_uv, r_texture *texture)
|
||||
{
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
// Shader
|
||||
glUseProgram(r_render_state.shader_2d.id);
|
||||
// Texture
|
||||
set_texture_in_shader(&r_render_state.shader_2d, texture);
|
||||
|
||||
// Vertex buffer data
|
||||
GLuint gl_VAO, gl_VBO;
|
||||
glGenVertexArrays(1, &gl_VAO);
|
||||
glBindVertexArray(gl_VAO);
|
||||
glGenBuffers(1, &gl_VBO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gl_VBO);
|
||||
|
||||
f32 data[24] = {
|
||||
a.x, a.y, b.x, b.y, c.x, c.y,
|
||||
a_color.r, a_color.g, a_color.b, a_color.a,
|
||||
b_color.r, b_color.g, b_color.b, b_color.a,
|
||||
c_color.r, c_color.g, c_color.b, c_color.a,
|
||||
a_uv.x, a_uv.y, b_uv.x, b_uv.y, c_uv.x, c_uv.y
|
||||
};
|
||||
glBufferData(GL_ARRAY_BUFFER, 3*sizeof(v2)+3*sizeof(v4)+3*sizeof(v2), data, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(v2), (void*)0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(v4), (void*)(3*sizeof(v2)));
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(v2), (void*)(3*sizeof(v2)+3*sizeof(v4)));
|
||||
|
||||
// Draw
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
// Deinit
|
||||
glDeleteBuffers(1, &gl_VBO);
|
||||
glDeleteVertexArrays(1, &gl_VAO);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void r_2d_immediate_quad(v2 a, v2 b, v2 c, v2 d, v4 color, v2 a_uv, v2 b_uv, v2 c_uv, v2 d_uv, r_texture *texture)
|
||||
{
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
// Shader
|
||||
glUseProgram(r_render_state.shader_2d.id);
|
||||
// Texture
|
||||
set_texture_in_shader(&r_render_state.shader_2d, texture);
|
||||
|
||||
// Vertex buffer data
|
||||
GLuint gl_VAO, gl_VBO;
|
||||
glGenVertexArrays(1, &gl_VAO);
|
||||
glBindVertexArray(gl_VAO);
|
||||
glGenBuffers(1, &gl_VBO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gl_VBO);
|
||||
|
||||
f32 data[16] = {
|
||||
a.x, a.y, b.x, b.y, d.x, d.y, c.x, c.y,
|
||||
a_uv.x, a_uv.y, b_uv.x, b_uv.y, d_uv.x, d_uv.y, c_uv.x, c_uv.y
|
||||
};
|
||||
glBufferData(GL_ARRAY_BUFFER, 4*sizeof(v2)+4*sizeof(v2), data, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(v2), (void*)0);
|
||||
//glDisableVertexAttribArray(1);
|
||||
glVertexAttrib4f(1, color.r, color.g, color.b, color.a);
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(v2), (void*)(4*sizeof(v2)));
|
||||
|
||||
// Draw
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
// Deinit
|
||||
glDeleteBuffers(1, &gl_VBO);
|
||||
glDeleteVertexArrays(1, &gl_VAO);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void r_2d_immediate_rectangle(Rect r, v4 color, Rect uv, r_texture *texture)
|
||||
{
|
||||
v2 a = r.position + v2{r.w, 0 };
|
||||
v2 b = r.position + v2{0 , 0 };
|
||||
v2 c = r.position + v2{0 , r.h};
|
||||
v2 d = r.position + v2{r.w, r.h};
|
||||
v2 a_uv = uv.position + v2{uv.w, 0 };
|
||||
v2 b_uv = uv.position + v2{0 , 0 };
|
||||
v2 c_uv = uv.position + v2{0 , uv.h};
|
||||
v2 d_uv = uv.position + v2{uv.w, uv.h};
|
||||
r_2d_immediate_quad(a, b, c, d, color, a_uv, b_uv, c_uv, d_uv, texture);
|
||||
}
|
||||
|
||||
void r_2d_immediate_rounded_rectangle(Rect r, f32 radius, v4 color)
|
||||
{
|
||||
radius = clamp(0, minimum(abs(r.w), abs(r.h)) / 2, radius);
|
||||
|
||||
// Should compute PIXELS_PER_SEGMENT from the size of the radius
|
||||
u32 num_of_segments = floor(0.5 + radius * TAU * 0.25 / PIXELS_PER_SEGMENT);
|
||||
|
||||
// Split into 9 sections:
|
||||
// - 5 quads (center, top, bottom, left, right)
|
||||
// - 4 semicircles (corners)
|
||||
// Inner vertices (CCW starting from 1st quadrant/upper-right)
|
||||
v2 i0, i1, i2, i3;
|
||||
i0.x = r.x + r.w - radius;
|
||||
i0.y = r.y + radius;
|
||||
i1.x = r.x + radius;
|
||||
i1.y = r.y + radius;
|
||||
i2.x = r.x + radius;
|
||||
i2.y = r.y + r.h - radius;
|
||||
i3.x = r.x + r.w - radius;
|
||||
i3.y = r.y + r.h - radius;
|
||||
|
||||
// Outer vertices
|
||||
v2 o0, o1, o2, o3, o4, o5, o6, o7;
|
||||
o0.x = i0.x;
|
||||
o0.y = i0.y - radius;
|
||||
o1.x = i1.x;
|
||||
o1.y = i1.y - radius;
|
||||
o2.x = i1.x - radius;
|
||||
o2.y = i1.y;
|
||||
o3.x = i2.x - radius;
|
||||
o3.y = i2.y;
|
||||
o4.x = i2.x;
|
||||
o4.y = i2.y + radius;
|
||||
o5.x = i3.x;
|
||||
o5.y = i3.y + radius;
|
||||
o6.x = i3.x + radius;
|
||||
o6.y = i3.y;
|
||||
o7.x = i0.x + radius;
|
||||
o7.y = i0.y;
|
||||
|
||||
// Reserve space for vertices
|
||||
u32 vertices_count = 30; // 5 quads, specified by 2 triangles each = 5 quads * 2 triangles * 3 vertices = 30 vertices
|
||||
vertices_count += num_of_segments * 12; // Add corner semicircles = 4 corners * N triangles * 3 vertices = N * 12
|
||||
|
||||
|
||||
// Build 5 quads
|
||||
v2 vertices[vertices_count] = {
|
||||
i0, i1, i2, i0, i2, i3, // Center quad: i0, i1, i2, i3
|
||||
o0, o1, i1, o0, i1, i0, // Top quad: o0, o1, i1, i0
|
||||
i1, o2, o3, i1, o3, i2, // Left quad: i1, o2, o3, i2
|
||||
i3, i2, o4, i3, o4, o5, // Bottom quad: i3, i2, o4, o5
|
||||
o7, i0, i3, o7, i3, o6 // Right quad: o7, i0, i3, o6
|
||||
};
|
||||
u32 corner_offset = 30;
|
||||
// Corner semicircles
|
||||
f32 factor = TAU * .25 / num_of_segments;
|
||||
v2 inner_vertices[4] = {i0, i1, i2, i3};
|
||||
for(u32 quadrant = 0; quadrant < 4; quadrant++)
|
||||
{
|
||||
for(u32 i = quadrant*num_of_segments; i < (quadrant+1)*num_of_segments; i++)
|
||||
{
|
||||
v2 inner = inner_vertices[quadrant];
|
||||
v2 a = inner + radius * v2{cos( i * factor), -sin( i * factor)};
|
||||
v2 b = inner + radius * v2{cos((i+1) * factor), -sin((i+1) * factor)};
|
||||
vertices[corner_offset + 3*i + 0] = inner;
|
||||
vertices[corner_offset + 3*i + 1] = a;
|
||||
vertices[corner_offset + 3*i + 2] = b;
|
||||
}
|
||||
}
|
||||
|
||||
r_2d_immediate_mesh(vertices_count, vertices, color, NULL, NULL);
|
||||
}
|
||||
|
||||
void r_2d_immediate_mesh(u64 count, v2 *vertices, v4 color, v2 *uvs, r_texture *texture)
|
||||
{
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
// Shader
|
||||
glUseProgram(r_render_state.shader_2d.id);
|
||||
// Texture
|
||||
set_texture_in_shader(&r_render_state.shader_2d, texture);
|
||||
|
||||
// Vertex buffer data
|
||||
GLuint gl_VAO, gl_vertices, gl_uvs;
|
||||
glGenVertexArrays(1, &gl_VAO);
|
||||
glBindVertexArray(gl_VAO);
|
||||
glGenBuffers(1, &gl_vertices);
|
||||
glGenBuffers(1, &gl_uvs);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gl_vertices);
|
||||
glBufferData(GL_ARRAY_BUFFER, count * sizeof(v2), vertices, GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(v2), (void*)0);
|
||||
//glDisableVertexAttribArray(1);
|
||||
glVertexAttrib4f(1, color.r, color.g, color.b, color.a);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gl_uvs);
|
||||
glBufferData(GL_ARRAY_BUFFER, count * sizeof(v2), uvs , GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(v2), (void*)0);
|
||||
|
||||
// Draw
|
||||
glDrawArrays(GL_TRIANGLES, 0, count);
|
||||
|
||||
// Deinitvoid r_2d_draw_mesh(r_2d_mesh *mesh, r_texture *texture);
|
||||
glDeleteBuffers(1, &gl_vertices);
|
||||
glDeleteBuffers(1, &gl_uvs);
|
||||
glDeleteVertexArrays(1, &gl_VAO);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void r_2d_immediate_rectangle_outline(Rect r, v4 color, f32 thickness)
|
||||
{
|
||||
v2 vertices[5];
|
||||
vertices[0] = r.position + v2{ 0, 0};
|
||||
vertices[1] = r.position + v2{ 0, r.h};
|
||||
vertices[2] = r.position + v2{r.w, r.h};
|
||||
vertices[3] = r.position + v2{r.w, 0};
|
||||
vertices[4] = r.position + v2{ 0, 0};
|
||||
r_2d_immediate_polygonal_chain(5, vertices, color, thickness);
|
||||
}
|
||||
|
||||
void r_2d_immediate_rounded_rectangle_outline(Rect r, f32 radius, v4 color, f32 thickness)
|
||||
{
|
||||
radius = clamp(0, minimum(abs(r.w), abs(r.h)) / 2, radius);
|
||||
|
||||
// Should compute PIXELS_PER_SEGMENT from the size of the radius
|
||||
u32 num_of_segments = floor(0.5 + radius * TAU * 0.25 / PIXELS_PER_SEGMENT);
|
||||
|
||||
// Split into 9 sections:
|
||||
// - 5 quads (center, top, bottom, left, right)
|
||||
// - 4 semicircles (corners)
|
||||
// Inner vertices (CCW starting from 1st quadrant/upper-right)
|
||||
v2 i0, i1, i2, i3;
|
||||
i0.x = r.x + r.w - radius;
|
||||
i0.y = r.y + radius;
|
||||
i1.x = r.x + radius;
|
||||
i1.y = r.y + radius;
|
||||
i2.x = r.x + radius;
|
||||
i2.y = r.y + r.h - radius;
|
||||
i3.x = r.x + r.w - radius;
|
||||
i3.y = r.y + r.h - radius;
|
||||
|
||||
// Reserve space for vertices
|
||||
u32 vertices_count = 1 + 4 + 4*num_of_segments; // Starting vertex (1) + one for each side (4) + one for each segment (4*num_of_segments)
|
||||
|
||||
v2 inner_vertices[4] = {i0, i1, i2, i3};
|
||||
|
||||
v2 vertices[vertices_count] = {
|
||||
i3 + v2{radius, 0} // Starting vertex
|
||||
};
|
||||
u32 v_index = 1;
|
||||
|
||||
// Corner semicircles
|
||||
f32 factor = TAU * .25 / num_of_segments;
|
||||
for(u32 quadrant = 0; quadrant < 4; quadrant++)
|
||||
{
|
||||
v2 inner = inner_vertices[quadrant];
|
||||
for(u32 i = quadrant*num_of_segments; i < (quadrant+1)*num_of_segments; i++)
|
||||
{
|
||||
v2 a = inner + radius * v2{cos( i * factor), -sin( i * factor)};
|
||||
vertices[v_index] = a;
|
||||
v_index++;
|
||||
}
|
||||
vertices[v_index] = inner + radius * v2{cos( (quadrant+1)*num_of_segments * factor), -sin( (quadrant+1)*num_of_segments * factor)};
|
||||
v_index++;
|
||||
}
|
||||
|
||||
r_2d_immediate_polygonal_chain(vertices_count, vertices, color, thickness);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void r_2d_draw_mesh(r_2d_mesh *mesh, r_texture *texture)
|
||||
{
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
// Shader
|
||||
glUseProgram(r_render_state.shader_2d.id);
|
||||
// Texture
|
||||
set_texture_in_shader(&r_render_state.shader_2d, texture);
|
||||
|
||||
// Draw
|
||||
glBindVertexArray(mesh->gl_VAO);
|
||||
glDrawArrays(GL_TRIANGLES, 0, mesh->count);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Internal use functions
|
||||
static void set_texture_in_shader(r_shader *shader, r_texture *texture, v4 color, u32 texture_index)
|
||||
{
|
||||
// Remember to call glUseProgram before using this
|
||||
if(texture)
|
||||
{
|
||||
glUniform1i(shader->has_texture[texture_index], 1);
|
||||
glUniform1i(shader->texture[texture_index], 0);
|
||||
glUniform1i(shader->texture_channels[texture_index], r_texture_channels(texture));
|
||||
glActiveTexture(GL_TEXTURE0 + texture_index);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->gl_id);
|
||||
glUniform4f(shader->color[texture_index], color.r, color.g, color.b, color.a);
|
||||
}
|
||||
else
|
||||
{
|
||||
glUniform1i(shader->has_texture[texture_index], 0);
|
||||
}
|
||||
}
|
||||
27
code/render/2d.h
Normal file
27
code/render/2d.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef _PIUMA_RENDER_2D_H_
|
||||
#define _PIUMA_RENDER_2D_H_
|
||||
|
||||
#include "../lib/types.h"
|
||||
#include "../lib/math.h"
|
||||
#include "../lib/geometry.h"
|
||||
#include "primitives.h"
|
||||
|
||||
// Immediate functions: less efficient but easy to use
|
||||
void r_2d_immediate_segment(v2 a, v2 b, v4 a_color, v4 b_color, f32 thickness = 1.0f);
|
||||
void r_2d_immediate_polygonal_chain(u64 count, v2 *vertices, v4 color, f32 thickness = 1.0f);
|
||||
void r_2d_immediate_triangle(v2 a, v2 b, v2 c, v4 a_color, v4 b_color, v4 c_color, v2 a_uv = {0,0}, v2 b_uv = {0,0}, v2 c_uv = {0,0}, r_texture *texture = NULL);
|
||||
void r_2d_immediate_quad(v2 a, v2 b, v2 c, v2 d, v4 color, v2 a_uv = {0,0}, v2 b_uv = {0,0}, v2 c_uv = {0,0}, v2 d_uv = {0,0}, r_texture *texture = NULL);
|
||||
void r_2d_immediate_rectangle(Rect r, v4 color, Rect uv = {0,0,1,1}, r_texture *texture = NULL);
|
||||
void r_2d_immediate_rounded_rectangle(Rect r, f32 radius, v4 color);
|
||||
void r_2d_immediate_mesh(u64 count, v2 *vertices, v4 color, v2 *uvs = NULL, r_texture *texture = NULL);
|
||||
|
||||
void r_2d_immediate_rectangle_outline(Rect r, v4 color, f32 thickness = 1.0f);
|
||||
void r_2d_immediate_rounded_rectangle_outline(Rect r, f32 radius, v4 color, f32 thickness = 1.0f);
|
||||
|
||||
// Draw functions: usual interface (create objects / send to gpu, draw call, remove from gpu)
|
||||
void r_2d_draw_mesh(r_2d_mesh *mesh, r_texture *texture);
|
||||
// @Feature: @Performance: something for text rendering (a lot of quads/rects)
|
||||
// Maybe we could send to the gpu the following: texture of the characters, array of uvs for indexing the texture, character position + index of its uv.
|
||||
|
||||
|
||||
#endif
|
||||
52
code/render/gl_helpers.h
Normal file
52
code/render/gl_helpers.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef _PIUMA_RENDER_GL_HELPERS_H_
|
||||
#define _PIUMA_RENDER_GL_HELPERS_H_
|
||||
|
||||
#include "../debug/logger.h"
|
||||
|
||||
inline void APIENTRY glDebugOutput(GLenum source, GLenum type, unsigned int id, GLenum severity, GLsizei length, const char *message, const void *userParam)
|
||||
{
|
||||
// ignore non-significant error/warning codes
|
||||
if(id == 131169 || id == 131185 || id == 131218 || id == 131204)
|
||||
return;
|
||||
|
||||
if (severity == GL_DEBUG_SEVERITY_NOTIFICATION)
|
||||
return;
|
||||
|
||||
// @Cleanup: LOG does not replace printf here. We need to merge the multiple printfs into a single log message
|
||||
LOG(LOG_DEBUG, "---------------");
|
||||
LOG(LOG_DEBUG, "Debug message (%u): %s", id, message);
|
||||
|
||||
switch (source)
|
||||
{
|
||||
case GL_DEBUG_SOURCE_API: LOG(LOG_DEBUG, "Source: API"); break;
|
||||
case GL_DEBUG_SOURCE_WINDOW_SYSTEM: LOG(LOG_DEBUG, "Source: Window System"); break;
|
||||
case GL_DEBUG_SOURCE_SHADER_COMPILER: LOG(LOG_DEBUG, "Source: Shader Compiler"); break;
|
||||
case GL_DEBUG_SOURCE_THIRD_PARTY: LOG(LOG_DEBUG, "Source: Third Party"); break;
|
||||
case GL_DEBUG_SOURCE_APPLICATION: LOG(LOG_DEBUG, "Source: Application"); break;
|
||||
case GL_DEBUG_SOURCE_OTHER: LOG(LOG_DEBUG, "Source: Other"); break;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case GL_DEBUG_TYPE_ERROR: LOG(LOG_DEBUG, "Type: Error"); break;
|
||||
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: LOG(LOG_DEBUG, "Type: Deprecated Behaviour"); break;
|
||||
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: LOG(LOG_DEBUG, "Type: Undefined Behaviour"); break;
|
||||
case GL_DEBUG_TYPE_PORTABILITY: LOG(LOG_DEBUG, "Type: Portability"); break;
|
||||
case GL_DEBUG_TYPE_PERFORMANCE: LOG(LOG_DEBUG, "Type: Performance"); break;
|
||||
case GL_DEBUG_TYPE_MARKER: LOG(LOG_DEBUG, "Type: Marker"); break;
|
||||
case GL_DEBUG_TYPE_PUSH_GROUP: LOG(LOG_DEBUG, "Type: Push Group"); break;
|
||||
case GL_DEBUG_TYPE_POP_GROUP: LOG(LOG_DEBUG, "Type: Pop Group"); break;
|
||||
case GL_DEBUG_TYPE_OTHER: LOG(LOG_DEBUG, "Type: Other"); break;
|
||||
}
|
||||
|
||||
switch (severity)
|
||||
{
|
||||
case GL_DEBUG_SEVERITY_HIGH: LOG(LOG_DEBUG, "Severity: high"); break;
|
||||
case GL_DEBUG_SEVERITY_MEDIUM: LOG(LOG_DEBUG, "Severity: medium"); break;
|
||||
case GL_DEBUG_SEVERITY_LOW: LOG(LOG_DEBUG, "Severity: low"); break;
|
||||
case GL_DEBUG_SEVERITY_NOTIFICATION: LOG(LOG_DEBUG, "Severity: notification"); break;
|
||||
}
|
||||
LOG(LOG_DEBUG, "");
|
||||
}
|
||||
|
||||
#endif
|
||||
0
code/render/lights.cpp
Normal file
0
code/render/lights.cpp
Normal file
44
code/render/lights.h
Normal file
44
code/render/lights.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef _PIUMA_RENDER_LIGHTS_H_
|
||||
#define _PIUMA_RENDER_LIGHTS_H_
|
||||
|
||||
struct r_sun_light
|
||||
{
|
||||
v3 direction;
|
||||
f32 _padding0;
|
||||
v3 color;
|
||||
f32 intensity;
|
||||
};
|
||||
|
||||
struct r_point_light
|
||||
{
|
||||
v3 position;
|
||||
f32 _padding0;
|
||||
v3 color;
|
||||
f32 intensity;
|
||||
};
|
||||
|
||||
struct r_spot_light
|
||||
{
|
||||
v3 position;
|
||||
f32 inner_radius;
|
||||
v3 color;
|
||||
f32 intensity;
|
||||
v3 direction;
|
||||
f32 outer_radius;
|
||||
};
|
||||
|
||||
#define MAX_SUN_LIGHTS 4
|
||||
#define MAX_POINT_LIGHTS 128
|
||||
#define MAX_SPOT_LIGHTS 128
|
||||
struct r_light_container
|
||||
{
|
||||
u32 sun_light_count;
|
||||
u32 point_light_count;
|
||||
u32 spot_light_count;
|
||||
f32 ambient_light;
|
||||
r_sun_light sun_lights[MAX_SUN_LIGHTS];
|
||||
r_point_light point_lights[MAX_POINT_LIGHTS];
|
||||
r_spot_light spot_lights[MAX_SPOT_LIGHTS];
|
||||
};
|
||||
|
||||
#endif
|
||||
79
code/render/object.cpp
Normal file
79
code/render/object.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "object.h"
|
||||
#include "../lib/math.h"
|
||||
#include "../lib/geometry.h"
|
||||
#include "../platform.h"
|
||||
#include "string.h"
|
||||
#include "state.h"
|
||||
#include "2d.h"
|
||||
|
||||
|
||||
r_object r_object_create(u64 count, r_mesh **meshes, r_material **materials, v3 position, v3 rotation, v3 scale)
|
||||
{
|
||||
r_object object;
|
||||
|
||||
object.meshes = (r_mesh**)p_alloc(count * sizeof(r_mesh*));
|
||||
object.mesh_material = (r_material**)p_alloc(count * sizeof(r_material*));
|
||||
object.mesh_local_transform = (m4*)p_alloc(count * sizeof(m4));
|
||||
|
||||
memcpy(object.meshes, meshes, count * sizeof(r_mesh*));
|
||||
memcpy(object.mesh_material, materials, count * sizeof(r_material*));
|
||||
for(u64 i = 0; i < count; i++)
|
||||
object.mesh_local_transform[i] = m4_identity;
|
||||
|
||||
object.count = count;
|
||||
|
||||
object.position = position;
|
||||
object.rotation = rotation;
|
||||
object.scale = scale;
|
||||
|
||||
object.has_shadow = true;
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
r_object r_object_allocate(u64 count)
|
||||
{
|
||||
r_object object;
|
||||
|
||||
object.meshes = (r_mesh**)p_alloc(count * sizeof(r_mesh*));
|
||||
object.mesh_material = (r_material**)p_alloc(count * sizeof(r_material*));
|
||||
object.mesh_local_transform = (m4*)p_alloc(count * sizeof(m4));
|
||||
|
||||
for(u64 i = 0; i < count; i++)
|
||||
object.mesh_local_transform[i] = m4_identity;
|
||||
|
||||
object.count = count;
|
||||
|
||||
object.position = v3{0,0,0};
|
||||
object.rotation = v3{0,0,0};
|
||||
object.scale = v3{1,1,1};
|
||||
|
||||
object.has_shadow = true;
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
void r_object_destroy(r_object *object)
|
||||
{
|
||||
p_free(object->mesh_material);
|
||||
p_free(object->meshes);
|
||||
p_free(object->mesh_local_transform);
|
||||
object->mesh_material = NULL;
|
||||
object->meshes = NULL;
|
||||
object->mesh_local_transform = NULL;
|
||||
object->count = 0;
|
||||
}
|
||||
|
||||
m4 r_object_transform_matrix(r_object *object)
|
||||
{
|
||||
// @Performance: replace with rototranslation matrix
|
||||
return translation_v3(object->position) * rotation_v3(object->rotation) * scale_v3(object->scale);
|
||||
}
|
||||
|
||||
m4 r_object_mesh_transform_matrix(r_object *object, u64 mesh_i)
|
||||
{
|
||||
// @Performance: replace with rototranslation matrix
|
||||
if(object->mesh_local_transform)
|
||||
return r_object_transform_matrix(object) * object->mesh_local_transform[mesh_i];
|
||||
return r_object_transform_matrix(object);
|
||||
}
|
||||
64
code/render/object.h
Normal file
64
code/render/object.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef _PIUMA_RENDER_OBJECT_H_
|
||||
#define _PIUMA_RENDER_OBJECT_H_
|
||||
|
||||
#include "primitives.h"
|
||||
#include "shader.h"
|
||||
|
||||
struct r_material
|
||||
{
|
||||
// @Feature: PBR materials
|
||||
r_shader *shader;
|
||||
|
||||
r_texture *albedo_texture;
|
||||
v4 albedo_factor;
|
||||
|
||||
r_texture *metallic_texture;
|
||||
f32 metallic_factor;
|
||||
|
||||
r_texture *roughness_texture;
|
||||
f32 roughness_factor;
|
||||
|
||||
r_texture *normal_texture;
|
||||
|
||||
r_texture *emissive_texture;
|
||||
v4 emissive_factor;
|
||||
/*
|
||||
albedo |
|
||||
metallic | --> Disney + UE4 paper
|
||||
roughness / specular |
|
||||
cavity |
|
||||
subsurface |
|
||||
anisotropy | --> Disney paper
|
||||
clearcoat |
|
||||
sheen |
|
||||
ambient occlusion | --> Valve Source2, same as cavity?
|
||||
emission
|
||||
normals
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct r_object
|
||||
{
|
||||
// @Feature: actually support multiple meshes/materials in the implementation code
|
||||
r_mesh **meshes;
|
||||
r_material **mesh_material;
|
||||
m4 *mesh_local_transform;
|
||||
u64 count;
|
||||
|
||||
v3 scale;
|
||||
v3 position;
|
||||
v3 rotation;
|
||||
|
||||
bool has_shadow;
|
||||
};
|
||||
|
||||
r_object r_object_create(u64 count, r_mesh **meshes, r_material **materials, v3 position = {0,0,0}, v3 rotation = {0,0,0}, v3 scale = {1,1,1});
|
||||
r_object r_object_allocate(u64 count);
|
||||
void r_object_destroy(r_object *object);
|
||||
m4 r_object_transform_matrix(r_object *object);
|
||||
m4 r_object_mesh_transform_matrix(r_object *object, u64 mesh_i);
|
||||
|
||||
|
||||
#endif
|
||||
424
code/render/primitives.cpp
Normal file
424
code/render/primitives.cpp
Normal file
@@ -0,0 +1,424 @@
|
||||
#include "primitives.h"
|
||||
#include "../platform.h"
|
||||
#include <string.h>
|
||||
|
||||
// GL utils
|
||||
static GLint gl_texture_internal_format(u32 texture_flags);
|
||||
static GLenum gl_texture_format (u32 texture_flags);
|
||||
static GLenum gl_texture_type (u32 texture_flags);
|
||||
|
||||
// Texture
|
||||
r_texture r_texture_create(u8 *data, v2s size, u32 flags)
|
||||
{
|
||||
r_texture texture;
|
||||
|
||||
texture.data = data;
|
||||
texture.size = size;
|
||||
texture.flags = flags | R_TEXTURE_INITIALIZED;
|
||||
|
||||
glGenTextures(1, &texture.gl_id);
|
||||
glBindTexture(GL_TEXTURE_2D, texture.gl_id);
|
||||
|
||||
GLint internal_format = gl_texture_internal_format(flags);
|
||||
GLenum format = gl_texture_format (flags);
|
||||
GLenum type = gl_texture_type (flags);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size.x, size.y, 0, format, type, data);
|
||||
|
||||
if(flags & R_TEXTURE_NO_MIPMAP)
|
||||
{
|
||||
// The default for GL_TEXTURE_{MIN,MAG}_FILTER is GL_NEAREST_MIPMAP_LINEAR, but we are not using mipmaps for this texture. If we don't change this parameter, the image will not render.
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
if(flags & R_TEXTURE_DONT_OWN)
|
||||
texture.data = NULL;
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void r_texture_resize(r_texture *texture, v2s size)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, texture->gl_id);
|
||||
GLint internal_format = gl_texture_internal_format(texture->flags);
|
||||
GLenum format = gl_texture_format (texture->flags);
|
||||
GLenum type = gl_texture_type (texture->flags);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size.x, size.y, 0, format, type, NULL);
|
||||
texture->size = size;
|
||||
}
|
||||
|
||||
void r_texture_update(r_texture *texture, u8 *data, v2s size, v2s position, u32 stride)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, texture->gl_id);
|
||||
GLenum format = gl_texture_format(texture->flags);
|
||||
GLenum type = gl_texture_type (texture->flags);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, position.x, position.y, size.x, size.y, format, type, data);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
if(texture->flags & R_TEXTURE_NO_MIPMAP)
|
||||
{
|
||||
// The default for GL_TEXTURE_{MIN,MAG}_FILTER is GL_NEAREST_MIPMAP_LINEAR, but we are not using mipmaps for this texture. If we don't change this parameter, the image will not render.
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
}
|
||||
}
|
||||
|
||||
void r_texture_destroy(r_texture *texture)
|
||||
{
|
||||
glDeleteTextures(1, &texture->gl_id);
|
||||
|
||||
if(texture->data && !(texture->flags & R_TEXTURE_DONT_OWN))
|
||||
p_free(texture->data);
|
||||
texture->size = {0,0};
|
||||
texture->flags = R_TEXTURE_DESTROYED;
|
||||
}
|
||||
|
||||
s32 r_texture_channels(r_texture *texture)
|
||||
{
|
||||
if(texture->flags & R_TEXTURE_ALPHA)
|
||||
return 1;
|
||||
if(texture->flags & R_TEXTURE_RGB)
|
||||
return 3;
|
||||
if(texture->flags & (R_TEXTURE_RGBA | R_TEXTURE_SRGB))
|
||||
return 4;
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
||||
// Cubemap
|
||||
r_cubemap r_cubemap_create(float *data[6], v2s size, u32 flags)
|
||||
{
|
||||
r_cubemap cubemap;
|
||||
|
||||
for(u32 i = 0; i < 6; i++)
|
||||
cubemap.data[i] = data[i];
|
||||
cubemap.size = size;
|
||||
cubemap.flags = flags | R_CUBEMAP_INITIALIZED;
|
||||
|
||||
glGenTextures(1, &cubemap.gl_id);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.gl_id);
|
||||
for(u32 i = 0; i < 6; i++)
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size.x, size.y, 0, GL_RGB, GL_FLOAT, data[i]);
|
||||
|
||||
if(flags & R_CUBEMAP_DONT_OWN)
|
||||
cubemap.data[i] = NULL;
|
||||
}
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
|
||||
|
||||
return cubemap;
|
||||
}
|
||||
|
||||
void r_cubemap_destroy(r_cubemap *cubemap)
|
||||
{
|
||||
glDeleteTextures(1, &cubemap->gl_id);
|
||||
|
||||
for(u32 i = 0; i < 6; i++)
|
||||
{
|
||||
if(cubemap->data[i] && !(cubemap->flags & R_CUBEMAP_DONT_OWN))
|
||||
p_free(cubemap->data[i]);
|
||||
}
|
||||
cubemap->size = {0,0};
|
||||
cubemap->flags = R_CUBEMAP_DESTROYED;
|
||||
}
|
||||
|
||||
|
||||
// 2D mesh
|
||||
r_2d_mesh r_2d_mesh_create(u64 count, v2 *vertices, v4 *colors, v2 *uvs)
|
||||
{
|
||||
r_2d_mesh mesh;
|
||||
|
||||
mesh.vertices = vertices;
|
||||
mesh.colors = colors;
|
||||
mesh.uvs = uvs;
|
||||
mesh.count = count;
|
||||
|
||||
glGenVertexArrays(1, &mesh.gl_VAO);
|
||||
glBindVertexArray(mesh.gl_VAO);
|
||||
|
||||
glGenBuffers(1, &mesh.gl_vertex_buffer);
|
||||
glGenBuffers(1, &mesh.gl_color_buffer);
|
||||
glGenBuffers(1, &mesh.gl_uv_buffer);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.gl_vertex_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.count * sizeof(v2), mesh.vertices, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(v2), (void*)0);
|
||||
|
||||
glEnableVertexAttribArray(1);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.gl_color_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.count * sizeof(v4), mesh.colors, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(v4), (void*)0);
|
||||
|
||||
if(mesh.uvs)
|
||||
{
|
||||
glEnableVertexAttribArray(2);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.gl_uv_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.count * sizeof(v2), mesh.uvs, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(v2), (void*)0);
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void r_2d_mesh_destroy(r_2d_mesh *mesh)
|
||||
{
|
||||
glBindVertexArray(mesh->gl_VAO);
|
||||
glDeleteBuffers(1, &mesh->gl_vertex_buffer);
|
||||
glDeleteBuffers(1, &mesh->gl_color_buffer);
|
||||
glDeleteBuffers(1, &mesh->gl_uv_buffer);
|
||||
glDeleteVertexArrays(1, &mesh->gl_VAO);
|
||||
|
||||
if(mesh->vertices)
|
||||
p_free(mesh->vertices);
|
||||
if(mesh->colors)
|
||||
p_free(mesh->colors);
|
||||
if(mesh->uvs)
|
||||
p_free(mesh->uvs);
|
||||
}
|
||||
|
||||
|
||||
// 3D mesh
|
||||
r_mesh r_mesh_create(u64 indices_count, u32 *indices, u64 vertices_count, v3 *vertices, v3 *normals, v3 *tangents, v2 *uvs)
|
||||
{
|
||||
r_mesh mesh;
|
||||
|
||||
mesh.vertices = vertices;
|
||||
mesh.normals = normals;
|
||||
mesh.tangents = tangents;
|
||||
mesh.uvs = uvs;
|
||||
mesh.vertices_count = vertices_count;
|
||||
mesh.indices = indices;
|
||||
mesh.indices_count = indices_count;
|
||||
|
||||
glGenVertexArrays(1, &mesh.gl_VAO);
|
||||
glBindVertexArray(mesh.gl_VAO);
|
||||
|
||||
glGenBuffers(1, &mesh.gl_vertex_buffer);
|
||||
glGenBuffers(1, &mesh.gl_normal_buffer);
|
||||
glGenBuffers(1, &mesh.gl_tangent_buffer);
|
||||
glGenBuffers(1, &mesh.gl_uv_buffer);
|
||||
glGenBuffers(1, &mesh.gl_index_buffer);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl_index_buffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh.indices_count * sizeof(u32), mesh.indices, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.gl_vertex_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.vertices_count * sizeof(v3), mesh.vertices, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(v3), (void*)0);
|
||||
|
||||
if(mesh.normals)
|
||||
{
|
||||
glEnableVertexAttribArray(1);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.gl_normal_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.vertices_count * sizeof(v3), mesh.normals, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(v3), (void*)0);
|
||||
}
|
||||
|
||||
if(mesh.tangents)
|
||||
{
|
||||
glEnableVertexAttribArray(2);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.gl_tangent_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.vertices_count * sizeof(v3), mesh.tangents, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(v3), (void*)0);
|
||||
}
|
||||
|
||||
if(mesh.uvs)
|
||||
{
|
||||
glEnableVertexAttribArray(3);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.gl_uv_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.vertices_count * sizeof(v2), mesh.uvs, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(v2), (void*)0);
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void r_mesh_destroy(r_mesh *mesh)
|
||||
{
|
||||
glBindVertexArray(mesh->gl_VAO);
|
||||
glDeleteBuffers(1, &mesh->gl_vertex_buffer);
|
||||
glDeleteBuffers(1, &mesh->gl_normal_buffer);
|
||||
glDeleteBuffers(1, &mesh->gl_uv_buffer);
|
||||
glDeleteBuffers(1, &mesh->gl_index_buffer);
|
||||
glDeleteVertexArrays(1, &mesh->gl_VAO);
|
||||
|
||||
if(mesh->vertices)
|
||||
p_free(mesh->vertices);
|
||||
if(mesh->normals)
|
||||
p_free(mesh->normals);
|
||||
if(mesh->uvs)
|
||||
p_free(mesh->uvs);
|
||||
if(mesh->indices)
|
||||
p_free(mesh->indices);
|
||||
}
|
||||
|
||||
|
||||
// Common meshes
|
||||
r_mesh r_mesh_build_cube()
|
||||
{
|
||||
v3 v[24] = {
|
||||
{0.5, 0.5, -0.5},
|
||||
{0.5, 0.5, -0.5},
|
||||
{0.5, 0.5, -0.5},
|
||||
{0.5, -0.5, -0.5},
|
||||
{0.5, -0.5, -0.5},
|
||||
{0.5, -0.5, -0.5},
|
||||
{0.5, 0.5, 0.5},
|
||||
{0.5, 0.5, 0.5},
|
||||
{0.5, 0.5, 0.5},
|
||||
{0.5, -0.5, 0.5},
|
||||
{0.5, -0.5, 0.5},
|
||||
{0.5, -0.5, 0.5},
|
||||
{-0.5, 0.5, -0.5},
|
||||
{-0.5, 0.5, -0.5},
|
||||
{-0.5, 0.5, -0.5},
|
||||
{-0.5, -0.5, -0.5},
|
||||
{-0.5, -0.5, -0.5},
|
||||
{-0.5, -0.5, -0.5},
|
||||
{-0.5, 0.5, 0.5},
|
||||
{-0.5, 0.5, 0.5},
|
||||
{-0.5, 0.5, 0.5},
|
||||
{-0.5, -0.5, 0.5},
|
||||
{-0.5, -0.5, 0.5},
|
||||
{-0.5, -0.5, 0.5}
|
||||
};
|
||||
v3 n[24] = {
|
||||
{0.0, 1.0, 0.0},
|
||||
{1.0, 0.0, 0.0},
|
||||
{0.0, 0.0, -1.0},
|
||||
{0.0, -1.0, 0.0},
|
||||
{1.0, 0.0, 0.0},
|
||||
{0.0, 0.0, -1.0},
|
||||
{0.0, 1.0, 0.0},
|
||||
{0.0, 0.0, 1.0},
|
||||
{1.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 1.0},
|
||||
{0.0, -1.0, 0.0},
|
||||
{1.0, 0.0, 0.0},
|
||||
{0.0, 1.0, 0.0},
|
||||
{-1.0, 0.0, 0.0},
|
||||
{0.0, 0.0, -1.0},
|
||||
{-1.0, 0.0, 0.0},
|
||||
{0.0, -1.0, 0.0},
|
||||
{0.0, 0.0, -1.0},
|
||||
{0.0, 1.0, 0.0},
|
||||
{0.0, 0.0, 1.0},
|
||||
{-1.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 1.0},
|
||||
{-1.0, 0.0, 0.0},
|
||||
{0.0, -1.0, 0.0}
|
||||
};
|
||||
u32 i[36] = {12, 6, 0, 7, 21, 9, 20, 15, 22, 3, 23, 16, 1, 11, 4, 14, 5, 17, 12, 18, 6, 7, 19, 21, 20, 13, 15, 3, 10, 23, 1, 8, 11, 14, 2, 5};
|
||||
|
||||
v3 *vertices = (v3*)p_alloc(24 * sizeof(v3));
|
||||
v3 *normals = (v3*)p_alloc(24 * sizeof(v3));
|
||||
u32 *indices = (u32*)p_alloc(36 * sizeof(u32));
|
||||
|
||||
memcpy(vertices, v, 24 * sizeof(v3));
|
||||
memcpy(normals , n, 24 * sizeof(v3));
|
||||
memcpy(indices , i, 36 * sizeof(u32));
|
||||
|
||||
return r_mesh_create(36, indices, 24, vertices, normals, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Framebuffers
|
||||
r_framebuffer r_framebuffer_create(v2s size, u32 flags)
|
||||
{
|
||||
r_framebuffer fb;
|
||||
fb.flags = flags;
|
||||
fb.size = size;
|
||||
|
||||
glGenFramebuffers(1, &fb.gl_id);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb.gl_id);
|
||||
|
||||
fb.color_texture = r_texture_create(NULL, size, R_TEXTURE_RGBA | R_TEXTURE_HDR | R_TEXTURE_NO_MIPMAP);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.color_texture.gl_id, 0);
|
||||
|
||||
fb.gl_depth_id = 0;
|
||||
if(flags & R_FRAMEBUFFER_DEPTH)
|
||||
{
|
||||
glGenRenderbuffers(1, &fb.gl_depth_id);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, fb.gl_depth_id);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, size.x, size.y);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb.gl_depth_id);
|
||||
}
|
||||
|
||||
return fb;
|
||||
}
|
||||
|
||||
void r_framebuffer_destroy(r_framebuffer *fb)
|
||||
{
|
||||
r_texture_destroy(&fb->color_texture);
|
||||
if(fb->flags & R_FRAMEBUFFER_DEPTH)
|
||||
glDeleteRenderbuffers(1, &fb->gl_depth_id);
|
||||
glDeleteFramebuffers(1, &fb->gl_id);
|
||||
}
|
||||
|
||||
void r_framebuffer_update_size(r_framebuffer *fb, v2s size)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb->gl_id);
|
||||
|
||||
r_texture_resize(&fb->color_texture, size);
|
||||
|
||||
if(fb->flags & R_FRAMEBUFFER_DEPTH)
|
||||
{
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, fb->gl_depth_id);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, size.x, size.y);
|
||||
}
|
||||
|
||||
fb->size = size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// GL utils
|
||||
|
||||
static GLint gl_texture_internal_format(u32 texture_flags)
|
||||
{
|
||||
if(texture_flags & R_TEXTURE_ALPHA)
|
||||
return GL_RED;
|
||||
else if(texture_flags & R_TEXTURE_RGB)
|
||||
return (texture_flags & R_TEXTURE_HDR) ? GL_RGB16F : GL_RGB;
|
||||
else if(texture_flags & R_TEXTURE_RGBA)
|
||||
return (texture_flags & R_TEXTURE_HDR) ? GL_RGBA16F : GL_RGBA;
|
||||
else if(texture_flags & R_TEXTURE_SRGB)
|
||||
return GL_SRGB_ALPHA;
|
||||
return GL_RGBA;
|
||||
}
|
||||
|
||||
static GLenum gl_texture_format(u32 texture_flags)
|
||||
{
|
||||
if(texture_flags & R_TEXTURE_ALPHA)
|
||||
return GL_RED;
|
||||
else if(texture_flags & R_TEXTURE_RGB)
|
||||
return GL_RGB;
|
||||
else if(texture_flags & R_TEXTURE_RGBA)
|
||||
return GL_RGBA;
|
||||
else if(texture_flags & R_TEXTURE_SRGB)
|
||||
return GL_RGBA;
|
||||
return GL_RGBA;
|
||||
}
|
||||
|
||||
static GLenum gl_texture_type(u32 texture_flags)
|
||||
{
|
||||
if(texture_flags & R_TEXTURE_HDR)
|
||||
return GL_FLOAT;
|
||||
return GL_UNSIGNED_BYTE;
|
||||
}
|
||||
149
code/render/primitives.h
Normal file
149
code/render/primitives.h
Normal file
@@ -0,0 +1,149 @@
|
||||
#ifndef _PIUMA_RENDER_PRIMITIVES_H_
|
||||
#define _PIUMA_RENDER_PRIMITIVES_H_
|
||||
|
||||
#include "../lib/types.h"
|
||||
#include "../lib/math.h"
|
||||
#include "GL/glcorearb.h"
|
||||
|
||||
enum r_texture_flags : u32
|
||||
{
|
||||
R_TEXTURE_NONE = 0x00,
|
||||
|
||||
R_TEXTURE_ALPHA = 0x01,
|
||||
R_TEXTURE_RGB = 0x02,
|
||||
R_TEXTURE_RGBA = 0x04,
|
||||
R_TEXTURE_SRGB = 0x08,
|
||||
|
||||
R_TEXTURE_HDR = 0x10,
|
||||
|
||||
R_TEXTURE_NO_MIPMAP = 0x00010000,
|
||||
|
||||
R_TEXTURE_DONT_OWN = 0x20000000,
|
||||
R_TEXTURE_INITIALIZED = 0x40000000,
|
||||
R_TEXTURE_DESTROYED = 0x80000000
|
||||
};
|
||||
|
||||
struct r_texture
|
||||
{
|
||||
u8 *data;
|
||||
v2s size;
|
||||
u32 flags;
|
||||
|
||||
// OpenGL
|
||||
GLuint gl_id;
|
||||
};
|
||||
|
||||
r_texture r_texture_create(u8 *data, v2s size, u32 flags);
|
||||
void r_texture_destroy(r_texture *texture);
|
||||
void r_texture_resize(r_texture *texture, v2s size);
|
||||
void r_texture_update(r_texture *texture, u8 *data, v2s size, v2s position = {0,0}, u32 stride = 0);
|
||||
s32 r_texture_channels(r_texture *texture);
|
||||
|
||||
|
||||
|
||||
|
||||
enum r_cubemap_flags : u32
|
||||
{
|
||||
R_CUBEMAP_NONE = 0x00,
|
||||
|
||||
// R_TEXTURE_ALPHA = 0x01,
|
||||
// R_TEXTURE_RGB = 0x02,
|
||||
// R_TEXTURE_RGBA = 0x04,
|
||||
// R_TEXTURE_SRGB = 0x08,
|
||||
|
||||
R_CUBEMAP_DONT_OWN = 0x20000000,
|
||||
R_CUBEMAP_INITIALIZED = 0x40000000,
|
||||
R_CUBEMAP_DESTROYED = 0x80000000
|
||||
};
|
||||
|
||||
struct r_cubemap
|
||||
{
|
||||
float *data[6];
|
||||
v2s size;
|
||||
u32 flags;
|
||||
|
||||
// OpenGL
|
||||
GLuint gl_id;
|
||||
};
|
||||
|
||||
r_cubemap r_cubemap_create(float *data[6], v2s size, u32 flags);
|
||||
void r_cubemap_destroy(r_cubemap *cubemap);
|
||||
|
||||
|
||||
|
||||
|
||||
struct r_2d_mesh
|
||||
{
|
||||
v2 *vertices;
|
||||
v4 *colors;
|
||||
v2 *uvs;
|
||||
u64 count;
|
||||
|
||||
// OpenGL
|
||||
GLuint gl_VAO;
|
||||
GLuint gl_vertex_buffer;
|
||||
GLuint gl_color_buffer;
|
||||
GLuint gl_uv_buffer;
|
||||
};
|
||||
|
||||
r_2d_mesh r_2d_mesh_create(u64 count, v2 *vertices, v4 *colors, v2 *uvs = NULL);
|
||||
void r_2d_mesh_destroy(r_2d_mesh *mesh);
|
||||
// r_2d_mesh_update/change
|
||||
|
||||
|
||||
|
||||
|
||||
struct r_mesh
|
||||
{
|
||||
v3 *vertices;
|
||||
v3 *normals;
|
||||
v3 *tangents;
|
||||
v2 *uvs;
|
||||
u64 vertices_count;
|
||||
|
||||
u32 *indices;
|
||||
u64 indices_count;
|
||||
|
||||
// OpenGL
|
||||
GLuint gl_VAO;
|
||||
GLuint gl_vertex_buffer;
|
||||
GLuint gl_normal_buffer;
|
||||
GLuint gl_tangent_buffer;
|
||||
GLuint gl_uv_buffer;
|
||||
GLuint gl_index_buffer;
|
||||
};
|
||||
|
||||
r_mesh r_mesh_create(u64 indices_count, u32 *indices, u64 vertices_count, v3 *vertices, v3 *normals = NULL, v3 *tangents = NULL, v2 *uvs = NULL);
|
||||
void r_mesh_destroy(r_mesh *mesh);
|
||||
// r_mesh_update/change
|
||||
|
||||
|
||||
// Common meshes
|
||||
r_mesh r_mesh_build_cube();
|
||||
|
||||
|
||||
|
||||
// Framebuffers
|
||||
enum r_framebuffer_flags : u32
|
||||
{
|
||||
R_FRAMEBUFFER_NONE = 0,
|
||||
R_FRAMEBUFFER_DEPTH,
|
||||
};
|
||||
|
||||
struct r_framebuffer
|
||||
{
|
||||
u32 gl_id;
|
||||
u32 gl_depth_id;
|
||||
r_texture color_texture;
|
||||
v2s size;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
r_framebuffer r_framebuffer_create(v2s size, u32 flags);
|
||||
void r_framebuffer_destroy(r_framebuffer *fb);
|
||||
void r_framebuffer_update_size(r_framebuffer *fb, v2s size);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
513
code/render/render.cpp
Normal file
513
code/render/render.cpp
Normal file
@@ -0,0 +1,513 @@
|
||||
#include "render.h"
|
||||
#include "state.h"
|
||||
#include "../platform.h"
|
||||
#include "../lib/math.h"
|
||||
#include "../debug/logger.h"
|
||||
#include "gl_helpers.h"
|
||||
#include "string.h"
|
||||
#include "../camera.h" // @Cleanup: remove dependency from camera
|
||||
|
||||
r_state r_render_state;
|
||||
|
||||
|
||||
void r_init()
|
||||
{
|
||||
// OpenGL debug messages
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
glDebugMessageCallback(glDebugOutput, nullptr);
|
||||
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
|
||||
|
||||
// Depth test
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
// Face culling
|
||||
glEnable(GL_CULL_FACE);
|
||||
// Texture pixel alignment (default is 4, so rgb textures should have every pixel padded to 4 bytes. With this we can have 3 byte pixels with no padding between eachother)
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
// Blending
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
// Cubemap
|
||||
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
|
||||
|
||||
// Load shaders
|
||||
if(!r_shader_from_files(&r_render_state.shader_2d, "shaders/2d.vert", "shaders/2d.frag"))
|
||||
{
|
||||
LOG(LOG_ERROR, "Cannot load 2D shader.");
|
||||
}
|
||||
if(!r_shader_from_files(&r_render_state.shader_postprocessing, "shaders/postprocessing.vert", "shaders/postprocessing.frag"))
|
||||
{
|
||||
LOG(LOG_ERROR, "Cannot load postprocessing shader.");
|
||||
}
|
||||
if(!r_shader_from_files(&r_render_state.shader_pbr, "shaders/pbr.vert", "shaders/pbr.frag"))
|
||||
{
|
||||
LOG(LOG_ERROR, "Cannot load pbr shader.");
|
||||
}
|
||||
if(!r_shader_from_files(&r_render_state.shader_shadow_map, "shaders/shadow_map.vert", "shaders/shadow_map.frag"))
|
||||
{
|
||||
LOG(LOG_ERROR, "Cannot load shadow_map shader.");
|
||||
}
|
||||
if(!r_shader_from_files(&r_render_state.shader_environment_map, "shaders/environment_map.vert", "shaders/environment_map.frag"))
|
||||
{
|
||||
LOG(LOG_ERROR, "Cannot load environment_map shader.");
|
||||
}
|
||||
|
||||
// Screen size
|
||||
u32 width, height;
|
||||
p_window_dimensions(&width, &height);
|
||||
glViewport(0, 0, width, height);
|
||||
|
||||
|
||||
/* We have to apply some post-processing effects only to the 3D world
|
||||
* and some effects to both the 3D world and the HUD.
|
||||
*
|
||||
* So we make 2 framebuffers:
|
||||
* 1. target for 3D world
|
||||
* 2. target for HUD
|
||||
* After rendering, we apply the correct post-processing effects and
|
||||
* merge them toghether.
|
||||
*/
|
||||
// Init framebuffers
|
||||
v2s size = {width, height};
|
||||
r_render_state.framebuffer_SCREEN = {.gl_id = 0, .size = size, .flags = 0}; // This is a special framebuffer, because it's already there. We don't need to create it
|
||||
r_render_state.framebuffer_HUD = r_framebuffer_create(size, 0);
|
||||
r_render_state.framebuffer_3D = r_framebuffer_create(size, R_FRAMEBUFFER_DEPTH);
|
||||
|
||||
// Default framebuffer
|
||||
r_framebuffer_select(&r_render_state.framebuffer_SCREEN);
|
||||
|
||||
// Init fullscreen quad
|
||||
glGenVertexArrays(1, &r_render_state.gl_screen_quad_VAO);
|
||||
glBindVertexArray(r_render_state.gl_screen_quad_VAO);
|
||||
glGenBuffers(1, &r_render_state.gl_screen_quad_VBO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, r_render_state.gl_screen_quad_VBO);
|
||||
v2 quad_vertices[2*6] =
|
||||
{
|
||||
// position UV coords
|
||||
v2{-1, 1}, v2{0, 1},
|
||||
v2{-1, -1}, v2{0, 0},
|
||||
v2{ 1, -1}, v2{1, 0},
|
||||
v2{-1, 1}, v2{0, 1},
|
||||
v2{ 1, -1}, v2{1, 0},
|
||||
v2{ 1, 1}, v2{1, 1}
|
||||
};
|
||||
glBufferData(GL_ARRAY_BUFFER, 2*6 * sizeof(v2), quad_vertices, GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(v2), (void*)(0));
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2*sizeof(v2), (void*)(sizeof(v2)));
|
||||
|
||||
// Render state
|
||||
r_size_update(width, height);
|
||||
}
|
||||
|
||||
void r_deinit()
|
||||
{
|
||||
r_framebuffer_destroy(&r_render_state.framebuffer_HUD);
|
||||
r_framebuffer_destroy(&r_render_state.framebuffer_3D);
|
||||
|
||||
glDeleteBuffers(1, &r_render_state.gl_screen_quad_VBO);
|
||||
glDeleteVertexArrays(1, &r_render_state.gl_screen_quad_VAO);
|
||||
}
|
||||
|
||||
void r_size_update(u32 width, u32 height)
|
||||
{
|
||||
// Screen size
|
||||
r_render_state.width = width;
|
||||
r_render_state.height = height;
|
||||
// Update shaders
|
||||
glUseProgram(r_render_state.shader_2d.id);
|
||||
glUniform1i(r_render_state.shader_2d.width , width);
|
||||
glUniform1i(r_render_state.shader_2d.height, height);
|
||||
|
||||
// Update framebuffers size
|
||||
v2s size = {width, height};
|
||||
r_render_state.framebuffer_SCREEN.size = size;
|
||||
r_framebuffer_update_size(&r_render_state.framebuffer_HUD, size);
|
||||
r_framebuffer_update_size(&r_render_state.framebuffer_3D , size);
|
||||
}
|
||||
|
||||
void r_time_update(f64 time)
|
||||
{
|
||||
r_render_state.time = time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void r_clear(v4 color)
|
||||
{
|
||||
glClearColor(color.r, color.g, color.b, color.a);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void r_swap()
|
||||
{
|
||||
p_graphics_swap();
|
||||
}
|
||||
|
||||
|
||||
|
||||
r_scene r_scene_create()
|
||||
{
|
||||
r_scene scene;
|
||||
|
||||
scene.view_matrix = m4_identity;
|
||||
scene.view_matrix_inverse = m4_identity;
|
||||
|
||||
scene.projection_matrix = m4_identity;
|
||||
scene.projection_matrix_inverse = m4_identity;
|
||||
|
||||
scene.objects = NULL;
|
||||
scene.objects_count = 0;
|
||||
|
||||
|
||||
// Init lights memory
|
||||
memset(&scene.lights, 0, sizeof(r_light_container));
|
||||
glGenBuffers(1, &scene.gl_lights);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, scene.gl_lights);
|
||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(r_light_container), &scene.lights, GL_STATIC_DRAW);
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, 0, scene.gl_lights);
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
void r_scene_destroy(r_scene *scene)
|
||||
{
|
||||
glDeleteBuffers(1, &scene->gl_lights);
|
||||
r_cubemap_destroy(&scene->environment_map);
|
||||
}
|
||||
|
||||
void r_scene_set_view(r_scene *scene, m4 m)
|
||||
{
|
||||
scene->view_matrix = m;
|
||||
scene->view_matrix_inverse = inverse(m);
|
||||
}
|
||||
|
||||
void r_scene_set_projection(r_scene *scene, m4 m)
|
||||
{
|
||||
scene->projection_matrix = m;
|
||||
scene->projection_matrix_inverse = inverse(m);
|
||||
}
|
||||
|
||||
void r_update_lights(r_scene *scene)
|
||||
{
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, scene->gl_lights);
|
||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(r_light_container), &scene->lights, GL_STATIC_DRAW);
|
||||
}
|
||||
|
||||
|
||||
|
||||
r_object build_basic_cube()
|
||||
{
|
||||
r_object object = r_object_allocate(1);
|
||||
|
||||
object.meshes[0] = (r_mesh*)p_alloc(sizeof(r_mesh));
|
||||
*object.meshes[0] = r_mesh_build_cube();
|
||||
|
||||
object.mesh_material[0] = (r_material*)p_alloc(sizeof(r_material));
|
||||
memset(object.mesh_material[0], 0, sizeof(r_material));
|
||||
object.mesh_material[0]->shader = &r_render_state.shader_pbr;
|
||||
object.mesh_material[0]->albedo_factor = {1,1,1,1};
|
||||
object.mesh_material[0]->emissive_factor = {1,1,1,0};
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
void r_render_scene(r_scene *scene)
|
||||
{
|
||||
// Render shadow maps
|
||||
scene->shadow_map = r_build_shadow_map_sun(scene, &scene->lights.sun_lights[0]);
|
||||
|
||||
// Render environment map
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
static r_object cube = build_basic_cube();
|
||||
cube.position = extract_column(scene->view_matrix_inverse, 3).xyz;
|
||||
glUseProgram(r_render_state.shader_environment_map.id);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, scene->environment_map.gl_id);
|
||||
glUniform1i(r_render_state.shader_environment_map.has_environment_map, 1);
|
||||
glUniform1i(r_render_state.shader_environment_map.environment_map , 0);
|
||||
r_render_object(scene, &cube, &r_render_state.shader_environment_map);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
// Render objects
|
||||
glUseProgram(r_render_state.shader_pbr.id);
|
||||
|
||||
// Set shadow map
|
||||
// @Cleanup: this should be in r_render_objects
|
||||
glActiveTexture(GL_TEXTURE5);
|
||||
glBindTexture(GL_TEXTURE_2D, scene->shadow_map.gl_depth_texture);
|
||||
glUniform1i (r_render_state.shader_pbr.has_shadow_map, 1);
|
||||
glUniform1i (r_render_state.shader_pbr.shadow_map , 5);
|
||||
glUniformMatrix4fv(r_render_state.shader_pbr.shadow_matrix , 1, GL_TRUE, (const f32 *)(scene->shadow_map.view_matrix.E));
|
||||
|
||||
// Environment map
|
||||
glActiveTexture(GL_TEXTURE6);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, scene->environment_map.gl_id);
|
||||
glUniform1i(r_render_state.shader_pbr.has_environment_map, 1);
|
||||
glUniform1i(r_render_state.shader_pbr.environment_map , 6);
|
||||
|
||||
// Render objects
|
||||
for(u32 i = 0; i < scene->objects_count; i++)
|
||||
{
|
||||
r_render_object(scene, &scene->objects[i]);
|
||||
}
|
||||
|
||||
glUniform1i(r_render_state.shader_pbr.has_shadow_map, 0);
|
||||
glUniform1i(r_render_state.shader_pbr.has_environment_map, 0);
|
||||
r_free_shadow_map(&scene->shadow_map);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Single object rendering functions (batched funcs are below)
|
||||
void r_render_object(r_scene *scene, r_object *object, r_shader *shader_override)
|
||||
{
|
||||
// @Performance: Minimize draw calls by batching mesh rendering
|
||||
for(u32 i = 0; i < object->count; i++)
|
||||
{
|
||||
r_mesh *mesh = object->meshes[i];
|
||||
r_material *material = object->mesh_material[i];
|
||||
r_shader *shader = material->shader;
|
||||
if(shader_override)
|
||||
shader = shader_override;
|
||||
|
||||
glUseProgram(shader->id);
|
||||
|
||||
glUniform1f(shader->time , (f32)r_render_state.time );
|
||||
glUniform1f(shader->width , (f32)r_render_state.width );
|
||||
glUniform1f(shader->height, (f32)r_render_state.height);
|
||||
|
||||
// Transform matrices
|
||||
m4 projview_matrix = scene->projection_matrix * scene->view_matrix;
|
||||
m4 projview_matrix_inverse = inverse(projview_matrix);
|
||||
glUniformMatrix4fv(shader->view_matrix, 1, GL_TRUE, (const f32 *)(&projview_matrix));
|
||||
glUniformMatrix4fv(shader->view_matrix_inverse, 1, GL_TRUE, (const f32 *)(&projview_matrix_inverse));
|
||||
|
||||
m4 model_transform = r_object_mesh_transform_matrix(object, i);
|
||||
glUniformMatrix4fv(shader->model_matrix, 1, GL_TRUE, (const f32 *)(&model_transform));
|
||||
|
||||
// Textures
|
||||
// Albedo
|
||||
glUniform1i(shader->has_albedo_texture, material->albedo_texture != NULL);
|
||||
if(material->albedo_texture)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, material->albedo_texture->gl_id);
|
||||
glUniform1i(shader->albedo_texture, 0);
|
||||
}
|
||||
glUniform4f(shader->albedo_factor, material->albedo_factor.r, material->albedo_factor.g, material->albedo_factor.b, material->albedo_factor.a);
|
||||
|
||||
// Metallic
|
||||
glUniform1i(shader->has_metallic_texture, material->metallic_texture != NULL);
|
||||
if(material->metallic_texture)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, material->metallic_texture->gl_id);
|
||||
glUniform1i(shader->metallic_texture, 1);
|
||||
}
|
||||
glUniform1f(shader->metallic_factor, material->metallic_factor);
|
||||
|
||||
// Roughness
|
||||
glUniform1i(shader->has_roughness_texture, material->roughness_texture != NULL);
|
||||
if(material->roughness_texture)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, material->roughness_texture->gl_id);
|
||||
glUniform1i(shader->roughness_texture, 2);
|
||||
}
|
||||
glUniform1f(shader->roughness_factor, material->roughness_factor);
|
||||
|
||||
// Normal
|
||||
glUniform1i(shader->has_normal_texture, material->normal_texture != NULL);
|
||||
if(material->normal_texture)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
glBindTexture(GL_TEXTURE_2D, material->normal_texture->gl_id);
|
||||
glUniform1i(shader->normal_texture, 3);
|
||||
}
|
||||
|
||||
// Emissive
|
||||
glUniform1i(shader->has_emissive_texture, material->emissive_texture != NULL);
|
||||
if(material->emissive_texture)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE4);
|
||||
glBindTexture(GL_TEXTURE_2D, material->emissive_texture->gl_id);
|
||||
glUniform1i(shader->emissive_texture, 4);
|
||||
}
|
||||
glUniform4f(shader->emissive_factor, material->emissive_factor.r, material->emissive_factor.g, material->emissive_factor.b, material->emissive_factor.a);
|
||||
|
||||
|
||||
|
||||
// Draw call
|
||||
glBindVertexArray(mesh->gl_VAO);
|
||||
glDrawElements(GL_TRIANGLES, mesh->indices_count, GL_UNSIGNED_INT, (void*)(0));
|
||||
}
|
||||
}
|
||||
|
||||
void r_render_object_wireframe(r_scene *scene, r_object *object)
|
||||
{
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
r_render_object(scene, object);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
}
|
||||
|
||||
void r_render_line(r_scene *scene, v3 a, v3 b, v4 a_color, v4 b_color, f32 thickness)
|
||||
{
|
||||
m4 projview_matrix = scene->projection_matrix * scene->view_matrix;
|
||||
v4 a_trans = projview_matrix * V4(a, 1);
|
||||
v4 b_trans = projview_matrix * V4(b, 1);
|
||||
a_trans /= a_trans.w;
|
||||
b_trans /= b_trans.w;
|
||||
if(a_trans.z > 1 || b_trans.z > 1)
|
||||
return;
|
||||
v2 a_2d = a_trans.xy;
|
||||
v2 b_2d = b_trans.xy;
|
||||
a_2d = (v2{.5,.5} + v2{.5,-0.5} * a_2d) * v2{(f32)r_render_state.width, (f32)r_render_state.height};
|
||||
b_2d = (v2{.5,.5} + v2{.5,-0.5} * b_2d) * v2{(f32)r_render_state.width, (f32)r_render_state.height};
|
||||
|
||||
r_2d_immediate_segment(a_2d, b_2d, a_color, b_color, thickness); // @Cleanup: This should be independent from the 2D drawing functions, probably.
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Batch render functions
|
||||
void r_render_objects(r_scene *scene, u64 count, r_object **objects)
|
||||
{
|
||||
// @Feature: implement
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
r_shadow_map r_build_shadow_map_sun(r_scene *scene, r_sun_light *sun)
|
||||
{
|
||||
glCullFace(GL_FRONT);
|
||||
|
||||
r_shadow_map sm;
|
||||
u32 width = 2*1024;
|
||||
u32 height = 2*1024;
|
||||
|
||||
// Init depth texture/framebuffer
|
||||
glGenTextures(1, &sm.gl_depth_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, sm.gl_depth_texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
||||
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);
|
||||
|
||||
glGenFramebuffers(1, &sm.gl_FBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sm.gl_FBO);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, sm.gl_depth_texture, 0);
|
||||
glDrawBuffer(GL_NONE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// Compute light frustum
|
||||
m4 projview_matrix = scene->projection_matrix * scene->view_matrix;
|
||||
m4 projview_matrix_inverse = inverse(projview_matrix);
|
||||
v4 center_point_4 = projview_matrix_inverse * v4{0, 0, 0, 1};
|
||||
v3 center_point = center_point_4.xyz / center_point_4.w;
|
||||
f32 size = 1;
|
||||
v4 bottom = projview_matrix_inverse * v4{ 0,-1, 0, 1};
|
||||
v4 top = projview_matrix_inverse * v4{ 0, 1, 0, 1};
|
||||
v4 left = projview_matrix_inverse * v4{-1, 0, 0, 1};
|
||||
v4 right = projview_matrix_inverse * v4{ 1, 0, 0, 1};
|
||||
v4 front = projview_matrix_inverse * v4{ 0, 0,-1, 1};
|
||||
v4 back = projview_matrix_inverse * v4{ 0, 0, 1, 1};
|
||||
size = maximum(size, length(top.xyz/top.w - bottom.xyz/bottom.w));
|
||||
size = maximum(size, length(right.xyz/right.w - left.xyz/left.w));
|
||||
size = maximum(size, length(back.xyz/back.w - front.xyz/front.w));
|
||||
size /= 2; // @Cleanup: hack to have better precision. There are multiple ways to do it right: smallest box around all objects, cascaded shadow maps
|
||||
|
||||
|
||||
v3 light_position = center_point - size * sun->direction;
|
||||
m4 light_camera_matrix = r_view_matrix(light_position, sun->direction, v3{0, 0, 1});
|
||||
m4 projection_matrix = r_orthographic_matrix(-size/2, size/2, -size/2, size/2, 0.1, 100.0);
|
||||
|
||||
sm.view_matrix = projection_matrix * light_camera_matrix;
|
||||
|
||||
// Render shadow map
|
||||
glViewport(0, 0, width, height);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// @Feature @Cleanup: Some objects might not need to be drawn. Add a "hidden" flag. Maybe take the list of objects to render as an argument
|
||||
m4 old_view = scene->view_matrix;
|
||||
m4 old_proj = scene->projection_matrix;
|
||||
r_scene_set_view (scene, sm.view_matrix);
|
||||
r_scene_set_projection(scene, m4_identity);
|
||||
for(u32 i = 0; i < scene->objects_count; i++)
|
||||
{
|
||||
if(scene->objects[i].has_shadow)
|
||||
{
|
||||
r_render_object(scene, &scene->objects[i], &r_render_state.shader_shadow_map);
|
||||
}
|
||||
}
|
||||
r_scene_set_view (scene, old_view);
|
||||
r_scene_set_projection(scene, old_proj);
|
||||
|
||||
// Restore framebuffer
|
||||
r_framebuffer_select(r_render_state.current_framebuffer);
|
||||
|
||||
glCullFace(GL_BACK);
|
||||
return sm;
|
||||
}
|
||||
|
||||
void r_free_shadow_map(r_shadow_map *sm)
|
||||
{
|
||||
glDeleteTextures(1, &sm->gl_depth_texture);
|
||||
glDeleteFramebuffers(1, &sm->gl_FBO);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void r_merge_and_postprocess()
|
||||
{
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_FRAMEBUFFER_SRGB);
|
||||
|
||||
glUseProgram(r_render_state.shader_postprocessing.id);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, r_render_state.framebuffer_3D.color_texture.gl_id);
|
||||
glUniform1i(r_render_state.shader_postprocessing.texture[0], 0);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, r_render_state.framebuffer_HUD.color_texture.gl_id);
|
||||
glUniform1i(r_render_state.shader_postprocessing.texture[1], 1);
|
||||
|
||||
glBindVertexArray(r_render_state.gl_screen_quad_VAO);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void r_framebuffer_select(r_framebuffer *fb)
|
||||
{
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fb->gl_id);
|
||||
glViewport(0, 0, fb->size.x, fb->size.y);
|
||||
|
||||
glUseProgram(r_render_state.shader_2d.id);
|
||||
glUniform1i(r_render_state.shader_2d.width , fb->size.x);
|
||||
glUniform1i(r_render_state.shader_2d.height, fb->size.y);
|
||||
|
||||
r_render_state.current_framebuffer = fb;
|
||||
}
|
||||
90
code/render/render.h
Normal file
90
code/render/render.h
Normal file
@@ -0,0 +1,90 @@
|
||||
// 2d: Functions to render 2d things immediatly. Simple things like meshes, lines, triangles, quads.
|
||||
// render: Renderer, takes complex objects with materials and renders them.
|
||||
// Might use an object buffer/queue and render things later, to enable
|
||||
// sorting and other complex rendering procedures (culling).
|
||||
// shader: Shaders! They have enough code to have their own source files
|
||||
// object: Objects, materials, maybe other things. To be used by the renderer.
|
||||
// light: Lights to be used by the renderer. There are enought types to separate them from objects.
|
||||
|
||||
// Might (or might not) add: compute shaders, vfx/postprocessing passes, animations
|
||||
|
||||
#ifndef _PIUMA_RENDER_RENDER_H_
|
||||
#define _PIUMA_RENDER_RENDER_H_
|
||||
|
||||
#include "primitives.h"
|
||||
#include "shader.h"
|
||||
#include "2d.h"
|
||||
#include "lights.h"
|
||||
#include "object.h"
|
||||
#include "state.h"
|
||||
|
||||
void r_init();
|
||||
void r_deinit();
|
||||
|
||||
void r_size_update(u32 width, u32 height);
|
||||
void r_time_update(f64 time);
|
||||
|
||||
void r_clear(v4 color = {0.0, 0.0, 0.0, 0.0});
|
||||
void r_swap();
|
||||
|
||||
|
||||
struct r_shadow_map
|
||||
{
|
||||
// FBO + depth
|
||||
u32 gl_FBO;
|
||||
u32 gl_depth_texture;
|
||||
m4 view_matrix;
|
||||
};
|
||||
|
||||
struct r_scene
|
||||
{
|
||||
m4 view_matrix;
|
||||
m4 view_matrix_inverse;
|
||||
|
||||
m4 projection_matrix;
|
||||
m4 projection_matrix_inverse;
|
||||
|
||||
r_object *objects;
|
||||
u64 objects_count;
|
||||
|
||||
r_light_container lights;
|
||||
GLuint gl_lights;
|
||||
|
||||
r_shadow_map shadow_map;
|
||||
|
||||
r_cubemap environment_map;
|
||||
};
|
||||
|
||||
r_scene r_scene_create();
|
||||
void r_scene_destroy(r_scene *scene);
|
||||
|
||||
void r_scene_set_view (r_scene *scene, m4 m);
|
||||
void r_scene_set_projection(r_scene *scene, m4 m);
|
||||
void r_update_lights(r_scene *scene);
|
||||
|
||||
|
||||
void r_render_scene(r_scene *scene);
|
||||
|
||||
|
||||
|
||||
// Single object rendering functions (batched funcs are below)
|
||||
void r_render_object(r_scene *scene, r_object *object, r_shader *shader_override = NULL);
|
||||
void r_render_object_wireframe(r_scene *scene, r_object *object);
|
||||
void r_render_line(r_scene *scene, v3 a, v3 b, v4 a_color, v4 b_color, f32 thickness = 1.0);
|
||||
|
||||
|
||||
// Batch render functions
|
||||
void r_render_objects(r_scene *scene, u64 count, r_object **objects);
|
||||
|
||||
|
||||
|
||||
// Shadow maps
|
||||
r_shadow_map r_build_shadow_map_sun(r_scene *scene, r_sun_light *sun);
|
||||
void r_free_shadow_map(r_shadow_map *sm);
|
||||
|
||||
|
||||
void r_framebuffer_select(r_framebuffer *fb);
|
||||
void r_merge_and_postprocess();
|
||||
|
||||
|
||||
#endif
|
||||
193
code/render/shader.cpp
Normal file
193
code/render/shader.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
#include "shader.h"
|
||||
#include "../debug/logger.h"
|
||||
|
||||
#define STB_INCLUDE_IMPLEMENTATION
|
||||
#define STB_INCLUDE_LINE_GLSL
|
||||
#include "stb_include.h"
|
||||
|
||||
// Internal functions
|
||||
void r_shader_set_uniform_locations(r_shader *shader);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool r_shader_from_files(r_shader *shader, const char *vertex, const char *fragment, const char *geometry, const char *tesseletion_control, const char *tesseletion_evaluation, const char *compute)
|
||||
{
|
||||
const int count = 6;
|
||||
char *source[count] = {NULL, NULL, NULL, NULL, NULL, NULL};
|
||||
const char *filename[count] = {vertex, fragment, geometry, tesseletion_control, tesseletion_evaluation, compute};
|
||||
const char *type[count] = {"vertex", "fragment", "geometry", "tesseletion_control", "tesseletion_evaluation", "compute"};
|
||||
|
||||
// Load sources
|
||||
bool has_error = false;
|
||||
char error[256];
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
if(filename[i])
|
||||
{
|
||||
char path[4096];
|
||||
u32 len = strlen(filename[i]);
|
||||
memcpy(path, filename[i], len+1);
|
||||
int last_slash = len;
|
||||
while(last_slash > 0)
|
||||
{
|
||||
if(filename[i][last_slash] == '/')
|
||||
break;
|
||||
last_slash--;
|
||||
}
|
||||
path[last_slash] = '\0';
|
||||
|
||||
source[i] = stb_include_file((char*)filename[i], NULL, path, error);
|
||||
if(!source[i])
|
||||
{
|
||||
has_error = true;
|
||||
LOG(LOG_ERROR, "Error loading %s shader: %s", type[i], error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compile shader
|
||||
if(!has_error)
|
||||
{
|
||||
has_error = !r_shader_from_text(shader, source[0], source[1], source[2], source[3], source[5], source[5]);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
if(source[i])
|
||||
free(source[i]);
|
||||
}
|
||||
|
||||
return !has_error;
|
||||
}
|
||||
|
||||
|
||||
bool r_shader_from_text(r_shader *shader, const char *vertex, const char *fragment, const char *geometry, const char *tesseletion_control, const char *tesseletion_evaluation, const char *compute)
|
||||
{
|
||||
int count = 6;
|
||||
GLuint type[count] = {GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER, GL_COMPUTE_SHADER};
|
||||
const char *source[count] = {vertex, fragment, geometry, tesseletion_control, tesseletion_evaluation, compute};
|
||||
|
||||
// Create shader program
|
||||
shader->id = glCreateProgram();
|
||||
|
||||
bool has_error = false;
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
if(!source[i])
|
||||
continue;
|
||||
|
||||
// Compile current shader source
|
||||
GLuint source_id = glCreateShader(type[i]);
|
||||
GLint size = strlen(source[i]);
|
||||
glShaderSource(source_id, 1, &source[i], &size);
|
||||
glCompileShader(source_id);
|
||||
|
||||
// Check for success/errors
|
||||
char build_info[2048];
|
||||
GLint build_success;
|
||||
glGetShaderiv(source_id, GL_COMPILE_STATUS, &build_success);
|
||||
if (!build_success)
|
||||
{
|
||||
glGetShaderInfoLog(source_id, 2048, NULL, build_info);
|
||||
LOG(LOG_ERROR, "Cannot compile shader %.*s: %s", (int)size, source, build_info);
|
||||
glDeleteShader(source_id);
|
||||
has_error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Attach compiler shader to program
|
||||
glAttachShader(shader->id, source_id);
|
||||
}
|
||||
|
||||
// @Correctness: Clean up shader sources after fail
|
||||
if(has_error)
|
||||
return false;
|
||||
|
||||
// Link program
|
||||
glLinkProgram(shader->id);
|
||||
|
||||
// Check for success/error
|
||||
GLint build_success;
|
||||
char build_info[512];
|
||||
glGetProgramiv(shader->id, GL_LINK_STATUS, &build_success);
|
||||
if(!build_success) {
|
||||
glGetProgramInfoLog(shader->id, 512, NULL, build_info);
|
||||
LOG(LOG_ERROR, "Cannot link shader program: %s", build_info);
|
||||
glDeleteShader(shader->id);
|
||||
has_error = true;
|
||||
}
|
||||
|
||||
// Load uniform locations
|
||||
if(!has_error)
|
||||
r_shader_set_uniform_locations(shader);
|
||||
|
||||
return !has_error;
|
||||
}
|
||||
|
||||
|
||||
void r_shader_delete(r_shader *shader)
|
||||
{
|
||||
glDeleteProgram(shader->id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Internal functions
|
||||
void r_shader_set_uniform_locations(r_shader *shader)
|
||||
{
|
||||
shader->time = glGetUniformLocation(shader->id, "time");
|
||||
shader->width = glGetUniformLocation(shader->id, "width");
|
||||
shader->height = glGetUniformLocation(shader->id, "height");
|
||||
|
||||
shader->view_matrix = glGetUniformLocation(shader->id, "view_matrix");
|
||||
shader->view_matrix_inverse = glGetUniformLocation(shader->id, "view_matrix_inverse");
|
||||
shader->model_matrix = glGetUniformLocation(shader->id, "model_matrix");
|
||||
shader->camera_position = glGetUniformLocation(shader->id, "camera_position");
|
||||
|
||||
for(int i = 0; i < R_SHADER_COLOR_MAX; i++)
|
||||
{
|
||||
char uniform_name[32]; sprintf(uniform_name, "color%d", i);
|
||||
shader->color[i] = glGetUniformLocation(shader->id, uniform_name);
|
||||
}
|
||||
for(int i = 0; i < R_SHADER_TEXTURES_MAX; i++)
|
||||
{
|
||||
char uniform_name[32];
|
||||
sprintf(uniform_name, "has_texture%d", i);
|
||||
shader->has_texture [i] = glGetUniformLocation(shader->id, uniform_name);
|
||||
sprintf(uniform_name, "texture%d", i);
|
||||
shader->texture [i] = glGetUniformLocation(shader->id, uniform_name);
|
||||
sprintf(uniform_name, "texture_channels%d", i);
|
||||
shader->texture_channels[i] = glGetUniformLocation(shader->id, uniform_name);
|
||||
}
|
||||
|
||||
shader->lights = glGetUniformBlockIndex(shader->id, "lights");
|
||||
if(shader->lights != GL_INVALID_INDEX)
|
||||
glUniformBlockBinding(shader->id, shader->lights, 0);
|
||||
shader->has_shadow_map = glGetUniformLocation(shader->id, "has_shadow_map");
|
||||
shader->shadow_map = glGetUniformLocation(shader->id, "shadow_map");
|
||||
shader->shadow_matrix = glGetUniformLocation(shader->id, "shadow_matrix");
|
||||
|
||||
shader->has_environment_map = glGetUniformLocation(shader->id, "has_environment_map");
|
||||
shader->environment_map = glGetUniformLocation(shader->id, "environment_map");
|
||||
|
||||
shader->has_albedo_texture = glGetUniformLocation(shader->id, "has_albedo_texture");
|
||||
shader->albedo_texture = glGetUniformLocation(shader->id, "albedo_texture");
|
||||
shader->albedo_factor = glGetUniformLocation(shader->id, "albedo_factor");
|
||||
shader->has_metallic_texture = glGetUniformLocation(shader->id, "has_metallic_texture");
|
||||
shader->metallic_texture = glGetUniformLocation(shader->id, "metallic_texture");
|
||||
shader->metallic_factor = glGetUniformLocation(shader->id, "metallic_factor");
|
||||
shader->has_roughness_texture = glGetUniformLocation(shader->id, "has_roughness_texture");
|
||||
shader->roughness_texture = glGetUniformLocation(shader->id, "roughness_texture");
|
||||
shader->roughness_factor = glGetUniformLocation(shader->id, "roughness_factor");
|
||||
shader->has_normal_texture = glGetUniformLocation(shader->id, "has_normal_texture");
|
||||
shader->normal_texture = glGetUniformLocation(shader->id, "normal_texture");
|
||||
shader->has_emissive_texture = glGetUniformLocation(shader->id, "has_emissive_texture");
|
||||
shader->emissive_texture = glGetUniformLocation(shader->id, "emissive_texture");
|
||||
shader->emissive_factor = glGetUniformLocation(shader->id, "emissive_factor");
|
||||
}
|
||||
85
code/render/shader.h
Normal file
85
code/render/shader.h
Normal file
@@ -0,0 +1,85 @@
|
||||
#ifndef _PIUMA_RENDER_SHADER_H_
|
||||
#define _PIUMA_RENDER_SHADER_H_
|
||||
|
||||
#include "../lib/types.h"
|
||||
#include "GL/glcorearb.h"
|
||||
|
||||
/*
|
||||
I put the uniform ids of all the shaders in the r_shader structure. Then I use only the
|
||||
ones I need. Yeah, it's not very flexible.
|
||||
|
||||
I would like to have automatic syncronization between shader and C++ code.
|
||||
There are 3 ways to do that:
|
||||
- Parse shader code and auto-generate C++ structures and code;
|
||||
- Parse C++ structures and generate a shader source, or update an existing one;
|
||||
- Use a language than let me define shader code directly in that language, then it's compiled
|
||||
directly to GPU ASM, or it generates GLSL code that is then given to the GPU driver. This is
|
||||
the ideal solution, but yeah, that language is not C++... if it event exists. Let's hope for
|
||||
a better future.
|
||||
*/
|
||||
|
||||
#define R_SHADER_TEXTURES_MAX 4
|
||||
#define R_SHADER_COLOR_MAX 4
|
||||
|
||||
struct r_shader
|
||||
{
|
||||
GLuint id;
|
||||
|
||||
// Common state
|
||||
GLint time;
|
||||
GLint width;
|
||||
GLint height;
|
||||
|
||||
// View and camera
|
||||
GLint view_matrix;
|
||||
GLint view_matrix_inverse;
|
||||
GLint model_matrix;
|
||||
GLint camera_position;
|
||||
|
||||
// For arrays, the name in the shader is in the format [name][index].
|
||||
// Example: color[4] will be: color0, color1, color2, color3
|
||||
|
||||
// Generic parameters that can be used for different purpose based on the shader needs.
|
||||
// Example: texture1 could be a diffuse texture, texture2 an emissive texture, texture3 bump mapping
|
||||
GLint color[R_SHADER_COLOR_MAX];
|
||||
GLint has_texture [R_SHADER_TEXTURES_MAX]; // Is textureX assigned or not?
|
||||
GLint texture [R_SHADER_TEXTURES_MAX]; // Actual texture
|
||||
GLint texture_channels[R_SHADER_TEXTURES_MAX]; // Number of channels in the texture data
|
||||
|
||||
// Lights and shadows
|
||||
// @Cleanup: maybe merge this with the generic texture parameter?
|
||||
GLint lights;
|
||||
GLint has_shadow_map;
|
||||
GLint shadow_map;
|
||||
GLint shadow_matrix;
|
||||
|
||||
// Environment map
|
||||
GLint has_environment_map;
|
||||
GLint environment_map;
|
||||
|
||||
// PBR material
|
||||
GLint has_albedo_texture;
|
||||
GLint albedo_texture;
|
||||
GLint albedo_factor;
|
||||
GLint has_metallic_texture;
|
||||
GLint metallic_texture;
|
||||
GLint metallic_factor;
|
||||
GLint has_roughness_texture;
|
||||
GLint roughness_texture;
|
||||
GLint roughness_factor;
|
||||
GLint has_normal_texture;
|
||||
GLint normal_texture;
|
||||
GLint has_emissive_texture;
|
||||
GLint emissive_texture;
|
||||
GLint emissive_factor;
|
||||
};
|
||||
|
||||
|
||||
bool r_shader_from_files(r_shader *shader, const char *vertex, const char *fragment, const char *geometry = NULL, const char *tesseletion_control = NULL, const char *tesseletion_evaluation = NULL, const char *compute = NULL);
|
||||
bool r_shader_from_text(r_shader *shader, const char *vertex, const char *fragment, const char *geometry = NULL, const char *tesseletion_control = NULL, const char *tesseletion_evaluation = NULL, const char *compute = NULL);
|
||||
|
||||
void r_shader_delete(r_shader *shader);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
36
code/render/state.h
Normal file
36
code/render/state.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef _PIUMA_RENDER_STATE_H_
|
||||
#define _PIUMA_RENDER_STATE_H_
|
||||
|
||||
#include "shader.h"
|
||||
#include "primitives.h"
|
||||
|
||||
struct r_state
|
||||
{
|
||||
// Shaders
|
||||
r_shader shader_2d;
|
||||
r_shader shader_postprocessing;
|
||||
r_shader shader_pbr;
|
||||
r_shader shader_shadow_map;
|
||||
r_shader shader_environment_map;
|
||||
|
||||
// Screen size
|
||||
u32 width, height;
|
||||
|
||||
// Time
|
||||
f64 time;
|
||||
|
||||
// Framebuffers
|
||||
r_framebuffer *current_framebuffer;
|
||||
|
||||
r_framebuffer framebuffer_SCREEN;
|
||||
r_framebuffer framebuffer_HUD;
|
||||
r_framebuffer framebuffer_3D;
|
||||
|
||||
// Quads
|
||||
u32 gl_screen_quad_VAO;
|
||||
u32 gl_screen_quad_VBO;
|
||||
};
|
||||
|
||||
extern r_state r_render_state;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user