Files
Server_Monitor/code/render/2d.cpp

383 lines
11 KiB
C++
Raw Normal View History

2023-09-26 19:40:16 +02:00
#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);
}
}