diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 34e0bea..11fb20d 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -9,7 +9,6 @@ on: - main jobs: - run-tests: runs-on: ubuntu-latest steps: diff --git a/CMakeLists.txt b/CMakeLists.txt index f274faf..aa9d414 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,11 @@ target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PUBLIC # Add main code add_subdirectory(${DUSK_SOURCES_DIR}) +# Include generated headers +target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PUBLIC + ${DUSK_GENERATED_HEADERS_DIR} +) + # Handle tests if(ENABLE_TESTS) enable_testing() @@ -102,4 +107,4 @@ add_custom_command( VERBATIM ) add_custom_target(DUSK_ASSETS_BUILT DEPENDS "${DUSK_ASSETS_ZIP}") -add_dependencies(${DUSK_LIBRARY_TARGET_NAME} DUSK_ASSETS_BUILT) \ No newline at end of file +add_dependencies(${DUSK_LIBRARY_TARGET_NAME} DUSK_ASSETS_BUILT) diff --git a/assets/scene/minesweeper.lua b/assets/scene/minesweeper.lua index 9c85b4d..70094cd 100644 --- a/assets/scene/minesweeper.lua +++ b/assets/scene/minesweeper.lua @@ -187,19 +187,20 @@ function sceneRender() if INPUT_POINTER then mouseX = inputGetValue(INPUT_ACTION_POINTERX) * screenGetWidth() mouseY = inputGetValue(INPUT_ACTION_POINTERY) * screenGetHeight() + + -- Draw cursor + spriteBatchPush( + nil, + mouseX - 2, mouseY - 2, + mouseX + 2, mouseY + 2, + colorRed(), + 0, 0, + 1, 1 + ) end - -- Draw cursor - spriteBatchPush( - nil, - mouseX - 2, mouseY - 2, - mouseX + 2, mouseY + 2, - colorRed(), - 0, 0, - 1, 1 - ) - textDraw(10, 10, "Minesweeper") + textDraw(10, 10, "Hello World") -- centerX = math.floor(screenGetWidth() / 2) -- centerY = math.floor(screenGetHeight() / 2) diff --git a/assets/ui/minogram.dpt b/assets/ui/minogram.dpt index 9fb8c56..688283d 100644 Binary files a/assets/ui/minogram.dpt and b/assets/ui/minogram.dpt differ diff --git a/assets/ui/minogram.dtf b/assets/ui/minogram.dtf new file mode 100644 index 0000000..41511ea Binary files /dev/null and b/assets/ui/minogram.dtf differ diff --git a/cmake/configure/dolphin.cmake b/cmake/configure/dolphin.cmake new file mode 100644 index 0000000..866ca7f --- /dev/null +++ b/cmake/configure/dolphin.cmake @@ -0,0 +1,63 @@ +message(FATAL_ERROR "Configure Dolphin") + +if(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii") + # Override to make library and binary be the same. + set(DUSK_LIBRARY_TARGET_NAME "${DUSK_LIBRARY_TARGET_NAME}.elf" CACHE INTERNAL ${DUSK_CACHE_TARGET}) +endif() + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions") +# configure_file(opengl.pc.in opengl.pc @ONLY) +find_package(PkgConfig REQUIRED) +pkg_check_modules(zip IMPORTED_TARGET libzip) +target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC + DOLPHIN +) + +# Disable all warnings +target_compile_options(${DUSK_LIBRARY_TARGET_NAME} PRIVATE -w) + +# Custom flags for cglm +set(CGLM_SHARED OFF CACHE BOOL "Build cglm shared" FORCE) +set(CGLM_STATIC ON CACHE BOOL "Build cglm static" FORCE) +find_package(cglm REQUIRED) + +# Compile lua +include(FetchContent) +FetchContent_Declare( + liblua + URL https://www.lua.org/ftp/lua-5.5.0.tar.gz +) +FetchContent_MakeAvailable(liblua) +set(LUA_SRC_DIR "${liblua_SOURCE_DIR}/src") +set(LUA_C_FILES + lapi.c lauxlib.c lbaselib.c lcode.c lcorolib.c lctype.c ldblib.c ldebug.c + ldo.c ldump.c lfunc.c lgc.c linit.c liolib.c llex.c lmathlib.c lmem.c + loadlib.c lobject.c lopcodes.c loslib.c lparser.c lstate.c lstring.c + lstrlib.c ltable.c ltablib.c ltm.c lundump.c lutf8lib.c lvm.c lzio.c +) +list(TRANSFORM LUA_C_FILES PREPEND "${LUA_SRC_DIR}/") +add_library(liblua STATIC ${LUA_C_FILES}) +target_include_directories(liblua PUBLIC "${LUA_SRC_DIR}") +target_compile_definitions(liblua PRIVATE LUA_USE_C89) +add_library(lua::lua ALIAS liblua) +set(Lua_FOUND TRUE CACHE BOOL "Lua found" FORCE) + +target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE + cglm + liblua + m + fat + PkgConfig::zip +) + +target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} + PUBLIC + DISPLAY_WINDOW_WIDTH_DEFAULT=640 + DISPLAY_WINDOW_HEIGHT_DEFAULT=480 + DISPLAY_WIDTH=640 + DISPLAY_HEIGHT=480 + DISPLAY_SIZE_DYNAMIC=0 + INPUT_GAMEPAD=1 + THREAD_PTHREAD=1 + TIME_FIXED=1 +) \ No newline at end of file diff --git a/cmake/configure/gamecube.cmake b/cmake/configure/gamecube.cmake new file mode 100644 index 0000000..7faef9a --- /dev/null +++ b/cmake/configure/gamecube.cmake @@ -0,0 +1 @@ +include(cmake/configure/gamecube.cmake) \ No newline at end of file diff --git a/cmake/configure/linux.cmake b/cmake/configure/linux.cmake new file mode 100644 index 0000000..d372dfc --- /dev/null +++ b/cmake/configure/linux.cmake @@ -0,0 +1,26 @@ +find_package(SDL2 REQUIRED) +find_package(OpenGL REQUIRED) + +target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC + SDL2 + pthread + OpenGL::GL + GL + m +) + +target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} + PUBLIC + DISPLAY_SDL2=1 + DISPLAY_WINDOW_WIDTH_DEFAULT=1080 + DISPLAY_WINDOW_HEIGHT_DEFAULT=810 + DISPLAY_SCREEN_HEIGHT_DEFAULT=270 + DISPLAY_SHADER=1 + INPUT_SDL2=1 + INPUT_KEYBOARD=1 + INPUT_POINTER=1 + INPUT_GAMEPAD=1 + THREAD_PTHREAD=1 + TIME_SDL2=1 + TIME_FIXED=0 +) \ No newline at end of file diff --git a/cmake/configure/psp.cmake b/cmake/configure/psp.cmake new file mode 100644 index 0000000..39ed682 --- /dev/null +++ b/cmake/configure/psp.cmake @@ -0,0 +1,36 @@ +find_package(pspsdk REQUIRED) +find_package(SDL2 REQUIRED) +find_package(OpenGL REQUIRED) + +target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC + ${SDL2_LIBRARIES} + SDL2 + pthread + OpenGL::GL + zip + bz2 + z + mbedtls + mbedcrypto + lzma + m +) + +target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE + ${SDL2_INCLUDE_DIRS} +) + +target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} + PUBLIC + DISPLAY_SDL2=1 + DISPLAY_WINDOW_WIDTH_DEFAULT=480 + DISPLAY_WINDOW_HEIGHT_DEFAULT=272 + DISPLAY_WIDTH=480 + DISPLAY_HEIGHT=272 + DISPLAY_SIZE_DYNAMIC=0 + DISPLAY_COLOR_TABLE=1 + INPUT_SDL2=1 + INPUT_GAMEPAD=1 + THREAD_PTHREAD=1 + TIME_FIXED=1 +) \ No newline at end of file diff --git a/cmake/configure/wii.cmake b/cmake/configure/wii.cmake new file mode 100644 index 0000000..c1450af --- /dev/null +++ b/cmake/configure/wii.cmake @@ -0,0 +1 @@ +include(cmake/configure/dolphin.cmake) \ No newline at end of file diff --git a/src/asset/type/assetmapchunk.c b/src/asset/type/assetmapchunk.c index 64eb4fc..e907ef0 100644 --- a/src/asset/type/assetmapchunk.c +++ b/src/asset/type/assetmapchunk.c @@ -8,6 +8,7 @@ #include "asset/asset.h" #include "assert/assert.h" #include "map/mapchunk.h" +#include "util/endian.h" #pragma pack(push, 1) typedef struct { @@ -56,7 +57,7 @@ errorret_t assetMapChunkHandler(assetcustom_t custom) { } // Fix endianess if necessary - header.tileCount = le32toh(header.tileCount); + header.tileCount = endianLittleToHost32(header.tileCount); if(header.tileCount != CHUNK_TILE_COUNT) { zip_fclose(custom.zipFile); @@ -111,7 +112,7 @@ errorret_t assetMapChunkHandler(assetcustom_t custom) { } // Fix endianess if necessary - modelHeader.vertexCount = le32toh(modelHeader.vertexCount); + modelHeader.vertexCount = endianLittleToHost32(modelHeader.vertexCount); if( vertexIndex + modelHeader.vertexCount > diff --git a/src/asset/type/assetpalette.h b/src/asset/type/assetpalette.h index 82ed2e0..cc328f2 100644 --- a/src/asset/type/assetpalette.h +++ b/src/asset/type/assetpalette.h @@ -7,7 +7,7 @@ #pragma once #include "error/error.h" -#include "display/palette/palette.h" +#include "display/texture/palette.h" typedef struct assetentire_s assetentire_t; diff --git a/src/asset/type/assettexture.c b/src/asset/type/assettexture.c index c2775b5..bcdca88 100644 --- a/src/asset/type/assettexture.c +++ b/src/asset/type/assettexture.c @@ -8,7 +8,8 @@ #include "assettexture.h" #include "asset/assettype.h" #include "assert/assert.h" -#include "display/texture.h" +#include "display/texture/texture.h" +#include "util/endian.h" errorret_t assetTextureLoad(assetentire_t entire) { assertNotNull(entire.data, "Data pointer cannot be NULL."); @@ -32,8 +33,8 @@ errorret_t assetTextureLoad(assetentire_t entire) { } // Fix endian - assetData->width = le32toh(assetData->width); - assetData->height = le32toh(assetData->height); + assetData->width = endianLittleToHost32(assetData->width); + assetData->height = endianLittleToHost32(assetData->height); // Check dimensions. if( diff --git a/src/asset/type/assettexture.h b/src/asset/type/assettexture.h index 258101a..6ff4cff 100644 --- a/src/asset/type/assettexture.h +++ b/src/asset/type/assettexture.h @@ -8,8 +8,8 @@ #pragma once #include "error/error.h" -#define ASSET_TEXTURE_WIDTH_MAX 256 -#define ASSET_TEXTURE_HEIGHT_MAX 256 +#define ASSET_TEXTURE_WIDTH_MAX 2048 +#define ASSET_TEXTURE_HEIGHT_MAX 2048 #define ASSET_TEXTURE_SIZE_MAX ( \ ASSET_TEXTURE_WIDTH_MAX * ASSET_TEXTURE_HEIGHT_MAX \ ) @@ -20,10 +20,8 @@ typedef struct assetentire_s assetentire_t; typedef struct { char_t header[3]; uint8_t version; - uint32_t width; uint32_t height; - uint8_t paletteIndex; uint8_t palette[ASSET_TEXTURE_SIZE_MAX]; } assettexture_t; #pragma pack(pop) diff --git a/src/asset/type/assettileset.c b/src/asset/type/assettileset.c index 04469cb..ea485e0 100644 --- a/src/asset/type/assettileset.c +++ b/src/asset/type/assettileset.c @@ -7,7 +7,9 @@ #include "asset/asset.h" #include "assert/assert.h" -#include "display/tileset/tileset.h" +#include "display/texture/tileset.h" +#include "util/memory.h" +#include "util/endian.h" errorret_t assetTilesetLoad(assetentire_t entire) { assertNotNull(entire.data, "Asset data cannot be null"); @@ -28,5 +30,41 @@ errorret_t assetTilesetLoad(assetentire_t entire) { errorThrow("Unsupported tileset version"); } - errorThrow("unfinished"); + // Fix endianness + tilesetData->tileWidth = endianLittleToHost16(tilesetData->tileWidth); + tilesetData->tileHeight = endianLittleToHost16(tilesetData->tileHeight); + tilesetData->columnCount = endianLittleToHost16(tilesetData->columnCount); + tilesetData->rowCount = endianLittleToHost16(tilesetData->rowCount); + tilesetData->right = endianLittleToHost16(tilesetData->right); + tilesetData->bottom = endianLittleToHost16(tilesetData->bottom); + + if(tilesetData->tileWidth == 0) { + errorThrow("Tile width cannot be 0"); + } + if(tilesetData->tileHeight == 0) { + errorThrow("Tile height cannot be 0"); + } + if(tilesetData->columnCount == 0) { + errorThrow("Column count cannot be 0"); + } + if(tilesetData->rowCount == 0) { + errorThrow("Row count cannot be 0"); + } + + tilesetData->u0 = endianLittleToHostFloat(tilesetData->u0); + tilesetData->v0 = endianLittleToHostFloat(tilesetData->v0); + + if(tilesetData->v0 < 0.0f || tilesetData->v0 > 1.0f) { + errorThrow("Invalid v0 value in tileset"); + } + + // Setup tileset + tileset->tileWidth = tilesetData->tileWidth; + tileset->tileHeight = tilesetData->tileHeight; + tileset->tileCount = tilesetData->columnCount * tilesetData->rowCount; + tileset->columns = tilesetData->columnCount; + tileset->rows = tilesetData->rowCount; + tileset->uv[0] = tilesetData->u0; + tileset->uv[1] = tilesetData->v0; + errorOk(); } \ No newline at end of file diff --git a/src/asset/type/assettileset.h b/src/asset/type/assettileset.h index 0bee407..a659fea 100644 --- a/src/asset/type/assettileset.h +++ b/src/asset/type/assettileset.h @@ -12,6 +12,14 @@ typedef struct { char_t header[3]; uint8_t version; + uint16_t tileWidth; + uint16_t tileHeight; + uint16_t columnCount; + uint16_t rowCount; + uint16_t right; + uint16_t bottom; + float_t u0; + float_t v0; } assettileset_t; #pragma pack(pop) diff --git a/src/debug/CMakeLists.txt b/src/debug/CMakeLists.txt index f8e8529..a01ae13 100644 --- a/src/debug/CMakeLists.txt +++ b/src/debug/CMakeLists.txt @@ -7,6 +7,4 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC debug.c -) - -# Subdirs \ No newline at end of file +) \ No newline at end of file diff --git a/src/display/CMakeLists.txt b/src/display/CMakeLists.txt index 71d8fc9..08af9fc 100644 --- a/src/display/CMakeLists.txt +++ b/src/display/CMakeLists.txt @@ -9,7 +9,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} display.c framebuffer.c screen.c - texture.c spritebatch.c text.c ) @@ -17,38 +16,9 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} # Subdirectories add_subdirectory(camera) add_subdirectory(mesh) -add_subdirectory(palette) -add_subdirectory(tileset) - -if(DUSK_TARGET_SYSTEM STREQUAL "linux") - target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - DISPLAY_SDL2=1 - DISPLAY_WINDOW_WIDTH_DEFAULT=1080 - DISPLAY_WINDOW_HEIGHT_DEFAULT=810 - DISPLAY_SCREEN_HEIGHT_DEFAULT=270 - ) -elseif(DUSK_TARGET_SYSTEM STREQUAL "psp") - target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - DISPLAY_SDL2=1 - DISPLAY_WINDOW_WIDTH_DEFAULT=480 - DISPLAY_WINDOW_HEIGHT_DEFAULT=272 - DISPLAY_WIDTH=480 - DISPLAY_HEIGHT=272 - DISPLAY_SIZE_DYNAMIC=0 - ) -elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii") - target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - DISPLAY_WINDOW_WIDTH_DEFAULT=640 - DISPLAY_WINDOW_HEIGHT_DEFAULT=480 - DISPLAY_WIDTH=640 - DISPLAY_HEIGHT=480 - DISPLAY_SIZE_DYNAMIC=0 - ) -endif() +add_subdirectory(texture) +# Color definitions dusk_run_python( dusk_color_defs tools.display.color.csv diff --git a/src/display/display.c b/src/display/display.c index 0520af2..7844114 100644 --- a/src/display/display.c +++ b/src/display/display.c @@ -88,6 +88,7 @@ errorret_t displayInit(void) { #else GLint mask = 0; glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); + DISPLAY.usingShaderedPalettes = true; if(mask & GL_CONTEXT_CORE_PROFILE_BIT) { GLint numExtens = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &numExtens); @@ -100,7 +101,7 @@ errorret_t displayInit(void) { } } else { const char* ext = (const char*)glGetString(GL_EXTENSIONS); - DISPLAY.usingShaderedPalettes = ( + DISPLAY.usingShaderedPalettes = !( ext && strstr(ext, "GL_EXT_paletted_texture") ); } diff --git a/src/display/framebuffer.h b/src/display/framebuffer.h index aa63488..3c7fd44 100644 --- a/src/display/framebuffer.h +++ b/src/display/framebuffer.h @@ -6,7 +6,7 @@ */ #pragma once -#include "display/texture.h" +#include "display/texture/texture.h" #define FRAMEBUFFER_CLEAR_COLOR (1 << 0) #define FRAMEBUFFER_CLEAR_DEPTH (1 << 1) diff --git a/src/display/spritebatch.h b/src/display/spritebatch.h index 9e236b3..4704de2 100644 --- a/src/display/spritebatch.h +++ b/src/display/spritebatch.h @@ -7,7 +7,7 @@ #pragma once #include "display/mesh/quad.h" -#include "display/texture.h" +#include "display/texture/texture.h" #define SPRITEBATCH_SPRITES_MAX 128 #define SPRITEBATCH_VERTEX_COUNT (SPRITEBATCH_SPRITES_MAX * QUAD_VERTEX_COUNT) diff --git a/src/display/text.c b/src/display/text.c index 8453e2e..926aee3 100644 --- a/src/display/text.c +++ b/src/display/text.c @@ -21,7 +21,7 @@ errorret_t textInit(void) { } void textDispose(void) { - // textureDispose(&DEFAULT_FONT_TEXTURE); + textureDispose(&DEFAULT_FONT_TEXTURE); } void textDrawChar( @@ -36,7 +36,6 @@ void textDrawChar( if(tileIndex < 0 || tileIndex >= tileset->tileCount) { tileIndex = ((int32_t)'@') - TEXT_CHAR_START; } - assertTrue( tileIndex >= 0 && tileIndex <= tileset->tileCount, "Character is out of bounds for font tiles" diff --git a/src/display/text.h b/src/display/text.h index 963dfb1..8b46536 100644 --- a/src/display/text.h +++ b/src/display/text.h @@ -7,8 +7,8 @@ #pragma once #include "asset/asset.h" -#include "display/texture.h" -#include "display/tileset/tileset.h" +#include "display/texture/texture.h" +#include "display/texture/tileset.h" #define TEXT_CHAR_START '!' diff --git a/src/display/palette/CMakeLists.txt b/src/display/texture/CMakeLists.txt similarity index 88% rename from src/display/palette/CMakeLists.txt rename to src/display/texture/CMakeLists.txt index be5f8fb..23ab16b 100644 --- a/src/display/palette/CMakeLists.txt +++ b/src/display/texture/CMakeLists.txt @@ -6,5 +6,7 @@ # Sources target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC + tileset.c + texture.c palette.c ) \ No newline at end of file diff --git a/src/display/palette/palette.c b/src/display/texture/palette.c similarity index 100% rename from src/display/palette/palette.c rename to src/display/texture/palette.c diff --git a/src/display/palette/palette.h b/src/display/texture/palette.h similarity index 84% rename from src/display/palette/palette.h rename to src/display/texture/palette.h index 3b085b8..63e3009 100644 --- a/src/display/palette/palette.h +++ b/src/display/texture/palette.h @@ -8,6 +8,18 @@ #pragma once #include "display/color.h" +#if DISPLAY_SDL2 + #if DISPLAY_SHADER == 1 + + #elif DISPLAY_COLOR_TABLE == 1 + + #else + #error "Unsupported palette mode" + #endif +#else + #error "Unsupported palette mode" +#endif + #define PALETTE_COUNT_MAX 4 #define PALETTE_COLOR_COUNT_MAX 0xFF diff --git a/src/display/texture/palettetexture.c b/src/display/texture/palettetexture.c new file mode 100644 index 0000000..d51bcfa --- /dev/null +++ b/src/display/texture/palettetexture.c @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "palettetexture.h" +#include "assert/assert.h" + +void paletteTextureInit( + palettetexture_t *texture, + const int32_t width, + const int32_t height, + const uint8_t *data +) { + assertNotNull(texture, "Palette texture cannot be NULL"); + assertTrue(width > 0 && height > 0, "width/height must be greater than 0"); + assertNotNull(data, "Palette texture data cannot be NULL"); + + #if DISPLAY_SDL2 + #if DISPLAY_SHADER == 1 + // Palette textures not supported, convert to GL_RED style texture + // so shader can perform the lookup. + uint8_t formatted[width * height]; + for(int32_t i = 0; i < width * height; i++) { + uint8_t index = data.paletteData[i]; + formatted[i] = index * 128; + } + glTexImage2D( + GL_TEXTURE_2D, 0, GL_R8, width, height, 0, + GL_RED, GL_UNSIGNED_BYTE, (void*)formatted + ); + + #else + glTexImage2D( + GL_TEXTURE_2D, + 0, GL_COLOR_INDEX8_EXT, + width, height, + 0, GL_COLOR_INDEX8_EXT, + GL_UNSIGNED_BYTE, (void*)data.paletteData + ); + // glColorTableEXT( + // GL_TEXTURE_2D, GL_RGBA, data.palette.palette->colorCount, GL_RGBA, + // GL_UNSIGNED_BYTE, (const void*)data.palette.palette->colors + // ); + #endif + #else + #error "Palette textures not supported on this platform" + #endif +} \ No newline at end of file diff --git a/src/display/texture/palettetexture.h b/src/display/texture/palettetexture.h new file mode 100644 index 0000000..7c4fc3e --- /dev/null +++ b/src/display/texture/palettetexture.h @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +typedef struct { + +} palettetexture_t; + +/** + * Initializes a palette texture. + * + * @param texture The palette texture to initialize. + * @param width The width of the texture. Must be a power of 2. + * @param height The height of the texture. Must be a power of 2. + * @param data The palette index data for the texture. + */ +void paletteTextureInit( + palettetexture_t *texture, + const int32_t width, + const int32_t height, + const uint8_t *data +); \ No newline at end of file diff --git a/src/display/texture.c b/src/display/texture/texture.c similarity index 96% rename from src/display/texture.c rename to src/display/texture/texture.c index d2ac69e..3bcc750 100644 --- a/src/display/texture.c +++ b/src/display/texture/texture.c @@ -52,12 +52,13 @@ void textureInit( uint8_t formatted[width * height]; for(int32_t i = 0; i < width * height; i++) { uint8_t index = data.paletteData[i]; - formatted[i] = index; + formatted[i] = index * 128; } glTexImage2D( - GL_TEXTURE_2D, 0, GL_R, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, (void*)formatted + GL_TEXTURE_2D, 0, GL_R8, width, height, 0, + GL_RED, GL_UNSIGNED_BYTE, (void*)formatted ); + } else { glTexImage2D( GL_TEXTURE_2D, @@ -66,12 +67,17 @@ void textureInit( 0, GL_COLOR_INDEX8_EXT, GL_UNSIGNED_BYTE, (void*)data.paletteData ); - // glColorTableEXT( // GL_TEXTURE_2D, GL_RGBA, data.palette.palette->colorCount, GL_RGBA, // GL_UNSIGNED_BYTE, (const void*)data.palette.palette->colors // ); } + + GLenum err = glGetError(); + if(err != GL_NO_ERROR) { + printf("GL Error uploading palette texture: %d\n", err); + assertUnreachable("GL error uploading palette texture"); + } break; default: diff --git a/src/display/texture.h b/src/display/texture/texture.h similarity index 97% rename from src/display/texture.h rename to src/display/texture/texture.h index c3e0ead..b10b676 100644 --- a/src/display/texture.h +++ b/src/display/texture/texture.h @@ -8,7 +8,7 @@ #pragma once #include "display/color.h" #include "display/displaydefs.h" -#include "display/palette/palette.h" +#include "display/texture/palette.h" typedef enum { #if DISPLAY_SDL2 diff --git a/src/display/tileset/tileset.c b/src/display/texture/tileset.c similarity index 100% rename from src/display/tileset/tileset.c rename to src/display/texture/tileset.c diff --git a/src/display/tileset/tileset.h b/src/display/texture/tileset.h similarity index 83% rename from src/display/tileset/tileset.h rename to src/display/texture/tileset.h index 01e3405..df53516 100644 --- a/src/display/tileset/tileset.h +++ b/src/display/texture/tileset.h @@ -9,14 +9,12 @@ #include "dusk.h" typedef struct tileset_s { - const char_t *name; - const uint16_t tileWidth; - const uint16_t tileHeight; - const uint16_t tileCount; - const uint16_t columns; - const uint16_t rows; - const vec2 uv; - const char_t *image; + uint16_t tileWidth; + uint16_t tileHeight; + uint16_t tileCount; + uint16_t columns; + uint16_t rows; + vec2 uv; } tileset_t; /** diff --git a/src/display/tileset/CMakeLists.txt b/src/display/tileset/CMakeLists.txt deleted file mode 100644 index 5d521d0..0000000 --- a/src/display/tileset/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - tileset.c -) \ No newline at end of file diff --git a/src/dusk.h b/src/dusk.h index 601521a..0352c83 100644 --- a/src/dusk.h +++ b/src/dusk.h @@ -33,11 +33,6 @@ #include #include #include - #include -#else - #ifndef le32toh - #define le32toh(x) (x) - #endif #endif typedef bool bool_t; diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index 00d8905..fec6279 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -11,30 +11,7 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} inputaction.c ) -if(DUSK_TARGET_SYSTEM STREQUAL "linux") - target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - INPUT_SDL2=1 - INPUT_KEYBOARD=1 - INPUT_POINTER=1 - INPUT_GAMEPAD=1 - ) - -elseif(DUSK_TARGET_SYSTEM STREQUAL "psp") - target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - INPUT_SDL2=1 - INPUT_GAMEPAD=1 - ) - -elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii") - target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - INPUT_GAMEPAD=1 - ) -endif() - -# CSV +# Input Action Definitions dusk_run_python( dusk_input_csv_defs tools.input.csv diff --git a/src/item/CMakeLists.txt b/src/item/CMakeLists.txt index 1a30a79..4f5606e 100644 --- a/src/item/CMakeLists.txt +++ b/src/item/CMakeLists.txt @@ -10,6 +10,7 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} backpack.c ) +# Item Definitions dusk_run_python( dusk_item_csv_defs tools.item.csv diff --git a/src/script/module/display/moduletexture.c b/src/script/module/display/moduletexture.c index 4c3621b..1c1732b 100644 --- a/src/script/module/display/moduletexture.c +++ b/src/script/module/display/moduletexture.c @@ -7,7 +7,7 @@ #include "moduletexture.h" #include "asset/asset.h" -#include "display/texture.h" +#include "display/texture/texture.h" #include "assert/assert.h" #include "util/memory.h" #include "util/string.h" diff --git a/src/script/module/display/moduletileset.c b/src/script/module/display/moduletileset.c index 55f8c60..368411e 100644 --- a/src/script/module/display/moduletileset.c +++ b/src/script/module/display/moduletileset.c @@ -7,7 +7,7 @@ #include "moduletileset.h" #include "assert/assert.h" -#include "display/tileset/tileset.h" +#include "display/texture/tileset.h" #include "util/memory.h" #include "util/string.h" #include "debug/debug.h" @@ -41,13 +41,7 @@ int moduleTilesetIndex(lua_State *l) { tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt"); assertNotNull(ts, "Tileset pointer cannot be NULL."); - if(stringCompare(key, "name") == 0) { - lua_pushstring(l, ts->name); - return 1; - } else if(stringCompare(key, "texture") == 0) { - lua_pushstring(l, ts->image); - return 1; - } else if(stringCompare(key, "tileWidth") == 0) { + if(stringCompare(key, "tileWidth") == 0) { lua_pushnumber(l, ts->tileWidth); return 1; } else if(stringCompare(key, "tileHeight") == 0) { @@ -72,7 +66,9 @@ int moduleTilesetToString(lua_State *l) { tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt"); assertNotNull(ts, "Tileset pointer cannot be NULL."); - lua_pushfstring(l, "Tileset: %s", ts->name); + lua_pushfstring(l, "Tileset: %dx%d tile, %d columns, %d rows", + ts->tileWidth, ts->tileHeight, ts->columns, ts->rows + ); return 1; } diff --git a/src/story/CMakeLists.txt b/src/story/CMakeLists.txt index b9553a2..880548a 100644 --- a/src/story/CMakeLists.txt +++ b/src/story/CMakeLists.txt @@ -9,6 +9,7 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} storyflag.c ) +# Story Flag Definitions dusk_run_python( dusk_story_defs tools.story.csv diff --git a/src/thread/CMakeLists.txt b/src/thread/CMakeLists.txt index 160cedd..17267ba 100644 --- a/src/thread/CMakeLists.txt +++ b/src/thread/CMakeLists.txt @@ -8,21 +8,4 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC thread.c threadmutex.c -) - -# Compiler flags. -if(DUSK_TARGET_SYSTEM STREQUAL "linux") - target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - THREAD_PTHREAD=1 - ) -elseif(DUSK_TARGET_SYSTEM STREQUAL "psp") - target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - THREAD_PTHREAD=1 - ) -elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii") - target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - ) -endif() \ No newline at end of file +) \ No newline at end of file diff --git a/src/time/CMakeLists.txt b/src/time/CMakeLists.txt index 69e9f48..94361ac 100644 --- a/src/time/CMakeLists.txt +++ b/src/time/CMakeLists.txt @@ -7,23 +7,4 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC time.c -) - -# Compiler defs -if(DUSK_TARGET_SYSTEM STREQUAL "linux") - target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - TIME_SDL2=1 - TIME_FIXED=0 - ) -elseif(DUSK_TARGET_SYSTEM STREQUAL "psp") - target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - TIME_FIXED=1 - ) -elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii") - target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - TIME_FIXED=1 - ) -endif() \ No newline at end of file +) \ No newline at end of file diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 095cfb7..304788c 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -7,6 +7,7 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC array.c + endian.c memory.c string.c math.c diff --git a/src/util/endian.c b/src/util/endian.c new file mode 100644 index 0000000..86a096f --- /dev/null +++ b/src/util/endian.c @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "util/endian.h" +#include "util/memory.h" + +bool_t isHostLittleEndian(void) { + uint32_t value = ENDIAN_MAGIC; + uint8_t *bytePtr = (uint8_t *)&value; + return bytePtr[0] == 0x04; +} + +uint32_t endianLittleToHost32(uint32_t value) { + if(isHostLittleEndian()) { + return value; + } + + return ( + ((value & 0x000000FF) << 24) | + ((value & 0x0000FF00) << 8) | + ((value & 0x00FF0000) >> 8) | + ((value & 0xFF000000) >> 24) + ); +} + +uint16_t endianLittleToHost16(uint16_t value) { + if(isHostLittleEndian()) { + return value; + } + return (uint16_t)(((value & 0x00FF) << 8) | + ((value & 0xFF00) >> 8)); +} + +uint64_t endianLittleToHost64(uint64_t value) { + if(isHostLittleEndian()) { + return value; + } + return ( + ((value & 0x00000000000000FFULL) << 56) | + ((value & 0x000000000000FF00ULL) << 40) | + ((value & 0x0000000000FF0000ULL) << 24) | + ((value & 0x00000000FF000000ULL) << 8) | + ((value & 0x000000FF00000000ULL) >> 8) | + ((value & 0x0000FF0000000000ULL) >> 24) | + ((value & 0x00FF000000000000ULL) >> 40) | + ((value & 0xFF00000000000000ULL) >> 56) + ); +} + +float_t endianLittleToHostFloat(float_t value) { + if(isHostLittleEndian()) { + return value; + } + + uint32_t temp; + float_t result; + memoryCopy(&temp, &value, sizeof(uint32_t)); + temp = endianLittleToHost32(temp); + memoryCopy(&result, &temp, sizeof(uint32_t)); + + return result; +} + diff --git a/src/util/endian.h b/src/util/endian.h new file mode 100644 index 0000000..14a9e79 --- /dev/null +++ b/src/util/endian.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +static const uint32_t ENDIAN_MAGIC = 0x01020304; + +/** + * Checks if the host system is little-endian. + * + * @return true if the host is little-endian, false otherwise. + */ +bool_t isHostLittleEndian(void); + +/** + * Converts a 32-bit integer from little-endian to host byte order. + * + * @param value The little-endian value to convert. + * @return The value in host byte order. + */ +uint32_t endianLittleToHost32(uint32_t value); + +/** + * Converts a 16-bit integer from little-endian to host byte order. + * @param value The little-endian value to convert. + * @return The value in host byte order. + */ +uint16_t endianLittleToHost16(uint16_t value); + +/** + * Converts a 64-bit integer from little-endian to host byte order. + * @param value The little-endian value to convert. + * @return The value in host byte order. + */ +uint64_t endianLittleToHost64(uint64_t value); + +/** + * Converts a float from little-endian to host byte order. + * + * @param value The little-endian value to convert. + * @return The value in host byte order. + */ +float_t endianLittleToHostFloat(float_t value); \ No newline at end of file diff --git a/tools/palette-indexer.html b/tools/palette-indexer.html index 4d8d901..9ae9726 100644 --- a/tools/palette-indexer.html +++ b/tools/palette-indexer.html @@ -661,7 +661,7 @@ const header = new Uint8Array([0x44, 0x50, 0x54, 0x01]); // 'DPT' + version 1 // Dimensions - const widthBytes = new Uint8Array([ imageWidth ]); + const widthBytes = new Uint32Array([ imageWidth ]); const heightBytes = new Uint32Array([ imageHeight ]); // add indexed image data (imageWidth * imageHeight bytes) diff --git a/tools/tile-joiner.html b/tools/tile-joiner.html index adb303f..b1f8a12 100644 --- a/tools/tile-joiner.html +++ b/tools/tile-joiner.html @@ -94,6 +94,9 @@ return onBadImages('Please select 2 or more image images.'); } + // Sort images by name to ensure consistent output + images = Object.fromEntries(Object.entries(images).sort(([nameA], [nameB]) => nameA.localeCompare(nameB))); + elFileError.style.display = 'none'; let strInfo = `Selected ${Object.keys(images).length} images:\n`; @@ -119,7 +122,16 @@ outputHeight = firstHeight; outputWidth = nextPowerOfTwo(Object.values(images).reduce((sum, img) => sum + img.width, 0)); } else { - onBadImages('All images must share the same width or height, and that dimension must be a power of two.'); + if(allImagesShareWidth) { + outputWidth = nextPowerOfTwo(firstWidth); + outputHeight = nextPowerOfTwo(Object.values(images).reduce((sum, img) => sum + img.height, 0)); + } else if(allImagesShareHeight) { + outputHeight = nextPowerOfTwo(firstHeight); + outputWidth = nextPowerOfTwo(Object.values(images).reduce((sum, img) => sum + img.width, 0)); + } else { + onBadImages('All images must share the same width or height to be joined together.'); + return; + } } // Update preview diff --git a/tools/tileset-creator.html b/tools/tileset-creator.html index ce8ba12..3dc5ae3 100644 --- a/tools/tileset-creator.html +++ b/tools/tileset-creator.html @@ -4,7 +4,7 @@ Dusk Tools / Tileset Creator - +