feat: Added methods for writing out the metadata about the atlas elements
misc: Refactoring
This commit is contained in:
parent
82ee56ef03
commit
178b0d5525
5 changed files with 233 additions and 155 deletions
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
|
|
@ -6,7 +6,7 @@
|
|||
"request": "launch",
|
||||
"preLaunchTask": "Build Debug",
|
||||
"name": "Debug",
|
||||
"program": "${workspaceFolder}/game_debug.exe",
|
||||
"program": "${workspaceFolder}/build/game_debug.exe",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
|
|
|
|||
167
.vscode/tasks.json
vendored
167
.vscode/tasks.json
vendored
|
|
@ -3,97 +3,90 @@
|
|||
"command": "",
|
||||
"args": [],
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build Debug",
|
||||
"type": "shell",
|
||||
"windows": {
|
||||
"command": "${workspaceFolder}/scripts/build_debug.bat",
|
||||
},
|
||||
"linux": {
|
||||
"command": "${workspaceFolder}/scripts/build_debug.sh",
|
||||
},
|
||||
"osx": {
|
||||
"command": "${workspaceFolder}/scripts/build_debug.sh",
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
{
|
||||
"label": "Build Debug",
|
||||
"type": "shell",
|
||||
"windows": {
|
||||
"command": "${workspaceFolder}/scripts/build_debug.bat"
|
||||
},
|
||||
{
|
||||
"label": "Build Release",
|
||||
"type": "shell",
|
||||
"windows": {
|
||||
"command": "${workspaceFolder}/scripts/build_release.bat",
|
||||
},
|
||||
"linux": {
|
||||
"command": "${workspaceFolder}/scripts/build_release.sh",
|
||||
},
|
||||
"osx": {
|
||||
"command": "${workspaceFolder}/scripts/build_release.sh",
|
||||
},
|
||||
"group": "build"
|
||||
"linux": {
|
||||
"command": "${workspaceFolder}/scripts/build_debug.sh"
|
||||
},
|
||||
{
|
||||
"label": "Clean build folder(s)",
|
||||
"type": "shell",
|
||||
"windows": {
|
||||
"command": "cd ${workspaceFolder}\\build && rm game*; cd ${workspaceFolder} && rm aseprite_odin_generator*",
|
||||
},
|
||||
// "linux": {
|
||||
// "command": "${workspaceFolder}/scripts/build_release.sh",
|
||||
// },
|
||||
// "osx": {
|
||||
// "command": "${workspaceFolder}/scripts/build_release.sh",
|
||||
// },
|
||||
"group": "build"
|
||||
"osx": {
|
||||
"command": "${workspaceFolder}/scripts/build_debug.sh"
|
||||
},
|
||||
{
|
||||
"label": "Build Hot Reload",
|
||||
"type": "shell",
|
||||
"windows": {
|
||||
"command": "${workspaceFolder}/scripts/build_hot_reload.bat; start game.exe",
|
||||
},
|
||||
"linux": {
|
||||
"command": "${workspaceFolder}/scripts/build_hot_reload.sh",
|
||||
},
|
||||
"osx": {
|
||||
"command": "${workspaceFolder}/scripts/build_hot_reload.sh",
|
||||
},
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "dedicated",
|
||||
"showReuseMessage": false,
|
||||
"clear": true
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
{
|
||||
"label": "Build&Run Atlas Generator Test",
|
||||
"type": "shell",
|
||||
"windows": {
|
||||
"command": "${workspaceFolder}/scripts/build_generator_debug.bat && build_generator\\aseprite_odin_generator.exe -input-files:value_of_custom_arg -h",
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "dedicated",
|
||||
"showReuseMessage": false,
|
||||
"clear": true
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Build Release",
|
||||
"type": "shell",
|
||||
"windows": {
|
||||
"command": "${workspaceFolder}/scripts/build_release.bat"
|
||||
},
|
||||
"linux": {
|
||||
"command": "${workspaceFolder}/scripts/build_release.sh"
|
||||
},
|
||||
"osx": {
|
||||
"command": "${workspaceFolder}/scripts/build_release.sh"
|
||||
},
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "Clean build folder(s)",
|
||||
"type": "shell",
|
||||
"windows": {
|
||||
"command": "cd ${workspaceFolder}\\build && rm game*; cd ${workspaceFolder} && rm aseprite_odin_generator*"
|
||||
},
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "Build Hot Reload",
|
||||
"type": "shell",
|
||||
"windows": {
|
||||
"command": "${workspaceFolder}/scripts/build_hot_reload.bat; start game.exe"
|
||||
},
|
||||
"linux": {
|
||||
"command": "${workspaceFolder}/scripts/build_hot_reload.sh"
|
||||
},
|
||||
"osx": {
|
||||
"command": "${workspaceFolder}/scripts/build_hot_reload.sh"
|
||||
},
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "dedicated",
|
||||
"showReuseMessage": false,
|
||||
"clear": true
|
||||
},
|
||||
"group": "build",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Build&Run Atlas Generator Test",
|
||||
"type": "shell",
|
||||
"windows": {
|
||||
"command": "${workspaceFolder}/scripts/build_generator_debug.bat && build_generator\\aseprite_odin_generator.exe -input-files:value_of_custom_arg -h"
|
||||
},
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "dedicated",
|
||||
"showReuseMessage": false,
|
||||
"clear": true
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ package game
|
|||
import "core:fmt"
|
||||
import "core:math"
|
||||
import "core:strings"
|
||||
import "utils"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
import diag "dialog"
|
||||
|
|
@ -261,8 +262,8 @@ draw_atlas_settings_and_preview :: proc() {
|
|||
// rl.GuiLine({y = elements_height, width = left_half_rect.width}, "Actions")
|
||||
// elements_height += small_offset
|
||||
|
||||
actions_label_y := elements_height
|
||||
{
|
||||
actions_label_y := elements_height
|
||||
defer rl.GuiGroupBox(
|
||||
{
|
||||
x = small_offset / 2,
|
||||
|
|
@ -286,6 +287,7 @@ draw_atlas_settings_and_preview :: proc() {
|
|||
g_mem.should_open_file_dialog = true
|
||||
g_mem.source_location_type = .SourceFiles
|
||||
}
|
||||
|
||||
if rl.GuiButton(
|
||||
{
|
||||
x = left_half_rect.width / 2,
|
||||
|
|
@ -312,6 +314,7 @@ draw_atlas_settings_and_preview :: proc() {
|
|||
) {
|
||||
g_mem.should_render_atlas = true
|
||||
}
|
||||
|
||||
if rl.GuiButton(
|
||||
{
|
||||
x = left_half_rect.width / 2,
|
||||
|
|
@ -336,6 +339,7 @@ draw_atlas_settings_and_preview :: proc() {
|
|||
) {
|
||||
save_output()
|
||||
}
|
||||
|
||||
if rl.GuiButton(
|
||||
{
|
||||
x = left_half_rect.width / 2,
|
||||
|
|
@ -345,6 +349,9 @@ draw_atlas_settings_and_preview :: proc() {
|
|||
},
|
||||
"Save To...",
|
||||
) {
|
||||
if output_folder, ok := g_mem.output_folder_path.(string); ok {
|
||||
save_metadata_simple(output_folder)
|
||||
}
|
||||
}
|
||||
elements_height += small_offset * 2
|
||||
}
|
||||
|
|
@ -467,7 +474,9 @@ open_file_dialog :: proc() {
|
|||
file_path: cstring
|
||||
patterns: []cstring = {"*.png"}
|
||||
if default_path, ok := g_mem.output_folder_path.(string); ok {
|
||||
default_path_filename := strings.concatenate({default_path, os_file_separator, "atlas.png"})
|
||||
default_path_filename := strings.concatenate(
|
||||
{default_path, os_file_separator, "atlas.png"},
|
||||
)
|
||||
default_path_to_save: cstring = strings.clone_to_cstring(default_path_filename)
|
||||
file_path = cstring(
|
||||
diag.save_file_dialog(
|
||||
|
|
@ -491,9 +500,9 @@ open_file_dialog :: proc() {
|
|||
}
|
||||
|
||||
clear_atlas_data :: proc() {
|
||||
if metadata, ok := g_mem.atlas_metadata.([dynamic]SpriteAtlasMetadata); ok {
|
||||
delete(metadata)
|
||||
// g_mem.atlas_metadata = nil
|
||||
}
|
||||
if metadata, ok := g_mem.atlas_metadata.([dynamic]SpriteAtlasMetadata); ok {
|
||||
delete(metadata)
|
||||
// g_mem.atlas_metadata = nil
|
||||
}
|
||||
g_mem.atlas_render_has_preview = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ unmarshall_aseprite_files :: proc(
|
|||
atlas_entry_from_compressed_cells :: proc(document: ase.Document) -> (atlas_entry: AtlasEntry) {
|
||||
atlas_entry.frames = auto_cast 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
|
||||
// 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.
|
||||
|
|
@ -250,7 +250,7 @@ pack_atlas_entries :: proc(
|
|||
}
|
||||
cell_metadata := SpriteAtlasMetadata {
|
||||
name = cell_name,
|
||||
location = {
|
||||
location = {
|
||||
auto_cast rect.x + auto_cast offset_x,
|
||||
auto_cast rect.y + auto_cast offset_y,
|
||||
},
|
||||
|
|
@ -264,8 +264,10 @@ pack_atlas_entries :: proc(
|
|||
|
||||
SourceCodeGeneratorMetadata :: struct {
|
||||
file_defines: struct {
|
||||
top: string,
|
||||
bottom: string,
|
||||
top: string,
|
||||
bottom: string,
|
||||
file_name: string,
|
||||
file_extension: 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}
|
||||
|
|
@ -290,18 +292,23 @@ SourceCodeGeneratorMetadata :: struct {
|
|||
}
|
||||
|
||||
odin_source_generator_metadata := SourceCodeGeneratorMetadata {
|
||||
file_defines = {top = "package atlas_bindings\n\n", bottom = ""},
|
||||
custom_data_type = {
|
||||
file_defines = {
|
||||
top = "package atlas_bindings\n\n",
|
||||
bottom = "",
|
||||
file_name = "metadata",
|
||||
file_extension = ".odin",
|
||||
},
|
||||
custom_data_type = {
|
||||
name = "AtlasRect",
|
||||
type_declaration = "%v :: struct {{ x, y, w, h: i32 }}\n\n",
|
||||
},
|
||||
enum_data = {
|
||||
enum_data = {
|
||||
name = "AtlasEnum",
|
||||
begin_line = "%v :: enum {{\n",
|
||||
entry_line = "\t%s,\n",
|
||||
end_line = "}\n\n",
|
||||
},
|
||||
array_data = {
|
||||
array_data = {
|
||||
name = "ATLAS_SPRITES",
|
||||
type = "[]AtlasRect",
|
||||
begin_line = "%v := %v {{\n",
|
||||
|
|
@ -313,18 +320,23 @@ odin_source_generator_metadata := SourceCodeGeneratorMetadata {
|
|||
|
||||
|
||||
cpp_source_generator_metadata := SourceCodeGeneratorMetadata {
|
||||
file_defines = {top = "#include <iostream>\n\n", bottom = ""},
|
||||
custom_data_type = {
|
||||
file_defines = {
|
||||
top = "#include <iostream>\n\n",
|
||||
bottom = "",
|
||||
file_name = "metadata",
|
||||
file_extension = ".hpp",
|
||||
},
|
||||
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 = {
|
||||
enum_data = {
|
||||
name = "AtlasEnum",
|
||||
begin_line = "enum %v {{\n",
|
||||
entry_line = "\t%s,\n",
|
||||
end_line = "\n\tCOUNT\n}\n\n",
|
||||
},
|
||||
array_data = {
|
||||
array_data = {
|
||||
name = "ATLAS_SPRITES",
|
||||
type = "AtlasRect[size_t(AtlasEnum::COUNT)-1]",
|
||||
begin_line = "{1} {0} = {{\n",
|
||||
|
|
@ -384,14 +396,9 @@ generate_odin_enums_and_atlas_offsets_file_sb :: proc(
|
|||
|
||||
metadata_source_code_generate :: proc(
|
||||
metadata: []SpriteAtlasMetadata,
|
||||
code_generation_metadata: Maybe(SourceCodeGeneratorMetadata),
|
||||
codegen: 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")
|
||||
|
|
@ -452,6 +459,117 @@ metadata_source_code_generate :: proc(
|
|||
|
||||
}
|
||||
|
||||
save_output :: proc() {
|
||||
output_path, ok := g_mem.output_folder_path.(string)
|
||||
if !ok || output_path == "" {
|
||||
fmt.println("Output path is empty!")
|
||||
return
|
||||
}
|
||||
|
||||
image := rl.LoadImageFromTexture(g_mem.atlas_render_texture_target.texture)
|
||||
rl.ImageFlipVertical(&image)
|
||||
|
||||
cstring_atlas_output_path := strings.clone_to_cstring(
|
||||
strings.concatenate({output_path, os_file_separator, "atlas.png"}),
|
||||
)
|
||||
|
||||
rl.ExportImage(image, cstring_atlas_output_path)
|
||||
|
||||
if metadata, ok := g_mem.atlas_metadata.([dynamic]SpriteAtlasMetadata); ok {
|
||||
fmt.println("Building metadata...")
|
||||
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)
|
||||
ok := os.write_entire_file(
|
||||
strings.concatenate({output_path, os_file_separator, "metadata.odin"}),
|
||||
transmute([]byte)odin_metadata,
|
||||
)
|
||||
if !ok {
|
||||
fmt.println("Failed to save 'metadata.odin'")
|
||||
}
|
||||
} else {
|
||||
fmt.println("No metadata to export!")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
save_metadata_simple :: proc(
|
||||
output_path: string,
|
||||
json_file_name: Maybe(string),
|
||||
source_file_name: Maybe(string),
|
||||
source_gen_metadata: Maybe(SourceCodeGeneratorMetadata),
|
||||
) {
|
||||
json_file_base_name, json_file_name_ok := json_file_name.(string)
|
||||
source_file_base_name, source_file_name_ok := source_file_name.(string)
|
||||
|
||||
if !json_file_name_ok && !source_file_name_ok {
|
||||
fmt.println("Neither a json file name or a source code filename has been provided!")
|
||||
return
|
||||
}
|
||||
|
||||
metadata, ok := g_mem.atlas_metadata.([dynamic]SpriteAtlasMetadata);if !ok {
|
||||
fmt.println("No metadata to export!")
|
||||
}
|
||||
|
||||
fmt.println("Building metadata...")
|
||||
if json_file_name_ok {
|
||||
if json_metadata, jok := json.marshal(metadata); jok == nil {
|
||||
json_output_path := strings.concatenate(
|
||||
{output_path, os_file_separator, json_file_base_name},
|
||||
)
|
||||
if ok = os.write_entire_file(json_output_path, json_metadata); !ok {
|
||||
fmt.println("Failed to write json to file: ", json_output_path)
|
||||
}
|
||||
} else {
|
||||
fmt.println("Failed to marshall the atlas metadata to a json!")
|
||||
}
|
||||
}
|
||||
|
||||
// note(stefan): Having source_file_name & source_gen_metadata is redundant but this is fine for now
|
||||
if source_file_name_ok {
|
||||
// if src_gen_metadata
|
||||
if codegen, cok := source_gen_metadata.(SourceCodeGeneratorMetadata); cok {
|
||||
sb := metadata_source_code_generate(metadata[:], codegen)
|
||||
|
||||
source_metadata := strings.to_string(sb)
|
||||
source_output_path := strings.concatenate(
|
||||
{
|
||||
output_path,
|
||||
os_file_separator,
|
||||
codegen.file_defines.file_name,
|
||||
codegen.file_defines.file_extension,
|
||||
},
|
||||
)
|
||||
ok := os.write_entire_file(source_output_path, transmute([]byte)source_metadata)
|
||||
if !ok {
|
||||
fmt.println("Failed to save source code to file:", source_output_path)
|
||||
}
|
||||
} else {
|
||||
sb := metadata_source_code_generate(metadata[:], odin_source_generator_metadata)
|
||||
odin_metadata := strings.to_string(sb)
|
||||
source_output_path := strings.concatenate(
|
||||
{output_path, os_file_separator, "metadata.odin"},
|
||||
)
|
||||
|
||||
ok := os.write_entire_file(source_output_path, transmute([]byte)odin_metadata)
|
||||
if !ok {
|
||||
fmt.println("Failed to save source code to file:", source_output_path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
save_metadata :: proc(
|
||||
settings: utils.CLIPackerSettings,
|
||||
atlas_entries: []AtlasEntry,
|
||||
|
|
@ -473,46 +591,3 @@ save_metadata :: proc(
|
|||
os.write_entire_file(source_code_path, transmute([]byte)source_code_output_str)
|
||||
}
|
||||
}
|
||||
|
||||
save_output :: proc() {
|
||||
output_path, ok := g_mem.output_folder_path.(string)
|
||||
if !ok {
|
||||
fmt.println("Output path is empty!")
|
||||
return
|
||||
} else if output_path == "" {
|
||||
fmt.println("Output path is empty!")
|
||||
return
|
||||
}
|
||||
|
||||
image := rl.LoadImageFromTexture(g_mem.atlas_render_texture_target.texture)
|
||||
rl.ImageFlipVertical(&image)
|
||||
|
||||
output_path = strings.concatenate({output_path, os_file_separator, "atlas.png"})
|
||||
cstring_output_path := strings.clone_to_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!")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ parse_arguments :: proc(args: []string) -> (cliargs: map[CLIFlagType]CLIFlag) {
|
|||
|
||||
for arg in args {
|
||||
arg_name_and_value, err := s.split(arg, ":")
|
||||
if err != nil {continue}
|
||||
name := arg_name_and_value[0]
|
||||
|
||||
if name[0] == '-' {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue