Compare commits

..

17 Commits

Author SHA1 Message Date
5919881568 Vita progress 2026-03-28 19:09:21 -05:00
cbb68a399d Fix compile error 2026-03-28 15:43:38 -05:00
0e794f28b1 Disable paletted textures for now 2026-03-28 15:40:30 -05:00
87d2d9123e Re-implement RGBA textures 2026-03-28 15:21:33 -05:00
6823a4ddb5 Try again again 2026-03-28 11:35:11 -05:00
20a7c70081 Fixiing weird action path missing? 2026-03-28 11:26:25 -05:00
9caa33b3bb Restore all builds 2026-03-28 11:14:15 -05:00
2d7e61460a fix 2026-03-28 11:05:36 -05:00
a4b7fb3f44 Try again 2026-03-28 11:04:42 -05:00
70056cf4ca Temp only build knulli
Some checks failed
Build Dusk / build-knulli (push) Failing after 21s
2026-03-28 11:02:43 -05:00
5f4ab71ade Add knulli build 2026-03-28 11:02:34 -05:00
f3adb3257b Cleanup knulli 2026-03-28 11:00:18 -05:00
438edda7fd Fixed knulli 2026-03-28 10:56:40 -05:00
d5b0441e6f Fixed GLES support (partially), PSP still not working 2026-03-28 10:51:50 -05:00
9ba0ceb000 Moved texture setting around 2026-03-28 09:48:24 -05:00
9474a68995 Slightly more accurate, likely going to have to change how paletted textures work 2026-03-27 21:01:29 -05:00
09c35f0aa6 Builds on knulli 2026-03-27 20:48:43 -05:00
38 changed files with 826 additions and 391 deletions

View File

@@ -1,5 +1,4 @@
name: Build Dusk name: Build Dusk
on: on:
push: push:
branches: branches:
@@ -7,7 +6,6 @@ on:
pull_request: pull_request:
branches: branches:
- main - main
jobs: jobs:
run-tests: run-tests:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -55,6 +53,26 @@ jobs:
path: ./git-artifcats/Dusk path: ./git-artifcats/Dusk
if-no-files-found: error if-no-files-found: error
build-knulli:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up Docker
uses: docker/setup-docker-action@v5
- name: Build knulli
run: ./scripts/build-knulli-docker.sh
- name: Move output to Dusk subfolder
run: |
mkdir -p ./git-artifcats/Dusk
cp -r build-knulli/dusk ./git-artifcats/Dusk
- name: Upload knulli binary
uses: actions/upload-artifact@v6
with:
name: dusk-knulli
path: ./git-artifcats/Dusk
if-no-files-found: error
build-gamecube: build-gamecube:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -74,6 +92,7 @@ jobs:
with: with:
name: dusk-gamecube name: dusk-gamecube
path: ./git-artifcats/Dusk path: ./git-artifcats/Dusk
if-no-files-found: error
build-wii: build-wii:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -94,4 +113,5 @@ jobs:
uses: actions/upload-artifact@v6 uses: actions/upload-artifact@v6
with: with:
name: dusk-wii name: dusk-wii
path: ./git-artifcats/Dusk path: ./git-artifcats/Dusk
if-no-files-found: error

View File

@@ -0,0 +1,17 @@
include(FetchContent)
set(ENABLE_ZSTD OFF CACHE BOOL "" FORCE)
set(BUILD_TOOLS OFF CACHE BOOL "" FORCE)
set(BUILD_REGRESS OFF CACHE BOOL "" FORCE)
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(BUILD_DOC OFF CACHE BOOL "" FORCE)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
set(LIBZIP_DO_INSTALL OFF CACHE BOOL "" FORCE)
FetchContent_Declare(
libzip
GIT_REPOSITORY https://github.com/nih-at/libzip.git
GIT_TAG v1.11.4
)
FetchContent_MakeAvailable(libzip)

View File

@@ -0,0 +1,20 @@
# 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)

View File

@@ -1,17 +1,43 @@
# Allow user to manually specify libzip paths
# LIBZIP_ROOT: root directory for libzip (optional)
# LIBZIP_INCLUDE_DIR: path to zip.h (optional)
# LIBZIP_LIBRARY: path to libzip library (optional)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
find_path(LIBZIP_INCLUDE_DIR NAMES zip.h) if(NOT LIBZIP_INCLUDE_DIR AND LIBZIP_ROOT)
find_path(LIBZIP_INCLUDE_DIR NAMES zip.h HINTS "${LIBZIP_ROOT}/include")
endif()
if(NOT LIBZIP_INCLUDE_DIR)
find_path(LIBZIP_INCLUDE_DIR NAMES zip.h)
endif()
mark_as_advanced(LIBZIP_INCLUDE_DIR) mark_as_advanced(LIBZIP_INCLUDE_DIR)
find_library(LIBZIP_LIBRARY NAMES zip) if(NOT LIBZIP_LIBRARY AND LIBZIP_ROOT)
find_library(LIBZIP_LIBRARY NAMES zip HINTS "${LIBZIP_ROOT}/lib")
endif()
if(NOT LIBZIP_LIBRARY)
find_library(LIBZIP_LIBRARY NAMES zip)
endif()
mark_as_advanced(LIBZIP_LIBRARY) mark_as_advanced(LIBZIP_LIBRARY)
get_filename_component(_libzip_libdir ${LIBZIP_LIBRARY} DIRECTORY) if(LIBZIP_LIBRARY)
find_file(_libzip_pkgcfg libzip.pc get_filename_component(_libzip_libdir ${LIBZIP_LIBRARY} DIRECTORY)
HINTS ${_libzip_libdir} ${LIBZIP_INCLUDE_DIR}/.. endif()
PATH_SUFFIXES pkgconfig lib/pkgconfig libdata/pkgconfig if(NOT _libzip_pkgcfg AND LIBZIP_ROOT)
NO_DEFAULT_PATH find_file(_libzip_pkgcfg libzip.pc
) HINTS "${LIBZIP_ROOT}/lib/pkgconfig" "${LIBZIP_ROOT}/libdata/pkgconfig"
NO_DEFAULT_PATH
)
endif()
if(NOT _libzip_pkgcfg AND LIBZIP_LIBRARY)
find_file(_libzip_pkgcfg libzip.pc
HINTS ${_libzip_libdir} ${LIBZIP_INCLUDE_DIR}/..
PATH_SUFFIXES pkgconfig lib/pkgconfig libdata/pkgconfig
NO_DEFAULT_PATH
)
endif()
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
find_package_handle_standard_args( find_package_handle_standard_args(

View File

@@ -21,26 +21,7 @@ set(CGLM_SHARED OFF CACHE BOOL "Build cglm shared" FORCE)
set(CGLM_STATIC ON CACHE BOOL "Build cglm static" FORCE) set(CGLM_STATIC ON CACHE BOOL "Build cglm static" FORCE)
find_package(cglm REQUIRED) find_package(cglm REQUIRED)
# Compile lua include(cmake/modules/CompileLua.cmake)
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)
# Link libraries # Link libraries
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE

View File

@@ -1,5 +1,8 @@
# Find link platform-specific libraries # Find link platform-specific libraries
set(OpenGL_GL_PREFERENCE LEGACY)
find_package(SDL2 REQUIRED) find_package(SDL2 REQUIRED)
find_library(EGL_LIB EGL REQUIRED)
find_library(GL_LIB GL REQUIRED)
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
# Setup endianess at compile time to optimize. # Setup endianess at compile time to optimize.
@@ -16,11 +19,12 @@ else()
endif() endif()
# Link required libraries. # Link required libraries.
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
SDL2 SDL2
pthread pthread
OpenGL::GL OpenGL::GLES2
GL ${GL_LIB}
${EGL_LIB}
m m
) )
@@ -28,6 +32,7 @@ target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_SDL2 DUSK_SDL2
DUSK_OPENGL DUSK_OPENGL
DUSK_OPENGL_ES
DUSK_LINUX DUSK_LINUX
DUSK_DISPLAY_SIZE_DYNAMIC DUSK_DISPLAY_SIZE_DYNAMIC
DUSK_DISPLAY_WIDTH_DEFAULT=640 DUSK_DISPLAY_WIDTH_DEFAULT=640

View File

@@ -28,6 +28,7 @@ target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_SDL2 DUSK_SDL2
DUSK_OPENGL DUSK_OPENGL
# DUSK_OPENGL_LEGACY
DUSK_LINUX DUSK_LINUX
DUSK_DISPLAY_SIZE_DYNAMIC DUSK_DISPLAY_SIZE_DYNAMIC
DUSK_DISPLAY_WIDTH_DEFAULT=640 DUSK_DISPLAY_WIDTH_DEFAULT=640

View File

@@ -1,5 +0,0 @@
include(cmake/targets/knulli.cmake)
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_RG35XXH
)

62
cmake/targets/vita.cmake Normal file
View File

@@ -0,0 +1,62 @@
include("${VITASDK}/share/vita.cmake" REQUIRED)
# Manually define libzip for Vita
set(LIBZIP_LIBRARY "${VITASDK}/lib/libzip.a" CACHE FILEPATH "libzip library for Vita")
set(LIBZIP_INCLUDE_DIR "${VITASDK}/include" CACHE PATH "libzip include dir for Vita")
set(VITA_APP_NAME "Red Rectangle")
set(VITA_TITLEID "VSDK00017")
set(VITA_VERSION "01.00")
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
mathneon
vitashark
kubridge_stub
SceAppMgr_stub
SceAudio_stub
SceCtrl_stub
SceCommonDialog_stub
SceDisplay_stub
SceKernelDmacMgr_stub
SceGxm_stub
SceShaccCg_stub
SceSysmodule_stub
ScePower_stub
SceTouch_stub
SceVshBridge_stub
SceIofilemgr_stub
SceShaccCgExt
SDL2-static
libtaihen_stub.a
lua::lua
zip
pthread
m
)
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
${SDL2_INCLUDE_DIRS}
)
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_SDL2
DUSK_OPENGL
DUSK_VITA
DUSK_INPUT_GAMEPAD
DUSK_PLATFORM_ENDIAN_LITTLE
DUSK_DISPLAY_WIDTH=960
DUSK_DISPLAY_HEIGHT=544
)
vita_create_self(${DUSK_BINARY_TARGET_NAME}.self ${DUSK_BINARY_TARGET_NAME})
vita_create_vpk(${DUSK_BINARY_TARGET_NAME}.vpk ${VITA_TITLEID} ${DUSK_BINARY_TARGET_NAME}.self
VERSION ${VITA_VERSION}
NAME ${VITA_APP_NAME}
# FILE sce_sys/icon0.png sce_sys/icon0.png
# FILE sce_sys/livearea/contents/bg.png sce_sys/livearea/contents/bg.png
# FILE sce_sys/livearea/contents/startup.png sce_sys/livearea/contents/startup.png
# FILE sce_sys/livearea/contents/template.xml sce_sys/livearea/contents/template.xml
)

View File

@@ -1,4 +1,4 @@
FROM debian:bookworm FROM debian:trixie
ENV DEBIAN_FRONTEND=noninteractive ENV DEBIAN_FRONTEND=noninteractive
WORKDIR /workdir WORKDIR /workdir
RUN dpkg --add-architecture arm64 && \ RUN dpkg --add-architecture arm64 && \
@@ -19,13 +19,17 @@ RUN dpkg --add-architecture arm64 && \
python3-dotenv \ python3-dotenv \
python3-pyqt5 \ python3-pyqt5 \
python3-opengl \ python3-opengl \
liblua5.3-dev:arm64 \ liblua5.4-dev:arm64 \
xz-utils:arm64 \ xz-utils:arm64 \
libbz2-dev:arm64 \ libbz2-dev:arm64 \
zlib1g-dev:arm64 \ zlib1g-dev:arm64 \
libzip-dev:arm64 \ libzip-dev:arm64 \
libbz2-dev:arm64 \
libssl-dev:arm64 \ libssl-dev:arm64 \
libsdl2-dev:arm64 \ libsdl2-dev:arm64 \
liblzma-dev:arm64 \
libopengl0:arm64 \
libgl1:arm64 \
libegl1:arm64 \
libgles2:arm64 \
libgl1-mesa-dev:arm64 && \ libgl1-mesa-dev:arm64 && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*

64
docker/vita/Dockerfile Normal file
View File

@@ -0,0 +1,64 @@
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
cmake \
git \
curl \
sudo \
wget \
libarchive-tools \
python3 \
python3-pip \
python3-dotenv \
python3-polib \
python3-pil \
python3-pyqt5 \
python3-opengl \
&& rm -rf /var/lib/apt/lists/*
RUN git clone https://github.com/vitasdk/vdpm /vdpm
WORKDIR /vdpm
RUN ./bootstrap-vitasdk.sh
ENV VITASDK=/usr/local/vitasdk
ENV PATH="${VITASDK}/bin:${PATH}"
RUN git clone https://github.com/vitasdk/packages.git /vitapackages
WORKDIR /vitapackages
RUN bash -lc '\
dir_array=( \
zlib \
bzip2 \
henkaku \
taihen \
kubridge \
openal-soft \
openssl \
curl \
curlpp \
expat \
opus \
opusfile \
glm \
kuio \
vitaShaRK \
libmathneon \
vitaGL \
SceShaccCgExt \
sdl2 \
libzip \
luajit \
); \
curdir=$(pwd); \
for d in "${dir_array[@]}"; do \
echo "${curdir}/${d}"; \
cd "${curdir}/${d}"; \
vita-makepkg; \
vdpm *-arm.tar.xz; \
done \
'
WORKDIR /workdir

3
scripts/build-knulli-docker.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
docker build -t dusk-knulli -f docker/knulli/Dockerfile .
docker run --rm -v $(pwd):/workdir dusk-knulli /bin/bash -c "./scripts/build-knulli.sh"

23
scripts/build-knulli.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/bin/bash
cmake -S . -B build-knulli -G Ninja \
-DDUSK_TARGET_SYSTEM=knulli \
-DCMAKE_TOOLCHAIN_FILE=./cmake/toolchains/aarch64-linux-gnu.cmake \
-DCMAKE_BUILD_TYPE=Release
cmake --build build-knulli -- -j$(nproc)
# Copy necessary libs out
mkdir -p ./build-knulli/dusk
cp ./build-knulli/Dusk ./build-knulli/dusk/Dusk
cp ./build-knulli/dusk.dsk ./build-knulli/dusk/dusk.dsk
echo '#!/bin/bash' > build-knulli/dusk/Dusk.sh
echo 'cd "$(dirname "$(readlink -f "$0")")"' >> build-knulli/dusk/Dusk.sh
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(dirname "$(readlink -f "$0")")' >> build-knulli/dusk/Dusk.sh
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/gl4es' >> build-knulli/dusk/Dusk.sh
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib' >> build-knulli/dusk/Dusk.sh
echo '$(dirname "$(readlink -f "$0")")/Dusk' >> build-knulli/dusk/Dusk.sh
chmod +x build-knulli/dusk/Dusk.sh
cp /usr/lib/aarch64-linux-gnu/liblua5.4.so.0 build-knulli/dusk/
# cp /usr/lib/aarch64-linux-gnu/libSDL2-2.0.so.0 build-knulli/dusk/
# cp /usr/lib/aarch64-linux-gnu/libGL.so.1 build-knulli/dusk/
# cp /usr/lib/aarch64-linux-gnu/libEGL.so.1 build-knulli/dusk/
# cp /usr/lib/aarch64-linux-gnu/libGLESv2.so.2 build-knulli/dusk/

View File

@@ -1,3 +0,0 @@
#!/bin/bash
docker build -t dusk-rg35xxh -f docker/knulli/Dockerfile .
docker run --rm -v $(pwd):/workdir dusk-rg35xxh /bin/bash -c "./scripts/build-rg35xxh.sh"

View File

@@ -1,7 +0,0 @@
#!/bin/bash
cmake -S . -B build-rg35xxh -G Ninja \
-DDUSK_BUILD_TESTS=ON \
-DDUSK_TARGET_SYSTEM=rg35xxh \
-DCMAKE_TOOLCHAIN_FILE=./cmake/toolchains/aarch64-linux-gnu.cmake \
-DCMAKE_BUILD_TYPE=Release
cmake --build build-rg35xxh -- -j$(nproc)

3
scripts/build-vita-docker.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
docker build -t dusk-vita -f docker/vita/Dockerfile .
docker run --rm -v $(pwd):/workdir dusk-vita /bin/bash -c "./scripts/build-vita.sh"

6
scripts/build-vita.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/bash
cd /workdir
cmake -S . -B build-vita \
-DDUSK_TARGET_SYSTEM=vita \
-DCMAKE_TOOLCHAIN_FILE="$VITASDK/share/vita.toolchain.cmake"
cmake --build build-vita -- -j$(nproc)

View File

@@ -5,12 +5,7 @@
add_subdirectory(dusk) add_subdirectory(dusk)
if(DUSK_TARGET_SYSTEM STREQUAL "linux") if(DUSK_TARGET_SYSTEM STREQUAL "linux" OR DUSK_TARGET_SYSTEM STREQUAL "knulli" OR DUSK_TARGET_SYSTEM STREQUAL "vita")
add_subdirectory(dusklinux)
add_subdirectory(dusksdl2)
add_subdirectory(duskgl)
elseif(DUSK_TARGET_SYSTEM STREQUAL "rg35xxh")
add_subdirectory(dusklinux) add_subdirectory(dusklinux)
add_subdirectory(dusksdl2) add_subdirectory(dusksdl2)
add_subdirectory(duskgl) add_subdirectory(duskgl)

View File

@@ -7,6 +7,7 @@
#include "assert.h" #include "assert.h"
#include "log/log.h" #include "log/log.h"
#include "util/string.h"
#ifndef DUSK_ASSERTIONS_FAKED #ifndef DUSK_ASSERTIONS_FAKED
#ifdef DUSK_TEST_ASSERT #ifdef DUSK_TEST_ASSERT
@@ -98,4 +99,14 @@
) { ) {
assertUnreachableImpl(file, line, message); assertUnreachableImpl(file, line, message);
} }
void assertStringEqualImpl(
const char *file,
const int32_t line,
const char *a,
const char *b,
const char *message
) {
assertTrueImpl(file, line, stringCompare(a, b) == 0, message);
}
#endif #endif

View File

@@ -104,6 +104,23 @@
const char *message const char *message
); );
/**
* Asserts two strings to be equal.
*
* @param file File that the assertion is being made from.
* @param line Line that the assertion is being made from.
* @param a First string to compare.
* @param b Second string to compare.
* @param message Message to throw against assertion failure.
*/
void assertStringEqualImpl(
const char *file,
const int32_t line,
const char *a,
const char *b,
const char *message
);
/** /**
* Asserts a given value to be true. * Asserts a given value to be true.
* *
@@ -178,6 +195,16 @@
#define assertStrLenMin(str, len, message) \ #define assertStrLenMin(str, len, message) \
assertTrue(strlen(str) >= len, message) assertTrue(strlen(str) >= len, message)
/**
* Asserts two strings to be equal.
*
* @param a First string to compare.
* @param b Second string to compare.
* @param message Message to throw against assertion failure.
*/
#define assertStringEqual(a, b, message) \
assertStringEqualImpl(__FILE__, __LINE__, a, b, message)
#else #else
// If assertions are faked, we define the macros to do nothing. // If assertions are faked, we define the macros to do nothing.
#define assertTrue(x, message) ((void)0) #define assertTrue(x, message) ((void)0)

View File

@@ -12,50 +12,50 @@
#include "util/endian.h" #include "util/endian.h"
errorret_t assetTextureLoad(assetentire_t entire) { errorret_t assetTextureLoad(assetentire_t entire) {
assertNotNull(entire.data, "Data pointer cannot be NULL."); // assertNotNull(entire.data, "Data pointer cannot be NULL.");
assertNotNull(entire.output, "Output pointer cannot be NULL."); // assertNotNull(entire.output, "Output pointer cannot be NULL.");
assettexture_t *assetData = (assettexture_t *)entire.data; // assettexture_t *assetData = (assettexture_t *)entire.data;
texture_t *texture = (texture_t *)entire.output; // texture_t *texture = (texture_t *)entire.output;
// Read header and version (first 4 bytes) // // Read header and version (first 4 bytes)
if( // if(
assetData->header[0] != 'D' || // assetData->header[0] != 'D' ||
assetData->header[1] != 'P' || // assetData->header[1] != 'P' ||
assetData->header[2] != 'T' // assetData->header[2] != 'T'
) { // ) {
errorThrow("Invalid texture header"); // errorThrow("Invalid texture header");
} // }
// Version (can only be 1 atm) // // Version (can only be 1 atm)
if(assetData->version != 0x01) { // if(assetData->version != 0x01) {
errorThrow("Unsupported texture version"); // errorThrow("Unsupported texture version");
} // }
// Fix endian // // Fix endian
assetData->width = endianLittleToHost32(assetData->width); // assetData->width = endianLittleToHost32(assetData->width);
assetData->height = endianLittleToHost32(assetData->height); // assetData->height = endianLittleToHost32(assetData->height);
// Check dimensions. // // Check dimensions.
if( // if(
assetData->width == 0 || assetData->width > ASSET_TEXTURE_WIDTH_MAX || // assetData->width == 0 || assetData->width > ASSET_TEXTURE_WIDTH_MAX ||
assetData->height == 0 || assetData->height > ASSET_TEXTURE_HEIGHT_MAX // assetData->height == 0 || assetData->height > ASSET_TEXTURE_HEIGHT_MAX
) { // ) {
errorThrow("Invalid texture dimensions"); // errorThrow("Invalid texture dimensions");
} // }
textureInit( // textureInit(
texture, // texture,
assetData->width, // assetData->width,
assetData->height, // assetData->height,
TEXTURE_FORMAT_PALETTE, // TEXTURE_FORMAT_PALETTE,
(texturedata_t){ // (texturedata_t){
.paletted = { // .paletted = {
.indices = NULL, // .indices = NULL,
.palette = NULL // .palette = NULL
} // }
} // }
); // );
errorOk(); // errorOk();
} }

View File

@@ -20,4 +20,5 @@ pink,1,0.75,0.8,1
lime,0.75,1,0,1 lime,0.75,1,0,1
navy,0,0,0.5,1 navy,0,0,0.5,1
teal,0,0.5,0.5,1 teal,0,0.5,0.5,1
cornflower_blue,0.39,0.58,0.93,1 cornflower_blue,0.39,0.58,0.93,1
salmon,1,0.5,0.5,1
1 name r g b a
20 lime 0.75 1 0 1
21 navy 0 0 0.5 1
22 teal 0 0.5 0.5 1
23 cornflower_blue 0.39 0.58 0.93 1
24 salmon 1 0.5 0.5 1

View File

@@ -22,12 +22,9 @@
display_t DISPLAY = { 0 }; display_t DISPLAY = { 0 };
texture_t TEXTURE; texture_t PALETTE_TEXTURE;
texture_t UNCOMPRESSED_TEXTURE;
uint8_t indices[2 * 2] = { texture_t COMPRESSED_TEXTURE;
0, 1,
2, 3
};
errorret_t displayInit(void) { errorret_t displayInit(void) {
memoryZero(&DISPLAY, sizeof(DISPLAY)); memoryZero(&DISPLAY, sizeof(DISPLAY));
@@ -43,20 +40,53 @@ errorret_t displayInit(void) {
errorChain(textInit()); errorChain(textInit());
errorChain(screenInit()); errorChain(screenInit());
PALETTES[0].colors[0] = COLOR_RED; // PALETTES[0].colors[0] = COLOR_RED;
PALETTES[0].colors[1] = COLOR_GREEN; // PALETTES[0].colors[1] = COLOR_GREEN;
PALETTES[0].colors[2] = COLOR_BLUE; // PALETTES[0].colors[2] = COLOR_BLUE;
PALETTES[0].colors[3] = COLOR_WHITE; // PALETTES[0].colors[3] = COLOR_WHITE;
PALETTES[0].count = 4; // PALETTES[0].colors[4] = COLOR_MAGENTA;
// PALETTES[0].colors[5] = COLOR_CYAN;
// PALETTES[0].colors[6] = COLOR_YELLOW;
// PALETTES[0].colors[7] = COLOR_BLACK;
// PALETTES[0].count = 8;
// uint8_t indices[64] = {
// 0,0,0,0,0,0,0,0,
// 1,1,1,1,1,1,1,1,
// 2,2,2,2,2,2,2,2,
// 3,3,3,3,3,3,3,3,
// 4,4,4,4,4,4,4,4,
// 5,5,5,5,5,5,5,5,
// 6,6,6,6,6,6,6,6,
// 7,7,7,7,7,7,7,7
// };
// errorChain(textureInit(
// &PALETTE_TEXTURE,
// 8, 8,
// TEXTURE_FORMAT_PALETTE,
// (texturedata_t){
// .paletted = {
// .indices = indices,
// .palette = &PALETTES[0]
// }
// }
// ));
errorChain(textureInit( errorChain(textureInit(
&TEXTURE, &UNCOMPRESSED_TEXTURE,
2, 2, 8, 8,
TEXTURE_FORMAT_PALETTE, TEXTURE_FORMAT_RGBA,
(texturedata_t){ (texturedata_t){
.paletted = { .rgbaColors = (color_t[]){
.indices = indices, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_WHITE, COLOR_MAGENTA, COLOR_CYAN, COLOR_YELLOW, COLOR_BLACK,
.palette = &PALETTES[0] COLOR_GREEN, COLOR_BLUE, COLOR_WHITE, COLOR_MAGENTA, COLOR_CYAN, COLOR_YELLOW, COLOR_BLACK, COLOR_RED,
COLOR_BLUE, COLOR_WHITE, COLOR_MAGENTA, COLOR_CYAN, COLOR_YELLOW, COLOR_BLACK, COLOR_RED, COLOR_GREEN,
COLOR_WHITE, COLOR_MAGENTA, COLOR_CYAN, COLOR_YELLOW, COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_BLUE,
COLOR_MAGENTA, COLOR_CYAN, COLOR_YELLOW, COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_WHITE,
COLOR_CYAN, COLOR_YELLOW, COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_WHITE, COLOR_MAGENTA,
COLOR_YELLOW, COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_WHITE, COLOR_MAGENTA, COLOR_CYAN,
COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_WHITE, COLOR_MAGENTA, COLOR_CYAN, COLOR_YELLOW
} }
} }
)); ));
@@ -85,7 +115,7 @@ errorret_t displayUpdate(void) {
// camera.orthographic.left = 0.0f; // camera.orthographic.left = 0.0f;
// camera.orthographic.right = SCREEN.width; // camera.orthographic.right = SCREEN.width;
// camera.orthographic.top = SCREEN.height; // camera.orthographic.top = SCREEN.height;
// camera.orthographic.bottom = 0.0f; // camera.orthographic.bottom = 0.0f;
cameraInitPerspective(&camera); cameraInitPerspective(&camera);
camera.lookat.position[0] = 3.0f; camera.lookat.position[0] = 3.0f;
camera.lookat.position[1] = 3.0f; camera.lookat.position[1] = 3.0f;
@@ -100,7 +130,8 @@ errorret_t displayUpdate(void) {
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_PROJECTION, proj)); errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_PROJECTION, proj));
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, view)); errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, view));
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_MODEL, model)); errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_MODEL, model));
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, &TEXTURE)); // errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, &PALETTE_TEXTURE));
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, &UNCOMPRESSED_TEXTURE));
errorChain(spriteBatchPush( errorChain(spriteBatchPush(
0.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f,

View File

@@ -12,8 +12,8 @@
#define PALETTE_COUNT 6 #define PALETTE_COUNT 6
typedef struct { typedef struct {
uint8_t count;
color_t colors[PALETTE_COLOR_COUNT]; color_t colors[PALETTE_COLOR_COUNT];
uint8_t count;
} palette_t; } palette_t;
extern palette_t PALETTES[PALETTE_COUNT]; extern palette_t PALETTES[PALETTE_COUNT];

View File

@@ -47,8 +47,6 @@ errorret_t meshDrawDolphin(
assertTrue(offsetof(meshvertex_t, uv) == 4, "uv offset wrong"); assertTrue(offsetof(meshvertex_t, uv) == 4, "uv offset wrong");
assertTrue(offsetof(meshvertex_t, pos) == 12, "pos offset wrong"); assertTrue(offsetof(meshvertex_t, pos) == 12, "pos offset wrong");
textureDolphinUploadTEV();
DCFlushRange( DCFlushRange(
(void*)&mesh->vertices[vertexOffset], (void*)&mesh->vertices[vertexOffset],
sizeof(meshvertex_t) * vertexCount sizeof(meshvertex_t) * vertexCount

View File

@@ -77,6 +77,88 @@ errorret_t shaderSetMatrixDolphin(
errorOk(); errorOk();
} }
errorret_t shaderSetTextureDolphin(
shaderdolphin_t *shader,
const char_t *name,
texture_t *texture
) {
assertNotNull(shader, "Shader must not be null");
assertNotNull(name, "Uniform name must not be null");
assertStrLenMin(name, 1, "Uniform name cannot be empty");
if(texture == NULL) {
// GX_SetNumChans(0);
GX_SetNumChans(1);
GX_SetChanCtrl(
GX_COLOR0A0,
GX_DISABLE,
GX_SRC_REG,
GX_SRC_VTX,
GX_LIGHTNULL,
GX_DF_NONE,
GX_AF_NONE
);
GX_SetChanAmbColor(GX_COLOR0A0, (GXColor){ 0, 0, 0, 0 });
GX_SetChanMatColor(GX_COLOR0A0, (GXColor){ 255, 255, 255, 255 });
GX_SetNumTexGens(0);
GX_SetNumTevStages(1);
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_NULL, GX_COLOR0A0);
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
GX_SetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR);
GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
errorOk();
}
// Add channel for vertex color
GX_LoadTexObj(&texture->texObj, GX_TEXMAP0);
GX_SetNumChans(1);
GX_SetChanCtrl(
GX_COLOR0A0,// Store in color channel 0
GX_DISABLE,// Lighting disabled
GX_SRC_REG,// Ambient color?
GX_SRC_VTX,// Material color?
GX_LIGHTNULL,// Light Mask
GX_DF_NONE,// Diffuse function
GX_AF_NONE// Attenuation function
);
// One set of UVs
GX_SetNumTexGens(1);
GX_SetTexCoordGen(
GX_TEXCOORD0,
GX_TG_MTX2x4,
GX_TG_TEX0,
GX_IDENTITY
);
// Basically the shader setup
switch(texture->format) {
case TEXTURE_FORMAT_RGBA:
// One TEV stage: vertex color * texture color
GX_SetNumTevStages(1);
GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
GX_SetTevOrder(
GX_TEVSTAGE0,
GX_TEXCOORD0,
GX_TEXMAP0,
GX_COLOR0A0
);
GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
break;
default:
assertUnreachable("Unknown texture format in meshDraw");
break;
}
errorOk();
}
errorret_t shaderDisposeDolphin(shaderdolphin_t *shader) { errorret_t shaderDisposeDolphin(shaderdolphin_t *shader) {
assertNotNull(shader, "Shader must not be null"); assertNotNull(shader, "Shader must not be null");

View File

@@ -6,7 +6,7 @@
*/ */
#pragma once #pragma once
#include "error/error.h" #include "display/texture/texture.h"
typedef struct { typedef struct {
mat4 view; mat4 view;
@@ -66,6 +66,20 @@ errorret_t shaderSetMatrixDolphin(
mat4 matrix mat4 matrix
); );
/**
* Sets a texture uniform in the dolphin shader. Basically does nothing.
*
* @param shader Shader to set the texture in.
* @param name Name of the uniform to set.
* @param texture Texture to set.
* @return Error code if failure.
*/
errorret_t shaderSetTextureDolphin(
shaderdolphin_t *shader,
const char_t *name,
texture_t *texture
);
/** /**
* Disposes a dolphin shader. Basically does nothing. * Disposes a dolphin shader. Basically does nothing.
* *

View File

@@ -14,5 +14,5 @@ typedef shaderdefinitiondolphin_t shaderdefinitionplatform_t;
#define shaderInitPlatform shaderInitDolphin #define shaderInitPlatform shaderInitDolphin
#define shaderBindPlatform shaderBindDolphin #define shaderBindPlatform shaderBindDolphin
#define shaderSetMatrixPlatform shaderSetMatrixDolphin #define shaderSetMatrixPlatform shaderSetMatrixDolphin
// #define shaderSetTexturePlatform shaderSetTextureDolphin #define shaderSetTexturePlatform shaderSetTextureDolphin
#define shaderDisposePlatform shaderDisposeDolphin #define shaderDisposePlatform shaderDisposeDolphin

View File

@@ -7,6 +7,7 @@
#include "display/texture/texture.h" #include "display/texture/texture.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "util/memory.h"
errorret_t textureInitDolphin( errorret_t textureInitDolphin(
texturedolphin_t *texture, texturedolphin_t *texture,
@@ -15,191 +16,101 @@ errorret_t textureInitDolphin(
const textureformatdolphin_t format, const textureformatdolphin_t format,
const texturedata_t data const texturedata_t data
) { ) {
// switch(format) { switch(format) {
// case TEXTURE_FORMAT_RGBA: case TEXTURE_FORMAT_RGBA: {
// assertTrue( size_t rgbaSize = width * height * sizeof(uint8_t) * 4;
// (width % 4) == 0 && (height % 4) == 0,
// "RGB5A3 requires w/h multiple of 4 (or pad)"
// );
// // Convert to RGB5A3 format // Dolphin takes the RGBA data as 4x4 tiled layout.
// size_t rgbaSize = width * height * sizeof(u16); texture->rgba = memoryAllocate(rgbaSize);
// texture->rgba = (u16*)memalign(32, rgbaSize);
// assertNotNull(texture->rgba, "Failed to allocate texture RGBA data"); for(uint32_t y = 0; y < height; ++y) {
for(uint32_t x = 0; x < width; ++x) {
const int src = y * width + x;
// for(uint32_t y = 0; y < height; ++y) { const int tileX = x >> 2;
// for(uint32_t x = 0; x < width; ++x) { const int tileY = y >> 2;
// const int src = y * width + x; const int tilesPerRow = width >> 2;
const int tileIndex = tileY * tilesPerRow + tileX;
const int inTile = ((y & 3) << 2) + (x & 3);
const int tileBase = tileIndex * 64;
// const int tileX = x >> 2; color_t col = data.rgbaColors[src];
// const int tileY = y >> 2;
// const int tilesPerRow = width >> 2;
// const int tileIndex = tileY * tilesPerRow + tileX;
// const int tileBaseWords = tileIndex * 16;
// const int inTile = ((y & 3) << 2) + (x & 3);
// const int dest = tileBaseWords + inTile;
// color4b_t col = data.rgba.colors[src];
// u16 outCol; // AR plane
// if(col.a < 255) { texture->rgba[tileBase + inTile * 2 + 0] = col.a;
// // 0AAA RRRR GGGG BBBB texture->rgba[tileBase + inTile * 2 + 1] = col.r;
// outCol = (
// (0u << 15) |
// ((u16)(col.a >> 5) << 12) |
// ((u16)(col.r >> 4) << 8) |
// ((u16)(col.g >> 4) << 4) |
// ((u16)(col.b >> 4) << 0)
// );
// } else {
// // 1RRRR RRGG GGGB BBBB
// outCol = (
// (1u << 15) |
// ((u16)(col.r >> 3) << 10) |
// ((u16)(col.g >> 3) << 5) |
// ((u16)(col.b >> 3) << 0)
// );
// }
// texture->rgba[dest] = outCol;
// }
// }
// DCFlushRange(texture->rgba, rgbaSize); // GB plane
// GX_InitTexObj( texture->rgba[tileBase + 32 + inTile * 2 + 0] = col.g;
// &texture->texObj, texture->rgba[tileBase + 32 + inTile * 2 + 1] = col.b;
// texture->rgba, }
// width, height, }
// GX_TF_RGB5A3, DCFlushRange(texture->rgba, rgbaSize);
// GX_REPEAT, GX_REPEAT, GX_InitTexObj(
// GX_FALSE &texture->texObj,
// ); texture->rgba,
width, height,
format,
GX_REPEAT, GX_REPEAT,
GX_FALSE
);
// DCFlushRange(texture->rgba, rgbaSize); DCFlushRange(texture->rgba, rgbaSize);
// GX_InvalidateTexAll(); GX_InvalidateTexAll();
// GX_InitTexObjLOD( GX_InitTexObjLOD(
// &texture->texObj, &texture->texObj,
// GX_NEAR, GX_NEAR, GX_NEAR, GX_NEAR,
// 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
// GX_FALSE, GX_FALSE,
// GX_FALSE, GX_FALSE,
// GX_ANISO_1 GX_ANISO_1
// ); );
// break; break;
}
// case TEXTURE_FORMAT_PALETTE: { case TEXTURE_FORMAT_PALETTE: {
// // Not supported, convert to RGBA using lookup assertUnreachable("Paletted textures not yet implemented for Dolphin");
// color_t* formatted = memoryAllocate(width * height * sizeof(color_t)); break;
// for(int32_t i = 0; i < width * height; i++) { }
// uint8_t index = data.palette.data[i];
// assertTrue(
// index < data.palette.palette->colorCount,
// "Palette index out of range"
// );
// formatted[i] = data.palette.palette->colors[index];
// }
// textureInit( default: {
// texture, width, height, TEXTURE_FORMAT_RGBA, assertUnreachable("Unsupported texture format for Dolphin");
// (texturedata_t){ break;
// .rgba = { .colors = formatted } }
// }
// );
// memoryFree(formatted);
// break;
// }
// default:
// assertUnreachable("Unsupported texture format for Dolphin");
// break;
// }
// texture->ready = true;
errorOk();
}
errorret_t textureBindDolphin(texturedolphin_t *texture) {
if(texture == NULL) {
GX_SetNumChans(0);
errorOk();
} }
GX_SetNumChans(1);
GX_LoadTexObj(&texture->texObj, GX_TEXMAP0);
errorOk(); errorOk();
} }
errorret_t textureDisposeDolphin(texturedolphin_t *texture) { errorret_t textureDisposeDolphin(texturedolphin_t *texture) {
errorOk(); switch(texture->format) {
} case TEXTURE_FORMAT_RGBA: {
if(texture->rgba) {
memoryFree(texture->rgba);
texture->rgba = NULL;
}
break;
}
void textureDolphinUploadTEV(void) { // case TEXTURE_FORMAT_RGB4A3: {
if(TEXTURE_BOUND == NULL) { // assertUnreachable("RGB4A3 texture format not yet implemented");
GX_SetNumChans(1); // }
GX_SetChanCtrl(
GX_COLOR0A0,
GX_DISABLE,
GX_SRC_REG,
GX_SRC_VTX,
GX_LIGHTNULL,
GX_DF_NONE,
GX_AF_NONE
);
GX_SetChanAmbColor(GX_COLOR0A0, (GXColor){0, 0, 0, 0});
GX_SetChanMatColor(GX_COLOR0A0, (GXColor){255, 255, 255, 255});
GX_SetNumTexGens(0);
GX_SetNumTevStages(1);
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_NULL, GX_COLOR0A0);
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
GX_SetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR);
GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
return; // case TEXTURE_FORMAT_RGB5: {
} // assertUnreachable("RGB5 texture format not yet implemented");
// }
// Add channel for vertex color // case TEXTURE_FORMAT_PALETTE: {
GX_SetNumChans(1); // assertUnreachable("Paletted textures not yet implemented for Dolphin");
GX_SetChanCtrl( // break;
GX_COLOR0A0,// Store in color channel 0 // }
GX_DISABLE,// Lighting disabled
GX_SRC_REG,// Ambient color?
GX_SRC_VTX,// Material color?
GX_LIGHTNULL,// Light Mask
GX_DF_NONE,// Diffuse function
GX_AF_NONE// Attenuation function
);
// One set of UVs default: {
GX_SetNumTexGens(1); assertUnreachable("Unsupported texture format for Dolphin");
GX_SetTexCoordGen(
GX_TEXCOORD0,
GX_TG_MTX2x4,
GX_TG_TEX0,
GX_IDENTITY
);
// Basically the shader setup
switch(TEXTURE_BOUND->format) {
case TEXTURE_FORMAT_RGBA:
// One TEV stage: vertex color * texture color
GX_SetNumTevStages(1);
GX_SetTevOp(GX_TEVSTAGE0, GX_MODULATE);
GX_SetTevOrder(
GX_TEVSTAGE0,
GX_TEXCOORD0,
GX_TEXMAP0,
GX_COLOR0A0
);
GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
GX_SetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
break;
default:
assertUnreachable("Unknown texture format in meshDraw");
break; break;
}
} }
errorOk();
} }

View File

@@ -13,6 +13,8 @@ typedef union texturedata_u texturedata_t;
typedef enum { typedef enum {
TEXTURE_FORMAT_RGBA = GX_TF_RGBA8, TEXTURE_FORMAT_RGBA = GX_TF_RGBA8,
TEXTURE_FORMAT_PALETTE = GX_TF_CI8, TEXTURE_FORMAT_PALETTE = GX_TF_CI8,
// TEXTURE_FORMAT_RGB4A3 = GX_TF_RGB5A3,
// TEXTURE_FORMAT_RGB5 = GX_TF_RGB565,
} textureformatdolphin_t; } textureformatdolphin_t;
typedef struct { typedef struct {
@@ -20,6 +22,11 @@ typedef struct {
textureformatdolphin_t format; textureformatdolphin_t format;
int32_t width; int32_t width;
int32_t height; int32_t height;
union {
uint8_t *rgba;
// u16 *rgba;
};
} texturedolphin_t; } texturedolphin_t;
/** /**
@@ -54,10 +61,4 @@ errorret_t textureBindDolphin(texturedolphin_t *texture);
* @param texture The texture to dispose. * @param texture The texture to dispose.
* @return An error if the texture failed to dispose, otherwise success. * @return An error if the texture failed to dispose, otherwise success.
*/ */
errorret_t textureDisposeDolphin(texturedolphin_t *texture); errorret_t textureDisposeDolphin(texturedolphin_t *texture);
/**
* Internal method that uploads the texture environment variables to the GPU
* for rendering. This is basically uploading the shader information.
*/
void textureDolphinUploadTEV(void);

View File

@@ -29,8 +29,6 @@ errorret_t displayOpenGLInit(void) {
errorChain(errorGLCheck()); errorChain(errorGLCheck());
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
errorChain(errorGLCheck()); errorChain(errorGLCheck());
glPixelStorei(GL_PACK_ALIGNMENT, 1);
errorChain(errorGLCheck());
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
errorChain(errorGLCheck()); errorChain(errorGLCheck());

View File

@@ -28,6 +28,11 @@ errorret_t shaderInitGL(shadergl_t *shader, const shaderdefinitiongl_t *def) {
SHADER_LEGACY.boundShader = NULL; SHADER_LEGACY.boundShader = NULL;
errorOk(); errorOk();
#else #else
assertNotNull(def->vert, "Vertex shader source cannot be null");
assertNotNull(def->frag, "Fragment shader source cannot be null");
shader->setTexture = def->setTexture;
// Create vertex shader // Create vertex shader
shader->vertexShaderId = glCreateShader(GL_VERTEX_SHADER); shader->vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
errorret_t err = errorGLCheck(); errorret_t err = errorGLCheck();
@@ -212,6 +217,12 @@ errorret_t shaderSetTextureGL(
assertStrLenMin(name, 1, "Uniform name cannot be empty"); assertStrLenMin(name, 1, "Uniform name cannot be empty");
#ifdef DUSK_OPENGL_LEGACY #ifdef DUSK_OPENGL_LEGACY
assertStringEqual(
name,
SHADER_UNLIT_TEXTURE,
"Only one texture supported in legacy opengl."
);
if(texture == NULL) { if(texture == NULL) {
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
errorChain(errorGLCheck()); errorChain(errorGLCheck());
@@ -222,48 +233,12 @@ errorret_t shaderSetTextureGL(
errorChain(errorGLCheck()); errorChain(errorGLCheck());
glBindTexture(GL_TEXTURE_2D, texture->id); glBindTexture(GL_TEXTURE_2D, texture->id);
errorChain(errorGLCheck()); errorChain(errorGLCheck());
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
errorChain(errorGLCheck());
#else #else
if(texture == NULL) { if(shader->setTexture == NULL) {
glActiveTexture(GL_TEXTURE0); assertUnreachable("Shader does not support setting textures.");
errorChain(errorGLCheck());
glBindTexture(GL_TEXTURE_2D, 0);
errorChain(errorGLCheck());
errorOk();
} }
errorChain(shader->setTexture(shader, name, texture));
GLint location;
errorChain(shaderParamGetLocationGL(shader, name, &location));
glActiveTexture(GL_TEXTURE0);
errorChain(errorGLCheck());
glBindTexture(GL_TEXTURE_2D, texture->id);
errorChain(errorGLCheck());
glUniform1i(location, 0);
errorChain(errorGLCheck());
if(texture->format == TEXTURE_FORMAT_PALETTE) {
shaderParamGetLocationGL(shader, "u_ColorCount", &location);
glUniform1i(location, texture->palette->count);
errorChain(errorGLCheck());
shaderParamGetLocationGL(shader, "u_Colors", &location);
GLuint paletteData[texture->palette->count];
for(size_t i = 0; i < texture->palette->count; i++) {
color_t color = texture->palette->colors[i];
paletteData[i] = (
((uint32_t)color.r << 24) |
((uint32_t)color.g << 16) |
((uint32_t)color.b << 8) |
((uint32_t)color.a << 0)
);
}
glUniform1uiv(location, texture->palette->count, paletteData);
errorChain(errorGLCheck());
}
#endif #endif
errorOk(); errorOk();

View File

@@ -9,28 +9,35 @@
#include "error/errorgl.h" #include "error/errorgl.h"
#include "display/texture/texture.h" #include "display/texture/texture.h"
typedef struct { typedef struct shadergl_s shadergl_t;
typedef errorret_t (*shadersettexturefn_t)(
shadergl_t *,
const char_t *,
texture_t *
);
typedef struct shadergl_s {
#ifdef DUSK_OPENGL_LEGACY #ifdef DUSK_OPENGL_LEGACY
void *nothing; mat4 view;
mat4 proj;
mat4 model;
#else #else
GLuint shaderProgramId; GLuint shaderProgramId;
GLuint vertexShaderId; GLuint vertexShaderId;
GLuint fragmentShaderId; GLuint fragmentShaderId;
#endif shadersettexturefn_t setTexture;
#if DUSK_OPENGL_LEGACY
mat4 view;
mat4 proj;
mat4 model;
#endif #endif
} shadergl_t; } shadergl_t;
typedef struct { typedef struct {
#ifdef DUSK_OPENGL_LEGACY #ifdef DUSK_OPENGL_LEGACY
void *nothing; void *nothing;
#else #else
const char_t *vert; const char_t *vert;
const char_t *frag; const char_t *frag;
shadersettexturefn_t setTexture;
#endif #endif
} shaderdefinitiongl_t; } shaderdefinitiongl_t;

View File

@@ -6,46 +6,184 @@
*/ */
#include "display/shader/shaderunlit.h" #include "display/shader/shaderunlit.h"
#include "assert/assertgl.h"
#ifdef DUSK_OPENGL_LEGACY #ifdef DUSK_OPENGL_LEGACY
shaderdefinition_t SHADER_UNLIT_DEFINITION = { 0 }; shaderdefinition_t SHADER_UNLIT_DEFINITION = { 0 };
#else #else
errorret_t shaderUnlitSetTextureGL(
shadergl_t *shader,
const char_t *name,
texture_t *texture
) {
assertNotNull(shader, "Shader cannot be null");
assertStrLenMin(name, 1, "Uniform name cannot be empty");
assertStringEqual(
name,
SHADER_UNLIT_TEXTURE,
"Only one texture supported in unlit shader."
);
GLint locTexture, locType, locColorCount, locColors;
errorChain(shaderParamGetLocationGL(shader, "u_TextureType", &locType));
// NULL textures
if(texture == NULL) {
glUniform1i(locType, 0);
errorChain(errorGLCheck());
errorOk();
}
// Set texture.
glActiveTexture(GL_TEXTURE0);
errorChain(errorGLCheck());
glBindTexture(GL_TEXTURE_2D, texture->id);
errorChain(errorGLCheck());
errorChain(shaderParamGetLocationGL(shader, name, &locTexture));
glUniform1i(locTexture, 0);
errorChain(errorGLCheck());
// Set texture type
if(texture->format == TEXTURE_FORMAT_PALETTE) {
glUniform1i(locType, 2);
errorChain(errorGLCheck());
shaderParamGetLocationGL(shader, "u_ColorCount", &locColorCount);
glUniform1i(locColorCount, texture->palette->count);
errorChain(errorGLCheck());
shaderParamGetLocationGL(shader, "u_Colors", &locColors);
GLuint paletteData[texture->palette->count];
for(size_t i = 0; i < texture->palette->count; i++) {
color_t color = texture->palette->colors[i];
paletteData[i] = (
((uint32_t)color.r << 24) |
((uint32_t)color.g << 16) |
((uint32_t)color.b << 8) |
((uint32_t)color.a << 0)
);
}
glUniform1uiv(locColors, texture->palette->count, paletteData);
errorChain(errorGLCheck());
} else {
glUniform1i(locType, 1);
errorChain(errorGLCheck());
}
errorOk();
}
shaderdefinition_t SHADER_UNLIT_DEFINITION = { shaderdefinition_t SHADER_UNLIT_DEFINITION = {
.vert = .vert =
"#version 330 core\n" #ifdef DUSK_OPENGL_ES
"layout(location = 0) in vec3 a_Pos;\n" "#version 300 es\n"
"layout(location = 1) in vec2 a_TexCoord;\n" "precision mediump float;\n"
"layout(location = 2) in vec4 a_Color;\n" // Attributes
"uniform mat4 u_Proj;\n" "layout(location = 0) in vec3 a_Pos;\n"
"uniform mat4 u_View;\n" "layout(location = 1) in vec2 a_TexCoord;\n"
"uniform mat4 u_Model;\n" "layout(location = 2) in vec4 a_Color;\n"
"out vec4 v_Color;\n" // Uniforms
"out vec2 v_TexCoord;\n" "uniform mat4 u_Proj;\n"
"void main() {\n" "uniform mat4 u_View;\n"
" gl_Position = u_Proj * u_View * u_Model * vec4(a_Pos, 1.0);\n" "uniform mat4 u_Model;\n"
" v_Color = a_Color;\n" // Vertex shader outputs
" v_TexCoord = a_TexCoord;\n" "out vec4 v_Color;\n"
"}\n", "out vec2 v_TexCoord;\n"
"void main() {\n"
" gl_Position = u_Proj * u_View * u_Model * vec4(a_Pos, 1.0);\n"
" v_Color = a_Color;\n"
" v_TexCoord = a_TexCoord;\n"
"}\n",
#else
"#version 330 core\n"
// Attributes
"layout(location = 0) in vec3 a_Pos;\n"
"layout(location = 1) in vec2 a_TexCoord;\n"
"layout(location = 2) in vec4 a_Color;\n"
// Uniforms
"uniform mat4 u_Proj;\n"
"uniform mat4 u_View;\n"
"uniform mat4 u_Model;\n"
// Vertex shader outputs
"out vec4 v_Color;\n"
"out vec2 v_TexCoord;\n"
"void main() {\n"
" gl_Position = u_Proj * u_View * u_Model * vec4(a_Pos, 1.0);\n"
" v_Color = a_Color;\n"
" v_TexCoord = a_TexCoord;\n"
"}\n",
#endif
.frag = .frag =
"#version 330 core\n" #ifdef DUSK_OPENGL_ES
"uniform sampler2D u_Texture;\n" "#version 300 es\n"
"uniform uint u_Colors[256];\n" "precision mediump float;\n"
"uniform int u_ColorCount;\n" // Uniforms
"in vec4 v_Color;\n" "uniform sampler2D u_Texture;\n"
"in vec2 v_TexCoord;\n" "uniform int u_TextureType;\n"
"out vec4 FragColor;\n" "uniform vec4 u_Colors[256];\n"// For paletted textures.
"void main() {\n" "uniform int u_ColorCount;\n"
" vec4 texColor = texture(u_Texture, v_TexCoord);\n" // Fragment shader inputs
" uint index = uint(floor(texColor.r * 255.0));\n" "in vec4 v_Color;\n"
" uint palColor = u_Colors[index];\n" "in vec2 v_TexCoord;\n"
" float r = float((palColor >> 24) & 0xFFu) / 255.0;\n" // Fragment shader output
" float g = float((palColor >> 16) & 0xFFu) / 255.0;\n" "out vec4 FragColor;\n"
" float b = float((palColor >> 8) & 0xFFu) / 255.0;\n" "void main() {\n"
" float a = float((palColor >> 0) & 0xFFu) / 255.0;\n" " if(u_TextureType == 0) {\n"// No texture
" vec4 paletteColor = vec4(r, g, b, a);\n" " FragColor = v_Color;\n"
" FragColor = paletteColor;\n" " return;\n"
// " FragColor = paletteColor * v_Color;\n" " }\n"
"}\n" " if(u_TextureType == 1) {\n"// Regular texture
" FragColor = texture(u_Texture, v_TexCoord) * v_Color;\n"
" return;\n"
" }\n"
" if(u_TextureType == 2) {\n"// Paletted texture
" vec4 texColor = texture(u_Texture, v_TexCoord);\n"
" int index = int(floor(texColor.r * 255.0));\n"
" vec4 paletteColor = u_Colors[index];\n"
" FragColor = paletteColor;\n"
" return;\n"
" }\n"
" FragColor = v_Color;\n"// Unknown texture type?
"}\n",
#else
"#version 330 core\n"
// Uniforms
"uniform sampler2D u_Texture;\n"
"uniform int u_TextureType;\n"
"uniform uint u_Colors[256];\n"// For paletted textures.
"uniform int u_ColorCount;\n"
// Fragment shader inputs
"in vec4 v_Color;\n"
"in vec2 v_TexCoord;\n"
// Fragment shader output
"out vec4 FragColor;\n"
"void main() {\n"
" if(u_TextureType == 0) {\n"// No texture
" FragColor = v_Color;\n"
" return;\n"
" }\n"
" if(u_TextureType == 1) {\n"// Regular texture
" FragColor = texture(u_Texture, v_TexCoord) * v_Color;\n"
" return;\n"
" }\n"
" if(u_TextureType == 2) {\n"// Paletted texture
" vec4 texColor = texture(u_Texture, v_TexCoord);\n"
" uint index = uint(floor(texColor.r * 255.0));\n"
" uint palColor = u_Colors[index];\n"
" float r = float((palColor >> 24) & 0xFFu) / 255.0;\n"
" float g = float((palColor >> 16) & 0xFFu) / 255.0;\n"
" float b = float((palColor >> 8) & 0xFFu) / 255.0;\n"
" float a = float((palColor >> 0) & 0xFFu) / 255.0;\n"
" vec4 paletteColor = vec4(r, g, b, a);\n"
" FragColor = paletteColor;\n"
" return;\n"
" }\n"
" FragColor = v_Color;\n"// Unknown texture type?
"}\n",
#endif
.setTexture = shaderUnlitSetTextureGL
}; };
#endif #endif

View File

@@ -25,16 +25,25 @@ errorret_t textureInitGL(
switch(format) { switch(format) {
case TEXTURE_FORMAT_RGBA: case TEXTURE_FORMAT_RGBA:
glTexImage2D( glTexImage2D(
GL_TEXTURE_2D, 0, format, width, height, 0, GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
format, GL_UNSIGNED_BYTE, (void*)data.rgbaColors GL_RGBA, GL_UNSIGNED_BYTE, (void*)data.rgbaColors
); );
errorChain(errorGLCheck()); errorChain(errorGLCheck());
break; break;
case TEXTURE_FORMAT_PALETTE: case TEXTURE_FORMAT_PALETTE:
texture->palette = data.paletted.palette; texture->palette = data.paletted.palette;
assertTrue(
texture->palette == &PALETTES[0],
"Only the first palette is supported in legacy opengl."
);
#ifdef DUSK_OPENGL_LEGACY #ifdef DUSK_OPENGL_LEGACY
glColorTableEXT(
GL_TEXTURE_2D, GL_RGBA, texture->palette->count, GL_RGBA,
GL_UNSIGNED_BYTE, (const void*)texture->palette->colors
);
errorChain(errorGLCheck());
glTexImage2D( glTexImage2D(
GL_TEXTURE_2D, GL_TEXTURE_2D,
0, GL_COLOR_INDEX8_EXT, 0, GL_COLOR_INDEX8_EXT,
@@ -42,13 +51,7 @@ errorret_t textureInitGL(
0, GL_COLOR_INDEX8_EXT, 0, GL_COLOR_INDEX8_EXT,
GL_UNSIGNED_BYTE, (void*)data.paletted.indices GL_UNSIGNED_BYTE, (void*)data.paletted.indices
); );
glColorTableEXT(
GL_TEXTURE_2D, GL_RGBA, texture->palette->count, GL_RGBA,
GL_UNSIGNED_BYTE, (const void*)texture->palette->colors
);
errorChain(errorGLCheck()); errorChain(errorGLCheck());
#else #else
// For modern systems we send to only the R channel and the shader does // For modern systems we send to only the R channel and the shader does
// the rest. // the rest.
@@ -74,6 +77,10 @@ errorret_t textureInitGL(
errorChain(errorGLCheck()); errorChain(errorGLCheck());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
errorChain(errorGLCheck()); errorChain(errorGLCheck());
#ifdef DUSK_OPENGL_LEGACY
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
#endif
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
errorChain(errorGLCheck()); errorChain(errorGLCheck());

View File

@@ -13,6 +13,7 @@ typedef union texturedata_u texturedata_t;
typedef enum { typedef enum {
TEXTURE_FORMAT_RGBA = GL_RGBA, TEXTURE_FORMAT_RGBA = GL_RGBA,
TEXTURE_FORMAT_PALETTE = GL_COLOR_INDEX8_EXT, TEXTURE_FORMAT_PALETTE = GL_COLOR_INDEX8_EXT,
// TEXTURE_FORMAT_DXT5 = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
} textureformatgl_t; } textureformatgl_t;
typedef struct { typedef struct {

View File

@@ -6,6 +6,23 @@
*/ */
#pragma once #pragma once
#define GL_GLEXT_PROTOTYPES #ifdef DUSK_OPENGL_ES
#include <GL/gl.h> #include <GLES3/gl3.h>
#include <GL/glext.h> #define GL_COLOR_INDEX8_EXT 0x80E5
#define GL_FRAMEBUFFER_EXT GL_FRAMEBUFFER
#define GL_FRAMEBUFFER_COMPLETE_EXT GL_FRAMEBUFFER_COMPLETE
#define glCheckFramebufferStatusEXT glCheckFramebufferStatus
#define glDeleteFramebuffersEXT glDeleteFramebuffers
#define glGenFramebuffersEXT glGenFramebuffers
#define glBindFramebufferEXT glBindFramebuffer
#define glFramebufferTexture2DEXT glFramebufferTexture2D
#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0
#define glClearDepth(depth) glClearDepthf(depth)
#else
#define GL_GLEXT_PROTOTYPES
#include <vitaGL.h>
#define GL_COLOR_INDEX8_EXT 0x80E5
// #include <GL/glext.h>
#endif

View File

@@ -19,4 +19,5 @@ void logError(const char_t *message, ...) {
va_start(args, message); va_start(args, message);
vprintf(message, args); vprintf(message, args);
va_end(args); va_end(args);
fflush(stdout);
} }