summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoromnisci3nce <omniscient.oce@gmail.com>2024-07-17 14:45:31 +1000
committeromnisci3nce <omniscient.oce@gmail.com>2024-07-17 14:45:31 +1000
commitf8641a5cc4c8baf1f0a7be3685afc219d90143d9 (patch)
tree6f6edf43f88b456933330ec83a203bf2f414bea4 /src
parentb9315f9cb625db09c3c41d8adf5230a67510bef7 (diff)
whole thing is compiling and running again
Diffstat (limited to 'src')
-rw-r--r--src/core/core.c8
-rw-r--r--src/maths/maths.h2
-rw-r--r--src/new_render/render.c30
-rw-r--r--src/new_render/render.h3
-rw-r--r--src/new_render/render_scene.h2
-rw-r--r--src/new_render/shadows.c5
-rw-r--r--src/new_render/shadows.h2
-rw-r--r--src/platform/file.c2
-rw-r--r--src/ral/backends/opengl/backend_opengl.c505
-rw-r--r--src/ral/backends/opengl/backend_opengl.h7
-rw-r--r--src/ral/backends/opengl/opengl_helpers.h (renamed from src/render/backends/opengl/opengl_helpers.h)70
-rw-r--r--src/ral/ral_common.h12
-rw-r--r--src/ral/ral_impl.h8
-rw-r--r--src/ral/ral_types.h9
-rw-r--r--src/std/str.c88
-rw-r--r--src/std/str.h2
16 files changed, 456 insertions, 299 deletions
diff --git a/src/core/core.c b/src/core/core.c
index 6ccd0d0..de67b56 100644
--- a/src/core/core.c
+++ b/src/core/core.c
@@ -22,6 +22,8 @@ inline Core* GetCore() { return &g_core; }
void Core_Bringup() {
INFO("Initiate Core bringup");
+ memset(&g_core, 0, sizeof(Core));
+
RendererConfig conf = { .window_name = { "Celeritas Engine Core" },
.scr_width = SCR_WIDTH,
.scr_height = SCR_HEIGHT,
@@ -29,7 +31,7 @@ void Core_Bringup() {
g_core.renderer = malloc(Renderer_GetMemReqs());
// initialise all subsystems
- if (!Renderer_Init(conf, g_core.renderer)) {
+ if (!Renderer_Init(conf, g_core.renderer, &g_core.window)) {
// FATAL("Failed to start renderer");
ERROR_EXIT("Failed to start renderer\n");
}
@@ -50,8 +52,6 @@ void Core_Bringup() {
// scene_init(&g_core.default_scene);
}
-#include <glfw3.h>
-
void Core_Shutdown() {
Input_Shutdown(&g_core.input);
Renderer_Shutdown(g_core.renderer);
@@ -63,7 +63,7 @@ bool ShouldExit() {
}
void Frame_Begin() {
- glfwPollEvents();
+ Input_Update(&g_core.input);
Render_FrameBegin(g_core.renderer);
}
void Frame_Draw() {}
diff --git a/src/maths/maths.h b/src/maths/maths.h
index 76790ea..930ee0a 100644
--- a/src/maths/maths.h
+++ b/src/maths/maths.h
@@ -21,7 +21,7 @@
// --- Vector Implementations
// Dimension 3
-static inline Vec3 vec3_create(f32 x, f32 y, f32 z) { return (Vec3){ x, y, z }; }
+PUB static inline Vec3 vec3_create(f32 x, f32 y, f32 z) { return (Vec3){ x, y, z }; }
#define vec3(x, y, z) ((Vec3){ x, y, z })
static inline Vec3 vec3_add(Vec3 a, Vec3 b) { return (Vec3){ a.x + b.x, a.y + b.y, a.z + b.z }; }
static inline Vec3 vec3_sub(Vec3 a, Vec3 b) { return (Vec3){ a.x - b.x, a.y - b.y, a.z - b.z }; }
diff --git a/src/new_render/render.c b/src/new_render/render.c
index 21046ea..1fef610 100644
--- a/src/new_render/render.c
+++ b/src/new_render/render.c
@@ -35,7 +35,9 @@ struct Renderer {
ResourcePools* resource_pools;
};
-bool Renderer_Init(RendererConfig config, Renderer* ren) {
+Renderer* get_renderer() { return g_core.renderer; }
+
+bool Renderer_Init(RendererConfig config, Renderer* ren, GLFWwindow** out_window) {
INFO("Renderer init");
// init resource pools
@@ -66,6 +68,7 @@ bool Renderer_Init(RendererConfig config, Renderer* ren) {
return false;
}
ren->window = window;
+ *out_window = window;
glfwMakeContextCurrent(ren->window);
@@ -81,16 +84,17 @@ bool Renderer_Init(RendererConfig config, Renderer* ren) {
Camera default_cam =
Camera_Create(vec3(0.0, 2.0, 4.0), vec3_normalise(vec3(0.0, -2.0, -4.0)), VEC3_Y, 45.0);
SetCamera(default_cam);
- PointLight default_light = { /* TODO */ };
- SetPointLight(default_light);
+ DirectionalLight default_light = { /* TODO */ };
+ SetMainLight(default_light);
// create our renderpasses
- Shadow_Init(ren->shadows);
+ ren->shadows = malloc(sizeof(Shadow_Storage));
+ Shadow_Init(ren->shadows, u32x2(512, 512));
return true;
}
-void Renderer_Shutdown(Renderer* ren) {}
+void Renderer_Shutdown(Renderer* ren) { free(ren->shadows); }
size_t Renderer_GetMemReqs() { return sizeof(Renderer); }
void Render_FrameBegin(Renderer* ren) {
@@ -107,9 +111,11 @@ void Render_FrameEnd(Renderer* ren) {
}
GPU_CmdEncoder* enc = GPU_GetDefaultEncoder();
+
+ GPU_Backend_EndFrame();
}
void Render_RenderEntities(RenderEnt* entities, size_t entity_count) {
- Renderer* ren = Core_GetRenderer(&g_core);
+ Renderer* ren = get_renderer();
RenderScene scene = ren->scene;
// -- Shadows
@@ -144,3 +150,15 @@ Mesh Mesh_Create(Geometry* geometry, bool free_on_upload) {
}
return m;
}
+
+void Geometry_Destroy(Geometry* geometry) {
+ if (geometry->indices) {
+ u32_darray_free(geometry->indices);
+ }
+ if (geometry->vertices) {
+ Vertex_darray_free(geometry->vertices);
+ }
+}
+
+void SetCamera(Camera camera) { g_core.renderer->scene.camera = camera; }
+void SetMainLight(DirectionalLight light) { g_core.renderer->scene.sun = light; } \ No newline at end of file
diff --git a/src/new_render/render.h b/src/new_render/render.h
index 6e9f380..fa05fec 100644
--- a/src/new_render/render.h
+++ b/src/new_render/render.h
@@ -9,6 +9,7 @@
#include "render_types.h"
typedef struct Renderer Renderer;
+typedef struct GLFWwindow GLFWwindow;
typedef struct RendererConfig {
char window_name[256];
u32 scr_width, scr_height;
@@ -22,7 +23,7 @@ typedef struct RenderCtx {
// --- Lifecycle
-PUB bool Renderer_Init(RendererConfig config, Renderer* renderer);
+PUB bool Renderer_Init(RendererConfig config, Renderer* renderer, GLFWwindow** out_window);
PUB void Renderer_Shutdown(Renderer* renderer);
PUB size_t Renderer_GetMemReqs();
diff --git a/src/new_render/render_scene.h b/src/new_render/render_scene.h
index 791e862..1e4660a 100644
--- a/src/new_render/render_scene.h
+++ b/src/new_render/render_scene.h
@@ -17,4 +17,4 @@ typedef struct RenderScene {
// --- Public APIs
PUB void SetCamera(Camera camera);
-PUB void SetPointLight(PointLight light);
+PUB void SetMainLight(DirectionalLight light);
diff --git a/src/new_render/shadows.c b/src/new_render/shadows.c
index df836b4..612fd34 100644
--- a/src/new_render/shadows.c
+++ b/src/new_render/shadows.c
@@ -1,6 +1,7 @@
-#include <string.h>
#include "shadows.h"
+#include <string.h>
#include "core.h"
+#include "file.h"
#include "log.h"
#include "maths.h"
#include "ral_common.h"
@@ -28,7 +29,7 @@ ShaderDataLayout ShadowUniforms_GetLayout(void* data) {
};
if (has_data) {
- b1.data.bytes.data = data;
+ b1.data.bytes.data = data;
}
return (ShaderDataLayout){ .binding_count = 1, .bindings = { b1 } };
diff --git a/src/new_render/shadows.h b/src/new_render/shadows.h
index 81711de..4dc20e2 100644
--- a/src/new_render/shadows.h
+++ b/src/new_render/shadows.h
@@ -22,7 +22,7 @@ typedef struct Camera Camera;
typedef struct Mat4 Mat4;
// --- Public API
-PUB void Shadow_Init(Shadow_Storage* storage);
+PUB void Shadow_Init(Shadow_Storage* storage, u32x2 shadowmap_extents);
/** @brief Run shadow map generation for given entities, and store in a texture.
* @note Uses active directional light for now */
diff --git a/src/platform/file.c b/src/platform/file.c
index 33194d7..ea69e20 100644
--- a/src/platform/file.c
+++ b/src/platform/file.c
@@ -51,7 +51,7 @@ str8_opt str8_from_file(arena *a, Str8 path) {
rewind(f);
u8 *raw = arena_alloc(a, fsize + 1);
- Str8 contents = str8_create(raw, fsize);
+ Str8 contents = Str8_create(raw, fsize);
contents.buf[contents.len] = '\0';
fread(raw, fsize, 1, f);
diff --git a/src/ral/backends/opengl/backend_opengl.c b/src/ral/backends/opengl/backend_opengl.c
index 2c7c411..cbfd855 100644
--- a/src/ral/backends/opengl/backend_opengl.c
+++ b/src/ral/backends/opengl/backend_opengl.c
@@ -1,7 +1,9 @@
-#include <assert.h>
#include "backend_opengl.h"
+#if defined(CEL_REND_BACKEND_OPENGL)
+#include <assert.h>
#include "log.h"
#include "mem.h"
+#include "opengl_helpers.h"
#include "ral_common.h"
#include "ral_impl.h"
#include "ral_types.h"
@@ -10,42 +12,43 @@
#include <glfw3.h>
typedef struct OpenglCtx {
- GLFWwindow* window;
- arena pool_arena;
- GPU_CmdBuffer main_cmd_buffer;
- GPU_BackendPools gpu_pools;
- ResourcePools* resource_pools;
+ GLFWwindow* window;
+ arena pool_arena;
+ GPU_CmdEncoder main_encoder;
+ GPU_BackendPools gpu_pools;
+ ResourcePools* resource_pools;
} OpenglCtx;
static OpenglCtx context;
-bool GPU_Backend_Init(const char* window_name, struct GLFWwindow *window, struct ResourcePools* res_pools) {
- INFO("loading OpenGL backend");
+bool GPU_Backend_Init(const char* window_name, struct GLFWwindow* window,
+ struct ResourcePools* res_pools) {
+ INFO("loading OpenGL backend");
- memset(&context, 0, sizeof(context));
- context.window = window;
+ memset(&context, 0, sizeof(context));
+ context.window = window;
- size_t pool_buffer_size = 1024 * 1024;
- context.pool_arena = arena_create(malloc(pool_buffer_size), pool_buffer_size);
+ size_t pool_buffer_size = 1024 * 1024;
+ context.pool_arena = arena_create(malloc(pool_buffer_size), pool_buffer_size);
- BackendPools_Init(&context.pool_arena, &context.gpu_pools);
- context.resource_pools = res_pools;
+ BackendPools_Init(&context.pool_arena, &context.gpu_pools);
+ context.resource_pools = res_pools;
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
- glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
- glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
- // glad: load all opengl function pointers
- if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
- ERROR("Failed to initialise GLAD \n");
- return false;
- }
+ // glad: load all opengl function pointers
+ if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
+ ERROR("Failed to initialise GLAD \n");
+ return false;
+ }
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
- return true;
+ return true;
}
// All of these are no-ops in OpenGL
@@ -57,108 +60,107 @@ void GPU_Swapchain_Destroy(GPU_Swapchain* swapchain) {}
void GPU_CmdEncoder_Destroy(GPU_CmdEncoder* encoder) {}
void GPU_CmdEncoder_BeginRender(GPU_CmdEncoder* encoder, GPU_Renderpass* renderpass) {}
void GPU_CmdEncoder_EndRender(GPU_CmdEncoder* encoder) {}
-GPU_CmdEncoder* GPU_GetDefaultEncoder() {
- return context.
-}
+GPU_CmdEncoder* GPU_GetDefaultEncoder() { return &context.main_encoder; }
void GPU_QueueSubmit(GPU_CmdBuffer* cmd_buffer) {}
GPU_Renderpass* GPU_Renderpass_Create(GPU_RenderpassDesc description) {
- // allocate new pass
- GPU_Renderpass* renderpass = Renderpass_pool_alloc(&context.gpu_pools.renderpasses, NULL);
- renderpass->description = description;
-
- if (!description.default_framebuffer) {
- // If we're not using the default framebuffer we need to generate a new one
- GLuint gl_fbo_id;
- glGenFramebuffers(1, &gl_fbo_id);
- renderpass->fbo = gl_fbo_id;
- } else {
- renderpass->fbo = OPENGL_DEFAULT_FRAMEBUFFER;
- assert(!description.has_color_target);
- assert(!description.has_depth_stencil);
- }
- glBindFramebuffer(GL_FRAMEBUFFER, renderpass->fbo);
-
- if (description.has_color_target && !description.default_framebuffer) {
- GPU_Texture* colour_attachment = TEXTURE_GET(description.color_target);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- colour_attachment->id, 0);
- }
- if (description.has_depth_stencil && !description.default_framebuffer) {
- GPU_Texture* depth_attachment = TEXTURE_GET(description.depth_stencil);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_attachment->id,
- 0);
- }
-
- if (description.has_depth_stencil && !description.has_color_target) {
- glDrawBuffer(GL_NONE);
- glReadBuffer(GL_NONE);
- }
-
- glBindFramebuffer(GL_FRAMEBUFFER, 0); // reset to default framebuffer
-
- return renderpass;
+ // allocate new pass
+ GPU_Renderpass* renderpass = Renderpass_pool_alloc(&context.gpu_pools.renderpasses, NULL);
+ renderpass->description = description;
+
+ if (!description.default_framebuffer) {
+ // If we're not using the default framebuffer we need to generate a new one
+ GLuint gl_fbo_id;
+ glGenFramebuffers(1, &gl_fbo_id);
+ renderpass->fbo = gl_fbo_id;
+ } else {
+ renderpass->fbo = OPENGL_DEFAULT_FRAMEBUFFER;
+ assert(!description.has_color_target);
+ assert(!description.has_depth_stencil);
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, renderpass->fbo);
+
+ if (description.has_color_target && !description.default_framebuffer) {
+ GPU_Texture* colour_attachment = TEXTURE_GET(description.color_target);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ colour_attachment->id, 0);
+ }
+ if (description.has_depth_stencil && !description.default_framebuffer) {
+ GPU_Texture* depth_attachment = TEXTURE_GET(description.depth_stencil);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_attachment->id,
+ 0);
+ }
+
+ if (description.has_depth_stencil && !description.has_color_target) {
+ glDrawBuffer(GL_NONE);
+ glReadBuffer(GL_NONE);
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0); // reset to default framebuffer
+
+ return renderpass;
}
void GPU_Renderpass_Destroy(GPU_Renderpass* pass) { glDeleteFramebuffers(1, &pass->fbo); }
-GPU_Pipeline* GPU_GraphicsPipeline_Create(GraphicsPipelineDesc description, GPU_Renderpass* renderpass) {
- GPU_Pipeline* pipeline = Pipeline_pool_alloc(&context.gpu_pools.pipelines, NULL);
-
- // Create shader program
- u32 shader_id = shader_create_separate(description.vs.filepath.buf, description.fs.filepath.buf);
- pipeline->shader_id = shader_id;
-
- // Vertex format
- pipeline->vertex_desc = description.vertex_desc;
-
- // Allocate uniform buffers if needed
- u32 ubo_count = 0;
- // printf("data layouts %d\n", description.data_layouts_count);
- for (u32 layout_i = 0; layout_i < description.data_layouts_count; layout_i++) {
- ShaderDataLayout sdl = description.data_layouts[layout_i].get_layout(NULL);
- TRACE("Got shader data layout %d's bindings! . found %d", layout_i, sdl.binding_count);
-
- for (u32 binding_j = 0; binding_j < sdl.binding_count; binding_j++) {
- u32 binding_id = binding_j;
- assert(binding_id < MAX_PIPELINE_UNIFORM_BUFFERS);
- ShaderBinding binding = sdl.bindings[binding_j];
- // Do I want Buffer vs Bytes?
- if (binding.kind == BINDING_BUFFER) {
- static u32 s_binding_point = 0;
- BufferHandle ubo_handle =
- GPU_BufferCreate(binding.data.bytes.size, BUFFER_UNIFORM, BUFFER_FLAG_GPU, NULL); // no data right now
- pipeline->uniform_bindings[ubo_count++] = ubo_handle;
- GPU_Buffer* ubo_buf = BUFFER_GET(ubo_handle);
-
- i32 blockIndex = glGetUniformBlockIndex(pipeline->shader_id, binding.label);
- printf("Block index for %s: %d", binding.label, blockIndex);
- if (blockIndex < 0) {
- WARN("Couldn't retrieve block index for uniform block '%s'", binding.label);
- } else {
- // DEBUG("Retrived block index %d for %s", blockIndex, binding.label);
- }
- u32 blocksize;
- glGetActiveUniformBlockiv(pipeline->shader_id, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE,
- &blocksize);
- printf("\t with size %d bytes\n", blocksize);
-
- glBindBufferBase(GL_UNIFORM_BUFFER, s_binding_point, ubo_buf->id.ubo);
- if (blockIndex != GL_INVALID_INDEX) {
- glUniformBlockBinding(pipeline->shader_id, blockIndex, s_binding_point);
- }
- ubo_buf->ubo_binding_point = s_binding_point++;
- ubo_buf->name = binding.label;
- assert(s_binding_point < GL_MAX_UNIFORM_BUFFER_BINDINGS);
+GPU_Pipeline* GPU_GraphicsPipeline_Create(GraphicsPipelineDesc description,
+ GPU_Renderpass* renderpass) {
+ GPU_Pipeline* pipeline = Pipeline_pool_alloc(&context.gpu_pools.pipelines, NULL);
+
+ // Create shader program
+ u32 shader_id = shader_create_separate(description.vs.filepath.buf, description.fs.filepath.buf);
+ pipeline->shader_id = shader_id;
+
+ // Vertex format
+ pipeline->vertex_desc = description.vertex_desc;
+
+ // Allocate uniform buffers if needed
+ u32 ubo_count = 0;
+ // printf("data layouts %d\n", description.data_layouts_count);
+ for (u32 layout_i = 0; layout_i < description.data_layouts_count; layout_i++) {
+ ShaderDataLayout sdl = description.data_layouts[layout_i].get_layout(NULL);
+ TRACE("Got shader data layout %d's bindings! . found %d", layout_i, sdl.binding_count);
+
+ for (u32 binding_j = 0; binding_j < sdl.binding_count; binding_j++) {
+ u32 binding_id = binding_j;
+ assert(binding_id < MAX_PIPELINE_UNIFORM_BUFFERS);
+ ShaderBinding binding = sdl.bindings[binding_j];
+ // Do I want Buffer vs Bytes?
+ if (binding.kind == BINDING_BUFFER) {
+ static u32 s_binding_point = 0;
+ BufferHandle ubo_handle = GPU_BufferCreate(binding.data.bytes.size, BUFFER_UNIFORM,
+ BUFFER_FLAG_GPU, NULL); // no data right now
+ pipeline->uniform_bindings[ubo_count++] = ubo_handle;
+ GPU_Buffer* ubo_buf = BUFFER_GET(ubo_handle);
+
+ i32 blockIndex = glGetUniformBlockIndex(pipeline->shader_id, binding.label);
+ printf("Block index for %s: %d", binding.label, blockIndex);
+ if (blockIndex < 0) {
+ WARN("Couldn't retrieve block index for uniform block '%s'", binding.label);
+ } else {
+ // DEBUG("Retrived block index %d for %s", blockIndex, binding.label);
}
+ u32 blocksize;
+ glGetActiveUniformBlockiv(pipeline->shader_id, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE,
+ &blocksize);
+ printf("\t with size %d bytes\n", blocksize);
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, s_binding_point, ubo_buf->id.ubo);
+ if (blockIndex != GL_INVALID_INDEX) {
+ glUniformBlockBinding(pipeline->shader_id, blockIndex, s_binding_point);
+ }
+ ubo_buf->ubo_binding_point = s_binding_point++;
+ ubo_buf->name = binding.label;
+ assert(s_binding_point < GL_MAX_UNIFORM_BUFFER_BINDINGS);
}
}
- pipeline->uniform_count = ubo_count;
+ }
+ pipeline->uniform_count = ubo_count;
- pipeline->renderpass = description.renderpass;
- pipeline->wireframe = description.wireframe;
+ pipeline->renderpass = renderpass;
+ pipeline->wireframe = description.wireframe;
- return pipeline;
+ return pipeline;
}
void GraphicsPipeline_Destroy(GPU_Pipeline* pipeline) {}
@@ -168,117 +170,190 @@ GPU_CmdEncoder GPU_CmdEncoder_Create() {
return encoder;
}
+BufferHandle GPU_BufferCreate(u64 size, GPU_BufferType buf_type, GPU_BufferFlags flags,
+ const void* data) {
+ // "allocating" the cpu-side buffer struct
+ BufferHandle handle;
+ GPU_Buffer* buffer = Buffer_pool_alloc(&context.resource_pools, &handle);
+ buffer->size = size;
+ buffer->vao = 0;
+
+ // Opengl buffer
+ GLuint gl_buffer_id;
+ glGenBuffers(1, &gl_buffer_id);
+
+ GLenum gl_buf_type;
+ GLenum gl_buf_usage = GL_STATIC_DRAW;
+
+ switch (buf_type) {
+ case BUFFER_UNIFORM:
+ DEBUG("Creating Uniform buffer");
+ gl_buf_type = GL_UNIFORM_BUFFER;
+ /* gl_buf_usage = GL_DYNAMIC_DRAW; */
+ buffer->id.ubo = gl_buffer_id;
+ break;
+ case BUFFER_DEFAULT:
+ case BUFFER_VERTEX:
+ DEBUG("Creating Vertex buffer");
+ gl_buf_type = GL_ARRAY_BUFFER;
+ buffer->id.vbo = gl_buffer_id;
+ break;
+ case BUFFER_INDEX:
+ DEBUG("Creating Index buffer");
+ gl_buf_type = GL_ELEMENT_ARRAY_BUFFER;
+ buffer->id.ibo = gl_buffer_id;
+ break;
+ default:
+ WARN("Unimplemented gpu_buffer_type provided %s", buffer_type_names[buf_type]);
+ break;
+ }
+ // bind buffer
+ glBindBuffer(gl_buf_type, gl_buffer_id);
+
+ if (data) {
+ TRACE("Upload data (%d bytes) as part of buffer creation", size);
+ glBufferData(gl_buf_type, buffer->size, data, gl_buf_usage);
+ } else {
+ TRACE("Allocating but not uploading (%d bytes)", size);
+ glBufferData(gl_buf_type, buffer->size, NULL, gl_buf_usage);
+ }
+
+ glBindBuffer(gl_buf_type, 0);
+
+ return handle;
+}
-BufferHandle GPU_BufferCreate(u64 size, GPU_BufferType buf_type, GPU_BufferFlags flags, const void *data) {
- // "allocating" the cpu-side buffer struct
- BufferHandle handle;
- GPU_Buffer* buffer = Buffer_pool_alloc(&context.resource_pools, &handle);
- buffer->size = size;
- buffer->vao = 0;
-
- // Opengl buffer
- GLuint gl_buffer_id;
- glGenBuffers(1, &gl_buffer_id);
-
- GLenum gl_buf_type;
- GLenum gl_buf_usage = GL_STATIC_DRAW;
-
- switch (buf_type) {
- case BUFFER_UNIFORM:
- DEBUG("Creating Uniform buffer");
- gl_buf_type = GL_UNIFORM_BUFFER;
- /* gl_buf_usage = GL_DYNAMIC_DRAW; */
- buffer->id.ubo = gl_buffer_id;
- break;
- case BUFFER_DEFAULT:
- case BUFFER_VERTEX:
- DEBUG("Creating Vertex buffer");
- gl_buf_type = GL_ARRAY_BUFFER;
- buffer->id.vbo = gl_buffer_id;
- break;
- case BUFFER_INDEX:
- DEBUG("Creating Index buffer");
- gl_buf_type = GL_ELEMENT_ARRAY_BUFFER;
- buffer->id.ibo = gl_buffer_id;
- break;
- default:
- WARN("Unimplemented gpu_buffer_type provided %s", buffer_type_names[buf_type]);
- break;
- }
- // bind buffer
- glBindBuffer(gl_buf_type, gl_buffer_id);
-
- if (data) {
- TRACE("Upload data (%d bytes) as part of buffer creation", size);
- glBufferData(gl_buf_type, buffer->size, data, gl_buf_usage);
- } else {
- TRACE("Allocating but not uploading (%d bytes)", size);
- glBufferData(gl_buf_type, buffer->size, NULL, gl_buf_usage);
- }
+TextureHandle GPU_TextureCreate(TextureDesc desc, bool create_view, const void* data) {
+ // "allocating" the cpu-side struct
+ TextureHandle handle;
+ GPU_Texture* texture = Texture_pool_alloc(&context.resource_pools->textures, &handle);
+ DEBUG("Allocated texture with handle %d", handle.raw);
+
+ GLuint gl_texture_id;
+ glGenTextures(1, &gl_texture_id);
+ texture->id = gl_texture_id;
+
+ glBindTexture(GL_TEXTURE_2D, gl_texture_id);
+
+ GLint internal_format = desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_DEPTH_COMPONENT : GL_RGB;
+ GLenum format = desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_DEPTH_COMPONENT : GL_RGBA;
+ GLenum data_type = desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_FLOAT : GL_UNSIGNED_BYTE;
+
+ if (desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ } else {
+ // set the texture wrapping parameters
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
+ GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ // set texture filtering parameters
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+
+ if (data) {
+ glTexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.extents.x, desc.extents.y, 0, format,
+ data_type, data);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ } else {
+ WARN("No image data provided");
+ glTexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.extents.x, desc.extents.y, 0, format,
+ data_type, NULL);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ return handle;
+}
- glBindBuffer(gl_buf_type, 0);
+void GPU_TextureDestroy(TextureHandle handle) { glDeleteTextures(1, &handle.raw); }
- return handle;
+// TODO: void GPU_TextureUpload(TextureHandle handle, size_t n_bytes, const void* data)
+
+void GPU_EncodeBindPipeline(GPU_CmdEncoder* encoder, GPU_Pipeline* pipeline) {
+ encoder->pipeline = pipeline;
+
+ // In OpenGL binding a pipeline is more or less equivalent to just setting the shader
+ glUseProgram(pipeline->shader_id);
}
-TextureHandle GPU_TextureCreate(TextureDesc desc, bool create_view, const void *data) {
- // "allocating" the cpu-side struct
- TextureHandle handle;
- GPU_Texture* texture = Texture_pool_alloc(&context.resource_pools->textures, &handle);
- DEBUG("Allocated texture with handle %d", handle.raw);
-
- GLuint gl_texture_id;
- glGenTextures(1, &gl_texture_id);
- texture->id = gl_texture_id;
-
- glBindTexture(GL_TEXTURE_2D, gl_texture_id);
-
- GLint internal_format =
- desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_DEPTH_COMPONENT : GL_RGB;
- GLenum format = desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_DEPTH_COMPONENT : GL_RGBA;
- GLenum data_type = desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT ? GL_FLOAT : GL_UNSIGNED_BYTE;
-
- if (desc.format == TEXTURE_FORMAT_DEPTH_DEFAULT) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
- } else {
- // set the texture wrapping parameters
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
- GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- // set texture filtering parameters
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- }
+PUB void GPU_EncodeBindShaderData(GPU_CmdEncoder* encoder, u32 group, ShaderData data) {
+ ShaderDataLayout sdl = data.get_layout(data.data);
+
+ for (u32 i = 0; i < sdl.binding_count; i++) {
+ ShaderBinding binding = sdl.bindings[i];
+ /* print_shader_binding(binding); */
+
+ if (binding.kind == BINDING_BYTES) {
+ BufferHandle b;
+ GPU_Buffer* ubo_buf;
+ bool found = false;
+ for (u32 i = 0; i < encoder->pipeline->uniform_count; i++) {
+ b = encoder->pipeline->uniform_bindings[i];
+ ubo_buf = BUFFER_GET(b);
+ assert(ubo_buf->name != NULL);
+ if (strcmp(ubo_buf->name, binding.label) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ERROR("Couldnt find uniform buffer object!!");
+ }
- if (data) {
- glTexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.extents.x, desc.extents.y, 0, format,
- data_type, data);
- glGenerateMipmap(GL_TEXTURE_2D);
- } else {
- WARN("No image data provided");
- glTexImage2D(GL_TEXTURE_2D, 0, internal_format, desc.extents.x, desc.extents.y, 0, format,
- data_type, NULL);
- }
+ i32 blockIndex = glGetUniformBlockIndex(encoder->pipeline->shader_id, binding.label);
+ if (blockIndex < 0) {
+ WARN("Couldn't retrieve block index for uniform block '%s'", binding.label);
+ } else {
+ // DEBUG("Retrived block index %d for %s", blockIndex, binding.label);
+ }
- glBindTexture(GL_TEXTURE_2D, 0);
+ glBindBuffer(GL_UNIFORM_BUFFER, ubo_buf->id.ubo);
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, ubo_buf->size, binding.data.bytes.data);
- return handle;
+ } else if (binding.kind == BINDING_TEXTURE) {
+ GPU_Texture* tex = TEXTURE_GET(binding.data.texture.handle);
+ GLint tex_slot = glGetUniformLocation(encoder->pipeline->shader_id, binding.label);
+ // printf("%d slot \n", tex_slot);
+ if (tex_slot == GL_INVALID_VALUE || tex_slot < 0) {
+ WARN("Invalid binding label for texture %s - couldn't fetch texture slot uniform",
+ binding.label);
+ }
+ glUniform1i(tex_slot, i);
+ glActiveTexture(GL_TEXTURE0 + i);
+ glBindTexture(GL_TEXTURE_2D, tex->id);
+ }
+ }
}
-void GPU_TextureDestroy(TextureHandle handle) {
- glDeleteTextures(1, &handle.raw);
-}
+void GPU_EncodeSetDefaults(GPU_CmdEncoder* encoder) {}
-// TODO: void GPU_TextureUpload(TextureHandle handle, size_t n_bytes, const void* data)
+void GPU_EncodeSetVertexBuffer(GPU_CmdEncoder* encoder, BufferHandle buf) {
+ GPU_Buffer* buffer = BUFFER_GET(buf);
+ if (buffer->vao == 0) { // if no VAO for this vertex buffer, create it
+ INFO("Setting up VAO");
+ buffer->vao = opengl_bindcreate_vao(buffer, encoder->pipeline->vertex_desc);
+ }
+ glBindVertexArray(buffer->vao);
+}
+void GPU_EncodeSetIndexBuffer(GPU_CmdEncoder* encoder, BufferHandle buf) {
+ GPU_Buffer* buffer = BUFFER_GET(buf);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->id.ibo);
+}
+void GPU_EncodeDraw(GPU_CmdEncoder* encoder, u64 count) { glDrawArrays(GL_TRIANGLES, 0, count); }
+void GPU_EncodeDrawIndexed(GPU_CmdEncoder* encoder, u64 index_count) {
+ glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, 0);
+}
bool GPU_Backend_BeginFrame() {
- glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ return true;
}
-void GPU_Backend_EndFrame() {
- glfwSwapBuffers(context.window);
-}
+void GPU_Backend_EndFrame() { glfwSwapBuffers(context.window); }
+
+#endif \ No newline at end of file
diff --git a/src/ral/backends/opengl/backend_opengl.h b/src/ral/backends/opengl/backend_opengl.h
index 4fbb4bb..f8e76b8 100644
--- a/src/ral/backends/opengl/backend_opengl.h
+++ b/src/ral/backends/opengl/backend_opengl.h
@@ -1,11 +1,10 @@
#pragma once
+#include "defines.h"
-#include "ral_impl.h"
-#ifdef CEL_REND_BACKEND_OPENGL
+#if defined(CEL_REND_BACKEND_OPENGL)
-#include "defines.h"
#include "maths_types.h"
-#include "ral.h"
+#include "ral_impl.h"
#include "ral_types.h"
#define MAX_PIPELINE_UNIFORM_BUFFERS 32
diff --git a/src/render/backends/opengl/opengl_helpers.h b/src/ral/backends/opengl/opengl_helpers.h
index 41018cb..f40bbca 100644
--- a/src/render/backends/opengl/opengl_helpers.h
+++ b/src/ral/backends/opengl/opengl_helpers.h
@@ -1,19 +1,23 @@
-#if defined(CEL_REND_BACKEND_OPENGL)
#pragma once
+#include "defines.h"
+#include "ral_common.h"
+#include "ral_impl.h"
+#if defined(CEL_REND_BACKEND_OPENGL)
#include "backend_opengl.h"
#include "log.h"
-#include "ral.h"
+#include "file.h"
#include "ral_types.h"
#include <glad/glad.h>
#include <glfw3.h>
#include "ral_types.h"
+
typedef struct opengl_vertex_attr {
u32 count;
GLenum data_type;
} opengl_vertex_attr;
-static opengl_vertex_attr format_from_vertex_attr(vertex_attrib_type attr) {
+static opengl_vertex_attr format_from_vertex_attr(VertexAttribType attr) {
switch (attr) {
case ATTR_F32:
return (opengl_vertex_attr){ .count = 1, .data_type = GL_FLOAT };
@@ -42,7 +46,7 @@ static opengl_vertex_attr format_from_vertex_attr(vertex_attrib_type attr) {
}
}
-static u32 opengl_bindcreate_vao(gpu_buffer* buf, vertex_description desc) {
+static u32 opengl_bindcreate_vao(GPU_Buffer* buf, VertexDescription desc) {
DEBUG("Vertex format name %s", desc.debug_label);
// 1. Bind the buffer
glBindBuffer(GL_ARRAY_BUFFER, buf->id.vbo);
@@ -55,15 +59,15 @@ static u32 opengl_bindcreate_vao(gpu_buffer* buf, vertex_description desc) {
u32 attr_count = desc.attributes_count;
printf("N attributes %d\n", attr_count);
u64 offset = 0;
- size_t vertex_size = desc.use_full_vertex_size ? sizeof(vertex) : desc.stride;
+ size_t vertex_size = desc.use_full_vertex_size ? sizeof(Vertex) : desc.stride;
for (u32 i = 0; i < desc.attributes_count; i++) {
opengl_vertex_attr format = format_from_vertex_attr(desc.attributes[i]);
glVertexAttribPointer(i, format.count, format.data_type, GL_FALSE, vertex_size, (void*)offset);
TRACE(" %d %d %d %d %d %s", i, format.count, format.data_type, vertex_size, offset,
desc.attr_names[i]);
glEnableVertexAttribArray(i); // nth index
- size_t this_offset = vertex_attrib_size(desc.attributes[i]);
- printf("offset total %lld this attr %ld\n", offset, this_offset);
+ size_t this_offset = VertexAttribSize(desc.attributes[i]);
+ printf("offset total %lld this attr %zu\n", offset, this_offset);
offset += this_offset;
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -71,4 +75,56 @@ static u32 opengl_bindcreate_vao(gpu_buffer* buf, vertex_description desc) {
return vao;
}
+static u32 shader_create_separate(const char* vert_shader, const char* frag_shader) {
+ INFO("Load shaders at %s and %s", vert_shader, frag_shader);
+ int success;
+ char info_log[512];
+
+ u32 vertex = glCreateShader(GL_VERTEX_SHADER);
+ const char* vertex_shader_src = string_from_file(vert_shader);
+ if (vertex_shader_src == NULL) {
+ ERROR("EXIT: couldnt load shader");
+ exit(-1);
+ }
+ glShaderSource(vertex, 1, &vertex_shader_src, NULL);
+ glCompileShader(vertex);
+ glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(vertex, 512, NULL, info_log);
+ printf("%s\n", info_log);
+ ERROR("EXIT: vertex shader compilation failed");
+ exit(-1);
+ }
+
+ // fragment shader
+ u32 fragment = glCreateShader(GL_FRAGMENT_SHADER);
+ const char* fragment_shader_src = string_from_file(frag_shader);
+ if (fragment_shader_src == NULL) {
+ ERROR("EXIT: couldnt load shader");
+ exit(-1);
+ }
+ glShaderSource(fragment, 1, &fragment_shader_src, NULL);
+ glCompileShader(fragment);
+ glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
+ if (!success) {
+ glGetShaderInfoLog(fragment, 512, NULL, info_log);
+ printf("%s\n", info_log);
+ ERROR("EXIT: fragment shader compilation failed");
+ exit(-1);
+ }
+
+ u32 shader_prog;
+ shader_prog = glCreateProgram();
+
+ glAttachShader(shader_prog, vertex);
+ glAttachShader(shader_prog, fragment);
+ glLinkProgram(shader_prog);
+ glDeleteShader(vertex);
+ glDeleteShader(fragment);
+ free((char*)vertex_shader_src);
+ free((char*)fragment_shader_src);
+
+ return shader_prog;
+}
+
#endif
diff --git a/src/ral/ral_common.h b/src/ral/ral_common.h
index 0f7c1b7..6a373ee 100644
--- a/src/ral/ral_common.h
+++ b/src/ral/ral_common.h
@@ -6,7 +6,13 @@
#include "buf.h"
#include "mem.h"
#include "ral_types.h"
-#include "ral_impl.h"
+// #include "ral_impl.h"
+
+// Concrete implementation
+#if defined(CEL_REND_BACKEND_OPENGL)
+#include "backend_opengl.h"
+#endif
+
TYPED_POOL(GPU_Buffer, Buffer);
TYPED_POOL(GPU_Texture, Texture);
@@ -15,8 +21,8 @@ TYPED_POOL(GPU_Pipeline, Pipeline);
TYPED_POOL(GPU_Renderpass, Renderpass);
// --- Handy macros
-#define BUFFER_GET(h) (buffer_pool_get(&context.resource_pools->buffers, h))
-#define TEXTURE_GET(h) (texture_pool_get(&context.resource_pools->textures, h))
+#define BUFFER_GET(h) (Buffer_pool_get(&context.resource_pools->buffers, h))
+#define TEXTURE_GET(h) (Texture_pool_get(&context.resource_pools->textures, h))
// --- Pools
typedef struct GPU_BackendPools {
diff --git a/src/ral/ral_impl.h b/src/ral/ral_impl.h
index 3c3eaa5..7cc9459 100644
--- a/src/ral/ral_impl.h
+++ b/src/ral/ral_impl.h
@@ -4,7 +4,6 @@
#pragma once
#include "buf.h"
#include "defines.h"
-#include "ral_common.h"
#include "ral_types.h"
struct GLFWwindow;
@@ -77,9 +76,4 @@ PUB void GPU_EncodeDrawIndexed(GPU_CmdEncoder* encoder, u64 index_count);
// --- Frame cycle
PUB bool GPU_Backend_BeginFrame();
-PUB void GPU_Backend_EndFrame();
-
-// Concrete implementation
-#if defined(CEL_REND_BACKEND_OPENGL)
-#include "backend_opengl.h"
-#endif
+PUB void GPU_Backend_EndFrame(); \ No newline at end of file
diff --git a/src/ral/ral_types.h b/src/ral/ral_types.h
index 4470700..ffcc2cd 100644
--- a/src/ral/ral_types.h
+++ b/src/ral/ral_types.h
@@ -2,6 +2,7 @@
#include "defines.h"
#include "darray.h"
#include "maths_types.h"
+#include "str.h"
// --- Max size constants
#define MAX_SHADER_DATA_LAYOUTS 8
@@ -149,7 +150,13 @@ typedef enum ShaderVisibility {
VISIBILITY_COMPUTE = 1 << 2,
} ShaderVisibility ;
-typedef struct ShaderDesc {} ShaderDesc;
+typedef struct ShaderDesc {
+ const char* debug_name;
+ Str8 filepath; // Where it came from
+ Str8 code; // Either GLSL or SPIRV bytecode
+ bool is_spirv;
+ bool is_combined_vert_frag; // Contains both vertex and fragment stages
+} ShaderDesc;
typedef enum ShaderBindingKind {
BINDING_BYTES,
diff --git a/src/std/str.c b/src/std/str.c
index e15c38f..2aac15f 100644
--- a/src/std/str.c
+++ b/src/std/str.c
@@ -3,62 +3,62 @@
#include <string.h>
#include "mem.h"
-// str8 str8_create(u8* buf, size_t len) { return (str8){ .buf = buf, .len = len }; }
+Str8 Str8_create(u8* buf, size_t len) { return (Str8){ .buf = buf, .len = len }; }
-// str8 str8_cstr_view(char* string) { return str8_create((u8*)string, strlen(string)); }
+Str8 Str8_cstr_view(char* string) { return Str8_create((u8*)string, strlen(string)); }
-// bool str8_equals(str8 a, str8 b) {
-// if (a.len != b.len) {
-// return false;
-// }
+bool Str8_equals(Str8 a, Str8 b) {
+ if (a.len != b.len) {
+ return false;
+ }
-// for (size_t i = 0; i < a.len; i++) {
-// if (a.buf[i] != b.buf[i]) {
-// return false;
-// }
-// }
-// return true;
-// }
+ for (size_t i = 0; i < a.len; i++) {
+ if (a.buf[i] != b.buf[i]) {
+ return false;
+ }
+ }
+ return true;
+}
-// char* str8_to_cstr(arena* a, str8 s) {
-// bool is_null_terminated = s.buf[s.len - 1] == 0;
-// size_t n_bytes = is_null_terminated ? s.len : s.len + 1;
+char* Str8_to_cstr(arena* a, Str8 s) {
+ bool is_null_terminated = s.buf[s.len - 1] == 0;
+ size_t n_bytes = is_null_terminated ? s.len : s.len + 1;
-// u8* dest = arena_alloc(a, n_bytes);
+ u8* dest = arena_alloc(a, n_bytes);
-// memcpy(dest, s.buf, s.len);
-// if (is_null_terminated) {
-// dest[s.len] = '\0';
-// }
-// return (char*)dest;
-// }
+ memcpy(dest, s.buf, s.len);
+ if (is_null_terminated) {
+ dest[s.len] = '\0';
+ }
+ return (char*)dest;
+}
-// str8 str8_concat(arena* a, str8 left, str8 right) {
-// size_t n_bytes = left.len + right.len + 1;
+Str8 Str8_concat(arena* a, Str8 left, Str8 right) {
+ size_t n_bytes = left.len + right.len + 1;
-// u8* dest = arena_alloc(a, n_bytes);
-// memcpy(dest, left.buf, left.len);
-// memcpy(dest + right.len, right.buf, right.len);
+ u8* dest = arena_alloc(a, n_bytes);
+ memcpy(dest, left.buf, left.len);
+ memcpy(dest + right.len, right.buf, right.len);
-// dest[n_bytes - 1] = '\0';
+ dest[n_bytes - 1] = '\0';
-// return str8_create(dest, n_bytes);
-// }
+ return Str8_create(dest, n_bytes);
+}
-// str8 str8_substr(str8 s, u64 min, u64 max) {
-// assert(min >= 0);
-// assert(min < s.len);
-// assert(max >= 0);
-// assert(max <= s.len);
-// uint8_t* start = s.buf + (ptrdiff_t)min;
-// size_t new_len = max - min;
-// return (str8){ .buf = start, .len = new_len };
-// }
+Str8 Str8_substr(Str8 s, u64 min, u64 max) {
+ assert(min >= 0);
+ assert(min < s.len);
+ assert(max >= 0);
+ assert(max <= s.len);
+ uint8_t* start = s.buf + (ptrdiff_t)min;
+ size_t new_len = max - min;
+ return (Str8){ .buf = start, .len = new_len };
+}
-// str8 str8_take(str8 s, u64 first_n) { return str8_substr(s, 0, first_n); }
+Str8 Str8_take(Str8 s, u64 first_n) { return Str8_substr(s, 0, first_n); }
-// str8 str8_drop(str8 s, u64 last_n) { return str8_substr(s, s.len - last_n, s.len); }
+Str8 Str8_drop(Str8 s, u64 last_n) { return Str8_substr(s, s.len - last_n, s.len); }
-// str8 str8_skip(str8 s, u64 n) { return str8_substr(s, n, s.len); }
+Str8 Str8_skip(Str8 s, u64 n) { return Str8_substr(s, n, s.len); }
-// str8 str8_chop(str8 s, u64 n) { return str8_substr(s, 0, s.len - n); }
+Str8 Str8_chop(Str8 s, u64 n) { return Str8_substr(s, 0, s.len - n); }
diff --git a/src/std/str.h b/src/std/str.h
index e9c4098..9e712e6 100644
--- a/src/std/str.h
+++ b/src/std/str.h
@@ -31,7 +31,7 @@ typedef struct {
#define str8(s) \
(Str8) { (u8*)s, ((sizeof(s) / sizeof(*(s)) - 1)) }
-Str8 str8_create(u8* buf, size_t len);
+Str8 Str8_create(u8* buf, size_t len);
/** @brief Return a null-terminated C string cloned onto an arena */
char* Str8_to_cstr(arena* a, Str8 s);