Browse Source

Merge pull request #36177 from Chaosus/shader_fix_swizzling

Fix bugs in shader swizzling
Yuri Roubinsky 5 years ago
parent
commit
5c3944e7da
2 changed files with 123 additions and 2 deletions
  1. 120 1
      servers/visual/shader_language.cpp
  2. 3 1
      servers/visual/shader_language.h

+ 120 - 1
servers/visual/shader_language.cpp

@@ -2933,6 +2933,13 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
 	} else if (p_node->type == Node::TYPE_MEMBER) {
 	} else if (p_node->type == Node::TYPE_MEMBER) {
 
 
 		MemberNode *member = static_cast<MemberNode *>(p_node);
 		MemberNode *member = static_cast<MemberNode *>(p_node);
+
+		if (member->has_swizzling_duplicates) {
+			if (r_message)
+				*r_message = RTR("Swizzling assignment contains duplicates.");
+			return false;
+		}
+
 		return _validate_assign(member->owner, p_builtin_types, r_message);
 		return _validate_assign(member->owner, p_builtin_types, r_message);
 
 
 	} else if (p_node->type == Node::TYPE_VARIABLE) {
 	} else if (p_node->type == Node::TYPE_VARIABLE) {
@@ -3710,9 +3717,17 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 				String ident = identifier;
 				String ident = identifier;
 
 
 				bool ok = true;
 				bool ok = true;
+				bool repeated = false;
 				DataType member_type = TYPE_VOID;
 				DataType member_type = TYPE_VOID;
 				StringName member_struct_name = "";
 				StringName member_struct_name = "";
 				int array_size = 0;
 				int array_size = 0;
+
+				Set<char> position_symbols;
+				Set<char> color_symbols;
+				Set<char> texture_symbols;
+
+				bool mix_error = false;
+
 				switch (dt) {
 				switch (dt) {
 					case TYPE_STRUCT: {
 					case TYPE_STRUCT: {
 						ok = false;
 						ok = false;
@@ -3758,8 +3773,39 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 							switch (c[i]) {
 							switch (c[i]) {
 								case 'r':
 								case 'r':
 								case 'g':
 								case 'g':
+									if (position_symbols.size() > 0 || texture_symbols.size() > 0) {
+										mix_error = true;
+										break;
+									}
+									if (!color_symbols.has(c[i])) {
+										color_symbols.insert(c[i]);
+									} else {
+										repeated = true;
+									}
+									break;
 								case 'x':
 								case 'x':
 								case 'y':
 								case 'y':
+									if (color_symbols.size() > 0 || texture_symbols.size() > 0) {
+										mix_error = true;
+										break;
+									}
+									if (!position_symbols.has(c[i])) {
+										position_symbols.insert(c[i]);
+									} else {
+										repeated = true;
+									}
+									break;
+								case 's':
+								case 't':
+									if (color_symbols.size() > 0 || position_symbols.size() > 0) {
+										mix_error = true;
+										break;
+									}
+									if (!texture_symbols.has(c[i])) {
+										texture_symbols.insert(c[i]);
+									} else {
+										repeated = true;
+									}
 									break;
 									break;
 								default:
 								default:
 									ok = false;
 									ok = false;
@@ -3794,9 +3840,41 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 								case 'r':
 								case 'r':
 								case 'g':
 								case 'g':
 								case 'b':
 								case 'b':
+									if (position_symbols.size() > 0 || texture_symbols.size() > 0) {
+										mix_error = true;
+										break;
+									}
+									if (!color_symbols.has(c[i])) {
+										color_symbols.insert(c[i]);
+									} else {
+										repeated = true;
+									}
+									break;
 								case 'x':
 								case 'x':
 								case 'y':
 								case 'y':
 								case 'z':
 								case 'z':
+									if (color_symbols.size() > 0 || texture_symbols.size() > 0) {
+										mix_error = true;
+										break;
+									}
+									if (!position_symbols.has(c[i])) {
+										position_symbols.insert(c[i]);
+									} else {
+										repeated = true;
+									}
+									break;
+								case 's':
+								case 't':
+								case 'p':
+									if (color_symbols.size() > 0 || position_symbols.size() > 0) {
+										mix_error = true;
+										break;
+									}
+									if (!texture_symbols.has(c[i])) {
+										texture_symbols.insert(c[i]);
+									} else {
+										repeated = true;
+									}
 									break;
 									break;
 								default:
 								default:
 									ok = false;
 									ok = false;
@@ -3832,10 +3910,43 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 								case 'g':
 								case 'g':
 								case 'b':
 								case 'b':
 								case 'a':
 								case 'a':
+									if (position_symbols.size() > 0 || texture_symbols.size() > 0) {
+										mix_error = true;
+										break;
+									}
+									if (!color_symbols.has(c[i])) {
+										color_symbols.insert(c[i]);
+									} else {
+										repeated = true;
+									}
+									break;
 								case 'x':
 								case 'x':
 								case 'y':
 								case 'y':
 								case 'z':
 								case 'z':
 								case 'w':
 								case 'w':
+									if (color_symbols.size() > 0 || texture_symbols.size() > 0) {
+										mix_error = true;
+										break;
+									}
+									if (!position_symbols.has(c[i])) {
+										position_symbols.insert(c[i]);
+									} else {
+										repeated = true;
+									}
+									break;
+								case 's':
+								case 't':
+								case 'p':
+								case 'q':
+									if (color_symbols.size() > 0 || position_symbols.size() > 0) {
+										mix_error = true;
+										break;
+									}
+									if (!texture_symbols.has(c[i])) {
+										texture_symbols.insert(c[i]);
+									} else {
+										repeated = true;
+									}
 									break;
 									break;
 								default:
 								default:
 									ok = false;
 									ok = false;
@@ -3850,8 +3961,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 					}
 					}
 				}
 				}
 
 
-				if (!ok) {
+				if (mix_error) {
+					_set_error("Cannot combine symbols from different sets in expression ." + ident);
+					return NULL;
+				}
 
 
+				if (!ok) {
 					_set_error("Invalid member for " + (dt == TYPE_STRUCT ? st : get_datatype_name(dt)) + " expression: ." + ident);
 					_set_error("Invalid member for " + (dt == TYPE_STRUCT ? st : get_datatype_name(dt)) + " expression: ." + ident);
 					return NULL;
 					return NULL;
 				}
 				}
@@ -3865,6 +3980,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 				mn->array_size = array_size;
 				mn->array_size = array_size;
 				mn->name = ident;
 				mn->name = ident;
 				mn->owner = expr;
 				mn->owner = expr;
+				mn->has_swizzling_duplicates = repeated;
+
 				if (array_size > 0) {
 				if (array_size > 0) {
 
 
 					tk = _get_token();
 					tk = _get_token();
@@ -6684,6 +6801,7 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
 
 
 			const char colv[4] = { 'r', 'g', 'b', 'a' };
 			const char colv[4] = { 'r', 'g', 'b', 'a' };
 			const char coordv[4] = { 'x', 'y', 'z', 'w' };
 			const char coordv[4] = { 'x', 'y', 'z', 'w' };
+			const char coordt[4] = { 's', 't', 'p', 'q' };
 
 
 			int limit = 0;
 			int limit = 0;
 
 
@@ -6721,6 +6839,7 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
 			for (int i = 0; i < limit; i++) {
 			for (int i = 0; i < limit; i++) {
 				r_options->push_back(ScriptCodeCompletionOption(String::chr(colv[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
 				r_options->push_back(ScriptCodeCompletionOption(String::chr(colv[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
 				r_options->push_back(ScriptCodeCompletionOption(String::chr(coordv[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
 				r_options->push_back(ScriptCodeCompletionOption(String::chr(coordv[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
+				r_options->push_back(ScriptCodeCompletionOption(String::chr(coordt[i]), ScriptCodeCompletionOption::KIND_PLAIN_TEXT));
 			}
 			}
 
 
 		} break;
 		} break;

+ 3 - 1
servers/visual/shader_language.h

@@ -538,6 +538,7 @@ public:
 		StringName name;
 		StringName name;
 		Node *owner;
 		Node *owner;
 		Node *index_expression;
 		Node *index_expression;
+		bool has_swizzling_duplicates;
 
 
 		virtual DataType get_datatype() const { return datatype; }
 		virtual DataType get_datatype() const { return datatype; }
 		virtual String get_datatype_name() const { return String(struct_name); }
 		virtual String get_datatype_name() const { return String(struct_name); }
@@ -549,7 +550,8 @@ public:
 				datatype(TYPE_VOID),
 				datatype(TYPE_VOID),
 				array_size(0),
 				array_size(0),
 				owner(NULL),
 				owner(NULL),
-				index_expression(NULL) {}
+				index_expression(NULL),
+				has_swizzling_duplicates(false) {}
 	};
 	};
 
 
 	struct StructNode : public Node {
 	struct StructNode : public Node {