diff --git a/.gitignore b/.gitignore index f15e789cc4bf..0c8be1977780 100644 --- a/.gitignore +++ b/.gitignore @@ -371,6 +371,5 @@ templates/ # Switch *.nro -*.nacp -/switch/ -/config/nx-hbmenu/ +switch/ +config/nx-hbmenu/ diff --git a/BUILDING-switch.md b/BUILDING-switch.md deleted file mode 100644 index 2c9df475cd51..000000000000 --- a/BUILDING-switch.md +++ /dev/null @@ -1,44 +0,0 @@ -# Building for Nintendo Switch - -These steps must be done under Linux / Windows Subsystem for Linux (WSL) or MSYS2 on Windows. - -## Dependencies - -If you haven't done so already, install the dependencies called for by the [official Godot docs](https://docs.godotengine.org/en/3.5/development/compiling/compiling_for_x11.html) - -1. Install [devkitPro pacman] or add DKP to your existing pacman configuration: -2. Install the required packages from the terminal - ```sh - # On systems without pacman pre-installed (Such as Debian, Ubuntu): - sudo dkp-pacman -S switch-pkg-config switch-freetype switch-bulletphysics switch-libtheora switch-libpcre2 switch-mesa switch-opusfile switch-mbedtls switch-libwebp switch-libvpx switch-miniupnpc switch-libzstd switch-wslay - ``` - OR - ```sh - # On systems with pacman pre-installed (Such as Arch, Manjaro, MSYS2): - sudo pacman -S switch-pkg-config switch-freetype switch-bulletphysics switch-libtheora switch-libpcre2 switch-mesa switch-opusfile switch-mbedtls switch-libwebp switch-libvpx switch-miniupnpc switch-libzstd switch-wslay - -## Building - -1. Run `scons platform=switch` in the root of the repo.
- Add `target=release` to the end to build for release instead of debug. -2. Run `misc/scripts/build/create-switch-release.sh` from inside the `bin` folder - to create an installable release for your Switch. -3. Run `misc/scripts/build/create-switch-template.sh` from inside the `bin` folder - to create an export template for your editor. - -# Exporting for Nintendo Switch - -The [editor releases] add a `Switch` exporter to the list - -it can generate a Switch homebrew NRO or a generic Godot PCK file -that can be transferred to your Switch. - -If additional debugging is required, sending the NRO file via nxlink -(make sure to send it to the right place with the -p argument) -will allow the output of the console to be viewed on PC. - -# Need help? - -Either make an issue on this repo, or join the [Discord](https://discordapp.com/invite/yUC3rUk)! - -[editor releases]:https://github.com/Homebrodot/godot/releases/latest -[devkitPro pacman]:https://devkitpro.org/wiki/devkitPro_pacman diff --git a/BUILDING-vita.md b/BUILDING-vita.md deleted file mode 100644 index 530d78815b46..000000000000 --- a/BUILDING-vita.md +++ /dev/null @@ -1,57 +0,0 @@ -# Building for PS Vita or PS TV - -These steps must be done under Linux / Windows Subsystem for Linux (WSL). - -## Dependencies - -If you haven't done so already, install the dependencies called for by the [official Godot docs](https://docs.godotengine.org/en/3.5/development/compiling/compiling_for_x11.html) - -1. Install [VitaSDK] -
- - ```sh - # Clone and bootstrap - git clone https://github.com/vitasdk/vdpm - cd vdpm - ./bootstrap-vitasdk.sh - # Add to PATH (add this to ~/.bashrc for persistence after reboot) - export VITASDK=/usr/local/vitasdk - export PATH=$VITASDK/bin:$PATH # add vitasdk tool to $PATH - # Finish install - ./install-all.sh - # Update - vitasdk-update - ``` - -
-2. Install [PVR-PSP2] -
- - ```sh - # Clone, build and install - git clone https://github.com/isage/vita-packages-extra - cd vita-packages-extra/pvr_psp2 - vita-makepkg - vdpm *-arm.tar.xz - ``` - -
- -## Building - -1. Run `scons platform=vita` in the root of the repo. - Add `target=release` to the end to build for release instead of debug. - -# Exporting for PS Vita or PS TV - -The [editor releases] add a `Vita` exporter to the list - -it will generate a homebrew VPK file that can be installed on -your PlayStation Vita or PlayStation TV with VitaShell. - -# Need help? - -Either make an issue on this repo, or join the [Discord](https://discordapp.com/invite/yUC3rUk)! - -[editor releases]:https://github.com/Homebrodot/godot/releases/latest -[VitaSDK]:https://vitasdk.org/ -[PVR-PSP2]:https://github.com/GrapheneCt/PVR_PSP2 diff --git a/README-homebrodot.md b/README-homebrodot.md deleted file mode 100644 index 794f746b9cbd..000000000000 --- a/README-homebrodot.md +++ /dev/null @@ -1,56 +0,0 @@ -# Homebrodot - -It's a port of the Godot open source game engine to homebrew platforms, -using homebrew libraries such as LibNX and [VitaSDK]. -See the original [README.md](./README.md) for info about Godot. - -## Releases - -See [the GitHub releases page](https://github.com/Hombrodot/godot/releases) -for pre-built editors for Windows, macOS, and Linux, -and export templates for all supported platforms. - -## How do I export my game? - -Instructions for platforms supported by Homebrodot can be found below. - -- [Nintendo Switch](./BUILDING-switch.md#Exporting-for-Nintendo-Switch) -- [PlayStation Vita / PS TV](./BUILDING-vita.md#Exporting-for-PS-Vita-or-PS-TV) - -Otherwise, please see the [Godot docs]. - -## How to build - -**You shouldn't need to build the engine if you use a release** as the templates should be included - -**these instructions are for engine developers!** - -Please see the [Godot docs] -for compilation instructions for officially Godot platform. -***These are also useful for learning the basic requirements.*** - -Instructions for platforms supported by Homebrodot can be found here: - -- [Nintendo Switch](./BUILDING-switch.md#Building-for-Nintendo-Switch) -- [PlayStation Vita / PS TV](./BUILDING-vita.md#Building-for-PS-Vita-or-PS-TV) - -## How can I get help? - -Either make an issue on this repo, or join the [Discord](https://discord.gg/yUC3rUk "Homebrodot - Godot Homebrew Hub")! - -# Credits - -- Thanks to [@devkitPro] and [@switchbrew] for producing devkitA64/libnx. -- Thanks to the [@VitaSDK] team for producing [VitaSDK]. -- Extra special thanks to [@fincs] from devkitPro.
- The Switch port would have never been possible without their port of the open source nouveau graphics driver. -- Thanks to [@cpasjuste] for help with development. -- Thanks to [@fhidalgosola]/utnad for their Switch port / help with development. - -[@devkitPro]:https://github.com/devkitPro -[@switchbrew]:https://github.com/switchbrew -[@fincs]:https://github.com/fincs -[@cpasjuste]:https://github.com/Cpasjuste -[@fhidalgosola]:https://github.com/fhidalgosola - -[@VitaSDK]:https://github.com/VitaSDK -[VitaSDK]:https://vitasdk.org diff --git a/README-switch.md b/README-switch.md new file mode 100644 index 000000000000..2a6025c9daff --- /dev/null +++ b/README-switch.md @@ -0,0 +1,48 @@ +# Godot for Switch + +It's a port of the Godot open source game engine to the Switch, via homebrew libraries provided by devkitPro/switchbrew. +See the original [README.md](./README.md) for info about Godot. + +## Releases + +See [the GitHub releases page](https://github.com/Homebrodot/Godot/releases) for pre-built editors for Windows, macOS and +Linux. + +## How do I export my game? + +The editor builds above add a `Switch` exporter to the list - it will generate a .nro and a .pck file that can be +transferred to your Switch. +If additional debugging is required, sending the nro via nxlink (make sure to send it to the right place with the -p +argument) will allow the output of the console to be viewed on PC. + +## How to build? + +You shouldn't need to build the engine if you use a release as the templates should be included - these instructions are +for development! + +[See the official docs](https://docs.godotengine.org/en/latest/development/compiling/) +for compilation instructions for every officially supported platform. + +### For Switch: + +Install these packages from [devkitPro pacman](https://devkitpro.org/wiki/devkitPro_pacman): +`switch-pkg-config switch-freetype switch-bulletphysics switch-libtheora switch-libpcre2 switch-mesa switch-opusfile switch-mbedtls switch-libwebp switch-libvpx switch-miniupnpc switch-libzstd switch-wslay` +then run `scons platform=switch` in the root of the repo. Add `target=release` to build for release instead of debug. + +Then, to build an engine release for Switch, +run `./scripts/create-switch-release.sh` in the root of the repo. + +Or to build an export template for the editor, +run `./scripts/create-switch-template.sh` in the root of the repo. + +## How can I get help? + +Either make an issue on this repo, or join the [Discord](https://discord.gg/yUC3rUk "Homebrodot - Godot Homebrew Hub")! + +# Credits + +* Thanks to devkitPro / switchbrew for producing devkitA64/libnx. +* Extra special thanks to fincs from devkitPro - This port would have never been possible without their port of the open + source nouveau graphics driver. +* cpasjuste for help with development. +* fhidalgosola/utnad for their port / help with development. diff --git a/core/os/input.cpp b/core/os/input.cpp index 0943a127d053..932ce56f7ee6 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -86,18 +86,10 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("get_accelerometer"), &Input::get_accelerometer); ClassDB::bind_method(D_METHOD("get_magnetometer"), &Input::get_magnetometer); ClassDB::bind_method(D_METHOD("get_gyroscope"), &Input::get_gyroscope); - ClassDB::bind_method(D_METHOD("get_joy_gravity", "device"), &Input::get_joy_gravity); - ClassDB::bind_method(D_METHOD("get_joy_accelerometer", "device"), &Input::get_joy_accelerometer); - ClassDB::bind_method(D_METHOD("get_joy_magnetometer", "device"), &Input::get_joy_magnetometer); - ClassDB::bind_method(D_METHOD("get_joy_gyroscope", "device"), &Input::get_joy_gyroscope); ClassDB::bind_method(D_METHOD("set_gravity", "value"), &Input::set_gravity); ClassDB::bind_method(D_METHOD("set_accelerometer", "value"), &Input::set_accelerometer); ClassDB::bind_method(D_METHOD("set_magnetometer", "value"), &Input::set_magnetometer); ClassDB::bind_method(D_METHOD("set_gyroscope", "value"), &Input::set_gyroscope); - ClassDB::bind_method(D_METHOD("set_joy_gravity", "device", "value"), &Input::set_joy_gravity); - ClassDB::bind_method(D_METHOD("set_joy_accelerometer", "device", "value"), &Input::set_joy_accelerometer); - ClassDB::bind_method(D_METHOD("set_joy_magnetometer", "device", "value"), &Input::set_joy_magnetometer); - ClassDB::bind_method(D_METHOD("set_joy_gyroscope", "device", "value"), &Input::set_joy_gyroscope); //ClassDB::bind_method(D_METHOD("get_mouse_position"),&Input::get_mouse_position); - this is not the function you want ClassDB::bind_method(D_METHOD("get_last_mouse_speed"), &Input::get_last_mouse_speed); ClassDB::bind_method(D_METHOD("get_mouse_button_mask"), &Input::get_mouse_button_mask); diff --git a/core/os/input.h b/core/os/input.h index b6a2cafcc8ad..f6ae3e57b6b8 100644 --- a/core/os/input.h +++ b/core/os/input.h @@ -117,18 +117,10 @@ class Input : public Object { virtual Vector3 get_accelerometer() const = 0; virtual Vector3 get_magnetometer() const = 0; virtual Vector3 get_gyroscope() const = 0; - virtual Vector3 get_joy_gravity(int p_device) const = 0; - virtual Vector3 get_joy_accelerometer(int p_device) const = 0; - virtual Vector3 get_joy_magnetometer(int p_device) const = 0; - virtual Vector3 get_joy_gyroscope(int p_device) const = 0; virtual void set_gravity(const Vector3 &p_gravity) = 0; virtual void set_accelerometer(const Vector3 &p_accel) = 0; virtual void set_magnetometer(const Vector3 &p_magnetometer) = 0; virtual void set_gyroscope(const Vector3 &p_gyroscope) = 0; - virtual void set_joy_gravity(int p_device, const Vector3 &p_gravity) = 0; - virtual void set_joy_accelerometer(int p_device, const Vector3 &p_accel) = 0; - virtual void set_joy_magnetometer(int p_device, const Vector3 &p_magnetometer) = 0; - virtual void set_joy_gyroscope(int p_device, const Vector3 &p_gyroscope) = 0; virtual void action_press(const StringName &p_action, float p_strength = 1.f) = 0; virtual void action_release(const StringName &p_action) = 0; diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index ad46fcedd866..1d51658a026d 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -62,10 +62,6 @@ The [NavigationServer] singleton. - - The [NintendoSwitch] singleton. - [b]Note:[/b] Only implemented on Nintendo Switch. - The [OS] singleton. diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index e1f94db3988f..70a3baa77c4e 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -105,13 +105,6 @@ [b]Note:[/b] This method only works on Android and iOS. On other platforms, it always returns [constant Vector3.ZERO]. - - - - - Returns the acceleration of the controller's accelerometer sensor, if the controller has one. Otherwise, the method returns [constant Vector3.ZERO]. - - @@ -148,13 +141,6 @@ Receives a gamepad button from [enum JoystickList] and returns its equivalent name as a string. - - - - - Returns the gravity of the controller's accelerometer sensor, if the controller has one. Otherwise, the method returns [constant Vector3.ZERO]. - - @@ -162,20 +148,6 @@ Returns a SDL2-compatible device GUID on platforms that use gamepad remapping, e.g. [code]030000004c050000c405000000010000[/code]. Returns [code]"Default Gamepad"[/code] otherwise. Godot uses the [url=https://github.com/gabomdq/SDL_GameControllerDB]SDL2 game controller database[/url] to determine gamepad names and mappings based on this GUID. - - - - - Returns the rotation rate in rad/s around a controller's X, Y, and Z axes of the gyroscope sensor, if the controller has one. Otherwise, the method returns [constant Vector3.ZERO]. - - - - - - - Returns the magnetic field strength in micro-Tesla for all axes of the controller's magnetometer sensor, if the controller has one. Otherwise, the method returns [constant Vector3.ZERO]. - - @@ -374,53 +346,15 @@ - Sets the value of the rotation rate of the device's gyroscope sensor. - Can be used for debugging on devices without a hardware sensor, for example in an editor on a PC. + Sets the value of the rotation rate of the gyroscope sensor. Can be used for debugging on devices without a hardware sensor, for example in an editor on a PC. [b]Note:[/b] This value can be immediately overwritten by the hardware sensor value on Android and iOS. - - - - - - Sets the acceleration value of the controller's accelerometer sensor. - Can be used for debugging on devices without a hardware sensor, for example in an editor on a PC. - - - - - - - - Sets the gravity value of the controller's accelerometer sensor. - Can be used for debugging on devices without a hardware sensor, for example in an editor on a PC. - - - - - - - - Sets the value of the rotation rate of the controller's gyroscope sensor. - Can be used for debugging on devices without a hardware sensor, for example in an editor on a PC. - - - - - - - - Sets the value of the magnetic field of the controller's magnetometer sensor. - Can be used for debugging on devices without a hardware sensor, for example in an editor on a PC. - - - Sets the value of the magnetic field of the device's magnetometer sensor. - Can be used for debugging on devices without a hardware sensor, for example in an editor on a PC. + Sets the value of the magnetic field of the magnetometer sensor. Can be used for debugging on devices without a hardware sensor, for example in an editor on a PC. [b]Note:[/b] This value can be immediately overwritten by the hardware sensor value on Android and iOS. diff --git a/doc/classes/NintendoSwitch.xml b/doc/classes/NintendoSwitch.xml deleted file mode 100644 index d2b44f684f3c..000000000000 --- a/doc/classes/NintendoSwitch.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - Singleton that adds new functions specific to Nintendo Switch's Horizon OS. - - - The NintendoSwitch singleton is implemented only in the Nintendo Switch export. It's used to access features that are only supported by Horizon OS. - - - - - - - - - - Shows the virtual keyboard of the type specified. - The [code]existing_text[/code] parameter is useful for implementing your own [LineEdit] or [TextEdit], as it tells the virtual keyboard what text has already been typed. - - - - - - Normal keyboard. - - - Number pad. - - - QWERTY (and variants) keyboard only. - - - All Latin like languages keyboard only (without CJK keyboard). - - - Chinese Simplified keyboard only. - - - Chinese Traditional keyboard only. - - - Korean keyboard only. - - - All language keyboards. - - - diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 8404972b4967..10b53e76c74d 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -1019,7 +1019,7 @@ Shows the virtual keyboard if the platform has one. The [code]existing_text[/code] parameter is useful for implementing your own [LineEdit] or [TextEdit], as it tells the virtual keyboard what text has already been typed (the virtual keyboard uses it for auto-correct and predictions). The [code]multiline[/code] parameter needs to be set to [code]true[/code] to be able to enter multiple lines of text, as in [TextEdit]. - [b]Note:[/b] This method is implemented on Android, iOS, UWP, Nintendo Switch, and PlayStation Vita. + [b]Note:[/b] This method is implemented on Android, iOS and UWP. diff --git a/drivers/SCsub b/drivers/SCsub index 36c5bb909462..890877981874 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -10,8 +10,6 @@ SConscript("windows/SCsub") # Sounds drivers SConscript("alsa/SCsub") -if env["platform"] == "switch": - SConscript("audren/SCsub") SConscript("coreaudio/SCsub") SConscript("pulseaudio/SCsub") if env["platform"] == "windows": diff --git a/drivers/audren/SCsub b/drivers/audren/SCsub deleted file mode 100644 index 783e725ea283..000000000000 --- a/drivers/audren/SCsub +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env python - -Import("env") - -# Driver source files -env.add_source_files(env.drivers_sources, "audio_driver_audren.cpp") diff --git a/drivers/audren/audio_driver_audren.cpp b/drivers/audren/audio_driver_audren.cpp deleted file mode 100644 index 6a53251d4e57..000000000000 --- a/drivers/audren/audio_driver_audren.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/**************************************************************************/ -/* audio_driver_audren.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#include "audio_driver_audren.h" - -#include "core/os/os.h" -#include "core/project_settings.h" - -#include -#include - -static const AudioRendererConfig arConfig = { - .output_rate = AudioRendererOutputRate_48kHz, - .num_voices = 24, - .num_effects = 0, - .num_sinks = 1, - .num_mix_objs = 1, - .num_mix_buffers = 2, -}; - -Error AudioDriverAudren::init_device() { - int latency = GLOBAL_GET("audio/output_latency"); - mix_rate = GLOBAL_GET("audio/mix_rate"); - channels = 2; - speaker_mode = SPEAKER_MODE_STEREO; - buffer_size = closest_power_of_2(latency * mix_rate / 1000); - samples_in.resize(buffer_size * channels); - samples_out.resize(buffer_size * channels); - - Result res = audrenInitialize(&arConfig); - printf("audrenInitialize: %x\n", res); - res = audrvCreate(&audren_driver, &arConfig, 2); - printf("audrenInitialize: %x\n", res); - - audren_buffer_size = (sizeof(int16_t) * buffer_size * channels); - audren_pool_size = ((audren_buffer_size * 2) + 0xFFF) & ~0xFFF; - audren_pool_ptr = memalign(0x1000, audren_pool_size); - - for (int i = 0; i < 2; i++) { - audren_buffers[i] = { 0 }; - audren_buffers[i].data_raw = audren_pool_ptr; - audren_buffers[i].size = audren_buffer_size * 2; - audren_buffers[i].start_sample_offset = i * buffer_size; - audren_buffers[i].end_sample_offset = audren_buffers[i].start_sample_offset + buffer_size; - } - - int mpid = audrvMemPoolAdd(&audren_driver, audren_pool_ptr, audren_pool_size); - audrvMemPoolAttach(&audren_driver, mpid); - - static const u8 sink_channels[] = { 0, 1 }; - audrvDeviceSinkAdd(&audren_driver, AUDREN_DEFAULT_DEVICE_NAME, 2, sink_channels); - - res = audrvUpdate(&audren_driver); - printf("audrvUpdate: %x\n", res); - - res = audrenStartAudioRenderer(); - printf("audrenStartAudioRenderer: %x\n", res); - - audrvVoiceInit(&audren_driver, 0, channels, PcmFormat_Int16, mix_rate); - audrvVoiceSetDestinationMix(&audren_driver, 0, AUDREN_FINAL_MIX_ID); - if (channels == 1) { - audrvVoiceSetMixFactor(&audren_driver, 0, 1.0f, 0, 0); - audrvVoiceSetMixFactor(&audren_driver, 0, 1.0f, 0, 1); - } else { - audrvVoiceSetMixFactor(&audren_driver, 0, 1.0f, 0, 0); - audrvVoiceSetMixFactor(&audren_driver, 0, 0.0f, 0, 1); - audrvVoiceSetMixFactor(&audren_driver, 0, 0.0f, 1, 0); - audrvVoiceSetMixFactor(&audren_driver, 0, 1.0f, 1, 1); - } - - return OK; -} - -Error AudioDriverAudren::init() { - active = false; - thread_exited = false; - exit_thread = false; - - Error err = init_device(); - if (err == OK) { - thread.start(AudioDriverAudren::thread_func, this); - } - - return err; -} - -void AudioDriverAudren::thread_func(void *p_udata) { - AudioDriverAudren *ad = (AudioDriverAudren *)p_udata; - - svcSetThreadPriority(CUR_THREAD_HANDLE, 0x2B); - - while (!ad->exit_thread) { - ad->lock(); - ad->start_counting_ticks(); - - if (!ad->active) { - for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) { - ad->samples_out.write[i] = 0; - } - } else { - ad->audio_server_process(ad->buffer_size, ad->samples_in.ptrw()); - for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) { - ad->samples_out.write[i] = ad->samples_in[i] >> 16; - } - } - - int free_buffer = -1; - for (int i = 0; i < 2; i++) { - if (ad->audren_buffers[i].state == AudioDriverWaveBufState_Free || ad->audren_buffers[i].state == AudioDriverWaveBufState_Done) { - free_buffer = i; - break; - } - } - - if (free_buffer >= 0) { - uint8_t *ptr = (uint8_t *)ad->audren_pool_ptr + (free_buffer * ad->audren_buffer_size); - memcpy(ptr, ad->samples_out.ptr(), ad->audren_buffer_size); - armDCacheFlush(ptr, ad->audren_buffer_size); - audrvVoiceAddWaveBuf(&ad->audren_driver, 0, &ad->audren_buffers[free_buffer]); - if (!audrvVoiceIsPlaying(&ad->audren_driver, 0)) { - audrvVoiceStart(&ad->audren_driver, 0); - } - audrvUpdate(&ad->audren_driver); - audrenWaitFrame(); - while (ad->audren_buffers[free_buffer].state != AudioDriverWaveBufState_Playing) { - audrvUpdate(&ad->audren_driver); - } - } else { - //printf("aud: no free buffer\n"); - ad->stop_counting_ticks(); - ad->unlock(); - OS::get_singleton()->delay_usec(1000); - ad->lock(); - ad->start_counting_ticks(); - } - - ad->stop_counting_ticks(); - ad->unlock(); - } - - ad->thread_exited = true; -} - -void AudioDriverAudren::start() { - active = true; -} - -int AudioDriverAudren::get_mix_rate() const { - return mix_rate; -} - -AudioDriver::SpeakerMode AudioDriverAudren::get_speaker_mode() const { - return speaker_mode; -} - -Array AudioDriverAudren::get_device_list() { - Array list; - list.push_back("Default"); - return list; -} - -String AudioDriverAudren::get_device() { - return device_name; -} - -void AudioDriverAudren::set_device(String device) { - lock(); - new_device = device; - unlock(); -} - -void AudioDriverAudren::lock() { - mutex.lock(); -} - -void AudioDriverAudren::unlock() { - mutex.unlock(); -} - -void AudioDriverAudren::finish() { - exit_thread = true; - thread.wait_to_finish(); - - audrvClose(&audren_driver); - audrenExit(); -} - -AudioDriverAudren::AudioDriverAudren() : - device_name("Default"), - new_device("Default") { -} - -AudioDriverAudren::~AudioDriverAudren() { -} diff --git a/drivers/audren/audio_driver_audren.h b/drivers/audren/audio_driver_audren.h deleted file mode 100644 index c0604b8c120a..000000000000 --- a/drivers/audren/audio_driver_audren.h +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************************/ -/* audio_driver_audren.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#pragma once -#ifndef AUDIO_DRIVER_AUDREN_H -#define AUDIO_DRIVER_AUDREN_H - -#include "servers/audio_server.h" -#include "switch_wrapper.h" - -#include "core/os/mutex.h" -#include "core/os/thread.h" - -class AudioDriverAudren : public AudioDriver { - Thread thread; - Mutex mutex; - - LibnxAudioDriver audren_driver; - AudioDriverWaveBuf audren_buffers[2]; - size_t audren_pool_size; - void *audren_pool_ptr; - unsigned int audren_buffer_size; - unsigned int buffer_size; - Vector samples_in; - Vector samples_out; - - String device_name; - String new_device; - - Error init_device(); - void finish_device(); - - static void thread_func(void *p_udata); - - unsigned int mix_rate; - SpeakerMode speaker_mode; - int channels; - - bool active; - bool thread_exited; - mutable bool exit_thread; - -public: - const char *get_name() const { - return "AUDREN"; - }; - - virtual Error init(); - virtual void start(); - virtual int get_mix_rate() const; - virtual SpeakerMode get_speaker_mode() const; - virtual Array get_device_list(); - virtual String get_device(); - virtual void set_device(String device); - virtual void lock(); - virtual void unlock(); - virtual void finish(); - - AudioDriverAudren(); - ~AudioDriverAudren(); -}; - -#endif // !AUDIO_DRIVER_AUDREN_H diff --git a/main/input_default.cpp b/main/input_default.cpp index 4ce3ab687ec3..8a0635c5f44c 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -205,26 +205,6 @@ float InputDefault::get_joy_axis(int p_device, int p_axis) const { } } -Vector3 InputDefault::get_joy_gravity(int p_device) const { - _THREAD_SAFE_METHOD_ - return gravity; -} - -Vector3 InputDefault::get_joy_accelerometer(int p_device) const { - _THREAD_SAFE_METHOD_ - return accelerometer; -} - -Vector3 InputDefault::get_joy_magnetometer(int p_device) const { - _THREAD_SAFE_METHOD_ - return magnetometer; -} - -Vector3 InputDefault::get_joy_gyroscope(int p_device) const { - _THREAD_SAFE_METHOD_ - return gyroscope; -} - String InputDefault::get_joy_name(int p_idx) { _THREAD_SAFE_METHOD_ return joy_names[p_idx].name; @@ -519,30 +499,6 @@ void InputDefault::set_joy_axis(int p_device, int p_axis, float p_value) { _joy_axis[c] = p_value; } -void InputDefault::set_joy_gravity(int p_device, const Vector3 &p_gravity) { - _THREAD_SAFE_METHOD_ - - gravity = p_gravity; -} - -void InputDefault::set_joy_accelerometer(int p_device, const Vector3 &p_accel) { - _THREAD_SAFE_METHOD_ - - accelerometer = p_accel; -} - -void InputDefault::set_joy_magnetometer(int p_device, const Vector3 &p_magnetometer) { - _THREAD_SAFE_METHOD_ - - magnetometer = p_magnetometer; -} - -void InputDefault::set_joy_gyroscope(int p_device, const Vector3 &p_gyroscope) { - _THREAD_SAFE_METHOD_ - - gyroscope = p_gyroscope; -} - void InputDefault::start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration) { _THREAD_SAFE_METHOD_ if (p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) { diff --git a/main/input_default.h b/main/input_default.h index aa6e1677d051..00905ac19db4 100644 --- a/main/input_default.h +++ b/main/input_default.h @@ -226,10 +226,6 @@ class InputDefault : public Input { virtual float get_action_raw_strength(const StringName &p_action, bool p_exact = false) const; virtual float get_joy_axis(int p_device, int p_axis) const; - virtual Vector3 get_joy_gravity(int p_device) const; - virtual Vector3 get_joy_accelerometer(int p_device) const; - virtual Vector3 get_joy_magnetometer(int p_device) const; - virtual Vector3 get_joy_gyroscope(int p_device) const; String get_joy_name(int p_idx); virtual Array get_connected_joypads(); virtual Vector2 get_joy_vibration_strength(int p_device); @@ -256,10 +252,6 @@ class InputDefault : public Input { virtual void set_magnetometer(const Vector3 &p_magnetometer); virtual void set_gyroscope(const Vector3 &p_gyroscope); void set_joy_axis(int p_device, int p_axis, float p_value); - virtual void set_joy_gravity(int p_device, const Vector3 &p_gravity); - virtual void set_joy_accelerometer(int p_device, const Vector3 &p_accel); - virtual void set_joy_magnetometer(int p_device, const Vector3 &p_magnetometer); - virtual void set_joy_gyroscope(int p_device, const Vector3 &p_gyroscope); virtual void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0); virtual void stop_joy_vibration(int p_device); diff --git a/platform/switch/SCsub b/platform/switch/SCsub index e190389ec04d..83fad068a4ef 100644 --- a/platform/switch/SCsub +++ b/platform/switch/SCsub @@ -7,7 +7,9 @@ Import("env") files = [ "godot_switch.cpp", "os_switch.cpp", + "power_switch.cpp", "joypad_switch.cpp", + "audio_driver_switch.cpp", "context_gl_switch_egl.cpp", ] diff --git a/platform/switch/api/api.cpp b/platform/switch/api/api.cpp deleted file mode 100644 index ca6a8fe4e9a4..000000000000 --- a/platform/switch/api/api.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/**************************************************************************/ -/* api.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#include "api.h" -#ifdef HORIZON_ENABLED -#include "os_switch.h" -#endif // HORIZON_ENABLED -#include "switch_singleton.h" - -#include "core/engine.h" -#include "core/os/keyboard.h" - -// === === === -// === API === -// === === === - -static NintendoSwitch *switch_eval; - -void register_switch_api() { - ClassDB::register_virtual_class(); - switch_eval = memnew(NintendoSwitch); - Engine::get_singleton()->add_singleton(Engine::Singleton("NintendoSwitch", switch_eval)); -} - -void unregister_switch_api() { - memdelete(switch_eval); -} - -// === === === === === === === === === -// === Nintendo Switch Singleton === -// === === === === === === === === === - -bool g_swkbd_open = false; - -NintendoSwitch *NintendoSwitch::singleton = nullptr; - -NintendoSwitch *NintendoSwitch::get_singleton() { - return singleton; -} - -NintendoSwitch::NintendoSwitch() { - ERR_FAIL_COND_MSG(singleton != nullptr, "NintendoSwitch singleton already exists."); - singleton = this; -#ifdef HORIZON_ENABLED - swkbdInlineCreate(&inline_keyboard); -#endif // HORIZON_ENABLED -} - -void NintendoSwitch::_bind_methods() { - ClassDB::bind_method(D_METHOD("show_virtual_keyboard", "existing_text", "type"), &NintendoSwitch::show_virtual_keyboard, DEFVAL(""), DEFVAL(NORMAL_KEYBOARD)); - - BIND_ENUM_CONSTANT(NORMAL_KEYBOARD) - BIND_ENUM_CONSTANT(NUMPAD_KEYBOARD) - BIND_ENUM_CONSTANT(QWERTY_KEYBOARD) - BIND_ENUM_CONSTANT(LATIN_KEYBOARD) - BIND_ENUM_CONSTANT(SIMPLIFIED_CHINESE_KEYBOARD) - BIND_ENUM_CONSTANT(TRADITIONAL_CHINESE_KEYBOARD) - BIND_ENUM_CONSTANT(KOREAN_KEYBOARD) - BIND_ENUM_CONSTANT(ALL_LANGUAGES_KEYBOARD) -} - -#ifdef HORIZON_ENABLED -int g_eat_string_events = 0; - -u32 last_length = 0; -void keyboard_string_changed_callback(const char *str, SwkbdChangedStringArg *arg) { - // Adjusted for NUL-terminator - u32 string_length = arg->stringLen + 3; - - // We get a string changed event on appear, and another one on setting text. - if (g_eat_string_events) { - last_length = string_length; - g_eat_string_events--; - return; - } - - if (string_length < last_length) { - OS_Switch::get_singleton()->key(KEY_BACKSPACE, true); - } else if (string_length > 0) { - OS_Switch::get_singleton()->key(str[string_length - 1], true); - } - last_length = string_length; -} - -int last_cursor = 0; -void keyboard_moved_cursor_callback(const char *str, SwkbdMovedCursorArg *arg) { - if (arg->cursorPos < last_cursor) { - OS_Switch::get_singleton()->key(KEY_LEFT, true); - } else { - OS_Switch::get_singleton()->key(KEY_RIGHT, true); - } - - last_cursor = arg->cursorPos; -} - -void keyboard_decided_enter_callback(const char *str, SwkbdDecidedEnterArg *arg) { - OS_Switch::get_singleton()->key(KEY_ENTER, true); - - g_swkbd_open = false; -} - -void keyboard_decided_cancel_callback() { - g_swkbd_open = false; -} -#endif // HORIZON_ENABLED - -void NintendoSwitch::initialize_software_keyboard() { -#ifdef HORIZON_ENABLED - swkbdInlineLaunchForLibraryApplet(&inline_keyboard, SwkbdInlineMode_AppletDisplay, 0); - swkbdInlineSetChangedStringCallback(&inline_keyboard, keyboard_string_changed_callback); - swkbdInlineSetMovedCursorCallback(&inline_keyboard, keyboard_moved_cursor_callback); - swkbdInlineSetDecidedEnterCallback(&inline_keyboard, keyboard_decided_enter_callback); - swkbdInlineSetDecidedCancelCallback(&inline_keyboard, keyboard_decided_cancel_callback); -#endif // HORIZON_ENABLED -} - -void NintendoSwitch::update() { -#ifdef HORIZON_ENABLED - swkbdInlineUpdate(&inline_keyboard, NULL); -#endif // HORIZON_ENABLED -} - -void NintendoSwitch::show_virtual_keyboard(const String &p_existing_text, SoftwareKeyboardType p_type) { -#ifdef HORIZON_ENABLED - if (!g_swkbd_open) { - SwkbdAppearArg appear_arg; - swkbdInlineMakeAppearArg(&appear_arg, (SwkbdType)p_type); - swkbdInlineSetInputText(&inline_keyboard, p_existing_text.utf8().get_data()); - swkbdInlineSetCursorPos(&inline_keyboard, p_existing_text.size() - 1); - - swkbdInlineAppear(&inline_keyboard, &appear_arg); - - g_eat_string_events = 2; - g_swkbd_open = true; - } -#endif // HORIZON_ENABLED -} - -void NintendoSwitch::hide_virtual_keyboard() { -#ifdef HORIZON_ENABLED - swkbdInlineDisappear(&inline_keyboard); - g_swkbd_open = false; -#endif // HORIZON_ENABLED -} - -bool NintendoSwitch::is_virtual_keyboard_open() { - return g_swkbd_open; -} - -void NintendoSwitch::cleanup() { -#ifdef HORIZON_ENABLED - swkbdInlineClose(&inline_keyboard); -#endif // HORIZON_ENABLED -} diff --git a/platform/switch/api/api.h b/platform/switch/api/api.h deleted file mode 100644 index 065a2448300e..000000000000 --- a/platform/switch/api/api.h +++ /dev/null @@ -1,41 +0,0 @@ -/**************************************************************************/ -/* api.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#ifndef SWITCH_API_H -#define SWITCH_API_H - -#ifndef MODULE_MONO_ENABLED - -void register_switch_api(); -void unregister_switch_api(); - -#endif // MODULE_MONO_ENABLED` - -#endif // SWITCH_API_H diff --git a/platform/switch/api/switch_singleton.h b/platform/switch/api/switch_singleton.h deleted file mode 100644 index dcf1a6dfbc1c..000000000000 --- a/platform/switch/api/switch_singleton.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************/ -/* switch_singleton.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#ifndef SWITCH_SINGLETON_H -#define SWITCH_SINGLETON_H - -#ifndef MODULE_MONO_ENABLED - -#include "core/object.h" -#include "core/variant.h" -#ifdef HORIZON_ENABLED -#include "switch_wrapper.h" -#endif // HORIZON_ENABLED - -class NintendoSwitch : public Object { - GDCLASS(NintendoSwitch, Object); - -public: - enum SoftwareKeyboardType { - NORMAL_KEYBOARD = 0, - NUMPAD_KEYBOARD = 1, - QWERTY_KEYBOARD = 2, - LATIN_KEYBOARD = 4, - SIMPLIFIED_CHINESE_KEYBOARD = 5, - TRADITIONAL_CHINESE_KEYBOARD = 6, - KOREAN_KEYBOARD = 7, - ALL_LANGUAGES_KEYBOARD = 8, - }; - - int g_eat_string_events = 0; -#ifdef HORIZON_ENABLED - SwkbdInline inline_keyboard; -#endif // HORIZON_ENABLED - -protected: - static NintendoSwitch *singleton; - - static void _bind_methods(); - -public: - static NintendoSwitch *get_singleton(); - - void initialize_software_keyboard(); - void update(); - void show_virtual_keyboard(const String &p_existing_text, SoftwareKeyboardType p_type); - void hide_virtual_keyboard(); - bool is_virtual_keyboard_open(); - - void cleanup(); - - NintendoSwitch(); -}; - -VARIANT_ENUM_CAST(NintendoSwitch::SoftwareKeyboardType); - -#endif // MODULE_MONO_ENABLED - -#endif // SWITCH_SINGLETON_H diff --git a/platform/switch/export/export.cpp b/platform/switch/export/export.cpp index 6673d0c17f03..9a275a638f2f 100644 --- a/platform/switch/export/export.cpp +++ b/platform/switch/export/export.cpp @@ -36,14 +36,93 @@ #include "core/io/packet_peer_udp.h" #include "core/os/file_access.h" +#include "core/os/thread.h" +#include "core/os/mutex.h" #include "editor/editor_export.h" #include "editor/editor_node.h" #include "platform/switch/logo.gen.h" #include "scene/resources/texture.h" +#ifdef WINDOWS_ENABLED +#include +#include +#endif + #define TEMPLATE_RELEASE "switch_release.nro" #define TEMPLATE_APPLET_SPLASH "switch_applet_splash.rgba.gz" +// NXLink output streaming using proper stdout capture +class NXLinkStreamThread { +private: + Thread thread; + Mutex mutex; + bool running; + String nxlink_path; + List nxlink_args; + String tmp_pack_path; // Store the path to clean up later + +public: + NXLinkStreamThread() : running(false) {} + + void start(const String &p_nxlink_path, const List &p_args, const String &p_tmp_pack_path) { + if (running) return; + + nxlink_path = p_nxlink_path; + nxlink_args = p_args; + tmp_pack_path = p_tmp_pack_path; + running = true; + thread.start(_thread_function, this); + } + + void stop() { + if (!running) return; + + running = false; + thread.wait_to_finish(); + } + + bool is_running() const { return running; } + +private: + static void _thread_function(void *p_userdata) { + NXLinkStreamThread *self = (NXLinkStreamThread *)p_userdata; + self->_run(); + } + + void _run() { + // Build the nxlink command string + String command = nxlink_path; + for (List::Element *E = nxlink_args.front(); E; E = E->next()) { + command += " " + E->get(); + } + + print_line("Executing nxlink with real-time output capture..."); + print_line("NXLink command: " + command); + + // Run nxlink directly without capturing output to avoid UI issues + // This will open a separate console window like command prompt + print_line("Starting nxlink in separate console window..."); + print_line("Check the new console window for nxlink output"); + + // Use start command to open nxlink in a new console window + String start_command = "start " + command; + int result = system(start_command.utf8().ptr()); + + // Wait a moment for the console to open + OS::get_singleton()->delay_usec(1000000); // 1 second + + print_line("nxlink started in separate console window"); + + // Clean up the temporary file + if (!tmp_pack_path.empty()) { + DirAccess::remove_file_or_error(tmp_pack_path); + print_line("Cleaned up temporary export file"); + } + + print_line("=== NXLINK PROCESS COMPLETED ==="); + } +}; + class ExportPluginSwitch : public EditorExportPlugin { public: Vector editor_id_vec; @@ -68,6 +147,7 @@ class EditorExportPlatformSwitch : public EditorExportPlatform { volatile bool quit_request; ExportPluginSwitch *export_plugin; + NXLinkStreamThread *nxlink_thread; static void _device_poll_thread(void *ud) { EditorExportPlatformSwitch *ea = (EditorExportPlatformSwitch *)ud; @@ -223,18 +303,27 @@ class EditorExportPlatformSwitch : public EditorExportPlatform { return ERR_SKIP; } - String tmp_pack_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport.pck"); + // Export the full .nro file instead of just a .pck + String tmp_nro_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport.nro"); - Error err = save_pack(p_preset, tmp_pack_path); + Error err = export_project(p_preset, true, tmp_nro_path, p_debug_flags); if (err != OK) { - DirAccess::remove_file_or_error(tmp_pack_path); + DirAccess::remove_file_or_error(tmp_nro_path); return err; } + + // Verify the .nro file was created + if (!FileAccess::exists(tmp_nro_path)) { + print_line("ERROR: .nro file was not created at: " + tmp_nro_path); + return ERR_FILE_NOT_FOUND; + } + + print_line("Successfully created .nro file: " + tmp_nro_path); print_line("Sending..."); if (ep.step("Sending...", 1)) { - DirAccess::remove_file_or_error(tmp_pack_path); + DirAccess::remove_file_or_error(tmp_nro_path); return err; } @@ -249,29 +338,41 @@ class EditorExportPlatformSwitch : public EditorExportPlatform { } if (FileAccess::exists(nxlink)) { + // Check if nxlink is already running + if (nxlink_thread && nxlink_thread->is_running()) { + print_line("NXLink is already running. Please wait for the current session to end."); + return OK; + } + List args; int ec; - - args.push_back(tmp_pack_path); - args.push_back("-a"); - args.push_back(devices[p_device]); - args.push_back("-p"); - args.push_back("TempExport.pck"); - args.push_back("--args"); - - Vector inner_args; - // todo: editor arg - inner_args.push_back("-v"); - - gen_export_flags(inner_args, p_debug_flags); - args.push_back(String(" ").join(inner_args)); - - OS::get_singleton()->execute(nxlink, args, true, NULL, NULL, &ec); + String pipe_output; + + args.push_back("-s"); // Enable server mode for real-time debugging + args.push_back(tmp_nro_path); + + // Game arguments are not needed for nxlink - they're passed to the game itself + // nxlink just needs the -s flag and the nro file path + + // Create and start nxlink streaming thread + nxlink_thread = memnew(NXLinkStreamThread); + print_line("Starting nxlink with remote debugging..."); + print_line("=== NXLINK OUTPUT ==="); + + nxlink_thread->start(nxlink, args, tmp_nro_path); + + // Give nxlink a moment to start + OS::get_singleton()->delay_usec(2000000); // 2 seconds + + print_line("=== NXLINK STREAMING STARTED ==="); + print_line("Real-time debug output will appear below as the game runs on Switch."); + print_line("The nxlink stream will continue until the game exits or you close Godot."); } else { EditorNode::get_singleton()->show_warning(TTR("nxlink binary not found! Set its path in Editor Settings.")); } - DirAccess::remove_file_or_error(tmp_pack_path); + // Don't remove the file immediately - let nxlink use it + // The file will be cleaned up when the thread ends return OK; } @@ -568,12 +669,19 @@ class EditorExportPlatformSwitch : public EditorExportPlatform { export_plugin = memnew(ExportPluginSwitch); EditorExport::get_singleton()->add_export_plugin(export_plugin); + nxlink_thread = nullptr; } ~EditorExportPlatformSwitch() { quit_request = true; device_thread.wait_to_finish(); + // Stop nxlink thread if running + if (nxlink_thread && nxlink_thread->is_running()) { + nxlink_thread->stop(); + memdelete(nxlink_thread); + } + // DO NOT free it //memdelete(export_plugin); } diff --git a/platform/switch/export/export.h b/platform/switch/export/export.h index 88d2799df9ee..288ca0ad1064 100644 --- a/platform/switch/export/export.h +++ b/platform/switch/export/export.h @@ -28,11 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef SWITCH_EXPORT_H -#define SWITCH_EXPORT_H - -#ifndef MODULE_MONO_ENABLED - #include "thirdparty/libnx/nacp.h" #include "thirdparty/libnx/nro.h" #include @@ -43,7 +38,3 @@ unsigned char *read_bytes(const char *fn, size_t off, size_t len); size_t write_bytes(const char *fn, size_t off, size_t len, const unsigned char *data); void register_switch_exporter(); - -#endif // !MODULE_MONO_ENABLED - -#endif // !SWITCH_EXPORT_H diff --git a/platform/switch/os_switch.cpp b/platform/switch/os_switch.cpp index 554a90df8534..917e3ee1e6c6 100644 --- a/platform/switch/os_switch.cpp +++ b/platform/switch/os_switch.cpp @@ -77,13 +77,13 @@ void OS_Switch::initialize_core() { } void OS_Switch::swap_buffers() { -#ifdef OPENGL_ENABLED +#if defined(OPENGL_ENABLED) gl_context->swap_buffers(); #endif } Error OS_Switch::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { -#ifdef OPENGL_ENABLED +#if defined(OPENGL_ENABLED) bool gles3_context = true; if (p_video_driver == VIDEO_DRIVER_GLES2) { gles3_context = false; @@ -144,8 +144,8 @@ Error OS_Switch::initialize(const VideoMode &p_desired, int p_video_driver, int } if (gl_initialization_error) { - OS::get_singleton()->alert("Your firmware does not support any of the supported OpenGL versions.\n" - "Please update your custom firmware to install the latest OpenGL driver.", + OS::get_singleton()->alert("Your video card driver does not support any of the supported OpenGL versions.\n" + "Please update your drivers or if you have a very old or integrated GPU upgrade it.", "Unable to initialize Video driver"); return ERR_UNAVAILABLE; } @@ -170,12 +170,12 @@ Error OS_Switch::initialize(const VideoMode &p_desired, int p_video_driver, int } joypad = memnew(JoypadSwitch(input)); - if (R_SUCCEEDED(psmInitialize())) { - OS_Switch::psm_initialized = true; - } + power_manager = memnew(PowerSwitch); AudioDriverManager::initialize(p_audio_driver); + //_ensure_user_data_dir(); + return OK; } @@ -191,14 +191,12 @@ void OS_Switch::delete_main_loop() { } void OS_Switch::finalize() { - NintendoSwitch::get_singleton()->cleanup(); - memdelete(input); memdelete(joypad); visual_server->finish(); memdelete(visual_server); + memdelete(power_manager); memdelete(gl_context); - psmExit(); } void OS_Switch::finalize_core() { @@ -209,16 +207,11 @@ bool OS_Switch::_check_internal_feature_support(const String &p_feature) { //TODO support etc2 only if GLES3 driver is selected return true; } - if (p_feature == "arm64-v8a") { - return true; - } return false; } void OS_Switch::alert(const String &p_alert, const String &p_title) { - ErrorApplicationConfig config; - errorApplicationCreate(&config, p_title.utf8().ptr(), p_alert.utf8().ptr()); - errorApplicationShow(&config); + printf("got alert %ls", p_alert.c_str()); } String OS_Switch::get_stdin_string(bool p_block) { return ""; @@ -308,72 +301,16 @@ MainLoop *OS_Switch::get_main_loop() const { return main_loop; } -/// From os_unix.cpp -OS::Date OS_Switch::get_date(bool utc) const { - time_t t = time(nullptr); - struct tm lt; - if (utc) { - gmtime_r(&t, <); - } else { - localtime_r(&t, <); - } - Date ret; - ret.year = 1900 + lt.tm_year; - // Index starting at 1 to match OS_Unix::get_date - // and Windows SYSTEMTIME and tm_mon follows the typical structure - // of 0-11, noted here: http://www.cplusplus.com/reference/ctime/tm/ - ret.month = (Month)(lt.tm_mon + 1); - ret.day = lt.tm_mday; - ret.weekday = (Weekday)lt.tm_wday; - ret.dst = lt.tm_isdst; - - return ret; -} - -/// From os_unix.cpp -OS::Time OS_Switch::get_time(bool utc) const { - time_t t = time(nullptr); - struct tm lt; - if (utc) { - gmtime_r(&t, <); - } else { - localtime_r(&t, <); - } - Time ret; - ret.hour = lt.tm_hour; - ret.min = lt.tm_min; - ret.sec = lt.tm_sec; - get_time_zone_info(); - return ret; +OS::Date OS_Switch::get_date(bool local) const { + return OS::Date(); } -/// From os_unix.cpp -OS::TimeZoneInfo OS_Switch::get_time_zone_info() const { - time_t t = time(nullptr); - struct tm lt; - localtime_r(&t, <); - char name[16]; - strftime(name, 16, "%Z", <); - name[15] = 0; - TimeZoneInfo ret; - ret.name = name; - - char bias_buf[16]; - strftime(bias_buf, 16, "%z", <); - int bias; - bias_buf[15] = 0; - sscanf(bias_buf, "%d", &bias); - - // convert from ISO 8601 (1 minute=1, 1 hour=100) to minutes - int hour = (int)bias / 100; - int minutes = bias % 100; - if (bias < 0) { - ret.bias = hour * 60 - minutes; - } else { - ret.bias = hour * 60 + minutes; - } +OS::Time OS_Switch::get_time(bool local) const { + return OS::Time(); +} - return ret; +OS::TimeZoneInfo OS_Switch::get_time_zone_info() const { + return OS::TimeZoneInfo(); } void OS_Switch::delay_usec(uint32_t p_usec) const { @@ -392,6 +329,46 @@ bool OS_Switch::can_draw() const { void OS_Switch::set_cursor_shape(CursorShape p_shape) {} void OS_Switch::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {} +bool g_swkbd_open = false; +int g_eat_string_events = 0; +u32 last_len = 0; +s32 last_cursor = 0; + +void keyboard_string_changed_callback(const char *str, SwkbdChangedStringArg *arg) { + // We get a string changed event on appear, and another one on setting text. + if (g_eat_string_events) { + last_len = arg->stringLen; + g_eat_string_events--; + return; + } + + if (arg->stringLen < last_len) { + OS_Switch::get_singleton()->key(KEY_BACKSPACE, true); + } else if (arg->stringLen != 0) { + OS_Switch::get_singleton()->key(str[arg->stringLen - 1], true); + } + last_len = arg->stringLen; +} + +void keyboard_moved_cursor_callback(const char *str, SwkbdMovedCursorArg *arg) { + if (arg->cursorPos < last_cursor) { + OS_Switch::get_singleton()->key(KEY_LEFT, true); + } else { + OS_Switch::get_singleton()->key(KEY_RIGHT, true); + } + + last_cursor = arg->cursorPos; +} + +void keyboard_decided_enter_callback(const char *str, SwkbdDecidedEnterArg *arg) { + OS_Switch::get_singleton()->key(KEY_ENTER, true); + g_swkbd_open = false; +} + +void keyboard_decided_cancel_callback() { + g_swkbd_open = false; +} + void OS_Switch::key(uint32_t p_key, bool p_pressed) { Ref ev; ev.instance(); @@ -404,13 +381,17 @@ void OS_Switch::key(uint32_t p_key, bool p_pressed) { void OS_Switch::run() { if (!main_loop) { - TRACE("No main loop?\n"); + TRACE("no main loop???\n"); return; } main_loop->init(); - NintendoSwitch::get_singleton()->initialize_software_keyboard(); + swkbdInlineLaunchForLibraryApplet(&inline_keyboard, SwkbdInlineMode_AppletDisplay, 0); + swkbdInlineSetChangedStringCallback(&inline_keyboard, keyboard_string_changed_callback); + swkbdInlineSetMovedCursorCallback(&inline_keyboard, keyboard_moved_cursor_callback); + swkbdInlineSetDecidedEnterCallback(&inline_keyboard, keyboard_decided_enter_callback); + swkbdInlineSetDecidedCancelCallback(&inline_keyboard, keyboard_decided_cancel_callback); int last_touch_count = 0; // maximum of 16 touches @@ -420,7 +401,7 @@ void OS_Switch::run() { hidInitializeTouchScreen(); while (appletMainLoop()) { - if (NintendoSwitch::get_singleton()->is_virtual_keyboard_open()) { + if (g_swkbd_open) { for (int i = 0; i < last_touch_count; i++) { Ref st; st.instance(); @@ -473,17 +454,18 @@ void OS_Switch::run() { last_touch_count = touch_state.count; } - - joypad->process(); - input->flush_buffered_events(); } - NintendoSwitch::get_singleton()->update(); + joypad->process(); + input->flush_buffered_events(); + + swkbdInlineUpdate(&inline_keyboard, NULL); if (Main::iteration()) break; } + swkbdInlineClose(&inline_keyboard); main_loop->finish(); } @@ -496,54 +478,44 @@ bool OS_Switch::has_virtual_keyboard() const { } int OS_Switch::get_virtual_keyboard_height() const { - if (!NintendoSwitch::get_singleton()->is_virtual_keyboard_open()) { + // todo: actually figure this out + if (!g_swkbd_open) { return 0; } - return 400; + return 300; } -void OS_Switch::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { - NintendoSwitch::get_singleton()->show_virtual_keyboard(p_existing_text, NintendoSwitch::NORMAL_KEYBOARD); -} +void OS_Switch::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, int p_max_input_length) { + if (!g_swkbd_open) { + g_swkbd_open = true; -void OS_Switch::hide_virtual_keyboard() { - NintendoSwitch::get_singleton()->hide_virtual_keyboard(); -} + SwkbdAppearArg appear_arg; + swkbdInlineMakeAppearArg(&appear_arg, SwkbdType_Normal); + swkbdInlineSetInputText(&inline_keyboard, p_existing_text.utf8().get_data()); + swkbdInlineSetCursorPos(&inline_keyboard, p_existing_text.size() - 1); -OS::PowerState OS_Switch::get_power_state() { - if (!OS_Switch::psm_initialized) { - return OS::POWERSTATE_UNKNOWN; - } - - bool enough_power; - psmIsEnoughPowerSupplied(&enough_power); + g_eat_string_events = 2; - if (!enough_power) { - return OS::PowerState::POWERSTATE_ON_BATTERY; + swkbdInlineAppear(&inline_keyboard, &appear_arg); } +} - int percentage = OS_Switch::get_power_percent_left(); - - if (percentage == 100) { - return OS::PowerState::POWERSTATE_CHARGED; - } +void OS_Switch::hide_virtual_keyboard() { + printf("Hiding kbd!\n"); + g_swkbd_open = false; + swkbdInlineDisappear(&inline_keyboard); +} - return OS::PowerState::POWERSTATE_CHARGING; +OS::PowerState OS_Switch::get_power_state() { + return power_manager->get_power_state(); } int OS_Switch::get_power_seconds_left() { - WARN_PRINT("power_seconds_left is not implemented on this platform, defaulting to -1"); - return -1; + return power_manager->get_power_seconds_left(); } int OS_Switch::get_power_percent_left() { - if (!OS_Switch::psm_initialized) { - return -1; - } - - u32 voltage_percentage; - psmGetBatteryChargePercentage(&voltage_percentage); - return (int)voltage_percentage; + return power_manager->get_power_percent_left(); } String OS_Switch::get_executable_path() const { @@ -584,7 +556,9 @@ OS_Switch::OS_Switch() { main_loop = nullptr; visual_server = nullptr; input = nullptr; + power_manager = nullptr; gl_context = nullptr; + AudioDriverManager::add_driver(&driver_switch); - AudioDriverManager::add_driver(&driver_audren); + swkbdInlineCreate(&inline_keyboard); } diff --git a/platform/switch/os_switch.h b/platform/switch/os_switch.h index 4907b9f70d53..dc14c0cd1029 100644 --- a/platform/switch/os_switch.h +++ b/platform/switch/os_switch.h @@ -28,32 +28,29 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#include "api/switch_singleton.h" +#include "audio_driver_switch.h" #include "context_gl_switch_egl.h" #include "core/os/input.h" #include "core/os/os.h" -#include "drivers/audren/audio_driver_audren.h" #include "joypad_switch.h" #include "main/input_default.h" +#include "power_switch.h" #include "servers/visual/visual_server_raster.h" -#include - class OS_Switch : public OS { int video_driver_index; MainLoop *main_loop; VideoMode current_videomode; VisualServer *visual_server; InputDefault *input; + PowerSwitch *power_manager; ContextGLSwitchEGL *gl_context; JoypadSwitch *joypad; - AudioDriverAudren driver_audren; + AudioDriverSwitch driver_switch; String switch_execpath; SwkbdInline inline_keyboard; - bool psm_initialized = false; - protected: virtual void initialize_core(); virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -95,8 +92,8 @@ class OS_Switch : public OS { virtual bool set_environment(const String &p_var, const String &p_value) const; virtual String get_name() const; virtual MainLoop *get_main_loop() const; - virtual Date get_date(bool utc = false) const; - virtual Time get_time(bool utc = false) const; + virtual Date get_date(bool local = false) const; + virtual Time get_time(bool local = false) const; virtual TimeZoneInfo get_time_zone_info() const; virtual void delay_usec(uint32_t p_usec) const; virtual uint64_t get_ticks_usec() const; @@ -111,7 +108,7 @@ class OS_Switch : public OS { virtual bool has_touchscreen_ui_hint() const; virtual bool has_virtual_keyboard() const; - virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1); + virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), int p_max_input_length = -1); virtual void hide_virtual_keyboard(); virtual int get_virtual_keyboard_height() const; diff --git a/platform/vita/export/export.h b/platform/vita/export/export.h index 0e64de355cdb..86d1be7eda65 100644 --- a/platform/vita/export/export.h +++ b/platform/vita/export/export.h @@ -31,8 +31,6 @@ #ifndef VITA_EXPORT_H #define VITA_EXPORT_H -#ifndef MODULE_MONO_ENABLED - #include "core/io/file_access_memory.h" #include "editor/editor_export.h" #include "editor/editor_node.h" @@ -51,6 +49,4 @@ typedef struct ParamSFOStruct { int mksfoex(ParamSFOStruct *sfo, String outDir); void register_vita_exporter(); -#endif // !MODULE_MONO_ENABLED - -#endif // !VITA_EXPORT_H +#endif // VITA_EXPORT_H diff --git a/scons b/scons new file mode 100644 index 000000000000..e69de29bb2d1