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}
PRIVATE
asset.c
assetpalette.c
assettileset.c
)
# Compile definitions

View File

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

View File

@@ -11,6 +11,7 @@
#include "assettileset.h"
#include "error/error.h"
#include <zip.h>
#include "display/texture/texture.h"
#define ASSET_COUNT_MAX 128
#define ASSET_FILENAME_MAX 128
@@ -21,6 +22,7 @@
#error "Unsupported ASSET_TYPE"
#endif
#pragma pack(push, 1)
typedef struct {
char_t header[ASSET_HEADER_LENGTH];
union {
@@ -28,6 +30,14 @@ typedef struct {
assettileset_t tileset;
};
} assetdata_t;
#pragma pack(pop)
typedef struct {
union {
texture_t palette;
assettileset_t *tileset;
};
} assetloaded_t;
typedef enum {
ASSET_STATE_NONE,
@@ -46,11 +56,16 @@ typedef struct {
assetstate_t state;
char_t filename[ASSET_FILENAME_MAX];
assetdata_t data;
assetloaded_t loaded;
void (*callback)(void* data);
void *callbackData;
} asset_t;
typedef struct {
const char_t *header;
const char_t *extension;
void (*parser)();
} assetmap_t;
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[] = {
{ "DPF", "test.palette.dpf" },
{ "DPT", "test.tileset.dpt" },
{ NULL, NULL }
{ "DPF", ".dpf", assetParsePalette },
{ "DPT", ".dpt", assetParseTileset },
{ NULL, NULL, NULL }
};
#define ASSET_SEARCH_PATHS_COUNT (\
@@ -83,9 +98,15 @@ errorret_t assetInit(void);
* Gets an asset by filename, does not load it.
*
* @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.
*/
void assetLoad(const char_t *filename);
void assetLoad(
const char_t *filename,
void (*callback)(void* data),
void *data
);
/**
* 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 {
int32_t colorCount;
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 columns;
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;
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) {
memoryZero(&ENGINE, sizeof(engine_t));
ENGINE.running = true;
@@ -28,9 +34,8 @@ errorret_t engineInit(void) {
ecsSystemInit();
errorChain(assetInit());
errorChain(displayInit());
// assetLoad("test.palette.dp123123");
assetLoad("test.palette.dpf");
assetLoad("test.palette.dpf", assetLoadCallback, NULL);
if(ASSET.state == ASSET_STATE_ERROR) errorChain(ASSET.error);
sceneTestAdd();

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
import os
from args import args
from PIL import Image
import struct
def extractPaletteFromImage(image):
# goes through and finds all unique colors in the image
@@ -14,19 +15,14 @@ def extractPaletteFromImage(image):
return uniqueColors
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)
data += colorCount.to_bytes(4, byteorder='little').decode('latin1')
for r, g, b, a in pixels:
data += bytes([r, g, b, a]).decode('latin1')
buf = bytearray(b"DPF")
buf += struct.pack("<i", colorCount) # little-endian int32_t
for r, g, b, a in pixels: # each channel 0..255
buf += struct.pack("BBBB", r, g, b, a) # raw bytes
os.makedirs(os.path.dirname(outputFilePath), exist_ok=True)
with open(outputFilePath, 'wb') as f:
f.write(data.encode('latin1'))
with open(outputFilePath, "wb") as f:
f.write(buf)
def processPalette(assetPath):
# Process the image file