package resource import "core:log" import bk "../backend" // Load a texture from a file path. Returns pool slot ID, dimensions, and success. load_texture_from_file :: proc( state: ^Resource_State, b: ^bk.Backend, path: string, ) -> (id: u32, width, height: i32, ok: bool) { img, img_ok := load_image_from_file(path) if !img_ok { return 0, 0, 0, false } defer destroy_image(img) w := i32(img.width) h := i32(img.height) pixels := img.pixels.buf[:] slot, slot_ok := load_texture_from_pixels(state, b, raw_data(pixels), u32(w), u32(h)) if !slot_ok { return 0, 0, 0, false } state.textures[slot].width = w state.textures[slot].height = h return slot, w, h, true } // Load a texture from raw RGBA pixel data. load_texture_from_pixels :: proc( state: ^Resource_State, b: ^bk.Backend, pixels: rawptr, width, height: u32, ) -> (id: u32, ok: bool) { slot, slot_ok := allocate_texture_slot(state) if !slot_ok { log.error("gpu/resource: texture pool full") return 0, false } tex := &state.textures[slot] // Create texture (backend handles staging, layout transitions, and image view) tex_handle, tex_ok := b.create_texture(bk.Texture_Desc{ width = width, height = height, format = .R8G8B8A8_SRGB, usage = {.Sampled, .Transfer_Dst}, }, pixels) if !tex_ok { return 0, false } tex.texture = tex_handle tex.owns_texture = true // Create sampler sam_handle, sam_ok := b.create_sampler(bk.Sampler_Desc{ mag_filter = .Linear, min_filter = .Linear, address_mode_u = .Repeat, address_mode_v = .Repeat, enable_aniso = true, }) if !sam_ok { b.destroy_texture(tex_handle) return 0, false } tex.sampler = sam_handle // Allocate descriptor set desc_handle, desc_ok := b.allocate_descriptor_set(state.desc_pool, state.desc_layout) if !desc_ok { b.destroy_sampler(sam_handle) b.destroy_texture(tex_handle) return 0, false } tex.descriptor_set = desc_handle // Update descriptor with texture + sampler b.update_descriptor_image(desc_handle, 0, tex_handle, sam_handle, .Shader_Read_Only) tex.width = i32(width) tex.height = i32(height) tex.active = true return slot, true } unload_texture :: proc(state: ^Resource_State, b: ^bk.Backend, id: u32) { if id == WHITE_TEXTURE_ID { log.warn("gpu/resource: cannot unload the default white texture") return } if id >= MAX_TEXTURES || !state.textures[id].active { return } destroy_texture_slot(b, &state.textures[id]) } @(private) allocate_texture_slot :: proc(state: ^Resource_State) -> (u32, bool) { for i in 0..