More cleanup. Hooray!

This commit is contained in:
Stefan Stefanov 2026-01-02 18:49:24 +02:00
parent faf42da522
commit a51f5c6b57
4 changed files with 180 additions and 251 deletions

View file

@ -4,10 +4,12 @@ import generator "../generator"
import rl "vendor:raylib"
PIXEL_WINDOW_HEIGHT :: 180
FILE_DIALOG_SIZE :: 1000
scaling: f32 = 2
@(rodata)
ATLAS_RENDER_SIZES := []i32{256, 512, 1024, 2048, 4096}
WindowInformation :: struct {
w: f32,
h: f32,
@ -22,9 +24,7 @@ MonitorInformation :: struct {
FileDialogType :: enum {
SourceFiles,
SourceFolder,
OutputFolder,
SaveFileAs,
}
PackerSettings :: struct {
@ -37,28 +37,16 @@ PackerSettings :: struct {
output_odin: bool,
}
ApplicationState :: struct {
file_dialog_text_buffer: [FILE_DIALOG_SIZE + 1]u8,
is_packing_whole_source_folder: bool,
should_open_file_dialog: bool,
window_info: WindowInformation,
monitor_info: MonitorInformation,
// Where the output files will be written (atlas.png, json output, etc)
output_folder_path: Maybe(string),
// If files were chosen as input - their paths
source_location_to_pack: Maybe(string),
// If a folder was chosen as input - the path
source_files_to_pack: Maybe([]string),
// What type of file dialog to open
source_location_type: FileDialogType,
// Packer settings
packer_settings: PackerSettings,
atlas_render_texture_target: rl.RenderTexture2D,
atlas_checked_background: rl.RenderTexture2D,
should_render_atlas: bool,
atlas_render_has_preview: bool,
atlas_render_size: i32,
atlas_metadata: Maybe([dynamic]generator.SpriteAtlasMetadata),
}
g_mem: ApplicationState
window_info: WindowInformation
monitor_info: MonitorInformation
// Where the output files will be written (atlas.png json output, etc)
output_folder_path: Maybe(string)
// If a folder was chosen as input - the path
source_files_to_pack: Maybe([]string)
// Packer settings
packer_settings: PackerSettings
atlas_render_texture_target: rl.RenderTexture2D
atlas_checked_background: rl.RenderTexture2D
atlas_render_has_preview: bool
atlas_render_size: i32
atlas_metadata: Maybe([dynamic]generator.SpriteAtlasMetadata)

View file

@ -1,5 +1,7 @@
package frontend
import "base:runtime"
import "core:c/libc"
import "core:fmt"
import "core:log"
import "core:math"
@ -12,59 +14,58 @@ import rl "vendor:raylib"
import diag "../../vendors/dialog"
import generator "../generator"
should_pack_atlas_and_render: bool
main :: proc() {
default_allocator := context.allocator
tracking_allocator: mem.Tracking_Allocator
mem.tracking_allocator_init(&tracking_allocator, default_allocator)
context.allocator = mem.tracking_allocator(&tracking_allocator)
mode: int = 0
when ODIN_OS == .Linux || ODIN_OS == .Darwin {
mode = os.S_IRUSR | os.S_IWUSR | os.S_IRGRP | os.S_IROTH
}
context.logger = log.create_console_logger()
{
init()
logh, logh_err := os.open("log.txt", (os.O_CREATE | os.O_TRUNC | os.O_RDWR), mode)
defer cleanup()
if logh_err == os.ERROR_NONE {
os.stdout = logh
os.stderr = logh
}
for !rl.WindowShouldClose() {
update()
draw()
logger :=
logh_err == os.ERROR_NONE ? log.create_file_logger(logh) : log.create_console_logger()
context.logger = logger
defer if logh_err == os.ERROR_NONE {
log.destroy_file_logger(logger)
for b in tracking_allocator.bad_free_array {
log.errorf("Bad free at: %v", b.location)
}
clear(&tracking_allocator.bad_free_array)
free_all(context.temp_allocator)
}
}
log.destroy_console_logger(context.logger)
for key, value in tracking_allocator.allocation_map {
log.errorf("%v: Leaked %v bytes\n", value.location, value.size)
}
mem.tracking_allocator_destroy(&tracking_allocator)
}
init :: proc() {
atlas_render_size = ATLAS_RENDER_SIZES[0]
rl.SetConfigFlags({.WINDOW_RESIZABLE})
rl.InitWindow(1400, 800, "YAAP - Yet Another Atlas Packer")
defer rl.CloseWindow()
rl.SetWindowMinSize(1400, 800)
rl.SetTraceLogCallback(rl_log)
}
for !rl.WindowShouldClose() {
update()
draw()
for b in tracking_allocator.bad_free_array {
log.error("Bad free at: %v", b.location)
}
clear(&tracking_allocator.bad_free_array)
free_all(context.temp_allocator)
}
for key, value in tracking_allocator.allocation_map {
log.error("%v: Leaked %v bytes\n", value.location, value.size)
}
mem.tracking_allocator_destroy(&tracking_allocator)
cleanup :: proc() {
log.info("Bye")
rl.CloseWindow()
}
update :: proc() {
// Update the width/height
win_info := &g_mem.window_info
win_info := &window_info
win_info.w = f32(rl.GetScreenWidth())
win_info.h = f32(rl.GetScreenHeight())
win_info.height_scaled = win_info.h / scaling
@ -73,10 +74,6 @@ update :: proc() {
// Update the virtual mouse position (needed for GUI interaction to work properly for instance)
mouse_scale := 1 / scaling
rl.SetMouseScale(mouse_scale, mouse_scale)
if g_mem.should_open_file_dialog {
open_file_dialog()
}
}
draw :: proc() {
@ -87,8 +84,8 @@ draw :: proc() {
draw_screen_ui()
if g_mem.should_render_atlas {
draw_screen_target()
if should_pack_atlas_and_render {
pack_atlas_and_render()
}
free_all(context.temp_allocator)
@ -100,41 +97,23 @@ ui_camera :: proc() -> rl.Camera2D {
draw_screen_ui :: proc() {
rl.BeginMode2D(ui_camera())
defer rl.EndMode2D()
draw_atlas_settings_and_preview()
draw_settings_and_preview()
rl.EndMode2D()
}
pick_sources :: proc() {
g_mem.should_open_file_dialog = true
g_mem.source_location_type = .SourceFiles
save_atlas_to_file :: proc() {
generator.save_output(output_folder_path, atlas_metadata, atlas_render_texture_target)
}
pick_output :: proc() {
g_mem.should_open_file_dialog = true
g_mem.source_location_type = .OutputFolder
save_to_atlas_to_file :: proc() {
open_file_dialog(.OutputFolder)
save_atlas_to_file()
}
pack_atlas :: proc() {
g_mem.should_render_atlas = true
}
save :: proc() {
generator.save_output(
g_mem.output_folder_path,
g_mem.atlas_metadata,
g_mem.atlas_render_texture_target,
)
}
save_to :: proc() {
// if output_folder, ok := g_mem.output_folder_path.(string); ok {
// generator.save_metadata_simple(output_folder, g_mem.atlas_metadata, nil, nil, nil)
// }
}
draw_screen_target :: proc() {
atlas_render_target := &g_mem.atlas_render_texture_target
pack_atlas_and_render :: proc() {
atlas_render_target := &atlas_render_texture_target
rl.BeginTextureMode(atlas_render_target^)
defer rl.EndTextureMode()
@ -142,28 +121,21 @@ draw_screen_target :: proc() {
atlas_entries: [dynamic]generator.AtlasEntry
delete(atlas_entries)
if files, ok := g_mem.source_files_to_pack.([]string); ok {
if files, ok := source_files_to_pack.([]string); ok {
generator.unmarshall_aseprite_files(files, &atlas_entries)
} else {
log.error("No source folder or files set! Can't pack the void!!!")
g_mem.should_render_atlas = false
should_pack_atlas_and_render = false
return
}
atlas: rl.Image = rl.GenImageColor(g_mem.atlas_render_size, g_mem.atlas_render_size, rl.BLANK)
atlas: rl.Image = rl.GenImageColor(atlas_render_size, atlas_render_size, rl.BLANK)
// defer rl.UnloadImage(atlas)
padding_x :=
g_mem.packer_settings.pixel_padding_x_int if g_mem.packer_settings.padding_enabled else 0
padding_y :=
g_mem.packer_settings.pixel_padding_y_int if g_mem.packer_settings.padding_enabled else 0
padding_x := packer_settings.pixel_padding_x_int if packer_settings.padding_enabled else 0
padding_y := packer_settings.pixel_padding_y_int if packer_settings.padding_enabled else 0
g_mem.atlas_metadata = generator.pack_atlas_entries(
atlas_entries[:],
&atlas,
padding_x,
padding_y,
)
atlas_metadata = generator.pack_atlas_entries(atlas_entries[:], &atlas, padding_x, padding_y)
// OpenGL's Y buffer is flipped
rl.ImageFlipVertical(&atlas)
@ -171,28 +143,27 @@ draw_screen_target :: proc() {
log.info("Packed everything!")
atlas_render_target.texture = rl.LoadTextureFromImage(atlas)
g_mem.should_render_atlas = false
g_mem.atlas_render_has_preview = true
should_pack_atlas_and_render = false
atlas_render_has_preview = true
}
draw_atlas_settings_and_preview :: proc() {
draw_settings_and_preview :: proc() {
left_half_rect := rl.Rectangle {
x = 0,
y = 0,
width = cast(f32)g_mem.window_info.width_scaled / 3,
height = cast(f32)g_mem.window_info.height_scaled,
width = cast(f32)window_info.width_scaled / 3,
height = cast(f32)window_info.height_scaled,
}
right_half_rect := rl.Rectangle {
x = cast(f32)g_mem.window_info.width_scaled / 3,
x = cast(f32)window_info.width_scaled / 3,
y = 0,
width = cast(f32)(g_mem.window_info.width_scaled / 3) * 2,
height = cast(f32)g_mem.window_info.height_scaled,
width = cast(f32)(window_info.width_scaled / 3) * 2,
height = cast(f32)window_info.height_scaled,
}
rl.DrawRectangleRec(left_half_rect, rl.WHITE)
rl.DrawRectangleRec(right_half_rect, rl.MAROON)
@(static)
spinner_edit_mode: bool
@(static) spinner_edit_mode: bool
small_offset := 10 * scaling
big_offset := 30 * scaling
@ -201,10 +172,7 @@ draw_atlas_settings_and_preview :: proc() {
rl.GuiPanel(left_half_rect, "Atlas Settings")
elements_height += small_offset / 2
@(static)
SettingsDropBoxEditMode: bool
@(static)
SettingsDropdownBoxActive: i32
@(static) settings_dropdown_box_active_idx: i32
elements_height += small_offset + 5 * scaling
@ -214,10 +182,8 @@ draw_atlas_settings_and_preview :: proc() {
)
elements_height += small_offset / 2
@(static)
dropdown_resolution_edit_mode: bool
@(static)
dropdown_resolution_mode: i32
@(static) dropdown_resolution_edit_mode: bool
@(static) dropdown_resolution_mode: i32
dropdown_rect := rl.Rectangle {
x = small_offset,
@ -230,21 +196,21 @@ draw_atlas_settings_and_preview :: proc() {
if dropdown_resolution_edit_mode {rl.GuiLock()}
if rl.GuiDropdownBox(
dropdown_rect,
"256x;512x;1024x;2048x;4096x",
&dropdown_resolution_mode,
dropdown_resolution_edit_mode,
) {
dropdown_rect,
"256x;512x;1024x;2048x;4096x",
&dropdown_resolution_mode,
dropdown_resolution_edit_mode,
) {
dropdown_resolution_edit_mode = !dropdown_resolution_edit_mode
g_mem.atlas_render_size = 256 * auto_cast math.pow(2, f32(dropdown_resolution_mode))
atlas_render_size =
ATLAS_RENDER_SIZES[max(i32(len(ATLAS_RENDER_SIZES) - 1), dropdown_resolution_mode)]
}
rl.GuiUnlock()
}
elements_height += small_offset * 2
// General Options
if SettingsDropdownBoxActive == 0 {
if settings_dropdown_box_active_idx == 0 {
padding_settings_y := elements_height
{
defer {
@ -267,7 +233,7 @@ draw_atlas_settings_and_preview :: proc() {
rl.GuiCheckBox(
enable_padding_rect,
" Enable padding",
&g_mem.packer_settings.padding_enabled,
&packer_settings.padding_enabled,
)
elements_height += small_offset * 2
@ -282,7 +248,7 @@ draw_atlas_settings_and_preview :: proc() {
padding_x_spinner := rl.GuiSpinner(
padding_x_spinner_rect,
"",
&g_mem.packer_settings.pixel_padding_x_int,
&packer_settings.pixel_padding_x_int,
0,
10,
spinner_edit_mode,
@ -291,7 +257,7 @@ draw_atlas_settings_and_preview :: proc() {
spinner_edit_mode = !spinner_edit_mode
}
rl.GuiLabel(
{
{
x = (small_offset * 2) + big_offset * 2,
y = elements_height,
width = big_offset,
@ -313,7 +279,7 @@ draw_atlas_settings_and_preview :: proc() {
padding_y_spinner := rl.GuiSpinner(
padding_y_spinner_rect,
"",
&g_mem.packer_settings.pixel_padding_y_int,
&packer_settings.pixel_padding_y_int,
0,
10,
spinner_edit_mode,
@ -322,7 +288,7 @@ draw_atlas_settings_and_preview :: proc() {
spinner_edit_mode = !spinner_edit_mode
}
rl.GuiLabel(
{
{
x = (small_offset * 2) + big_offset * 2,
y = elements_height,
width = big_offset,
@ -336,9 +302,6 @@ draw_atlas_settings_and_preview :: proc() {
}
elements_height += small_offset
// rl.GuiLine({y = elements_height, width = left_half_rect.width}, "Actions")
// elements_height += small_offset
{
actions_label_y := elements_height
@ -360,7 +323,7 @@ draw_atlas_settings_and_preview :: proc() {
height = small_offset,
}
if rl.GuiButton(pick_sources_rect, "Pick Source(s)") {
pick_sources()
open_file_dialog(.SourceFiles)
}
pick_output_rect := rl.Rectangle {
@ -370,7 +333,7 @@ draw_atlas_settings_and_preview :: proc() {
height = small_offset,
}
if rl.GuiButton(pick_output_rect, "Pick Output") {
pick_output()
open_file_dialog(.OutputFolder)
}
elements_height += small_offset * 2
@ -381,7 +344,7 @@ draw_atlas_settings_and_preview :: proc() {
height = small_offset,
}
if rl.GuiButton(pack_atlas_rect, "Pack Atlas") {
pack_atlas()
should_pack_atlas_and_render = true
}
clear_atlas_rect := rl.Rectangle {
@ -402,7 +365,7 @@ draw_atlas_settings_and_preview :: proc() {
height = small_offset,
}
if rl.GuiButton(save_rect, "Save") {
save()
save_atlas_to_file()
}
save_to_rect := rl.Rectangle {
@ -412,7 +375,7 @@ draw_atlas_settings_and_preview :: proc() {
height = small_offset,
}
if rl.GuiButton(save_to_rect, "Save To...") {
save_to()
save_to_atlas_to_file()
}
elements_height += small_offset * 2
}
@ -420,10 +383,9 @@ draw_atlas_settings_and_preview :: proc() {
}
// Packing Options
if SettingsDropdownBoxActive == 1 {
if settings_dropdown_box_active_idx == 1 {
@(static)
active_tab: i32
@(static) active_tab: i32
tabs: []cstring = {"One", "Two", "Three"}
rl.GuiTabBar(
{x = small_offset, y = elements_height, width = 100, height = small_offset},
@ -434,9 +396,8 @@ draw_atlas_settings_and_preview :: proc() {
}
// Save Options
if SettingsDropdownBoxActive == 2 {
}
// if settings_dropdown_box_active_idx == 2 {
// }
elements_height = 0
rl.GuiPanel(right_half_rect, "Atlas Preview")
@ -450,11 +411,11 @@ draw_atlas_settings_and_preview :: proc() {
width = short_edge,
height = short_edge,
}
if !g_mem.atlas_render_has_preview {
if !atlas_render_has_preview {
rl.GuiDummyRec(preview_rect, "PREVIEW")
} else {
// rl.DrawRectangleRec(preview_rect, rl.WHITE)
bg_texture := g_mem.atlas_checked_background.texture
bg_texture := atlas_checked_background.texture
rl.DrawTexturePro(
bg_texture,
{width = auto_cast bg_texture.width, height = auto_cast bg_texture.height},
@ -463,9 +424,7 @@ draw_atlas_settings_and_preview :: proc() {
0,
rl.WHITE,
)
// preview_rect.x +=
// 10;preview_rect.y += 10;preview_rect.height -= 20;preview_rect.width -= 20
atlas_texture := g_mem.atlas_render_texture_target.texture
atlas_texture := atlas_render_texture_target.texture
rl.DrawTexturePro(
atlas_texture,
{width = auto_cast atlas_texture.width, height = auto_cast -atlas_texture.height},
@ -477,96 +436,80 @@ draw_atlas_settings_and_preview :: proc() {
}
}
open_file_dialog :: proc() {
switch g_mem.source_location_type {
open_file_dialog :: proc(dialog_type: FileDialogType) {
switch dialog_type {
case .SourceFiles:
// `open_file_dialog` returns a single cstring with one or more paths, divided by a separator ('|'),
// `open_file_dialog` returns a single cstring with one or more paths divided by a separator ('|'),
// https://github.com/native-toolkit/libtinyfiledialogs/blob/master/tinyfiledialogs.c#L2706
file_paths_conc := cstring(
diag.open_file_dialog(
"Select source files",
cstring(&g_mem.file_dialog_text_buffer[0]),
0,
nil,
"",
1,
),
diag.open_file_dialog("Select source files", nil, 0, nil, "", 1),
)
if len(file_paths_conc) > 0 {
// todo(stefan): Currently we're not doing any checks if the filepaths are valid at all,
// this should be fine because it's returned by the OS' file picker but who knows...
source_files_to_pack := strings.clone_from_cstring(file_paths_conc, context.allocator)
g_mem.source_files_to_pack = strings.split(source_files_to_pack, "|")
// todo(stefan): We're assuming the filepaths returned libtinydialog are valid...
source_files := strings.clone_from_cstring(file_paths_conc, context.allocator)
source_files_to_pack = strings.split(source_files, "|")
log.info(g_mem.source_files_to_pack)
log.info(source_files_to_pack)
} else {
log.error("No files were selected!")
}
case .SourceFolder:
file := cstring(
diag.select_folder_dialog(
"Select source folder",
cstring(&g_mem.file_dialog_text_buffer[0]),
),
)
if len(file) > 0 {
g_mem.source_location_to_pack = strings.clone_from_cstring(file)
log.info(g_mem.source_location_to_pack)
} else {
log.error("Got an empty path from the file dialog!")
}
case .OutputFolder:
file := cstring(
diag.select_folder_dialog(
"Select source folder",
cstring(&g_mem.file_dialog_text_buffer[0]),
),
)
file := cstring(diag.select_folder_dialog("Select source folder", nil))
if len(file) > 0 {
g_mem.output_folder_path = strings.clone_from_cstring(file)
log.info(g_mem.output_folder_path)
output_folder_path = strings.clone_from_cstring(file)
log.info(output_folder_path)
} else {
log.error("Got an empty path from the file dialog!")
}
case .SaveFileAs:
file_path: cstring
patterns: []cstring = {"*.png"}
if default_path, ok := g_mem.output_folder_path.(string); ok {
default_path_filename := strings.concatenate(
{default_path, generator.OS_FILE_SEPARATOR, "atlas.png"},
)
default_path_to_save: cstring = strings.clone_to_cstring(default_path_filename)
file_path = cstring(
diag.save_file_dialog(
"Save as...",
default_path_to_save,
1,
&patterns[0],
"Atlas",
),
)
} else {
file_path = cstring(diag.save_file_dialog("Save as...", "", 1, &patterns[0], "Atlas"))
}
if file_path != nil {
generator.save_output(
g_mem.output_folder_path,
g_mem.atlas_metadata,
g_mem.atlas_render_texture_target,
)
}
}
g_mem.should_open_file_dialog = false
}
clear_atlas_data :: proc() {
if metadata, ok := g_mem.atlas_metadata.([dynamic]generator.SpriteAtlasMetadata); ok {
if metadata, ok := atlas_metadata.([dynamic]generator.SpriteAtlasMetadata); ok {
delete(metadata)
}
g_mem.atlas_render_has_preview = false
atlas_render_has_preview = false
}
logger: log.Logger
rl_log_buf: []byte
rl_log :: proc "c" (logLevel: rl.TraceLogLevel, text: cstring, args: ^libc.va_list) {
context = runtime.default_context()
context.logger = logger
level: log.Level
switch logLevel {
case .TRACE, .DEBUG:
level = .Debug
case .ALL, .NONE, .INFO:
level = .Info
case .WARNING:
level = .Warning
case .ERROR:
level = .Error
case .FATAL:
level = .Fatal
}
if level < logger.lowest_level {
return
}
if rl_log_buf == nil {
rl_log_buf = make([]byte, 1024)
}
defer mem.zero_slice(rl_log_buf)
n: int
for {
va := args
n = int(libc.vsnprintf(raw_data(rl_log_buf), len(rl_log_buf), text, va))
if n < len(rl_log_buf) do break
log.infof("Resizing raylib log buffer from %m to %m", len(rl_log_buf), len(rl_log_buf) * 2)
rl_log_buf, _ = mem.resize_bytes(rl_log_buf, len(rl_log_buf) * 2)
}
formatted := string(rl_log_buf[:n])
log.log(level, formatted)
}

View file

@ -182,28 +182,27 @@ pack_atlas_entries :: proc(
atlas: ^rl.Image,
offset_x: i32,
offset_y: i32,
allocator := context.allocator,
) -> [dynamic]SpriteAtlasMetadata {
assert(atlas.width != 0, "Atlas width shouldn't be 0!")
assert(atlas.height != 0, "Atlas height shouldn't be 0!")
all_cell_images := make([dynamic]rl.Image, allocator) // it's fine to store it like this, rl.Image just stores a pointer to the data
all_cell_images := make([dynamic]rl.Image) // it's fine to store it like this, rl.Image just stores a pointer to the data
for &entry in entries {
for cell in entry.cells {
append(&all_cell_images, cell.img)
}
entry.layer_cell_count = make([dynamic]i32, len(entry.cells), allocator)
entry.layer_cell_count = make([dynamic]i32, len(entry.cells))
}
num_entries := len(all_cell_images)
nodes := make([]stbrp.Node, num_entries, allocator)
rects := make([]stbrp.Rect, num_entries, allocator)
nodes := make([]stbrp.Node, num_entries)
rects := make([]stbrp.Rect, num_entries)
EntryAndCell :: struct {
entry: ^AtlasEntry,
cell_of_entry: ^CellData,
}
rect_idx_to_entry_and_cell := make(map[int]EntryAndCell, 100, allocator)
rect_idx_to_entry_and_cell := make(map[int]EntryAndCell, 100)
// Set the custom IDs
cellIdx: int
@ -241,15 +240,15 @@ pack_atlas_entries :: proc(
src_rect := rl.Rectangle {
x = 0,
y = 0,
width = auto_cast cell.img.width,
height = auto_cast cell.img.height,
width = f32(cell.img.width),
height = f32(cell.img.height),
}
dst_rect := rl.Rectangle {
auto_cast rect.x + auto_cast offset_x,
auto_cast rect.y + auto_cast offset_y,
auto_cast cell.img.width,
auto_cast cell.img.height,
f32(i32(rect.x) + offset_x),
f32(i32(rect.y) + offset_y),
f32(cell.img.width),
f32(cell.img.height),
}
// note(stefan): drawing the sprite in the atlas in the packed coordinates
@ -258,7 +257,7 @@ pack_atlas_entries :: proc(
log.infof("Src rect: {0}\nDst rect:{1}", src_rect, dst_rect)
}
metadata := make([dynamic]SpriteAtlasMetadata, allocator)
metadata := make([dynamic]SpriteAtlasMetadata)
for rect, rectIdx in rects {
entry_and_cell := rect_idx_to_entry_and_cell[auto_cast rectIdx]
entry := entry_and_cell.entry
@ -267,10 +266,9 @@ pack_atlas_entries :: proc(
cell_name: string
if entry.layer_cell_count[cell.layer_index] > 1 {
cell_name = fmt.aprintf(
"{0}_%d",
"{0}_{1}",
entry.layer_names[cell.layer_index],
cell.frame_index,
allocator,
)
} else {
cell_name = entry.layer_names[cell.layer_index]
@ -278,8 +276,8 @@ pack_atlas_entries :: proc(
cell_metadata := SpriteAtlasMetadata {
name = cell_name,
location = {
auto_cast rect.x + auto_cast offset_x,
auto_cast rect.y + auto_cast offset_y,
i32(rect.x) + offset_x,
i32(rect.y) + offset_y,
},
size = {auto_cast cell.img.width, auto_cast cell.img.height},
}
@ -308,7 +306,7 @@ odin_source_generator_metadata := SourceCodeGeneratorMetadata {
},
array_data = {
name = "ATLAS_SPRITES",
type = "[]AtlasRect",
type = "[AtlasSprite]AtlasRect",
begin_line = "%v := %v {{\n",
entry_line = "\t.%v = {{ x = %v, y = %v, w = %v, h = %v }},\n",
end_line = "}\n\n",
@ -369,7 +367,7 @@ generate_odin_enums_and_atlas_offsets_file_sb :: proc(
// start offsets array
// todo(stefan): the name of the array can be based on the output name?
strings.write_string(&sb, "ATLAS_SPRITES := []AtlasRect {\n")
strings.write_string(&sb, "ATLAS_SPRITES := [AtlasSprite]AtlasRect {\n")
{
entry: string
for cell in metadata {

View file

@ -1,7 +1,7 @@
#!/usr/bin/env sh
set -e
gcc ./libtinyfiledialogs/tinyfiledialogs.c -c -o libtinyfiledialogs.o
ar rcs libtinyfiledialogs.a libtinyfiledialogs.o
rm libtinyfiledialogs.o