Browse Source

Refactor shader hints

Yuri Rubinsky 3 years ago
parent
commit
cf240a7ae0

+ 1 - 1
servers/rendering/renderer_rd/storage_rd/material_storage.cpp

@@ -1150,7 +1150,7 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet
 				p_textures[k++] = rd_texture;
 				p_textures[k++] = rd_texture;
 			}
 			}
 		} else {
 		} else {
-			bool srgb = p_use_linear_color && p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_SOURCE_COLOR;
+			bool srgb = p_use_linear_color && p_texture_uniforms[i].use_color;
 
 
 			for (int j = 0; j < textures.size(); j++) {
 			for (int j = 0; j < textures.size(); j++) {
 				Texture *tex = TextureStorage::get_singleton()->get_texture(textures[j]);
 				Texture *tex = TextureStorage::get_singleton()->get_texture(textures[j]);

+ 1 - 0
servers/rendering/shader_compiler.cpp

@@ -571,6 +571,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
 					texture.name = uniform_name;
 					texture.name = uniform_name;
 					texture.hint = uniform.hint;
 					texture.hint = uniform.hint;
 					texture.type = uniform.type;
 					texture.type = uniform.type;
+					texture.use_color = uniform.use_color;
 					texture.filter = uniform.filter;
 					texture.filter = uniform.filter;
 					texture.repeat = uniform.repeat;
 					texture.repeat = uniform.repeat;
 					texture.global = uniform.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL;
 					texture.global = uniform.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL;

+ 1 - 0
servers/rendering/shader_compiler.h

@@ -61,6 +61,7 @@ public:
 			StringName name;
 			StringName name;
 			ShaderLanguage::DataType type;
 			ShaderLanguage::DataType type;
 			ShaderLanguage::ShaderNode::Uniform::Hint hint;
 			ShaderLanguage::ShaderNode::Uniform::Hint hint;
+			bool use_color = false;
 			ShaderLanguage::TextureFilter filter;
 			ShaderLanguage::TextureFilter filter;
 			ShaderLanguage::TextureRepeat repeat;
 			ShaderLanguage::TextureRepeat repeat;
 			bool global;
 			bool global;

+ 319 - 161
servers/rendering/shader_language.cpp

@@ -1014,6 +1014,93 @@ String ShaderLanguage::get_datatype_name(DataType p_type) {
 	return "";
 	return "";
 }
 }
 
 
+String ShaderLanguage::get_uniform_hint_name(ShaderNode::Uniform::Hint p_hint) {
+	String result;
+	switch (p_hint) {
+		case ShaderNode::Uniform::HINT_RANGE: {
+			result = "hint_range";
+		} break;
+		case ShaderNode::Uniform::HINT_SOURCE_COLOR: {
+			result = "hint_color";
+		} break;
+		case ShaderNode::Uniform::HINT_NORMAL: {
+			result = "hint_normal";
+		} break;
+		case ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL: {
+			result = "hint_roughness_normal";
+		} break;
+		case ShaderNode::Uniform::HINT_ROUGHNESS_R: {
+			result = "hint_roughness_r";
+		} break;
+		case ShaderNode::Uniform::HINT_ROUGHNESS_G: {
+			result = "hint_roughness_g";
+		} break;
+		case ShaderNode::Uniform::HINT_ROUGHNESS_B: {
+			result = "hint_roughness_b";
+		} break;
+		case ShaderNode::Uniform::HINT_ROUGHNESS_A: {
+			result = "hint_roughness_a";
+		} break;
+		case ShaderNode::Uniform::HINT_ROUGHNESS_GRAY: {
+			result = "hint_roughness_gray";
+		} break;
+		case ShaderNode::Uniform::HINT_DEFAULT_BLACK: {
+			result = "hint_default_black";
+		} break;
+		case ShaderNode::Uniform::HINT_DEFAULT_WHITE: {
+			result = "hint_default_white";
+		} break;
+		case ShaderNode::Uniform::HINT_ANISOTROPY: {
+			result = "hint_anisotropy";
+		} break;
+		default:
+			break;
+	}
+	return result;
+}
+
+String ShaderLanguage::get_texture_filter_name(TextureFilter p_filter) {
+	String result;
+	switch (p_filter) {
+		case FILTER_NEAREST: {
+			result = "filter_nearest";
+		} break;
+		case FILTER_LINEAR: {
+			result = "filter_linear";
+		} break;
+		case FILTER_NEAREST_MIPMAP: {
+			result = "filter_nearest_mipmap";
+		} break;
+		case FILTER_LINEAR_MIPMAP: {
+			result = "filter_linear_mipmap";
+		} break;
+		case FILTER_NEAREST_MIPMAP_ANISOTROPIC: {
+			result = "filter_nearest_mipmap_anisotropic";
+		} break;
+		case FILTER_LINEAR_MIPMAP_ANISOTROPIC: {
+			result = "filter_linear_mipmap_anisotropic";
+		} break;
+		default: {
+		} break;
+	}
+	return result;
+}
+
+String ShaderLanguage::get_texture_repeat_name(TextureRepeat p_repeat) {
+	String result;
+	switch (p_repeat) {
+		case REPEAT_DISABLE: {
+			result = "repeat_disable";
+		} break;
+		case REPEAT_ENABLE: {
+			result = "repeat_enable";
+		} break;
+		default: {
+		} break;
+	}
+	return result;
+}
+
 bool ShaderLanguage::is_token_nonvoid_datatype(TokenType p_type) {
 bool ShaderLanguage::is_token_nonvoid_datatype(TokenType p_type) {
 	return is_token_datatype(p_type) && p_type != TK_TYPE_VOID;
 	return is_token_datatype(p_type) && p_type != TK_TYPE_VOID;
 }
 }
@@ -7970,11 +8057,11 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 				[[fallthrough]];
 				[[fallthrough]];
 			case TK_UNIFORM:
 			case TK_UNIFORM:
 			case TK_VARYING: {
 			case TK_VARYING: {
-				bool uniform = tk.type == TK_UNIFORM;
+				bool is_uniform = tk.type == TK_UNIFORM;
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
 				keyword_completion_context = CF_UNSPECIFIED;
 				keyword_completion_context = CF_UNSPECIFIED;
 #endif // DEBUG_ENABLED
 #endif // DEBUG_ENABLED
-				if (!uniform) {
+				if (!is_uniform) {
 					if (shader_type_identifier == "particles" || shader_type_identifier == "sky" || shader_type_identifier == "fog") {
 					if (shader_type_identifier == "particles" || shader_type_identifier == "sky" || shader_type_identifier == "fog") {
 						_set_error(vformat(RTR("Varyings cannot be used in '%s' shaders."), shader_type_identifier));
 						_set_error(vformat(RTR("Varyings cannot be used in '%s' shaders."), shader_type_identifier));
 						return ERR_PARSE_ERROR;
 						return ERR_PARSE_ERROR;
@@ -7991,7 +8078,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 				bool temp_error = false;
 				bool temp_error = false;
 				uint32_t datatype_flag;
 				uint32_t datatype_flag;
 
 
-				if (!uniform) {
+				if (!is_uniform) {
 					datatype_flag = CF_VARYING_TYPE;
 					datatype_flag = CF_VARYING_TYPE;
 					keyword_completion_context = CF_INTERPOLATION_QUALIFIER | CF_PRECISION_MODIFIER | datatype_flag;
 					keyword_completion_context = CF_INTERPOLATION_QUALIFIER | CF_PRECISION_MODIFIER | datatype_flag;
 
 
@@ -8019,7 +8106,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 #endif // DEBUG_ENABLED
 #endif // DEBUG_ENABLED
 
 
 				if (is_token_interpolation(tk.type)) {
 				if (is_token_interpolation(tk.type)) {
-					if (uniform) {
+					if (is_uniform) {
 						_set_error(RTR("Interpolation qualifiers are not supported for uniforms."));
 						_set_error(RTR("Interpolation qualifiers are not supported for uniforms."));
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
 						temp_error = true;
 						temp_error = true;
@@ -8065,7 +8152,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 				}
 				}
 
 
 				if (shader->structs.has(tk.text)) {
 				if (shader->structs.has(tk.text)) {
-					if (uniform) {
+					if (is_uniform) {
 						_set_error(vformat(RTR("The '%s' data type is not supported for uniforms."), "struct"));
 						_set_error(vformat(RTR("The '%s' data type is not supported for uniforms."), "struct"));
 						return ERR_PARSE_ERROR;
 						return ERR_PARSE_ERROR;
 					} else {
 					} else {
@@ -8090,7 +8177,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 					return ERR_PARSE_ERROR;
 					return ERR_PARSE_ERROR;
 				}
 				}
 
 
-				if (!uniform && (type < TYPE_FLOAT || type > TYPE_MAT4)) {
+				if (!is_uniform && (type < TYPE_FLOAT || type > TYPE_MAT4)) {
 					_set_error(RTR("Invalid type for varying, only 'float', 'vec2', 'vec3', 'vec4', 'mat2', 'mat3', 'mat4', or arrays of these types are allowed."));
 					_set_error(RTR("Invalid type for varying, only 'float', 'vec2', 'vec3', 'vec4', 'mat2', 'mat3', 'mat4', or arrays of these types are allowed."));
 					return ERR_PARSE_ERROR;
 					return ERR_PARSE_ERROR;
 				}
 				}
@@ -8131,7 +8218,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 					return ERR_PARSE_ERROR;
 					return ERR_PARSE_ERROR;
 				}
 				}
 
 
-				if (uniform) {
+				if (is_uniform) {
 					if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL && Engine::get_singleton()->is_editor_hint()) { // Type checking for global uniforms is not allowed outside the editor.
 					if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL && Engine::get_singleton()->is_editor_hint()) { // Type checking for global uniforms is not allowed outside the editor.
 						//validate global uniform
 						//validate global uniform
 						DataType gvtype = global_var_get_type_func(name);
 						DataType gvtype = global_var_get_type_func(name);
@@ -8145,16 +8232,16 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 							return ERR_PARSE_ERROR;
 							return ERR_PARSE_ERROR;
 						}
 						}
 					}
 					}
-					ShaderNode::Uniform uniform2;
+					ShaderNode::Uniform uniform;
 
 
-					uniform2.type = type;
-					uniform2.scope = uniform_scope;
-					uniform2.precision = precision;
-					uniform2.array_size = array_size;
+					uniform.type = type;
+					uniform.scope = uniform_scope;
+					uniform.precision = precision;
+					uniform.array_size = array_size;
 
 
 					tk = _get_token();
 					tk = _get_token();
 					if (tk.type == TK_BRACKET_OPEN) {
 					if (tk.type == TK_BRACKET_OPEN) {
-						Error error = _parse_array_size(nullptr, constants, true, nullptr, &uniform2.array_size, nullptr);
+						Error error = _parse_array_size(nullptr, constants, true, nullptr, &uniform.array_size, nullptr);
 						if (error != OK) {
 						if (error != OK) {
 							return error;
 							return error;
 						}
 						}
@@ -8166,14 +8253,14 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 							_set_error(vformat(RTR("The '%s' qualifier is not supported for sampler types."), "SCOPE_INSTANCE"));
 							_set_error(vformat(RTR("The '%s' qualifier is not supported for sampler types."), "SCOPE_INSTANCE"));
 							return ERR_PARSE_ERROR;
 							return ERR_PARSE_ERROR;
 						}
 						}
-						uniform2.texture_order = texture_uniforms++;
-						uniform2.texture_binding = texture_binding;
-						if (uniform2.array_size > 0) {
-							texture_binding += uniform2.array_size;
+						uniform.texture_order = texture_uniforms++;
+						uniform.texture_binding = texture_binding;
+						if (uniform.array_size > 0) {
+							texture_binding += uniform.array_size;
 						} else {
 						} else {
 							++texture_binding;
 							++texture_binding;
 						}
 						}
-						uniform2.order = -1;
+						uniform.order = -1;
 						if (_validate_datatype(type) != OK) {
 						if (_validate_datatype(type) != OK) {
 							return ERR_PARSE_ERROR;
 							return ERR_PARSE_ERROR;
 						}
 						}
@@ -8182,20 +8269,20 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 							_set_error(vformat(RTR("The '%s' qualifier is not supported for matrix types."), "SCOPE_INSTANCE"));
 							_set_error(vformat(RTR("The '%s' qualifier is not supported for matrix types."), "SCOPE_INSTANCE"));
 							return ERR_PARSE_ERROR;
 							return ERR_PARSE_ERROR;
 						}
 						}
-						uniform2.texture_order = -1;
+						uniform.texture_order = -1;
 						if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) {
 						if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) {
-							uniform2.order = uniforms++;
+							uniform.order = uniforms++;
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
 							if (check_device_limit_warnings) {
 							if (check_device_limit_warnings) {
-								if (uniform2.array_size > 0) {
-									int size = get_datatype_size(uniform2.type) * uniform2.array_size;
-									int m = (16 * uniform2.array_size);
+								if (uniform.array_size > 0) {
+									int size = get_datatype_size(uniform.type) * uniform.array_size;
+									int m = (16 * uniform.array_size);
 									if ((size % m) != 0U) {
 									if ((size % m) != 0U) {
 										size += m - (size % m);
 										size += m - (size % m);
 									}
 									}
 									uniform_buffer_size += size;
 									uniform_buffer_size += size;
 								} else {
 								} else {
-									uniform_buffer_size += get_datatype_size(uniform2.type);
+									uniform_buffer_size += get_datatype_size(uniform.type);
 								}
 								}
 
 
 								if (uniform_buffer_exceeded_line == -1 && uniform_buffer_size > max_uniform_buffer_size) {
 								if (uniform_buffer_exceeded_line == -1 && uniform_buffer_size > max_uniform_buffer_size) {
@@ -8206,7 +8293,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 						}
 						}
 					}
 					}
 
 
-					if (uniform2.array_size > 0) {
+					if (uniform.array_size > 0) {
 						if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL) {
 						if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL) {
 							_set_error(vformat(RTR("The '%s' qualifier is not supported for uniform arrays."), "SCOPE_GLOBAL"));
 							_set_error(vformat(RTR("The '%s' qualifier is not supported for uniform arrays."), "SCOPE_GLOBAL"));
 							return ERR_PARSE_ERROR;
 							return ERR_PARSE_ERROR;
@@ -8222,7 +8309,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 					if (tk.type == TK_COLON) {
 					if (tk.type == TK_COLON) {
 						completion_type = COMPLETION_HINT;
 						completion_type = COMPLETION_HINT;
 						completion_base = type;
 						completion_base = type;
-						completion_base_array = uniform2.array_size > 0;
+						completion_base_array = uniform.array_size > 0;
 
 
 						//hint
 						//hint
 						do {
 						do {
@@ -8234,180 +8321,251 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 								return ERR_PARSE_ERROR;
 								return ERR_PARSE_ERROR;
 							}
 							}
 
 
-							if (uniform2.array_size > 0) {
+							if (uniform.array_size > 0) {
 								if (tk.type != TK_HINT_SOURCE_COLOR) {
 								if (tk.type != TK_HINT_SOURCE_COLOR) {
 									_set_error(RTR("This hint is not supported for uniform arrays."));
 									_set_error(RTR("This hint is not supported for uniform arrays."));
 									return ERR_PARSE_ERROR;
 									return ERR_PARSE_ERROR;
 								}
 								}
 							}
 							}
 
 
-							if (tk.type == TK_HINT_DEFAULT_WHITE_TEXTURE) {
-								uniform2.hint = ShaderNode::Uniform::HINT_DEFAULT_WHITE;
-							} else if (tk.type == TK_HINT_DEFAULT_BLACK_TEXTURE) {
-								uniform2.hint = ShaderNode::Uniform::HINT_DEFAULT_BLACK;
-							} else if (tk.type == TK_HINT_NORMAL_TEXTURE) {
-								uniform2.hint = ShaderNode::Uniform::HINT_NORMAL;
-							} else if (tk.type == TK_HINT_ROUGHNESS_NORMAL_TEXTURE) {
-								uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL;
-							} else if (tk.type == TK_HINT_ROUGHNESS_R) {
-								uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_R;
-							} else if (tk.type == TK_HINT_ROUGHNESS_G) {
-								uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_G;
-							} else if (tk.type == TK_HINT_ROUGHNESS_B) {
-								uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_B;
-							} else if (tk.type == TK_HINT_ROUGHNESS_A) {
-								uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_A;
-							} else if (tk.type == TK_HINT_ROUGHNESS_GRAY) {
-								uniform2.hint = ShaderNode::Uniform::HINT_ROUGHNESS_GRAY;
-							} else if (tk.type == TK_HINT_ANISOTROPY_TEXTURE) {
-								uniform2.hint = ShaderNode::Uniform::HINT_ANISOTROPY;
-							} else if (tk.type == TK_HINT_SOURCE_COLOR) {
-								if (type != TYPE_VEC3 && type != TYPE_VEC4 && type <= TYPE_MAT4) {
-									_set_error(vformat(RTR("Source color hint is for '%s', '%s' or sampler types only."), "vec3", "vec4"));
-									return ERR_PARSE_ERROR;
-								}
-								uniform2.hint = ShaderNode::Uniform::HINT_SOURCE_COLOR;
-							} else if (tk.type == TK_HINT_RANGE) {
-								uniform2.hint = ShaderNode::Uniform::HINT_RANGE;
-								if (type != TYPE_FLOAT && type != TYPE_INT) {
-									_set_error(vformat(RTR("Range hint is for '%s' and '%s' only."), "float", "int"));
-									return ERR_PARSE_ERROR;
-								}
-
-								tk = _get_token();
-								if (tk.type != TK_PARENTHESIS_OPEN) {
-									_set_expected_after_error("(", "hint_range");
-									return ERR_PARSE_ERROR;
-								}
+							ShaderNode::Uniform::Hint new_hint = ShaderNode::Uniform::HINT_NONE;
+							TextureFilter new_filter = FILTER_DEFAULT;
+							TextureRepeat new_repeat = REPEAT_DEFAULT;
 
 
-								tk = _get_token();
+							switch (tk.type) {
+								case TK_HINT_SOURCE_COLOR: {
+									if (type != TYPE_VEC3 && type != TYPE_VEC4 && !is_sampler_type(type)) {
+										_set_error(vformat(RTR("Source color hint is for '%s', '%s' or sampler types only."), "vec3", "vec4"));
+										return ERR_PARSE_ERROR;
+									}
 
 
-								float sign = 1.0;
+									if (is_sampler_type(type)) {
+										if (uniform.use_color) {
+											_set_error(vformat(RTR("Duplicated hint: '%s'."), "source_color"));
+											return ERR_PARSE_ERROR;
+										}
+										uniform.use_color = true;
+									} else {
+										new_hint = ShaderNode::Uniform::HINT_SOURCE_COLOR;
+									}
+								} break;
+								case TK_HINT_DEFAULT_BLACK_TEXTURE: {
+									new_hint = ShaderNode::Uniform::HINT_DEFAULT_BLACK;
+								} break;
+								case TK_HINT_DEFAULT_WHITE_TEXTURE: {
+									new_hint = ShaderNode::Uniform::HINT_DEFAULT_WHITE;
+								} break;
+								case TK_HINT_NORMAL_TEXTURE: {
+									new_hint = ShaderNode::Uniform::HINT_NORMAL;
+								} break;
+								case TK_HINT_ROUGHNESS_NORMAL_TEXTURE: {
+									new_hint = ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL;
+								} break;
+								case TK_HINT_ROUGHNESS_R: {
+									new_hint = ShaderNode::Uniform::HINT_ROUGHNESS_R;
+								} break;
+								case TK_HINT_ROUGHNESS_G: {
+									new_hint = ShaderNode::Uniform::HINT_ROUGHNESS_G;
+								} break;
+								case TK_HINT_ROUGHNESS_B: {
+									new_hint = ShaderNode::Uniform::HINT_ROUGHNESS_B;
+								} break;
+								case TK_HINT_ROUGHNESS_A: {
+									new_hint = ShaderNode::Uniform::HINT_ROUGHNESS_A;
+								} break;
+								case TK_HINT_ROUGHNESS_GRAY: {
+									new_hint = ShaderNode::Uniform::HINT_ROUGHNESS_GRAY;
+								} break;
+								case TK_HINT_ANISOTROPY_TEXTURE: {
+									new_hint = ShaderNode::Uniform::HINT_ANISOTROPY;
+								} break;
+								case TK_HINT_RANGE: {
+									if (type != TYPE_FLOAT && type != TYPE_INT) {
+										_set_error(vformat(RTR("Range hint is for '%s' and '%s' only."), "float", "int"));
+										return ERR_PARSE_ERROR;
+									}
 
 
-								if (tk.type == TK_OP_SUB) {
-									sign = -1.0;
 									tk = _get_token();
 									tk = _get_token();
-								}
-
-								if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) {
-									_set_error(RTR("Expected an integer constant."));
-									return ERR_PARSE_ERROR;
-								}
+									if (tk.type != TK_PARENTHESIS_OPEN) {
+										_set_expected_after_error("(", "hint_range");
+										return ERR_PARSE_ERROR;
+									}
 
 
-								uniform2.hint_range[0] = tk.constant;
-								uniform2.hint_range[0] *= sign;
+									tk = _get_token();
 
 
-								tk = _get_token();
+									float sign = 1.0;
 
 
-								if (tk.type != TK_COMMA) {
-									_set_error(RTR("Expected ',' after integer constant."));
-									return ERR_PARSE_ERROR;
-								}
+									if (tk.type == TK_OP_SUB) {
+										sign = -1.0;
+										tk = _get_token();
+									}
 
 
-								tk = _get_token();
+									if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) {
+										_set_error(RTR("Expected an integer constant."));
+										return ERR_PARSE_ERROR;
+									}
 
 
-								sign = 1.0;
+									uniform.hint_range[0] = tk.constant;
+									uniform.hint_range[0] *= sign;
 
 
-								if (tk.type == TK_OP_SUB) {
-									sign = -1.0;
 									tk = _get_token();
 									tk = _get_token();
-								}
 
 
-								if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) {
-									_set_error(RTR("Expected an integer constant after ','."));
-									return ERR_PARSE_ERROR;
-								}
+									if (tk.type != TK_COMMA) {
+										_set_error(RTR("Expected ',' after integer constant."));
+										return ERR_PARSE_ERROR;
+									}
 
 
-								uniform2.hint_range[1] = tk.constant;
-								uniform2.hint_range[1] *= sign;
+									tk = _get_token();
 
 
-								tk = _get_token();
+									sign = 1.0;
 
 
-								if (tk.type == TK_COMMA) {
-									tk = _get_token();
+									if (tk.type == TK_OP_SUB) {
+										sign = -1.0;
+										tk = _get_token();
+									}
 
 
 									if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) {
 									if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) {
 										_set_error(RTR("Expected an integer constant after ','."));
 										_set_error(RTR("Expected an integer constant after ','."));
 										return ERR_PARSE_ERROR;
 										return ERR_PARSE_ERROR;
 									}
 									}
 
 
-									uniform2.hint_range[2] = tk.constant;
+									uniform.hint_range[1] = tk.constant;
+									uniform.hint_range[1] *= sign;
+
 									tk = _get_token();
 									tk = _get_token();
-								} else {
-									if (type == TYPE_INT) {
-										uniform2.hint_range[2] = 1;
+
+									if (tk.type == TK_COMMA) {
+										tk = _get_token();
+
+										if (tk.type != TK_FLOAT_CONSTANT && !tk.is_integer_constant()) {
+											_set_error(RTR("Expected an integer constant after ','."));
+											return ERR_PARSE_ERROR;
+										}
+
+										uniform.hint_range[2] = tk.constant;
+										tk = _get_token();
 									} else {
 									} else {
-										uniform2.hint_range[2] = 0.001;
+										if (type == TYPE_INT) {
+											uniform.hint_range[2] = 1;
+										} else {
+											uniform.hint_range[2] = 0.001;
+										}
 									}
 									}
-								}
 
 
-								if (tk.type != TK_PARENTHESIS_CLOSE) {
-									_set_expected_error(")");
-									return ERR_PARSE_ERROR;
-								}
-							} else if (tk.type == TK_HINT_INSTANCE_INDEX) {
-								if (custom_instance_index != -1) {
-									_set_error(vformat(RTR("Can only specify '%s' once."), "instance_index"));
-									return ERR_PARSE_ERROR;
-								}
+									if (tk.type != TK_PARENTHESIS_CLOSE) {
+										_set_expected_error(")");
+										return ERR_PARSE_ERROR;
+									}
 
 
-								tk = _get_token();
-								if (tk.type != TK_PARENTHESIS_OPEN) {
-									_set_expected_after_error("(", "instance_index");
-									return ERR_PARSE_ERROR;
-								}
+									new_hint = ShaderNode::Uniform::HINT_RANGE;
+								} break;
+								case TK_HINT_INSTANCE_INDEX: {
+									if (custom_instance_index != -1) {
+										_set_error(vformat(RTR("Can only specify '%s' once."), "instance_index"));
+										return ERR_PARSE_ERROR;
+									}
 
 
-								tk = _get_token();
+									tk = _get_token();
+									if (tk.type != TK_PARENTHESIS_OPEN) {
+										_set_expected_after_error("(", "instance_index");
+										return ERR_PARSE_ERROR;
+									}
 
 
-								if (tk.type == TK_OP_SUB) {
-									_set_error(RTR("The instance index can't be negative."));
-									return ERR_PARSE_ERROR;
-								}
+									tk = _get_token();
 
 
-								if (!tk.is_integer_constant()) {
-									_set_error(RTR("Expected an integer constant."));
-									return ERR_PARSE_ERROR;
-								}
+									if (tk.type == TK_OP_SUB) {
+										_set_error(RTR("The instance index can't be negative."));
+										return ERR_PARSE_ERROR;
+									}
+
+									if (!tk.is_integer_constant()) {
+										_set_error(RTR("Expected an integer constant."));
+										return ERR_PARSE_ERROR;
+									}
+
+									custom_instance_index = tk.constant;
 
 
-								custom_instance_index = tk.constant;
+									if (custom_instance_index >= MAX_INSTANCE_UNIFORM_INDICES) {
+										_set_error(vformat(RTR("Allowed instance uniform indices must be within [0..%d] range."), MAX_INSTANCE_UNIFORM_INDICES - 1));
+										return ERR_PARSE_ERROR;
+									}
+
+									tk = _get_token();
+
+									if (tk.type != TK_PARENTHESIS_CLOSE) {
+										_set_expected_error(")");
+										return ERR_PARSE_ERROR;
+									}
+								} break;
+								case TK_FILTER_NEAREST: {
+									new_filter = FILTER_NEAREST;
+								} break;
+								case TK_FILTER_LINEAR: {
+									new_filter = FILTER_LINEAR;
+								} break;
+								case TK_FILTER_NEAREST_MIPMAP: {
+									new_filter = FILTER_NEAREST_MIPMAP;
+								} break;
+								case TK_FILTER_LINEAR_MIPMAP: {
+									new_filter = FILTER_LINEAR_MIPMAP;
+								} break;
+								case TK_FILTER_NEAREST_MIPMAP_ANISOTROPIC: {
+									new_filter = FILTER_NEAREST_MIPMAP_ANISOTROPIC;
+								} break;
+								case TK_FILTER_LINEAR_MIPMAP_ANISOTROPIC: {
+									new_filter = FILTER_LINEAR_MIPMAP_ANISOTROPIC;
+								} break;
+								case TK_REPEAT_DISABLE: {
+									new_repeat = REPEAT_DISABLE;
+								} break;
+								case TK_REPEAT_ENABLE: {
+									new_repeat = REPEAT_ENABLE;
+								} break;
+								default:
+									break;
+							}
+							if (((new_filter != FILTER_DEFAULT || new_repeat != REPEAT_DEFAULT) || (new_hint != ShaderNode::Uniform::HINT_NONE && new_hint != ShaderNode::Uniform::HINT_SOURCE_COLOR && new_hint != ShaderNode::Uniform::HINT_RANGE)) && !is_sampler_type(type)) {
+								_set_error(RTR("This hint is only for sampler types."));
+								return ERR_PARSE_ERROR;
+							}
 
 
-								if (custom_instance_index >= MAX_INSTANCE_UNIFORM_INDICES) {
-									_set_error(vformat(RTR("Allowed instance uniform indices must be within [0..%d] range."), MAX_INSTANCE_UNIFORM_INDICES - 1));
+							if (new_hint != ShaderNode::Uniform::HINT_NONE) {
+								if (uniform.hint != ShaderNode::Uniform::HINT_NONE) {
+									if (uniform.hint == new_hint) {
+										_set_error(vformat(RTR("Duplicated hint: '%s'."), get_uniform_hint_name(new_hint)));
+									} else {
+										_set_error(vformat(RTR("Redefinition of hint: '%s'. The hint has already been set to '%s'."), get_uniform_hint_name(new_hint), get_uniform_hint_name(uniform.hint)));
+									}
 									return ERR_PARSE_ERROR;
 									return ERR_PARSE_ERROR;
+								} else {
+									uniform.hint = new_hint;
 								}
 								}
+							}
 
 
-								tk = _get_token();
-
-								if (tk.type != TK_PARENTHESIS_CLOSE) {
-									_set_expected_error(")");
+							if (new_filter != FILTER_DEFAULT) {
+								if (uniform.filter != FILTER_DEFAULT) {
+									if (uniform.filter == new_filter) {
+										_set_error(vformat(RTR("Duplicated hint: '%s'."), get_texture_filter_name(new_filter)));
+									} else {
+										_set_error(vformat(RTR("Redefinition of hint: '%s'. The filter mode has already been set to '%s'."), get_texture_filter_name(new_filter), get_texture_filter_name(uniform.filter)));
+									}
 									return ERR_PARSE_ERROR;
 									return ERR_PARSE_ERROR;
+								} else {
+									uniform.filter = new_filter;
 								}
 								}
-							} else if (tk.type == TK_FILTER_LINEAR) {
-								uniform2.filter = FILTER_LINEAR;
-							} else if (tk.type == TK_FILTER_NEAREST) {
-								uniform2.filter = FILTER_NEAREST;
-							} else if (tk.type == TK_FILTER_NEAREST_MIPMAP) {
-								uniform2.filter = FILTER_NEAREST_MIPMAP;
-							} else if (tk.type == TK_FILTER_LINEAR_MIPMAP) {
-								uniform2.filter = FILTER_LINEAR_MIPMAP;
-							} else if (tk.type == TK_FILTER_NEAREST_MIPMAP_ANISOTROPIC) {
-								uniform2.filter = FILTER_NEAREST_MIPMAP_ANISOTROPIC;
-							} else if (tk.type == TK_FILTER_LINEAR_MIPMAP_ANISOTROPIC) {
-								uniform2.filter = FILTER_LINEAR_MIPMAP_ANISOTROPIC;
-							} else if (tk.type == TK_REPEAT_DISABLE) {
-								uniform2.repeat = REPEAT_DISABLE;
-							} else if (tk.type == TK_REPEAT_ENABLE) {
-								uniform2.repeat = REPEAT_ENABLE;
 							}
 							}
 
 
-							if (uniform2.hint == ShaderNode::Uniform::HINT_SOURCE_COLOR) {
-								if (type != TYPE_VEC3 && type != TYPE_VEC4 && !is_sampler_type(type)) {
-									_set_error(vformat(RTR("This hint is only for '%s', '%s' or sampler types."), "vec3", "vec4"));
+							if (new_repeat != REPEAT_DEFAULT) {
+								if (uniform.repeat != REPEAT_DEFAULT) {
+									if (uniform.repeat == new_repeat) {
+										_set_error(vformat(RTR("Duplicated hint: '%s'."), get_texture_repeat_name(new_repeat)));
+									} else {
+										_set_error(vformat(RTR("Redefinition of hint: '%s'. The repeat mode has already been set to '%s'."), get_texture_repeat_name(new_repeat), get_texture_repeat_name(uniform.repeat)));
+									}
 									return ERR_PARSE_ERROR;
 									return ERR_PARSE_ERROR;
+								} else {
+									uniform.repeat = new_repeat;
 								}
 								}
-							} else if (uniform2.hint != ShaderNode::Uniform::HINT_RANGE && uniform2.hint != ShaderNode::Uniform::HINT_NONE && !is_sampler_type(type)) {
-								_set_error(RTR("This hint is only for sampler types."));
-								return ERR_PARSE_ERROR;
 							}
 							}
 
 
 							tk = _get_token();
 							tk = _get_token();
@@ -8417,9 +8575,9 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 
 
 					if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) {
 					if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) {
 						if (custom_instance_index >= 0) {
 						if (custom_instance_index >= 0) {
-							uniform2.instance_index = custom_instance_index;
+							uniform.instance_index = custom_instance_index;
 						} else {
 						} else {
-							uniform2.instance_index = instance_index++;
+							uniform.instance_index = instance_index++;
 							if (instance_index > MAX_INSTANCE_UNIFORM_INDICES) {
 							if (instance_index > MAX_INSTANCE_UNIFORM_INDICES) {
 								_set_error(vformat(RTR("Too many '%s' uniforms in shader, maximum supported is %d."), "instance", MAX_INSTANCE_UNIFORM_INDICES));
 								_set_error(vformat(RTR("Too many '%s' uniforms in shader, maximum supported is %d."), "instance", MAX_INSTANCE_UNIFORM_INDICES));
 								return ERR_PARSE_ERROR;
 								return ERR_PARSE_ERROR;
@@ -8430,7 +8588,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 					//reset scope for next uniform
 					//reset scope for next uniform
 
 
 					if (tk.type == TK_OP_ASSIGN) {
 					if (tk.type == TK_OP_ASSIGN) {
-						if (uniform2.array_size > 0) {
+						if (uniform.array_size > 0) {
 							_set_error(RTR("Setting default values to uniform arrays is not supported."));
 							_set_error(RTR("Setting default values to uniform arrays is not supported."));
 							return ERR_PARSE_ERROR;
 							return ERR_PARSE_ERROR;
 						}
 						}
@@ -8446,16 +8604,16 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
 
 
 						ConstantNode *cn = static_cast<ConstantNode *>(expr);
 						ConstantNode *cn = static_cast<ConstantNode *>(expr);
 
 
-						uniform2.default_value.resize(cn->values.size());
+						uniform.default_value.resize(cn->values.size());
 
 
-						if (!convert_constant(cn, uniform2.type, uniform2.default_value.ptrw())) {
-							_set_error(vformat(RTR("Can't convert constant to '%s'."), get_datatype_name(uniform2.type)));
+						if (!convert_constant(cn, uniform.type, uniform.default_value.ptrw())) {
+							_set_error(vformat(RTR("Can't convert constant to '%s'."), get_datatype_name(uniform.type)));
 							return ERR_PARSE_ERROR;
 							return ERR_PARSE_ERROR;
 						}
 						}
 						tk = _get_token();
 						tk = _get_token();
 					}
 					}
 
 
-					shader->uniforms[name] = uniform2;
+					shader->uniforms[name] = uniform;
 #ifdef DEBUG_ENABLED
 #ifdef DEBUG_ENABLED
 					if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_UNIFORM_FLAG)) {
 					if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_UNIFORM_FLAG)) {
 						used_uniforms.insert(name, Usage(tk_line));
 						used_uniforms.insert(name, Usage(tk_line));

+ 4 - 0
servers/rendering/shader_language.h

@@ -681,6 +681,7 @@ public:
 			Vector<ConstantNode::Value> default_value;
 			Vector<ConstantNode::Value> default_value;
 			Scope scope = SCOPE_LOCAL;
 			Scope scope = SCOPE_LOCAL;
 			Hint hint = HINT_NONE;
 			Hint hint = HINT_NONE;
+			bool use_color = false;
 			TextureFilter filter = FILTER_DEFAULT;
 			TextureFilter filter = FILTER_DEFAULT;
 			TextureRepeat repeat = REPEAT_DEFAULT;
 			TextureRepeat repeat = REPEAT_DEFAULT;
 			float hint_range[3];
 			float hint_range[3];
@@ -756,6 +757,9 @@ public:
 	static DataPrecision get_token_precision(TokenType p_type);
 	static DataPrecision get_token_precision(TokenType p_type);
 	static String get_precision_name(DataPrecision p_type);
 	static String get_precision_name(DataPrecision p_type);
 	static String get_datatype_name(DataType p_type);
 	static String get_datatype_name(DataType p_type);
+	static String get_uniform_hint_name(ShaderNode::Uniform::Hint p_hint);
+	static String get_texture_filter_name(TextureFilter p_filter);
+	static String get_texture_repeat_name(TextureRepeat p_repeat);
 	static bool is_token_nonvoid_datatype(TokenType p_type);
 	static bool is_token_nonvoid_datatype(TokenType p_type);
 	static bool is_token_operator(TokenType p_type);
 	static bool is_token_operator(TokenType p_type);
 	static bool is_token_operator_assign(TokenType p_type);
 	static bool is_token_operator_assign(TokenType p_type);