Image generation?
This commit is contained in:
@@ -3,6 +3,5 @@
|
|||||||
# This software is released under the MIT License.
|
# This software is released under the MIT License.
|
||||||
# https://opensource.org/licenses/MIT
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
add_asset(test.palette.png)
|
add_asset(first.palette.png)
|
||||||
# add_asset(first.palette.png)
|
add_asset(entities.tsx)
|
||||||
# add_asset(entities.tsx)
|
|
Binary file not shown.
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 268 B |
Binary file not shown.
Before Width: | Height: | Size: 84 B |
@@ -40,18 +40,6 @@ errorret_t assetInit(void) {
|
|||||||
// Did we open the asset?
|
// Did we open the asset?
|
||||||
if(ASSET.zip == NULL) errorThrow("Failed to open asset file.");
|
if(ASSET.zip == NULL) errorThrow("Failed to open asset file.");
|
||||||
|
|
||||||
// Get "test.palette.dpf" file.
|
|
||||||
zip_file_t *file = zip_fopen(ASSET.zip, "test.palette.dpf", 0);
|
|
||||||
if(file == NULL) errorThrow("Failed to open test.palette.dpf in asset file.");
|
|
||||||
|
|
||||||
// Read it
|
|
||||||
char_t buffer[256];
|
|
||||||
zip_int64_t n = zip_fread(file, buffer, 256);
|
|
||||||
if(n < 0) {
|
|
||||||
zip_fclose(file);
|
|
||||||
errorThrow("Failed to read test.palette.dpf in asset file.");
|
|
||||||
}
|
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +86,8 @@ void assetLoad(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("Loading asset: %s\n", filename);
|
||||||
|
|
||||||
// Determine length of the file (uncompressed)
|
// Determine length of the file (uncompressed)
|
||||||
struct zip_stat st;
|
struct zip_stat st;
|
||||||
if(zip_stat(ASSET.zip, filename, 0, &st) != 0) {
|
if(zip_stat(ASSET.zip, filename, 0, &st) != 0) {
|
||||||
|
@@ -35,7 +35,7 @@ errorret_t engineInit(void) {
|
|||||||
errorChain(assetInit());
|
errorChain(assetInit());
|
||||||
errorChain(displayInit());
|
errorChain(displayInit());
|
||||||
|
|
||||||
assetLoad("test.palette.dpf", assetLoadCallback, NULL);
|
assetLoad("first.palette.dpf", assetLoadCallback, NULL);
|
||||||
if(ASSET.state == ASSET_STATE_ERROR) errorChain(ASSET.error);
|
if(ASSET.state == ASSET_STATE_ERROR) errorChain(ASSET.error);
|
||||||
|
|
||||||
sceneTestAdd();
|
sceneTestAdd();
|
||||||
|
@@ -2,6 +2,10 @@ import os
|
|||||||
from args import args
|
from args import args
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import struct
|
import struct
|
||||||
|
import sys
|
||||||
|
from assethelpers import getAssetRelativePath
|
||||||
|
|
||||||
|
PALETTES = []
|
||||||
|
|
||||||
def extractPaletteFromImage(image):
|
def extractPaletteFromImage(image):
|
||||||
# goes through and finds all unique colors in the image
|
# goes through and finds all unique colors in the image
|
||||||
@@ -10,6 +14,9 @@ def extractPaletteFromImage(image):
|
|||||||
pixels = list(image.getdata())
|
pixels = list(image.getdata())
|
||||||
uniqueColors = []
|
uniqueColors = []
|
||||||
for color in pixels:
|
for color in pixels:
|
||||||
|
# We treat alpha 0 as rgba(0,0,0,0) for palette purposes
|
||||||
|
if color[3] == 0:
|
||||||
|
color = (0, 0, 0, 0)
|
||||||
if color not in uniqueColors:
|
if color not in uniqueColors:
|
||||||
uniqueColors.append(color)
|
uniqueColors.append(color)
|
||||||
return uniqueColors
|
return uniqueColors
|
||||||
@@ -40,21 +47,70 @@ def processPalette(assetPath):
|
|||||||
|
|
||||||
outputRelative = os.path.relpath(outputFilePath, args.output_assets)
|
outputRelative = os.path.relpath(outputFilePath, args.output_assets)
|
||||||
|
|
||||||
return {
|
palette = {
|
||||||
"outputFile": outputRelative,
|
"outputFile": outputRelative,
|
||||||
"paletteColors": len(pixels),
|
"paletteColors": len(pixels),
|
||||||
"files": [ outputFilePath ]
|
"files": [ outputFilePath ],
|
||||||
|
"pixels": pixels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PALETTES.append(palette)
|
||||||
|
|
||||||
|
return palette
|
||||||
|
|
||||||
def processImage(assetPath):
|
def processImage(assetPath):
|
||||||
print(f"Processing image: {assetPath}")
|
print(f"Processing image: {assetPath}")
|
||||||
|
|
||||||
# Load the image
|
# Load the image
|
||||||
image = Image.open(assetPath)
|
image = Image.open(assetPath)
|
||||||
pixels = extractPaletteFromImage(image)
|
|
||||||
|
# Get the image's palette because we are going to try and find a matching
|
||||||
|
# palette from the already processed palettes...
|
||||||
|
imagePalette = extractPaletteFromImage(image)
|
||||||
|
|
||||||
|
# Now find which palette has every single color in this image's palette
|
||||||
|
paletteIndex = -1
|
||||||
|
for i, palette in enumerate(PALETTES):
|
||||||
|
paletteColors = palette["pixels"]
|
||||||
|
if all(color in paletteColors for color in imagePalette):
|
||||||
|
paletteIndex = i
|
||||||
|
break
|
||||||
|
|
||||||
|
# Did we manage to find a matching palette?
|
||||||
|
if paletteIndex == -1:
|
||||||
|
print(f"Error: No matching palette found for image {assetPath}. Please process a suitable palette first.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# We found the palette, so now we can convert the image to use that palette
|
||||||
|
palette = PALETTES[paletteIndex]
|
||||||
|
indexes = []
|
||||||
|
for color in imagePalette:
|
||||||
|
if color in palette["pixels"]:
|
||||||
|
index = palette["pixels"].index(color)
|
||||||
|
indexes.append(index)
|
||||||
|
else:
|
||||||
|
print(f"Error: Color {color} in image {assetPath} not found in palette.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
relative = getAssetRelativePath(assetPath)
|
||||||
|
fileNameWithoutExt = os.path.splitext(os.path.basename(assetPath))[0]
|
||||||
|
outputFileRelative = os.path.join(os.path.dirname(relative), f"{fileNameWithoutExt}.dpi")
|
||||||
|
outputFilePath = os.path.join(args.output_assets, outputFileRelative)
|
||||||
|
os.makedirs(os.path.dirname(outputFilePath), exist_ok=True)
|
||||||
|
with open(outputFilePath, "wb") as f:
|
||||||
|
# Write header
|
||||||
|
f.write(b"DPI") # Dusk Palettized Image
|
||||||
|
f.write(struct.pack("<i", image.width)) # Width
|
||||||
|
f.write(struct.pack("<i", image.height)) # Height
|
||||||
|
f.write(struct.pack("<i", paletteIndex)) # Palette index
|
||||||
|
|
||||||
|
# Write uint8_t pixel index.
|
||||||
|
for index in indexes:
|
||||||
|
f.write(struct.pack("B", index))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
# "outputFile": os.path.relpath(assetPath, args.input_assets),
|
"paletteIndex": paletteIndex,
|
||||||
# "paletteColors": len(pixels),
|
"palette": PALETTES[paletteIndex],
|
||||||
"files": [ assetPath ]
|
"outputFile": outputFileRelative,
|
||||||
|
"files": [ assetPath, outputFilePath ]
|
||||||
}
|
}
|
@@ -47,32 +47,28 @@ def processTileset(assetPath):
|
|||||||
relativeFile = getAssetRelativePath(assetPath)
|
relativeFile = getAssetRelativePath(assetPath)
|
||||||
relativeDir = os.path.dirname(relativeFile)
|
relativeDir = os.path.dirname(relativeFile)
|
||||||
|
|
||||||
data = "DTF" # Header for Dusk Tileset Format
|
|
||||||
# Write width (int32_t)
|
|
||||||
data += tilewidth.to_bytes(4, byteorder='little').decode('latin1')
|
|
||||||
# Write height (int32_t)
|
|
||||||
data += tileheight.to_bytes(4, byteorder='little').decode('latin1')
|
|
||||||
# Write tilecount (int32_t)
|
|
||||||
data += tilecount.to_bytes(4, byteorder='little').decode('latin1')
|
|
||||||
# Write column count (int32_t)
|
|
||||||
data += columns.to_bytes(4, byteorder='little').decode('latin1')
|
|
||||||
# Write row count (int32_t)
|
|
||||||
rows = (tilecount + columns - 1) // columns
|
rows = (tilecount + columns - 1) // columns
|
||||||
data += rows.to_bytes(4, byteorder='little').decode('latin1')
|
|
||||||
|
buf = bytearray(b"DTF")
|
||||||
|
buf += tilewidth.to_bytes(4, byteorder='little')
|
||||||
|
buf += tileheight.to_bytes(4, byteorder='little')
|
||||||
|
buf += tilecount.to_bytes(4, byteorder='little')
|
||||||
|
buf += columns.to_bytes(4, byteorder='little')
|
||||||
|
buf += rows.to_bytes(4, byteorder='little')
|
||||||
|
|
||||||
# Write image source file name, padd to ASSET_FILE_NAME_MAX_LENGTH
|
# Write image source file name, padd to ASSET_FILE_NAME_MAX_LENGTH
|
||||||
imageSourceBytes = image["outputFile"].encode('utf-8')
|
imageSourceBytes = image["outputFile"].encode('utf-8')
|
||||||
data += len(imageSourceBytes).to_bytes(4, byteorder='little').decode('latin1')
|
buf += len(imageSourceBytes).to_bytes(4, byteorder='little')
|
||||||
data += imageSourceBytes.decode('latin1')
|
buf += imageSourceBytes
|
||||||
paddingLength = max(0, ASSET_FILE_NAME_MAX_LENGTH - len(imageSourceBytes))
|
paddingLength = max(0, ASSET_FILE_NAME_MAX_LENGTH - len(imageSourceBytes))
|
||||||
data += '\x00' * paddingLength
|
buf += b'\x00' * paddingLength
|
||||||
|
|
||||||
# Write to output file
|
# Write to output file
|
||||||
fileNameWithoutExt = os.path.splitext(os.path.basename(assetPath))[0]
|
fileNameWithoutExt = os.path.splitext(os.path.basename(assetPath))[0]
|
||||||
outputFilePath = os.path.join(args.output_assets, relativeDir, f"{fileNameWithoutExt}.dtf")
|
outputFilePath = os.path.join(args.output_assets, relativeDir, f"{fileNameWithoutExt}.dtf")
|
||||||
os.makedirs(os.path.dirname(outputFilePath), exist_ok=True)
|
os.makedirs(os.path.dirname(outputFilePath), exist_ok=True)
|
||||||
with open(outputFilePath, 'wb') as f:
|
with open(outputFilePath, 'wb') as f:
|
||||||
f.write(data.encode('latin1'))
|
f.write(buf)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"outputFile": os.path.relpath(outputFilePath, args.output_assets),
|
"outputFile": os.path.relpath(outputFilePath, args.output_assets),
|
||||||
@@ -81,5 +77,6 @@ def processTileset(assetPath):
|
|||||||
"tileCount": tilecount,
|
"tileCount": tilecount,
|
||||||
"columns": columns,
|
"columns": columns,
|
||||||
"rows": rows,
|
"rows": rows,
|
||||||
"image": image
|
"image": image,
|
||||||
|
"files": [ outputFilePath ] + image["files"]
|
||||||
}
|
}
|
Reference in New Issue
Block a user