diff options
author | omniscient <17525998+omnisci3nce@users.noreply.github.com> | 2024-10-26 20:26:40 +1100 |
---|---|---|
committer | omniscient <17525998+omnisci3nce@users.noreply.github.com> | 2024-10-26 20:26:40 +1100 |
commit | d900e713c8aebcc0a56eb594007de62584d470ea (patch) | |
tree | 048d619dc84d12fcc4fabd40af0cffcea5b92223 | |
parent | 6182860f1b1aba4128b4f66eda7977600e60d1a0 (diff) |
spin cube in place
-rw-r--r-- | assets/shaders/cube.metal | 2 | ||||
-rw-r--r-- | examples/cube.c | 88 | ||||
-rw-r--r-- | examples/triangle.c | 6 | ||||
-rw-r--r-- | include/celeritas.h | 20 | ||||
-rw-r--r-- | src/backend_mtl.m | 15 | ||||
-rw-r--r-- | src/geometry.c | 39 | ||||
-rw-r--r-- | src/maths.c | 142 |
7 files changed, 267 insertions, 45 deletions
diff --git a/assets/shaders/cube.metal b/assets/shaders/cube.metal index dc7ace1..93fa727 100644 --- a/assets/shaders/cube.metal +++ b/assets/shaders/cube.metal @@ -24,6 +24,8 @@ vertex VertexOut cubeVertexShader(uint vertexID [[vertex_id]], { VertexOut out; out.position = transformationData->perspectiveMatrix * transformationData->viewMatrix * transformationData->modelMatrix * vertexData[vertexID].position; + // out.position = transformationData->modelMatrix * vertexData[vertexID].position; + // out.position = vertexData[vertexID].position; out.textureCoordinate = vertexData[vertexID].texCoords; return out; }
\ No newline at end of file diff --git a/examples/cube.c b/examples/cube.c index 629a570..8fd85de 100644 --- a/examples/cube.c +++ b/examples/cube.c @@ -1,8 +1,10 @@ #include <celeritas.h> #include "glfw3.h" +camera cam; pipeline_handle draw_pipeline; buf_handle cube_vbuf; +buf_handle transform_buf; tex_handle texture; // transformation data @@ -12,24 +14,83 @@ typedef struct MVPData { mat4 projection; } MVPData; +// draw calls for a single frame void draw() { - // prepare data - mat4 translation_matrix = mat4_translation(vec3(0, 0, -1)); - - f32 angle_degrees = glfwGetTime() / 2.0 * 45.0; + // prepare model data + f32 angle_degrees = glfwGetTime() * 45.0; f32 angle = angle_degrees * PI / 180.0; - mat4 rotation_matrix = mat4_rotation(quat_from_axis_angle(VEC3_Y, angle, true)); + + // Move origin to cube center + vec3 center_offset = vec3(0.5, 0.5, 0.5); + mat4 to_center = mat4_translation(vec3_negate(center_offset)); + mat4 from_center = mat4_translation(center_offset); + + // Create rotation around Y axis + mat4 rotation = mat4_rotation(quat_from_axis_angle(VEC3_Y, angle, true)); + + // Print debug info for one frame + static bool printed = false; + if (!printed) { + printf("\nTo Center:\n"); + for (int i = 0; i < 16; i += 4) { + printf("%f %f %f %f\n", to_center.data[i], to_center.data[i + 1], to_center.data[i + 2], to_center.data[i + 3]); + } + printed = true; + } + + // Order: first move to center, then rotate, then move back + mat4 cube_transform = mat4_mult(from_center, mat4_mult(rotation, to_center)); + + mat4 move = mat4_translation(vec3(-0.5, -0.5, 0)); + cube_transform = mat4_mult(move, cube_transform); + + // prepare camera data + mat4 view, proj; + camera_view_proj(cam, 800, 600, &view, &proj); render_pass_desc d = {}; gpu_encoder* enc = ral_render_encoder(d); ral_encode_bind_pipeline(enc, draw_pipeline); + ral_set_default_settings(enc); + + MVPData mvp = { .model = cube_transform, .view = view, .projection = proj }; + + ral_buffer_upload_data(transform_buf, sizeof(MVPData), &mvp); + ral_bind_buffer(enc, transform_buf, 1); // bind the transform data buffer to binding 1 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); } +void test_matrix_mult() { + // Create a simple translation matrix (1 unit in x) + mat4 trans1 = mat4_translation(vec3(1, 0, 0)); + // Create another translation matrix (1 unit in y) + mat4 trans2 = mat4_translation(vec3(0, 1, 0)); + + printf("Matrix 1 (translate x+1):\n"); + for (int i = 0; i < 16; i += 4) { + printf("%f %f %f %f\n", trans1.data[i], trans1.data[i + 1], trans1.data[i + 2], trans1.data[i + 3]); + } + + printf("\nMatrix 2 (translate y+1):\n"); + for (int i = 0; i < 16; i += 4) { + printf("%f %f %f %f\n", trans2.data[i], trans2.data[i + 1], trans2.data[i + 2], trans2.data[i + 3]); + } + + mat4 result = mat4_mult(trans1, trans2); + + printf("\nResult matrix:\n"); + for (int i = 0; i < 16; i += 4) { + printf("%f %f %f %f\n", result.data[i], result.data[i + 1], result.data[i + 2], result.data[i + 3]); + } +} + int main() { + test_matrix_mult(); + // exit(1); + core_bringup("Celeritas Example: Triangle", NULL); // create rendering pipeline @@ -52,12 +113,29 @@ 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"); + + cam = (camera){ .position = vec3(0, 3, 5), .forwards = vec3(0, -3, -5), .fov = 45.0, .up = VEC3_Y }; + // create the cube geometry geometry cube = geo_cuboid(1.0, 1.0, 1.0); + // (debug) print out each vertex + size_t vertex_stride = cube.data_length / cube.n_vertices; + printf("Vertex stride %ld\n", vertex_stride); + for (int i = 0; i < cube.n_vertices; i++) { + static_3d_vert* vertex = (static_3d_vert*)(cube.vertex_data + vertex_stride * i); + print_static_3d_vert(vertex); + } + // upload vertex data to the gpu cube_vbuf = ral_buffer_create(64 * 36, cube.vertex_data); + // create a buffer to hold the MVP transforms + MVPData d = {}; + transform_buf = ral_buffer_create(sizeof(MVPData), &d); + while (!app_should_exit()) { glfwPollEvents(); diff --git a/examples/triangle.c b/examples/triangle.c index 7770fd1..8cf8dd2 100644 --- a/examples/triangle.c +++ b/examples/triangle.c @@ -2,12 +2,6 @@ #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} -// }; - typedef struct VertexData { vec4 position; vec2 texCoords; diff --git a/include/celeritas.h b/include/celeritas.h index 0b56bf5..979e8c4 100644 --- a/include/celeritas.h +++ b/include/celeritas.h @@ -264,7 +264,7 @@ 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_squared(vec3 a); inlined f32 vec3_len(vec3 a); inlined vec3 vec3_negate(vec3 a); inlined vec3 vec3_normalise(vec3 a); @@ -275,11 +275,13 @@ inlined vec4 vec4_create(f32 x, f32 y, f32 z, f32 w); // quaternion functions inlined quat quat_ident(); +quat quat_normalise(quat a); +f32 quat_dot(quat a, quat b); 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_ident(); mat4 mat4_translation(vec3 position); mat4 mat4_scale(vec3 scale); mat4 mat4_rotation(quat rotation); @@ -366,9 +368,18 @@ typedef struct vertex_desc { u32 padding; } vertex_desc; +typedef struct static_3d_vert { + vec4 pos; + vec4 norm; + vec2 uv; + vec2 pad; +} static_3d_vert; + // Some default formats vertex_desc static_3d_vertex_format(); +void print_static_3d_vert(static_3d_vert* vertex_data); + typedef enum shader_binding_type { BINDING_BYTES, BINDING_BUFFER, @@ -437,6 +448,7 @@ typedef struct render_pass_desc { // Resources buf_handle ral_buffer_create(u64 size, const void* data); void ral_buffer_destroy(buf_handle handle); +void ral_buffer_upload_data(buf_handle, u64 size, const void* data); tex_handle ral_texture_create(texture_desc desc, bool create_view, const void* data); tex_handle ral_texture_load_from_file(const char* filepath); @@ -460,9 +472,11 @@ void ral_compute_pipeline_destroy(compute_pipeline_handle handle); // Encoding void ral_encode_bind_pipeline(gpu_encoder* enc, pipeline_handle pipeline); +void ral_set_default_settings(gpu_encoder* enc); 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_bind_buffer(gpu_encoder* enc, buf_handle, u32 index); void ral_encode_draw_tris(gpu_encoder* enc, size_t start, size_t count); // Backend lifecycle @@ -491,6 +505,8 @@ DEFINE_HANDLE(model_handle); typedef struct geometry { vertex_desc vertex_format; void* vertex_data; + size_t data_length; + size_t n_vertices; bool has_indices; // When this is false indexed drawing is not used u32_darray* indices; } geometry; diff --git a/src/backend_mtl.m b/src/backend_mtl.m index 48e0ab0..2564ff0 100644 --- a/src/backend_mtl.m +++ b/src/backend_mtl.m @@ -128,6 +128,11 @@ buf_handle ral_buffer_create(u64 size, const void *data) { return handle; } +void ral_buffer_upload_data(buf_handle buf, u64 size, const void *data) { + metal_buffer* b = buf_pool_get(&ctx.bufpool, buf); + memcpy(b->id.contents, data, size); +} + 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); @@ -229,11 +234,21 @@ void ral_encode_bind_pipeline(gpu_encoder *enc, pipeline_handle pipeline) { [enc->cmd_encoder setRenderPipelineState:p->pso]; } +void ral_set_default_settings(gpu_encoder* enc) { + [enc->cmd_encoder setFrontFacingWinding:MTLWindingCounterClockwise]; + [enc->cmd_encoder setCullMode:MTLCullModeBack]; +} + void ral_encode_set_vertex_buf(gpu_encoder *enc, buf_handle vbuf) { metal_buffer* b = buf_pool_get(&ctx.bufpool, vbuf); [enc->cmd_encoder setVertexBuffer:b->id offset:0 atIndex:0 ]; } +void ral_bind_buffer(gpu_encoder *enc, buf_handle buf, u32 index) { + metal_buffer* b = buf_pool_get(&ctx.bufpool, buf); + [enc->cmd_encoder setVertexBuffer:b->id offset:0 atIndex:index ]; +} + 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]; diff --git a/src/geometry.c b/src/geometry.c index 05414d3..46bb058 100644 --- a/src/geometry.c +++ b/src/geometry.c @@ -1,12 +1,5 @@ #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"; @@ -19,18 +12,23 @@ vertex_desc static_3d_vertex_format() { return desc; } +void print_static_3d_vert(static_3d_vert* vertex_data) { + printf("Pos (%.2f, %.2f %.2f)\n", vertex_data->pos.x, vertex_data->pos.y, vertex_data->pos.z); +} + 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 }; + vec4 BACK_BOT_LEFT = (vec4){ 0, 0, 0, 1 }; + vec4 BACK_BOT_RIGHT = (vec4){ 1, 0, 0, 1 }; + vec4 BACK_TOP_LEFT = (vec4){ 0, 1, 0, 1 }; + vec4 BACK_TOP_RIGHT = (vec4){ 1, 1, 0, 1 }; + vec4 FRONT_BOT_LEFT = (vec4){ 0, 0, 1, 1 }; + vec4 FRONT_BOT_RIGHT = (vec4){ 1, 0, 1, 1 }; + vec4 FRONT_TOP_LEFT = (vec4){ 0, 1, 1, 1 }; + vec4 FRONT_TOP_RIGHT = (vec4){ 1, 1, 1, 1 }; // allocate the data - static_3d_vert* vertices = malloc(36 * 64); + size_t buffer_length = 36 * 64; + static_3d_vert* vertices = malloc(buffer_length); 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 } }; @@ -79,7 +77,10 @@ geometry geo_cuboid(f32 x_scale, f32 y_scale, f32 z_scale) { 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 - }; + return (geometry){ .vertex_format = static_3d_vertex_format(), + .vertex_data = vertices, + .data_length = buffer_length, + .n_vertices = 36, + .has_indices = false, + .indices = NULL }; }
\ No newline at end of file diff --git a/src/maths.c b/src/maths.c index c1fab2a..3a7ecf1 100644 --- a/src/maths.c +++ b/src/maths.c @@ -1,27 +1,116 @@ #include <celeritas.h> vec3 vec3_create(f32 x, f32 y, f32 z) { return (vec3){ x, y, z }; } - vec3 vec3_add(vec3 u, vec3 v) { return (vec3){ .x = u.x + v.x, .y = u.y + v.y, .z = u.z + v.z }; } +vec3 vec3_sub(vec3 a, vec3 b) { return (vec3){ a.x - b.x, a.y - b.y, a.z - b.z }; } +vec3 vec3_mult(vec3 a, f32 s) { return (vec3){ a.x * s, a.y * s, a.z * s }; } +vec3 vec3_div(vec3 a, f32 s) { return (vec3){ a.x / s, a.y / s, a.z / s }; } + +f32 vec3_len_squared(vec3 a) { return (a.x * a.x) + (a.y * a.y) + (a.z * a.z); } +f32 vec3_len(vec3 a) { return sqrtf(vec3_len_squared(a)); } +vec3 vec3_negate(vec3 a) { return (vec3){ -a.x, -a.y, -a.z }; } + +vec3 vec3_normalise(vec3 a) { + f32 length = vec3_len(a); + return vec3_div(a, length); +} + +f32 vec3_dot(vec3 a, vec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; } + +vec3 vec3_cross(vec3 a, vec3 b) { + return (vec3){ .x = a.y * b.z - a.z * b.y, .y = a.z * b.x - a.x * b.z, .z = a.x * b.y - a.y * b.x }; +} vec4 vec4_create(f32 x, f32 y, f32 z, f32 w) { return (vec4){ x, y, z, w }; } +f32 quat_dot(quat a, quat b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } + +quat quat_normalise(quat a) { + f32 length = sqrtf(quat_dot(a, a)); // same as len squared + + return (quat){ a.x / length, a.y / length, a.z / length, a.w / length }; +} + +quat quat_from_axis_angle(vec3 axis, f32 angle, bool normalize) { + const f32 half_angle = 0.5f * angle; + f32 s = sinf(half_angle); + f32 c = cosf(half_angle); + + quat q = (quat){ s * axis.x, s * axis.y, s * axis.z, c }; + if (normalize) { + return quat_normalise(q); + } + return q; +} + mat4 mat4_ident() { return (mat4){ .data = { 1.0, 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1.0 } }; } -mat4 mat4_mult(mat4 lhs, mat4 rhs) { +mat4 mat4_translation(vec3 position) { + mat4 out_matrix = mat4_ident(); + out_matrix.data[12] = position.x; + out_matrix.data[13] = position.y; + out_matrix.data[14] = position.z; + return out_matrix; +} + +mat4 mat4_scale(vec3 scale) { mat4 out_matrix = mat4_ident(); + out_matrix.data[0] = scale.x; + out_matrix.data[5] = scale.y; + out_matrix.data[10] = scale.z; + return out_matrix; +} + +// TODO: double check this +mat4 mat4_rotation(quat rotation) { + mat4 out_matrix = mat4_ident(); + quat n = quat_normalise(rotation); + + out_matrix.data[0] = 1.0f - 2.0f * n.y * n.y - 2.0f * n.z * n.z; + out_matrix.data[1] = 2.0f * n.x * n.y - 2.0f * n.z * n.w; + out_matrix.data[2] = 2.0f * n.x * n.z + 2.0f * n.y * n.w; + + out_matrix.data[4] = 2.0f * n.x * n.y + 2.0f * n.z * n.w; + out_matrix.data[5] = 1.0f - 2.0f * n.x * n.x - 2.0f * n.z * n.z; + out_matrix.data[6] = 2.0f * n.y * n.z - 2.0f * n.x * n.w; + + out_matrix.data[8] = 2.0f * n.x * n.z - 2.0f * n.y * n.w; + out_matrix.data[9] = 2.0f * n.y * n.z + 2.0f * n.x * n.w; + out_matrix.data[10] = 1.0f - 2.0f * n.x * n.x - 2.0f * n.y * n.y; + + return out_matrix; +} - const f32* m1_ptr = lhs.data; - const f32* m2_ptr = rhs.data; - f32* dst_ptr = out_matrix.data; +// mat4 mat4_mult(mat4 lhs, mat4 rhs) { +// mat4 out_matrix = mat4_ident(); - for (i32 i = 0; i < 4; ++i) { - for (i32 j = 0; j < 4; ++j) { - *dst_ptr = m1_ptr[0] * m2_ptr[0 + j] + m1_ptr[1] * m2_ptr[4 + j] + m1_ptr[2] * m2_ptr[8 + j] + - m1_ptr[3] * m2_ptr[12 + j]; - dst_ptr++; +// const f32* m1_ptr = lhs.data; +// const f32* m2_ptr = rhs.data; +// f32* dst_ptr = out_matrix.data; + +// for (i32 i = 0; i < 4; ++i) { +// for (i32 j = 0; j < 4; ++j) { +// *dst_ptr = m1_ptr[0] * m2_ptr[0 + j] + m1_ptr[1] * m2_ptr[4 + j] + m1_ptr[2] * m2_ptr[8 + j] + +// m1_ptr[3] * m2_ptr[12 + j]; +// dst_ptr++; +// } +// m1_ptr += 4; +// } + +// return out_matrix; +// } +mat4 mat4_mult(mat4 lhs, mat4 rhs) { + mat4 out_matrix = mat4_ident(); + + for (i32 row = 0; row < 4; row++) { + for (i32 col = 0; col < 4; col++) { + f32 sum = 0; + for (i32 i = 0; i < 4; i++) { + // column-major: first matrix columns × second matrix rows + sum += lhs.data[row + i * 4] * rhs.data[i + col * 4]; + } + out_matrix.data[row + col * 4] = sum; } - m1_ptr += 4; } return out_matrix; @@ -39,5 +128,32 @@ mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_z, f32 far_z) } mat4 mat4_look_at(vec3 position, vec3 target, vec3 up) { - // TODO -}
\ No newline at end of file + mat4 out_matrix; + vec3 z_axis; + z_axis.x = target.x - position.x; + z_axis.y = target.y - position.y; + z_axis.z = target.z - position.z; + + z_axis = vec3_normalise(z_axis); + vec3 x_axis = vec3_normalise(vec3_cross(z_axis, up)); + vec3 y_axis = vec3_cross(x_axis, z_axis); + + out_matrix.data[0] = x_axis.x; + out_matrix.data[1] = y_axis.x; + out_matrix.data[2] = -z_axis.x; + out_matrix.data[3] = 0; + out_matrix.data[4] = x_axis.y; + out_matrix.data[5] = y_axis.y; + out_matrix.data[6] = -z_axis.y; + out_matrix.data[7] = 0; + out_matrix.data[8] = x_axis.z; + out_matrix.data[9] = y_axis.z; + out_matrix.data[10] = -z_axis.z; + out_matrix.data[11] = 0; + out_matrix.data[12] = -vec3_dot(x_axis, position); + out_matrix.data[13] = -vec3_dot(y_axis, position); + out_matrix.data[14] = vec3_dot(z_axis, position); + out_matrix.data[15] = 1.0f; + + return out_matrix; +} |