Compare commits
4 commits
67d7b3e227
...
44e88f7fd0
| Author | SHA1 | Date | |
|---|---|---|---|
| 44e88f7fd0 | |||
| 043892cdd1 | |||
| 99194e943a | |||
| 52364f28b9 |
7 changed files with 315 additions and 45 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -19,4 +19,6 @@ ols.json
|
||||||
libtinyfiledialogs.a
|
libtinyfiledialogs.a
|
||||||
libtinyfiledialogs.obj
|
libtinyfiledialogs.obj
|
||||||
tinyfiledialogs.lib
|
tinyfiledialogs.lib
|
||||||
tinyfiledialogs.obj
|
tinyfiledialogs.obj
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,35 @@ main :: proc() {
|
||||||
target_dir := s.concatenate({cwd, "\\src\\aseprite_odin_generator\\"})
|
target_dir := s.concatenate({cwd, "\\src\\aseprite_odin_generator\\"})
|
||||||
|
|
||||||
atlas: rl.Image = rl.GenImageColor(ATLAS_SIZE, ATLAS_SIZE, rl.BLANK)
|
atlas: rl.Image = rl.GenImageColor(ATLAS_SIZE, ATLAS_SIZE, rl.BLANK)
|
||||||
atlas_entries: [dynamic]gen.AtlasEntry
|
atlas_entries: [dynamic]gen.AtlasEntry = make([dynamic]gen.AtlasEntry)
|
||||||
gen.unmarshall_aseprite_dir(target_dir, &atlas_entries)
|
gen.unmarshall_aseprite_dir(target_dir, &atlas_entries)
|
||||||
|
|
||||||
metadata := gen.pack_atlas_entries(atlas_entries[:], &atlas, 10, 10)
|
metadata := gen.pack_atlas_entries(atlas_entries[:], &atlas, 10, 10)
|
||||||
|
|
||||||
json_bytes, jerr := json.marshal(metadata)
|
json_bytes, jerr := json.marshal(metadata)
|
||||||
os.write_entire_file("src/aseprite_odin_generator/metadata.json", json_bytes)
|
os.write_entire_file("src/aseprite_odin_generator/metadata.json", json_bytes)
|
||||||
|
sb := gen.metadata_source_code_generate(metadata[:], gen.odin_source_generator_metadata)
|
||||||
|
odin_output_str := s.to_string(sb)
|
||||||
|
os.write_entire_file(
|
||||||
|
"src/aseprite_odin_generator/output.odino",
|
||||||
|
transmute([]byte)odin_output_str,
|
||||||
|
)
|
||||||
|
|
||||||
rl.ExportImage(atlas, EXPORT_PATH)
|
rl.ExportImage(atlas, EXPORT_PATH)
|
||||||
|
|
||||||
|
// something : string = "hello"
|
||||||
|
// fmt.printf("{1} {2} else", something, 10)
|
||||||
|
|
||||||
|
// TestStruct :: struct {
|
||||||
|
// something: struct {
|
||||||
|
// name: string,
|
||||||
|
// age: int,
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// ts: TestStruct
|
||||||
|
// ts.something.name = "name"
|
||||||
|
|
||||||
|
// jb, err := json.marshal(ts)
|
||||||
|
// sjb := transmute(string)jb
|
||||||
|
// fmt.println(sjb)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
[{"name":"Edinica","location":[95,10],"size":[58,57]},{"name":"Dvoika_0","location":[234,10],"size":[55,31]},{"name":"Troika","location":[10,10],"size":[75,75]},{"name":"Dvoika_1","location":[163,10],"size":[61,33]}]
|
[{"name":"Edinica","location":[95,10],"size":[58,57]},{"name":"Dvoika_0","location":[234,10],"size":[55,31]},{"name":"Dvoika_1","location":[163,10],"size":[61,33]},{"name":"Troika","location":[10,10],"size":[75,75]}]
|
||||||
|
|
@ -95,7 +95,8 @@ draw_screen_target :: proc() {
|
||||||
g_mem.packer_settings.pixel_padding_x_int if g_mem.packer_settings.padding_enabled else 0
|
g_mem.packer_settings.pixel_padding_x_int if g_mem.packer_settings.padding_enabled else 0
|
||||||
padding_y :=
|
padding_y :=
|
||||||
g_mem.packer_settings.pixel_padding_y_int if g_mem.packer_settings.padding_enabled else 0
|
g_mem.packer_settings.pixel_padding_y_int if g_mem.packer_settings.padding_enabled else 0
|
||||||
pack_atlas_entries(atlas_entries[:], &atlas, padding_x, padding_y)
|
|
||||||
|
g_mem.atlas_metadata = pack_atlas_entries(atlas_entries[:], &atlas, padding_x, padding_y)
|
||||||
|
|
||||||
// OpenGL's Y buffer is flipped
|
// OpenGL's Y buffer is flipped
|
||||||
rl.ImageFlipVertical(&atlas)
|
rl.ImageFlipVertical(&atlas)
|
||||||
|
|
@ -320,7 +321,7 @@ draw_atlas_settings_and_preview :: proc() {
|
||||||
},
|
},
|
||||||
"Clear Atlas",
|
"Clear Atlas",
|
||||||
) {
|
) {
|
||||||
g_mem.atlas_render_has_preview = false
|
clear_atlas_data()
|
||||||
}
|
}
|
||||||
elements_height += small_offset * 2
|
elements_height += small_offset * 2
|
||||||
|
|
||||||
|
|
@ -466,7 +467,7 @@ open_file_dialog :: proc() {
|
||||||
file_path: cstring
|
file_path: cstring
|
||||||
patterns: []cstring = {"*.png"}
|
patterns: []cstring = {"*.png"}
|
||||||
if default_path, ok := g_mem.output_folder_path.(string); ok {
|
if default_path, ok := g_mem.output_folder_path.(string); ok {
|
||||||
default_path_filename := strings.concatenate({default_path, atlas_path})
|
default_path_filename := strings.concatenate({default_path, os_file_separator, "atlas.png"})
|
||||||
default_path_to_save: cstring = strings.clone_to_cstring(default_path_filename)
|
default_path_to_save: cstring = strings.clone_to_cstring(default_path_filename)
|
||||||
file_path = cstring(
|
file_path = cstring(
|
||||||
diag.save_file_dialog(
|
diag.save_file_dialog(
|
||||||
|
|
@ -488,3 +489,11 @@ open_file_dialog :: proc() {
|
||||||
|
|
||||||
g_mem.should_open_file_dialog = false
|
g_mem.should_open_file_dialog = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear_atlas_data :: proc() {
|
||||||
|
if metadata, ok := g_mem.atlas_metadata.([dynamic]SpriteAtlasMetadata); ok {
|
||||||
|
delete(metadata)
|
||||||
|
// g_mem.atlas_metadata = nil
|
||||||
|
}
|
||||||
|
g_mem.atlas_render_has_preview = false
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
package game
|
package game
|
||||||
|
|
||||||
import ase "./aseprite"
|
import ase "./aseprite"
|
||||||
import "core:encoding/json"
|
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:mem"
|
|
||||||
import "core:os"
|
import "core:os"
|
||||||
import fp "core:path/filepath"
|
import fp "core:path/filepath"
|
||||||
|
import "core:slice"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
import stbrp "vendor:stb/rect_pack"
|
import stbrp "vendor:stb/rect_pack"
|
||||||
|
|
@ -25,24 +24,23 @@ AtlasEntry :: struct {
|
||||||
layer_cell_count: [dynamic]i32,
|
layer_cell_count: [dynamic]i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
SingleFrameSprite :: distinct rl.Rectangle
|
|
||||||
|
|
||||||
AnimatedSprite :: struct {
|
|
||||||
x, y: i32,
|
|
||||||
width, height: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
SpriteAtlasMetadata :: struct {
|
SpriteAtlasMetadata :: struct {
|
||||||
name: string,
|
name: string,
|
||||||
location: [2]i32,
|
location: [2]i32,
|
||||||
size: [2]i32,
|
size: [2]i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
unmarshall_aseprite_dir :: proc(path: string, atlas_entries: ^[dynamic]AtlasEntry) {
|
unmarshall_aseprite_dir :: proc(
|
||||||
|
path: string,
|
||||||
|
atlas_entries: ^[dynamic]AtlasEntry,
|
||||||
|
alloc := context.allocator,
|
||||||
|
) {
|
||||||
|
if len(path) == 0 do return
|
||||||
|
|
||||||
if dir_fd, err := os.open(path, os.O_RDONLY); err == os.ERROR_NONE {
|
if dir_fd, err := os.open(path, os.O_RDONLY); err == os.ERROR_NONE {
|
||||||
fis: []os.File_Info
|
fis: []os.File_Info
|
||||||
if fis, err = os.read_dir(dir_fd, -1); err == os.ERROR_NONE {
|
if fis, err = os.read_dir(dir_fd, -1); err == os.ERROR_NONE {
|
||||||
unmarshall_aseprite_files_file_info(fis, atlas_entries)
|
unmarshall_aseprite_files_file_info(fis, atlas_entries, alloc)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.println("Couldn't open folder: ", path)
|
fmt.println("Couldn't open folder: ", path)
|
||||||
|
|
@ -52,30 +50,35 @@ unmarshall_aseprite_dir :: proc(path: string, atlas_entries: ^[dynamic]AtlasEntr
|
||||||
unmarshall_aseprite_files_file_info :: proc(
|
unmarshall_aseprite_files_file_info :: proc(
|
||||||
files: []os.File_Info,
|
files: []os.File_Info,
|
||||||
atlas_entries: ^[dynamic]AtlasEntry,
|
atlas_entries: ^[dynamic]AtlasEntry,
|
||||||
|
alloc := context.allocator,
|
||||||
) {
|
) {
|
||||||
if len(files) == 0 do return
|
if len(files) == 0 do return
|
||||||
|
|
||||||
paths := make([]string, len(files))
|
paths := make([]string, len(files), alloc)
|
||||||
defer delete(paths)
|
defer delete(paths)
|
||||||
|
|
||||||
for f, fi in files {
|
for f, fi in files {
|
||||||
paths[fi] = f.fullpath
|
paths[fi] = f.fullpath
|
||||||
}
|
}
|
||||||
|
|
||||||
unmarshall_aseprite_files(paths[:], atlas_entries)
|
unmarshall_aseprite_files(paths[:], atlas_entries, alloc)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unmarshall_aseprite_files :: proc(file_paths: []string, atlas_entries: ^[dynamic]AtlasEntry) {
|
unmarshall_aseprite_files :: proc(
|
||||||
|
file_paths: []string,
|
||||||
|
atlas_entries: ^[dynamic]AtlasEntry,
|
||||||
|
alloc := context.allocator,
|
||||||
|
) {
|
||||||
if len(file_paths) == 0 do return
|
if len(file_paths) == 0 do return
|
||||||
|
|
||||||
aseprite_document: ase.Document
|
aseprite_document: ase.Document
|
||||||
for file in file_paths {
|
for file in file_paths {
|
||||||
extension := fp.ext(file)
|
extension := fp.ext(file)
|
||||||
if extension != ".aseprite" {continue}
|
if extension != ".aseprite" do continue
|
||||||
|
|
||||||
fmt.println("Unmarshalling file: ", file)
|
fmt.println("Unmarshalling file: ", file)
|
||||||
ase.unmarshal_from_filename(file, &aseprite_document)
|
ase.unmarshal_from_filename(file, &aseprite_document, alloc)
|
||||||
atlas_entry := atlas_entry_from_compressed_cells(aseprite_document)
|
atlas_entry := atlas_entry_from_compressed_cells(aseprite_document)
|
||||||
atlas_entry.path = file
|
atlas_entry.path = file
|
||||||
|
|
||||||
|
|
@ -89,6 +92,13 @@ unmarshall_aseprite_files :: proc(file_paths: []string, atlas_entries: ^[dynamic
|
||||||
atlas_entry_from_compressed_cells :: proc(document: ase.Document) -> (atlas_entry: AtlasEntry) {
|
atlas_entry_from_compressed_cells :: proc(document: ase.Document) -> (atlas_entry: AtlasEntry) {
|
||||||
atlas_entry.frames = auto_cast len(document.frames)
|
atlas_entry.frames = auto_cast len(document.frames)
|
||||||
fmt.println("N Frames: ", len(document.frames))
|
fmt.println("N Frames: ", len(document.frames))
|
||||||
|
// note(stefan): Since the expected input for the program is multiple files containing a single sprite
|
||||||
|
// it's probably a safe assumption most of the files will be a single layer with 1 or more frames
|
||||||
|
// which means we can first prod the file for information about how many frames are there and
|
||||||
|
// allocate a slice that is going to be [Frames X Layers]CellData.
|
||||||
|
// which would allow us to gain an already sorted list of sprites if we iterate all frames of a single layer
|
||||||
|
// instead of iterating all layers for each frame
|
||||||
|
// might be even quicker to first get that information an allocate at once the amount of cells we need
|
||||||
for frame, frameIdx in document.frames {
|
for frame, frameIdx in document.frames {
|
||||||
fmt.printfln("Frame_{0} Chunks: ", frameIdx, len(frame.chunks))
|
fmt.printfln("Frame_{0} Chunks: ", frameIdx, len(frame.chunks))
|
||||||
for chunk in frame.chunks {
|
for chunk in frame.chunks {
|
||||||
|
|
@ -109,14 +119,21 @@ atlas_entry_from_compressed_cells :: proc(document: ase.Document) -> (atlas_entr
|
||||||
opacity = cel_chunk.opacity_level,
|
opacity = cel_chunk.opacity_level,
|
||||||
layer_index = cel_chunk.layer_index,
|
layer_index = cel_chunk.layer_index,
|
||||||
}
|
}
|
||||||
|
|
||||||
append(&atlas_entry.cells, cell)
|
append(&atlas_entry.cells, cell)
|
||||||
}
|
}
|
||||||
|
|
||||||
if layer_chunk, ok := chunk.(ase.Layer_Chunk); ok {
|
if layer_chunk, ok := chunk.(ase.Layer_Chunk); ok {
|
||||||
fmt.println("Layer chunk: ", layer_chunk)
|
fmt.println("Layer chunk: ", layer_chunk)
|
||||||
append(&atlas_entry.layer_names, layer_chunk.name)
|
append(&atlas_entry.layer_names, layer_chunk.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slice.sort_by(atlas_entry.cells[:], proc(i, j: CellData) -> bool {
|
||||||
|
return i.layer_index < j.layer_index
|
||||||
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,17 +227,17 @@ pack_atlas_entries :: proc(
|
||||||
entry := entry_and_cell.entry
|
entry := entry_and_cell.entry
|
||||||
cell := entry_and_cell.cell_of_entry
|
cell := entry_and_cell.cell_of_entry
|
||||||
|
|
||||||
cell_name : string
|
cell_name: string
|
||||||
if entry.layer_cell_count[cell.layer_index] > 1 {
|
if entry.layer_cell_count[cell.layer_index] > 1 {
|
||||||
cell_name = fmt.aprintf(
|
cell_name = fmt.aprintf(
|
||||||
"{0}_%d",
|
"{0}_%d",
|
||||||
entry.layer_names[cell.layer_index],
|
entry.layer_names[cell.layer_index],
|
||||||
cell.frame_index,
|
cell.frame_index,
|
||||||
allocator,
|
allocator,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
cell_name = entry.layer_names[cell.layer_index]
|
cell_name = entry.layer_names[cell.layer_index]
|
||||||
}
|
}
|
||||||
cell_metadata := SpriteAtlasMetadata {
|
cell_metadata := SpriteAtlasMetadata {
|
||||||
name = cell_name,
|
name = cell_name,
|
||||||
location = {
|
location = {
|
||||||
|
|
@ -231,5 +248,196 @@ pack_atlas_entries :: proc(
|
||||||
}
|
}
|
||||||
append(&metadata, cell_metadata)
|
append(&metadata, cell_metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadata
|
return metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceCodeGeneratorMetadata :: struct {
|
||||||
|
file_defines: struct {
|
||||||
|
top: string,
|
||||||
|
bottom: string,
|
||||||
|
},
|
||||||
|
lanugage_settings: struct {
|
||||||
|
first_class_enum_arrays: bool, // for languages that support creating arrays that contain for each enum value an entry in the enum_data.entry_line: .EnumCase = {array entry}
|
||||||
|
},
|
||||||
|
custom_data_type: struct {
|
||||||
|
name: string,
|
||||||
|
type_declaration: string, // contains one param: custom_data_type.name + the rest of the type declaration like braces of the syntax & the type members
|
||||||
|
},
|
||||||
|
enum_data: struct {
|
||||||
|
name: string,
|
||||||
|
begin_line: string, // contains one params: enum_data.name
|
||||||
|
entry_line: string,
|
||||||
|
end_line: string,
|
||||||
|
},
|
||||||
|
array_data: struct {
|
||||||
|
name: string,
|
||||||
|
type: string,
|
||||||
|
begin_line: string, // array begin line contains 2 params in the listed order: array.name, array.type
|
||||||
|
entry_line: string, // array entry contains 5 params in the listed order: cell.name, cell.location.x, cell.location.y, cell.size.x, cell.size.y,
|
||||||
|
end_line: string,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
odin_source_generator_metadata := SourceCodeGeneratorMetadata {
|
||||||
|
file_defines = {top = "package atlas_bindings\n\n", bottom = ""},
|
||||||
|
custom_data_type = {
|
||||||
|
name = "AtlasRect",
|
||||||
|
type_declaration = "%v :: struct {{ x, y, w, h: i32 }}\n\n",
|
||||||
|
},
|
||||||
|
enum_data = {
|
||||||
|
name = "AtlasEnum",
|
||||||
|
begin_line = "%v :: enum {{\n",
|
||||||
|
entry_line = "\t%s,\n",
|
||||||
|
end_line = "}\n\n",
|
||||||
|
},
|
||||||
|
array_data = {
|
||||||
|
name = "ATLAS_SPRITES",
|
||||||
|
type = "[]AtlasRect",
|
||||||
|
begin_line = "%v := %v {{\n",
|
||||||
|
entry_line = "\t.%v = {{ x = %v, y = %v, w = %v, h = %v }},\n",
|
||||||
|
end_line = "}\n\n",
|
||||||
|
},
|
||||||
|
lanugage_settings = {first_class_enum_arrays = true},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cpp_source_generator_metadata := SourceCodeGeneratorMetadata {
|
||||||
|
file_defines = {top = "#include <iostream>\n\n", bottom = ""},
|
||||||
|
custom_data_type = {
|
||||||
|
name = "AtlasRect",
|
||||||
|
type_declaration = "struct %v {{\n\tint x;\n\tint y;\n\tint w;\n\tint h;\n}};\n\n",
|
||||||
|
},
|
||||||
|
enum_data = {
|
||||||
|
name = "AtlasEnum",
|
||||||
|
begin_line = "enum %v {{\n",
|
||||||
|
entry_line = "\t%s,\n",
|
||||||
|
end_line = "\n\tCOUNT\n}\n\n",
|
||||||
|
},
|
||||||
|
array_data = {
|
||||||
|
name = "ATLAS_SPRITES",
|
||||||
|
type = "AtlasRect[size_t(AtlasEnum::COUNT)-1]",
|
||||||
|
begin_line = "{1} {0} = {{\n",
|
||||||
|
entry_line = "\t{{ {1}, {2}, {3}, {4} }},\n",
|
||||||
|
end_line = "}\n\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Generates a barebones file with the package name "atlas_bindings",
|
||||||
|
the file contains an array of offsets, indexed by an enum.
|
||||||
|
The enum has unique names
|
||||||
|
*/
|
||||||
|
generate_odin_enums_and_atlas_offsets_file_sb :: proc(
|
||||||
|
metadata: []SpriteAtlasMetadata,
|
||||||
|
alloc := context.allocator,
|
||||||
|
) -> strings.Builder {
|
||||||
|
sb := strings.builder_make(alloc)
|
||||||
|
strings.write_string(&sb, "package atlas_bindings\n\n")
|
||||||
|
|
||||||
|
// Introduce the Rect type
|
||||||
|
strings.write_string(&sb, "AtlasRect :: struct { x, y, w, h: i32 }\n\n")
|
||||||
|
// start enum
|
||||||
|
strings.write_string(&sb, "AtlasSprite :: enum {\n")
|
||||||
|
{
|
||||||
|
for cell in metadata {
|
||||||
|
strings.write_string(&sb, fmt.aprintf("\t%s,\n", cell.name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end enum
|
||||||
|
strings.write_string(&sb, "}\n\n")
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
{
|
||||||
|
entry: string
|
||||||
|
for cell in metadata {
|
||||||
|
entry = fmt.aprintf(
|
||||||
|
"\t.%v = {{ x = %v, y = %v, w = %v, h = %v }},\n",
|
||||||
|
cell.name,
|
||||||
|
cell.location.x,
|
||||||
|
cell.location.y,
|
||||||
|
cell.size.x,
|
||||||
|
cell.size.y,
|
||||||
|
)
|
||||||
|
strings.write_string(&sb, entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end offsets array
|
||||||
|
strings.write_string(&sb, "}\n\n")
|
||||||
|
|
||||||
|
fmt.println("\n", strings.to_string(sb))
|
||||||
|
|
||||||
|
return sb
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata_source_code_generate :: proc(
|
||||||
|
metadata: []SpriteAtlasMetadata,
|
||||||
|
code_generation_metadata: Maybe(SourceCodeGeneratorMetadata),
|
||||||
|
alloc := context.allocator,
|
||||||
|
) -> strings.Builder {
|
||||||
|
codegen, ok := code_generation_metadata.(SourceCodeGeneratorMetadata)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return generate_odin_enums_and_atlas_offsets_file_sb(metadata, alloc)
|
||||||
|
}
|
||||||
|
|
||||||
|
sb := strings.builder_make(alloc)
|
||||||
|
// strings.write_string(&sb, "package atlas_bindings\n\n")
|
||||||
|
strings.write_string(&sb, codegen.file_defines.top)
|
||||||
|
|
||||||
|
// Introduce the Rect type
|
||||||
|
// strings.write_string(&sb, "AtlasRect :: struct { x, y, w, h: i32 }\n\n")
|
||||||
|
strings.write_string(
|
||||||
|
&sb,
|
||||||
|
fmt.aprintf(codegen.custom_data_type.type_declaration, codegen.custom_data_type.name),
|
||||||
|
)
|
||||||
|
// start enum
|
||||||
|
// strings.write_string(&sb, "AtlasSprite :: enum {\n")
|
||||||
|
strings.write_string(&sb, fmt.aprintf(codegen.enum_data.begin_line, codegen.enum_data.name))
|
||||||
|
{
|
||||||
|
for cell in metadata {
|
||||||
|
// strings.write_string(&sb, fmt.aprintf("\t%s,\n", cell.name))
|
||||||
|
strings.write_string(&sb, fmt.aprintf(codegen.enum_data.entry_line, cell.name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end enum
|
||||||
|
// strings.write_string(&sb, "}\n\n")
|
||||||
|
strings.write_string(&sb, codegen.enum_data.end_line)
|
||||||
|
|
||||||
|
// start offsets array
|
||||||
|
// strings.write_string(&sb, "ATLAS_SPRITES := []AtlasRect {\n")
|
||||||
|
strings.write_string(
|
||||||
|
&sb,
|
||||||
|
fmt.aprintf(
|
||||||
|
codegen.array_data.begin_line,
|
||||||
|
codegen.array_data.name,
|
||||||
|
codegen.array_data.type,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
entry: string
|
||||||
|
for cell in metadata {
|
||||||
|
entry = fmt.aprintf(
|
||||||
|
codegen.array_data.entry_line, // "\t.%v = {{ x = %v, y = %v, w = %v, h = %v }},\n",
|
||||||
|
cell.name,
|
||||||
|
cell.location.x,
|
||||||
|
cell.location.y,
|
||||||
|
cell.size.x,
|
||||||
|
cell.size.y,
|
||||||
|
)
|
||||||
|
strings.write_string(&sb, entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end offsets array
|
||||||
|
// strings.write_string(&sb, "}\n\n")
|
||||||
|
strings.write_string(&sb, codegen.array_data.end_line)
|
||||||
|
|
||||||
|
strings.write_string(&sb, codegen.file_defines.bottom)
|
||||||
|
|
||||||
|
fmt.println("\n", strings.to_string(sb))
|
||||||
|
|
||||||
|
return sb
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,4 +59,5 @@ GameMemory :: struct {
|
||||||
should_render_atlas: bool,
|
should_render_atlas: bool,
|
||||||
atlas_render_has_preview: bool,
|
atlas_render_has_preview: bool,
|
||||||
atlas_render_size: i32,
|
atlas_render_size: i32,
|
||||||
|
atlas_metadata: Maybe([dynamic]SpriteAtlasMetadata),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,57 @@
|
||||||
package game
|
package game
|
||||||
|
|
||||||
import "core:strings"
|
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
import "core:strings"
|
||||||
|
import "core:os"
|
||||||
|
import "core:encoding/json"
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
|
||||||
when ODIN_OS == .Windows {
|
when ODIN_OS == .Windows {
|
||||||
atlas_path :: "\\atlas.png"
|
os_file_separator :: "\\"
|
||||||
} else {
|
} else {
|
||||||
atlas_path :: "/atlas.png"
|
os_file_separator :: "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
save_output :: proc() {
|
save_output :: proc() {
|
||||||
if output_path, ok := g_mem.output_folder_path.(string); ok {
|
if output_path, ok := g_mem.output_folder_path.(string); ok {
|
||||||
if len(output_path) == 0 {
|
if len(output_path) == 0 {
|
||||||
fmt.println("Output path is empty!")
|
fmt.println("Output path is empty!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
image := rl.LoadImageFromTexture(g_mem.atlas_render_texture_target.texture)
|
image := rl.LoadImageFromTexture(g_mem.atlas_render_texture_target.texture)
|
||||||
rl.ImageFlipVertical(&image)
|
rl.ImageFlipVertical(&image)
|
||||||
output_path := strings.concatenate({output_path, atlas_path})
|
|
||||||
|
output_path := strings.concatenate({output_path, os_file_separator, "atlas.png"})
|
||||||
cstring_output_path := strings.clone_to_cstring(output_path)
|
cstring_output_path := strings.clone_to_cstring(output_path)
|
||||||
|
|
||||||
rl.ExportImage(image, cstring_output_path)
|
rl.ExportImage(image, cstring_output_path)
|
||||||
|
|
||||||
|
if metadata, ok := g_mem.atlas_metadata.([dynamic]SpriteAtlasMetadata); ok {
|
||||||
|
if json_metadata, jok := json.marshal(metadata); jok == nil {
|
||||||
|
os.write_entire_file(
|
||||||
|
strings.concatenate({output_path, os_file_separator, "metadata.json"}),
|
||||||
|
json_metadata,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
fmt.println("Failed to marshall the atlas metadata to a json!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(stefan): Think of a more generic alternative to just straight output to a odin file
|
||||||
|
// maybe supply a config.json that defines the start, end, line by line entry and enum format strings
|
||||||
|
// this way you can essentially support any language
|
||||||
|
sb := generate_odin_enums_and_atlas_offsets_file_sb(metadata[:])
|
||||||
|
odin_metadata := strings.to_string(sb)
|
||||||
|
os.write_entire_file(
|
||||||
|
strings.concatenate({output_path, os_file_separator, "metadata.odin"}),
|
||||||
|
transmute([]byte)odin_metadata,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
fmt.println("No metadata to export!")
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
fmt.println("Output path is empty!")
|
fmt.println("Output path is empty!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue