Browse Source

Merge pull request #72174 from bitsawer/shader_include_fixes

Close undefined
Fix undefined
Yuri Rubinsky 2 years ago
parent
commit
2afa175195

+ 3 - 2
editor/plugins/text_shader_editor.cpp

@@ -383,11 +383,12 @@ void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptLa
 	List<ScriptLanguage::CodeCompletionOption> pp_defines;
 	ShaderPreprocessor preprocessor;
 	String code;
-	complete_from_path = (shader.is_valid() ? shader->get_path() : shader_inc->get_path()).get_base_dir();
+	String resource_path = (shader.is_valid() ? shader->get_path() : shader_inc->get_path());
+	complete_from_path = resource_path.get_base_dir();
 	if (!complete_from_path.ends_with("/")) {
 		complete_from_path += "/";
 	}
-	preprocessor.preprocess(p_code, "", code, nullptr, nullptr, nullptr, nullptr, &pp_options, &pp_defines, _complete_include_paths);
+	preprocessor.preprocess(p_code, resource_path, code, nullptr, nullptr, nullptr, nullptr, &pp_options, &pp_defines, _complete_include_paths);
 	complete_from_path = String();
 	if (pp_options.size()) {
 		for (const ScriptLanguage::CodeCompletionOption &E : pp_options) {

+ 12 - 1
scene/resources/shader.cpp

@@ -55,6 +55,12 @@ void Shader::set_path(const String &p_path, bool p_take_over) {
 	RS::get_singleton()->shader_set_path_hint(shader, p_path);
 }
 
+void Shader::set_include_path(const String &p_path) {
+	// Used only if the shader does not have a resource path set,
+	// for example during loading stage or when created by code.
+	include_path = p_path;
+}
+
 void Shader::set_code(const String &p_code) {
 	for (Ref<ShaderInclude> E : include_dependencies) {
 		E->disconnect(SNAME("changed"), callable_mp(this, &Shader::_dependency_changed));
@@ -80,11 +86,15 @@ void Shader::set_code(const String &p_code) {
 	HashSet<Ref<ShaderInclude>> new_include_dependencies;
 
 	{
+		String path = get_path();
+		if (path.is_empty()) {
+			path = include_path;
+		}
 		// Preprocessor must run here and not in the server because:
 		// 1) Need to keep track of include dependencies at resource level
 		// 2) Server does not do interaction with Resource filetypes, this is a scene level feature.
 		ShaderPreprocessor preprocessor;
-		preprocessor.preprocess(p_code, "", pp_code, nullptr, nullptr, nullptr, &new_include_dependencies);
+		preprocessor.preprocess(p_code, path, pp_code, nullptr, nullptr, nullptr, &new_include_dependencies);
 	}
 
 	// This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower)
@@ -231,6 +241,7 @@ Ref<Resource> ResourceFormatLoaderShader::load(const String &p_path, const Strin
 	String str;
 	str.parse_utf8((const char *)buffer.ptr(), buffer.size());
 
+	shader->set_include_path(p_path);
 	shader->set_code(str);
 
 	if (r_error) {

+ 2 - 0
scene/resources/shader.h

@@ -56,6 +56,7 @@ private:
 	Mode mode = MODE_SPATIAL;
 	HashSet<Ref<ShaderInclude>> include_dependencies;
 	String code;
+	String include_path;
 
 	HashMap<StringName, HashMap<int, Ref<Texture2D>>> default_textures;
 
@@ -72,6 +73,7 @@ public:
 	virtual Mode get_mode() const;
 
 	virtual void set_path(const String &p_path, bool p_take_over = false) override;
+	void set_include_path(const String &p_path);
 
 	void set_code(const String &p_code);
 	String get_code() const;

+ 11 - 1
scene/resources/shader_include.cpp

@@ -45,9 +45,14 @@ void ShaderInclude::set_code(const String &p_code) {
 	}
 
 	{
+		String path = get_path();
+		if (path.is_empty()) {
+			path = include_path;
+		}
+
 		String pp_code;
 		ShaderPreprocessor preprocessor;
-		preprocessor.preprocess(p_code, "", pp_code, nullptr, nullptr, nullptr, &new_dependencies);
+		preprocessor.preprocess(p_code, path, pp_code, nullptr, nullptr, nullptr, &new_dependencies);
 	}
 
 	// This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower)
@@ -64,6 +69,10 @@ String ShaderInclude::get_code() const {
 	return code;
 }
 
+void ShaderInclude::set_include_path(const String &p_path) {
+	include_path = p_path;
+}
+
 void ShaderInclude::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_code", "code"), &ShaderInclude::set_code);
 	ClassDB::bind_method(D_METHOD("get_code"), &ShaderInclude::get_code);
@@ -86,6 +95,7 @@ Ref<Resource> ResourceFormatLoaderShaderInclude::load(const String &p_path, cons
 	String str;
 	str.parse_utf8((const char *)buffer.ptr(), buffer.size());
 
+	shader_inc->set_include_path(p_path);
 	shader_inc->set_code(str);
 
 	if (r_error) {

+ 3 - 0
scene/resources/shader_include.h

@@ -42,6 +42,7 @@ class ShaderInclude : public Resource {
 
 private:
 	String code;
+	String include_path;
 	HashSet<Ref<ShaderInclude>> dependencies;
 	void _dependency_changed();
 
@@ -51,6 +52,8 @@ protected:
 public:
 	void set_code(const String &p_text);
 	String get_code() const;
+
+	void set_include_path(const String &p_path);
 };
 
 class ResourceFormatLoaderShaderInclude : public ResourceFormatLoader {

+ 5 - 0
servers/rendering/shader_preprocessor.cpp

@@ -674,6 +674,11 @@ void ShaderPreprocessor::process_include(Tokenizer *p_tokenizer) {
 		return;
 	}
 
+	path = path.simplify_path();
+	if (path.is_relative_path()) {
+		path = state->current_filename.get_base_dir().path_join(path);
+	}
+
 	Ref<Resource> res = ResourceLoader::load(path);
 	if (res.is_null()) {
 		set_error(RTR("Shader include load failed. Does the shader include exist? Is there a cyclic dependency?"), line);