This commit is contained in:
pavel 2026-05-29 00:36:55 +02:00
commit 28f0d737b1
18 changed files with 3472 additions and 493 deletions

768
main copy.odin Normal file
View file

@ -0,0 +1,768 @@
package main
import "core:c"
import "core:fmt"
import "core:math"
import "core:mem"
import "core:os"
import "core:time"
import "core:path/filepath"
import "core:strings"
import "core:math/linalg"
import sdl "vendor:sdl3"
modelIndex := 0
Vec3 :: [3]f32
Mat4 :: [16]f32 // column-major
Camera :: struct {
center: Vec3,
distance: f32,
orientation: Rotor,
fov_deg: f32,
}
Debug_State :: struct {
enabled: bool,
accum: f32,
}
Rotor :: struct {
s, x, y, z: f32,
}
Cube_Instance :: struct {
pos: Vec3,
scale: f32,
color: Vec3,
}
Vertex :: struct {
pos: Vec3,
}
Push_Constants :: struct {
mvp: matrix[4,4]f32,
color: [4]f32,
}
mat4_identity :: proc() -> Mat4 {
return Mat4{1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1}
}
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
r := Mat4{}
for c in 0 ..< 4 {
for row in 0 ..< 4 {
r[c*4+row] =
a[0*4+row] * b[c*4+0] +
a[1*4+row] * b[c*4+1] +
a[2*4+row] * b[c*4+2] +
a[3*4+row] * b[c*4+3]
}
}
return r
}
vec3_sub :: proc(a, b: Vec3) -> Vec3 {
return Vec3{a[0] - b[0], a[1] - b[1], a[2] - b[2]}
}
vec3_add :: proc(a, b: Vec3) -> Vec3 {
return Vec3{a[0] + b[0], a[1] + b[1], a[2] + b[2]}
}
vec3_scale :: proc(v: Vec3, s: f32) -> Vec3 {
return Vec3{v[0] * s, v[1] * s, v[2] * s}
}
vec3_dot :: proc(a, b: Vec3) -> f32 {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
vec3_cross :: proc(a, b: Vec3) -> Vec3 {
return Vec3{
a[1] * b[2] - a[2] * b[1],
a[2] * b[0] - a[0] * b[2],
a[0] * b[1] - a[1] * b[0],
}
}
vec3_normalize :: proc(v: Vec3) -> Vec3 {
len2 := vec3_dot(v, v)
if len2 <= 0.000001 {
return Vec3{0, 0, 0}
}
inv := 1.0 / math.sqrt(len2)
return vec3_scale(v, inv)
}
rotor_identity :: proc() -> Rotor {
return Rotor{1, 0, 0, 0}
}
rotor_normalize :: proc(r: Rotor) -> Rotor {
len2 := r.s*r.s + r.x*r.x + r.y*r.y + r.z*r.z
if len2 <= 0.000001 {
return rotor_identity()
}
inv := 1.0 / math.sqrt(len2)
return Rotor{r.s * inv, r.x * inv, r.y * inv, r.z * inv}
}
rotor_mul :: proc(a, b: Rotor) -> Rotor {
return Rotor{
a.s*b.s - a.x*b.x - a.y*b.y - a.z*b.z,
a.s*b.x + a.x*b.s + a.y*b.z - a.z*b.y,
a.s*b.y - a.x*b.z + a.y*b.s + a.z*b.x,
a.s*b.z + a.x*b.y - a.y*b.x + a.z*b.s,
}
}
rotor_from_axis_angle :: proc(axis: Vec3, angle: f32) -> Rotor {
a := vec3_normalize(axis)
h := angle * 0.5
c := math.cos(h)
s := math.sin(h)
return Rotor{c, a[0] * s, a[1] * s, a[2] * s}
}
rotate_vec3 :: proc(r: Rotor, v: Vec3) -> Vec3 {
u := Vec3{r.x, r.y, r.z}
t := vec3_scale(vec3_cross(u, v), 2.0)
return vec3_add(v, vec3_add(vec3_scale(t, r.s), vec3_cross(u, t)))
}
mat4_translate :: proc(p: Vec3) -> Mat4 {
m := mat4_identity()
m[12] = p[0]
m[13] = p[1]
m[14] = p[2]
return m
}
mat4_scale_uniform :: proc(s: f32) -> Mat4 {
m := mat4_identity()
m[0] = s
m[5] = s
m[10] = s
return m
}
mat4_perspective :: proc(fov_deg, aspect, z_near, z_far: f32) -> Mat4 {
f := 1.0 / math.tan((fov_deg * 0.5) * (math.PI / 180.0))
m := Mat4{}
m[0] = f / aspect
m[5] = f
m[10] = (z_far + z_near) / (z_near - z_far)
m[11] = -1
m[14] = (2.0 * z_far * z_near) / (z_near - z_far)
return m
}
mat4_look_at :: proc(eye, target, up: Vec3) -> Mat4 {
fwd := vec3_normalize(vec3_sub(target, eye))
right := vec3_normalize(vec3_cross(fwd, up))
real_up := vec3_cross(right, fwd)
m := mat4_identity()
m[0] = right[0]
m[1] = real_up[0]
m[2] = -fwd[0]
m[4] = right[1]
m[5] = real_up[1]
m[6] = -fwd[1]
m[8] = right[2]
m[9] = real_up[2]
m[10] = -fwd[2]
m[12] = -vec3_dot(right, eye)
m[13] = -vec3_dot(real_up, eye)
m[14] = vec3_dot(fwd, eye)
return m
}
camera_forward :: proc(c: Camera) -> Vec3 {
return vec3_normalize(rotate_vec3(c.orientation, Vec3{0, 0, -1}))
}
camera_right :: proc(c: Camera) -> Vec3 {
return vec3_normalize(rotate_vec3(c.orientation, Vec3{1, 0, 0}))
}
camera_up :: proc(c: Camera) -> Vec3 {
return vec3_normalize(rotate_vec3(c.orientation, Vec3{0, 1, 0}))
}
camera_position :: proc(c: Camera) -> Vec3 {
return vec3_sub(c.center, vec3_scale(camera_forward(c), c.distance))
}
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) -> ^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 = 0,
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
}
loadModel :: proc(device: ^sdl.GPUDevice, model: ^RSM_Model, vertices: ^[dynamic]Vertex, indices: ^[dynamic]u16) -> (vbuf: ^sdl.GPUBuffer, ibuf: ^sdl.GPUBuffer) {
clear(vertices)
clear(indices)
for node in model.nodes {
fmt.println(node.offset_matrix)
fmt.println(node.translation1)
fmt.println(node.translation2)
fmt.println(node.scale)
fmt.println(node.rotation_angle)
fmt.println(node.rotation_axis)
fmt.println(node.rotation_keyframes[:])
for face in node.faces {
for i in 0..<3 {
v_idx := face.vertex_position_indices[i]
t_idx := face.texture_coordinate_indices[i]
pos := node.vertex_positions[v_idx]
uv := node.texture_coordinates[t_idx].coordinates
append(vertices, Vertex{
pos = pos
// uv = uv,
})
append(indices, u16(len(vertices)-1))
}
}
}
vbuf_info := sdl.GPUBufferCreateInfo{
usage = sdl.GPUBufferUsageFlags{.VERTEX},
size = u32(len(vertices) * size_of(vertices[0])),
props = 0,
}
vbuf = sdl.CreateGPUBuffer(device, vbuf_info)
if vbuf == nil {
fmt.println("CreateGPUBuffer failed:", sdl.GetError())
return
}
ibuf_info := sdl.GPUBufferCreateInfo{
usage = sdl.GPUBufferUsageFlags{.INDEX},
size = u32(len(indices) * size_of(indices[0])),
props = 0,
}
ibuf = sdl.CreateGPUBuffer(device, ibuf_info)
if ibuf == nil {
fmt.println("CreateGPUBuffer failed:", sdl.GetError())
return
}
{
setup_cmd := sdl.AcquireGPUCommandBuffer(device)
if setup_cmd == nil {
fmt.println("AcquireGPUCommandBuffer failed:", sdl.GetError())
return
}
if !copy_data_to_gpu(device, setup_cmd, vertices[:], vbuf, indices[:], ibuf) {
_ = sdl.CancelGPUCommandBuffer(setup_cmd)
return
}
if !sdl.SubmitGPUCommandBuffer(setup_cmd) {
fmt.println("SubmitGPUCommandBuffer (setup) failed:", sdl.GetError())
return
}
}
return vbuf, ibuf
}
copy_data_to_gpu :: proc(device: ^sdl.GPUDevice, cmd: ^sdl.GPUCommandBuffer, vertices: []Vertex, vert_buf: ^sdl.GPUBuffer, indices: []u16, ind_buf: ^sdl.GPUBuffer) -> bool {
vert_byte_count := len(vertices) * size_of(vertices[0])
ind_byte_count := len(indices) * size_of(indices[0])
tb_info := sdl.GPUTransferBufferCreateInfo{
usage = .UPLOAD,
size = u32(vert_byte_count + ind_byte_count),
props = 0,
}
tb := sdl.CreateGPUTransferBuffer(device, tb_info)
if tb == nil {
fmt.println("CreateGPUTransferBuffer failed:", sdl.GetError())
return false
}
defer sdl.ReleaseGPUTransferBuffer(device, tb)
mapped := transmute([^]byte)sdl.MapGPUTransferBuffer(device, tb, false)
if mapped == nil {
fmt.println("MapGPUTransferBuffer failed:", sdl.GetError())
return false
}
mem.copy_non_overlapping(mapped, raw_data(vertices), vert_byte_count)
mem.copy_non_overlapping(mapped[vert_byte_count:], raw_data(indices), ind_byte_count)
sdl.UnmapGPUTransferBuffer(device, tb)
cp := sdl.BeginGPUCopyPass(cmd)
if cp == nil {
fmt.println("BeginGPUCopyPass failed:", sdl.GetError())
return false
}
vert_src := sdl.GPUTransferBufferLocation{transfer_buffer = tb, offset = 0}
vert_dst := sdl.GPUBufferRegion{buffer = vert_buf, offset = 0, size = u32(vert_byte_count)}
sdl.UploadToGPUBuffer(cp, vert_src, vert_dst, false)
ind_src := sdl.GPUTransferBufferLocation{transfer_buffer = tb, offset = u32(vert_byte_count)}
ind_dst := sdl.GPUBufferRegion{buffer = ind_buf, offset = 0, size = u32(ind_byte_count)}
sdl.UploadToGPUBuffer(cp, ind_src, ind_dst, false)
sdl.EndGPUCopyPass(cp)
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)
if vertex_shader == nil {
return
}
defer sdl.ReleaseGPUShader(device, vertex_shader)
fragment_shader := create_gpu_shader(device, "shaders/cubes.frag.spv", .FRAGMENT)
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 := [1]sdl.GPUVertexBufferDescription{
{slot = 0, pitch = size_of(Vertex), input_rate = .VERTEX, instance_step_rate = 0},
}
vattrs := [1]sdl.GPUVertexAttribute{
{location = 0, buffer_slot = 0, format = .FLOAT3, offset = 0},
}
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 = 1,
},
primitive_type = .TRIANGLELIST,
rasterizer_state = sdl.GPURasterizerState{
fill_mode = .FILL,
cull_mode = .BACK,
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 = false,
enable_depth_write = false,
enable_stencil_test = false,
},
target_info = sdl.GPUGraphicsPipelineTargetInfo{
color_target_descriptions = &color_targets[0],
num_color_targets = 1,
depth_stencil_format = .INVALID,
has_depth_stencil_target = false,
},
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 = .LINE,
cull_mode = .NONE,
}
}
models: [dynamic]RSM_Model
walk("/home/pavel/neoragnarok_backup/kro_client/data", &models)
vertices: [dynamic]Vertex
indices: [dynamic]u16
vbuf, ibuf := loadModel(device, &models[modelIndex], &vertices, &indices)
defer sdl.ReleaseGPUBuffer(device, ibuf)
defer sdl.ReleaseGPUBuffer(device, vbuf)
init_yaw := rotor_from_axis_angle(Vec3{0, 1, 0}, 0.9)
init_right := rotate_vec3(init_yaw, Vec3{1, 0, 0})
init_pitch := rotor_from_axis_angle(init_right, -0.45)
camera := Camera{
center = Vec3{0, 0.5, 0},
distance = 8,
orientation = rotor_normalize(rotor_mul(init_pitch, init_yaw)),
fov_deg = 60,
}
cubes := []Cube_Instance{
{pos = Vec3{0, 0, 0}, scale = 1.0, color = Vec3{0.95, 0.45, 0.20}},
{pos = Vec3{2, 0.5, -1}, scale = 0.8, color = Vec3{0.20, 0.70, 0.95}},
{pos = Vec3{-2, -0.2, 1.5}, scale = 1.2, color = Vec3{0.85, 0.85, 0.30}},
{pos = Vec3{1.0, 1.4, 2.0}, scale = 0.6, color = Vec3{0.40, 0.95, 0.60}},
}
running := true
last := time.tick_now()
left_down := false
middle_down := false
debug := Debug_State{}
for running {
now := time.tick_now()
dt := f32(time.duration_seconds(time.tick_diff(last, now)))
last = now
event: sdl.Event
for sdl.PollEvent(&event) {
#partial switch event.type {
case .QUIT:
running = false
case .MOUSE_BUTTON_DOWN:
switch event.button.button {
case sdl.BUTTON_LEFT:
left_down = true
case sdl.BUTTON_MIDDLE:
middle_down = true
}
case .MOUSE_BUTTON_UP:
switch event.button.button {
case sdl.BUTTON_LEFT:
left_down = false
case sdl.BUTTON_MIDDLE:
middle_down = false
}
case .MOUSE_WHEEL:
camera.distance = math.clamp(camera.distance - event.wheel.y * 0.7, 1.5, 80.0)
case .KEY_DOWN:
if event.key.key == sdl.K_ESCAPE {
running = false
} else if event.key.scancode == sdl.Scancode.F1 && !event.key.repeat {
debug.enabled = !debug.enabled
fmt.println("debug:", debug.enabled)
} else if event.key.key == sdl.K_N {
modelIndex += 1
sdl.ReleaseGPUBuffer(device, ibuf)
sdl.ReleaseGPUBuffer(device, vbuf)
vbuf, ibuf = loadModel(device, &models[modelIndex], &vertices, &indices)
}
}
}
x_rel: f32 = 0
y_rel: f32 = 0
_ = sdl.GetRelativeMouseState(&x_rel, &y_rel)
if left_down {
yaw_r := rotor_from_axis_angle(Vec3{0, 1, 0}, -x_rel * 0.006)
q1 := rotor_normalize(rotor_mul(yaw_r, camera.orientation))
right_axis := vec3_normalize(rotate_vec3(q1, Vec3{1, 0, 0}))
pitch_r := rotor_from_axis_angle(right_axis, -y_rel * 0.006)
q2 := rotor_normalize(rotor_mul(pitch_r, q1))
fwd2 := camera_forward(Camera{center = camera.center, distance = camera.distance, orientation = q2, fov_deg = camera.fov_deg})
if math.abs(vec3_dot(fwd2, Vec3{0, 1, 0})) < 0.98 {
camera.orientation = q2
} else {
camera.orientation = q1
}
}
if middle_down {
right := camera_right(camera)
up := camera_up(camera)
pan_speed := 0.008 * camera.distance
camera.center = vec3_add(camera.center, vec3_scale(right, -x_rel * pan_speed))
camera.center = vec3_add(camera.center, vec3_scale(up, y_rel * pan_speed))
}
keys := sdl.GetKeyboardState(nil)
forward := camera_forward(camera)
right := camera_right(camera)
up := camera_up(camera)
move_speed := camera.distance * dt * 1.4
if keys[sdl.Scancode.W] {
camera.center = vec3_add(camera.center, vec3_scale(forward, move_speed))
}
if keys[sdl.Scancode.S] {
camera.center = vec3_add(camera.center, vec3_scale(forward, -move_speed))
}
if keys[sdl.Scancode.A] {
camera.center = vec3_add(camera.center, vec3_scale(right, -move_speed))
}
if keys[sdl.Scancode.D] {
camera.center = vec3_add(camera.center, vec3_scale(right, move_speed))
}
if debug.enabled {
debug.accum += dt
if debug.accum >= 0.2 {
debug.accum = 0
eye := camera_position(camera)
fmt.println("cam eye:", eye,
"center:", camera.center,
"fwd:", forward,
"right:", right,
"up:", up)
}
}
w: c.int = 0
h: c.int = 0
sdl.GetWindowSize(window, &w, &h)
if w <= 0 || h <= 0 {
continue
}
cmd := sdl.AcquireGPUCommandBuffer(device)
if cmd == nil {
fmt.println("AcquireGPUCommandBuffer failed:", sdl.GetError())
break
}
swap_tex: ^sdl.GPUTexture
swap_w: sdl.Uint32 = 0
swap_h: sdl.Uint32 = 0
if !sdl.WaitAndAcquireGPUSwapchainTexture(cmd, window, &swap_tex, &swap_w, &swap_h) {
fmt.println("WaitAndAcquireGPUSwapchainTexture failed:", sdl.GetError())
_ = sdl.CancelGPUCommandBuffer(cmd)
break
}
if swap_tex == nil {
if !sdl.SubmitGPUCommandBuffer(cmd) {
fmt.println("SubmitGPUCommandBuffer failed:", sdl.GetError())
break
}
continue
}
clear := sdl.FColor{0.08, 0.09, 0.12, 1.0}
cti := sdl.GPUColorTargetInfo{
texture = swap_tex,
mip_level = 0,
layer_or_depth_plane = 0,
clear_color = clear,
load_op = .CLEAR,
store_op = .STORE,
resolve_texture = nil,
resolve_mip_level = 0,
resolve_layer = 0,
cycle = false,
cycle_resolve_texture = false,
}
rp := sdl.BeginGPURenderPass(cmd, &cti, 1, nil)
if rp == nil {
fmt.println("BeginGPURenderPass failed:", sdl.GetError())
_ = sdl.CancelGPUCommandBuffer(cmd)
break
}
vp := sdl.GPUViewport{x = 0, y = 0, w = f32(swap_w), h = f32(swap_h), min_depth = 0, max_depth = 1}
sdl.SetGPUViewport(rp, vp)
sdl.BindGPUGraphicsPipeline(rp, pipeline)
vb_binding := sdl.GPUBufferBinding{buffer = vbuf, offset = 0}
sdl.BindGPUVertexBuffers(rp, 0, &vb_binding, 1)
ib_binding := sdl.GPUBufferBinding{buffer = ibuf, offset = 0}
sdl.BindGPUIndexBuffer(rp, ib_binding, ._16BIT)
aspect := f32(swap_w) / f32(swap_h)
proj := linalg.matrix4_perspective(camera.fov_deg, aspect, 0.1, 300.0)
view := linalg.matrix4_look_at(camera_position(camera), camera.center, camera_up(camera))
vp_mat := proj * view
for node in models[modelIndex].nodes {
rotation := linalg.quaternion_angle_axis(node.rotation_angle, node.rotation_axis)
if (len(node.rotation_keyframes) > 0) {
q := node.rotation_keyframes[0].quaternion
rotation = quaternion(imag=q[0], jmag=q[1], kmag=q[2], real=q[3])
}
rotation = linalg.quaternion_normalize(rotation)
r := linalg.matrix3_from_quaternion(rotation)
s := matrix[3,3]f32{
node.scale[0], 0, 0 ,
0, node.scale[1], 0 ,
0, 0, node.scale[2],
}
a3 := r * node.offset_matrix * s
t := node.translation1 + node.translation2
// 4x4 affine matrix
model := matrix[4,4]f32{
a3[0][0], a3[0][1], a3[0][2], t[0],
a3[1][0], a3[1][1], a3[1][2], t[1],
a3[2][0], a3[2][1], a3[2][2], t[2],
0, 0, 0, 1 ,
}
// append(vertices, Vertex{
// pos = linalg.matrix3_from_quaternion(rotation) * node.offset_matrix * (node.scale * pos) + node.translation1 + node.translation2
// // uv = uv,
// })
// model := mat4_mul(node., mat4_scale_uniform(1))
pc := Push_Constants{}
pc.mvp = vp_mat * model
pc.color = [4]f32{1, 0, 0, 1.0}
sdl.PushGPUVertexUniformData(cmd, 0, &pc, u32(size_of(Push_Constants)))
sdl.PushGPUFragmentUniformData(cmd, 0, &pc, u32(size_of(Push_Constants)))
sdl.DrawGPUIndexedPrimitives(rp, u32(len(indices)), 1, 0, 0, 0)
}
sdl.EndGPURenderPass(rp)
if !sdl.SubmitGPUCommandBuffer(cmd) {
fmt.println("SubmitGPUCommandBuffer failed:", sdl.GetError())
break
}
}
_ = sdl.WaitForGPUIdle(device)
}
walk :: proc(dir: string, models: ^[dynamic]RSM_Model) {
f, _ := os.open(dir)
entries, ok := os.read_dir(f, 0, context.allocator)
for entry in entries {
path, _ := filepath.join({dir, entry.name})
if entry.type == .Directory {
walk(path, models)
}
if strings.contains(entry.name, ".rsm") {
data, _ := os.read_entire_file(path, context.allocator)
parsed, err := parse_rsm(data)
if err != nil {
fmt.printfln("%v", err)
} else {
append_elem(models, parsed)
}
}
}
}