Lumenarium/src_v2/platform/win32/lumenarium_win32_graphics.cpp

336 lines
9.7 KiB
C++

#define win32_gl_no_error() win32_gl_no_error_(__FILE__, __LINE__)
void win32_gl_no_error_(char* file, u32 line) {
u32 error = glGetError();
char* str = 0;
if (error) {
str = win32_gl_error_to_string(error);
}
if (error != 0)
{
err_write("OpenGL error: %s:%d\n\t%s :: %d\n", file, line, str, error);
invalid_code_path;
}
}
Platform_Geometry_Buffer
platform_geometry_buffer_create(
r32* vertices, u32 vertices_len,
u32* indices, u32 indices_len
){
Platform_Geometry_Buffer result = {};
gl.glGenVertexArrays(1, &result.buffer_id_vao);
win32_gl_no_error();
GLuint buffers[2];
gl.glGenBuffers(2, (GLuint*)buffers);
win32_gl_no_error();
result.buffer_id_vertices = buffers[0];
result.buffer_id_indices = buffers[1];
// Vertices
gl.glBindVertexArray(result.buffer_id_vao);
gl.glBindBuffer(GL_ARRAY_BUFFER, result.buffer_id_vertices);
win32_gl_no_error();
gl.glBufferData(
GL_ARRAY_BUFFER, sizeof(r32) * vertices_len, vertices, GL_STATIC_DRAW
);
win32_gl_no_error();
result.vertices_len = vertices_len;
// Indices
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, result.buffer_id_indices);
win32_gl_no_error();
gl.glBufferData(
GL_ELEMENT_ARRAY_BUFFER, sizeof(u32) * indices_len, indices, GL_STATIC_DRAW
);
win32_gl_no_error();
result.indices_len = indices_len;
gl.glBindBuffer(GL_ARRAY_BUFFER, NULL);
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);
return result;
}
void
platform_geometry_buffer_update(
Platform_Geometry_Buffer* buffer,
r32* verts,
u32 verts_offset,
u32 verts_len,
u32* indices,
u32 indices_offset,
u32 indices_len
){
gl.glBindVertexArray(buffer->buffer_id_vao);
gl.glBindBuffer(GL_ARRAY_BUFFER, buffer->buffer_id_vertices);
win32_gl_no_error();
if (verts_len > buffer->vertices_len)
{
// NOTE(PS): this is because we're going to delete the old buffer and
// create a new one. In order to do that and not lose data, the update
// function needs to have been passed all the buffer's data
assert(verts_offset == 0);
gl.glBufferData(
GL_ARRAY_BUFFER, verts_len * sizeof(r32), (void*)verts, GL_STATIC_DRAW
);
}
else
{
gl.glBufferSubData(
GL_ARRAY_BUFFER, verts_offset * sizeof(r32), verts_len * sizeof(r32), (void*)verts
);
}
win32_gl_no_error();
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->buffer_id_indices);
win32_gl_no_error();
if (indices_len > buffer->indices_len)
{
// NOTE(PS): this is because we're going to delete the old buffer and
// create a new one. In order to do that and not lose data, the update
// function needs to have been passed all the buffer's data
assert(indices_offset == 0);
gl.glBufferData(
GL_ELEMENT_ARRAY_BUFFER, indices_len * sizeof(u32), (void*)indices, GL_STATIC_DRAW
);
}
else
{
gl.glBufferSubData(
GL_ELEMENT_ARRAY_BUFFER, indices_offset * sizeof(u32), indices_len * sizeof(u32), (void*)indices
);
}
win32_gl_no_error();
}
Platform_Shader
platform_shader_create(
String code_vert, String code_frag, String* attrs, u32 attrs_len, String* uniforms, u32 uniforms_len
){
Platform_Shader result = {};
GLuint shader_vert = gl.glCreateShader(GL_VERTEX_SHADER);
gl.glShaderSource(shader_vert, 1, (const char**)&code_vert.str, &(s32)code_vert.len);
gl.glCompileShader(shader_vert);
{ // errors
GLint shader_vert_compiled;
gl.glGetShaderiv(shader_vert, GL_COMPILE_STATUS, &shader_vert_compiled);
if (!shader_vert_compiled)
{
GLsizei log_length = 0;
GLchar message[1024];
gl.glGetShaderInfoLog(shader_vert, 1024, &log_length, message);
invalid_code_path;
}
}
GLuint shader_frag = gl.glCreateShader(GL_FRAGMENT_SHADER);
gl.glShaderSource(shader_frag, 1, (const char**)&code_frag.str, &(s32)code_frag.len);
gl.glCompileShader(shader_frag);
{ // errors
GLint shader_frag_compiled;
gl.glGetShaderiv(shader_frag, GL_COMPILE_STATUS, &shader_frag_compiled);
if (!shader_frag_compiled)
{
GLsizei log_length = 0;
GLchar message[1024];
gl.glGetShaderInfoLog(shader_frag, 1024, &log_length, message);
invalid_code_path;
}
}
result.id = (u32)gl.glCreateProgram();
gl.glAttachShader(result.id, shader_vert);
gl.glAttachShader(result.id, shader_frag);
gl.glLinkProgram(result.id);
GLint program_linked;
gl.glGetProgramiv(result.id, GL_LINK_STATUS, &program_linked);
if (program_linked != GL_TRUE)
{
GLsizei log_length = 0;
GLchar message[1024];
gl.glGetProgramInfoLog(result.id, 1024, &log_length, message);
invalid_code_path;
}
gl.glUseProgram(result.id);
// TODO(PS): delete the vert and frag programs
assert(attrs_len < PLATFORM_SHADER_MAX_ATTRS);
for (u32 i = 0; i < attrs_len; i++)
{
result.attrs[i] = gl.glGetAttribLocation(
result.id, (char*)attrs[i].str
);
win32_gl_no_error();
}
result.attrs[attrs_len] = PLATFORM_SHADER_ATTR_LAST;
assert(uniforms_len < PLATFORM_SHADER_MAX_ATTRS);
for (GLuint i = 0; i < uniforms_len; i++)
{
s32 len = (s32)uniforms[i].len;
result.uniforms[i] = gl.glGetUniformLocation(
result.id, (char*)uniforms[i].str
);
}
result.uniforms[uniforms_len] = PLATFORM_SHADER_ATTR_LAST;
return result;
}
void
platform_set_uniform(Platform_Shader shader, u32 index, m44 u)
{
gl.glUniformMatrix4fv(shader.uniforms[index], 1, GL_FALSE, (r32*)u.Elements);
}
void
platform_geometry_bind(Platform_Geometry_Buffer geo)
{
gl.glBindVertexArray(geo.buffer_id_vao);
win32_gl_no_error();
gl.glBindBuffer(GL_ARRAY_BUFFER, geo.buffer_id_vertices);
win32_gl_no_error();
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geo.buffer_id_indices);
win32_gl_no_error();
}
void
platform_shader_bind(Platform_Shader shader)
{
gl.glUseProgram(shader.id);
win32_gl_no_error();
for (u32 i = 0;
((i < PLATFORM_SHADER_MAX_ATTRS) && (shader.attrs[i] != PLATFORM_SHADER_ATTR_LAST));
i++)
{
gl.glEnableVertexAttribArray(shader.attrs[i]);
win32_gl_no_error();
}
}
void
platform_geometry_draw(
Platform_Geometry_Buffer geo, u32 indices
){
glDrawElements(GL_TRIANGLES, indices, GL_UNSIGNED_INT, 0);
win32_gl_no_error();
}
void
platform_geometry_draw(
Platform_Geometry_Buffer geo
){
platform_geometry_draw(geo, geo.indices_len);
}
void platform_vertex_attrib_pointer(
Platform_Geometry_Buffer geo, Platform_Shader shader, GLuint count, GLuint attr_index, GLuint stride, GLuint offset
){
platform_geometry_bind(geo);
gl.glVertexAttribPointer(shader.attrs[attr_index], count, GL_FLOAT, false, stride * sizeof(float), (void*)(offset * sizeof(float)));
win32_gl_no_error();
gl.glEnableVertexAttribArray(shader.attrs[attr_index]);
win32_gl_no_error();
}
Platform_Texture
platform_texture_create(u8* pixels, u32 width, u32 height, u32 stride)
{
Platform_Texture result = {};
glGenTextures(1, &result.id);
win32_gl_no_error();
glBindTexture(GL_TEXTURE_2D, result.id);
win32_gl_no_error();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
win32_gl_no_error();
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA,
width,
height,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
pixels
);
win32_gl_no_error();
result.w = width;
result.h = height;
result.s = stride;
return result;
}
void
platform_texture_update(Platform_Texture tex, u8* new_pixels, u32 width, u32 height, u32 stride)
{
// NOTE(PS): this function simply replaces the entire image
// we can write a more granular version if we need it
assert(tex.w == width && tex.h == height && tex.s == stride);
platform_texture_bind(tex);
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0, 0, // offset
width, height,
GL_RGBA,
GL_UNSIGNED_BYTE,
new_pixels
);
}
void
platform_texture_bind(Platform_Texture tex)
{
glBindTexture(GL_TEXTURE_2D, tex.id);
win32_gl_no_error();
}
void
platform_frame_begin(Platform_Graphics_Frame_Desc desc)
{
v4 cc = desc.clear_color;
glClearColor(cc.r, cc.g, cc.b, cc.a);
v2 vmin = desc.viewport_min;
v2 vmax = desc.viewport_max;
glViewport((GLsizei)vmin.x, (GLsizei)vmin.y, (GLint)vmax.x, (GLint)vmax.y);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
win32_gl_no_error();
}
void
platform_frame_clear()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}