22 Commits

Author SHA1 Message Date
YourWishes 643a8077dd Socket first pass 2026-04-19 18:53:09 -05:00
YourWishes 4205899f5a No idea why gamecube is crashing, disabling this for now 2026-04-18 21:57:57 -05:00
YourWishes 7dd3940770 Moved code to dolphin for network 2026-04-18 17:41:30 -05:00
YourWishes 00d94e3015 Slight wii improvements 2026-04-18 16:01:53 -05:00
YourWishes 7bacb3ee2b Testing on real wii hardware some more 2026-04-18 15:59:25 -05:00
YourWishes 8e49be5ac4 Testing some wii rendering bugs 2026-04-18 15:29:40 -05:00
YourWishes 3b94598d2c Fixed dolphin matricies the ugly way 2026-04-18 00:36:35 -05:00
YourWishes bddc9af3b6 "Improved" Dolphin matricies slightly 2026-04-18 00:32:50 -05:00
YourWishes 2451d73a7c Improved Wii aspect ratio significantly 2026-04-17 23:49:39 -05:00
YourWishes 1dd2efa182 Dolphin compiles, network untested 2026-04-17 22:53:49 -05:00
YourWishes acea610773 Disable curl on linux 2026-04-17 22:53:29 -05:00
YourWishes 8f2f1fd496 Added network info 2026-04-17 17:00:03 -05:00
YourWishes 39c775872a PSP networking matches linux now. 2026-04-17 16:32:45 -05:00
YourWishes bdb3cbd109 Fixed crash for cross/cancel logic 2026-04-17 16:02:45 -05:00
YourWishes ff84ce2b04 Added PSP Accept/Cance 2026-04-17 15:28:03 -05:00
YourWishes 225f405592 PSP Networking refactor 2026-04-17 14:57:10 -05:00
YourWishes 715ecffa18 Taking a break on net 2026-04-16 06:38:56 -05:00
YourWishes e51cdc8992 PSP net code first pass 2026-04-15 15:50:43 -05:00
YourWishes 133685ea37 Linux HTTP implementation 2026-04-15 15:11:44 -05:00
YourWishes 6aff98d555 Fix PSP build 2026-04-15 06:10:38 -05:00
YourWishes acdc524284 bit more accurate 2026-04-15 06:04:30 -05:00
YourWishes 1ee5ec7b43 Vita builds for the first time 2026-04-15 05:52:30 -05:00
88 changed files with 2566 additions and 81 deletions
+16
View File
@@ -53,6 +53,22 @@ jobs:
path: ./git-artifcats/Dusk
if-no-files-found: error
build-vita:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up Docker
uses: docker/setup-docker-action@v5
- name: Build Vita
run: ./scripts/build-vita-docker.sh
- name: Upload Vita binary
uses: actions/upload-artifact@v6
with:
name: dusk-vita
path: build-vita/Dusk.vpk
if-no-files-found: error
build-knulli:
runs-on: ubuntu-latest
steps:
+2 -2
View File
@@ -9,8 +9,8 @@ if PSP then
inputBind("down", INPUT_ACTION_DOWN)
inputBind("left", INPUT_ACTION_LEFT)
inputBind("right", INPUT_ACTION_RIGHT)
inputBind("circle", INPUT_ACTION_CANCEL)
inputBind("cross", INPUT_ACTION_ACCEPT)
inputBind("accept", INPUT_ACTION_ACCEPT)
inputBind("cancel", INPUT_ACTION_CANCEL)
inputBind("select", INPUT_ACTION_RAGEQUIT)
inputBind("lstick_up", INPUT_ACTION_UP)
inputBind("lstick_down", INPUT_ACTION_DOWN)
+6 -1
View File
@@ -2,4 +2,9 @@ include(cmake/targets/dolphin.cmake)
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_GAMECUBE
)
)
# Link libraries
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
# bba
)
+5 -1
View File
@@ -1,6 +1,7 @@
# Find link platform-specific libraries
find_package(SDL2 REQUIRED)
find_package(OpenGL REQUIRED)
# find_package(CURL REQUIRED)
# Setup endianess at compile time to optimize.
include(TestBigEndian)
@@ -16,12 +17,13 @@ else()
endif()
# Link required libraries.
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
SDL2
pthread
OpenGL::GL
GL
m
# CURL::libcurl
)
# Define platform-specific macros.
@@ -38,4 +40,6 @@ target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_INPUT_POINTER
DUSK_INPUT_GAMEPAD
DUSK_TIME_DYNAMIC
DUSK_NETWORK_IPV6
THREAD_PTHREAD=1
)
+6
View File
@@ -24,6 +24,11 @@ target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
pspvfpu
pspvram
psphprm
pspnet
pspnet_inet
pspnet_apctl
psphttp
pspssl
)
target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE
@@ -39,6 +44,7 @@ target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
DUSK_OPENGL_LEGACY
DUSK_DISPLAY_WIDTH=480
DUSK_DISPLAY_HEIGHT=272
THREAD_PTHREAD=1
)
# Postbuild, create .pbp file for PSP.
+110
View File
@@ -0,0 +1,110 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
if(NOT DEFINED ENV{VITASDK})
message(FATAL_ERROR "VITASDK environment variable is not set.")
endif()
include("$ENV{VITASDK}/share/vita.cmake" REQUIRED)
set(VITA_APP_NAME "Dusk")
set(VITA_TITLEID "DUSK00001")
set(VITA_VERSION "01.00")
find_package(SDL2 REQUIRED)
# Custom flags for cglm
set(CGLM_SHARED OFF CACHE BOOL "Build cglm shared" FORCE)
set(CGLM_STATIC ON CACHE BOOL "Build cglm static" FORCE)
find_package(cglm REQUIRED)
# Compile lua
include(FetchContent)
FetchContent_Declare(
liblua
URL https://www.lua.org/ftp/lua-5.5.0.tar.gz
)
FetchContent_MakeAvailable(liblua)
set(LUA_SRC_DIR "${liblua_SOURCE_DIR}/src")
set(LUA_C_FILES
lapi.c lauxlib.c lbaselib.c lcode.c lcorolib.c lctype.c ldblib.c ldebug.c
ldo.c ldump.c lfunc.c lgc.c linit.c liolib.c llex.c lmathlib.c lmem.c
loadlib.c lobject.c lopcodes.c loslib.c lparser.c lstate.c lstring.c
lstrlib.c ltable.c ltablib.c ltm.c lundump.c lutf8lib.c lvm.c lzio.c
)
list(TRANSFORM LUA_C_FILES PREPEND "${LUA_SRC_DIR}/")
add_library(liblua STATIC ${LUA_C_FILES})
target_include_directories(liblua PUBLIC "${LUA_SRC_DIR}")
target_compile_definitions(liblua PRIVATE LUA_USE_C89)
add_library(lua::lua ALIAS liblua)
set(Lua_FOUND TRUE CACHE BOOL "Lua found" FORCE)
# Link libraries
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
${SDL2_LIBRARIES}
liblua
cglm
SDL2
SDL2main
zip
bz2
z
zstd
crypto
lzma
m
pthread
stdc++
vitaGL
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
libtaihen_stub.a
# SceKernel_stub
SceAppUtil_stub
SceHid_stub
SceRtc_stub
)
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_OPENGL_LEGACY
DUSK_DISPLAY_WIDTH=960
DUSK_DISPLAY_HEIGHT=544
)
# Post-build: create SELF from the ELF binary (UNSAFE = homebrew, no signing)
vita_create_self(${DUSK_BINARY_TARGET_NAME}.self ${DUSK_BINARY_TARGET_NAME} UNSAFE)
# Post-build: package SELF + assets into a .vpk installable on the Vita
vita_create_vpk(${DUSK_BINARY_TARGET_NAME}.vpk ${VITA_TITLEID} ${DUSK_BINARY_TARGET_NAME}.self
VERSION ${VITA_VERSION}
NAME ${VITA_APP_NAME}
FILE ${DUSK_ASSETS_ZIP} dusk.dsk
)
+13
View File
@@ -0,0 +1,13 @@
FROM vitasdk/vitasdk:latest
WORKDIR /workdir
# Install vitaGL and its dependencies (vitashark, SceShaccCg) via vdpm
RUN which vdpm
# Install Python (needed for Dusk code generation tools)
RUN apk add --no-cache \
python3 \
py3-pip \
py3-dotenv
VOLUME ["/workdir"]
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
docker build -t dusk-vita -f docker/vita/Dockerfile .
docker run --rm -v $(pwd):/workdir dusk-vita /bin/bash -c "./scripts/build-vita.sh"
+13
View File
@@ -0,0 +1,13 @@
#!/bin/bash
if [ -z "$VITASDK" ]; then
echo "VITASDK environment variable is not set. Please set it to the path of your VitaSDK installation."
exit 1
fi
mkdir -p build-vita
cd build-vita
cmake \
-DCMAKE_TOOLCHAIN_FILE=$VITASDK/share/vita.toolchain.cmake \
-DDUSK_TARGET_SYSTEM=vita \
..
make -j$(nproc)
+6 -1
View File
@@ -16,7 +16,12 @@ elseif(DUSK_TARGET_SYSTEM STREQUAL "psp")
add_subdirectory(dusksdl2)
add_subdirectory(duskgl)
elseif(DUSK_TARGET_SYSTEM STREQUAL "gamecube" OR DUSK_TARGET_SYSTEM STREQUAL "wii")
elseif(DUSK_TARGET_SYSTEM STREQUAL "vita")
add_subdirectory(duskvita)
add_subdirectory(dusksdl2)
add_subdirectory(duskgl)
elseif(DUSK_TARGET_SYSTEM STREQUAL "wii" OR DUSK_TARGET_SYSTEM STREQUAL "gamecube")
add_subdirectory(duskdolphin)
endif()
+3 -4
View File
@@ -72,10 +72,9 @@ add_subdirectory(locale)
add_subdirectory(physics)
add_subdirectory(scene)
add_subdirectory(script)
add_subdirectory(system)
add_subdirectory(time)
add_subdirectory(ui)
add_subdirectory(network)
add_subdirectory(util)
# if(DUSK_TARGET_SYSTEM STREQUAL "linux" OR DUSK_TARGET_SYSTEM STREQUAL "psp")
# add_subdirectory(thread)
# endif()
add_subdirectory(thread)
+1 -4
View File
@@ -64,7 +64,7 @@ errorret_t displayInit(void) {
glm_perspective(
glm_rad(45.0f),
(float_t)SCREEN.width / (float_t)SCREEN.height,
SCREEN.aspect,
0.1f,
100.0f,
proj
@@ -101,9 +101,6 @@ errorret_t displayUpdate(void) {
errorChain(sceneRender());
// Render UI
// uiRender();
// Finish up
screenUnbind();
screenRender();
@@ -40,6 +40,17 @@ uint32_t frameBufferGetHeight(const framebuffer_t *framebuffer) {
return frameBufferPlatformGetHeight(framebuffer);
}
float_t frameBufferGetAspect(const framebuffer_t *framebuffer) {
#ifdef frameBufferPlatformGetAspect
return frameBufferPlatformGetAspect(framebuffer);
#endif
uint32_t width = frameBufferGetWidth(framebuffer);
uint32_t height = frameBufferGetHeight(framebuffer);
if(height == 0) return 1.0f; // Avoid divide by zero, just return 1:1 aspect.
return (float_t)width / (float_t)height;
}
void frameBufferClear(const uint8_t flags, const color_t color) {
frameBufferPlatformClear(flags, color);
}
@@ -58,6 +58,16 @@ uint32_t frameBufferGetWidth(const framebuffer_t *framebuffer);
*/
uint32_t frameBufferGetHeight(const framebuffer_t *framebuffer);
/**
* Returns the aspect ratio of the framebuffer. This is ALMOST always just
* the width / height, however some platforms may choose to override this if
* they have stretched styled back buffers, e.g. 640x480 stretched.
*
* @param framebuffer The framebuffer to get the aspect ratio of.
* @return The aspect ratio of the framebuffer.
*/
float_t frameBufferGetAspect(const framebuffer_t *framebuffer);
/**
* Binds the framebuffer for rendering, or the backbuffer if the framebuffer
* provided is NULL.
+4 -4
View File
@@ -52,7 +52,7 @@ errorret_t screenBind() {
// Screen mode backbuffer uses the full display size
SCREEN.width = frameBufferGetWidth(FRAMEBUFFER_BOUND);
SCREEN.height = frameBufferGetHeight(FRAMEBUFFER_BOUND);
SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height;
SCREEN.aspect = frameBufferGetAspect(FRAMEBUFFER_BOUND);
// No needd for a framebuffer.
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
@@ -100,8 +100,7 @@ errorret_t screenBind() {
int32_t fbWidth, fbHeight;
fbWidth = frameBufferGetWidth(FRAMEBUFFER_BOUND);
fbHeight = frameBufferGetHeight(FRAMEBUFFER_BOUND);
float_t currentAspect = (float_t)fbWidth / (float_t)fbHeight;
float_t currentAspect = frameBufferGetAspect(FRAMEBUFFER_BOUND);
if(currentAspect == SCREEN.aspectRatio.ratio) {
// No need to use framebuffer.
SCREEN.width = fbWidth;
@@ -129,13 +128,14 @@ errorret_t screenBind() {
if(SCREEN.framebufferReady) {
// Is current framebuffer the correct size?
int32_t curFbWidth, curFbHeight;
float_t curFbAspect = frameBufferGetAspect(&SCREEN.framebuffer);
curFbWidth = frameBufferGetWidth(&SCREEN.framebuffer);
curFbHeight = frameBufferGetHeight(&SCREEN.framebuffer);
if(curFbWidth == newFbWidth && curFbHeight == newFbHeight) {
// Correct size, nothing to do.
SCREEN.width = newFbWidth;
SCREEN.height = newFbHeight;
SCREEN.aspect = (float_t)SCREEN.width / (float_t)SCREEN.height;
SCREEN.aspect = curFbAspect;
errorChain(frameBufferBind(&SCREEN.framebuffer));
errorOk();
}
+6 -3
View File
@@ -70,9 +70,7 @@ errorret_t textDraw(
const float_t x,
const float_t y,
const char_t *text,
#if MESH_ENABLE_COLOR
const color_t color,
#endif
const color_t color,
const tileset_t *tileset,
texture_t *texture
) {
@@ -83,6 +81,11 @@ errorret_t textDraw(
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, texture));
#if MESH_ENABLE_COLOR
#else
errorChain(shaderSetColor(&SHADER_UNLIT, SHADER_UNLIT_COLOR, color));
#endif
// errorChain(spriteBatchPush(
// // texture,
// posX, posY,
+1 -3
View File
@@ -66,9 +66,7 @@ errorret_t textDraw(
const float_t x,
const float_t y,
const char_t *text,
#if MESH_ENABLE_COLOR
const color_t color,
#endif
const color_t color,
const tileset_t *tileset,
texture_t *texture
);
+123 -19
View File
@@ -20,14 +20,104 @@
#include "entity/component/physics/entityphysics.h"
#include "game/game.h"
#include "physics/physicsmanager.h"
#include "network/network.h"
#include "network/networkinfo.h"
#include "network/networksocketclient.h"
#include "system/system.h"
#include "display/mesh/cube.h"
#include "display/mesh/plane.h"
engine_t ENGINE;
entityid_t phBoxEnt;
componentid_t phBoxPhys;
networksocketclient_t sockClient;
float_t onlineSwapTime = FLT_MAX;
void goOnline();
void goOffline();
void onSocketConnected(void *user) {
sceneLog("Socket connected.\n");
}
void onSocketError(errorret_t error, void *user) {
sceneLog("Socket error: %s\n", error.state->message);
errorCatch(errorPrint(error));
}
void onSocketDisconnected(void *user) {
sceneLog("Socket disconnected.\n");
}
void onNetworkConnected(void *user) {
onlineSwapTime = TIME.time + 1.5f;
networkinfo_t info = networkGetInfo();
if(info.type == NETWORK_TYPE_IPV4) {
sceneLog(
"Connected to network with IPv4 address: " NETWORK_INFO_FORMAT_IPV4 "\n",
info.ipv4.ip[0], info.ipv4.ip[1], info.ipv4.ip[2], info.ipv4.ip[3]
);
#ifdef DUSK_NETWORK_IPV6
} else if(info.type == NETWORK_TYPE_IPV6) {
sceneLog(
"Connected to network with IPv6 address: " NETWORK_INFO_FORMAT_IPV6 "\n",
info.ipv6.ip[0], info.ipv6.ip[1], info.ipv6.ip[2], info.ipv6.ip[3],
info.ipv6.ip[4], info.ipv6.ip[5], info.ipv6.ip[6], info.ipv6.ip[7],
info.ipv6.ip[8], info.ipv6.ip[9], info.ipv6.ip[10], info.ipv6.ip[11],
info.ipv6.ip[12], info.ipv6.ip[13], info.ipv6.ip[14], info.ipv6.ip[15]
);
#endif
}
sceneLog("Network connected, opening socket: %.2f1.\n", onlineSwapTime);
networkSocketClientInit(
&sockClient,
"google.com",
443,
NULL,
onSocketConnected,
onSocketError,
onSocketDisconnected
);
onlineSwapTime = FLT_MAX;
// sceneLog("Network connected, I will disconnect at: %.2f1.\n", onlineSwapTime);
}
void onNetworkFailed(errorret_t error, void *user) {
onlineSwapTime = TIME.time + 3.0f;
sceneLog("Failed to connect to network, will try again at %.2f1.\n", onlineSwapTime);
}
void onNetworkDisconnected(errorret_t error, void *user) {
onlineSwapTime = TIME.time + 3.0f;
sceneLog("Network disconnected, will go online at %.2f1.\n", onlineSwapTime);
errorCatch(errorPrint(error));
}
void onNetworkDisconnectFinished(void *user) {
onlineSwapTime = TIME.time + 3.0f;
sceneLog("Finished disconnecting from network, will go online at %.2f1.\n", onlineSwapTime);
}
void goOnline() {
sceneLog("Going online...\n");
networkRequestConnection(
onNetworkConnected,
onNetworkFailed,
onNetworkDisconnected,
NULL
);
}
void goOffline() {
sceneLog("Going offline...\n");
networkRequestDisconnection(onNetworkDisconnectFinished, NULL);
}
/* Kept module-level only because engineUpdate needs them for the reset. */
static entityid_t phBoxEnt;
static componentid_t phBoxPhys;
errorret_t engineInit(const int32_t argc, const char_t **argv) {
memoryZero(&ENGINE, sizeof(engine_t));
@@ -36,6 +126,7 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
ENGINE.argv = argv;
// Init systems. Order is important.
errorChain(systemInit());
timeInit();
errorChain(inputInit());
errorChain(assetInit());
@@ -46,9 +137,13 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
errorChain(sceneInit());
entityManagerInit();
physicsManagerInit();
// errorChain(networkInit());
errorChain(gameInit());
/* ---- Camera ---- */
onlineSwapTime = TIME.time + 1.0f;
sceneLog("Init done, going to queue online at %.2f1.\n", onlineSwapTime);
// Camera
entityid_t cam = entityManagerAdd();
componentid_t camPos = entityAddComponent(cam, COMPONENT_TYPE_POSITION);
float_t distance = 6.0f;
@@ -59,13 +154,13 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
(vec3){ distance, distance, distance }
);
componentid_t camCam = entityAddComponent(cam, COMPONENT_TYPE_CAMERA);
entityCameraSetZFar(cam, camCam, distance * 6.0f);
entityCameraSetZFar(cam, camCam, 100.0f);
/* ---- Static floor (visual + physics) ---- */
entityid_t floorEnt = entityManagerAdd();
componentid_t floorPos = entityAddComponent(floorEnt, COMPONENT_TYPE_POSITION);
// Floor
entityid_t floorEnt = entityManagerAdd();
componentid_t floorPos = entityAddComponent(floorEnt, COMPONENT_TYPE_POSITION);
componentid_t floorMesh = entityAddComponent(floorEnt, COMPONENT_TYPE_MESH);
componentid_t floorMat = entityAddComponent(floorEnt, COMPONENT_TYPE_MATERIAL);
componentid_t floorMat = entityAddComponent(floorEnt, COMPONENT_TYPE_MATERIAL);
componentid_t floorPhys = entityAddComponent(floorEnt, COMPONENT_TYPE_PHYSICS);
entityPositionSetPosition(floorEnt, floorPos, (vec3){ -5.0f, 0.0f, -5.0f });
@@ -74,27 +169,24 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
entityMaterialGetShaderMaterial(floorEnt, floorMat)->unlit.color = COLOR_GREEN;
entityphysics_t *floorPhysData = entityPhysicsGet(floorEnt, floorPhys);
floorPhysData->type = PHYSICS_BODY_STATIC;
floorPhysData->shape.type = PHYSICS_SHAPE_PLANE;
floorPhysData->type = PHYSICS_BODY_STATIC;
floorPhysData->shape.type = PHYSICS_SHAPE_PLANE;
floorPhysData->shape.data.plane.normal[0] = 0.0f;
floorPhysData->shape.data.plane.normal[1] = 1.0f;
floorPhysData->shape.data.plane.normal[2] = 0.0f;
floorPhysData->shape.data.plane.distance = 0.0f;
floorPhysData->shape.data.plane.distance = 0.0f;
/* ---- Dynamic box ---- */
// Box
phBoxEnt = entityManagerAdd();
componentid_t boxPos = entityAddComponent(phBoxEnt, COMPONENT_TYPE_POSITION);
componentid_t boxPos = entityAddComponent(phBoxEnt, COMPONENT_TYPE_POSITION);
componentid_t boxMesh = entityAddComponent(phBoxEnt, COMPONENT_TYPE_MESH);
componentid_t boxMat = entityAddComponent(phBoxEnt, COMPONENT_TYPE_MATERIAL);
componentid_t boxMat = entityAddComponent(phBoxEnt, COMPONENT_TYPE_MATERIAL);
phBoxPhys = entityAddComponent(phBoxEnt, COMPONENT_TYPE_PHYSICS);
entityMeshSetMesh(phBoxEnt, boxMesh, &CUBE_MESH_SIMPLE);
entityMaterialGetShaderMaterial(phBoxEnt, boxMat)->unlit.color = COLOR_RED;
/* Physics position lives in the POSITION component. CUBE_MESH_SIMPLE is
* centred at origin (-0.5..0.5), so entity position == physics centre. */
entityPositionSetPosition(phBoxEnt, boxPos, (vec3){ 0.0f, 4.0f, 0.0f });
/* Run the init script. */
scriptcontext_t ctx;
errorChain(scriptContextInit(&ctx));
@@ -105,6 +197,8 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
}
errorret_t engineUpdate(void) {
// errorChain(networkUpdate());
timeUpdate();
inputUpdate();
@@ -126,6 +220,15 @@ errorret_t engineUpdate(void) {
if(inputPressed(INPUT_ACTION_RAGEQUIT)) ENGINE.running = false;
if(TIME.time >= onlineSwapTime) {
onlineSwapTime = FLT_MAX;
if(NETWORK.state == NETWORK_STATE_CONNECTED) {
goOffline();
} else {
goOnline();
}
}
errorOk();
}
@@ -134,6 +237,7 @@ void engineExit(void) {
}
errorret_t engineDispose(void) {
// errorChain(networkDispose());
sceneDispose();
errorChain(gameDispose());
entityManagerDispose();
+2 -2
View File
@@ -8,8 +8,8 @@
#pragma once
#include "dusk.h"
#define ENTITY_COUNT_MAX 64
#define ENTITY_COMPONENT_COUNT_MAX 16
#define ENTITY_COUNT_MAX 6
#define ENTITY_COMPONENT_COUNT_MAX 6
typedef uint8_t entityid_t;
typedef uint8_t componentid_t;
+3 -2
View File
@@ -8,6 +8,7 @@
#include "entitymanager.h"
#include "assert/assert.h"
#include "util/memory.h"
#include "scene/scene.h"
entitymanager_t ENTITY_MANAGER;
@@ -18,8 +19,8 @@ void entityManagerInit(void) {
sizeof(entityid_t) * COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX
);
printf(
"Entity Manager size is currently: %zu bytes (%.2f KB)\n",
sceneLog(
"Entity Manager size: %zu bytes (%.2f KB)\n",
sizeof(entitymanager_t),
sizeof(entitymanager_t) / 1024.0f
);
+11
View File
@@ -0,0 +1,11 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
network.c
networkinfo.c
networksocketclient.c
)
+116
View File
@@ -0,0 +1,116 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "network.h"
#include "util/memory.h"
#include "assert/assert.h"
#include "log/log.h"
network_t NETWORK;
errorret_t networkInit() {
memoryZero(&NETWORK, sizeof(network_t));
NETWORK.errorState.code = ERROR_OK;
NETWORK.onDisconnect = NULL;
return networkPlatformInit();
}
errorret_t networkUpdate() {
errorChain(networkPlatformUpdate());
if(NETWORK.state == NETWORK_STATE_CONNECTED && !networkIsConnected()) {
NETWORK.state = NETWORK_STATE_DISCONNECTED;
if(NETWORK.onDisconnect) {
errorret_t ret;
if(NETWORK.errorState.code == ERROR_OK) {
ret = errorThrowImpl(
&NETWORK.errorState,
ERROR_NOT_OK,
__FILE__, __func__, __LINE__,
"Network connection lost"
);
} else {
ret.code = NETWORK.errorState.code;
ret.state = &NETWORK.errorState;
}
NETWORK.onDisconnect(ret, NETWORK.disconnectUser);
}
}
errorOk();
}
bool_t networkIsConnected() {
return networkPlatformIsConnected();
}
void networkRequestConnection(
void (*onConnected)(void *user),
void (*onFailed)(errorret_t error, void *user),
void (*onDisconnect)(errorret_t error, void *user),
void *user
) {
assertNotNull(onConnected, "onConnected callback must not be null");
assertNotNull(onFailed, "onFailed callback must not be null");
assertNotNull(onDisconnect, "onDisconnect callback must not be null");
NETWORK.state = NETWORK_STATE_CONNECTING;
NETWORK.onDisconnect = onDisconnect;
NETWORK.disconnectUser = user;
#ifndef networkPlatformRequestConnection
// This is a platform cannot be requested to go online, this would basically
// be for platforms like Linux or Windows where the OS is responsible for
// maintaining the network connection.
if(networkIsConnected()) {
NETWORK.state = NETWORK_STATE_CONNECTED;
onConnected(user);
} else {
errorret_t ret = errorThrowImpl(
&NETWORK.errorState,
ERROR_NOT_OK,
__FILE__, __func__, __LINE__,
"No network connection available"
);
onFailed(ret, user);
}
#else
networkPlatformRequestConnection(onConnected, onFailed, onDisconnect, user);
#endif
}
void networkRequestDisconnection(
void (*onComplete)(void *user),
void *user
) {
assertNotNull(onComplete, "onComplete callback must not be null");
NETWORK.state = NETWORK_STATE_DISCONNECTING;
#ifndef networkPlatformRequestDisconnection
NETWORK.state = NETWORK_STATE_DISCONNECTED;
onComplete(user);
#else
networkPlatformRequestDisconnection(onComplete, user);
#endif
}
void networkDisconnectedDuringDispose(void *u) {
logDebug("Network disconnected during dispose\n");
}
errorret_t networkDispose() {
if(NETWORK.state == NETWORK_STATE_CONNECTED) {
networkRequestDisconnection(networkDisconnectedDuringDispose, NULL);
}
errorChain(networkPlatformDispose());
errorOk();
}
+126
View File
@@ -0,0 +1,126 @@
/**
* 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 "network/networkplatform.h"
#ifndef networkPlatformInit
#error "networkPlatformInit must be defined"
#endif
#ifndef networkPlatformUpdate
#error "networkPlatformUpdate must be defined"
#endif
#ifndef networkPlatformDispose
#error "networkPlatformDispose must be defined"
#endif
#ifndef networkPlatformIsConnected
#error "networkPlatformIsConnected must be defined"
#endif
typedef enum {
NETWORK_STATE_DISCONNECTED,
NETWORK_STATE_CONNECTING,
NETWORK_STATE_CONNECTED,
NETWORK_STATE_DISCONNECTING,
} networkstate_t;
typedef struct {
networkplatform_t platform;
errorstate_t errorState;
networkstate_t state;
void (*onDisconnect)(errorret_t error, void *user);
void *disconnectUser;
} network_t;
extern network_t NETWORK;
/**
* Initializes the network system. This will NOT connect to the network.
*
* @return An error code indicating success or failure.
*/
errorret_t networkInit();
/**
* Updates the network manager, dispatching any completed async request
* callbacks on the main thread.
*
* @return An error code indicating success or failure.
*/
errorret_t networkUpdate();
/**
* Disposes of the network manager. This will NOT disconnect from the network.
*
* @return An error code indicating success or failure.
*/
errorret_t networkDispose();
/**
* Returns true if the system is connected to AN network, this doesn't mean that
* requests will succeed, doesn't mean there's internet, just that we could
* possibly make network requests. If this is false, this usually means
* something like;
* - A network cable is not connnected
* - No Wi-Fi Connection has been established
* - No IP Address has been assigned
*
* That kinda stuff.
*
* In future I will probably have REASONS for why it's not connected, for
* example;
* - On PSP you need to "request" network access
* - On GameCube, network settings need to be defined, including DHCP, etc.
* - On Windows, this may require additional permissions
*
* @return True if some network connection is detected.
*/
bool_t networkIsConnected();
/**
* See networkIsConnected for a bit more info, but this is for some
* platforms (mainly PSP) to request the system to start doing networking.
*
* You should only call this once and assume that it is "pending" until either
* onComplete or onFailed is invoked. If you call this twice it is undefined
* behavior.
*
* onDisconnect must be provided, and is called whenever the network is lost
* after a successful connection. This will NOT be called if disconnect is
* manually triggered, but WILL if an error occurs, or a network stack bug, etc.
*
* @param onConnected Callback to invoke when the network is connected.
* @param onFailed Callback to invoke if the network connection fails.
* @param onDisconnect Called after a successful connection, when disconnected.
* @param user User data to pass to the callbacks.
*/
void networkRequestConnection(
void (*onConnected)(void *user),
void (*onFailed)(errorret_t error, void *user),
void (*onDisconnect)(errorret_t error, void *user),
void *user
);
/**
* Requests the system to disconnect from the network. This is basically just
* for PSP, but I guess it could be used on other platforms in future if they
* have some kind of "network connection mode" that needs to be exited.
*
* You should only call this once and assume that it is "pending" until
* onComplete is invoked. If you call this twice it is undefined behavior.
*
* If it fails, you still get onComplete called, but may fail if you try to
* reconnect later unfortunately.
*
* @param onComplete Callback to invoke when the network is disconnected.
* @param user User data to pass to the callback.
*/
void networkRequestDisconnection(
void (*onComplete)(void *user),
void *user
);
+25
View File
@@ -0,0 +1,25 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
typedef struct {
const char_t *key;
const char_t *value;
} networkhttpheader_t;
typedef struct {
} networkhttprequest_t;
void networkHTTP(
const char_t *url,
const char_t *method,
void *user,
void (*onComplete)(void *user),
void (*onError)(errorret_t error, void *user)
);
+24
View File
@@ -0,0 +1,24 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "network.h"
#include "networkinfo.h"
#include "network/networkplatform.h"
#include "assert/assert.h"
#ifndef networkPlatformGetInfo
#error "networkPlatformGetInfo must be defined"
#endif
networkinfo_t networkGetInfo() {
assertTrue(
NETWORK.state == NETWORK_STATE_CONNECTED,
"networkGetInfo called when not connected"
);
return networkPlatformGetInfo();
}
+57
View File
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#define NETWORK_INFO_IPV4_DNS_COUNT_MAX 2
#define NETWORK_INFO_IPV4_OCTET_COUNT 4
#define NETWORK_INFO_IPV6_OCTET_COUNT 16
#define NETWORK_INFO_IPV6_DNS_COUNT_MAX 2
#define NETWORK_INFO_FORMAT_IPV4 "%u.%u.%u.%u"
#define NETWORK_INFO_FORMAT_IPV6 \
"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x"
typedef enum {
NETWORK_TYPE_IPV4,
#ifdef DUSK_NETWORK_IPV6
NETWORK_TYPE_IPV6,
#endif
} networktype_t;
typedef struct {
uint8_t ip[NETWORK_INFO_IPV4_OCTET_COUNT];
// uint8_t subnet[NETWORK_INFO_IPV4_OCTET_COUNT];
// uint8_t gateway[NETWORK_INFO_IPV4_OCTET_COUNT];
// uint8_t dns[NETWORK_INFO_IPV4_OCTET_COUNT][NETWORK_INFO_IPV4_DNS_COUNT_MAX];
} networkinfoipv4_t;
#ifdef DUSK_NETWORK_IPV6
typedef struct {
uint8_t ip[NETWORK_INFO_IPV6_OCTET_COUNT];
// uint8_t subnet[NETWORK_INFO_IPV6_OCTET_COUNT];
// uint8_t gateway[NETWORK_INFO_IPV6_OCTET_COUNT];
// uint8_t dns[NETWORK_INFO_IPV6_OCTET_COUNT][NETWORK_INFO_IPV6_DNS_COUNT_MAX];
} networkinfoipv6_t;
#endif
typedef struct {
networktype_t type;
union {
networkinfoipv4_t ipv4;
#ifdef DUSK_NETWORK_IPV6
networkinfoipv6_t ipv6;
#endif
};
} networkinfo_t;
/**
* Returns the network information for the currently active network connection.
*
* @return Network information for the currently active network connection.
*/
networkinfo_t networkGetInfo();
+44
View File
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "networksocketclient.h"
#include "assert/assert.h"
#include "util/memory.h"
void networkSocketClientInit(
networksocketclient_t *client,
const char_t *host,
uint16_t port,
void *user,
void (*onConnect)(void *user),
void (*onError)(errorret_t error, void *user),
void (*onDisconnect)(void *user)
) {
assertNotNull(client, "Client cannot be NULL");
assertStrLenMin(host, 1, "Host cannot be empty");
assertNotNull(onConnect, "onConnect callback cannot be NULL");
assertNotNull(onError, "onError callback cannot be NULL");
assertNotNull(onDisconnect, "onDisconnect callback cannot be NULL");
memoryZero(client, sizeof(networksocketclient_t));
client->user = user;
client->onConnect = onConnect;
client->onError = onError;
client->onDisconnect = onDisconnect;
client->state = NETWORK_SOCKET_CLIENT_STATE_CONNECTING;
// Pass to platform for implementation.
networkSocketClientPlatformInit(
client,
host,
port,
user,
onConnect,
onError,
onDisconnect
);
}
+50
View File
@@ -0,0 +1,50 @@
/**
* 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 "network/networksocketclientplatform.h"
#ifndef networkSocketClientPlatformInit
#error "Define networkSocketClientPlatformInit"
#endif
typedef enum {
NETWORK_SOCKET_CLIENT_STATE_DISCONNECTED,
NETWORK_SOCKET_CLIENT_STATE_CONNECTING,
} networksocketclientstate_t;
typedef struct networksocketclient_s {
void *user;
void (*onConnect)(void *user);
void (*onError)(errorret_t error, void *user);
void (*onDisconnect)(void *user);
networksocketclientstate_t state;
networksocketclientplatform_t platform;
errorstate_t errorState;
} networksocketclient_t;
/**
* Initializes a network socket client connection.
*
* @param client The client struct to initialize.
* @param host The hostname or IP address to connect to.
* @param port The port number to connect to.
* @param user User data to pass to callbacks.
* @param onConnect Callback for when the connection is established.
* @param onError Callback for when an error occurs.
* @param onDisconnect Callback for when the connection is disconnected.
*/
void networkSocketClientInit(
networksocketclient_t *client,
const char_t *host,
uint16_t port,
void *user,
void (*onConnect)(void *user),
void (*onError)(errorret_t error, void *user),
void (*onDisconnect)(void *user)
);
+79
View File
@@ -12,12 +12,59 @@
#include "entity/entitymanager.h"
#include "display/shader/shaderunlit.h"
#include "display/mesh/cube.h"
#include "display/spritebatch/spritebatch.h"
#include "display/text/text.h"
#include "display/screen/screen.h"
scene_t SCENE;
char_t SCENE_LOG[SCENE_LOG_SIZE];
void sceneLog(const char *fmt, ...) {
char temp[512];
// 1. Format input like printf
va_list args;
va_start(args, fmt);
vsnprintf(temp, sizeof(temp), fmt, args);
va_end(args);
printf("%s", temp);
// 2. Split into lines
char *lines[64];
int line_count = 0;
char *ptr = temp;
while (*ptr && line_count < 64) {
lines[line_count++] = ptr;
char *nl = strchr(ptr, '\n');
if (!nl) break;
*nl = '\0';
ptr = nl + 1;
}
// 3. Prepend lines in reverse order (so final order is correct)
for (int i = 0; i < line_count; i++) {
char new_log[SCENE_LOG_SIZE];
snprintf(new_log, sizeof(new_log), "%s\n%s", lines[i], SCENE_LOG);
// Copy back safely
strncpy(SCENE_LOG, new_log, SCENE_LOG_SIZE - 1);
SCENE_LOG[SCENE_LOG_SIZE - 1] = '\0';
}
}
errorret_t sceneInit(void) {
memoryZero(&SCENE, sizeof(scene_t));
memoryZero(SCENE_LOG, sizeof(SCENE_LOG));
sceneLog("Init\n");
errorOk();
}
@@ -52,6 +99,7 @@ errorret_t sceneRender(void) {
mat4 view, proj, model;
errorChain(shaderBind(&SHADER_UNLIT));
// For each camera.
for(entityid_t camIndex = 0; camIndex < camCount; camIndex++) {
entityid_t camEnt = camEnts[camIndex];
componentid_t camComp = camComps[camIndex];
@@ -110,6 +158,37 @@ errorret_t sceneRender(void) {
}
}
// Here is where UI will go
glm_ortho(
0.0f, SCREEN.width,
SCREEN.height, 0.0f,
0.1f, 100.0f,
proj
);
glm_lookat(
(vec3){ 0.0f, 0.0f, 1.0f },
(vec3){ 0.0f, 0.0f, 0.0f },
(vec3){ 0.0f, 1.0f, 0.0f },
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_0TEXTURE, &DEFAULT_FONT_TEXTURE));
// errorChain(shaderSetColor(&SHADER_UNLIT, SHADER_UNLIT_COLOR, COLOR_WHITE));
errorChain(textDraw(
32, 32,
// "Hello World",
SCENE_LOG,
COLOR_WHITE,
&DEFAULT_FONT_TILESET,
&DEFAULT_FONT_TEXTURE
));
errorChain(spriteBatchFlush());
errorOk();
}
+4
View File
@@ -14,6 +14,10 @@ typedef struct {
extern scene_t SCENE;
#define SCENE_LOG_SIZE 1024
extern char_t SCENE_LOG[SCENE_LOG_SIZE];
void sceneLog(const char *fmt, ...);
/**
* Initialize the scene subsystem.
*
+1 -3
View File
@@ -52,9 +52,7 @@ int moduleTextDraw(lua_State *L) {
x,
y,
text,
#if MESH_ENABLE_COLOR
color == NULL ? COLOR_WHITE : *color,
#endif
color == NULL ? COLOR_WHITE : *color,
&DEFAULT_FONT_TILESET,
&DEFAULT_FONT_TEXTURE
);
+9
View File
@@ -0,0 +1,9 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
system.c
)
+25
View File
@@ -0,0 +1,25 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "system.h"
#include "system/systemplatform.h"
#ifndef systemGetActiveDialogTypePlatform
#error "systemGetActiveDialogTypePlatform is not defined"
#endif
#ifndef systemInitPlatform
#error "systemInitPlatform is not defined"
#endif
errorret_t systemInit() {
return systemInitPlatform();
}
systemdialogtype_t systemGetActiveDialogType() {
return systemGetActiveDialogTypePlatform();
}
+38
View File
@@ -0,0 +1,38 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "error/error.h"
typedef enum {
SYSTEM_DIALOG_TYPE_NONE,
SYSTEM_DIALOG_TYPE_RENDER_BLOCKING,
SYSTEM_DIALOG_TYPE_TICK_BLOCKING
} systemdialogtype_t;
/**
* Initializes the system module. This is called really early in the init
* process of the engine.
*
* @return Error code indicating success or failure.
*/
errorret_t systemInit(void);
/**
* Basically this is only used on a few system types, it is to ask the plaform,
* e.g. PSP "What dialog is currently open?" and then the engine will change the
* behavior of the main loop to accomodate.
*
* For example, PSP can show dialogs for things like, save files, wifi, system
* information, etc. When these are open, the engine really can't do much and
* the system needs to finish processing.
*
* For most systems this will go unused.
*
* @return Dialog type currently open.
*/
systemdialogtype_t systemGetActiveDialogType();
+3 -1
View File
@@ -18,4 +18,6 @@ target_sources(${DUSK_BINARY_TARGET_NAME}
add_subdirectory(asset)
add_subdirectory(log)
add_subdirectory(display)
add_subdirectory(input)
add_subdirectory(input)
add_subdirectory(network)
add_subdirectory(system)
+1 -1
View File
@@ -76,7 +76,7 @@ errorret_t displayInitDolphin(void) {
);
// Setup cull modes
GX_SetCullMode(GX_CULL_BACK);
GX_SetCullMode(GX_CULL_NONE);
GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
GX_SetZMode(GX_TRUE, GX_ALWAYS, GX_FALSE);
GX_SetDispCopyGamma(GX_GM_1_0);
@@ -8,6 +8,7 @@
#include "display/framebuffer/framebuffer.h"
#include "display/display.h"
#include "assert/assert.h"
#include "system/systemdolphin.h"
errorret_t frameBufferInitBackBufferDolphin(void) {
errorOk();
@@ -15,16 +16,29 @@ errorret_t frameBufferInitBackBufferDolphin(void) {
uint32_t frameBufferGetWidthDolphin(const framebufferdolphin_t *framebuffer) {
assertNotNull(framebuffer, "Cannot get width of NULL framebuffer.");
return DISPLAY.screenMode->fbWidth;
}
uint32_t frameBufferGetHeightDolphin(const framebufferdolphin_t *framebuffer) {
assertNotNull(framebuffer, "Cannot get height of NULL framebuffer.");
return DISPLAY.screenMode->efbHeight;
}
float_t frameBufferGetAspectDolphin(const framebufferdolphin_t *framebuffer) {
assertNotNull(framebuffer, "Cannot get aspect of NULL framebuffer.");
switch(systemGetAspectRatioDolphin()) {
case CONF_ASPECT_16_9:
return 16.0f / 9.0f;
case CONF_ASPECT_4_3:
return 4.0f / 3.0f;
default:
return (
(float_t)DISPLAY.screenMode->fbWidth /
(float_t)DISPLAY.screenMode->efbHeight
);
}
}
errorret_t frameBufferBindDolphin(framebufferdolphin_t *framebuffer) {
assertNotNull(framebuffer, "Cannot bind NULL framebuffer.");
assertTrue(
@@ -38,6 +38,15 @@ uint32_t frameBufferGetWidthDolphin(const framebufferdolphin_t *framebuffer);
*/
uint32_t frameBufferGetHeightDolphin(const framebufferdolphin_t *framebuffer);
/**
* Gets the aspect ratio of the framebuffer. (Dolphin implementation). Taking
* the Wii aspect setting into consideration.
*
* @param framebuffer The framebuffer to get the aspect ratio of.
* @return The aspect ratio of the framebuffer.
*/
float_t frameBufferGetAspectDolphin(const framebufferdolphin_t *framebuffer);
/**
* Binds the framebuffer for rendering. (Dolphin implementation).
*
@@ -13,5 +13,6 @@ typedef framebufferdolphin_t framebufferplatform_t;
#define frameBufferPlatformInitBackBuffer frameBufferInitBackBufferDolphin
#define frameBufferPlatformGetWidth frameBufferGetWidthDolphin
#define frameBufferPlatformGetHeight frameBufferGetHeightDolphin
#define frameBufferPlatformGetAspect frameBufferGetAspectDolphin
#define frameBufferPlatformBind frameBufferBindDolphin
#define frameBufferPlatformClear frameBufferClearDolphin
#define frameBufferPlatformClear frameBufferClearDolphin
@@ -52,6 +52,7 @@ errorret_t meshDrawDolphin(
assertTrue(offsetof(meshvertex_t, pos) == 8, "pos offset wrong");
#endif
// Flush vertex data to GPU. This is required before drawing with GX.
DCFlushRange(
(void*)&mesh->vertices[vertexOffset],
sizeof(meshvertex_t) * vertexCount
+13 -16
View File
@@ -43,10 +43,10 @@ errorret_t shaderBindDolphin(shaderdolphin_t *shader) {
GX_LoadProjectionMtx(
shader->matrixProjection,
shader->dolphinProj,
shader->isProjectionPerspective ? GX_PERSPECTIVE : GX_ORTHOGRAPHIC
);
GX_LoadPosMtxImm(shader->matrixModelView, GX_PNMTX0);
GX_LoadPosMtxImm(shader->dolphinModelView, GX_PNMTX0);
errorOk();
}
@@ -193,13 +193,13 @@ errorret_t shaderUpdateMVPDolphin() {
// Need to update projection?
if((SHADER_BOUND->dirtyMatrix & SHADER_DOLPHIN_DIRTY_PROJ) != 0) {
shaderMat4ToMtx44(SHADER_BOUND->proj, SHADER_BOUND->matrixProjection);
shaderMat4ToMtx44(SHADER_BOUND->proj, SHADER_BOUND->dolphinProj);
// 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;
float A = SHADER_BOUND->dolphinProj[2][2];
float B = SHADER_BOUND->dolphinProj[2][3];
SHADER_BOUND->dolphinProj[2][2] = 0.5f * (A + 1.0f);
SHADER_BOUND->dolphinProj[2][3] = 0.5f * B;
// Is this perspective or ortho originally? Dolphin cares for some reason.
const float_t epsilon = 0.0001f;
@@ -209,7 +209,7 @@ errorret_t shaderUpdateMVPDolphin() {
);
GX_LoadProjectionMtx(
SHADER_BOUND->matrixProjection,
SHADER_BOUND->dolphinProj,
SHADER_BOUND->isProjectionPerspective ? GX_PERSPECTIVE : GX_ORTHOGRAPHIC
);
}
@@ -217,23 +217,18 @@ errorret_t shaderUpdateMVPDolphin() {
// 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);
glm_mat4_mul(SHADER_BOUND->view, SHADER_BOUND->model, SHADER_BOUND->modelView);
shaderMat4ToMtx(SHADER_BOUND->modelView, SHADER_BOUND->dolphinModelView);
GX_LoadPosMtxImm(SHADER_BOUND->dolphinModelView, GX_PNMTX0);
}
SHADER_BOUND->dirtyMatrix = 0;
@@ -255,6 +250,8 @@ void shaderMat4ToMtx(const mat4 inGlmMatrix, Mtx outGXMatrix) {
assertNotNull(inGlmMatrix, "Input matrix cannot be null");
assertNotNull(outGXMatrix, "Output matrix cannot be null");
guMtxIdentity(outGXMatrix);
for(int row = 0; row < 3; ++row) {
for(int col = 0; col < 4; ++col) {
outGXMatrix[row][col] = inGlmMatrix[col][row];
@@ -24,13 +24,12 @@ typedef struct shaderdolphin_s {
mat4 view;
mat4 proj;
mat4 model;
mat4 modelView;
Mtx dolphinProj;
Mtx dolphinModelView;
bool_t isProjectionPerspective;
Mtx44 matrixProjection;
Mtx matrixView;
Mtx matrixModel;
Mtx matrixModelView;
uint_fast8_t dirtyMatrix;
} shaderdolphin_t;
+9 -1
View File
@@ -8,4 +8,12 @@
#pragma once
#include <ogcsys.h>
#include <gccore.h>
#include <malloc.h>
#include <malloc.h>
#ifdef DUSK_GAMECUBE
#define CONF_ASPECT_4_3 0
#define CONF_ASPECT_16_9 1
#define CONF_GetAspectRatio() CONF_ASPECT_4_3
#define CONF_GetLanguage() SYS_GetLanguage()
#endif
+9
View File
@@ -0,0 +1,9 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
networkdolphin.c
)
+118
View File
@@ -0,0 +1,118 @@
// /**
// * Copyright (c) 2026 Dominic Masters
// *
// * This software is released under the MIT License.
// * https://opensource.org/licenses/MIT
// */
#include "network/network.h"
#include "util/memory.h"
#include "assert/assert.h"
errorret_t networkDolphinInit() {
// s32 ret = net_init();
// if(ret < 0) errorThrow("Failed to init network stack: %d", ret);
errorOk();
}
errorret_t networkDolphinUpdate() {
errorOk();
}
errorret_t networkDolphinDispose() {
// #ifdef DUSK_WII
// net_deinit();
// #endif
errorOk();
}
bool_t networkDolphinIsConnected() {
return NETWORK.state == NETWORK_STATE_CONNECTED;
}
void networkDolphinRequestConnection(
void (*onConnected)(void *user),
void (*onFailed)(errorret_t error, void *user),
void (*onDisconnect)(errorret_t error, void *user),
void *user
) {
assertTrue(
NETWORK.state == NETWORK_STATE_CONNECTING,
"Network host should be in a connecting state."
);
NETWORK.platform.onConnected = onConnected;
NETWORK.platform.onFailed = onFailed;
NETWORK.platform.onConnectedUser = user;
memoryZero(NETWORK.platform.ip, sizeof(NETWORK.platform.ip));
memoryZero(NETWORK.platform.netmask, sizeof(NETWORK.platform.netmask));
memoryZero(NETWORK.platform.gateway, sizeof(NETWORK.platform.gateway));
// Negotiate DHCP using the Wi-Fi settings saved in Wii System Menu.
// This call blocks until the interface is configured or times out.
#ifdef DUSK_WII
s32 ret = if_config(
NETWORK.platform.ip,
NETWORK.platform.netmask,
NETWORK.platform.gateway,
true,
20
);
#else
s32 ret = -1;
#endif
if(ret >= 0) {
NETWORK.state = NETWORK_STATE_CONNECTED;
assertNotNull(
NETWORK.platform.onConnected,
"Network platform onConnected callback should be set."
);
NETWORK.platform.onConnected(NETWORK.platform.onConnectedUser);
} else {
NETWORK.state = NETWORK_STATE_DISCONNECTED;
assertNotNull(
NETWORK.platform.onFailed,
"Network platform onFailed callback should be set."
);
errorret_t error = errorThrowImpl(
&NETWORK.errorState,
ERROR_NOT_OK,
__FILE__, __func__, __LINE__,
"Failed to connect to network"
);
NETWORK.platform.onFailed(error, NETWORK.platform.onConnectedUser);
}
}
void networkDolphinRequestDisconnection(
void (*onComplete)(void *user),
void *user
) {
assertTrue(
NETWORK.state == NETWORK_STATE_DISCONNECTING,
"Network host should be in a disconnecting state."
);
NETWORK.state = NETWORK_STATE_DISCONNECTED;
onComplete(user);
}
networkinfo_t networkDolphinGetInfo() {
networkinfo_t info;
memoryZero(&info, sizeof(networkinfo_t));
info.type = NETWORK_TYPE_IPV4;
int ret = sscanf(
NETWORK.platform.ip,
"%hhu.%hhu.%hhu.%hhu",
&info.ipv4.ip[0],
&info.ipv4.ip[1],
&info.ipv4.ip[2],
&info.ipv4.ip[3]
);
assertTrue(ret == 4, "Failed to parse IP address");
return info;
}
+86
View File
@@ -0,0 +1,86 @@
/**
* 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 "network/networkinfo.h"
#include <network.h>
#define NETWORK_DOLPHIN_IP_MAX 16
typedef struct {
char_t ip[NETWORK_DOLPHIN_IP_MAX];
char_t netmask[NETWORK_DOLPHIN_IP_MAX];
char_t gateway[NETWORK_DOLPHIN_IP_MAX];
void *onConnectedUser;
void (*onConnected)(void *user);
void (*onFailed)(errorret_t error, void *user);
} networkdolphin_t;
/**
* Initializes the Wii network stack via IOS. Does not connect; use
* networkDolphinRequestConnection for that.
*
* @return Error state (if any).
*/
errorret_t networkDolphinInit();
/**
* Called each frame. No-op on Wii since connection is synchronous.
*
* @return Error state (if any).
*/
errorret_t networkDolphinUpdate();
/**
* Disposes the Wii network stack.
*
* @return Error state (if any).
*/
errorret_t networkDolphinDispose();
/**
* Returns true if the Wii is connected to a network.
*
* @return True if connected.
*/
bool_t networkDolphinIsConnected();
/**
* Requests the Wii to connect to the network using the Wi-Fi settings saved
* in the Wii System Menu. Blocks until connected or failed.
*
* @param onConnected Callback on successful connection.
* @param onFailed Callback if connection fails.
* @param onDisconnect Callback when connection is later lost.
* @param user User data passed to all callbacks.
*/
void networkDolphinRequestConnection(
void (*onConnected)(void *user),
void (*onFailed)(errorret_t error, void *user),
void (*onDisconnect)(errorret_t error, void *user),
void *user
);
/**
* Requests the Wii to disconnect from the network.
*
* @param onComplete Callback when disconnection is complete.
* @param user User data passed to the callback.
*/
void networkDolphinRequestDisconnection(
void (*onComplete)(void *user),
void *user
);
/**
* Returns the current network IP information.
*
* @return Network info for the active connection.
*/
networkinfo_t networkDolphinGetInfo();
+19
View File
@@ -0,0 +1,19 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "networkdolphin.h"
#define networkPlatformInit networkDolphinInit
#define networkPlatformUpdate networkDolphinUpdate
#define networkPlatformDispose networkDolphinDispose
#define networkPlatformIsConnected networkDolphinIsConnected
#define networkPlatformRequestConnection networkDolphinRequestConnection
#define networkPlatformRequestDisconnection networkDolphinRequestDisconnection
#define networkPlatformGetInfo networkDolphinGetInfo
typedef networkdolphin_t networkplatform_t;
+9
View File
@@ -0,0 +1,9 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
systemdolphin.c
)
+27
View File
@@ -0,0 +1,27 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "systemdolphin.h"
#include "input/input.h"
#include "util/string.h"
#include "assert/assert.h"
errorret_t systemInitDolphin(void) {
errorOk();
}
systemdialogtype_t systemGetActiveDialogTypeDolphin(void) {
return SYSTEM_DIALOG_TYPE_NONE;
}
int32_t systemGetAspectRatioDolphin(void) {
return CONF_GetAspectRatio();
}
int32_t systemGetLanguageDolphin(void) {
return CONF_GetLanguage();
}
+51
View File
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "system/system.h"
/**
* Initializes the Dolphin system module.
*
* @return Error code indicating success or failure.
*/
errorret_t systemInitDolphin(void);
/**
* Returns which Dolphin system dialog is currently open (if any).
*
* @return Currently open system dialog type.
*/
systemdialogtype_t systemGetActiveDialogTypeDolphin(void);
/**
* Returns either CONF_ASPECT_4_3 or CONF_ASPECT_16_9 depending on the aspect
* ratio of the system. I do believe that Gamecube will only ever return 4:3.
*
* Refer to;
* https://github.com/devkitPro/libogc/blob/20d90e944b83c8991538e88b00b1e5f309428e85/gc/ogc/conf.h#L190
*
* @return Aspect ratio of the system.
*/
int32_t systemGetAspectRatioDolphin(void);
/**
* Returns the language the system is set to. This is used for things like
* locale management, to try to match the system language if possible.
*
* Refer to;
* https://github.com/devkitPro/libogc/blob/20d90e944b83c8991538e88b00b1e5f309428e85/gc/ogc/conf.h#L190
*
* On gamecube, refer to;
* https://libogc.devkitpro.org/system_8h.html
*
* @return System language.
*/
int32_t systemGetLanguageDolphin(void);
// There's actually a tonne more things Wii can return, this is it for now
// though.
+12
View File
@@ -0,0 +1,12 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "system/systemdolphin.h"
#define systemInitPlatform systemInitDolphin
#define systemGetActiveDialogTypePlatform systemGetActiveDialogTypeDolphin
+8 -3
View File
@@ -19,7 +19,12 @@
#define GL_COLOR_ATTACHMENT0_EXT GL_COLOR_ATTACHMENT0
#define glClearDepth(depth) glClearDepthf(depth)
#else
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
// For some platforms (Vita) we do not include GL extensions.
#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#else
#include <GL/gl.h>
#endif
#endif
+3 -1
View File
@@ -12,4 +12,6 @@ target_include_directories(${DUSK_LIBRARY_TARGET_NAME}
# Subdirs
add_subdirectory(asset)
add_subdirectory(log)
add_subdirectory(input)
add_subdirectory(input)
add_subdirectory(network)
add_subdirectory(system)
+10
View File
@@ -0,0 +1,10 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
networklinux.c
networksocketclientlinux.c
)
+120
View File
@@ -0,0 +1,120 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "networklinux.h"
#include "util/memory.h"
#include "util/string.h"
#include "assert/assert.h"
errorret_t networkLinuxInit() {
errorOk();
}
errorret_t networkLinuxUpdate() {
errorOk();
}
bool_t networkLinuxIsConnected() {
// Call the OS network stack to check for connectivity.
struct ifaddrs *ifaddr, *ifa;
if(getifaddrs(&ifaddr) == -1) {
return false;
}
// Check if any non loopback interfaces have running flag set.
bool_t connected = false;
for(ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (!ifa->ifa_name || !ifa->ifa_flags) continue;
// Skip loopback (localhost)
if(ifa->ifa_flags & IFF_LOOPBACK) continue;
// Is interface up and running?
if(!(ifa->ifa_flags & IFF_UP)) continue;
if(!(ifa->ifa_flags & IFF_RUNNING)) continue;
connected = true;
break;
}
// Free the linked list of interfaces
freeifaddrs(ifaddr);
return connected;
}
errorret_t networkLinuxDispose() {
errorOk();
}
networkinfo_t networkLinuxGetInfo() {
networkinfo_t info;
memset(&info, 0, sizeof(networkinfo_t));
bool_t found = false;
struct ifaddrs *ifaddr, *ifa;
if(getifaddrs(&ifaddr) == -1) {
assertUnreachable("getifaddrs failed");
}
// Find the first non-loopback interface with an IP address
for(ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (!ifa->ifa_name || !ifa->ifa_flags) continue;
// Skip loopback (localhost)
if(ifa->ifa_flags & IFF_LOOPBACK) continue;
// Is interface up and running?
if(!(ifa->ifa_flags & IFF_UP)) continue;
if(!(ifa->ifa_flags & IFF_RUNNING)) continue;
if(ifa->ifa_addr == NULL) continue;
// Check for IPv4 address
if(ifa->ifa_addr->sa_family == AF_INET) {
info.type = NETWORK_TYPE_IPV4;
struct sockaddr_in *sa = (struct sockaddr_in *)ifa->ifa_addr;
memoryCopy(
info.ipv4.ip,
&sa->sin_addr,
NETWORK_INFO_IPV4_OCTET_COUNT
);
found = true;
// sa = (struct sockaddr_in *)ifa->ifa_netmask;
// memoryCopy(
// info.ipv4.subnet,
// &sa->sin_addr,
// NETWORK_INFO_IPV4_OCTET_COUNT
// );
break;
}
// Check for IPv6 address
#ifdef DUSK_NETWORK_IPV6
if(ifa->ifa_addr->sa_family == AF_INET6) {
info.type = NETWORK_TYPE_IPV6;
struct sockaddr_in6 *sa = (struct sockaddr_in6 *)ifa->ifa_addr;
memoryCopy(
info.ipv6.ip,
&sa->sin6_addr,
NETWORK_INFO_IPV6_OCTET_COUNT
);
found = true;
break;
}
#endif
}
freeifaddrs(ifaddr);
assertTrue(found, "No active network interface found?");
return info;
}
+54
View File
@@ -0,0 +1,54 @@
/**
* 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 "network/networkinfo.h"
#include <ifaddrs.h>
#include <net/if.h>
#include <netinet/in.h>
typedef struct {
void *nothing;
} networklinux_t;
/**
* Initializes the network manager. Must be called before any other network
* functions.
*
* @return Any error that occurs.
*/
errorret_t networkLinuxInit();
/**
* Updates the network manager, called once per frame to handle completed
* HTTP requests.
*
* @return Any error that occurs.
*/
errorret_t networkLinuxUpdate();
/**
* Returns true — Linux uses the OS network stack which is always available.
*
* @return true
*/
bool_t networkLinuxIsConnected();
/**
* Disposes the network manager.
*
* @return Any error that occurs.
*/
errorret_t networkLinuxDispose();
/**
* Gets the network information for the currently active network connection.
*
* @return Network information for the currently active network connection.
*/
networkinfo_t networkLinuxGetInfo();
+17
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 "networklinux.h"
#define networkPlatformInit networkLinuxInit
#define networkPlatformUpdate networkLinuxUpdate
#define networkPlatformDispose networkLinuxDispose
#define networkPlatformIsConnected networkLinuxIsConnected
#define networkPlatformGetInfo networkLinuxGetInfo
typedef networklinux_t networkplatform_t;
@@ -0,0 +1,99 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "network/networksocketclient.h"
#include "assert/assert.h"
#include "util/memory.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
void networkSocketClientLinuxInit(
networksocketclient_t *client,
const char_t *host,
uint16_t port,
void *user,
void (*onConnect)(void *user),
void (*onError)(errorret_t error, void *user),
void (*onDisconnect)(void *user)
) {
assertTrue(client->user == user, "Net client init mismatch?");
assertTrue(client->onConnect == onConnect, "Net client init mismatch?");
assertTrue(client->onError == onError, "Net client init mismatch?");
assertTrue(client->onDisconnect == onDisconnect, "Net client init mismatch?");
// Create the thread.
threadInit(&client->platform.thread, networkSocketClientLinuxThread);
client->platform.thread.data = client;
threadStart(&client->platform.thread);
}
void networkSocketClientLinuxThread(thread_t *thread) {
assertNotNull(thread, "Thread cannot be NULL.");
assertNotNull(thread->data, "Thread data cannot be NULL.");
networksocketclient_t *client = (networksocketclient_t *)thread->data;
// Setup socket FD
client->platform.sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(client->platform.sockfd < 0) {
errorret_t ret = errorThrowImpl(
&client->errorState, ERROR_NOT_OK,
__FILE__, __func__, __LINE__,
"Failed to create socket."
);
client->onError(ret, client->user);
return;
}
// Configure server address.
char_t *host = "google.com";
int port = 443;
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
struct hostent *server = gethostbyname(host);
if(server == NULL) {
errorret_t ret = errorThrowImpl(
&client->errorState, ERROR_NOT_OK,
__FILE__, __func__, __LINE__,
"Failed to resolve host."
);
client->onError(ret, client->user);
return;
}
memoryCopy(&serverAddr.sin_addr.s_addr, server->h_addr, server->h_length);
// Connect to server.
if(connect(
client->platform.sockfd,
(struct sockaddr *)&serverAddr,
sizeof(serverAddr)
) < 0) {
errorret_t ret = errorThrowImpl(
&client->errorState, ERROR_NOT_OK,
__FILE__, __func__, __LINE__,
"Failed to connect to server."
);
client->onError(ret, client->user);
return;
}
// At this point we are connected.
client->onConnect(client->user);
// Hangup for now.
close(client->platform.sockfd);
client->onDisconnect(client->user);
}
@@ -0,0 +1,37 @@
/**
* 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 "thread/thread.h"
typedef struct {
int sockfd;
thread_t thread;
} networksocketclientlinux_t;
typedef struct networksocketclient_s networksocketclient_t;
/**
* Refer to networkSocketClientInit for documentation.
*/
void networkSocketClientLinuxInit(
networksocketclient_t *client,
const char_t *host,
uint16_t port,
void *user,
void (*onConnect)(void *user),
void (*onError)(errorret_t error, void *user),
void (*onDisconnect)(void *user)
);
/**
* Async thread for handling the socket connection.
*
* @param thread Thread structure passed.
*/
void networkSocketClientLinuxThread(thread_t *thread);
@@ -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 "networksocketclientlinux.h"
#define networkSocketClientPlatformInit networkSocketClientLinuxInit
typedef networksocketclientlinux_t networksocketclientplatform_t;
+9
View File
@@ -0,0 +1,9 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
systemlinux.c
)
+16
View File
@@ -0,0 +1,16 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "systemlinux.h"
errorret_t systemInitLinux() {
errorOk();
}
systemdialogtype_t systemGetActiveDialogTypeLinux() {
return SYSTEM_DIALOG_TYPE_NONE;
}
+21
View File
@@ -0,0 +1,21 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "system/system.h"
/**
* Initializes the Linux system module.
*/
errorret_t systemInitLinux(void);
/**
* Currently just returns SYSTEM_DIALOG_TYPE_NONE.
*
* @return Currently open system dialog type.
*/
systemdialogtype_t systemGetActiveDialogTypeLinux();
+12
View File
@@ -0,0 +1,12 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "system/systemlinux.h"
#define systemInitPlatform systemInitLinux
#define systemGetActiveDialogTypePlatform systemGetActiveDialogTypeLinux
+3 -1
View File
@@ -17,4 +17,6 @@ target_sources(${DUSK_BINARY_TARGET_NAME}
# Subdirs
add_subdirectory(asset)
add_subdirectory(input)
add_subdirectory(log)
add_subdirectory(log)
add_subdirectory(network)
add_subdirectory(system)
+7
View File
@@ -7,6 +7,9 @@
#include "input/input.h"
// #define INPUT_PSP_GAMEPAD_BUTTON_ACCEPT INPUT_SDL2_GAMEPAD_BUTTON_CUSTOM
// #define INPUT_PSP_GAMEPAD_BUTTON_CANCEL INPUT_SDL2_GAMEPAD_BUTTON_CUSTOM
inputbuttondata_t INPUT_BUTTON_DATA[] = {
{ .name = "triangle", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_Y } },
{ .name = "cross", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_A } },
@@ -21,6 +24,10 @@ inputbuttondata_t INPUT_BUTTON_DATA[] = {
{ .name = "l", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_LEFTSHOULDER } },
{ .name = "r", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER } },
// Refer to systempsp.c for some extra info.
{ .name = "accept", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_A } },
{ .name = "cancel", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_B } },
{ .name = "lstick_down", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTY, .positive = true } } },
{ .name = "lstick_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTY, .positive = false } } },
{ .name = "lstick_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTX, .positive = true } } },
+9
View File
@@ -0,0 +1,9 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
networkpsp.c
)
+19
View File
@@ -0,0 +1,19 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "networkpsp.h"
#define networkPlatformInit networkPSPInit
#define networkPlatformUpdate networkPSPUpdate
#define networkPlatformDispose networkPSPDispose
#define networkPlatformIsConnected networkPSPIsConnected
#define networkPlatformRequestConnection networkPSPRequestConnection
#define networkPlatformRequestDisconnection networkPSPRequestDisconnection
#define networkPlatformGetInfo networkPSPGetInfo
typedef networkpsp_t networkplatform_t;
+259
View File
@@ -0,0 +1,259 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "network/network.h"
#include "util/memory.h"
#include "util/string.h"
#include "assert/assert.h"
#include "display/displaysdl2.h"
errorret_t networkPSPInit() {
// Requests the PSP to load the network modules.
int ret;
ret = sceUtilityLoadNetModule(PSP_NET_MODULE_COMMON);
if(ret < 0) errorThrow("Failed to init NET COMMON: 0x%08X", ret);
ret = sceUtilityLoadNetModule(PSP_NET_MODULE_INET);
if(ret < 0) errorThrow("Failed to init NET INET: 0x%08X", ret);
// ret = sceUtilityLoadNetModule(PSP_NET_MODULE_PARSEURI);
// if(ret < 0) errorThrow("Failed to init NET PARSEURI: 0x%08X", ret);
// ret = sceUtilityLoadNetModule(PSP_NET_MODULE_PARSEHTTP);
// if(ret < 0) errorThrow("Failed to init NET PARSEHTTP: 0x%08X", ret);
// ret = sceUtilityLoadNetModule(PSP_NET_MODULE_SSL);
// if(ret < 0) errorThrow("Failed to init NET SSL: 0x%08X", ret);
// ret = sceUtilityLoadNetModule(PSP_NET_MODULE_HTTP);
// if(ret < 0) errorThrow("Failed to init NET HTTP: 0x%08X", ret);
// ret = sceSslInit(0x28000);
// if(ret < 0) errorThrow("sceSslInit failed: 0x%08X", ret);
// ret = sceHttpInit(0x25800);
// if(ret < 0) errorThrow("sceHttpInit failed: 0x%08X", ret);
// ret = sceHttpsInit(0, 0, 0, 0);
// if(ret < 0) errorThrow("sceHttpsInit failed: 0x%08X", ret);
// ret = sceHttpsLoadDefaultCert(0, 0);
// if(ret < 0) errorThrow("sceHttpsLoadDefaultCert failed: 0x%08X", ret);
// ret = sceHttpLoadSystemCookie();
// if(ret < 0) errorThrow("sceHttpLoadSystemCookie failed: 0x%08X", ret);
// All good.
errorOk();
}
errorret_t networkPSPUpdate() {
int ret;
if(NETWORK.state == NETWORK_STATE_CONNECTING) {
switch(sceUtilityNetconfGetStatus()) {
case PSP_UTILITY_DIALOG_INIT:
break;
case PSP_UTILITY_DIALOG_NONE:
NETWORK.state = NETWORK_STATE_DISCONNECTED;
errorThrow("PSP Netconf dialog disappeared without result");
break;
case PSP_UTILITY_DIALOG_VISIBLE:
// 1 is mandatory?
ret = sceUtilityNetconfUpdate(1);
if(ret != 0) {
errorThrow("sceUtilityNetconfUpdate failed: 0x%08X", ret);
}
break;
case PSP_UTILITY_DIALOG_QUIT:
ret = sceUtilityNetconfShutdownStart();
if(ret != 0) {
errorThrow("sceUtilityNetconfShutdownStart failed: 0x%08X", ret);
}
break;
case PSP_UTILITY_DIALOG_FINISHED:
// Did we connect?
int apState = 0;
sceNetApctlGetState(&apState);
if(apState == PSP_NET_APCTL_STATE_GOT_IP) {
NETWORK.state = NETWORK_STATE_CONNECTED;
assertNotNull(
NETWORK.platform.onConnected,
"Network platform onConnected callback should be set."
);
NETWORK.platform.onConnected(NETWORK.platform.onConnectedUser);
} else {
NETWORK.state = NETWORK_STATE_DISCONNECTED;
assertNotNull(
NETWORK.platform.onFailed,
"Network platform onFailed callback should be set."
);
// Kill the PSP network stack.
errorret_t err = networkPSPTerm();
if(err.code != ERROR_OK) {
errorCatch(errorPrint(err));
}
errorret_t error = errorThrowImpl(
&NETWORK.errorState,
ERROR_NOT_OK,
__FILE__, __func__, __LINE__,
"Failed to connect to network"
);
NETWORK.platform.onFailed(error, NETWORK.platform.onConnectedUser);
}
break;
default:
errorThrow("Unknown PSP Netconf dialog status: %d", sceUtilityNetconfGetStatus());
}
}
errorOk();
}
errorret_t networkPSPDispose() {
sceUtilityNetconfGetStatus();
errorCatch(errorPrint(networkPSPTerm()));
sceUtilityUnloadNetModule(PSP_NET_MODULE_HTTP);
sceUtilityUnloadNetModule(PSP_NET_MODULE_INET);
sceUtilityUnloadNetModule(PSP_NET_MODULE_COMMON);
errorOk();
}
bool_t networkPSPIsConnected() {
return NETWORK.state == NETWORK_STATE_CONNECTED;
}
void networkPSPRequestConnection(
void (*onConnected)(void *user),
void (*onFailed)(errorret_t error, void *user),
void (*onDisconnect)(errorret_t error, void *user),
void *user
) {
assertTrue(
NETWORK.state == NETWORK_STATE_CONNECTING,
"Network host should be in a connecting state."
);
NETWORK.platform.onConnected = onConnected;
NETWORK.platform.onFailed = onFailed;
NETWORK.platform.onConnectedUser = user;
int ret;
// Init the PSP network stack.
ret = sceNetInit(0x20000, 0x20, 4096, 0x20, 4096);
assertTrue(ret >= 0, "Failed to init net: 0x%08X");
ret = sceNetInetInit();
assertTrue(ret >= 0, "Failed to init net inet: 0x%08X");
ret = sceNetResolverInit();
assertTrue(ret >= 0, "Failed to init net resolver: 0x%08X");
ret = sceNetApctlInit(0x1800, 0x30);
assertTrue(ret >= 0, "Failed to init net apctl: 0x%08X");
// This is all related to getting the PSP online, refer to;
// https://github.com/joel16/CMFileManager-PSP/blob/00dab16c64cd48bf6452fc274a3b898d77c39a8d/app/source/net.cpp#L97
// since I follow this implementation closely.
memoryZero(&NETWORK.platform.dialogData, sizeof(NETWORK.platform.dialogData));
memoryZero(&NETWORK.platform.dialogAdhoc, sizeof(NETWORK.platform.dialogAdhoc));
NETWORK.platform.dialogData.base.size = sizeof(pspUtilityNetconfData);
NETWORK.platform.dialogData.base.language = systemPSPGetLanguage();
NETWORK.platform.dialogData.base.buttonSwap = systemPSPGetCrossButtonSetting();
NETWORK.platform.dialogData.base.graphicsThread = 17;
NETWORK.platform.dialogData.base.accessThread = 19;
NETWORK.platform.dialogData.base.fontThread = 18;
NETWORK.platform.dialogData.base.soundThread = 16;
NETWORK.platform.dialogData.action = PSP_NETCONF_ACTION_CONNECTAP;
NETWORK.platform.dialogData.adhocparam = (
&NETWORK.platform.dialogAdhoc
);
ret = sceUtilityNetconfInitStart(&NETWORK.platform.dialogData);
assertTrue(ret >= 0, "Failed to init netconf");
}
void networkPSPRequestDisconnection(
void (*onComplete)(void *user),
void *user
) {
assertTrue(
NETWORK.state == NETWORK_STATE_DISCONNECTING,
"Network host should be in a disconnecting state."
);
errorret_t err = networkPSPTerm();
if(err.code != ERROR_OK) {
errorCatch(errorPrint(err));
}
NETWORK.state = NETWORK_STATE_DISCONNECTED;
onComplete(user);
}
errorret_t networkPSPTerm() {
int ret;
ret = sceNetApctlTerm();
if(ret < 0) {
errorThrow("Failed to terminate netctl: 0x%08X", ret);
}
ret = sceNetResolverTerm();
if(ret < 0) {
errorThrow("Failed to terminate net resolver: 0x%08X", ret);
}
ret = sceNetInetTerm();
if(ret < 0) {
errorThrow("Failed to terminate net inet: 0x%08X", ret);
}
ret = sceNetTerm();
if(ret < 0) {
errorThrow("Failed to terminate net: 0x%08X", ret);
}
errorOk();
}
networkinfo_t networkPSPGetInfo() {
networkinfo_t netInfo;
memoryZero(&netInfo, sizeof(networkinfo_t));
// Get the IP address of the current connection.
union SceNetApctlInfo info;
int ret = sceNetApctlGetInfo(PSP_NET_APCTL_INFO_IP, &info);
assertTrue(ret >= 0, "Failed to get IP address");
// Parse the IP address string into octets.
netInfo.type = NETWORK_TYPE_IPV4;
ret = sscanf(
info.ip,
"%hhu.%hhu.%hhu.%hhu",
&netInfo.ipv4.ip[0],
&netInfo.ipv4.ip[1],
&netInfo.ipv4.ip[2],
&netInfo.ipv4.ip[3]
);
assertTrue(ret == 4, "Failed to parse IP address");
return netInfo;
}
+110
View File
@@ -0,0 +1,110 @@
/**
* 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 "network/networkinfo.h"
#include "system/systempsp.h"
#include <psphttp.h>
#include <pspnet.h>
#include <pspnet_inet.h>
#include <pspnet_apctl.h>
#include <pspssl.h>
#include <pspnet_resolver.h>
#include <psphttp.h>
// #define NETWORK_HTTP_PENDING_MAX 4
// #define NETWORK_HTTP_URL_MAX 512
// #define NETWORK_HTTP_BODY_MAX 2048
// #define NETWORK_HTTP_RESPONSE_MAX 16384
// #define NETWORK_HTTP_HEADER_MAX 8
// #define NETWORK_HTTP_HEADER_KEY_MAX 64
// #define NETWORK_HTTP_HEADER_VAL_MAX 256
// #define NETWORK_ERROR_MESSAGE_MAX 256
// #define NETWORK_PSP_AGENT "DuskEngine/1.0"
typedef struct {
pspUtilityNetconfData dialogData;
struct pspUtilityNetconfAdhoc dialogAdhoc;
// Used during establishing connection
void *onConnectedUser;
void (*onConnected)(void *user);
void (*onFailed)(errorret_t error, void *user);
} networkpsp_t;
/**
* Initializes the PSP Network manager. This will NOT do network connecting,
* only prep it for being able to connect in future.
*
* @return Error state (if any).
*/
errorret_t networkPSPInit();
/**
* Called each frame for handling PSP requests, basically this is where all
* communication between the HTTP thread and the main thread happens.
*
* @return Error state (if any).
*/
errorret_t networkPSPUpdate();
/**
* Disposes the PSP Network manager, this will clean all resources and, if the
* network is connected, it will disconnect it safely.
*
* @return Error state (if any).
*/
errorret_t networkPSPDispose();
/**
* Checks if the PSP network is connected.
*
* @return True if the PSP is connected to a network, false otherwise.
*/
bool_t networkPSPIsConnected();
/**
* Requests the PSP to connect to a network (Shows the Wi-Fi connected).
*
* @param onConnected Callback connected successfully.
* @param onFailed Callback if the connection failed.
* @param onDisconnect Callback when connection is lost.
* @param user User data to pass to the callbacks.
*/
void networkPSPRequestConnection(
void (*onConnected)(void *user),
void (*onFailed)(errorret_t error, void *user),
void (*onDisconnect)(errorret_t error, void *user),
void *user
);
/**
* Requests the PSP to disconnect from the network (Shows the Wi-Fi disconnecting).
*
* @param onComplete Callback when disconnection is complete.
* @param user User data to pass to the callback.
*/
void networkPSPRequestDisconnection(
void (*onComplete)(void *user),
void *user
);
/**
* Disposes the PSP sce net libraries, doesn't unload the modules and won't
* term the dialog if it's active.
*
* @return Error state (if any).
*/
errorret_t networkPSPTerm();
/**
* Gets the network information for the currently active network connection.
*
* @return Network information for the currently active network connection.
*/
networkinfo_t networkPSPGetInfo();
+9
View File
@@ -0,0 +1,9 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
systempsp.c
)
+12
View File
@@ -0,0 +1,12 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "system/systempsp.h"
#define systemInitPlatform systemInitPSP
#define systemGetActiveDialogTypePlatform systemGetActiveDialogTypePSP
+64
View File
@@ -0,0 +1,64 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "systempsp.h"
#include "input/input.h"
#include "util/string.h"
#include "assert/assert.h"
errorret_t systemInitPSP() {
// Bind ACCEPT and CANCEL binds.
inputbuttondata_t *buttonCross, *buttonCircle, *buttonAccept, *buttonCancel;
inputbuttondata_t *i = INPUT_BUTTON_DATA;
while(i->name) {
if(stringCompare(i->name, "cross") == 0) {
buttonCross = i;
} else if(stringCompare(i->name, "circle") == 0) {
buttonCircle = i;
} else if(stringCompare(i->name, "accept") == 0) {
buttonAccept = i;
} else if(stringCompare(i->name, "cancel") == 0) {
buttonCancel = i;
}
i++;
}
assertNotNull(buttonCross, "Cross button not found!");
assertNotNull(buttonCircle, "Circle button not found!");
assertNotNull(buttonAccept, "Accept button not found!");
assertNotNull(buttonCancel, "Cancel button not found!");
if(systemPSPGetCrossButtonSetting() == PSP_UTILITY_ACCEPT_CROSS) {
buttonAccept->button.gpButton = buttonCross->button.gpButton;
buttonCancel->button.gpButton = buttonCircle->button.gpButton;
} else {
buttonAccept->button.gpButton = buttonCircle->button.gpButton;
buttonCancel->button.gpButton = buttonCross->button.gpButton;
}
errorOk();
}
systemdialogtype_t systemGetActiveDialogTypePSP() {
return SYSTEM_DIALOG_TYPE_NONE;
}
int systemPSPGetLanguage() {
int ret;
sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_LANGUAGE, &ret);
return ret;
}
int systemPSPGetCrossButtonSetting() {
int ret;
// See: https://pspdev.github.io/pspsdk/psputility__sysparam_8h.html#ab588fd5a14adc025f065e09325ffe729
sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_UNKNOWN, &ret);
return (
ret == 1 ? PSP_UTILITY_ACCEPT_CROSS : PSP_UTILITY_ACCEPT_CIRCLE
);
}
+40
View File
@@ -0,0 +1,40 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "system/system.h"
#include <psputility.h>
/**
* Initializes the PSP system module.
*
* @return Error code indicating success or failure.
*/
errorret_t systemInitPSP(void);
/**
* Returns which PSP system dialog is currently open (if any).
*
* @return Currently open system dialog type.
*/
systemdialogtype_t systemGetActiveDialogTypePSP();
/**
* Returns the PSP_SYSTEMPARAM language for the current system.
*
* @return PSP_SYSTEMPARAM language value.
*/
int systemPSPGetLanguage();
/**
* Returns the user's setting for the PSP "Cross Button" configuration, which
* determines whether the "Cross" or "Circle" button is used for "Accept"
* actions in system dialogs.
*
* @return PSP_UTILITY_ACCEPT_CROSS or PSP_UTILITY_ACCEPT_CIRCLE.
*/
int systemPSPGetCrossButtonSetting();
+5
View File
@@ -73,6 +73,11 @@ float_t inputButtonGetValueSDL2(const inputbutton_t button) {
#ifdef DUSK_INPUT_GAMEPAD
case INPUT_BUTTON_TYPE_GAMEPAD: {
assertTrue(
button.gpButton < SDL_CONTROLLER_BUTTON_MAX,
"Gamepad button out of range"
);
if(SDL_GameControllerGetButton(
INPUT.platform.controller, button.gpButton
)) {
+20
View File
@@ -0,0 +1,20 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Includes
target_include_directories(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
)
# Sources
target_sources(${DUSK_BINARY_TARGET_NAME}
PUBLIC
)
# Subdirs
add_subdirectory(asset)
add_subdirectory(input)
add_subdirectory(log)
+10
View File
@@ -0,0 +1,10 @@
# 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
assetvita.c
)
+13
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 "assetvita.h"
typedef assetvita_t assetplatform_t;
#define assetInitPlatform assetInitVita
#define assetDisposePlatform assetDisposeVita
+22
View File
@@ -0,0 +1,22 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "asset/asset.h"
#include "assert/assert.h"
errorret_t assetInitVita(void) {
int32_t error;
ASSET.zip = zip_open(ASSET_VITA_DSK_PATH, ZIP_RDONLY, &error);
if(ASSET.zip == NULL) {
errorThrow("Failed to open asset file: " ASSET_VITA_DSK_PATH);
}
errorOk();
}
errorret_t assetDisposeVita(void) {
errorOk();
}
+30
View File
@@ -0,0 +1,30 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "error/error.h"
// dusk.dsk is packaged at the root of the VPK and accessible via app0:/
#define ASSET_VITA_DSK_PATH "app0:/" ASSET_FILE_NAME
typedef struct {
uint8_t _unused;
} assetvita_t;
/**
* Initializes the Vita asset system, opening dusk.dsk from the VPK mount.
*
* @returns An errorret_t indicating success or failure.
*/
errorret_t assetInitVita(void);
/**
* Disposes the Vita asset system.
*
* @returns An errorret_t indicating success or failure.
*/
errorret_t assetDisposeVita(void);
+16
View File
@@ -0,0 +1,16 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/displaysdl2.h"
typedef displaysdl2_t displayplatform_t;
#define displayPlatformInit displaySDL2Init
#define displayPlatformUpdate displaySDL2Update
#define displayPlatformSwap displaySDL2Swap
#define displayPlatformDispose displaySDL2Dispose
+22
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 <vitasdk.h>
#define GL_COLOR_INDEX8_EXT 0x80E5
#define GL_NO_ERROR 0
#define glDrawArrays(type, first, count) ((void)0)
#define glColorTableEXT(target, internalformat, count, format, type, pixels) ((void)0)
#define glDepthFunc(func) ((void)0)
#define glBlendFunc(sfactor, dfactor) ((void)0)
#define glGetError() GL_NO_ERROR
#define GL_GLEXT_PROTOTYPES
typedef uint32_t GLbitfield;
#include "dusksdl2.h"
+10
View File
@@ -0,0 +1,10 @@
# 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
inputvita.c
)
+39
View File
@@ -0,0 +1,39 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "input/input.h"
inputbuttondata_t INPUT_BUTTON_DATA[] = {
{ .name = "triangle", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_Y } },
{ .name = "cross", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_A } },
{ .name = "circle", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_B } },
{ .name = "square", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_X } },
{ .name = "start", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_START } },
{ .name = "select", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_BACK } },
{ .name = "up", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_DPAD_UP } },
{ .name = "down", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_DPAD_DOWN } },
{ .name = "left", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_DPAD_LEFT } },
{ .name = "right", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_DPAD_RIGHT } },
{ .name = "l", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_LEFTSHOULDER } },
{ .name = "r", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER } },
{ .name = "lstick_down", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTY, .positive = true } } },
{ .name = "lstick_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTY, .positive = false } } },
{ .name = "lstick_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTX, .positive = true } } },
{ .name = "lstick_left", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTX, .positive = false } } },
{ .name = "rstick_down", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_RIGHTY, .positive = true } } },
{ .name = "rstick_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_RIGHTY, .positive = false } } },
{ .name = "rstick_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_RIGHTX, .positive = true } } },
{ .name = "rstick_left", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_RIGHTX, .positive = false } } },
{ .name = NULL }
};
float_t inputGetDeadzoneSDL2(const inputbutton_t button) {
return 0.17f;
}
+10
View File
@@ -0,0 +1,10 @@
# 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
log.c
)
+52
View File
@@ -0,0 +1,52 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "log/log.h"
void logDebug(const char_t *message, ...) {
va_list args;
va_start(args, message);
// print to stdout
va_list copy;
va_copy(copy, args);
vprintf(message, copy);
va_end(copy);
// print to file
FILE *file = fopen("ux0:data/Dusk/debug.log", "a");
if(file) {
va_copy(copy, args);
vfprintf(file, message, copy);
va_end(copy);
fclose(file);
}
va_end(args);
}
void logError(const char_t *message, ...) {
va_list args;
va_start(args, message);
// print to stderr
va_list copy;
va_copy(copy, args);
vfprintf(stderr, message, copy);
va_end(copy);
// print to file
FILE *file = fopen("ux0:data/Dusk/error.log", "a");
if(file) {
va_copy(copy, args);
vfprintf(file, message, copy);
va_end(copy);
fclose(file);
}
va_end(args);
}
@@ -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 "moduleplatformvita.h"
#define modulePlatformPlatform modulePlatformVita
@@ -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 "script/scriptcontext.h"
void modulePlatformVita(scriptcontext_t *ctx) {
scriptContextExec(ctx, "VITA = true\n");
}