diff options
| author | kobewi <kobewi4e@gmail.com> | 2023-04-06 14:47:49 +0200 | 
|---|---|---|
| committer | Rémi Verschelde <rverschelde@gmail.com> | 2023-05-12 12:31:22 +0200 | 
| commit | 1146172b302a68393e4f97b47e6460d78db75518 (patch) | |
| tree | 6b2cfc2e2ac14f2e6aa177ea561c569630c11f73 | |
| parent | 2a8501e1a26b12dadd4f6fcbed799e319cd77027 (diff) | |
Prevent errors when using ViewportTexture
(cherry picked from commit 1b9802fa8cb45e876cd90d6a174b95b270a7f934)
| -rw-r--r-- | doc/classes/Node.xml | 7 | ||||
| -rw-r--r-- | doc/classes/ViewportTexture.xml | 2 | ||||
| -rw-r--r-- | scene/main/node.cpp | 5 | ||||
| -rw-r--r-- | scene/main/node.h | 1 | ||||
| -rw-r--r-- | scene/main/viewport.cpp | 72 | ||||
| -rw-r--r-- | scene/main/viewport.h | 3 | 
6 files changed, 70 insertions, 20 deletions
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 62d708618a..ead022ecb3 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -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> diff --git a/doc/classes/ViewportTexture.xml b/doc/classes/ViewportTexture.xml index 6bd64a50bb..8ecda45bd6 100644 --- a/doc/classes/ViewportTexture.xml +++ b/doc/classes/ViewportTexture.xml @@ -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> diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 52c1df8110..057fd15f1b 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2759,6 +2759,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;  } @@ -2897,6 +2901,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); diff --git a/scene/main/node.h b/scene/main/node.h index 493578bc5b..4a606538a8 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -455,6 +455,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(); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 8cd57536bf..8bdcd9302f 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -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); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 5213c0db01..e88e0628dd 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -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;  |