Game no longer crashes on Dolphin
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC
|
||||||
DUSK_PLATFORM_ENDIAN_BIG
|
DUSK_PLATFORM_ENDIAN_BIG
|
||||||
DUSK_DOLPHIN
|
DUSK_DOLPHIN
|
||||||
|
DUSK_DISPLAY_WIDTH=640
|
||||||
|
DUSK_DISPLAY_HEIGHT=480
|
||||||
)
|
)
|
||||||
|
|
||||||
# Custom compiler flags
|
# Custom compiler flags
|
||||||
|
|||||||
@@ -22,12 +22,13 @@ errorret_t textureInit(
|
|||||||
) {
|
) {
|
||||||
assertNotNull(texture, "Texture cannot be NULL");
|
assertNotNull(texture, "Texture cannot be NULL");
|
||||||
assertTrue(width > 0 && height > 0, "width/height must be greater than 0");
|
assertTrue(width > 0 && height > 0, "width/height must be greater than 0");
|
||||||
|
assertTrue(width == mathNextPowTwo(width), "Width must be a power of 2.");
|
||||||
|
assertTrue(height == mathNextPowTwo(height), "Height must be a power of 2.");
|
||||||
|
|
||||||
memoryZero(texture, sizeof(texture_t));
|
memoryZero(texture, sizeof(texture_t));
|
||||||
texture->width = width;
|
texture->width = width;
|
||||||
texture->height = height;
|
texture->height = height;
|
||||||
texture->format = format;
|
texture->format = format;
|
||||||
assertTrue(width == mathNextPowTwo(width), "Width must be a power of 2.");
|
|
||||||
assertTrue(height == mathNextPowTwo(height), "Height must be a power of 2.");
|
|
||||||
|
|
||||||
errorChain(textureInitPlatform(texture, width, height, format, data));
|
errorChain(textureInitPlatform(texture, width, height, format, data));
|
||||||
errorOk();
|
errorOk();
|
||||||
|
|||||||
@@ -50,10 +50,6 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
errorret_t engineUpdate(void) {
|
errorret_t engineUpdate(void) {
|
||||||
#if DOLPHIN
|
|
||||||
ENGINE.running = SYS_MainLoop();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
timeUpdate();
|
timeUpdate();
|
||||||
inputUpdate();
|
inputUpdate();
|
||||||
|
|
||||||
|
|||||||
@@ -131,5 +131,6 @@ errorret_t errorPrint(const errorret_t retval) {
|
|||||||
retval.state->message,
|
retval.state->message,
|
||||||
retval.state->lines
|
retval.state->lines
|
||||||
);
|
);
|
||||||
|
debugFlush();
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -10,61 +10,6 @@
|
|||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
|
||||||
// inputbuttondata_t INPUT_BUTTON_DATA[] = {
|
|
||||||
// #if INPUT_SDL2 == 1
|
|
||||||
// #if INPUT_GAMEPAD == 1
|
|
||||||
// #if PSP
|
|
||||||
// { .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_LEFTX, .positive = true } } },
|
|
||||||
// { .name = "lstick_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTX, .positive = false } } },
|
|
||||||
// { .name = "lstick_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTY, .positive = true } } },
|
|
||||||
// { .name = "lstick_left", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = SDL_CONTROLLER_AXIS_LEFTY, .positive = false } } },
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
|
|
||||||
// #elif DOLPHIN
|
|
||||||
// #if INPUT_GAMEPAD == 1
|
|
||||||
// { .name = "a", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_A } },
|
|
||||||
// { .name = "b", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_B } },
|
|
||||||
// { .name = "x", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_X } },
|
|
||||||
// { .name = "y", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_Y } },
|
|
||||||
// { .name = "start", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_START } },
|
|
||||||
// { .name = "up", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_UP } },
|
|
||||||
// { .name = "down", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_DOWN } },
|
|
||||||
// { .name = "left", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_LEFT } },
|
|
||||||
// { .name = "right", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_RIGHT } },
|
|
||||||
// { .name = "l", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_TRIGGER_L } },
|
|
||||||
// { .name = "r", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_TRIGGER_R } },
|
|
||||||
// { .name = "z", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_TRIGGER_Z } },
|
|
||||||
// { .name = "menu", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_MENU } },
|
|
||||||
// { .name = "lstick_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_X, .positive = true } } },
|
|
||||||
// { .name = "lstick_down", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_X, .positive = false } } },
|
|
||||||
// { .name = "lstick_left", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_Y, .positive = true } } },
|
|
||||||
// { .name = "lstick_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_Y, .positive = false } } },
|
|
||||||
// { .name = "rstick_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_X, .positive = true } } },
|
|
||||||
// { .name = "rstick_down", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_X, .positive = false } } },
|
|
||||||
// { .name = "rstick_left", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_Y, .positive = true } } },
|
|
||||||
// { .name = "rstick_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_Y, .positive = false } } },
|
|
||||||
// { .name = "ltrigger", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_TRIGGER_LEFT, .positive = true } } },
|
|
||||||
// { .name = "rtrigger", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_TRIGGER_RIGHT, .positive = true } } },
|
|
||||||
// #endif
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// { .name = NULL }
|
|
||||||
// };
|
|
||||||
|
|
||||||
inputbutton_t inputButtonGetByName(const char_t *name) {
|
inputbutton_t inputButtonGetByName(const char_t *name) {
|
||||||
assertNotNull(name, "name must not be NULL");
|
assertNotNull(name, "name must not be NULL");
|
||||||
|
|
||||||
@@ -78,3 +23,7 @@ inputbutton_t inputButtonGetByName(const char_t *name) {
|
|||||||
|
|
||||||
return (inputbutton_t){ .type = INPUT_BUTTON_TYPE_NONE };
|
return (inputbutton_t){ .type = INPUT_BUTTON_TYPE_NONE };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float_t inputButtonGetValue(const inputbutton_t button) {
|
||||||
|
return inputButtonGetValuePlatform(button);
|
||||||
|
}
|
||||||
@@ -7,13 +7,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "dusk.h"
|
#include "dusk.h"
|
||||||
#include "time/timeplatform.h"
|
|
||||||
|
|
||||||
#ifndef DUSK_TIME_STEP
|
#ifndef DUSK_TIME_STEP
|
||||||
#define DUSK_TIME_STEP (16.0f / 1000.0f)
|
#define DUSK_TIME_STEP (16.0f / 1000.0f)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DUSK_TIME_DYNAMIC
|
#ifdef DUSK_TIME_DYNAMIC
|
||||||
|
#include "time/timeplatform.h"
|
||||||
|
|
||||||
#ifndef timeTickPlatform
|
#ifndef timeTickPlatform
|
||||||
#error "DUSK_TIME_DYNAMIC needs tick method defined"
|
#error "DUSK_TIME_DYNAMIC needs tick method defined"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,5 +9,13 @@ target_include_directories(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
${CMAKE_CURRENT_LIST_DIR}
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Sources
|
||||||
|
target_sources(${DUSK_BINARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
||||||
|
add_subdirectory(asset)
|
||||||
add_subdirectory(debug)
|
add_subdirectory(debug)
|
||||||
|
add_subdirectory(display)
|
||||||
|
add_subdirectory(input)
|
||||||
11
src/duskdolphin/asset/CMakeLists.txt
Normal file
11
src/duskdolphin/asset/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# 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
|
||||||
|
assetdolphin.c
|
||||||
|
)
|
||||||
@@ -1,53 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
// Init FAT driver.
|
#include "asset/asset.h"
|
||||||
if(!fatInitDefault()) errorThrow("Failed to initialize FAT filesystem.");
|
#include "util/string.h"
|
||||||
|
#include <fat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
char_t **dolphinSearchPath = (char_t **)ASSET_DOLPHIN_PATHS;
|
errorret_t assetInitDolphin(void) {
|
||||||
char_t foundPath[FILENAME_MAX];
|
// Init FAT driver.
|
||||||
foundPath[0] = '\0';
|
if(!fatInitDefault()) errorThrow("Failed to initialize FAT filesystem.");
|
||||||
do {
|
|
||||||
// Try open dir
|
|
||||||
DIR *pdir = opendir(*dolphinSearchPath);
|
|
||||||
if(pdir == NULL) continue;
|
|
||||||
|
|
||||||
|
char_t **dolphinSearchPath = (char_t **)ASSET_DOLPHIN_PATHS;
|
||||||
|
char_t foundPath[FILENAME_MAX];
|
||||||
|
foundPath[0] = '\0';
|
||||||
|
do {
|
||||||
|
// Try open dir
|
||||||
|
DIR *pdir = opendir(*dolphinSearchPath);
|
||||||
|
if(pdir == NULL) continue;
|
||||||
|
|
||||||
// Scan if file is present
|
// Scan if file is present
|
||||||
while(true) {
|
while(true) {
|
||||||
struct dirent* pent = readdir(pdir);
|
struct dirent* pent = readdir(pdir);
|
||||||
if(pent == NULL) break;
|
if(pent == NULL) break;
|
||||||
|
|
||||||
if(stringCompareInsensitive(pent->d_name, ASSET_FILE) != 0) {
|
if(stringCompareInsensitive(pent->d_name, ASSET_FILE_NAME) != 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
// Copy out filename
|
|
||||||
snprintf(
|
|
||||||
foundPath,
|
|
||||||
FILENAME_MAX,
|
|
||||||
"%s/%s",
|
|
||||||
*dolphinSearchPath,
|
|
||||||
ASSET_FILE
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close dir.
|
// Copy out filename
|
||||||
closedir(pdir);
|
snprintf(
|
||||||
|
foundPath,
|
||||||
// Did we find the file here?
|
FILENAME_MAX,
|
||||||
if(foundPath[0] != '\0') break;
|
"%s/%s",
|
||||||
} while(*(++dolphinSearchPath) != NULL);
|
*dolphinSearchPath,
|
||||||
|
ASSET_FILE_NAME
|
||||||
if(foundPath[0] != '\0') {
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Did we find the asset file?
|
// Close dir.
|
||||||
if(foundPath[0] == '\0') {
|
closedir(pdir);
|
||||||
errorThrow("Failed to find asset file on FAT filesystem.");
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSET.zip = zip_open(foundPath, ZIP_RDONLY, NULL);
|
// Did we find the file here?
|
||||||
if(ASSET.zip == NULL) {
|
if(foundPath[0] != '\0') break;
|
||||||
errorThrow("Failed to open asset file on FAT filesystem.");
|
} while(*(++dolphinSearchPath) != NULL);
|
||||||
}
|
|
||||||
errorOk();
|
// Did we find the asset file?
|
||||||
|
if(foundPath[0] == '\0') {
|
||||||
|
errorThrow("Failed to find asset file on FAT filesystem.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSET.zip = zip_open(foundPath, ZIP_RDONLY, NULL);
|
||||||
|
if(ASSET.zip == NULL) {
|
||||||
|
errorThrow("Failed to open asset file on FAT filesystem.");
|
||||||
|
}
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t assetDisposeDolphin() {
|
||||||
|
// Nothing doing.
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
@@ -6,14 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <fat.h>
|
#include "error/error.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
static const char_t *ASSET_DOLPHIN_PATHS[] = {
|
static const char_t *ASSET_DOLPHIN_PATHS[] = {
|
||||||
"/",
|
"/",
|
||||||
@@ -35,3 +28,21 @@ static const char_t *ASSET_DOLPHIN_PATHS[] = {
|
|||||||
"./apps/DUSK",
|
"./apps/DUSK",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t nothing;
|
||||||
|
} assetdolphin_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Dolphin asset system.
|
||||||
|
*
|
||||||
|
* @return An error code indicating success or failure.
|
||||||
|
*/
|
||||||
|
errorret_t assetInitDolphin(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes of the Dolphin asset system, freeing any allocated resources.
|
||||||
|
*
|
||||||
|
* @return An error code indicating success or failure.
|
||||||
|
*/
|
||||||
|
errorret_t assetDisposeDolphin(void);
|
||||||
14
src/duskdolphin/asset/assetplatform.h
Normal file
14
src/duskdolphin/asset/assetplatform.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "assetdolphin.h"
|
||||||
|
|
||||||
|
#define assetInitPlatform assetInitDolphin
|
||||||
|
#define assetDisposePlatform assetDisposeDolphin
|
||||||
|
|
||||||
|
typedef assetdolphin_t assetplatform_t;
|
||||||
@@ -5,8 +5,9 @@
|
|||||||
* https://opensource.org/licenses/MIT
|
* https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dolphin.h"
|
#include "debug/debug.h"
|
||||||
#include "display/display.h"
|
#include "display/display.h"
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
static char_t DEBUG_ERROR_BUFFER[16*1024] = {0};
|
static char_t DEBUG_ERROR_BUFFER[16*1024] = {0};
|
||||||
|
|
||||||
@@ -14,6 +15,10 @@ void debugPrint(const char_t *message, ...) {
|
|||||||
// append to error buffer
|
// append to error buffer
|
||||||
size_t start = strlen(DEBUG_ERROR_BUFFER);
|
size_t start = strlen(DEBUG_ERROR_BUFFER);
|
||||||
va_list args;
|
va_list args;
|
||||||
|
va_start(args, message);
|
||||||
|
fprintf(stdout, message, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
va_start(args, message);
|
va_start(args, message);
|
||||||
vsnprintf(
|
vsnprintf(
|
||||||
DEBUG_ERROR_BUFFER + start,
|
DEBUG_ERROR_BUFFER + start,
|
||||||
@@ -25,6 +30,8 @@ void debugPrint(const char_t *message, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void debugFlush() {
|
void debugFlush() {
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
// Either create graphics, or hijack the displays' graphics.
|
// Either create graphics, or hijack the displays' graphics.
|
||||||
void *xfb = NULL;
|
void *xfb = NULL;
|
||||||
GXRModeObj *rmode = NULL;
|
GXRModeObj *rmode = NULL;
|
||||||
|
|||||||
17
src/duskdolphin/display/CMakeLists.txt
Normal file
17
src/duskdolphin/display/CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# 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
|
||||||
|
displaydolphin.c
|
||||||
|
# debug.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# Subdirs
|
||||||
|
add_subdirectory(camera)
|
||||||
|
add_subdirectory(framebuffer)
|
||||||
|
add_subdirectory(mesh)
|
||||||
|
add_subdirectory(texture)
|
||||||
11
src/duskdolphin/display/camera/CMakeLists.txt
Normal file
11
src/duskdolphin/display/camera/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# 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
|
||||||
|
cameradolphin.c
|
||||||
|
)
|
||||||
107
src/duskdolphin/display/camera/cameradolphin.c
Normal file
107
src/duskdolphin/display/camera/cameradolphin.c
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "display/camera/camera.h"
|
||||||
|
#include "display/framebuffer/framebuffer.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
|
void cameraPushMatrixDolphin(camera_t *camera) {
|
||||||
|
assertNotNull(camera, "Camera cannot be null");
|
||||||
|
|
||||||
|
Mtx44 guProjection;
|
||||||
|
Mtx guView;
|
||||||
|
Mtx modelView;
|
||||||
|
|
||||||
|
switch(camera->projType) {
|
||||||
|
case CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC:
|
||||||
|
guOrtho(
|
||||||
|
guProjection,
|
||||||
|
camera->orthographic.top,
|
||||||
|
camera->orthographic.bottom,
|
||||||
|
camera->orthographic.left,
|
||||||
|
camera->orthographic.right,
|
||||||
|
camera->nearClip,
|
||||||
|
camera->farClip
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CAMERA_PROJECTION_TYPE_PERSPECTIVE:
|
||||||
|
guPerspective(
|
||||||
|
guProjection,
|
||||||
|
// FOV is in degrees.
|
||||||
|
camera->perspective.fov * (180.0f / GLM_PIf),
|
||||||
|
(float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND) /
|
||||||
|
(float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND),
|
||||||
|
camera->nearClip,
|
||||||
|
camera->farClip
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED:
|
||||||
|
assertUnreachable("Flipped perspective not implemented on Dolphin");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assertUnreachable("Invalid camera projection type");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(camera->viewType) {
|
||||||
|
case CAMERA_VIEW_TYPE_LOOKAT:
|
||||||
|
guVector eye = {
|
||||||
|
camera->lookat.position[0],
|
||||||
|
camera->lookat.position[1],
|
||||||
|
camera->lookat.position[2]
|
||||||
|
};
|
||||||
|
guVector up = {
|
||||||
|
camera->lookat.up[0],
|
||||||
|
camera->lookat.up[1],
|
||||||
|
camera->lookat.up[2]
|
||||||
|
};
|
||||||
|
guVector look = {
|
||||||
|
camera->lookat.target[0],
|
||||||
|
camera->lookat.target[1],
|
||||||
|
camera->lookat.target[2]
|
||||||
|
};
|
||||||
|
guLookAt(guView, &eye, &up, &look);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CAMERA_VIEW_TYPE_MATRIX:
|
||||||
|
assertUnreachable("Matrix camera not implemented");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT:
|
||||||
|
assertUnreachable("Pixel perfect camera not implemented");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CAMERA_VIEW_TYPE_2D:
|
||||||
|
guMtxIdentity(guView);
|
||||||
|
guMtxTrans(guView, -camera->_2d.position[0], -camera->_2d.position[1], 0.0f);
|
||||||
|
guMtxScale(guView, camera->_2d.zoom, camera->_2d.zoom, 1.0f);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assertUnreachable("Invalid camera view type");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Projection Matrix
|
||||||
|
GX_LoadProjectionMtx(
|
||||||
|
guProjection,
|
||||||
|
camera->projType == CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC ?
|
||||||
|
GX_ORTHOGRAPHIC :
|
||||||
|
GX_PERSPECTIVE
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set view and model matrix. Dunno how I'll handle models but whatever.
|
||||||
|
guMtxIdentity(modelView);
|
||||||
|
guMtxTransApply(modelView, modelView, 0.0F, 0.0F, 0.0F);
|
||||||
|
guMtxConcat(guView,modelView,modelView);
|
||||||
|
GX_LoadPosMtxImm(modelView, GX_PNMTX0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cameraPopMatrixDolphin(void) {
|
||||||
|
|
||||||
|
}
|
||||||
23
src/duskdolphin/display/camera/cameradolphin.h
Normal file
23
src/duskdolphin/display/camera/cameradolphin.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* 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 camera_s camera_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes the camera's transformation matrix onto the graphics stack.
|
||||||
|
*
|
||||||
|
* @param camera The camera to push the matrix of.
|
||||||
|
*/
|
||||||
|
void cameraPushMatrixDolphin(camera_t *camera);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pops the camera's transformation matrix from the graphics stack.
|
||||||
|
*/
|
||||||
|
void cameraPopMatrixDolphin(void);
|
||||||
12
src/duskdolphin/display/camera/cameraplatform.h
Normal file
12
src/duskdolphin/display/camera/cameraplatform.h
Normal 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 "cameradolphin.h"
|
||||||
|
|
||||||
|
#define cameraPushMatrixPlatform cameraPushMatrixDolphin
|
||||||
|
#define cameraPopMatrixPlatform cameraPopMatrixDolphin
|
||||||
102
src/duskdolphin/display/displaydolphin.c
Normal file
102
src/duskdolphin/display/displaydolphin.c
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "display/display.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
#include "engine/engine.h"
|
||||||
|
|
||||||
|
errorret_t 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_DOLPHIN_FIFO_SIZE);
|
||||||
|
memoryZero(DISPLAY.fifoBuffer, DISPLAY_DOLPHIN_FIFO_SIZE);
|
||||||
|
|
||||||
|
GX_Init(DISPLAY.fifoBuffer, DISPLAY_DOLPHIN_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);
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t displayUpdateDolphin(void) {
|
||||||
|
ENGINE.running = SYS_MainLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t displaySwapDolphin(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();
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
33
src/duskdolphin/display/displaydolphin.h
Normal file
33
src/duskdolphin/display/displaydolphin.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "error/error.h"
|
||||||
|
|
||||||
|
#define DISPLAY_DOLPHIN_FIFO_SIZE (256*1024)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *frameBuffer[2];// Double-Bufferred
|
||||||
|
int whichFrameBuffer;
|
||||||
|
GXRModeObj *screenMode;
|
||||||
|
void *fifoBuffer;
|
||||||
|
} displaydolphin_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the display system on Dolphin.
|
||||||
|
*/
|
||||||
|
errorret_t displayInitDolphin(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells the display system to actually draw the frame on Dolphin.
|
||||||
|
*/
|
||||||
|
errorret_t displayUpdateDolphin(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swaps the display buffers on Dolphin.
|
||||||
|
*/
|
||||||
|
errorret_t displaySwapDolphin(void);
|
||||||
15
src/duskdolphin/display/displayplatform.h
Normal file
15
src/duskdolphin/display/displayplatform.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "displaydolphin.h"
|
||||||
|
|
||||||
|
#define displayPlatformInit displayInitDolphin
|
||||||
|
#define displayPlatformUpdate displayUpdateDolphin
|
||||||
|
#define displayPlatformSwap displaySwapDolphin
|
||||||
|
|
||||||
|
typedef displaydolphin_t displayplatform_t;
|
||||||
11
src/duskdolphin/display/framebuffer/CMakeLists.txt
Normal file
11
src/duskdolphin/display/framebuffer/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# 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
|
||||||
|
framebufferdolphin.c
|
||||||
|
)
|
||||||
54
src/duskdolphin/display/framebuffer/framebufferdolphin.c
Normal file
54
src/duskdolphin/display/framebuffer/framebufferdolphin.c
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "display/framebuffer/framebuffer.h"
|
||||||
|
#include "display/display.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
|
errorret_t frameBufferInitBackBufferDolphin(void) {
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t frameBufferBindDolphin(framebufferdolphin_t *framebuffer) {
|
||||||
|
assertNotNull(framebuffer, "Cannot bind NULL framebuffer.");
|
||||||
|
assertTrue(
|
||||||
|
framebuffer == &FRAMEBUFFER_BACKBUFFER,
|
||||||
|
"Cannot bind framebuffer that is not the back buffer."
|
||||||
|
);
|
||||||
|
|
||||||
|
GX_InvVtxCache();
|
||||||
|
GX_InvalidateTexAll();
|
||||||
|
GX_SetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE);
|
||||||
|
|
||||||
|
GX_SetViewport(
|
||||||
|
0, 0,
|
||||||
|
frameBufferGetWidth(framebuffer),
|
||||||
|
frameBufferGetHeight(framebuffer),
|
||||||
|
0, 1
|
||||||
|
);
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void frameBufferClearDolphin(const uint8_t flags, const color_t color) {
|
||||||
|
GX_SetCopyClear(
|
||||||
|
(GXColor){ color.r, color.g, color.b, color.a },
|
||||||
|
GX_MAX_Z24
|
||||||
|
);
|
||||||
|
}
|
||||||
55
src/duskdolphin/display/framebuffer/framebufferdolphin.h
Normal file
55
src/duskdolphin/display/framebuffer/framebufferdolphin.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "display/color.h"
|
||||||
|
#include "error/error.h"
|
||||||
|
|
||||||
|
#ifdef DUSK_DISPLAY_SIZE_DYNAMIC
|
||||||
|
#error "Dolphin does not support dynamic display sizes."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t nothing;
|
||||||
|
} framebufferdolphin_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the backbuffer framebuffer. (Dolphin implementation).
|
||||||
|
*/
|
||||||
|
errorret_t frameBufferInitBackBufferDolphin(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the height of the framebuffer. (Dolphin implementation).
|
||||||
|
*
|
||||||
|
* @param framebuffer The framebuffer to get the height of.
|
||||||
|
* @return The height of the framebuffer, or 0 if the framebuffer is NULL.
|
||||||
|
*/
|
||||||
|
uint32_t frameBufferGetWidthDolphin(const framebufferdolphin_t *framebuffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the width of the framebuffer. (Dolphin implementation).
|
||||||
|
*
|
||||||
|
* @param framebuffer The framebuffer to get the width of.
|
||||||
|
* @return The width of the framebuffer, or 0 if the framebuffer is NULL.
|
||||||
|
*/
|
||||||
|
uint32_t frameBufferGetHeightDolphin(const framebufferdolphin_t *framebuffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds the framebuffer for rendering. (Dolphin implementation).
|
||||||
|
*
|
||||||
|
* @param framebuffer The framebuffer to bind.
|
||||||
|
* @return Either error or not.
|
||||||
|
*/
|
||||||
|
errorret_t frameBufferBindDolphin(framebufferdolphin_t *framebuffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the framebuffer with the specified flags and color.
|
||||||
|
*
|
||||||
|
* @param flags The clear flags.
|
||||||
|
* @param color The clear color.
|
||||||
|
*/
|
||||||
|
void frameBufferClearDolphin(const uint8_t flags, const color_t color);
|
||||||
17
src/duskdolphin/display/framebuffer/framebufferplatform.h
Normal file
17
src/duskdolphin/display/framebuffer/framebufferplatform.h
Normal 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 "framebufferdolphin.h"
|
||||||
|
|
||||||
|
typedef framebufferdolphin_t framebufferplatform_t;
|
||||||
|
|
||||||
|
#define frameBufferPlatformInitBackBuffer frameBufferInitBackBufferDolphin
|
||||||
|
#define frameBufferPlatformGetWidth frameBufferGetWidthDolphin
|
||||||
|
#define frameBufferPlatformGetHeight frameBufferGetHeightDolphin
|
||||||
|
#define frameBufferPlatformBind frameBufferBindDolphin
|
||||||
|
#define frameBufferPlatformClear frameBufferClearDolphin
|
||||||
11
src/duskdolphin/display/mesh/CMakeLists.txt
Normal file
11
src/duskdolphin/display/mesh/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# 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
|
||||||
|
meshdolphin.c
|
||||||
|
)
|
||||||
73
src/duskdolphin/display/mesh/meshdolphin.c
Normal file
73
src/duskdolphin/display/mesh/meshdolphin.c
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "display/mesh/mesh.h"
|
||||||
|
#include "display/texture/texture.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
|
errorret_t meshInitDolphin(
|
||||||
|
meshdolphin_t *mesh,
|
||||||
|
const meshprimitivetypedolphin_t primitiveType,
|
||||||
|
const int32_t vertexCount,
|
||||||
|
const meshvertex_t *vertices
|
||||||
|
) {
|
||||||
|
assertNotNull(mesh, "Mesh cannot be null.");
|
||||||
|
assertNotNull(vertices, "Vertices cannot be null.");
|
||||||
|
assertTrue(vertexCount > 0, "Vertex count must be greater than 0.");
|
||||||
|
|
||||||
|
mesh->primitiveType = primitiveType;
|
||||||
|
mesh->vertexCount = vertexCount;
|
||||||
|
mesh->vertices = vertices;
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t meshDrawDolphin(
|
||||||
|
const meshdolphin_t *mesh,
|
||||||
|
const int32_t vertexOffset,
|
||||||
|
const int32_t vertexCount
|
||||||
|
) {
|
||||||
|
assertNotNull(mesh, "Mesh cannot be NULL.");
|
||||||
|
assertTrue(vertexOffset >= 0, "Vertex offset must be >= 0");
|
||||||
|
assertTrue(vertexCount > 0, "Vertex count must be > 0");
|
||||||
|
assertTrue(
|
||||||
|
vertexOffset + vertexCount <= mesh->vertexCount,
|
||||||
|
"Requested vertex range is invalid"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Prepare Vertex descriptor
|
||||||
|
DCFlushRange(
|
||||||
|
(void*)&mesh->vertices[vertexOffset],
|
||||||
|
sizeof(meshvertex_t) * vertexCount
|
||||||
|
);
|
||||||
|
|
||||||
|
const u8 stride = (u8)sizeof(meshvertex_t);
|
||||||
|
GX_SetArray(GX_VA_POS, (void*)&mesh->vertices[vertexOffset].pos[0], stride);
|
||||||
|
GX_SetArray(GX_VA_CLR0, (void*)&mesh->vertices[vertexOffset].color, stride);
|
||||||
|
GX_SetArray(GX_VA_TEX0, (void*)&mesh->vertices[vertexOffset].uv[0], stride);
|
||||||
|
|
||||||
|
textureDolphinUploadTEV();
|
||||||
|
|
||||||
|
GX_Begin(mesh->primitiveType, GX_VTXFMT0, (uint16_t)vertexCount);
|
||||||
|
for(u16 i = 0; i < (u16)vertexCount; ++i) {
|
||||||
|
GX_Position1x16(i);
|
||||||
|
GX_Color1x16(i);
|
||||||
|
GX_TexCoord1x16(i);
|
||||||
|
}
|
||||||
|
GX_End();
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t meshGetVertexCountDolphin(const meshdolphin_t *mesh) {
|
||||||
|
assertNotNull(mesh, "Mesh cannot be NULL.");
|
||||||
|
return mesh->vertexCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t meshDisposeDolphin(meshdolphin_t *mesh) {
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
68
src/duskdolphin/display/mesh/meshdolphin.h
Normal file
68
src/duskdolphin/display/mesh/meshdolphin.h
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "display/mesh/meshvertex.h"
|
||||||
|
#include "error/error.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MESH_PRIMITIVE_TYPE_TRIANGLES = GX_TRIANGLES,
|
||||||
|
MESH_PRIMITIVE_TYPE_LINES = GX_LINES,
|
||||||
|
MESH_PRIMITIVE_TYPE_POINTS = GX_POINTS,
|
||||||
|
} meshprimitivetypedolphin_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const meshvertex_t *vertices;
|
||||||
|
int32_t vertexCount;
|
||||||
|
meshprimitivetypedolphin_t primitiveType;
|
||||||
|
} meshdolphin_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a mesh.
|
||||||
|
*
|
||||||
|
* @param mesh The mesh to initialize.
|
||||||
|
* @param primitiveType The Dolphin primitive type (e.g., GX_TRIANGLES).
|
||||||
|
* @param vertexCount The number of vertices in the mesh.
|
||||||
|
* @param vertices The vertex data for the mesh.
|
||||||
|
* @return An error indicating success or failure.
|
||||||
|
*/
|
||||||
|
errorret_t meshInitDolphin(
|
||||||
|
meshdolphin_t *mesh,
|
||||||
|
const meshprimitivetypedolphin_t primitiveType,
|
||||||
|
const int32_t vertexCount,
|
||||||
|
const meshvertex_t *vertices
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a mesh.
|
||||||
|
*
|
||||||
|
* @param mesh The mesh to draw.
|
||||||
|
* @param vertexOffset The offset in the vertex array to start drawing from.
|
||||||
|
* @param vertexCount The number of vertices to draw. If -1, draws all vertices.
|
||||||
|
* @return An error indicating success or failure.
|
||||||
|
*/
|
||||||
|
errorret_t meshDrawDolphin(
|
||||||
|
const meshdolphin_t *mesh,
|
||||||
|
const int32_t vertexOffset,
|
||||||
|
const int32_t vertexCount
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the vertex count of a mesh.
|
||||||
|
*
|
||||||
|
* @param mesh The mesh to get the vertex count from.
|
||||||
|
* @return The vertex count of the mesh.
|
||||||
|
*/
|
||||||
|
int32_t meshGetVertexCountDolphin(const meshdolphin_t *mesh);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes of a mesh, freeing any associated resources.
|
||||||
|
*
|
||||||
|
* @param mesh The mesh to dispose of.
|
||||||
|
* @return An error indicating success or failure.
|
||||||
|
*/
|
||||||
|
errorret_t meshDisposeDolphin(meshdolphin_t *mesh);
|
||||||
16
src/duskdolphin/display/mesh/meshplatform.h
Normal file
16
src/duskdolphin/display/mesh/meshplatform.h
Normal 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 "meshdolphin.h"
|
||||||
|
|
||||||
|
#define meshInitPlatform meshInitDolphin
|
||||||
|
#define meshDrawPlatform meshDrawDolphin
|
||||||
|
#define meshGetVertexCountPlatform meshGetVertexCountDolphin
|
||||||
|
#define meshDisposePlatform meshDisposeDolphin
|
||||||
|
typedef meshprimitivetypedolphin_t meshprimitivetypeplatform_t;
|
||||||
|
typedef meshdolphin_t meshplatform_t;
|
||||||
11
src/duskdolphin/display/texture/CMakeLists.txt
Normal file
11
src/duskdolphin/display/texture/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# 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
|
||||||
|
texturedolphin.c
|
||||||
|
)
|
||||||
188
src/duskdolphin/display/texture/texturedolphin.c
Normal file
188
src/duskdolphin/display/texture/texturedolphin.c
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "display/texture/texture.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
|
errorret_t textureInitDolphin(
|
||||||
|
texturedolphin_t *texture,
|
||||||
|
const int32_t width,
|
||||||
|
const int32_t height,
|
||||||
|
const textureformatdolphin_t format,
|
||||||
|
const texturedata_t data
|
||||||
|
) {
|
||||||
|
// switch(format) {
|
||||||
|
// case TEXTURE_FORMAT_RGBA:
|
||||||
|
// assertTrue(
|
||||||
|
// (width % 4) == 0 && (height % 4) == 0,
|
||||||
|
// "RGB5A3 requires w/h multiple of 4 (or pad)"
|
||||||
|
// );
|
||||||
|
|
||||||
|
// // Convert to RGB5A3 format
|
||||||
|
// size_t rgbaSize = width * height * sizeof(u16);
|
||||||
|
// texture->rgba = (u16*)memalign(32, rgbaSize);
|
||||||
|
// assertNotNull(texture->rgba, "Failed to allocate texture RGBA data");
|
||||||
|
|
||||||
|
// for(uint32_t y = 0; y < height; ++y) {
|
||||||
|
// for(uint32_t x = 0; x < width; ++x) {
|
||||||
|
// const int src = y * width + x;
|
||||||
|
|
||||||
|
// const int tileX = x >> 2;
|
||||||
|
// const int tileY = y >> 2;
|
||||||
|
// const int tilesPerRow = width >> 2;
|
||||||
|
// const int tileIndex = tileY * tilesPerRow + tileX;
|
||||||
|
// const int tileBaseWords = tileIndex * 16;
|
||||||
|
// const int inTile = ((y & 3) << 2) + (x & 3);
|
||||||
|
// const int dest = tileBaseWords + inTile;
|
||||||
|
|
||||||
|
// color4b_t col = data.rgba.colors[src];
|
||||||
|
|
||||||
|
// u16 outCol;
|
||||||
|
// if(col.a < 255) {
|
||||||
|
// // 0AAA RRRR GGGG BBBB
|
||||||
|
// outCol = (
|
||||||
|
// (0u << 15) |
|
||||||
|
// ((u16)(col.a >> 5) << 12) |
|
||||||
|
// ((u16)(col.r >> 4) << 8) |
|
||||||
|
// ((u16)(col.g >> 4) << 4) |
|
||||||
|
// ((u16)(col.b >> 4) << 0)
|
||||||
|
// );
|
||||||
|
// } else {
|
||||||
|
// // 1RRRR RRGG GGGB BBBB
|
||||||
|
// outCol = (
|
||||||
|
// (1u << 15) |
|
||||||
|
// ((u16)(col.r >> 3) << 10) |
|
||||||
|
// ((u16)(col.g >> 3) << 5) |
|
||||||
|
// ((u16)(col.b >> 3) << 0)
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// texture->rgba[dest] = outCol;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// DCFlushRange(texture->rgba, rgbaSize);
|
||||||
|
// GX_InitTexObj(
|
||||||
|
// &texture->texObj,
|
||||||
|
// texture->rgba,
|
||||||
|
// width, height,
|
||||||
|
// GX_TF_RGB5A3,
|
||||||
|
// GX_REPEAT, GX_REPEAT,
|
||||||
|
// GX_FALSE
|
||||||
|
// );
|
||||||
|
|
||||||
|
// DCFlushRange(texture->rgba, rgbaSize);
|
||||||
|
// GX_InvalidateTexAll();
|
||||||
|
|
||||||
|
// GX_InitTexObjLOD(
|
||||||
|
// &texture->texObj,
|
||||||
|
// GX_NEAR, GX_NEAR,
|
||||||
|
// 0.0f, 0.0f, 0.0f,
|
||||||
|
// GX_FALSE,
|
||||||
|
// GX_FALSE,
|
||||||
|
// GX_ANISO_1
|
||||||
|
// );
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case TEXTURE_FORMAT_ALPHA: {
|
||||||
|
// assertTrue(
|
||||||
|
// (width % 4) == 0 && (height % 4) == 0,
|
||||||
|
// "GX_TF_I8 requires w/h multiple of 4 (or pad)"
|
||||||
|
// );
|
||||||
|
|
||||||
|
// // 1 byte per pixel (I8), GX expects 4x4 tiled layout
|
||||||
|
// const size_t alphaSize = (size_t)width * (size_t)height;
|
||||||
|
|
||||||
|
// texture->alpha = (u8*)memalign(32, alphaSize);
|
||||||
|
// assertNotNull(texture->alpha, "Failed to allocate alpha texture data");
|
||||||
|
|
||||||
|
// const u32 tilesPerRow = ((u32)width) >> 3; // /8
|
||||||
|
|
||||||
|
// for (u32 y = 0; y < (u32)height; ++y) {
|
||||||
|
// const u32 tileY = y >> 2; // /4
|
||||||
|
// const u32 inTileY = (y & 3) << 3; // (y%4)*8
|
||||||
|
|
||||||
|
// for (u32 x = 0; x < (u32)width; ++x) {
|
||||||
|
// const u32 srcI = y * (u32)width + x;
|
||||||
|
// const u8 srcA = data.alpha.data[srcI]; // linear input
|
||||||
|
|
||||||
|
// const u32 tileX = x >> 3; // /8
|
||||||
|
// const u32 tileIndex = tileY * tilesPerRow + tileX;
|
||||||
|
|
||||||
|
// const u32 tileBase = tileIndex * 32; // 8*4*1 = 32 bytes per tile
|
||||||
|
// const u32 inTile = inTileY + (x & 7); // (y%4)*8 + (x%8)
|
||||||
|
|
||||||
|
// texture->alpha[tileBase + inTile] = 0xFF - srcA;// Fixes inverted alpha.
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Flush CPU cache so GX sees the swizzled I8 texture data
|
||||||
|
// DCFlushRange(texture->alpha, alphaSize);
|
||||||
|
|
||||||
|
// // Initialize GX texture object with swizzled data
|
||||||
|
// GX_InitTexObj(
|
||||||
|
// &texture->texObj,
|
||||||
|
// texture->alpha,
|
||||||
|
// width, height,
|
||||||
|
// GX_TF_I8,
|
||||||
|
// GX_REPEAT, GX_REPEAT,
|
||||||
|
// GX_FALSE
|
||||||
|
// );
|
||||||
|
|
||||||
|
// GX_InitTexObjLOD(
|
||||||
|
// &texture->texObj,
|
||||||
|
// GX_NEAR, GX_NEAR,
|
||||||
|
// 0.0f, 0.0f, 0.0f,
|
||||||
|
// GX_FALSE,
|
||||||
|
// GX_FALSE,
|
||||||
|
// GX_ANISO_1
|
||||||
|
// );
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// case TEXTURE_FORMAT_PALETTE: {
|
||||||
|
// // Not supported, convert to RGBA using lookup
|
||||||
|
// color_t* formatted = memoryAllocate(width * height * sizeof(color_t));
|
||||||
|
// for(int32_t i = 0; i < width * height; i++) {
|
||||||
|
// uint8_t index = data.palette.data[i];
|
||||||
|
// assertTrue(
|
||||||
|
// index < data.palette.palette->colorCount,
|
||||||
|
// "Palette index out of range"
|
||||||
|
// );
|
||||||
|
// formatted[i] = data.palette.palette->colors[index];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// textureInit(
|
||||||
|
// texture, width, height, TEXTURE_FORMAT_RGBA,
|
||||||
|
// (texturedata_t){
|
||||||
|
// .rgba = { .colors = formatted }
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// memoryFree(formatted);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// default:
|
||||||
|
// assertUnreachable("Unsupported texture format for Dolphin");
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// texture->ready = true;
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t textureBindDolphin(texturedolphin_t *texture) {
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t textureDisposeDolphin(texturedolphin_t *texture) {
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void textureDolphinUploadTEV(void) {
|
||||||
|
|
||||||
|
}
|
||||||
63
src/duskdolphin/display/texture/texturedolphin.h
Normal file
63
src/duskdolphin/display/texture/texturedolphin.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
|
||||||
|
typedef union texturedata_u texturedata_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TEXTURE_FORMAT_RGBA = GX_TF_RGBA8,
|
||||||
|
TEXTURE_FORMAT_PALETTE = GX_TF_CI8,
|
||||||
|
} textureformatdolphin_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GXTexObj texObj;
|
||||||
|
textureformatdolphin_t format;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
} texturedolphin_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a texture.
|
||||||
|
*
|
||||||
|
* @param texture The texture to initialize.
|
||||||
|
* @param width The width of the texture.
|
||||||
|
* @param height The height of the texture.
|
||||||
|
* @param format The format of the texture (e.g., GX_TF_RGBA8, GX_TF_CI8).
|
||||||
|
* @param data The data for the texture, the format changes per format.
|
||||||
|
* @return An error if the texture failed to initialize, otherwise success.
|
||||||
|
*/
|
||||||
|
errorret_t textureInitDolphin(
|
||||||
|
texturedolphin_t *texture,
|
||||||
|
const int32_t width,
|
||||||
|
const int32_t height,
|
||||||
|
const textureformatdolphin_t format,
|
||||||
|
const texturedata_t data
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds a texture for rendering. Providing NULL will unbind any texture.
|
||||||
|
*
|
||||||
|
* @param texture The texture to bind.
|
||||||
|
* @return An error if the texture failed to bind, otherwise success.
|
||||||
|
*/
|
||||||
|
errorret_t textureBindDolphin(texturedolphin_t *texture);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes a texture.
|
||||||
|
*
|
||||||
|
* @param texture The texture to dispose.
|
||||||
|
* @return An error if the texture failed to dispose, otherwise success.
|
||||||
|
*/
|
||||||
|
errorret_t textureDisposeDolphin(texturedolphin_t *texture);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method that uploads the texture environment variables to the GPU
|
||||||
|
* for rendering. This is basically uploading the shader information.
|
||||||
|
*/
|
||||||
|
void textureDolphinUploadTEV(void);
|
||||||
16
src/duskdolphin/display/texture/textureplatform.h
Normal file
16
src/duskdolphin/display/texture/textureplatform.h
Normal 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 "texturedolphin.h"
|
||||||
|
|
||||||
|
typedef textureformatdolphin_t textureformatplatform_t;
|
||||||
|
typedef texturedolphin_t textureplatform_t;
|
||||||
|
|
||||||
|
#define textureInitPlatform textureInitDolphin
|
||||||
|
#define textureBindPlatform textureBindDolphin
|
||||||
|
#define textureDisposePlatform textureDisposeDolphin
|
||||||
12
src/duskdolphin/input/CMakeLists.txt
Normal file
12
src/duskdolphin/input/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# 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
|
||||||
|
inputdolphin.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# Subdirs
|
||||||
96
src/duskdolphin/input/inputdolphin.c
Normal file
96
src/duskdolphin/input/inputdolphin.c
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "input/input.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
|
inputbuttondata_t INPUT_BUTTON_DATA[] = {
|
||||||
|
#ifdef DUSK_INPUT_GAMEPAD
|
||||||
|
{ .name = "a", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_A } },
|
||||||
|
{ .name = "b", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_B } },
|
||||||
|
{ .name = "x", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_X } },
|
||||||
|
{ .name = "y", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_Y } },
|
||||||
|
{ .name = "start", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_START } },
|
||||||
|
{ .name = "up", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_UP } },
|
||||||
|
{ .name = "down", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_DOWN } },
|
||||||
|
{ .name = "left", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_LEFT } },
|
||||||
|
{ .name = "right", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_RIGHT } },
|
||||||
|
{ .name = "l", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_TRIGGER_L } },
|
||||||
|
{ .name = "r", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_TRIGGER_R } },
|
||||||
|
{ .name = "z", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_TRIGGER_Z } },
|
||||||
|
{ .name = "menu", { .type = INPUT_BUTTON_TYPE_GAMEPAD, .gpButton = PAD_BUTTON_MENU } },
|
||||||
|
{ .name = "lstick_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_X, .positive = true } } },
|
||||||
|
{ .name = "lstick_down", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_X, .positive = false } } },
|
||||||
|
{ .name = "lstick_left", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_Y, .positive = true } } },
|
||||||
|
{ .name = "lstick_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_LEFT_Y, .positive = false } } },
|
||||||
|
{ .name = "rstick_up", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_X, .positive = true } } },
|
||||||
|
{ .name = "rstick_down", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_X, .positive = false } } },
|
||||||
|
{ .name = "rstick_left", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_Y, .positive = true } } },
|
||||||
|
{ .name = "rstick_right", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_C_Y, .positive = false } } },
|
||||||
|
{ .name = "ltrigger", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_TRIGGER_LEFT, .positive = true } } },
|
||||||
|
{ .name = "rtrigger", { .type = INPUT_BUTTON_TYPE_GAMEPAD_AXIS, .gpAxis = { .axis = INPUT_GAMEPAD_AXIS_TRIGGER_RIGHT, .positive = true } } },
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{ .name = NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
void inputUpdateDolphin(void) {
|
||||||
|
PAD_ScanPads();
|
||||||
|
|
||||||
|
#ifdef DUSK_INPUT_GAMEPAD
|
||||||
|
for(uint8_t i = 0; i < INPUT_PAD_COUNT; i++) {
|
||||||
|
INPUT.platform.padState[i] = PAD_ButtonsDown(i);
|
||||||
|
|
||||||
|
INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_LEFT_X] = (
|
||||||
|
INPUT_DOLPHIN_AXIS(PAD_StickX(i))
|
||||||
|
);
|
||||||
|
|
||||||
|
INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_LEFT_Y] = (
|
||||||
|
INPUT_DOLPHIN_AXIS(PAD_StickY(i))
|
||||||
|
);
|
||||||
|
|
||||||
|
INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_C_X] = (
|
||||||
|
INPUT_DOLPHIN_AXIS(PAD_SubStickX(i))
|
||||||
|
);
|
||||||
|
|
||||||
|
INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_C_Y] = (
|
||||||
|
INPUT_DOLPHIN_AXIS(PAD_SubStickY(i))
|
||||||
|
);
|
||||||
|
|
||||||
|
INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_TRIGGER_LEFT] = (
|
||||||
|
INPUT_DOLPHIN_AXIS(PAD_TriggerL(i))
|
||||||
|
);
|
||||||
|
|
||||||
|
INPUT.platform.pads[i][INPUT_GAMEPAD_AXIS_TRIGGER_RIGHT] = (
|
||||||
|
INPUT_DOLPHIN_AXIS(PAD_TriggerR(i))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
float_t inputButtonGetValueDolphin(const inputbutton_t button) {
|
||||||
|
switch(button.type) {
|
||||||
|
#ifdef DUSK_INPUT_GAMEPAD
|
||||||
|
case INPUT_BUTTON_TYPE_GAMEPAD: {
|
||||||
|
if(INPUT.padState[0] & button.gpButton) return 1.0f;
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
case INPUT_BUTTON_TYPE_GAMEPAD_AXIS: {
|
||||||
|
float_t value = INPUT.pads[0][button.gpAxis.axis];
|
||||||
|
if(!button.gpAxis.positive) value = -value;
|
||||||
|
if(value >= INPUT.deadzone) return value;
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default: {
|
||||||
|
assertUnreachable("Unknown input button type");
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/duskdolphin/input/inputdolphin.h
Normal file
58
src/duskdolphin/input/inputdolphin.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
|
||||||
|
#define INPUT_DOLPHIN_PAD_COUNT PAD_CHANMAX
|
||||||
|
#define INPUT_DOLPHIN_AXIS(value) ((float_t)(value) / 128.0f)
|
||||||
|
|
||||||
|
typedef struct inputbutton_s inputbutton_t;
|
||||||
|
|
||||||
|
#ifdef DUSK_INPUT_POINTER
|
||||||
|
#error "Wii not implemented"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DUSK_INPUT_KEYBOARD
|
||||||
|
#error "Keyboard not implemented"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DUSK_INPUT_GAMEPAD
|
||||||
|
// TODO: Can I support wiimote, gamecube, pro controller, etc?
|
||||||
|
|
||||||
|
typedef u16 inputgamepadbuttondolphin_t;
|
||||||
|
typedef enum {
|
||||||
|
INPUT_GAMEPAD_AXIS_LEFT_X,
|
||||||
|
INPUT_GAMEPAD_AXIS_LEFT_Y,
|
||||||
|
INPUT_GAMEPAD_AXIS_C_X,
|
||||||
|
INPUT_GAMEPAD_AXIS_C_Y,
|
||||||
|
INPUT_GAMEPAD_AXIS_TRIGGER_LEFT,
|
||||||
|
INPUT_GAMEPAD_AXIS_TRIGGER_RIGHT,
|
||||||
|
|
||||||
|
INPUT_GAMEPAD_AXIS_COUNT
|
||||||
|
} inputgamepadaxisdolphin_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
#ifdef DUSK_INPUT_GAMEPAD
|
||||||
|
int padState[INPUT_DOLPHIN_PAD_COUNT];
|
||||||
|
float_t pads[INPUT_DOLPHIN_PAD_COUNT][INPUT_GAMEPAD_AXIS_COUNT];
|
||||||
|
#endif
|
||||||
|
} inputdolphin_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the input state for Dolphin.
|
||||||
|
*/
|
||||||
|
void inputUpdateDolphin(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the input value (between 0 and 1) of the given button.
|
||||||
|
*
|
||||||
|
* @param button The button to get the value of.
|
||||||
|
* @return The value of the button, between 0 and 1.
|
||||||
|
*/
|
||||||
|
float_t inputButtonGetValueDolphin(const inputbutton_t button);
|
||||||
19
src/duskdolphin/input/inputplatform.h
Normal file
19
src/duskdolphin/input/inputplatform.h
Normal 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 "inputdolphin.h"
|
||||||
|
|
||||||
|
#ifdef DUSK_INPUT_GAMEPAD
|
||||||
|
typedef inputgamepadbuttondolphin_t inputgamepadbuttonplatform_t;
|
||||||
|
typedef inputgamepadaxisdolphin_t inputgamepadaxissplatform_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef inputdolphin_t inputplatform_t;
|
||||||
|
|
||||||
|
#define inputUpdatePlatform inputUpdateDolphin
|
||||||
|
#define inputButtonGetValuePlatform inputButtonGetValueDolphin
|
||||||
@@ -12,7 +12,6 @@ target_include_directories(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
# Sources
|
# Sources
|
||||||
target_sources(${DUSK_BINARY_TARGET_NAME}
|
target_sources(${DUSK_BINARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
# hello.c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
#include <pspuser.h>
|
|
||||||
#include <pspdebug.h>
|
|
||||||
#include <pspdisplay.h>
|
|
||||||
|
|
||||||
// PSP_MODULE_INFO is required
|
|
||||||
PSP_MODULE_INFO("Hello World", 0, 1, 0);
|
|
||||||
PSP_MAIN_THREAD_ATTR(PSP_THREAD_ATTR_USER);
|
|
||||||
|
|
||||||
int exit_callback(int arg1, int arg2, void *common) {
|
|
||||||
sceKernelExitGame();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int callback_thread(SceSize args, void *argp) {
|
|
||||||
int cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
|
|
||||||
sceKernelRegisterExitCallback(cbid);
|
|
||||||
sceKernelSleepThreadCB();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int setup_callbacks(void) {
|
|
||||||
int thid = sceKernelCreateThread("update_thread", callback_thread, 0x11, 0xFA0, 0, 0);
|
|
||||||
if(thid >= 0)
|
|
||||||
sceKernelStartThread(thid, 0, 0);
|
|
||||||
return thid;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
// Use above functions to make exiting possible
|
|
||||||
setup_callbacks();
|
|
||||||
|
|
||||||
// Print Hello World! on a debug screen on a loop
|
|
||||||
pspDebugScreenInit();
|
|
||||||
while(1) {
|
|
||||||
pspDebugScreenSetXY(0, 0);
|
|
||||||
pspDebugScreenPrintf("Hello World!");
|
|
||||||
sceDisplayWaitVblankStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -38,7 +38,7 @@ void inputUpdateSDL2(void) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
float_t inputButtonGetValue(const inputbutton_t button) {
|
float_t inputButtonGetValueSDL2(const inputbutton_t button) {
|
||||||
switch(button.type) {
|
switch(button.type) {
|
||||||
#ifdef DUSK_INPUT_KEYBOARD
|
#ifdef DUSK_INPUT_KEYBOARD
|
||||||
case INPUT_BUTTON_TYPE_KEYBOARD: {
|
case INPUT_BUTTON_TYPE_KEYBOARD: {
|
||||||
|
|||||||
Reference in New Issue
Block a user