From 0695440124bc83c1829462ccf999c32f9ed81be0 Mon Sep 17 00:00:00 2001
From: Brennen Green <brennengreen@outlook.com>
Date: Fri, 14 Jan 2022 20:42:25 -0500
Subject: Add shader cache and filter variable to PanoramaSkyMaterial

---
 doc/classes/PanoramaSkyMaterial.xml |  3 +++
 scene/resources/sky_material.cpp    | 49 ++++++++++++++++++++++++++-----------
 scene/resources/sky_material.h      |  7 +++++-
 3 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/doc/classes/PanoramaSkyMaterial.xml b/doc/classes/PanoramaSkyMaterial.xml
index 6707c03fac..a04626e9b0 100644
--- a/doc/classes/PanoramaSkyMaterial.xml
+++ b/doc/classes/PanoramaSkyMaterial.xml
@@ -11,6 +11,9 @@
 	<tutorials>
 	</tutorials>
 	<members>
+		<member name="filter" type="bool" setter="set_filtering_enabled" getter="is_filtering_enabled" default="true">
+			A boolean value to determine if the background texture should be filtered or not.
+		</member>
 		<member name="panorama" type="Texture2D" setter="set_panorama" getter="get_panorama">
 			[Texture2D] to be applied to the [PanoramaSkyMaterial].
 		</member>
diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp
index 3918cc5ef8..6ec16f12df 100644
--- a/scene/resources/sky_material.cpp
+++ b/scene/resources/sky_material.cpp
@@ -308,14 +308,30 @@ Ref<Texture2D> PanoramaSkyMaterial::get_panorama() const {
 	return panorama;
 }
 
+void PanoramaSkyMaterial::set_filtering_enabled(bool p_enabled) {
+	filter = p_enabled;
+	notify_property_list_changed();
+	_update_shader();
+	// Only set if shader already compiled
+	if (shader_set) {
+		RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(filter)]);
+	}
+}
+
+bool PanoramaSkyMaterial::is_filtering_enabled() const {
+	return filter;
+}
+
 Shader::Mode PanoramaSkyMaterial::get_shader_mode() const {
 	return Shader::MODE_SKY;
 }
 
 RID PanoramaSkyMaterial::get_rid() const {
 	_update_shader();
+	// Don't compile shaders until first use, then compile both
 	if (!shader_set) {
-		RS::get_singleton()->material_set_shader(_get_material(), shader);
+		RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(filter)]);
+		RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(filter)]);
 		shader_set = true;
 	}
 	return _get_material();
@@ -323,42 +339,47 @@ RID PanoramaSkyMaterial::get_rid() const {
 
 RID PanoramaSkyMaterial::get_shader_rid() const {
 	_update_shader();
-	return shader;
+	return shader_cache[int(filter)];
 }
 
 void PanoramaSkyMaterial::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_panorama", "texture"), &PanoramaSkyMaterial::set_panorama);
 	ClassDB::bind_method(D_METHOD("get_panorama"), &PanoramaSkyMaterial::get_panorama);
 
+	ClassDB::bind_method(D_METHOD("set_filtering_enabled", "enabled"), &PanoramaSkyMaterial::set_filtering_enabled);
+	ClassDB::bind_method(D_METHOD("is_filtering_enabled"), &PanoramaSkyMaterial::is_filtering_enabled);
+
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "panorama", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_panorama", "get_panorama");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter"), "set_filtering_enabled", "is_filtering_enabled");
 }
 
 Mutex PanoramaSkyMaterial::shader_mutex;
-RID PanoramaSkyMaterial::shader;
+RID PanoramaSkyMaterial::shader_cache[2];
 
 void PanoramaSkyMaterial::cleanup_shader() {
-	if (shader.is_valid()) {
-		RS::get_singleton()->free(shader);
+	if (shader_cache[0].is_valid()) {
+		RS::get_singleton()->free(shader_cache[0]);
+		RS::get_singleton()->free(shader_cache[1]);
 	}
 }
 
 void PanoramaSkyMaterial::_update_shader() {
 	shader_mutex.lock();
-	if (shader.is_null()) {
-		shader = RS::get_singleton()->shader_create();
+	if (shader_cache[0].is_null()) {
+		for (int i = 0; i < 2; i++) {
+			shader_cache[i] = RS::get_singleton()->shader_create();
 
-		// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
-		RS::get_singleton()->shader_set_code(shader, R"(
+			// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
+			RS::get_singleton()->shader_set_code(shader_cache[i], vformat(R"(
 // NOTE: Shader automatically converted from )" VERSION_NAME " " VERSION_FULL_CONFIG R"('s PanoramaSkyMaterial.
-
 shader_type sky;
-
-uniform sampler2D source_panorama : filter_linear, hint_albedo;
-
+uniform sampler2D source_panorama : %s, hint_albedo;
 void sky() {
 	COLOR = texture(source_panorama, SKY_COORDS).rgb;
 }
-)");
+)",
+																		  i ? "filter_linear" : "filter_nearest"));
+		}
 	}
 
 	shader_mutex.unlock();
diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h
index 74b2965ce8..7f421beb8d 100644
--- a/scene/resources/sky_material.h
+++ b/scene/resources/sky_material.h
@@ -110,10 +110,12 @@ private:
 	Ref<Texture2D> panorama;
 
 	static Mutex shader_mutex;
-	static RID shader;
+	static RID shader_cache[2];
 	static void _update_shader();
 	mutable bool shader_set = false;
 
+	bool filter = true;
+
 protected:
 	static void _bind_methods();
 
@@ -121,6 +123,9 @@ public:
 	void set_panorama(const Ref<Texture2D> &p_panorama);
 	Ref<Texture2D> get_panorama() const;
 
+	void set_filtering_enabled(bool p_enabled);
+	bool is_filtering_enabled() const;
+
 	virtual Shader::Mode get_shader_mode() const override;
 	virtual RID get_shader_rid() const override;
 	virtual RID get_rid() const override;
-- 
cgit v1.2.3