package resource import "core:log" import "core:math" import bk "../backend" MAX_MESHES :: 256 // Legacy 48-byte vertex (position + normal + tex_coord + color). // Kept for backward compatibility with gen_mesh_custom. Mesh_Vertex :: struct { position: [3]f32, normal: [3]f32, tex_coord: [2]f32, color: [4]f32, } // 32-byte vertex (position + normal + tex_coord). Used by procedural generators. Mesh_Vertex_PNU :: struct { position: [3]f32, normal: [3]f32, tex_coord: [2]f32, } Internal_Mesh :: struct { vertex_buffer: bk.Buffer_Handle, index_buffer: bk.Buffer_Handle, vertex_count: i32, index_count: i32, layout: bk.Vertex_Layout, active: bool, } allocate_mesh_slot :: proc(state: ^Resource_State) -> (u32, bool) { for i in 1.. (id: u32, index_count: i32, ok: bool) { slot, slot_ok := allocate_mesh_slot(state) if !slot_ok { return 0, 0, false } ib_size := len(indices) * size_of(u32) vb, vb_ok := b.create_buffer_staged( vertex_data, vertex_data_size, {.Vertex}, ) if !vb_ok { log.error("gpu/resource: failed to create mesh vertex buffer") return 0, 0, false } ib, ib_ok := b.create_buffer_staged( raw_data(indices), ib_size, {.Index}, ) if !ib_ok { b.destroy_buffer(vb) log.error("gpu/resource: failed to create mesh index buffer") return 0, 0, false } state.meshes[slot] = Internal_Mesh{ vertex_buffer = vb, index_buffer = ib, vertex_count = vertex_count, index_count = i32(len(indices)), layout = layout, active = true, } return slot, i32(len(indices)), true } // Upload a []Mesh_Vertex slice (legacy 48-byte format). upload_mesh :: proc( state: ^Resource_State, b: ^bk.Backend, vertices: []Mesh_Vertex, indices: []u32, ) -> (id: u32, vertex_count, index_count: i32, ok: bool) { mid, ic, upload_ok := upload_mesh_raw( state, b, raw_data(vertices), len(vertices) * size_of(Mesh_Vertex), i32(len(vertices)), indices, bk.LAYOUT_POS_NORM_UV_COLOR, ) if !upload_ok { return 0, 0, 0, false } return mid, i32(len(vertices)), ic, true } get_mesh_layout :: proc(state: ^Resource_State, id: u32) -> (bk.Vertex_Layout, bool) { if id >= MAX_MESHES || !state.meshes[id].active { return {}, false } return state.meshes[id].layout, true } get_mesh_info :: proc(state: ^Resource_State, id: u32) -> (vertex_count, index_count: i32, layout: bk.Vertex_Layout, ok: bool) { if id >= MAX_MESHES || !state.meshes[id].active { return 0, 0, {}, false } m := &state.meshes[id] return m.vertex_count, m.index_count, m.layout, true } unload_mesh :: proc(state: ^Resource_State, b: ^bk.Backend, id: u32) { if id == 0 || id >= MAX_MESHES || !state.meshes[id].active { return } b.destroy_buffer(state.meshes[id].vertex_buffer) b.destroy_buffer(state.meshes[id].index_buffer) state.meshes[id].active = false } get_mesh_buffers :: proc(state: ^Resource_State, id: u32) -> (vb: bk.Buffer_Handle, ib: bk.Buffer_Handle, index_count: i32, ok: bool) { if id >= MAX_MESHES || !state.meshes[id].active { return {}, {}, 0, false } m := &state.meshes[id] return m.vertex_buffer, m.index_buffer, m.index_count, true } shutdown_meshes :: proc(state: ^Resource_State, b: ^bk.Backend) { for i in 0.. ([]Mesh_Vertex_PNU, []u32) { hw := w * 0.5 hh := h * 0.5 hl := l * 0.5 vertices := make([]Mesh_Vertex_PNU, 24) indices := make([]u32, 36) // Front face (+Z) vertices[0] = {{-hw, -hh, hl}, { 0, 0, 1}, {0, 1}} vertices[1] = {{ hw, -hh, hl}, { 0, 0, 1}, {1, 1}} vertices[2] = {{ hw, hh, hl}, { 0, 0, 1}, {1, 0}} vertices[3] = {{-hw, hh, hl}, { 0, 0, 1}, {0, 0}} // Back face (-Z) vertices[4] = {{ hw, -hh, -hl}, { 0, 0, -1}, {0, 1}} vertices[5] = {{-hw, -hh, -hl}, { 0, 0, -1}, {1, 1}} vertices[6] = {{-hw, hh, -hl}, { 0, 0, -1}, {1, 0}} vertices[7] = {{ hw, hh, -hl}, { 0, 0, -1}, {0, 0}} // Top face (+Y) vertices[8] = {{-hw, hh, hl}, { 0, 1, 0}, {0, 1}} vertices[9] = {{ hw, hh, hl}, { 0, 1, 0}, {1, 1}} vertices[10] = {{ hw, hh, -hl}, { 0, 1, 0}, {1, 0}} vertices[11] = {{-hw, hh, -hl}, { 0, 1, 0}, {0, 0}} // Bottom face (-Y) vertices[12] = {{-hw, -hh, -hl}, { 0, -1, 0}, {0, 1}} vertices[13] = {{ hw, -hh, -hl}, { 0, -1, 0}, {1, 1}} vertices[14] = {{ hw, -hh, hl}, { 0, -1, 0}, {1, 0}} vertices[15] = {{-hw, -hh, hl}, { 0, -1, 0}, {0, 0}} // Right face (+X) vertices[16] = {{ hw, -hh, hl}, { 1, 0, 0}, {0, 1}} vertices[17] = {{ hw, -hh, -hl}, { 1, 0, 0}, {1, 1}} vertices[18] = {{ hw, hh, -hl}, { 1, 0, 0}, {1, 0}} vertices[19] = {{ hw, hh, hl}, { 1, 0, 0}, {0, 0}} // Left face (-X) vertices[20] = {{-hw, -hh, -hl}, {-1, 0, 0}, {0, 1}} vertices[21] = {{-hw, -hh, hl}, {-1, 0, 0}, {1, 1}} vertices[22] = {{-hw, hh, hl}, {-1, 0, 0}, {1, 0}} vertices[23] = {{-hw, hh, -hl}, {-1, 0, 0}, {0, 0}} // Indices (two triangles per face, CCW winding) for face in 0.. ([]Mesh_Vertex_PNU, []u32) { vert_count := int((rings + 1) * (slices + 1)) idx_count := int(rings * slices * 6) vertices := make([]Mesh_Vertex_PNU, vert_count) indices := make([]u32, idx_count) vi := 0 ii := 0 for ring in 0..=rings { phi := f32(ring) * math.PI / f32(rings) sp := math.sin(phi) cp := math.cos(phi) for slice in 0..=slices { theta := f32(slice) * 2.0 * math.PI / f32(slices) st := math.sin(theta) ct := math.cos(theta) nx := ct * sp ny := cp nz := st * sp vertices[vi] = { position = {nx * radius, ny * radius, nz * radius}, normal = {nx, ny, nz}, tex_coord = {f32(slice) / f32(slices), f32(ring) / f32(rings)}, } vi += 1 } } for ring in 0.. ([]Mesh_Vertex_PNU, []u32) { vert_count := int((res_x + 1) * (res_z + 1)) idx_count := int(res_x * res_z * 6) vertices := make([]Mesh_Vertex_PNU, vert_count) indices := make([]u32, idx_count) vi := 0 ii := 0 for z in 0..=res_z { for x in 0..=res_x { fx := f32(x) / f32(res_x) fz := f32(z) / f32(res_z) vertices[vi] = { position = {(fx - 0.5) * w, 0, (fz - 0.5) * l}, normal = {0, 1, 0}, tex_coord = {fx, fz}, } vi += 1 } } for z in 0.. ([]Mesh_Vertex_PNU, []u32) { line_count := max(slices + 1, 0) * 2 vertices := make([]Mesh_Vertex_PNU, int(line_count * 4)) indices := make([]u32, int(line_count * 12)) half := f32(slices) * spacing * 0.5 half_t := thickness * 0.5 vi := 0 ii := 0 add_quad :: proc(vertices: []Mesh_Vertex_PNU, indices: []u32, vi, ii: ^int, x0, z0, x1, z1: f32) { base := u32(vi^) vertices[vi^ + 0] = {{x0, 0, z0}, {0, 1, 0}, {0, 0}} vertices[vi^ + 1] = {{x1, 0, z0}, {0, 1, 0}, {1, 0}} vertices[vi^ + 2] = {{x1, 0, z1}, {0, 1, 0}, {1, 1}} vertices[vi^ + 3] = {{x0, 0, z1}, {0, 1, 0}, {0, 1}} // Emit both windings so the debug grid remains visible above and below with back-face culling. indices[ii^ + 0] = base + 0 indices[ii^ + 1] = base + 2 indices[ii^ + 2] = base + 1 indices[ii^ + 3] = base + 0 indices[ii^ + 4] = base + 3 indices[ii^ + 5] = base + 2 indices[ii^ + 6] = base + 0 indices[ii^ + 7] = base + 1 indices[ii^ + 8] = base + 2 indices[ii^ + 9] = base + 0 indices[ii^ + 10] = base + 2 indices[ii^ + 11] = base + 3 vi^ += 4 ii^ += 12 } for i in 0..=slices { x := -half + f32(i) * spacing add_quad(vertices, indices, &vi, &ii, x - half_t, -half, x + half_t, half) z := -half + f32(i) * spacing add_quad(vertices, indices, &vi, &ii, -half, z - half_t, half, z + half_t) } return vertices, indices }