From 3701ab66ddee42b30d9fbc5c96942465c89d36ef Mon Sep 17 00:00:00 2001 From: nefrace Date: Fri, 9 May 2025 20:11:45 +0300 Subject: [PATCH] Two colorful triangles --- .gitignore | 2 + build.sh | 17 +++ shaders/src/shader.glsl.frag | 9 ++ shaders/src/shader.glsl.vert | 16 +++ src/main.odin | 195 +++++++++++++++++++++++++++++++++++ 5 files changed, 239 insertions(+) create mode 100644 .gitignore create mode 100755 build.sh create mode 100644 shaders/src/shader.glsl.frag create mode 100644 shaders/src/shader.glsl.vert create mode 100644 src/main.odin diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f4dcf56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +sdlgpu +shaders/*.spv.* diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..7eb39a6 --- /dev/null +++ b/build.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -e +set -x + +for i in shaders/src/*; do + filename=$(basename $i) + basename=$(printf $filename | cut -d. -f1) + ext=$(printf $filename | cut -d. -f3) + glslc "$i" -o shaders/${basename}.spv.${ext} +done +# glslc shader.glsl.vert -o shader.spv.vert +# glslc shader.glsl.frag -o shader.spv.frag + +odin build src -debug -out:sdlgpu + +./sdlgpu diff --git a/shaders/src/shader.glsl.frag b/shaders/src/shader.glsl.frag new file mode 100644 index 0000000..59318f4 --- /dev/null +++ b/shaders/src/shader.glsl.frag @@ -0,0 +1,9 @@ +#version 460 + + +layout(location=0) in vec3 color; +layout(location=0) out vec4 frag_color; + +void main() { + frag_color = vec4(color, 1); +} diff --git a/shaders/src/shader.glsl.vert b/shaders/src/shader.glsl.vert new file mode 100644 index 0000000..6da049c --- /dev/null +++ b/shaders/src/shader.glsl.vert @@ -0,0 +1,16 @@ +#version 460 + +layout(set=1, binding=0) uniform UBO { + mat4 mvp; +}; + +layout(location=0) in vec3 position; +layout(location=1) in vec3 color; + +layout(location=0) out vec3 out_color; + +void main() { + gl_Position = mvp * vec4(position, 1); + out_color = color; +} + diff --git a/src/main.odin b/src/main.odin new file mode 100644 index 0000000..0868982 --- /dev/null +++ b/src/main.odin @@ -0,0 +1,195 @@ +package main + +import "core:log" +import "core:math/linalg" +import "core:mem" +import sdl "vendor:sdl3" + +frag_shader_code := #load("../shaders/shader.spv.frag") +vert_shader_code := #load("../shaders/shader.spv.vert") + +main :: proc() { + context.logger = log.create_console_logger() + + sdl.SetLogPriorities(.VERBOSE) + + ok := sdl.Init({.VIDEO});assert(ok) + + window := sdl.CreateWindow("hi sdl", 800, 400, {});assert(window != nil) + + gpu := sdl.CreateGPUDevice({.SPIRV}, true, nil);assert(gpu != nil) + + ok = sdl.ClaimWindowForGPUDevice(gpu, window);assert(ok) + + vert_shader := load_shader(gpu, vert_shader_code, .VERTEX, 1) + frag_shader := load_shader(gpu, frag_shader_code, .FRAGMENT, 0) + + Vec3 :: [3]f32 + Vertex :: struct { + pos: Vec3, + col: Vec3, + } + vertices := []Vertex { + {{-0.5, 0, 0}, {1, 0, 0}}, + {{0, 1.0, 0}, {0, 1, 0}}, + {{0.5, 0, 0}, {0, 0, 1}}, + {{0.5, 0, 0}, {1, 1, 0}}, + {{0, -0.5, 0}, {0, 1, 1}}, + {{-0.5, -0, 0}, {1, 0, 1}}, + } + vertices_byte_size := len(vertices) * size_of(vertices[0]) + vertex_attrs := []sdl.GPUVertexAttribute { + {location = 0, format = .FLOAT3, offset = 0}, // Position + {location = 1, format = .FLOAT3, offset = size_of(Vec3)}, // Color + } + vertex_buf := sdl.CreateGPUBuffer( + gpu, + sdl.GPUBufferCreateInfo{usage = {.VERTEX}, size = u32(vertices_byte_size)}, + ) + + transfer_buf := sdl.CreateGPUTransferBuffer( + gpu, + sdl.GPUTransferBufferCreateInfo{usage = .UPLOAD, size = u32(vertices_byte_size)}, + ) + { // Copy verticies to the transfer buffer + + transfer_mem := sdl.MapGPUTransferBuffer( + gpu, + transfer_buf, + false, + );assert(transfer_mem != nil) + defer sdl.UnmapGPUTransferBuffer(gpu, transfer_buf) + + mem.copy(transfer_mem, raw_data(vertices), vertices_byte_size) + } + + { // Upload buffer to gpu + copy_cmd_buf := sdl.AcquireGPUCommandBuffer(gpu) + defer {ok = sdl.SubmitGPUCommandBuffer(copy_cmd_buf);assert(ok)} + copy_pass := sdl.BeginGPUCopyPass(copy_cmd_buf) + defer sdl.EndGPUCopyPass(copy_pass) + + sdl.UploadToGPUBuffer( + copy_pass, + {transfer_buffer = transfer_buf}, + {buffer = vertex_buf, size = u32(vertices_byte_size)}, + false, + ) + } + sdl.ReleaseGPUTransferBuffer(gpu, transfer_buf) + + pipeline := sdl.CreateGPUGraphicsPipeline( + gpu, + { + vertex_shader = vert_shader, + fragment_shader = frag_shader, + vertex_input_state = { + num_vertex_buffers = 1, + vertex_buffer_descriptions = &sdl.GPUVertexBufferDescription { + slot = 0, + pitch = size_of(Vertex), + }, + num_vertex_attributes = u32(len(vertex_attrs)), + vertex_attributes = raw_data(vertex_attrs), + }, + primitive_type = .TRIANGLELIST, + target_info = { + num_color_targets = 1, + color_target_descriptions = &(sdl.GPUColorTargetDescription { + format = sdl.GetGPUSwapchainTextureFormat(gpu, window), + }), + }, + }, + ) + + sdl.ReleaseGPUShader(gpu, vert_shader) + sdl.ReleaseGPUShader(gpu, frag_shader) + + wsize := [2]i32{} + ok = sdl.GetWindowSize(window, &wsize.x, &wsize.y);assert(ok) + + rotation := f32(0) + + proj := linalg.matrix4_perspective_f32( + linalg.to_radians(f32(30)), + f32(wsize.x) / f32(wsize.y), + 0.001, + 1000, + ) + + UBO :: struct { + mvp: matrix[4, 4]f32, + } + + last_ticks := sdl.GetTicks() + + loop: for { + new_ticks := sdl.GetTicks() + delta := f32(new_ticks - last_ticks) / 1000 + last_ticks = new_ticks + ev: sdl.Event + for sdl.PollEvent(&ev) { + #partial switch ev.type { + case .QUIT: + break loop + case .KEY_DOWN: + if ev.key.scancode == .ESCAPE do break loop + } + } + cmd_buf := sdl.AcquireGPUCommandBuffer(gpu) + swaptex: ^sdl.GPUTexture + ok = sdl.WaitAndAcquireGPUSwapchainTexture(cmd_buf, window, &swaptex, nil, nil);assert(ok) + + rotation += 1 * delta + + model_mat := + linalg.matrix4_translate_f32({0, 0, -5}) * + linalg.matrix4_rotate_f32(rotation, {0, 1, 0}) + ubo := UBO{proj * model_mat} + + if swaptex != nil { + color_target := sdl.GPUColorTargetInfo { + texture = swaptex, + load_op = .CLEAR, + clear_color = {0.3, 0.1, 0.7, 1}, + store_op = .STORE, + } + + render_pass := sdl.BeginGPURenderPass(cmd_buf, &color_target, 1, nil) + sdl.BindGPUGraphicsPipeline(render_pass, pipeline) + sdl.BindGPUVertexBuffers( + render_pass, + 0, + &(sdl.GPUBufferBinding{buffer = vertex_buf}), + 1, + ) + sdl.PushGPUVertexUniformData(cmd_buf, 0, &ubo, size_of(ubo)) + sdl.DrawGPUPrimitives(render_pass, u32(len(vertices)), 1, 0, 0) + sdl.EndGPURenderPass(render_pass) + + } + + ok = sdl.SubmitGPUCommandBuffer(cmd_buf) + } +} + +load_shader :: proc( + gpu: ^sdl.GPUDevice, + code: []u8, + stage: sdl.GPUShaderStage, + num_uniforms: u32, +) -> ^sdl.GPUShader { + shader := sdl.CreateGPUShader( + gpu, + sdl.GPUShaderCreateInfo { + code_size = len(code), + code = raw_data(code), + entrypoint = "main", + format = {.SPIRV}, + stage = stage, + num_uniform_buffers = num_uniforms, + }, + ) + return shader +} +