diff --git a/src/assets.cpp b/src/assets.cpp index f37402e..77cc918 100644 --- a/src/assets.cpp +++ b/src/assets.cpp @@ -205,9 +205,8 @@ apLoadImage(u8 *data, u64 len) image.h = -1; image.ch = -1; - int ch = 4; int w, h, has_ch; - u8 *bytes = stbi_load_from_memory(data, len, &w, &h, &has_ch, ch); + u8 *bytes = stbi_load_from_memory(data, len, &w, &h, &has_ch, 0); if (w <= 0 || h <= 0 || has_ch <= 0) { Printfln("apLoadImage failure: %s", stbi_failure_reason()); @@ -250,6 +249,7 @@ apParseModel(u8 *data) m3d_t *m3d = m3d_load(data, NULL, NULL, NULL); Assert(m3d != NULL, "model returned is NULL"); + /* Printfln("model: %s", m3d->name); Printfln("numcmap: %llu", m3d->numcmap); Printfln("numtmap: %llu", m3d->numtmap); @@ -266,6 +266,7 @@ apParseModel(u8 *data) Printfln("numaction: %llu", m3d->numaction); Printfln("numinlined: %llu", m3d->numinlined); Printfln("numextra: %llu", m3d->numextra); + */ apModel *model = (apModel *)malloc(sizeof(apModel)); @@ -283,8 +284,6 @@ apParseModel(u8 *data) for (u64 i = 0; i < m3d->numtexture; i += 1) { - Printfln("texture: %s", m3d->texture[i].name); - model->textures.data[i].bytes = m3d->texture[i].d; model->textures.data[i].w = m3d->texture[i].w; model->textures.data[i].h = m3d->texture[i].h; @@ -298,8 +297,6 @@ apParseModel(u8 *data) for (u64 i = 0; i < m3d->nummaterial; i += 1) { - Printfln("material: %llu %s", i, m3d->material[i].name); - model->materials.data[i].tex.albedo = UINT32_MAX; model->materials.data[i].tex.ambient = UINT32_MAX; model->materials.data[i].tex.specular = UINT32_MAX; @@ -322,17 +319,14 @@ apParseModel(u8 *data) } break; case m3dp_map_Kd: { - Printfln("albedo: %llu", m3d->material[i].prop[j].value.textureid); model->materials.data[i].tex.albedo = m3d->material[i].prop[j].value.textureid; } break; case m3dp_map_Ka: { - Printfln("ambient: %llu", m3d->material[i].prop[j].value.textureid); model->materials.data[i].tex.ambient = m3d->material[i].prop[j].value.textureid; } break; case m3dp_map_Ks: { - Printfln("specular: %llu", m3d->material[i].prop[j].value.textureid); model->materials.data[i].tex.specular = m3d->material[i].prop[j].value.textureid; } break; default: diff --git a/src/codegen.cpp b/src/codegen.cpp index 415ec37..6999d41 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1,4 +1,4 @@ -#include "codegen.h" +#include "os.h" #include "os.cpp" diff --git a/src/codegen.h b/src/codegen.h deleted file mode 100644 index f732cf7..0000000 --- a/src/codegen.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#define STG_IMPLEMENTATION - -#include "os.h" - diff --git a/src/renderer.cpp b/src/renderer.cpp index 11bd5b9..03a6020 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -2,411 +2,9 @@ #include "assets.cpp" -// ::Globals:: - -PipelineCreateInfo g_Pipeline_Create_Info[] = { - { .vertex_shader = "shaders/pbr.vert", .fragment_shader = "shaders/pbr.frag" }, - //{ .vertex_shader = "shaders/gui.vert", .fragment_shader = "shaders/gui.frag" }, -}; - -// ::Init::Impl::Start:: - -rIndexedBuffer yoder; - -static b32 -Init(Renderer *renderer) -{ - b32 success = true; - - renderer->perm_arena = ArenaCreate(MB(32)); - - for (u64 i = 0; i < FRAME_OVERLAP; i += 1) - { - renderer->frame_arenas[i] = ArenaCreate(MB(16)); - } - - RGFW_setGLHint(RGFW_glMajor, 4); - RGFW_setGLHint(RGFW_glMinor, 6); - RGFW_setGLHint(RGFW_glProfile, RGFW_glCore); - - renderer->window = RGFW_createWindow("Video Game", RGFW_RECT(0, 0, 1280, 720), RGFW_windowCenter | RGFW_windowNoResize); - if (renderer->window == NULL) - { - Printfln("Failed to create window"); - success = false; - } - - if (success) - { - RGFW_window_makeCurrent(renderer->window); - - int glad_version = gladLoaderLoadGL(); - if (!glad_version) - { - Printfln("gladLoaderLoadGL failure"); - success = false; - } - } - -#ifdef BUILD_DEBUG - glEnable(GL_DEBUG_OUTPUT); - glDebugMessageCallback(DebugCallback, NULL); -#endif - - for (u32 i = 0; i < PIPELINE_MAX; i += 1) - { - renderer->pipelines[i] = BuildPipeline(g_Pipeline_Create_Info + i); - } - - glCreateBuffers(1, &renderer->mat_buf); - apMatProps props = {0}; - glNamedBufferData(renderer->mat_buf, sizeof(apMatProps), &props, GL_STATIC_DRAW); - - InitModels(renderer); - - return success; -} - -static void -InitModels(Renderer *renderer) -{ - Arena *arena = renderer->perm_arena; - - for (u64 i = 0; i < MODEL_ASSET_MAX; i += 1) - { - u64 hash = g_Model_Asset_Hashes[i]; - Asset asset = apLoadWithHash(hash); - Assert(asset.model != NULL, "InitModels failure: Model loaded is NULL"); - - apModel *a_model = asset.model; - rModel *model = renderer->models + i; - - model->textures.length = a_model->textures.length; - model->textures.data = (u32 *)ArenaAlloc(arena, sizeof(u32) * model->textures.length); - - for (u64 j = 0; j < model->textures.length; j += 1) - { - apTexData *t_data = a_model->textures.data + j; - model->textures.data[j] = CreateTexture(t_data->bytes, t_data->w, t_data->h, t_data->ch); - Assert(model->textures.data[j] != GL_NONE, "InitModels failure: texture data is GL_NONE"); - } - - apVertexArray v_arr = a_model->vertices; - u32Array i_arr = a_model->indices; - model->buffer = CreateIndexedBuffer(v_arr.data, v_arr.length, i_arr.data, i_arr.length); - - - // TODO: placeholder/error material - model->meshes.length = a_model->meshes.length; - model->meshes.data = (rMesh *)ArenaAlloc(arena, sizeof(rMesh) * a_model->meshes.length); - for (u64 i = 0; i < model->meshes.length; i += 1) - { - apMesh *a_mesh = a_model->meshes.data + i; - rMesh *mesh = model->meshes.data + i; - - mesh->length = a_mesh->length; - mesh->idx_offset = uintptr(a_mesh->start_idx * sizeof(u32)); - - mesh->type = PPT_NONE; - if (a_mesh->mat_idx != UINT32_MAX) - { - Printfln("mesh: %llu mat_idx: %llu", i, a_mesh->mat_idx); - apMaterial *mat = a_model->materials.data + a_mesh->mat_idx; - - mesh->type |= mat->tex.albedo != UINT32_MAX ? PPT_ALBEDO_TEX : PPT_ALBEDO_VALUE; - mesh->type |= mat->tex.ambient != UINT32_MAX ? PPT_AMBIENT_TEX : PPT_AMBIENT_VALUE; - mesh->type |= mat->tex.specular != UINT32_MAX ? PPT_SPECULAR_TEX : PPT_SPECULAR_VALUE; - - mesh->values = mat->props; - mesh->textures.albedo = mat->tex.albedo != UINT32_MAX ? model->textures.data[mat->tex.albedo] : 0; - mesh->textures.ambient = mat->tex.ambient != UINT32_MAX ? model->textures.data[mat->tex.ambient] : 0; - mesh->textures.specular = mat->tex.specular != UINT32_MAX ? model->textures.data[mat->tex.specular] : 0; - } - } - } -} - -static PipelineHandle -BuildPipeline(PipelineCreateInfo *create_info) -{ - auto vertex_shader = CreateShader(GL_VERTEX_SHADER); - Assert(BuildShader(&vertex_shader, create_info->vertex_shader), "BuildShader vertex failure"); - - auto fragment_shader = CreateShader(GL_FRAGMENT_SHADER); - Assert(BuildShader(&fragment_shader, create_info->fragment_shader), "BuildShader fragment failure"); - - auto pipeline = CreatePipeline(); - glAttachShader(pipeline, vertex_shader); - glAttachShader(pipeline, fragment_shader); - glLinkProgram(pipeline); - - int success = 0; - glGetProgramiv(pipeline, GL_LINK_STATUS, &success); - if (!success) - { - char info_log[512]; - glGetProgramInfoLog(pipeline, 512, NULL, info_log); - Assert(false, "Failed to build pipeline"); - } - - return pipeline; -} - -static b32 -BuildShader(ShaderHandle *handle, char *asset) -{ - b32 success = true; - - Asset data = apLoad(asset); - Assert(data.bytes != NULL && asset, "Shader data is NULL"); - - glShaderBinary(1, handle, GL_SHADER_BINARY_FORMAT_SPIR_V, data.bytes, data.len); - glSpecializeShader(*handle, "main", 0, 0, 0); - - int compiled = 0; - glGetShaderiv(*handle, GL_COMPILE_STATUS, &compiled); - if (!compiled) - { - char info_log[512]; - glGetShaderInfoLog(*handle, 512, NULL, info_log); - Printfln("Unable to compile shader: %s", info_log); - success = false; - } - - return success; -} - -static PipelineHandle -CreatePipeline() -{ - PipelineHandle pipeline = glCreateProgram(); - return pipeline; -} - -static VertexBuffer -CreateVertexBuffer() -{ - VertexBuffer buf; - glGenBuffers(1, &buf); - - return buf; -} - -static IndexBuffer -CreateIndexBuffer() -{ - IndexBuffer buf; - glGenBuffers(1, &buf); - - return buf; -} - -static VertexArray -CreateVertexArray() -{ - VertexArray array; - glGenVertexArrays(1, &array); - - return array; -} - -static ShaderHandle -CreateShader(int type) -{ - return (ShaderHandle)glCreateShader(type); -} - -// ::Init::Impl::End:: - - -// ::Draw::Impl::Start:: - -static void -rDrawModel(Renderer *renderer, rModel *model) -{ - glUseProgram(renderer->pipelines[PIPELINE_PBR]); - - for (u64 i = 0; i < model->meshes.length; i += 1) - { - rMesh *mesh = model->meshes.data + i; - - u32 albedo = mesh->textures.albedo != UINT32_MAX ? mesh->textures.albedo : 0; - glBindTextureUnit(0, albedo); - - u32 ambient = mesh->textures.ambient != UINT32_MAX ? mesh->textures.ambient : 0; - glBindTextureUnit(1, ambient); - - u32 specular = mesh->textures.specular != UINT32_MAX ? mesh->textures.ambient : 0; - glBindTextureUnit(2, specular); - - glNamedBufferSubData(renderer->mat_buf, 0, sizeof(apMatProps), &mesh->values); - - glBindBufferBase(GL_UNIFORM_BUFFER, 0, renderer->mat_buf); - - glBindVertexArray(model->buffer.vao); - glDrawElements(GL_TRIANGLES, mesh->length, GL_UNSIGNED_INT, (void *)(model->buffer.ioffset + mesh->idx_offset)); - } -} - -static void -DrawIndexedBuffer(rIndexedBuffer *buffer) -{ - glBindVertexArray(buffer->vao); - glDrawElements(GL_TRIANGLES, buffer->icount, GL_UNSIGNED_INT, (void *)buffer->ioffset); -} - -// ::Draw::Impl::End:: - - -// ::Buffers::Impl::Start:: - -static rIndexedBuffer -CreateIndexedBuffer(rawptr vert_data, u32 vcount, rawptr idx_data, u32 icount) -{ - i32 alignment = GL_NONE; - glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment); - - u32 vao = GL_NONE; - u32 buffer = GL_NONE; - - isize vert_len = isize(vcount * sizeof(apVertex)); - isize idx_len = isize(icount * sizeof(u32)); - - isize vert_len_aligned = Align(vert_len, alignment); - isize idx_len_aligned = Align(idx_len, alignment); - -#if BUILD_DEBUG - Assert((vert_len_aligned % alignment) == 0, "Buffers are not aligned"); - Assert((idx_len_aligned % alignment) == 0, "Buffers are not aligned"); -#endif - - isize vert_offset = 0; - isize idx_offset = vert_len_aligned; - - glCreateBuffers(1, &buffer); - glNamedBufferStorage(buffer, idx_len_aligned + vert_len_aligned, NULL, GL_DYNAMIC_STORAGE_BIT); - - glNamedBufferSubData(buffer, vert_offset, vert_len, vert_data); - glNamedBufferSubData(buffer, idx_offset, idx_len, idx_data); - - glCreateVertexArrays(1, &vao); - - constexpr u32 pos_size = SizeOfMember(apVertex, pos) / sizeof(f32); - SetVertexAttrib(vao, 0, pos_size, GL_FLOAT, GL_FALSE, offsetof(apVertex, pos)); - - constexpr u32 normal_size = SizeOfMember(apVertex, normal) / sizeof(f32); - SetVertexAttrib(vao, 1, normal_size, GL_FLOAT, GL_FALSE, offsetof(apVertex, normal)); - - constexpr u32 col_size = SizeOfMember(apVertex, color) / sizeof(u8); - SetVertexAttrib(vao, 2, col_size, GL_UNSIGNED_BYTE, GL_FALSE, offsetof(apVertex, color)); - - constexpr u32 uv_size = SizeOfMember(apVertex, uv) / sizeof(f32); - SetVertexAttrib(vao, 3, uv_size, GL_FLOAT, GL_FALSE, offsetof(apVertex, uv)); - - glVertexArrayVertexBuffer(vao, 0, buffer, vert_offset, sizeof(apVertex)); - glVertexArrayElementBuffer(vao, buffer); - - rIndexedBuffer indexed_buffer = {0}; - indexed_buffer.ioffset = idx_offset; - indexed_buffer.icount = icount; - indexed_buffer.vao = vao; - indexed_buffer.buffer = buffer; - - return indexed_buffer; -} - -static void -SetVertexAttrib(u32 vao, u32 idx, u32 count, i32 type, b32 normalized, u32 offset) -{ - glEnableVertexArrayAttrib(vao, idx); - glVertexArrayAttribBinding(vao, idx, 0); - glVertexArrayAttribFormat(vao, idx, count, type, normalized, offset); -} - -// ::Buffers::Impl::End:: - - - -// ::Textures::Impl::Start:: - -static u32 -CreateTexture(rawptr data, u32 width, u32 height, u32 channels) -{ - u32 tex; - glCreateTextures(GL_TEXTURE_2D, 1, &tex); - - i32 mipmap = Mini32(5, i32(log2f(f32(Maxi32(width, height))))); - - u32 format, copy_format; - switch (channels) - { - case 1: - { - format = GL_R8; - copy_format = GL_RED; - } break; - case 2: - { - format = GL_RG8; - copy_format = GL_RG; - } break; - case 3: - { - format = GL_RGB8; - copy_format = GL_RGB; - } break; - case 4: - { - format = GL_RGBA8; - copy_format = GL_RGBA; - } break; - default: - { - Assert(false, "CreateTexture failure: unsupported channel number passed in"); - } break; - } - - glTextureStorage2D(tex, mipmap, format, width, height); - glTextureSubImage2D(tex, 0, 0, 0, width, height, copy_format, GL_UNSIGNED_BYTE, data); - - glTextureParameteri(tex, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTextureParameteri(tex, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTextureParameterf(tex, GL_TEXTURE_BASE_LEVEL, 0); - glTextureParameteri(tex, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTextureParameteri(tex, GL_TEXTURE_WRAP_T, GL_REPEAT); - - glGenerateTextureMipmap(tex); - - return tex; -} - -// ::Textures::Impl::End:: - -static b32 -RunCycle(Renderer *renderer) -{ - while (RGFW_window_checkEvent(renderer->window)); - - glUseProgram(renderer->pipelines[PIPELINE_PBR]); - - glClearColor(0.1f, 0.8f, 0.4f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - rDrawModel(renderer, renderer->models + 2); - - RGFW_window_swapBuffers(renderer->window); - - return !RGFW_window_shouldClose(renderer->window); -} - - - -// ::Debug::Impl::Start:: - void DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, GLchar const* message, void const* user_param) { - return; if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) return; const char *source_str, *type_str, *severity_str; @@ -506,4 +104,379 @@ DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei le Printfln("Source: [%s] \nType: [%s] \nSeverity: [%s] \n%s", source_str, type_str, severity_str, message); } -// ::Debug::Impl::End:: +static void +SetVertexAttrib(u32 vao, u32 idx, u32 count, i32 type, b32 normalized, u32 offset) +{ + glEnableVertexArrayAttrib(vao, idx); + glVertexArrayAttribBinding(vao, idx, 0); + glVertexArrayAttribFormat(vao, idx, count, type, normalized, offset); +} + +static rIndexedBuffer +CreateIndexedBuffer(rawptr vert_data, u32 vcount, rawptr idx_data, u32 icount) +{ + i32 alignment = GL_NONE; + glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &alignment); + + u32 vao = GL_NONE; + u32 buffer = GL_NONE; + + isize vert_len = isize(vcount * sizeof(apVertex)); + isize idx_len = isize(icount * sizeof(u32)); + + isize vert_len_aligned = Align(vert_len, alignment); + isize idx_len_aligned = Align(idx_len, alignment); + +#if BUILD_DEBUG + Assert((vert_len_aligned % alignment) == 0, "Buffers are not aligned"); + Assert((idx_len_aligned % alignment) == 0, "Buffers are not aligned"); +#endif + + isize vert_offset = 0; + isize idx_offset = vert_len_aligned; + + glCreateBuffers(1, &buffer); + glNamedBufferStorage(buffer, idx_len_aligned + vert_len_aligned, NULL, GL_DYNAMIC_STORAGE_BIT); + + glNamedBufferSubData(buffer, vert_offset, vert_len, vert_data); + glNamedBufferSubData(buffer, idx_offset, idx_len, idx_data); + + glCreateVertexArrays(1, &vao); + + constexpr u32 pos_size = SizeOfMember(apVertex, pos) / sizeof(f32); + SetVertexAttrib(vao, 0, pos_size, GL_FLOAT, GL_FALSE, offsetof(apVertex, pos)); + + constexpr u32 normal_size = SizeOfMember(apVertex, normal) / sizeof(f32); + SetVertexAttrib(vao, 1, normal_size, GL_FLOAT, GL_FALSE, offsetof(apVertex, normal)); + + constexpr u32 col_size = SizeOfMember(apVertex, color) / sizeof(u8); + SetVertexAttrib(vao, 2, col_size, GL_UNSIGNED_BYTE, GL_FALSE, offsetof(apVertex, color)); + + constexpr u32 uv_size = SizeOfMember(apVertex, uv) / sizeof(f32); + SetVertexAttrib(vao, 3, uv_size, GL_FLOAT, GL_FALSE, offsetof(apVertex, uv)); + + glVertexArrayVertexBuffer(vao, 0, buffer, vert_offset, sizeof(apVertex)); + glVertexArrayElementBuffer(vao, buffer); + + rIndexedBuffer indexed_buffer = {0}; + indexed_buffer.ioffset = idx_offset; + indexed_buffer.icount = icount; + indexed_buffer.vao = vao; + indexed_buffer.buffer = buffer; + + return indexed_buffer; +} + +static b32 +BuildShader(GLuint *handle, char *asset) +{ + b32 success = true; + + Asset data = apLoad(asset); + Assert(data.bytes != NULL && asset, "Shader data is NULL"); + + glShaderBinary(1, handle, GL_SHADER_BINARY_FORMAT_SPIR_V, data.bytes, data.len); + glSpecializeShader(*handle, "main", 0, 0, 0); + + int compiled = 0; + glGetShaderiv(*handle, GL_COMPILE_STATUS, &compiled); + if (!compiled) + { + char info_log[512]; + glGetShaderInfoLog(*handle, 512, NULL, info_log); + Printfln("Unable to compile shader: %s", info_log); + success = false; + } + + return success; +} + +static u32 +CreateTexture(rawptr data, u32 width, u32 height, u32 channels) +{ + u32 tex; + glCreateTextures(GL_TEXTURE_2D, 1, &tex); + + i32 mipmap = Mini32(5, i32(log2f(f32(Maxi32(width, height))))); + + u32 format, copy_format; + switch (channels) + { + case 1: + { + format = GL_R8; + copy_format = GL_RED; + } break; + case 2: + { + format = GL_RG8; + copy_format = GL_RG; + } break; + case 3: + { + format = GL_RGB8; + copy_format = GL_RGB; + } break; + case 4: + { + format = GL_RGBA8; + copy_format = GL_RGBA; + } break; + default: + { + Assert(false, "CreateTexture failure: unsupported channel number passed in"); + } break; + } + + glTextureStorage2D(tex, mipmap, format, width, height); + glTextureSubImage2D(tex, 0, 0, 0, width, height, copy_format, GL_UNSIGNED_BYTE, data); + + glTextureParameteri(tex, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTextureParameteri(tex, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTextureParameterf(tex, GL_TEXTURE_BASE_LEVEL, 0); + glTextureParameteri(tex, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTextureParameteri(tex, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glGenerateTextureMipmap(tex); + + return tex; +} + +static void +InitModels(Renderer *renderer) +{ + Arena *arena = renderer->perm_arena; + + for (u64 i = 0; i < MODEL_ASSET_MAX; i += 1) + { + // Init/Load Model + u64 hash = g_Model_Asset_Hashes[i]; + Asset asset = apLoadWithHash(hash); + Assert(asset.model != NULL, "InitModels failure: Model loaded is NULL"); + + apModel *a_model = asset.model; + rModel *model = renderer->models + i; + + // Textures + model->textures.length = a_model->textures.length; + model->textures.data = (u32 *)ArenaAlloc(arena, sizeof(u32) * model->textures.length); + + for (u64 j = 0; j < model->textures.length; j += 1) + { + apTexData *t_data = a_model->textures.data + j; + model->textures.data[j] = CreateTexture(t_data->bytes, t_data->w, t_data->h, t_data->ch); + Assert(model->textures.data[j] != GL_NONE, "InitModels failure: texture data is GL_NONE"); + } + + // Vertex/Index Buffers + apVertexArray v_arr = a_model->vertices; + u32Array i_arr = a_model->indices; + model->buffer = CreateIndexedBuffer(v_arr.data, v_arr.length, i_arr.data, i_arr.length); + + // Material Meshes + // TODO: placeholder/error material + + struct StateIndex { + rPBRState state; + u32 buffer; + }; + + StateIndex *prev_state = (StateIndex *)ArenaAlloc(arena, sizeof(StateIndex) * a_model->meshes.length); + u32 state_length = 0; + model->meshes.length = a_model->meshes.length; + model->meshes.data = (rMesh *)ArenaAlloc(arena, sizeof(rMesh) * a_model->meshes.length); + for (u64 i = 0; i < model->meshes.length; i += 1) + { + apMesh *a_mesh = a_model->meshes.data + i; + rMesh *mesh = model->meshes.data + i; + + *mesh = { + .idx_offset = uintptr(a_mesh->start_idx * sizeof(u32)), + .length = a_mesh->length, + }; + + rPBRState state; + if (a_mesh->mat_idx != INVALID_INDEX) + { + apMaterial *mat = a_model->materials.data + a_mesh->mat_idx; + + state = { + .albedo_tex = mat->tex.albedo != INVALID_INDEX, + .ambient_tex = mat->tex.ambient != INVALID_INDEX, + .specular_tex = mat->tex.specular != INVALID_INDEX, + }; + + if (state.albedo_tex) + state.channels = a_model->textures.data[mat->tex.albedo].ch; + + u32 state_buffer = INVALID_INDEX; + for (u32 i = 0; i < state_length; i += 1) + { + if (state.albedo_tex != prev_state[i].state.albedo_tex) continue; + if (state.ambient_tex != prev_state[i].state.ambient_tex) continue; + if (state.specular_tex != prev_state[i].state.specular_tex) continue; + if (state.channels != prev_state[i].state.channels) continue; + + state_buffer = prev_state[i].buffer; + break; + } + + if (state_buffer == INVALID_INDEX) + { + glCreateBuffers(1, &state_buffer); + glNamedBufferStorage(state_buffer, sizeof(rPBRState), &state, GL_DYNAMIC_STORAGE_BIT); + prev_state[state_length].state = state; + prev_state[state_length].buffer = state_buffer; + state_length += 1; + } + + mesh->state_buffer = state_buffer; + + glCreateBuffers(1, &mesh->mat_buffer); + glNamedBufferStorage(mesh->mat_buffer, sizeof(apMatProps), &mat->props, GL_DYNAMIC_STORAGE_BIT); + mesh->textures.albedo = mat->tex.albedo != UINT32_MAX ? model->textures.data[mat->tex.albedo] : 0; + mesh->textures.ambient = mat->tex.ambient != UINT32_MAX ? model->textures.data[mat->tex.ambient] : 0; + mesh->textures.specular = mat->tex.specular != UINT32_MAX ? model->textures.data[mat->tex.specular] : 0; + } + } + + apUnloadWithHash(hash); + } +} + +static GLuint +BuildPipeline(PipelineCreateInfo *create_info) +{ + auto vertex_shader = glCreateShader(GL_VERTEX_SHADER); + Assert(BuildShader(&vertex_shader, create_info->vertex_shader), "BuildShader vertex failure"); + + auto fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + Assert(BuildShader(&fragment_shader, create_info->fragment_shader), "BuildShader fragment failure"); + + auto pipeline = glCreateProgram(); + glAttachShader(pipeline, vertex_shader); + glAttachShader(pipeline, fragment_shader); + glLinkProgram(pipeline); + + int success = 0; + glGetProgramiv(pipeline, GL_LINK_STATUS, &success); + if (!success) + { + char info_log[512]; + glGetProgramInfoLog(pipeline, 512, NULL, info_log); + Assert(false, "Failed to build pipeline"); + } + + return pipeline; +} + +static b32 +Init(Renderer *renderer) +{ + b32 success = true; + + renderer->perm_arena = ArenaCreate(MB(32)); + + for (u64 i = 0; i < FRAME_OVERLAP; i += 1) + { + renderer->frame_arenas[i] = ArenaCreate(MB(16)); + } + + RGFW_setGLHint(RGFW_glMajor, 4); + RGFW_setGLHint(RGFW_glMinor, 6); + RGFW_setGLHint(RGFW_glProfile, RGFW_glCore); + + renderer->window = RGFW_createWindow("Video Game", RGFW_RECT(0, 0, 1280, 720), RGFW_windowCenter | RGFW_windowNoResize); + if (renderer->window == NULL) + { + Printfln("Failed to create window"); + success = false; + } + + if (success) + { + RGFW_window_makeCurrent(renderer->window); + + int glad_version = gladLoaderLoadGL(); + if (!glad_version) + { + Printfln("gladLoaderLoadGL failure"); + success = false; + } + } + +#ifdef BUILD_DEBUG + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(DebugCallback, NULL); +#endif + + for (u32 i = 0; i < PIPELINE_MAX; i += 1) + { + renderer->pipelines[i] = BuildPipeline(g_Pipeline_Create_Info + i); + } + + glCreateBuffers(1, &renderer->mat_buf); + apMatProps props = {0}; + glNamedBufferData(renderer->mat_buf, sizeof(apMatProps), &props, GL_STATIC_DRAW); + + InitModels(renderer); + + return success; +} + + +// ::Init::Impl::End:: + + +// ::Draw::Impl::Start:: + +static void +rDrawModel(Renderer *renderer, rModel *model) +{ + glUseProgram(renderer->pipelines[PIPELINE_PBR]); + + for (u64 i = 0; i < model->meshes.length; i += 1) + { + rMesh *mesh = model->meshes.data + i; + + u32 albedo = mesh->textures.albedo != UINT32_MAX ? mesh->textures.albedo : 0; + glBindTextureUnit(0, albedo); + + u32 ambient = mesh->textures.ambient != UINT32_MAX ? mesh->textures.ambient : 0; + glBindTextureUnit(1, ambient); + + u32 specular = mesh->textures.specular != UINT32_MAX ? mesh->textures.ambient : 0; + glBindTextureUnit(2, specular); + + glBindBufferBase(GL_UNIFORM_BUFFER, 0, mesh->mat_buffer); + glBindBufferBase(GL_UNIFORM_BUFFER, 1, mesh->state_buffer); + + glBindVertexArray(model->buffer.vao); + glDrawElements(GL_TRIANGLES, mesh->length, GL_UNSIGNED_INT, (void *)(model->buffer.ioffset + mesh->idx_offset)); + } +} + +static void +DrawIndexedBuffer(rIndexedBuffer *buffer) +{ + glBindVertexArray(buffer->vao); + glDrawElements(GL_TRIANGLES, buffer->icount, GL_UNSIGNED_INT, (void *)buffer->ioffset); +} + +static b32 +RunCycle(Renderer *renderer) +{ + while (RGFW_window_checkEvent(renderer->window)); + + glUseProgram(renderer->pipelines[PIPELINE_PBR]); + + glClearColor(0.1f, 0.8f, 0.4f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + rDrawModel(renderer, renderer->models + 2); + + RGFW_window_swapBuffers(renderer->window); + + return !RGFW_window_shouldClose(renderer->window); +} + diff --git a/src/renderer.h b/src/renderer.h index 9388be4..441775e 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -6,6 +6,7 @@ #include "assets.h" constexpr u64 FRAME_OVERLAP = 2; +constexpr u32 INVALID_INDEX = UINT32_MAX; typedef enum Pipeline_e { @@ -31,25 +32,27 @@ typedef struct PipelineCreateInfo char *fragment_shader; } PipelineCreateInfo; -typedef unsigned int VertexBuffer; -typedef unsigned int IndexBuffer; -typedef unsigned int PipelineHandle; -typedef unsigned int ShaderHandle; -typedef unsigned int VertexArray; -typedef unsigned int UBO; - typedef struct rIndexedBuffer { i64 icount, ioffset; u32 vao, buffer; } rIndexedBuffer; +typedef struct rPBRState +{ + u32 channels; + b32 albedo_tex; + b32 ambient_tex; + b32 specular_tex; +} rPBRState; + typedef struct rMesh { - apMatProps values; apMatTextures textures; uintptr idx_offset; u64 length; + u32 mat_buffer; + u32 state_buffer; u32 type; } rMesh; @@ -65,47 +68,14 @@ typedef struct rModel typedef struct Renderer { RGFW_window *window; - PipelineHandle pipelines[PIPELINE_MAX]; + GLuint pipelines[PIPELINE_MAX]; rModel models[MODEL_ASSET_MAX]; - u32 mat_buf; + GLuint mat_buf; Arena *perm_arena; Arena *frame_arenas[FRAME_OVERLAP]; } Renderer; -// ::Init::Decl:: - -static b32 Init(Renderer *renderer); -static void InitModels(Renderer *renderer); -static PipelineHandle CreatePipeline(); -static VertexBuffer CreateVertexBuffer(); -static IndexBuffer CreateIndexBuffer(); -static VertexArray CreateVertexArray(); -static ShaderHandle CreateShader(int type); -static PipelineHandle BuildPipeline(PipelineCreateInfo *create_info); -static UBO CreateUBO(rawptr data, u32 size); -static b32 BuildShader(ShaderHandle *handle, char *asset); - -// ::Draw::Decl:: - -static void DrawIndexedBuffer(rIndexedBuffer *buffer); -static void rDrawModel(Renderer *renderer, rModel *model); - -// ::Buffers::Decl:: - -static rIndexedBuffer rLoadModel(char *asset); -static rIndexedBuffer CreateIndexedBuffer(rawptr vert_data, u32 vcount, rawptr idx_data, u32 icount); -static void SetVertexAttrib(u32 vao, u32 idx, u32 count, i32 type, b32 normalized, u32 offset); -static u32 rCreateBuffer(rawptr data, u32 size); - -// ::Textures::Decl:: - -static u32 CreateTexture(rawptr data, u32 width, u32 height, u32 channels); - -// ::Draw::Decl:: - -static void DrawMeshBuffer(rIndexedBuffer *mesh); - -// ::Debug::Decl:: - -void DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, GLchar const* message, void const* user_param); - +PipelineCreateInfo g_Pipeline_Create_Info[] = { + { .vertex_shader = "shaders/pbr.vert", .fragment_shader = "shaders/pbr.frag" }, + //{ .vertex_shader = "shaders/gui.vert", .fragment_shader = "shaders/gui.frag" }, +}; diff --git a/src/shaders/pbr.vert.glsl b/src/shaders/pbr.vert.glsl index b2fcf04..fab7747 100644 --- a/src/shaders/pbr.vert.glsl +++ b/src/shaders/pbr.vert.glsl @@ -14,7 +14,15 @@ layout (std140, binding = 0) uniform Properties vec4 diffuse; vec4 specular; float shininess; -}; +} Props; + +layout (std140, binding = 1) uniform PBRState +{ + uint channels; + bool albedo_tex; + bool ambient_tex; + bool specular_tex; +} State; layout (binding = 0) uniform sampler2D albedo_texture; layout (binding = 1) uniform sampler2D ambient_texture; @@ -22,6 +30,14 @@ layout (binding = 2) uniform sampler2D specular_texture; void main() { + vec4 col = in_color; + + if (State.albedo_tex) + col = texture(albedo_texture, in_uv); + + if (State.channels == 1) + col.rgb = col.rrr; + gl_Position = vec4(in_pos, 1.0); - out_color = texture(albedo_texture, in_uv); + out_color = col; }