Palette loading done.

This commit is contained in:
2025-08-27 19:59:55 -05:00
parent 7a90d2d38f
commit 6c11096fd2
11 changed files with 110 additions and 27 deletions

View File

@@ -7,6 +7,8 @@
target_sources(${DUSK_TARGET_NAME} target_sources(${DUSK_TARGET_NAME}
PRIVATE PRIVATE
asset.c asset.c
assetpalette.c
assettileset.c
) )
# Compile definitions # Compile definitions

View File

@@ -55,7 +55,11 @@ errorret_t assetInit(void) {
errorOk(); errorOk();
} }
void assetLoad(const char_t *filename) { void assetLoad(
const char_t *filename,
void (*callback)(void* data),
void *data
) {
assertNotNull(filename, "Filename cannot be NULL."); assertNotNull(filename, "Filename cannot be NULL.");
assertTrue(strlen(filename) < ASSET_FILENAME_MAX, "Filename too long."); assertTrue(strlen(filename) < ASSET_FILENAME_MAX, "Filename too long.");
assertTrue(strlen(filename) > 0, "Filename cannot be empty."); assertTrue(strlen(filename) > 0, "Filename cannot be empty.");
@@ -74,6 +78,8 @@ void assetLoad(const char_t *filename) {
assertNotNull(expected->extension, "Unknown asset type."); assertNotNull(expected->extension, "Unknown asset type.");
// Pass off to the thread to begin loading. // Pass off to the thread to begin loading.
ASSET.callback = callback;
ASSET.callbackData = data;
ASSET.errorState = ERROR_STATE_INIT; ASSET.errorState = ERROR_STATE_INIT;
ASSET.state = ASSET_STATE_LOADING; ASSET.state = ASSET_STATE_LOADING;
stringCopy(ASSET.filename, filename, ASSET_FILENAME_MAX); stringCopy(ASSET.filename, filename, ASSET_FILENAME_MAX);
@@ -88,6 +94,7 @@ void assetLoad(const char_t *filename) {
"Failed to open asset: %s", "Failed to open asset: %s",
filename filename
); );
if(ASSET.callback) ASSET.callback(ASSET.callbackData);
return; return;
} }
@@ -101,11 +108,13 @@ void assetLoad(const char_t *filename) {
"Failed to stat asset: %s", "Failed to stat asset: %s",
filename filename
); );
if(ASSET.callback) ASSET.callback(ASSET.callbackData);
return; return;
} }
if(st.size > sizeof(ASSET.data.palette)) { if(st.size > sizeof(ASSET.data.palette)) {
zip_fclose(file); zip_fclose(file);
ASSET.state = ASSET_STATE_ERROR;
ASSET.error = errorCreate( ASSET.error = errorCreate(
&ASSET.errorState, &ASSET.errorState,
"Asset size mismatch: %s (got %d, expected %d)", "Asset size mismatch: %s (got %d, expected %d)",
@@ -113,11 +122,12 @@ void assetLoad(const char_t *filename) {
(int)st.size, (int)st.size,
(int)sizeof(ASSET.data.palette) (int)sizeof(ASSET.data.palette)
); );
if(ASSET.callback) ASSET.callback(ASSET.callbackData);
return; return;
} }
// Read entire file into the asset data. // Read entire file into the asset data.
zip_fread(file, &ASSET.data, st.size); zip_fread(file, &ASSET.data, st.size);
zip_fclose(file); zip_fclose(file);
ASSET.state = ASSET_STATE_LOADED; ASSET.state = ASSET_STATE_LOADED;
@@ -136,10 +146,16 @@ void assetLoad(const char_t *filename) {
expected->header[1], expected->header[1],
expected->header[2] expected->header[2]
); );
if(ASSET.callback) ASSET.callback(ASSET.callbackData);
return; return;
} }
// Parse the asset.
assertNotNull(expected->parser, "Asset parser cannot be NULL.");
expected->parser();
printf("Loaded asset: %s\n", filename); printf("Loaded asset: %s\n", filename);
if(ASSET.callback) ASSET.callback(ASSET.callbackData);
} }
void assetDispose(void) { void assetDispose(void) {

View File

@@ -11,6 +11,7 @@
#include "assettileset.h" #include "assettileset.h"
#include "error/error.h" #include "error/error.h"
#include <zip.h> #include <zip.h>
#include "display/texture/texture.h"
#define ASSET_COUNT_MAX 128 #define ASSET_COUNT_MAX 128
#define ASSET_FILENAME_MAX 128 #define ASSET_FILENAME_MAX 128
@@ -21,6 +22,7 @@
#error "Unsupported ASSET_TYPE" #error "Unsupported ASSET_TYPE"
#endif #endif
#pragma pack(push, 1)
typedef struct { typedef struct {
char_t header[ASSET_HEADER_LENGTH]; char_t header[ASSET_HEADER_LENGTH];
union { union {
@@ -28,6 +30,14 @@ typedef struct {
assettileset_t tileset; assettileset_t tileset;
}; };
} assetdata_t; } assetdata_t;
#pragma pack(pop)
typedef struct {
union {
texture_t palette;
assettileset_t *tileset;
};
} assetloaded_t;
typedef enum { typedef enum {
ASSET_STATE_NONE, ASSET_STATE_NONE,
@@ -46,11 +56,16 @@ typedef struct {
assetstate_t state; assetstate_t state;
char_t filename[ASSET_FILENAME_MAX]; char_t filename[ASSET_FILENAME_MAX];
assetdata_t data; assetdata_t data;
assetloaded_t loaded;
void (*callback)(void* data);
void *callbackData;
} asset_t; } asset_t;
typedef struct { typedef struct {
const char_t *header; const char_t *header;
const char_t *extension; const char_t *extension;
void (*parser)();
} assetmap_t; } assetmap_t;
static const char_t ASSET_SEARCH_PATHS[][FILENAME_MAX] = { static const char_t ASSET_SEARCH_PATHS[][FILENAME_MAX] = {
@@ -63,9 +78,9 @@ static const char_t ASSET_SEARCH_PATHS[][FILENAME_MAX] = {
}; };
static const assetmap_t ASSET_MAP[] = { static const assetmap_t ASSET_MAP[] = {
{ "DPF", "test.palette.dpf" }, { "DPF", ".dpf", assetParsePalette },
{ "DPT", "test.tileset.dpt" }, { "DPT", ".dpt", assetParseTileset },
{ NULL, NULL } { NULL, NULL, NULL }
}; };
#define ASSET_SEARCH_PATHS_COUNT (\ #define ASSET_SEARCH_PATHS_COUNT (\
@@ -83,9 +98,15 @@ errorret_t assetInit(void);
* Gets an asset by filename, does not load it. * Gets an asset by filename, does not load it.
* *
* @param filename The filename of the asset to get. * @param filename The filename of the asset to get.
* @param callback The callback to call when the asset is loaded.
* @param data The data for the callback function.
* @return The asset. * @return The asset.
*/ */
void assetLoad(const char_t *filename); void assetLoad(
const char_t *filename,
void (*callback)(void* data),
void *data
);
/** /**
* Disposes/cleans up the asset system. * Disposes/cleans up the asset system.

18
src/asset/assetpalette.c Normal file
View File

@@ -0,0 +1,18 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "asset.h"
void assetParsePalette() {
textureInit(
&ASSET.loaded.palette,
ASSET.data.palette.colorCount,
1,
TEXTURE_FORMAT_RGBA,
ASSET.data.palette.colors
);
}

View File

@@ -14,4 +14,9 @@
typedef struct { typedef struct {
int32_t colorCount; int32_t colorCount;
color4b_t colors[ASSET_PALETTE_COLOR_COUNT_MAX]; color4b_t colors[ASSET_PALETTE_COLOR_COUNT_MAX];
} assetpalette_t; } assetpalette_t;
/**
* Parse the palette from the loaded raw data.
*/
void assetParsePalette();

12
src/asset/assettileset.c Normal file
View File

@@ -0,0 +1,12 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "asset.h"
void assetParseTileset() {
ASSET.loaded.tileset = &ASSET.data.tileset;
}

View File

@@ -16,4 +16,9 @@ typedef struct {
int32_t tileCount; int32_t tileCount;
int32_t columns; int32_t columns;
char_t tilesetName[256]; char_t tilesetName[256];
} assettileset_t; } assettileset_t;
/**
* Parse the tileset from the loaded raw data.
*/
void assetParseTileset();

View File

@@ -18,6 +18,12 @@
engine_t ENGINE; engine_t ENGINE;
void assetLoadCallback(void *data) {
consolePrint("Asset load callback called!");
test = ASSET.loaded.palette;
consolePrint("Loaded palette with %d colors", ASSET.data.palette.colorCount);
}
errorret_t engineInit(void) { errorret_t engineInit(void) {
memoryZero(&ENGINE, sizeof(engine_t)); memoryZero(&ENGINE, sizeof(engine_t));
ENGINE.running = true; ENGINE.running = true;
@@ -28,9 +34,8 @@ errorret_t engineInit(void) {
ecsSystemInit(); ecsSystemInit();
errorChain(assetInit()); errorChain(assetInit());
errorChain(displayInit()); errorChain(displayInit());
// assetLoad("test.palette.dp123123"); assetLoad("test.palette.dpf", assetLoadCallback, NULL);
assetLoad("test.palette.dpf");
if(ASSET.state == ASSET_STATE_ERROR) errorChain(ASSET.error); if(ASSET.state == ASSET_STATE_ERROR) errorChain(ASSET.error);
sceneTestAdd(); sceneTestAdd();

View File

@@ -28,11 +28,11 @@ void sceneTestAdd(void) {
); );
nodeMatrixSet(camera, lookAt); nodeMatrixSet(camera, lookAt);
color4b_t pixels[4] = { // color4b_t pixels[4] = {
COLOR_RED, COLOR_GREEN, // COLOR_RED, COLOR_GREEN,
COLOR_BLUE, COLOR_WHITE // COLOR_BLUE, COLOR_WHITE
}; // };
textureInit(&test, 2, 2, TEXTURE_FORMAT_RGBA, pixels); // textureInit(&test, 2, 2, TEXTURE_FORMAT_RGBA, pixels);
// Test cube // Test cube
ecsid_t cube = ecsEntityAdd(); ecsid_t cube = ecsEntityAdd();

View File

@@ -7,5 +7,8 @@
#pragma once #pragma once
#include "ecs/ecssystem.h" #include "ecs/ecssystem.h"
#include "display/texture/texture.h"
extern texture_t test;
void sceneTestAdd(void); void sceneTestAdd(void);

View File

@@ -1,6 +1,7 @@
import os import os
from args import args from args import args
from PIL import Image from PIL import Image
import struct
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
@@ -14,19 +15,14 @@ def extractPaletteFromImage(image):
return uniqueColors return uniqueColors
def savePalette(pixels, outputFilePath): def savePalette(pixels, outputFilePath):
# Pixels is a list of (R, G, B, A) tuples
data = "DPF" # Header for Dusk Palette Format
# Count of colors (int32_t)
colorCount = len(pixels) colorCount = len(pixels)
data += colorCount.to_bytes(4, byteorder='little').decode('latin1') buf = bytearray(b"DPF")
buf += struct.pack("<i", colorCount) # little-endian int32_t
for r, g, b, a in pixels: for r, g, b, a in pixels: # each channel 0..255
data += bytes([r, g, b, a]).decode('latin1') buf += struct.pack("BBBB", r, g, b, a) # raw bytes
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)
def processPalette(assetPath): def processPalette(assetPath):
# Process the image file # Process the image file