This commit is contained in:
2026-03-06 13:40:27 -06:00
parent 82b3dc576c
commit 38ce768168
32 changed files with 539 additions and 416 deletions

View File

@@ -32,7 +32,6 @@ set(DUSK_LIBRARY_TARGET_NAME "DuskCore" CACHE INTERNAL ${DUSK_CACHE_TARGET})
set(DUSK_BINARY_TARGET_NAME "Dusk" CACHE INTERNAL ${DUSK_CACHE_TARGET}) set(DUSK_BINARY_TARGET_NAME "Dusk" CACHE INTERNAL ${DUSK_CACHE_TARGET})
set(DUSK_ASSETS_ZIP "${DUSK_BUILD_DIR}/dusk.dsk" CACHE INTERNAL ${DUSK_CACHE_TARGET}) set(DUSK_ASSETS_ZIP "${DUSK_BUILD_DIR}/dusk.dsk" CACHE INTERNAL ${DUSK_CACHE_TARGET})
# Set default target system
if(NOT DEFINED DUSK_TARGET_SYSTEM) if(NOT DEFINED DUSK_TARGET_SYSTEM)
set(DUSK_TARGET_SYSTEM "linux") set(DUSK_TARGET_SYSTEM "linux")
endif() endif()
@@ -52,7 +51,7 @@ project(${DUSK_LIBRARY_TARGET_NAME}
) )
# Either, create library and binary separately (used for tests), or make them # Either, create library and binary separately (used for tests), or make them
# one in the same so all code is in the binary. # one in the same so all code is in the binary only.
if(ENABLE_TESTS) if(ENABLE_TESTS)
# MainLibrary # MainLibrary
add_library(${DUSK_LIBRARY_TARGET_NAME} STATIC) add_library(${DUSK_LIBRARY_TARGET_NAME} STATIC)
@@ -70,6 +69,12 @@ else()
add_executable(${DUSK_BINARY_TARGET_NAME} ${DUSK_SOURCES_DIR}/null.c) add_executable(${DUSK_BINARY_TARGET_NAME} ${DUSK_SOURCES_DIR}/null.c)
endif() endif()
# Definitions
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
DUSK_TARGET_SYSTEM="${DUSK_TARGET_SYSTEM}"
)
# Toolchains # Toolchains
include(cmake/targets/${DUSK_TARGET_SYSTEM}.cmake) include(cmake/targets/${DUSK_TARGET_SYSTEM}.cmake)

View File

@@ -1,106 +0,0 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
if(NOT TARGET pspsdk)
message(STATUS "Looking for PSPSDK...")
set(PSPSDK_FOUND FALSE CACHE INTERNAL "PSPSDK found")
set(PSPSDK_DOWNLOAD_DIR "${CMAKE_BINARY_DIR}/_pspsdk")
set(PSPSDK_SEARCH_ROOTS
"${PSPSDK_ROOT}"
"$ENV{PSPDEV}"
"$ENV{HOME}/pspdev"
"/usr/local/pspdev"
"/opt/pspdev"
"/usr/pspdev"
"${PSPSDK_DOWNLOAD_DIR}/pspdev"
)
foreach(root IN LISTS PSPSDK_SEARCH_ROOTS)
list(APPEND PSPSDK_BIN_HINTS "${root}/bin")
list(APPEND PSPSDK_INCLUDE_HINTS "${root}/include")
list(APPEND PSPSDK_LIB_HINTS "${root}/lib")
endforeach()
# Find PSP GCC
find_program(PSPSDK_PSP_GCC NAMES psp-gcc HINTS ${PSPSDK_BIN_HINTS})
# If we did not find it, download it.
if(NOT PSPSDK_PSP_GCC)
message(STATUS "psp-gcc not found in system paths. Downloading PSPSDK tarball...")
file(DOWNLOAD
"https://github.com/pspdev/pspdev/releases/download/v20260101/pspdev-ubuntu-latest-x86_64.tar.gz"
"${CMAKE_BINARY_DIR}/pspsdk.tar.gz"
EXPECTED_HASH SHA256=68fb6063323e695a43415a151b3dd9ded61d00605f02d20146cc6933c11830f8
SHOW_PROGRESS
)
# Make output dir
file(MAKE_DIRECTORY "${PSPSDK_DOWNLOAD_DIR}")
# Extract the tarball
execute_process(
COMMAND
${CMAKE_COMMAND} -E tar xzf "${CMAKE_BINARY_DIR}/pspsdk.tar.gz"
WORKING_DIRECTORY
"${PSPSDK_DOWNLOAD_DIR}"
RESULT_VARIABLE
tar_result
)
if(NOT tar_result EQUAL 0)
message(FATAL_ERROR "Failed to extract PSPSDK tarball")
endif()
# Retry discovery with extracted fallback
find_program(PSPSDK_PSP_GCC NAMES psp-gcc HINTS ${PSPSDK_BIN_HINTS})
endif()
if(PSPSDK_PSP_GCC)
get_filename_component(PSPSDK_BIN_ROOT "${PSPSDK_PSP_GCC}" DIRECTORY)
get_filename_component(PSPSDK_ROOT "${PSPSDK_BIN_ROOT}" DIRECTORY)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
set(ENV{PSPDEV} "${PSPSDK_ROOT}")
set(CMAKE_TOOLCHAIN_FILE "${PSPSDK_ROOT}/psp/share/pspdev.cmake")
set(BUILD_PRX ON CACHE BOOL "Build PRX modules")
include("${PSPSDK_ROOT}/psp/share/pspdev.cmake")
set(CMAKE_C_COMPILER ${PSPSDK_BIN_ROOT}/psp-gcc)
set(CMAKE_CXX_COMPILER ${PSPSDK_BIN_ROOT}/psp-g++)
if(NOT DEFINED PSP)
message(FATAL_ERROR "PSP environment variable is not set correctly.")
endif()
add_library(pspsdk INTERFACE IMPORTED)
set_target_properties(pspsdk PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${PSPSDK_INCLUDE_DIR}"
INTERFACE_LINK_DIRECTORIES "${PSPSDK_LIB_DIR}"
)
target_include_directories(pspsdk
INTERFACE
${PSPDEV}/psp/include
${PSPDEV}/psp/sdk/include
)
target_link_directories(pspsdk
INTERFACE
${PSPDEV}/lib
${PSPDEV}/psp/lib
${PSPDEV}/psp/sdk/lib
)
target_link_libraries(pspsdk INTERFACE
pspdebug
pspdisplay
pspge
pspctrl
pspgu
pspaudio
pspaudiolib
psputility
pspvfpu
pspvram
psphprm
)
endif()
endif()

View File

@@ -1,12 +1,16 @@
set(DUSK_LIBRARY_TARGET_NAME "${DUSK_LIBRARY_TARGET_NAME}.elf" CACHE INTERNAL ${DUSK_CACHE_TARGET}) set(DUSK_LIBRARY_TARGET_NAME "${DUSK_LIBRARY_TARGET_NAME}.elf" CACHE INTERNAL ${DUSK_CACHE_TARGET})
# Target definitions
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_DOLPHIN
)
# Custom compiler flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
# configure_file(opengl.pc.in opengl.pc @ONLY)
# Need PkgConfig
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(zip IMPORTED_TARGET libzip) pkg_check_modules(zip IMPORTED_TARGET libzip)
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DOLPHIN
)
# Disable all warnings # Disable all warnings
target_compile_options(${DUSK_LIBRARY_TARGET_NAME} PRIVATE -w) target_compile_options(${DUSK_LIBRARY_TARGET_NAME} PRIVATE -w)
@@ -37,6 +41,7 @@ target_compile_definitions(liblua PRIVATE LUA_USE_C89)
add_library(lua::lua ALIAS liblua) add_library(lua::lua ALIAS liblua)
set(Lua_FOUND TRUE CACHE BOOL "Lua found" FORCE) set(Lua_FOUND TRUE CACHE BOOL "Lua found" FORCE)
# Link libraries
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
cglm cglm
liblua liblua
@@ -46,7 +51,6 @@ target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
) )
# Postbuild # Postbuild
set(DUSK_BINARY_TARGET_NAME_DOL "${DUSK_BUILD_DIR}/Dusk.dol") set(DUSK_BINARY_TARGET_NAME_DOL "${DUSK_BUILD_DIR}/Dusk.dol")
add_custom_command(TARGET ${DUSK_BINARY_TARGET_NAME} POST_BUILD add_custom_command(TARGET ${DUSK_BINARY_TARGET_NAME} POST_BUILD
COMMAND elf2dol COMMAND elf2dol

View File

@@ -0,0 +1,3 @@
include(./dolphin.cmake)
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC DUSK_GAMECUBE)

View File

@@ -10,4 +10,8 @@ target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
m m
) )
# TEST target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_SDL2
DUSK_OPENGL
DUSK_LINUX
)

View File

@@ -1,4 +1,3 @@
# find_package(pspsdk REQUIRED)
find_package(SDL2 REQUIRED) find_package(SDL2 REQUIRED)
find_package(OpenGL REQUIRED) find_package(OpenGL REQUIRED)
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
@@ -14,10 +13,17 @@ target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
lzma lzma
m m
) )
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
${SDL2_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS}
) )
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_SDL2
DUSK_OPENGL
DUSK_PSP
)
# Postbuild, create .pbp file for PSP. # Postbuild, create .pbp file for PSP.
create_pbp_file( create_pbp_file(
TARGET "${DUSK_BINARY_TARGET_NAME}" TARGET "${DUSK_BINARY_TARGET_NAME}"

View File

@@ -1 +1,3 @@
include(./dolphin.cmake) include(./dolphin.cmake)
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC DUSK_WII)

View File

@@ -42,10 +42,6 @@ target_sources(${DUSK_BINARY_TARGET_NAME}
# Defs # Defs
dusk_env_to_h(duskdefs.env duskdefs.h) dusk_env_to_h(duskdefs.env duskdefs.h)
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
DUSK_TARGET_SYSTEM="${DUSK_TARGET_SYSTEM}"
)
# Subdirs # Subdirs
add_subdirectory(assert) add_subdirectory(assert)

View File

@@ -8,7 +8,7 @@
#include "assert.h" #include "assert.h"
#include "debug/debug.h" #include "debug/debug.h"
#ifndef ASSERTIONS_FAKED #ifndef DUSK_ASSERTIONS_FAKED
#ifdef DUSK_TEST_ASSERT #ifdef DUSK_TEST_ASSERT
void assertTrueImpl( void assertTrueImpl(
const char *file, const char *file,

View File

@@ -11,12 +11,12 @@
#ifdef DUSK_TEST_ASSERT #ifdef DUSK_TEST_ASSERT
#include <cmocka.h> #include <cmocka.h>
#ifdef ASSERTIONS_FAKED #ifdef DUSK_ASSERTIONS_FAKED
#error "Cannot fake assertions when DUSK_TEST_ASSERT is set." #error "Cannot fake assertions when DUSK_TEST_ASSERT is set."
#endif #endif
#endif #endif
#ifndef ASSERTIONS_FAKED #ifndef DUSK_ASSERTIONS_FAKED
/** /**
* Assert a given value to be true. * Assert a given value to be true.
* *

View File

@@ -7,4 +7,6 @@
target_sources(${DUSK_LIBRARY_TARGET_NAME} target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC PUBLIC
debug.c debug.c
) )
add_subdirectory(platform)

View File

@@ -6,10 +6,11 @@
*/ */
#include "debug.h" #include "debug.h"
#if DOLPHIN
#include "display/display.h"
static char_t DEBUG_ERROR_BUFFER[16*1024] = {0}; #if PSP
#include "platform/psp.h"
#elif DOLPHIN
#include "platform/dolphin.h"
#endif #endif
void debugPrint(const char_t *message, ...) { void debugPrint(const char_t *message, ...) {
@@ -19,26 +20,9 @@ void debugPrint(const char_t *message, ...) {
va_end(args); va_end(args);
#if PSP #if PSP
FILE *file = fopen("ms0:/PSP/GAME/Dusk/debug.log", "a"); debugPrintPSP(message, args);
if(file) {
va_start(args, message);
vfprintf(file, message, args);
va_end(args);
fclose(file);
}
#elif DOLPHIN #elif DOLPHIN
// append to error buffer debugPrintDolphin(message, args);
size_t start = strlen(DEBUG_ERROR_BUFFER);
va_start(args, message);
vsnprintf(
DEBUG_ERROR_BUFFER + start,
sizeof(DEBUG_ERROR_BUFFER) - start,
message,
args
);
va_end(args);
#endif #endif
} }
@@ -46,50 +30,8 @@ void debugFlush() {
#if PSP #if PSP
// No buffering, so nothing to flush // No buffering, so nothing to flush
#elif DOLPHIN #elif DOLPHIN
// Either create graphics, or hijack the displays' graphics. debugFlushDolphin();
void *xfb = NULL;
GXRModeObj *rmode = NULL;
void *framebuffer;
if(DISPLAY.frameBuffer[0]) {
console_init(
DISPLAY.frameBuffer[0],
20,
20,
DISPLAY.screenMode->fbWidth,
DISPLAY.screenMode->xfbHeight,
DISPLAY.screenMode->fbWidth * VI_DISPLAY_PIX_SZ
);
} else {
VIDEO_Init();
rmode = VIDEO_GetPreferredMode(NULL);
framebuffer = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
console_init(
framebuffer,
20,
20,
rmode->fbWidth,
rmode->xfbHeight,
rmode->fbWidth*VI_DISPLAY_PIX_SZ
);
VIDEO_Configure(rmode);
VIDEO_SetNextFramebuffer(framebuffer);
VIDEO_SetBlack(FALSE);
VIDEO_Flush();
VIDEO_WaitVSync();
if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
}
// Printf
printf("SOB\n");
printf(DEBUG_ERROR_BUFFER);
printf("\nEOB.");
while(SYS_MainLoop()) {
VIDEO_WaitVSync();
}
#else #else
fflush(stdout); fflush(stdout);
#endif #endif
} }

View File

@@ -3,7 +3,10 @@
# This software is released under the MIT License. # This software is released under the MIT License.
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
if(DUSK_TARGET_SYSTEM STREQUAL "linux") # Sources
add_subdirectory(linux)
add_subdirectory(SDL2) target_sources(${DUSK_LIBRARY_TARGET_NAME}
endif() PUBLIC
psp.c
dolphin.c
)

View File

@@ -0,0 +1,70 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "dolphin.h"
#include "display/display.h"
static char_t DEBUG_ERROR_BUFFER[16*1024] = {0};
void debugPrintDolphin(const char_t *message, ...) {
// append to error buffer
size_t start = strlen(DEBUG_ERROR_BUFFER);
va_list args;
va_start(args, message);
vsnprintf(
DEBUG_ERROR_BUFFER + start,
sizeof(DEBUG_ERROR_BUFFER) - start,
message,
args
);
va_end(args);
}
void debugFlushDolphin() {
// Either create graphics, or hijack the displays' graphics.
void *xfb = NULL;
GXRModeObj *rmode = NULL;
void *framebuffer;
if(DISPLAY.frameBuffer[0]) {
console_init(
DISPLAY.frameBuffer[0],
20,
20,
DISPLAY.screenMode->fbWidth,
DISPLAY.screenMode->xfbHeight,
DISPLAY.screenMode->fbWidth * VI_DISPLAY_PIX_SZ
);
} else {
VIDEO_Init();
rmode = VIDEO_GetPreferredMode(NULL);
framebuffer = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
console_init(
framebuffer,
20,
20,
rmode->fbWidth,
rmode->xfbHeight,
rmode->fbWidth*VI_DISPLAY_PIX_SZ
);
VIDEO_Configure(rmode);
VIDEO_SetNextFramebuffer(framebuffer);
VIDEO_SetBlack(FALSE);
VIDEO_Flush();
VIDEO_WaitVSync();
if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
}
// Printf
printf("SOB\n");
printf(DEBUG_ERROR_BUFFER);
printf("\nEOB.");
while(SYS_MainLoop()) {
VIDEO_WaitVSync();
}
}

View File

@@ -0,0 +1,22 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "debug/debug.h"
/**
* Platform-specific debug print function for Dolphin.
*
* @param message The message format string.
* @param ... Additional arguments for the format string.
*/
void debugPrintDolphin(const char_t *message, ...);
/**
* Flushes the Dolphin debug output buffer.
*/
void debugFlushDolphin();

19
src/debug/platform/psp.c Normal file
View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "psp.h"
void debugPrintPSP(const char_t *message, ...) {
FILE *file = fopen("ms0:/PSP/GAME/Dusk/debug.log", "a");
if(!file) return;
va_list args;
va_start(args, message);
vfprintf(file, message, args);
va_end(args);
fclose(file);
}

17
src/debug/platform/psp.h Normal file
View File

@@ -0,0 +1,17 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "debug/debug.h"
/**
* Platform-specific debug print function for PSP.
*
* @param message The message format string.
* @param ... Additional arguments for the format string.
*/
void debugPrintPSP(const char_t *message, ...);

View File

@@ -17,6 +17,7 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
add_subdirectory(camera) add_subdirectory(camera)
add_subdirectory(mesh) add_subdirectory(mesh)
add_subdirectory(texture) add_subdirectory(texture)
add_subdirectory(platform)
# Color definitions # Color definitions
dusk_run_python( dusk_run_python(

View File

@@ -26,157 +26,9 @@ errorret_t displayInit(void) {
memoryZero(&DISPLAY, sizeof(DISPLAY)); memoryZero(&DISPLAY, sizeof(DISPLAY));
#if DISPLAY_SDL2 #if DISPLAY_SDL2
uint32_t flags = SDL_INIT_VIDEO; displaySDL2Init();
#if INPUT_GAMEPAD == 1
flags |= SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK;
#endif
if(SDL_Init(flags) != 0) {
errorThrow("SDL Failed to Initialize: %s", SDL_GetError());
}
// Set OpenGL attributes (Needs to be done now or later?)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
// Create window with OpenGL flag.
DISPLAY.window = SDL_CreateWindow(
"Dusk",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
DISPLAY_WINDOW_WIDTH_DEFAULT,
DISPLAY_WINDOW_HEIGHT_DEFAULT,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI |
SDL_WINDOW_OPENGL
);
if(!DISPLAY.window) {
errorThrow("SDL_CreateWindow failed: %s", SDL_GetError());
}
// Create OpenGL context
DISPLAY.glContext = SDL_GL_CreateContext(DISPLAY.window);
if(!DISPLAY.glContext) {
errorThrow("SDL_GL_CreateContext failed: %s", SDL_GetError());
}
SDL_GL_SetSwapInterval(1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);// PSP defaults this on?
glShadeModel(GL_SMOOTH); // Fixes color on PSP?
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glClearDepth(1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glEnableClientState(GL_COLOR_ARRAY);// To confirm: every frame on PSP?
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
// Get and validate GL state.
GLenum err = glGetError();
if(err != GL_NO_ERROR) {
assertUnreachable("GL Error before checking support");
}
// Check if paletted textures are supported.
#if PSP
DISPLAY.usingShaderedPalettes = false;
#else
GLint mask = 0;
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask);
DISPLAY.usingShaderedPalettes = true;
if(mask & GL_CONTEXT_CORE_PROFILE_BIT) {
GLint numExtens = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtens);
for(GLint i = 0; i < numExtens; ++i) {
const char* e = (const char*)glGetStringi(GL_EXTENSIONS, i);
if(!e) continue;
if(stringCompare(e, "GL_EXT_paletted_texture") != 0) continue;
DISPLAY.usingShaderedPalettes = false;
break;
}
} else {
const char* ext = (const char*)glGetString(GL_EXTENSIONS);
DISPLAY.usingShaderedPalettes = !(
ext && strstr(ext, "GL_EXT_paletted_texture")
);
}
#endif
#elif DOLPHIN #elif DOLPHIN
VIDEO_Init(); displayDolphinInit();
DISPLAY.screenMode = VIDEO_GetPreferredMode(NULL);
DISPLAY.frameBuffer[0] = MEM_K0_TO_K1(
SYS_AllocateFramebuffer(DISPLAY.screenMode)
);
DISPLAY.frameBuffer[1] = MEM_K0_TO_K1(
SYS_AllocateFramebuffer(DISPLAY.screenMode)
);
VIDEO_Configure(DISPLAY.screenMode);
VIDEO_SetNextFramebuffer(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer]);
// VIDEO_SetPostRetraceCallback(copy_buffers);
VIDEO_SetBlack(FALSE);
VIDEO_Flush();
VIDEO_WaitVSync();
if(DISPLAY.screenMode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();
DISPLAY.fifoBuffer = memalign(32, DISPLAY_FIFO_SIZE);
memoryZero(DISPLAY.fifoBuffer, DISPLAY_FIFO_SIZE);
GX_Init(DISPLAY.fifoBuffer, DISPLAY_FIFO_SIZE);
// This seems to be mostly related to interlacing vs progressive
GX_SetViewport(
0, 0,
DISPLAY.screenMode->fbWidth, DISPLAY.screenMode->efbHeight,
0, 1
);
float_t yscale = GX_GetYScaleFactor(
DISPLAY.screenMode->efbHeight, DISPLAY.screenMode->xfbHeight
);
uint32_t xfbHeight = GX_SetDispCopyYScale(yscale);
GX_SetScissor(
0, 0,
DISPLAY.screenMode->fbWidth, DISPLAY.screenMode->efbHeight
);
GX_SetDispCopySrc(
0, 0,
DISPLAY.screenMode->fbWidth, DISPLAY.screenMode->efbHeight
);
GX_SetDispCopyDst(DISPLAY.screenMode->fbWidth, xfbHeight);
GX_SetCopyFilter(
DISPLAY.screenMode->aa,
DISPLAY.screenMode->sample_pattern,
GX_TRUE,
DISPLAY.screenMode->vfilter
);
GX_SetFieldMode(
DISPLAY.screenMode->field_rendering,
(
(DISPLAY.screenMode->viHeight == 2 * DISPLAY.screenMode->xfbHeight) ?
GX_ENABLE :
GX_DISABLE
)
);
// Setup cull modes
GX_SetCullMode(GX_CULL_NONE);
GX_SetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE);
GX_CopyDisp(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer], GX_TRUE);
GX_SetDispCopyGamma(GX_GM_1_0);
GX_ClearVtxDesc();
GX_SetVtxDesc(GX_VA_POS, GX_INDEX16);
GX_SetVtxDesc(GX_VA_CLR0, GX_INDEX16);
GX_SetVtxDesc(GX_VA_TEX0, GX_INDEX16);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_U8, 0);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
#endif #endif
quadInit(); quadInit();
@@ -191,35 +43,7 @@ errorret_t displayInit(void) {
errorret_t displayUpdate(void) { errorret_t displayUpdate(void) {
#if DISPLAY_SDL2 #if DISPLAY_SDL2
SDL_Event event; displaySDL2Update();
while(SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_QUIT: {
ENGINE.running = false;
break;
}
case SDL_WINDOWEVENT: {
switch(event.window.event) {
case SDL_WINDOWEVENT_CLOSE: {
ENGINE.running = false;
break;
}
default: {
break;
}
}
}
default: {
break;
}
}
}
SDL_GL_MakeCurrent(DISPLAY.window, DISPLAY.glContext);
#endif #endif
// Reset state // Reset state
@@ -243,22 +67,9 @@ errorret_t displayUpdate(void) {
screenRender(); screenRender();
#if DISPLAY_SDL2 #if DISPLAY_SDL2
SDL_GL_SwapWindow(DISPLAY.window); displaySDL2Swap();
GLenum err;
while((err = glGetError()) != GL_NO_ERROR) {
debugPrint("GL Error: %d\n", err);
}
#elif DOLPHIN #elif DOLPHIN
GX_DrawDone(); displayDolphinSwap();
DISPLAY.whichFrameBuffer ^= 1;
GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
GX_SetColorUpdate(GX_TRUE);
GX_CopyDisp(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer], GX_TRUE);
VIDEO_SetNextFramebuffer(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer]);
VIDEO_Flush();
VIDEO_WaitVSync();
#endif #endif
// For now, we just return an OK error. // For now, we just return an OK error.
@@ -271,15 +82,7 @@ errorret_t displayDispose(void) {
textDispose(); textDispose();
#if DISPLAY_SDL2 #if DISPLAY_SDL2
if(DISPLAY.glContext) { displaySDL2Dispose();
SDL_GL_DeleteContext(DISPLAY.glContext);
DISPLAY.glContext = NULL;
}
if(DISPLAY.window) {
SDL_DestroyWindow(DISPLAY.window);
DISPLAY.window = NULL;
}
SDL_Quit();
#endif #endif
// For now, we just return an OK error. // For now, we just return an OK error.

View File

@@ -10,19 +10,17 @@
#include "error/error.h" #include "error/error.h"
#include "display/camera/camera.h" #include "display/camera/camera.h"
#include "display/framebuffer.h" #include "display/framebuffer.h"
#if DISPLAY_SDL2
#include "display/platform/sdl2.h"
#elif DOLPHIN
#include "display/platform/dolphin.h"
#endif
typedef struct { typedef struct {
#if DISPLAY_SDL2 #if DISPLAY_SDL2
SDL_Window *window; displaysdl2_t sdl2;
SDL_GLContext glContext;
bool_t usingShaderedPalettes;
#elif DOLPHIN #elif DOLPHIN
void *frameBuffer[2];// Double-Bufferred displaydolphin_t dolphin;
int whichFrameBuffer;
GXRModeObj *screenMode;
void *fifoBuffer;
#endif #endif
} display_t; } display_t;

View File

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

View File

@@ -0,0 +1,92 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "dolphin.h"
void displayInitDolphin(void) {
VIDEO_Init();
DISPLAY.screenMode = VIDEO_GetPreferredMode(NULL);
DISPLAY.frameBuffer[0] = MEM_K0_TO_K1(
SYS_AllocateFramebuffer(DISPLAY.screenMode)
);
DISPLAY.frameBuffer[1] = MEM_K0_TO_K1(
SYS_AllocateFramebuffer(DISPLAY.screenMode)
);
VIDEO_Configure(DISPLAY.screenMode);
VIDEO_SetNextFramebuffer(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer]);
// VIDEO_SetPostRetraceCallback(copy_buffers);
VIDEO_SetBlack(FALSE);
VIDEO_Flush();
VIDEO_WaitVSync();
if(DISPLAY.screenMode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();
DISPLAY.fifoBuffer = memalign(32, DISPLAY_FIFO_SIZE);
memoryZero(DISPLAY.fifoBuffer, DISPLAY_FIFO_SIZE);
GX_Init(DISPLAY.fifoBuffer, DISPLAY_FIFO_SIZE);
// This seems to be mostly related to interlacing vs progressive
GX_SetViewport(
0, 0,
DISPLAY.screenMode->fbWidth, DISPLAY.screenMode->efbHeight,
0, 1
);
float_t yscale = GX_GetYScaleFactor(
DISPLAY.screenMode->efbHeight, DISPLAY.screenMode->xfbHeight
);
uint32_t xfbHeight = GX_SetDispCopyYScale(yscale);
GX_SetScissor(
0, 0,
DISPLAY.screenMode->fbWidth, DISPLAY.screenMode->efbHeight
);
GX_SetDispCopySrc(
0, 0,
DISPLAY.screenMode->fbWidth, DISPLAY.screenMode->efbHeight
);
GX_SetDispCopyDst(DISPLAY.screenMode->fbWidth, xfbHeight);
GX_SetCopyFilter(
DISPLAY.screenMode->aa,
DISPLAY.screenMode->sample_pattern,
GX_TRUE,
DISPLAY.screenMode->vfilter
);
GX_SetFieldMode(
DISPLAY.screenMode->field_rendering,
(
(DISPLAY.screenMode->viHeight == 2 * DISPLAY.screenMode->xfbHeight) ?
GX_ENABLE :
GX_DISABLE
)
);
// Setup cull modes
GX_SetCullMode(GX_CULL_NONE);
GX_SetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE);
GX_CopyDisp(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer], GX_TRUE);
GX_SetDispCopyGamma(GX_GM_1_0);
GX_ClearVtxDesc();
GX_SetVtxDesc(GX_VA_POS, GX_INDEX16);
GX_SetVtxDesc(GX_VA_CLR0, GX_INDEX16);
GX_SetVtxDesc(GX_VA_TEX0, GX_INDEX16);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_U8, 0);
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
}
void displayDolphinSwap(void) {
GX_DrawDone();
DISPLAY.whichFrameBuffer ^= 1;
GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
GX_SetColorUpdate(GX_TRUE);
GX_CopyDisp(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer], GX_TRUE);
VIDEO_SetNextFramebuffer(DISPLAY.frameBuffer[DISPLAY.whichFrameBuffer]);
VIDEO_Flush();
VIDEO_WaitVSync();
}

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#include "display/displaydefs.h"
typedef struct {
void *frameBuffer[2];// Double-Bufferred
int whichFrameBuffer;
GXRModeObj *screenMode;
void *fifoBuffer;
} displaydolphin_t;
/**
* Initializes the display for Dolphin.
*/
void displayDolphinInit(void);
/**
* Swaps the back buffer to the front for Dolphin.
*/
void displayDolphinSwap(void);

View File

@@ -0,0 +1,12 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "psp.h"
void displayInitPSP(void) {
DISPLAY.usingShaderedPalettes = false;
}

View File

@@ -0,0 +1,13 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
/**
* Initializes the display for PSP.
*/
void displayInitPSP(void);

124
src/display/platform/sdl2.c Normal file
View File

@@ -0,0 +1,124 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "sdl2.h"
void displaySDL2Init(void) {
uint32_t flags = SDL_INIT_VIDEO;
#if INPUT_GAMEPAD == 1
flags |= SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK;
#endif
if(SDL_Init(flags) != 0) {
errorThrow("SDL Failed to Initialize: %s", SDL_GetError());
}
// Set OpenGL attributes (Needs to be done now or later?)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
// Create window with OpenGL flag.
DISPLAY.window = SDL_CreateWindow(
"Dusk",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
DISPLAY_WINDOW_WIDTH_DEFAULT,
DISPLAY_WINDOW_HEIGHT_DEFAULT,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI |
SDL_WINDOW_OPENGL
);
if(!DISPLAY.window) {
errorThrow("SDL_CreateWindow failed: %s", SDL_GetError());
}
// Create OpenGL context
DISPLAY.glContext = SDL_GL_CreateContext(DISPLAY.window);
if(!DISPLAY.glContext) {
errorThrow("SDL_GL_CreateContext failed: %s", SDL_GetError());
}
SDL_GL_SetSwapInterval(1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);// PSP defaults this on?
glShadeModel(GL_SMOOTH); // Fixes color on PSP?
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glClearDepth(1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glEnableClientState(GL_COLOR_ARRAY);// To confirm: every frame on PSP?
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
// Get and validate GL state.
GLenum err = glGetError();
if(err != GL_NO_ERROR) {
assertUnreachable("GL Error before checking support");
}
#if PSP
displayInitPSP();
#else
#endif
}
void displaySDL2Update(void) {
SDL_Event event;
while(SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_QUIT: {
ENGINE.running = false;
break;
}
case SDL_WINDOWEVENT: {
switch(event.window.event) {
case SDL_WINDOWEVENT_CLOSE: {
ENGINE.running = false;
break;
}
default: {
break;
}
}
}
default: {
break;
}
}
}
SDL_GL_MakeCurrent(DISPLAY.window, DISPLAY.glContext);
}
void displaySDL2Swap(void) {
SDL_GL_SwapWindow(DISPLAY.window);
GLenum err;
while((err = glGetError()) != GL_NO_ERROR) {
debugPrint("GL Error: %d\n", err);
}
}
void displaySDL2Dispose(void) {
if(DISPLAY.glContext) {
SDL_GL_DeleteContext(DISPLAY.glContext);
DISPLAY.glContext = NULL;
}
if(DISPLAY.window) {
SDL_DestroyWindow(DISPLAY.window);
DISPLAY.window = NULL;
}
SDL_Quit();
}

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct {
SDL_Window *window;
SDL_GLContext glContext;
bool_t usingShaderedPalettes;
} displaysdl2_t;
/**
* Initializes the display for SDL2.
*/
void displaySDL2Init(void);
/**
* Updates the display for SDL2.
*/
void displaySDL2Update(void);
/**
* Swaps the display buffers for SDL2.
*/
void displaySDL2Swap(void);
/**
* Disposes of the display for SDL2.
*/
void displaySDL2Dispose(void);

View File

@@ -6,6 +6,7 @@
*/ */
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
@@ -22,17 +23,9 @@
#include <cglm/vec2.h> #include <cglm/vec2.h>
#if PSP #if PSP
#include <pspkernel.h> #include "duskpsp.h"
#include <pspdebug.h> #elif DOLPHIN
#include <pspdisplay.h> #include "duskdolphin.h"
#include <pspctrl.h>
#include <psphprm.h>
#endif
#if DOLPHIN
#include <ogcsys.h>
#include <gccore.h>
#include <malloc.h>
#endif #endif
typedef bool bool_t; typedef bool bool_t;

11
src/duskdolphin.h Normal file
View File

@@ -0,0 +1,11 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include <ogcsys.h>
#include <gccore.h>
#include <malloc.h>

13
src/duskpsp.h Normal file
View File

@@ -0,0 +1,13 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspdisplay.h>
#include <pspctrl.h>
#include <psphprm.h>