mirror of
https://github.com/libsdl-org/SDL.git
synced 2024-11-23 02:43:30 +08:00
N3DS port (squashed)
A dedicated renderer using Citro3D would likely allow for better much better graphical performances.
This commit is contained in:
parent
61b5360e17
commit
655275378d
40
.github/workflows/n3ds.yml
vendored
Normal file
40
.github/workflows/n3ds.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
name: Build (Nintendo 3DS)
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
n3ds:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: devkitpro/devkitarm:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install build requirements
|
||||
run: |
|
||||
apt update
|
||||
apt install ninja-build
|
||||
- name: Configure CMake
|
||||
run: |
|
||||
cmake -S . -B build -G Ninja \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/3DS.cmake \
|
||||
-DSDL_TESTS=ON \
|
||||
-DSDL_INSTALL_TESTS=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=prefix
|
||||
- name: Build
|
||||
run: cmake --build build --verbose
|
||||
- name: Install CMake
|
||||
run: |
|
||||
echo "SDL2_DIR=$(pwd)/prefix" >> $GITHUB_ENV
|
||||
cmake --install build/
|
||||
( cd prefix; find ) | LC_ALL=C sort -u
|
||||
- name: Verify CMake configuration files
|
||||
run: |
|
||||
cmake -S cmake/test -B cmake_config_build -G Ninja \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/3DS.cmake \
|
||||
-DTEST_SHARED=FALSE \
|
||||
-DCMAKE_PREFIX_PATH=${{ env.SDL2_DIR }} \
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build cmake_config_build --verbose
|
||||
# Not running test_pkgconfig.sh and test_sdlconfig.sh
|
||||
# as invoking the compiler manually is not supported
|
@ -196,6 +196,8 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "BeOS.*")
|
||||
message_error("BeOS support has been removed as of SDL 2.0.2.")
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "Haiku.*")
|
||||
set(HAIKU TRUE)
|
||||
elseif(NINTENDO_3DS)
|
||||
set(N3DS TRUE)
|
||||
endif()
|
||||
|
||||
# Don't mistake osx for unix
|
||||
@ -277,7 +279,7 @@ if(APPLE OR ARCH_64 OR MSVC_CLANG)
|
||||
set(OPT_DEF_SSEMATH ON)
|
||||
endif()
|
||||
endif()
|
||||
if(UNIX OR MINGW OR MSYS OR (USE_CLANG AND NOT WINDOWS) OR VITA OR PSP OR PS2)
|
||||
if(UNIX OR MINGW OR MSYS OR (USE_CLANG AND NOT WINDOWS) OR VITA OR PSP OR PS2 OR N3DS)
|
||||
set(OPT_DEF_LIBC ON)
|
||||
endif()
|
||||
|
||||
@ -381,7 +383,7 @@ if(EMSCRIPTEN)
|
||||
set(SDL_TEST_ENABLED_BY_DEFAULT OFF)
|
||||
endif()
|
||||
|
||||
if(VITA OR PSP OR PS2)
|
||||
if(VITA OR PSP OR PS2 OR N3DS)
|
||||
set(SDL_SHARED_ENABLED_BY_DEFAULT OFF)
|
||||
set(SDL_LOADSO_ENABLED_BY_DEFAULT OFF)
|
||||
endif()
|
||||
@ -2734,6 +2736,74 @@ elseif(OS2)
|
||||
if(SDL_HIDAPI)
|
||||
CheckHIDAPI()
|
||||
endif()
|
||||
|
||||
elseif(N3DS)
|
||||
file(GLOB N3DS_MAIN_SOURCES ${SDL2_SOURCE_DIR}/src/main/n3ds/*.c)
|
||||
set(SDLMAIN_SOURCES ${SDLMAIN_SOURCES} ${N3DS_MAIN_SOURCES})
|
||||
|
||||
if(SDL_AUDIO)
|
||||
set(SDL_AUDIO_DRIVER_N3DS 1)
|
||||
file(GLOB N3DS_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/n3ds/*.c)
|
||||
list(APPEND SOURCE_FILES ${N3DS_AUDIO_SOURCES})
|
||||
set(HAVE_SDL_AUDIO TRUE)
|
||||
endif()
|
||||
|
||||
if(SDL_FILESYSTEM)
|
||||
set(SDL_FILESYSTEM_N3DS 1)
|
||||
file(GLOB N3DS_FILESYSTEM_SOURCES ${SDL2_SOURCE_DIR}/src/filesystem/n3ds/*.c)
|
||||
list(APPEND SOURCE_FILES ${N3DS_FILESYSTEM_SOURCES})
|
||||
set(HAVE_SDL_FILESYSTEM TRUE)
|
||||
endif()
|
||||
|
||||
if(SDL_JOYSTICK)
|
||||
set(SDL_JOYSTICK_N3DS 1)
|
||||
file(GLOB N3DS_JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/n3ds/*.c)
|
||||
list(APPEND SOURCE_FILES ${N3DS_JOYSTICK_SOURCES})
|
||||
set(HAVE_SDL_JOYSTICK TRUE)
|
||||
endif()
|
||||
|
||||
if(SDL_POWER)
|
||||
set(SDL_POWER_N3DS 1)
|
||||
file(GLOB N3DS_POWER_SOURCES ${SDL2_SOURCE_DIR}/src/power/n3ds/*.c)
|
||||
list(APPEND SOURCE_FILES ${N3DS_POWER_SOURCES})
|
||||
set(HAVE_SDL_POWER TRUE)
|
||||
endif()
|
||||
|
||||
if(SDL_THREADS)
|
||||
set(SDL_THREAD_N3DS 1)
|
||||
file(GLOB N3DS_THREAD_SOURCES ${SDL2_SOURCE_DIR}/src/thread/n3ds/*.c)
|
||||
list(APPEND SOURCE_FILES ${N3DS_THREAD_SOURCES} ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_systls.c)
|
||||
set(HAVE_SDL_THREADS TRUE)
|
||||
endif()
|
||||
|
||||
if(SDL_TIMERS)
|
||||
set(SDL_TIMER_N3DS 1)
|
||||
file(GLOB TIMER_SOURCES ${SDL2_SOURCE_DIR}/src/timer/n3ds/*.c)
|
||||
list(APPEND SOURCE_FILES ${TIMER_SOURCES})
|
||||
set(HAVE_SDL_TIMERS TRUE)
|
||||
endif()
|
||||
|
||||
if(SDL_VIDEO)
|
||||
set(SDL_VIDEO_DRIVER_N3DS 1)
|
||||
file(GLOB N3DS_VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/n3ds/*.c)
|
||||
list(APPEND SOURCE_FILES ${N3DS_VIDEO_SOURCES})
|
||||
set(HAVE_SDL_VIDEO TRUE)
|
||||
endif()
|
||||
|
||||
if(SDL_LOCALE)
|
||||
file(GLOB N3DS_LOCALE_SOURCES ${SDL2_SOURCE_DIR}/src/locale/n3ds/*.c)
|
||||
list(APPEND SOURCE_FILES ${N3DS_LOCALE_SOURCES})
|
||||
set(HAVE_SDL_LOCALE TRUE)
|
||||
endif()
|
||||
|
||||
# Requires the n3ds file implementation
|
||||
if(SDL_FILE)
|
||||
file(GLOB N3DS_FILE_SOURCES ${SDL2_SOURCE_DIR}/src/file/n3ds/*.c)
|
||||
list(APPEND SOURCE_FILES ${N3DS_FILE_SOURCES})
|
||||
set(HAVE_SDL_FILE TRUE)
|
||||
else()
|
||||
message_error("SDL_FILE must be enabled to build on N3DS")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(HAVE_VULKAN AND NOT SDL_LOADSO)
|
||||
|
27
docs/README-n3ds.md
Normal file
27
docs/README-n3ds.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Nintendo 3DS
|
||||
|
||||
SDL port for the Nintendo 3DS [Homebrew toolchain](https://devkitpro.org/) contributed by:
|
||||
|
||||
- [Pierre Wendling](https://github.com/FtZPetruska)
|
||||
|
||||
Credits to:
|
||||
|
||||
- The awesome people who ported SDL to other homebrew platforms.
|
||||
- The Devkitpro team for making all the tools necessary to achieve this.
|
||||
|
||||
## Building
|
||||
|
||||
To build for the Nintendo 3DS, make sure you have devkitARM and cmake installed and run:
|
||||
|
||||
```bash
|
||||
cmake -S. -Bbuild -DCMAKE_TOOLCHAIN_FILE="$DEVKITPRO/cmake/3DS.cmake" -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build
|
||||
cmake --install build
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Currently only software rendering is supported.
|
||||
- Window are created on the top screen by default, use the `SDL_WINDOW_N3DS_BOTTOM` flag to put them on the bottom screen.
|
||||
- SDL2main should be used to ensure all the necessary services are initialised.
|
||||
- By default, the extra L2 cache and higher clock speeds of the New 2/3DS lineup are enabled. If you wish to turn it off, [use the PTMSYSM service](https://libctru.devkitpro.org/ptmsysm_8h.html#ae3a437bfd0de05fbc5ba9a460d148430) to turn it off in your program.
|
@ -325,6 +325,7 @@
|
||||
#cmakedefine SDL_AUDIO_DRIVER_VITA @SDL_AUDIO_DRIVER_VITA@
|
||||
#cmakedefine SDL_AUDIO_DRIVER_PSP @SDL_AUDIO_DRIVER_PSP@
|
||||
#cmakedefine SDL_AUDIO_DRIVER_PS2 @SDL_AUDIO_DRIVER_PS2@
|
||||
#cmakedefine SDL_AUDIO_DRIVER_N3DS @SDL_AUDIO_DRIVER_N3DS@
|
||||
|
||||
/* Enable various input drivers */
|
||||
#cmakedefine SDL_INPUT_LINUXEV @SDL_INPUT_LINUXEV@
|
||||
@ -349,6 +350,7 @@
|
||||
#cmakedefine SDL_JOYSTICK_VITA @SDL_JOYSTICK_VITA@
|
||||
#cmakedefine SDL_JOYSTICK_PSP @SDL_JOYSTICK_PSP@
|
||||
#cmakedefine SDL_JOYSTICK_PS2 @SDL_JOYSTICK_PS2@
|
||||
#cmakedefine SDL_JOYSTICK_N3DS @SDL_JOYSTICK_N3DS@
|
||||
#cmakedefine SDL_HAPTIC_DUMMY @SDL_HAPTIC_DUMMY@
|
||||
#cmakedefine SDL_HAPTIC_LINUX @SDL_HAPTIC_LINUX@
|
||||
#cmakedefine SDL_HAPTIC_IOKIT @SDL_HAPTIC_IOKIT@
|
||||
@ -381,6 +383,7 @@
|
||||
#cmakedefine SDL_THREAD_VITA @SDL_THREAD_VITA@
|
||||
#cmakedefine SDL_THREAD_PSP @SDL_THREAD_PSP@
|
||||
#cmakedefine SDL_THREAD_PS2 @SDL_THREAD_PS2@
|
||||
#cmakedefine SDL_THREAD_N3DS @SDL_THREAD_N3DS@
|
||||
|
||||
/* Enable various timer systems */
|
||||
#cmakedefine SDL_TIMER_HAIKU @SDL_TIMER_HAIKU@
|
||||
@ -391,6 +394,7 @@
|
||||
#cmakedefine SDL_TIMER_VITA @SDL_TIMER_VITA@
|
||||
#cmakedefine SDL_TIMER_PSP @SDL_TIMER_PSP@
|
||||
#cmakedefine SDL_TIMER_PS2 @SDL_TIMER_PS2@
|
||||
#cmakedefine SDL_TIMER_N3DS @SDL_TIMER_N3DS@
|
||||
|
||||
/* Enable various video drivers */
|
||||
#cmakedefine SDL_VIDEO_DRIVER_ANDROID @SDL_VIDEO_DRIVER_ANDROID@
|
||||
@ -444,6 +448,7 @@
|
||||
#cmakedefine SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS @SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS@
|
||||
#cmakedefine SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM @SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM@
|
||||
#cmakedefine SDL_VIDEO_DRIVER_VITA @SDL_VIDEO_DRIVER_VITA@
|
||||
#cmakedefine SDL_VIDEO_DRIVER_N3DS @SDL_VIDEO_DRIVER_N3DS@
|
||||
|
||||
#cmakedefine SDL_VIDEO_RENDER_D3D @SDL_VIDEO_RENDER_D3D@
|
||||
#cmakedefine SDL_VIDEO_RENDER_D3D11 @SDL_VIDEO_RENDER_D3D11@
|
||||
@ -487,6 +492,7 @@
|
||||
#cmakedefine SDL_POWER_HARDWIRED @SDL_POWER_HARDWIRED@
|
||||
#cmakedefine SDL_POWER_VITA @SDL_POWER_VITA@
|
||||
#cmakedefine SDL_POWER_PSP @SDL_POWER_PSP@
|
||||
#cmakedefine SDL_POWER_N3DS @SDL_POWER_N3DS@
|
||||
|
||||
/* Enable system filesystem support */
|
||||
#cmakedefine SDL_FILESYSTEM_ANDROID @SDL_FILESYSTEM_ANDROID@
|
||||
@ -501,6 +507,7 @@
|
||||
#cmakedefine SDL_FILESYSTEM_VITA @SDL_FILESYSTEM_VITA@
|
||||
#cmakedefine SDL_FILESYSTEM_PSP @SDL_FILESYSTEM_PSP@
|
||||
#cmakedefine SDL_FILESYSTEM_PS2 @SDL_FILESYSTEM_PS2@
|
||||
#cmakedefine SDL_FILESYSTEM_N3DS @SDL_FILESYSTEM_N3DS@
|
||||
|
||||
/* Enable misc subsystem */
|
||||
#cmakedefine SDL_MISC_DUMMY @SDL_MISC_DUMMY@
|
||||
|
@ -108,6 +108,15 @@
|
||||
void reset_IOP(); \
|
||||
void reset_IOP() {}
|
||||
|
||||
#elif defined(__3DS__)
|
||||
/*
|
||||
On N3DS, SDL provides a main function that sets up the screens
|
||||
and storage.
|
||||
|
||||
If you provide this yourself, you may define SDL_MAIN_HANDLED
|
||||
*/
|
||||
#define SDL_MAIN_AVAILABLE
|
||||
|
||||
#endif
|
||||
#endif /* SDL_MAIN_HANDLED */
|
||||
|
||||
|
@ -221,6 +221,11 @@
|
||||
#define __VITA__ 1
|
||||
#endif
|
||||
|
||||
#if defined(__3DS__)
|
||||
#undef __3DS__
|
||||
#define __3DS__ 1
|
||||
#endif
|
||||
|
||||
#include "begin_code.h"
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
|
@ -410,7 +410,7 @@ SDL_COMPILE_TIME_ASSERT(sint64, sizeof(Sint64) == 8);
|
||||
|
||||
/** \cond */
|
||||
#ifndef DOXYGEN_SHOULD_IGNORE_THIS
|
||||
#if !defined(__ANDROID__) && !defined(__VITA__)
|
||||
#if !defined(__ANDROID__) && !defined(__VITA__) && !defined(__3DS__)
|
||||
/* TODO: include/SDL_stdinc.h:174: error: size of array 'SDL_dummy_enum' is negative */
|
||||
typedef enum
|
||||
{
|
||||
|
@ -126,6 +126,7 @@ typedef enum
|
||||
SDL_WINDOW_KEYBOARD_GRABBED = 0x00100000, /**< window has grabbed keyboard input */
|
||||
SDL_WINDOW_VULKAN = 0x10000000, /**< window usable for Vulkan surface */
|
||||
SDL_WINDOW_METAL = 0x20000000, /**< window usable for Metal view */
|
||||
SDL_WINDOW_N3DS_BOTTOM = 0x40000000, /**< window should be on the bottom screen (N3DS only) */
|
||||
|
||||
SDL_WINDOW_INPUT_GRABBED = SDL_WINDOW_MOUSE_GRABBED /**< equivalent to SDL_WINDOW_MOUSE_GRABBED for compatibility */
|
||||
} SDL_WindowFlags;
|
||||
|
@ -609,6 +609,8 @@ SDL_GetPlatform(void)
|
||||
return "PlayStation Vita";
|
||||
#elif __NGAGE__
|
||||
return "Nokia N-Gage";
|
||||
#elif __3DS__
|
||||
return "Nintendo 3DS";
|
||||
#else
|
||||
return "Unknown (see SDL_platform.h)";
|
||||
#endif
|
||||
|
@ -485,6 +485,13 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
|
||||
fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message);
|
||||
fclose (pFile);
|
||||
}
|
||||
#elif defined(__3DS__)
|
||||
{
|
||||
FILE* pFile;
|
||||
pFile = fopen ("/SDL_Log.txt", "a");
|
||||
fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message);
|
||||
fclose (pFile);
|
||||
}
|
||||
#endif
|
||||
#if HAVE_STDIO_H && \
|
||||
!(defined(__APPLE__) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT)))
|
||||
|
@ -105,6 +105,9 @@ static const AudioBootStrap *const bootstrap[] = {
|
||||
#if SDL_AUDIO_DRIVER_VITA
|
||||
&VITAAUD_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_N3DS
|
||||
&N3DSAUDIO_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_EMSCRIPTEN
|
||||
&EMSCRIPTENAUDIO_bootstrap,
|
||||
#endif
|
||||
|
@ -209,6 +209,7 @@ extern AudioBootStrap ANDROIDAUDIO_bootstrap;
|
||||
extern AudioBootStrap PS2AUDIO_bootstrap;
|
||||
extern AudioBootStrap PSPAUDIO_bootstrap;
|
||||
extern AudioBootStrap VITAAUD_bootstrap;
|
||||
extern AudioBootStrap N3DSAUDIO_bootstrap;
|
||||
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
|
||||
extern AudioBootStrap OS2AUDIO_bootstrap;
|
||||
|
||||
|
363
src/audio/n3ds/SDL_n3dsaudio.c
Normal file
363
src/audio/n3ds/SDL_n3dsaudio.c
Normal file
@ -0,0 +1,363 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_AUDIO_DRIVER_N3DS
|
||||
|
||||
#include "SDL_audio.h"
|
||||
|
||||
/* N3DS Audio driver */
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
#include "SDL_n3dsaudio.h"
|
||||
#include "SDL_timer.h"
|
||||
|
||||
#define N3DSAUDIO_DRIVER_NAME "n3ds"
|
||||
|
||||
static dspHookCookie dsp_hook;
|
||||
static SDL_AudioDevice *audio_device;
|
||||
|
||||
static void FreePrivateData(_THIS);
|
||||
static int FindAudioFormat(_THIS);
|
||||
|
||||
static SDL_INLINE void
|
||||
contextLock(_THIS)
|
||||
{
|
||||
LightLock_Lock(&this->hidden->lock);
|
||||
}
|
||||
|
||||
static SDL_INLINE void
|
||||
contextUnlock(_THIS)
|
||||
{
|
||||
LightLock_Unlock(&this->hidden->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
N3DSAUD_LockAudio(_THIS)
|
||||
{
|
||||
contextLock(this);
|
||||
}
|
||||
|
||||
static void
|
||||
N3DSAUD_UnlockAudio(_THIS)
|
||||
{
|
||||
contextUnlock(this);
|
||||
}
|
||||
|
||||
static void
|
||||
N3DSAUD_DspHook(DSP_HookType hook)
|
||||
{
|
||||
if (hook == DSPHOOK_ONCANCEL) {
|
||||
contextLock(audio_device);
|
||||
audio_device->hidden->isCancelled = SDL_TRUE;
|
||||
SDL_AtomicSet(&audio_device->enabled, SDL_FALSE);
|
||||
CondVar_Broadcast(&audio_device->hidden->cv);
|
||||
contextUnlock(audio_device);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
AudioFrameFinished(void *device)
|
||||
{
|
||||
bool shouldBroadcast = false;
|
||||
unsigned i;
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) device;
|
||||
|
||||
contextLock(this);
|
||||
|
||||
for (i = 0; i < NUM_BUFFERS; i++) {
|
||||
if (this->hidden->waveBuf[i].status == NDSP_WBUF_DONE) {
|
||||
this->hidden->waveBuf[i].status = NDSP_WBUF_FREE;
|
||||
shouldBroadcast = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldBroadcast) {
|
||||
CondVar_Broadcast(&this->hidden->cv);
|
||||
}
|
||||
|
||||
contextUnlock(this);
|
||||
}
|
||||
|
||||
static int
|
||||
N3DSAUDIO_OpenDevice(_THIS, const char *devname)
|
||||
{
|
||||
Result ndsp_init_res;
|
||||
Uint8 *data_vaddr;
|
||||
float mix[12];
|
||||
this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof *this->hidden);
|
||||
|
||||
if (this->hidden == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
/* Initialise the DSP service */
|
||||
ndsp_init_res = ndspInit();
|
||||
if (R_FAILED(ndsp_init_res)) {
|
||||
if ((R_SUMMARY(ndsp_init_res) == RS_NOTFOUND) && (R_MODULE(ndsp_init_res) == RM_DSP)) {
|
||||
SDL_SetError("DSP init failed: dspfirm.cdc missing!");
|
||||
} else {
|
||||
SDL_SetError("DSP init failed. Error code: 0x%lX", ndsp_init_res);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialise internal state */
|
||||
LightLock_Init(&this->hidden->lock);
|
||||
CondVar_Init(&this->hidden->cv);
|
||||
|
||||
if (this->spec.channels > 2) {
|
||||
this->spec.channels = 2;
|
||||
}
|
||||
|
||||
/* Should not happen but better be safe. */
|
||||
if (FindAudioFormat(this) < 0) {
|
||||
return SDL_SetError("No supported audio format found.");
|
||||
}
|
||||
|
||||
/* Update the fragment size as size in bytes */
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Allocate mixing buffer */
|
||||
if (this->spec.size >= SDL_MAX_UINT32 / 2) {
|
||||
return SDL_SetError("Mixing buffer is too large.");
|
||||
}
|
||||
|
||||
this->hidden->mixlen = this->spec.size;
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
|
||||
if (this->hidden->mixbuf == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||
|
||||
data_vaddr = (Uint8 *) linearAlloc(this->hidden->mixlen * NUM_BUFFERS);
|
||||
if (data_vaddr == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
SDL_memset(data_vaddr, 0, this->hidden->mixlen * NUM_BUFFERS);
|
||||
DSP_FlushDataCache(data_vaddr, this->hidden->mixlen * NUM_BUFFERS);
|
||||
|
||||
this->hidden->nextbuf = 0;
|
||||
this->hidden->channels = this->spec.channels;
|
||||
this->hidden->samplerate = this->spec.freq;
|
||||
|
||||
ndspChnReset(0);
|
||||
|
||||
ndspChnSetInterp(0, NDSP_INTERP_LINEAR);
|
||||
ndspChnSetRate(0, this->spec.freq);
|
||||
ndspChnSetFormat(0, this->hidden->format);
|
||||
|
||||
SDL_memset(mix, 0, sizeof(mix));
|
||||
mix[0] = 1.0;
|
||||
mix[1] = 1.0;
|
||||
ndspChnSetMix(0, mix);
|
||||
|
||||
SDL_memset(this->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
|
||||
|
||||
for (unsigned i = 0; i < NUM_BUFFERS; i++) {
|
||||
this->hidden->waveBuf[i].data_vaddr = data_vaddr;
|
||||
this->hidden->waveBuf[i].nsamples = this->hidden->mixlen / this->hidden->bytePerSample;
|
||||
data_vaddr += this->hidden->mixlen;
|
||||
}
|
||||
|
||||
/* Setup callback */
|
||||
audio_device = this;
|
||||
ndspSetCallback(AudioFrameFinished, this);
|
||||
dspHook(&dsp_hook, N3DSAUD_DspHook);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
N3DSAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||
{
|
||||
/* Delay to make this sort of simulate real audio input. */
|
||||
SDL_Delay((this->spec.samples * 1000) / this->spec.freq);
|
||||
|
||||
/* always return a full buffer of silence. */
|
||||
SDL_memset(buffer, this->spec.silence, buflen);
|
||||
return buflen;
|
||||
}
|
||||
|
||||
static void
|
||||
N3DSAUDIO_PlayDevice(_THIS)
|
||||
{
|
||||
size_t nextbuf;
|
||||
size_t sampleLen;
|
||||
contextLock(this);
|
||||
|
||||
nextbuf = this->hidden->nextbuf;
|
||||
sampleLen = this->hidden->mixlen;
|
||||
|
||||
if (this->hidden->isCancelled ||
|
||||
this->hidden->waveBuf[nextbuf].status != NDSP_WBUF_FREE) {
|
||||
contextUnlock(this);
|
||||
return;
|
||||
}
|
||||
|
||||
this->hidden->nextbuf = (nextbuf + 1) % NUM_BUFFERS;
|
||||
|
||||
contextUnlock(this);
|
||||
|
||||
memcpy((void *) this->hidden->waveBuf[nextbuf].data_vaddr,
|
||||
this->hidden->mixbuf, sampleLen);
|
||||
DSP_FlushDataCache(this->hidden->waveBuf[nextbuf].data_vaddr, sampleLen);
|
||||
|
||||
ndspChnWaveBufAdd(0, &this->hidden->waveBuf[nextbuf]);
|
||||
}
|
||||
|
||||
static void
|
||||
N3DSAUDIO_WaitDevice(_THIS)
|
||||
{
|
||||
contextLock(this);
|
||||
while (!this->hidden->isCancelled &&
|
||||
this->hidden->waveBuf[this->hidden->nextbuf].status != NDSP_WBUF_FREE) {
|
||||
CondVar_Wait(&this->hidden->cv, &this->hidden->lock);
|
||||
}
|
||||
contextUnlock(this);
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
N3DSAUDIO_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return this->hidden->mixbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
N3DSAUDIO_CloseDevice(_THIS)
|
||||
{
|
||||
contextLock(this);
|
||||
|
||||
dspUnhook(&dsp_hook);
|
||||
ndspSetCallback(NULL, NULL);
|
||||
|
||||
if (!this->hidden->isCancelled) {
|
||||
ndspChnReset(0);
|
||||
memset(this->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
|
||||
CondVar_Broadcast(&this->hidden->cv);
|
||||
}
|
||||
|
||||
contextUnlock(this);
|
||||
|
||||
ndspExit();
|
||||
|
||||
FreePrivateData(this);
|
||||
}
|
||||
|
||||
static void
|
||||
N3DSAUDIO_ThreadInit(_THIS)
|
||||
{
|
||||
s32 current_priority;
|
||||
svcGetThreadPriority(¤t_priority, CUR_THREAD_HANDLE);
|
||||
current_priority--;
|
||||
/* 0x18 is reserved for video, 0x30 is the default for main thread */
|
||||
current_priority = SDL_clamp(current_priority, 0x19, 0x2F);
|
||||
svcSetThreadPriority(CUR_THREAD_HANDLE, current_priority);
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
N3DSAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||
{
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = N3DSAUDIO_OpenDevice;
|
||||
impl->PlayDevice = N3DSAUDIO_PlayDevice;
|
||||
impl->WaitDevice = N3DSAUDIO_WaitDevice;
|
||||
impl->GetDeviceBuf = N3DSAUDIO_GetDeviceBuf;
|
||||
impl->CloseDevice = N3DSAUDIO_CloseDevice;
|
||||
impl->ThreadInit = N3DSAUDIO_ThreadInit;
|
||||
impl->LockDevice = N3DSAUD_LockAudio;
|
||||
impl->UnlockDevice = N3DSAUD_UnlockAudio;
|
||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||
|
||||
/* Should be possible, but micInit would fail */
|
||||
impl->HasCaptureSupport = SDL_FALSE;
|
||||
impl->CaptureFromDevice = N3DSAUDIO_CaptureFromDevice;
|
||||
|
||||
return SDL_TRUE; /* this audio target is available. */
|
||||
}
|
||||
|
||||
AudioBootStrap N3DSAUDIO_bootstrap = {
|
||||
N3DSAUDIO_DRIVER_NAME,
|
||||
"SDL N3DS audio driver",
|
||||
N3DSAUDIO_Init,
|
||||
0
|
||||
};
|
||||
|
||||
/**
|
||||
* Cleans up all allocated memory, safe to call with null pointers
|
||||
*/
|
||||
static void
|
||||
FreePrivateData(_THIS)
|
||||
{
|
||||
if (!this->hidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->hidden->waveBuf[0].data_vaddr) {
|
||||
linearFree((void *) this->hidden->waveBuf[0].data_vaddr);
|
||||
}
|
||||
|
||||
if (this->hidden->mixbuf) {
|
||||
SDL_free(this->hidden->mixbuf);
|
||||
this->hidden->mixbuf = NULL;
|
||||
}
|
||||
|
||||
SDL_free(this->hidden);
|
||||
this->hidden = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
FindAudioFormat(_THIS)
|
||||
{
|
||||
SDL_bool found_valid_format = SDL_FALSE;
|
||||
Uint16 test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
|
||||
while (!found_valid_format && test_format) {
|
||||
this->spec.format = test_format;
|
||||
switch (test_format) {
|
||||
case AUDIO_S8:
|
||||
/* Signed 8-bit audio supported */
|
||||
this->hidden->format = (this->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM8 : NDSP_FORMAT_MONO_PCM8;
|
||||
this->hidden->isSigned = 1;
|
||||
this->hidden->bytePerSample = this->spec.channels;
|
||||
found_valid_format = SDL_TRUE;
|
||||
break;
|
||||
case AUDIO_S16:
|
||||
/* Signed 16-bit audio supported */
|
||||
this->hidden->format = (this->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM16 : NDSP_FORMAT_MONO_PCM16;
|
||||
this->hidden->isSigned = 1;
|
||||
this->hidden->bytePerSample = this->spec.channels * 2;
|
||||
found_valid_format = SDL_TRUE;
|
||||
break;
|
||||
default:
|
||||
test_format = SDL_NextAudioFormat();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found_valid_format ? 0 : -1;
|
||||
}
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_N3DS */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
50
src/audio/n3ds/SDL_n3dsaudio.h
Normal file
50
src/audio/n3ds/SDL_n3dsaudio.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef _SDL_n3dsaudio_h_
|
||||
#define _SDL_n3dsaudio_h_
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
#define NUM_BUFFERS 2 /* -- Don't lower this! */
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
{
|
||||
/* Speaker data */
|
||||
Uint8 *mixbuf;
|
||||
Uint32 mixlen;
|
||||
Uint32 format;
|
||||
Uint32 samplerate;
|
||||
Uint32 channels;
|
||||
Uint8 bytePerSample;
|
||||
Uint32 isSigned;
|
||||
Uint32 nextbuf;
|
||||
ndspWaveBuf waveBuf[NUM_BUFFERS];
|
||||
LightLock lock;
|
||||
CondVar cv;
|
||||
SDL_bool isCancelled;
|
||||
};
|
||||
|
||||
#endif /* _SDL_n3dsaudio_h_ */
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
@ -468,6 +468,8 @@ CPU_haveNEON(void)
|
||||
return 1; /* ARMv8 always has non-optional NEON support. */
|
||||
#elif __VITA__
|
||||
return 1;
|
||||
#elif __3DS__
|
||||
return 1;
|
||||
#elif defined(__APPLE__) && defined(__ARM_ARCH) && (__ARM_ARCH >= 7)
|
||||
/* (note that sysctlbyname("hw.optional.neon") doesn't work!) */
|
||||
return 1; /* all Apple ARMv7 chips and later have NEON. */
|
||||
|
@ -63,6 +63,8 @@
|
||||
#define SDL_DYNAMIC_API 0 /* vitasdk doesn't support dynamic linking */
|
||||
#elif defined(__NGAGE__)
|
||||
#define SDL_DYNAMIC_API 0 /* The N-Gage doesn't support dynamic linking either */
|
||||
#elif defined(__3DS__)
|
||||
#define SDL_DYNAMIC_API 0 /* devkitARM doesn't support dynamic linking */
|
||||
#elif defined(DYNAPI_NEEDS_DLOPEN) && !defined(HAVE_DLOPEN)
|
||||
#define SDL_DYNAMIC_API 0 /* we need dlopen(), but don't have it.... */
|
||||
#endif
|
||||
|
@ -53,6 +53,10 @@
|
||||
#include "cocoa/SDL_rwopsbundlesupport.h"
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#ifdef __3DS__
|
||||
#include "n3ds/SDL_rwopsromfs.h"
|
||||
#endif /* __3DS__ */
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "../core/android/SDL_android.h"
|
||||
#include "SDL_system.h"
|
||||
@ -601,6 +605,8 @@ SDL_RWFromFile(const char *file, const char *mode)
|
||||
#elif __WINRT__
|
||||
FILE *fp = NULL;
|
||||
fopen_s(&fp, file, mode);
|
||||
#elif __3DS__
|
||||
FILE *fp = N3DS_FileOpen(file, mode);
|
||||
#else
|
||||
FILE *fp = fopen(file, mode);
|
||||
#endif
|
||||
|
56
src/file/n3ds/SDL_rwopsromfs.c
Normal file
56
src/file/n3ds/SDL_rwopsromfs.c
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "SDL_rwopsromfs.h"
|
||||
|
||||
/* Nintendo 3DS applications may embed resources in the executable. The
|
||||
resources are stored in a special read-only partition prefixed with
|
||||
'romfs:/'. As such, when opening a file, we should first try the romfs
|
||||
unless sdmc is specifically mentionned.
|
||||
*/
|
||||
FILE *
|
||||
N3DS_FileOpen(const char *file, const char *mode)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char romfs_path[4096];
|
||||
|
||||
/* romfs are read-only */
|
||||
if (SDL_strchr(mode, 'r') == NULL) {
|
||||
return fopen(file, mode);
|
||||
}
|
||||
|
||||
/* If the path has an explicit prefix, we skip the guess work */
|
||||
if (SDL_strncmp("romfs:/", file, 7) == 0 ||
|
||||
SDL_strncmp("sdmc:/", file, 6) == 0) {
|
||||
return fopen(file, mode);
|
||||
}
|
||||
|
||||
SDL_snprintf(romfs_path, 4096, "romfs:/%s", file);
|
||||
|
||||
fp = fopen(romfs_path, mode);
|
||||
if (fp == NULL) {
|
||||
fp = fopen(file, mode);
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
30
src/file/n3ds/SDL_rwopsromfs.h
Normal file
30
src/file/n3ds/SDL_rwopsromfs.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef SDL_rwopsromfs_h_
|
||||
#define SDL_rwopsromfs_h_
|
||||
|
||||
FILE *N3DS_FileOpen(const char *file, const char *mode);
|
||||
|
||||
#endif /* SDL_rwopsromfs_h_ */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
86
src/filesystem/n3ds/SDL_sysfilesystem.c
Normal file
86
src/filesystem/n3ds/SDL_sysfilesystem.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_FILESYSTEM_N3DS
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
/* System dependent filesystem routines */
|
||||
|
||||
#include <3ds.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "SDL_error.h"
|
||||
#include "SDL_filesystem.h"
|
||||
|
||||
SDL_FORCE_INLINE char *MakePrefPath(const char *app);
|
||||
SDL_FORCE_INLINE int CreatePrefPathDir(const char *pref);
|
||||
|
||||
char *
|
||||
SDL_GetBasePath(void)
|
||||
{
|
||||
char *base_path = SDL_strdup("romfs:/");
|
||||
return base_path;
|
||||
}
|
||||
|
||||
char *
|
||||
SDL_GetPrefPath(const char *org, const char *app)
|
||||
{
|
||||
char *pref_path = NULL;
|
||||
if (app == NULL) {
|
||||
SDL_InvalidParamError("app");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pref_path = MakePrefPath(app);
|
||||
if (CreatePrefPathDir(pref_path) < 0) {
|
||||
SDL_free(pref_path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pref_path;
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE char *
|
||||
MakePrefPath(const char *app)
|
||||
{
|
||||
static const char *FMT = "/3ds/%s/";
|
||||
size_t length = SDL_snprintf(NULL, 0, FMT, app) + 1;
|
||||
char *pref_path = (char *) SDL_calloc(length, sizeof(char));
|
||||
SDL_snprintf(pref_path, length, FMT, app);
|
||||
return pref_path;
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE int
|
||||
CreatePrefPathDir(const char *pref)
|
||||
{
|
||||
int result = mkdir(pref, 0666);
|
||||
|
||||
if (result == -1 && errno != EEXIST) {
|
||||
return SDL_SetError("Failed to create '%s' (%s)", pref, strerror(errno));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SDL_FILESYSTEM_N3DS */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
@ -977,6 +977,9 @@ static const char *s_ControllerMappings [] =
|
||||
#endif
|
||||
#if SDL_JOYSTICK_VITA
|
||||
"0000000050535669746120436f6e7400,PSVita Controller,crc:d598,a:b2,b:b1,back:b10,dpdown:b6,dpleft:b7,dpright:b9,dpup:b8,leftshoulder:b4,leftstick:b14,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
|
||||
#endif
|
||||
#if SDL_JOYSTICK_N3DS
|
||||
"4e696e74656e646f20334453206d6170,Nintendo 3DS,a:b0,b:b1,back:b2,dpdown:b7,dpleft:b5,dpright:b4,dpup:b6,leftshoulder:b9,leftstick:b14,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b15,rightx:a2,righty:a3,start:b3,x:b10,y:b11,",
|
||||
#endif
|
||||
"hidapi,*,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
|
||||
NULL
|
||||
|
@ -102,6 +102,9 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = {
|
||||
#ifdef SDL_JOYSTICK_VITA
|
||||
&SDL_VITA_JoystickDriver,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_N3DS
|
||||
&SDL_N3DS_JoystickDriver
|
||||
#endif
|
||||
#if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED)
|
||||
&SDL_DUMMY_JoystickDriver
|
||||
#endif
|
||||
|
@ -238,6 +238,7 @@ extern SDL_JoystickDriver SDL_OS2_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_PS2_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_PSP_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_VITA_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_N3DS_JoystickDriver;
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
|
367
src/joystick/n3ds/SDL_sysjoystick.c
Normal file
367
src/joystick/n3ds/SDL_sysjoystick.c
Normal file
@ -0,0 +1,367 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_JOYSTICK_N3DS
|
||||
|
||||
/* This is the N3DS implementation of the SDL joystick API */
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "SDL_events.h"
|
||||
|
||||
#define NB_BUTTONS 23
|
||||
|
||||
/*
|
||||
N3DS sticks values are roughly within +/-160
|
||||
which is too small to pass the jitter tolerance.
|
||||
This correction factor is applied to axis values
|
||||
so they fit better in SDL's value range.
|
||||
*/
|
||||
#define CORRECTION_FACTOR_X SDL_JOYSTICK_AXIS_MAX / 160
|
||||
|
||||
/*
|
||||
The Y axis needs to be flipped because SDL's "up"
|
||||
is reversed compared to libctru's "up"
|
||||
*/
|
||||
#define CORRECTION_FACTOR_Y -CORRECTION_FACTOR_X
|
||||
|
||||
/*
|
||||
Factors used to convert touchscreen coordinates to
|
||||
SDL's 0-1 values. Note that the N3DS's screen is
|
||||
internally in a portrait disposition so the
|
||||
GSP_SCREEN constants are flipped.
|
||||
*/
|
||||
#define TOUCHPAD_SCALE_X 1.0f / GSP_SCREEN_HEIGHT_BOTTOM
|
||||
#define TOUCHPAD_SCALE_Y 1.0f / GSP_SCREEN_WIDTH
|
||||
|
||||
typedef struct N3DSJoystickState
|
||||
{
|
||||
u32 kDown;
|
||||
u32 kUp;
|
||||
circlePosition circlePos;
|
||||
circlePosition cStickPos;
|
||||
accelVector acceleration;
|
||||
angularRate rate;
|
||||
} N3DSJoystickState;
|
||||
|
||||
SDL_FORCE_INLINE void UpdateAxis(SDL_Joystick *joystick, N3DSJoystickState *previous_state);
|
||||
SDL_FORCE_INLINE void UpdateButtons(SDL_Joystick *joystick, N3DSJoystickState *previous_state);
|
||||
SDL_FORCE_INLINE void UpdateSensors(SDL_Joystick *joystick, N3DSJoystickState *previous_state);
|
||||
SDL_FORCE_INLINE void UpdateTouch(SDL_Joystick *joystick);
|
||||
|
||||
static N3DSJoystickState current_state;
|
||||
static SDL_bool sensors_enabled = SDL_FALSE;
|
||||
|
||||
static int
|
||||
N3DS_JoystickInit(void)
|
||||
{
|
||||
hidInit();
|
||||
HIDUSER_EnableAccelerometer();
|
||||
HIDUSER_EnableGyroscope();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *
|
||||
N3DS_JoystickGetDeviceName(int device_index)
|
||||
{
|
||||
return "Nintendo 3DS";
|
||||
}
|
||||
|
||||
static int
|
||||
N3DS_JoystickGetCount(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SDL_JoystickGUID
|
||||
N3DS_JoystickGetDeviceGUID(int device_index)
|
||||
{
|
||||
/* GUID corresponds to the name "Nintendo 3DS map" */
|
||||
SDL_JoystickGUID guid = { { 0x4e, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x6f, 0x20, 0x33, 0x44, 0x53, 0x20, 0x6d, 0x61, 0x70 } };
|
||||
return guid;
|
||||
}
|
||||
|
||||
static SDL_JoystickID
|
||||
N3DS_JoystickGetDeviceInstanceID(int device_index)
|
||||
{
|
||||
return device_index;
|
||||
}
|
||||
|
||||
static int
|
||||
N3DS_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||
{
|
||||
joystick->nbuttons = NB_BUTTONS;
|
||||
joystick->naxes = 4;
|
||||
joystick->nhats = 0;
|
||||
joystick->instance_id = device_index;
|
||||
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 0.0f);
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 0.0f);
|
||||
SDL_PrivateJoystickAddTouchpad(joystick, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
N3DS_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
|
||||
{
|
||||
sensors_enabled = enabled;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
N3DS_JoystickUpdate(SDL_Joystick *joystick)
|
||||
{
|
||||
N3DSJoystickState previous_state = current_state;
|
||||
hidScanInput();
|
||||
|
||||
UpdateAxis(joystick, &previous_state);
|
||||
UpdateButtons(joystick, &previous_state);
|
||||
UpdateTouch(joystick);
|
||||
|
||||
if (sensors_enabled) {
|
||||
UpdateSensors(joystick, &previous_state);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void
|
||||
UpdateAxis(SDL_Joystick *joystick, N3DSJoystickState *previous_state)
|
||||
{
|
||||
hidCircleRead(¤t_state.circlePos);
|
||||
if (previous_state->circlePos.dx != current_state.circlePos.dx) {
|
||||
SDL_PrivateJoystickAxis(joystick,
|
||||
0,
|
||||
current_state.circlePos.dx * CORRECTION_FACTOR_X);
|
||||
}
|
||||
if (previous_state->circlePos.dy != current_state.circlePos.dy) {
|
||||
SDL_PrivateJoystickAxis(joystick,
|
||||
1,
|
||||
current_state.circlePos.dy * CORRECTION_FACTOR_Y);
|
||||
}
|
||||
|
||||
hidCstickRead(¤t_state.cStickPos);
|
||||
if (previous_state->cStickPos.dx != current_state.cStickPos.dx) {
|
||||
SDL_PrivateJoystickAxis(joystick,
|
||||
2,
|
||||
current_state.cStickPos.dx * CORRECTION_FACTOR_X);
|
||||
}
|
||||
if (previous_state->cStickPos.dy != current_state.cStickPos.dy) {
|
||||
SDL_PrivateJoystickAxis(joystick,
|
||||
3,
|
||||
current_state.cStickPos.dy * CORRECTION_FACTOR_Y);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void
|
||||
UpdateButtons(SDL_Joystick *joystick, N3DSJoystickState *previous_state)
|
||||
{
|
||||
u32 updated_down, updated_up;
|
||||
|
||||
current_state.kDown = hidKeysDown();
|
||||
updated_down = previous_state->kDown ^ current_state.kDown;
|
||||
if (updated_down) {
|
||||
for (Uint8 i = 0; i < joystick->nbuttons; i++) {
|
||||
if (current_state.kDown & BIT(i) & updated_down) {
|
||||
SDL_PrivateJoystickButton(joystick, i, SDL_PRESSED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
current_state.kUp = hidKeysUp();
|
||||
updated_up = previous_state->kUp ^ current_state.kUp;
|
||||
if (updated_up) {
|
||||
for (Uint8 i = 0; i < joystick->nbuttons; i++) {
|
||||
if (current_state.kUp & BIT(i) & updated_up) {
|
||||
SDL_PrivateJoystickButton(joystick, i, SDL_RELEASED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void
|
||||
UpdateTouch(SDL_Joystick *joystick)
|
||||
{
|
||||
touchPosition touch;
|
||||
Uint8 state;
|
||||
hidTouchRead(&touch);
|
||||
state = (touch.px == 0 && touch.py == 0) ? SDL_RELEASED : SDL_PRESSED;
|
||||
|
||||
SDL_PrivateJoystickTouchpad(joystick,
|
||||
0,
|
||||
0,
|
||||
state,
|
||||
touch.px * TOUCHPAD_SCALE_X,
|
||||
touch.py * TOUCHPAD_SCALE_Y,
|
||||
state == SDL_PRESSED ? 1.0f : 0.0f);
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void
|
||||
UpdateSensors(SDL_Joystick *joystick, N3DSJoystickState *previous_state)
|
||||
{
|
||||
float data[3];
|
||||
|
||||
hidAccelRead(¤t_state.acceleration);
|
||||
if (SDL_memcmp(&previous_state->acceleration, ¤t_state.acceleration, sizeof(accelVector)) != 0) {
|
||||
SDL_memcpy(&previous_state->acceleration, ¤t_state.acceleration, sizeof(accelVector));
|
||||
data[0] = (float) current_state.acceleration.x * SDL_STANDARD_GRAVITY;
|
||||
data[1] = (float) current_state.acceleration.y * SDL_STANDARD_GRAVITY;
|
||||
data[2] = (float) current_state.acceleration.z * SDL_STANDARD_GRAVITY;
|
||||
SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_ACCEL, data, sizeof data);
|
||||
}
|
||||
|
||||
hidGyroRead(¤t_state.rate);
|
||||
if (SDL_memcmp(&previous_state->rate, ¤t_state.rate, sizeof(angularRate)) != 0) {
|
||||
SDL_memcpy(&previous_state->rate, ¤t_state.rate, sizeof(angularRate));
|
||||
data[0] = (float) current_state.rate.y;
|
||||
data[1] = (float) current_state.rate.z;
|
||||
data[2] = (float) current_state.rate.x;
|
||||
SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_GYRO, data, sizeof data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
N3DS_JoystickClose(SDL_Joystick *joystick)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
N3DS_JoystickQuit(void)
|
||||
{
|
||||
HIDUSER_DisableGyroscope();
|
||||
HIDUSER_DisableAccelerometer();
|
||||
hidExit();
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
N3DS_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
|
||||
{
|
||||
/* There is only one possible mapping. */
|
||||
*out = (SDL_GamepadMapping){
|
||||
.a = { EMappingKind_Button, 0 },
|
||||
.b = { EMappingKind_Button, 1 },
|
||||
.x = { EMappingKind_Button, 10 },
|
||||
.y = { EMappingKind_Button, 11 },
|
||||
.back = { EMappingKind_Button, 2 },
|
||||
.guide = { EMappingKind_None, 255 },
|
||||
.start = { EMappingKind_Button, 3 },
|
||||
.leftstick = { EMappingKind_None, 255 },
|
||||
.rightstick = { EMappingKind_None, 255 },
|
||||
.leftshoulder = { EMappingKind_Button, 9 },
|
||||
.rightshoulder = { EMappingKind_Button, 8 },
|
||||
.dpup = { EMappingKind_Button, 6 },
|
||||
.dpdown = { EMappingKind_Button, 7 },
|
||||
.dpleft = { EMappingKind_Button, 5 },
|
||||
.dpright = { EMappingKind_Button, 4 },
|
||||
.misc1 = { EMappingKind_None, 255 },
|
||||
.paddle1 = { EMappingKind_None, 255 },
|
||||
.paddle2 = { EMappingKind_None, 255 },
|
||||
.paddle3 = { EMappingKind_None, 255 },
|
||||
.paddle4 = { EMappingKind_None, 255 },
|
||||
.leftx = { EMappingKind_Axis, 0 },
|
||||
.lefty = { EMappingKind_Axis, 1 },
|
||||
.rightx = { EMappingKind_Axis, 2 },
|
||||
.righty = { EMappingKind_Axis, 3 },
|
||||
.lefttrigger = { EMappingKind_Button, 14 },
|
||||
.righttrigger = { EMappingKind_Button, 15 },
|
||||
};
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
N3DS_JoystickDetect(void)
|
||||
{
|
||||
}
|
||||
|
||||
static const char *
|
||||
N3DS_JoystickGetDevicePath(int device_index)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
N3DS_JoystickGetDevicePlayerIndex(int device_index)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
N3DS_JoystickSetDevicePlayerIndex(int device_index, int player_index)
|
||||
{
|
||||
}
|
||||
|
||||
static Uint32
|
||||
N3DS_JoystickGetCapabilities(SDL_Joystick *joystick)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
N3DS_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static int
|
||||
N3DS_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static int
|
||||
N3DS_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static int
|
||||
N3DS_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
SDL_JoystickDriver SDL_N3DS_JoystickDriver = {
|
||||
N3DS_JoystickInit,
|
||||
N3DS_JoystickGetCount,
|
||||
N3DS_JoystickDetect,
|
||||
N3DS_JoystickGetDeviceName,
|
||||
N3DS_JoystickGetDevicePath,
|
||||
N3DS_JoystickGetDevicePlayerIndex,
|
||||
N3DS_JoystickSetDevicePlayerIndex,
|
||||
N3DS_JoystickGetDeviceGUID,
|
||||
N3DS_JoystickGetDeviceInstanceID,
|
||||
N3DS_JoystickOpen,
|
||||
N3DS_JoystickRumble,
|
||||
N3DS_JoystickRumbleTriggers,
|
||||
N3DS_JoystickGetCapabilities,
|
||||
N3DS_JoystickSetLED,
|
||||
N3DS_JoystickSendEffect,
|
||||
N3DS_JoystickSetSensorsEnabled,
|
||||
N3DS_JoystickUpdate,
|
||||
N3DS_JoystickClose,
|
||||
N3DS_JoystickQuit,
|
||||
N3DS_JoystickGetGamepadMapping
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_N3DS */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
@ -27,7 +27,7 @@
|
||||
#define libm_hidden_def(x)
|
||||
#define strong_alias(x, y)
|
||||
|
||||
#if !defined(__HAIKU__) && !defined(__PSP__) && !defined(__PS2__) /* already defined in a system header. */
|
||||
#if !defined(__HAIKU__) && !defined(__PSP__) && !defined(__3DS__) && !defined(__PS2__) /* already defined in a system header. */
|
||||
typedef unsigned int u_int32_t;
|
||||
#endif
|
||||
|
||||
|
59
src/locale/n3ds/SDL_syslocale.c
Normal file
59
src/locale/n3ds/SDL_syslocale.c
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../SDL_syslocale.h"
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
/* Used when the CFGU fails to work. */
|
||||
#define BAD_LOCALE 255
|
||||
|
||||
SDL_FORCE_INLINE u8 GetLocaleIndex(void);
|
||||
|
||||
void
|
||||
SDL_SYS_GetPreferredLocales(char *buf, size_t buflen)
|
||||
{
|
||||
/* The 3DS only supports these 12 languages, only one can be active at a time */
|
||||
static const char AVAILABLE_LOCALES[][6] = { "ja_JP", "en_US", "fr_FR", "de_DE",
|
||||
"it_IT", "es_ES", "zn_CN", "ko_KR",
|
||||
"nl_NL", "pt_PT", "ru_RU", "zh_TW" };
|
||||
u8 current_locale = GetLocaleIndex();
|
||||
if (current_locale != BAD_LOCALE) {
|
||||
SDL_strlcpy(buf, AVAILABLE_LOCALES[current_locale], buflen);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE u8
|
||||
GetLocaleIndex(void)
|
||||
{
|
||||
u8 current_locale;
|
||||
if (R_FAILED(cfguInit())) {
|
||||
return BAD_LOCALE;
|
||||
}
|
||||
if (R_FAILED(CFGU_GetSystemLanguage(¤t_locale))) {
|
||||
return BAD_LOCALE;
|
||||
}
|
||||
cfguExit();
|
||||
return current_locale;
|
||||
}
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
82
src/main/n3ds/SDL_n3ds_main.c
Normal file
82
src/main/n3ds/SDL_n3ds_main.c
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef __3DS__
|
||||
|
||||
#include "SDL_main.h"
|
||||
#include <3ds.h>
|
||||
|
||||
#ifdef main
|
||||
#undef main
|
||||
#endif
|
||||
|
||||
SDL_FORCE_INLINE void N3DS_Init(void);
|
||||
SDL_FORCE_INLINE void N3DS_SetCPUSpeed(void);
|
||||
SDL_FORCE_INLINE void N3DS_Quit(void);
|
||||
|
||||
#define HIGH_CLOCK 1
|
||||
#define L2_CACHE 2
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int result;
|
||||
N3DS_Init();
|
||||
SDL_SetMainReady();
|
||||
result = SDL_main(argc, argv);
|
||||
N3DS_Quit();
|
||||
return result;
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void
|
||||
N3DS_Init(void)
|
||||
{
|
||||
N3DS_SetCPUSpeed();
|
||||
romfsInit();
|
||||
gfxInit(GSP_RGBA8_OES, GSP_RGBA8_OES, false);
|
||||
hidInit();
|
||||
}
|
||||
|
||||
/* If available, enable L2 cache and high CPU clock */
|
||||
SDL_FORCE_INLINE void
|
||||
N3DS_SetCPUSpeed(void)
|
||||
{
|
||||
if (R_SUCCEEDED(ptmSysmInit())) {
|
||||
if (R_SUCCEEDED(PTMSYSM_CheckNew3DS())) {
|
||||
PTMSYSM_ConfigureNew3DSCPU(HIGH_CLOCK | L2_CACHE);
|
||||
}
|
||||
ptmSysmExit();
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void
|
||||
N3DS_Quit(void)
|
||||
{
|
||||
hidExit();
|
||||
gfxExit();
|
||||
romfsExit();
|
||||
}
|
||||
|
||||
#endif /* __3DS__ */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
@ -71,6 +71,9 @@ static SDL_GetPowerInfo_Impl implementations[] = {
|
||||
#ifdef SDL_POWER_VITA /* handles PSVita. */
|
||||
SDL_GetPowerInfo_VITA,
|
||||
#endif
|
||||
#ifdef SDL_POWER_N3DS /* handles N3DS. */
|
||||
SDL_GetPowerInfo_N3DS,
|
||||
#endif
|
||||
#ifdef SDL_POWER_WINRT /* handles WinRT */
|
||||
SDL_GetPowerInfo_WinRT,
|
||||
#endif
|
||||
|
@ -39,6 +39,7 @@ SDL_bool SDL_GetPowerInfo_Haiku(SDL_PowerState *, int *, int *);
|
||||
SDL_bool SDL_GetPowerInfo_Android(SDL_PowerState *, int *, int *);
|
||||
SDL_bool SDL_GetPowerInfo_PSP(SDL_PowerState *, int *, int *);
|
||||
SDL_bool SDL_GetPowerInfo_VITA(SDL_PowerState *, int *, int *);
|
||||
SDL_bool SDL_GetPowerInfo_N3DS(SDL_PowerState *, int *, int *);
|
||||
SDL_bool SDL_GetPowerInfo_WinRT(SDL_PowerState *, int *, int *);
|
||||
SDL_bool SDL_GetPowerInfo_Emscripten(SDL_PowerState *, int *, int *);
|
||||
|
||||
|
111
src/power/n3ds/SDL_syspower.c
Normal file
111
src/power/n3ds/SDL_syspower.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#if !defined(SDL_POWER_DISABLED) && defined(SDL_POWER_N3DS)
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
#include "SDL_error.h"
|
||||
#include "SDL_power.h"
|
||||
|
||||
SDL_FORCE_INLINE SDL_PowerState GetPowerState(void);
|
||||
SDL_FORCE_INLINE int ReadStateFromPTMU(bool *is_plugged, u8 *is_charging);
|
||||
SDL_FORCE_INLINE int GetBatteryPercentage(void);
|
||||
|
||||
#define BATTERY_PERCENT_REG 0xB
|
||||
#define BATTERY_PERCENT_REG_SIZE 2
|
||||
|
||||
SDL_bool
|
||||
SDL_GetPowerInfo_N3DS(SDL_PowerState *state, int *seconds, int *percent)
|
||||
{
|
||||
*state = GetPowerState();
|
||||
*percent = GetBatteryPercentage();
|
||||
*seconds = -1; /* libctru doesn't provide a way to estimate battery life */
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE SDL_PowerState
|
||||
GetPowerState(void)
|
||||
{
|
||||
bool is_plugged;
|
||||
u8 is_charging;
|
||||
|
||||
if (ReadStateFromPTMU(&is_plugged, &is_charging) < 0) {
|
||||
return SDL_POWERSTATE_UNKNOWN;
|
||||
}
|
||||
|
||||
if (is_charging) {
|
||||
return SDL_POWERSTATE_CHARGING;
|
||||
}
|
||||
|
||||
if (is_plugged) {
|
||||
return SDL_POWERSTATE_CHARGED;
|
||||
}
|
||||
|
||||
return SDL_POWERSTATE_ON_BATTERY;
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE int
|
||||
ReadStateFromPTMU(bool *is_plugged, u8 *is_charging)
|
||||
{
|
||||
if (R_FAILED(ptmuInit())) {
|
||||
return SDL_SetError("Failed to initialise PTMU service");
|
||||
}
|
||||
|
||||
if (R_FAILED(PTMU_GetAdapterState(is_plugged))) {
|
||||
ptmuExit();
|
||||
return SDL_SetError("Failed to read adapter state");
|
||||
}
|
||||
|
||||
if (R_FAILED(PTMU_GetBatteryChargeState(is_charging))) {
|
||||
ptmuExit();
|
||||
return SDL_SetError("Failed to read battery charge state");
|
||||
}
|
||||
|
||||
ptmuExit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE int
|
||||
GetBatteryPercentage(void)
|
||||
{
|
||||
u8 data[BATTERY_PERCENT_REG_SIZE];
|
||||
|
||||
if (R_FAILED(mcuHwcInit())) {
|
||||
return SDL_SetError("Failed to initialise mcuHwc service");
|
||||
}
|
||||
|
||||
if (R_FAILED(MCUHWC_ReadRegister(BATTERY_PERCENT_REG, data, BATTERY_PERCENT_REG_SIZE))) {
|
||||
mcuHwcExit();
|
||||
return SDL_SetError("Failed to read battery register");
|
||||
}
|
||||
|
||||
mcuHwcExit();
|
||||
|
||||
return (int) SDL_round(data[0] + data[1] / 256.0);
|
||||
}
|
||||
|
||||
#endif /* !SDL_POWER_DISABLED && SDL_POWER_N3DS */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
@ -38,6 +38,8 @@
|
||||
#include "psp/SDL_systhread_c.h"
|
||||
#elif SDL_THREAD_VITA
|
||||
#include "vita/SDL_systhread_c.h"
|
||||
#elif SDL_THREAD_N3DS
|
||||
#include "n3ds/SDL_systhread_c.h"
|
||||
#elif SDL_THREAD_STDCPP
|
||||
#include "stdcpp/SDL_systhread_c.h"
|
||||
#elif SDL_THREAD_OS2
|
||||
|
133
src/thread/n3ds/SDL_syscond.c
Normal file
133
src/thread/n3ds/SDL_syscond.c
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_THREAD_N3DS
|
||||
|
||||
/* An implementation of condition variables using libctru's CondVar */
|
||||
|
||||
#include "SDL_sysmutex_c.h"
|
||||
|
||||
struct SDL_cond
|
||||
{
|
||||
CondVar cond_variable;
|
||||
};
|
||||
|
||||
/* Create a condition variable */
|
||||
SDL_cond *
|
||||
SDL_CreateCond(void)
|
||||
{
|
||||
SDL_cond *cond = (SDL_cond *) SDL_malloc(sizeof(SDL_cond));
|
||||
if (cond) {
|
||||
CondVar_Init(&cond->cond_variable);
|
||||
} else {
|
||||
SDL_OutOfMemory();
|
||||
}
|
||||
return cond;
|
||||
}
|
||||
|
||||
/* Destroy a condition variable */
|
||||
void
|
||||
SDL_DestroyCond(SDL_cond *cond)
|
||||
{
|
||||
if (cond) {
|
||||
SDL_free(cond);
|
||||
}
|
||||
}
|
||||
|
||||
/* Restart one of the threads that are waiting on the condition variable */
|
||||
int
|
||||
SDL_CondSignal(SDL_cond *cond)
|
||||
{
|
||||
if (!cond) {
|
||||
return SDL_SetError("Passed a NULL condition variable");
|
||||
}
|
||||
|
||||
CondVar_Signal(&cond->cond_variable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Restart all threads that are waiting on the condition variable */
|
||||
int
|
||||
SDL_CondBroadcast(SDL_cond *cond)
|
||||
{
|
||||
if (!cond) {
|
||||
return SDL_SetError("Passed a NULL condition variable");
|
||||
}
|
||||
|
||||
CondVar_Broadcast(&cond->cond_variable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wait on the condition variable for at most 'ms' milliseconds.
|
||||
The mutex must be locked before entering this function!
|
||||
The mutex is unlocked during the wait, and locked again after the wait.
|
||||
|
||||
Typical use:
|
||||
|
||||
Thread A:
|
||||
SDL_LockMutex(lock);
|
||||
while ( ! condition ) {
|
||||
SDL_CondWait(cond, lock);
|
||||
}
|
||||
SDL_UnlockMutex(lock);
|
||||
|
||||
Thread B:
|
||||
SDL_LockMutex(lock);
|
||||
...
|
||||
condition = true;
|
||||
...
|
||||
SDL_CondSignal(cond);
|
||||
SDL_UnlockMutex(lock);
|
||||
*/
|
||||
int
|
||||
SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
|
||||
{
|
||||
Result res;
|
||||
|
||||
if (!cond) {
|
||||
return SDL_SetError("Passed a NULL condition variable");
|
||||
}
|
||||
if (!mutex) {
|
||||
return SDL_SetError("Passed a NULL mutex");
|
||||
}
|
||||
|
||||
res = 0;
|
||||
if (ms == SDL_MUTEX_MAXWAIT) {
|
||||
CondVar_Wait(&cond->cond_variable, &mutex->lock.lock);
|
||||
} else {
|
||||
res = CondVar_WaitTimeout(&cond->cond_variable, &mutex->lock.lock,
|
||||
(s64) ms * 1000000LL);
|
||||
}
|
||||
|
||||
return R_SUCCEEDED(res) ? 0 : SDL_MUTEX_TIMEDOUT;
|
||||
}
|
||||
|
||||
/* Wait on the condition variable forever */
|
||||
int
|
||||
SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex)
|
||||
{
|
||||
return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
|
||||
}
|
||||
|
||||
#endif /* SDL_THREAD_N3DS */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
93
src/thread/n3ds/SDL_sysmutex.c
Normal file
93
src/thread/n3ds/SDL_sysmutex.c
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_THREAD_N3DS
|
||||
|
||||
/* An implementation of mutexes using libctru's RecursiveLock */
|
||||
|
||||
#include "SDL_sysmutex_c.h"
|
||||
|
||||
/* Create a mutex */
|
||||
SDL_mutex *
|
||||
SDL_CreateMutex(void)
|
||||
{
|
||||
SDL_mutex *mutex;
|
||||
|
||||
/* Allocate mutex memory */
|
||||
mutex = (SDL_mutex *) SDL_malloc(sizeof(*mutex));
|
||||
if (mutex) {
|
||||
RecursiveLock_Init(&mutex->lock);
|
||||
} else {
|
||||
SDL_OutOfMemory();
|
||||
}
|
||||
return mutex;
|
||||
}
|
||||
|
||||
/* Free the mutex */
|
||||
void
|
||||
SDL_DestroyMutex(SDL_mutex *mutex)
|
||||
{
|
||||
if (mutex) {
|
||||
SDL_free(mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/* Lock the mutex */
|
||||
int
|
||||
SDL_LockMutex(SDL_mutex *mutex)
|
||||
{
|
||||
if (mutex == NULL) {
|
||||
return SDL_SetError("Passed a NULL mutex");
|
||||
}
|
||||
|
||||
RecursiveLock_Lock(&mutex->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* try Lock the mutex */
|
||||
int
|
||||
SDL_TryLockMutex(SDL_mutex *mutex)
|
||||
{
|
||||
if (mutex == NULL) {
|
||||
return SDL_SetError("Passed a NULL mutex");
|
||||
}
|
||||
|
||||
return RecursiveLock_TryLock(&mutex->lock);
|
||||
}
|
||||
|
||||
/* Unlock the mutex */
|
||||
int
|
||||
SDL_mutexV(SDL_mutex *mutex)
|
||||
{
|
||||
if (mutex == NULL) {
|
||||
return SDL_SetError("Passed a NULL mutex");
|
||||
}
|
||||
|
||||
RecursiveLock_Unlock(&mutex->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SDL_THREAD_N3DS */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
37
src/thread/n3ds/SDL_sysmutex_c.h
Normal file
37
src/thread/n3ds/SDL_sysmutex_c.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef SDL_sysmutex_c_h_
|
||||
#define SDL_sysmutex_c_h_
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
#include "SDL_mutex.h"
|
||||
|
||||
struct SDL_mutex
|
||||
{
|
||||
RecursiveLock lock;
|
||||
};
|
||||
|
||||
#endif /* SDL_sysmutex_c_h */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
134
src/thread/n3ds/SDL_syssem.c
Normal file
134
src/thread/n3ds/SDL_syssem.c
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_THREAD_N3DS
|
||||
|
||||
/* An implementation of semaphores using libctru's LightSemaphore */
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
#include "SDL_thread.h"
|
||||
|
||||
struct SDL_semaphore
|
||||
{
|
||||
LightSemaphore semaphore;
|
||||
};
|
||||
|
||||
SDL_sem *
|
||||
SDL_CreateSemaphore(Uint32 initial_value)
|
||||
{
|
||||
SDL_sem *sem;
|
||||
|
||||
if (initial_value > SDL_MAX_SINT16) {
|
||||
SDL_SetError("Initial semaphore value too high for this platform");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sem = (SDL_sem *) SDL_malloc(sizeof(*sem));
|
||||
if (!sem) {
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LightSemaphore_Init(&sem->semaphore, initial_value, SDL_MAX_SINT16);
|
||||
|
||||
return sem;
|
||||
}
|
||||
|
||||
/* WARNING:
|
||||
You cannot call this function when another thread is using the semaphore.
|
||||
*/
|
||||
void
|
||||
SDL_DestroySemaphore(SDL_sem *sem)
|
||||
{
|
||||
if (sem) {
|
||||
SDL_free(sem);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SemTryWait(SDL_sem *sem)
|
||||
{
|
||||
if (!sem) {
|
||||
return SDL_SetError("Passed a NULL semaphore");
|
||||
}
|
||||
|
||||
return SDL_SemWaitTimeout(sem, 0);
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (!sem) {
|
||||
return SDL_SetError("Passed a NULL semaphore");
|
||||
}
|
||||
|
||||
if (timeout == SDL_MUTEX_MAXWAIT) {
|
||||
LightSemaphore_Acquire(&sem->semaphore, 1);
|
||||
retval = 0;
|
||||
} else {
|
||||
int return_code = LightSemaphore_TryAcquire(&sem->semaphore, 1);
|
||||
if (return_code != 0) {
|
||||
for (u32 i = 0; i < timeout; i++) {
|
||||
svcSleepThread(1000000LL);
|
||||
return_code = LightSemaphore_TryAcquire(&sem->semaphore, 1);
|
||||
if (return_code == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
retval = return_code != 0 ? SDL_MUTEX_TIMEDOUT : 0;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SemWait(SDL_sem *sem)
|
||||
{
|
||||
return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
|
||||
}
|
||||
|
||||
Uint32
|
||||
SDL_SemValue(SDL_sem *sem)
|
||||
{
|
||||
if (!sem) {
|
||||
return SDL_SetError("Passed a NULL semaphore");
|
||||
}
|
||||
return sem->semaphore.current_count;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SemPost(SDL_sem *sem)
|
||||
{
|
||||
if (!sem) {
|
||||
return SDL_SetError("Passed a NULL semaphore");
|
||||
}
|
||||
LightSemaphore_Release(&sem->semaphore, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SDL_THREAD_N3DS */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
148
src/thread/n3ds/SDL_systhread.c
Normal file
148
src/thread/n3ds/SDL_systhread.c
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_THREAD_N3DS
|
||||
|
||||
/* Thread management routines for SDL */
|
||||
|
||||
#include "../SDL_systhread.h"
|
||||
|
||||
/* N3DS has very limited RAM (128MB), so we put a limit on thread stack size. */
|
||||
#define N3DS_THREAD_STACK_SIZE_MAX (16 * 1024)
|
||||
#define N3DS_THREAD_STACK_SIZE_DEFAULT (4 * 1024)
|
||||
|
||||
#define N3DS_THREAD_PRIORITY_LOW 0x3F /**< Minimum priority */
|
||||
#define N3DS_THREAD_PRIORITY_MEDIUM 0x2F /**< Slightly higher than main thread (0x30) */
|
||||
#define N3DS_THREAD_PRIORITY_HIGH 0x19 /**< High priority for non-video work */
|
||||
#define N3DS_THREAD_PRIORITY_TIME_CRITICAL 0x18 /**< Highest priority */
|
||||
|
||||
static size_t GetStackSize(size_t requested_size);
|
||||
|
||||
static void
|
||||
ThreadEntry(void *arg)
|
||||
{
|
||||
SDL_RunThread((SDL_Thread *) arg);
|
||||
threadExit(0);
|
||||
}
|
||||
|
||||
#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
|
||||
#error "SDL_PASSED_BEGINTHREAD_ENDTHREAD is not supported on N3DS"
|
||||
#endif
|
||||
|
||||
int
|
||||
SDL_SYS_CreateThread(SDL_Thread *thread)
|
||||
{
|
||||
s32 priority = N3DS_THREAD_PRIORITY_MEDIUM;
|
||||
size_t stack_size = GetStackSize(thread->stacksize);
|
||||
|
||||
thread->handle = threadCreate(ThreadEntry,
|
||||
thread,
|
||||
stack_size,
|
||||
priority,
|
||||
-1,
|
||||
false);
|
||||
|
||||
if (thread->handle == NULL) {
|
||||
return SDL_SetError("Couldn't create thread");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t
|
||||
GetStackSize(size_t requested_size)
|
||||
{
|
||||
if (requested_size == 0) {
|
||||
return N3DS_THREAD_STACK_SIZE_DEFAULT;
|
||||
}
|
||||
|
||||
if (requested_size > N3DS_THREAD_STACK_SIZE_MAX) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_SYSTEM,
|
||||
"Requested a thread size of %zu,"
|
||||
" falling back to the maximum supported of %zu\n",
|
||||
requested_size,
|
||||
N3DS_THREAD_STACK_SIZE_MAX);
|
||||
requested_size = N3DS_THREAD_STACK_SIZE_MAX;
|
||||
}
|
||||
return requested_size;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_SYS_SetupThread(const char *name)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_threadID
|
||||
SDL_ThreadID(void)
|
||||
{
|
||||
u32 thread_ID = 0;
|
||||
svcGetThreadId(&thread_ID, CUR_THREAD_HANDLE);
|
||||
return (SDL_threadID) thread_ID;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SYS_SetThreadPriority(SDL_ThreadPriority sdl_priority)
|
||||
{
|
||||
s32 svc_priority;
|
||||
switch (sdl_priority) {
|
||||
case SDL_THREAD_PRIORITY_LOW:
|
||||
svc_priority = N3DS_THREAD_PRIORITY_LOW;
|
||||
break;
|
||||
case SDL_THREAD_PRIORITY_NORMAL:
|
||||
svc_priority = N3DS_THREAD_PRIORITY_MEDIUM;
|
||||
break;
|
||||
case SDL_THREAD_PRIORITY_HIGH:
|
||||
svc_priority = N3DS_THREAD_PRIORITY_HIGH;
|
||||
break;
|
||||
case SDL_THREAD_PRIORITY_TIME_CRITICAL:
|
||||
svc_priority = N3DS_THREAD_PRIORITY_TIME_CRITICAL;
|
||||
break;
|
||||
default:
|
||||
svc_priority = N3DS_THREAD_PRIORITY_MEDIUM;
|
||||
}
|
||||
return (int) svcSetThreadPriority(CUR_THREAD_HANDLE, svc_priority);
|
||||
}
|
||||
|
||||
void
|
||||
SDL_SYS_WaitThread(SDL_Thread *thread)
|
||||
{
|
||||
Result res = threadJoin(thread->handle, U64_MAX);
|
||||
|
||||
/*
|
||||
Detached threads can be waited on, but should NOT be cleaned manually
|
||||
as it would result in a fatal error.
|
||||
*/
|
||||
if (R_SUCCEEDED(res) && SDL_AtomicGet(&thread->state) != SDL_THREAD_STATE_DETACHED) {
|
||||
threadFree(thread->handle);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_SYS_DetachThread(SDL_Thread *thread)
|
||||
{
|
||||
threadDetach(thread->handle);
|
||||
}
|
||||
|
||||
#endif /* SDL_THREAD_N3DS */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
32
src/thread/n3ds/SDL_systhread_c.h
Normal file
32
src/thread/n3ds/SDL_systhread_c.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef SDL_systhread_c_h_
|
||||
#define SDL_systhread_c_h_
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
typedef Thread SYS_ThreadHandle;
|
||||
|
||||
#endif /* SDL_systhread_c_h_ */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
81
src/timer/n3ds/SDL_systimer.c
Normal file
81
src/timer/n3ds/SDL_systimer.c
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_TIMER_N3DS
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
static SDL_bool ticks_started = SDL_FALSE;
|
||||
static u64 start_tick;
|
||||
|
||||
#define NSEC_PER_MSEC 1000000ULL
|
||||
|
||||
void
|
||||
SDL_TicksInit(void)
|
||||
{
|
||||
if (ticks_started) {
|
||||
return;
|
||||
}
|
||||
ticks_started = SDL_TRUE;
|
||||
|
||||
start_tick = svcGetSystemTick();
|
||||
}
|
||||
|
||||
void
|
||||
SDL_TicksQuit(void)
|
||||
{
|
||||
ticks_started = SDL_FALSE;
|
||||
}
|
||||
|
||||
Uint64
|
||||
SDL_GetTicks64(void)
|
||||
{
|
||||
u64 elapsed;
|
||||
if (!ticks_started) {
|
||||
SDL_TicksInit();
|
||||
}
|
||||
|
||||
elapsed = svcGetSystemTick() - start_tick;
|
||||
return elapsed / CPU_TICKS_PER_MSEC;
|
||||
}
|
||||
|
||||
Uint64
|
||||
SDL_GetPerformanceCounter(void)
|
||||
{
|
||||
return svcGetSystemTick();
|
||||
}
|
||||
|
||||
Uint64
|
||||
SDL_GetPerformanceFrequency(void)
|
||||
{
|
||||
return SYSCLOCK_ARM11;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_Delay(Uint32 ms)
|
||||
{
|
||||
svcSleepThread(ms * NSEC_PER_MSEC);
|
||||
}
|
||||
|
||||
#endif /* SDL_TIMER_N3DS */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
@ -461,6 +461,7 @@ extern VideoBootStrap PS2_bootstrap;
|
||||
extern VideoBootStrap PSP_bootstrap;
|
||||
extern VideoBootStrap VITA_bootstrap;
|
||||
extern VideoBootStrap RISCOS_bootstrap;
|
||||
extern VideoBootStrap N3DS_bootstrap;
|
||||
extern VideoBootStrap RPI_bootstrap;
|
||||
extern VideoBootStrap KMSDRM_bootstrap;
|
||||
extern VideoBootStrap KMSDRM_LEGACY_bootstrap;
|
||||
|
@ -100,6 +100,9 @@ static VideoBootStrap *bootstrap[] = {
|
||||
#if SDL_VIDEO_DRIVER_VITA
|
||||
&VITA_bootstrap,
|
||||
#endif
|
||||
#if SDL_VIDEO_DRIVER_N3DS
|
||||
&N3DS_bootstrap,
|
||||
#endif
|
||||
#if SDL_VIDEO_DRIVER_KMSDRM
|
||||
&KMSDRM_bootstrap,
|
||||
#endif
|
||||
@ -1498,7 +1501,7 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
|
||||
}
|
||||
|
||||
#define CREATE_FLAGS \
|
||||
(SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_METAL)
|
||||
(SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP | SDL_WINDOW_VULKAN | SDL_WINDOW_MINIMIZED | SDL_WINDOW_METAL | SDL_WINDOW_N3DS_BOTTOM)
|
||||
|
||||
static SDL_INLINE SDL_bool
|
||||
IsAcceptingDragAndDrop(void)
|
||||
|
45
src/video/n3ds/SDL_n3dsevents.c
Normal file
45
src/video/n3ds/SDL_n3dsevents.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_N3DS
|
||||
|
||||
/* Pumping the events for the Home and Power buttons. */
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
#include "../../events/SDL_events_c.h"
|
||||
#include "SDL_n3dsevents_c.h"
|
||||
|
||||
void
|
||||
N3DS_PumpEvents(_THIS)
|
||||
{
|
||||
if (!aptMainLoop()) {
|
||||
SDL_Event ev;
|
||||
ev.type = SDL_QUIT;
|
||||
SDL_PushEvent(&ev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_N3DS */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
31
src/video/n3ds/SDL_n3dsevents_c.h
Normal file
31
src/video/n3ds/SDL_n3dsevents_c.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_n3dsevents_c_h_
|
||||
#define SDL_n3dsevents_c_h_
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
extern void N3DS_PumpEvents(_THIS);
|
||||
|
||||
#endif /* SDL_n3dsevents_c_h_ */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
148
src/video/n3ds/SDL_n3dsframebuffer.c
Normal file
148
src/video/n3ds/SDL_n3dsframebuffer.c
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_N3DS
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "SDL_n3dsframebuffer_c.h"
|
||||
#include "SDL_n3dsvideo.h"
|
||||
|
||||
#define N3DS_SURFACE "_SDL_N3DSSurface"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int width, height;
|
||||
} Dimensions;
|
||||
|
||||
SDL_FORCE_INLINE void FreePreviousWindowFramebuffer(SDL_Window *window);
|
||||
SDL_FORCE_INLINE SDL_Surface *CreateNewWindowFramebuffer(SDL_Window *window);
|
||||
SDL_FORCE_INLINE void CopyFramebuffertoN3DS(u32 *dest, const Dimensions dest_dim, const u32 *source, const Dimensions source_dim);
|
||||
SDL_FORCE_INLINE int GetDestOffset(int x, int y, int dest_width);
|
||||
SDL_FORCE_INLINE int GetSourceOffset(int x, int y, int source_width);
|
||||
SDL_FORCE_INLINE void FlushN3DSBuffer(const void *buffer, u32 bufsize, gfxScreen_t screen);
|
||||
|
||||
int
|
||||
SDL_N3DS_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, void **pixels, int *pitch)
|
||||
{
|
||||
SDL_Surface *framebuffer;
|
||||
|
||||
FreePreviousWindowFramebuffer(window);
|
||||
framebuffer = CreateNewWindowFramebuffer(window);
|
||||
|
||||
if (!framebuffer) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
SDL_SetWindowData(window, N3DS_SURFACE, framebuffer);
|
||||
*format = FRAMEBUFFER_FORMAT;
|
||||
*pixels = framebuffer->pixels;
|
||||
*pitch = framebuffer->pitch;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void
|
||||
FreePreviousWindowFramebuffer(SDL_Window *window)
|
||||
{
|
||||
SDL_Surface *surface = (SDL_Surface *) SDL_GetWindowData(window, N3DS_SURFACE);
|
||||
SDL_FreeSurface(surface);
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE SDL_Surface *
|
||||
CreateNewWindowFramebuffer(SDL_Window *window)
|
||||
{
|
||||
int w, h, bpp;
|
||||
Uint32 Rmask, Gmask, Bmask, Amask;
|
||||
SDL_PixelFormatEnumToMasks(FRAMEBUFFER_FORMAT, &bpp, &Rmask, &Gmask, &Bmask, &Amask);
|
||||
SDL_GetWindowSize(window, &w, &h);
|
||||
return SDL_CreateRGBSurface(0, w, h, bpp, Rmask, Gmask, Bmask, Amask);
|
||||
}
|
||||
|
||||
int
|
||||
SDL_N3DS_UpdateWindowFramebuffer(_THIS, SDL_Window *window, const SDL_Rect *rects, int numrects)
|
||||
{
|
||||
SDL_WindowData *drv_data = (SDL_WindowData *) window->driverdata;
|
||||
SDL_Surface *surface;
|
||||
u16 width, height;
|
||||
u32 *framebuffer;
|
||||
u32 bufsize;
|
||||
|
||||
surface = (SDL_Surface *) SDL_GetWindowData(window, N3DS_SURFACE);
|
||||
if (!surface) {
|
||||
return SDL_SetError("%s: Unable to get the window surface.", __func__);
|
||||
}
|
||||
|
||||
/* Get the N3DS internal framebuffer and its size */
|
||||
framebuffer = (u32 *) gfxGetFramebuffer(drv_data->screen, GFX_LEFT, &width, &height);
|
||||
bufsize = width * height * 4;
|
||||
|
||||
CopyFramebuffertoN3DS(framebuffer, (Dimensions){ width, height },
|
||||
surface->pixels, (Dimensions){ surface->w, surface->h });
|
||||
FlushN3DSBuffer(framebuffer, bufsize, drv_data->screen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void
|
||||
CopyFramebuffertoN3DS(u32 *dest, const Dimensions dest_dim, const u32 *source, const Dimensions source_dim)
|
||||
{
|
||||
int rows = SDL_min(dest_dim.width, source_dim.height);
|
||||
int cols = SDL_min(dest_dim.height, source_dim.width);
|
||||
for (int y = 0; y < rows; ++y) {
|
||||
for (int x = 0; x < cols; ++x) {
|
||||
SDL_memcpy(
|
||||
dest + GetDestOffset(x, y, dest_dim.width),
|
||||
source + GetSourceOffset(x, y, source_dim.width),
|
||||
4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE int
|
||||
GetDestOffset(int x, int y, int dest_width)
|
||||
{
|
||||
return dest_width - y - 1 + dest_width * x;
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE int
|
||||
GetSourceOffset(int x, int y, int source_width)
|
||||
{
|
||||
return x + y * source_width;
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void
|
||||
FlushN3DSBuffer(const void *buffer, u32 bufsize, gfxScreen_t screen)
|
||||
{
|
||||
GSPGPU_FlushDataCache(buffer, bufsize);
|
||||
gfxScreenSwapBuffers(screen, false);
|
||||
}
|
||||
|
||||
void
|
||||
SDL_N3DS_DestroyWindowFramebuffer(_THIS, SDL_Window *window)
|
||||
{
|
||||
SDL_Surface *surface;
|
||||
surface = (SDL_Surface *) SDL_SetWindowData(window, N3DS_SURFACE, NULL);
|
||||
SDL_FreeSurface(surface);
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_N3DS */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
33
src/video/n3ds/SDL_n3dsframebuffer_c.h
Normal file
33
src/video/n3ds/SDL_n3dsframebuffer_c.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_n3dsframebuffer_c_h_
|
||||
#define SDL_n3dsframebuffer_c_h_
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
int SDL_N3DS_CreateWindowFramebuffer(_THIS, SDL_Window *window, Uint32 *format, void **pixels, int *pitch);
|
||||
int SDL_N3DS_UpdateWindowFramebuffer(_THIS, SDL_Window *window, const SDL_Rect *rects, int numrects);
|
||||
void SDL_N3DS_DestroyWindowFramebuffer(_THIS, SDL_Window *window);
|
||||
|
||||
#endif /* SDL_n3dsframebuffer_c_h_ */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
76
src/video/n3ds/SDL_n3dsswkb.c
Normal file
76
src/video/n3ds/SDL_n3dsswkb.c
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_N3DS
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
#include "SDL_n3dsswkb.h"
|
||||
|
||||
static SwkbdState sw_keyboard;
|
||||
const static size_t BUFFER_SIZE = 256;
|
||||
|
||||
void
|
||||
N3DS_SwkbInit()
|
||||
{
|
||||
swkbdInit(&sw_keyboard, SWKBD_TYPE_NORMAL, 2, -1);
|
||||
}
|
||||
|
||||
void
|
||||
N3DS_SwkbPoll()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
N3DS_SwkbQuit()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
N3DS_HasScreenKeyboardSupport(_THIS)
|
||||
{
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
N3DS_StartTextInput(_THIS)
|
||||
{
|
||||
char buffer[BUFFER_SIZE];
|
||||
SwkbdButton button_pressed;
|
||||
button_pressed = swkbdInputText(&sw_keyboard, buffer, BUFFER_SIZE);
|
||||
if (button_pressed == SWKBD_BUTTON_CONFIRM) {
|
||||
SDL_SendKeyboardText(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
N3DS_StopTextInput(_THIS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_N3DS */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
38
src/video/n3ds/SDL_n3dsswkb.h
Normal file
38
src/video/n3ds/SDL_n3dsswkb.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_n3dskeyboard_h_
|
||||
#define SDL_n3dskeyboard_h_
|
||||
|
||||
#include "../../events/SDL_events_c.h"
|
||||
|
||||
void N3DS_SwkbInit();
|
||||
void N3DS_SwkbPoll();
|
||||
void N3DS_SwkbQuit();
|
||||
|
||||
SDL_bool N3DS_HasScreenKeyboardSupport(_THIS);
|
||||
|
||||
void N3DS_StartTextInput(_THIS);
|
||||
void N3DS_StopTextInput(_THIS);
|
||||
|
||||
#endif /* SDL_n3dskeyboard_h_ */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
163
src/video/n3ds/SDL_n3dsvideo.c
Normal file
163
src/video/n3ds/SDL_n3dsvideo.c
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_N3DS
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "SDL_n3dsevents_c.h"
|
||||
#include "SDL_n3dsframebuffer_c.h"
|
||||
#include "SDL_n3dsswkb.h"
|
||||
#include "SDL_n3dsvideo.h"
|
||||
|
||||
#define N3DSVID_DRIVER_NAME "n3ds"
|
||||
|
||||
SDL_FORCE_INLINE void AddN3DSDisplay(gfxScreen_t screen);
|
||||
|
||||
static int N3DS_VideoInit(_THIS);
|
||||
static void N3DS_VideoQuit(_THIS);
|
||||
static void N3DS_GetDisplayModes(_THIS, SDL_VideoDisplay *display);
|
||||
static int N3DS_CreateWindow(_THIS, SDL_Window *window);
|
||||
static void N3DS_DestroyWindow(_THIS, SDL_Window *window);
|
||||
|
||||
/* N3DS driver bootstrap functions */
|
||||
|
||||
static void
|
||||
N3DS_DeleteDevice(SDL_VideoDevice *device)
|
||||
{
|
||||
SDL_free(device->displays);
|
||||
SDL_free(device->driverdata);
|
||||
SDL_free(device);
|
||||
}
|
||||
|
||||
static SDL_VideoDevice *
|
||||
N3DS_CreateDevice(void)
|
||||
{
|
||||
SDL_VideoDevice *device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
|
||||
if (!device) {
|
||||
SDL_OutOfMemory();
|
||||
return (0);
|
||||
}
|
||||
|
||||
device->VideoInit = N3DS_VideoInit;
|
||||
device->VideoQuit = N3DS_VideoQuit;
|
||||
|
||||
device->GetDisplayModes = N3DS_GetDisplayModes;
|
||||
|
||||
device->CreateSDLWindow = N3DS_CreateWindow;
|
||||
device->DestroyWindow = N3DS_DestroyWindow;
|
||||
|
||||
device->HasScreenKeyboardSupport = N3DS_HasScreenKeyboardSupport;
|
||||
device->StartTextInput = N3DS_StartTextInput;
|
||||
device->StopTextInput = N3DS_StopTextInput;
|
||||
|
||||
device->PumpEvents = N3DS_PumpEvents;
|
||||
|
||||
device->CreateWindowFramebuffer = SDL_N3DS_CreateWindowFramebuffer;
|
||||
device->UpdateWindowFramebuffer = SDL_N3DS_UpdateWindowFramebuffer;
|
||||
device->DestroyWindowFramebuffer = SDL_N3DS_DestroyWindowFramebuffer;
|
||||
|
||||
device->num_displays = 2;
|
||||
|
||||
device->free = N3DS_DeleteDevice;
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
VideoBootStrap N3DS_bootstrap = { N3DSVID_DRIVER_NAME, "N3DS Video Driver", N3DS_CreateDevice };
|
||||
|
||||
static int
|
||||
N3DS_VideoInit(_THIS)
|
||||
{
|
||||
AddN3DSDisplay(GFX_TOP);
|
||||
AddN3DSDisplay(GFX_BOTTOM);
|
||||
|
||||
N3DS_SwkbInit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_FORCE_INLINE void
|
||||
AddN3DSDisplay(gfxScreen_t screen)
|
||||
{
|
||||
SDL_DisplayMode mode;
|
||||
SDL_VideoDisplay display;
|
||||
|
||||
SDL_zero(mode);
|
||||
SDL_zero(display);
|
||||
|
||||
mode.w = (screen == GFX_TOP) ? GSP_SCREEN_HEIGHT_TOP : GSP_SCREEN_HEIGHT_BOTTOM;
|
||||
mode.h = GSP_SCREEN_WIDTH;
|
||||
mode.refresh_rate = 60;
|
||||
mode.format = FRAMEBUFFER_FORMAT;
|
||||
mode.driverdata = NULL;
|
||||
|
||||
display.desktop_mode = mode;
|
||||
display.current_mode = mode;
|
||||
display.driverdata = NULL;
|
||||
|
||||
SDL_AddVideoDisplay(&display, SDL_FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
N3DS_VideoQuit(_THIS)
|
||||
{
|
||||
N3DS_SwkbQuit();
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
N3DS_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
|
||||
{
|
||||
/* Each display only has a single mode */
|
||||
SDL_AddDisplayMode(display, &display->current_mode);
|
||||
}
|
||||
|
||||
static int
|
||||
N3DS_CreateWindow(_THIS, SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *drv_data = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData));
|
||||
if (drv_data == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
if (window->flags & SDL_WINDOW_N3DS_BOTTOM) {
|
||||
drv_data->screen = GFX_BOTTOM;
|
||||
} else {
|
||||
drv_data->screen = GFX_TOP;
|
||||
}
|
||||
|
||||
window->driverdata = drv_data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
N3DS_DestroyWindow(_THIS, SDL_Window *window)
|
||||
{
|
||||
if (window == NULL) {
|
||||
return;
|
||||
}
|
||||
SDL_free(window->driverdata);
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_N3DS */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
38
src/video/n3ds/SDL_n3dsvideo.h
Normal file
38
src/video/n3ds/SDL_n3dsvideo.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef SDL_n3dsvideo_h_
|
||||
#define SDL_n3dsvideo_h_
|
||||
|
||||
#include <3ds.h>
|
||||
|
||||
#include "../SDL_sysvideo.h"
|
||||
typedef struct SDL_WindowData
|
||||
{
|
||||
gfxScreen_t screen; /**< Keeps track of which N3DS screen is targetted */
|
||||
} SDL_WindowData;
|
||||
|
||||
#define FRAMEBUFFER_FORMAT SDL_PIXELFORMAT_RGBA8888
|
||||
|
||||
#endif /* SDL_n3dsvideo_h_ */
|
||||
|
||||
/* vi: set sts=4 ts=4 sw=4 expandtab: */
|
@ -14,6 +14,10 @@ if(SDL_INSTALL_TESTS)
|
||||
include(GNUInstallDirs)
|
||||
endif()
|
||||
|
||||
if(N3DS)
|
||||
link_libraries(SDL2::SDL2main)
|
||||
endif()
|
||||
|
||||
if(PSP)
|
||||
link_libraries(
|
||||
SDL2::SDL2main
|
||||
@ -430,6 +434,27 @@ if(PSP)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(N3DS)
|
||||
set(ROMFS_DIR "${CMAKE_CURRENT_BINARY_DIR}/romfs")
|
||||
file(COPY ${RESOURCE_FILES} DESTINATION "${ROMFS_DIR}")
|
||||
|
||||
foreach(APP IN LISTS ALL_TESTS)
|
||||
get_target_property(TARGET_BINARY_DIR ${APP} BINARY_DIR)
|
||||
set(SMDH_FILE "${TARGET_BINARY_DIR}/${APP}.smdh")
|
||||
ctr_generate_smdh("${SMDH_FILE}"
|
||||
NAME "SDL-${APP}"
|
||||
DESCRIPTION "SDL2 Test suite"
|
||||
AUTHOR "SDL2 Contributors"
|
||||
ICON "${CMAKE_CURRENT_SOURCE_DIR}/n3ds/logo48x48.png"
|
||||
)
|
||||
ctr_create_3dsx(
|
||||
${APP}
|
||||
ROMFS "${ROMFS_DIR}"
|
||||
SMDH "${SMDH_FILE}"
|
||||
)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(RISCOS)
|
||||
set(ALL_TESTS_AIF "")
|
||||
foreach(APP IN LISTS ALL_TESTS)
|
||||
|
BIN
test/n3ds/logo48x48.png
Normal file
BIN
test/n3ds/logo48x48.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
Loading…
Reference in New Issue
Block a user