diff --git a/.gitignore b/.gitignore index cf4ba8e..5dd6a90 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ bin/ *.dll *.dylib *.so -*.spv diff --git a/idk/main.odin b/idk/main.odin deleted file mode 100644 index f8b6c82..0000000 --- a/idk/main.odin +++ /dev/null @@ -1,211 +0,0 @@ -package main - -import sdl "vendor:sdl3" -import "core:math/linalg" -import "core:mem" - -frag_shader_code := #load("shader.spv.frag") -vert_shader_code := #load("shader.spv.vert") - -main :: proc() { - ok := sdl.Init({.VIDEO}); assert(ok) - - sdl.SetLogPriorities(.VERBOSE) - - window := sdl.CreateWindow("Pain and Suffering and Pleasure", 800, 500, nil) - - device := sdl.CreateGPUDevice({.SPIRV}, true, nil) - - ok = sdl.ClaimWindowForGPUDevice(device, window); assert(ok) - - vert_shader := sdl.CreateGPUShader(device, { - code_size = len(vert_shader_code), - code = raw_data(vert_shader_code), - entrypoint = "main", - format = {.SPIRV}, - stage = .VERTEX, - num_uniform_buffers = 1, - }) - - frag_shader := sdl.CreateGPUShader(device, { - code_size = len(frag_shader_code), - code = raw_data(frag_shader_code), - entrypoint = "main", - format = {.SPIRV}, - stage = .FRAGMENT, - num_uniform_buffers = 0, - }) - - Vec3 :: [3]f32 - - Vertex_Data :: struct { - pos: Vec3, - color: sdl.FColor, - } - - size : f32= 1 - - vertices := []Vertex_Data { - { pos = {-size, size, 1}, color = {1,0,0,1} }, - {pos = {size, size, 1}, color = {0,1,1,1}}, - {pos={-size,-size, 1}, color = {1,0,1,1}}, - {pos={size,-size, 1}, color = {1,0,1,1}}, - } - - vertices_byte_size := len(vertices) * size_of(vertices[0]) - - indicies := []u16 { - 0,1,2, - 2,1,3 - } - - indices_byte_size := len(indicies) * size_of(indicies[0]) - vertex_buf := sdl.CreateGPUBuffer(device, { - usage = {.VERTEX}, - size = u32(vertices_byte_size), - }) - - index_buf := sdl.CreateGPUBuffer(device, { - usage = {.INDEX}, - size = u32(vertices_byte_size), - }) - - transfer_buf := sdl.CreateGPUTransferBuffer(device, { - usage = .UPLOAD, - size = u32(vertices_byte_size + indices_byte_size), - }) - - transfer_mem := transmute([^]byte)sdl.MapGPUTransferBuffer(device, transfer_buf, false) - mem.copy(transfer_mem, raw_data(vertices), vertices_byte_size) - mem.copy(transfer_mem[vertices_byte_size:], raw_data(indicies), indices_byte_size) - sdl.UnmapGPUTransferBuffer(device, transfer_buf) - - copy_buffer := sdl.AcquireGPUCommandBuffer(device) - copy_pass := sdl.BeginGPUCopyPass(copy_buffer) - - sdl.UploadToGPUBuffer(copy_pass, { - transfer_buffer = transfer_buf, - }, { - buffer = vertex_buf, - size = u32(vertices_byte_size), - }, false) - - sdl.UploadToGPUBuffer(copy_pass, { - transfer_buffer = transfer_buf, offset = u32(vertices_byte_size) - }, { - buffer = index_buf, - size = u32(indices_byte_size) - }, false) - - sdl.EndGPUCopyPass(copy_pass) - - ok = sdl.SubmitGPUCommandBuffer(copy_buffer); assert(ok) - - sdl.ReleaseGPUTransferBuffer(device, transfer_buf) - - - vertex_attrs := []sdl.GPUVertexAttribute { - { - location = 0, - format = .FLOAT3, - offset = u32(offset_of(Vertex_Data, pos)), - }, - { - location = 1, - format = .FLOAT4, - offset = u32(offset_of(Vertex_Data, color)), - } - } - - pipeline := sdl.CreateGPUGraphicsPipeline(device, { - vertex_shader = vert_shader, - fragment_shader = frag_shader, - primitive_type = .TRIANGLELIST, - vertex_input_state = { - num_vertex_buffers = 1, - vertex_buffer_descriptions = &(sdl.GPUVertexBufferDescription{ - slot = 0, - pitch = size_of(Vertex_Data), - }), - num_vertex_attributes = u32(len(vertex_attrs)), - vertex_attributes = raw_data(vertex_attrs), - }, - target_info = { - num_color_targets = 1, - color_target_descriptions = &(sdl.GPUColorTargetDescription{ - format = sdl.GetGPUSwapchainTextureFormat(device, window) - }) - } - }) - - defer sdl.ReleaseGPUShader(device, frag_shader) - defer sdl.ReleaseGPUShader(device, vert_shader) - - win_size: [2]i32 - ok = sdl.GetWindowSize(window, &win_size.x, &win_size.y); assert(ok) - - rotation_speed := linalg.to_radians(f32(90)) - - rotation := f32(0.62) - - proj := linalg.matrix4_perspective_f32(linalg.to_radians(f32(70)), f32(win_size.x) / f32(win_size.y), 0.0001, 1000) - - - UBO :: struct { - mvp: matrix[4,4]f32 - } - - last_ticks := sdl.GetTicks() - - - for { - new_ticks := sdl.GetTicks() - delta_time := f32(new_ticks - last_ticks) / 1000 - last_ticks = new_ticks - event: sdl.Event - for sdl.PollEvent(&event) { - #partial switch(event.type) { - case .QUIT: - return - case .KEY_DOWN: - #partial switch(event.key.scancode) { - case .ESCAPE: - return - } - } - } - - buffer := sdl.AcquireGPUCommandBuffer(device) - - texture: ^sdl.GPUTexture - - ok = sdl.WaitAndAcquireGPUSwapchainTexture(buffer, window, &texture, nil, nil); assert(ok) - - rotation += rotation_speed * delta_time - model_mat := linalg.matrix4_translate_f32({0,0,-5}) * linalg.matrix4_rotate_f32(rotation, {0,1,0}) - - ubo := UBO {mvp = proj * model_mat} - - if texture != nil { - color_target := sdl.GPUColorTargetInfo{ - texture = texture, - load_op = .CLEAR, - clear_color = {0,0.2,0.4,1}, - store_op = .STORE, - } - render_pass := sdl.BeginGPURenderPass(buffer, &color_target, 1, nil) - - sdl.BindGPUGraphicsPipeline(render_pass, pipeline) - sdl.BindGPUVertexBuffers(render_pass, 0, &(sdl.GPUBufferBinding{ - buffer = vertex_buf, - - }),1) - sdl.BindGPUIndexBuffer(render_pass, {buffer = index_buf}, ._16BIT) - sdl.PushGPUVertexUniformData(buffer, 0, &ubo, size_of(ubo)) - sdl.DrawGPUIndexedPrimitives(render_pass, 6, 1, 0, 0 ,0) - sdl.EndGPURenderPass(render_pass) - } - - ok = sdl.SubmitGPUCommandBuffer(buffer); assert(ok) - } -} \ No newline at end of file diff --git a/idk/run.sh b/idk/run.sh deleted file mode 100755 index 74d360c..0000000 --- a/idk/run.sh +++ /dev/null @@ -1,4 +0,0 @@ -glslc ./idk/shader.glsl.vert -o idk/shader.spv.vert -glslc ./idk/shader.glsl.frag -o idk/shader.spv.frag - -odin run idk/ \ No newline at end of file diff --git a/idk/shader.glsl.frag b/idk/shader.glsl.frag deleted file mode 100644 index 1612d8a..0000000 --- a/idk/shader.glsl.frag +++ /dev/null @@ -1,9 +0,0 @@ -#version 460 - -layout(location=0) out vec4 frag_color; - -layout(location=0) in vec4 color; - -void main() { - frag_color = color; -} \ No newline at end of file diff --git a/idk/shader.glsl.vert b/idk/shader.glsl.vert deleted file mode 100644 index c9c163f..0000000 --- a/idk/shader.glsl.vert +++ /dev/null @@ -1,16 +0,0 @@ -#version 460 - -layout(set=1, binding=0) uniform UBO { - mat4 mvp; -}; - -layout(location=0) in vec3 position; -layout(location=1) in vec4 color; - -layout(location=0) out vec4 out_color; - -void main() { - gl_Position = mvp * vec4(position, 1); - out_color = color; - -} \ No newline at end of file diff --git a/idk/shader.spv.frag b/idk/shader.spv.frag deleted file mode 100644 index fabe49f..0000000 Binary files a/idk/shader.spv.frag and /dev/null differ diff --git a/idk/shader.spv.vert b/idk/shader.spv.vert deleted file mode 100644 index 5ce92d8..0000000 Binary files a/idk/shader.spv.vert and /dev/null differ diff --git a/main copy.odin b/main copy.odin deleted file mode 100644 index 15d1b56..0000000 --- a/main copy.odin +++ /dev/null @@ -1,768 +0,0 @@ -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) - } - } - } -} diff --git a/shaders/cubes.frag.glsl b/shaders/cubes.frag.glsl index 3800ac2..1b2abfd 100644 --- a/shaders/cubes.frag.glsl +++ b/shaders/cubes.frag.glsl @@ -2,16 +2,11 @@ layout(location = 0) out vec4 out_color; -layout(location = 0) in vec2 uv; - -layout(set = 2, binding = 0) uniform sampler2D tex_sampler; +layout(set = 3, binding = 0) uniform FragmentUniforms { + mat4 u_mvp; + vec4 u_color; +}; void main() { - vec4 c = texture(tex_sampler, uv); - float tol = 0.02; - if (distance(c.rgb, vec3(1.0, 0.0, 1.0)) < tol || distance(c.rgb, vec3(0.0, 0.0, 0.0)) < tol) { - discard; - } - - out_color = c; + out_color = u_color; } diff --git a/shaders/cubes.frag.spv b/shaders/cubes.frag.spv index 5d3bfc4..883b7ee 100644 Binary files a/shaders/cubes.frag.spv and b/shaders/cubes.frag.spv differ diff --git a/shaders/cubes.vert.glsl b/shaders/cubes.vert.glsl index f6cab24..437895a 100644 --- a/shaders/cubes.vert.glsl +++ b/shaders/cubes.vert.glsl @@ -7,11 +7,6 @@ layout(set = 1, binding = 0) uniform VertexUniforms { vec4 u_color; }; -layout(location=1) in vec2 uv; - -layout(location=0) out vec2 out_uv; - void main() { gl_Position = u_mvp * vec4(a_pos, 1.0); - out_uv = uv; } diff --git a/shaders/cubes.vert.spv b/shaders/cubes.vert.spv index 1adb205..7db0df5 100644 Binary files a/shaders/cubes.vert.spv and b/shaders/cubes.vert.spv differ diff --git a/src/format/common.odin b/src/format/common.odin deleted file mode 100644 index fb79d6f..0000000 --- a/src/format/common.odin +++ /dev/null @@ -1,114 +0,0 @@ -package format - -import "core:strings" - -Version :: struct { - major: u8, - minor: u8, -} - -version_ge :: #force_inline proc(v: Version, major, minor: int) -> bool { - return int(v.major) > major || (int(v.major) == major && int(v.minor) >= minor) -} - -version_below :: #force_inline proc(v: Version, major, minor: int) -> bool { - return !version_ge(v, major, minor) -} - - -normalize_path :: proc(p: string) -> string { - // Byte-preserving normalization for legacy CP949/EUC-KR path bytes. - // Only ASCII transforms are applied. - b := transmute([]u8)p - out := make([]u8, len(b), context.allocator) - for i in 0..= 'A' && ch <= 'Z' { - out[i] = ch + ('a' - 'A') - } else { - out[i] = ch - } - } - return string(out) -} - -latin1_bytes_to_utf8_string :: proc(src: []u8, allocator := context.allocator) -> string { - // 0x00..0x7F => 1 byte UTF-8, 0x80..0xFF => 2 bytes UTF-8 - out := make([dynamic]u8, 0, len(src) * 2, allocator) - for b in src { - if b < 0x80 { - append(&out, b) - } else { - append(&out, 0xC0 | (b >> 6)) - append(&out, 0x80 | (b & 0x3F)) - } - } - return string(out[:]) -} - -read_u8 :: proc(r: ^RSM_Reader) -> (u8, bool) { - if r.at+1 > len(r.data) { return 0, false } - v := r.data[r.at] - r.at += 1 - return v, true -} - -read_u16 :: proc(r: ^RSM_Reader) -> (u16, bool) { - if r.at+2 > len(r.data) { return 0, false } - v := u16(r.data[r.at]) | (u16(r.data[r.at+1]) << 8) - r.at += 2 - return v, true -} - -read_u32 :: proc(r: ^RSM_Reader) -> (u32, bool) { - if r.at+4 > len(r.data) { return 0, false } - v := u32(r.data[r.at]) | (u32(r.data[r.at+1]) << 8) | (u32(r.data[r.at+2]) << 16) | (u32(r.data[r.at+3]) << 24) - r.at += 4 - return v, true -} - -read_i32 :: proc(r: ^RSM_Reader) -> (i32, bool) { - v, ok := read_u32(r) - return i32(v), ok -} - -read_f32 :: proc(r: ^RSM_Reader) -> (f32, bool) { - bits, ok := read_u32(r) - if !ok { return 0, false } - return transmute(f32)bits, true -} - -read_fixed_string_clean :: proc(r: ^RSM_Reader, n: int) -> (string, bool) { - s, ok := read_fixed_string(r, n) - if !ok { return "", false } - return strings.trim_space(s), true -} - -read_fixed_string :: proc(r: ^RSM_Reader, n: int) -> (string, bool) { - if r.at+n > len(r.data) { return "", false } - buf := r.data[r.at:r.at+n] - r.at += n - end := 0 - for end < len(buf) && buf[end] != 0 { - end += 1 - } - return latin1_bytes_to_utf8_string(buf[:end]), true -} - -read_model_string :: proc(r: ^RSM_Reader, version: Version, fixed_len: int) -> (string, bool) { - if version_ge(version, 2, 2) { - n, ok := read_u32(r) - if !ok || int(n) < 0 || r.at+int(n) > len(r.data) { return "", false } - s := latin1_bytes_to_utf8_string(r.data[r.at:r.at+int(n)]) - r.at += int(n) - return s, true - } - return read_fixed_string(r, fixed_len) -} - -read_vec3 :: proc(r: ^RSM_Reader) -> ([3]f32, bool) { - x, ok1 := read_f32(r); y, ok2 := read_f32(r); z, ok3 := read_f32(r) - return [3]f32{x,y,z}, ok1 && ok2 && ok3 -} \ No newline at end of file diff --git a/src/format/gnd_format.odin b/src/format/gnd_format.odin deleted file mode 100644 index 0434563..0000000 --- a/src/format/gnd_format.odin +++ /dev/null @@ -1,385 +0,0 @@ -package format - -import "core:strings" - -RSW_Parse_Error :: enum { - None, - UnexpectedEOF, - InvalidSignature, -} - -RSW_WaterSettings :: struct { - water_level: f32, - water_type: i32, - wave_height: f32, - wave_speed: f32, - wave_pitch: f32, - texture_cycling_interval: u32, -} - -RSW_LightSettings :: struct { - light_longitude: i32, - light_latitude: i32, - diffuse_color: [3]f32, - ambient_color: [3]f32, - shadow_map_alpha: f32, -} - -RSW_Transform :: struct { - position: [3]f32, - rotation_deg: [3]f32, - scale: [3]f32, -} - -RSW_Object :: struct { - name: string, - model_name: string, - node_name: string, - transform: RSW_Transform, -} - -RSW_LightSource :: struct { - name: string, - position: [3]f32, - color: [3]f32, - range: f32, -} - -RSW_SoundSource :: struct { - name: string, - sound_file: string, - position: [3]f32, - volume: f32, - width: u32, - height: u32, - range: f32, - cycle: f32, -} - -RSW_EffectSource :: struct { - name: string, - position: [3]f32, - effect_type: u32, - emit_speed: f32, - param0: f32, - param1: f32, - param2: f32, - param3: f32, -} - -RSW_Data :: struct { - version: Version, - build_version: u32, - ground_file: string, - gat_file: string, - water: RSW_WaterSettings, - light: RSW_LightSettings, - objects: [dynamic]RSW_Object, - light_sources: [dynamic]RSW_LightSource, - sound_sources: [dynamic]RSW_SoundSource, - effect_sources: [dynamic]RSW_EffectSource, -} - -read_vec3f :: proc(r: ^RSM_Reader) -> ([3]f32, bool) { - x, ok1 := read_f32(r) - y, ok2 := read_f32(r) - z, ok3 := read_f32(r) - return [3]f32{x,y,z}, ok1 && ok2 && ok3 -} - -parse_rsw :: proc(data: []u8) -> (RSW_Data, RSW_Parse_Error) { - out := RSW_Data{ - objects = make([dynamic]RSW_Object), - light_sources = make([dynamic]RSW_LightSource), - sound_sources = make([dynamic]RSW_SoundSource), - effect_sources = make([dynamic]RSW_EffectSource), - } - - r := RSM_Reader{data = data} - sig, ok := read_fixed_string(&r, 4) - resources_amount: u32 - rtype: i32 - if !ok || sig != "GRSW" { - return out, .InvalidSignature - } - - maj, ok1 := read_u8(&r) - min, ok2 := read_u8(&r) - if !(ok1 && ok2) { return out, .UnexpectedEOF } - out.version = Version{maj, min} - - if version_ge(out.version, 2, 5) { - out.build_version, ok = read_u32(&r) - if !ok { return out, .UnexpectedEOF } - } - if version_ge(out.version, 2, 2) { - _, ok = read_u8(&r) - if !ok { return out, .UnexpectedEOF } - } - - _, ok = read_fixed_string_clean(&r, 40) - if !ok { return out, .UnexpectedEOF } - out.ground_file, ok = read_fixed_string_clean(&r, 40) - if !ok { return out, .UnexpectedEOF } - out.gat_file, ok = read_fixed_string_clean(&r, 40) - if !ok { return out, .UnexpectedEOF } - if version_ge(out.version, 1, 4) { - _, ok = read_fixed_string_clean(&r, 40) - if !ok { return out, .UnexpectedEOF } - } - - if !version_ge(out.version, 2, 6) { - if version_ge(out.version, 1, 3) { - out.water.water_level, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - } - if version_ge(out.version, 1, 8) { - out.water.water_type, ok = read_i32(&r); if !ok { return out, .UnexpectedEOF } - out.water.wave_height, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - out.water.wave_speed, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - out.water.wave_pitch, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - } - if version_ge(out.version, 1, 9) { - out.water.texture_cycling_interval, ok = read_u32(&r); if !ok { return out, .UnexpectedEOF } - } - } - - if version_ge(out.version, 1, 5) { - out.light.light_longitude, ok = read_i32(&r); if !ok { return out, .UnexpectedEOF } - out.light.light_latitude, ok = read_i32(&r); if !ok { return out, .UnexpectedEOF } - out.light.diffuse_color, ok = read_vec3f(&r); if !ok { return out, .UnexpectedEOF } - out.light.ambient_color, ok = read_vec3f(&r); if !ok { return out, .UnexpectedEOF } - } - if version_ge(out.version, 1, 7) { - out.light.shadow_map_alpha, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - } - - if version_ge(out.version, 1, 6) { - for _ in 0..<4 { - _, ok = read_i32(&r) - if !ok { return out, .UnexpectedEOF } - } - } - - resources_amount, ok = read_u32(&r) - if !ok { return out, .UnexpectedEOF } - - for i := 0; i < int(resources_amount); i += 1 { - rtype, ok = read_i32(&r) - if !ok { return out, .UnexpectedEOF } - - switch rtype { - case 1: - obj := RSW_Object{} - if version_ge(out.version, 1, 3) { - obj.name, ok = read_fixed_string_clean(&r, 40); if !ok { return out, .UnexpectedEOF } - _, ok = read_i32(&r); if !ok { return out, .UnexpectedEOF } - _, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - _, ok = read_i32(&r); if !ok { return out, .UnexpectedEOF } - } - if version_ge(out.version, 2, 6) && out.build_version >= 186 { - _, ok = read_u8(&r) - if !ok { return out, .UnexpectedEOF } - } - obj.model_name, ok = read_fixed_string_clean(&r, 80); if !ok { return out, .UnexpectedEOF } - obj.node_name, ok = read_fixed_string_clean(&r, 80); if !ok { return out, .UnexpectedEOF } - obj.model_name = normalize_path(obj.model_name) - obj.transform.position, ok = read_vec3f(&r); if !ok { return out, .UnexpectedEOF } - obj.transform.rotation_deg, ok = read_vec3f(&r); if !ok { return out, .UnexpectedEOF } - obj.transform.scale, ok = read_vec3f(&r); if !ok { return out, .UnexpectedEOF } - obj.transform.position[1] = -obj.transform.position[1] - append(&out.objects, obj) - case 2: - l := RSW_LightSource{} - l.name, ok = read_fixed_string_clean(&r, 80); if !ok { return out, .UnexpectedEOF } - l.position, ok = read_vec3f(&r); if !ok { return out, .UnexpectedEOF } - l.position[1] = -l.position[1] - l.color, ok = read_vec3f(&r); if !ok { return out, .UnexpectedEOF } - l.range, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - append(&out.light_sources, l) - case 3: - s := RSW_SoundSource{} - s.name, ok = read_fixed_string_clean(&r, 80); if !ok { return out, .UnexpectedEOF } - s.sound_file, ok = read_fixed_string_clean(&r, 80); if !ok { return out, .UnexpectedEOF } - s.position, ok = read_vec3f(&r); if !ok { return out, .UnexpectedEOF } - s.position[1] = -s.position[1] - s.volume, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - s.width, ok = read_u32(&r); if !ok { return out, .UnexpectedEOF } - s.height, ok = read_u32(&r); if !ok { return out, .UnexpectedEOF } - s.range, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - if version_ge(out.version, 2, 0) { - s.cycle, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - } else { - s.cycle = 4.0 - } - append(&out.sound_sources, s) - case 4: - e := RSW_EffectSource{} - e.name, ok = read_fixed_string_clean(&r, 80); if !ok { return out, .UnexpectedEOF } - e.position, ok = read_vec3f(&r); if !ok { return out, .UnexpectedEOF } - e.position[1] = -e.position[1] - e.effect_type, ok = read_u32(&r); if !ok { return out, .UnexpectedEOF } - e.emit_speed, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - e.param0, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - e.param1, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - e.param2, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - e.param3, ok = read_f32(&r); if !ok { return out, .UnexpectedEOF } - append(&out.effect_sources, e) - case: - return out, .UnexpectedEOF - } - } - - return out, .None -} - -GND_Info :: struct { version: Version, width, height: i32, zoom: f32 } -GAT_Info :: struct { version: Version, width, height: i32 } - -GND_Surface :: struct { - u: [4]f32, - v: [4]f32, - texture_index: i16, - light_map_index: i16, - color_bgra: [4]u8, -} - -GND_Tile :: struct { - h_sw, h_se, h_nw, h_ne: f32, - top_surface_index: i32, - north_surface_index: i32, - east_surface_index: i32, -} - -GND_Data :: struct { - info: GND_Info, - textures: [dynamic]string, - surfaces: [dynamic]GND_Surface, - tiles: [dynamic]GND_Tile, -} - -parse_gnd_info :: proc(data: []u8) -> (GND_Info, RSW_Parse_Error) { - r := RSM_Reader{data = data} - sig, ok := read_fixed_string(&r, 4) - if !ok || sig != "GRGN" { return GND_Info{}, .InvalidSignature } - maj, ok1 := read_u8(&r) - min, ok2 := read_u8(&r) - if !(ok1 && ok2) { return GND_Info{}, .UnexpectedEOF } - w, ok3 := read_i32(&r) - h, ok4 := read_i32(&r) - z, ok5 := read_f32(&r) - if !(ok3 && ok4 && ok5) { return GND_Info{}, .UnexpectedEOF } - return GND_Info{version = Version{maj, min}, width = w, height = h, zoom = z}, .None -} - -parse_gnd :: proc(data: []u8) -> (GND_Data, RSW_Parse_Error) { - out := GND_Data{ - textures = make([dynamic]string), - surfaces = make([dynamic]GND_Surface), - tiles = make([dynamic]GND_Tile), - } - - info, err := parse_gnd_info(data) - if err != .None { - return out, err - } - out.info = info - - r := RSM_Reader{data = data, at = 4 + 2 + 4 + 4 + 4} - texture_count, ok_tc := read_i32(&r) - if !ok_tc { return out, .UnexpectedEOF } - texture_name_length, ok_tnl := read_i32(&r) - if !ok_tnl { return out, .UnexpectedEOF } - - for _ in 0.. len(r.data) { return out, .UnexpectedEOF } - r.at += skip - } else { - skip := int(light_map_count * 16) - if r.at+skip > len(r.data) { return out, .UnexpectedEOF } - r.at += skip - } - - surface_count, ok_sc := read_i32(&r) - if !ok_sc { return out, .UnexpectedEOF } - for _ in 0.. (GAT_Info, RSW_Parse_Error) { - r := RSM_Reader{data = data} - sig, ok := read_fixed_string(&r, 4) - if !ok || sig != "GRAT" { return GAT_Info{}, .InvalidSignature } - maj, ok1 := read_u8(&r) - min, ok2 := read_u8(&r) - if !(ok1 && ok2) { return GAT_Info{}, .UnexpectedEOF } - w, ok3 := read_i32(&r) - h, ok4 := read_i32(&r) - if !(ok3 && ok4) { return GAT_Info{}, .UnexpectedEOF } - return GAT_Info{version = Version{maj, min}, width = w, height = h}, .None -} diff --git a/src/format/rsm_format.odin b/src/format/rsm_format.odin deleted file mode 100644 index 411c0f9..0000000 --- a/src/format/rsm_format.odin +++ /dev/null @@ -1,282 +0,0 @@ -package format - -import "core:strings" -import "core:fmt" - -RSM_ScaleKeyframe :: struct { frame: i32, scale: [3]f32, _reserved: f32 } -RSM_RotationKeyframe :: struct { frame: i32, quaternion: [4]f32 } -RSM_TranslationKeyframe :: struct { frame: i32, translation: [3]f32, _reserved: f32 } -RSM_TextureFrame :: struct { frame: i32, operation_value: f32 } -RSM_TextureKeyframe :: struct { operation_type: u32, texture_frames: [dynamic]RSM_TextureFrame } -RSM_TexturesKeyframe :: struct { texture_index: u32, texture_keyframes: [dynamic]RSM_TextureKeyframe } - -RSM_Face :: struct { - length: u32, - vertex_position_indices: [3]u16, - texture_coordinate_indices:[3]u16, - texture_index: u16, - padding: u16, - two_sided: i32, - smooth_group: i32, - smooth_group_extra: [dynamic]i32, -} - -RSM_TextureCoordinate :: struct { color: u32, coordinates: [2]f32 } - -RSM_Node :: struct { - node_name: string, - parent_node_name: string, - texture_indices: [dynamic]u32, - texture_names: [dynamic]string, - offset_matrix: matrix[3,3] f32, - translation1: [3]f32, - translation2: [3]f32, - rotation_angle: f32, - rotation_axis: [3]f32, - scale: [3]f32, - vertex_positions: [dynamic][3]f32, - texture_coordinates: [dynamic]RSM_TextureCoordinate, - faces: [dynamic]RSM_Face, - scale_keyframes: [dynamic]RSM_ScaleKeyframe, - rotation_keyframes: [dynamic]RSM_RotationKeyframe, - translation_keyframes: [dynamic]RSM_TranslationKeyframe, - textures_keyframes: [dynamic]RSM_TexturesKeyframe, -} - -RSM_Model :: struct { - version: Version, - animation_length:u32, - shade_type: u32, - alpha: u8, - frames_per_second:f32, - texture_names: [dynamic]string, - root_node_names: [dynamic]string, - nodes: [dynamic]RSM_Node, -} - -RSM_Parse_Error :: enum { - None, - UnexpectedEOF, - InvalidSignature, - InvalidUtf8, -} - -RSM_Reader :: struct { - data: []u8, - at: int, -} - -parse_rsm :: proc(data: []u8) -> (RSM_Model, RSM_Parse_Error) { - model := RSM_Model{} - r := RSM_Reader{data = data} - ok: bool - sig: string - alpha: u8 - fps: f32 - texture_count, root_count, node_count: u32 - count, vp_count, tc_count, face_count, s_count, r_count, t_count, tk_count, key_count, frame_count: u32 - name, root: string - idx: u32 - v: [3]f32 - sg: i32 - - sig, ok = read_fixed_string(&r, 4) - if !ok || sig != "GRSM" { - fmt.printfln("signature is %v") - return model, .InvalidSignature - } - major, ok1 := read_u8(&r) - minor, ok2 := read_u8(&r) - if !(ok1 && ok2) { return model, .UnexpectedEOF } - model.version = Version{major = major, minor = minor} - - animation_length, ok3 := read_u32(&r) - shade_type, ok4 := read_u32(&r) - if !(ok3 && ok4) { return model, .UnexpectedEOF } - model.animation_length = animation_length - model.shade_type = shade_type - - if version_ge(model.version, 1, 4) { - alpha, ok = read_u8(&r) - if !ok { return model, .UnexpectedEOF } - model.alpha = alpha - } - if version_below(model.version, 2, 2) { - if r.at+16 > len(r.data) { return model, .UnexpectedEOF } - r.at += 16 - } - if version_ge(model.version, 2, 2) { - fps, ok = read_f32(&r) - if !ok { return model, .UnexpectedEOF } - model.frames_per_second = fps - } - - if version_below(model.version, 2, 3) { - texture_count, ok = read_u32(&r) - if !ok { return model, .UnexpectedEOF } - for _ in 0.. 0 { - for _ in 0.. int { - for i := 0; i < len(textures); i+=1 { - if textures[i].path == path { - return i - } - } - - index := len(textures) - - c_path := strings.clone_to_cstring(path) - defer delete(c_path) - - img_size: [2]i32 - pixels := stbi.load(c_path, &img_size.x, &img_size.y, nil, 4); - assert(pixels != nil) - - append(textures, TextureHolder{ - pixels = pixels, - w = img_size.x, - h = img_size.y, - path = path, - }) - - return index -} - -uploadTextures :: proc(device: ^sdl.GPUDevice, textures: ^[dynamic]TextureHolder) { - setup_cmd := sdl.AcquireGPUCommandBuffer(device) - if setup_cmd == nil { - fmt.println("AcquireGPUCommandBuffer failed:", sdl.GetError()) - return - } - fmt.println("copying textures to transfer buffer") - for &texture in textures { - texture.texture = sdl.CreateGPUTexture(device, sdl.GPUTextureCreateInfo{ - format = .R8G8B8A8_UNORM, - usage = {.SAMPLER}, - width = u32(texture.w), - height = u32(texture.h), - layer_count_or_depth = 1, - num_levels = 1, - }); assert(texture.texture != nil) - - tb_tex := sdl.CreateGPUTransferBuffer(device, sdl.GPUTransferBufferCreateInfo{ - usage = .UPLOAD, - size = u32(texture.w * texture.h * 4), - props = 0, - }); assert(tb_tex != nil) - - tex_mapped := sdl.MapGPUTransferBuffer(device, tb_tex, false); assert(tex_mapped != nil) - mem.copy_non_overlapping(tex_mapped, texture.pixels, int(texture.w * texture.h * 4)) - sdl.UnmapGPUTransferBuffer(device, tb_tex) - texture.transferBuffer = tb_tex - } - - cp := sdl.BeginGPUCopyPass(setup_cmd) - if cp == nil { - fmt.println("BeginGPUCopyPass failed:", sdl.GetError()) - return - } - for &texture in textures { - fmt.println("transferring textures") - fmt.println("tex ptr:", texture, "w/h:", texture.w, texture.h) - sdl.UploadToGPUTexture(cp, - { - transfer_buffer = texture.transferBuffer, - offset = 0, - pixels_per_row = u32(texture.w), - rows_per_layer = u32(texture.h), - }, - {texture = texture.texture, w = u32(texture.w), h = u32(texture.h), d = 1}, - false, - ) - sdl.ReleaseGPUTransferBuffer(device, texture.transferBuffer) - fmt.println("transferred textures") - } - - sdl.EndGPUCopyPass(cp) - if !sdl.SubmitGPUCommandBuffer(setup_cmd) { - fmt.println("SubmitGPUCommandBuffer (setup) failed:", sdl.GetError()) - return - } - -} - - -loadGndModel :: proc(device: ^sdl.GPUDevice, model: ^format.GND_Data, vertices: ^[dynamic]shared.Vertex, indices: ^[dynamic]u32, nodes: ^[dynamic]GndNode, textures: ^[dynamic]TextureHolder) -> (vbuf: ^sdl.GPUBuffer, ibuf: ^sdl.GPUBuffer) { - clear(vertices) - clear(indices) - clear(nodes) - - fmt.println("version ", model.info.version) - - textureMap : [dynamic]int - defer delete(textureMap) - - fmt.printfln("loading model texture %v", model.textures) - for textureName in model.textures { - textureName, _ := strings.replace_all(textureName, "\\", "/") - - full_path, err := filepath.join({"/home/pavel/neoragnarok_backup/kro_client/data/texture", textureName}); assert(err == nil) - full_path, err = filepath.clean(full_path); assert(err == nil) - - append(&textureMap, loadTexture(full_path, textures)) - } - - width := model.info.width - height := model.info.height - - for node_idx := 0; node_idx < len(model.tiles); node_idx+= 1 { - x := i32(node_idx) % width - y := i32(node_idx) / width - node := &model.tiles[node_idx] - // fmt.println("h_ne", node.h_ne) - // fmt.println("h_nw", node.h_nw) - // fmt.println("h_se", node.h_se) - // fmt.println("h_sw", node.h_sw) - // fmt.println("east_surface_index", node.east_surface_index) - // fmt.println("north_surface_index", node.north_surface_index) - // fmt.println("top_surface_index", node.top_surface_index) - - - - surface := model.surfaces[0] - - if node.top_surface_index != -1 { - surface = model.surfaces[node.top_surface_index] - } - - fmt.println(surface.u, surface.v) - - n := GndNode{ - start = len(indices), - node = node, - texture = textureMap[0], - } - - if surface.texture_index != -1 { - n.texture = textureMap[surface.texture_index] - } - - // fmt.println("top_surface_index", surface.u) - - - offset := len(vertices) - - pos := shared.Vec2{f32(x) - f32(model.info.width)/2.0, f32(y) - f32(model.info.height)/2.0} - - // node.h_ne = 0 - // node.h_nw = 0 - // node.h_se = 0 - // node.h_sw = 0 - - append(vertices, shared.Vertex{ - pos = {pos.x * model.info.zoom,-node.h_nw, -pos.y * model.info.zoom}, - uv = {surface.u[2], surface.v[2]}, - }) - append(vertices, shared.Vertex{ - pos = {(pos.x+1)* model.info.zoom,-node.h_ne,-pos.y* model.info.zoom}, - uv = {surface.u[3], surface.v[3]}, - }) - append(vertices, shared.Vertex{ - pos = {pos.x* model.info.zoom,-node.h_sw,-(pos.y+1)* model.info.zoom}, - uv = {surface.u[1], surface.v[1]}, - }) - append(vertices, shared.Vertex{ - pos = {(pos.x+1)* model.info.zoom,-node.h_se,-(pos.y+1)* model.info.zoom}, - uv = {surface.u[0], surface.v[0]}, - }) - - append(indices, u32(offset)) - append(indices, u32(offset+1)) - append(indices, u32(offset+2)) - - append(indices, u32(offset+1)) - append(indices, u32(offset+3)) - append(indices, u32(offset+2)) - - n.end = len(indices) - - append(nodes, n) - - } - - 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 - } - - 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 - } - defer sdl.ReleaseGPUTransferBuffer(device, tb) - - mapped := transmute([^]byte)sdl.MapGPUTransferBuffer(device, tb, false) - if mapped == nil { - fmt.println("MapGPUTransferBuffer failed:", sdl.GetError()) - return - } - 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(setup_cmd) - if cp == nil { - fmt.println("BeginGPUCopyPass failed:", sdl.GetError()) - return - } - - vert_src := sdl.GPUTransferBufferLocation{transfer_buffer = tb, offset = 0} - vert_dst := sdl.GPUBufferRegion{buffer = vbuf, 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 = ibuf, offset = 0, size = u32(ind_byte_count)} - sdl.UploadToGPUBuffer(cp, ind_src, ind_dst, false) - - sdl.EndGPUCopyPass(cp) - if !sdl.SubmitGPUCommandBuffer(setup_cmd) { - fmt.println("SubmitGPUCommandBuffer (setup) failed:", sdl.GetError()) - return - } - } - - return vbuf, ibuf -} - -walk :: proc(dir: string, models: ^[dynamic]format.GND_Data) { - 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, ".gnd") { - data, _ := os.read_entire_file(path, context.allocator) - parsed, err := format.parse_gnd(data) - if err != nil { - fmt.printfln("%v", err) - } else { - append_elem(models, parsed) - } - } - } -} - -loadRsw :: proc() -> format.RSW_Data { - prontera := "/home/pavel/neoragnarok_backup/kro_client/data/aldebaran.rsw" - data, _ := os.read_entire_file(prontera, context.allocator) - parsed, err := format.parse_rsw(data) - if err != nil { - fmt.printfln("%v", err) - panic("aaa") - } - return parsed -} - -loadRsmModel :: proc(device: ^sdl.GPUDevice, model: ^format.RSM_Model, modelIndex: int, nodes: ^[dynamic]RsmNode, textures: ^[dynamic]TextureHolder, vbufs: ^[dynamic]^sdl.GPUBuffer, ibufs: ^[dynamic]^sdl.GPUBuffer, transform: matrix[4,4]f32) { - vertices: [dynamic]shared.Vertex - indices: [dynamic]u16 - - vbufIndex := len(vbufs) - ibufIndex := len(ibufs) - - - fmt.printfln("version %v", model.version) - - textureMap : [dynamic]int - defer delete(textureMap) - - fmt.printfln("loading model texture %v", model.texture_names[:]) - for textureName in model.texture_names { - textureName, _ := strings.replace_all(textureName, "\\", "/") - - full_path, err := filepath.join({"/home/pavel/neoragnarok_backup/kro_client/data/texture", textureName}); assert(err == nil) - full_path, err = filepath.clean(full_path); assert(err == nil) - - append(&textureMap, loadTexture(full_path, textures)) - } - - for node_idx := 0; node_idx < len(model.nodes); node_idx+= 1 { - textureOffset := (0) - node := &model.nodes[node_idx] - fmt.println("offset_matrix", node.offset_matrix) - fmt.println("node.translation1", node.translation1) - fmt.println("node.translation2", node.translation2) - fmt.println("node.scale", node.scale) - fmt.println("node.rotation_angle", node.rotation_angle) - fmt.println("node.rotation_axis", node.rotation_axis) - // fmt.println("node.scale_keyframes[:]", node.scale_keyframes[:]) - // fmt.println("node.texture_names[:]", node.texture_names[:]) - - if model.version.major >= 2 && model.version.minor > 2 { - textureOffset = (len(textures)) - } - - for textureName in node.texture_names { - fmt.printfln("loading texture %s", textureName) - full_path, err := filepath.join({"/home/pavel/neoragnarok_backup/kro_client/data/texture", textureName}); assert(err == nil) - full_path, err = filepath.clean(full_path); assert(err == nil) - full_path, _ = strings.replace_all(full_path, "\\", "/") - - append(&textureMap, loadTexture(full_path, textures)) - } - - for face in node.faces { - n := RsmNode{ - start = len(indices), - node = node, - texture = textureMap[int(face.texture_index) + textureOffset], - modelIndex = modelIndex, - vbufIndex = vbufIndex, - ibufIndex = ibufIndex, - transform = transform, - } - - - 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, shared.Vertex{ - pos = pos, - uv = uv, - }) - - append(&indices, u16(len(vertices)-1)) - } - n.end = len(indices) - - append(nodes, n) - } - - } - - vbuf_info := sdl.GPUBufferCreateInfo{ - usage = sdl.GPUBufferUsageFlags{.VERTEX}, - size = u32(len(vertices) * size_of(vertices[0])), - props = 0, - } - vbuf := sdl.CreateGPUBuffer(device, vbuf_info); assert(vbuf != nil) - append(vbufs, vbuf) - - ibuf_info := sdl.GPUBufferCreateInfo{ - usage = sdl.GPUBufferUsageFlags{.INDEX}, - size = u32(len(indices) * size_of(indices[0])), - props = 0, - } - ibuf := sdl.CreateGPUBuffer(device, ibuf_info); assert(ibuf != nil) - append(ibufs, ibuf) - - - { - setup_cmd := sdl.AcquireGPUCommandBuffer(device) - if setup_cmd == nil { - fmt.println("AcquireGPUCommandBuffer failed:", sdl.GetError()) - return - } - - 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()) - panic("fail") - } - defer sdl.ReleaseGPUTransferBuffer(device, tb) - - mapped := transmute([^]byte)sdl.MapGPUTransferBuffer(device, tb, false) - if mapped == nil { - fmt.println("MapGPUTransferBuffer failed:", sdl.GetError()) - panic("fail") - } - 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(setup_cmd) - if cp == nil { - fmt.println("BeginGPUCopyPass failed:", sdl.GetError()) - panic("fail") - } - - vert_src := sdl.GPUTransferBufferLocation{transfer_buffer = tb, offset = 0} - vert_dst := sdl.GPUBufferRegion{buffer = vbuf, 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 = ibuf, offset = 0, size = u32(ind_byte_count)} - sdl.UploadToGPUBuffer(cp, ind_src, ind_dst, false) - - sdl.EndGPUCopyPass(cp) - if !sdl.SubmitGPUCommandBuffer(setup_cmd) { - fmt.println("SubmitGPUCommandBuffer (setup) failed:", sdl.GetError()) - return - } - } -} - -runGame :: proc(window: ^sdl.Window, device: ^sdl.GPUDevice, pipeline: ^sdl.GPUGraphicsPipeline) { - sampler := sdl.CreateGPUSampler(device, {}) - modelIndex := 0 - models: [dynamic]format.RSM_Model - - rsw := loadRsw() - - rsmVbufs: [dynamic]^sdl.GPUBuffer - rsmIbufs: [dynamic]^sdl.GPUBuffer - textures: [dynamic]TextureHolder - defer for texture in textures do sdl.ReleaseGPUTexture(device, texture.texture) - rsmNodes: [dynamic]RsmNode - - for object in rsw.objects { - modelPath, err1 := filepath.join({"/home/pavel/neoragnarok_backup/kro_client/data/model", object.model_name}); assert(err1 ==nil) - fmt.println(modelPath) - data, err := os.read_entire_file(modelPath, context.allocator) - if err != nil { - fmt.println(err) - panic("failed to read rsm") - } - fmt.println(object.model_name) - - parsed, err2 := format.parse_rsm(data) - if err2 != nil { - fmt.println(err2) - panic("failed to parse rsm") - } - modelIndex := len(models) - append_elem(&models, parsed) - - T := linalg.matrix4_translate(object.transform.position) - S := linalg.matrix4_scale(object.transform.scale) - - Rx := linalg.matrix4_rotate_f32(object.transform.rotation_deg[0], {1,0,0}) - Ry := linalg.matrix4_rotate_f32(object.transform.rotation_deg[1], {0,1,0}) - Rz := linalg.matrix4_rotate_f32(object.transform.rotation_deg[2], {0,0,1}) - - R := Rz * Ry * Rx - - M := T * R * S - - loadRsmModel(device, &parsed, modelIndex, &rsmNodes, &textures, &rsmVbufs, &rsmIbufs, M) - } - - gnd, err1 := filepath.join({"/home/pavel/neoragnarok_backup/kro_client/data", rsw.ground_file}); assert(err1 ==nil) - data, _ := os.read_entire_file(gnd, context.allocator) - - gndModel, err := format.parse_gnd(data); assert(err == nil) - - gndVertices: [dynamic]shared.Vertex - gndIndices: [dynamic]u32 - gndNodes: [dynamic]GndNode - - gndVbuf, gndIbuf := loadGndModel(device, &gndModel, &gndVertices, &gndIndices, &gndNodes, &textures) - defer sdl.ReleaseGPUBuffer(device, gndIbuf) - defer sdl.ReleaseGPUBuffer(device, gndVbuf) - - uploadTextures(device, &textures) - - init_yaw := shared.rotor_from_axis_angle(shared.Vec3{0, 1, 0}, 0.9) - init_right := shared.rotate_vec3(init_yaw, shared.Vec3{1, 0, 0}) - init_pitch := shared.rotor_from_axis_angle(init_right, -0.45) - - camera := shared.Camera{ - center = shared.Vec3{0, 0.5, 0}, - distance = 8, - orientation = shared.rotor_normalize(shared.rotor_mul(init_pitch, init_yaw)), - fov_deg = 60, - } - - - start := time.tick_now() - last := start - left_down := false - middle_down := false - running := true - - depthTex : ^sdl.GPUTexture - dti : sdl.GPUDepthStencilTargetInfo - for running { - now := time.tick_now() - elapsed_ms := time.duration_milliseconds(time.tick_diff(start, now)) - dt_ms := time.duration_milliseconds(time.tick_diff(last, 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.key == sdl.K_N { - // modelIndex += 1 - // sdl.ReleaseGPUBuffer(device, gndIbuf) - // sdl.ReleaseGPUBuffer(device, gndVbuf) - // for texture in gndTextures do sdl.ReleaseGPUTexture(device, texture.texture) - // gndVbuf, gndIbuf, gndTextures = loadGndModel(device, &gndModel, &gndVertices, &gndIndices, &gndNodes) - // } - } - } - - x_rel: f32 = 0 - y_rel: f32 = 0 - _ = sdl.GetRelativeMouseState(&x_rel, &y_rel) - - if left_down { - yaw_r := shared.rotor_from_axis_angle(shared.Vec3{0, 1, 0}, -x_rel * 0.006) - q1 := shared.rotor_normalize(shared.rotor_mul(yaw_r, camera.orientation)) - - right_axis := shared.vec3_normalize(shared.rotate_vec3(q1, shared.Vec3{1, 0, 0})) - pitch_r := shared.rotor_from_axis_angle(right_axis, -y_rel * 0.006) - q2 := shared.rotor_normalize(shared.rotor_mul(pitch_r, q1)) - - fwd2 := shared.camera_forward(shared.Camera{center = camera.center, distance = camera.distance, orientation = q2, fov_deg = camera.fov_deg}) - if math.abs(shared.vec3_dot(fwd2, shared.Vec3{0, 1, 0})) < 0.98 { - camera.orientation = q2 - } else { - camera.orientation = q1 - } - } - - if middle_down { - right := shared.camera_right(camera) - up := shared.camera_up(camera) - pan_speed := 0.008 * camera.distance - camera.center = camera.center + right * -x_rel * pan_speed - camera.center = camera.center + up * y_rel * pan_speed - } - - keys := sdl.GetKeyboardState(nil) - forward := shared.camera_forward(camera) - right := shared.camera_right(camera) - up := shared.camera_up(camera) - move_speed := camera.distance * dt * 1.4 - - if keys[sdl.Scancode.W] { - camera.center = camera.center + forward * move_speed - } - if keys[sdl.Scancode.S] { - camera.center = camera.center + forward * -move_speed - } - if keys[sdl.Scancode.A] { - camera.center = camera.center + right * -move_speed - } - if keys[sdl.Scancode.D] { - camera.center = camera.center + right * move_speed - } - - 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 - } - - if depthTex == nil { - - depthTex = sdl.CreateGPUTexture(device, { - format = .D32_FLOAT, - usage = {.DEPTH_STENCIL_TARGET}, - width = swap_w, - height = swap_h, - layer_count_or_depth = 1, - num_levels = 1, - }) - - dti = sdl.GPUDepthStencilTargetInfo{ - texture = depthTex, - clear_depth = 1.0, - load_op = .CLEAR, - store_op = .STORE, - } - } - - - 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, &dti) - 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 = gndVbuf, offset = 0} - sdl.BindGPUVertexBuffers(rp, 0, &vb_binding, 1) - ib_binding := sdl.GPUBufferBinding{buffer = gndIbuf, offset = 0} - sdl.BindGPUIndexBuffer(rp, ib_binding, ._32BIT) - - - - aspect := f32(swap_w) / f32(swap_h) - proj := linalg.matrix4_perspective(linalg.to_radians(camera.fov_deg), aspect, 0.5, 2000.0) - view := linalg.matrix4_look_at(shared.camera_position(camera), camera.center, shared.camera_up(camera)) - vp_mat := proj * view - - for mesh in gndNodes { - node := mesh.node - - pc := Push_Constants{} - - pc.mvp = vp_mat * linalg.MATRIX4F32_IDENTITY - pc.color = [4]f32{1, 0, 0, 1.0} - - sdl.BindGPUFragmentSamplers(rp, 0, &(sdl.GPUTextureSamplerBinding{ - texture = textures[mesh.texture].texture, - sampler = sampler, - }), 1) - - sdl.PushGPUVertexUniformData(cmd, 0, &pc, u32(size_of(Push_Constants))) - sdl.DrawGPUIndexedPrimitives(rp, u32(mesh.end-mesh.start), 1, u32(mesh.start), 0, 0) - } - - - renderModel(&models, elapsed_ms, rsmNodes, &textures, sampler, cmd, vp_mat, rp, &rsmVbufs, &rsmIbufs) - - sdl.EndGPURenderPass(rp) - - if !sdl.SubmitGPUCommandBuffer(cmd) { - fmt.println("SubmitGPUCommandBuffer failed:", sdl.GetError()) - break - } - } -} - -renderModel :: proc(models: ^[dynamic]format.RSM_Model, elapsed_ms: f64, nodes: [dynamic]RsmNode, textures: ^[dynamic]TextureHolder, sampler: ^sdl.GPUSampler, cmd: ^sdl.GPUCommandBuffer, vp_mat: matrix[4,4]f32, rp: ^sdl.GPURenderPass, vbufs: ^[dynamic]^sdl.GPUBuffer, ibufs: ^[dynamic]^sdl.GPUBuffer) { - for mesh in nodes { - vb_binding := sdl.GPUBufferBinding{buffer = vbufs[mesh.vbufIndex], offset = 0} - sdl.BindGPUVertexBuffers(rp, 0, &vb_binding, 1) - ib_binding := sdl.GPUBufferBinding{buffer = ibufs[mesh.ibufIndex], offset = 0} - sdl.BindGPUIndexBuffer(rp, ib_binding, ._16BIT) - - model := &models[mesh.modelIndex] - animation_length := model.animation_length - fps := model.frames_per_second - frame_delay : f32 - total_frames : u32 - - if fps == 0 { - total_seconds := f32(animation_length) / 1000 - total_frames = u32(total_seconds * 30) - frame_delay = 1000 / f32(30) - } else { - total_frames = animation_length - frame_delay = 1000 / fps - } - - current_frame := u32(f32(elapsed_ms) / frame_delay) % total_frames - - node := mesh.node - rotation := linalg.quaternion_angle_axis(node.rotation_angle, node.rotation_axis) - - if len(node.rotation_keyframes) > 0 { - keyframe_idx := 0 - for i := 0; i < len(node.rotation_keyframes); i+= 1 { - keyframe := node.rotation_keyframes[i] - if u32(keyframe.frame) <= current_frame { - keyframe_idx = i - } else do break - } - - q := node.rotation_keyframes[keyframe_idx].quaternion - rotation = quaternion(imag=q[0], jmag=q[1], kmag=q[2], real=q[3]) - } - - rotation = linalg.quaternion_normalize(rotation) - - scale := node.scale - if len(node.scale_keyframes) > 0 { - keyframe_idx := 0 - for i := 0; i < len(node.scale_keyframes); i+= 1 { - keyframe := node.scale_keyframes[i] - if u32(keyframe.frame) <= current_frame { - keyframe_idx = i - } else do break - } - scale = node.scale_keyframes[keyframe_idx].scale - } - - translation := [3]f32{0,0,0} - if(len(node.translation_keyframes) > 0) { - keyframe_idx := 0 - for i := 0; i < len(node.translation_keyframes); i+= 1 { - keyframe := node.translation_keyframes[i] - if u32(keyframe.frame) <= current_frame { - keyframe_idx = i - } else do break - } - translation = node.translation_keyframes[keyframe_idx].translation - } - - r := linalg.matrix3_from_quaternion(rotation) - - s := matrix[3,3]f32{ - scale[0], 0, 0 , - 0, scale[1], 0 , - 0, 0, scale[2], - } - - a3 := r * node.offset_matrix * s - - t := node.translation1 + node.translation2 + translation - - // 4x4 affine matrix - model_mat := 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 , - } - - pc := Push_Constants{} - - pc.mvp = vp_mat * mesh.transform * model_mat - pc.color = [4]f32{1, 0, 0, 1.0} - sdl.BindGPUFragmentSamplers(rp, 0, &(sdl.GPUTextureSamplerBinding{ - texture = textures[mesh.texture].texture, - sampler = sampler, - }), 1) - - sdl.PushGPUVertexUniformData(cmd, 0, &pc, u32(size_of(Push_Constants))) - sdl.DrawGPUIndexedPrimitives(rp, u32(mesh.end-mesh.start), 1, u32(mesh.start), 0, 0) - } -} \ No newline at end of file diff --git a/src/main.odin b/src/main.odin index 15293cb..e03e621 100644 --- a/src/main.odin +++ b/src/main.odin @@ -1,12 +1,201 @@ package main +import "core:c" import "core:fmt" +import "core:math" +import "core:mem" import "core:os" -import sdl "vendor:sdl3" -import "rsmview" -import "gndview" -import "shared" +import "core:time" +import sdl "vendor:sdl3" + +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: Mat4, + 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) @@ -17,7 +206,7 @@ read_file_or_fail :: proc(path: string) -> []u8 { return file_bytes } -create_gpu_shader :: proc(device: ^sdl.GPUDevice, path: string, stage: sdl.GPUShaderStage, num_samplers: u32) -> ^sdl.GPUShader { +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 @@ -29,7 +218,7 @@ create_gpu_shader :: proc(device: ^sdl.GPUDevice, path: string, stage: sdl.GPUSh entrypoint = cstring("main"), format = sdl.GPUShaderFormat{.SPIRV}, stage = stage, - num_samplers = num_samplers, + num_samplers = 0, num_storage_textures = 0, num_storage_buffers = 0, num_uniform_buffers = 1, @@ -44,21 +233,39 @@ create_gpu_shader :: proc(device: ^sdl.GPUDevice, path: string, stage: sdl.GPUSh 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 -} +copy_vertices_to_gpu :: proc(device: ^sdl.GPUDevice, cmd: ^sdl.GPUCommandBuffer, vertices: []Vertex, dst: ^sdl.GPUBuffer) -> bool { + byte_count := len(vertices) * size_of(Vertex) + tb_info := sdl.GPUTransferBufferCreateInfo{ + usage = .UPLOAD, + size = u32(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) -GPU_Vertex :: struct { - position: [3]f32, - uv: [2]f32, + mapped := sdl.MapGPUTransferBuffer(device, tb, false) + if mapped == nil { + fmt.println("MapGPUTransferBuffer failed:", sdl.GetError()) + return false + } + mem.copy_non_overlapping(mapped, raw_data(vertices), byte_count) + sdl.UnmapGPUTransferBuffer(device, tb) + + cp := sdl.BeginGPUCopyPass(cmd) + if cp == nil { + fmt.println("BeginGPUCopyPass failed:", sdl.GetError()) + return false + } + + src := sdl.GPUTransferBufferLocation{transfer_buffer = tb, offset = 0} + dst_region := sdl.GPUBufferRegion{buffer = dst, offset = 0, size = u32(byte_count)} + sdl.UploadToGPUBuffer(cp, src, dst_region, false) + sdl.EndGPUCopyPass(cp) + return true } main :: proc() { @@ -95,13 +302,13 @@ main :: proc() { return } - vertex_shader := create_gpu_shader(device, "shaders/cubes.vert.spv", .VERTEX, 0) + 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, 1) + fragment_shader := create_gpu_shader(device, "shaders/cubes.frag.spv", .FRAGMENT) if fragment_shader == nil { return } @@ -113,12 +320,11 @@ main :: proc() { return } - vb_descs := []sdl.GPUVertexBufferDescription{ - {slot = 0, pitch = size_of(shared.Vertex), input_rate = .VERTEX, instance_step_rate = 0}, + vb_descs := [1]sdl.GPUVertexBufferDescription{ + {slot = 0, pitch = size_of(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))}, + vattrs := [1]sdl.GPUVertexAttribute{ + {location = 0, buffer_slot = 0, format = .FLOAT3, offset = 0}, } blend := sdl.GPUColorTargetBlendState{ @@ -136,15 +342,15 @@ main :: proc() { {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, - }, + 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, @@ -168,15 +374,15 @@ main :: proc() { 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, + 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 = .D32_FLOAT, - has_depth_stencil_target = true, + depth_stencil_format = .INVALID, + has_depth_stencil_target = false, }, props = 0, } @@ -188,16 +394,249 @@ main :: proc() { } defer sdl.ReleaseGPUGraphicsPipeline(device, pipeline) - - pipeline_create_info := sdl.GPUGraphicsPipelineCreateInfo{ - primitive_type = .TRIANGLELIST, - rasterizer_state = { - fill_mode = .LINE, - cull_mode = .FRONT, + vertices := [36]Vertex{ + {pos = Vec3{-0.5, -0.5, -0.5}}, {pos = Vec3{0.5, 0.5, -0.5}}, {pos = Vec3{0.5, -0.5, -0.5}}, + {pos = Vec3{-0.5, -0.5, -0.5}}, {pos = Vec3{-0.5, 0.5, -0.5}}, {pos = Vec3{0.5, 0.5, -0.5}}, + {pos = Vec3{-0.5, -0.5, 0.5}}, {pos = Vec3{0.5, -0.5, 0.5}}, {pos = Vec3{0.5, 0.5, 0.5}}, + {pos = Vec3{-0.5, -0.5, 0.5}}, {pos = Vec3{0.5, 0.5, 0.5}}, {pos = Vec3{-0.5, 0.5, 0.5}}, + {pos = Vec3{-0.5, 0.5, 0.5}}, {pos = Vec3{-0.5, 0.5, -0.5}}, {pos = Vec3{-0.5, -0.5, -0.5}}, + {pos = Vec3{-0.5, -0.5, -0.5}}, {pos = Vec3{-0.5, -0.5, 0.5}}, {pos = Vec3{-0.5, 0.5, 0.5}}, + {pos = Vec3{0.5, 0.5, 0.5}}, {pos = Vec3{0.5, -0.5, -0.5}}, {pos = Vec3{0.5, 0.5, -0.5}}, + {pos = Vec3{0.5, -0.5, -0.5}}, {pos = Vec3{0.5, 0.5, 0.5}}, {pos = Vec3{0.5, -0.5, 0.5}}, + {pos = Vec3{-0.5, -0.5, -0.5}}, {pos = Vec3{0.5, -0.5, -0.5}}, {pos = Vec3{0.5, -0.5, 0.5}}, + {pos = Vec3{-0.5, -0.5, -0.5}}, {pos = Vec3{0.5, -0.5, 0.5}}, {pos = Vec3{-0.5, -0.5, 0.5}}, + {pos = Vec3{-0.5, 0.5, -0.5}}, {pos = Vec3{0.5, 0.5, 0.5}}, {pos = Vec3{0.5, 0.5, -0.5}}, + {pos = Vec3{-0.5, 0.5, -0.5}}, {pos = Vec3{-0.5, 0.5, 0.5}}, {pos = Vec3{0.5, 0.5, 0.5}}, + } + + vbuf_info := sdl.GPUBufferCreateInfo{ + usage = sdl.GPUBufferUsageFlags{.VERTEX}, + size = u32(len(vertices) * size_of(Vertex)), + props = 0, + } + vbuf := sdl.CreateGPUBuffer(device, vbuf_info) + if vbuf == nil { + fmt.println("CreateGPUBuffer failed:", sdl.GetError()) + return + } + defer sdl.ReleaseGPUBuffer(device, vbuf) + + { + setup_cmd := sdl.AcquireGPUCommandBuffer(device) + if setup_cmd == nil { + fmt.println("AcquireGPUCommandBuffer failed:", sdl.GetError()) + return + } + if !copy_vertices_to_gpu(device, setup_cmd, vertices[:], vbuf) { + _ = sdl.CancelGPUCommandBuffer(setup_cmd) + return + } + if !sdl.SubmitGPUCommandBuffer(setup_cmd) { + fmt.println("SubmitGPUCommandBuffer (setup) failed:", sdl.GetError()) + return + } + } + + 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) + } + } + } + + 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) + + aspect := f32(swap_w) / f32(swap_h) + proj := mat4_perspective(camera.fov_deg, aspect, 0.1, 300.0) + view := mat4_look_at(camera_position(camera), camera.center, camera_up(camera)) + vp_mat := mat4_mul(proj, view) + + for cube in cubes { + model := mat4_mul(mat4_translate(cube.pos), mat4_scale_uniform(cube.scale)) + pc := Push_Constants{} + pc.mvp = mat4_mul(vp_mat, model) + pc.color = [4]f32{cube.color[0], cube.color[1], cube.color[2], 1.0} + sdl.PushGPUVertexUniformData(cmd, 0, &pc, u32(size_of(Push_Constants))) + sdl.PushGPUFragmentUniformData(cmd, 0, &pc, u32(size_of(Push_Constants))) + sdl.DrawGPUPrimitives(rp, 36, 1, 0, 0) + } + + sdl.EndGPURenderPass(rp) + + if !sdl.SubmitGPUCommandBuffer(cmd) { + fmt.println("SubmitGPUCommandBuffer failed:", sdl.GetError()) + break } } - - gndview.runGame(window, device, pipeline) _ = sdl.WaitForGPUIdle(device) -} \ No newline at end of file +} diff --git a/src/rsmview/rsmview.odin b/src/rsmview/rsmview.odin deleted file mode 100644 index 53c9a46..0000000 --- a/src/rsmview/rsmview.odin +++ /dev/null @@ -1,646 +0,0 @@ -package rsmview - -import sdl "vendor:sdl3" -import "core:os" -import "core:strings" -import "core:path/filepath" -import "core:fmt" -import stbi "vendor:stb/image" -import "core:time" -import "core:mem" -import "core:math" -import "../format" -import "../shared" -import "core:math/linalg" -import "core:c" - -TextureHolder :: struct { - texture: ^sdl.GPUTexture, - pixels: [^]byte, - transferBuffer: ^sdl.GPUTransferBuffer, - w: i32, - h: i32, -} - -Node :: struct { - start: int, - end: int, - texture: u16, - node: ^format.RSM_Node, - textures: []sdl.GPUTexture, -} - -Push_Constants :: struct { - mvp: matrix[4,4]f32, - color: [4]f32, -} - -last_path_component :: proc(s: string) -> string { - last_slash := strings.last_index_byte(s, '/') - last_backslash := strings.last_index_byte(s, '\\') - last := max(last_slash, last_backslash) - if last < 0 do return s - return s[last+1:] -} - -find_texture_by_basename :: proc(root, wanted_name: string) -> (string, bool) { - wanted_lower := strings.to_lower(last_path_component(wanted_name), context.temp_allocator) - return find_texture_by_basename_walk(root, wanted_lower) -} - -find_texture_by_basename_walk :: proc(dir, wanted_lower: string) -> (string, bool) { - f, err := os.open(dir) - if err != nil do return "", false - defer os.close(f) - - entries, _ := os.read_dir(f, 0, context.temp_allocator) - - for entry in entries { - path, join_err := filepath.join({dir, entry.name}) - if join_err != nil do continue - - if entry.type == .Directory { - if resolved, found := find_texture_by_basename_walk(path, wanted_lower); found { - return resolved, true - } - continue - } - - name_lower := strings.to_lower(entry.name, context.temp_allocator) - if name_lower == wanted_lower { - return path, true - } - } - - return "", false -} - - -loadModel :: proc(device: ^sdl.GPUDevice, model: ^format.RSM_Model, vertices: ^[dynamic]shared.Vertex, indices: ^[dynamic]u16, nodes: ^[dynamic]Node) -> (vbuf: ^sdl.GPUBuffer, ibuf: ^sdl.GPUBuffer, textures: [dynamic]TextureHolder) { - clear(vertices) - clear(indices) - clear(nodes) - - fmt.println("version %v", model.version) - - version := 0 - if model.version.major > 2 && model.version.minor > 2 { - version = 1 - } - - fmt.printfln("loading model texture %v", model.texture_names[:]) - for textureName in model.texture_names { - textureName, _ := strings.replace_all(textureName, "\\", "/") - - full_path, err := filepath.join({"/home/pavel/neoragnarok_backup/kro_client/data/texture/", textureName}); assert(err == nil) - full_path, err = filepath.clean(full_path); assert(err == nil) - - c_path := strings.clone_to_cstring(full_path) - defer delete(c_path) - - img_size: [2]i32 - pixels := stbi.load(c_path, &img_size.x, &img_size.y, nil, 4); - if pixels == nil { - if fallback_path, found := find_texture_by_basename("/home/pavel/neoragnarok_backup/kro_client/data/texture", textureName); found { - fmt.printfln("fallback texture match %q -> %q", textureName, fallback_path) - c_path := strings.clone_to_cstring(fallback_path) - defer delete(c_path) - pixels = stbi.load(c_path, &img_size.x, &img_size.y, nil, 4) - } - } - if pixels == nil { - fmt.printfln("missing model texture: %q", textureName) - continue - } - - texture := sdl.CreateGPUTexture(device, sdl.GPUTextureCreateInfo{ - format = .R8G8B8A8_UNORM, - usage = {.SAMPLER}, - width = u32(img_size.x), - height = u32(img_size.y), - layer_count_or_depth = 1, - num_levels = 1, - }); assert(texture != nil) - - texture_byte_size := img_size.x * img_size.y * 4 - - append(&textures, TextureHolder{ - texture = texture, - pixels = pixels, - w = img_size.x, - h = img_size.y, - }) - } - - for node_idx := 0; node_idx < len(model.nodes); node_idx+= 1 { - textureOffset := u16(0) - node := &model.nodes[node_idx] - fmt.println("offset_matrix", node.offset_matrix) - fmt.println("node.translation1", node.translation1) - fmt.println("node.translation2", node.translation2) - fmt.println("node.scale", node.scale) - fmt.println("node.rotation_angle", node.rotation_angle) - fmt.println("node.rotation_axis", node.rotation_axis) - // fmt.println("node.scale_keyframes[:]", node.scale_keyframes[:]) - // fmt.println("node.texture_names[:]", node.texture_names[:]) - - if model.version.major >= 2 && model.version.minor > 2 { - textureOffset = u16(len(textures)) - } - - fmt.printfln("texture offset %v", textureOffset) - - fmt.printfln("loading node texture %v", node.texture_names[:]) - for textureName in node.texture_names { - fmt.printfln("loading texture %s", textureName) - full_path, err := filepath.join({"/home/pavel/neoragnarok_backup/kro_client/data/texture/", textureName}); assert(err == nil) - full_path, err = filepath.clean(full_path); assert(err == nil) - full_path, _ = strings.replace_all(full_path, "\\", "/") - - c_path := strings.clone_to_cstring(full_path) - defer delete(c_path) - - img_size: [2]i32 - pixels := stbi.load(c_path, &img_size.x, &img_size.y, nil, 4) - - fmt.printfln("texture has size %v", img_size) - - texture := sdl.CreateGPUTexture(device, sdl.GPUTextureCreateInfo{ - format = .R8G8B8A8_UNORM, - usage = {.SAMPLER}, - width = u32(img_size.x), - height = u32(img_size.y), - layer_count_or_depth = 1, - num_levels = 1, - }); assert(texture != nil) - - texture_byte_size := img_size.x * img_size.y * 4 - - append(&textures, TextureHolder{ - texture = texture, - pixels = pixels, - w = img_size.x, - h = img_size.y, - }) - } - - - - for face in node.faces { - n := Node{ - start = len(indices), - node = node, - texture = face.texture_index + textureOffset, - } - - - 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, shared.Vertex{ - pos = pos, - uv = uv, - }) - - append(indices, u16(len(vertices)-1)) - } - n.end = len(indices) - - append(nodes, n) - } - - } - - 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 - } - - - fmt.println("copying textures to transfer buffer") - for &texture in textures { - tb_tex := sdl.CreateGPUTransferBuffer(device, sdl.GPUTransferBufferCreateInfo{ - usage = .UPLOAD, - size = u32(texture.w * texture.h * 4), - props = 0, - }); assert(tb_tex != nil) - - tex_mapped := sdl.MapGPUTransferBuffer(device, tb_tex, false); assert(tex_mapped != nil) - mem.copy_non_overlapping(tex_mapped, texture.pixels, int(texture.w * texture.h * 4)) - sdl.UnmapGPUTransferBuffer(device, tb_tex) - - texture.transferBuffer = tb_tex - } - fmt.println("copying textures to transfer buffer") - - 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 - } - defer sdl.ReleaseGPUTransferBuffer(device, tb) - - mapped := transmute([^]byte)sdl.MapGPUTransferBuffer(device, tb, false) - if mapped == nil { - fmt.println("MapGPUTransferBuffer failed:", sdl.GetError()) - return - } - 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(setup_cmd) - if cp == nil { - fmt.println("BeginGPUCopyPass failed:", sdl.GetError()) - return - } - - vert_src := sdl.GPUTransferBufferLocation{transfer_buffer = tb, offset = 0} - vert_dst := sdl.GPUBufferRegion{buffer = vbuf, 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 = ibuf, offset = 0, size = u32(ind_byte_count)} - sdl.UploadToGPUBuffer(cp, ind_src, ind_dst, false) - - fmt.println("transferring textures") - for texture in textures { - fmt.println("tex ptr:", texture, "w/h:", texture.w, texture.h) - sdl.UploadToGPUTexture(cp, - { - transfer_buffer = texture.transferBuffer, - offset = 0, - pixels_per_row = u32(texture.w), - rows_per_layer = u32(texture.h), - }, - {texture = texture.texture, w = u32(texture.w), h = u32(texture.h), d = 1}, - false, - ) - } - fmt.println("transferred textures") - - sdl.EndGPUCopyPass(cp) - if !sdl.SubmitGPUCommandBuffer(setup_cmd) { - fmt.println("SubmitGPUCommandBuffer (setup) failed:", sdl.GetError()) - return - } - } - - return vbuf, ibuf, textures -} - -walk :: proc(dir: string, models: ^[dynamic]format.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 := format.parse_rsm(data) - if err != nil { - fmt.printfln("%v", err) - } else { - for node in parsed.nodes { - if parsed.version.major == 2 && parsed.version.minor == 3{ - append_elem(models, parsed) - break - } - } - - } - } - } -} - - -runGame :: proc(window: ^sdl.Window, device: ^sdl.GPUDevice, pipeline: ^sdl.GPUGraphicsPipeline) {\ - sampler := sdl.CreateGPUSampler(device, {}) - modelIndex := 0 - models: [dynamic]format.RSM_Model - - walk("/home/pavel/neoragnarok_backup/kro_client/data", &models) - - vertices: [dynamic]shared.Vertex - indices: [dynamic]u16 - nodes: [dynamic]Node - - vbuf, ibuf, textures := loadModel(device, &models[modelIndex], &vertices, &indices, &nodes) - defer sdl.ReleaseGPUBuffer(device, ibuf) - defer sdl.ReleaseGPUBuffer(device, vbuf) - defer for texture in textures do sdl.ReleaseGPUTexture(device, texture.texture) - - init_yaw := shared.rotor_from_axis_angle(shared.Vec3{0, 1, 0}, 0.9) - init_right := shared.rotate_vec3(init_yaw, shared.Vec3{1, 0, 0}) - init_pitch := shared.rotor_from_axis_angle(init_right, -0.45) - - camera := shared.Camera{ - center = shared.Vec3{0, 0.5, 0}, - distance = 8, - orientation = shared.rotor_normalize(shared.rotor_mul(init_pitch, init_yaw)), - fov_deg = 60, - } - - - start := time.tick_now() - last := start - left_down := false - middle_down := false - running := true - - for running { - now := time.tick_now() - elapsed_ms := time.duration_milliseconds(time.tick_diff(start, now)) - dt_ms := time.duration_milliseconds(time.tick_diff(last, 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.key == sdl.K_N { - modelIndex += 1 - sdl.ReleaseGPUBuffer(device, ibuf) - sdl.ReleaseGPUBuffer(device, vbuf) - for texture in textures do sdl.ReleaseGPUTexture(device, texture.texture) - vbuf, ibuf, textures = loadModel(device, &models[modelIndex], &vertices, &indices, &nodes) - } - } - } - - x_rel: f32 = 0 - y_rel: f32 = 0 - _ = sdl.GetRelativeMouseState(&x_rel, &y_rel) - - if left_down { - yaw_r := shared.rotor_from_axis_angle(shared.Vec3{0, 1, 0}, -x_rel * 0.006) - q1 := shared.rotor_normalize(shared.rotor_mul(yaw_r, camera.orientation)) - - right_axis := shared.vec3_normalize(shared.rotate_vec3(q1, shared.Vec3{1, 0, 0})) - pitch_r := shared.rotor_from_axis_angle(right_axis, -y_rel * 0.006) - q2 := shared.rotor_normalize(shared.rotor_mul(pitch_r, q1)) - - fwd2 := shared.camera_forward(shared.Camera{center = camera.center, distance = camera.distance, orientation = q2, fov_deg = camera.fov_deg}) - if math.abs(shared.vec3_dot(fwd2, shared.Vec3{0, 1, 0})) < 0.98 { - camera.orientation = q2 - } else { - camera.orientation = q1 - } - } - - if middle_down { - right := shared.camera_right(camera) - up := shared.camera_up(camera) - pan_speed := 0.008 * camera.distance - camera.center = camera.center + right * -x_rel * pan_speed - camera.center = camera.center + up * y_rel * pan_speed - } - - keys := sdl.GetKeyboardState(nil) - forward := shared.camera_forward(camera) - right := shared.camera_right(camera) - up := shared.camera_up(camera) - move_speed := camera.distance * dt * 1.4 - - if keys[sdl.Scancode.W] { - camera.center = camera.center + forward * move_speed - } - if keys[sdl.Scancode.S] { - camera.center = camera.center + forward * -move_speed - } - if keys[sdl.Scancode.A] { - camera.center = camera.center + right * -move_speed - } - if keys[sdl.Scancode.D] { - camera.center = camera.center + right * move_speed - } - - 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(linalg.to_radians(camera.fov_deg), aspect, 0.1, 300.0) - view := linalg.matrix4_look_at(shared.camera_position(camera), camera.center, shared.camera_up(camera)) - vp_mat := proj * view - - renderModel(&models[modelIndex], elapsed_ms, nodes, &textures, sampler, cmd, vp_mat, rp) - - sdl.EndGPURenderPass(rp) - - if !sdl.SubmitGPUCommandBuffer(cmd) { - fmt.println("SubmitGPUCommandBuffer failed:", sdl.GetError()) - break - } - } -} - -renderModel :: proc(model: ^format.RSM_Model, elapsed_ms: f64, nodes: [dynamic]Node, textures: ^[dynamic]TextureHolder, sampler: ^sdl.GPUSampler, cmd: ^sdl.GPUCommandBuffer, vp_mat: matrix[4,4]f32, rp: ^sdl.GPURenderPass) { - animation_length := model.animation_length - fps := model.frames_per_second - frame_delay : f32 - total_frames : u32 - - if fps == 0 { - total_seconds := f32(animation_length) / 1000 - total_frames = u32(total_seconds * 30) - frame_delay = 1000 / f32(30) - } else { - total_frames = animation_length - frame_delay = 1000 / fps - } - - current_frame := u32(f32(elapsed_ms) / frame_delay) % total_frames - - for mesh in nodes { - node := mesh.node - rotation := linalg.quaternion_angle_axis(node.rotation_angle, node.rotation_axis) - - if len(node.rotation_keyframes) > 0 { - keyframe_idx := 0 - for i := 0; i < len(node.rotation_keyframes); i+= 1 { - keyframe := node.rotation_keyframes[i] - if u32(keyframe.frame) <= current_frame { - keyframe_idx = i - } else do break - } - - q := node.rotation_keyframes[keyframe_idx].quaternion - rotation = quaternion(imag=q[0], jmag=q[1], kmag=q[2], real=q[3]) - } - - rotation = linalg.quaternion_normalize(rotation) - - scale := node.scale - if len(node.scale_keyframes) > 0 { - keyframe_idx := 0 - for i := 0; i < len(node.scale_keyframes); i+= 1 { - keyframe := node.scale_keyframes[i] - if u32(keyframe.frame) <= current_frame { - keyframe_idx = i - } else do break - } - scale = node.scale_keyframes[keyframe_idx].scale - } - - translation := [3]f32{0,0,0} - if(len(node.translation_keyframes) > 0) { - keyframe_idx := 0 - for i := 0; i < len(node.translation_keyframes); i+= 1 { - keyframe := node.translation_keyframes[i] - if u32(keyframe.frame) <= current_frame { - keyframe_idx = i - } else do break - } - translation = node.translation_keyframes[keyframe_idx].translation - } - - r := linalg.matrix3_from_quaternion(rotation) - - s := matrix[3,3]f32{ - scale[0], 0, 0 , - 0, scale[1], 0 , - 0, 0, scale[2], - } - - a3 := r * node.offset_matrix * s - - t := node.translation1 + node.translation2 + translation - - // 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 , - } - - pc := Push_Constants{} - - pc.mvp = vp_mat * model - pc.color = [4]f32{1, 0, 0, 1.0} - sdl.BindGPUFragmentSamplers(rp, 0, &(sdl.GPUTextureSamplerBinding{ - texture = textures[mesh.texture].texture, - sampler = sampler, - }), 1) - - sdl.PushGPUVertexUniformData(cmd, 0, &pc, u32(size_of(Push_Constants))) - sdl.DrawGPUIndexedPrimitives(rp, u32(mesh.end-mesh.start), 1, u32(mesh.start), 0, 0) - } -} \ No newline at end of file diff --git a/src/shared/shared.odin b/src/shared/shared.odin deleted file mode 100644 index c19f6e7..0000000 --- a/src/shared/shared.odin +++ /dev/null @@ -1,98 +0,0 @@ -package shared - -import "core:math" - -Vec3 :: [3]f32 -Vec2 :: [2]f32 - -Camera :: struct { - center: Vec3, - distance: f32, - orientation: Rotor, - fov_deg: f32, -} - - -Rotor :: struct { - s, x, y, z: f32, -} - - -Vertex :: struct { - pos: Vec3, - uv: Vec2, -} - -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 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_cross(u, v) * 2.0 - return v + t * r.s + vec3_cross(u, t) -} - - -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 (c.center - camera_forward(c) * c.distance) -} \ No newline at end of file