From 44d62a9f4b6ac892b1fb9b8998be4162409952e3 Mon Sep 17 00:00:00 2001 From: reduz Date: Mon, 23 Aug 2021 14:53:27 -0300 Subject: [PATCH] Implement NativeExtension pointer arguments * Allows calling into native extensions directly with a pointer * Makes it easier to implement some APIs more efficiently * Appears with a "*" in the documentation for the argument. * Implementing the pointer handling is entirely up to the implementation, although the extension API provides some hint. * AudioStream has been implemented as an example, allowing to create NativeExtension based AudioStreams. --- core/core_constants.cpp | 1 + core/doc_data.cpp | 18 +++- core/extension/extension_api_dump.cpp | 21 +++++ core/object/make_virtuals.py | 5 +- core/object/object.h | 1 + core/variant/method_ptrcall.h | 7 ++ core/variant/native_ptr.h | 130 ++++++++++++++++++++++++++ doc/classes/@GlobalScope.xml | 4 +- doc/classes/AudioStream.xml | 15 +++ doc/classes/AudioStreamPlayback.xml | 40 ++++++++ doc/tools/makerst.py | 2 + editor/editor_help.cpp | 6 +- scene/2d/audio_stream_player_2d.cpp | 6 +- scene/3d/audio_stream_player_3d.cpp | 6 +- scene/audio/audio_stream_player.cpp | 6 +- servers/audio/audio_stream.cpp | 84 +++++++++++++++++ servers/audio/audio_stream.h | 39 +++++--- servers/register_server_types.cpp | 4 +- 18 files changed, 370 insertions(+), 25 deletions(-) create mode 100644 core/variant/native_ptr.h diff --git a/core/core_constants.cpp b/core/core_constants.cpp index ffddcbabc4..4f3f1fd16e 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -558,6 +558,7 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_PATH_VALID_TYPES); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_SAVE_FILE); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_OBJECTID); + BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_INT_IS_POINTER); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ARRAY_TYPE); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX); diff --git a/core/doc_data.cpp b/core/doc_data.cpp index 45450bf97a..4b284a30aa 100644 --- a/core/doc_data.cpp +++ b/core/doc_data.cpp @@ -31,7 +31,14 @@ #include "doc_data.h" void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo) { - if (p_retinfo.type == Variant::INT && p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + if (p_retinfo.type == Variant::INT && p_retinfo.hint == PROPERTY_HINT_INT_IS_POINTER) { + p_method.return_type = p_retinfo.hint_string; + if (p_method.return_type == "") { + p_method.return_type = "void*"; + } else { + p_method.return_type += "*"; + } + } else if (p_retinfo.type == Variant::INT && p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { p_method.return_enum = p_retinfo.class_name; if (p_method.return_enum.begins_with("_")) { //proxy class p_method.return_enum = p_method.return_enum.substr(1, p_method.return_enum.length()); @@ -55,7 +62,14 @@ void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const Proper void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo) { p_argument.name = p_arginfo.name; - if (p_arginfo.type == Variant::INT && p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + if (p_arginfo.type == Variant::INT && p_arginfo.hint == PROPERTY_HINT_INT_IS_POINTER) { + p_argument.type = p_arginfo.hint_string; + if (p_argument.type == "") { + p_argument.type = "void*"; + } else { + p_argument.type += "*"; + } + } else if (p_arginfo.type == Variant::INT && p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { p_argument.enumeration = p_arginfo.class_name; if (p_argument.enumeration.begins_with("_")) { //proxy class p_argument.enumeration = p_argument.enumeration.substr(1, p_argument.enumeration.length()); diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index 46dc5f284b..a8547a0090 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -39,6 +39,13 @@ #ifdef TOOLS_ENABLED static String get_type_name(const PropertyInfo &p_info) { + if (p_info.type == Variant::INT && (p_info.hint == PROPERTY_HINT_INT_IS_POINTER)) { + if (p_info.hint_string == "") { + return "void*"; + } else { + return p_info.hint_string + "*"; + } + } if (p_info.type == Variant::INT && (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM)) { return String("enum::") + String(p_info.class_name); } @@ -831,6 +838,20 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() { } } + { + Array native_structures; + + { + Dictionary d; + d["name"] = "AudioFrame"; + d["format"] = "float left,float right"; + + native_structures.push_back(d); + } + + api_dump["native_structures"] = native_structures; + } + return api_dump; } diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py index af90593140..65a421cfb2 100644 --- a/core/object/make_virtuals.py +++ b/core/object/make_virtuals.py @@ -2,7 +2,7 @@ proto = """ #define GDVIRTUAL$VER($RET m_name $ARG) \\ StringName _gdvirtual_##m_name##_sn = #m_name;\\ GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\ -bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\ +_FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\ ScriptInstance *script_instance = ((Object*)(this))->get_script_instance();\\ if (script_instance) {\\ Callable::CallError ce; \\ @@ -23,7 +23,7 @@ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\ \\ return false;\\ }\\ -bool _gdvirtual_##m_name##_overriden() const { \\ +_FORCE_INLINE_ bool _gdvirtual_##m_name##_overriden() const { \\ ScriptInstance *script_instance = ((Object*)(this))->get_script_instance();\\ if (script_instance) {\\ return script_instance->has_method(_gdvirtual_##m_name##_sn);\\ @@ -42,7 +42,6 @@ _FORCE_INLINE_ static MethodInfo _gdvirtual_##m_name##_get_method_info() { \\ return method_info;\\ } - """ diff --git a/core/object/object.h b/core/object/object.h index aede48343c..a53143158b 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -97,6 +97,7 @@ enum PropertyHint { PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog PROPERTY_HINT_INT_IS_OBJECTID, PROPERTY_HINT_ARRAY_TYPE, + PROPERTY_HINT_INT_IS_POINTER, PROPERTY_HINT_MAX, // When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit }; diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h index 8836e257a9..98304621f2 100644 --- a/core/variant/method_ptrcall.h +++ b/core/variant/method_ptrcall.h @@ -191,6 +191,7 @@ struct PtrToArg { // This is for the special cases used by Variant. +// No EncodeT because direct pointer conversion not possible. #define MAKE_VECARG(m_type) \ template <> \ struct PtrToArg> { \ @@ -236,6 +237,7 @@ struct PtrToArg { } \ } +// No EncodeT because direct pointer conversion not possible. #define MAKE_VECARG_ALT(m_type, m_type_alt) \ template <> \ struct PtrToArg> { \ @@ -285,6 +287,7 @@ MAKE_VECARG_ALT(String, StringName); // For stuff that gets converted to Array vectors. +// No EncodeT because direct pointer conversion not possible. #define MAKE_VECARR(m_type) \ template <> \ struct PtrToArg> { \ @@ -325,6 +328,7 @@ MAKE_VECARR(Variant); MAKE_VECARR(RID); MAKE_VECARR(Plane); +// No EncodeT because direct pointer conversion not possible. #define MAKE_DVECARR(m_type) \ template <> \ struct PtrToArg> { \ @@ -372,6 +376,7 @@ MAKE_VECARR(Plane); // Special case for IPAddress. +// No EncodeT because direct pointer conversion not possible. #define MAKE_STRINGCONV_BY_REFERENCE(m_type) \ template <> \ struct PtrToArg { \ @@ -395,6 +400,7 @@ MAKE_VECARR(Plane); MAKE_STRINGCONV_BY_REFERENCE(IPAddress); +// No EncodeT because direct pointer conversion not possible. template <> struct PtrToArg> { _FORCE_INLINE_ static Vector convert(const void *p_ptr) { @@ -429,6 +435,7 @@ struct PtrToArg> { } }; +// No EncodeT because direct pointer conversion not possible. template <> struct PtrToArg &> { _FORCE_INLINE_ static Vector convert(const void *p_ptr) { diff --git a/core/variant/native_ptr.h b/core/variant/native_ptr.h new file mode 100644 index 0000000000..b4ec0df7d6 --- /dev/null +++ b/core/variant/native_ptr.h @@ -0,0 +1,130 @@ +/*************************************************************************/ +/* native_ptr.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 NATIVE_PTR_H +#define NATIVE_PTR_H + +#include "core/math/audio_frame.h" +#include "core/variant/method_ptrcall.h" +#include "core/variant/type_info.h" + +template +struct GDNativeConstPtr { + const T *data = nullptr; + GDNativeConstPtr(const T *p_assign) { data = p_assign; } + static const char *get_name() { return "const void"; } + operator const T *() const { return data; } + operator Variant() const { return uint64_t(data); } +}; + +template +struct GDNativePtr { + T *data = nullptr; + GDNativePtr(T *p_assign) { data = p_assign; } + static const char *get_name() { return "void"; } + operator T *() const { return data; } + operator Variant() const { return uint64_t(data); } +}; + +#define GDVIRTUAL_NATIVE_PTR(m_type) \ + template <> \ + struct GDNativeConstPtr { \ + const m_type *data = nullptr; \ + GDNativeConstPtr(const m_type *p_assign) { data = p_assign; } \ + static const char *get_name() { return "const " #m_type; } \ + operator const m_type *() const { return data; } \ + operator Variant() const { return uint64_t(data); } \ + }; \ + template <> \ + struct GDNativePtr { \ + m_type *data = nullptr; \ + GDNativePtr(m_type *p_assign) { data = p_assign; } \ + static const char *get_name() { return #m_type; } \ + operator m_type *() const { return data; } \ + operator Variant() const { return uint64_t(data); } \ + }; + +template +struct GetTypeInfo> { + static const Variant::Type VARIANT_TYPE = Variant::NIL; + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; + static inline PropertyInfo get_class_info() { + return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_INT_IS_POINTER, GDNativeConstPtr::get_name()); + } +}; + +template +struct GetTypeInfo> { + static const Variant::Type VARIANT_TYPE = Variant::NIL; + static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; + static inline PropertyInfo get_class_info() { + return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_INT_IS_POINTER, GDNativePtr::get_name()); + } +}; + +template +struct PtrToArg> { + _FORCE_INLINE_ static GDNativeConstPtr convert(const void *p_ptr) { + return GDNativeConstPtr(reinterpret_cast(p_ptr)); + } + typedef const T *EncodeT; + _FORCE_INLINE_ static void encode(GDNativeConstPtr p_val, void *p_ptr) { + *((const T **)p_ptr) = p_val.data; + } +}; +template +struct PtrToArg> { + _FORCE_INLINE_ static GDNativePtr convert(const void *p_ptr) { + return GDNativePtr(reinterpret_cast(p_ptr)); + } + typedef T *EncodeT; + _FORCE_INLINE_ static void encode(GDNativePtr p_val, void *p_ptr) { + *((T **)p_ptr) = p_val.data; + } +}; + +GDVIRTUAL_NATIVE_PTR(AudioFrame) +GDVIRTUAL_NATIVE_PTR(bool) +GDVIRTUAL_NATIVE_PTR(char) +GDVIRTUAL_NATIVE_PTR(char16_t) +GDVIRTUAL_NATIVE_PTR(char32_t) +GDVIRTUAL_NATIVE_PTR(wchar_t) +GDVIRTUAL_NATIVE_PTR(uint8_t) +GDVIRTUAL_NATIVE_PTR(int8_t) +GDVIRTUAL_NATIVE_PTR(uint16_t) +GDVIRTUAL_NATIVE_PTR(int16_t) +GDVIRTUAL_NATIVE_PTR(uint32_t) +GDVIRTUAL_NATIVE_PTR(int32_t) +GDVIRTUAL_NATIVE_PTR(int64_t) +GDVIRTUAL_NATIVE_PTR(uint64_t) +GDVIRTUAL_NATIVE_PTR(float) +GDVIRTUAL_NATIVE_PTR(double) + +#endif // NATIVE_PTR_H diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 46b9bdd52d..af39069b38 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -2351,9 +2351,11 @@ + + - + diff --git a/doc/classes/AudioStream.xml b/doc/classes/AudioStream.xml index 8a58b178d8..a954a06117 100644 --- a/doc/classes/AudioStream.xml +++ b/doc/classes/AudioStream.xml @@ -13,6 +13,21 @@ https://godotengine.org/asset-library/asset/528 + + + + + + + + + + + + + + + diff --git a/doc/classes/AudioStreamPlayback.xml b/doc/classes/AudioStreamPlayback.xml index cb01aa75e8..09d063ed3b 100644 --- a/doc/classes/AudioStreamPlayback.xml +++ b/doc/classes/AudioStreamPlayback.xml @@ -10,6 +10,46 @@ https://godotengine.org/asset-library/asset/526 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py index 4691b61e1b..a23324fd24 100755 --- a/doc/tools/makerst.py +++ b/doc/tools/makerst.py @@ -1007,6 +1007,8 @@ def format_table(f, data, remove_empty_columns=False): # type: (TextIO, Iterabl def make_type(klass, state): # type: (str, State) -> str + if klass.find("*") != -1: # Pointer, ignore + return klass link_type = klass if link_type.endswith("[]"): # Typed array, strip [] to link to contained type. link_type = link_type[:-2] diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 7df5f15a81..16151e36de 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -170,7 +170,7 @@ void EditorHelp::_add_type(const String &p_type, const String &p_enum) { if (t.is_empty()) { t = "void"; } - bool can_ref = (t != "void") || !p_enum.is_empty(); + bool can_ref = (t != "void" && t.find("*") == -1) || !p_enum.is_empty(); if (!p_enum.is_empty()) { if (p_enum.get_slice_count(".") > 1) { @@ -632,8 +632,8 @@ void EditorHelp::_update_doc() { continue; } } - // Ignore undocumented private. - if (cd.methods[i].name.begins_with("_") && cd.methods[i].description.is_empty()) { + // Ignore undocumented non virtual private. + if (cd.methods[i].name.begins_with("_") && cd.methods[i].description.is_empty() && cd.methods[i].qualifiers.find("virtual") == -1) { continue; } methods.push_back(cd.methods[i]); diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index e0b994f27d..8a4d42fd1f 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -272,8 +272,12 @@ void AudioStreamPlayer2D::set_stream(Ref p_stream) { } if (p_stream.is_valid()) { - stream = p_stream; stream_playback = p_stream->instance_playback(); + if (stream_playback.is_valid()) { + stream = p_stream; + } else { + stream.unref(); + } } AudioServer::get_singleton()->unlock(); diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index d2424c9a3b..3b44580264 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -624,8 +624,12 @@ void AudioStreamPlayer3D::set_stream(Ref p_stream) { } if (p_stream.is_valid()) { - stream = p_stream; stream_playback = p_stream->instance_playback(); + if (stream_playback.is_valid()) { + stream = p_stream; + } else { + stream.unref(); + } } AudioServer::get_singleton()->unlock(); diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index 298d75b668..9383355292 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -202,8 +202,12 @@ void AudioStreamPlayer::set_stream(Ref p_stream) { } if (p_stream.is_valid()) { - stream = p_stream; stream_playback = p_stream->instance_playback(); + if (stream_playback.is_valid()) { + stream = p_stream; + } else { + stream.unref(); + } } AudioServer::get_singleton()->unlock(); diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index f3fa857682..5544a09ac0 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -33,6 +33,63 @@ #include "core/config/project_settings.h" #include "core/os/os.h" +void AudioStreamPlayback::start(float p_from_pos) { + if (GDVIRTUAL_CALL(_start, p_from_pos)) { + return; + } + ERR_FAIL_MSG("AudioStreamPlayback::start unimplemented!"); +} +void AudioStreamPlayback::stop() { + if (GDVIRTUAL_CALL(_stop)) { + return; + } + ERR_FAIL_MSG("AudioStreamPlayback::stop unimplemented!"); +} +bool AudioStreamPlayback::is_playing() const { + bool ret; + if (GDVIRTUAL_CALL(_is_playing, ret)) { + return ret; + } + ERR_FAIL_V_MSG(false, "AudioStreamPlayback::is_playing unimplemented!"); +} + +int AudioStreamPlayback::get_loop_count() const { + int ret; + if (GDVIRTUAL_CALL(_get_loop_count, ret)) { + return ret; + } + return 0; +} + +float AudioStreamPlayback::get_playback_position() const { + float ret; + if (GDVIRTUAL_CALL(_get_playback_position, ret)) { + return ret; + } + ERR_FAIL_V_MSG(0, "AudioStreamPlayback::get_playback_position unimplemented!"); +} +void AudioStreamPlayback::seek(float p_time) { + if (GDVIRTUAL_CALL(_seek, p_time)) { + return; + } +} + +void AudioStreamPlayback::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) { + if (GDVIRTUAL_CALL(_mix, p_buffer, p_rate_scale, p_frames)) { + return; + } + WARN_PRINT_ONCE("AudioStreamPlayback::mix unimplemented!"); +} + +void AudioStreamPlayback::_bind_methods() { + GDVIRTUAL_BIND(_start, "from_pos") + GDVIRTUAL_BIND(_stop) + GDVIRTUAL_BIND(_is_playing) + GDVIRTUAL_BIND(_get_loop_count) + GDVIRTUAL_BIND(_get_playback_position) + GDVIRTUAL_BIND(_seek, "position") + GDVIRTUAL_BIND(_mix, "buffer", "rate_scale", "frames"); +} ////////////////////////////// void AudioStreamPlaybackResampled::_begin_resample() { @@ -92,8 +149,34 @@ void AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale, //////////////////////////////// +Ref AudioStream::instance_playback() { + Ref ret; + if (GDVIRTUAL_CALL(_instance_playback, ret)) { + return ret; + } + ERR_FAIL_V_MSG(Ref(), "Method must be implemented!"); +} +String AudioStream::get_stream_name() const { + String ret; + if (GDVIRTUAL_CALL(_get_stream_name, ret)) { + return ret; + } + return String(); +} + +float AudioStream::get_length() const { + float ret; + if (GDVIRTUAL_CALL(_get_length, ret)) { + return ret; + } + return 0; +} + void AudioStream::_bind_methods() { ClassDB::bind_method(D_METHOD("get_length"), &AudioStream::get_length); + GDVIRTUAL_BIND(_instance_playback); + GDVIRTUAL_BIND(_get_stream_name); + GDVIRTUAL_BIND(_get_length); } //////////////////////////////// @@ -358,3 +441,4 @@ void AudioStreamPlaybackRandomPitch::mix(AudioFrame *p_buffer, float p_rate_scal AudioStreamPlaybackRandomPitch::~AudioStreamPlaybackRandomPitch() { random_pitch->playbacks.erase(this); } +///////////////////////////////////////////// diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index 0d426f99b2..25f0017211 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -36,20 +36,33 @@ #include "servers/audio/audio_filter_sw.h" #include "servers/audio_server.h" +#include "core/object/gdvirtual.gen.inc" +#include "core/object/script_language.h" +#include "core/variant/native_ptr.h" + class AudioStreamPlayback : public RefCounted { GDCLASS(AudioStreamPlayback, RefCounted); +protected: + static void _bind_methods(); + GDVIRTUAL1(_start, float) + GDVIRTUAL0(_stop) + GDVIRTUAL0RC(bool, _is_playing) + GDVIRTUAL0RC(int, _get_loop_count) + GDVIRTUAL0RC(float, _get_playback_position) + GDVIRTUAL1(_seek, float) + GDVIRTUAL3(_mix, GDNativePtr, float, int) public: - virtual void start(float p_from_pos = 0.0) = 0; - virtual void stop() = 0; - virtual bool is_playing() const = 0; + virtual void start(float p_from_pos = 0.0); + virtual void stop(); + virtual bool is_playing() const; - virtual int get_loop_count() const = 0; //times it looped + virtual int get_loop_count() const; //times it looped - virtual float get_playback_position() const = 0; - virtual void seek(float p_time) = 0; + virtual float get_playback_position() const; + virtual void seek(float p_time); - virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) = 0; + virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames); }; class AudioStreamPlaybackResampled : public AudioStreamPlayback { @@ -84,11 +97,15 @@ class AudioStream : public Resource { protected: static void _bind_methods(); -public: - virtual Ref instance_playback() = 0; - virtual String get_stream_name() const = 0; + GDVIRTUAL0RC(Ref, _instance_playback) + GDVIRTUAL0RC(String, _get_stream_name) + GDVIRTUAL0RC(float, _get_length) - virtual float get_length() const = 0; //if supported, otherwise return 0 +public: + virtual Ref instance_playback(); + virtual String get_stream_name() const; + + virtual float get_length() const; }; // Microphone diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 857f112102..8e86957d9b 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -140,8 +140,8 @@ void register_server_types() { GDREGISTER_VIRTUAL_CLASS(XRInterface); GDREGISTER_CLASS(XRPositionalTracker); - GDREGISTER_VIRTUAL_CLASS(AudioStream); - GDREGISTER_VIRTUAL_CLASS(AudioStreamPlayback); + GDREGISTER_CLASS(AudioStream); + GDREGISTER_CLASS(AudioStreamPlayback); GDREGISTER_VIRTUAL_CLASS(AudioStreamPlaybackResampled); GDREGISTER_CLASS(AudioStreamMicrophone); GDREGISTER_CLASS(AudioStreamRandomPitch);