Moved C++ tools out
This commit is contained in:
20
tools/CMakeLists.txt
Normal file
20
tools/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
||||
# Copyright (c) 2023 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Tool Level Values
|
||||
set(
|
||||
DAWN_TOOL_INCLUDES
|
||||
${CMAKE_CURRENT_LIST_DIR}
|
||||
CACHE INTERNAL ${DAWN_CACHE_TARGET}
|
||||
)
|
||||
|
||||
set(
|
||||
DAWN_TOOL_GENERATED_DEPENDENCIES
|
||||
CACHE INTERNAL ${DAWN_CACHE_TARGET}
|
||||
)
|
||||
|
||||
# Tools
|
||||
add_subdirectory(assetstool)
|
||||
add_subdirectory(texturetool)
|
13
tools/assetstool/CMakeLists.txt
Normal file
13
tools/assetstool/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_custom_target(dawnassets
|
||||
COMMAND ${DAWN_TOOLS_DIR}/assetstool/assetstool.py
|
||||
--input=${DAWN_ASSETS_BUILD_DIR}
|
||||
--output=${DAWN_BUILD_DIR}/assets.tar
|
||||
COMMENT "Bundling assets..."
|
||||
USES_TERMINAL
|
||||
DEPENDS ${DAWN_ASSETS}
|
||||
)
|
60
tools/assetstool/assetstool.py
Executable file
60
tools/assetstool/assetstool.py
Executable file
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
import os
|
||||
import tarfile
|
||||
import argparse
|
||||
|
||||
# Args
|
||||
parser = argparse.ArgumentParser(description='Bundles all assets into the internal archive format.')
|
||||
parser.add_argument('-i', '--input');
|
||||
parser.add_argument('-o', '--output');
|
||||
args = parser.parse_args()
|
||||
|
||||
# Ensure the directory for the output path exists
|
||||
if not os.path.exists(os.path.dirname(args.output)):
|
||||
os.makedirs(os.path.dirname(args.output))
|
||||
|
||||
# Create a ZIP archive and add the specified directory
|
||||
# archive = tarfile.open(args.output, 'w:bz2') # BZ2 Compression
|
||||
|
||||
# Does the archive already exist?
|
||||
filesInArchive = []
|
||||
|
||||
if os.path.exists(args.output):
|
||||
# Yes, open it
|
||||
archive = tarfile.open(args.output, 'r:')
|
||||
|
||||
# Get all the files in the archive
|
||||
for member in archive.getmembers():
|
||||
filesInArchive.append(member.name)
|
||||
|
||||
archive.close()
|
||||
|
||||
# Open archive for appending.
|
||||
archive = tarfile.open(args.output, 'a:')
|
||||
else:
|
||||
# No, create it
|
||||
archive = tarfile.open(args.output, 'w:')
|
||||
|
||||
# Add all files in the input directory
|
||||
for foldername, subfolders, filenames in os.walk(args.input):
|
||||
for filename in filenames:
|
||||
|
||||
# Is the file already in the archive?
|
||||
absolute_path = os.path.join(foldername, filename)
|
||||
relative_path = os.path.relpath(absolute_path, args.input)
|
||||
|
||||
if relative_path in filesInArchive:
|
||||
# Yes, skip it
|
||||
continue
|
||||
|
||||
# No, add it
|
||||
print(f"Archiving asset {filename}...")
|
||||
archive.add(absolute_path, arcname=relative_path)
|
||||
|
||||
# Close the archive
|
||||
archive.close()
|
50
tools/texturetool/CMakeLists.txt
Normal file
50
tools/texturetool/CMakeLists.txt
Normal file
@ -0,0 +1,50 @@
|
||||
# Copyright (c) 2021 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Tool Function
|
||||
function(tool_texture target)
|
||||
# Defaults
|
||||
set(FILE "" )
|
||||
set(FILTER_MIN "")
|
||||
set(FILTER_MAG "")
|
||||
set(WRAP_X "")
|
||||
set(WRAP_Y "")
|
||||
set(SCALE "")
|
||||
set(CROP_START_X "")
|
||||
set(CROP_START_Y "")
|
||||
set(CROP_END_X "")
|
||||
set(CROP_END_Y "")
|
||||
|
||||
# Parse Args
|
||||
foreach(_PAIR IN LISTS ARGN)
|
||||
if (_PAIR MATCHES "^([^:]+)=(.*)$")
|
||||
set(${CMAKE_MATCH_1} ${CMAKE_MATCH_2})
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid pair: ${_PAIR}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Check for missing args
|
||||
if(NOT DEFINED FILE)
|
||||
message(FATAL_ERROR "Missing FILE input")
|
||||
endif()
|
||||
|
||||
add_custom_target(${target}
|
||||
COMMAND ${DAWN_TOOLS_DIR}/texturetool/texturetool.py
|
||||
--input="${FILE}"
|
||||
--output="${DAWN_ASSETS_BUILD_DIR}/${target}.texture"
|
||||
--wrap-x="${WRAP_X}"
|
||||
--wrap-y="${WRAP_Y}"
|
||||
--filter-min="${FILTER_MIN}"
|
||||
--filter-mag="${FILTER_MIN}"
|
||||
--scale="${SCALE}"
|
||||
--crop-start-x="${CROP_START_X}"
|
||||
--crop-start-y="${CROP_START_Y}"
|
||||
--crop-end-x="${CROP_END_X}"
|
||||
--crop-end-y="${CROP_END_Y}"
|
||||
COMMENT "Generating texture ${target} from ${FILE}"
|
||||
)
|
||||
add_dependencies(dawnassets ${target})
|
||||
endfunction()
|
113
tools/texturetool/texturetool.py
Executable file
113
tools/texturetool/texturetool.py
Executable file
@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
from PIL import Image
|
||||
import argparse
|
||||
import os
|
||||
|
||||
# Args
|
||||
parser = argparse.ArgumentParser(description='Converts image textures to internal game data format.')
|
||||
parser.add_argument('-i', '--input');
|
||||
parser.add_argument('-o', '--output');
|
||||
parser.add_argument('-s', '--scale');
|
||||
parser.add_argument('-sf', '--scale-filter');
|
||||
parser.add_argument('-wx', '--wrap-x');
|
||||
parser.add_argument('-wy', '--wrap-y');
|
||||
parser.add_argument('-fi', '--filter-min')
|
||||
parser.add_argument('-fg', '--filter-mag')
|
||||
parser.add_argument('-csx', '--crop-start-x');
|
||||
parser.add_argument('-csy', '--crop-start-y');
|
||||
parser.add_argument('-cex', '--crop-end-x');
|
||||
parser.add_argument('-cey', '--crop-end-y');
|
||||
args = parser.parse_args()
|
||||
|
||||
# Ensure input exists
|
||||
if not os.path.exists(args.input):
|
||||
print(f"Input file '{args.input}' does not exist.")
|
||||
exit(1)
|
||||
|
||||
# Open image
|
||||
img = Image.open(args.input)
|
||||
|
||||
# Normalize the image
|
||||
hasAlpha = img.mode == 'RGBA' or img.mode == 'LA'
|
||||
|
||||
# Convert the image to RGB or RGBA mode based on alpha channel
|
||||
if hasAlpha:
|
||||
img = img.convert('RGBA')
|
||||
else:
|
||||
img = img.convert('RGB')
|
||||
|
||||
# Apply cropping
|
||||
crop_box = [
|
||||
int(args.crop_start_x) if args.crop_start_x not in (None, "") else 0,
|
||||
int(args.crop_start_y) if args.crop_start_y not in (None, "") else 0,
|
||||
int(args.crop_end_x) if args.crop_end_x not in (None, "") else img.width,
|
||||
int(args.crop_end_y) if args.crop_end_y not in (None, "") else img.height
|
||||
]
|
||||
img = img.crop(crop_box)
|
||||
|
||||
# Apply scaling
|
||||
if args.scale not in (None, ""):
|
||||
scale = float(args.scale)
|
||||
newSize = (int(img.width * scale), int(img.height * scale))
|
||||
if args.scale_filter == 'NEAREST':
|
||||
img = img.resize(newSize, Image.NEAREST)
|
||||
elif args.scale_filter == 'BILINEAR':
|
||||
img = img.resize(newSize, Image.BILINEAR)
|
||||
elif args.scale_filter == 'BICUBIC':
|
||||
img = img.resize(newSize, Image.BICUBIC)
|
||||
elif args.scale_filter == 'LANCZOS':
|
||||
img = img.resize(newSize, Image.LANCZOS)
|
||||
else:
|
||||
img = img.resize(newSize)
|
||||
|
||||
|
||||
# Filter
|
||||
if args.filter_min.lower() == 'NEAREST':
|
||||
filterMin = 0
|
||||
else:
|
||||
filterMin = 1
|
||||
|
||||
if args.filter_mag.lower() == 'NEAREST':
|
||||
filterMag = 0
|
||||
else:
|
||||
filterMag = 1
|
||||
|
||||
# Wrap
|
||||
if args.wrap_x.lower() == 'repeat':
|
||||
wrapX = 0
|
||||
elif args.wrap_x.lower() == 'mirror':
|
||||
wrapX = 1
|
||||
elif args.wrap_x.lower() == 'clamp':
|
||||
wrapX = 2
|
||||
elif args.wrap_x.lower() == 'border':
|
||||
wrapX = 3
|
||||
else:
|
||||
wrapX = 2
|
||||
|
||||
if args.wrap_y.lower() == 'repeat':
|
||||
wrapY = 0
|
||||
elif args.wrap_y.lower() == 'mirror':
|
||||
wrapY = 1
|
||||
elif args.wrap_y.lower() == 'clamp':
|
||||
wrapY = 2
|
||||
elif args.wrap_y.lower() == 'border':
|
||||
wrapY = 3
|
||||
else:
|
||||
wrapY = 2
|
||||
|
||||
# Get raw pixel data
|
||||
buffer = img.tobytes()
|
||||
|
||||
# Create the output directory if it doesn't exist
|
||||
os.makedirs(os.path.dirname(args.output), exist_ok=True)
|
||||
|
||||
# Write the image metadata and pixel data to the output file
|
||||
with open(args.output, 'wb') as f:
|
||||
header = f"DT_2.00|{img.width}|{img.height}|{4 if hasAlpha else 3}|{wrapX}|{wrapY}|{filterMin}|{filterMag}|"
|
||||
f.write(header.encode())
|
||||
f.write(buffer)
|
Reference in New Issue
Block a user