Compare commits

..

1 Commits

Author SHA1 Message Date
71c5756e71 Prog on knulli 2026-03-16 11:45:36 -05:00
83 changed files with 607 additions and 2485 deletions

View File

@@ -1,4 +1,5 @@
name: Build Dusk name: Build Dusk
on: on:
push: push:
branches: branches:
@@ -6,6 +7,7 @@ on:
pull_request: pull_request:
branches: branches:
- main - main
jobs: jobs:
run-tests: run-tests:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -53,26 +55,6 @@ 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:
@@ -92,7 +74,6 @@ 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
@@ -114,4 +95,3 @@ jobs:
with: with:
name: dusk-wii name: dusk-wii
path: ./git-artifcats/Dusk path: ./git-artifcats/Dusk
if-no-files-found: error

View File

@@ -42,7 +42,7 @@ file(MAKE_DIRECTORY ${DUSK_TEMP_DIR})
file(MAKE_DIRECTORY ${DUSK_BUILT_ASSETS_DIR}) file(MAKE_DIRECTORY ${DUSK_BUILT_ASSETS_DIR})
# Required build packages # Required build packages
find_package(Python3 COMPONENTS Interpreter REQUIRED) find_package(Python3 REQUIRED COMPONENTS Interpreter)
# Init Project. # Init Project.
project(${DUSK_LIBRARY_TARGET_NAME} project(${DUSK_LIBRARY_TARGET_NAME}

View File

@@ -192,7 +192,7 @@ function sceneRender()
spriteBatchPush( spriteBatchPush(
nil, nil,
x, y, x + 32, y + 32, x, y, x + 32, y + 32,
colorWhite() colorBlue()
) )
-- Update mouse position -- Update mouse position

View File

@@ -1,17 +0,0 @@
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

@@ -1,20 +0,0 @@
# 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,43 +1,17 @@
# 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)
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) find_path(LIBZIP_INCLUDE_DIR NAMES zip.h)
endif()
mark_as_advanced(LIBZIP_INCLUDE_DIR) mark_as_advanced(LIBZIP_INCLUDE_DIR)
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) find_library(LIBZIP_LIBRARY NAMES zip)
endif()
mark_as_advanced(LIBZIP_LIBRARY) mark_as_advanced(LIBZIP_LIBRARY)
if(LIBZIP_LIBRARY)
get_filename_component(_libzip_libdir ${LIBZIP_LIBRARY} DIRECTORY) get_filename_component(_libzip_libdir ${LIBZIP_LIBRARY} DIRECTORY)
endif()
if(NOT _libzip_pkgcfg AND LIBZIP_ROOT)
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 find_file(_libzip_pkgcfg libzip.pc
HINTS ${_libzip_libdir} ${LIBZIP_INCLUDE_DIR}/.. HINTS ${_libzip_libdir} ${LIBZIP_INCLUDE_DIR}/..
PATH_SUFFIXES pkgconfig lib/pkgconfig libdata/pkgconfig PATH_SUFFIXES pkgconfig lib/pkgconfig libdata/pkgconfig
NO_DEFAULT_PATH NO_DEFAULT_PATH
) )
endif()
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
find_package_handle_standard_args( find_package_handle_standard_args(

View File

@@ -21,7 +21,26 @@ 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)
include(cmake/modules/CompileLua.cmake) # 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)
# Link libraries # Link libraries
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE

View File

@@ -1,45 +0,0 @@
# 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,7 +28,6 @@ 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

@@ -36,7 +36,6 @@ target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_PSP DUSK_PSP
DUSK_INPUT_GAMEPAD DUSK_INPUT_GAMEPAD
DUSK_PLATFORM_ENDIAN_LITTLE DUSK_PLATFORM_ENDIAN_LITTLE
DUSK_OPENGL_LEGACY
DUSK_DISPLAY_WIDTH=480 DUSK_DISPLAY_WIDTH=480
DUSK_DISPLAY_HEIGHT=272 DUSK_DISPLAY_HEIGHT=272
) )

View File

@@ -1,62 +0,0 @@
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,29 +0,0 @@
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 "")

View File

@@ -0,0 +1,16 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER aarch64-buildroot-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-buildroot-linux-gnu-g++)
set(CMAKE_SYSROOT /opt/aarch64-buildroot-linux-gnu_sdk-buildroot/aarch64-buildroot-linux-gnu/sysroot)
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
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_SYSROOT_DIR} ${CMAKE_SYSROOT})
set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_SYSROOT}/usr/lib/pkgconfig:${CMAKE_SYSROOT}/usr/share/pkgconfig")

View File

@@ -1,35 +1,40 @@
FROM debian:trixie FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive ENV DEBIAN_FRONTEND=noninteractive
WORKDIR /workdir WORKDIR /workdir
RUN dpkg --add-architecture arm64 && \ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
apt-get update && \ RUN apt-get -y update && apt-get -y install \
apt-get install -y --no-install-recommends \ python3-dotenv \
crossbuild-essential-arm64 \ bc \
ca-certificates \ bison \
pkg-config \ build-essential \
bzip2 \
bzr \
cmake \ cmake \
make \ cmake-curses-gui \
ninja-build \ cpio \
device-tree-compiler \
flex \
git \ git \
file \ imagemagick \
libncurses5-dev \
locales \
make \
nano \
p7zip-full \
rsync \
sharutils \
scons \
tree \
unzip \
vim \
wget \
zip \
python3 \ python3 \
python3-pip \ python3-pip \
python3-polib \ python3-polib \
python3-pil \ python3-pil \
python3-dotenv \ gcc-aarch64-linux-gnu \
python3-pyqt5 \ g++-aarch64-linux-gnu \
python3-opengl \ && apt clean
liblua5.4-dev:arm64 \ VOLUME ["/workdir"]
xz-utils:arm64 \ CMD ["/bin/bash"]
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/*

View File

@@ -1,64 +0,0 @@
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

View File

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

View File

@@ -1,23 +1,15 @@
#!/bin/bash #!/bin/bash
cmake -S . -B build-knulli -G Ninja \ git clone --depth 1 --branch SDL2 https://github.com/libsdl-org/SDL.git /tmp/SDL2 && \
-DDUSK_TARGET_SYSTEM=knulli \ cmake -S /tmp/SDL2 -B /tmp/SDL2/build \
-DCMAKE_TOOLCHAIN_FILE=./cmake/toolchains/aarch64-linux-gnu.cmake \ -DCMAKE_TOOLCHAIN_FILE=/workdir/toolchain-aarch64-buildroot.cmake \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_TYPE=Release \
cmake --build build-knulli -- -j$(nproc) -DCMAKE_INSTALL_PREFIX="$SYSROOT/usr" && \
cmake --build /tmp/SDL2/build -j"$(nproc)" && \
cmake --install /tmp/SDL2/build
# Copy necessary libs out cmake -S . \
mkdir -p ./build-knulli/dusk -B build-knulli \
cp ./build-knulli/Dusk ./build-knulli/dusk/Dusk -DDUSK_BUILD_TESTS=ON \
cp ./build-knulli/dusk.dsk ./build-knulli/dusk/dusk.dsk -DDUSK_TARGET_SYSTEM=linux \
echo '#!/bin/bash' > build-knulli/dusk/Dusk.sh -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/toolchain-aarch64-buildroot.cmake
echo 'cd "$(dirname "$(readlink -f "$0")")"' >> build-knulli/dusk/Dusk.sh cmake --build build-knulli -- -j$(nproc)
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-vita -f docker/vita/Dockerfile .
docker run --rm -v $(pwd):/workdir dusk-vita /bin/bash -c "./scripts/build-vita.sh"

View File

@@ -1,6 +0,0 @@
#!/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" OR DUSK_TARGET_SYSTEM STREQUAL "knulli" OR DUSK_TARGET_SYSTEM STREQUAL "vita") if(DUSK_TARGET_SYSTEM STREQUAL "linux")
add_subdirectory(dusklinux) add_subdirectory(dusklinux)
add_subdirectory(dusksdl2) add_subdirectory(dusksdl2)
add_subdirectory(duskgl) add_subdirectory(duskgl)

View File

@@ -7,7 +7,6 @@
#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
@@ -99,14 +98,4 @@
) { ) {
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,23 +104,6 @@
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.
* *
@@ -195,16 +178,6 @@
#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,47 @@
#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 = { .paletteData = assetData->palette
// .indices = NULL, }
// .palette = NULL );
// }
// } errorOk();
// );
// errorOk();
} }

View File

@@ -14,7 +14,6 @@ add_subdirectory(camera)
add_subdirectory(framebuffer) add_subdirectory(framebuffer)
add_subdirectory(mesh) add_subdirectory(mesh)
add_subdirectory(screen) add_subdirectory(screen)
add_subdirectory(shader)
add_subdirectory(spritebatch) add_subdirectory(spritebatch)
add_subdirectory(text) add_subdirectory(text)
add_subdirectory(texture) add_subdirectory(texture)

View File

@@ -45,63 +45,13 @@ void cameraInitOrthographic(camera_t *camera) {
camera->_2d.zoom = 1.0f; camera->_2d.zoom = 1.0f;
} }
void cameraGetProjectionMatrix(camera_t *camera, mat4 dest) { void cameraPushMatrix(camera_t *camera) {
assertNotNull(camera, "Not a camera component"); assertNotNull(camera, "Invalid camera");
assertNotNull(dest, "Destination matrix must not be null"); cameraPushMatrixPlatform(camera);
if(
camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE ||
camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED
) {
glm_mat4_identity(dest);
glm_perspective(
camera->perspective.fov,
SCREEN.aspect,
camera->nearClip,
camera->farClip,
dest
);
if(camera->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED) {
dest[1][1] *= -1.0f;
}
} else if(camera->projType == CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
glm_mat4_identity(dest);
glm_ortho(
camera->orthographic.left,
camera->orthographic.right,
camera->orthographic.top,
camera->orthographic.bottom,
camera->nearClip,
camera->farClip,
dest
);
}
} }
void cameraGetViewMatrix(camera_t *camera, mat4 dest) { void cameraPopMatrix(void) {
assertNotNull(camera, "Not a camera component"); #ifdef cameraPopMatrixPlatform
assertNotNull(dest, "Destination matrix must not be null"); cameraPopMatrixPlatform();
#endif
if(camera->viewType == CAMERA_VIEW_TYPE_MATRIX) {
glm_mat4_copy(camera->view, dest);
} else if(camera->viewType == CAMERA_VIEW_TYPE_LOOKAT) {
glm_mat4_identity(dest);
glm_lookat(
camera->lookat.position,
camera->lookat.target,
camera->lookat.up,
dest
);
} else if(camera->viewType == CAMERA_VIEW_TYPE_2D) {
glm_mat4_identity(dest);
glm_lookat(
(vec3){ camera->_2d.position[0], camera->_2d.position[1], 0.5f },
(vec3){ camera->_2d.position[0], camera->_2d.position[1], 0.0f },
(vec3){ 0.0f, 1.0f, 0.0f },
dest
);
} else if(camera->viewType == CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT) {
assertUnreachable("LOOKAT_PIXEL_PERFECT view type is not implemented yet");
}
} }

View File

@@ -86,17 +86,13 @@ void cameraInitPerspective(camera_t *camera);
void cameraInitOrthographic(camera_t *camera); void cameraInitOrthographic(camera_t *camera);
/** /**
* Gets the projection matrix for a camera. * Pushes the camera's view matrix onto the matrix stack.
* *
* @param camera Camera to get the projection matrix for * @param id The ID of the camera entity to use.
* @param dest Matrix to store the projection matrix in
*/ */
void cameraGetProjectionMatrix(camera_t *camera, mat4 dest); void cameraPushMatrix(camera_t *camera);
/** /**
* Gets the view matrix for a camera. * Pops the camera's view matrix off the matrix stack.
*
* @param camera Camera to get the view matrix for
* @param dest Matrix to store the view matrix in
*/ */
void cameraGetViewMatrix(camera_t *camera, mat4 dest); void cameraPopMatrix(void);

View File

@@ -21,4 +21,3 @@ 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
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
salmon 1 0.5 0.5 1

View File

@@ -17,15 +17,9 @@
#include "util/memory.h" #include "util/memory.h"
#include "util/string.h" #include "util/string.h"
#include "asset/asset.h" #include "asset/asset.h"
#include "display/shader/shaderunlit.h"
#include "time/time.h"
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));
@@ -33,64 +27,12 @@ errorret_t displayInit(void) {
errorChain(displayPlatformInit()); errorChain(displayPlatformInit());
#endif #endif
errorChain(shaderInit(&SHADER_UNLIT, &SHADER_UNLIT_DEFINITION));
errorChain(quadInit()); errorChain(quadInit());
errorChain(frameBufferInitBackBuffer()); errorChain(frameBufferInitBackBuffer());
errorChain(spriteBatchInit()); errorChain(spriteBatchInit());
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();
} }
@@ -104,47 +46,16 @@ errorret_t displayUpdate(void) {
errorChain(frameBufferBind(NULL)); errorChain(frameBufferBind(NULL));
// Bind screen and render scene // Bind screen and render scene
errorChain(screenBind()); screenBind();
frameBufferClear( frameBufferClear(
FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH, FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH,
SCREEN.background SCREEN.background
); );
camera_t camera; errorChain(sceneRender());
// cameraInitOrthographic(&camera);
// camera.orthographic.left = 0.0f;
// camera.orthographic.right = SCREEN.width;
// camera.orthographic.top = SCREEN.height;
// camera.orthographic.bottom = 0.0f;
cameraInitPerspective(&camera);
camera.lookat.position[0] = 3.0f;
camera.lookat.position[1] = 3.0f;
camera.lookat.position[2] = 3.0f;
mat4 proj, view, model;
cameraGetProjectionMatrix(&camera, proj);
cameraGetViewMatrix(&camera, view);
glm_mat4_identity(model);
errorChain(shaderBind(&SHADER_UNLIT));
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_PROJECTION, proj));
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, view));
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(
0.0f, 0.0f,
1.0f, 1.0f,
COLOR_WHITE,
0.0f, 0.0f,
1.0f, 1.0f
));
errorChain(spriteBatchFlush());
// errorCatch(errorPrint(sceneRender()));
// Render UI // Render UI
// uiRender(); uiRender();
// Finish up // Finish up
screenUnbind(); screenUnbind();
@@ -158,7 +69,6 @@ errorret_t displayUpdate(void) {
} }
errorret_t displayDispose(void) { errorret_t displayDispose(void) {
errorChain(shaderDispose(&SHADER_UNLIT));
errorChain(spriteBatchDispose()); errorChain(spriteBatchDispose());
screenDispose(); screenDispose();
errorChain(textDispose()); errorChain(textDispose());

View File

@@ -25,29 +25,6 @@ errorret_t meshInit(
errorOk(); errorOk();
} }
errorret_t meshFlush(
mesh_t *mesh,
const int32_t vertexOffset,
const int32_t vertexCount
) {
#ifdef meshFlushPlatform
assertNotNull(mesh, "Mesh cannot be NULL");
assertTrue(vertexOffset >= 0, "Vertex offset must be non-negative.");
assertTrue(vertexCount == -1 || vertexCount > 0, "Vertex count incorrect.");
int32_t vertCount = meshGetVertexCount(mesh);
assertTrue(vertexOffset < (vertCount - 1), "Need at least one vert to draw");
int32_t drawCount = vertexCount;
if(vertexCount == -1) {
drawCount = vertCount - vertexOffset;
}
errorChain(meshFlushPlatform(mesh, vertexOffset, vertexCount));
#endif
errorOk();
}
errorret_t meshDraw( errorret_t meshDraw(
const mesh_t *mesh, const mesh_t *mesh,
const int32_t vertexOffset, const int32_t vertexOffset,
@@ -55,7 +32,7 @@ errorret_t meshDraw(
) { ) {
assertNotNull(mesh, "Mesh cannot be NULL"); assertNotNull(mesh, "Mesh cannot be NULL");
assertTrue(vertexOffset >= 0, "Vertex offset must be non-negative"); assertTrue(vertexOffset >= 0, "Vertex offset must be non-negative");
assertTrue(vertexCount == -1 || vertexCount > 0, "Incorrect vert count"); assertTrue(vertexCount >= -1, "Vertex count must be -1 or non-negative");
int32_t vertDrawCount = vertexCount; int32_t vertDrawCount = vertexCount;
if(vertexCount == -1) { if(vertexCount == -1) {

View File

@@ -40,22 +40,6 @@ errorret_t meshInit(
const meshvertex_t *vertices const meshvertex_t *vertices
); );
/**
* Instructs the mesh to flush the vertices to the GPU. This is surprisingly
* only really necessary on modern devices, as we tend to let older devices
* read the vertices from the main memory directly.
*
* @param mesh Mesh to flush the vertices for.
* @param vertexOffset Start vertex to flush.
* @param vertexCount Count of vertices to flush, set to -1 for all.
* @return Error state.
*/
errorret_t meshFlush(
mesh_t *mesh,
const int32_t vertexOffset,
const int32_t vertexCount
);
/** /**
* Draws a mesh. * Draws a mesh.
* *

View File

@@ -9,7 +9,6 @@
#include "assert/assert.h" #include "assert/assert.h"
#include "util/memory.h" #include "util/memory.h"
#include "display/mesh/quad.h" #include "display/mesh/quad.h"
#include "display/shader/shaderunlit.h"
screen_t SCREEN; screen_t SCREEN;
@@ -45,23 +44,22 @@ errorret_t screenInit() {
#endif #endif
// Init screen to backbuffer mode by default // Init screen to backbuffer mode by default
errorChain(screenBind()); screenBind();
errorOk(); errorOk();
} }
errorret_t screenBind() { void screenBind() {
// Assume backbuffer is currently bound. // Assume backbuffer is currently bound.
switch(SCREEN.mode) { switch(SCREEN.mode) {
case SCREEN_MODE_BACKBUFFER: { case SCREEN_MODE_BACKBUFFER: {
// 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
if(SCREEN.framebufferReady) { if(SCREEN.framebufferReady) {
errorChain(frameBufferDispose(&SCREEN.framebuffer)); frameBufferDispose(&SCREEN.framebuffer);
SCREEN.framebufferReady = false; SCREEN.framebufferReady = false;
} }
#endif #endif
@@ -81,21 +79,19 @@ errorret_t screenBind() {
curFbHeight = frameBufferGetHeight(&SCREEN.framebuffer); curFbHeight = frameBufferGetHeight(&SCREEN.framebuffer);
if(curFbWidth == SCREEN.width && curFbHeight == SCREEN.height) { if(curFbWidth == SCREEN.width && curFbHeight == SCREEN.height) {
// Correct size, nothing to do. // Correct size, nothing to do.
errorChain(frameBufferBind(&SCREEN.framebuffer)); frameBufferBind(&SCREEN.framebuffer);
errorOk(); return;
} }
// Need a new framebuffer. // Need a new framebuffer.
errorChain(frameBufferDispose(&SCREEN.framebuffer)); frameBufferDispose(&SCREEN.framebuffer);
SCREEN.framebufferReady = false; SCREEN.framebufferReady = false;
} }
// Create new framebuffer // Create new framebuffer
errorChain(frameBufferInit( frameBufferInit(&SCREEN.framebuffer, SCREEN.width, SCREEN.height);
&SCREEN.framebuffer, SCREEN.width, SCREEN.height
));
SCREEN.framebufferReady = true; SCREEN.framebufferReady = true;
errorChain(frameBufferBind(&SCREEN.framebuffer)); frameBufferBind(&SCREEN.framebuffer);
break; break;
} }
@@ -113,10 +109,10 @@ errorret_t screenBind() {
SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height; SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height;
if(SCREEN.framebufferReady) { if(SCREEN.framebufferReady) {
errorChain(frameBufferDispose(&SCREEN.framebuffer)); frameBufferDispose(&SCREEN.framebuffer);
SCREEN.framebufferReady = false; SCREEN.framebufferReady = false;
} }
errorOk(); return;
} }
int32_t newFbWidth, newFbHeight; int32_t newFbWidth, newFbHeight;
@@ -140,26 +136,24 @@ errorret_t screenBind() {
SCREEN.width = newFbWidth; SCREEN.width = newFbWidth;
SCREEN.height = newFbHeight; SCREEN.height = newFbHeight;
SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height; SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height;
errorChain(frameBufferBind(&SCREEN.framebuffer)); frameBufferBind(&SCREEN.framebuffer);
errorOk(); return;
} }
// Need a new framebuffer. // Need a new framebuffer.
errorChain(frameBufferDispose(&SCREEN.framebuffer)); frameBufferDispose(&SCREEN.framebuffer);
SCREEN.framebufferReady = false; SCREEN.framebufferReady = false;
} }
// Create new framebuffer // Create new framebuffer
errorChain(frameBufferInit( frameBufferInit(&SCREEN.framebuffer, newFbWidth, newFbHeight);
&SCREEN.framebuffer, newFbWidth, newFbHeight
));
SCREEN.width = newFbWidth; SCREEN.width = newFbWidth;
SCREEN.height = newFbHeight; SCREEN.height = newFbHeight;
SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height; SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height;
SCREEN.framebufferReady = true; SCREEN.framebufferReady = true;
// Bind FB // Bind FB
errorChain(frameBufferBind(&SCREEN.framebuffer)); frameBufferBind(&SCREEN.framebuffer);
break; break;
} }
@@ -179,10 +173,10 @@ errorret_t screenBind() {
if(fbWidth == newFbWidth && fbHeight == newFbHeight) { if(fbWidth == newFbWidth && fbHeight == newFbHeight) {
// No need to use framebuffer. // No need to use framebuffer.
if(SCREEN.framebufferReady) { if(SCREEN.framebufferReady) {
errorChain(frameBufferDispose(&SCREEN.framebuffer)); frameBufferDispose(&SCREEN.framebuffer);
SCREEN.framebufferReady = false; SCREEN.framebufferReady = false;
} }
errorOk(); return;
} }
if(SCREEN.framebufferReady) { if(SCREEN.framebufferReady) {
@@ -191,21 +185,19 @@ errorret_t screenBind() {
curFbWidth = frameBufferGetWidth(&SCREEN.framebuffer); curFbWidth = frameBufferGetWidth(&SCREEN.framebuffer);
curFbHeight = frameBufferGetHeight(&SCREEN.framebuffer); curFbHeight = frameBufferGetHeight(&SCREEN.framebuffer);
if(curFbWidth == newFbWidth && curFbHeight == newFbHeight) { if(curFbWidth == newFbWidth && curFbHeight == newFbHeight) {
errorChain(frameBufferBind(&SCREEN.framebuffer)); frameBufferBind(&SCREEN.framebuffer);
errorOk(); return;
} }
// Need a new framebuffer. // Need a new framebuffer.
errorChain(frameBufferDispose(&SCREEN.framebuffer)); frameBufferDispose(&SCREEN.framebuffer);
SCREEN.framebufferReady = false; SCREEN.framebufferReady = false;
} }
// Create a new framebuffer. // Create a new framebuffer.
errorChain(frameBufferInit( frameBufferInit(&SCREEN.framebuffer, newFbWidth, newFbHeight);
&SCREEN.framebuffer, newFbWidth, newFbHeight
));
SCREEN.framebufferReady = true; SCREEN.framebufferReady = true;
errorChain(frameBufferBind(&SCREEN.framebuffer)); frameBufferBind(&SCREEN.framebuffer);
break; break;
} }
@@ -225,10 +217,10 @@ errorret_t screenBind() {
if(fbWidth == newFbWidth && fbHeight == newFbHeight) { if(fbWidth == newFbWidth && fbHeight == newFbHeight) {
// No need to use framebuffer. // No need to use framebuffer.
if(SCREEN.framebufferReady) { if(SCREEN.framebufferReady) {
errorChain(frameBufferDispose(&SCREEN.framebuffer)); frameBufferDispose(&SCREEN.framebuffer);
SCREEN.framebufferReady = false; SCREEN.framebufferReady = false;
} }
errorOk(); return;
} }
if(SCREEN.framebufferReady) { if(SCREEN.framebufferReady) {
@@ -237,21 +229,19 @@ errorret_t screenBind() {
curFbWidth = frameBufferGetWidth(&SCREEN.framebuffer); curFbWidth = frameBufferGetWidth(&SCREEN.framebuffer);
curFbHeight = frameBufferGetHeight(&SCREEN.framebuffer); curFbHeight = frameBufferGetHeight(&SCREEN.framebuffer);
if(curFbWidth == newFbWidth && curFbHeight == newFbHeight) { if(curFbWidth == newFbWidth && curFbHeight == newFbHeight) {
errorChain(frameBufferBind(&SCREEN.framebuffer)); frameBufferBind(&SCREEN.framebuffer);
errorOk(); return;
} }
// Need a new framebuffer. // Need a new framebuffer.
errorChain(frameBufferDispose(&SCREEN.framebuffer)); frameBufferDispose(&SCREEN.framebuffer);
SCREEN.framebufferReady = false; SCREEN.framebufferReady = false;
} }
// Create a new framebuffer. // Create a new framebuffer.
errorChain(frameBufferInit( frameBufferInit(&SCREEN.framebuffer, newFbWidth, newFbHeight);
&SCREEN.framebuffer, newFbWidth, newFbHeight
));
SCREEN.framebufferReady = true; SCREEN.framebufferReady = true;
errorChain(frameBufferBind(&SCREEN.framebuffer)); frameBufferBind(&SCREEN.framebuffer);
break; break;
} }
@@ -272,11 +262,9 @@ errorret_t screenBind() {
break; break;
} }
} }
errorOk();
} }
errorret_t screenUnbind() { void screenUnbind() {
switch(SCREEN.mode) { switch(SCREEN.mode) {
// Nothing to do here. // Nothing to do here.
case SCREEN_MODE_BACKBUFFER: case SCREEN_MODE_BACKBUFFER:
@@ -287,9 +275,7 @@ errorret_t screenUnbind() {
case SCREEN_MODE_FIXED_HEIGHT: case SCREEN_MODE_FIXED_HEIGHT:
case SCREEN_MODE_FIXED_SIZE: case SCREEN_MODE_FIXED_SIZE:
case SCREEN_MODE_FIXED_WIDTH: case SCREEN_MODE_FIXED_WIDTH:
if(SCREEN.framebufferReady) { if(SCREEN.framebufferReady) frameBufferBind(NULL);
errorChain(frameBufferBind(NULL));
}
break; break;
case SCREEN_MODE_FIXED_VIEWPORT_HEIGHT: case SCREEN_MODE_FIXED_VIEWPORT_HEIGHT:
@@ -300,19 +286,17 @@ errorret_t screenUnbind() {
assertUnreachable("Invalid screen mode."); assertUnreachable("Invalid screen mode.");
break; break;
} }
errorOk();
} }
errorret_t screenRender() { void screenRender() {
if(SCREEN.mode == SCREEN_MODE_BACKBUFFER) { if(SCREEN.mode == SCREEN_MODE_BACKBUFFER) {
errorOk(); return;
} }
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC #ifdef DUSK_DISPLAY_SIZE_DYNAMIC
if(SCREEN.mode == SCREEN_MODE_FIXED_VIEWPORT_HEIGHT) { if(SCREEN.mode == SCREEN_MODE_FIXED_VIEWPORT_HEIGHT) {
glViewport(0, 0, SCREEN.width, SCREEN.height); glViewport(0, 0, SCREEN.width, SCREEN.height);
errorOk(); return;
} }
if( if(
@@ -323,7 +307,7 @@ errorret_t screenRender() {
) { ) {
if(!SCREEN.framebufferReady) { if(!SCREEN.framebufferReady) {
// Nothing to do here. // Nothing to do here.
errorOk(); return;
} }
float_t bbWidth, bbHeight; float_t bbWidth, bbHeight;
@@ -372,34 +356,23 @@ errorret_t screenRender() {
FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH, FRAMEBUFFER_CLEAR_COLOR | FRAMEBUFFER_CLEAR_DEPTH,
COLOR_BLACK COLOR_BLACK
); );
cameraPushMatrix(&SCREEN.framebufferCamera);
textureBind(&SCREEN.framebuffer.texture);
meshDraw(&SCREEN.frameBufferMesh, 0, -1);
cameraPopMatrix();
shaderBind(&SHADER_UNLIT); return;
mat4 proj, view, model;
cameraGetProjectionMatrix(&SCREEN.framebufferCamera, proj);
cameraGetViewMatrix(&SCREEN.framebufferCamera, view);
glm_mat4_identity(model);
shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_PROJECTION, proj);
shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, view);
shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_MODEL, model);
// errorChain(textureBind(&SCREEN.framebuffer.texture));
errorChain(meshDraw(&SCREEN.frameBufferMesh, 0, -1));
errorOk();
}; };
#endif #endif
assertUnreachable("Invalid screen mode."); assertUnreachable("Invalid screen mode.");
errorThrow("Invalid screen mode.");
} }
errorret_t screenDispose() { void screenDispose() {
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC #ifdef DUSK_DISPLAY_SIZE_DYNAMIC
if(SCREEN.framebufferReady) { if(SCREEN.framebufferReady) {
errorChain(frameBufferDispose(&SCREEN.framebuffer)); frameBufferDispose(&SCREEN.framebuffer);
SCREEN.framebufferReady = false; SCREEN.framebufferReady = false;
} }
#endif #endif
errorOk();
} }

View File

@@ -90,28 +90,20 @@ errorret_t screenInit();
/** /**
* Binds the screen, this is done before rendering game content. * Binds the screen, this is done before rendering game content.
*
* @return Error code and state, if error occurs.
*/ */
errorret_t screenBind(); void screenBind();
/** /**
* Unbinds the screen, does nothing for now. * Unbinds the screen, does nothing for now.
*
* @return Error code and state, if error occurs.
*/ */
errorret_t screenUnbind(); void screenUnbind();
/** /**
* Renders the screen to the current framebuffer. * Renders the screen to the current framebuffer.
*
* @return Error code and state, if error occurs.
*/ */
errorret_t screenRender(); void screenRender();
/** /**
* Disposes the screen system. * Disposes the screen system.
*
* @return Error code and state, if error occurs.
*/ */
errorret_t screenDispose(); void screenDispose();

View File

@@ -1,10 +0,0 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
shader.c
)

View File

@@ -1,61 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "shader.h"
#include "assert/assert.h"
errorret_t shaderInit(shader_t *shader, const shaderdefinition_t *def) {
assertNotNull(shader, "Shader cannot be null");
errorChain(shaderInitPlatform(shader, def));
errorOk();
}
errorret_t shaderBind(shader_t *shader) {
assertNotNull(shader, "Shader cannot be null");
errorChain(shaderBindPlatform(shader));
errorOk();
}
errorret_t shaderSetMatrix(
shader_t *shader,
const char_t *name,
mat4 matrix
) {
assertNotNull(shader, "Shader cannot be null");
assertStrLenMin(name, 1, "Uniform name cannot be empty");
assertNotNull(matrix, "Matrix cannot be null");
errorChain(shaderSetMatrixPlatform(shader, name, matrix));
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) {
assertNotNull(shader, "Shader cannot be null");
errorChain(shaderDisposePlatform(shader));
errorOk();
}

View File

@@ -1,94 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "error/error.h"
#include "display/texture/texture.h"
#include "display/shader/shaderplatform.h"
#ifndef shaderInitPlatform
#error "shaderInitPlatform must be defined to use shader.h"
#endif
#ifndef shaderBindPlatform
#error "shaderBindPlatform must be defined to use shader.h"
#endif
#ifndef shaderSetMatrixPlatform
#error "shaderSetMatrixPlatform must be defined to use shader.h"
#endif
#ifndef shaderDisposePlatform
#error "shaderDisposePlatform must be defined to use shader.h"
#endif
typedef shaderplatform_t shader_t;
typedef shaderdefinitionplatform_t shaderdefinition_t;
/**
* Initializes a shader. This is platform dependant.
*
* @param shader Shader to initialize
* @param def Definition of the shader to initialize with.
* @return Error if failure, otherwise errorOk
*/
errorret_t shaderInit(shader_t *shader, const shaderdefinition_t *def);
/**
* Binds a shader. This is platform dependant.
*
* @param shader Shader to bind
* @return Error if failure, otherwise errorOk
*/
errorret_t shaderBind(shader_t *shader);
/**
* Sets a matrix uniform in the shader. This is platform dependant.
*
* @param shader Shader to set the matrix in
* @param name Name of the uniform to set
* @param matrix Matrix to set
* @return Error if failure, otherwise errorOk
*/
errorret_t shaderSetMatrix(
shader_t *shader,
const char_t *name,
mat4 matrix
);
/**
* Sets a texture uniform in the shader. This is platform dependant.
*
* @param shader Shader to set the texture in
* @param name Name of the uniform to set
* @param texture Texture to set
* @return Error if failure, otherwise errorOk
*/
errorret_t shaderSetTexture(
shader_t *shader,
const char_t *name,
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.
*
* @param shader Shader to dispose
* @return Error if failure, otherwise errorOk
*/
errorret_t shaderDispose(shader_t *shader);

View File

@@ -1,18 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "shader.h"
#define SHADER_UNLIT_PROJECTION "u_Proj"
#define SHADER_UNLIT_VIEW "u_View"
#define SHADER_UNLIT_MODEL "u_Model"
#define SHADER_UNLIT_TEXTURE "u_Texture"
// #define SHADER_UNLIT_COLOR "u_Color"
extern shaderdefinition_t SHADER_UNLIT_DEFINITION;
static shader_t SHADER_UNLIT;

View File

@@ -19,12 +19,13 @@ errorret_t spriteBatchInit() {
&SPRITEBATCH.mesh, &SPRITEBATCH.mesh,
QUAD_PRIMITIVE_TYPE, QUAD_PRIMITIVE_TYPE,
SPRITEBATCH_VERTEX_COUNT, SPRITEBATCH_VERTEX_COUNT,
SPRITEBATCH_VERTICES &SPRITEBATCH_VERTICES[0]
)); ));
errorOk(); errorOk();
} }
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,
@@ -36,6 +37,7 @@ 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,
@@ -46,6 +48,7 @@ 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,
@@ -53,8 +56,12 @@ errorret_t spriteBatchPush3D(
const vec2 uv1 const vec2 uv1
) { ) {
// Need to flush? // Need to flush?
if(SPRITEBATCH.spriteCount >= SPRITEBATCH_SPRITES_MAX) { if(
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;
@@ -68,6 +75,7 @@ errorret_t spriteBatchPush3D(
void spriteBatchClear() { void spriteBatchClear() {
SPRITEBATCH.spriteCount = 0; SPRITEBATCH.spriteCount = 0;
SPRITEBATCH.currentTexture = NULL;
} }
errorret_t spriteBatchFlush() { errorret_t spriteBatchFlush() {
@@ -75,9 +83,10 @@ errorret_t spriteBatchFlush() {
errorOk(); errorOk();
} }
size_t vertexCount = QUAD_VERTEX_COUNT * SPRITEBATCH.spriteCount; errorChain(textureBind(SPRITEBATCH.currentTexture));
errorChain(meshFlush(&SPRITEBATCH.mesh, 0, vertexCount)); errorChain(meshDraw(
errorChain(meshDraw(&SPRITEBATCH.mesh, 0, vertexCount)); &SPRITEBATCH.mesh, 0, QUAD_VERTEX_COUNT * SPRITEBATCH.spriteCount
));
spriteBatchClear(); spriteBatchClear();
errorOk(); errorOk();
} }

View File

@@ -7,13 +7,16 @@
#pragma once #pragma once
#include "display/mesh/quad.h" #include "display/mesh/quad.h"
#include "display/texture/texture.h"
#define SPRITEBATCH_SPRITES_MAX 16 #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.
@@ -36,6 +39,7 @@ 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.
@@ -48,6 +52,7 @@ 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,
@@ -63,6 +68,7 @@ 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.
@@ -71,6 +77,7 @@ 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,5 +8,4 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC PUBLIC
tileset.c tileset.c
texture.c texture.c
palette.c
) )

View File

@@ -1,10 +0,0 @@
/**
* 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

@@ -1,19 +0,0 @@
/**
* 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,6 +11,8 @@
#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,
@@ -23,18 +25,6 @@ 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;
@@ -44,9 +34,18 @@ 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,12 +7,15 @@
#pragma once #pragma once
#include "error/error.h" #include "error/error.h"
#include "display/texture/palette.h" #include "display/color.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
@@ -21,13 +24,12 @@ typedef textureformatplatform_t textureformat_t;
typedef textureplatform_t texture_t; typedef textureplatform_t texture_t;
typedef union texturedata_u { typedef union texturedata_u {
struct { uint8_t *paletteData;
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.
* *
@@ -45,6 +47,13 @@ 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

@@ -69,6 +69,8 @@ void moduleCamera(scriptcontext_t *context) {
// Methods // Methods
lua_register(context->luaState, "cameraCreate", moduleCameraCreate); lua_register(context->luaState, "cameraCreate", moduleCameraCreate);
lua_register(context->luaState, "cameraPushMatrix", moduleCameraPushMatrix);
lua_register(context->luaState, "cameraPopMatrix", moduleCameraPopMatrix);
} }
int moduleCameraCreate(lua_State *L) { int moduleCameraCreate(lua_State *L) {
@@ -116,6 +118,25 @@ int moduleCameraCreate(lua_State *L) {
return 1; return 1;
} }
int moduleCameraPushMatrix(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL.");
assertTrue(lua_gettop(L) >= 1, "cameraPushMatrix requires 1 arg.");
assertTrue(lua_isuserdata(L, 1), "cameraPushMatrix arg must be userdata.");
// Camera should be provided (pointer to camera_t).
camera_t *cam = (camera_t *)luaL_checkudata(L, 1, "camera_mt");
assertNotNull(cam, "Camera pointer cannot be NULL.");
cameraPushMatrix(cam);
return 0;
}
int moduleCameraPopMatrix(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL.");
cameraPopMatrix();
return 0;
}
int moduleCameraIndex(lua_State *l) { int moduleCameraIndex(lua_State *l) {
assertNotNull(l, "Lua state cannot be NULL."); assertNotNull(l, "Lua state cannot be NULL.");

View File

@@ -23,6 +23,22 @@ void moduleCamera(scriptcontext_t *context);
*/ */
int moduleCameraCreate(lua_State *L); int moduleCameraCreate(lua_State *L);
/**
* Script binding for pushing the camera matrix onto the matrix stack.
*
* @param L The Lua state.
* @return Number of return values on the Lua stack.
*/
int moduleCameraPushMatrix(lua_State *L);
/**
* Script binding for popping the camera matrix from the matrix stack.
*
* @param L The Lua state.
* @return Number of return values on the Lua stack.
*/
int moduleCameraPopMatrix(lua_State *L);
/** /**
* Getter for camera structure fields. * Getter for camera structure fields.
* *

View File

@@ -32,20 +32,32 @@ 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, 1) || !lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4) ||
!lua_isnumber(L, 4) !lua_isnumber(L, 5)
) { ) {
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) < 5 || lua_isnil(L, 5)) { if(lua_gettop(L) < 6 || lua_isnil(L, 6)) {
// Allow NULL // Allow NULL
} else if(lua_isuserdata(L, 5)) { } else if(lua_isuserdata(L, 6)) {
color = (color_t*)luaL_checkudata(L, 5, "color_mt"); color = (color_t*)luaL_checkudata(L, 6, "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");
} }
@@ -56,30 +68,31 @@ 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) >= 7) { if(lua_gettop(L) >= 8) {
if(!lua_isnumber(L, 6) || !lua_isnumber(L, 7)) { if(!lua_isnumber(L, 7) || !lua_isnumber(L, 8)) {
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, 6); u0 = (float_t)lua_tonumber(L, 7);
v0 = (float_t)lua_tonumber(L, 7); v0 = (float_t)lua_tonumber(L, 8);
} }
if(lua_gettop(L) >= 9) { if(lua_gettop(L) >= 10) {
if(!lua_isnumber(L, 8) || !lua_isnumber(L, 9)) { if(!lua_isnumber(L, 9) || !lua_isnumber(L, 10)) {
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, 8); u1 = (float_t)lua_tonumber(L, 9);
v1 = (float_t)lua_tonumber(L, 9); v1 = (float_t)lua_tonumber(L, 10);
} }
float_t minX = (float_t)lua_tonumber(L, 1); float_t minX = (float_t)lua_tonumber(L, 2);
float_t minY = (float_t)lua_tonumber(L, 2); float_t minY = (float_t)lua_tonumber(L, 3);
float_t maxX = (float_t)lua_tonumber(L, 3); float_t maxX = (float_t)lua_tonumber(L, 4);
float_t maxY = (float_t)lua_tonumber(L, 4); float_t maxY = (float_t)lua_tonumber(L, 5);
errorret_t ret = spriteBatchPush( spriteBatchPush(
tex,
minX, minX,
minY, minY,
maxX, maxX,
@@ -90,14 +103,6 @@ int moduleSpriteBatchPush(lua_State *L) {
u1, u1,
v1 v1
); );
if(ret.code != ERROR_OK) {
int err = luaL_error(L,
"Failed to push sprite to batch: %s",
ret.state->message
);
errorCatch(errorPrint(ret));
return err;
}
return 0; return 0;
} }

View File

@@ -30,11 +30,11 @@ void uiRender(void) {
UI.camera.orthographic.right = SCREEN.width; UI.camera.orthographic.right = SCREEN.width;
UI.camera.orthographic.top = SCREEN.height; UI.camera.orthographic.top = SCREEN.height;
// cameraPushMatrix(&UI.camera); cameraPushMatrix(&UI.camera);
spriteBatchClear(); spriteBatchClear();
spriteBatchFlush(); spriteBatchFlush();
// cameraPopMatrix(); cameraPopMatrix();
} }
void uiDispose(void) { void uiDispose(void) {

View File

@@ -15,4 +15,3 @@ add_subdirectory(camera)
add_subdirectory(framebuffer) add_subdirectory(framebuffer)
add_subdirectory(mesh) add_subdirectory(mesh)
add_subdirectory(texture) add_subdirectory(texture)
add_subdirectory(shader)

View File

@@ -8,7 +8,6 @@
#include "display/mesh/mesh.h" #include "display/mesh/mesh.h"
#include "display/texture/texture.h" #include "display/texture/texture.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "display/shader/shader.h"
errorret_t meshInitDolphin( errorret_t meshInitDolphin(
meshdolphin_t *mesh, meshdolphin_t *mesh,
@@ -47,14 +46,13 @@ 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
); );
// Update matrix.
errorChain(shaderUpdateMVPDolphin());
const uint8_t stride = (uint8_t)sizeof(meshvertex_t); const uint8_t stride = (uint8_t)sizeof(meshvertex_t);
GX_SetArray(GX_VA_POS, (void*)&mesh->vertices[vertexOffset].pos[0], stride); GX_SetArray(GX_VA_POS, (void*)&mesh->vertices[vertexOffset].pos[0], stride);
GX_SetArray(GX_VA_CLR0, (void*)&mesh->vertices[vertexOffset].color.r, stride); GX_SetArray(GX_VA_CLR0, (void*)&mesh->vertices[vertexOffset].color.r, stride);

View File

@@ -1,11 +0,0 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
shaderdolphin.c
shaderunlitdolphin.c
)

View File

@@ -1,245 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "util/memory.h"
#include "util/string.h"
#include "display/shader/shaderunlit.h"
#include "assert/assert.h"
#include "log/log.h"
shaderdolphin_t *SHADER_BOUND;
errorret_t shaderInitDolphin(
shaderdolphin_t *shader,
const shaderdefinitiondolphin_t *def
) {
assertNotNull(shader, "Shader must not be null");
assertNotNull(def, "Shader definition must not be null");
memoryZero(shader, sizeof(shaderdolphin_t));
glm_mat4_identity(shader->view);
glm_mat4_identity(shader->proj);
glm_mat4_identity(shader->model);
shader->dirtyMatrix = (
SHADER_DOLPHIN_DIRTY_MODEL |
SHADER_DOLPHIN_DIRTY_PROJ |
SHADER_DOLPHIN_DIRTY_VIEW
);
errorOk();
}
errorret_t shaderBindDolphin(shaderdolphin_t *shader) {
assertNotNull(shader, "Shader must not be null");
SHADER_BOUND = shader;
GX_LoadProjectionMtx(
shader->matrixProjection,
shader->isProjectionPerspective ? GX_PERSPECTIVE : GX_ORTHOGRAPHIC
);
GX_LoadPosMtxImm(shader->matrixModelView, GX_PNMTX0);
errorOk();
}
errorret_t shaderSetMatrixDolphin(
shaderdolphin_t *shader,
const char_t *name,
mat4 mat
) {
assertNotNull(shader, "Shader must not be null");
assertNotNull(name, "Uniform name must not be null");
assertStrLenMin(name, 1, "Uniform name cannot be empty");
if(stringCompare(name, SHADER_UNLIT_PROJECTION) == 0) {
shader->dirtyMatrix |= SHADER_DOLPHIN_DIRTY_PROJ;
glm_mat4_copy(mat, shader->proj);
} else if(stringCompare(name, SHADER_UNLIT_VIEW) == 0) {
shader->dirtyMatrix |= SHADER_DOLPHIN_DIRTY_VIEW;
glm_mat4_copy(mat, shader->view);
} else if(stringCompare(name, SHADER_UNLIT_MODEL) == 0) {
shader->dirtyMatrix |= SHADER_DOLPHIN_DIRTY_MODEL;
glm_mat4_copy(mat, shader->model);
} else {
assertUnreachable("Cannot use a custom matrix on dolphin.");
}
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) {
assertNotNull(shader, "Shader must not be null");
SHADER_BOUND = NULL;
errorOk();
}
errorret_t shaderUpdateMVPDolphin() {
assertNotNull(SHADER_BOUND, "Shader must not be null");
// Any changes?
if(SHADER_BOUND->dirtyMatrix == 0) errorOk();
// Need to update projection?
if((SHADER_BOUND->dirtyMatrix & SHADER_DOLPHIN_DIRTY_PROJ) != 0) {
shaderMat4ToMtx44(SHADER_BOUND->proj, SHADER_BOUND->matrixProjection);
// Fix projection Z mapping between GLM and GX.
float A = SHADER_BOUND->matrixProjection[2][2];
float B = SHADER_BOUND->matrixProjection[2][3];
SHADER_BOUND->matrixProjection[2][2] = 0.5f * (A + 1.0f);
SHADER_BOUND->matrixProjection[2][3] = 0.5f * B;
// Is this perspective or ortho originally? Dolphin cares for some reason.
const float_t epsilon = 0.0001f;
SHADER_BOUND->isProjectionPerspective = (
fabsf(SHADER_BOUND->proj[3][2]) > epsilon &&
fabsf(SHADER_BOUND->proj[3][3]) < epsilon
);
GX_LoadProjectionMtx(
SHADER_BOUND->matrixProjection,
SHADER_BOUND->isProjectionPerspective ? GX_PERSPECTIVE : GX_ORTHOGRAPHIC
);
}
// Need to update view or model?
bool_t mvDirt = false;
if((SHADER_BOUND->dirtyMatrix & SHADER_DOLPHIN_DIRTY_VIEW) != 0) {
shaderMat4ToMtx(SHADER_BOUND->view, SHADER_BOUND->matrixView);
mvDirt = true;
}
if((SHADER_BOUND->dirtyMatrix & SHADER_DOLPHIN_DIRTY_MODEL) != 0) {
shaderMat4ToMtx(SHADER_BOUND->model, SHADER_BOUND->matrixModel);
mvDirt = true;
}
// Set Model/View Matrix
if(mvDirt) {
guMtxConcat(
SHADER_BOUND->matrixView,
SHADER_BOUND->matrixModel,
SHADER_BOUND->matrixModelView
);
GX_LoadPosMtxImm(SHADER_BOUND->matrixModelView, GX_PNMTX0);
}
SHADER_BOUND->dirtyMatrix = 0;
errorOk();
}
void shaderMat4ToMtx44(const mat4 inGlmMatrix, Mtx44 outGXMatrix) {
assertNotNull(inGlmMatrix, "Input matrix cannot be null");
assertNotNull(outGXMatrix, "Output matrix cannot be null");
for(int row = 0; row < 4; ++row) {
for(int col = 0; col < 4; ++col) {
outGXMatrix[row][col] = inGlmMatrix[col][row];
}
}
}
void shaderMat4ToMtx(const mat4 inGlmMatrix, Mtx outGXMatrix) {
assertNotNull(inGlmMatrix, "Input matrix cannot be null");
assertNotNull(outGXMatrix, "Output matrix cannot be null");
for(int row = 0; row < 3; ++row) {
for(int col = 0; col < 4; ++col) {
outGXMatrix[row][col] = inGlmMatrix[col][row];
}
}
}

View File

@@ -1,113 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/texture/texture.h"
typedef struct {
mat4 view;
mat4 proj;
mat4 model;
bool_t isProjectionPerspective;
Mtx44 matrixProjection;
Mtx matrixView;
Mtx matrixModel;
Mtx matrixModelView;
uint_fast8_t dirtyMatrix;
} shaderdolphin_t;
typedef struct {
void *empty;
} shaderdefinitiondolphin_t;
#define SHADER_DOLPHIN_DIRTY_MODEL (1 << 0)
#define SHADER_DOLPHIN_DIRTY_PROJ (1 << 1)
#define SHADER_DOLPHIN_DIRTY_VIEW (1 << 2)
extern shaderdolphin_t *SHADER_BOUND;
/**
* Initializes a dolphin shader. Basically a render parameter pipeline.
*
* @param shader Shader to initialize.
* @param def Definition of the shader to initialize with.
* @return Error code if failure.
*/
errorret_t shaderInitDolphin(
shaderdolphin_t *shader,
const shaderdefinitiondolphin_t *def
);
/**
* Binds a dolphin shader. Basically sets the render parameters for rendering.
*
* @param shader Shader to bind.
* @return Error code if failure.
*/
errorret_t shaderBindDolphin(shaderdolphin_t *shader);
/**
* Sets a matrix uniform in the dolphin shader. Basically does nothing.
*
* @param shader Shader to set the matrix in.
* @param name Name of the uniform to set.
* @param matrix Matrix to set.
* @return Error code if failure.
*/
errorret_t shaderSetMatrixDolphin(
shaderdolphin_t *shader,
const char_t *name,
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.
*
* @param shader Shader to dispose.
* @return Error code if failure.
*/
errorret_t shaderDisposeDolphin(shaderdolphin_t *shader);
/**
* Internal Dolphin method, called right before a draw call to perform a matrix
* update and recalc.
*
* @return Error code if failure.
*/
errorret_t shaderUpdateMVPDolphin();
/**
* Converts a glm style column major mat4 to a GX compatible row major Mtx44.
*
* @param in Matrix to convert.
* @param out Output converted matrix.
*/
void shaderMat4ToMtx44(const mat4 in, Mtx44 out);
/**
* Converts a glm style column major mat4 to a GX compatible row major Mtx.
*
* @param inGlmMatrix Matrix to convert.
* @param outGXMatrix Output converted matrix.
*/
void shaderMat4ToMtx(const mat4 inGlmMatrix, Mtx outGXMatrix);

View File

@@ -1,18 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "shaderdolphin.h"
typedef shaderdolphin_t shaderplatform_t;
typedef shaderdefinitiondolphin_t shaderdefinitionplatform_t;
#define shaderInitPlatform shaderInitDolphin
#define shaderBindPlatform shaderBindDolphin
#define shaderSetMatrixPlatform shaderSetMatrixDolphin
#define shaderSetTexturePlatform shaderSetTextureDolphin
#define shaderDisposePlatform shaderDisposeDolphin

View File

@@ -1,12 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "display/shader/shaderunlit.h"
shaderdefinition_t SHADER_UNLIT_DEFINITION = {
0
};

View File

@@ -7,7 +7,6 @@
#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,
@@ -16,101 +15,191 @@ 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:
size_t rgbaSize = width * height * sizeof(uint8_t) * 4; // assertTrue(
// (width % 4) == 0 && (height % 4) == 0,
// "RGB5A3 requires w/h multiple of 4 (or pad)"
// );
// Dolphin takes the RGBA data as 4x4 tiled layout. // // Convert to RGB5A3 format
texture->rgba = memoryAllocate(rgbaSize); // size_t rgbaSize = width * height * sizeof(u16);
// 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 y = 0; y < height; ++y) {
for(uint32_t x = 0; x < width; ++x) { // for(uint32_t x = 0; x < width; ++x) {
const int src = y * width + x; // const int src = y * width + x;
const int tileX = x >> 2; // const int tileX = x >> 2;
const int tileY = y >> 2; // const int tileY = y >> 2;
const int tilesPerRow = width >> 2; // const int tilesPerRow = width >> 2;
const int tileIndex = tileY * tilesPerRow + tileX; // const int tileIndex = tileY * tilesPerRow + tileX;
const int inTile = ((y & 3) << 2) + (x & 3); // const int tileBaseWords = tileIndex * 16;
const int tileBase = tileIndex * 64; // const int inTile = ((y & 3) << 2) + (x & 3);
// const int dest = tileBaseWords + inTile;
color_t col = data.rgbaColors[src]; // color4b_t col = data.rgba.colors[src];
// AR plane // u16 outCol;
texture->rgba[tileBase + inTile * 2 + 0] = col.a; // if(col.a < 255) {
texture->rgba[tileBase + inTile * 2 + 1] = col.r; // // 0AAA RRRR GGGG BBBB
// outCol = (
// GB plane // (0u << 15) |
texture->rgba[tileBase + 32 + inTile * 2 + 0] = col.g; // ((u16)(col.a >> 5) << 12) |
texture->rgba[tileBase + 32 + inTile * 2 + 1] = col.b; // ((u16)(col.r >> 4) << 8) |
} // ((u16)(col.g >> 4) << 4) |
} // ((u16)(col.b >> 4) << 0)
DCFlushRange(texture->rgba, rgbaSize); // );
GX_InitTexObj( // } else {
&texture->texObj, // // 1RRRR RRGG GGGB BBBB
texture->rgba, // outCol = (
width, height, // (1u << 15) |
format, // ((u16)(col.r >> 3) << 10) |
GX_REPEAT, GX_REPEAT, // ((u16)(col.g >> 3) << 5) |
GX_FALSE // ((u16)(col.b >> 3) << 0)
); // );
// }
DCFlushRange(texture->rgba, rgbaSize); // texture->rgba[dest] = outCol;
GX_InvalidateTexAll(); // }
GX_InitTexObjLOD(
&texture->texObj,
GX_NEAR, GX_NEAR,
0.0f, 0.0f, 0.0f,
GX_FALSE,
GX_FALSE,
GX_ANISO_1
);
break;
}
case TEXTURE_FORMAT_PALETTE: {
assertUnreachable("Paletted textures not yet implemented for Dolphin");
break;
}
default: {
assertUnreachable("Unsupported texture format for Dolphin");
break;
}
}
errorOk();
}
errorret_t textureDisposeDolphin(texturedolphin_t *texture) {
switch(texture->format) {
case TEXTURE_FORMAT_RGBA: {
if(texture->rgba) {
memoryFree(texture->rgba);
texture->rgba = NULL;
}
break;
}
// case TEXTURE_FORMAT_RGB4A3: {
// assertUnreachable("RGB4A3 texture format not yet implemented");
// } // }
// case TEXTURE_FORMAT_RGB5: { // DCFlushRange(texture->rgba, rgbaSize);
// assertUnreachable("RGB5 texture format not yet implemented"); // GX_InitTexObj(
// } // &texture->texObj,
// texture->rgba,
// width, height,
// GX_TF_RGB5A3,
// GX_REPEAT, GX_REPEAT,
// GX_FALSE
// );
// DCFlushRange(texture->rgba, rgbaSize);
// GX_InvalidateTexAll();
// GX_InitTexObjLOD(
// &texture->texObj,
// GX_NEAR, GX_NEAR,
// 0.0f, 0.0f, 0.0f,
// GX_FALSE,
// GX_FALSE,
// GX_ANISO_1
// );
// break;
// case TEXTURE_FORMAT_PALETTE: { // case TEXTURE_FORMAT_PALETTE: {
// assertUnreachable("Paletted textures not yet implemented for Dolphin"); // // Not supported, convert to RGBA using lookup
// color_t* formatted = memoryAllocate(width * height * sizeof(color_t));
// 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(
// texture, width, height, TEXTURE_FORMAT_RGBA,
// (texturedata_t){
// .rgba = { .colors = formatted }
// }
// );
// memoryFree(formatted);
// break; // break;
// } // }
default: { // default:
assertUnreachable("Unsupported texture format for Dolphin"); // 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();
}
errorret_t textureDisposeDolphin(texturedolphin_t *texture) {
errorOk();
}
void textureDolphinUploadTEV(void) {
if(TEXTURE_BOUND == NULL) {
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;
}
// Add channel for vertex color
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_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,8 +13,6 @@ 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 {
@@ -22,11 +20,6 @@ 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;
/** /**
@@ -62,3 +55,9 @@ errorret_t textureBindDolphin(texturedolphin_t *texture);
* @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

@@ -1,15 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "assert/assert.h"
#include "error/errorgl.h"
#define assertNoGLError(message) \
assertTrue(errorGLCheck().code == ERROR_OK, message)
// EOF

View File

@@ -14,4 +14,3 @@ add_subdirectory(camera)
add_subdirectory(framebuffer) add_subdirectory(framebuffer)
add_subdirectory(texture) add_subdirectory(texture)
add_subdirectory(mesh) add_subdirectory(mesh)
add_subdirectory(shader)

View File

@@ -8,7 +8,7 @@
#include "display/camera/camera.h" #include "display/camera/camera.h"
#include "display/framebuffer/framebuffer.h" #include "display/framebuffer/framebuffer.h"
#include "display/screen/screen.h" #include "display/screen/screen.h"
#include "assert/assertgl.h" #include "assert/assert.h"
void cameraPushMatrixGL(camera_t *camera) { void cameraPushMatrixGL(camera_t *camera) {
assertNotNull(camera, "Not a camera component"); assertNotNull(camera, "Not a camera component");
@@ -117,19 +117,16 @@ void cameraPushMatrixGL(camera_t *camera) {
assertUnreachable("Invalid camera view type"); assertUnreachable("Invalid camera view type");
} }
// glPushMatrix(); glPushMatrix();
// glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
// glLoadIdentity(); glLoadIdentity();
// glLoadMatrixf((const GLfloat*)projection); glLoadMatrixf((const GLfloat*)projection);
assertNoGLError("Failed to set projection matrix");
// glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
// glLoadIdentity(); glLoadIdentity();
// glLoadMatrixf((const GLfloat*)view); glLoadMatrixf((const GLfloat*)view);
assertNoGLError("Failed to set view matrix");
} }
void cameraPopMatrixGL(void) { void cameraPopMatrixGL(void) {
// glPopMatrix(); glPopMatrix();
assertNoGLError("Failed to pop camera matrix");
} }

View File

@@ -9,28 +9,24 @@
errorret_t displayOpenGLInit(void) { errorret_t displayOpenGLInit(void) {
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
errorChain(errorGLCheck());
#if DUSK_OPENGL_LEGACY
glDisable(GL_LIGHTING);// PSP defaults this on? glDisable(GL_LIGHTING);// PSP defaults this on?
errorChain(errorGLCheck());
glShadeModel(GL_SMOOTH); // Fixes color on PSP? glShadeModel(GL_SMOOTH); // Fixes color on PSP?
errorChain(errorGLCheck()); 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);
errorChain(errorGLCheck()); glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
errorChain(errorGLCheck()); errorChain(errorGLCheck());
glEnableClientState(GL_COLOR_ARRAY);// To confirm: every frame on PSP?
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
errorChain(errorGLCheck());
errorOk(); errorOk();
} }

View File

@@ -10,7 +10,5 @@
/** /**
* Initializes the OpenGL specific contexts for rendering. * Initializes the OpenGL specific contexts for rendering.
*
* @return An errorret_t indicating success or failure of the initialization.
*/ */
errorret_t displayOpenGLInit(void); errorret_t displayOpenGLInit(void);

View File

@@ -7,7 +7,7 @@
#include "display/display.h" #include "display/display.h"
#include "display/framebuffer/framebuffer.h" #include "display/framebuffer/framebuffer.h"
#include "assert/assertgl.h" #include "assert/assert.h"
#include "util/memory.h" #include "util/memory.h"
errorret_t frameBufferGLInitBackBuffer(void) { errorret_t frameBufferGLInitBackBuffer(void) {
@@ -86,7 +86,6 @@ void frameBufferGLClear(const uint8_t flags, const color_t color) {
color.b / 255.0f, color.b / 255.0f,
color.a / 255.0f color.a / 255.0f
); );
assertNoGLError("Failed to set clear color");
} }
if(flags & FRAMEBUFFER_CLEAR_DEPTH) { if(flags & FRAMEBUFFER_CLEAR_DEPTH) {
@@ -94,7 +93,6 @@ void frameBufferGLClear(const uint8_t flags, const color_t color) {
} }
glClear(glFlags); glClear(glFlags);
assertNoGLError("Failed to clear framebuffer");
} }
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC #ifdef DUSK_DISPLAY_SIZE_DYNAMIC

View File

@@ -6,9 +6,7 @@
*/ */
#include "display/mesh/mesh.h" #include "display/mesh/mesh.h"
#include "assert/assertgl.h" #include "assert/assert.h"
#include "error/errorgl.h"
#include "display/shader/shadergl.h"
errorret_t meshInitGL( errorret_t meshInitGL(
meshgl_t *mesh, meshgl_t *mesh,
@@ -24,101 +22,6 @@ errorret_t meshInitGL(
mesh->vertexCount = vertexCount; mesh->vertexCount = vertexCount;
mesh->vertices = vertices; mesh->vertices = vertices;
#ifdef DUSK_OPENGL_LEGACY
// Nothing needed.
glEnableClientState(GL_COLOR_ARRAY);
errorChain(errorGLCheck());
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
errorChain(errorGLCheck());
glEnableClientState(GL_VERTEX_ARRAY);
errorChain(errorGLCheck());
#else
// Generate Vertex Buffer Object
glGenBuffers(1, &mesh->vboId);
errorChain(errorGLCheck());
glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId);
errorChain(errorGLCheck());
glBufferData(
GL_ARRAY_BUFFER,
vertexCount * sizeof(meshvertex_t),
vertices,
GL_DYNAMIC_DRAW
);
errorChain(errorGLCheck());
// Generate Vertex Array Object
glGenVertexArrays(1, &mesh->vaoId);
errorChain(errorGLCheck());
glBindVertexArray(mesh->vaoId);
errorChain(errorGLCheck());
glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId);
errorChain(errorGLCheck());
// Set up vertex attribute pointers
glVertexAttribPointer(
0,
MESH_VERTEX_POS_SIZE,
GL_FLOAT,
GL_FALSE,
sizeof(meshvertex_t),
(const GLvoid*)offsetof(meshvertex_t, pos)
);
errorChain(errorGLCheck());
glEnableVertexAttribArray(0);
errorChain(errorGLCheck());
glVertexAttribPointer(
1,
MESH_VERTEX_UV_SIZE,
GL_FLOAT,
GL_FALSE,
sizeof(meshvertex_t),
(const GLvoid*)offsetof(meshvertex_t, uv)
);
errorChain(errorGLCheck());
glEnableVertexAttribArray(1);
errorChain(errorGLCheck());
glVertexAttribPointer(
2,
sizeof(color_t) / sizeof(GLubyte),
GL_UNSIGNED_BYTE,
GL_TRUE,
sizeof(meshvertex_t),
(const GLvoid*)offsetof(meshvertex_t, color)
);
errorChain(errorGLCheck());
glEnableVertexAttribArray(2);
errorChain(errorGLCheck());
// Unbind VAO and VBO to prevent accidental modification
glBindBuffer(GL_ARRAY_BUFFER, 0);
errorChain(errorGLCheck());
glBindVertexArray(0);
errorChain(errorGLCheck());
#endif
errorOk();
}
errorret_t meshFlushGL(
meshgl_t *mesh,
const int32_t vertOffset,
const int32_t vertCount
) {
#ifdef DUSK_OPENGL_LEGACY
// Nothing doing, we use the glClientState stuff.
#else
glBindBuffer(GL_ARRAY_BUFFER, mesh->vboId);
errorChain(errorGLCheck());
glBufferData(
GL_ARRAY_BUFFER,
vertCount * sizeof(meshvertex_t),
&mesh->vertices[vertOffset],
GL_DYNAMIC_DRAW
);
errorChain(errorGLCheck());
#endif
errorOk(); errorOk();
} }
@@ -127,8 +30,7 @@ errorret_t meshDrawGL(
const int32_t offset, const int32_t offset,
const int32_t count const int32_t count
) { ) {
#ifdef DUSK_OPENGL_LEGACY // PSP style pointer legacy OpenGL
// Legacy pointer style rendering
const GLsizei stride = sizeof(meshvertex_t); const GLsizei stride = sizeof(meshvertex_t);
glColorPointer( glColorPointer(
@@ -141,32 +43,16 @@ errorret_t meshDrawGL(
MESH_VERTEX_UV_SIZE, MESH_VERTEX_UV_SIZE,
GL_FLOAT, GL_FLOAT,
stride, stride,
(const GLvoid*)&mesh->vertices[offset].uv[0] (const GLvoid*)&mesh->vertices[offset].uv
); );
glVertexPointer( glVertexPointer(
MESH_VERTEX_POS_SIZE, MESH_VERTEX_POS_SIZE,
GL_FLOAT, GL_FLOAT,
stride, stride,
(const GLvoid*)&mesh->vertices[offset].pos[0] (const GLvoid*)&mesh->vertices[offset].pos
); );
// Shader may have model matrix here
#ifdef DUSK_OPENGL_LEGACY
errorChain(shaderLegacyMatrixUpdate());
#endif
// glDrawArrays(mesh->primitiveType, offset, count);
glDrawArrays(mesh->primitiveType, 0, count);
errorChain(errorGLCheck());
#else
// Modern VAO/VBO rendering
glBindVertexArray(mesh->vaoId);
errorChain(errorGLCheck());
glDrawArrays(mesh->primitiveType, offset, count); glDrawArrays(mesh->primitiveType, offset, count);
errorChain(errorGLCheck());
glBindVertexArray(0);
errorChain(errorGLCheck());
#endif
errorOk(); errorOk();
} }
@@ -176,14 +62,6 @@ int32_t meshGetVertexCountGL(const meshgl_t *mesh) {
} }
errorret_t meshDisposeGL(meshgl_t *mesh) { errorret_t meshDisposeGL(meshgl_t *mesh) {
#ifdef DUSK_OPENGL_LEGACY
// No dynamic resources to free for this mesh implementation // No dynamic resources to free for this mesh implementation
#else
glDeleteBuffers(1, &mesh->vboId);
errorChain(errorGLCheck());
glDeleteVertexArrays(1, &mesh->vaoId);
errorChain(errorGLCheck());
#endif
errorOk(); errorOk();
} }

View File

@@ -16,16 +16,9 @@ typedef enum {
} meshprimitivetypegl_t; } meshprimitivetypegl_t;
typedef struct { typedef struct {
const meshvertex_t *vertices;
int32_t vertexCount; int32_t vertexCount;
meshprimitivetypegl_t primitiveType; meshprimitivetypegl_t primitiveType;
const meshvertex_t *vertices;
#ifdef DUSK_OPENGL_LEGACY
// Nothing needed
#else
GLuint vaoId;
GLuint vboId;
#endif
} meshgl_t; } meshgl_t;
/** /**
@@ -44,20 +37,6 @@ errorret_t meshInitGL(
const meshvertex_t *vertices const meshvertex_t *vertices
); );
/**
* Flushes the vertices (stored in memory) to the GPU.
*
* @param mesh Mesh to flush vertices for.
* @param vertOffset First vertice index to flush.
* @param vertCount Count of vertices to flush.
* @return Error state.
*/
errorret_t meshFlushGL(
meshgl_t *mesh,
const int32_t vertOffset,
const int32_t vertCount
);
/** /**
* Draws a mesh using OpenGL. * Draws a mesh using OpenGL.
* *

View File

@@ -12,7 +12,6 @@ typedef meshprimitivetypegl_t meshprimitivetypeplatform_t;
typedef meshgl_t meshplatform_t; typedef meshgl_t meshplatform_t;
#define meshInitPlatform meshInitGL #define meshInitPlatform meshInitGL
#define meshFlushPlatform meshFlushGL
#define meshDrawPlatform meshDrawGL #define meshDrawPlatform meshDrawGL
#define meshGetVertexCountPlatform meshGetVertexCountGL #define meshGetVertexCountPlatform meshGetVertexCountGL
#define meshDisposePlatform meshDisposeGL #define meshDisposePlatform meshDisposeGL

View File

@@ -1,11 +0,0 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
shadergl.c
shaderunlitgl.c
)

View File

@@ -1,322 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "shadergl.h"
#include "util/memory.h"
#include "util/string.h"
#include "assert/assertgl.h"
#include "display/shader/shaderunlit.h"
#ifdef DUSK_OPENGL_LEGACY
shaderlegacygl_t SHADER_LEGACY = { 0 };
#endif
errorret_t shaderInitGL(shadergl_t *shader, const shaderdefinitiongl_t *def) {
assertNotNull(shader, "Shader cannot be null");
assertNotNull(def, "Shader definition cannot be null");
memoryZero(shader, sizeof(shadergl_t));
#ifdef DUSK_OPENGL_LEGACY
glm_mat4_identity(shader->view);
glm_mat4_identity(shader->proj);
glm_mat4_identity(shader->model);
SHADER_LEGACY.boundShader = NULL;
errorOk();
#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
shader->vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
errorret_t err = errorGLCheck();
errorChain(err);
glShaderSource(shader->vertexShaderId, 1, &def->vert, NULL);
err = errorGLCheck();
if(err.code != ERROR_OK) {
glDeleteShader(shader->vertexShaderId);
errorChain(err);
}
glCompileShader(shader->vertexShaderId);
err = errorGLCheck();
if(err.code != ERROR_OK) {
glDeleteShader(shader->vertexShaderId);
errorChain(err);
}
GLint ok = 0;
glGetShaderiv(shader->vertexShaderId, GL_COMPILE_STATUS, &ok);
if(!ok) {
GLchar log[1024];
glGetShaderInfoLog(shader->vertexShaderId, sizeof(log), NULL, log);
glDeleteShader(shader->vertexShaderId);
errorThrow("Vertex shader compilation failed: %s", log);
}
// Create fragment shader
shader->fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
err = errorGLCheck();
if(err.code != ERROR_OK) {
glDeleteShader(shader->vertexShaderId);
errorChain(err);
}
glShaderSource(shader->fragmentShaderId, 1, &def->frag, NULL);
err = errorGLCheck();
if(err.code != ERROR_OK) {
glDeleteShader(shader->vertexShaderId);
glDeleteShader(shader->fragmentShaderId);
errorChain(err);
}
glCompileShader(shader->fragmentShaderId);
err = errorGLCheck();
if(err.code != ERROR_OK) {
glDeleteShader(shader->vertexShaderId);
glDeleteShader(shader->fragmentShaderId);
errorChain(err);
}
glGetShaderiv(shader->fragmentShaderId, GL_COMPILE_STATUS, &ok);
if(!ok) {
GLchar log[1024];
glGetShaderInfoLog(shader->fragmentShaderId, sizeof(log), NULL, log);
glDeleteShader(shader->vertexShaderId);
glDeleteShader(shader->fragmentShaderId);
errorThrow("Fragment shader compilation failed: %s", log);
}
// Create shader program
shader->shaderProgramId = glCreateProgram();
err = errorGLCheck();
if(err.code != ERROR_OK) {
glDeleteShader(shader->vertexShaderId);
glDeleteShader(shader->fragmentShaderId);
errorChain(err);
}
glAttachShader(shader->shaderProgramId, shader->vertexShaderId);
err = errorGLCheck();
if(err.code != ERROR_OK) {
glDeleteProgram(shader->shaderProgramId);
glDeleteShader(shader->vertexShaderId);
glDeleteShader(shader->fragmentShaderId);
errorChain(err);
}
glAttachShader(shader->shaderProgramId, shader->fragmentShaderId);
err = errorGLCheck();
if(err.code != ERROR_OK) {
glDeleteProgram(shader->shaderProgramId);
glDeleteShader(shader->vertexShaderId);
glDeleteShader(shader->fragmentShaderId);
errorChain(err);
}
glLinkProgram(shader->shaderProgramId);
err = errorGLCheck();
if(err.code != ERROR_OK) {
glDeleteProgram(shader->shaderProgramId);
glDeleteShader(shader->vertexShaderId);
glDeleteShader(shader->fragmentShaderId);
errorChain(err);
}
ok = 0;
glGetProgramiv(shader->shaderProgramId, GL_LINK_STATUS, &ok);
if(!ok) {
GLchar log[1024];
glGetProgramInfoLog(shader->shaderProgramId, sizeof(log), NULL, log);
glDeleteProgram(shader->shaderProgramId);
glDeleteShader(shader->vertexShaderId);
glDeleteShader(shader->fragmentShaderId);
errorThrow("Shader program linking failed: %s", log);
}
#endif
errorOk();
}
errorret_t shaderParamGetLocationGL(
shadergl_t *shader,
const char_t *name,
GLint *location
) {
assertNotNull(shader, "Shader cannot be null");
assertStrLenMin(name, 1, "Uniform name cannot be empty");
assertNotNull(location, "Location cannot be null");
#ifdef DUSK_OPENGL_LEGACY
assertUnreachable("Cannot get uniform locations on legacy opengl.");
#else
shadergl_t *shaderGL = (shadergl_t *)shader;
*location = glGetUniformLocation(shaderGL->shaderProgramId, name);
errorret_t err = errorGLCheck();
if(err.code != ERROR_OK) {
errorChain(err);
}
#endif
errorOk();
}
errorret_t shaderSetMatrixGL(
shadergl_t *shader,
const char_t *name,
mat4 mat
) {
assertNotNull(shader, "Shader cannot be null");
assertNotNull(mat, "Matrix data cannot be null");
assertStrLenMin(name, 1, "Uniform name cannot be empty");
#ifdef DUSK_OPENGL_LEGACY
assertTrue(
SHADER_LEGACY.boundShader == shader,
"Shader must be bound to set legacy matrices."
);
if(stringCompare(name, SHADER_UNLIT_PROJECTION) == 0) {
SHADER_LEGACY.dirty |= SHADER_LEGACY_DIRTY_PROJ;
glm_mat4_copy(mat, shader->proj);
} else if(stringCompare(name, SHADER_UNLIT_VIEW) == 0) {
SHADER_LEGACY.dirty |= SHADER_LEGACY_DIRTY_VIEW;
glm_mat4_copy(mat, shader->view);
} else if(stringCompare(name, SHADER_UNLIT_MODEL) == 0) {
SHADER_LEGACY.dirty |= SHADER_LEGACY_DIRTY_MODEL;
glm_mat4_copy(mat, shader->model);
} else {
assertUnreachable("Cannot use a custom matrix on legacy opengl.");
}
#else
GLint location;
errorChain(shaderParamGetLocationGL(shader, name, &location));
glUniformMatrix4fv(location, 1, GL_FALSE, (const GLfloat *)mat);
errorChain(errorGLCheck());
#endif
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) {
#ifdef DUSK_OPENGL_LEGACY
assertNotNull(shader, "Cannot bind a null shader.");
SHADER_LEGACY.boundShader = shader;
SHADER_LEGACY.dirty = (
SHADER_LEGACY_DIRTY_MODEL |
SHADER_LEGACY_DIRTY_PROJ |
SHADER_LEGACY_DIRTY_VIEW
);
#else
assertNotNull(shader, "Shader cannot be null");
glUseProgram(shader->shaderProgramId);
errorChain(errorGLCheck());
#endif
errorOk();
}
errorret_t shaderDisposeGL(shadergl_t *shader) {
assertNotNull(shader, "Shader cannot be null");
#ifdef DUSK_OPENGL_LEGACY
SHADER_LEGACY.boundShader = NULL;
#else
if(shader->shaderProgramId != 0) {
glDeleteProgram(shader->shaderProgramId);
}
if(shader->vertexShaderId != 0) {
glDeleteShader(shader->vertexShaderId);
}
if(shader->fragmentShaderId != 0) {
glDeleteShader(shader->fragmentShaderId);
}
assertNoGLError("Failed disposing shader");
#endif
memoryZero(shader, sizeof(shadergl_t));
errorOk();
}
#ifdef DUSK_OPENGL_LEGACY
errorret_t shaderLegacyMatrixUpdate() {
assertNotNull(SHADER_LEGACY.boundShader, "No shader is currently bound.");
if((SHADER_LEGACY.dirty & SHADER_LEGACY_DIRTY_PROJ) != 0) {
glMatrixMode(GL_PROJECTION);
errorChain(errorGLCheck());
glLoadIdentity();
errorChain(errorGLCheck());
glMultMatrixf((const GLfloat *)SHADER_LEGACY.boundShader->proj);
errorChain(errorGLCheck());
}
if((SHADER_LEGACY.dirty & SHADER_LEGACY_DIRTY_VIEW) != 0) {
glMatrixMode(GL_MODELVIEW);
errorChain(errorGLCheck());
glLoadIdentity();
errorChain(errorGLCheck());
glMultMatrixf((const GLfloat *)SHADER_LEGACY.boundShader->view);
errorChain(errorGLCheck());
}
if((SHADER_LEGACY.dirty & SHADER_LEGACY_DIRTY_MODEL) != 0) {
glMatrixMode(GL_MODELVIEW);
errorChain(errorGLCheck());
glMultMatrixf((const GLfloat *)SHADER_LEGACY.boundShader->model);
errorChain(errorGLCheck());
}
SHADER_LEGACY.dirty = 0;
errorOk();
}
#endif

View File

@@ -1,145 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "error/errorgl.h"
#include "display/texture/texture.h"
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
mat4 view;
mat4 proj;
mat4 model;
#else
GLuint shaderProgramId;
GLuint vertexShaderId;
GLuint fragmentShaderId;
shadersettexturefn_t setTexture;
#endif
} shadergl_t;
typedef struct {
#ifdef DUSK_OPENGL_LEGACY
void *nothing;
#else
const char_t *vert;
const char_t *frag;
shadersettexturefn_t setTexture;
#endif
} shaderdefinitiongl_t;
#if DUSK_OPENGL_LEGACY
typedef struct {
shadergl_t *boundShader;
uint_fast8_t dirty;
} shaderlegacygl_t;
extern shaderlegacygl_t SHADER_LEGACY;
#define SHADER_LEGACY_DIRTY_PROJ (1 << 0)
#define SHADER_LEGACY_DIRTY_VIEW (1 << 1)
#define SHADER_LEGACY_DIRTY_MODEL (1 << 2)
#endif
/**
* Initializes a shader.
*
* @param shader The shader to initialize.
* @param def The definition of the shader to initialize with.
* @return An errorret_t indicating success or failure.
*/
errorret_t shaderInitGL(shadergl_t *shader, const shaderdefinitiongl_t *def);
/**
* Binds a shader for use in rendering.
*
* @param shader The shader to bind.
* @return An errorret_t indicating success or failure.
*/
errorret_t shaderBindGL(shadergl_t *shader);
/**
* Retrieves the location of a shader uniform parameter.
*
* @param shader The shader to query.
* @param name The name of the uniform parameter.
* @param location Output parameter to receive the location of the uniform.
* @return An errorret_t indicating success or failure.
*/
errorret_t shaderParamGetLocationGL(
shadergl_t *shader,
const char_t *name,
GLint *location
);
/**
* Sets a mat4 uniform parameter in the shader.
*
* @param shader The shader to update.
* @param name The name of the uniform parameter.
* @param mat The 4x4 matrix data to set.
* @return An errorret_t indicating success or failure.
*/
errorret_t shaderSetMatrixGL(
shadergl_t *shader,
const char_t *name,
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.
*
* @param shader The shader to dispose.
*/
errorret_t shaderDisposeGL(shadergl_t *shader);
#ifdef DUSK_OPENGL_LEGACY
/**
* During mesh rendering, this is requesting the legacy system to push all
* shaders necessary to render the currently bound shader's matrices.
*
* @return Any error state.
*/
errorret_t shaderLegacyMatrixUpdate();
#endif

View File

@@ -1,19 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "shadergl.h"
typedef shadergl_t shaderplatform_t;
typedef shaderdefinitiongl_t shaderdefinitionplatform_t;
#define shaderInitPlatform shaderInitGL
#define shaderBindPlatform shaderBindGL
#define shaderSetMatrixPlatform shaderSetMatrixGL
#define shaderSetTexturePlatform shaderSetTextureGL
// #define shaderSetColorPlatform shaderSetColorGL
#define shaderDisposePlatform shaderDisposeGL

View File

@@ -1,189 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "display/shader/shaderunlit.h"
#include "assert/assertgl.h"
#ifdef DUSK_OPENGL_LEGACY
shaderdefinition_t SHADER_UNLIT_DEFINITION = { 0 };
#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 = {
.vert =
#ifdef DUSK_OPENGL_ES
"#version 300 es\n"
"precision mediump float;\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",
#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 =
#ifdef DUSK_OPENGL_ES
"#version 300 es\n"
"precision mediump float;\n"
// Uniforms
"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

View File

@@ -8,7 +8,6 @@
#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,
@@ -18,49 +17,32 @@ 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, GL_RGBA, width, height, 0, GL_TEXTURE_2D, 0, format, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, (void*)data.rgbaColors format, GL_UNSIGNED_BYTE, (void*)data.rgbaColors
); );
errorChain(errorGLCheck());
break; break;
case TEXTURE_FORMAT_PALETTE: case TEXTURE_FORMAT_PALETTE:
texture->palette = data.paletted.palette; assertNotNull(data.paletteData, "Palette texture data cannot be NULL");
assertTrue(
texture->palette == &PALETTES[0],
"Only the first palette is supported in legacy opengl."
);
#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,
width, height, width, height,
0, GL_COLOR_INDEX8_EXT, 0, GL_COLOR_INDEX8_EXT,
GL_UNSIGNED_BYTE, (void*)data.paletted.indices GL_UNSIGNED_BYTE, (void*)data.paletteData
); );
errorChain(errorGLCheck()); errorChain(errorGLCheck());
#else
// For modern systems we send to only the R channel and the shader does // glColorTableEXT(
// the rest. // GL_TEXTURE_2D, GL_RGBA, data.palette.palette->colorCount, GL_RGBA,
glTexImage2D( // GL_UNSIGNED_BYTE, (const void*)data.palette.palette->colors
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:
@@ -70,30 +52,35 @@ 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());
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,7 +13,6 @@ 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 {
@@ -21,10 +20,6 @@ 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;
/** /**
@@ -45,6 +40,14 @@ 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,4 +12,5 @@ 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,23 +6,6 @@
*/ */
#pragma once #pragma once
#ifdef DUSK_OPENGL_ES
#include <GLES3/gl3.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 #define GL_GLEXT_PROTOTYPES
#include <vitaGL.h> #include <GL/gl.h>
#include <GL/glext.h>
#define GL_COLOR_INDEX8_EXT 0x80E5
// #include <GL/glext.h>
#endif

View File

@@ -19,5 +19,4 @@ 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

@@ -22,14 +22,6 @@ 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);
#ifdef DUSK_OPENGL_LEGACY
// SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
#else
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_MINOR_VERSION, 3);
#endif
// Create window with OpenGL flag. // Create window with OpenGL flag.
DISPLAY.window = SDL_CreateWindow( DISPLAY.window = SDL_CreateWindow(
"Dusk", "Dusk",
@@ -90,8 +82,6 @@ errorret_t displaySDL2Update(void) {
} }
SDL_GL_MakeCurrent(DISPLAY.window, DISPLAY.glContext); SDL_GL_MakeCurrent(DISPLAY.window, DISPLAY.glContext);
errorChain(errorGLCheck());
// errorChain(shaderPaletteTextureBindGL(&testShader));
errorOk(); errorOk();
} }