Palettized image test.
This commit is contained in:
@@ -9,3 +9,6 @@ target_sources(${DUSK_TARGET_NAME}
|
|||||||
asset.c
|
asset.c
|
||||||
assetmanager.c
|
assetmanager.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Subdirs
|
||||||
|
add_subdirectory(type)
|
@@ -11,6 +11,10 @@
|
|||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "console/console.h"
|
#include "console/console.h"
|
||||||
|
|
||||||
|
assetdef_t ASSET_DEFINITIONS[ASSET_TYPE_COUNT] = {
|
||||||
|
[ASSET_TYPE_PALETTE_IMAGE] = { "DPI", assetPaletteImageLoad },
|
||||||
|
};
|
||||||
|
|
||||||
errorret_t assetInit(asset_t *asset, const char_t *filename) {
|
errorret_t assetInit(asset_t *asset, const char_t *filename) {
|
||||||
assertNotNull(asset, "Asset cannot be NULL.");
|
assertNotNull(asset, "Asset cannot be NULL.");
|
||||||
assertNotNull(filename, "Filename cannot be NULL.");
|
assertNotNull(filename, "Filename cannot be NULL.");
|
||||||
@@ -27,10 +31,101 @@ errorret_t assetInit(asset_t *asset, const char_t *filename) {
|
|||||||
ASSET_REFERENCE_COUNT_MAX
|
ASSET_REFERENCE_COUNT_MAX
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Test the file can be opened. In future I may make the handle stay open for
|
||||||
|
// a while to see if it increases performance and stops disk thrashing.
|
||||||
asset->file = zip_fopen(ASSET_MANAGER.zip, filename, 0);
|
asset->file = zip_fopen(ASSET_MANAGER.zip, filename, 0);
|
||||||
if(asset->file == NULL) errorThrow("Failed to open asset file: %s", filename);
|
if(asset->file == NULL) errorThrow("Failed to open asset file: %s", filename);
|
||||||
|
zip_fclose(asset->file);
|
||||||
|
asset->file = NULL;
|
||||||
|
|
||||||
consolePrint("Initialized asset: %s", filename);
|
consolePrint("Initialized asset: %s", filename);
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref_t assetLock(asset_t *asset) {
|
||||||
|
assertNotNull(asset, "Asset cannot be NULL.");
|
||||||
|
|
||||||
|
return refListLock(&asset->refList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void assetUnlock(asset_t *asset, const ref_t ref) {
|
||||||
|
assertNotNull(asset, "Asset cannot be NULL.");
|
||||||
|
assertTrue(ref > 0, "Reference must be greater than 0.");
|
||||||
|
|
||||||
|
// Just unlock the reference in the reference list.
|
||||||
|
refListUnlock(&asset->refList, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t assetLoad(asset_t *asset) {
|
||||||
|
assertNotNull(asset, "Asset cannot be NULL.");
|
||||||
|
assertTrue(
|
||||||
|
asset->state == ASSET_STATE_NOT_LOADED,
|
||||||
|
"Asset is already loaded or loading."
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mark as loading.
|
||||||
|
asset->state = ASSET_STATE_LOADING;
|
||||||
|
|
||||||
|
// Open the file.
|
||||||
|
if(asset->file == NULL) {
|
||||||
|
asset->file = zip_fopen(ASSET_MANAGER.zip, asset->filename, 0);
|
||||||
|
if(asset->file == NULL) {
|
||||||
|
asset->state = ASSET_STATE_ERROR;
|
||||||
|
errorThrow("Failed to open asset file: %s", asset->filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read header.
|
||||||
|
char_t header[ASSET_HEADER_SIZE + 1];
|
||||||
|
memoryZero(header, ASSET_HEADER_SIZE + 1);
|
||||||
|
zip_int64_t bytesRead = zip_fread(asset->file, header, ASSET_HEADER_SIZE);
|
||||||
|
if(bytesRead != ASSET_HEADER_SIZE) {
|
||||||
|
asset->state = ASSET_STATE_ERROR;
|
||||||
|
zip_fclose(asset->file);
|
||||||
|
asset->file = NULL;
|
||||||
|
errorThrow("Failed to read asset header for: %s", asset->filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check header.
|
||||||
|
if(strlen(header) != ASSET_HEADER_SIZE) {
|
||||||
|
asset->state = ASSET_STATE_ERROR;
|
||||||
|
zip_fclose(asset->file);
|
||||||
|
asset->file = NULL;
|
||||||
|
errorThrow("Invalid asset header for: %s", asset->filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the asset definition based on the header.
|
||||||
|
assetdef_t *def;
|
||||||
|
for(uint_fast8_t i = 0; i < ASSET_TYPE_COUNT; i++) {
|
||||||
|
if(strcmp(header, ASSET_DEFINITIONS[i].header) == 0) {
|
||||||
|
def = &ASSET_DEFINITIONS[i];
|
||||||
|
asset->type = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertNotNull(def, "Failed to find asset definition for header.");
|
||||||
|
|
||||||
|
// Load the asset
|
||||||
|
errorret_t ret = def->load(asset);
|
||||||
|
if(ret.code != ERROR_OK) {
|
||||||
|
asset->state = ASSET_STATE_ERROR;
|
||||||
|
zip_fclose(asset->file);
|
||||||
|
asset->file = NULL;
|
||||||
|
errorChain(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finished loading.
|
||||||
|
asset->state = ASSET_STATE_LOADED;
|
||||||
|
zip_fclose(asset->file);
|
||||||
|
asset->file = NULL;
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void assetDispose(asset_t *asset) {
|
||||||
|
assertNotNull(asset, "Asset cannot be NULL.");
|
||||||
|
|
||||||
|
if(asset->file) {
|
||||||
|
zip_fclose(asset->file);
|
||||||
|
asset->file = NULL;
|
||||||
|
}
|
||||||
|
}
|
@@ -6,14 +6,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "assetpaletteimage.h"
|
|
||||||
#include "error/error.h"
|
#include "error/error.h"
|
||||||
#include "util/reflist.h"
|
#include "util/reflist.h"
|
||||||
#include <zip.h>
|
#include <zip.h>
|
||||||
|
|
||||||
|
#include "asset/type/assetpaletteimage.h"
|
||||||
|
|
||||||
#define ASSET_HEADER_SIZE 3
|
#define ASSET_HEADER_SIZE 3
|
||||||
#define ASSET_REFERENCE_COUNT_MAX 8
|
#define ASSET_REFERENCE_COUNT_MAX 8
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void (*load)();
|
||||||
|
} assetcallback_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ASSET_STATE_NOT_LOADED,
|
ASSET_STATE_NOT_LOADED,
|
||||||
ASSET_STATE_LOADING,
|
ASSET_STATE_LOADING,
|
||||||
@@ -24,18 +29,30 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
ASSET_TYPE_UNKNOWN,
|
ASSET_TYPE_UNKNOWN,
|
||||||
ASSET_TYPE_PALETTE_IMAGE,
|
ASSET_TYPE_PALETTE_IMAGE,
|
||||||
|
|
||||||
|
ASSET_TYPE_COUNT
|
||||||
} assettype_t;
|
} assettype_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct asset_s {
|
||||||
const char_t filename[FILENAME_MAX];
|
char_t filename[FILENAME_MAX];
|
||||||
ref_t refListArray[ASSET_REFERENCE_COUNT_MAX];
|
ref_t refListArray[ASSET_REFERENCE_COUNT_MAX];
|
||||||
reflist_t refList;
|
reflist_t refList;
|
||||||
assetstate_t state;
|
assetstate_t state;
|
||||||
assettype_t type;
|
assettype_t type;
|
||||||
void *data;
|
|
||||||
zip_file_t *file;
|
zip_file_t *file;
|
||||||
|
|
||||||
|
union {
|
||||||
|
assetpaletteimage_t paletteImage;
|
||||||
|
};
|
||||||
} asset_t;
|
} asset_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char_t header[ASSET_HEADER_SIZE + 1];
|
||||||
|
errorret_t (*load)(asset_t *asset);
|
||||||
|
} assetdef_t;
|
||||||
|
|
||||||
|
extern assetdef_t ASSET_DEFINITIONS[ASSET_TYPE_COUNT];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes an asset structure. This should be called by the asset manager
|
* Initializes an asset structure. This should be called by the asset manager
|
||||||
* only.
|
* only.
|
||||||
@@ -45,3 +62,39 @@ typedef struct {
|
|||||||
* @return An error code.
|
* @return An error code.
|
||||||
*/
|
*/
|
||||||
errorret_t assetInit(asset_t *asset, const char_t *filename);
|
errorret_t assetInit(asset_t *asset, const char_t *filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests a lock on the given asset. This will increase the reference count
|
||||||
|
* of the asset, and prevent it from being unloaded until all locks are
|
||||||
|
* released.
|
||||||
|
*
|
||||||
|
* @param asset The asset to lock.
|
||||||
|
* @return A unique reference ID for the lock.
|
||||||
|
*/
|
||||||
|
ref_t assetLock(asset_t *asset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases a lock on the given asset. This will decrease the reference count
|
||||||
|
* of the asset, and allow it to be unloaded if there are no more locks.
|
||||||
|
*
|
||||||
|
* @param asset The asset to unlock.
|
||||||
|
* @param ref The reference ID of the lock to release.
|
||||||
|
*/
|
||||||
|
void assetUnlock(asset_t *asset, const ref_t ref);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permission has been granted to load the asset data from disk. This should
|
||||||
|
* only be called by the asset manager.
|
||||||
|
*
|
||||||
|
* @param asset The asset to load.
|
||||||
|
* @return An error code.
|
||||||
|
*/
|
||||||
|
errorret_t assetLoad(asset_t *asset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes of the asset, freeing any allocated memory and closing any open
|
||||||
|
* file handles. This should only be called by the asset manager.
|
||||||
|
*
|
||||||
|
* @param asset The asset to dispose of.
|
||||||
|
*/
|
||||||
|
void assetDispose(asset_t *asset);
|
@@ -44,7 +44,18 @@ errorret_t assetManagerInit(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void assetManagerUpdate(void) {
|
void assetManagerUpdate(void) {
|
||||||
|
// Update all assets
|
||||||
|
asset_t *asset = ASSET_MANAGER.assets;
|
||||||
|
while(asset < &ASSET_MANAGER.assets[ASSET_MANAGER.assetCount]) {
|
||||||
|
if(asset->state == ASSET_STATE_LOADING) {
|
||||||
|
// Check if the asset is loaded
|
||||||
|
if(asset->file != NULL) {
|
||||||
|
asset->state = ASSET_STATE_LOADED;
|
||||||
|
consolePrint("Asset loaded: %s", asset->filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++asset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t assetManagerGetAsset(const char_t *filename, asset_t **outAsset) {
|
errorret_t assetManagerGetAsset(const char_t *filename, asset_t **outAsset) {
|
||||||
@@ -71,6 +82,7 @@ errorret_t assetManagerGetAsset(const char_t *filename, asset_t **outAsset) {
|
|||||||
|
|
||||||
// Pop an asset off the struct
|
// Pop an asset off the struct
|
||||||
asset = &ASSET_MANAGER.assets[ASSET_MANAGER.assetCount++];
|
asset = &ASSET_MANAGER.assets[ASSET_MANAGER.assetCount++];
|
||||||
|
*outAsset = asset;
|
||||||
errorChain(assetInit(asset, filename));
|
errorChain(assetInit(asset, filename));
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
static const char_t ASSET_MANAGER_SEARCH_PATHS[][FILENAME_MAX] = {
|
static const char_t ASSET_MANAGER_SEARCH_PATHS[][FILENAME_MAX] = {
|
||||||
"%s/%s",
|
"%s/%s",
|
||||||
"./%s",
|
"%s",
|
||||||
"../%s",
|
"../%s",
|
||||||
"../../%s",
|
"../../%s",
|
||||||
"data/%s",
|
"data/%s",
|
||||||
@@ -50,7 +50,8 @@ void assetManagerUpdate(void);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an asset by filename. This will return NULL if the asset does not exist.
|
* Get an asset by filename. This will return NULL if the asset does not exist.
|
||||||
* This will not lock the asset, you must do that separately.
|
* This will not lock the asset, you must do that separately. If you do not
|
||||||
|
* lock the asset there is no guarantee the asset pointer will remain valid.
|
||||||
*
|
*
|
||||||
* @param filename The filename of the asset to get.
|
* @param filename The filename of the asset to get.
|
||||||
* @param outAsset The output asset pointer.
|
* @param outAsset The output asset pointer.
|
||||||
|
@@ -1,17 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "dusk.h"
|
|
||||||
|
|
||||||
#define ASSET_PALETTE_IMAGE_SIZE_MAX (256*256)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t width;
|
|
||||||
uint32_t height;
|
|
||||||
uint8_t data[ASSET_PALETTE_IMAGE_SIZE_MAX];
|
|
||||||
} assetpaletteimage_t;
|
|
10
src/asset/type/CMakeLists.txt
Normal file
10
src/asset/type/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Copyright (c) 2025 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
# Sources
|
||||||
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
|
PRIVATE
|
||||||
|
assetpaletteimage.c
|
||||||
|
)
|
57
src/asset/type/assetpaletteimage.c
Normal file
57
src/asset/type/assetpaletteimage.c
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "asset/asset.h"
|
||||||
|
#include "display/palette/palettelist.h"
|
||||||
|
|
||||||
|
errorret_t assetPaletteImageLoad(asset_t *asset) {
|
||||||
|
// Read entire palettized image.
|
||||||
|
assetpaletteimageraw_t raw;
|
||||||
|
zip_int64_t bytesRead = zip_fread(asset->file, &raw, sizeof(raw));
|
||||||
|
|
||||||
|
if(bytesRead < sizeof(raw.width) + sizeof(raw.height)) {
|
||||||
|
errorThrow("Failed to read palette image dimensions.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(raw.width <= 0 || raw.width > ASSET_PALETTE_IMAGE_WIDTH_MAX) {
|
||||||
|
errorThrow("Invalid palette image width.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(raw.height <= 0 || raw.height > ASSET_PALETTE_IMAGE_HEIGHT_MAX) {
|
||||||
|
errorThrow("Invalid palette image height.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(raw.paletteIndex >= PALETTE_LIST_COUNT) {
|
||||||
|
errorThrow("Invalid palette index.");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Palette image dimensions: %ux%u\n", raw.width, raw.height);
|
||||||
|
zip_int64_t expecting = (
|
||||||
|
sizeof(raw.width) +
|
||||||
|
sizeof(raw.height) +
|
||||||
|
sizeof(raw.paletteIndex) +
|
||||||
|
(raw.width * raw.height * sizeof(uint8_t))
|
||||||
|
);
|
||||||
|
if(bytesRead != expecting) {
|
||||||
|
errorThrow("Incorrect palette filesize.");
|
||||||
|
}
|
||||||
|
|
||||||
|
textureInit(
|
||||||
|
&asset->paletteImage.texture,
|
||||||
|
(int32_t)raw.width,
|
||||||
|
(int32_t)raw.height,
|
||||||
|
TEXTURE_FORMAT_PALETTE,
|
||||||
|
(texturedata_t){
|
||||||
|
.palette = {
|
||||||
|
.palette = raw.paletteIndex,
|
||||||
|
.data = raw.palette
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
40
src/asset/type/assetpaletteimage.h
Normal file
40
src/asset/type/assetpaletteimage.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "error/error.h"
|
||||||
|
#include "display/texture/texture.h"
|
||||||
|
|
||||||
|
#define ASSET_PALETTE_IMAGE_WIDTH_MAX 256
|
||||||
|
#define ASSET_PALETTE_IMAGE_HEIGHT_MAX 256
|
||||||
|
#define ASSET_PALETTE_IMAGE_SIZE_MAX ( \
|
||||||
|
ASSET_PALETTE_IMAGE_WIDTH_MAX * ASSET_PALETTE_IMAGE_HEIGHT_MAX \
|
||||||
|
)
|
||||||
|
|
||||||
|
typedef struct asset_s asset_t;
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct {
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
uint8_t paletteIndex;
|
||||||
|
uint8_t palette[ASSET_PALETTE_IMAGE_SIZE_MAX];
|
||||||
|
} assetpaletteimageraw_t;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
texture_t texture;
|
||||||
|
} assetpaletteimage_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a palette image asset from the given asset structure. The asset must
|
||||||
|
* be of type ASSET_TYPE_PALETTE_IMAGE and must be loaded.
|
||||||
|
*
|
||||||
|
* @param asset The asset to load the palette image from.
|
||||||
|
* @return An error code.
|
||||||
|
*/
|
||||||
|
errorret_t assetPaletteImageLoad(asset_t *asset);
|
@@ -11,8 +11,10 @@
|
|||||||
#include "display/framebuffer/framebuffer.h"
|
#include "display/framebuffer/framebuffer.h"
|
||||||
#include "display/scene/scenemanager.h"
|
#include "display/scene/scenemanager.h"
|
||||||
#include "display/mesh/quad.h"
|
#include "display/mesh/quad.h"
|
||||||
|
#include "asset/assetmanager.h"
|
||||||
|
|
||||||
camera_t SCENE_OVERWORLD_CAMERA;
|
camera_t SCENE_OVERWORLD_CAMERA;
|
||||||
|
asset_t *testAsset;
|
||||||
|
|
||||||
void sceneOverworldInit(void) {
|
void sceneOverworldInit(void) {
|
||||||
cameraInit(&SCENE_OVERWORLD_CAMERA);
|
cameraInit(&SCENE_OVERWORLD_CAMERA);
|
||||||
@@ -20,6 +22,10 @@ void sceneOverworldInit(void) {
|
|||||||
|
|
||||||
scene_t *scene = &SCENE_MANAGER_SCENES[SCENE_TYPE_OVERWORLD];
|
scene_t *scene = &SCENE_MANAGER_SCENES[SCENE_TYPE_OVERWORLD];
|
||||||
scene->flags |= SCENE_FLAG_ACTIVE | SCENE_FLAG_VISIBLE;
|
scene->flags |= SCENE_FLAG_ACTIVE | SCENE_FLAG_VISIBLE;
|
||||||
|
|
||||||
|
assetManagerGetAsset("entities.dpi", &testAsset);
|
||||||
|
ref_t lock = assetLock(testAsset);
|
||||||
|
assetLoad(testAsset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sceneOverworldUpdate(void) {
|
void sceneOverworldUpdate(void) {
|
||||||
@@ -35,7 +41,7 @@ void sceneOverworldRender(void) {
|
|||||||
// Draw overlay layer.
|
// Draw overlay layer.
|
||||||
|
|
||||||
spriteBatchPush(
|
spriteBatchPush(
|
||||||
NULL,
|
&testAsset->paletteImage.texture,
|
||||||
0.0f, 0.0f, 12.0f, 12.0f,
|
0.0f, 0.0f, 12.0f, 12.0f,
|
||||||
0xFF, 0x00, 0x00, 0xFF,
|
0xFF, 0x00, 0x00, 0xFF,
|
||||||
0.0f, 0.0f, 1.0f, 1.0f
|
0.0f, 0.0f, 1.0f, 1.0f
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "util/math.h"
|
#include "util/math.h"
|
||||||
|
#include "display/palette/palettelist.h"
|
||||||
|
|
||||||
const texture_t *TEXTURE_BOUND = NULL;
|
const texture_t *TEXTURE_BOUND = NULL;
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ void textureInit(
|
|||||||
const int32_t width,
|
const int32_t width,
|
||||||
const int32_t height,
|
const int32_t height,
|
||||||
const textureformat_t format,
|
const textureformat_t format,
|
||||||
const void *data
|
const texturedata_t data
|
||||||
) {
|
) {
|
||||||
assertNotNull(texture, "Texture cannot be NULL");
|
assertNotNull(texture, "Texture cannot be NULL");
|
||||||
assertTrue(width > 0 && height > 0, "width/height must be greater than 0");
|
assertTrue(width > 0 && height > 0, "width/height must be greater than 0");
|
||||||
@@ -40,15 +41,96 @@ void textureInit(
|
|||||||
#if DISPLAY_SDL2
|
#if DISPLAY_SDL2
|
||||||
glGenTextures(1, &texture->id);
|
glGenTextures(1, &texture->id);
|
||||||
glBindTexture(GL_TEXTURE_2D, texture->id);
|
glBindTexture(GL_TEXTURE_2D, texture->id);
|
||||||
glTexImage2D(
|
|
||||||
GL_TEXTURE_2D, 0, format, width, height, 0,
|
switch(format) {
|
||||||
format, GL_UNSIGNED_BYTE, data
|
case TEXTURE_FORMAT_RGBA:
|
||||||
);
|
assertNotNull(data.rgba.colors, "RGBA texture data cannot be NULL");
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D, 0, format, width, height, 0,
|
||||||
|
format, GL_UNSIGNED_BYTE, (void*)data.rgba.colors
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TEXTURE_FORMAT_ALPHA:
|
||||||
|
assertNotNull(data.alpha.data, "Alpha texture data cannot be NULL");
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D, 0, format, width, height, 0,
|
||||||
|
format, GL_UNSIGNED_BYTE, (void*)data.alpha.data
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TEXTURE_FORMAT_PALETTE:
|
||||||
|
assertNotNull(data.palette.data, "Palette texture data cannot be NULL");
|
||||||
|
assertTrue(
|
||||||
|
data.palette.palette < PALETTE_LIST_COUNT,
|
||||||
|
"Palette index out of range"
|
||||||
|
);
|
||||||
|
|
||||||
|
const palette_t *pal = PALETTE_LIST[data.palette.palette];
|
||||||
|
assertNotNull(pal, "Palette cannot be NULL");
|
||||||
|
GLenum err = glGetError();
|
||||||
|
if (err != GL_NO_ERROR) {
|
||||||
|
assertUnreachable("GL Error before setting color table");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we support paletted textures?
|
||||||
|
bool_t havePalTex = false;
|
||||||
|
GLint mask = 0;
|
||||||
|
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
|
||||||
|
if(mask & GL_CONTEXT_CORE_PROFILE_BIT) {
|
||||||
|
GLint n=0; glGetIntegerv(GL_NUM_EXTENSIONS, &n);
|
||||||
|
for (GLint i=0; i<n; ++i) {
|
||||||
|
const char* e = (const char*)glGetStringi(GL_EXTENSIONS, i);
|
||||||
|
if (e && strcmp(e, "GL_EXT_paletted_texture")==0) { havePalTex = true; break; }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const char* ext = (const char*)glGetString(GL_EXTENSIONS);
|
||||||
|
havePalTex = ext && strstr(ext, "GL_EXT_paletted_texture");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!havePalTex) {
|
||||||
|
// Not supported, convert to RGBA using lookup
|
||||||
|
color_t formatted[width * height];
|
||||||
|
for(int32_t i = 0; i < width * height; i++) {
|
||||||
|
uint8_t index = data.palette.data[i];
|
||||||
|
assertTrue(
|
||||||
|
index < pal->colorCount,
|
||||||
|
"Palette index out of range"
|
||||||
|
);
|
||||||
|
formatted[i] = pal->colors[index];
|
||||||
|
}
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
||||||
|
GL_RGBA, GL_UNSIGNED_BYTE, (void*)formatted
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Supported.
|
||||||
|
glColorTableEXT(
|
||||||
|
GL_TEXTURE_2D, GL_RGBA, pal->colorCount, GL_RGBA,
|
||||||
|
GL_UNSIGNED_BYTE, (const void*)pal->colors
|
||||||
|
);
|
||||||
|
glTexImage2D(
|
||||||
|
GL_TEXTURE_2D,
|
||||||
|
0, GL_COLOR_INDEX8_EXT,
|
||||||
|
width, height,
|
||||||
|
0, GL_COLOR_INDEX8_EXT,
|
||||||
|
GL_UNSIGNED_BYTE, (void*)data.palette.data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assertUnreachable("Unknown texture format");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
#endif
|
#endif
|
||||||
|
@@ -13,6 +13,7 @@ typedef enum {
|
|||||||
#if DISPLAY_SDL2
|
#if DISPLAY_SDL2
|
||||||
TEXTURE_FORMAT_RGBA = GL_RGBA,
|
TEXTURE_FORMAT_RGBA = GL_RGBA,
|
||||||
TEXTURE_FORMAT_ALPHA = GL_ALPHA,
|
TEXTURE_FORMAT_ALPHA = GL_ALPHA,
|
||||||
|
TEXTURE_FORMAT_PALETTE = GL_COLOR_INDEX8_EXT,
|
||||||
#endif
|
#endif
|
||||||
} textureformat_t;
|
} textureformat_t;
|
||||||
|
|
||||||
@@ -25,6 +26,21 @@ typedef struct {
|
|||||||
int32_t height;
|
int32_t height;
|
||||||
} texture_t;
|
} texture_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
struct {
|
||||||
|
color_t *colors;
|
||||||
|
} rgba;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t palette;
|
||||||
|
uint8_t *data;
|
||||||
|
} palette;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t *data;
|
||||||
|
} alpha;
|
||||||
|
} texturedata_t;
|
||||||
|
|
||||||
extern const texture_t *TEXTURE_BOUND;
|
extern const texture_t *TEXTURE_BOUND;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,14 +50,14 @@ extern const texture_t *TEXTURE_BOUND;
|
|||||||
* @param width The width of the texture.
|
* @param width The width of the texture.
|
||||||
* @param height The height of the texture.
|
* @param height The height of the texture.
|
||||||
* @param format The format of the texture (e.g., GL_RGBA, GL_ALPHA).
|
* @param format The format of the texture (e.g., GL_RGBA, GL_ALPHA).
|
||||||
* @param data The pixel data for the texture.
|
* @param data The data for the texture, the format changes per format.
|
||||||
*/
|
*/
|
||||||
void textureInit(
|
void textureInit(
|
||||||
texture_t *texture,
|
texture_t *texture,
|
||||||
const int32_t width,
|
const int32_t width,
|
||||||
const int32_t height,
|
const int32_t height,
|
||||||
const textureformat_t format,
|
const textureformat_t format,
|
||||||
const void *data
|
const texturedata_t data
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
engine_t ENGINE;
|
engine_t ENGINE;
|
||||||
|
|
||||||
asset_t *testAsset;
|
|
||||||
|
|
||||||
errorret_t engineInit(void) {
|
errorret_t engineInit(void) {
|
||||||
memoryZero(&ENGINE, sizeof(engine_t));
|
memoryZero(&ENGINE, sizeof(engine_t));
|
||||||
@@ -28,8 +27,6 @@ errorret_t engineInit(void) {
|
|||||||
errorChain(displayInit());
|
errorChain(displayInit());
|
||||||
rpgInit();
|
rpgInit();
|
||||||
|
|
||||||
errorChain(assetManagerGetAsset("entities.dpi", &testAsset));
|
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -30,7 +30,7 @@ ref_t refListLock(reflist_t *list) {
|
|||||||
assertFalse(refListIsFull(list), "Reference list is full");
|
assertFalse(refListIsFull(list), "Reference list is full");
|
||||||
|
|
||||||
ref_t ref = list->refNext++;
|
ref_t ref = list->refNext++;
|
||||||
assertTrue(ref > 0, "Reference ID overflow");
|
assertTrue(ref >= 0, "Reference ID overflow");
|
||||||
assertTrue(ref < UINT16_MAX, "Reference ID too large.");
|
assertTrue(ref < UINT16_MAX, "Reference ID too large.");
|
||||||
|
|
||||||
bool_t empty = list->onNotEmpty && refListIsEmpty(list);
|
bool_t empty = list->onNotEmpty && refListIsEmpty(list);
|
||||||
|
Reference in New Issue
Block a user