diff options
124 files changed, 1428 insertions, 1885 deletions
diff --git a/SConstruct b/SConstruct index 2281b8a77f..3795fc1c3c 100644 --- a/SConstruct +++ b/SConstruct @@ -308,7 +308,7 @@ if selected_platform in platform_list: else: env = env_base.Clone() - # Compilation DB requires SCons 3.1.1+. + # Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later. from SCons import __version__ as scons_raw_version scons_ver = env._get_major_minor_revision(scons_raw_version) diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 99c68eb433..456a97e5e5 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -1995,24 +1995,13 @@ Error _Thread::start(Object *p_instance, const StringName &p_method, const Varia Thread::Settings s; s.priority = (Thread::Priority)p_priority; - thread = Thread::create(_start_func, ud, s); - if (!thread) { - active = false; - target_method = StringName(); - target_instance = nullptr; - userdata = Variant(); - return ERR_CANT_CREATE; - } + thread.start(_start_func, ud, s); return OK; } String _Thread::get_id() const { - if (!thread) { - return String(); - } - - return itos(thread->get_id()); + return itos(thread.get_id()); } bool _Thread::is_active() const { @@ -2020,18 +2009,13 @@ bool _Thread::is_active() const { } Variant _Thread::wait_to_finish() { - ERR_FAIL_COND_V_MSG(!thread, Variant(), "Thread must exist to wait for its completion."); ERR_FAIL_COND_V_MSG(!active, Variant(), "Thread must be active to wait for its completion."); - Thread::wait_to_finish(thread); + thread.wait_to_finish(); Variant r = ret; active = false; target_method = StringName(); target_instance = nullptr; userdata = Variant(); - if (thread) { - memdelete(thread); - } - thread = nullptr; return r; } @@ -2047,10 +2031,6 @@ void _Thread::_bind_methods() { BIND_ENUM_CONSTANT(PRIORITY_HIGH); } -_Thread::~_Thread() { - ERR_FAIL_COND_MSG(active, "Reference to a Thread object was lost while the thread is still running..."); -} - ////// _ClassDB ////// PackedStringArray _ClassDB::get_class_list() const { diff --git a/core/core_bind.h b/core/core_bind.h index 0fe5d9c80c..3305c93089 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -554,7 +554,7 @@ protected: volatile bool active = false; Object *target_instance = nullptr; StringName target_method; - Thread *thread = nullptr; + Thread thread; static void _bind_methods(); static void _start_func(void *ud); @@ -570,9 +570,6 @@ public: String get_id() const; bool is_active() const; Variant wait_to_finish(); - - _Thread() {} - ~_Thread(); }; VARIANT_ENUM_CAST(_Thread::Priority); diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp index 2e388d5934..857e3af268 100644 --- a/core/debugger/remote_debugger_peer.cpp +++ b/core/debugger/remote_debugger_peer.cpp @@ -65,12 +65,8 @@ int RemoteDebuggerPeerTCP::get_max_message_size() const { } void RemoteDebuggerPeerTCP::close() { - if (thread) { - running = false; - Thread::wait_to_finish(thread); - memdelete(thread); - thread = nullptr; - } + running = false; + thread.wait_to_finish(); tcp_client->disconnect_from_host(); out_buf.resize(0); in_buf.resize(0); @@ -85,7 +81,7 @@ RemoteDebuggerPeerTCP::RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_tcp) { connected = true; #ifndef NO_THREADS running = true; - thread = Thread::create(_thread_func, this); + thread.start(_thread_func, this); #endif } else { tcp_client.instance(); @@ -188,7 +184,7 @@ Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_po connected = true; #ifndef NO_THREADS running = true; - thread = Thread::create(_thread_func, this); + thread.start(_thread_func, this); #endif return OK; } diff --git a/core/debugger/remote_debugger_peer.h b/core/debugger/remote_debugger_peer.h index c759c65568..652e2d9d20 100644 --- a/core/debugger/remote_debugger_peer.h +++ b/core/debugger/remote_debugger_peer.h @@ -58,7 +58,7 @@ class RemoteDebuggerPeerTCP : public RemoteDebuggerPeer { private: Ref<StreamPeerTCP> tcp_client; Mutex mutex; - Thread *thread = nullptr; + Thread thread; List<Array> in_queue; List<Array> out_queue; int out_left = 0; diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 1d9aa846eb..97838fd14c 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -201,7 +201,7 @@ Error FileAccessNetworkClient::connect(const String &p_host, int p_port, const S return ERR_INVALID_PARAMETER; } - thread = Thread::create(_thread_func, this); + thread.start(_thread_func, this); return OK; } @@ -214,12 +214,9 @@ FileAccessNetworkClient::FileAccessNetworkClient() { } FileAccessNetworkClient::~FileAccessNetworkClient() { - if (thread) { - quit = true; - sem.post(); - Thread::wait_to_finish(thread); - memdelete(thread); - } + quit = true; + sem.post(); + thread.wait_to_finish(); } void FileAccessNetwork::_set_block(int p_offset, const Vector<uint8_t> &p_block) { diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h index 6aec2869fc..1f5de3e5dd 100644 --- a/core/io/file_access_network.h +++ b/core/io/file_access_network.h @@ -48,7 +48,7 @@ class FileAccessNetworkClient { List<BlockRequest> block_requests; Semaphore sem; - Thread *thread = nullptr; + Thread thread; bool quit = false; Mutex mutex; Mutex blockrequest_mutex; diff --git a/core/io/ip.cpp b/core/io/ip.cpp index 6fb812e78d..df95785000 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -71,7 +71,7 @@ struct _IP_ResolverPrivate { Mutex mutex; Semaphore sem; - Thread *thread; + Thread thread; //Semaphore* semaphore; bool thread_abort; @@ -141,7 +141,7 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Typ } else { resolver->queue[id].response = IP_Address(); resolver->queue[id].status = IP::RESOLVER_STATUS_WAITING; - if (resolver->thread) { + if (resolver->thread.is_started()) { resolver->sem.post(); } else { resolver->resolve_queues(); @@ -285,26 +285,14 @@ IP::IP() { singleton = this; resolver = memnew(_IP_ResolverPrivate); -#ifndef NO_THREADS - resolver->thread_abort = false; - - resolver->thread = Thread::create(_IP_ResolverPrivate::_thread_function, resolver); -#else - resolver->thread = nullptr; -#endif + resolver->thread.start(_IP_ResolverPrivate::_thread_function, resolver); } IP::~IP() { -#ifndef NO_THREADS - if (resolver->thread) { - resolver->thread_abort = true; - resolver->sem.post(); - Thread::wait_to_finish(resolver->thread); - memdelete(resolver->thread); - } - -#endif + resolver->thread_abort = true; + resolver->sem.post(); + resolver->thread.wait_to_finish(); memdelete(resolver); } diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 1a2b1ed033..d66511a39f 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -362,7 +362,8 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String & print_lt("REQUEST: load count: " + itos(thread_loading_count) + " / wait count: " + itos(thread_waiting_count) + " / suspended count: " + itos(thread_suspended_count) + " / active: " + itos(thread_loading_count - thread_suspended_count)); - load_task.thread = Thread::create(_thread_load_function, &thread_load_tasks[local_path]); + load_task.thread = memnew(Thread); + load_task.thread->start(_thread_load_function, &thread_load_tasks[local_path]); load_task.loader_id = load_task.thread->get_id(); } @@ -489,7 +490,7 @@ RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) { if (load_task.requests == 0) { if (load_task.thread) { //thread may not have been used - Thread::wait_to_finish(load_task.thread); + load_task.thread->wait_to_finish(); memdelete(load_task.thread); } thread_load_tasks.erase(local_path); diff --git a/core/os/thread.cpp b/core/os/thread.cpp index 0ed8825452..936e5d5500 100644 --- a/core/os/thread.cpp +++ b/core/os/thread.cpp @@ -30,30 +30,70 @@ #include "thread.h" -Thread *(*Thread::create_func)(ThreadCreateCallback, void *, const Settings &) = nullptr; -Thread::ID (*Thread::get_thread_id_func)() = nullptr; -void (*Thread::wait_to_finish_func)(Thread *) = nullptr; +#include "core/object/script_language.h" + +#if !defined(NO_THREADS) + Error (*Thread::set_name_func)(const String &) = nullptr; +void (*Thread::set_priority_func)(Thread::Priority) = nullptr; +void (*Thread::init_func)() = nullptr; +void (*Thread::term_func)() = nullptr; + +Thread::ID Thread::main_thread_id = 1; +Thread::ID Thread::last_thread_id = 1; +thread_local Thread::ID Thread::caller_id = 1; -Thread::ID Thread::_main_thread_id = 0; +void Thread::_set_platform_funcs( + Error (*p_set_name_func)(const String &), + void (*p_set_priority_func)(Thread::Priority), + void (*p_init_func)(), + void (*p_term_func)()) { + Thread::set_name_func = p_set_name_func; + Thread::set_priority_func = p_set_priority_func; + Thread::init_func = p_init_func; + Thread::term_func = p_term_func; +} -Thread::ID Thread::get_caller_id() { - if (get_thread_id_func) { - return get_thread_id_func(); +void Thread::callback(Thread *p_self, const Settings &p_settings, Callback p_callback, void *p_userdata) { + Thread::caller_id = p_self->id; + if (set_priority_func) { + set_priority_func(p_settings.priority); + } + if (init_func) { + init_func(); + } + ScriptServer::thread_enter(); //scripts may need to attach a stack + p_callback(p_userdata); + ScriptServer::thread_exit(); + if (term_func) { + term_func(); } - return 0; } -Thread *Thread::create(ThreadCreateCallback p_callback, void *p_user, const Settings &p_settings) { - if (create_func) { - return create_func(p_callback, p_user, p_settings); +void Thread::start(Thread::Callback p_callback, void *p_user, const Settings &p_settings) { + if (id != 0) { +#ifdef DEBUG_ENABLED + WARN_PRINT("A Thread object has been re-started without wait_to_finish() having been called on it. Please do so to ensure correct cleanup of the thread."); +#endif + thread.detach(); + std::thread empty_thread; + thread.swap(empty_thread); } - return nullptr; + id = atomic_increment(&last_thread_id); + std::thread new_thread(&Thread::callback, this, p_settings, p_callback, p_user); + thread.swap(new_thread); } -void Thread::wait_to_finish(Thread *p_thread) { - if (wait_to_finish_func) { - wait_to_finish_func(p_thread); +bool Thread::is_started() const { + return id != 0; +} + +void Thread::wait_to_finish() { + if (id != 0) { + thread.join(); + std::thread empty_thread; + thread.swap(empty_thread); + id = 0; } } @@ -64,3 +104,14 @@ Error Thread::set_name(const String &p_name) { return ERR_UNAVAILABLE; } + +Thread::~Thread() { + if (id != 0) { +#ifdef DEBUG_ENABLED + WARN_PRINT("A Thread object has been destroyed without wait_to_finish() having been called on it. Please do so to ensure correct cleanup of the thread."); +#endif + thread.detach(); + } +} + +#endif diff --git a/core/os/thread.h b/core/os/thread.h index 993c7ad33d..b5449d2ed6 100644 --- a/core/os/thread.h +++ b/core/os/thread.h @@ -31,13 +31,20 @@ #ifndef THREAD_H #define THREAD_H -#include "core/string/ustring.h" #include "core/typedefs.h" -typedef void (*ThreadCreateCallback)(void *p_userdata); +#if !defined(NO_THREADS) +#include <thread> +#endif + +class String; class Thread { public: + typedef void (*Callback)(void *p_userdata); + + typedef uint64_t ID; + enum Priority { PRIORITY_LOW, PRIORITY_NORMAL, @@ -49,30 +56,60 @@ public: Settings() { priority = PRIORITY_NORMAL; } }; - typedef uint64_t ID; +private: +#if !defined(NO_THREADS) + friend class Main; -protected: - static Thread *(*create_func)(ThreadCreateCallback p_callback, void *, const Settings &); - static ID (*get_thread_id_func)(); - static void (*wait_to_finish_func)(Thread *); - static Error (*set_name_func)(const String &); + static ID main_thread_id; + static ID last_thread_id; - friend class Main; + ID id = 0; + static thread_local ID caller_id; + std::thread thread; - static ID _main_thread_id; + static void callback(Thread *p_self, const Settings &p_settings, Thread::Callback p_callback, void *p_userdata); - Thread() {} + static Error (*set_name_func)(const String &); + static void (*set_priority_func)(Thread::Priority); + static void (*init_func)(); + static void (*term_func)(); +#endif public: - virtual ID get_id() const = 0; + static void _set_platform_funcs( + Error (*p_set_name_func)(const String &), + void (*p_set_priority_func)(Thread::Priority), + void (*p_init_func)() = nullptr, + void (*p_term_func)() = nullptr); + +#if !defined(NO_THREADS) + _FORCE_INLINE_ ID get_id() const { return id; } + // get the ID of the caller thread + _FORCE_INLINE_ static ID get_caller_id() { return caller_id; } + // get the ID of the main thread + _FORCE_INLINE_ static ID get_main_id() { return main_thread_id; } static Error set_name(const String &p_name); - _FORCE_INLINE_ static ID get_main_id() { return _main_thread_id; } ///< get the ID of the main thread - static ID get_caller_id(); ///< get the ID of the caller function ID - static void wait_to_finish(Thread *p_thread); ///< waits until thread is finished, and deallocates it. - static Thread *create(ThreadCreateCallback p_callback, void *p_user, const Settings &p_settings = Settings()); ///< Static function to create a thread, will call p_callback - virtual ~Thread() {} + void start(Thread::Callback p_callback, void *p_user, const Settings &p_settings = Settings()); + bool is_started() const; + ///< waits until thread is finished, and deallocates it. + void wait_to_finish(); + + ~Thread(); +#else + _FORCE_INLINE_ ID get_id() const { return 0; } + // get the ID of the caller thread + _FORCE_INLINE_ static ID get_caller_id() { return 0; } + // get the ID of the main thread + _FORCE_INLINE_ static ID get_main_id() { return 0; } + + static Error set_name(const String &p_name) { return ERR_UNAVAILABLE; } + + void start(Thread::Callback p_callback, void *p_user, const Settings &p_settings = Settings()) {} + bool is_started() const { return false; } + void wait_to_finish() {} +#endif }; #endif // THREAD_H diff --git a/core/os/thread_dummy.cpp b/core/os/thread_dummy.cpp deleted file mode 100644 index a72e1298d1..0000000000 --- a/core/os/thread_dummy.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/*************************************************************************/ -/* thread_dummy.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 "thread_dummy.h" - -#include "core/os/memory.h" - -Thread *ThreadDummy::create(ThreadCreateCallback p_callback, void *p_user, const Thread::Settings &p_settings) { - return memnew(ThreadDummy); -} - -void ThreadDummy::make_default() { - Thread::create_func = &ThreadDummy::create; -} diff --git a/core/os/thread_dummy.h b/core/os/thread_dummy.h deleted file mode 100644 index 0bd59ea309..0000000000 --- a/core/os/thread_dummy.h +++ /dev/null @@ -1,47 +0,0 @@ -/*************************************************************************/ -/* thread_dummy.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 THREAD_DUMMY_H -#define THREAD_DUMMY_H - -#include "core/os/rw_lock.h" -#include "core/os/semaphore.h" -#include "core/os/thread.h" - -class ThreadDummy : public Thread { - static Thread *create(ThreadCreateCallback p_callback, void *p_user, const Settings &p_settings = Settings()); - -public: - virtual ID get_id() const { return 0; }; - - static void make_default(); -}; - -#endif // THREAD_DUMMY_H diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h index 57f3de20bf..9538ac5957 100644 --- a/core/os/threaded_array_processor.h +++ b/core/os/threaded_array_processor.h @@ -74,18 +74,17 @@ void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_us data.elements = p_elements; data.process(data.index); //process first, let threads increment for next - Vector<Thread *> threads; + int thread_count = OS::get_singleton()->get_processor_count(); + Thread *threads = memnew_arr(Thread, thread_count); - threads.resize(OS::get_singleton()->get_processor_count()); - - for (int i = 0; i < threads.size(); i++) { - threads.write[i] = Thread::create(process_array_thread<ThreadArrayProcessData<C, U>>, &data); + for (int i = 0; i < thread_count; i++) { + threads[i].start(process_array_thread<ThreadArrayProcessData<C, U>>, &data); } - for (int i = 0; i < threads.size(); i++) { - Thread::wait_to_finish(threads[i]); - memdelete(threads[i]); + for (int i = 0; i < thread_count; i++) { + threads[i].wait_to_finish(); } + memdelete_arr(threads); } #else diff --git a/core/templates/thread_work_pool.cpp b/core/templates/thread_work_pool.cpp index ea784e510c..17969a2c90 100644 --- a/core/templates/thread_work_pool.cpp +++ b/core/templates/thread_work_pool.cpp @@ -32,14 +32,15 @@ #include "core/os/os.h" -void ThreadWorkPool::_thread_function(ThreadData *p_thread) { +void ThreadWorkPool::_thread_function(void *p_user) { + ThreadData *thread = static_cast<ThreadData *>(p_user); while (true) { - p_thread->start.wait(); - if (p_thread->exit.load()) { + thread->start.wait(); + if (thread->exit.load()) { break; } - p_thread->work->work(); - p_thread->completed.post(); + thread->work->work(); + thread->completed.post(); } } @@ -54,7 +55,7 @@ void ThreadWorkPool::init(int p_thread_count) { for (uint32_t i = 0; i < thread_count; i++) { threads[i].exit.store(false); - threads[i].thread = memnew(std::thread(ThreadWorkPool::_thread_function, &threads[i])); + threads[i].thread.start(&ThreadWorkPool::_thread_function, &threads[i]); } } @@ -68,8 +69,7 @@ void ThreadWorkPool::finish() { threads[i].start.post(); } for (uint32_t i = 0; i < thread_count; i++) { - threads[i].thread->join(); - memdelete(threads[i].thread); + threads[i].thread.wait_to_finish(); } memdelete_arr(threads); diff --git a/core/templates/thread_work_pool.h b/core/templates/thread_work_pool.h index 7c3508814f..19ab1dda3a 100644 --- a/core/templates/thread_work_pool.h +++ b/core/templates/thread_work_pool.h @@ -33,9 +33,9 @@ #include "core/os/memory.h" #include "core/os/semaphore.h" +#include "core/os/thread.h" #include <atomic> -#include <thread> class ThreadWorkPool { std::atomic<uint32_t> index; @@ -64,7 +64,7 @@ class ThreadWorkPool { }; struct ThreadData { - std::thread *thread; + Thread thread; Semaphore start; Semaphore completed; std::atomic<bool> exit; @@ -75,7 +75,7 @@ class ThreadWorkPool { uint32_t thread_count = 0; BaseWork *current_work = nullptr; - static void _thread_function(ThreadData *p_thread); + static void _thread_function(void *p_user); public: template <class C, class M, class U> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index e8913f2623..5f0d6462e2 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -623,10 +623,11 @@ </return> <argument index="0" name="node" type="Node"> </argument> - <argument index="1" name="keep_data" type="bool" default="false"> + <argument index="1" name="keep_groups" type="bool" default="false"> </argument> <description> Replaces a node in a scene by the given one. Subscriptions that pass through this node will be lost. + If [code]keep_groups[/code] is [code]true[/code], the [code]node[/code] is added to the same groups that the replaced node is in. </description> </method> <method name="request_ready"> diff --git a/doc/classes/VisualShaderNodeClamp.xml b/doc/classes/VisualShaderNodeClamp.xml new file mode 100644 index 0000000000..504171bb13 --- /dev/null +++ b/doc/classes/VisualShaderNodeClamp.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeClamp" inherits="VisualShaderNode" version="4.0"> + <brief_description> + Clamps a value within the visual shader graph. + </brief_description> + <description> + Constrains a value to lie between [code]min[/code] and [code]max[/code] values. + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="op_type" type="int" setter="set_op_type" getter="get_op_type" enum="VisualShaderNodeClamp.OpType" default="0"> + A type of operands and returned value. + </member> + </members> + <constants> + <constant name="OP_TYPE_FLOAT" value="0" enum="OpType"> + A floating-point scalar. + </constant> + <constant name="OP_TYPE_INT" value="1" enum="OpType"> + An integer scalar. + </constant> + <constant name="OP_TYPE_VECTOR" value="2" enum="OpType"> + A vector type. + </constant> + <constant name="OP_TYPE_MAX" value="3" enum="OpType"> + Represents the size of the [enum OpType] enum. + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeIntFunc.xml b/doc/classes/VisualShaderNodeIntFunc.xml index 5c68c0ec71..a9f4144a01 100644 --- a/doc/classes/VisualShaderNodeIntFunc.xml +++ b/doc/classes/VisualShaderNodeIntFunc.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="function" type="int" setter="set_function" getter="get_function" enum="VisualShaderNodeIntFunc.Function" default="3"> + <member name="function" type="int" setter="set_function" getter="get_function" enum="VisualShaderNodeIntFunc.Function" default="2"> A function to be applied to the scalar. See [enum Function] for options. </member> </members> @@ -19,13 +19,10 @@ <constant name="FUNC_ABS" value="0" enum="Function"> Returns the absolute value of the parameter. Translates to [code]abs(x)[/code] in the Godot Shader Language. </constant> - <constant name="FUNC_CLAMP" value="1" enum="Function"> - Constrains a parameter between [code]min[/code] and [code]max[/code]. Translates to [code]clamp(x, min, max)[/code] in the Godot Shader Language. - </constant> - <constant name="FUNC_NEGATE" value="2" enum="Function"> + <constant name="FUNC_NEGATE" value="1" enum="Function"> Negates the [code]x[/code] using [code]-(x)[/code]. </constant> - <constant name="FUNC_SIGN" value="3" enum="Function"> + <constant name="FUNC_SIGN" value="2" enum="Function"> Extracts the sign of the parameter. Translates to [code]sign(x)[/code] in the Godot Shader Language. </constant> </constants> diff --git a/doc/classes/VisualShaderNodeMix.xml b/doc/classes/VisualShaderNodeMix.xml new file mode 100644 index 0000000000..c70ac7e599 --- /dev/null +++ b/doc/classes/VisualShaderNodeMix.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeMix" inherits="VisualShaderNode" version="4.0"> + <brief_description> + Linearly interpolates between two values within the visual shader graph. + </brief_description> + <description> + Translates to [code]mix(a, b, weight)[/code] in the shader language. + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="op_type" type="int" setter="set_op_type" getter="get_op_type" enum="VisualShaderNodeMix.OpType" default="0"> + A type of operands and returned value. + </member> + </members> + <constants> + <constant name="OP_TYPE_SCALAR" value="0" enum="OpType"> + A scalar type. + </constant> + <constant name="OP_TYPE_VECTOR" value="1" enum="OpType"> + A vector type. + </constant> + <constant name="OP_TYPE_VECTOR_SCALAR" value="2" enum="OpType"> + A vector type. [code]weight[/code] port is using a scalar type. + </constant> + <constant name="OP_TYPE_MAX" value="3" enum="OpType"> + Represents the size of the [enum OpType] enum. + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeScalarClamp.xml b/doc/classes/VisualShaderNodeScalarClamp.xml deleted file mode 100644 index 7432e8dfca..0000000000 --- a/doc/classes/VisualShaderNodeScalarClamp.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualShaderNodeScalarClamp" inherits="VisualShaderNode" version="4.0"> - <brief_description> - Clamps a scalar value within the visual shader graph. - </brief_description> - <description> - Constrains a value to lie between [code]min[/code] and [code]max[/code] values. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <constants> - </constants> -</class> diff --git a/doc/classes/VisualShaderNodeScalarInterp.xml b/doc/classes/VisualShaderNodeScalarInterp.xml deleted file mode 100644 index 393ea70e1a..0000000000 --- a/doc/classes/VisualShaderNodeScalarInterp.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualShaderNodeScalarInterp" inherits="VisualShaderNode" version="4.0"> - <brief_description> - Linearly interpolates between two scalars within the visual shader graph. - </brief_description> - <description> - Translates to [code]mix(a, b, weight)[/code] in the shader language. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <constants> - </constants> -</class> diff --git a/doc/classes/VisualShaderNodeScalarSmoothStep.xml b/doc/classes/VisualShaderNodeScalarSmoothStep.xml deleted file mode 100644 index e619cc8571..0000000000 --- a/doc/classes/VisualShaderNodeScalarSmoothStep.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualShaderNodeScalarSmoothStep" inherits="VisualShaderNode" version="4.0"> - <brief_description> - Calculates a scalar SmoothStep function within the visual shader graph. - </brief_description> - <description> - Translates to [code]smoothstep(edge0, edge1, x)[/code] in the shader language. - Returns [code]0.0[/code] if [code]x[/code] is smaller than [code]edge0[/code] and [code]1.0[/code] if [code]x[/code] is larger than [code]edge1[/code]. Otherwise the return value is interpolated between [code]0.0[/code] and [code]1.0[/code] using Hermite polynomials. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <constants> - </constants> -</class> diff --git a/doc/classes/VisualShaderNodeScalarSwitch.xml b/doc/classes/VisualShaderNodeScalarSwitch.xml deleted file mode 100644 index 2ad5202745..0000000000 --- a/doc/classes/VisualShaderNodeScalarSwitch.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualShaderNodeScalarSwitch" inherits="VisualShaderNodeSwitch" version="4.0"> - <brief_description> - A boolean/scalar function for use within the visual shader graph. - </brief_description> - <description> - Returns an associated scalar if the provided boolean value is [code]true[/code] or [code]false[/code]. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <constants> - </constants> -</class> diff --git a/doc/classes/VisualShaderNodeSmoothStep.xml b/doc/classes/VisualShaderNodeSmoothStep.xml new file mode 100644 index 0000000000..fa22d16da8 --- /dev/null +++ b/doc/classes/VisualShaderNodeSmoothStep.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeSmoothStep" inherits="VisualShaderNode" version="4.0"> + <brief_description> + Calculates a SmoothStep function within the visual shader graph. + </brief_description> + <description> + Translates to [code]smoothstep(edge0, edge1, x)[/code] in the shader language. + Returns [code]0.0[/code] if [code]x[/code] is smaller than [code]edge0[/code] and [code]1.0[/code] if [code]x[/code] is larger than [code]edge1[/code]. Otherwise the return value is interpolated between [code]0.0[/code] and [code]1.0[/code] using Hermite polynomials. + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="op_type" type="int" setter="set_op_type" getter="get_op_type" enum="VisualShaderNodeSmoothStep.OpType" default="0"> + A type of operands and returned value. + </member> + </members> + <constants> + <constant name="OP_TYPE_SCALAR" value="0" enum="OpType"> + A scalar type. + </constant> + <constant name="OP_TYPE_VECTOR" value="1" enum="OpType"> + A vector type. + </constant> + <constant name="OP_TYPE_VECTOR_SCALAR" value="2" enum="OpType"> + A vector type. [code]edge0[/code] and [code]edge1[/code] are using a scalar type. + </constant> + <constant name="OP_TYPE_MAX" value="3" enum="OpType"> + Represents the size of the [enum OpType] enum. + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeStep.xml b/doc/classes/VisualShaderNodeStep.xml new file mode 100644 index 0000000000..694c144445 --- /dev/null +++ b/doc/classes/VisualShaderNodeStep.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeStep" inherits="VisualShaderNode" version="4.0"> + <brief_description> + Calculates a Step function within the visual shader graph. + </brief_description> + <description> + Translates to [code]step(edge, x)[/code] in the shader language. + Returns [code]0.0[/code] if [code]x[/code] is smaller than [code]edge[/code] and [code]1.0[/code] otherwise. + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="op_type" type="int" setter="set_op_type" getter="get_op_type" enum="VisualShaderNodeStep.OpType" default="0"> + A type of operands and returned value. + </member> + </members> + <constants> + <constant name="OP_TYPE_SCALAR" value="0" enum="OpType"> + A scalar type. + </constant> + <constant name="OP_TYPE_VECTOR" value="1" enum="OpType"> + A vector type. + </constant> + <constant name="OP_TYPE_VECTOR_SCALAR" value="2" enum="OpType"> + A vector type. [code]edge[/code] port is using a scalar type. + </constant> + <constant name="OP_TYPE_MAX" value="3" enum="OpType"> + Represents the size of the [enum OpType] enum. + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeSwitch.xml b/doc/classes/VisualShaderNodeSwitch.xml index 9f8a12c0fd..3961070a74 100644 --- a/doc/classes/VisualShaderNodeSwitch.xml +++ b/doc/classes/VisualShaderNodeSwitch.xml @@ -1,15 +1,38 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualShaderNodeSwitch" inherits="VisualShaderNode" version="4.0"> <brief_description> - A boolean/vector function for use within the visual shader graph. + A selector function for use within the visual shader graph. </brief_description> <description> - Returns an associated vector if the provided boolean value is [code]true[/code] or [code]false[/code]. + Returns an associated value of the [code]op_type[/code] type if the provided boolean value is [code]true[/code] or [code]false[/code]. </description> <tutorials> </tutorials> <methods> </methods> + <members> + <member name="op_type" type="int" setter="set_op_type" getter="get_op_type" enum="VisualShaderNodeSwitch.OpType" default="0"> + A type of operands and returned value. + </member> + </members> <constants> + <constant name="OP_TYPE_FLOAT" value="0" enum="OpType"> + A floating-point scalar. + </constant> + <constant name="OP_TYPE_INT" value="1" enum="OpType"> + An integer scalar. + </constant> + <constant name="OP_TYPE_VECTOR" value="2" enum="OpType"> + A vector type. + </constant> + <constant name="OP_TYPE_BOOLEAN" value="3" enum="OpType"> + A boolean type. + </constant> + <constant name="OP_TYPE_TRANSFORM" value="4" enum="OpType"> + A transform type. + </constant> + <constant name="OP_TYPE_MAX" value="5" enum="OpType"> + Represents the size of the [enum OpType] enum. + </constant> </constants> </class> diff --git a/doc/classes/VisualShaderNodeVectorClamp.xml b/doc/classes/VisualShaderNodeVectorClamp.xml deleted file mode 100644 index 567fed8a41..0000000000 --- a/doc/classes/VisualShaderNodeVectorClamp.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualShaderNodeVectorClamp" inherits="VisualShaderNode" version="4.0"> - <brief_description> - Clamps a vector value within the visual shader graph. - </brief_description> - <description> - Constrains a value to lie between [code]min[/code] and [code]max[/code] values. The operation is performed on each component of the vector individually. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <constants> - </constants> -</class> diff --git a/doc/classes/VisualShaderNodeVectorInterp.xml b/doc/classes/VisualShaderNodeVectorInterp.xml deleted file mode 100644 index b63d34b742..0000000000 --- a/doc/classes/VisualShaderNodeVectorInterp.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualShaderNodeVectorInterp" inherits="VisualShaderNode" version="4.0"> - <brief_description> - Linearly interpolates between two vectors within the visual shader graph. - </brief_description> - <description> - Translates to [code]mix(a, b, weight)[/code] in the shader language, where [code]weight[/code] is a [Vector3] with weights for each component. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <constants> - </constants> -</class> diff --git a/doc/classes/VisualShaderNodeVectorScalarMix.xml b/doc/classes/VisualShaderNodeVectorScalarMix.xml deleted file mode 100644 index 791a9e6be1..0000000000 --- a/doc/classes/VisualShaderNodeVectorScalarMix.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualShaderNodeVectorScalarMix" inherits="VisualShaderNode" version="4.0"> - <brief_description> - Linearly interpolates between two vectors using a scalar. For use within the visual shader graph. - </brief_description> - <description> - Translates to [code]mix(a, b, weight)[/code] in the shader language, where [code]a[/code] and [code]b[/code] are vectors and [code]weight[/code] is a scalar. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <constants> - </constants> -</class> diff --git a/doc/classes/VisualShaderNodeVectorScalarSmoothStep.xml b/doc/classes/VisualShaderNodeVectorScalarSmoothStep.xml deleted file mode 100644 index 580abaf5fe..0000000000 --- a/doc/classes/VisualShaderNodeVectorScalarSmoothStep.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualShaderNodeVectorScalarSmoothStep" inherits="VisualShaderNode" version="4.0"> - <brief_description> - Calculates a vector SmoothStep function using scalar within the visual shader graph. - </brief_description> - <description> - Translates to [code]smoothstep(edge0, edge1, x)[/code] in the shader language, where [code]x[/code] is a scalar. - Returns [code]0.0[/code] if [code]x[/code] is smaller than [code]edge0[/code] and [code]1.0[/code] if [code]x[/code] is larger than [code]edge1[/code]. Otherwise the return value is interpolated between [code]0.0[/code] and [code]1.0[/code] using Hermite polynomials. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <constants> - </constants> -</class> diff --git a/doc/classes/VisualShaderNodeVectorScalarStep.xml b/doc/classes/VisualShaderNodeVectorScalarStep.xml deleted file mode 100644 index d61414f3a8..0000000000 --- a/doc/classes/VisualShaderNodeVectorScalarStep.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualShaderNodeVectorScalarStep" inherits="VisualShaderNode" version="4.0"> - <brief_description> - Calculates a vector Step function within the visual shader graph. - </brief_description> - <description> - Translates to [code]step(edge, x)[/code] in the shader language. - Returns [code]0.0[/code] if [code]x[/code] is smaller than [code]edge[/code] and [code]1.0[/code] otherwise. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <constants> - </constants> -</class> diff --git a/doc/classes/VisualShaderNodeVectorSmoothStep.xml b/doc/classes/VisualShaderNodeVectorSmoothStep.xml deleted file mode 100644 index 1b77a3c535..0000000000 --- a/doc/classes/VisualShaderNodeVectorSmoothStep.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualShaderNodeVectorSmoothStep" inherits="VisualShaderNode" version="4.0"> - <brief_description> - Calculates a vector SmoothStep function within the visual shader graph. - </brief_description> - <description> - Translates to [code]smoothstep(edge0, edge1, x)[/code] in the shader language, where [code]x[/code] is a vector. - Returns [code]0.0[/code] if [code]x[/code] is smaller than [code]edge0[/code] and [code]1.0[/code] if [code]x[/code] is larger than [code]edge1[/code]. Otherwise the return value is interpolated between [code]0.0[/code] and [code]1.0[/code] using Hermite polynomials. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <constants> - </constants> -</class> diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index 5b0d2233e0..ea0cba6c52 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.cpp @@ -153,7 +153,7 @@ Error AudioDriverALSA::init() { Error err = init_device(); if (err == OK) { - thread = Thread::create(AudioDriverALSA::thread_func, this); + thread.start(AudioDriverALSA::thread_func, this); } return err; @@ -291,16 +291,10 @@ void AudioDriverALSA::set_device(String device) { } void AudioDriverALSA::lock() { - if (!thread) { - return; - } mutex.lock(); } void AudioDriverALSA::unlock() { - if (!thread) { - return; - } mutex.unlock(); } @@ -312,13 +306,8 @@ void AudioDriverALSA::finish_device() { } void AudioDriverALSA::finish() { - if (thread) { - exit_thread = true; - Thread::wait_to_finish(thread); - - memdelete(thread); - thread = nullptr; - } + exit_thread = true; + thread.wait_to_finish(); finish_device(); } diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h index 7441229704..c0233f41e1 100644 --- a/drivers/alsa/audio_driver_alsa.h +++ b/drivers/alsa/audio_driver_alsa.h @@ -40,7 +40,7 @@ #include <alsa/asoundlib.h> class AudioDriverALSA : public AudioDriver { - Thread *thread = nullptr; + Thread thread; Mutex mutex; snd_pcm_t *pcm_handle = nullptr; diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp index 2e1034fc66..245ea07730 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.cpp +++ b/drivers/alsamidi/midi_driver_alsamidi.cpp @@ -150,19 +150,14 @@ Error MIDIDriverALSAMidi::open() { snd_device_name_free_hint(hints); exit_thread = false; - thread = Thread::create(MIDIDriverALSAMidi::thread_func, this); + thread.start(MIDIDriverALSAMidi::thread_func, this); return OK; } void MIDIDriverALSAMidi::close() { - if (thread) { - exit_thread = true; - Thread::wait_to_finish(thread); - - memdelete(thread); - thread = nullptr; - } + exit_thread = true; + thread.wait_to_finish(); for (int i = 0; i < connected_inputs.size(); i++) { snd_rawmidi_t *midi_in = connected_inputs[i]; @@ -198,8 +193,6 @@ PackedStringArray MIDIDriverALSAMidi::get_connected_inputs() { } MIDIDriverALSAMidi::MIDIDriverALSAMidi() { - thread = nullptr; - exit_thread = false; } diff --git a/drivers/alsamidi/midi_driver_alsamidi.h b/drivers/alsamidi/midi_driver_alsamidi.h index 1ce0d397df..474f139bd6 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.h +++ b/drivers/alsamidi/midi_driver_alsamidi.h @@ -42,7 +42,7 @@ #include <stdio.h> class MIDIDriverALSAMidi : public MIDIDriver { - Thread *thread; + Thread thread; Mutex mutex; Vector<snd_rawmidi_t *> connected_inputs; diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 440b7d7f53..a5092c8c5c 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -287,7 +287,7 @@ Error AudioDriverPulseAudio::init() { Error err = init_device(); if (err == OK) { - thread = Thread::create(AudioDriverPulseAudio::thread_func, this); + thread.start(AudioDriverPulseAudio::thread_func, this); } return OK; @@ -581,16 +581,10 @@ void AudioDriverPulseAudio::set_device(String device) { } void AudioDriverPulseAudio::lock() { - if (!thread) { - return; - } mutex.lock(); } void AudioDriverPulseAudio::unlock() { - if (!thread) { - return; - } mutex.unlock(); } @@ -603,12 +597,12 @@ void AudioDriverPulseAudio::finish_device() { } void AudioDriverPulseAudio::finish() { - if (!thread) { + if (!thread.is_started()) { return; } exit_thread = true; - Thread::wait_to_finish(thread); + thread.wait_to_finish(); finish_device(); @@ -622,10 +616,6 @@ void AudioDriverPulseAudio::finish() { pa_mainloop_free(pa_ml); pa_ml = nullptr; } - - memdelete(thread); - - thread = nullptr; } Error AudioDriverPulseAudio::capture_init_device() { diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h index 71ab2ef1c8..2ddf8d2592 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.h +++ b/drivers/pulseaudio/audio_driver_pulseaudio.h @@ -40,7 +40,7 @@ #include <pulse/pulseaudio.h> class AudioDriverPulseAudio : public AudioDriver { - Thread *thread = nullptr; + Thread thread; Mutex mutex; pa_mainloop *pa_ml = nullptr; diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 36560eb736..b9bd773c2e 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -35,7 +35,6 @@ #include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" #include "core/debugger/script_debugger.h" -#include "core/os/thread_dummy.h" #include "drivers/unix/dir_access_unix.h" #include "drivers/unix/file_access_unix.h" #include "drivers/unix/net_socket_posix.h" @@ -63,6 +62,7 @@ #include <string.h> #include <sys/time.h> #include <sys/wait.h> +#include <time.h> #include <unistd.h> /// Clock Setup function (used by get_ticks_usec) @@ -116,11 +116,10 @@ int OS_Unix::unix_initialize_audio(int p_audio_driver) { } void OS_Unix::initialize_core() { -#ifdef NO_THREADS - ThreadDummy::make_default(); -#else - ThreadPosix::make_default(); +#if !defined(NO_THREADS) + init_thread_posix(); #endif + FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES); FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA); FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM); diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp index 5c7a546b29..19fab1d475 100644 --- a/drivers/unix/thread_posix.cpp +++ b/drivers/unix/thread_posix.cpp @@ -28,88 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "thread_posix.h" - #if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(NO_THREADS) -#include "core/object/script_language.h" -#include "core/os/memory.h" -#include "core/templates/safe_refcount.h" - -#ifdef PTHREAD_BSD_SET_NAME -#include <pthread_np.h> -#endif - -static void _thread_id_key_destr_callback(void *p_value) { - memdelete(static_cast<Thread::ID *>(p_value)); -} - -static pthread_key_t _create_thread_id_key() { - pthread_key_t key; - pthread_key_create(&key, &_thread_id_key_destr_callback); - return key; -} - -pthread_key_t ThreadPosix::thread_id_key = _create_thread_id_key(); -Thread::ID ThreadPosix::next_thread_id = 0; - -Thread::ID ThreadPosix::get_id() const { - return id; -} - -Thread *ThreadPosix::create_thread_posix() { - return memnew(ThreadPosix); -} - -void *ThreadPosix::thread_callback(void *userdata) { - ThreadPosix *t = reinterpret_cast<ThreadPosix *>(userdata); - t->id = atomic_increment(&next_thread_id); - pthread_setspecific(thread_id_key, (void *)memnew(ID(t->id))); - - ScriptServer::thread_enter(); //scripts may need to attach a stack - - t->callback(t->user); - - ScriptServer::thread_exit(); - - return nullptr; -} - -Thread *ThreadPosix::create_func_posix(ThreadCreateCallback p_callback, void *p_user, const Settings &) { - ThreadPosix *tr = memnew(ThreadPosix); - tr->callback = p_callback; - tr->user = p_user; - pthread_attr_init(&tr->pthread_attr); - pthread_attr_setdetachstate(&tr->pthread_attr, PTHREAD_CREATE_JOINABLE); - pthread_attr_setstacksize(&tr->pthread_attr, 256 * 1024); - - pthread_create(&tr->pthread, &tr->pthread_attr, thread_callback, tr); - - return tr; -} - -Thread::ID ThreadPosix::get_thread_id_func_posix() { - void *value = pthread_getspecific(thread_id_key); - - if (value) { - return *static_cast<ID *>(value); - } - - ID new_id = atomic_increment(&next_thread_id); - pthread_setspecific(thread_id_key, (void *)memnew(ID(new_id))); - return new_id; -} - -void ThreadPosix::wait_to_finish_func_posix(Thread *p_thread) { - ThreadPosix *tp = static_cast<ThreadPosix *>(p_thread); - ERR_FAIL_COND(!tp); - ERR_FAIL_COND(tp->pthread == 0); +#include "thread_posix.h" - pthread_join(tp->pthread, nullptr); - tp->pthread = 0; -} +#include "core/os/thread.h" +#include "core/string/ustring.h" -Error ThreadPosix::set_name_func_posix(const String &p_name) { +static Error set_name(const String &p_name) { #ifdef PTHREAD_NO_RENAME return ERR_UNAVAILABLE; @@ -137,20 +63,10 @@ Error ThreadPosix::set_name_func_posix(const String &p_name) { return err == 0 ? OK : ERR_INVALID_PARAMETER; #endif // PTHREAD_NO_RENAME -}; - -void ThreadPosix::make_default() { - create_func = create_func_posix; - get_thread_id_func = get_thread_id_func_posix; - wait_to_finish_func = wait_to_finish_func_posix; - set_name_func = set_name_func_posix; -} - -ThreadPosix::ThreadPosix() { - pthread = 0; } -ThreadPosix::~ThreadPosix() { +void init_thread_posix() { + Thread::_set_platform_funcs(&set_name, nullptr); } #endif diff --git a/drivers/unix/thread_posix.h b/drivers/unix/thread_posix.h index fa2037e1a2..8b8a736bf0 100644 --- a/drivers/unix/thread_posix.h +++ b/drivers/unix/thread_posix.h @@ -31,42 +31,8 @@ #ifndef THREAD_POSIX_H #define THREAD_POSIX_H -#if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(NO_THREADS) - -#include "core/os/thread.h" -#include <pthread.h> -#include <sys/types.h> - -class ThreadPosix : public Thread { - static pthread_key_t thread_id_key; - static ID next_thread_id; - - pthread_t pthread; - pthread_attr_t pthread_attr; - ThreadCreateCallback callback; - void *user; - ID id; - - static Thread *create_thread_posix(); - - static void *thread_callback(void *userdata); - - static Thread *create_func_posix(ThreadCreateCallback p_callback, void *, const Settings &); - static ID get_thread_id_func_posix(); - static void wait_to_finish_func_posix(Thread *p_thread); - - static Error set_name_func_posix(const String &p_name); - - ThreadPosix(); - -public: - virtual ID get_id() const; - - static void make_default(); - - ~ThreadPosix(); -}; - +#if !defined(NO_THREADS) +void init_thread_posix(); #endif #endif diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 7d5082d276..f2d541754f 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -397,7 +397,7 @@ Error AudioDriverWASAPI::init() { exit_thread = false; thread_exited = false; - thread = Thread::create(thread_func, this); + thread.start(thread_func, this); return OK; } @@ -767,13 +767,8 @@ void AudioDriverWASAPI::unlock() { } void AudioDriverWASAPI::finish() { - if (thread) { - exit_thread = true; - Thread::wait_to_finish(thread); - - memdelete(thread); - thread = nullptr; - } + exit_thread = true; + thread.wait_to_finish(); finish_capture_device(); finish_render_device(); diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h index 2df07d16f7..b9b325f0fb 100644 --- a/drivers/wasapi/audio_driver_wasapi.h +++ b/drivers/wasapi/audio_driver_wasapi.h @@ -64,7 +64,7 @@ class AudioDriverWASAPI : public AudioDriver { AudioDeviceWASAPI audio_output; Mutex mutex; - Thread *thread = nullptr; + Thread thread; Vector<int32_t> samples_in; diff --git a/drivers/windows/thread_windows.cpp b/drivers/windows/thread_windows.cpp deleted file mode 100644 index ec95c9523d..0000000000 --- a/drivers/windows/thread_windows.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/*************************************************************************/ -/* thread_windows.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 "thread_windows.h" - -#if defined(WINDOWS_ENABLED) && !defined(UWP_ENABLED) - -#include "core/os/memory.h" - -Thread::ID ThreadWindows::get_id() const { - return id; -} - -Thread *ThreadWindows::create_thread_windows() { - return memnew(ThreadWindows); -} - -DWORD ThreadWindows::thread_callback(LPVOID userdata) { - ThreadWindows *t = reinterpret_cast<ThreadWindows *>(userdata); - - ScriptServer::thread_enter(); //scripts may need to attach a stack - - t->id = (ID)GetCurrentThreadId(); // must implement - t->callback(t->user); - SetEvent(t->handle); - - ScriptServer::thread_exit(); - - return 0; -} - -Thread *ThreadWindows::create_func_windows(ThreadCreateCallback p_callback, void *p_user, const Settings &) { - ThreadWindows *tr = memnew(ThreadWindows); - tr->callback = p_callback; - tr->user = p_user; - tr->handle = CreateEvent(nullptr, TRUE, FALSE, nullptr); - - QueueUserWorkItem(thread_callback, tr, WT_EXECUTELONGFUNCTION); - - return tr; -} - -Thread::ID ThreadWindows::get_thread_id_func_windows() { - return (ID)GetCurrentThreadId(); //must implement -} - -void ThreadWindows::wait_to_finish_func_windows(Thread *p_thread) { - ThreadWindows *tp = static_cast<ThreadWindows *>(p_thread); - ERR_FAIL_COND(!tp); - WaitForSingleObject(tp->handle, INFINITE); - CloseHandle(tp->handle); - //`memdelete(tp); -} - -void ThreadWindows::make_default() { - create_func = create_func_windows; - get_thread_id_func = get_thread_id_func_windows; - wait_to_finish_func = wait_to_finish_func_windows; -} - -#endif diff --git a/drivers/windows/thread_windows.h b/drivers/windows/thread_windows.h deleted file mode 100644 index 3801bddc2c..0000000000 --- a/drivers/windows/thread_windows.h +++ /dev/null @@ -1,67 +0,0 @@ -/*************************************************************************/ -/* thread_windows.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 THREAD_WINDOWS_H -#define THREAD_WINDOWS_H - -#ifdef WINDOWS_ENABLED - -#include "core/object/script_language.h" -#include "core/os/thread.h" - -#include <windows.h> - -class ThreadWindows : public Thread { - ThreadCreateCallback callback; - void *user; - ID id; - HANDLE handle = nullptr; - - static Thread *create_thread_windows(); - - static DWORD WINAPI thread_callback(LPVOID userdata); - - static Thread *create_func_windows(ThreadCreateCallback p_callback, void *, const Settings &); - static ID get_thread_id_func_windows(); - static void wait_to_finish_func_windows(Thread *p_thread); - - ThreadWindows() {} - -public: - virtual ID get_id() const; - - static void make_default(); - - ~ThreadWindows() {} -}; - -#endif - -#endif diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp index 3b3c3481b6..1bb8da769b 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.cpp +++ b/drivers/xaudio2/audio_driver_xaudio2.cpp @@ -78,7 +78,7 @@ Error AudioDriverXAudio2::init() { hr = xaudio->CreateSourceVoice(&source_voice, &wave_format, 0, XAUDIO2_MAX_FREQ_RATIO, &voice_callback); ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_UNAVAILABLE, "Error creating XAudio2 source voice. Error code: " + itos(hr) + "."); - thread = Thread::create(AudioDriverXAudio2::thread_func, this); + thread.start(AudioDriverXAudio2::thread_func, this); return OK; } @@ -146,23 +146,16 @@ float AudioDriverXAudio2::get_latency() { } void AudioDriverXAudio2::lock() { - if (!thread) - return; mutex.lock(); } void AudioDriverXAudio2::unlock() { - if (!thread) - return; mutex.unlock(); } void AudioDriverXAudio2::finish() { - if (!thread) - return; - exit_thread = true; - Thread::wait_to_finish(thread); + thread.wait_to_finish(); if (source_voice) { source_voice->Stop(0); @@ -179,9 +172,6 @@ void AudioDriverXAudio2::finish() { } mastering_voice->DestroyVoice(); - - memdelete(thread); - thread = nullptr; } AudioDriverXAudio2::AudioDriverXAudio2() { diff --git a/drivers/xaudio2/audio_driver_xaudio2.h b/drivers/xaudio2/audio_driver_xaudio2.h index e3c2d3a326..d3938a19d0 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.h +++ b/drivers/xaudio2/audio_driver_xaudio2.h @@ -62,7 +62,7 @@ class AudioDriverXAudio2 : public AudioDriver { void STDMETHODCALLTYPE OnVoiceError(void *pBufferContext, HRESULT Error) {} }; - Thread *thread = nullptr; + Thread thread; Mutex mutex; int32_t *samples_in = nullptr; diff --git a/editor/audio_stream_preview.cpp b/editor/audio_stream_preview.cpp index 2e0c3491f7..8be8735f3e 100644 --- a/editor/audio_stream_preview.cpp +++ b/editor/audio_stream_preview.cpp @@ -197,7 +197,8 @@ Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref< preview->preview->length = len_s; if (preview->playback.is_valid()) { - preview->thread = Thread::create(_preview_thread, preview); + preview->thread = memnew(Thread); + preview->thread->start(_preview_thread, preview); } return preview->preview; @@ -218,7 +219,8 @@ void AudioStreamPreviewGenerator::_notification(int p_what) { for (Map<ObjectID, Preview>::Element *E = previews.front(); E; E = E->next()) { if (!E->get().generating) { if (E->get().thread) { - Thread::wait_to_finish(E->get().thread); + E->get().thread->wait_to_finish(); + memdelete(E->get().thread); E->get().thread = nullptr; } if (!ObjectDB::get_instance(E->key())) { //no longer in use, get rid of preview diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 76814ea378..4b68de26e7 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -595,7 +595,7 @@ void EditorFileSystem::scan() { return; } - if (scanning || scanning_changes || thread) { + if (scanning || scanning_changes || thread.is_started()) { return; } @@ -619,13 +619,13 @@ void EditorFileSystem::scan() { _queue_update_script_classes(); first_scan = false; } else { - ERR_FAIL_COND(thread); + ERR_FAIL_COND(thread.is_started()); set_process(true); Thread::Settings s; scanning = true; scan_total = 0; s.priority = Thread::PRIORITY_LOW; - thread = Thread::create(_thread_func, this, s); + thread.start(_thread_func, this, s); //tree->hide(); //progress->show(); } @@ -1046,7 +1046,7 @@ void EditorFileSystem::_thread_func_sources(void *_userdata) { void EditorFileSystem::scan_changes() { if (first_scan || // Prevent a premature changes scan from inhibiting the first full scan - scanning || scanning_changes || thread) { + scanning || scanning_changes || thread.is_started()) { scan_changes_pending = true; set_process(true); return; @@ -1076,12 +1076,12 @@ void EditorFileSystem::scan_changes() { scanning_changes_done = true; emit_signal("sources_changed", sources_changed.size() > 0); } else { - ERR_FAIL_COND(thread_sources); + ERR_FAIL_COND(thread_sources.is_started()); set_process(true); scan_total = 0; Thread::Settings s; s.priority = Thread::PRIORITY_LOW; - thread_sources = Thread::create(_thread_func_sources, this, s); + thread_sources.start(_thread_func_sources, this, s); } } @@ -1092,17 +1092,14 @@ void EditorFileSystem::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { - Thread *active_thread = thread ? thread : thread_sources; - if (use_threads && active_thread) { + Thread &active_thread = thread.is_started() ? thread : thread_sources; + if (use_threads && active_thread.is_started()) { //abort thread if in progress abort_scan = true; while (scanning) { OS::get_singleton()->delay_usec(1000); } - Thread::wait_to_finish(active_thread); - memdelete(active_thread); - thread = nullptr; - thread_sources = nullptr; + active_thread.wait_to_finish(); WARN_PRINT("Scan thread aborted..."); set_process(false); } @@ -1125,9 +1122,7 @@ void EditorFileSystem::_notification(int p_what) { set_process(false); - Thread::wait_to_finish(thread_sources); - memdelete(thread_sources); - thread_sources = nullptr; + thread_sources.wait_to_finish(); if (_update_scan_actions()) { emit_signal("filesystem_changed"); } @@ -1135,7 +1130,7 @@ void EditorFileSystem::_notification(int p_what) { _queue_update_script_classes(); first_scan = false; } - } else if (!scanning && thread) { + } else if (!scanning && thread.is_started()) { set_process(false); if (filesystem) { @@ -1143,9 +1138,7 @@ void EditorFileSystem::_notification(int p_what) { } filesystem = new_filesystem; new_filesystem = nullptr; - Thread::wait_to_finish(thread); - memdelete(thread); - thread = nullptr; + thread.wait_to_finish(); _update_scan_actions(); emit_signal("filesystem_changed"); emit_signal("sources_changed", sources_changed.size() > 0); @@ -2080,11 +2073,9 @@ EditorFileSystem::EditorFileSystem() { filesystem = memnew(EditorFileSystemDirectory); //like, empty filesystem->parent = nullptr; - thread = nullptr; scanning = false; importing = false; use_threads = true; - thread_sources = nullptr; new_filesystem = nullptr; abort_scan = false; diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index c0e11a0402..fa0b89e667 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -127,7 +127,7 @@ class EditorFileSystem : public Node { }; bool use_threads; - Thread *thread; + Thread thread; static void _thread_func(void *_userdata); EditorFileSystemDirectory *new_filesystem; @@ -189,7 +189,7 @@ class EditorFileSystem : public Node { void _scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess *da, const ScanProgress &p_progress); - Thread *thread_sources; + Thread thread_sources; bool scanning_changes; bool scanning_changes_done; diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index df330d8685..ac36b7e762 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -2506,22 +2506,11 @@ void EditorInspector::_update_script_class_properties(const Object &p_object, Li return; } - List<StringName> classes; - Map<StringName, String> paths; + List<Ref<Script>> classes; // NodeC -> NodeB -> NodeA while (script.is_valid()) { - String n = EditorNode::get_editor_data().script_class_get_name(script->get_path()); - if (n.length()) { - classes.push_front(n); - } else if (script->get_path() != String() && script->get_path().find("::") == -1) { - n = script->get_path().get_file(); - classes.push_front(n); - } else { - n = TTR("Built-in script"); - classes.push_front(n); - } - paths[n] = script->get_path(); + classes.push_front(script); script = script->get_base_script(); } @@ -2545,17 +2534,18 @@ void EditorInspector::_update_script_class_properties(const Object &p_object, Li } Set<StringName> added; - for (List<StringName>::Element *E = classes.front(); E; E = E->next()) { - StringName name = E->get(); - String path = paths[name]; - Ref<Script> s; - if (path == String()) { - // Built-in script. It can't be inherited, so must be the script attached to the object. - s = p_object.get_script(); - } else { - s = ResourceLoader::load(path, "Script"); + for (List<Ref<Script>>::Element *E = classes.front(); E; E = E->next()) { + Ref<Script> s = E->get(); + String path = s->get_path(); + String name = EditorNode::get_editor_data().script_class_get_name(path); + if (name.is_empty()) { + if (!path.is_empty() && path.find("::") == -1) { + name = path.get_file(); + } else { + name = TTR("Built-in script"); + } } - ERR_FAIL_COND(!s->is_valid()); + List<PropertyInfo> props; s->get_script_property_list(&props); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index e24cda1932..040f1b1640 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -5494,9 +5494,7 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p int prev_len = 0; - eta.execute_output_thread = Thread::create(_execute_thread, &eta); - - ERR_FAIL_COND_V(!eta.execute_output_thread, 0); + eta.execute_output_thread.start(_execute_thread, &eta); while (!eta.done) { { @@ -5511,8 +5509,7 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p OS::get_singleton()->delay_usec(1000); } - Thread::wait_to_finish(eta.execute_output_thread); - memdelete(eta.execute_output_thread); + eta.execute_output_thread.wait_to_finish(); execute_outputs->add_text("\nExit Code: " + itos(eta.exitcode)); if (p_close_on_errors && eta.exitcode != 0) { diff --git a/editor/editor_node.h b/editor/editor_node.h index 1da162dc9c..356ac0caac 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -108,7 +108,7 @@ public: String path; List<String> args; String output; - Thread *execute_output_thread = nullptr; + Thread execute_output_thread; Mutex execute_output_mutex; int exitcode = 0; volatile bool done = false; diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 29a929d179..8056846f52 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -424,26 +424,23 @@ void EditorResourcePreview::check_for_invalidation(const String &p_path) { } void EditorResourcePreview::start() { - ERR_FAIL_COND_MSG(thread, "Thread already started."); - thread = Thread::create(_thread_func, this); + ERR_FAIL_COND_MSG(thread.is_started(), "Thread already started."); + thread.start(_thread_func, this); } void EditorResourcePreview::stop() { - if (thread) { + if (thread.is_started()) { exit = true; preview_sem.post(); while (!exited) { OS::get_singleton()->delay_usec(10000); RenderingServer::get_singleton()->sync(); //sync pending stuff, as thread may be blocked on visual server } - Thread::wait_to_finish(thread); - memdelete(thread); - thread = nullptr; + thread.wait_to_finish(); } } EditorResourcePreview::EditorResourcePreview() { - thread = nullptr; singleton = this; order = 0; exit = false; diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h index c119ccd99f..99c48967d8 100644 --- a/editor/editor_resource_preview.h +++ b/editor/editor_resource_preview.h @@ -70,7 +70,7 @@ class EditorResourcePreview : public Node { Mutex preview_mutex; Semaphore preview_sem; - Thread *thread; + Thread thread; volatile bool exit; volatile bool exited; diff --git a/editor/fileserver/editor_file_server.cpp b/editor/fileserver/editor_file_server.cpp index 02bbeb57c7..07edae833d 100644 --- a/editor/fileserver/editor_file_server.cpp +++ b/editor/fileserver/editor_file_server.cpp @@ -43,7 +43,7 @@ void EditorFileServer::_close_client(ClientData *cd) { cd->connection->disconnect_from_host(); { MutexLock lock(cd->efs->wait_mutex); - cd->efs->to_wait.insert(cd->thread); + cd->efs->to_wait.insert(&cd->thread); } while (cd->files.size()) { memdelete(cd->files.front()->get()); @@ -278,7 +278,7 @@ void EditorFileServer::_thread_start(void *s) { cd->connection = self->server->take_connection(); cd->efs = self; cd->quit = false; - cd->thread = Thread::create(_subthread_start, cd); + cd->thread.start(_subthread_start, cd); } } @@ -287,8 +287,7 @@ void EditorFileServer::_thread_start(void *s) { Thread *w = self->to_wait.front()->get(); self->to_wait.erase(w); self->wait_mutex.unlock(); - Thread::wait_to_finish(w); - memdelete(w); + w->wait_to_finish(); self->wait_mutex.lock(); } self->wait_mutex.unlock(); @@ -317,7 +316,7 @@ EditorFileServer::EditorFileServer() { quit = false; active = false; cmd = CMD_NONE; - thread = Thread::create(_thread_start, this); + thread.start(_thread_start, this); EDITOR_DEF("filesystem/file_server/port", 6010); EDITOR_DEF("filesystem/file_server/password", ""); @@ -325,6 +324,5 @@ EditorFileServer::EditorFileServer() { EditorFileServer::~EditorFileServer() { quit = true; - Thread::wait_to_finish(thread); - memdelete(thread); + thread.wait_to_finish(); } diff --git a/editor/fileserver/editor_file_server.h b/editor/fileserver/editor_file_server.h index 267b129bda..e4c8327d76 100644 --- a/editor/fileserver/editor_file_server.h +++ b/editor/fileserver/editor_file_server.h @@ -47,7 +47,7 @@ class EditorFileServer : public Object { }; struct ClientData { - Thread *thread = nullptr; + Thread thread; Ref<StreamPeerTCP> connection; Map<int, FileAccess *> files; EditorFileServer *efs = nullptr; @@ -61,7 +61,7 @@ class EditorFileServer : public Object { static void _subthread_start(void *s); Mutex wait_mutex; - Thread *thread; + Thread thread; static void _thread_start(void *); bool quit; Command cmd; diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index fb821a0856..ea6afe7f84 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -1737,114 +1737,220 @@ void VisualShaderEditor::_add_curve_node(const String &p_path) { curve->set_texture(ResourceLoader::load(p_path)); } -VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) { - ERR_FAIL_INDEX_V(p_idx, add_options.size(), nullptr); +void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) { + // FLOAT_OP + { + VisualShaderNodeFloatOp *floatOp = Object::cast_to<VisualShaderNodeFloatOp>(p_node); - Ref<VisualShaderNode> vsnode; + if (floatOp) { + floatOp->set_operator((VisualShaderNodeFloatOp::Operator)p_op_idx); + return; + } + } - bool is_custom = add_options[p_idx].is_custom; + // FLOAT_FUNC + { + VisualShaderNodeFloatFunc *floatFunc = Object::cast_to<VisualShaderNodeFloatFunc>(p_node); - if (!is_custom && add_options[p_idx].type != String()) { - VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(add_options[p_idx].type)); - ERR_FAIL_COND_V(!vsn, nullptr); + if (floatFunc) { + floatFunc->set_function((VisualShaderNodeFloatFunc::Function)p_op_idx); + return; + } + } - VisualShaderNodeFloatConstant *constant = Object::cast_to<VisualShaderNodeFloatConstant>(vsn); + // VECTOR_OP + { + VisualShaderNodeVectorOp *vecOp = Object::cast_to<VisualShaderNodeVectorOp>(p_node); - if (constant) { - if ((int)add_options[p_idx].value != -1) { - constant->set_constant(add_options[p_idx].value); - } + if (vecOp) { + vecOp->set_operator((VisualShaderNodeVectorOp::Operator)p_op_idx); + return; } + } - if (p_op_idx != -1) { - VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsn); + // VECTOR_FUNC + { + VisualShaderNodeVectorFunc *vecFunc = Object::cast_to<VisualShaderNodeVectorFunc>(p_node); - if (input) { - input->set_input_name(add_options[p_idx].sub_func_str); - } + if (vecFunc) { + vecFunc->set_function((VisualShaderNodeVectorFunc::Function)p_op_idx); + return; + } + } - VisualShaderNodeIs *is = Object::cast_to<VisualShaderNodeIs>(vsn); + // COLOR_OP + { + VisualShaderNodeColorOp *colorOp = Object::cast_to<VisualShaderNodeColorOp>(p_node); - if (is) { - is->set_function((VisualShaderNodeIs::Function)p_op_idx); - } + if (colorOp) { + colorOp->set_operator((VisualShaderNodeColorOp::Operator)p_op_idx); + return; + } + } - VisualShaderNodeCompare *cmp = Object::cast_to<VisualShaderNodeCompare>(vsn); + // COLOR_FUNC + { + VisualShaderNodeColorFunc *colorFunc = Object::cast_to<VisualShaderNodeColorFunc>(p_node); - if (cmp) { - cmp->set_function((VisualShaderNodeCompare::Function)p_op_idx); - } + if (colorFunc) { + colorFunc->set_function((VisualShaderNodeColorFunc::Function)p_op_idx); + return; + } + } - VisualShaderNodeColorOp *colorOp = Object::cast_to<VisualShaderNodeColorOp>(vsn); + // INT_OP + { + VisualShaderNodeIntOp *intOp = Object::cast_to<VisualShaderNodeIntOp>(p_node); - if (colorOp) { - colorOp->set_operator((VisualShaderNodeColorOp::Operator)p_op_idx); - } + if (intOp) { + intOp->set_operator((VisualShaderNodeIntOp::Operator)p_op_idx); + return; + } + } - VisualShaderNodeColorFunc *colorFunc = Object::cast_to<VisualShaderNodeColorFunc>(vsn); + // INT_FUNC + { + VisualShaderNodeIntFunc *intFunc = Object::cast_to<VisualShaderNodeIntFunc>(p_node); - if (colorFunc) { - colorFunc->set_function((VisualShaderNodeColorFunc::Function)p_op_idx); - } + if (intFunc) { + intFunc->set_function((VisualShaderNodeIntFunc::Function)p_op_idx); + return; + } + } - VisualShaderNodeFloatOp *floatOp = Object::cast_to<VisualShaderNodeFloatOp>(vsn); + // TRANSFORM_FUNC + { + VisualShaderNodeTransformFunc *matFunc = Object::cast_to<VisualShaderNodeTransformFunc>(p_node); - if (floatOp) { - floatOp->set_operator((VisualShaderNodeFloatOp::Operator)p_op_idx); - } + if (matFunc) { + matFunc->set_function((VisualShaderNodeTransformFunc::Function)p_op_idx); + return; + } + } - VisualShaderNodeIntOp *intOp = Object::cast_to<VisualShaderNodeIntOp>(vsn); + // IS + { + VisualShaderNodeIs *is = Object::cast_to<VisualShaderNodeIs>(p_node); - if (intOp) { - intOp->set_operator((VisualShaderNodeIntOp::Operator)p_op_idx); - } + if (is) { + is->set_function((VisualShaderNodeIs::Function)p_op_idx); + return; + } + } - VisualShaderNodeFloatFunc *floatFunc = Object::cast_to<VisualShaderNodeFloatFunc>(vsn); + // COMPARE + { + VisualShaderNodeCompare *cmp = Object::cast_to<VisualShaderNodeCompare>(p_node); - if (floatFunc) { - floatFunc->set_function((VisualShaderNodeFloatFunc::Function)p_op_idx); - } + if (cmp) { + cmp->set_function((VisualShaderNodeCompare::Function)p_op_idx); + return; + } + } - VisualShaderNodeIntFunc *intFunc = Object::cast_to<VisualShaderNodeIntFunc>(vsn); + // DERIVATIVE + { + VisualShaderNodeScalarDerivativeFunc *sderFunc = Object::cast_to<VisualShaderNodeScalarDerivativeFunc>(p_node); - if (intFunc) { - intFunc->set_function((VisualShaderNodeIntFunc::Function)p_op_idx); - } + if (sderFunc) { + sderFunc->set_function((VisualShaderNodeScalarDerivativeFunc::Function)p_op_idx); + return; + } - VisualShaderNodeVectorOp *vecOp = Object::cast_to<VisualShaderNodeVectorOp>(vsn); + VisualShaderNodeVectorDerivativeFunc *vderFunc = Object::cast_to<VisualShaderNodeVectorDerivativeFunc>(p_node); - if (vecOp) { - vecOp->set_operator((VisualShaderNodeVectorOp::Operator)p_op_idx); - } + if (vderFunc) { + vderFunc->set_function((VisualShaderNodeVectorDerivativeFunc::Function)p_op_idx); + return; + } + } - VisualShaderNodeVectorFunc *vecFunc = Object::cast_to<VisualShaderNodeVectorFunc>(vsn); + // MIX + { + VisualShaderNodeMix *mix = Object::cast_to<VisualShaderNodeMix>(p_node); - if (vecFunc) { - vecFunc->set_function((VisualShaderNodeVectorFunc::Function)p_op_idx); - } + if (mix) { + mix->set_op_type((VisualShaderNodeMix::OpType)p_op_idx); + return; + } + } - VisualShaderNodeTransformFunc *matFunc = Object::cast_to<VisualShaderNodeTransformFunc>(vsn); + // CLAMP + { + VisualShaderNodeClamp *clampFunc = Object::cast_to<VisualShaderNodeClamp>(p_node); - if (matFunc) { - matFunc->set_function((VisualShaderNodeTransformFunc::Function)p_op_idx); - } + if (clampFunc) { + clampFunc->set_op_type((VisualShaderNodeClamp::OpType)p_op_idx); + return; + } + } - VisualShaderNodeScalarDerivativeFunc *sderFunc = Object::cast_to<VisualShaderNodeScalarDerivativeFunc>(vsn); + // SWITCH + { + VisualShaderNodeSwitch *switchFunc = Object::cast_to<VisualShaderNodeSwitch>(p_node); - if (sderFunc) { - sderFunc->set_function((VisualShaderNodeScalarDerivativeFunc::Function)p_op_idx); - } + if (switchFunc) { + switchFunc->set_op_type((VisualShaderNodeSwitch::OpType)p_op_idx); + return; + } + } - VisualShaderNodeVectorDerivativeFunc *vderFunc = Object::cast_to<VisualShaderNodeVectorDerivativeFunc>(vsn); + // SMOOTHSTEP + { + VisualShaderNodeSmoothStep *smoothStepFunc = Object::cast_to<VisualShaderNodeSmoothStep>(p_node); - if (vderFunc) { - vderFunc->set_function((VisualShaderNodeVectorDerivativeFunc::Function)p_op_idx); - } + if (smoothStepFunc) { + smoothStepFunc->set_op_type((VisualShaderNodeSmoothStep::OpType)p_op_idx); + return; + } + } - VisualShaderNodeMultiplyAdd *fmaFunc = Object::cast_to<VisualShaderNodeMultiplyAdd>(vsn); + // STEP + { + VisualShaderNodeStep *stepFunc = Object::cast_to<VisualShaderNodeStep>(p_node); + + if (stepFunc) { + stepFunc->set_op_type((VisualShaderNodeStep::OpType)p_op_idx); + return; + } + } + + // MULTIPLY_ADD + { + VisualShaderNodeMultiplyAdd *fmaFunc = Object::cast_to<VisualShaderNodeMultiplyAdd>(p_node); - if (fmaFunc) { - fmaFunc->set_op_type((VisualShaderNodeMultiplyAdd::OpType)p_op_idx); + if (fmaFunc) { + fmaFunc->set_op_type((VisualShaderNodeMultiplyAdd::OpType)p_op_idx); + } + } +} + +VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) { + ERR_FAIL_INDEX_V(p_idx, add_options.size(), nullptr); + + Ref<VisualShaderNode> vsnode; + + bool is_custom = add_options[p_idx].is_custom; + + if (!is_custom && add_options[p_idx].type != String()) { + VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(add_options[p_idx].type)); + ERR_FAIL_COND_V(!vsn, nullptr); + + VisualShaderNodeFloatConstant *constant = Object::cast_to<VisualShaderNodeFloatConstant>(vsn); + + if (constant) { + if ((int)add_options[p_idx].value != -1) { + constant->set_constant(add_options[p_idx].value); + } + } else { + if (p_op_idx != -1) { + VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsn); + + if (input) { + input->set_input_name(add_options[p_idx].sub_func_str); + } else { + _setup_node(vsn, p_op_idx); + } } } @@ -1923,11 +2029,22 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) { int _from_node = id_to_use; int _from_slot = 0; - if (created_expression_port || visual_shader->is_port_types_compatible(vsnode->get_output_port_type(_from_slot), input_port_type)) { + if (created_expression_port) { undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot); undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, _from_node, _from_slot, to_node, to_slot); undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot); undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, _from_node, _from_slot, to_node, to_slot); + } else { + // Attempting to connect to the first correct port. + for (int i = 0; i < vsnode->get_output_port_count(); i++) { + if (visual_shader->is_port_types_compatible(vsnode->get_output_port_type(i), input_port_type)) { + undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, _from_node, i, to_node, to_slot); + undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, _from_node, i, to_node, to_slot); + undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, _from_node, i, to_node, to_slot); + undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, _from_node, i, to_node, to_slot); + break; + } + } } } } else if (from_node != -1 && from_slot != -1) { @@ -1945,11 +2062,22 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) { int _to_node = id_to_use; int _to_slot = 0; - if (created_expression_port || visual_shader->is_port_types_compatible(output_port_type, vsnode->get_input_port_type(_to_slot))) { + if (created_expression_port) { undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot); undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot); undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, _to_slot); undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, _to_slot); + } else { + // Attempting to connect to the first correct port. + for (int i = 0; i < vsnode->get_input_port_count(); i++) { + if (visual_shader->is_port_types_compatible(output_port_type, vsnode->get_input_port_type(i))) { + undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, i); + undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, i); + undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_slot, _to_node, i); + undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_slot, _to_node, i); + break; + } + } } } } @@ -3446,8 +3574,11 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("LessThan", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than (<)")), VisualShaderNodeCompare::FUNC_LESS_THAN, VisualShaderNode::PORT_TYPE_BOOLEAN)); add_options.push_back(AddOption("LessThanEqual", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than or Equal (<=)")), VisualShaderNodeCompare::FUNC_LESS_THAN_EQUAL, VisualShaderNode::PORT_TYPE_BOOLEAN)); add_options.push_back(AddOption("NotEqual", "Conditional", "Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Not Equal (!=)")), VisualShaderNodeCompare::FUNC_NOT_EQUAL, VisualShaderNode::PORT_TYPE_BOOLEAN)); - add_options.push_back(AddOption("Switch", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated vector if the provided boolean value is true or false."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("SwitchS", "Conditional", "Functions", "VisualShaderNodeScalarSwitch", TTR("Returns an associated scalar if the provided boolean value is true or false."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Switch", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated vector if the provided boolean value is true or false."), VisualShaderNodeSwitch::OP_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("SwitchBool", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated boolean if the provided boolean value is true or false."), VisualShaderNodeSwitch::OP_TYPE_BOOLEAN, VisualShaderNode::PORT_TYPE_BOOLEAN)); + add_options.push_back(AddOption("SwitchFloat", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated floating-point scalar if the provided boolean value is true or false."), VisualShaderNodeSwitch::OP_TYPE_FLOAT, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("SwitchInt", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated integer scalar if the provided boolean value is true or false."), VisualShaderNodeSwitch::OP_TYPE_INT, VisualShaderNode::PORT_TYPE_SCALAR_INT)); + add_options.push_back(AddOption("SwitchTransform", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated transform if the provided boolean value is true or false."), VisualShaderNodeSwitch::OP_TYPE_TRANSFORM, VisualShaderNode::PORT_TYPE_TRANSFORM)); add_options.push_back(AddOption("Compare", "Conditional", "Common", "VisualShaderNodeCompare", TTR("Returns the boolean result of the comparison between two parameters."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN)); add_options.push_back(AddOption("Is", "Conditional", "Common", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between INF (or NaN) and a scalar parameter."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN)); @@ -3670,8 +3801,8 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("ATan2", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the arc-tangent of the parameters."), VisualShaderNodeFloatOp::OP_ATAN2, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("ATanH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), VisualShaderNodeFloatFunc::FUNC_ATANH, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Ceil", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), VisualShaderNodeFloatFunc::FUNC_CEIL, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Clamp", "Scalar", "Functions", "VisualShaderNodeScalarClamp", TTR("Constrains a value to lie between two further values."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Clamp", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Constrains a value to lie between two further values."), VisualShaderNodeIntFunc::FUNC_CLAMP, VisualShaderNode::PORT_TYPE_SCALAR_INT)); + add_options.push_back(AddOption("Clamp", "Scalar", "Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), VisualShaderNodeClamp::OP_TYPE_FLOAT, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Clamp", "Scalar", "Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), VisualShaderNodeClamp::OP_TYPE_INT, VisualShaderNode::PORT_TYPE_SCALAR_INT)); add_options.push_back(AddOption("Cos", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the cosine of the parameter."), VisualShaderNodeFloatFunc::FUNC_COS, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("CosH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic cosine of the parameter."), VisualShaderNodeFloatFunc::FUNC_COSH, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Degrees", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in radians to degrees."), VisualShaderNodeFloatFunc::FUNC_DEGREES, VisualShaderNode::PORT_TYPE_SCALAR)); @@ -3684,7 +3815,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Log2", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Base-2 logarithm."), VisualShaderNodeFloatFunc::FUNC_LOG2, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Max", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the greater of two values."), VisualShaderNodeFloatOp::OP_MAX, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Min", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Returns the lesser of two values."), VisualShaderNodeFloatOp::OP_MIN, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Mix", "Scalar", "Functions", "VisualShaderNodeScalarInterp", TTR("Linear interpolation between two scalars."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Mix", "Scalar", "Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two scalars."), VisualShaderNodeMix::OP_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("MultiplyAdd", "Scalar", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on scalars."), VisualShaderNodeMultiplyAdd::OP_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeFloatFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Negate", "Scalar", "Functions", "VisualShaderNodeIntFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeIntFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_SCALAR_INT)); @@ -3700,8 +3831,8 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Sin", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeFloatFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("SinH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic sine of the parameter."), VisualShaderNodeFloatFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Sqrt", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeFloatFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("SmoothStep", "Scalar", "Functions", "VisualShaderNodeScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeFloatOp", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeFloatOp::OP_STEP, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("SmoothStep", "Scalar", "Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), VisualShaderNodeSmoothStep::OP_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeStep::OP_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Tan", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeFloatFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("TanH", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic tangent of the parameter."), VisualShaderNodeFloatFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Trunc", "Scalar", "Functions", "VisualShaderNodeFloatFunc", TTR("Finds the truncated value of the parameter."), VisualShaderNodeFloatFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_SCALAR)); @@ -3785,7 +3916,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("ATan2", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the arc-tangent of the parameters."), VisualShaderNodeVectorOp::OP_ATAN2, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("ATanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the inverse hyperbolic tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_ATANH, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Ceil", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer that is greater than or equal to the parameter."), VisualShaderNodeVectorFunc::FUNC_CEIL, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("Clamp", "Vector", "Functions", "VisualShaderNodeVectorClamp", TTR("Constrains a value to lie between two further values."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("Clamp", "Vector", "Functions", "VisualShaderNodeClamp", TTR("Constrains a value to lie between two further values."), VisualShaderNodeClamp::OP_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Cos", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_COS, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("CosH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic cosine of the parameter."), VisualShaderNodeVectorFunc::FUNC_COSH, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Cross", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Calculates the cross product of two vectors."), VisualShaderNodeVectorOp::OP_CROSS, VisualShaderNode::PORT_TYPE_VECTOR)); @@ -3803,8 +3934,8 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Log2", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Base-2 logarithm."), VisualShaderNodeVectorFunc::FUNC_LOG2, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Max", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the greater of two values."), VisualShaderNodeVectorOp::OP_MAX, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Min", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the lesser of two values."), VisualShaderNodeVectorOp::OP_MIN, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("Mix", "Vector", "Functions", "VisualShaderNodeVectorInterp", TTR("Linear interpolation between two vectors."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("MixS", "Vector", "Functions", "VisualShaderNodeVectorScalarMix", TTR("Linear interpolation between two vectors using scalar."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("Mix", "Vector", "Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors."), VisualShaderNodeMix::OP_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("MixS", "Vector", "Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors using scalar."), VisualShaderNodeMix::OP_TYPE_VECTOR_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("MultiplyAdd", "Vector", "Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Negate", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Normalize", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNode::PORT_TYPE_VECTOR)); @@ -3821,10 +3952,10 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Sin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("SinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Sqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeVectorFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeVectorSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeVectorScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("Step", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeVectorOp::OP_STEP, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeVectorScalarStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), VisualShaderNodeSmoothStep::OP_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), VisualShaderNodeSmoothStep::OP_TYPE_VECTOR_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("Step", "Vector", "Functions", "VisualShaderNodeStep", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeStep::OP_TYPE_VECTOR, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeStep::OP_TYPE_VECTOR_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Tan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("TanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Trunc", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the truncated value of the parameter."), VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_VECTOR)); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 72ed46b35c..182bed6ba6 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -276,6 +276,7 @@ class VisualShaderEditor : public VBoxContainer { void _add_texture3d_node(const String &p_path); void _add_curve_node(const String &p_path); + void _setup_node(VisualShaderNode *p_node, int p_op_idx); VisualShaderNode *_add_node(int p_idx, int p_op_idx = -1); void _update_options_menu(); void _set_mode(int p_which); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index e46b2711c1..a0eb923bc5 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1375,11 +1375,10 @@ void ProjectList::create_project_item_control(int p_index) { vb->add_child(path_hb); Button *show = memnew(Button); - // Display a folder icon if the project directory can be opened, or a "broken file" icon if it can't + // Display a folder icon if the project directory can be opened, or a "broken file" icon if it can't. show->set_icon(get_theme_icon(!item.missing ? "Load" : "FileBroken", "EditorIcons")); - show->set_flat(true); if (!item.grayed) { - // Don't make the icon less prominent if the parent is already grayed out + // Don't make the icon less prominent if the parent is already grayed out. show->set_modulate(Color(1, 1, 1, 0.5)); } path_hb->add_child(show); diff --git a/main/main.cpp b/main/main.cpp index a9354b8011..657a6ad822 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -516,8 +516,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph MAIN_PRINT("Main: Initialize Globals"); - Thread::_main_thread_id = Thread::get_caller_id(); - globals = memnew(ProjectSettings); input_map = memnew(InputMap); @@ -1471,9 +1469,11 @@ Error Main::setup2(Thread::ID p_main_tid_override) { // Print engine name and version print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); +#if !defined(NO_THREADS) if (p_main_tid_override) { - Thread::_main_thread_id = p_main_tid_override; + Thread::main_thread_id = p_main_tid_override; } +#endif /* Determine text driver */ diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp index 6661dbbb0b..43faa52218 100644 --- a/modules/cvtt/image_compress_cvtt.cpp +++ b/modules/cvtt/image_compress_cvtt.cpp @@ -267,12 +267,13 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::UsedChann job_queue.num_tasks = static_cast<uint32_t>(tasks.size()); for (int i = 0; i < num_job_threads; i++) { - threads_wb[i] = Thread::create(_digest_job_queue, &job_queue); + threads_wb[i] = memnew(Thread); + threads_wb[i]->start(_digest_job_queue, &job_queue); } _digest_job_queue(&job_queue); for (int i = 0; i < num_job_threads; i++) { - Thread::wait_to_finish(threads_wb[i]); + threads_wb[i]->wait_to_finish(); memdelete(threads_wb[i]); } } diff --git a/modules/gdnative/android/android_gdn.cpp b/modules/gdnative/android/android_gdn.cpp index a48e51a390..fe3b3e7e12 100644 --- a/modules/gdnative/android/android_gdn.cpp +++ b/modules/gdnative/android/android_gdn.cpp @@ -48,7 +48,7 @@ extern "C" { JNIEnv *GDAPI godot_android_get_env() { #ifdef __ANDROID__ - return ThreadAndroid::get_env(); + return get_jni_env(); #else return nullptr; #endif diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp index aac9cb7fd7..12ed56a568 100644 --- a/modules/gdscript/language_server/gdscript_language_server.cpp +++ b/modules/gdscript/language_server/gdscript_language_server.cpp @@ -36,7 +36,6 @@ #include "editor/editor_node.h" GDScriptLanguageServer::GDScriptLanguageServer() { - thread = nullptr; thread_running = false; started = false; @@ -87,9 +86,8 @@ void GDScriptLanguageServer::start() { if (protocol.start(port, IP_Address("127.0.0.1")) == OK) { EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR); if (use_thread) { - ERR_FAIL_COND(thread != nullptr); thread_running = true; - thread = Thread::create(GDScriptLanguageServer::thread_main, this); + thread.start(GDScriptLanguageServer::thread_main, this); } set_process_internal(!use_thread); started = true; @@ -98,11 +96,9 @@ void GDScriptLanguageServer::start() { void GDScriptLanguageServer::stop() { if (use_thread) { - ERR_FAIL_COND(nullptr == thread); + ERR_FAIL_COND(!thread.is_started()); thread_running = false; - Thread::wait_to_finish(thread); - memdelete(thread); - thread = nullptr; + thread.wait_to_finish(); } protocol.stop(); started = false; diff --git a/modules/gdscript/language_server/gdscript_language_server.h b/modules/gdscript/language_server/gdscript_language_server.h index 218f42199e..7b7837a463 100644 --- a/modules/gdscript/language_server/gdscript_language_server.h +++ b/modules/gdscript/language_server/gdscript_language_server.h @@ -40,7 +40,7 @@ class GDScriptLanguageServer : public EditorPlugin { GDScriptLanguageProtocol protocol; - Thread *thread; + Thread thread; bool thread_running; bool started; bool use_thread; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index 4dc182fb73..98efa89ef0 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -462,18 +462,18 @@ namespace Godot } // <summary> - // Hash the string and return a 32 bits integer. + // Hash the string and return a 32 bits unsigned integer. // </summary> - public static int Hash(this string instance) + public static uint Hash(this string instance) { - int index = 0; - int hashv = 5381; - int c; + uint hash = 5381; - while ((c = instance[index++]) != 0) - hashv = (hashv << 5) + hashv + c; // hash * 33 + c + foreach(uint c in instance) + { + hash = (hash << 5) + hash + c; // hash * 33 + c + } - return hashv; + return hash; } /// <summary> diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp index 59e1385e7e..cba29d63cd 100644 --- a/modules/mono/mono_gd/support/android_support.cpp +++ b/modules/mono/mono_gd/support/android_support.cpp @@ -109,7 +109,7 @@ bool jni_exception_check(JNIEnv *p_env) { String app_native_lib_dir_cache; String determine_app_native_lib_dir() { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); ScopedLocalRef<jclass> activityThreadClass(env, env->FindClass("android/app/ActivityThread")); jmethodID currentActivityThread = env->GetStaticMethodID(activityThreadClass, "currentActivityThread", "()Landroid/app/ActivityThread;"); @@ -253,7 +253,7 @@ int32_t get_build_version_sdk_int() { // android.os.Build.VERSION.SDK_INT if (build_version_sdk_int == 0) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jclass versionClass = env->FindClass("android/os/Build$VERSION"); ERR_FAIL_NULL_V(versionClass, 0); @@ -281,7 +281,7 @@ MonoBoolean _gd_mono_init_cert_store() { // return false; // } - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); ScopedLocalRef<jclass> keyStoreClass(env, env->FindClass("java/security/KeyStore")); @@ -322,7 +322,7 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) { return nullptr; } - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); ScopedLocalRef<jstring> js_alias(env, env->NewStringUTF(alias_utf8)); mono_free(alias_utf8); @@ -380,7 +380,7 @@ void cleanup() { if (godot_dl_handle) gd_mono_android_dlclose(godot_dl_handle, nullptr); - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); if (certStore) { env->DeleteGlobalRef(certStore); @@ -437,7 +437,7 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_up_state(const char *r_is_up = 0; - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jclass networkInterfaceClass = env->FindClass("java/net/NetworkInterface"); ERR_FAIL_NULL_V(networkInterfaceClass, 0); @@ -469,7 +469,7 @@ GD_PINVOKE_EXPORT mono_bool _monodroid_get_network_interface_supports_multicast( *r_supports_multicast = 0; - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jclass networkInterfaceClass = env->FindClass("java/net/NetworkInterface"); ERR_FAIL_NULL_V(networkInterfaceClass, 0); @@ -507,7 +507,7 @@ static void interop_get_active_network_dns_servers(char **r_dns_servers, int *dn CRASH_COND(get_build_version_sdk_int() < 23); #endif - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); GodotJavaWrapper *godot_java = ((OS_Android *)OS::get_singleton())->get_godot_java(); jobject activity = godot_java->get_activity(); @@ -648,7 +648,7 @@ GD_PINVOKE_EXPORT const char *_monodroid_timezone_get_default_id() { // // TimeZone.getDefault().getID() - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); ScopedLocalRef<jclass> timeZoneClass(env, env->FindClass("java/util/TimeZone")); ERR_FAIL_NULL_V(timeZoneClass, nullptr); diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp index 1d75e46747..30a0ca3464 100644 --- a/modules/opensimplex/noise_texture.cpp +++ b/modules/opensimplex/noise_texture.cpp @@ -34,7 +34,6 @@ NoiseTexture::NoiseTexture() { update_queued = false; - noise_thread = nullptr; regen_queued = false; first_time = true; @@ -52,10 +51,7 @@ NoiseTexture::~NoiseTexture() { if (texture.is_valid()) { RS::get_singleton()->free(texture); } - if (noise_thread) { - Thread::wait_to_finish(noise_thread); - memdelete(noise_thread); - } + noise_thread.wait_to_finish(); } void NoiseTexture::_bind_methods() { @@ -109,11 +105,9 @@ void NoiseTexture::_set_texture_data(const Ref<Image> &p_image) { void NoiseTexture::_thread_done(const Ref<Image> &p_image) { _set_texture_data(p_image); - Thread::wait_to_finish(noise_thread); - memdelete(noise_thread); - noise_thread = nullptr; + noise_thread.wait_to_finish(); if (regen_queued) { - noise_thread = Thread::create(_thread_function, this); + noise_thread.start(_thread_function, this); regen_queued = false; } } @@ -165,8 +159,8 @@ void NoiseTexture::_update_texture() { use_thread = false; #endif if (use_thread) { - if (!noise_thread) { - noise_thread = Thread::create(_thread_function, this); + if (!noise_thread.is_started()) { + noise_thread.start(_thread_function, this); regen_queued = false; } else { regen_queued = true; diff --git a/modules/opensimplex/noise_texture.h b/modules/opensimplex/noise_texture.h index 9f6e2cbf43..170275bd2e 100644 --- a/modules/opensimplex/noise_texture.h +++ b/modules/opensimplex/noise_texture.h @@ -45,7 +45,7 @@ class NoiseTexture : public Texture2D { private: Ref<Image> data; - Thread *noise_thread; + Thread noise_thread; bool first_time; bool update_queued; diff --git a/modules/text_server_adv/bitmap_font_adv.cpp b/modules/text_server_adv/bitmap_font_adv.cpp index 01fa94aa7c..51cc242348 100644 --- a/modules/text_server_adv/bitmap_font_adv.cpp +++ b/modules/text_server_adv/bitmap_font_adv.cpp @@ -540,7 +540,7 @@ Vector2 BitmapFontDataAdvanced::draw_glyph(RID p_canvas, int p_size, const Vecto ERR_FAIL_COND_V(c == nullptr, Vector2()); ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), Vector2()); if (c->texture_idx != -1) { - Point2 cpos = p_pos; + Point2i cpos = p_pos; cpos += c->align * (float(p_size) / float(base_size)); cpos.y -= ascent * (float(p_size) / float(base_size)); if (RenderingServer::get_singleton() != nullptr) { diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp index fcefa60d98..5a16158c0f 100644 --- a/modules/text_server_adv/dynamic_font_adv.cpp +++ b/modules/text_server_adv/dynamic_font_adv.cpp @@ -946,7 +946,7 @@ Vector2 DynamicFontDataAdvanced::draw_glyph(RID p_canvas, int p_size, const Vect ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2()); if (ch.texture_idx != -1) { - Point2 cpos = p_pos; + Point2i cpos = p_pos; cpos += ch.align; Color modulate = p_color; if (FT_HAS_COLOR(fds->face)) { @@ -977,7 +977,7 @@ Vector2 DynamicFontDataAdvanced::draw_glyph_outline(RID p_canvas, int p_size, in ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2()); if (ch.texture_idx != -1) { - Point2 cpos = p_pos; + Point2i cpos = p_pos; cpos += ch.align; Color modulate = p_color; if (FT_HAS_COLOR(fds->face)) { diff --git a/modules/text_server_fb/bitmap_font_fb.cpp b/modules/text_server_fb/bitmap_font_fb.cpp index 5c691b7bbd..6bc838bd6a 100644 --- a/modules/text_server_fb/bitmap_font_fb.cpp +++ b/modules/text_server_fb/bitmap_font_fb.cpp @@ -321,7 +321,7 @@ Vector2 BitmapFontDataFallback::draw_glyph(RID p_canvas, int p_size, const Vecto ERR_FAIL_COND_V(c == nullptr, Vector2()); ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), Vector2()); if (c->texture_idx != -1) { - Point2 cpos = p_pos; + Point2i cpos = p_pos; cpos += c->align * (float(p_size) / float(base_size)); cpos.y -= ascent * (float(p_size) / float(base_size)); diff --git a/modules/text_server_fb/dynamic_font_fb.cpp b/modules/text_server_fb/dynamic_font_fb.cpp index 4eecba6ae8..df7756cbd0 100644 --- a/modules/text_server_fb/dynamic_font_fb.cpp +++ b/modules/text_server_fb/dynamic_font_fb.cpp @@ -626,7 +626,7 @@ Vector2 DynamicFontDataFallback::draw_glyph(RID p_canvas, int p_size, const Vect ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2()); if (ch.texture_idx != -1) { - Point2 cpos = p_pos; + Point2i cpos = p_pos; cpos += ch.align; Color modulate = p_color; @@ -658,7 +658,7 @@ Vector2 DynamicFontDataFallback::draw_glyph_outline(RID p_canvas, int p_size, in ERR_FAIL_COND_V(ch.texture_idx < -1 || ch.texture_idx >= fds->textures.size(), Vector2()); if (ch.texture_idx != -1) { - Point2 cpos = p_pos; + Point2i cpos = p_pos; cpos += ch.align; Color modulate = p_color; diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index 243265769e..1026d58b85 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -140,9 +140,7 @@ void VideoStreamPlaybackTheora::clear() { #ifdef THEORA_USE_THREAD_STREAMING thread_exit = true; thread_sem->post(); //just in case - Thread::wait_to_finish(thread); - memdelete(thread); - thread = nullptr; + thread.wait_to_finish(); ring_buffer.clear(); #endif @@ -181,7 +179,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { int read = file->get_buffer(read_buffer.ptr(), to_read); ring_buffer.write(read_buffer.ptr(), read); - thread = Thread::create(_streaming_thread, this); + thread.start(_streaming_thread, this); #endif @@ -669,7 +667,6 @@ VideoStreamPlaybackTheora::VideoStreamPlaybackTheora() { ring_buffer.resize(rb_power); read_buffer.resize(RB_SIZE_KB * 1024); thread_sem = Semaphore::create(); - thread = nullptr; thread_exit = false; thread_eof = false; diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index d2036b5cb4..c315d682da 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -112,7 +112,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback { Vector<uint8_t> read_buffer; bool thread_eof; Semaphore *thread_sem; - Thread *thread; + Thread thread; volatile bool thread_exit; static void _streaming_thread(void *ud); diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml index 9469e4d055..2407d44496 100644 --- a/modules/webxr/doc_classes/WebXRInterface.xml +++ b/modules/webxr/doc_classes/WebXRInterface.xml @@ -10,77 +10,79 @@ Since WebXR is based on Javascript, it makes extensive use of callbacks, which means that [WebXRInterface] is forced to use signals, where other AR/VR interfaces would instead use functions that return a result immediately. This makes [WebXRInterface] quite a bit more complicated to intialize than other AR/VR interfaces. Here's the minimum code required to start an immersive VR session: [codeblock] - var webxr_interface - var vr_supported = false + extends Node3D - func _ready(): - # We assume this node has a button as a child. - # This button is for the user to consent to entering immersive VR mode. - $Button.connect("pressed", self, "_on_Button_pressed") + var webxr_interface + var vr_supported = false - webxr_interface = XRServer.find_interface("WebXR") - if webxr_interface: - # WebXR uses a lot of asynchronous callbacks, so we connect to various - # signals in order to receive them. - webxr_interface.connect("session_supported", self, "_webxr_session_supported") - webxr_interface.connect("session_started", self, "_webxr_session_started") - webxr_interface.connect("session_ended", self, "_webxr_session_ended") - webxr_interface.connect("session_failed", self, "_webxr_session_failed") + func _ready(): + # We assume this node has a button as a child. + # This button is for the user to consent to entering immersive VR mode. + $Button.connect("pressed", self, "_on_Button_pressed") - # This returns immediately - our _webxr_session_supported() method - # (which we connected to the "session_supported" signal above) will - # be called sometime later to let us know if it's supported or not. - webxr_interface.is_session_supported("immersive-vr") + webxr_interface = XRServer.find_interface("WebXR") + if webxr_interface: + # WebXR uses a lot of asynchronous callbacks, so we connect to various + # signals in order to receive them. + webxr_interface.connect("session_supported", self, "_webxr_session_supported") + webxr_interface.connect("session_started", self, "_webxr_session_started") + webxr_interface.connect("session_ended", self, "_webxr_session_ended") + webxr_interface.connect("session_failed", self, "_webxr_session_failed") - func _webxr_session_supported(session_mode, supported): - if session_mode == 'immersive-vr': - vr_supported = supported + # This returns immediately - our _webxr_session_supported() method + # (which we connected to the "session_supported" signal above) will + # be called sometime later to let us know if it's supported or not. + webxr_interface.is_session_supported("immersive-vr") - func _on_Button_pressed(): - if not vr_supported: - OS.alert("Your browser doesn't support VR") - return + func _webxr_session_supported(session_mode, supported): + if session_mode == 'immersive-vr': + vr_supported = supported - # We want an immersive VR session, as opposed to AR ('immersive-ar') or a - # simple 3DoF viewer ('viewer'). - webxr_interface.session_mode = 'immersive-vr' - # 'bounded-floor' is room scale, 'local-floor' is a standing or sitting - # experience (it puts you 1.6m above the ground if you have 3DoF headset), - # whereas as 'local' puts you down at the XROrigin. - # This list means it'll first try to request 'bounded-floor', then - # fallback on 'local-floor' and ultimately 'local', if nothing else is - # supported. - webxr_interface.requested_reference_space_types = 'bounded-floor, local-floor, local' - # In order to use 'local-floor' or 'bounded-floor' we must also - # mark the features as required or optional. - webxr_interface.required_features = 'local-floor' - webxr_interface.optional_features = 'bounded-floor' + func _on_Button_pressed(): + if not vr_supported: + OS.alert("Your browser doesn't support VR") + return - # This will return false if we're unable to even request the session, - # however, it can still fail asynchronously later in the process, so we - # only know if it's really succeeded or failed when our - # _webxr_session_started() or _webxr_session_failed() methods are called. - if not webxr_interface.initialize(): - OS.alert("Failed to initialize") - return + # We want an immersive VR session, as opposed to AR ('immersive-ar') or a + # simple 3DoF viewer ('viewer'). + webxr_interface.session_mode = 'immersive-vr' + # 'bounded-floor' is room scale, 'local-floor' is a standing or sitting + # experience (it puts you 1.6m above the ground if you have 3DoF headset), + # whereas as 'local' puts you down at the XROrigin. + # This list means it'll first try to request 'bounded-floor', then + # fallback on 'local-floor' and ultimately 'local', if nothing else is + # supported. + webxr_interface.requested_reference_space_types = 'bounded-floor, local-floor, local' + # In order to use 'local-floor' or 'bounded-floor' we must also + # mark the features as required or optional. + webxr_interface.required_features = 'local-floor' + webxr_interface.optional_features = 'bounded-floor' - func _webxr_session_started(): - $Button.visible = false - # This tells Godot to start rendering to the headset. - get_viewport().xr = true - # This will be the reference space type you ultimately got, out of the - # types that you requested above. This is useful if you want the game to - # work a little differently in 'bounded-floor' versus 'local-floor'. - print ("Reference space type: " + webxr_interface.reference_space_type) + # This will return false if we're unable to even request the session, + # however, it can still fail asynchronously later in the process, so we + # only know if it's really succeeded or failed when our + # _webxr_session_started() or _webxr_session_failed() methods are called. + if not webxr_interface.initialize(): + OS.alert("Failed to initialize") + return - func _webxr_session_ended(): - $Button.visible = true - # If the user exits immersive mode, then we tell Godot to render to the web - # page again. - get_viewport().xr = false + func _webxr_session_started(): + $Button.visible = false + # This tells Godot to start rendering to the headset. + get_viewport().xr = true + # This will be the reference space type you ultimately got, out of the + # types that you requested above. This is useful if you want the game to + # work a little differently in 'bounded-floor' versus 'local-floor'. + print ("Reference space type: " + webxr_interface.reference_space_type) - func _webxr_session_failed(message): - OS.alert("Failed to initialize: " + message) + func _webxr_session_ended(): + $Button.visible = true + # If the user exits immersive mode, then we tell Godot to render to the web + # page again. + get_viewport().xr = false + + func _webxr_session_failed(message): + OS.alert("Failed to initialize: " + message) [/codeblock] There are several ways to handle "controller" input: - Using [XRController3D] nodes and their [signal XRController3D.button_pressed] and [signal XRController3D.button_released] signals. This is how controllers are typically handled in AR/VR apps in Godot, however, this will only work with advanced VR controllers like the Oculus Touch or Index controllers, for example. The buttons codes are defined by [url=https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping]Section 3.3 of the WebXR Gamepads Module[/url]. diff --git a/platform/android/api/jni_singleton.h b/platform/android/api/jni_singleton.h index 49c0104e67..965eaabf81 100644 --- a/platform/android/api/jni_singleton.h +++ b/platform/android/api/jni_singleton.h @@ -83,7 +83,7 @@ public: v = (jvalue *)alloca(sizeof(jvalue) * p_argcount); } - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); int res = env->PushLocalFrame(16); diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp index 825132ac8c..ee28959adc 100644 --- a/platform/android/audio_driver_jandroid.cpp +++ b/platform/android/audio_driver_jandroid.cpp @@ -72,7 +72,7 @@ Error AudioDriverAndroid::init() { // __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device"); - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); int mix_rate = GLOBAL_GET("audio/mix_rate"); int latency = GLOBAL_GET("audio/output_latency"); @@ -98,7 +98,7 @@ void AudioDriverAndroid::start() { } void AudioDriverAndroid::setup(jobject p_io) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); io = p_io; jclass c = env->GetObjectClass(io); @@ -162,7 +162,7 @@ void AudioDriverAndroid::unlock() { } void AudioDriverAndroid::finish() { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); env->CallVoidMethod(io, _quit); if (audioBuffer) { @@ -175,7 +175,7 @@ void AudioDriverAndroid::finish() { } void AudioDriverAndroid::set_pause(bool p_pause) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); env->CallVoidMethod(io, _pause, p_pause); } diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index 78685991a8..f8ac29c738 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -47,7 +47,7 @@ DirAccess *DirAccessJAndroid::create_fs() { Error DirAccessJAndroid::list_dir_begin() { list_dir_end(); - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring js = env->NewStringUTF(current_dir.utf8().get_data()); int res = env->CallIntMethod(io, _dir_open, js); @@ -62,7 +62,7 @@ Error DirAccessJAndroid::list_dir_begin() { String DirAccessJAndroid::get_next() { ERR_FAIL_COND_V(id == 0, ""); - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring str = (jstring)env->CallObjectMethod(io, _dir_next, id); if (!str) return ""; @@ -73,7 +73,7 @@ String DirAccessJAndroid::get_next() { } bool DirAccessJAndroid::current_is_dir() const { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); return env->CallBooleanMethod(io, _dir_is_dir, id); } @@ -86,7 +86,7 @@ void DirAccessJAndroid::list_dir_end() { if (id == 0) return; - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); env->CallVoidMethod(io, _dir_close, id); id = 0; } @@ -100,7 +100,7 @@ String DirAccessJAndroid::get_drive(int p_drive) { } Error DirAccessJAndroid::change_dir(String p_dir) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); if (p_dir == "" || p_dir == "." || (p_dir == ".." && current_dir == "")) return OK; @@ -154,7 +154,7 @@ bool DirAccessJAndroid::file_exists(String p_file) { } bool DirAccessJAndroid::dir_exists(String p_dir) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); String sd; @@ -207,7 +207,7 @@ size_t DirAccessJAndroid::get_space_left() { } void DirAccessJAndroid::setup(jobject p_io) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); io = p_io; jclass c = env->GetObjectClass(io); diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 62720e8249..a963c5a741 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -269,7 +269,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { Vector<Device> devices; volatile bool devices_changed; Mutex device_lock; - Thread *check_for_changes_thread; + Thread check_for_changes_thread; volatile bool quit_request; static void _check_for_changes_poll_thread(void *ud) { @@ -2848,13 +2848,12 @@ public: devices_changed = true; plugins_changed = true; quit_request = false; - check_for_changes_thread = Thread::create(_check_for_changes_poll_thread, this); + check_for_changes_thread.start(_check_for_changes_poll_thread, this); } ~EditorExportPlatformAndroid() { quit_request = true; - Thread::wait_to_finish(check_for_changes_thread); - memdelete(check_for_changes_thread); + check_for_changes_thread.wait_to_finish(); } }; diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle index 89ce3d15e6..6260cadffb 100644 --- a/platform/android/java/lib/build.gradle +++ b/platform/android/java/lib/build.gradle @@ -68,7 +68,7 @@ android { File sconsExecutableFile = null def sconsName = "scons" def sconsExts = (org.gradle.internal.os.OperatingSystem.current().isWindows() - ? [".bat", ".exe"] + ? [".bat", ".cmd", ".ps1", ".exe"] : [""]) logger.lifecycle("Looking for $sconsName executable path") for (ext in sconsExts) { diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp index 2b5ca530da..ab03599dc3 100644 --- a/platform/android/java_class_wrapper.cpp +++ b/platform/android/java_class_wrapper.cpp @@ -37,7 +37,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method, if (!M) return false; - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); MethodInfo *method = nullptr; for (List<MethodInfo>::Element *E = M->get().front(); E; E = E->next()) { @@ -964,7 +964,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) { if (class_cache.has(p_class)) return class_cache[p_class]; - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jclass bclass = env->FindClass(p_class.utf8().get_data()); ERR_FAIL_COND_V(!bclass, Ref<JavaClass>()); @@ -1148,7 +1148,7 @@ JavaClassWrapper *JavaClassWrapper::singleton = nullptr; JavaClassWrapper::JavaClassWrapper(jobject p_activity) { singleton = this; - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jclass activityClass = env->FindClass("android/app/Activity"); jmethodID getClassLoader = env->GetMethodID(activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;"); diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp index 8f8275826d..4ee4427aa0 100644 --- a/platform/android/java_godot_io_wrapper.cpp +++ b/platform/android/java_godot_io_wrapper.cpp @@ -34,7 +34,7 @@ // JNIEnv is only valid within the thread it belongs to, in a multi threading environment // we can't cache it. // For GodotIO we call all access methods from our thread and we thus get a valid JNIEnv -// from ThreadAndroid. +// from get_jni_env(). GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instance) { godot_io_instance = p_env->NewGlobalRef(p_godot_io_instance); @@ -72,7 +72,7 @@ jobject GodotIOJavaWrapper::get_instance() { Error GodotIOJavaWrapper::open_uri(const String &p_uri) { if (_open_URI) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring jStr = env->NewStringUTF(p_uri.utf8().get_data()); return env->CallIntMethod(godot_io_instance, _open_URI, jStr) ? ERR_CANT_OPEN : OK; } else { @@ -82,7 +82,7 @@ Error GodotIOJavaWrapper::open_uri(const String &p_uri) { String GodotIOJavaWrapper::get_user_data_dir() { if (_get_data_dir) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_data_dir); return jstring_to_string(s, env); } else { @@ -92,7 +92,7 @@ String GodotIOJavaWrapper::get_user_data_dir() { String GodotIOJavaWrapper::get_locale() { if (_get_locale) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_locale); return jstring_to_string(s, env); } else { @@ -102,7 +102,7 @@ String GodotIOJavaWrapper::get_locale() { String GodotIOJavaWrapper::get_model() { if (_get_model) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_model); return jstring_to_string(s, env); } else { @@ -112,7 +112,7 @@ String GodotIOJavaWrapper::get_model() { int GodotIOJavaWrapper::get_screen_dpi() { if (_get_screen_DPI) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); return env->CallIntMethod(godot_io_instance, _get_screen_DPI); } else { return 160; @@ -121,7 +121,7 @@ int GodotIOJavaWrapper::get_screen_dpi() { void GodotIOJavaWrapper::screen_get_usable_rect(int (&p_rect_xywh)[4]) { if (_screen_get_usable_rect) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jintArray returnArray = (jintArray)env->CallObjectMethod(godot_io_instance, _screen_get_usable_rect); ERR_FAIL_COND(env->GetArrayLength(returnArray) != 4); jint *arrayBody = env->GetIntArrayElements(returnArray, JNI_FALSE); @@ -134,7 +134,7 @@ void GodotIOJavaWrapper::screen_get_usable_rect(int (&p_rect_xywh)[4]) { String GodotIOJavaWrapper::get_unique_id() { if (_get_unique_id) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_unique_id); return jstring_to_string(s, env); } else { @@ -148,7 +148,7 @@ bool GodotIOJavaWrapper::has_vk() { void GodotIOJavaWrapper::show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { if (_show_keyboard) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring jStr = env->NewStringUTF(p_existing.utf8().get_data()); env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end); } @@ -156,21 +156,21 @@ void GodotIOJavaWrapper::show_vk(const String &p_existing, bool p_multiline, int void GodotIOJavaWrapper::hide_vk() { if (_hide_keyboard) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); env->CallVoidMethod(godot_io_instance, _hide_keyboard); } } void GodotIOJavaWrapper::set_screen_orientation(int p_orient) { if (_set_screen_orientation) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); env->CallVoidMethod(godot_io_instance, _set_screen_orientation, p_orient); } } int GodotIOJavaWrapper::get_screen_orientation() { if (_get_screen_orientation) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); return env->CallIntMethod(godot_io_instance, _get_screen_orientation); } else { return 0; @@ -179,7 +179,7 @@ int GodotIOJavaWrapper::get_screen_orientation() { String GodotIOJavaWrapper::get_system_dir(int p_dir) { if (_get_system_dir) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_system_dir, p_dir); return jstring_to_string(s, env); } else { diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index e3a4ce63ef..bb22162879 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -87,7 +87,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en godot_java = new GodotJavaWrapper(env, activity, godot_instance); godot_io_java = new GodotIOJavaWrapper(env, godot_java->get_member_object("io", "Lorg/godotengine/godot/GodotIO;", env)); - ThreadAndroid::make_default(jvm); + init_thread_jandroid(jvm, env); jobject amgr = env->NewGlobalRef(p_asset_manager); @@ -119,7 +119,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline) { - ThreadAndroid::setup_thread(); + setup_android_thread(); const char **cmdline = nullptr; jstring *j_cmdline = nullptr; @@ -206,7 +206,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jcl return; if (step == 0) { - // Since Godot is initialized on the UI thread, _main_thread_id was set to that thread's id, + // Since Godot is initialized on the UI thread, main_thread_id was set to that thread's id, // but for Godot purposes, the main thread is the one running the game loop Main::setup2(Thread::get_caller_id()); ++step; @@ -382,7 +382,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env, } JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jclass clazz) { - ThreadAndroid::setup_thread(); + setup_android_thread(); AudioDriverAndroid::thread_func(env); } diff --git a/platform/android/java_godot_view_wrapper.cpp b/platform/android/java_godot_view_wrapper.cpp index cb26c7b8c5..5b638300ef 100644 --- a/platform/android/java_godot_view_wrapper.cpp +++ b/platform/android/java_godot_view_wrapper.cpp @@ -33,7 +33,7 @@ #include "thread_jandroid.h" GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); _godot_view = env->NewGlobalRef(godot_view); @@ -47,20 +47,20 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) { void GodotJavaViewWrapper::request_pointer_capture() { if (_request_pointer_capture != 0) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); env->CallVoidMethod(_godot_view, _request_pointer_capture); } } void GodotJavaViewWrapper::release_pointer_capture() { if (_request_pointer_capture != 0) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); env->CallVoidMethod(_godot_view, _release_pointer_capture); } } GodotJavaViewWrapper::~GodotJavaViewWrapper() { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); env->DeleteGlobalRef(_godot_view); env->DeleteGlobalRef(_cls); } diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp index c4e7f272d3..759980373a 100644 --- a/platform/android/java_godot_wrapper.cpp +++ b/platform/android/java_godot_wrapper.cpp @@ -33,7 +33,7 @@ // JNIEnv is only valid within the thread it belongs to, in a multi threading environment // we can't cache it. // For Godot we call most access methods from our thread and we thus get a valid JNIEnv -// from ThreadAndroid. For one or two we expect to pass the environment +// from get_jni_env(). For one or two we expect to pass the environment // TODO we could probably create a base class for this... @@ -91,7 +91,7 @@ jobject GodotJavaWrapper::get_activity() { jobject GodotJavaWrapper::get_member_object(const char *p_name, const char *p_class, JNIEnv *p_env) { if (godot_class) { if (p_env == nullptr) - p_env = ThreadAndroid::get_env(); + p_env = get_jni_env(); jfieldID fid = p_env->GetStaticFieldID(godot_class, p_name, p_class); return p_env->GetStaticObjectField(godot_class, fid); @@ -102,7 +102,7 @@ jobject GodotJavaWrapper::get_member_object(const char *p_name, const char *p_cl jobject GodotJavaWrapper::get_class_loader() { if (_get_class_loader) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); return env->CallObjectMethod(activity, _get_class_loader); } else { return nullptr; @@ -113,7 +113,7 @@ GodotJavaViewWrapper *GodotJavaWrapper::get_godot_view() { if (_godot_view != nullptr) { return _godot_view; } - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jmethodID godot_view_getter = env->GetMethodID(godot_class, "getRenderView", "()Lorg/godotengine/godot/GodotRenderView;"); _godot_view = new GodotJavaViewWrapper(env->CallObjectMethod(godot_instance, godot_view_getter)); return _godot_view; @@ -122,7 +122,7 @@ GodotJavaViewWrapper *GodotJavaWrapper::get_godot_view() { void GodotJavaWrapper::on_video_init(JNIEnv *p_env) { if (_on_video_init) if (p_env == nullptr) - p_env = ThreadAndroid::get_env(); + p_env = get_jni_env(); p_env->CallVoidMethod(godot_instance, _on_video_init); } @@ -130,7 +130,7 @@ void GodotJavaWrapper::on_video_init(JNIEnv *p_env) { void GodotJavaWrapper::on_godot_main_loop_started(JNIEnv *p_env) { if (_on_godot_main_loop_started) { if (p_env == nullptr) { - p_env = ThreadAndroid::get_env(); + p_env = get_jni_env(); } } p_env->CallVoidMethod(godot_instance, _on_godot_main_loop_started); @@ -139,7 +139,7 @@ void GodotJavaWrapper::on_godot_main_loop_started(JNIEnv *p_env) { void GodotJavaWrapper::restart(JNIEnv *p_env) { if (_restart) if (p_env == nullptr) - p_env = ThreadAndroid::get_env(); + p_env = get_jni_env(); p_env->CallVoidMethod(godot_instance, _restart); } @@ -147,21 +147,21 @@ void GodotJavaWrapper::restart(JNIEnv *p_env) { void GodotJavaWrapper::force_quit(JNIEnv *p_env) { if (_finish) if (p_env == nullptr) - p_env = ThreadAndroid::get_env(); + p_env = get_jni_env(); p_env->CallVoidMethod(godot_instance, _finish); } void GodotJavaWrapper::set_keep_screen_on(bool p_enabled) { if (_set_keep_screen_on) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); env->CallVoidMethod(godot_instance, _set_keep_screen_on, p_enabled); } } void GodotJavaWrapper::alert(const String &p_message, const String &p_title) { if (_alert) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring jStrMessage = env->NewStringUTF(p_message.utf8().get_data()); jstring jStrTitle = env->NewStringUTF(p_title.utf8().get_data()); env->CallVoidMethod(godot_instance, _alert, jStrMessage, jStrTitle); @@ -169,7 +169,7 @@ void GodotJavaWrapper::alert(const String &p_message, const String &p_title) { } int GodotJavaWrapper::get_gles_version_code() { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); if (_get_GLES_version_code) { return env->CallIntMethod(godot_instance, _get_GLES_version_code); } @@ -183,7 +183,7 @@ bool GodotJavaWrapper::has_get_clipboard() { String GodotJavaWrapper::get_clipboard() { if (_get_clipboard) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring s = (jstring)env->CallObjectMethod(godot_instance, _get_clipboard); return jstring_to_string(s, env); } else { @@ -193,7 +193,7 @@ String GodotJavaWrapper::get_clipboard() { String GodotJavaWrapper::get_input_fallback_mapping() { if (_get_input_fallback_mapping) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring fallback_mapping = (jstring)env->CallObjectMethod(godot_instance, _get_input_fallback_mapping); return jstring_to_string(fallback_mapping, env); } else { @@ -207,7 +207,7 @@ bool GodotJavaWrapper::has_set_clipboard() { void GodotJavaWrapper::set_clipboard(const String &p_text) { if (_set_clipboard) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring jStr = env->NewStringUTF(p_text.utf8().get_data()); env->CallVoidMethod(godot_instance, _set_clipboard, jStr); } @@ -215,7 +215,7 @@ void GodotJavaWrapper::set_clipboard(const String &p_text) { bool GodotJavaWrapper::request_permission(const String &p_name) { if (_request_permission) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jstring jStrName = env->NewStringUTF(p_name.utf8().get_data()); return env->CallBooleanMethod(godot_instance, _request_permission, jStrName); } else { @@ -225,7 +225,7 @@ bool GodotJavaWrapper::request_permission(const String &p_name) { bool GodotJavaWrapper::request_permissions() { if (_request_permissions) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); return env->CallBooleanMethod(godot_instance, _request_permissions); } else { return false; @@ -235,7 +235,7 @@ bool GodotJavaWrapper::request_permissions() { Vector<String> GodotJavaWrapper::get_granted_permissions() const { Vector<String> permissions_list; if (_get_granted_permissions) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); jobject permissions_object = env->CallObjectMethod(godot_instance, _get_granted_permissions); jobjectArray *arr = reinterpret_cast<jobjectArray *>(&permissions_object); @@ -253,14 +253,14 @@ Vector<String> GodotJavaWrapper::get_granted_permissions() const { void GodotJavaWrapper::init_input_devices() { if (_init_input_devices) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); env->CallVoidMethod(godot_instance, _init_input_devices); } } jobject GodotJavaWrapper::get_surface() { if (_get_surface) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); return env->CallObjectMethod(godot_instance, _get_surface); } else { return nullptr; @@ -269,7 +269,7 @@ jobject GodotJavaWrapper::get_surface() { bool GodotJavaWrapper::is_activity_resumed() { if (_is_activity_resumed) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); return env->CallBooleanMethod(godot_instance, _is_activity_resumed); } else { return false; @@ -278,7 +278,7 @@ bool GodotJavaWrapper::is_activity_resumed() { void GodotJavaWrapper::vibrate(int p_duration_ms) { if (_vibrate) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); env->CallVoidMethod(godot_instance, _vibrate, p_duration_ms); } } diff --git a/platform/android/net_socket_android.cpp b/platform/android/net_socket_android.cpp index ba7b3d3775..ddc2368793 100644 --- a/platform/android/net_socket_android.cpp +++ b/platform/android/net_socket_android.cpp @@ -38,7 +38,7 @@ jmethodID NetSocketAndroid::_multicast_lock_acquire = 0; jmethodID NetSocketAndroid::_multicast_lock_release = 0; void NetSocketAndroid::setup(jobject p_net_utils) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); net_utils = env->NewGlobalRef(p_net_utils); @@ -51,14 +51,14 @@ void NetSocketAndroid::setup(jobject p_net_utils) { void NetSocketAndroid::multicast_lock_acquire() { if (_multicast_lock_acquire) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); env->CallVoidMethod(net_utils, _multicast_lock_acquire); } } void NetSocketAndroid::multicast_lock_release() { if (_multicast_lock_release) { - JNIEnv *env = ThreadAndroid::get_env(); + JNIEnv *env = get_jni_env(); env->CallVoidMethod(net_utils, _multicast_lock_release); } } diff --git a/platform/android/string_android.h b/platform/android/string_android.h index 25c6f749d4..3721315d3f 100644 --- a/platform/android/string_android.h +++ b/platform/android/string_android.h @@ -37,14 +37,14 @@ /** * Converts JNI jstring to Godot String. * @param source Source JNI string. If null an empty string is returned. - * @param env JNI environment instance. If null obtained by ThreadAndroid::get_env(). + * @param env JNI environment instance. If null obtained by get_jni_env(). * @return Godot string instance. */ static inline String jstring_to_string(jstring source, JNIEnv *env = nullptr) { String result; if (source) { if (!env) { - env = ThreadAndroid::get_env(); + env = get_jni_env(); } const char *const source_utf8 = env->GetStringUTFChars(source, nullptr); if (source_utf8) { diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp index cb3527067f..afcc7294f2 100644 --- a/platform/android/thread_jandroid.cpp +++ b/platform/android/thread_jandroid.cpp @@ -30,116 +30,29 @@ #include "thread_jandroid.h" -#include "core/object/script_language.h" -#include "core/os/memory.h" -#include "core/templates/safe_refcount.h" +#include "core/os/thread.h" -static void _thread_id_key_destr_callback(void *p_value) { - memdelete(static_cast<Thread::ID *>(p_value)); -} - -static pthread_key_t _create_thread_id_key() { - pthread_key_t key; - pthread_key_create(&key, &_thread_id_key_destr_callback); - return key; -} - -pthread_key_t ThreadAndroid::thread_id_key = _create_thread_id_key(); -Thread::ID ThreadAndroid::next_thread_id = 0; - -Thread::ID ThreadAndroid::get_id() const { - return id; -} - -Thread *ThreadAndroid::create_thread_jandroid() { - return memnew(ThreadAndroid); -} - -void *ThreadAndroid::thread_callback(void *userdata) { - ThreadAndroid *t = reinterpret_cast<ThreadAndroid *>(userdata); - setup_thread(); - ScriptServer::thread_enter(); //scripts may need to attach a stack - t->id = atomic_increment(&next_thread_id); - pthread_setspecific(thread_id_key, (void *)memnew(ID(t->id))); - t->callback(t->user); - ScriptServer::thread_exit(); - return nullptr; -} - -Thread *ThreadAndroid::create_func_jandroid(ThreadCreateCallback p_callback, void *p_user, const Settings &) { - ThreadAndroid *tr = memnew(ThreadAndroid); - tr->callback = p_callback; - tr->user = p_user; - pthread_attr_init(&tr->pthread_attr); - pthread_attr_setdetachstate(&tr->pthread_attr, PTHREAD_CREATE_JOINABLE); - - pthread_create(&tr->pthread, &tr->pthread_attr, thread_callback, tr); - - return tr; -} +static JavaVM *java_vm = nullptr; +static thread_local JNIEnv *env = nullptr; -Thread::ID ThreadAndroid::get_thread_id_func_jandroid() { - void *value = pthread_getspecific(thread_id_key); - - if (value) - return *static_cast<ID *>(value); - - ID new_id = atomic_increment(&next_thread_id); - pthread_setspecific(thread_id_key, (void *)memnew(ID(new_id))); - return new_id; -} - -void ThreadAndroid::wait_to_finish_func_jandroid(Thread *p_thread) { - ThreadAndroid *tp = static_cast<ThreadAndroid *>(p_thread); - ERR_FAIL_COND(!tp); - ERR_FAIL_COND(tp->pthread == 0); - - pthread_join(tp->pthread, nullptr); - tp->pthread = 0; -} - -void ThreadAndroid::_thread_destroyed(void *value) { - /* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */ - JNIEnv *env = (JNIEnv *)value; - if (env != nullptr) { - java_vm->DetachCurrentThread(); - pthread_setspecific(jvm_key, nullptr); - } -} - -pthread_key_t ThreadAndroid::jvm_key; -JavaVM *ThreadAndroid::java_vm = nullptr; - -void ThreadAndroid::setup_thread() { - if (pthread_getspecific(jvm_key)) - return; //already setup - JNIEnv *env; +static void init_thread() { java_vm->AttachCurrentThread(&env, nullptr); - pthread_setspecific(jvm_key, (void *)env); } -void ThreadAndroid::make_default(JavaVM *p_java_vm) { - java_vm = p_java_vm; - create_func = create_func_jandroid; - get_thread_id_func = get_thread_id_func_jandroid; - wait_to_finish_func = wait_to_finish_func_jandroid; - pthread_key_create(&jvm_key, _thread_destroyed); - setup_thread(); +static void term_thread() { + java_vm->DetachCurrentThread(); } -JNIEnv *ThreadAndroid::get_env() { - if (!pthread_getspecific(jvm_key)) { - setup_thread(); - } - - JNIEnv *env = nullptr; - java_vm->AttachCurrentThread(&env, nullptr); - return env; +void init_thread_jandroid(JavaVM *p_jvm, JNIEnv *p_env) { + java_vm = p_jvm; + env = p_env; + Thread::_set_platform_funcs(nullptr, nullptr, &init_thread, &term_thread); } -ThreadAndroid::ThreadAndroid() { - pthread = 0; +void setup_android_thread() { + init_thread(); } -ThreadAndroid::~ThreadAndroid() { +JNIEnv *get_jni_env() { + return env; } diff --git a/platform/android/thread_jandroid.h b/platform/android/thread_jandroid.h index c37e2d740e..ff13ae911f 100644 --- a/platform/android/thread_jandroid.h +++ b/platform/android/thread_jandroid.h @@ -28,46 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef THREAD_POSIX_H -#define THREAD_POSIX_H +#ifndef THREAD_JANDROID_H +#define THREAD_JANDROID_H -#include "core/os/thread.h" #include <jni.h> -#include <pthread.h> -#include <sys/types.h> -class ThreadAndroid : public Thread { - static pthread_key_t thread_id_key; - static ID next_thread_id; +void init_thread_jandroid(JavaVM *p_jvm, JNIEnv *p_env); - pthread_t pthread; - pthread_attr_t pthread_attr; - ThreadCreateCallback callback; - void *user; - ID id; - - static Thread *create_thread_jandroid(); - - static void *thread_callback(void *userdata); - - static Thread *create_func_jandroid(ThreadCreateCallback p_callback, void *, const Settings &); - static ID get_thread_id_func_jandroid(); - static void wait_to_finish_func_jandroid(Thread *p_thread); - - static void _thread_destroyed(void *value); - ThreadAndroid(); - - static pthread_key_t jvm_key; - static JavaVM *java_vm; - -public: - virtual ID get_id() const; - - static void make_default(JavaVM *p_java_vm); - static void setup_thread(); - static JNIEnv *get_env(); - - ~ThreadAndroid(); -}; +void setup_android_thread(); +JNIEnv *get_jni_env(); #endif diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 2229ebd4ab..604ad4e04b 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -57,7 +57,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform { // Plugins volatile bool plugins_changed; - Thread *check_for_changes_thread; + Thread check_for_changes_thread; volatile bool quit_request; Mutex plugins_lock; Vector<PluginConfigIOS> plugins; @@ -1940,13 +1940,12 @@ EditorExportPlatformIOS::EditorExportPlatformIOS() { plugins_changed = true; quit_request = false; - check_for_changes_thread = Thread::create(_check_for_changes_poll_thread, this); + check_for_changes_thread.start(_check_for_changes_poll_thread, this); } EditorExportPlatformIOS::~EditorExportPlatformIOS() { quit_request = true; - Thread::wait_to_finish(check_for_changes_thread); - memdelete(check_for_changes_thread); + check_for_changes_thread.wait_to_finish(); } void register_iphone_exporter() { diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp index 6395fdf721..f7cc9e6540 100644 --- a/platform/javascript/audio_driver_javascript.cpp +++ b/platform/javascript/audio_driver_javascript.cpp @@ -267,7 +267,7 @@ int AudioDriverJavaScript::WorkletNode::create(int p_buffer_size, int p_channels void AudioDriverJavaScript::WorkletNode::start(float *p_out_buf, int p_out_buf_size, float *p_in_buf, int p_in_buf_size) { godot_audio_worklet_start(p_in_buf, p_in_buf_size, p_out_buf, p_out_buf_size, state); - thread = Thread::create(_audio_thread_func, this); + thread.start(_audio_thread_func, this); } void AudioDriverJavaScript::WorkletNode::lock() { @@ -280,8 +280,6 @@ void AudioDriverJavaScript::WorkletNode::unlock() { void AudioDriverJavaScript::WorkletNode::finish() { quit = true; // Ask thread to quit. - Thread::wait_to_finish(thread); - memdelete(thread); - thread = nullptr; + thread.wait_to_finish(); } #endif diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h index d55ec261a4..393693640f 100644 --- a/platform/javascript/audio_driver_javascript.h +++ b/platform/javascript/audio_driver_javascript.h @@ -59,7 +59,7 @@ public: STATE_MAX, }; Mutex mutex; - Thread *thread = nullptr; + Thread thread; bool quit = false; int32_t state[STATE_MAX] = { 0 }; diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index 76683da947..653d18f791 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -57,12 +57,11 @@ def get_flags(): def configure(env): - if not isinstance(env["initial_memory"], int): - try: - env["initial_memory"] = int(env["initial_memory"]) - except: - print("Initial memory must be a valid integer") - sys.exit(255) + try: + env["initial_memory"] = int(env["initial_memory"]) + except Exception: + print("Initial memory must be a valid integer") + sys.exit(255) ## Build type if env["target"] == "release": diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index dd0938ee3e..f5d8a68994 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -214,7 +214,7 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform { Ref<EditorHTTPServer> server; bool server_quit = false; Mutex server_lock; - Thread *server_thread = nullptr; + Thread server_thread; enum ExportMode { EXPORT_MODE_NORMAL = 0, @@ -682,7 +682,7 @@ void EditorExportPlatformJavaScript::_server_thread_poll(void *data) { EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() { server.instance(); - server_thread = Thread::create(_server_thread_poll, this); + server_thread.start(_server_thread_poll, this); Ref<Image> img = memnew(Image(_javascript_logo)); logo.instance(); @@ -703,8 +703,7 @@ EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() { EditorExportPlatformJavaScript::~EditorExportPlatformJavaScript() { server->stop(); server_quit = true; - Thread::wait_to_finish(server_thread); - memdelete(server_thread); + server_thread.wait_to_finish(); } void register_javascript_exporter() { diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index a819731328..c093454b0a 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -64,14 +64,14 @@ def get_opts(): BoolVariable("use_llvm", "Use the LLVM compiler", False), BoolVariable("use_lld", "Use the LLD linker", False), BoolVariable("use_thinlto", "Use ThinLTO", False), - BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", False), + BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True), BoolVariable("use_coverage", "Test Godot coverage", False), BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False), BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN))", False), BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN))", False), BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN))", False), BoolVariable("pulseaudio", "Detect and use PulseAudio", True), - BoolVariable("udev", "Use udev for gamepad connection callbacks", False), + BoolVariable("udev", "Use udev for gamepad connection callbacks", True), EnumVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", "yes", ("yes", "no")), BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False), BoolVariable("touch", "Enable touch events", True), @@ -390,4 +390,7 @@ def configure(env): # Link those statically for portability if env["use_static_cpp"]: - env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"]) + # Workaround for GH-31743, Ubuntu 18.04 i386 crashes when it's used. + # That doesn't make any sense but it's likely a Ubuntu bug? + if is64 or env["bits"] == "64": + env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"]) diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 3f1a7ced60..53baf17858 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -4266,7 +4266,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } } - events_thread = Thread::create(_poll_events_thread, this); + events_thread.start(_poll_events_thread, this); _update_real_mouse_position(windows[MAIN_WINDOW_ID]); @@ -4280,9 +4280,7 @@ DisplayServerX11::~DisplayServerX11() { _clipboard_transfer_ownership(XInternAtom(x11_display, "CLIPBOARD", 0), x11_main_window); events_thread_done = true; - Thread::wait_to_finish(events_thread); - memdelete(events_thread); - events_thread = nullptr; + events_thread.wait_to_finish(); //destroy all windows for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 7784ba82b5..906710f933 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -252,7 +252,7 @@ class DisplayServerX11 : public DisplayServer { void _dispatch_input_event(const Ref<InputEvent> &p_event); mutable Mutex events_mutex; - Thread *events_thread = nullptr; + Thread events_thread; bool events_thread_done = false; LocalVector<XEvent> polled_events; static void _poll_events_thread(void *ud); diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index d54d805199..4e96e6d687 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -74,13 +74,12 @@ void JoypadLinux::Joypad::reset() { JoypadLinux::JoypadLinux(Input *in) { exit_udev = false; input = in; - joy_thread = Thread::create(joy_thread_func, this); + joy_thread.start(joy_thread_func, this); } JoypadLinux::~JoypadLinux() { exit_udev = true; - Thread::wait_to_finish(joy_thread); - memdelete(joy_thread); + joy_thread.wait_to_finish(); close_joypad(); } diff --git a/platform/linuxbsd/joypad_linux.h b/platform/linuxbsd/joypad_linux.h index 20d30b510c..bf343b7ceb 100644 --- a/platform/linuxbsd/joypad_linux.h +++ b/platform/linuxbsd/joypad_linux.h @@ -72,7 +72,7 @@ private: bool exit_udev; Mutex joy_mutex; - Thread *joy_thread; + Thread joy_thread; Input *input; Joypad joypads[JOYPADS_MAX]; Vector<String> attached_devices; diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index f43c4ecdaf..8b60e55d2d 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -45,7 +45,6 @@ #include "servers/audio_server.h" #include "servers/rendering/rendering_server_default.h" #include "servers/rendering/rendering_server_wrap_mt.h" -#include "thread_uwp.h" #include <ppltasks.h> #include <wrl.h> @@ -130,8 +129,6 @@ void OS_UWP::initialize_core() { //RedirectIOToConsole(); - ThreadUWP::make_default(); - FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES); FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA); FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_FILESYSTEM); diff --git a/platform/uwp/thread_uwp.cpp b/platform/uwp/thread_uwp.cpp deleted file mode 100644 index 364c414375..0000000000 --- a/platform/uwp/thread_uwp.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************/ -/* thread_uwp.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 "thread_uwp.h" - -#include "core/os/memory.h" - -Thread *ThreadUWP::create_func_uwp(ThreadCreateCallback p_callback, void *p_user, const Settings &) { - ThreadUWP *thread = memnew(ThreadUWP); - - std::thread new_thread(p_callback, p_user); - std::swap(thread->thread, new_thread); - - return thread; -}; - -Thread::ID ThreadUWP::get_thread_id_func_uwp() { - return std::hash<std::thread::id>()(std::this_thread::get_id()); -}; - -void ThreadUWP::wait_to_finish_func_uwp(Thread *p_thread) { - ThreadUWP *tp = static_cast<ThreadUWP *>(p_thread); - tp->thread.join(); -}; - -Thread::ID ThreadUWP::get_id() const { - return std::hash<std::thread::id>()(thread.get_id()); -}; - -void ThreadUWP::make_default() { - create_func = create_func_uwp; - get_thread_id_func = get_thread_id_func_uwp; - wait_to_finish_func = wait_to_finish_func_uwp; -}; diff --git a/platform/uwp/thread_uwp.h b/platform/uwp/thread_uwp.h deleted file mode 100644 index 0bfc71d2e0..0000000000 --- a/platform/uwp/thread_uwp.h +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************/ -/* thread_uwp.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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 THREAD_UWP_H -#define THREAD_UWP_H - -#ifdef UWP_ENABLED - -#include "core/os/thread.h" - -#include <thread> - -class ThreadUWP : public Thread { - std::thread thread; - - static Thread *create_func_uwp(ThreadCreateCallback p_callback, void *, const Settings &); - static ID get_thread_id_func_uwp(); - static void wait_to_finish_func_uwp(Thread *p_thread); - - ThreadUWP() {} - -public: - virtual ID get_id() const; - - static void make_default(); - - ~ThreadUWP() {} -}; - -#endif // UWP_ENABLED - -#endif // THREAD_UWP_H diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 3c38c715c1..fe007027da 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -39,7 +39,6 @@ #include "core/version_generated.gen.h" #include "drivers/windows/dir_access_windows.h" #include "drivers/windows/file_access_windows.h" -#include "drivers/windows/thread_windows.h" #include "joypad_windows.h" #include "lang_table.h" #include "main/main.h" @@ -176,8 +175,6 @@ void OS_Windows::initialize() { //RedirectIOToConsole(); - ThreadWindows::make_default(); - FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES); FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA); FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_FILESYSTEM); diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index b7b1415091..e8cfa05a4b 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -170,18 +170,17 @@ void _bake_navigation_mesh(void *p_user_data) { } void NavigationRegion3D::bake_navigation_mesh() { - ERR_FAIL_COND(bake_thread != nullptr); + ERR_FAIL_COND(bake_thread.is_started()); BakeThreadsArgs *args = memnew(BakeThreadsArgs); args->nav_region = this; - bake_thread = Thread::create(_bake_navigation_mesh, args); - ERR_FAIL_COND(bake_thread == nullptr); + bake_thread.start(_bake_navigation_mesh, args); } void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) { set_navigation_mesh(p_nav_mesh); - bake_thread = nullptr; + bake_thread.wait_to_finish(); emit_signal("bake_finished"); } diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h index a5b8c2cd5e..e966523b64 100644 --- a/scene/3d/navigation_region_3d.h +++ b/scene/3d/navigation_region_3d.h @@ -46,7 +46,7 @@ class NavigationRegion3D : public Node3D { Navigation3D *navigation = nullptr; Node *debug_view = nullptr; - Thread *bake_thread = nullptr; + Thread bake_thread; protected: void _notification(int p_what); diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index f7c9583fbf..8b3daf79a8 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -306,10 +306,10 @@ void Button::_notification(int p_what) { Color font_outline_color = get_theme_color("font_outline_color"); int outline_size = get_theme_constant("outline_size"); if (outline_size > 0 && font_outline_color.a > 0) { - text_buf->draw_outline(ci, text_ofs.floor(), outline_size, font_outline_color); + text_buf->draw_outline(ci, text_ofs, outline_size, font_outline_color); } - text_buf->draw(ci, text_ofs.floor(), color); + text_buf->draw(ci, text_ofs, color); if (!_icon.is_null() && icon_region.size.width > 0) { draw_texture_rect_region(_icon, icon_region, Rect2(Point2(), _icon->get_size()), color_icon); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 799b0ed612..bd57817bd3 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -1194,7 +1194,6 @@ void ItemList::_notification(int p_what) { } if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) { - text_ofs = text_ofs.floor(); text_ofs += base_ofs; text_ofs += items[i].rect_cache.position; @@ -1217,7 +1216,6 @@ void ItemList::_notification(int p_what) { text_ofs.y += (items[i].rect_cache.size.height - size2.y) / 2; } - text_ofs = text_ofs.floor(); text_ofs += base_ofs; text_ofs += items[i].rect_cache.position; diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index ddcf07c8e9..4c6b85d78b 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -163,7 +163,7 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust thread_done = false; thread_request_quit = false; client->set_blocking_mode(true); - thread = Thread::create(_thread_func, this); + thread.start(_thread_func, this); } else { client->set_blocking_mode(false); err = _request(); @@ -209,9 +209,7 @@ void HTTPRequest::cancel_request() { set_process_internal(false); } else { thread_request_quit = true; - Thread::wait_to_finish(thread); - memdelete(thread); - thread = nullptr; + thread.wait_to_finish(); } if (file) { @@ -640,8 +638,6 @@ void HTTPRequest::_bind_methods() { } HTTPRequest::HTTPRequest() { - thread = nullptr; - port = 80; redirections = 0; max_redirects = 8; diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 6f606296e4..9dbf561cd4 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -110,7 +110,7 @@ private: volatile bool thread_done; volatile bool thread_request_quit; - Thread *thread; + Thread thread; void _request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data); static void _thread_func(void *p_userdata); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 6a1b896b04..0c01516032 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2332,12 +2332,7 @@ static void find_owned_by(Node *p_by, Node *p_node, List<Node *> *p_owned) { } } -struct _NodeReplaceByPair { - String name; - Variant value; -}; - -void Node::replace_by(Node *p_node, bool p_keep_data) { +void Node::replace_by(Node *p_node, bool p_keep_groups) { ERR_FAIL_NULL(p_node); ERR_FAIL_COND(p_node->data.parent); @@ -2345,21 +2340,7 @@ void Node::replace_by(Node *p_node, bool p_keep_data) { List<Node *> owned_by_owner; Node *owner = (data.owner == this) ? p_node : data.owner; - List<_NodeReplaceByPair> replace_data; - - if (p_keep_data) { - List<PropertyInfo> plist; - get_property_list(&plist); - - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - _NodeReplaceByPair rd; - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { - continue; - } - rd.name = E->get().name; - rd.value = get(rd.name); - } - + if (p_keep_groups) { List<GroupInfo> groups; get_groups(&groups); @@ -2404,10 +2385,6 @@ void Node::replace_by(Node *p_node, bool p_keep_data) { } p_node->set_filename(get_filename()); - - for (List<_NodeReplaceByPair>::Element *E = replace_data.front(); E; E = E->next()) { - p_node->set(E->get().name, E->get().value); - } } void Node::_replace_connections_target(Node *p_new_target) { @@ -2774,7 +2751,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tree"), &Node::get_tree); ClassDB::bind_method(D_METHOD("duplicate", "flags"), &Node::duplicate, DEFVAL(DUPLICATE_USE_INSTANCING | DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS)); - ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_data"), &Node::replace_by, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_groups"), &Node::replace_by, DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_scene_instance_load_placeholder", "load_placeholder"), &Node::set_scene_instance_load_placeholder); ClassDB::bind_method(D_METHOD("get_scene_instance_load_placeholder"), &Node::get_scene_instance_load_placeholder); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index c349d090d8..b14c44689e 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -557,19 +557,14 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeDeterminant>(); ClassDB::register_class<VisualShaderNodeScalarDerivativeFunc>(); ClassDB::register_class<VisualShaderNodeVectorDerivativeFunc>(); - ClassDB::register_class<VisualShaderNodeScalarClamp>(); - ClassDB::register_class<VisualShaderNodeVectorClamp>(); + ClassDB::register_class<VisualShaderNodeClamp>(); ClassDB::register_class<VisualShaderNodeFaceForward>(); ClassDB::register_class<VisualShaderNodeOuterProduct>(); - ClassDB::register_class<VisualShaderNodeVectorScalarStep>(); - ClassDB::register_class<VisualShaderNodeScalarSmoothStep>(); - ClassDB::register_class<VisualShaderNodeVectorSmoothStep>(); - ClassDB::register_class<VisualShaderNodeVectorScalarSmoothStep>(); + ClassDB::register_class<VisualShaderNodeSmoothStep>(); + ClassDB::register_class<VisualShaderNodeStep>(); ClassDB::register_class<VisualShaderNodeVectorDistance>(); ClassDB::register_class<VisualShaderNodeVectorRefract>(); - ClassDB::register_class<VisualShaderNodeScalarInterp>(); - ClassDB::register_class<VisualShaderNodeVectorInterp>(); - ClassDB::register_class<VisualShaderNodeVectorScalarMix>(); + ClassDB::register_class<VisualShaderNodeMix>(); ClassDB::register_class<VisualShaderNodeVectorCompose>(); ClassDB::register_class<VisualShaderNodeTransformCompose>(); ClassDB::register_class<VisualShaderNodeVectorDecompose>(); @@ -595,7 +590,6 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeCubemapUniform>(); ClassDB::register_class<VisualShaderNodeIf>(); ClassDB::register_class<VisualShaderNodeSwitch>(); - ClassDB::register_class<VisualShaderNodeScalarSwitch>(); ClassDB::register_class<VisualShaderNodeFresnel>(); ClassDB::register_class<VisualShaderNodeExpression>(); ClassDB::register_class<VisualShaderNodeGlobalExpression>(); @@ -935,6 +929,16 @@ void register_scene_types() { ClassDB::add_compatibility_class("VisualShaderNodeScalarFunc", "VisualShaderNodeFloatFunc"); ClassDB::add_compatibility_class("VisualShaderNodeScalarOp", "VisualShaderNodeFloatOp"); ClassDB::add_compatibility_class("VisualShaderNodeScalarUniform", "VisualShaderNodeFloatUniform"); + ClassDB::add_compatibility_class("VisualShaderNodeScalarClamp", "VisualShaderNodeClamp"); + ClassDB::add_compatibility_class("VisualShaderNodeVectorClamp", "VisualShaderNodeClamp"); + ClassDB::add_compatibility_class("VisualShaderNodeScalarInterp", "VisualShaderNodeMix"); + ClassDB::add_compatibility_class("VisualShaderNodeVectorInterp", "VisualShaderNodeMix"); + ClassDB::add_compatibility_class("VisualShaderNodeVectorScalarMix", "VisualShaderNodeMix"); + ClassDB::add_compatibility_class("VisualShaderNodeScalarSmoothStep", "VisualShaderNodeSmoothStep"); + ClassDB::add_compatibility_class("VisualShaderNodeVectorSmoothStep", "VisualShaderNodeSmoothStep"); + ClassDB::add_compatibility_class("VisualShaderNodeVectorScalarSmoothStep", "VisualShaderNodeSmoothStep"); + ClassDB::add_compatibility_class("VisualShaderNodeVectorScalarStep", "VisualShaderNodeStep"); + ClassDB::add_compatibility_class("VisualShaderNodeScalarSwitch", "VisualShaderNodeSwitch"); ClassDB::add_compatibility_class("World", "World3D"); ClassDB::add_compatibility_class("StreamTexture", "StreamTexture2D"); ClassDB::add_compatibility_class("Light2D", "PointLight2D"); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 8b60c0a979..d6200059f6 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -2086,9 +2086,6 @@ String VisualShaderNodeIntFunc::get_caption() const { } int VisualShaderNodeIntFunc::get_input_port_count() const { - if (func == FUNC_CLAMP) { - return 3; - } return 1; } @@ -2097,15 +2094,6 @@ VisualShaderNodeIntFunc::PortType VisualShaderNodeIntFunc::get_input_port_type(i } String VisualShaderNodeIntFunc::get_input_port_name(int p_port) const { - if (func == FUNC_CLAMP) { - if (p_port == 0) { - return ""; - } else if (p_port == 1) { - return "min"; - } else if (p_port == 2) { - return "max"; - } - } return ""; } @@ -2122,13 +2110,8 @@ String VisualShaderNodeIntFunc::get_output_port_name(int p_port) const { } String VisualShaderNodeIntFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - if (func == FUNC_CLAMP) { - return "\t" + p_output_vars[0] + " = clamp(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; - } - static const char *int_func_id[FUNC_SIGN + 1] = { "abs($)", - "", "-($)", "sign($)" }; @@ -2137,12 +2120,6 @@ String VisualShaderNodeIntFunc::generate_code(Shader::Mode p_mode, VisualShader: } void VisualShaderNodeIntFunc::set_function(Function p_func) { - if (func != p_func) { - if (p_func == FUNC_CLAMP) { - set_input_port_default_value(1, 0); - set_input_port_default_value(2, 0); - } - } func = p_func; emit_changed(); } @@ -2161,10 +2138,9 @@ void VisualShaderNodeIntFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeIntFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeIntFunc::get_function); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Abs,Clamp,Negate,Sign"), "set_function", "get_function"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Abs,Negate,Sign"), "set_function", "get_function"); BIND_ENUM_CONSTANT(FUNC_ABS); - BIND_ENUM_CONSTANT(FUNC_CLAMP); BIND_ENUM_CONSTANT(FUNC_NEGATE); BIND_ENUM_CONSTANT(FUNC_SIGN); } @@ -2754,21 +2730,31 @@ VisualShaderNodeVectorDerivativeFunc::VisualShaderNodeVectorDerivativeFunc() { set_input_port_default_value(0, Vector3()); } -////////////// Scalar Clamp +////////////// Clamp -String VisualShaderNodeScalarClamp::get_caption() const { - return "ScalarClamp"; +String VisualShaderNodeClamp::get_caption() const { + return "Clamp"; } -int VisualShaderNodeScalarClamp::get_input_port_count() const { +int VisualShaderNodeClamp::get_input_port_count() const { return 3; } -VisualShaderNodeScalarClamp::PortType VisualShaderNodeScalarClamp::get_input_port_type(int p_port) const { +VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_FLOAT: + return PORT_TYPE_SCALAR; + case OP_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarClamp::get_input_port_name(int p_port) const { +String VisualShaderNodeClamp::get_input_port_name(int p_port) const { if (p_port == 0) { return ""; } else if (p_port == 1) { @@ -2779,73 +2765,86 @@ String VisualShaderNodeScalarClamp::get_input_port_name(int p_port) const { return ""; } -int VisualShaderNodeScalarClamp::get_output_port_count() const { +int VisualShaderNodeClamp::get_output_port_count() const { return 1; } -VisualShaderNodeScalarClamp::PortType VisualShaderNodeScalarClamp::get_output_port_type(int p_port) const { +VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_FLOAT: + return PORT_TYPE_SCALAR; + case OP_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarClamp::get_output_port_name(int p_port) const { +String VisualShaderNodeClamp::get_output_port_name(int p_port) const { return ""; } -String VisualShaderNodeScalarClamp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { +String VisualShaderNodeClamp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { return "\t" + p_output_vars[0] + " = clamp(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } -VisualShaderNodeScalarClamp::VisualShaderNodeScalarClamp() { - set_input_port_default_value(0, 0.0); - set_input_port_default_value(1, 0.0); - set_input_port_default_value(2, 1.0); -} - -////////////// Vector Clamp - -String VisualShaderNodeVectorClamp::get_caption() const { - return "VectorClamp"; -} - -int VisualShaderNodeVectorClamp::get_input_port_count() const { - return 3; -} - -VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorClamp::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} - -String VisualShaderNodeVectorClamp::get_input_port_name(int p_port) const { - if (p_port == 0) { - return ""; - } else if (p_port == 1) { - return "min"; - } else if (p_port == 2) { - return "max"; +void VisualShaderNodeClamp::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; } - return ""; + switch (p_op_type) { + case OP_TYPE_FLOAT: + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, 0.0); + break; + case OP_TYPE_INT: + set_input_port_default_value(0, 0); + set_input_port_default_value(1, 0); + set_input_port_default_value(2, 0); + break; + case OP_TYPE_VECTOR: + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); + break; + default: + break; + } + op_type = p_op_type; + emit_changed(); } -int VisualShaderNodeVectorClamp::get_output_port_count() const { - return 1; +VisualShaderNodeClamp::OpType VisualShaderNodeClamp::get_op_type() const { + return op_type; } -VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorClamp::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +Vector<StringName> VisualShaderNodeClamp::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; } -String VisualShaderNodeVectorClamp::get_output_port_name(int p_port) const { - return ""; -} +void VisualShaderNodeClamp::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeClamp::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeClamp::get_op_type); -String VisualShaderNodeVectorClamp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = clamp(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_FLOAT); + BIND_ENUM_CONSTANT(OP_TYPE_INT); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); } -VisualShaderNodeVectorClamp::VisualShaderNodeVectorClamp() { - set_input_port_default_value(0, Vector3(0, 0, 0)); - set_input_port_default_value(1, Vector3(0, 0, 0)); - set_input_port_default_value(2, Vector3(1, 1, 1)); +VisualShaderNodeClamp::VisualShaderNodeClamp() { + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, 1.0); } ////////////// FaceForward @@ -2943,24 +2942,39 @@ VisualShaderNodeOuterProduct::VisualShaderNodeOuterProduct() { set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); } -////////////// Vector-Scalar Step +////////////// Step -String VisualShaderNodeVectorScalarStep::get_caption() const { - return "VectorScalarStep"; +String VisualShaderNodeStep::get_caption() const { + return "Step"; } -int VisualShaderNodeVectorScalarStep::get_input_port_count() const { +int VisualShaderNodeStep::get_input_port_count() const { return 2; } -VisualShaderNodeVectorScalarStep::PortType VisualShaderNodeVectorScalarStep::get_input_port_type(int p_port) const { - if (p_port == 0) { - return PORT_TYPE_SCALAR; +VisualShaderNodeStep::PortType VisualShaderNodeStep::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_SCALAR: + return PORT_TYPE_SCALAR; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + switch (p_port) { + case 0: + return PORT_TYPE_SCALAR; + case 1: + return PORT_TYPE_VECTOR; + default: + break; + } + break; + default: + break; } - return PORT_TYPE_VECTOR; + return PORT_TYPE_SCALAR; } -String VisualShaderNodeVectorScalarStep::get_input_port_name(int p_port) const { +String VisualShaderNodeStep::get_input_port_name(int p_port) const { if (p_port == 0) { return "edge"; } else if (p_port == 1) { @@ -2969,89 +2983,131 @@ String VisualShaderNodeVectorScalarStep::get_input_port_name(int p_port) const { return ""; } -int VisualShaderNodeVectorScalarStep::get_output_port_count() const { +int VisualShaderNodeStep::get_output_port_count() const { return 1; } -VisualShaderNodeVectorScalarStep::PortType VisualShaderNodeVectorScalarStep::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +VisualShaderNodeStep::PortType VisualShaderNodeStep::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_SCALAR: + return PORT_TYPE_SCALAR; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + return PORT_TYPE_VECTOR; + default: + break; + } + return PORT_TYPE_SCALAR; } -String VisualShaderNodeVectorScalarStep::get_output_port_name(int p_port) const { +String VisualShaderNodeStep::get_output_port_name(int p_port) const { return ""; } -String VisualShaderNodeVectorScalarStep::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = step(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; -} - -VisualShaderNodeVectorScalarStep::VisualShaderNodeVectorScalarStep() { - set_input_port_default_value(0, 0.0); - set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); -} - -////////////// Scalar SmoothStep - -String VisualShaderNodeScalarSmoothStep::get_caption() const { - return "ScalarSmoothStep"; -} - -int VisualShaderNodeScalarSmoothStep::get_input_port_count() const { - return 3; +void VisualShaderNodeStep::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_SCALAR: + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(0, 0.0); // edge + } + if (op_type == OP_TYPE_VECTOR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(1, 0.0); // x + } + break; + case OP_TYPE_VECTOR: + if (op_type == OP_TYPE_SCALAR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // edge + } + if (op_type == OP_TYPE_SCALAR) { + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // x + } + break; + case OP_TYPE_VECTOR_SCALAR: + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(0, 0.0); // edge + } + if (op_type == OP_TYPE_SCALAR) { + set_input_port_default_value(1, 0.0); // x + } + break; + default: + break; + } + op_type = p_op_type; + emit_changed(); } -VisualShaderNodeScalarSmoothStep::PortType VisualShaderNodeScalarSmoothStep::get_input_port_type(int p_port) const { - return PORT_TYPE_SCALAR; +VisualShaderNodeStep::OpType VisualShaderNodeStep::get_op_type() const { + return op_type; } -String VisualShaderNodeScalarSmoothStep::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "edge0"; - } else if (p_port == 1) { - return "edge1"; - } else if (p_port == 2) { - return "x"; - } - return ""; +String VisualShaderNodeStep::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + return "\t" + p_output_vars[0] + " = step(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } -int VisualShaderNodeScalarSmoothStep::get_output_port_count() const { - return 1; +Vector<StringName> VisualShaderNodeStep::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; } -VisualShaderNodeScalarSmoothStep::PortType VisualShaderNodeScalarSmoothStep::get_output_port_type(int p_port) const { - return PORT_TYPE_SCALAR; -} +void VisualShaderNodeStep::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeStep::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeStep::get_op_type); -String VisualShaderNodeScalarSmoothStep::get_output_port_name(int p_port) const { - return ""; -} + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector,VectorScalar"), "set_op_type", "get_op_type"); -String VisualShaderNodeScalarSmoothStep::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = smoothstep(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); } -VisualShaderNodeScalarSmoothStep::VisualShaderNodeScalarSmoothStep() { +VisualShaderNodeStep::VisualShaderNodeStep() { set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 0.0); - set_input_port_default_value(2, 0.0); } -////////////// Vector SmoothStep +////////////// SmoothStep -String VisualShaderNodeVectorSmoothStep::get_caption() const { - return "VectorSmoothStep"; +String VisualShaderNodeSmoothStep::get_caption() const { + return "SmoothStep"; } -int VisualShaderNodeVectorSmoothStep::get_input_port_count() const { +int VisualShaderNodeSmoothStep::get_input_port_count() const { return 3; } -VisualShaderNodeVectorSmoothStep::PortType VisualShaderNodeVectorSmoothStep::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_SCALAR: + return PORT_TYPE_SCALAR; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + switch (p_port) { + case 0: + return PORT_TYPE_SCALAR; // edge0 + case 1: + return PORT_TYPE_SCALAR; // edge1 + case 2: + return PORT_TYPE_VECTOR; // x + default: + break; + } + break; + default: + break; + } + return PORT_TYPE_SCALAR; } -String VisualShaderNodeVectorSmoothStep::get_input_port_name(int p_port) const { +String VisualShaderNodeSmoothStep::get_input_port_name(int p_port) const { if (p_port == 0) { return "edge0"; } else if (p_port == 1) { @@ -3062,78 +3118,98 @@ String VisualShaderNodeVectorSmoothStep::get_input_port_name(int p_port) const { return ""; } -int VisualShaderNodeVectorSmoothStep::get_output_port_count() const { +int VisualShaderNodeSmoothStep::get_output_port_count() const { return 1; } -VisualShaderNodeVectorSmoothStep::PortType VisualShaderNodeVectorSmoothStep::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_SCALAR: + return PORT_TYPE_SCALAR; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + return PORT_TYPE_VECTOR; + default: + break; + } + return PORT_TYPE_SCALAR; } -String VisualShaderNodeVectorSmoothStep::get_output_port_name(int p_port) const { +String VisualShaderNodeSmoothStep::get_output_port_name(int p_port) const { return ""; } -String VisualShaderNodeVectorSmoothStep::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = smoothstep(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; -} - -VisualShaderNodeVectorSmoothStep::VisualShaderNodeVectorSmoothStep() { - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); -} - -////////////// Vector-Scalar SmoothStep - -String VisualShaderNodeVectorScalarSmoothStep::get_caption() const { - return "VectorScalarSmoothStep"; -} - -int VisualShaderNodeVectorScalarSmoothStep::get_input_port_count() const { - return 3; -} - -VisualShaderNodeVectorScalarSmoothStep::PortType VisualShaderNodeVectorScalarSmoothStep::get_input_port_type(int p_port) const { - if (p_port == 0) { - return PORT_TYPE_SCALAR; - } else if (p_port == 1) { - return PORT_TYPE_SCALAR; +void VisualShaderNodeSmoothStep::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_SCALAR: + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(0, 0.0); // edge0 + set_input_port_default_value(1, 0.0); // edge1 + } + if (op_type == OP_TYPE_VECTOR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(2, 0.0); // x + } + break; + case OP_TYPE_VECTOR: + if (op_type == OP_TYPE_SCALAR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // edge0 + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // edge1 + } + if (op_type == OP_TYPE_SCALAR) { + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); // x + } + break; + case OP_TYPE_VECTOR_SCALAR: + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(0, 0.0); // edge0 + set_input_port_default_value(1, 0.0); // edge1 + } + if (op_type == OP_TYPE_SCALAR) { + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); // x + } + break; + default: + break; } - return PORT_TYPE_VECTOR; + op_type = p_op_type; + emit_changed(); } -String VisualShaderNodeVectorScalarSmoothStep::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "edge0"; - } else if (p_port == 1) { - return "edge1"; - } else if (p_port == 2) { - return "x"; - } - return ""; +VisualShaderNodeSmoothStep::OpType VisualShaderNodeSmoothStep::get_op_type() const { + return op_type; } -int VisualShaderNodeVectorScalarSmoothStep::get_output_port_count() const { - return 1; +String VisualShaderNodeSmoothStep::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + return "\t" + p_output_vars[0] + " = smoothstep(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } -VisualShaderNodeVectorScalarSmoothStep::PortType VisualShaderNodeVectorScalarSmoothStep::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +Vector<StringName> VisualShaderNodeSmoothStep::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; } -String VisualShaderNodeVectorScalarSmoothStep::get_output_port_name(int p_port) const { - return ""; -} +void VisualShaderNodeSmoothStep::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeSmoothStep::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeSmoothStep::get_op_type); -String VisualShaderNodeVectorScalarSmoothStep::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = smoothstep(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector,VectorScalar"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); } -VisualShaderNodeVectorScalarSmoothStep::VisualShaderNodeVectorScalarSmoothStep() { +VisualShaderNodeSmoothStep::VisualShaderNodeSmoothStep() { set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 0.0); - set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(2, 0.0); } ////////////// Distance @@ -3231,21 +3307,37 @@ VisualShaderNodeVectorRefract::VisualShaderNodeVectorRefract() { set_input_port_default_value(2, 0.0); } -////////////// Scalar Mix +////////////// Mix -String VisualShaderNodeScalarInterp::get_caption() const { - return "ScalarMix"; +String VisualShaderNodeMix::get_caption() const { + return "Mix"; } -int VisualShaderNodeScalarInterp::get_input_port_count() const { +int VisualShaderNodeMix::get_input_port_count() const { return 3; } -VisualShaderNodeScalarInterp::PortType VisualShaderNodeScalarInterp::get_input_port_type(int p_port) const { +VisualShaderNodeMix::PortType VisualShaderNodeMix::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_SCALAR: + return PORT_TYPE_SCALAR; + case OP_TYPE_VECTOR: + if (p_port == 2) { + return PORT_TYPE_VECTOR; + } + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + if (p_port == 2) { + return PORT_TYPE_SCALAR; + } + return PORT_TYPE_VECTOR; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarInterp::get_input_port_name(int p_port) const { +String VisualShaderNodeMix::get_input_port_name(int p_port) const { if (p_port == 0) { return "a"; } else if (p_port == 1) { @@ -3255,121 +3347,92 @@ String VisualShaderNodeScalarInterp::get_input_port_name(int p_port) const { } } -int VisualShaderNodeScalarInterp::get_output_port_count() const { +int VisualShaderNodeMix::get_output_port_count() const { return 1; } -VisualShaderNodeScalarInterp::PortType VisualShaderNodeScalarInterp::get_output_port_type(int p_port) const { +VisualShaderNodeMix::PortType VisualShaderNodeMix::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_SCALAR: + return PORT_TYPE_SCALAR; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + return PORT_TYPE_VECTOR; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarInterp::get_output_port_name(int p_port) const { +String VisualShaderNodeMix::get_output_port_name(int p_port) const { return "mix"; } -String VisualShaderNodeScalarInterp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = mix(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; -} - -VisualShaderNodeScalarInterp::VisualShaderNodeScalarInterp() { - set_input_port_default_value(0, 0.0); - set_input_port_default_value(1, 1.0); - set_input_port_default_value(2, 0.5); -} - -////////////// Vector Mix - -String VisualShaderNodeVectorInterp::get_caption() const { - return "VectorMix"; -} - -int VisualShaderNodeVectorInterp::get_input_port_count() const { - return 3; -} - -VisualShaderNodeVectorInterp::PortType VisualShaderNodeVectorInterp::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} - -String VisualShaderNodeVectorInterp::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "a"; - } else if (p_port == 1) { - return "b"; - } else { - return "weight"; +void VisualShaderNodeMix::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_SCALAR: + set_input_port_default_value(0, 0.0); // a + set_input_port_default_value(1, 1.0); // b + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(2, 0.5); // weight + } + break; + case OP_TYPE_VECTOR: + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // a + set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); // b + if (op_type == OP_TYPE_SCALAR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(2, Vector3(0.5, 0.5, 0.5)); // weight + } + break; + case OP_TYPE_VECTOR_SCALAR: + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // a + set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); // b + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(2, 0.5); // weight + } + break; + default: + break; } + op_type = p_op_type; + emit_changed(); } -int VisualShaderNodeVectorInterp::get_output_port_count() const { - return 1; -} - -VisualShaderNodeVectorInterp::PortType VisualShaderNodeVectorInterp::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} - -String VisualShaderNodeVectorInterp::get_output_port_name(int p_port) const { - return "mix"; +VisualShaderNodeMix::OpType VisualShaderNodeMix::get_op_type() const { + return op_type; } -String VisualShaderNodeVectorInterp::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { +String VisualShaderNodeMix::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { return "\t" + p_output_vars[0] + " = mix(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } -VisualShaderNodeVectorInterp::VisualShaderNodeVectorInterp() { - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); - set_input_port_default_value(2, Vector3(0.5, 0.5, 0.5)); -} - -////////////// Vector Mix (by scalar) - -String VisualShaderNodeVectorScalarMix::get_caption() const { - return "VectorScalarMix"; -} - -int VisualShaderNodeVectorScalarMix::get_input_port_count() const { - return 3; -} - -VisualShaderNodeVectorScalarMix::PortType VisualShaderNodeVectorScalarMix::get_input_port_type(int p_port) const { - if (p_port == 2) { - return PORT_TYPE_SCALAR; - } - return PORT_TYPE_VECTOR; -} - -String VisualShaderNodeVectorScalarMix::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "a"; - } else if (p_port == 1) { - return "b"; - } else { - return "weight"; - } -} - -int VisualShaderNodeVectorScalarMix::get_output_port_count() const { - return 1; +Vector<StringName> VisualShaderNodeMix::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; } -VisualShaderNodeVectorScalarMix::PortType VisualShaderNodeVectorScalarMix::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} +void VisualShaderNodeMix::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeMix::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeMix::get_op_type); -String VisualShaderNodeVectorScalarMix::get_output_port_name(int p_port) const { - return "mix"; -} + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector,VectorScalar"), "set_op_type", "get_op_type"); -String VisualShaderNodeVectorScalarMix::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - return "\t" + p_output_vars[0] + " = mix(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); } -VisualShaderNodeVectorScalarMix::VisualShaderNodeVectorScalarMix() { - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); - set_input_port_default_value(2, 0.5); +VisualShaderNodeMix::VisualShaderNodeMix() { + set_input_port_default_value(0, 0.0); // a + set_input_port_default_value(1, 1.0); // b + set_input_port_default_value(2, 0.5); // weight } ////////////// Vector Compose @@ -4847,7 +4910,7 @@ VisualShaderNodeIf::VisualShaderNodeIf() { ////////////// Switch String VisualShaderNodeSwitch::get_caption() const { - return "VectorSwitch"; + return "Switch"; } int VisualShaderNodeSwitch::get_input_port_count() const { @@ -4858,7 +4921,23 @@ VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_input_port_type(int if (p_port == 0) { return PORT_TYPE_BOOLEAN; } - return PORT_TYPE_VECTOR; + if (p_port == 1 || p_port == 2) { + switch (op_type) { + case OP_TYPE_FLOAT: + return PORT_TYPE_SCALAR; + case OP_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_BOOLEAN: + return PORT_TYPE_BOOLEAN; + case OP_TYPE_TRANSFORM: + return PORT_TYPE_TRANSFORM; + default: + break; + } + } + return PORT_TYPE_SCALAR; } String VisualShaderNodeSwitch::get_input_port_name(int p_port) const { @@ -4879,13 +4958,84 @@ int VisualShaderNodeSwitch::get_output_port_count() const { } VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + switch (op_type) { + case OP_TYPE_FLOAT: + return PORT_TYPE_SCALAR; + case OP_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_BOOLEAN: + return PORT_TYPE_BOOLEAN; + case OP_TYPE_TRANSFORM: + return PORT_TYPE_TRANSFORM; + default: + break; + } + return PORT_TYPE_SCALAR; } String VisualShaderNodeSwitch::get_output_port_name(int p_port) const { return "result"; } +void VisualShaderNodeSwitch::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_FLOAT: + set_input_port_default_value(1, 1.0); + set_input_port_default_value(2, 0.0); + break; + case OP_TYPE_INT: + set_input_port_default_value(1, 1); + set_input_port_default_value(2, 0); + break; + case OP_TYPE_VECTOR: + set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); + break; + case OP_TYPE_BOOLEAN: + set_input_port_default_value(1, true); + set_input_port_default_value(2, false); + break; + case OP_TYPE_TRANSFORM: + set_input_port_default_value(1, Transform()); + set_input_port_default_value(2, Transform()); + break; + default: + break; + } + op_type = p_op_type; + emit_changed(); +} + +VisualShaderNodeSwitch::OpType VisualShaderNodeSwitch::get_op_type() const { + return op_type; +} + +Vector<StringName> VisualShaderNodeSwitch::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; +} + +void VisualShaderNodeSwitch::_bind_methods() { // static + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeSwitch::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeSwitch::get_op_type); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector,Boolean,Transform"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_FLOAT); + BIND_ENUM_CONSTANT(OP_TYPE_INT); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_BOOLEAN); + BIND_ENUM_CONSTANT(OP_TYPE_TRANSFORM); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); +} + String VisualShaderNodeSwitch::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; code += "\tif(" + p_input_vars[0] + ")\n"; @@ -4902,29 +5052,6 @@ String VisualShaderNodeSwitch::generate_code(Shader::Mode p_mode, VisualShader:: VisualShaderNodeSwitch::VisualShaderNodeSwitch() { simple_decl = false; set_input_port_default_value(0, false); - set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); - set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); -} - -////////////// Switch(scalar) - -String VisualShaderNodeScalarSwitch::get_caption() const { - return "ScalarSwitch"; -} - -VisualShaderNodeScalarSwitch::PortType VisualShaderNodeScalarSwitch::get_input_port_type(int p_port) const { - if (p_port == 0) { - return PORT_TYPE_BOOLEAN; - } - return PORT_TYPE_SCALAR; -} - -VisualShaderNodeScalarSwitch::PortType VisualShaderNodeScalarSwitch::get_output_port_type(int p_port) const { - return PORT_TYPE_SCALAR; -} - -VisualShaderNodeScalarSwitch::VisualShaderNodeScalarSwitch() { - set_input_port_default_value(0, false); set_input_port_default_value(1, 1.0); set_input_port_default_value(2, 0.0); } @@ -5384,16 +5511,22 @@ String VisualShaderNodeMultiplyAdd::generate_code(Shader::Mode p_mode, VisualSha void VisualShaderNodeMultiplyAdd::set_op_type(OpType p_op_type) { ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); - if (p_op_type != op_type) { - if (p_op_type == OP_TYPE_SCALAR) { + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_SCALAR: set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 0.0); set_input_port_default_value(2, 0.0); - } else { + break; + case OP_TYPE_VECTOR: set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); - } + break; + default: + break; } op_type = p_op_type; emit_changed(); diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index e968bbae25..a5d0fe4649 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -826,7 +826,6 @@ class VisualShaderNodeIntFunc : public VisualShaderNode { public: enum Function { FUNC_ABS, - FUNC_CLAMP, FUNC_NEGATE, FUNC_SIGN, }; @@ -1088,29 +1087,20 @@ public: /// CLAMP /////////////////////////////////////// -class VisualShaderNodeScalarClamp : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarClamp, VisualShaderNode); +class VisualShaderNodeClamp : public VisualShaderNode { + GDCLASS(VisualShaderNodeClamp, VisualShaderNode); public: - virtual String get_caption() const override; - - virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; - virtual String get_input_port_name(int p_port) const override; - - virtual int get_output_port_count() const override; - virtual PortType get_output_port_type(int p_port) const override; - virtual String get_output_port_name(int p_port) const override; - - virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty - - VisualShaderNodeScalarClamp(); -}; - -/////////////////////////////////////// + enum OpType { + OP_TYPE_FLOAT, + OP_TYPE_INT, + OP_TYPE_VECTOR, + OP_TYPE_MAX, + }; -class VisualShaderNodeVectorClamp : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorClamp, VisualShaderNode); +protected: + OpType op_type = OP_TYPE_FLOAT; + static void _bind_methods(); public: virtual String get_caption() const override; @@ -1123,11 +1113,18 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + void set_op_type(OpType p_type); + OpType get_op_type() const; + + virtual Vector<StringName> get_editable_properties() const override; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty - VisualShaderNodeVectorClamp(); + VisualShaderNodeClamp(); }; +VARIANT_ENUM_CAST(VisualShaderNodeClamp::OpType) + /////////////////////////////////////// /// DERIVATIVE FUNCTIONS /////////////////////////////////////// @@ -1260,8 +1257,20 @@ public: /// STEP /////////////////////////////////////// -class VisualShaderNodeVectorScalarStep : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorScalarStep, VisualShaderNode); +class VisualShaderNodeStep : public VisualShaderNode { + GDCLASS(VisualShaderNodeStep, VisualShaderNode); + +public: + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR, + OP_TYPE_VECTOR_SCALAR, + OP_TYPE_MAX, + }; + +protected: + OpType op_type = OP_TYPE_SCALAR; + static void _bind_methods(); public: virtual String get_caption() const override; @@ -1274,38 +1283,36 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + void set_op_type(OpType p_type); + OpType get_op_type() const; + + virtual Vector<StringName> get_editable_properties() const override; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty - VisualShaderNodeVectorScalarStep(); + VisualShaderNodeStep(); }; +VARIANT_ENUM_CAST(VisualShaderNodeStep::OpType) + /////////////////////////////////////// /// SMOOTHSTEP /////////////////////////////////////// -class VisualShaderNodeScalarSmoothStep : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarSmoothStep, VisualShaderNode); +class VisualShaderNodeSmoothStep : public VisualShaderNode { + GDCLASS(VisualShaderNodeSmoothStep, VisualShaderNode); public: - virtual String get_caption() const override; - - virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; - virtual String get_input_port_name(int p_port) const override; - - virtual int get_output_port_count() const override; - virtual PortType get_output_port_type(int p_port) const override; - virtual String get_output_port_name(int p_port) const override; - - virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty - - VisualShaderNodeScalarSmoothStep(); -}; - -/////////////////////////////////////// + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR, + OP_TYPE_VECTOR_SCALAR, + OP_TYPE_MAX, + }; -class VisualShaderNodeVectorSmoothStep : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorSmoothStep, VisualShaderNode); +protected: + OpType op_type = OP_TYPE_SCALAR; + static void _bind_methods(); public: virtual String get_caption() const override; @@ -1318,32 +1325,18 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; - virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty - - VisualShaderNodeVectorSmoothStep(); -}; - -/////////////////////////////////////// - -class VisualShaderNodeVectorScalarSmoothStep : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorScalarSmoothStep, VisualShaderNode); - -public: - virtual String get_caption() const override; - - virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; - virtual String get_input_port_name(int p_port) const override; + void set_op_type(OpType p_type); + OpType get_op_type() const; - virtual int get_output_port_count() const override; - virtual PortType get_output_port_type(int p_port) const override; - virtual String get_output_port_name(int p_port) const override; + virtual Vector<StringName> get_editable_properties() const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty - VisualShaderNodeVectorScalarSmoothStep(); + VisualShaderNodeSmoothStep(); }; +VARIANT_ENUM_CAST(VisualShaderNodeSmoothStep::OpType) + /////////////////////////////////////// /// DISTANCE /////////////////////////////////////// @@ -1394,29 +1387,20 @@ public: /// MIX /////////////////////////////////////// -class VisualShaderNodeScalarInterp : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarInterp, VisualShaderNode); +class VisualShaderNodeMix : public VisualShaderNode { + GDCLASS(VisualShaderNodeMix, VisualShaderNode); public: - virtual String get_caption() const override; - - virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; - virtual String get_input_port_name(int p_port) const override; - - virtual int get_output_port_count() const override; - virtual PortType get_output_port_type(int p_port) const override; - virtual String get_output_port_name(int p_port) const override; - - virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty - - VisualShaderNodeScalarInterp(); -}; - -/////////////////////////////////////// + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR, + OP_TYPE_VECTOR_SCALAR, + OP_TYPE_MAX, + }; -class VisualShaderNodeVectorInterp : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorInterp, VisualShaderNode); +protected: + OpType op_type = OP_TYPE_SCALAR; + static void _bind_methods(); public: virtual String get_caption() const override; @@ -1429,32 +1413,18 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; - virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty - - VisualShaderNodeVectorInterp(); -}; - -/////////////////////////////////////// - -class VisualShaderNodeVectorScalarMix : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorScalarMix, VisualShaderNode); - -public: - virtual String get_caption() const override; - - virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; - virtual String get_input_port_name(int p_port) const override; + void set_op_type(OpType p_type); + OpType get_op_type() const; - virtual int get_output_port_count() const override; - virtual PortType get_output_port_type(int p_port) const override; - virtual String get_output_port_name(int p_port) const override; + virtual Vector<StringName> get_editable_properties() const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty - VisualShaderNodeVectorScalarMix(); + VisualShaderNodeMix(); }; +VARIANT_ENUM_CAST(VisualShaderNodeMix::OpType) + /////////////////////////////////////// /// COMPOSE /////////////////////////////////////// @@ -2023,6 +1993,21 @@ class VisualShaderNodeSwitch : public VisualShaderNode { GDCLASS(VisualShaderNodeSwitch, VisualShaderNode); public: + enum OpType { + OP_TYPE_FLOAT, + OP_TYPE_INT, + OP_TYPE_VECTOR, + OP_TYPE_BOOLEAN, + OP_TYPE_TRANSFORM, + OP_TYPE_MAX, + }; + +protected: + OpType op_type = OP_TYPE_FLOAT; + + static void _bind_methods(); + +public: virtual String get_caption() const override; virtual int get_input_port_count() const override; @@ -2033,22 +2018,17 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + void set_op_type(OpType p_type); + OpType get_op_type() const; + + virtual Vector<StringName> get_editable_properties() const override; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; VisualShaderNodeSwitch(); }; -class VisualShaderNodeScalarSwitch : public VisualShaderNodeSwitch { - GDCLASS(VisualShaderNodeScalarSwitch, VisualShaderNodeSwitch); - -public: - virtual String get_caption() const override; - - virtual PortType get_input_port_type(int p_port) const override; - virtual PortType get_output_port_type(int p_port) const override; - - VisualShaderNodeScalarSwitch(); -}; +VARIANT_ENUM_CAST(VisualShaderNodeSwitch::OpType) /////////////////////////////////////// /// FRESNEL diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp index 12cadb9301..faddced155 100644 --- a/servers/audio/audio_driver_dummy.cpp +++ b/servers/audio/audio_driver_dummy.cpp @@ -48,7 +48,7 @@ Error AudioDriverDummy::init() { samples_in = memnew_arr(int32_t, buffer_frames * channels); - thread = Thread::create(AudioDriverDummy::thread_func, this); + thread.start(AudioDriverDummy::thread_func, this); return OK; }; @@ -86,31 +86,18 @@ AudioDriver::SpeakerMode AudioDriverDummy::get_speaker_mode() const { }; void AudioDriverDummy::lock() { - if (!thread) { - return; - } mutex.lock(); }; void AudioDriverDummy::unlock() { - if (!thread) { - return; - } mutex.unlock(); }; void AudioDriverDummy::finish() { - if (!thread) { - return; - } - exit_thread = true; - Thread::wait_to_finish(thread); + thread.wait_to_finish(); if (samples_in) { memdelete_arr(samples_in); }; - - memdelete(thread); - thread = nullptr; }; diff --git a/servers/audio/audio_driver_dummy.h b/servers/audio/audio_driver_dummy.h index 617ffb2c79..7d84e7ffc8 100644 --- a/servers/audio/audio_driver_dummy.h +++ b/servers/audio/audio_driver_dummy.h @@ -37,7 +37,7 @@ #include "core/os/thread.h" class AudioDriverDummy : public AudioDriver { - Thread *thread = nullptr; + Thread thread; Mutex mutex; int32_t *samples_in; diff --git a/servers/audio/effects/audio_effect_record.cpp b/servers/audio/effects/audio_effect_record.cpp index e8832c92a3..2015ede81f 100644 --- a/servers/audio/effects/audio_effect_record.cpp +++ b/servers/audio/effects/audio_effect_record.cpp @@ -118,7 +118,7 @@ void AudioEffectRecordInstance::init() { #ifdef NO_THREADS AudioServer::get_singleton()->add_update_callback(&AudioEffectRecordInstance::_update, this); #else - io_thread = Thread::create(_thread_callback, this); + io_thread.start(_thread_callback, this); #endif } @@ -126,9 +126,7 @@ void AudioEffectRecordInstance::finish() { #ifdef NO_THREADS AudioServer::get_singleton()->remove_update_callback(&AudioEffectRecordInstance::_update, this); #else - if (thread_active) { - Thread::wait_to_finish(io_thread); - } + io_thread.wait_to_finish(); #endif } diff --git a/servers/audio/effects/audio_effect_record.h b/servers/audio/effects/audio_effect_record.h index 14e646e29d..b97ec43946 100644 --- a/servers/audio/effects/audio_effect_record.h +++ b/servers/audio/effects/audio_effect_record.h @@ -48,7 +48,7 @@ class AudioEffectRecordInstance : public AudioEffectInstance { Ref<AudioEffectRecord> base; bool is_recording; - Thread *io_thread; + Thread io_thread; bool thread_active = false; Vector<AudioFrame> ring_buffer; diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.cpp b/servers/physics_2d/physics_server_2d_wrap_mt.cpp index 15d875b3b7..897724fe6f 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.cpp +++ b/servers/physics_2d/physics_server_2d_wrap_mt.cpp @@ -76,7 +76,7 @@ void PhysicsServer2DWrapMT::step(real_t p_step) { } void PhysicsServer2DWrapMT::sync() { - if (thread) { + if (create_thread) { if (first_frame) { first_frame = false; } else { @@ -97,7 +97,7 @@ void PhysicsServer2DWrapMT::end_sync() { void PhysicsServer2DWrapMT::init() { if (create_thread) { //OS::get_singleton()->release_rendering_thread(); - thread = Thread::create(_thread_callback, this); + thread.start(_thread_callback, this); while (!step_thread_up) { OS::get_singleton()->delay_usec(1000); } @@ -107,12 +107,9 @@ void PhysicsServer2DWrapMT::init() { } void PhysicsServer2DWrapMT::finish() { - if (thread) { + if (thread.is_started()) { command_queue.push(this, &PhysicsServer2DWrapMT::thread_exit); - Thread::wait_to_finish(thread); - memdelete(thread); - - thread = nullptr; + thread.wait_to_finish(); } else { physics_2d_server->finish(); } @@ -135,7 +132,6 @@ PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool command_queue(p_create_thread) { physics_2d_server = p_contained; create_thread = p_create_thread; - thread = nullptr; step_pending = 0; step_thread_up = false; diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h index 3c6ec877e0..fbc5b1eaa1 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.h +++ b/servers/physics_2d/physics_server_2d_wrap_mt.h @@ -53,7 +53,7 @@ class PhysicsServer2DWrapMT : public PhysicsServer2D { Thread::ID server_thread; Thread::ID main_thread; volatile bool exit; - Thread *thread; + Thread thread; volatile bool step_thread_up; bool create_thread; diff --git a/servers/rendering/rendering_server_wrap_mt.cpp b/servers/rendering/rendering_server_wrap_mt.cpp index 3572c4dc78..9b8d35e5b3 100644 --- a/servers/rendering/rendering_server_wrap_mt.cpp +++ b/servers/rendering/rendering_server_wrap_mt.cpp @@ -97,7 +97,7 @@ void RenderingServerWrapMT::init() { print_verbose("RenderingServerWrapMT: Creating render thread"); DisplayServer::get_singleton()->release_rendering_thread(); if (create_thread) { - thread = Thread::create(_thread_callback, this); + thread.start(_thread_callback, this); print_verbose("RenderingServerWrapMT: Starting render thread"); } while (!draw_thread_up) { @@ -136,12 +136,9 @@ void RenderingServerWrapMT::finish() { canvas_light_occluder_free_cached_ids(); canvas_occluder_polygon_free_cached_ids(); - if (thread) { + if (create_thread) { command_queue.push(this, &RenderingServerWrapMT::thread_exit); - Thread::wait_to_finish(thread); - memdelete(thread); - - thread = nullptr; + thread.wait_to_finish(); } else { rendering_server->finish(); } @@ -160,7 +157,6 @@ RenderingServerWrapMT::RenderingServerWrapMT(RenderingServer *p_contained, bool rendering_server = p_contained; create_thread = p_create_thread; - thread = nullptr; draw_pending = 0; draw_thread_up = false; pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc"); diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h index 2f76577474..f8e73654a0 100644 --- a/servers/rendering/rendering_server_wrap_mt.h +++ b/servers/rendering/rendering_server_wrap_mt.h @@ -46,7 +46,7 @@ class RenderingServerWrapMT : public RenderingServer { Thread::ID server_thread; volatile bool exit; - Thread *thread; + Thread thread; volatile bool draw_thread_up; bool create_thread; diff --git a/tests/test_command_queue.h b/tests/test_command_queue.h index 2f0b75760d..b4fa63ad2b 100644 --- a/tests/test_command_queue.h +++ b/tests/test_command_queue.h @@ -122,8 +122,8 @@ public: int message_count_to_read = 0; bool exit_threads = false; - Thread *reader_thread = nullptr; - Thread *writer_thread = nullptr; + Thread reader_thread; + Thread writer_thread; int func1_count = 0; @@ -221,20 +221,16 @@ public: } void init_threads() { - reader_thread = Thread::create(&SharedThreadState::static_reader_thread_loop, this); - writer_thread = Thread::create(&SharedThreadState::static_writer_thread_loop, this); + reader_thread.start(&SharedThreadState::static_reader_thread_loop, this); + writer_thread.start(&SharedThreadState::static_writer_thread_loop, this); } void destroy_threads() { exit_threads = true; reader_threadwork.main_start_work(); writer_threadwork.main_start_work(); - Thread::wait_to_finish(reader_thread); - memdelete(reader_thread); - reader_thread = nullptr; - Thread::wait_to_finish(writer_thread); - memdelete(writer_thread); - writer_thread = nullptr; + reader_thread.wait_to_finish(); + writer_thread.wait_to_finish(); } }; |