neoragnarok/src/main.odin
2026-05-29 23:31:03 +02:00

203 lines
No EOL
5.4 KiB
Odin

package main
import "core:fmt"
import "core:os"
import sdl "vendor:sdl3"
import "rsmview"
import "gndview"
import "shared"
read_file_or_fail :: proc(path: string) -> []u8 {
file_bytes, err := os.read_entire_file(path, context.allocator)
if err != nil {
fmt.println("failed to read file:", path, "error:", err)
return nil
}
return file_bytes
}
create_gpu_shader :: proc(device: ^sdl.GPUDevice, path: string, stage: sdl.GPUShaderStage, num_samplers: u32) -> ^sdl.GPUShader {
bytes := read_file_or_fail(path)
if len(bytes) == 0 {
return nil
}
ci := sdl.GPUShaderCreateInfo{
code_size = uint(len(bytes)),
code = raw_data(bytes),
entrypoint = cstring("main"),
format = sdl.GPUShaderFormat{.SPIRV},
stage = stage,
num_samplers = num_samplers,
num_storage_textures = 0,
num_storage_buffers = 0,
num_uniform_buffers = 1,
props = 0,
}
shader := sdl.CreateGPUShader(device, ci)
delete(bytes)
if shader == nil {
fmt.println("CreateGPUShader failed:", path, "error:", sdl.GetError())
}
return shader
}
copy_data_to_gpu :: proc(
device: ^sdl.GPUDevice,
cmd: ^sdl.GPUCommandBuffer,
vertices: []shared.Vertex,
vert_buf: ^sdl.GPUBuffer,
indices: []u16,
ind_buf: ^sdl.GPUBuffer
) -> bool {
return true
}
GPU_Vertex :: struct {
position: [3]f32,
uv: [2]f32,
}
main :: proc() {
if !sdl.Init(sdl.INIT_VIDEO) {
fmt.println("SDL init failed:", sdl.GetError())
return
}
defer sdl.Quit()
window := sdl.CreateWindow("Odin + SDL3 GPU Cubes", 1280, 720, sdl.WINDOW_RESIZABLE)
if window == nil {
fmt.println("window create failed:", sdl.GetError())
return
}
defer sdl.DestroyWindow(window)
device := sdl.CreateGPUDevice(sdl.GPUShaderFormat{.SPIRV}, false, cstring("vulkan"))
if device == nil {
fmt.println("CreateGPUDevice failed:", sdl.GetError())
return
}
defer sdl.DestroyGPUDevice(device)
if !sdl.ClaimWindowForGPUDevice(device, window) {
fmt.println("ClaimWindowForGPUDevice failed:", sdl.GetError())
return
}
defer sdl.ReleaseWindowFromGPUDevice(device, window)
driver_name := sdl.GetGPUDeviceDriver(device)
fmt.println("SDL GPU driver:", string(driver_name))
if string(driver_name) != "vulkan" {
fmt.println("expected Vulkan driver, got:", string(driver_name))
return
}
vertex_shader := create_gpu_shader(device, "shaders/cubes.vert.spv", .VERTEX, 0)
if vertex_shader == nil {
return
}
defer sdl.ReleaseGPUShader(device, vertex_shader)
fragment_shader := create_gpu_shader(device, "shaders/cubes.frag.spv", .FRAGMENT, 1)
if fragment_shader == nil {
return
}
defer sdl.ReleaseGPUShader(device, fragment_shader)
color_format := sdl.GetGPUSwapchainTextureFormat(device, window)
if color_format == .INVALID {
fmt.println("invalid swapchain format:", sdl.GetError())
return
}
vb_descs := []sdl.GPUVertexBufferDescription{
{slot = 0, pitch = size_of(shared.Vertex), input_rate = .VERTEX, instance_step_rate = 0},
}
vattrs := []sdl.GPUVertexAttribute{
{location = 0, buffer_slot = 0, format = .FLOAT3, offset = u32(offset_of(shared.Vertex, pos))},
{location = 1, buffer_slot = 0, format = .FLOAT2, offset = u32(offset_of(shared.Vertex, uv))},
}
blend := sdl.GPUColorTargetBlendState{
src_color_blendfactor = .ONE,
dst_color_blendfactor = .ZERO,
color_blend_op = .ADD,
src_alpha_blendfactor = .ONE,
dst_alpha_blendfactor = .ZERO,
alpha_blend_op = .ADD,
color_write_mask = sdl.GPUColorComponentFlags{.R, .G, .B, .A},
enable_blend = false,
enable_color_write_mask = true,
}
color_targets := [1]sdl.GPUColorTargetDescription{
{format = color_format, blend_state = blend},
}
pipeline_ci := sdl.GPUGraphicsPipelineCreateInfo{
vertex_shader = vertex_shader,
fragment_shader = fragment_shader,
vertex_input_state = sdl.GPUVertexInputState{
vertex_buffer_descriptions = &vb_descs[0],
num_vertex_buffers = 1,
vertex_attributes = &vattrs[0],
num_vertex_attributes = 2,
},
primitive_type = .TRIANGLELIST,
rasterizer_state = sdl.GPURasterizerState{
fill_mode = .FILL,
cull_mode = .NONE,
front_face = .COUNTER_CLOCKWISE,
depth_bias_constant_factor = 0,
depth_bias_clamp = 0,
depth_bias_slope_factor = 0,
enable_depth_bias = false,
enable_depth_clip = true,
},
multisample_state = sdl.GPUMultisampleState{
sample_count = ._1,
sample_mask = 0,
enable_mask = false,
enable_alpha_to_coverage = false,
},
depth_stencil_state = sdl.GPUDepthStencilState{
compare_op = .LESS,
back_stencil_state = sdl.GPUStencilOpState{fail_op = .KEEP, pass_op = .KEEP, depth_fail_op = .KEEP, compare_op = .ALWAYS},
front_stencil_state = sdl.GPUStencilOpState{fail_op = .KEEP, pass_op = .KEEP, depth_fail_op = .KEEP, compare_op = .ALWAYS},
compare_mask = 0,
write_mask = 0,
enable_depth_test = true,
enable_depth_write = true,
enable_stencil_test = true,
},
target_info = sdl.GPUGraphicsPipelineTargetInfo{
color_target_descriptions = &color_targets[0],
num_color_targets = 1,
depth_stencil_format = .D32_FLOAT,
has_depth_stencil_target = true,
},
props = 0,
}
pipeline := sdl.CreateGPUGraphicsPipeline(device, pipeline_ci)
if pipeline == nil {
fmt.println("CreateGPUGraphicsPipeline failed:", sdl.GetError())
return
}
defer sdl.ReleaseGPUGraphicsPipeline(device, pipeline)
pipeline_create_info := sdl.GPUGraphicsPipelineCreateInfo{
primitive_type = .TRIANGLELIST,
rasterizer_state = {
fill_mode = .FILL,
cull_mode = .NONE,
}
}
gndview.runGame(window, device, pipeline)
_ = sdl.WaitForGPUIdle(device)
}