203 lines
No EOL
5.4 KiB
Odin
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)
|
|
} |