summaryrefslogtreecommitdiff
path: root/include/celeritas.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/celeritas.h')
-rw-r--r--include/celeritas.h482
1 files changed, 359 insertions, 123 deletions
diff --git a/include/celeritas.h b/include/celeritas.h
index 2e0bd28..0b56bf5 100644
--- a/include/celeritas.h
+++ b/include/celeritas.h
@@ -1,11 +1,23 @@
#pragma once
+/*
+ Common abbreviations:
+ buf = buffer
+ tex = texture
+ desc = description
+ idx = index
+*/
+
// Standard library includes
+#include <assert.h>
+#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
// Third party dependency includes
#include <glfw3.h>
@@ -59,55 +71,112 @@ _Static_assert(sizeof(ptrdiff_t) == 8, "type ptrdiff_t should be 8 bytes");
// Platform informs renderer backend (unless user overrides)
#if defined(CEL_PLATFORM_LINUX) || defined(CEL_PLATFORM_WINDOWS)
-#define CEL_REND_BACKEND_VULKAN 1
-#elif defined(CEL_PLATFORM_MAC)
-#define CEL_REND_BACKEND_METAL 1
+#define GPU_VULKAN 1
+#else
+#define GPU_METAL 1
#endif
// --- Forward declare vital structures
-typedef struct Core Core;
-typedef struct Renderer Renderer;
-typedef struct InputState InputState;
+typedef struct core core;
+typedef struct renderer renderer;
+typedef struct input_state input_state;
struct GLFWwindow;
// Global getters
-Core* GetGlobalCore();
-Renderer* GetRenderer();
-struct GLFWwindow* GetWindow();
+core* get_g_core();
+renderer* get_g_renderer();
+struct GLFWwindow* get_window();
-struct Core {
+struct core {
const char* app_name;
struct GLFWwindow* window;
- Renderer* renderer;
- InputState* input;
+ bool should_exit;
+ renderer* renderer;
+ input_state* input;
};
-extern Core g_core; /** @brief global `Core` that other files can use */
+extern core g_core; /** @brief global `Core` that other files can use */
+
+void core_bringup(const char* window_name, struct GLFWwindow* optional_window);
+void core_shutdown();
+void core_resize_viewport(int width, int height);
+bool app_should_exit();
+
+// --- Error handling
-void Core_Bringup(const char* window_name, struct GLFWwindow* optional_window);
-void Core_Shutdown();
-void Core_ResizeViewport(int width, int height);
-bool AppShouldExit();
+// global error handling
+#define CEL_OK 0
+extern int g_last_error;
+
+/** @brief get last global status value */
+int cel_check_status();
+void _cel_push_error(int error_code);
// --- Memory facilities: Allocators, helpers
// TODO: Arenas
-// TODO: Pool allocator
+
+// Pool
+typedef struct void_pool_header void_pool_header; // TODO: change name of this
+struct void_pool_header {
+ void_pool_header* next;
+};
+
+typedef struct void_pool {
+ u64 capacity;
+ u64 entry_size;
+ u64 count;
+ void* backing_buffer;
+ void_pool_header* free_list_head;
+ const char* debug_label;
+} void_pool;
+
+void_pool void_pool_create(void* storage, const char* debug_label, u64 capacity, u64 entry_size);
+void void_pool_free_all(void_pool* pool);
+bool void_pool_is_empty(void_pool* pool);
+bool void_pool_is_full(void_pool* pool);
+void* void_pool_get(void_pool* pool, u32 raw_handle);
+void* void_pool_alloc(void_pool* pool, u32* out_raw_handle);
+void void_pool_dealloc(void_pool* pool, u32 raw_handle);
+u32 void_pool_insert(void_pool* pool, void* item);
+
+#define TYPED_POOL(T, Name) \
+ typedef struct Name##_pool { \
+ void_pool inner; \
+ } Name##_pool; \
+ \
+ static Name##_pool Name##_pool_create(void* storage, u64 cap, u64 entry_size) { \
+ void_pool p = void_pool_create(storage, "\"" #Name "\"", cap, entry_size); \
+ return (Name##_pool){ .inner = p }; \
+ } \
+ static inline T* Name##_pool_get(Name##_pool* pool, Name##_handle handle) { \
+ return (T*)void_pool_get(&pool->inner, handle.raw); \
+ } \
+ static inline T* Name##_pool_alloc(Name##_pool* pool, Name##_handle* out_handle) { \
+ return (T*)void_pool_alloc(&pool->inner, &out_handle->raw); \
+ } \
+ static inline void Name##_pool_dealloc(Name##_pool* pool, Name##_handle handle) { \
+ void_pool_dealloc(&pool->inner, handle.raw); \
+ } \
+ static Name##_handle Name##_pool_insert(Name##_pool* pool, T* item) { \
+ u32 raw_handle = void_pool_insert(pool, item); \
+ return (Name##_handle){ .raw = raw_handle }; \
+ }
// --- Strings
// --- Logging
// Log levels
-typedef enum LogLevel {
+typedef enum loglevel {
LOG_LEVEL_FATAL = 0,
LOG_LEVEL_ERROR = 1,
LOG_LEVEL_WARN = 2,
LOG_LEVEL_INFO = 3,
LOG_LEVEL_DEBUG = 4,
LOG_LEVEL_TRACE = 5,
-} LogLevel;
+} loglevel;
-void log_output(char* module, LogLevel level, const char* msg, ...);
+void log_output(char* module, loglevel level, const char* msg, ...);
#define NAMESPACED_LOGGER(module) \
static inline void FATAL(const char* msg, ...) { \
@@ -119,31 +188,31 @@ void log_output(char* module, LogLevel level, const char* msg, ...);
static inline void ERROR(const char* msg, ...) { \
va_list args; \
va_start(args, msg); \
- log_output(#module, LOG_LEVEL_FATAL, msg, args); \
+ log_output(#module, LOG_LEVEL_ERROR, msg, args); \
va_end(args); \
} \
static inline void WARN(const char* msg, ...) { \
va_list args; \
va_start(args, msg); \
- log_output(#module, LOG_LEVEL_FATAL, msg, args); \
+ log_output(#module, LOG_LEVEL_WARN, msg, args); \
va_end(args); \
} \
static inline void INFO(const char* msg, ...) { \
va_list args; \
va_start(args, msg); \
- log_output(#module, LOG_LEVEL_FATAL, msg, args); \
+ log_output(#module, LOG_LEVEL_INFO, msg, args); \
va_end(args); \
} \
static inline void DEBUG(const char* msg, ...) { \
va_list args; \
va_start(args, msg); \
- log_output(#module, LOG_LEVEL_FATAL, msg, args); \
+ log_output(#module, LOG_LEVEL_DEBUG, msg, args); \
va_end(args); \
} \
static inline void TRACE(const char* msg, ...) { \
va_list args; \
va_start(args, msg); \
- log_output(#module, LOG_LEVEL_FATAL, msg, args); \
+ log_output(#module, LOG_LEVEL_TRACE, msg, args); \
va_end(args); \
}
@@ -155,77 +224,127 @@ void log_output(char* module, LogLevel level, const char* msg, ...);
#define TAU (2.0 * PI)
/** @brief 2D Vector */
-typedef struct Vec2 {
+typedef struct vec2 {
f32 x, y;
-} Vec2;
+} vec2;
/** @brief 3D Vector */
-typedef struct Vec3 {
+typedef struct vec3 {
f32 x, y, z;
-} Vec3;
+} vec3;
/** @brief 4D Vector */
-typedef struct Vec4 {
+typedef struct vec4 {
f32 x, y, z, w;
-} Vec4;
+} vec4;
/** @brief Quaternion */
-typedef Vec4 Quat;
+typedef vec4 quat;
/** @brief 4x4 Matrix */
-typedef struct Mat4 {
+typedef struct mat4 {
// TODO: use this format for more readable code: vec4 x_axis, y_axis, z_axis, w_axis;
f32 data[16];
-} Mat4;
+} mat4;
/** @brief 3D affine transformation */
-typedef struct Transform {
- Vec3 position;
- Quat rotation;
- Vec3 scale;
+typedef struct transform {
+ vec3 position;
+ quat rotation;
+ vec3 scale;
bool is_dirty;
-} Transform;
-
-inlined Vec3 Vec3_Create(f32 x, f32 y, f32 z);
-inlined Vec3 Vec3_Add(Vec3 u, Vec3 v);
-inlined Vec3 Vec3_Sub(Vec3 u, Vec3 v);
-inlined Vec3 Vec3_Mult(Vec3 u, f32 s);
-inlined Vec3 Vec3_Div(Vec3 u, f32 s);
+} transform;
+
+_Static_assert(alignof(vec3) == 4, "vec3 is 4 byte aligned");
+_Static_assert(sizeof(vec3) == 12, "vec3 is 12 bytes so has no padding");
+_Static_assert(alignof(vec4) == 4, "vec4 is 4 byte aligned");
+
+inlined vec3 vec3_create(f32 x, f32 y, f32 z);
+inlined vec3 vec3_add(vec3 u, vec3 v);
+inlined vec3 vec3_sub(vec3 u, vec3 v);
+inlined vec3 vec3_mult(vec3 u, f32 s);
+inlined vec3 vec3_div(vec3 u, f32 s);
+inlined vec3 vec3_len_squared(vec3 a);
+inlined f32 vec3_len(vec3 a);
+inlined vec3 vec3_negate(vec3 a);
+inlined vec3 vec3_normalise(vec3 a);
+inlined f32 vec3_dot(vec3 a, vec3 b);
+inlined vec3 vec3_cross(vec3 a, vec3 b);
+
+inlined vec4 vec4_create(f32 x, f32 y, f32 z, f32 w);
+
+// quaternion functions
+inlined quat quat_ident();
+quat quat_from_axis_angle(vec3 axis, f32 angle, bool normalise);
+quat quat_slerp(quat a, quat b, f32 percentage);
+
+// matrix functions
+inlined mat4 mat4_ident();
+mat4 mat4_translation(vec3 position);
+mat4 mat4_scale(vec3 scale);
+mat4 mat4_rotation(quat rotation);
+mat4 mat4_mult(mat4 lhs, mat4 rhs);
+mat4 mat4_transposed(mat4 m);
+mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_clip, f32 far_clip);
+mat4 mat4_orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 near_clip, f32 far_clip);
+mat4 mat4_look_at(vec3 position, vec3 target, vec3 up);
+
+// transform functions
+inlined transform transform_create(vec3 pos, quat rot, vec3 scale);
+mat4 transform_to_mat(transform* tf);
+
+// helpers
+
+#define vec3(x, y, z) ((vec3){ x, y, z })
+#define vec4(x, y, z, w) ((vec4){ x, y, z, w })
+inlined vec4 v3tov4(vec3 v3) { return vec4_create(v3.x, v3.y, v3.z, 1.0); }
+
+static const vec3 VEC3_X = vec3(1.0, 0.0, 0.0);
+static const vec3 VEC3_NEG_X = vec3(-1.0, 0.0, 0.0);
+static const vec3 VEC3_Y = vec3(0.0, 1.0, 0.0);
+static const vec3 VEC3_NEG_Y = vec3(0.0, -1.0, 0.0);
+static const vec3 VEC3_Z = vec3(0.0, 0.0, 1.0);
+static const vec3 VEC3_NEG_Z = vec3(0.0, 0.0, -1.0);
+static const vec3 VEC3_ZERO = vec3(0.0, 0.0, 0.0);
+static const vec3 VEC3_ONES = vec3(1.0, 1.0, 1.0);
// --- RAL
-DEFINE_HANDLE(BufHandle);
-DEFINE_HANDLE(TexHandle);
-DEFINE_HANDLE(PipelineHandle);
+DEFINE_HANDLE(buf_handle);
+DEFINE_HANDLE(tex_handle);
+DEFINE_HANDLE(pipeline_handle);
+DEFINE_HANDLE(compute_pipeline_handle);
#define MAX_VERTEX_ATTRIBUTES 16
#define MAX_SHADER_BINDINGS 16
// Backend-specific structs
-typedef struct GPU_Swapchain GPU_Swapchain;
-typedef struct GPU_Pipeline GPU_Pipeline;
-typedef struct GPU_CmdEncoder GPU_CmdEncoder;
+typedef struct gpu_swapchain gpu_swapchain;
+typedef struct gpu_encoder gpu_encoder; // Render command encoder
+typedef struct gpu_compute_encoder gpu_compute_encoder;
+typedef struct gpu_buffer gpu_buffer;
+typedef struct gpu_texture gpu_texture;
// NOTE: Can we just use Storage buffer for everything?
-// typedef enum GPU_BufferType {} GPU_BufferType;
+// typedef enum gpu_buf_type {} gpu_buf_type;
-typedef enum GPU_TextureType {
+typedef enum gpu_tex_type {
TEXTURE_TYPE_2D,
TEXTURE_TYPE_3D,
TEXTURE_TYPE_2D_ARRAY,
TEXTURE_TYPE_CUBE_MAP,
TEXTURE_TYPE_COUNT
-} GPU_TextureType;
+} gpu_tex_type;
/** @brief Texture Description - used by texture creation functions */
-typedef struct TextureDesc {
- GPU_TextureType tex_type;
+typedef struct texture_desc {
+ gpu_tex_type tex_type;
// GPU_TextureFormat format;
int width, height, num_channels;
-} TextureDesc;
+} texture_desc;
/// @strip_prefix(ATTR_)
-typedef enum VertexAttribType {
+typedef enum vertex_attrib_type {
ATTR_F32,
ATTR_F32x2,
ATTR_F32x3,
@@ -238,18 +357,19 @@ typedef enum VertexAttribType {
ATTR_I32x2,
ATTR_I32x3,
ATTR_I32x4,
-} VertexAttribType;
+} vertex_attrib_type;
-typedef struct VertexDesc {
+typedef struct vertex_desc {
const char* label;
- VertexAttribType attributes[MAX_VERTEX_ATTRIBUTES];
+ vertex_attrib_type attributes[MAX_VERTEX_ATTRIBUTES];
u32 attribute_count;
-} VertexDesc;
+ u32 padding;
+} vertex_desc;
-typedef struct ShaderDesc {
-} ShaderDesc;
+// Some default formats
+vertex_desc static_3d_vertex_format();
-typedef enum ShaderBindingKind {
+typedef enum shader_binding_type {
BINDING_BYTES,
BINDING_BUFFER,
BINDING_BUFFER_ARRAY,
@@ -257,105 +377,221 @@ typedef enum ShaderBindingKind {
BINDING_TEXTURE_ARRAY,
BINDING_SAMPLER,
BINDING_COUNT
-} ShaderBindingKind;
+} shader_binding_type;
-typedef enum ShaderVisibility {
- VISIBILITY_VERTEX = 1 << 0,
- VISIBILITY_FRAGMENT = 1 << 1,
- VISIBILITY_COMPUTE = 1 << 2,
-} ShaderVisibility;
+typedef enum shader_stage {
+ STAGE_VERTEX = 1 << 0,
+ STAGE_FRAGMENT = 1 << 1,
+ STAGE_COMPUTE = 1 << 2,
+} shader_stage;
-typedef struct ShaderBinding {
+typedef struct shader_binding {
const char* label;
- ShaderBindingKind kind;
- ShaderVisibility vis;
+ shader_binding_type binding_type;
+ shader_stage visibility;
union {
struct {
u32 size;
void* data;
} bytes;
struct {
- BufHandle handle;
+ buf_handle handle;
} buffer;
struct {
- TexHandle handle;
+ tex_handle handle;
} texture;
} data;
-} ShaderBinding;
+} shader_binding;
-typedef struct ShaderDataLayout {
- ShaderBinding bindings[MAX_SHADER_BINDINGS];
+typedef struct shader_data_layout {
+ shader_binding bindings[MAX_SHADER_BINDINGS];
size_t binding_count;
-} ShaderDataLayout;
+} shader_data_layout;
-typedef enum CullMode { CULL_BACK_FACE, CULL_FRONT_FACE } CullMode;
+typedef struct shader_function {
+ const char* source;
+ bool is_spirv;
+ const char* entry_point;
+ shader_stage stage;
+} shader_function;
-typedef struct GraphicsPipelineDesc {
+typedef enum cull_mode { Cull_BackFace, Cull_FrontFace } cull_mode;
+
+typedef struct gfx_pipeline_desc {
const char* label;
- VertexDesc vertex_desc;
- ShaderDesc vs;
- ShaderDesc fs;
+ vertex_desc vertex_desc;
+ shader_function vertex;
+ shader_function fragment;
// ShaderDataLayout data_layouts[MAX_SHADER_DATA_LAYOUTS];
// u32 data_layouts_count;
-} GraphicsPipelineDesc;
+} gfx_pipeline_desc;
+
+typedef struct compute_pipeline_desc { /* TODO */
+} compute_pipeline_desc;
+
+typedef struct render_pass_desc {
+} render_pass_desc;
// --- RAL Functions
-BufHandle GPU_BufferCreate(u64 size, const void* data);
-void GPU_BufferDestroy(BufHandle handle);
-TexHandle GPU_TextureCreate(TextureDesc desc, bool create_view, const void* data);
-void GPU_TextureDestroy(TexHandle handle);
+
+// Resources
+buf_handle ral_buffer_create(u64 size, const void* data);
+void ral_buffer_destroy(buf_handle handle);
+
+tex_handle ral_texture_create(texture_desc desc, bool create_view, const void* data);
+tex_handle ral_texture_load_from_file(const char* filepath);
+void ral_texture_destroy(tex_handle handle);
+
+// Encoders / cmd buffers
+/** @brief grabs a new command encoder from the pool of available ones and begins recording */
+gpu_encoder* ral_render_encoder(render_pass_desc rpass_desc);
+
+gpu_compute_encoder ral_compute_encoder();
+
+void ral_encoder_finish(gpu_encoder* enc);
+void ral_encoder_submit(gpu_encoder* enc);
+void ral_encoder_finish_and_submit(gpu_encoder* enc);
+
+pipeline_handle ral_gfx_pipeline_create(gfx_pipeline_desc desc);
+void ral_gfx_pipeline_destroy(pipeline_handle handle);
+
+compute_pipeline_handle ral_compute_pipeline_create(compute_pipeline_desc);
+void ral_compute_pipeline_destroy(compute_pipeline_handle handle);
+
+// Encoding
+void ral_encode_bind_pipeline(gpu_encoder* enc, pipeline_handle pipeline);
+void ral_encode_set_vertex_buf(gpu_encoder* enc, buf_handle vbuf);
+void ral_encode_set_index_buf(gpu_encoder* enc, buf_handle ibuf);
+void ral_encode_set_texture(gpu_encoder* enc, tex_handle texture, u32 slot);
+void ral_encode_draw_tris(gpu_encoder* enc, size_t start, size_t count);
+
+// Backend lifecycle
+void ral_backend_init(const char* window_name, struct GLFWwindow* window);
+void ral_backend_shutdown();
+void ral_backend_resize_framebuffer(int width, int height);
+
+// Frame lifecycle
+
+typedef void (*scoped_draw_commands)(); // callback that we run our draw commands within.
+// allows us to wrap some api-specific behaviour
+
+void ral_frame_start();
+void ral_frame_draw(scoped_draw_commands draw_fn);
+void ral_frame_end();
// --- Containers (Forward declared as internals are unnecessary for external header)
typedef struct u32_darray u32_darray;
// --- Base Renderer types
-DEFINE_HANDLE(MeshHandle);
-DEFINE_HANDLE(MaterialHandle);
-DEFINE_HANDLE(ModelHandle);
+DEFINE_HANDLE(mesh_handle);
+DEFINE_HANDLE(material_handle);
+DEFINE_HANDLE(model_handle);
-typedef struct Geometry {
- VertexDesc vertex_format;
+typedef struct geometry {
+ vertex_desc vertex_format;
void* vertex_data;
bool has_indices; // When this is false indexed drawing is not used
u32_darray* indices;
-} Geometry;
-
-typedef struct Mesh {
- BufHandle vertex_buffer;
- BufHandle index_buffer;
- MaterialHandle material;
- Geometry geometry;
- // bool is_skinned; // false = its static
- // Armature armature;
- // bool is_uploaded; // has the data been uploaded to the GPU
-} Mesh;
-
-// --- Render primitives
-
-Geometry Geo_CreatePlane(f32 x_scale, f32 z_scale, u32 tiling_u, u32 tiling_v);
-Geometry Geo_CreateCuboid(f32 x_scale, f32 y_scale, f32 z_scale);
-Geometry Geo_CreateCylinder(f32 radius, f32 height, u32 resolution);
-Geometry Geo_CreateCone(f32 radius, f32 height, u32 resolution);
-Geometry Geo_CreateUVsphere(f32 radius, u32 north_south_lines, u32 east_west_lines);
-Geometry Geo_CreateIcosphere(f32 radius, f32 n_subdivisions);
+} geometry;
+
+typedef u32 joint_idx;
+typedef struct armature {
+} armature;
+
+/** @brief Mesh data that has been uploaded to GPU and is ready to be rendered each frame
+ Gets stored in a pool */
+typedef struct mesh {
+ buf_handle vertex_buffer;
+ buf_handle index_buffer;
+ // todo: material?
+ geometry geo; // the originating mesh data
+ const armature* skinning_data;
+} mesh;
+
+typedef struct draw_mesh_cmd {
+ mesh_handle mesh;
+ mat4 transform;
+ vec3 bounding_sphere_center;
+ f32 bounding_sphere_radius;
+ const armature* skinning_data; // NULL = static mesh
+ bool cast_shadows;
+} draw_mesh_cmd;
+
+// --- Geometry/Mesh primitives
+
+geometry geo_plane(f32 x_scale, f32 z_scale, u32 tiling_u, u32 tiling_v);
+geometry geo_cuboid(f32 x_scale, f32 y_scale, f32 z_scale);
+geometry geo_cylinder(f32 radius, f32 height, u32 resolution);
+geometry geo_cone(f32 radius, f32 height, u32 resolution);
+geometry geo_uv_sphere(f32 radius, u32 north_south_lines, u32 east_west_lines);
+geometry geo_ico_sphere(f32 radius, f32 n_subdivisions);
+void geo_scale_uniform(geometry* geo, f32 scale);
+void geo_scale_xyz(geometry* geo, vec3 scale_xyz);
+
+// --- Renderer
+
+// void renderer_init(renderer* rend);
+// void renderer_shutdown(renderer* rend);
+
+typedef struct camera {
+ vec3 position;
+ // TODO: move to using a quaternion for the camera's orientation - need to update
+ // how the view transformation matrix is calculated
+ vec3 forwards;
+ vec3 up;
+ f32 fov;
+} camera;
+
+/** @brief calculates the view and projection matrices for a camera */
+mat4 camera_view_proj(camera camera, f32 lens_height, f32 lens_width, mat4* out_view, mat4* out_proj);
+
+// TODO: Filament PBR model
// --- Scene / Transform Hierarchy
// --- Gameplay
-typedef struct Camera {
- Vec3 position;
- Quat orientation;
- f32 fov;
-} Camera;
+// --- Game and model data
-// --- Reference Renderer
+typedef struct model {
+} model;
-// TODO: Filament PBR model
+model_handle model_load_from_gltf(const char* path);
// --- Animation
+typedef enum keyframe_kind { Keyframe_Rotation, Keyframe_Translation, Keyframe_Scale, Keyframe_Weights } keyframe_kind;
+
+extern const char* keyframe_kind_strings[4];
+
+typedef union keyframe {
+ quat rotation;
+ vec3 translation;
+ vec3 scale;
+ f32 weights[4];
+} keyframe;
+
+typedef struct keyframes {
+ keyframe_kind kind;
+ keyframe* values;
+ size_t n_frames;
+} keyframes;
+
+typedef enum interpolation { Interpolation_Step, Interpolation_Linear, Interpolation_Cubic } interpolation;
+
+extern const char* interpolation_strings[3];
+
+typedef struct animation_spline {
+ f32* timestamps;
+ size_t n_timestamps;
+ keyframes frames;
+} animation_spline;
+
+// Compute shader approach so we only need one kind of vertex format
+
+// --- Input
+
// --- Collisions
// --- Physics