From 136853328a28642486b04d578a41ae24312fe008 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 1 Nov 2026 17:38:22 +0000 Subject: [PATCH] Render texture and fix camera target --- src/gpu/gpu.h | 2 +- src/gpu/vulkan/vk_gpu.c | 4 ++ src/main.c | 141 ++++++++++++++++++++------------------- src/shaders/shader.slang | 13 ++-- 4 files changed, 88 insertions(+), 72 deletions(-) diff --git a/src/gpu/gpu.h b/src/gpu/gpu.h index 34051b1..fa36486 100644 --- a/src/gpu/gpu.h +++ b/src/gpu/gpu.h @@ -355,8 +355,8 @@ typedef struct GpuBufferCreateRequest { } GpuBufferCreateRequest; typedef struct GpuBufferFlushRequest { - GpuDevice *device; GpuBuffer buffer; + GpuDevice *device; u64 offset; u64 size; } GpuBufferFlushRequest; diff --git a/src/gpu/vulkan/vk_gpu.c b/src/gpu/vulkan/vk_gpu.c index b40a9fe..df0016d 100644 --- a/src/gpu/vulkan/vk_gpu.c +++ b/src/gpu/vulkan/vk_gpu.c @@ -321,6 +321,8 @@ wp_intern u32 calcMaxMipLevelsForSize(ivec3s size); GpuInstance *gpuInit(const WpAllocator *allocator, GpuInitRequest request) { assertWithLogger(volkInitialize() == VK_SUCCESS, &logger, "Failed to initialise volk"); + stbi_set_flip_vertically_on_load(true); + VpProfileProperties profile = { .profileName = VP_TEST_WINDOW_RENDERER_NAME, .specVersion = VP_TEST_WINDOW_RENDERER_SPEC_VERSION, @@ -859,6 +861,8 @@ GpuSampler *gpuCreateSampler(const WpAllocator *allocator, GpuSamplerCreateReque wpLogDebug(&logger, wpStr8Lit("Created Vulkan sampler")); + output->device = request.device; + return output; } diff --git a/src/main.c b/src/main.c index 2f18035..e71a6c5 100644 --- a/src/main.c +++ b/src/main.c @@ -20,7 +20,7 @@ enum Errors { typedef struct Vertex { vec3s position; vec3s color; - // vec2s uv; + vec2s uv; } Vertex; typedef Vertex *VertexArray; @@ -33,7 +33,6 @@ typedef ShaderData *ShaderDataArray; typedef struct Camera { vec3s position; - vec3s target; vec3s up; } Camera; @@ -47,20 +46,24 @@ typedef struct Projection { wp_intern const VertexArray vertices = wpArray( Vertex, (Vertex){ - .position = (vec3s){ .x = -0.5f, .y = -0.5f, .z = 0.0f }, - .color = (vec3s){ .r = 1.0f, .g = 0.0f, .b = 0.0f }, + .position = (vec3s){ .x = -0.5f, .y = -0.5f, .z = 0.0f }, + .color = (vec3s){ .r = 1.0f, .g = 1.0f, .b = 1.0f }, + .uv = (vec2s){ .x = 0.0f, .y = 0.0f }, }, (Vertex){ .position = (vec3s){ .x = -0.5f, .y = 0.5f, .z = 0.0f }, - .color = (vec3s){ .r = 0.0f, .g = 1.0f, .b = 0.0f }, + .color = (vec3s){ .r = 1.0f, .g = 1.0f, .b = 1.0f }, + .uv = (vec2s){ .x = 0.0f, .y = 1.0f }, }, (Vertex){ .position = (vec3s){ .x = 0.5f, .y = -0.5f, .z = 0.0f }, - .color = (vec3s){ .r = 0.0f, .g = 0.0f, .b = 1.0f }, + .color = (vec3s){ .r = 1.0f, .g = 1.0f, .b = 1.0f }, + .uv = (vec2s){ .x = 1.0f, .y = 0.0f }, }, (Vertex){ .position = (vec3s){ .x = 0.5f, .y = 0.5f, .z = 0.0f }, .color = (vec3s){ .r = 1.0f, .g = 1.0f, .b = 1.0f }, + .uv = (vec2s){ .x = 1.0f, .y = 1.0f }, }, ); wp_intern const WpU16Array indices = wpArray( @@ -69,6 +72,7 @@ wp_intern const WpU16Array indices = wpArray( 1, 3, 2, ); +wp_intern mat4s calculateModelViewProjection(vec3s translation, Camera camera, Projection projection); wp_intern mat4s modelViewProjection(mat4s model, mat4s view, mat4s proj); i32 main(void) { @@ -171,6 +175,17 @@ i32 main(void) { }; GpuImage *texture = gpuLoadImageFromFile(&arena, &temp_arena, load_img_req); + GpuSamplerCreateRequest sampler_req = { + .device = device, + .min_filter = GPU_FILTER_LINEAR, + .mag_filter = GPU_FILTER_LINEAR, + .address_mode_u = GPU_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .address_mode_v = GPU_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .address_mode_w = GPU_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + .mipmap_mode = GPU_SAMPLER_MIPMAP_MODE_LINEAR, + }; + GpuSampler *sampler = gpuCreateSampler(&arena, sampler_req); + GpuShaderCreateRequest shader_request = { .device = device, .code = (void *)code, @@ -194,7 +209,6 @@ i32 main(void) { Camera camera = { .position = { .x = 0.0f, .y = 0.0f, .z = 2.0f }, - .target = { 0 }, .up = { 0.0f, 1.0f, 0.0f }, }; Projection projection = { @@ -207,18 +221,10 @@ i32 main(void) { ShaderDataArray data = wpArray( ShaderData, (ShaderData){ - .mvp = modelViewProjection( - glms_translate(glms_mat4_identity(), translations[0]), - glms_lookat(camera.position, camera.target, camera.up), - glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far) - ), + .mvp = calculateModelViewProjection(translations[0], camera, projection), }, (ShaderData){ - .mvp = modelViewProjection( - glms_translate(glms_mat4_identity(), translations[1]), - glms_lookat(camera.position, camera.target, camera.up), - glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far) - ), + .mvp = calculateModelViewProjection(translations[1], camera, projection), }, ); memcpy(shader_data.cpu_mapping, data, wpArrayItemSize(data) * wpArrayCount(data)); @@ -226,7 +232,8 @@ i32 main(void) { GpuDescriptorPoolSizeArray pool_sizes = wpArray( GpuDescriptorPoolSize, - (GpuDescriptorPoolSize){ .type = GPU_DESCRIPTOR_TYPE_STORAGE_BUFFER, .count = 1 } + (GpuDescriptorPoolSize){ .type = GPU_DESCRIPTOR_TYPE_STORAGE_BUFFER, .count = 1 }, + (GpuDescriptorPoolSize){ .type = GPU_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .count = 1 } ); GpuDescriptorPoolCreateRequest desc_pool_req = { .descriptor_pool_sizes = pool_sizes, @@ -242,6 +249,12 @@ i32 main(void) { .type = GPU_DESCRIPTOR_TYPE_STORAGE_BUFFER, .descriptor_count = 1, .stages = GPU_SHADER_STAGE_VERTEX, + }, + (GpuDescriptorSetBinding){ + .binding = 1, + .type = GPU_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptor_count = 1, + .stages = GPU_SHADER_STAGE_FRAGMENT, } ); GpuDescriptorSetLayoutCreateRequest desc_set_layout_req = { @@ -259,14 +272,28 @@ i32 main(void) { GpuDescriptorSetWriteInfo shader_data_write_info = { .set = descriptor_sets[0], .descriptor_type = GPU_DESCRIPTOR_TYPE_STORAGE_BUFFER, + .dst_binding = 0, .buffer_infos = wpArray( GpuDescriptorBufferInfo, (GpuDescriptorBufferInfo){ .buffer = &shader_data }, ), }; + GpuDescriptorSetWriteInfo texture_write_info = { + .set = descriptor_sets[0], + .descriptor_type = GPU_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .dst_binding = 1, + .image_infos = wpArray( + GpuDescriptorImageInfo, + (GpuDescriptorImageInfo){ + .image = texture, + .image_layout = GPU_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, + .sampler = sampler, + } + ), + }; GpuDescriptorSetWriteRequest desc_set_req = { .device = device, - .write_infos = wpArray(GpuDescriptorSetWriteInfo, shader_data_write_info), + .write_infos = wpArray(GpuDescriptorSetWriteInfo, shader_data_write_info, texture_write_info), }; gpuWriteDescriptorSets(&temp_arena, desc_set_req); @@ -295,12 +322,12 @@ i32 main(void) { .offset = offsetof(Vertex, color), .format = GPU_FORMAT_R32G32B32_SFLOAT, }, - // (GpuVertexInputAttribute){ - // .location = 2, - // .binding = 0, - // .offset = offsetof(Vertex, uv), - // .format = GPU_FORMAT_R32G32_SFLOAT, - // }, + (GpuVertexInputAttribute){ + .location = 2, + .binding = 0, + .offset = offsetof(Vertex, uv), + .format = GPU_FORMAT_R32G32_SFLOAT, + }, ); GpuPipelineVertexInputStateInfo vert_info = { .bindings = wpArray(GpuVertexInputBinding, vert_binding), @@ -376,63 +403,29 @@ i32 main(void) { if (windowIsKeyPressed(KEYBOARD_KEY_UP)) { camera.position.z -= 0.01f; - data[0].mvp = modelViewProjection( - glms_translate(glms_mat4_identity(), translations[0]), - glms_lookat(camera.position, camera.target, camera.up), - glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far) - ); - data[1].mvp = modelViewProjection( - glms_translate(glms_mat4_identity(), translations[1]), - glms_lookat(camera.position, camera.target, camera.up), - glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far) - ); + data[0].mvp = calculateModelViewProjection(translations[0], camera, projection); + data[1].mvp = calculateModelViewProjection(translations[1], camera, projection); memcpy(shader_data.cpu_mapping, data, wpArrayItemSize(data) * wpArrayCount(data)); gpuFlushBuffer((GpuBufferFlushRequest){ .device = device, .buffer = shader_data }); } if (windowIsKeyPressed(KEYBOARD_KEY_DOWN)) { camera.position.z += 0.01f; - data[0].mvp = modelViewProjection( - glms_translate(glms_mat4_identity(), translations[0]), - glms_lookat(camera.position, camera.target, camera.up), - glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far) - ); - data[1].mvp = modelViewProjection( - glms_translate(glms_mat4_identity(), translations[1]), - glms_lookat(camera.position, camera.target, camera.up), - glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far) - ); + data[0].mvp = calculateModelViewProjection(translations[0], camera, projection); + data[1].mvp = calculateModelViewProjection(translations[1], camera, projection); memcpy(shader_data.cpu_mapping, data, wpArrayItemSize(data) * wpArrayCount(data)); gpuFlushBuffer((GpuBufferFlushRequest){ .device = device, .buffer = shader_data }); } if (windowIsKeyPressed(KEYBOARD_KEY_RIGHT)) { camera.position.x += 0.01f; - camera.target.x += 0.01f; - data[0].mvp = modelViewProjection( - glms_translate(glms_mat4_identity(), translations[0]), - glms_lookat(camera.position, camera.target, camera.up), - glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far) - ); - data[1].mvp = modelViewProjection( - glms_translate(glms_mat4_identity(), translations[1]), - glms_lookat(camera.position, camera.target, camera.up), - glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far) - ); + data[0].mvp = calculateModelViewProjection(translations[0], camera, projection); + data[1].mvp = calculateModelViewProjection(translations[1], camera, projection); memcpy(shader_data.cpu_mapping, data, wpArrayItemSize(data) * wpArrayCount(data)); gpuFlushBuffer((GpuBufferFlushRequest){ .device = device, .buffer = shader_data }); } if (windowIsKeyPressed(KEYBOARD_KEY_LEFT)) { camera.position.x -= 0.01f; - camera.target.x -= 0.01f; - data[0].mvp = modelViewProjection( - glms_translate(glms_mat4_identity(), translations[0]), - glms_lookat(camera.position, camera.target, camera.up), - glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far) - ); - data[1].mvp = modelViewProjection( - glms_translate(glms_mat4_identity(), translations[1]), - glms_lookat(camera.position, camera.target, camera.up), - glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far) - ); + data[0].mvp = calculateModelViewProjection(translations[0], camera, projection); + data[1].mvp = calculateModelViewProjection(translations[1], camera, projection); memcpy(shader_data.cpu_mapping, data, wpArrayItemSize(data) * wpArrayCount(data)); gpuFlushBuffer((GpuBufferFlushRequest){ .device = device, .buffer = shader_data }); } @@ -626,6 +619,7 @@ i32 main(void) { gpuDestroyDescriptorPool(desc_pool); gpuDestroyBuffer(&shader_data); gpuDestroyShader(shader); + gpuDestroySampler(sampler); gpuDestroyImage(texture); gpuDestroyCommandPool(pool); gpuDestroyBuffer(&vert_idx_buffer); @@ -645,6 +639,19 @@ i32 main(void) { return ERROR_NONE; } +wp_intern mat4s calculateModelViewProjection(vec3s translation, Camera camera, Projection projection) { + vec3s target = { + .x = camera.position.x, + .y = camera.position.y, + .z = camera.position.z - 2.0f + }; + return modelViewProjection( + glms_translate(glms_mat4_identity(), translation), + glms_lookat(camera.position, target, camera.up), + glms_perspective(glm_rad(projection.fov_deg), projection.aspect, projection.near, projection.far) + ); +} + wp_intern mat4s modelViewProjection(mat4s model, mat4s view, mat4s proj) { // Matrix to flip the Y-axis since in Vulkan Y points down mat4s clip = { diff --git a/src/shaders/shader.slang b/src/shaders/shader.slang index 3481d5b..2fba6a2 100644 --- a/src/shaders/shader.slang +++ b/src/shaders/shader.slang @@ -1,7 +1,7 @@ struct VSInput { float3 Pos; float3 Color; - // float2 Uv; + float2 Uv; }; struct ShaderData { @@ -9,20 +9,25 @@ struct ShaderData { }; StructuredBuffer data; +Sampler2D texture; + struct VertexOutput { - float3 Color; float4 sv_position : SV_Position; + float3 Color; + float2 Uv; }; [shader("vertex")] VertexOutput vertMain(VSInput input, uint idx: SV_InstanceID) { VertexOutput output; - output.Color = input.Color; output.sv_position = mul(data[idx].mvp, float4(input.Pos, 1.0)); + output.Color = input.Color; + output.Uv = input.Uv; return output; } [shader("fragment")] float4 fragMain(VertexOutput inVert) : SV_Target { - return float4(inVert.Color, 1.0); + float4 color = texture.Sample(inVert.Uv) * float4(inVert.Color, 1.0f); + return color; }