summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoromniscient <17525998+omnisci3nce@users.noreply.github.com>2024-10-17 21:44:44 +1100
committeromniscient <17525998+omnisci3nce@users.noreply.github.com>2024-10-17 21:44:44 +1100
commit70175cfce551a6b534771bd2b1dea6cfb417be1f (patch)
treef29381cde897b024ecb781ff63cd75c3a16f6434
parenta5f1733a09aa99379cf48ed326b4660fbc17cb25 (diff)
starting on cube
-rw-r--r--Makefile8
-rw-r--r--assets/textures/mc_grass.jpegbin0 -> 20480 bytes
-rw-r--r--bindgen/BINDGEN.md1
-rw-r--r--bindgen/odin/README.md1
-rw-r--r--examples/cube.c57
-rw-r--r--examples/triangle.c38
-rw-r--r--include/celeritas.h28
-rw-r--r--src/backend_mtl.m61
-rw-r--r--src/core.c9
-rw-r--r--src/geometry.c88
-rw-r--r--src/impl.c4
-rw-r--r--src/maths.c2
12 files changed, 284 insertions, 13 deletions
diff --git a/Makefile b/Makefile
index cc1c3c0..46890cd 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
CC := clang
-INCLUDES := -I./include -Ideps/glfw-3.3.8/include/GLFW
+INCLUDES := -I./include -Ideps/glfw-3.3.8/include/GLFW -Ideps/stb_image
CFLAGS := -Wall -Wextra -O2 $(INCLUDES)
LDFLAGS := -lglfw
@@ -79,6 +79,12 @@ triangle: $(EXAMPLES_DIR)/triangle.c $(SHARED_LIB) $(SHADER_OUT_DIR)/triangle.ai
$(CC) $(CFLAGS) $(EXAMPLES_DIR)/triangle.c -L$(BUILD_DIR) -lceleritas $(LDFLAGS) -o $(BUILD_DIR)/triangle.bin
MTL_DEBUG_LAYER=1 build/triangle.bin
+.PHONY: cube
+cube: $(EXAMPLES_DIR)/cube.c $(SHARED_LIB) $(SHADER_OUT_DIR)/cube.air $(METAL_LIB)
+ @mkdir -p $(BUILD_DIR)
+ $(CC) $(CFLAGS) $(EXAMPLES_DIR)/cube.c -L$(BUILD_DIR) -lceleritas $(LDFLAGS) -o $(BUILD_DIR)/cube.bin
+ MTL_DEBUG_LAYER=1 build/cube.bin
+
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)
diff --git a/assets/textures/mc_grass.jpeg b/assets/textures/mc_grass.jpeg
new file mode 100644
index 0000000..4f87254
--- /dev/null
+++ b/assets/textures/mc_grass.jpeg
Binary files differ
diff --git a/bindgen/BINDGEN.md b/bindgen/BINDGEN.md
index da7c785..6d32cdf 100644
--- a/bindgen/BINDGEN.md
+++ b/bindgen/BINDGEN.md
@@ -3,5 +3,4 @@ This is where we host code generation tools for generating bindings to `celerita
Planned languages are:
- OCaml (due to fairly different semantics we may have an extra high-level wrapper around the C bindings for convenience)
-- Odin
- Rust
diff --git a/bindgen/odin/README.md b/bindgen/odin/README.md
deleted file mode 100644
index f87f5c1..0000000
--- a/bindgen/odin/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# TODO \ No newline at end of file
diff --git a/examples/cube.c b/examples/cube.c
index e69de29..6642e2a 100644
--- a/examples/cube.c
+++ b/examples/cube.c
@@ -0,0 +1,57 @@
+#include <celeritas.h>
+
+// vertices
+
+pipeline_handle draw_pipeline;
+buf_handle cube_vbuf;
+tex_handle texture;
+
+void draw() {
+ render_pass_desc d = {};
+ gpu_encoder* enc = ral_render_encoder(d);
+ ral_encode_bind_pipeline(enc, draw_pipeline);
+ ral_encode_set_vertex_buf(enc, cube_vbuf);
+ ral_encode_set_texture(enc, texture, 0);
+ ral_encode_draw_tris(enc, 0, 36);
+ ral_encoder_finish_and_submit(enc);
+}
+
+int main() {
+ core_bringup("Celeritas Example: Triangle", NULL);
+
+ // create rendering pipeline
+ gfx_pipeline_desc pipeline_desc = {
+ .label = "Textured cube pipeline",
+ .vertex_desc = static_3d_vertex_format(),
+ .vertex = {
+ .source = NULL,
+ .is_spirv = false,
+ .entry_point = "cubeVertexShader",
+ .stage = STAGE_VERTEX,
+ },
+ .fragment = {
+ .source = NULL,
+ .is_spirv = false,
+ .entry_point = "cubeFragmentShader",
+ .stage = STAGE_FRAGMENT,
+ },
+ };
+
+ draw_pipeline = ral_gfx_pipeline_create(pipeline_desc);
+
+ // create the cube geometry
+ geometry cube = geo_cuboid(1.0, 1.0, 1.0);
+
+ // upload vertex data to the gpu
+ cube_vbuf = ral_buffer_create(64 * 36, cube.vertex_data);
+
+ while (!app_should_exit()) {
+ glfwPollEvents();
+
+ ral_frame_start();
+ ral_frame_draw(&draw);
+ ral_frame_end();
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/examples/triangle.c b/examples/triangle.c
index 401b5ac..e5cf92d 100644
--- a/examples/triangle.c
+++ b/examples/triangle.c
@@ -2,21 +2,39 @@
#include <celeritas.h>
-static vec4 vertices[] = {
- {-0.5f, -0.5f, 0.0f, 1.0},
- { 0.5f, -0.5f, 0.0f, 1.0},
- { 0.0f, 0.5f, 0.0f, 1.0}
-};
+// static vec4 vertices[] = {
+// {-0.5f, -0.5f, 0.0f, 1.0},
+// { 0.5f, -0.5f, 0.0f, 1.0},
+// { 0.0f, 0.5f, 0.0f, 1.0}
+// };
+
+typedef struct VertexData {
+ vec4 position;
+ vec2 texCoords;
+ f32 pad1;
+ f32 pad2;
+} VertexData;
+
+VertexData squareVertices[] = {
+ {{-0.5, -0.5, 0.5, 1.0f}, {0.0f, 0.0f}, 0.0, 0.0},
+ {{-0.5, 0.5, 0.5, 1.0f}, {0.0f, 1.0f}, 0.0, 0.0},
+ {{ 0.5, 0.5, 0.5, 1.0f}, {1.0f, 1.0f}, 0.0, 0.0},
+ {{-0.5, -0.5, 0.5, 1.0f}, {0.0f, 0.0f}, 0.0, 0.0},
+ {{ 0.5, 0.5, 0.5, 1.0f}, {1.0f, 1.0f}, 0.0, 0.0},
+ {{ 0.5, -0.5, 0.5, 1.0f}, {1.0f, 0.0f}, 0.0, 0.0}
+ };
pipeline_handle draw_pipeline;
buf_handle tri_vert_buffer;
+tex_handle texture;
void draw() {
render_pass_desc d = {};
gpu_encoder* enc = ral_render_encoder(d);
ral_encode_bind_pipeline(enc, draw_pipeline);
ral_encode_set_vertex_buf(enc, tri_vert_buffer);
- ral_encode_draw_tris(enc, 0, 3);
+ ral_encode_set_texture(enc, texture, 0);
+ ral_encode_draw_tris(enc, 0, 6);
ral_encoder_finish_and_submit(enc);
}
@@ -43,9 +61,13 @@ int main() {
draw_pipeline = ral_gfx_pipeline_create(pipeline_desc);
+ // load texture from file
+ texture = ral_texture_load_from_file("assets/textures/mc_grass.jpeg");
+
// create our buffer to hold vertices
- printf("size of vertices %ld\n", sizeof(vec4) * 3);
- tri_vert_buffer = ral_buffer_create(sizeof(vec4) * 3, &vertices);
+ size_t buffer_size = sizeof(VertexData) * 6;
+ printf("size of vertices %ld\n", buffer_size);
+ tri_vert_buffer = ral_buffer_create(buffer_size, &squareVertices);
while (!app_should_exit()) {
glfwPollEvents();
diff --git a/include/celeritas.h b/include/celeritas.h
index 14e39dd..77b7a9b 100644
--- a/include/celeritas.h
+++ b/include/celeritas.h
@@ -6,6 +6,7 @@
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
#include <assert.h>
#include <string.h>
@@ -252,6 +253,25 @@ 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 vec4 vec4_create(f32 x, f32 y, f32 z, f32 w);
+
+// 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, 0.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(buf_handle);
@@ -307,8 +327,12 @@ typedef struct vertex_desc {
const char* label;
vertex_attrib_type attributes[MAX_VERTEX_ATTRIBUTES];
u32 attribute_count;
+ u32 padding;
} vertex_desc;
+// Some default formats
+vertex_desc static_3d_vertex_format();
+
typedef enum shader_binding_type {
BINDING_BYTES,
BINDING_BUFFER,
@@ -377,7 +401,9 @@ typedef struct render_pass_desc {
// 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
@@ -400,11 +426,13 @@ void ral_compute_pipeline_destroy(compute_pipeline_handle handle);
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
diff --git a/src/backend_mtl.m b/src/backend_mtl.m
index 6ff5058..48e0ab0 100644
--- a/src/backend_mtl.m
+++ b/src/backend_mtl.m
@@ -2,18 +2,20 @@
#ifdef GPU_METAL
-#define MTL_DEBUG_LAYER 1
+#define MTL_DEBUG_LAYER 1 // enable all metal validation layers
// Obj-C imports
#import <Foundation/Foundation.h>
#import <Metal/Metal.h>
#import <MetalKit/MetalKit.h>
#import <QuartzCore/CAMetalLayer.h>
+#include <CoreGraphics/CGGeometry.h>
#define GLFW_INCLUDE_NONE
#import <GLFW/glfw3.h>
#define GLFW_EXPOSE_NATIVE_COCOA
#import <GLFW/glfw3native.h>
+#include "stb_image.h"
NAMESPACED_LOGGER(metal);
@@ -37,7 +39,12 @@ typedef struct metal_buffer {
id<MTLBuffer> id;
} metal_buffer;
+typedef struct metal_texture {
+ id<MTLTexture> id;
+} metal_texture;
+
TYPED_POOL(metal_buffer, buf);
+TYPED_POOL(metal_texture, tex);
TYPED_POOL(metal_pipeline, pipeline);
typedef struct metal_context {
@@ -53,6 +60,7 @@ typedef struct metal_context {
/* pools */
buf_pool bufpool;
+ tex_pool texpool;
pipeline_pool psopool; // pso = pipeline state object
} metal_context;
@@ -66,15 +74,18 @@ void ral_backend_init(const char* window_name, struct GLFWwindow* window) {
ctx.device = gpu;
TRACE("window init");
- glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwMakeContextCurrent(window);
NSWindow* nswindow = glfwGetCocoaWindow(window);
ctx.metal_window = nswindow;
+ int width, height;
+ glfwGetFramebufferSize(window, &width, &height);
+
// effectively the "framebuffer"
CAMetalLayer* metal_layer = [CAMetalLayer layer];
metal_layer.device = gpu;
metal_layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
+ metal_layer.drawableSize = CGSizeMake(width, height);
ctx.metal_window.contentView.layer = metal_layer;
ctx.metal_window.contentView.wantsLayer = true;
ctx.default_swapchain.swapchain = metal_layer;
@@ -87,6 +98,9 @@ void ral_backend_init(const char* window_name, struct GLFWwindow* window) {
metal_buffer* buffer_storage = malloc(sizeof(metal_buffer) * 100);
ctx.bufpool = buf_pool_create(buffer_storage, 100, sizeof(metal_buffer));
+ metal_texture* texture_storage = malloc(sizeof(metal_texture) * 100);
+ ctx.texpool = tex_pool_create(texture_storage, 100, sizeof(metal_texture));
+
metal_pipeline* pipeline_storage = malloc(sizeof(metal_pipeline) * 100);
ctx.psopool = pipeline_pool_create(pipeline_storage, 100, sizeof(metal_pipeline));
@@ -114,6 +128,39 @@ buf_handle ral_buffer_create(u64 size, const void *data) {
return handle;
}
+tex_handle ral_texture_create(texture_desc desc, bool create_view, const void *data) {
+ tex_handle handle;
+ metal_texture* texture = tex_pool_alloc(&ctx.texpool, &handle);
+
+ MTLTextureDescriptor* texture_descriptor = [[MTLTextureDescriptor alloc] init];
+ [texture_descriptor setPixelFormat:MTLPixelFormatRGBA8Unorm];
+ [texture_descriptor setWidth:desc.width];
+ [texture_descriptor setHeight:desc.height];
+
+ texture->id = [ctx.device newTextureWithDescriptor:texture_descriptor];
+
+ MTLRegion region = MTLRegionMake2D(0, 0, desc.width, desc.height);
+ u32 bytes_per_row = 4 * desc.width;
+
+ [texture->id replaceRegion:region mipmapLevel:0 withBytes:data bytesPerRow:bytes_per_row];
+
+ [texture_descriptor release];
+
+ return handle;
+}
+
+tex_handle ral_texture_load_from_file(const char* filepath) {
+ texture_desc desc;
+
+ stbi_set_flip_vertically_on_load(true);
+ unsigned char* image = stbi_load(filepath, &desc.width, &desc.height, &desc.num_channels, STBI_rgb_alpha);
+ assert(image != NULL);
+
+ tex_handle handle = ral_texture_create(desc, false, image);
+ stbi_image_free(image);
+ return handle;
+}
+
pipeline_handle ral_gfx_pipeline_create(gfx_pipeline_desc desc) {
TRACE("creating graphics pipeline");
@@ -187,6 +234,11 @@ void ral_encode_set_vertex_buf(gpu_encoder *enc, buf_handle vbuf) {
[enc->cmd_encoder setVertexBuffer:b->id offset:0 atIndex:0 ];
}
+void ral_encode_set_texture(gpu_encoder* enc, tex_handle texture, u32 slot) {
+ metal_texture* t = tex_pool_get(&ctx.texpool, texture);
+ [enc->cmd_encoder setFragmentTexture:t->id atIndex:slot];
+}
+
void ral_encode_draw_tris(gpu_encoder* enc, size_t start, size_t count) {
MTLPrimitiveType tri_primitive = MTLPrimitiveTypeTriangle;
[enc->cmd_encoder drawPrimitives:tri_primitive vertexStart:start vertexCount:count];
@@ -203,4 +255,9 @@ void ral_frame_draw(scoped_draw_commands draw_fn) {
void ral_frame_end() {}
+void ral_backend_resize_framebuffer(int width, int height) {
+ TRACE("resizing framebuffer");
+ ctx.default_swapchain.swapchain.drawableSize = CGSizeMake((float)width, (float)height);
+}
+
#endif \ No newline at end of file
diff --git a/src/core.c b/src/core.c
index 210c282..9359a6b 100644
--- a/src/core.c
+++ b/src/core.c
@@ -2,6 +2,7 @@
#include <celeritas.h>
#include <stdlib.h>
+#include "glfw3.h"
NAMESPACED_LOGGER(core);
@@ -15,6 +16,7 @@ static const char* gapi = "Vulkan";
// forward declares
void key_callback(GLFWwindow* win, int key, int scancode, int action, int mods);
+void resize_callback(GLFWwindow* win, int width, int height);
void core_bringup(const char* window_name, struct GLFWwindow* optional_window) {
INFO("Initiate Core bringup");
@@ -22,6 +24,8 @@ void core_bringup(const char* window_name, struct GLFWwindow* optional_window) {
INFO("Create GLFW window");
glfwInit();
+ glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+
char* full_window_name = malloc(sizeof(char) * 100);
int _offset = sprintf(full_window_name, "%s (%s)", window_name, gapi);
@@ -32,6 +36,7 @@ void core_bringup(const char* window_name, struct GLFWwindow* optional_window) {
ral_backend_init(window_name, glfw_window);
glfwSetKeyCallback(glfw_window, key_callback);
+ glfwSetFramebufferSizeCallback(glfw_window, resize_callback);
}
void core_shutdown() {
ral_backend_shutdown();
@@ -46,4 +51,8 @@ void key_callback(GLFWwindow* window, int key, int scancode, int action, int mod
if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) {
g_core.should_exit = true;
}
+}
+
+void resize_callback(GLFWwindow* window, int width, int height) {
+ ral_backend_resize_framebuffer(width, height);
} \ No newline at end of file
diff --git a/src/geometry.c b/src/geometry.c
new file mode 100644
index 0000000..d9b0aee
--- /dev/null
+++ b/src/geometry.c
@@ -0,0 +1,88 @@
+#include <celeritas.h>
+
+typedef struct static_3d_vert {
+ vec4 pos;
+ vec4 norm;
+ vec2 uv;
+ vec2 pad;
+} static_3d_vert;
+
+vertex_desc static_3d_vertex_format() {
+ vertex_desc desc;
+ desc.label = "Static 3D Vertex";
+ desc.attributes[0] = ATTR_F32x4; // position
+ desc.attributes[1] = ATTR_F32x4; // normal
+ desc.attributes[2] = ATTR_F32x2; // tex coord
+ desc.attribute_count = 3;
+ desc.padding = 16; // 16 bytes padding
+
+ return desc;
+}
+
+geometry geo_cuboid(f32 x_scale, f32 y_scale, f32 z_scale) {
+ vec4 BACK_BOT_LEFT = (vec4){ 0, 0, 0, 0 };
+ vec4 BACK_BOT_RIGHT = (vec4){ 1, 0, 0, 0 };
+ vec4 BACK_TOP_LEFT = (vec4){ 0, 1, 0, 0 };
+ vec4 BACK_TOP_RIGHT = (vec4){ 1, 1, 0, 0 };
+ vec4 FRONT_BOT_LEFT = (vec4){ 0, 0, 1, 0 };
+ vec4 FRONT_BOT_RIGHT = (vec4){ 1, 0, 1, 0 };
+ vec4 FRONT_TOP_LEFT = (vec4){ 0, 1, 1, 0 };
+ vec4 FRONT_TOP_RIGHT = (vec4){ 1, 1, 1, 0 };
+
+ // allocate the data
+ static_3d_vert* vertices = malloc(36 * 64);
+
+ vertices[0] = (static_3d_vert){ .pos = BACK_TOP_RIGHT, .norm = (v3tov4(VEC3_NEG_Z)), .uv = {0, 0}};
+ vertices[1] = (static_3d_vert){ .pos = BACK_BOT_LEFT, .norm = v3tov4(VEC3_NEG_Z), .uv = {0, 1} };
+ vertices[2] = (static_3d_vert){ .pos = BACK_TOP_LEFT, .norm = v3tov4(VEC3_NEG_Z), .uv = {0, 0} };
+ vertices[3] = (static_3d_vert){ .pos = BACK_TOP_RIGHT, .norm = v3tov4(VEC3_NEG_Z), .uv = {1, 0} };
+ vertices[4] = (static_3d_vert){ .pos = BACK_BOT_RIGHT, .norm = v3tov4(VEC3_NEG_Z), .uv = {1, 1} };
+ vertices[5] = (static_3d_vert){ .pos = BACK_BOT_LEFT, .norm = v3tov4(VEC3_NEG_Z), .uv = {0, 1} };
+
+ // front faces
+ vertices[6] = (static_3d_vert){ .pos = FRONT_BOT_LEFT, .norm = v3tov4(VEC3_Z), .uv = {0, 1} };
+ vertices[7] = (static_3d_vert){ .pos = FRONT_TOP_RIGHT, .norm = v3tov4(VEC3_Z), .uv = {1, 0} };
+ vertices[8] = (static_3d_vert){ .pos = FRONT_TOP_LEFT, .norm = v3tov4(VEC3_Z), .uv = {0, 0} };
+ vertices[9] = (static_3d_vert){ .pos = FRONT_BOT_LEFT, .norm = v3tov4(VEC3_Z), .uv = {0, 1} };
+ vertices[10] = (static_3d_vert){ .pos = FRONT_BOT_RIGHT, .norm = v3tov4(VEC3_Z), .uv = {1, 1} };
+ vertices[11] = (static_3d_vert){ .pos = FRONT_TOP_RIGHT, .norm = v3tov4(VEC3_Z), .uv = {1, 0} };
+
+ // top faces
+ vertices[12] = (static_3d_vert){ .pos = BACK_TOP_LEFT, .norm = v3tov4(VEC3_Y), .uv = {0, 0} };
+ vertices[13] = (static_3d_vert){ .pos = FRONT_TOP_LEFT, .norm = v3tov4(VEC3_Y), .uv = {0, 1} };
+ vertices[14] = (static_3d_vert){ .pos = FRONT_TOP_RIGHT, .norm = v3tov4(VEC3_Y), .uv = {1, 1} };
+ vertices[15] = (static_3d_vert){ .pos = BACK_TOP_LEFT, .norm = v3tov4(VEC3_Y), .uv = {0, 0} };
+ vertices[16] = (static_3d_vert){ .pos = FRONT_TOP_RIGHT, .norm = v3tov4(VEC3_Y), .uv = {1, 1} };
+ vertices[17] = (static_3d_vert){ .pos = BACK_TOP_RIGHT, .norm = v3tov4(VEC3_Y), .uv = {1, 0} };
+
+ // bottom faces
+ vertices[18] = (static_3d_vert){ .pos = BACK_BOT_LEFT, .norm = v3tov4(VEC3_NEG_Y), .uv = {0, 1} };
+ vertices[19] = (static_3d_vert){ .pos = FRONT_BOT_RIGHT, .norm = v3tov4(VEC3_NEG_Y), .uv = {1, 1} };
+ vertices[20] = (static_3d_vert){ .pos = FRONT_BOT_LEFT, .norm = v3tov4(VEC3_NEG_Y), .uv = {0, 1} };
+ vertices[21] = (static_3d_vert){ .pos = BACK_BOT_LEFT, .norm = v3tov4(VEC3_NEG_Y), .uv = {0, 1} };
+ vertices[22] = (static_3d_vert){ .pos = BACK_BOT_RIGHT, .norm = v3tov4(VEC3_NEG_Y), .uv = {1, 1} };
+ vertices[23] = (static_3d_vert){ .pos = FRONT_BOT_RIGHT, .norm = v3tov4(VEC3_NEG_Y), .uv = {0, 1} };
+
+ // right faces
+ vertices[24] = (static_3d_vert){ .pos = FRONT_TOP_RIGHT, .norm = v3tov4(VEC3_X), .uv = {0, 0} };
+ vertices[25] = (static_3d_vert){ .pos = BACK_BOT_RIGHT, .norm = v3tov4(VEC3_X), .uv = {1, 1} };
+ vertices[26] = (static_3d_vert){ .pos = BACK_TOP_RIGHT, .norm = v3tov4(VEC3_X), .uv = {1, 0} };
+ vertices[27] = (static_3d_vert){ .pos = BACK_BOT_RIGHT, .norm = v3tov4(VEC3_X), .uv = {1, 1} };
+ vertices[28] = (static_3d_vert){ .pos = FRONT_TOP_RIGHT, .norm = v3tov4(VEC3_X), .uv = {0, 0} };
+ vertices[29] = (static_3d_vert){ .pos = FRONT_BOT_RIGHT, .norm = v3tov4(VEC3_X), .uv = {0, 1} };
+
+ // left faces
+ vertices[30] = (static_3d_vert){ .pos = FRONT_TOP_LEFT, .norm = v3tov4(VEC3_NEG_X), .uv = {0, 0} };
+ vertices[31] = (static_3d_vert){ .pos = BACK_TOP_LEFT, .norm = v3tov4(VEC3_NEG_X), .uv = {0, 0} };
+ vertices[32] = (static_3d_vert){ .pos = BACK_BOT_LEFT, .norm = v3tov4(VEC3_NEG_X), .uv = {0, 0} };
+ vertices[33] = (static_3d_vert){ .pos = BACK_BOT_LEFT, .norm = v3tov4(VEC3_NEG_X), .uv = {0, 0} };
+ vertices[34] = (static_3d_vert){ .pos = FRONT_BOT_LEFT, .norm = v3tov4(VEC3_NEG_X), .uv = {0, 0} };
+ vertices[35] = (static_3d_vert){ .pos = FRONT_TOP_LEFT, .norm = v3tov4(VEC3_NEG_X), .uv = {0, 0} };
+
+ return (geometry) {
+ .vertex_format = static_3d_vertex_format(),
+ .vertex_data = vertices,
+ .has_indices = false,
+ .indices = NULL
+ };
+} \ No newline at end of file
diff --git a/src/impl.c b/src/impl.c
new file mode 100644
index 0000000..18f2549
--- /dev/null
+++ b/src/impl.c
@@ -0,0 +1,4 @@
+// For pulling in implementation files of single-header libraries
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h" \ No newline at end of file
diff --git a/src/maths.c b/src/maths.c
index f12c852..95283e6 100644
--- a/src/maths.c
+++ b/src/maths.c
@@ -1,3 +1,5 @@
#include <celeritas.h>
vec3 vec3_create(f32 x, f32 y, f32 z) { return (vec3){ x, y, z }; }
+
+vec4 vec4_create(f32 x, f32 y, f32 z, f32 w) { return (vec4){ x, y, z , w }; } \ No newline at end of file