Compare commits

...

24 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
a2113442cb Builds on knulli 2026-03-27 15:59:26 -05:00
d91808487f Allow texture to be NULL.
Some checks failed
Build Dusk / run-tests (push) Failing after 14s
Build Dusk / build-linux (push) Failing after 20s
Build Dusk / build-psp (push) Failing after 16s
Build Dusk / build-gamecube (push) Failing after 18s
Build Dusk / build-wii (push) Failing after 19s
2026-03-27 13:46:18 -05:00
933949cc19 Progress on PSP paletted textures
Some checks failed
Build Dusk / run-tests (push) Failing after 19s
Build Dusk / build-linux (push) Failing after 17s
Build Dusk / build-psp (push) Failing after 21s
Build Dusk / build-gamecube (push) Failing after 19s
Build Dusk / build-wii (push) Failing after 15s
2026-03-27 08:04:34 -05:00
407620387d Test paletted stuff
Some checks failed
Build Dusk / run-tests (push) Failing after 26s
Build Dusk / build-linux (push) Failing after 25s
Build Dusk / build-psp (push) Failing after 18s
Build Dusk / build-gamecube (push) Failing after 18s
Build Dusk / build-wii (push) Failing after 18s
2026-03-26 14:48:20 -05:00
98947dea26 starting textures
Some checks failed
Build Dusk / run-tests (push) Failing after 16s
Build Dusk / build-linux (push) Failing after 17s
Build Dusk / build-psp (push) Failing after 18s
Build Dusk / build-gamecube (push) Failing after 17s
Build Dusk / build-wii (push) Failing after 17s
2026-03-23 19:42:24 -05:00
ebff7af9b5 fix
Some checks failed
Build Dusk / run-tests (push) Failing after 17s
Build Dusk / build-linux (push) Failing after 20s
Build Dusk / build-psp (push) Failing after 20s
Build Dusk / build-gamecube (push) Failing after 19s
Build Dusk / build-wii (push) Failing after 17s
2026-03-23 15:37:53 -05:00
b23c4b83ae played around with color, will likely stick to textures.
Some checks failed
Build Dusk / run-tests (push) Failing after 13s
Build Dusk / build-linux (push) Failing after 15s
Build Dusk / build-psp (push) Failing after 14s
Build Dusk / build-gamecube (push) Failing after 13s
Build Dusk / build-wii (push) Failing after 14s
2026-03-22 23:53:23 -05:00
54 changed files with 1150 additions and 405 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

@@ -0,0 +1,45 @@
# Find link platform-specific libraries
set(OpenGL_GL_PREFERENCE LEGACY)
find_package(SDL2 REQUIRED)
find_library(EGL_LIB EGL REQUIRED)
find_library(GL_LIB GL REQUIRED)
find_package(OpenGL REQUIRED)
# Setup endianess at compile time to optimize.
include(TestBigEndian)
test_big_endian(IS_BIG_ENDIAN)
if(IS_BIG_ENDIAN)
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_PLATFORM_ENDIAN_BIG
)
else()
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_PLATFORM_ENDIAN_LITTLE
)
endif()
# Link required libraries.
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
SDL2
pthread
OpenGL::GLES2
${GL_LIB}
${EGL_LIB}
m
)
# Define platform-specific macros.
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_SDL2
DUSK_OPENGL
DUSK_OPENGL_ES
DUSK_LINUX
DUSK_DISPLAY_SIZE_DYNAMIC
DUSK_DISPLAY_WIDTH_DEFAULT=640
DUSK_DISPLAY_HEIGHT_DEFAULT=480
DUSK_DISPLAY_SCREEN_HEIGHT=240
DUSK_INPUT_KEYBOARD
DUSK_INPUT_POINTER
DUSK_INPUT_GAMEPAD
DUSK_TIME_DYNAMIC
)

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

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

@@ -0,0 +1,29 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
set(CMAKE_ASM_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_SYSROOT /)
set(CMAKE_C_COMPILER_TARGET aarch64-linux-gnu)
set(CMAKE_CXX_COMPILER_TARGET aarch64-linux-gnu)
set(CMAKE_FIND_ROOT_PATH
/usr/aarch64-linux-gnu
/usr/lib/aarch64-linux-gnu
/usr/include/aarch64-linux-gnu
)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig")
set(ENV{PKG_CONFIG_PATH} "/usr/lib/aarch64-linux-gnu/pkgconfig")
set(CMAKE_PREFIX_PATH "/usr/aarch64-linux-gnu;/usr/lib/aarch64-linux-gnu")
# Optional: helps some Find modules
set(SDL2_DIR "/usr/lib/aarch64-linux-gnu/cmake/SDL2" CACHE PATH "")

35
docker/knulli/Dockerfile Normal file
View File

@@ -0,0 +1,35 @@
FROM debian:trixie
ENV DEBIAN_FRONTEND=noninteractive
WORKDIR /workdir
RUN dpkg --add-architecture arm64 && \
apt-get update && \
apt-get install -y --no-install-recommends \
crossbuild-essential-arm64 \
ca-certificates \
pkg-config \
cmake \
make \
ninja-build \
git \
file \
python3 \
python3-pip \
python3-polib \
python3-pil \
python3-dotenv \
python3-pyqt5 \
python3-opengl \
liblua5.4-dev:arm64 \
xz-utils:arm64 \
libbz2-dev:arm64 \
zlib1g-dev:arm64 \
libzip-dev:arm64 \
libssl-dev:arm64 \
libsdl2-dev:arm64 \
liblzma-dev:arm64 \
libopengl0:arm64 \
libgl1:arm64 \
libegl1:arm64 \
libgles2:arm64 \
libgl1-mesa-dev:arm64 && \
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/

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,7 +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(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,47 +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){
.paletteData = assetData->palette // .paletted = {
} // .indices = NULL,
); // .palette = NULL
// }
// }
// );
errorOk(); // errorOk();
} }

View File

@@ -56,7 +56,7 @@ void cameraGetProjectionMatrix(camera_t *camera, mat4 dest) {
glm_mat4_identity(dest); glm_mat4_identity(dest);
glm_perspective( glm_perspective(
camera->perspective.fov, camera->perspective.fov,
(640.0f / 480.0f), SCREEN.aspect,
camera->nearClip, camera->nearClip,
camera->farClip, camera->farClip,
dest dest

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,6 +22,10 @@
display_t DISPLAY = { 0 }; display_t DISPLAY = { 0 };
texture_t PALETTE_TEXTURE;
texture_t UNCOMPRESSED_TEXTURE;
texture_t COMPRESSED_TEXTURE;
errorret_t displayInit(void) { errorret_t displayInit(void) {
memoryZero(&DISPLAY, sizeof(DISPLAY)); memoryZero(&DISPLAY, sizeof(DISPLAY));
@@ -36,6 +40,57 @@ errorret_t displayInit(void) {
errorChain(textInit()); errorChain(textInit());
errorChain(screenInit()); errorChain(screenInit());
// PALETTES[0].colors[0] = COLOR_RED;
// PALETTES[0].colors[1] = COLOR_GREEN;
// PALETTES[0].colors[2] = COLOR_BLUE;
// PALETTES[0].colors[3] = COLOR_WHITE;
// 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(
&UNCOMPRESSED_TEXTURE,
8, 8,
TEXTURE_FORMAT_RGBA,
(texturedata_t){
.rgbaColors = (color_t[]){
COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_WHITE, COLOR_MAGENTA, COLOR_CYAN, COLOR_YELLOW, COLOR_BLACK,
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
}
}
));
errorOk(); errorOk();
} }
@@ -55,31 +110,34 @@ errorret_t displayUpdate(void) {
SCREEN.background SCREEN.background
); );
errorChain(shaderBind(&SHADER_UNLIT));
camera_t camera; camera_t camera;
// cameraInitOrthographic(&camera); // cameraInitOrthographic(&camera);
// 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] = 10.0f; camera.lookat.position[0] = 3.0f;
camera.lookat.position[1] = 10.0f; camera.lookat.position[1] = 3.0f;
camera.lookat.position[2] = 10.0f; camera.lookat.position[2] = 3.0f;
mat4 proj, view, model; mat4 proj, view, model;
cameraGetProjectionMatrix(&camera, proj); cameraGetProjectionMatrix(&camera, proj);
cameraGetViewMatrix(&camera, view); cameraGetViewMatrix(&camera, view);
glm_mat4_identity(model); glm_mat4_identity(model);
errorChain(shaderBind(&SHADER_UNLIT));
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, &PALETTE_TEXTURE));
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, &UNCOMPRESSED_TEXTURE));
errorChain(spriteBatchPush( errorChain(spriteBatchPush(
NULL, 0.0f, 0.0f,
0.0f, 0.0f, 100, 100, COLOR_WHITE, 0, 0, 1, 1 1.0f, 1.0f,
COLOR_WHITE,
0.0f, 0.0f,
1.0f, 1.0f
)); ));
errorChain(spriteBatchFlush()); errorChain(spriteBatchFlush());

View File

@@ -56,6 +56,7 @@ errorret_t screenBind() {
// Screen mode backbuffer uses the full display size // Screen mode backbuffer uses the full display size
SCREEN.width = frameBufferGetWidth(FRAMEBUFFER_BOUND); SCREEN.width = frameBufferGetWidth(FRAMEBUFFER_BOUND);
SCREEN.height = frameBufferGetHeight(FRAMEBUFFER_BOUND); SCREEN.height = frameBufferGetHeight(FRAMEBUFFER_BOUND);
SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height;
// No needd for a framebuffer. // No needd for a framebuffer.
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC #ifdef DUSK_DISPLAY_SIZE_DYNAMIC

View File

@@ -32,6 +32,28 @@ errorret_t shaderSetMatrix(
errorOk(); errorOk();
} }
errorret_t shaderSetTexture(
shader_t *shader,
const char_t *name,
texture_t *texture
) {
assertNotNull(shader, "Shader cannot be null");
assertStrLenMin(name, 1, "Uniform name cannot be empty");
errorChain(shaderSetTexturePlatform(shader, name, texture));
errorOk();
}
// errorret_t shaderSetColor(
// shader_t *shader,
// const char_t *name,
// color_t color
// ) {
// assertNotNull(shader, "Shader cannot be null");
// assertStrLenMin(name, 1, "Uniform name cannot be empty");
// errorChain(shaderSetColorPlatform(shader, name, color));
// errorOk();
// }
errorret_t shaderDispose(shader_t *shader) { errorret_t shaderDispose(shader_t *shader) {
assertNotNull(shader, "Shader cannot be null"); assertNotNull(shader, "Shader cannot be null");
errorChain(shaderDisposePlatform(shader)); errorChain(shaderDisposePlatform(shader));

View File

@@ -71,6 +71,20 @@ errorret_t shaderSetTexture(
texture_t *texture texture_t *texture
); );
/**
* Sets a color uniform in the shader. This is platform dependant.
*
* @param shader Shader to set the color in
* @param name Name of the uniform to set
* @param color Color to set
* @return Error if failure, otherwise errorOk
*/
// errorret_t shaderSetColor(
// shader_t *shader,
// const char_t *name,
// color_t color
// );
/** /**
* Disposes of a shader. This is platform dependant. * Disposes of a shader. This is platform dependant.
* *

View File

@@ -11,6 +11,8 @@
#define SHADER_UNLIT_PROJECTION "u_Proj" #define SHADER_UNLIT_PROJECTION "u_Proj"
#define SHADER_UNLIT_VIEW "u_View" #define SHADER_UNLIT_VIEW "u_View"
#define SHADER_UNLIT_MODEL "u_Model" #define SHADER_UNLIT_MODEL "u_Model"
#define SHADER_UNLIT_TEXTURE "u_Texture"
// #define SHADER_UNLIT_COLOR "u_Color"
extern shaderdefinition_t SHADER_UNLIT_DEFINITION; extern shaderdefinition_t SHADER_UNLIT_DEFINITION;
static shader_t SHADER_UNLIT; static shader_t SHADER_UNLIT;

View File

@@ -25,7 +25,6 @@ errorret_t spriteBatchInit() {
} }
errorret_t spriteBatchPush( errorret_t spriteBatchPush(
texture_t *texture,
const float_t minX, const float_t minX,
const float_t minY, const float_t minY,
const float_t maxX, const float_t maxX,
@@ -37,7 +36,6 @@ errorret_t spriteBatchPush(
const float_t v1 const float_t v1
) { ) {
errorChain(spriteBatchPush3D( errorChain(spriteBatchPush3D(
texture,
(vec3){ minX, minY, 0 }, (vec3){ minX, minY, 0 },
(vec3){ maxX, maxY, 0 }, (vec3){ maxX, maxY, 0 },
color, color,
@@ -48,7 +46,6 @@ errorret_t spriteBatchPush(
} }
errorret_t spriteBatchPush3D( errorret_t spriteBatchPush3D(
texture_t *texture,
const vec3 min, const vec3 min,
const vec3 max, const vec3 max,
const color_t color, const color_t color,
@@ -56,12 +53,8 @@ errorret_t spriteBatchPush3D(
const vec2 uv1 const vec2 uv1
) { ) {
// Need to flush? // Need to flush?
if( if(SPRITEBATCH.spriteCount >= SPRITEBATCH_SPRITES_MAX) {
SPRITEBATCH.currentTexture != texture ||
SPRITEBATCH.spriteCount >= SPRITEBATCH_SPRITES_MAX
) {
errorChain(spriteBatchFlush()); errorChain(spriteBatchFlush());
SPRITEBATCH.currentTexture = texture;
} }
size_t vertexOffset = SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT; size_t vertexOffset = SPRITEBATCH.spriteCount * QUAD_VERTEX_COUNT;
@@ -75,7 +68,6 @@ errorret_t spriteBatchPush3D(
void spriteBatchClear() { void spriteBatchClear() {
SPRITEBATCH.spriteCount = 0; SPRITEBATCH.spriteCount = 0;
SPRITEBATCH.currentTexture = NULL;
} }
errorret_t spriteBatchFlush() { errorret_t spriteBatchFlush() {
@@ -85,7 +77,6 @@ errorret_t spriteBatchFlush() {
size_t vertexCount = QUAD_VERTEX_COUNT * SPRITEBATCH.spriteCount; size_t vertexCount = QUAD_VERTEX_COUNT * SPRITEBATCH.spriteCount;
errorChain(meshFlush(&SPRITEBATCH.mesh, 0, vertexCount)); errorChain(meshFlush(&SPRITEBATCH.mesh, 0, vertexCount));
errorChain(textureBind(SPRITEBATCH.currentTexture));
errorChain(meshDraw(&SPRITEBATCH.mesh, 0, vertexCount)); errorChain(meshDraw(&SPRITEBATCH.mesh, 0, vertexCount));
spriteBatchClear(); spriteBatchClear();
errorOk(); errorOk();

View File

@@ -7,16 +7,13 @@
#pragma once #pragma once
#include "display/mesh/quad.h" #include "display/mesh/quad.h"
#include "display/texture/texture.h"
#define SPRITEBATCH_SPRITES_MAX 1 #define SPRITEBATCH_SPRITES_MAX 16
#define SPRITEBATCH_VERTEX_COUNT (SPRITEBATCH_SPRITES_MAX * QUAD_VERTEX_COUNT) #define SPRITEBATCH_VERTEX_COUNT (SPRITEBATCH_SPRITES_MAX * QUAD_VERTEX_COUNT)
typedef struct { typedef struct {
mesh_t mesh; mesh_t mesh;
int32_t spriteCount; int32_t spriteCount;
texture_t *currentTexture;
} spritebatch_t; } spritebatch_t;
// Have to define these seperately because of alignment in certain platforms. // Have to define these seperately because of alignment in certain platforms.
@@ -39,7 +36,6 @@ errorret_t spriteBatchInit();
* Currently changing texture pointer will cause the buffer to flush but this is * Currently changing texture pointer will cause the buffer to flush but this is
* also likely to change in the future. * also likely to change in the future.
* *
* @param texture The texture to use for the sprite.
* @param minX The minimum x coordinate of the sprite. * @param minX The minimum x coordinate of the sprite.
* @param minY The minimum y coordinate of the sprite. * @param minY The minimum y coordinate of the sprite.
* @param maxX The maximum x coordinate of the sprite. * @param maxX The maximum x coordinate of the sprite.
@@ -52,7 +48,6 @@ errorret_t spriteBatchInit();
* @return An error code indicating success or failure. * @return An error code indicating success or failure.
*/ */
errorret_t spriteBatchPush( errorret_t spriteBatchPush(
texture_t *texture,
const float_t minX, const float_t minX,
const float_t minY, const float_t minY,
const float_t maxX, const float_t maxX,
@@ -68,7 +63,6 @@ errorret_t spriteBatchPush(
* Pushes a 3D sprite to the batch. This is like spriteBatchPush but takes * Pushes a 3D sprite to the batch. This is like spriteBatchPush but takes
* 3D coordinates instead of 2D. * 3D coordinates instead of 2D.
* *
* @param texture The texture to use for the sprite.
* @param min The minimum (x,y,z) coordinate of the sprite. * @param min The minimum (x,y,z) coordinate of the sprite.
* @param max The maximum (x,y,z) coordinate of the sprite. * @param max The maximum (x,y,z) coordinate of the sprite.
* @param color The color to tint the sprite with. * @param color The color to tint the sprite with.
@@ -77,7 +71,6 @@ errorret_t spriteBatchPush(
* @return An error code indicating success or failure. * @return An error code indicating success or failure.
*/ */
errorret_t spriteBatchPush3D( errorret_t spriteBatchPush3D(
texture_t *texture,
const vec3 min, const vec3 min,
const vec3 max, const vec3 max,
const color_t color, const color_t color,

View File

@@ -46,7 +46,7 @@ errorret_t textDrawChar(
tilesetTileGetUV(tileset, tileIndex, uv); tilesetTileGetUV(tileset, tileIndex, uv);
errorChain(spriteBatchPush( errorChain(spriteBatchPush(
texture, // texture,
x, y, x, y,
x + tileset->tileWidth, x + tileset->tileWidth,
y + tileset->tileHeight, y + tileset->tileHeight,

View File

@@ -8,4 +8,5 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC PUBLIC
tileset.c tileset.c
texture.c texture.c
palette.c
) )

View File

@@ -0,0 +1,10 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "palette.h"
palette_t PALETTES[PALETTE_COUNT];

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/color.h"
#define PALETTE_COLOR_COUNT 0xFF
#define PALETTE_COUNT 6
typedef struct {
color_t colors[PALETTE_COLOR_COUNT];
uint8_t count;
} palette_t;
extern palette_t PALETTES[PALETTE_COUNT];

View File

@@ -11,8 +11,6 @@
#include "util/math.h" #include "util/math.h"
#include "display/display.h" #include "display/display.h"
texture_t *TEXTURE_BOUND = NULL;
errorret_t textureInit( errorret_t textureInit(
texture_t *texture, texture_t *texture,
const int32_t width, const int32_t width,
@@ -25,6 +23,18 @@ errorret_t textureInit(
assertTrue(width == mathNextPowTwo(width), "Width must be a power of 2."); assertTrue(width == mathNextPowTwo(width), "Width must be a power of 2.");
assertTrue(height == mathNextPowTwo(height), "Height must be a power of 2."); assertTrue(height == mathNextPowTwo(height), "Height must be a power of 2.");
if(texture->format == TEXTURE_FORMAT_RGBA) {
assertNotNull(data.rgbaColors, "RGBA color data cannot be NULL");
} else if(texture->format == TEXTURE_FORMAT_PALETTE) {
assertNotNull(data.paletted.indices, "Palette indices cannot be NULL");
assertNotNull(data.paletted.palette, "Palette colors cannot be NULL");
assertTrue(
data.paletted.palette->count ==
mathNextPowTwo(data.paletted.palette->count),
"Palette color count must be a power of 2"
);
}
memoryZero(texture, sizeof(texture_t)); memoryZero(texture, sizeof(texture_t));
texture->width = width; texture->width = width;
texture->height = height; texture->height = height;
@@ -34,18 +44,9 @@ errorret_t textureInit(
errorOk(); errorOk();
} }
errorret_t textureBind(texture_t *texture) {
errorChain(textureBindPlatform(texture));
errorOk();
}
errorret_t textureDispose(texture_t *texture) { errorret_t textureDispose(texture_t *texture) {
assertNotNull(texture, "Texture cannot be NULL"); assertNotNull(texture, "Texture cannot be NULL");
if(TEXTURE_BOUND == texture) {
textureBind(NULL);
}
errorChain(textureDisposePlatform(texture)); errorChain(textureDisposePlatform(texture));
errorOk(); errorOk();
} }

View File

@@ -7,15 +7,12 @@
#pragma once #pragma once
#include "error/error.h" #include "error/error.h"
#include "display/color.h" #include "display/texture/palette.h"
#include "display/texture/textureplatform.h" #include "display/texture/textureplatform.h"
#ifndef textureInitPlatform #ifndef textureInitPlatform
#error "textureInitPlatform should not be defined." #error "textureInitPlatform should not be defined."
#endif #endif
#ifndef textureBindPlatform
#error "textureBindPlatform should not be defined."
#endif
#ifndef textureDisposePlatform #ifndef textureDisposePlatform
#error "textureDisposePlatform should not be defined." #error "textureDisposePlatform should not be defined."
#endif #endif
@@ -24,12 +21,13 @@ typedef textureformatplatform_t textureformat_t;
typedef textureplatform_t texture_t; typedef textureplatform_t texture_t;
typedef union texturedata_u { typedef union texturedata_u {
uint8_t *paletteData; struct {
uint8_t *indices;
palette_t *palette;
} paletted;
color_t *rgbaColors; color_t *rgbaColors;
} texturedata_t; } texturedata_t;
extern texture_t *TEXTURE_BOUND;
/** /**
* Initializes a texture. * Initializes a texture.
* *
@@ -47,13 +45,6 @@ errorret_t textureInit(
const texturedata_t data const texturedata_t data
); );
/**
* Binds a texture for rendering. Providing NULL will unbind any texture.
*
* @param texture The texture to bind.
*/
errorret_t textureBind(texture_t *texture);
/** /**
* Disposes a texture. * Disposes a texture.
* *

View File

@@ -176,7 +176,7 @@ void mapUpdate() {
void mapRender() { void mapRender() {
if(!mapIsLoaded()) return; if(!mapIsLoaded()) return;
textureBind(NULL); // textureBind(NULL);
for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) { for(chunkindex_t i = 0; i < MAP_CHUNK_COUNT; i++) {
mapChunkRender(&MAP.chunks[i]); mapChunkRender(&MAP.chunks[i]);
} }

View File

@@ -32,32 +32,20 @@ int moduleSpriteBatchClear(lua_State *L) {
int moduleSpriteBatchPush(lua_State *L) { int moduleSpriteBatchPush(lua_State *L) {
assertNotNull(L, "Lua state is null"); assertNotNull(L, "Lua state is null");
// Texture pointer or Nil for no texture
if(!lua_isuserdata(L, 1) && !lua_isnil(L, 1)) {
return luaL_error(L, "First argument must be a texture or nil");
}
// If texture is not nil, check it's a texture userdata
texture_t *tex = NULL;
if(lua_isuserdata(L, 1)) {
tex = (texture_t *)luaL_checkudata(L, 1, "texture_mt");
assertNotNull(tex, "Texture pointer cannot be NULL");
}
// MinX, MinY, MaxX, MaxY // MinX, MinY, MaxX, MaxY
if( if(
!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4) || !lua_isnumber(L, 1) || !lua_isnumber(L, 2) || !lua_isnumber(L, 3) ||
!lua_isnumber(L, 5) !lua_isnumber(L, 4)
) { ) {
return luaL_error(L, "Sprite coordinates must be numbers"); return luaL_error(L, "Sprite coordinates must be numbers");
} }
// Color (struct) or nil for white // Color (struct) or nil for white
color_t *color = NULL; color_t *color = NULL;
if(lua_gettop(L) < 6 || lua_isnil(L, 6)) { if(lua_gettop(L) < 5 || lua_isnil(L, 5)) {
// Allow NULL // Allow NULL
} else if(lua_isuserdata(L, 6)) { } else if(lua_isuserdata(L, 5)) {
color = (color_t*)luaL_checkudata(L, 6, "color_mt"); color = (color_t*)luaL_checkudata(L, 5, "color_mt");
} else { } else {
return luaL_error(L, "Sprite color must be a color struct or nil"); return luaL_error(L, "Sprite color must be a color struct or nil");
} }
@@ -68,31 +56,30 @@ int moduleSpriteBatchPush(lua_State *L) {
float_t u1 = 1.0f; float_t u1 = 1.0f;
float_t v1 = 1.0f; float_t v1 = 1.0f;
if(lua_gettop(L) >= 8) { if(lua_gettop(L) >= 7) {
if(!lua_isnumber(L, 7) || !lua_isnumber(L, 8)) { if(!lua_isnumber(L, 6) || !lua_isnumber(L, 7)) {
return luaL_error(L, "Sprite UV min coordinates must be numbers"); return luaL_error(L, "Sprite UV min coordinates must be numbers");
} }
u0 = (float_t)lua_tonumber(L, 7); u0 = (float_t)lua_tonumber(L, 6);
v0 = (float_t)lua_tonumber(L, 8); v0 = (float_t)lua_tonumber(L, 7);
} }
if(lua_gettop(L) >= 10) { if(lua_gettop(L) >= 9) {
if(!lua_isnumber(L, 9) || !lua_isnumber(L, 10)) { if(!lua_isnumber(L, 8) || !lua_isnumber(L, 9)) {
return luaL_error(L, "Sprite UV max coordinates must be numbers"); return luaL_error(L, "Sprite UV max coordinates must be numbers");
} }
u1 = (float_t)lua_tonumber(L, 9); u1 = (float_t)lua_tonumber(L, 8);
v1 = (float_t)lua_tonumber(L, 10); v1 = (float_t)lua_tonumber(L, 9);
} }
float_t minX = (float_t)lua_tonumber(L, 2); float_t minX = (float_t)lua_tonumber(L, 1);
float_t minY = (float_t)lua_tonumber(L, 3); float_t minY = (float_t)lua_tonumber(L, 2);
float_t maxX = (float_t)lua_tonumber(L, 4); float_t maxX = (float_t)lua_tonumber(L, 3);
float_t maxY = (float_t)lua_tonumber(L, 5); float_t maxY = (float_t)lua_tonumber(L, 4);
errorret_t ret = spriteBatchPush( errorret_t ret = spriteBatchPush(
tex,
minX, minX,
minY, minY,
maxX, maxX,

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

@@ -9,18 +9,26 @@
errorret_t displayOpenGLInit(void) { errorret_t displayOpenGLInit(void) {
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
// glDisable(GL_LIGHTING);// PSP defaults this on?
// glShadeModel(GL_SMOOTH); // Fixes color on PSP?
errorChain(errorGLCheck()); errorChain(errorGLCheck());
#if DUSK_OPENGL_LEGACY
glDisable(GL_LIGHTING);// PSP defaults this on?
errorChain(errorGLCheck());
glShadeModel(GL_SMOOTH); // Fixes color on PSP?
errorChain(errorGLCheck());
#endif
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
errorChain(errorGLCheck());
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);
errorChain(errorGLCheck());
glClearDepth(1.0f); glClearDepth(1.0f);
errorChain(errorGLCheck()); errorChain(errorGLCheck());
glEnable(GL_BLEND); glEnable(GL_BLEND);
errorChain(errorGLCheck());
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPixelStorei(GL_PACK_ALIGNMENT, 1); errorChain(errorGLCheck());
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
errorChain(errorGLCheck()); errorChain(errorGLCheck());

View File

@@ -27,7 +27,9 @@ errorret_t meshInitGL(
#ifdef DUSK_OPENGL_LEGACY #ifdef DUSK_OPENGL_LEGACY
// Nothing needed. // Nothing needed.
glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_COLOR_ARRAY);
errorChain(errorGLCheck());
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
errorChain(errorGLCheck());
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);
errorChain(errorGLCheck()); errorChain(errorGLCheck());
#else #else
@@ -139,13 +141,13 @@ errorret_t meshDrawGL(
MESH_VERTEX_UV_SIZE, MESH_VERTEX_UV_SIZE,
GL_FLOAT, GL_FLOAT,
stride, stride,
(const GLvoid*)&mesh->vertices[offset].uv (const GLvoid*)&mesh->vertices[offset].uv[0]
); );
glVertexPointer( glVertexPointer(
MESH_VERTEX_POS_SIZE, MESH_VERTEX_POS_SIZE,
GL_FLOAT, GL_FLOAT,
stride, stride,
(const GLvoid*)&mesh->vertices[offset].pos (const GLvoid*)&mesh->vertices[offset].pos[0]
); );
// Shader may have model matrix here // Shader may have model matrix here
@@ -153,7 +155,8 @@ errorret_t meshDrawGL(
errorChain(shaderLegacyMatrixUpdate()); errorChain(shaderLegacyMatrixUpdate());
#endif #endif
glDrawArrays(mesh->primitiveType, offset, count); // glDrawArrays(mesh->primitiveType, offset, count);
glDrawArrays(mesh->primitiveType, 0, count);
errorChain(errorGLCheck()); errorChain(errorGLCheck());
#else #else
// Modern VAO/VBO rendering // Modern VAO/VBO rendering
@@ -181,5 +184,6 @@ errorret_t meshDisposeGL(meshgl_t *mesh) {
glDeleteVertexArrays(1, &mesh->vaoId); glDeleteVertexArrays(1, &mesh->vaoId);
errorChain(errorGLCheck()); errorChain(errorGLCheck());
#endif #endif
errorOk(); errorOk();
} }

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();
@@ -203,6 +208,41 @@ errorret_t shaderSetMatrixGL(
errorOk(); errorOk();
} }
errorret_t shaderSetTextureGL(
shadergl_t *shader,
const char_t *name,
texture_t *texture
) {
assertNotNull(shader, "Shader cannot be null");
assertStrLenMin(name, 1, "Uniform name cannot be empty");
#ifdef DUSK_OPENGL_LEGACY
assertStringEqual(
name,
SHADER_UNLIT_TEXTURE,
"Only one texture supported in legacy opengl."
);
if(texture == NULL) {
glDisable(GL_TEXTURE_2D);
errorChain(errorGLCheck());
errorOk();
}
glEnable(GL_TEXTURE_2D);
errorChain(errorGLCheck());
glBindTexture(GL_TEXTURE_2D, texture->id);
errorChain(errorGLCheck());
#else
if(shader->setTexture == NULL) {
assertUnreachable("Shader does not support setting textures.");
}
errorChain(shader->setTexture(shader, name, texture));
#endif
errorOk();
}
errorret_t shaderBindGL(shadergl_t *shader) { errorret_t shaderBindGL(shadergl_t *shader) {
#ifdef DUSK_OPENGL_LEGACY #ifdef DUSK_OPENGL_LEGACY

View File

@@ -7,29 +7,37 @@
#pragma once #pragma once
#include "error/errorgl.h" #include "error/errorgl.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;
@@ -91,6 +99,34 @@ errorret_t shaderSetMatrixGL(
mat4 matrix mat4 matrix
); );
/**
* Sets a color uniform parameter in the shader.
*
* @param shader The shader to update.
* @param name The name of the uniform parameter.
* @param color The color data to set.
* @return An errorret_t indicating success or failure.
*/
errorret_t shaderSetTextureGL(
shadergl_t *shader,
const char_t *name,
texture_t *texture
);
/**
* Sets a color uniform parameter in the shader.
*
* @param shader The shader to update.
* @param name The name of the uniform parameter.
* @param color The color data to set.
* @return An errorret_t indicating success or failure.
*/
// errorret_t shaderSetColorGL(
// shadergl_t *shader,
// const char_t *name,
// color_t color
// );
/** /**
* Disposes of a shader, freeing any associated resources. * Disposes of a shader, freeing any associated resources.
* *

View File

@@ -14,5 +14,6 @@ typedef shaderdefinitiongl_t shaderdefinitionplatform_t;
#define shaderInitPlatform shaderInitGL #define shaderInitPlatform shaderInitGL
#define shaderBindPlatform shaderBindGL #define shaderBindPlatform shaderBindGL
#define shaderSetMatrixPlatform shaderSetMatrixGL #define shaderSetMatrixPlatform shaderSetMatrixGL
// #define shaderSetTexturePlatform shaderSetTextureGL #define shaderSetTexturePlatform shaderSetTextureGL
// #define shaderSetColorPlatform shaderSetColorGL
#define shaderDisposePlatform shaderDisposeGL #define shaderDisposePlatform shaderDisposeGL

View File

@@ -6,26 +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 aPos;\n" "#version 300 es\n"
"uniform mat4 u_Proj;\n" "precision mediump float;\n"
"uniform mat4 u_View;\n" // Attributes
"uniform mat4 u_Model;\n" "layout(location = 0) in vec3 a_Pos;\n"
"void main() {\n" "layout(location = 1) in vec2 a_TexCoord;\n"
" gl_Position = u_Proj * u_View * u_Model * vec4(aPos, 1.0);\n" "layout(location = 2) in vec4 a_Color;\n"
"}\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",
#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
"out vec4 FragColor;\n" "#version 300 es\n"
"void main() {\n" "precision mediump float;\n"
" FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" // Uniforms
"}\n" "uniform sampler2D u_Texture;\n"
"uniform int u_TextureType;\n"
"uniform vec4 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"
" 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

@@ -8,6 +8,7 @@
#include "display/texture/texture.h" #include "display/texture/texture.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "error/errorgl.h" #include "error/errorgl.h"
#include "util/memory.h"
errorret_t textureInitGL( errorret_t textureInitGL(
texturegl_t *texture, texturegl_t *texture,
@@ -17,32 +18,49 @@ errorret_t textureInitGL(
const texturedata_t data const texturedata_t data
) { ) {
glGenTextures(1, &texture->id); glGenTextures(1, &texture->id);
errorChain(errorGLCheck());
glBindTexture(GL_TEXTURE_2D, texture->id); glBindTexture(GL_TEXTURE_2D, texture->id);
errorChain(errorGLCheck()); errorChain(errorGLCheck());
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());
break; break;
case TEXTURE_FORMAT_PALETTE: case TEXTURE_FORMAT_PALETTE:
assertNotNull(data.paletteData, "Palette texture data cannot be NULL"); texture->palette = data.paletted.palette;
glTexImage2D( assertTrue(
GL_TEXTURE_2D, texture->palette == &PALETTES[0],
0, GL_COLOR_INDEX8_EXT, "Only the first palette is supported in legacy opengl."
width, height,
0, GL_COLOR_INDEX8_EXT,
GL_UNSIGNED_BYTE, (void*)data.paletteData
); );
errorChain(errorGLCheck());
// glColorTableEXT( #ifdef DUSK_OPENGL_LEGACY
// GL_TEXTURE_2D, GL_RGBA, data.palette.palette->colorCount, GL_RGBA, glColorTableEXT(
// GL_UNSIGNED_BYTE, (const void*)data.palette.palette->colors GL_TEXTURE_2D, GL_RGBA, texture->palette->count, GL_RGBA,
// ); GL_UNSIGNED_BYTE, (const void*)texture->palette->colors
);
errorChain(errorGLCheck());
glTexImage2D(
GL_TEXTURE_2D,
0, GL_COLOR_INDEX8_EXT,
width, height,
0, GL_COLOR_INDEX8_EXT,
GL_UNSIGNED_BYTE, (void*)data.paletted.indices
);
errorChain(errorGLCheck());
#else
// For modern systems we send to only the R channel and the shader does
// the rest.
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RED, width, height, 0,
GL_RED, GL_UNSIGNED_BYTE, (void*)data.paletted.indices
);
errorChain(errorGLCheck());
#endif
break; break;
default: default:
@@ -52,10 +70,17 @@ errorret_t textureInitGL(
errorChain(errorGLCheck()); errorChain(errorGLCheck());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
errorChain(errorGLCheck());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
errorChain(errorGLCheck());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
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());
@@ -63,24 +88,12 @@ errorret_t textureInitGL(
errorOk(); errorOk();
} }
errorret_t textureBindGL(texturegl_t *texture) {
if(texture == NULL) {
glBindTexture(GL_TEXTURE_2D, 0);
errorChain(errorGLCheck());
errorOk();
}
assertTrue(texture->id != 0, "Texture ID must be valid");
glBindTexture(GL_TEXTURE_2D, texture->id);
errorChain(errorGLCheck());
errorOk();
}
errorret_t textureDisposeGL(texturegl_t *texture) { errorret_t textureDisposeGL(texturegl_t *texture) {
assertNotNull(texture, "Texture cannot be NULL"); assertNotNull(texture, "Texture cannot be NULL");
assertTrue(texture->id != 0, "Texture ID must be valid"); assertTrue(texture->id != 0, "Texture ID must be valid");
glDeleteTextures(1, &texture->id); glDeleteTextures(1, &texture->id);
errorChain(errorGLCheck()); errorChain(errorGLCheck());
errorOk(); errorOk();
} }

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 {
@@ -20,6 +21,10 @@ typedef struct {
textureformatgl_t format; textureformatgl_t format;
int32_t width; int32_t width;
int32_t height; int32_t height;
union {
palette_t *palette;
};
} texturegl_t; } texturegl_t;
/** /**
@@ -40,14 +45,6 @@ errorret_t textureInitGL(
const texturedata_t data const texturedata_t data
); );
/**
* Binds a texture for rendering. Providing NULL will unbind any texture.
*
* @param texture The texture to bind.
* @return An error if the texture failed to bind, otherwise success.
*/
errorret_t textureBindGL(texturegl_t *texture);
/** /**
* Disposes a texture. * Disposes a texture.
* *

View File

@@ -12,5 +12,4 @@ typedef textureformatgl_t textureformatplatform_t;
typedef texturegl_t textureplatform_t; typedef texturegl_t textureplatform_t;
#define textureInitPlatform textureInitGL #define textureInitPlatform textureInitGL
#define textureBindPlatform textureBindGL
#define textureDisposePlatform textureDisposeGL #define textureDisposePlatform textureDisposeGL

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);
} }

View File

@@ -21,11 +21,9 @@ errorret_t displaySDL2Init(void) {
// Set OpenGL attributes (Needs to be done now or later?) // Set OpenGL attributes (Needs to be done now or later?)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
// SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
// SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
#ifdef DUSK_OPENGL_LEGACY #ifdef DUSK_OPENGL_LEGACY
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); // SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
#else #else
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
@@ -54,6 +52,7 @@ errorret_t displaySDL2Init(void) {
errorChain(errorGLCheck()); errorChain(errorGLCheck());
SDL_GL_SetSwapInterval(1); SDL_GL_SetSwapInterval(1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
errorChain(errorGLCheck()); errorChain(errorGLCheck());
errorChain(displayOpenGLInit()); errorChain(displayOpenGLInit());
@@ -91,9 +90,8 @@ errorret_t displaySDL2Update(void) {
} }
SDL_GL_MakeCurrent(DISPLAY.window, DISPLAY.glContext); SDL_GL_MakeCurrent(DISPLAY.window, DISPLAY.glContext);
errorChain(errorGLCheck());
// errorChain(shaderPaletteTextureBindGL(&testShader)); // errorChain(shaderPaletteTextureBindGL(&testShader));
errorOk(); errorOk();
} }