Prevent errors when using ViewportTexture

This commit is contained in:
kobewi 2023-04-06 14:47:49 +02:00
parent 491a437df5
commit 1b9802fa8c
6 changed files with 70 additions and 20 deletions

View File

@ -500,6 +500,13 @@
Returns [code]true[/code] if the local system is the multiplayer authority of this node.
</description>
</method>
<method name="is_node_ready" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the node is ready, i.e. it's inside scene tree and all its children are initialized.
[method request_ready] resets it back to [code]false[/code].
</description>
</method>
<method name="is_physics_processing" qualifiers="const">
<return type="bool" />
<description>

View File

@ -6,7 +6,7 @@
<description>
Displays the content of a [Viewport] node as a dynamic [Texture2D]. This can be used to mix controls, 2D, and 3D elements in the same scene.
To create a ViewportTexture in code, use the [method Viewport.get_texture] method on the target viewport.
[b]Note:[/b] When local to scene, this texture uses [method Resource.setup_local_to_scene] to set the proxy texture and flags in the local viewport.
[b]Note:[/b] When local to scene, this texture uses [method Resource.setup_local_to_scene] to set the proxy texture and flags in the local viewport. Local to scene viewport textures will return incorrect data until the scene root is ready (see [signal Node.ready]).
</description>
<tutorials>
<link title="GUI in 3D Demo">https://godotengine.org/asset-library/asset/127</link>

View File

@ -2786,6 +2786,10 @@ bool Node::is_displayed_folded() const {
return data.display_folded;
}
bool Node::is_ready() const {
return !data.ready_first;
}
void Node::request_ready() {
data.ready_first = true;
}
@ -2932,6 +2936,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("queue_free"), &Node::queue_free);
ClassDB::bind_method(D_METHOD("request_ready"), &Node::request_ready);
ClassDB::bind_method(D_METHOD("is_node_ready"), &Node::is_ready);
ClassDB::bind_method(D_METHOD("set_multiplayer_authority", "id", "recursive"), &Node::set_multiplayer_authority, DEFVAL(true));
ClassDB::bind_method(D_METHOD("get_multiplayer_authority"), &Node::get_multiplayer_authority);

View File

@ -500,6 +500,7 @@ public:
bool can_process_notification(int p_what) const;
bool is_enabled() const;
bool is_ready() const;
void request_ready();
static void print_orphan_nodes();

View File

@ -61,6 +61,10 @@
#include "servers/rendering/rendering_server_globals.h"
void ViewportTexture::setup_local_to_scene() {
if (vp_pending) {
return;
}
Node *loc_scene = get_local_scene();
if (!loc_scene) {
return;
@ -72,22 +76,11 @@ void ViewportTexture::setup_local_to_scene() {
vp = nullptr;
Node *vpn = loc_scene->get_node(path);
ERR_FAIL_COND_MSG(!vpn, "ViewportTexture: Path to node is invalid.");
vp = Object::cast_to<Viewport>(vpn);
ERR_FAIL_COND_MSG(!vp, "ViewportTexture: Path to node does not point to a viewport.");
vp->viewport_textures.insert(this);
ERR_FAIL_NULL(RenderingServer::get_singleton());
if (proxy_ph.is_valid()) {
RS::get_singleton()->texture_proxy_update(proxy, vp->texture_rid);
RS::get_singleton()->free(proxy_ph);
if (loc_scene->is_ready()) {
_setup_local_to_scene(loc_scene);
} else {
ERR_FAIL_COND(proxy.is_valid()); // Should be invalid.
proxy = RS::get_singleton()->texture_proxy_create(vp->texture_rid);
loc_scene->connect(SNAME("ready"), callable_mp(this, &ViewportTexture::_setup_local_to_scene).bind(loc_scene), CONNECT_ONE_SHOT);
vp_pending = true;
}
}
@ -108,17 +101,32 @@ NodePath ViewportTexture::get_viewport_path_in_scene() const {
}
int ViewportTexture::get_width() const {
ERR_FAIL_COND_V_MSG(!vp, 0, "Viewport Texture must be set to use it.");
if (!vp) {
if (!vp_pending) {
ERR_PRINT("Viewport Texture must be set to use it.");
}
return 0;
}
return vp->size.width;
}
int ViewportTexture::get_height() const {
ERR_FAIL_COND_V_MSG(!vp, 0, "Viewport Texture must be set to use it.");
if (!vp) {
if (!vp_pending) {
ERR_PRINT("Viewport Texture must be set to use it.");
}
return 0;
}
return vp->size.height;
}
Size2 ViewportTexture::get_size() const {
ERR_FAIL_COND_V_MSG(!vp, Size2(), "Viewport Texture must be set to use it.");
if (!vp) {
if (!vp_pending) {
ERR_PRINT("Viewport Texture must be set to use it.");
}
return Size2();
}
return vp->size;
}
@ -135,10 +143,36 @@ bool ViewportTexture::has_alpha() const {
}
Ref<Image> ViewportTexture::get_image() const {
ERR_FAIL_COND_V_MSG(!vp, Ref<Image>(), "Viewport Texture must be set to use it.");
if (!vp) {
if (!vp_pending) {
ERR_PRINT("Viewport Texture must be set to use it.");
}
return Ref<Image>();
}
return RS::get_singleton()->texture_2d_get(vp->texture_rid);
}
void ViewportTexture::_setup_local_to_scene(const Node *p_loc_scene) {
Node *vpn = p_loc_scene->get_node(path);
ERR_FAIL_COND_MSG(!vpn, "ViewportTexture: Path to node is invalid.");
vp = Object::cast_to<Viewport>(vpn);
ERR_FAIL_COND_MSG(!vp, "ViewportTexture: Path to node does not point to a viewport.");
vp->viewport_textures.insert(this);
ERR_FAIL_NULL(RenderingServer::get_singleton());
if (proxy_ph.is_valid()) {
RS::get_singleton()->texture_proxy_update(proxy, vp->texture_rid);
RS::get_singleton()->free(proxy_ph);
} else {
ERR_FAIL_COND(proxy.is_valid()); // Should be invalid.
proxy = RS::get_singleton()->texture_proxy_create(vp->texture_rid);
}
vp_pending = false;
}
void ViewportTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_viewport_path_in_scene", "path"), &ViewportTexture::set_viewport_path_in_scene);
ClassDB::bind_method(D_METHOD("get_viewport_path_in_scene"), &ViewportTexture::get_viewport_path_in_scene);

View File

@ -59,6 +59,9 @@ class ViewportTexture : public Texture2D {
friend class Viewport;
Viewport *vp = nullptr;
bool vp_pending = false;
void _setup_local_to_scene(const Node *p_loc_scene);
mutable RID proxy_ph;
mutable RID proxy;