summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/canvas_item.cpp6
-rw-r--r--scene/2d/canvas_item.h2
-rw-r--r--scene/animation/animation_player.cpp9
-rw-r--r--scene/gui/item_list.cpp4
-rw-r--r--scene/gui/scroll_container.cpp5
-rw-r--r--scene/gui/text_edit.cpp7
-rw-r--r--scene/gui/text_edit.h1
-rw-r--r--scene/gui/video_player.cpp144
-rw-r--r--scene/gui/video_player.h22
-rwxr-xr-xscene/main/node.cpp17
-rw-r--r--scene/main/node.h1
-rw-r--r--scene/resources/primitive_meshes.cpp38
-rw-r--r--scene/resources/primitive_meshes.h5
-rw-r--r--scene/resources/video_stream.h4
14 files changed, 219 insertions, 46 deletions
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index b41ba7f590..fa45c61f68 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -178,6 +178,12 @@ CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const {
void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
}
+RID CanvasItemMaterial::get_shader_rid() const {
+
+ ERR_FAIL_COND_V(!shader_map.has(current_key), RID());
+ return shader_map[current_key].shader;
+}
+
void CanvasItemMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_blend_mode", "blend_mode"), &CanvasItemMaterial::set_blend_mode);
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
index cb8ee761e6..1a043c204f 100644
--- a/scene/2d/canvas_item.h
+++ b/scene/2d/canvas_item.h
@@ -121,6 +121,8 @@ public:
static void finish_shaders();
static void flush_changes();
+ RID get_shader_rid() const;
+
CanvasItemMaterial();
virtual ~CanvasItemMaterial();
};
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 80b7748078..6be3ff88d9 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -545,7 +545,14 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, f
} else {
- next_pos = Math::fposmod(next_pos, len);
+ float looped_next_pos = Math::fposmod(next_pos, len);
+ if (looped_next_pos == 0 && next_pos != 0) {
+ // Loop multiples of the length to it, rather than 0
+ // so state at time=length is previewable in the editor
+ next_pos = len;
+ } else {
+ next_pos = looped_next_pos;
+ }
}
cd.pos = next_pos;
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 623a110263..e9e9dcc859 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -754,7 +754,7 @@ void ItemList::_notification(int p_what) {
int width = size.width - bg->get_minimum_size().width;
if (scroll_bar->is_visible()) {
- width -= mw + bg->get_margin(MARGIN_RIGHT);
+ width -= mw;
}
draw_style_box(bg, Rect2(Point2(), size));
@@ -1107,7 +1107,7 @@ void ItemList::_notification(int p_what) {
}
for (int i = 0; i < separators.size(); i++) {
- draw_line(Vector2(bg->get_margin(MARGIN_LEFT), base_ofs.y + separators[i]), Vector2(size.width - bg->get_margin(MARGIN_RIGHT), base_ofs.y + separators[i]), guide_color);
+ draw_line(Vector2(bg->get_margin(MARGIN_LEFT), base_ofs.y + separators[i]), Vector2(width, base_ofs.y + separators[i]), guide_color);
}
}
}
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 1ad1e3f638..9022d67a4a 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -347,12 +347,11 @@ void ScrollContainer::update_scrollbars() {
} else {
v_scroll->show();
+ v_scroll->set_max(min.height);
+ v_scroll->set_page(size.height - hmin.height);
scroll.y = v_scroll->get_value();
}
- v_scroll->set_max(min.height);
- v_scroll->set_page(size.height - hmin.height);
-
if (!scroll_h || min.width <= size.width - vmin.width) {
h_scroll->hide();
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 02b203b5e3..5d429f9f91 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -3905,7 +3905,12 @@ void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_t
update();
}
-
+void TextEdit::swap_lines(int line1, int line2) {
+ String tmp = get_line(line1);
+ String tmp2 = get_line(line2);
+ set_line(line2, tmp);
+ set_line(line1, tmp2);
+}
bool TextEdit::is_selection_active() const {
return selection.active;
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index b90571e0ab..50f005ed6a 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -464,6 +464,7 @@ public:
void select_all();
void select(int p_from_line, int p_from_column, int p_to_line, int p_to_column);
void deselect();
+ void swap_lines(int line1, int line2);
void set_search_text(const String &p_search_text);
void set_search_flags(uint32_t p_flags);
diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp
index 190ccd50d5..1b6bd30b58 100644
--- a/scene/gui/video_player.cpp
+++ b/scene/gui/video_player.cpp
@@ -42,44 +42,127 @@ void VideoPlayer::sp_set_mix_rate(int p_rate) {
server_mix_rate = p_rate;
}
-bool VideoPlayer::sp_mix(int32_t *p_buffer, int p_frames) {
-
- if (resampler.is_ready()) {
+bool VideoPlayer::mix(AudioFrame *p_buffer, int p_frames) {
+
+ // Check the amount resampler can really handle.
+ // If it cannot, wait "wait_resampler_phase_limit" times.
+ // This mechanism contributes to smoother pause/unpause operation.
+ if (p_frames <= resampler.get_num_of_ready_frames() ||
+ wait_resampler_limit <= wait_resampler) {
+ wait_resampler = 0;
return resampler.mix(p_buffer, p_frames);
}
-
+ wait_resampler++;
return false;
}
-int VideoPlayer::_audio_mix_callback(void *p_udata, const int16_t *p_data, int p_frames) {
+// Called from main thread (eg VideoStreamPlaybackWebm::update)
+int VideoPlayer::_audio_mix_callback(void *p_udata, const float *p_data, int p_frames) {
VideoPlayer *vp = (VideoPlayer *)p_udata;
- int todo = MIN(vp->resampler.get_todo(), p_frames);
+ int todo = MIN(vp->resampler.get_writer_space(), p_frames);
- int16_t *wb = vp->resampler.get_write_buffer();
+ float *wb = vp->resampler.get_write_buffer();
int c = vp->resampler.get_channel_count();
for (int i = 0; i < todo * c; i++) {
wb[i] = p_data[i];
}
vp->resampler.write(todo);
+
return todo;
}
+// Called from audio thread
+void VideoPlayer::_mix_audio() {
+
+ if (!stream.is_valid()) {
+ return;
+ }
+ if (!playback.is_valid() || !playback->is_playing() || playback->is_paused()) {
+ return;
+ }
+
+ AudioFrame *buffer = mix_buffer.ptr();
+ int buffer_size = mix_buffer.size();
+
+ // Resample
+ if (!mix(buffer, buffer_size))
+ return;
+
+ AudioFrame vol = AudioFrame(volume, volume);
+
+ // Copy to server's audio buffer
+ switch (AudioServer::get_singleton()->get_speaker_mode()) {
+
+ case AudioServer::SPEAKER_MODE_STEREO: {
+ AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 0);
+
+ for (int j = 0; j < buffer_size; j++) {
+
+ target[j] += buffer[j] * vol;
+ }
+
+ } break;
+ case AudioServer::SPEAKER_SURROUND_51: {
+
+ AudioFrame *targets[2] = {
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 1),
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 2),
+ };
+
+ for (int j = 0; j < buffer_size; j++) {
+
+ AudioFrame frame = buffer[j] * vol;
+ targets[0][j] = frame;
+ targets[1][j] = frame;
+ }
+ } break;
+ case AudioServer::SPEAKER_SURROUND_71: {
+
+ AudioFrame *targets[3] = {
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 1),
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 2),
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 3)
+ };
+
+ for (int j = 0; j < buffer_size; j++) {
+
+ AudioFrame frame = buffer[j] * vol;
+ targets[0][j] += frame;
+ targets[1][j] += frame;
+ targets[2][j] += frame;
+ }
+
+ } break;
+ }
+}
+
void VideoPlayer::_notification(int p_notification) {
switch (p_notification) {
case NOTIFICATION_ENTER_TREE: {
+ AudioServer::get_singleton()->add_callback(_mix_audios, this);
+
if (stream.is_valid() && autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
}
+
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+
+ AudioServer::get_singleton()->remove_callback(_mix_audios, this);
+
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
+ bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
+
if (stream.is_null())
return;
if (paused)
@@ -87,10 +170,11 @@ void VideoPlayer::_notification(int p_notification) {
if (!playback->is_playing())
return;
- double audio_time = USEC_TO_SEC(OS::get_singleton()->get_ticks_usec()); //AudioServer::get_singleton()->get_mix_time();
+ double audio_time = USEC_TO_SEC(OS::get_singleton()->get_ticks_usec());
double delta = last_audio_time == 0 ? 0 : audio_time - last_audio_time;
last_audio_time = audio_time;
+
if (delta == 0)
return;
@@ -135,6 +219,9 @@ bool VideoPlayer::has_expand() const {
void VideoPlayer::set_stream(const Ref<VideoStream> &p_stream) {
stop();
+ AudioServer::get_singleton()->lock();
+ mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size());
+ AudioServer::get_singleton()->unlock();
stream = p_stream;
if (stream.is_valid()) {
@@ -309,6 +396,40 @@ bool VideoPlayer::has_autoplay() const {
return autoplay;
};
+void VideoPlayer::set_bus(const StringName &p_bus) {
+
+ //if audio is active, must lock this
+ AudioServer::get_singleton()->lock();
+ bus = p_bus;
+ AudioServer::get_singleton()->unlock();
+}
+
+StringName VideoPlayer::get_bus() const {
+
+ for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
+ if (AudioServer::get_singleton()->get_bus_name(i) == bus) {
+ return bus;
+ }
+ }
+ return "Master";
+}
+
+void VideoPlayer::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "bus") {
+
+ String options;
+ for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
+ if (i > 0)
+ options += ",";
+ String name = AudioServer::get_singleton()->get_bus_name(i);
+ options += name;
+ }
+
+ property.hint_string = options;
+ }
+}
+
void VideoPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &VideoPlayer::set_stream);
@@ -345,6 +466,9 @@ void VideoPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_buffering_msec", "msec"), &VideoPlayer::set_buffering_msec);
ClassDB::bind_method(D_METHOD("get_buffering_msec"), &VideoPlayer::get_buffering_msec);
+ ClassDB::bind_method(D_METHOD("set_bus", "bus"), &VideoPlayer::set_bus);
+ ClassDB::bind_method(D_METHOD("get_bus"), &VideoPlayer::get_bus);
+
ClassDB::bind_method(D_METHOD("get_video_texture"), &VideoPlayer::get_video_texture);
ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_track", PROPERTY_HINT_RANGE, "0,128,1"), "set_audio_track", "get_audio_track");
@@ -354,6 +478,7 @@ void VideoPlayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "has_autoplay");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_paused", "is_paused");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand"), "set_expand", "has_expand");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
}
VideoPlayer::VideoPlayer() {
@@ -372,6 +497,9 @@ VideoPlayer::VideoPlayer() {
// internal_stream.player=this;
// stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream);
last_audio_time = 0;
+
+ wait_resampler = 0;
+ wait_resampler_limit = 2;
};
VideoPlayer::~VideoPlayer() {
diff --git a/scene/gui/video_player.h b/scene/gui/video_player.h
index f04e90365f..74e2f14e58 100644
--- a/scene/gui/video_player.h
+++ b/scene/gui/video_player.h
@@ -33,17 +33,24 @@
#include "scene/gui/control.h"
#include "scene/resources/video_stream.h"
#include "servers/audio/audio_rb_resampler.h"
+#include "servers/audio_server.h"
class VideoPlayer : public Control {
GDCLASS(VideoPlayer, Control);
+ struct Output {
+
+ AudioFrame vol;
+ int bus_index;
+ Viewport *viewport; //pointer only used for reference to previous mix
+ };
Ref<VideoStreamPlayback> playback;
Ref<VideoStream> stream;
int sp_get_channel_count() const;
void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate
- bool sp_mix(int32_t *p_buffer, int p_frames);
+ bool mix(AudioFrame *p_buffer, int p_frames);
RID stream_rid;
@@ -51,6 +58,8 @@ class VideoPlayer : public Control {
Ref<Image> last_frame;
AudioRBResampler resampler;
+ Vector<AudioFrame> mix_buffer;
+ int wait_resampler, wait_resampler_limit;
bool paused;
bool autoplay;
@@ -61,12 +70,18 @@ class VideoPlayer : public Control {
int buffering_ms;
int server_mix_rate;
int audio_track;
+ int bus_index;
+
+ StringName bus;
- static int _audio_mix_callback(void *p_udata, const int16_t *p_data, int p_frames);
+ void _mix_audio();
+ static int _audio_mix_callback(void *p_udata, const float *p_data, int p_frames);
+ static void _mix_audios(void *self) { reinterpret_cast<VideoPlayer *>(self)->_mix_audio(); }
protected:
static void _bind_methods();
void _notification(int p_notification);
+ void _validate_property(PropertyInfo &property) const;
public:
Size2 get_minimum_size() const;
@@ -104,6 +119,9 @@ public:
void set_buffering_msec(int p_msec);
int get_buffering_msec() const;
+ void set_bus(const StringName &p_bus);
+ StringName get_bus() const;
+
VideoPlayer();
~VideoPlayer();
};
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index e6e11de177..d38c688241 100755
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2067,7 +2067,7 @@ int Node::get_position_in_parent() const {
return data.pos;
}
-Node *Node::_duplicate(int p_flags) const {
+Node *Node::duplicate(int p_flags) const {
Node *node = NULL;
@@ -2170,17 +2170,6 @@ Node *Node::_duplicate(int p_flags) const {
return node;
}
-Node *Node::duplicate(int p_flags) const {
-
- Node *dupe = _duplicate(p_flags);
-
- if (dupe && (p_flags & DUPLICATE_SIGNALS)) {
- _duplicate_signals(this, dupe);
- }
-
- return dupe;
-}
-
void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const {
if (get_owner() != get_parent()->get_owner())
@@ -2422,7 +2411,9 @@ void Node::_replace_connections_target(Node *p_new_target) {
if (c.flags & CONNECT_PERSIST) {
c.source->disconnect(c.signal, this, c.method);
- ERR_CONTINUE(!p_new_target->has_method(c.method));
+ bool valid = p_new_target->has_method(c.method) || p_new_target->get_script().is_null() || Ref<Script>(p_new_target->get_script())->has_method(c.method);
+ ERR_EXPLAIN("Attempt to connect signal \'" + c.source->get_class() + "." + c.signal + "\' to nonexistent method \'" + c.target->get_class() + "." + c.method + "\'");
+ ERR_CONTINUE(!valid);
c.source->connect(c.signal, p_new_target, c.method, c.binds, c.flags);
}
}
diff --git a/scene/main/node.h b/scene/main/node.h
index c43e96063f..e8901f7b6e 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -169,7 +169,6 @@ private:
void _duplicate_signals(const Node *p_original, Node *p_copy) const;
void _duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const;
- Node *_duplicate(int p_flags) const;
Array _get_children() const;
Array _get_groups() const;
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index ba356d89b1..8e3899315c 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -1299,14 +1299,16 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const {
tangents.resize(4 * 4);
uvs.resize(4);
- for (int i = 0; i < 4; i++) {
+ Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f);
- static const Vector3 quad_faces[4] = {
- Vector3(-1, -1, 0),
- Vector3(-1, 1, 0),
- Vector3(1, 1, 0),
- Vector3(1, -1, 0),
- };
+ Vector3 quad_faces[4] = {
+ Vector3(-_size.x, -_size.y, 0),
+ Vector3(-_size.x, _size.y, 0),
+ Vector3(_size.x, _size.y, 0),
+ Vector3(_size.x, -_size.y, 0),
+ };
+
+ for (int i = 0; i < 4; i++) {
faces.set(i, quad_faces[i]);
normals.set(i, Vector3(0, 0, 1));
@@ -1325,18 +1327,30 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const {
uvs.set(i, quad_uv[i]);
}
- p_arr[ARRAY_VERTEX] = faces;
- p_arr[ARRAY_NORMAL] = normals;
- p_arr[ARRAY_TANGENT] = tangents;
- p_arr[ARRAY_TEX_UV] = uvs;
+ p_arr[VS::ARRAY_VERTEX] = faces;
+ p_arr[VS::ARRAY_NORMAL] = normals;
+ p_arr[VS::ARRAY_TANGENT] = tangents;
+ p_arr[VS::ARRAY_TEX_UV] = uvs;
};
void QuadMesh::_bind_methods() {
- // nothing here yet...
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &QuadMesh::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &QuadMesh::get_size);
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
}
QuadMesh::QuadMesh() {
primitive_type = PRIMITIVE_TRIANGLE_FAN;
+ size = Size2(1.0, 1.0);
+}
+
+void QuadMesh::set_size(const Size2 &p_size) {
+ size = p_size;
+ _request_update();
+}
+
+Size2 QuadMesh::get_size() const {
+ return size;
}
/**
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 38a5695883..f0c8935261 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -263,7 +263,7 @@ class QuadMesh : public PrimitiveMesh {
GDCLASS(QuadMesh, PrimitiveMesh)
private:
- // nothing? really? Maybe add size some day atleast... :)
+ Size2 size;
protected:
static void _bind_methods();
@@ -271,6 +271,9 @@ protected:
public:
QuadMesh();
+
+ void set_size(const Size2 &p_size);
+ Size2 get_size() const;
};
/**
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index 3f79858056..fbe52909e7 100644
--- a/scene/resources/video_stream.h
+++ b/scene/resources/video_stream.h
@@ -40,7 +40,7 @@ protected:
static void _bind_methods();
public:
- typedef int (*AudioMixCallback)(void *p_udata, const int16_t *p_data, int p_frames);
+ typedef int (*AudioMixCallback)(void *p_udata, const float *p_data, int p_frames);
virtual void stop() = 0;
virtual void play() = 0;
@@ -48,7 +48,7 @@ public:
virtual bool is_playing() const = 0;
virtual void set_paused(bool p_paused) = 0;
- virtual bool is_paused(bool p_paused) const = 0;
+ virtual bool is_paused() const = 0;
virtual void set_loop(bool p_enable) = 0;
virtual bool has_loop() const = 0;