From 55c053efe32c5702490932f686bb330ee9be7a97 Mon Sep 17 00:00:00 2001 From: MrHuu Date: Sun, 11 Aug 2024 22:16:50 +0200 Subject: [PATCH] [3DS] Initial 3DS port --- CMakeLists.txt | 55 +++++ lib/miniaudio/include/miniaudio/miniaudio.h | 2 + packaging/ctr/audio_silent.wav | Bin 0 -> 2212 bytes packaging/ctr/banner.png | Bin 0 -> 23925 bytes packaging/ctr/icon.png | Bin 0 -> 2670 bytes packaging/ctr/romfs/.gitignore | 4 + packaging/ctr/template.rsf | 219 ++++++++++++++++++++ src/harness/CMakeLists.txt | 4 + src/harness/audio/miniaudio.c | 5 + src/harness/harness.c | 14 ++ src/harness/os/ctr.c | 27 +++ src/harness/platforms/sdl2.c | 137 +++++++++++- 12 files changed, 466 insertions(+), 1 deletion(-) create mode 100644 packaging/ctr/audio_silent.wav create mode 100644 packaging/ctr/banner.png create mode 100644 packaging/ctr/icon.png create mode 100644 packaging/ctr/romfs/.gitignore create mode 100644 packaging/ctr/template.rsf create mode 100644 src/harness/os/ctr.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 4327fd02..dda63008 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,3 +129,58 @@ if(DETHRACE_INSTALL) include(CPack) endif() + +if (NINTENDO_3DS) + set(APP_TITLE "${PROJECT_NAME}") + set(APP_DESCRIPTION "${PROJECT_NAME} port for 3DS") + set(APP_AUTHOR "dethrace-labs") + set(APP_UNIQUE_ID "0xF02F6") + set(APP_ICON "${PROJECT_SOURCE_DIR}/packaging/ctr/icon.png") + set(APP_BANNER "${PROJECT_SOURCE_DIR}/packaging/ctr/banner.png") + set(APP_AUDIO "${PROJECT_SOURCE_DIR}/packaging/ctr/audio_silent.wav") + set(APP_ROMFS_DIR "${PROJECT_SOURCE_DIR}/packaging/ctr/romfs") + set(APP_RSF "${PROJECT_SOURCE_DIR}/packaging/ctr/template.rsf") + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.3dsx + COMMAND 3dsxtool ${PROJECT_NAME}.elf ${PROJECT_NAME}${ROM}.3dsx + --romfs=${APP_ROMFS_DIR} + --smdh=${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.smdh + DEPENDS ${PROJECT_NAME} ${PROJECT_NAME}.smdh + ) + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.cia + COMMAND makerom -f cia + -target t + -exefslogo + -o ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.cia + -elf ${PROJECT_NAME}.elf + -rsf ${APP_RSF} + -DAPP_TITLE=${APP_TITLE} + -DAPP_UNIQUE_ID=${APP_UNIQUE_ID} + -DAPP_ROMFS_DIR=${APP_ROMFS_DIR} + -banner ${PROJECT_NAME}.bnr + -icon ${PROJECT_NAME}.smdh + DEPENDS ${PROJECT_NAME} ${APP_RSF} ${PROJECT_NAME}.smdh ${PROJECT_NAME}.bnr + ) + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.smdh + COMMAND bannertool makesmdh -o ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.smdh + -s ${APP_TITLE} + -l ${APP_DESCRIPTION} + -p ${APP_AUTHOR} + -i ${APP_ICON} + + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.bnr + COMMAND bannertool makebanner -o ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.bnr + -i ${APP_BANNER} + -a ${APP_AUDIO} + ) + + add_custom_target( N3DS ALL + DEPENDS ${PROJECT_NAME}.3dsx + ${PROJECT_NAME}.cia + ) +endif () diff --git a/lib/miniaudio/include/miniaudio/miniaudio.h b/lib/miniaudio/include/miniaudio/miniaudio.h index 47332e11..6b0b45e7 100644 --- a/lib/miniaudio/include/miniaudio/miniaudio.h +++ b/lib/miniaudio/include/miniaudio/miniaudio.h @@ -16116,9 +16116,11 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority #endif } else if (priority == ma_thread_priority_realtime) { #ifdef SCHED_FIFO +#ifndef __3DS__ if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0) { scheduler = SCHED_FIFO; } +#endif #endif #ifdef MA_LINUX } else { diff --git a/packaging/ctr/audio_silent.wav b/packaging/ctr/audio_silent.wav new file mode 100644 index 0000000000000000000000000000000000000000..e0b684b62fea209617584c9533dfc2432b67ebfc GIT binary patch literal 2212 zcmZ9O!H&~F5JboJ*iLTw1bzhxR^rM5&MP5q-1fl7@CjV_IChiR&QPyw8wVn7Y|pf- zyQ``v`|-oW!;eELpWl9Z|MlC`n^P&JD}8zQvy{`XzSMFmUml+xzbhs`eYv%@jf%Rq zQbsMWjdz-!ioRPs6-C{2SGBhMjcctJJ~3Q3tq+RZTGi94wLxp_IRXrjL8{tY6gdd5 zi~F@5gnriA^or%$x2Ud`i{3hD=OQqw+=NALqW;Av4_PxGHSosrnw=U}t<8Z(wN-Dd zLaN%?qR+(av{Ql&YG;*i@H-*yeP@sKeN#5NgVjmbt1^s=U9{8du2&CqIYcZB@G-vc zK?eVR%@ui{UEZTsSoR%jsL+CcRGNfvQN*kWo~aTXdLE_sB1VVuqUTxHy>oL)_8N6} zLTWMwC_tq49r_e~f$4t9t@OLQV1&bw-zYLW%lgKtm= z7t$HtMKhGKXJOM>(GVUEipIxAr8n2WyUw{+Vx_6itWUbjv*SfrbdA2&%-Zb8sGhF& zIpRup#qHfO`eU-F45jdXIvpl(?nO)-)xlX@&$^mzxPo2Jf!U*f&Lpdc6OwD66sU*4 z(H{p@v3M2g6elL93#*$l9>msjT*puuWOI`Kf*WgrHdd088#e7lYQoJ|p-nm;IGdR~ zSfJaZV$V@6b<($I4;R`O;F0zJxi&-TVRShvk_?Do^d`*p{e6Ju7_xYu3c51pYD-N@Izf7 xP>)gb%%cx}8$3Hc{Wx(^2etUk^#2K<@H@vY^Z8p?v)%(cdDWIac#166@ek+nz@z{G literal 0 HcmV?d00001 diff --git a/packaging/ctr/banner.png b/packaging/ctr/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..c048f9ca03ef5e59487d7dd7481976b896f7823e GIT binary patch literal 23925 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 Z`vePesVqfN`NjUFhNMWK`*hRn8T|I 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 UqRG7v0Oa%eld5dBv{}gi0Z=*ul>h($ literal 0 HcmV?d00001 diff --git a/packaging/ctr/icon.png b/packaging/ctr/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f9d9dd11989836695971ca9ccb41b68f86c279f0 GIT binary patch literal 2670 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 literal 0 HcmV?d00001 diff --git a/packaging/ctr/romfs/.gitignore b/packaging/ctr/romfs/.gitignore new file mode 100644 index 00000000..86d0cb27 --- /dev/null +++ b/packaging/ctr/romfs/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/packaging/ctr/template.rsf b/packaging/ctr/template.rsf new file mode 100644 index 00000000..a77c7853 --- /dev/null +++ b/packaging/ctr/template.rsf @@ -0,0 +1,219 @@ +BasicInfo: + Title : $(APP_TITLE) + ProductCode : $(APP_PRODUCT_CODE) + Logo : Nintendo # Nintendo / Licensed / Distributed / iQue / iQueForSystem + +RomFs: + # Specifies the root path of the read only file system to include in the ROM. + RootPath : $(APP_ROMFS) + +TitleInfo: + Category : Application + UniqueId : $(APP_UNIQUE_ID) + +Option: + UseOnSD : true # true if App is to be installed to SD + FreeProductCode : true # Removes limitations on ProductCode + MediaFootPadding : false # If true CCI files are created with padding + EnableCrypt : false # Enables encryption for NCCH and CIA + EnableCompress : false # Compresses where applicable (currently only exefs:/.code) + +AccessControlInfo: + CoreVersion : 2 + + # Exheader Format Version + DescVersion : 2 + + # Minimum Required Kernel Version (below is for 4.5.0) + ReleaseKernelMajor : "02" + ReleaseKernelMinor : "33" + + # ExtData + UseExtSaveData : false # enables ExtData + #ExtSaveDataId : 0x300 # only set this when the ID is different to the UniqueId + + # FS:USER Archive Access Permissions + # Uncomment as required + FileSystemAccess: + #- CategorySystemApplication + #- CategoryHardwareCheck + - CategoryFileSystemTool + #- Debug + #- TwlCardBackup + #- TwlNandData + #- Boss + - DirectSdmc + #- Core + #- CtrNandRo + #- CtrNandRw + #- CtrNandRoWrite + #- CategorySystemSettings + #- CardBoard + #- ExportImportIvs + #- DirectSdmcWrite + #- SwitchCleanup + #- SaveDataMove + #- Shop + #- Shell + #- CategoryHomeMenu + + # Process Settings + MemoryType : Application # Application/System/Base + SystemMode : 64MB # 64MB(Default)/96MB/80MB/72MB/32MB + IdealProcessor : 0 + AffinityMask : 1 + Priority : 16 + MaxCpu : 0x9E # Default + HandleTableSize : 0x200 + DisableDebug : false + EnableForceDebug : false + CanWriteSharedPage : true + CanUsePrivilegedPriority : false + CanUseNonAlphabetAndNumber : true + PermitMainFunctionArgument : true + CanShareDeviceMemory : true + RunnableOnSleep : false + SpecialMemoryArrange : true + + # New3DS Exclusive Process Settings + SystemModeExt : $(APP_SYSTEM_MODE_EXT) # Legacy(Default)/124MB/178MB Legacy:Use Old3DS SystemMode + CpuSpeed : 804MHz # 256MHz(Default)/804MHz + EnableL2Cache : true # false(default)/true + CanAccessCore2 : true + + # Virtual Address Mappings + IORegisterMapping: + - 1ff00000-1ff7ffff # DSP memory + MemoryMapping: + - 1f000000-1f5fffff:r # VRAM + + # Accessible SVCs, : + SystemCallAccess: + ArbitrateAddress: 34 + Backdoor: 123 + Break: 60 + CancelTimer: 28 + ClearEvent: 25 + ClearTimer: 29 + CloseHandle: 35 + ConnectToPort: 45 + ControlMemory: 1 + ControlProcessMemory: 112 + CreateAddressArbiter: 33 + CreateEvent: 23 + CreateMemoryBlock: 30 + CreateMutex: 19 + CreateSemaphore: 21 + CreateThread: 8 + CreateTimer: 26 + DuplicateHandle: 39 + ExitProcess: 3 + ExitThread: 9 + GetCurrentProcessorNumber: 17 + GetHandleInfo: 41 + GetProcessId: 53 + GetProcessIdOfThread: 54 + GetProcessIdealProcessor: 6 + GetProcessInfo: 43 + GetResourceLimit: 56 + GetResourceLimitCurrentValues: 58 + GetResourceLimitLimitValues: 57 + GetSystemInfo: 42 + GetSystemTick: 40 + GetThreadContext: 59 + GetThreadId: 55 + GetThreadIdealProcessor: 15 + GetThreadInfo: 44 + GetThreadPriority: 11 + MapMemoryBlock: 31 + OutputDebugString: 61 + QueryMemory: 2 + ReleaseMutex: 20 + ReleaseSemaphore: 22 + SendSyncRequest1: 46 + SendSyncRequest2: 47 + SendSyncRequest3: 48 + SendSyncRequest4: 49 + SendSyncRequest: 50 + SetThreadPriority: 12 + SetTimer: 27 + SignalEvent: 24 + SleepThread: 10 + UnmapMemoryBlock: 32 + WaitSynchronization1: 36 + WaitSynchronizationN: 37 + + # Service List + # Maximum 34 services (32 if firmware is prior to 9.6.0) + ServiceAccessControl: + - APT:U + - ac:u + - am:net + - boss:U + - cam:u + - cecd:u + - cfg:nor + - cfg:u + - csnd:SND + - dsp::DSP + - frd:u + - fs:USER + - gsp::Gpu + - hid:USER + - http:C + - ir:rst + - ir:u + - ir:USER + - mic:u + - ndm:u + - news:u + - nwm::UDS + - ptm:u + - pxi:dev + - soc:U + - ssl:C + - y2r:u + + +SystemControlInfo: + SaveDataSize: 0KB # Change if the app uses savedata + RemasterVersion: 2 + StackSize: 0x40000 + + # Modules that run services listed above should be included below + # Maximum 48 dependencies + # : + Dependency: + ac: 0x0004013000002402 + act: 0x0004013000003802 + am: 0x0004013000001502 + boss: 0x0004013000003402 + camera: 0x0004013000001602 + cecd: 0x0004013000002602 + cfg: 0x0004013000001702 + codec: 0x0004013000001802 + csnd: 0x0004013000002702 + dlp: 0x0004013000002802 + dsp: 0x0004013000001a02 + friends: 0x0004013000003202 + gpio: 0x0004013000001b02 + gsp: 0x0004013000001c02 + hid: 0x0004013000001d02 + http: 0x0004013000002902 + i2c: 0x0004013000001e02 + ir: 0x0004013000003302 + mcu: 0x0004013000001f02 + mic: 0x0004013000002002 + ndm: 0x0004013000002b02 + news: 0x0004013000003502 + nfc: 0x0004013000004002 + nim: 0x0004013000002c02 + nwm: 0x0004013000002d02 + pdn: 0x0004013000002102 + ps: 0x0004013000003102 + ptm: 0x0004013000002202 + qtm: 0x0004013020004202 + ro: 0x0004013000003702 + socket: 0x0004013000002e02 + spi: 0x0004013000002302 + ssl: 0x0004013000002f02 diff --git a/src/harness/CMakeLists.txt b/src/harness/CMakeLists.txt index dc3ec120..a75b2d1d 100644 --- a/src/harness/CMakeLists.txt +++ b/src/harness/CMakeLists.txt @@ -81,6 +81,10 @@ elseif(APPLE) target_sources(harness PRIVATE os/macos.c ) +elseif(NINTENDO_3DS) + target_sources(harness PRIVATE + os/ctr.c + ) else() target_sources(harness PRIVATE os/linux.c diff --git a/src/harness/audio/miniaudio.c b/src/harness/audio/miniaudio.c index 054cbd7d..e27d08e6 100644 --- a/src/harness/audio/miniaudio.c +++ b/src/harness/audio/miniaudio.c @@ -6,6 +6,11 @@ #include "harness/os.h" #include "harness/trace.h" +#ifdef __3DS__ +#define MA_NO_PTHREAD_IN_HEADER +#define MA_NO_RUNTIME_LINKING +#endif + // Must come before miniaudio.h #define STB_VORBIS_HEADER_ONLY #include "stb/stb_vorbis.c" diff --git a/src/harness/harness.c b/src/harness/harness.c index 6ae60621..e99a1d90 100644 --- a/src/harness/harness.c +++ b/src/harness/harness.c @@ -11,6 +11,10 @@ #include #include +#ifdef __3DS__ +#include <3ds.h> +#endif + br_pixelmap* palette; uint32_t* screen_buffer; @@ -166,15 +170,25 @@ void Harness_Init(int* argc, char* argv[]) { Harness_ProcessCommandLine(argc, argv); +#ifdef __3DS__ + osSetSpeedupEnable(true); + gfxInitDefault(); + consoleInit(GFX_BOTTOM, NULL); + chdir("sdmc:/CARMA/"); + char* root_dir = NULL; +#else if (harness_game_config.install_signalhandler) { OS_InstallSignalHandler(argv[0]); } char* root_dir = getenv("DETHRACE_ROOT_DIR"); +#endif if (root_dir != NULL) { LOG_INFO("DETHRACE_ROOT_DIR is set to '%s'", root_dir); } else { +#ifndef __3DS__ root_dir = OS_GetWorkingDirectory(argv[0]); +#endif } // if root_dir is null or empty, no need to chdir if (root_dir != NULL && root_dir[0] != '\0') { diff --git a/src/harness/os/ctr.c b/src/harness/os/ctr.c new file mode 100644 index 00000000..8fed5c68 --- /dev/null +++ b/src/harness/os/ctr.c @@ -0,0 +1,27 @@ +#define _GNU_SOURCE +#include +#include + +void resolve_full_path(char* path, const char* argv0) { + return; +} + +FILE* OS_fopen(const char* pathname, const char* mode) { + FILE* f = fopen(pathname, mode); + if (f != NULL) { + return f; + } + return NULL; +} + +size_t OS_ConsoleReadPassword(char* pBuffer, size_t pBufferLen) { + return 0; +} + +char* OS_Basename(const char* path) { + return ""; +} + +char* OS_GetWorkingDirectory(char* argv0) { + return ""; +} diff --git a/src/harness/platforms/sdl2.c b/src/harness/platforms/sdl2.c index 6ba8ad8c..793bcbda 100644 --- a/src/harness/platforms/sdl2.c +++ b/src/harness/platforms/sdl2.c @@ -6,6 +6,10 @@ #include "harness/trace.h" #include "sdl2_scancode_to_dinput.h" +#ifdef __3DS__ +#include <3ds.h> +#endif + SDL_Window* window; SDL_Renderer* renderer; SDL_Texture* screen_texture; @@ -17,6 +21,12 @@ Uint32 last_frame_time; uint8_t directinput_key_state[SDL_NUM_SCANCODES]; +#ifdef __3DS__ +extern int sdlScanCodeToDirectInputKeyNum[SDL_NUM_SCANCODES]; +float pos_x, pos_y; +bool button_1, button_2; +#endif + static void* create_window_and_renderer(char* title, int x, int y, int width, int height) { render_width = width; render_height = height; @@ -24,7 +34,9 @@ static void* create_window_and_renderer(char* title, int x, int y, int width, in if (SDL_Init(SDL_INIT_VIDEO) != 0) { LOG_PANIC("SDL_INIT_VIDEO error: %s", SDL_GetError()); } - +#ifdef __3DS__ + consoleInit(GFX_BOTTOM, NULL); +#endif window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, @@ -61,10 +73,12 @@ static void* create_window_and_renderer(char* title, int x, int y, int width, in static int set_window_pos(void* hWnd, int x, int y, int nWidth, int nHeight) { // SDL_SetWindowPosition(hWnd, x, y); +#ifndef __3DS__ if (nWidth == 320 && nHeight == 200) { nWidth = 640; nHeight = 400; } +#endif SDL_SetWindowSize(hWnd, nWidth, nHeight); return 0; } @@ -76,6 +90,97 @@ static void destroy_window(void* hWnd) { window = NULL; } +#ifdef __3DS__ +static int map_3ds_key_to_sdl_scancode(u32 key) { + switch (key) { + case KEY_A: return SDL_SCANCODE_SPACE; + case KEY_B: return SDL_SCANCODE_B; + case KEY_X: return SDL_SCANCODE_X; + case KEY_Y: return SDL_SCANCODE_Y; + case KEY_L: return SDL_SCANCODE_L; +// case KEY_R: return SDL_SCANCODE_R; // used for mouse button instead + case KEY_ZL: return SDL_SCANCODE_MINUS; + case KEY_ZR: return SDL_SCANCODE_EQUALS; + case KEY_START: return SDL_SCANCODE_RETURN; + case KEY_SELECT: return SDL_SCANCODE_ESCAPE; + case KEY_DUP: return SDL_SCANCODE_KP_8; + case KEY_DDOWN: return SDL_SCANCODE_KP_2; + case KEY_DLEFT: return SDL_SCANCODE_KP_4; + case KEY_DRIGHT: return SDL_SCANCODE_KP_6; + + default: return -1; + } +} + +static int get_and_handle_message(MSG_* msg) { + hidScanInput(); + u32 kHeld = hidKeysHeld(); + int dinput_key; + + circlePosition circlePad; + hidCircleRead(&circlePad); + + for (u32 key = KEY_A; key <= KEY_ZR; key <<= 1) { + if (kHeld & key) { + int sdl_scancode = map_3ds_key_to_sdl_scancode(key); + if (sdl_scancode >= 0) { + dinput_key = sdlScanCodeToDirectInputKeyNum[sdl_scancode]; + if (dinput_key == 0) { + LOG_WARN("unexpected scan code %s (%d)", SDL_GetScancodeName(sdl_scancode), sdl_scancode); + continue; + } + directinput_key_state[dinput_key] = 0x80; + } + } else { + int sdl_scancode = map_3ds_key_to_sdl_scancode(key); + if (sdl_scancode >= 0) { + dinput_key = sdlScanCodeToDirectInputKeyNum[sdl_scancode]; + if (dinput_key != 0) { + directinput_key_state[dinput_key] = 0x00; + } + } + } + } + + if (circlePad.dy > 20) { + dinput_key = sdlScanCodeToDirectInputKeyNum[SDL_SCANCODE_UP]; + directinput_key_state[dinput_key] = 0x80; + } else if (circlePad.dy < -20) { + dinput_key = sdlScanCodeToDirectInputKeyNum[SDL_SCANCODE_DOWN]; + directinput_key_state[dinput_key] = 0x80; + } else { + dinput_key = sdlScanCodeToDirectInputKeyNum[SDL_SCANCODE_UP]; + directinput_key_state[dinput_key] = 0x00; + dinput_key = sdlScanCodeToDirectInputKeyNum[SDL_SCANCODE_DOWN]; + directinput_key_state[dinput_key] = 0x00; + } + + if (circlePad.dx > 20) { + dinput_key = sdlScanCodeToDirectInputKeyNum[SDL_SCANCODE_RIGHT]; + directinput_key_state[dinput_key] = 0x80; + } else if (circlePad.dx < -20) { + dinput_key = sdlScanCodeToDirectInputKeyNum[SDL_SCANCODE_LEFT]; + directinput_key_state[dinput_key] = 0x80; + } else { + dinput_key = sdlScanCodeToDirectInputKeyNum[SDL_SCANCODE_RIGHT]; + directinput_key_state[dinput_key] = 0x00; + dinput_key = sdlScanCodeToDirectInputKeyNum[SDL_SCANCODE_LEFT]; + directinput_key_state[dinput_key] = 0x00; + } + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + msg->message = WM_QUIT; + return 1; + } + } + + button_1 = (kHeld & KEY_R); + + return 0; +} +#else // Checks whether the `flag_check` is the only modifier applied. // e.g. is_only_modifier(event.key.keysym.mod, KMOD_ALT) returns true when only the ALT key was pressed static int is_only_key_modifier(int modifier_flags, int flag_check) { @@ -122,21 +227,41 @@ static int get_and_handle_message(MSG_* msg) { } return 0; } +#endif static void get_keyboard_state(unsigned int count, uint8_t* buffer) { memcpy(buffer, directinput_key_state, count); } static int get_mouse_buttons(int* pButton1, int* pButton2) { +#ifdef __3DS__ + *pButton1 = button_1; + *pButton2 = false; +#else int state = SDL_GetMouseState(NULL, NULL); *pButton1 = state & SDL_BUTTON_LMASK; *pButton2 = state & SDL_BUTTON_RMASK; +#endif return 0; } static int get_mouse_position(int* pX, int* pY) { float lX, lY; +#ifdef __3DS__ + touchPosition touch; + hidTouchRead(&touch); +if ((touch.px > 0) && (touch.py > 0)) +{ + pos_x = touch.px; + pos_y = touch.py; +} + + *pX = pos_x; + *pY = pos_y; + +#else SDL_GetMouseState(pX, pY); +#endif SDL_RenderWindowToLogical(renderer, *pX, *pY, &lX, &lY); #if defined(DETHRACE_FIX_BUGS) @@ -202,7 +327,17 @@ static void set_palette(PALETTEENTRY_* pal) { int show_error_message(void* window, char* text, char* caption) { fprintf(stderr, "%s", text); +#ifdef __3DS__ + if (!gspHasGpuRight()) + gfxInitDefault(); + + errorConf msg; + errorInit(&msg, ERROR_TEXT, CFG_LANGUAGE_EN); + errorText(&msg, text); + errorDisp(&msg); +#else SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, caption, text, window); +#endif return 0; }