summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/README.md11
-rw-r--r--examples/cube/ex_cube.c158
-rw-r--r--examples/example_scene.h31
-rw-r--r--examples/gltf_loading/ex_gltf_loading.c4
-rw-r--r--examples/input/ex_input.c120
-rw-r--r--examples/main_loop/ex_main_loop.c14
-rw-r--r--examples/obj_loading/ex_obj_loading.c4
-rw-r--r--examples/property_animation/ex_property_animation.c103
-rw-r--r--examples/skinned_animation/ex_skinned_animation.c122
-rw-r--r--examples/transforms/ex_transforms.c2
-rw-r--r--examples/triangle/ex_triangle.c104
11 files changed, 669 insertions, 4 deletions
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 0000000..f289e80
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,11 @@
+
+### RAL examples
+
+These examples show off how the lowest register of rendering, the Rendering Abstraction Layer (RAL), is used to draw things to the screen.
+
+- triangle
+- cube
+
+### Renderer
+
+The 'renderer' is the default renderer provided by Celeritas.
diff --git a/examples/cube/ex_cube.c b/examples/cube/ex_cube.c
new file mode 100644
index 0000000..fc59e2d
--- /dev/null
+++ b/examples/cube/ex_cube.c
@@ -0,0 +1,158 @@
+#include <glfw3.h>
+
+#include "buf.h"
+#include "camera.h"
+#include "core.h"
+#include "file.h"
+#include "log.h"
+#include "maths.h"
+#include "maths_types.h"
+#include "mem.h"
+#include "primitives.h"
+#include "ral.h"
+#include "ral_types.h"
+#include "render.h"
+#include "render_types.h"
+
+extern core g_core;
+
+// Define the shader data
+typedef struct mvp_uniforms {
+ mat4 model;
+ mat4 view;
+ mat4 projection;
+} mvp_uniforms;
+typedef struct my_shader_bind_group {
+ mvp_uniforms mvp;
+ texture_handle tex;
+} my_shader_bind_group;
+
+// We also must create a function that knows how to return a `shader_data_layout`
+shader_data_layout mvp_uniforms_layout(void* data) {
+ my_shader_bind_group* d = (my_shader_bind_group*)data;
+ bool has_data = data != NULL;
+
+ shader_binding b1 = { .label = "mvp_uniforms",
+ .type = SHADER_BINDING_BYTES,
+ .stores_data = has_data,
+ .data = { .bytes = { .size = sizeof(mvp_uniforms) } } };
+
+ shader_binding b2 = { .label = "texture_sampler",
+ .type = SHADER_BINDING_TEXTURE,
+ .stores_data = has_data };
+ if (has_data) {
+ b1.data.bytes.data = &d->mvp;
+ b2.data.texture.handle = d->tex;
+ }
+ return (shader_data_layout){ .name = "global_ubo", .bindings = { b1, b2 }, .bindings_count = 2 };
+}
+
+int main() {
+ core_bringup();
+ arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024);
+
+ DEBUG("render capacity %d", g_core.default_scene.renderables->capacity);
+
+ vec3 camera_pos = vec3(2., 2., 2.);
+ vec3 camera_front = vec3_normalise(vec3_negate(camera_pos));
+ camera cam = camera_create(camera_pos, camera_front, VEC3_Y, deg_to_rad(45.0));
+
+ vertex_description vertex_input = { .use_full_vertex_size = true };
+ vertex_input.debug_label = "Standard Static 3D Vertex Format";
+ vertex_desc_add(&vertex_input, "inPosition", ATTR_F32x3);
+ vertex_desc_add(&vertex_input, "inNormal", ATTR_F32x3);
+ vertex_desc_add(&vertex_input, "inTexCoords", ATTR_F32x2);
+
+ shader_data mvp_uniforms_data = { .data = NULL, .shader_data_get_layout = &mvp_uniforms_layout };
+
+ gpu_renderpass_desc pass_description = {};
+ gpu_renderpass* renderpass = gpu_renderpass_create(&pass_description);
+
+ str8 vert_path = str8lit("build/linux/x86_64/debug/cube.vert.spv");
+ str8 frag_path = str8lit("build/linux/x86_64/debug/cube.frag.spv");
+ str8_opt vertex_shader = str8_from_file(&scratch, vert_path);
+ str8_opt fragment_shader = str8_from_file(&scratch, frag_path);
+ if (!vertex_shader.has_value || !fragment_shader.has_value) {
+ ERROR_EXIT("Failed to load shaders from disk")
+ }
+
+ struct graphics_pipeline_desc pipeline_description = {
+ .debug_name = "Basic Pipeline",
+ .vertex_desc = vertex_input,
+ .data_layouts = { mvp_uniforms_data },
+ .data_layouts_count = 1,
+ .vs = { .debug_name = "Triangle Vertex Shader",
+ .filepath = vert_path,
+ .code = vertex_shader.contents,
+ .is_spirv = true },
+ .fs = { .debug_name = "Triangle Fragment Shader",
+ .filepath = frag_path,
+ .code = fragment_shader.contents,
+ .is_spirv = true },
+ .renderpass = renderpass,
+ .wireframe = false,
+ .depth_test = false
+ };
+ gpu_pipeline* gfx_pipeline = gpu_graphics_pipeline_create(pipeline_description);
+
+ // Geometry
+ geometry_data cube_data = geo_create_cuboid(f32x3(1, 1, 1));
+ mesh cube = mesh_create(&cube_data, false);
+
+ // Texture
+ texture_data tex_data = texture_data_load("assets/textures/texture.jpg", false);
+ texture_handle texture = texture_data_upload(tex_data, true);
+ printf("Texture %d", texture.raw);
+
+ // Main loop
+ while (!should_exit(&g_core)) {
+ input_update(&g_core.input);
+
+ if (!gpu_backend_begin_frame()) {
+ continue;
+ }
+ gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder();
+ // begin recording
+ gpu_cmd_encoder_begin(*enc);
+ gpu_cmd_encoder_begin_render(enc, renderpass);
+ encode_bind_pipeline(enc, PIPELINE_GRAPHICS, gfx_pipeline);
+ encode_set_default_settings(enc);
+
+ static f32 x = 0.0;
+ x += 0.01;
+ quat rotation = quat_from_axis_angle(VEC3_Y, x, true);
+ mat4 translation = mat4_translation(vec3(-0.5, -0.5, -0.5));
+ mat4 model = mat4_rotation(rotation);
+ model = mat4_mult(translation, model);
+ mat4 view, proj;
+ camera_view_projection(&cam, g_core.renderer.swapchain.extent.width,
+ g_core.renderer.swapchain.extent.height, &view, &proj);
+ mvp_uniforms mvp_data = { .model = model, .view = view, .projection = proj };
+ my_shader_bind_group shader_bind_data = { .mvp = mvp_data, .tex = texture };
+ mvp_uniforms_data.data = &shader_bind_data;
+ encode_bind_shader_data(enc, 0, &mvp_uniforms_data);
+
+ // Record draw calls
+ // -- NEW
+ draw_mesh(&cube, &model);
+ // -- OLD
+ /* encode_set_vertex_buffer(enc, triangle_vert_buf); */
+ /* encode_set_index_buffer(enc, triangle_index_buf); */
+ /* gpu_temp_draw(6); */
+
+ // End recording
+ gpu_cmd_encoder_end_render(enc);
+
+ gpu_cmd_buffer buf = gpu_cmd_encoder_finish(enc);
+ gpu_queue_submit(&buf);
+ // Submit
+ gpu_backend_end_frame();
+
+ // render_frame_end(&g_core.renderer);
+ // glfwSwapBuffers(core->renderer.window);
+ }
+
+ renderer_shutdown(&g_core.renderer);
+
+ return 0;
+}
diff --git a/examples/example_scene.h b/examples/example_scene.h
new file mode 100644
index 0000000..eb0be18
--- /dev/null
+++ b/examples/example_scene.h
@@ -0,0 +1,31 @@
+#pragma once
+#include "render_types.h"
+
+const vec3 pointlight_positions[4] = {
+ { 0.7, 0.2, 2.0 },
+ { 2.3, -3.3, -4.0 },
+ { -4.0, 2.0, -12.0 },
+ { 0.0, 0.0, -3.0 },
+};
+static point_light point_lights[4];
+
+static scene make_default_scene() {
+ directional_light dir_light = { .direction = (vec3){ -0.2, -1.0, -0.3 },
+ .ambient = (vec3){ 0.2, 0.2, 0.2 },
+ .diffuse = (vec3){ 0.5, 0.5, 0.5 },
+ .specular = (vec3){ 1.0, 1.0, 1.0 } };
+
+ for (int i = 0; i < 4; i++) {
+ point_lights[i].position = pointlight_positions[i];
+ point_lights[i].ambient = (vec3){ 0.05, 0.05, 0.05 };
+ point_lights[i].diffuse = (vec3){ 0.8, 0.8, 0.8 };
+ point_lights[i].specular = (vec3){ 1.0, 1.0, 1.0 };
+ point_lights[i].constant = 1.0;
+ point_lights[i].linear = 0.09;
+ point_lights[i].quadratic = 0.032;
+ }
+
+ scene our_scene = { .dir_light = dir_light, .n_point_lights = 4 };
+ memcpy(&our_scene.point_lights, &point_lights, sizeof(point_light[4]));
+ return our_scene;
+} \ No newline at end of file
diff --git a/examples/gltf_loading/ex_gltf_loading.c b/examples/gltf_loading/ex_gltf_loading.c
index 0c47fec..fa74ada 100644
--- a/examples/gltf_loading/ex_gltf_loading.c
+++ b/examples/gltf_loading/ex_gltf_loading.c
@@ -1,8 +1,10 @@
#include <glfw3.h>
+#include "animation.h"
#include "camera.h"
#include "core.h"
#include "loaders.h"
+#include "log.h"
#include "maths.h"
#include "maths_types.h"
#include "render.h"
@@ -52,7 +54,7 @@ int main() {
scene our_scene = { .dir_light = dir_light, .n_point_lights = 4 };
memcpy(&our_scene.point_lights, &point_lights, sizeof(point_light[4]));
- while (!glfwWindowShouldClose(core->renderer.window)) {
+ while (!should_exit(core)) {
currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
diff --git a/examples/input/ex_input.c b/examples/input/ex_input.c
new file mode 100644
index 0000000..576b364
--- /dev/null
+++ b/examples/input/ex_input.c
@@ -0,0 +1,120 @@
+#include <glfw3.h>
+
+#include "camera.h"
+#include "core.h"
+#include "input.h"
+#include "keys.h"
+#include "maths.h"
+#include "maths_types.h"
+#include "primitives.h"
+#include "render.h"
+#include "render_backend.h"
+#include "render_types.h"
+
+typedef struct game_state {
+ camera camera;
+ vec3 camera_euler;
+ bool first_mouse_update; // so the camera doesnt lurch when you run the first
+ // process_camera_rotation
+} game_state;
+
+void update_camera_rotation(input_state* input, game_state* game, camera* cam);
+
+int main() {
+ core* core = core_bringup();
+
+ vec3 cam_pos = vec3_create(5, 5, 5);
+ game_state game = {
+ .camera = camera_create(cam_pos, vec3_negate(cam_pos), VEC3_Y, deg_to_rad(45.0)),
+ .camera_euler = vec3_create(90, 0, 0),
+ .first_mouse_update = true,
+ };
+
+ // load a texture
+ texture tex = texture_data_load("assets/models/obj/cube/container.jpg", false);
+ texture_data_upload(&tex);
+
+ printf("Starting look direction: ");
+ print_vec3(game.camera.front);
+
+ // Main loop
+ const f32 camera_lateral_speed = 0.2;
+ const f32 camera_zoom_speed = 0.15;
+
+ while (!should_exit(core)) {
+ input_update(&core->input);
+
+ vec3 translation = VEC3_ZERO;
+ if (key_is_pressed(KEYCODE_W) || key_is_pressed(KEYCODE_KEY_UP)) {
+ printf("Move Forwards\n");
+ translation = vec3_mult(game.camera.front, camera_zoom_speed);
+ } else if (key_is_pressed(KEYCODE_S) || key_is_pressed(KEYCODE_KEY_DOWN)) {
+ printf("Move Backwards\n");
+ translation = vec3_mult(game.camera.front, -camera_zoom_speed);
+ } else if (key_is_pressed(KEYCODE_A) || key_is_pressed(KEYCODE_KEY_LEFT)) {
+ printf("Move Left\n");
+ vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up));
+ translation = vec3_mult(lateral, -camera_lateral_speed);
+ } else if (key_is_pressed(KEYCODE_D) || key_is_pressed(KEYCODE_KEY_RIGHT)) {
+ printf("Move Right\n");
+ vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up));
+ translation = vec3_mult(lateral, camera_lateral_speed);
+ }
+ game.camera.position = vec3_add(game.camera.position, translation);
+ // update_camera_rotation(&core->input, &game, &game.camera);
+
+ // UNUSED: threadpool_process_results(&core->threadpool, 1);
+
+ render_frame_begin(&core->renderer);
+
+ mat4 model = mat4_translation(VEC3_ZERO);
+
+ gfx_backend_draw_frame(&core->renderer, &game.camera, model, &tex);
+
+ render_frame_end(&core->renderer);
+ }
+
+ core_shutdown(core);
+
+ return 0;
+}
+
+void update_camera_rotation(input_state* input, game_state* game, camera* cam) {
+ float xoffset = -input->mouse.x_delta; // xpos - lastX;
+ float yoffset = -input->mouse.y_delta; // reversed since y-coordinates go from bottom to top
+ if (game->first_mouse_update) {
+ xoffset = 0.0;
+ yoffset = 0.0;
+ game->first_mouse_update = false;
+ }
+
+ float sensitivity = 0.2f; // change this value to your liking
+ xoffset *= sensitivity;
+ yoffset *= sensitivity;
+
+ // x = yaw
+ game->camera_euler.x += xoffset;
+ // y = pitch
+ game->camera_euler.y += yoffset;
+ // we dont update roll
+
+ f32 yaw = game->camera_euler.x;
+ f32 pitch = game->camera_euler.y;
+
+ // make sure that when pitch is out of bounds, screen doesn't get flipped
+ if (game->camera_euler.y > 89.0f) game->camera_euler.y = 89.0f;
+ if (game->camera_euler.y < -89.0f) game->camera_euler.y = -89.0f;
+
+ vec3 front = cam->front;
+ front.x = cos(deg_to_rad(yaw) * cos(deg_to_rad(pitch)));
+ front.y = sin(deg_to_rad(pitch));
+ front.z = sin(deg_to_rad(yaw)) * cos(deg_to_rad(pitch));
+
+ front = vec3_normalise(front);
+ // save it back
+ cam->front.x = front.x;
+ cam->front.y = front.y;
+ // roll is static
+
+ print_vec3(cam->front);
+}
diff --git a/examples/main_loop/ex_main_loop.c b/examples/main_loop/ex_main_loop.c
index 3b2354a..4e31313 100644
--- a/examples/main_loop/ex_main_loop.c
+++ b/examples/main_loop/ex_main_loop.c
@@ -1,21 +1,33 @@
#include <glfw3.h>
+#include "camera.h"
#include "core.h"
+#include "maths.h"
#include "render.h"
int main() {
core* core = core_bringup();
+ camera camera = camera_create(vec3_create(0, 0, 20), VEC3_NEG_Z, VEC3_Y, deg_to_rad(45.0));
+
// Main loop
while (!glfwWindowShouldClose(core->renderer.window)) {
input_update(&core->input);
- threadpool_process_results(&core->threadpool, 1);
+ // threadpool_process_results(&core->threadpool, 1);
render_frame_begin(&core->renderer);
+ static f32 x = 0.0;
+ x += 0.01;
+ mat4 model = mat4_translation(vec3(x, 0, 0));
+
+ gfx_backend_draw_frame(&core->renderer, &camera, model, NULL);
+
// insert work here
render_frame_end(&core->renderer);
+ glfwSwapBuffers(core->renderer.window);
+ glfwPollEvents();
}
return 0;
diff --git a/examples/obj_loading/ex_obj_loading.c b/examples/obj_loading/ex_obj_loading.c
index e225cb2..906816b 100644
--- a/examples/obj_loading/ex_obj_loading.c
+++ b/examples/obj_loading/ex_obj_loading.c
@@ -1,3 +1,4 @@
+#include <assert.h>
#include <glfw3.h>
#include <string.h>
@@ -25,6 +26,7 @@ int main() {
model_handle backpack_handle =
model_load_obj(core, "assets/models/obj/backpack/backpack.obj", true);
model* backpack = &core->models->data[backpack_handle.raw];
+ assert(backpack->meshes->data->is_skinned == false);
// 2. upload vertex data to gpu
model_upload_meshes(&core->renderer, backpack);
// 3. create a camera
@@ -53,7 +55,7 @@ int main() {
memcpy(&our_scene.point_lights, &point_lights, sizeof(point_light[4]));
// --- Enter Main loop
- while (!glfwWindowShouldClose(core->renderer.window)) {
+ while (!should_exit(core)) {
input_update(&core->input);
threadpool_process_results(&core->threadpool, 1);
diff --git a/examples/property_animation/ex_property_animation.c b/examples/property_animation/ex_property_animation.c
new file mode 100644
index 0000000..c548db4
--- /dev/null
+++ b/examples/property_animation/ex_property_animation.c
@@ -0,0 +1,103 @@
+#include <glfw3.h>
+
+#include "../example_scene.h"
+#include "animation.h"
+#include "camera.h"
+#include "core.h"
+#include "input.h"
+#include "keys.h"
+#include "log.h"
+#include "maths.h"
+#include "maths_types.h"
+#include "primitives.h"
+#include "render.h"
+#include "render_backend.h"
+#include "render_types.h"
+
+typedef struct game_state {
+ camera camera;
+ vec3 camera_euler;
+ bool first_mouse_update; // so the camera doesnt lurch when you run the first
+ // process_camera_rotation
+} game_state;
+
+void update_camera_rotation(input_state* input, game_state* game, camera* cam);
+
+int main() {
+ double currentFrame = glfwGetTime();
+ double lastFrame = currentFrame;
+ double deltaTime;
+
+ core* core = core_bringup();
+
+ model_handle animated_cube_handle =
+ model_load_gltf(core, "assets/models/gltf/AnimatedCube/glTF/AnimatedCube.gltf", false);
+ model* cube = &core->models->data[animated_cube_handle.raw];
+ model_upload_meshes(&core->renderer, cube);
+
+ scene our_scene = make_default_scene();
+
+ vec3 cam_pos = vec3_create(5, 5, 5);
+ game_state game = {
+ .camera = camera_create(cam_pos, vec3_negate(cam_pos), VEC3_Y, deg_to_rad(45.0)),
+ .camera_euler = vec3_create(90, 0, 0),
+ .first_mouse_update = true,
+ };
+
+ print_vec3(game.camera.front);
+
+ // Main loop
+ const f32 camera_lateral_speed = 0.2;
+ const f32 camera_zoom_speed = 0.15;
+
+ // animation
+ animation_clip track = cube->animations->data[0];
+ f64 total_time = 0.0;
+
+ while (!should_exit(core)) {
+ input_update(&core->input);
+
+ currentFrame = glfwGetTime();
+ deltaTime = currentFrame - lastFrame;
+ lastFrame = currentFrame;
+ total_time += deltaTime;
+ printf("delta time %f\n", deltaTime);
+ f64 t = fmod(total_time, 1.0);
+ INFO("Total time: %f", t);
+
+ vec3 translation = VEC3_ZERO;
+ if (key_is_pressed(KEYCODE_W) || key_is_pressed(KEYCODE_KEY_UP)) {
+ translation = vec3_mult(game.camera.front, camera_zoom_speed);
+ } else if (key_is_pressed(KEYCODE_S) || key_is_pressed(KEYCODE_KEY_DOWN)) {
+ translation = vec3_mult(game.camera.front, -camera_zoom_speed);
+ } else if (key_is_pressed(KEYCODE_A) || key_is_pressed(KEYCODE_KEY_LEFT)) {
+ vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up));
+ translation = vec3_mult(lateral, -camera_lateral_speed);
+ } else if (key_is_pressed(KEYCODE_D) || key_is_pressed(KEYCODE_KEY_RIGHT)) {
+ vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up));
+ translation = vec3_mult(lateral, camera_lateral_speed);
+ }
+ game.camera.position = vec3_add(game.camera.position, translation);
+
+ // UNUSED: threadpool_process_results(&core->threadpool, 1);
+
+ render_frame_begin(&core->renderer);
+
+ quat rot = animation_sample(track.rotation, t).rotation;
+ // quat rot = quat_ident();
+ transform tf = transform_create(VEC3_ZERO, rot, 1.0);
+ mat4 model_tf = transform_to_mat(&tf);
+ draw_model(&core->renderer, &game.camera, cube, &model_tf, &our_scene);
+
+ // gfx_backend_draw_frame(&core->renderer, &game.camera, model, NULL);
+
+ render_frame_end(&core->renderer);
+ }
+
+ INFO("Shutting down");
+ model_destroy(cube);
+
+ core_shutdown(core);
+
+ return 0;
+}
diff --git a/examples/skinned_animation/ex_skinned_animation.c b/examples/skinned_animation/ex_skinned_animation.c
new file mode 100644
index 0000000..c31e93c
--- /dev/null
+++ b/examples/skinned_animation/ex_skinned_animation.c
@@ -0,0 +1,122 @@
+#include <assert.h>
+#include <glfw3.h>
+
+#include "../example_scene.h"
+#include "animation.h"
+#include "camera.h"
+#include "core.h"
+#include "input.h"
+#include "keys.h"
+#include "log.h"
+#include "maths.h"
+#include "maths_types.h"
+#include "primitives.h"
+#include "render.h"
+#include "render_backend.h"
+#include "render_types.h"
+
+typedef struct game_state {
+ camera camera;
+ vec3 camera_euler;
+ bool first_mouse_update; // so the camera doesnt lurch when you run the first
+ // process_camera_rotation
+} game_state;
+
+void update_camera_rotation(input_state* input, game_state* game, camera* cam);
+
+int main() {
+ double currentFrame = glfwGetTime();
+ double lastFrame = currentFrame;
+ double deltaTime;
+
+ core* core = core_bringup();
+
+ model_handle handle =
+ model_load_gltf(core, "assets/models/gltf/SimpleSkin/glTF/SimpleSkin.gltf", false);
+
+ model* simple_skin = &core->models->data[handle.raw];
+
+ // Okay, right here we've loaded the model. let's assert some facts
+ assert(simple_skin->animations->len == 1);
+ assert(simple_skin->animations->data[0].rotation != NULL);
+ assert(simple_skin->animations->data[0].translation == NULL);
+ assert(simple_skin->animations->data[0].scale == NULL);
+
+ mesh* m = &simple_skin->meshes->data[0];
+ assert(m->is_skinned);
+ assert(m->bones->len == 2); // 1 root and 1 extra joint
+
+ // assert(false);
+
+ model_upload_meshes(&core->renderer, simple_skin);
+
+ scene our_scene = make_default_scene();
+
+ vec3 cam_pos = vec3_create(0, 5, -8);
+ game_state game = {
+ .camera = camera_create(cam_pos, vec3_negate(cam_pos), VEC3_Y, deg_to_rad(45.0)),
+ .camera_euler = vec3_create(90, 0, 0),
+ .first_mouse_update = true,
+ };
+
+ print_vec3(game.camera.front);
+
+ // Main loop
+ const f32 camera_lateral_speed = 0.2;
+ const f32 camera_zoom_speed = 0.10;
+
+ // animation
+ animation_clip track = simple_skin->animations->data[0];
+ f64 total_time = 0.0;
+
+ while (!should_exit(core)) {
+ input_update(&core->input);
+
+ currentFrame = glfwGetTime();
+ deltaTime = currentFrame - lastFrame;
+ lastFrame = currentFrame;
+ total_time += deltaTime;
+ // printf("delta time %f\n", deltaTime);
+ f64 t = fmod(total_time, track.rotation->max);
+ // INFO("Total time: %f", t);
+
+ vec3 translation = VEC3_ZERO;
+ if (key_is_pressed(KEYCODE_W)) {
+ translation = vec3_mult(game.camera.front, camera_zoom_speed);
+ } else if (key_is_pressed(KEYCODE_KEY_UP)) {
+ translation = vec3_mult(game.camera.up, camera_lateral_speed);
+ } else if (key_is_pressed(KEYCODE_KEY_DOWN)) {
+ translation = vec3_mult(game.camera.up, -camera_lateral_speed);
+ } else if (key_is_pressed(KEYCODE_S) || key_is_pressed(KEYCODE_KEY_DOWN)) {
+ translation = vec3_mult(game.camera.front, -camera_zoom_speed);
+ } else if (key_is_pressed(KEYCODE_A) || key_is_pressed(KEYCODE_KEY_LEFT)) {
+ vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up));
+ translation = vec3_mult(lateral, -camera_lateral_speed);
+ } else if (key_is_pressed(KEYCODE_D) || key_is_pressed(KEYCODE_KEY_RIGHT)) {
+ vec3 lateral = vec3_normalise(vec3_cross(game.camera.front, game.camera.up));
+ translation = vec3_mult(lateral, camera_lateral_speed);
+ }
+ game.camera.position = vec3_add(game.camera.position, translation);
+
+ render_frame_begin(&core->renderer);
+
+ // bone rotation
+ quat rot = animation_sample(track.rotation, t).rotation;
+
+ m->bones->data[1].transform_components.rotation = rot;
+
+ // quat rot = quat_ident();
+ transform tf = transform_create(VEC3_ZERO, quat_ident(), 1.0);
+
+ draw_skinned_model(&core->renderer, &game.camera, simple_skin, tf, &our_scene);
+
+ render_frame_end(&core->renderer);
+ }
+
+ INFO("Shutting down");
+ model_destroy(simple_skin);
+
+ core_shutdown(core);
+
+ return 0;
+}
diff --git a/examples/transforms/ex_transforms.c b/examples/transforms/ex_transforms.c
index 689c49d..fc225b4 100644
--- a/examples/transforms/ex_transforms.c
+++ b/examples/transforms/ex_transforms.c
@@ -5,7 +5,7 @@
#include "maths_types.h"
#include "mem.h"
#include "render.h"
-#include "render_types.h"
+// #include "render_types.h"
#include "transform_hierarchy.h"
const vec3 pointlight_positions[4] = {
diff --git a/examples/triangle/ex_triangle.c b/examples/triangle/ex_triangle.c
new file mode 100644
index 0000000..d57e224
--- /dev/null
+++ b/examples/triangle/ex_triangle.c
@@ -0,0 +1,104 @@
+#include <glfw3.h>
+
+#include "backend_vulkan.h"
+#include "buf.h"
+#include "camera.h"
+#include "core.h"
+#include "file.h"
+#include "log.h"
+#include "maths.h"
+#include "mem.h"
+#include "ral.h"
+#include "ral_types.h"
+#include "render.h"
+#include "render_types.h"
+
+extern core g_core;
+
+const custom_vertex vertices[] = {
+ (custom_vertex){ .pos = vec2(-0.5, -0.5), .color = vec3(1.0, 1.0, 1.0) },
+ (custom_vertex){ .pos = vec2(0.5, -0.5), .color = vec3(1.0, 0.0, 0.0) },
+ (custom_vertex){ .pos = vec2(-0.5, 0.5), .color = vec3(0.0, 0.0, 1.0) },
+ (custom_vertex){ .pos = vec2(0.5, 0.5), .color = vec3(0.0, 1.0, 0.0) },
+};
+const u32 indices[] = { 2, 1, 0, 1, 2, 3 };
+
+int main() {
+ core_bringup();
+ arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024);
+
+ vertex_description vertex_input = { .use_full_vertex_size = false };
+ vertex_input.debug_label = "Hello";
+ vertex_desc_add(&vertex_input, "inPos", ATTR_F32x2);
+ vertex_desc_add(&vertex_input, "inColor", ATTR_F32x3);
+
+ gpu_renderpass_desc pass_description = {};
+ gpu_renderpass* renderpass = gpu_renderpass_create(&pass_description);
+
+ str8 vert_path = str8lit("build/linux/x86_64/debug/triangle.vert.spv");
+ str8 frag_path = str8lit("build/linux/x86_64/debug/triangle.frag.spv");
+ str8_opt vertex_shader = str8_from_file(&scratch, vert_path);
+ str8_opt fragment_shader = str8_from_file(&scratch, frag_path);
+ if (!vertex_shader.has_value || !fragment_shader.has_value) {
+ ERROR_EXIT("Failed to load shaders from disk")
+ }
+
+ struct graphics_pipeline_desc pipeline_description = {
+ .debug_name = "Basic Pipeline",
+ .vertex_desc = vertex_input,
+ // .data_layouts = {0},
+ // .data_layouts_count = 0,
+ .vs = { .debug_name = "Triangle Vertex Shader",
+ .filepath = vert_path,
+ .code = vertex_shader.contents,
+ .is_spirv = true },
+ .fs = { .debug_name = "Triangle Fragment Shader",
+ .filepath = frag_path,
+ .code = fragment_shader.contents,
+ .is_spirv = true },
+ .renderpass = renderpass,
+ .wireframe = false,
+ .depth_test = false
+ };
+ gpu_pipeline* gfx_pipeline = gpu_graphics_pipeline_create(pipeline_description);
+
+ // Load triangle vertex and index data
+ buffer_handle triangle_vert_buf =
+ gpu_buffer_create(4 * sizeof(vertex), CEL_BUFFER_VERTEX, CEL_BUFFER_FLAG_GPU, vertices);
+
+ buffer_handle triangle_index_buf =
+ gpu_buffer_create(sizeof(indices), CEL_BUFFER_INDEX, CEL_BUFFER_FLAG_GPU, indices);
+
+ // Main loop
+ while (!should_exit()) {
+ input_update(&g_core.input);
+
+ if (!gpu_backend_begin_frame()) {
+ continue;
+ }
+ gpu_cmd_encoder* enc = gpu_get_default_cmd_encoder();
+ // Begin recording
+ gpu_cmd_encoder_begin(*enc);
+ gpu_cmd_encoder_begin_render(enc, renderpass);
+ encode_bind_pipeline(enc, PIPELINE_GRAPHICS, gfx_pipeline);
+ encode_set_default_settings(enc);
+
+ // Record draw calls
+ encode_set_vertex_buffer(enc, triangle_vert_buf);
+ encode_set_index_buffer(enc, triangle_index_buf);
+ encode_draw_indexed(enc, 6);
+
+ // End recording
+ gpu_cmd_encoder_end_render(enc);
+
+ gpu_cmd_buffer buf = gpu_cmd_encoder_finish(
+ enc); // Command buffer is no longer recording and is ready to submit
+ // Submit
+ gpu_queue_submit(&buf);
+ gpu_backend_end_frame();
+ }
+
+ renderer_shutdown(&g_core.renderer);
+
+ return 0;
+}