mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 13:41:03 +00:00 
			
		
		
		
	Backport dd0874e "Allow passing varying from fragment to light shader function" to 3.4
				
					
				
			This commit is contained in:
		
							parent
							
								
									0c028ad96e
								
							
						
					
					
						commit
						fba6b62054
					
				
					 6 changed files with 262 additions and 33 deletions
				
			
		|  | @ -210,7 +210,7 @@ static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNo | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ShaderCompilerGLES2::_dump_function_deps(SL::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, StringBuilder &r_to_add, Set<StringName> &r_added) { | void ShaderCompilerGLES2::_dump_function_deps(const SL::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, StringBuilder &r_to_add, Set<StringName> &r_added) { | ||||||
| 	int fidx = -1; | 	int fidx = -1; | ||||||
| 
 | 
 | ||||||
| 	for (int i = 0; i < p_node->functions.size(); i++) { | 	for (int i = 0; i < p_node->functions.size(); i++) { | ||||||
|  | @ -269,7 +269,7 @@ void ShaderCompilerGLES2::_dump_function_deps(SL::ShaderNode *p_node, const Stri | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope) { | String ShaderCompilerGLES2::_dump_node_code(const SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope) { | ||||||
| 	StringBuilder code; | 	StringBuilder code; | ||||||
| 
 | 
 | ||||||
| 	switch (p_node->type) { | 	switch (p_node->type) { | ||||||
|  | @ -378,7 +378,14 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 
 | 
 | ||||||
| 			// varyings
 | 			// varyings
 | ||||||
| 
 | 
 | ||||||
|  | 			List<Pair<StringName, SL::ShaderNode::Varying>> var_frag_to_light; | ||||||
|  | 
 | ||||||
| 			for (Map<StringName, SL::ShaderNode::Varying>::Element *E = snode->varyings.front(); E; E = E->next()) { | 			for (Map<StringName, SL::ShaderNode::Varying>::Element *E = snode->varyings.front(); E; E = E->next()) { | ||||||
|  | 				if (E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT || E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT) { | ||||||
|  | 					var_frag_to_light.push_back(Pair<StringName, SL::ShaderNode::Varying>(E->key(), E->get())); | ||||||
|  | 					fragment_varyings.insert(E->key()); | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
| 				StringBuffer<> varying_code; | 				StringBuffer<> varying_code; | ||||||
| 
 | 
 | ||||||
| 				varying_code += "varying "; | 				varying_code += "varying "; | ||||||
|  | @ -399,6 +406,21 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 				fragment_global += final_code; | 				fragment_global += final_code; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | 			if (var_frag_to_light.size() > 0) { | ||||||
|  | 				String gcode = "\n\nstruct {\n"; | ||||||
|  | 				for (List<Pair<StringName, SL::ShaderNode::Varying>>::Element *E = var_frag_to_light.front(); E; E = E->next()) { | ||||||
|  | 					gcode += "\t" + _prestr(E->get().second.precision) + _typestr(E->get().second.type) + " " + _mkid(E->get().first); | ||||||
|  | 					if (E->get().second.array_size > 0) { | ||||||
|  | 						gcode += "["; | ||||||
|  | 						gcode += itos(E->get().second.array_size); | ||||||
|  | 						gcode += "]"; | ||||||
|  | 					} | ||||||
|  | 					gcode += ";\n"; | ||||||
|  | 				} | ||||||
|  | 				gcode += "} frag_to_light;\n"; | ||||||
|  | 				r_gen_code.fragment_global += gcode; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
| 			// constants
 | 			// constants
 | ||||||
| 
 | 
 | ||||||
| 			for (int i = 0; i < snode->vconstants.size(); i++) { | 			for (int i = 0; i < snode->vconstants.size(); i++) { | ||||||
|  | @ -424,8 +446,10 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 
 | 
 | ||||||
| 			for (int i = 0; i < snode->functions.size(); i++) { | 			for (int i = 0; i < snode->functions.size(); i++) { | ||||||
| 				SL::FunctionNode *fnode = snode->functions[i].function; | 				SL::FunctionNode *fnode = snode->functions[i].function; | ||||||
|  | 				function = fnode; | ||||||
| 				current_func_name = fnode->name; | 				current_func_name = fnode->name; | ||||||
| 				function_code[fnode->name] = _dump_node_code(fnode->body, 1, r_gen_code, p_actions, p_default_actions, p_assigning); | 				function_code[fnode->name] = _dump_node_code(fnode->body, 1, r_gen_code, p_actions, p_default_actions, p_assigning); | ||||||
|  | 				function = nullptr; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			Set<StringName> added_vertex; | 			Set<StringName> added_vertex; | ||||||
|  | @ -434,6 +458,8 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 			for (int i = 0; i < snode->functions.size(); i++) { | 			for (int i = 0; i < snode->functions.size(); i++) { | ||||||
| 				SL::FunctionNode *fnode = snode->functions[i].function; | 				SL::FunctionNode *fnode = snode->functions[i].function; | ||||||
| 
 | 
 | ||||||
|  | 				function = fnode; | ||||||
|  | 
 | ||||||
| 				current_func_name = fnode->name; | 				current_func_name = fnode->name; | ||||||
| 
 | 
 | ||||||
| 				if (fnode->name == vertex_name) { | 				if (fnode->name == vertex_name) { | ||||||
|  | @ -448,6 +474,8 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 					_dump_function_deps(snode, fnode->name, function_code, fragment_global, added_fragment); | 					_dump_function_deps(snode, fnode->name, function_code, fragment_global, added_fragment); | ||||||
| 					r_gen_code.light = function_code[light_name]; | 					r_gen_code.light = function_code[light_name]; | ||||||
| 				} | 				} | ||||||
|  | 
 | ||||||
|  | 				function = nullptr; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			r_gen_code.vertex_global = vertex_global.as_string(); | 			r_gen_code.vertex_global = vertex_global.as_string(); | ||||||
|  | @ -519,6 +547,19 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 
 | 
 | ||||||
| 		case SL::Node::TYPE_VARIABLE: { | 		case SL::Node::TYPE_VARIABLE: { | ||||||
| 			SL::VariableNode *var_node = (SL::VariableNode *)p_node; | 			SL::VariableNode *var_node = (SL::VariableNode *)p_node; | ||||||
|  | 			bool use_fragment_varying = false; | ||||||
|  | 
 | ||||||
|  | 			if (current_func_name != vertex_name) { | ||||||
|  | 				if (p_assigning) { | ||||||
|  | 					if (shader->varyings.has(var_node->name)) { | ||||||
|  | 						use_fragment_varying = true; | ||||||
|  | 					} | ||||||
|  | 				} else { | ||||||
|  | 					if (fragment_varyings.has(var_node->name)) { | ||||||
|  | 						use_fragment_varying = true; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			if (p_assigning && p_actions.write_flag_pointers.has(var_node->name)) { | 			if (p_assigning && p_actions.write_flag_pointers.has(var_node->name)) { | ||||||
| 				*p_actions.write_flag_pointers[var_node->name] = true; | 				*p_actions.write_flag_pointers[var_node->name] = true; | ||||||
|  | @ -545,6 +586,8 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 
 | 
 | ||||||
| 			if (p_default_actions.renames.has(var_node->name)) { | 			if (p_default_actions.renames.has(var_node->name)) { | ||||||
| 				code += p_default_actions.renames[var_node->name]; | 				code += p_default_actions.renames[var_node->name]; | ||||||
|  | 			} else if (use_fragment_varying) { | ||||||
|  | 				code += "frag_to_light." + _mkid(var_node->name); | ||||||
| 			} else { | 			} else { | ||||||
| 				code += _mkid(var_node->name); | 				code += _mkid(var_node->name); | ||||||
| 			} | 			} | ||||||
|  | @ -605,6 +648,23 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 		} break; | 		} break; | ||||||
| 		case SL::Node::TYPE_ARRAY: { | 		case SL::Node::TYPE_ARRAY: { | ||||||
| 			SL::ArrayNode *arr_node = (SL::ArrayNode *)p_node; | 			SL::ArrayNode *arr_node = (SL::ArrayNode *)p_node; | ||||||
|  | 			bool use_fragment_varying = false; | ||||||
|  | 
 | ||||||
|  | 			if (current_func_name != vertex_name) { | ||||||
|  | 				if (arr_node->assign_expression != nullptr) { | ||||||
|  | 					use_fragment_varying = true; | ||||||
|  | 				} else { | ||||||
|  | 					if (p_assigning) { | ||||||
|  | 						if (shader->varyings.has(arr_node->name)) { | ||||||
|  | 							use_fragment_varying = true; | ||||||
|  | 						} | ||||||
|  | 					} else { | ||||||
|  | 						if (fragment_varyings.has(arr_node->name)) { | ||||||
|  | 							use_fragment_varying = true; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			if (p_assigning && p_actions.write_flag_pointers.has(arr_node->name)) { | 			if (p_assigning && p_actions.write_flag_pointers.has(arr_node->name)) { | ||||||
| 				*p_actions.write_flag_pointers[arr_node->name] = true; | 				*p_actions.write_flag_pointers[arr_node->name] = true; | ||||||
|  | @ -631,6 +691,8 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 
 | 
 | ||||||
| 			if (p_default_actions.renames.has(arr_node->name)) { | 			if (p_default_actions.renames.has(arr_node->name)) { | ||||||
| 				code += p_default_actions.renames[arr_node->name]; | 				code += p_default_actions.renames[arr_node->name]; | ||||||
|  | 			} else if (use_fragment_varying) { | ||||||
|  | 				code += "frag_to_light." + _mkid(arr_node->name); | ||||||
| 			} else { | 			} else { | ||||||
| 				code += _mkid(arr_node->name); | 				code += _mkid(arr_node->name); | ||||||
| 			} | 			} | ||||||
|  | @ -908,7 +970,7 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 			code += _dump_node_code(member_node->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); | 			code += _dump_node_code(member_node->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); | ||||||
| 			code += "."; | 			code += "."; | ||||||
| 			code += member_node->name; | 			code += member_node->name; | ||||||
| 			if (member_node->index_expression != NULL) { | 			if (member_node->index_expression != nullptr) { | ||||||
| 				code += "["; | 				code += "["; | ||||||
| 				code += _dump_node_code(member_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); | 				code += _dump_node_code(member_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); | ||||||
| 				code += "]"; | 				code += "]"; | ||||||
|  | @ -947,8 +1009,11 @@ Error ShaderCompilerGLES2::compile(VS::ShaderMode p_mode, const String &p_code, | ||||||
| 	used_name_defines.clear(); | 	used_name_defines.clear(); | ||||||
| 	used_rmode_defines.clear(); | 	used_rmode_defines.clear(); | ||||||
| 	used_flag_pointers.clear(); | 	used_flag_pointers.clear(); | ||||||
|  | 	fragment_varyings.clear(); | ||||||
| 
 | 
 | ||||||
| 	_dump_node_code(parser.get_shader(), 1, r_gen_code, *p_actions, actions[p_mode], false); | 	shader = parser.get_shader(); | ||||||
|  | 	function = nullptr; | ||||||
|  | 	_dump_node_code(shader, 1, r_gen_code, *p_actions, actions[p_mode], false); | ||||||
| 
 | 
 | ||||||
| 	return OK; | 	return OK; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -73,9 +73,11 @@ private: | ||||||
| 		Map<StringName, String> usage_defines; | 		Map<StringName, String> usage_defines; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	void _dump_function_deps(ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, StringBuilder &r_to_add, Set<StringName> &r_added); | 	void _dump_function_deps(const ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, StringBuilder &r_to_add, Set<StringName> &r_added); | ||||||
| 	String _dump_node_code(ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope = true); | 	String _dump_node_code(const ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope = true); | ||||||
| 
 | 
 | ||||||
|  | 	const ShaderLanguage::ShaderNode *shader; | ||||||
|  | 	const ShaderLanguage::FunctionNode *function; | ||||||
| 	StringName current_func_name; | 	StringName current_func_name; | ||||||
| 	StringName vertex_name; | 	StringName vertex_name; | ||||||
| 	StringName fragment_name; | 	StringName fragment_name; | ||||||
|  | @ -86,6 +88,7 @@ private: | ||||||
| 	Set<StringName> used_flag_pointers; | 	Set<StringName> used_flag_pointers; | ||||||
| 	Set<StringName> used_rmode_defines; | 	Set<StringName> used_rmode_defines; | ||||||
| 	Set<StringName> internal_functions; | 	Set<StringName> internal_functions; | ||||||
|  | 	Set<StringName> fragment_varyings; | ||||||
| 
 | 
 | ||||||
| 	DefaultIdentifierActions actions[VS::SHADER_MAX]; | 	DefaultIdentifierActions actions[VS::SHADER_MAX]; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -331,7 +331,7 @@ static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNo | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added) { | void ShaderCompilerGLES3::_dump_function_deps(const SL::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added) { | ||||||
| 	int fidx = -1; | 	int fidx = -1; | ||||||
| 
 | 
 | ||||||
| 	for (int i = 0; i < p_node->functions.size(); i++) { | 	for (int i = 0; i < p_node->functions.size(); i++) { | ||||||
|  | @ -388,7 +388,7 @@ void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode *p_node, const Stri | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope) { | String ShaderCompilerGLES3::_dump_node_code(const SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope) { | ||||||
| 	String code; | 	String code; | ||||||
| 
 | 
 | ||||||
| 	switch (p_node->type) { | 	switch (p_node->type) { | ||||||
|  | @ -521,7 +521,14 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 				r_gen_code.uniform_total_size += r_gen_code.uniform_total_size % 16; | 				r_gen_code.uniform_total_size += r_gen_code.uniform_total_size % 16; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | 			List<Pair<StringName, SL::ShaderNode::Varying>> var_frag_to_light; | ||||||
|  | 
 | ||||||
| 			for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) { | 			for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) { | ||||||
|  | 				if (E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT || E->get().stage == SL::ShaderNode::Varying::STAGE_FRAGMENT) { | ||||||
|  | 					var_frag_to_light.push_back(Pair<StringName, SL::ShaderNode::Varying>(E->key(), E->get())); | ||||||
|  | 					fragment_varyings.insert(E->key()); | ||||||
|  | 					continue; | ||||||
|  | 				} | ||||||
| 				String vcode; | 				String vcode; | ||||||
| 				String interp_mode = _interpstr(E->get().interpolation); | 				String interp_mode = _interpstr(E->get().interpolation); | ||||||
| 				vcode += _prestr(E->get().precision); | 				vcode += _prestr(E->get().precision); | ||||||
|  | @ -537,6 +544,21 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 				r_gen_code.fragment_global += interp_mode + "in " + vcode; | 				r_gen_code.fragment_global += interp_mode + "in " + vcode; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | 			if (var_frag_to_light.size() > 0) { | ||||||
|  | 				String gcode = "\n\nstruct {\n"; | ||||||
|  | 				for (List<Pair<StringName, SL::ShaderNode::Varying>>::Element *E = var_frag_to_light.front(); E; E = E->next()) { | ||||||
|  | 					gcode += "\t" + _prestr(E->get().second.precision) + _typestr(E->get().second.type) + " " + _mkid(E->get().first); | ||||||
|  | 					if (E->get().second.array_size > 0) { | ||||||
|  | 						gcode += "["; | ||||||
|  | 						gcode += itos(E->get().second.array_size); | ||||||
|  | 						gcode += "]"; | ||||||
|  | 					} | ||||||
|  | 					gcode += ";\n"; | ||||||
|  | 				} | ||||||
|  | 				gcode += "} frag_to_light;\n"; | ||||||
|  | 				r_gen_code.fragment_global += gcode; | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
| 			for (int i = 0; i < pnode->vconstants.size(); i++) { | 			for (int i = 0; i < pnode->vconstants.size(); i++) { | ||||||
| 				String gcode; | 				String gcode; | ||||||
| 				gcode += "const "; | 				gcode += "const "; | ||||||
|  | @ -559,8 +581,10 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 			//code for functions
 | 			//code for functions
 | ||||||
| 			for (int i = 0; i < pnode->functions.size(); i++) { | 			for (int i = 0; i < pnode->functions.size(); i++) { | ||||||
| 				SL::FunctionNode *fnode = pnode->functions[i].function; | 				SL::FunctionNode *fnode = pnode->functions[i].function; | ||||||
|  | 				function = fnode; | ||||||
| 				current_func_name = fnode->name; | 				current_func_name = fnode->name; | ||||||
| 				function_code[fnode->name] = _dump_node_code(fnode->body, p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); | 				function_code[fnode->name] = _dump_node_code(fnode->body, p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); | ||||||
|  | 				function = nullptr; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			//place functions in actual code
 | 			//place functions in actual code
 | ||||||
|  | @ -571,6 +595,8 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 			for (int i = 0; i < pnode->functions.size(); i++) { | 			for (int i = 0; i < pnode->functions.size(); i++) { | ||||||
| 				SL::FunctionNode *fnode = pnode->functions[i].function; | 				SL::FunctionNode *fnode = pnode->functions[i].function; | ||||||
| 
 | 
 | ||||||
|  | 				function = fnode; | ||||||
|  | 
 | ||||||
| 				current_func_name = fnode->name; | 				current_func_name = fnode->name; | ||||||
| 
 | 
 | ||||||
| 				if (fnode->name == vertex_name) { | 				if (fnode->name == vertex_name) { | ||||||
|  | @ -587,6 +613,8 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 					_dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment); | 					_dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment); | ||||||
| 					r_gen_code.light = function_code[light_name]; | 					r_gen_code.light = function_code[light_name]; | ||||||
| 				} | 				} | ||||||
|  | 
 | ||||||
|  | 				function = nullptr; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			//code+=dump_node_code(pnode->body,p_level);
 | 			//code+=dump_node_code(pnode->body,p_level);
 | ||||||
|  | @ -647,6 +675,19 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 		} break; | 		} break; | ||||||
| 		case SL::Node::TYPE_VARIABLE: { | 		case SL::Node::TYPE_VARIABLE: { | ||||||
| 			SL::VariableNode *vnode = (SL::VariableNode *)p_node; | 			SL::VariableNode *vnode = (SL::VariableNode *)p_node; | ||||||
|  | 			bool use_fragment_varying = false; | ||||||
|  | 
 | ||||||
|  | 			if (current_func_name != vertex_name) { | ||||||
|  | 				if (p_assigning) { | ||||||
|  | 					if (shader->varyings.has(vnode->name)) { | ||||||
|  | 						use_fragment_varying = true; | ||||||
|  | 					} | ||||||
|  | 				} else { | ||||||
|  | 					if (fragment_varyings.has(vnode->name)) { | ||||||
|  | 						use_fragment_varying = true; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			if (p_assigning && p_actions.write_flag_pointers.has(vnode->name)) { | 			if (p_assigning && p_actions.write_flag_pointers.has(vnode->name)) { | ||||||
| 				*p_actions.write_flag_pointers[vnode->name] = true; | 				*p_actions.write_flag_pointers[vnode->name] = true; | ||||||
|  | @ -668,6 +709,8 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 
 | 
 | ||||||
| 			if (p_default_actions.renames.has(vnode->name)) { | 			if (p_default_actions.renames.has(vnode->name)) { | ||||||
| 				code = p_default_actions.renames[vnode->name]; | 				code = p_default_actions.renames[vnode->name]; | ||||||
|  | 			} else if (use_fragment_varying) { | ||||||
|  | 				code = "frag_to_light." + _mkid(vnode->name); | ||||||
| 			} else { | 			} else { | ||||||
| 				code = _mkid(vnode->name); | 				code = _mkid(vnode->name); | ||||||
| 			} | 			} | ||||||
|  | @ -751,6 +794,23 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 		} break; | 		} break; | ||||||
| 		case SL::Node::TYPE_ARRAY: { | 		case SL::Node::TYPE_ARRAY: { | ||||||
| 			SL::ArrayNode *anode = (SL::ArrayNode *)p_node; | 			SL::ArrayNode *anode = (SL::ArrayNode *)p_node; | ||||||
|  | 			bool use_fragment_varying = false; | ||||||
|  | 
 | ||||||
|  | 			if (current_func_name != vertex_name) { | ||||||
|  | 				if (anode->assign_expression != nullptr) { | ||||||
|  | 					use_fragment_varying = true; | ||||||
|  | 				} else { | ||||||
|  | 					if (p_assigning) { | ||||||
|  | 						if (shader->varyings.has(anode->name)) { | ||||||
|  | 							use_fragment_varying = true; | ||||||
|  | 						} | ||||||
|  | 					} else { | ||||||
|  | 						if (fragment_varyings.has(anode->name)) { | ||||||
|  | 							use_fragment_varying = true; | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			if (p_assigning && p_actions.write_flag_pointers.has(anode->name)) { | 			if (p_assigning && p_actions.write_flag_pointers.has(anode->name)) { | ||||||
| 				*p_actions.write_flag_pointers[anode->name] = true; | 				*p_actions.write_flag_pointers[anode->name] = true; | ||||||
|  | @ -772,6 +832,8 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 
 | 
 | ||||||
| 			if (p_default_actions.renames.has(anode->name)) { | 			if (p_default_actions.renames.has(anode->name)) { | ||||||
| 				code = p_default_actions.renames[anode->name]; | 				code = p_default_actions.renames[anode->name]; | ||||||
|  | 			} else if (use_fragment_varying) { | ||||||
|  | 				code = "frag_to_light." + _mkid(anode->name); | ||||||
| 			} else { | 			} else { | ||||||
| 				code = _mkid(anode->name); | 				code = _mkid(anode->name); | ||||||
| 			} | 			} | ||||||
|  | @ -783,7 +845,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 				code += "["; | 				code += "["; | ||||||
| 				code += _dump_node_code(anode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); | 				code += _dump_node_code(anode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); | ||||||
| 				code += "]"; | 				code += "]"; | ||||||
| 			} else if (anode->assign_expression != NULL) { | 			} else if (anode->assign_expression != nullptr) { | ||||||
| 				code += "="; | 				code += "="; | ||||||
| 				code += _dump_node_code(anode->assign_expression, p_level, r_gen_code, p_actions, p_default_actions, true, false); | 				code += _dump_node_code(anode->assign_expression, p_level, r_gen_code, p_actions, p_default_actions, true, false); | ||||||
| 			} | 			} | ||||||
|  | @ -949,7 +1011,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener | ||||||
| 		case SL::Node::TYPE_MEMBER: { | 		case SL::Node::TYPE_MEMBER: { | ||||||
| 			SL::MemberNode *mnode = (SL::MemberNode *)p_node; | 			SL::MemberNode *mnode = (SL::MemberNode *)p_node; | ||||||
| 			code = _dump_node_code(mnode->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + "." + mnode->name; | 			code = _dump_node_code(mnode->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + "." + mnode->name; | ||||||
| 			if (mnode->index_expression != NULL) { | 			if (mnode->index_expression != nullptr) { | ||||||
| 				code += "["; | 				code += "["; | ||||||
| 				code += _dump_node_code(mnode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); | 				code += _dump_node_code(mnode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); | ||||||
| 				code += "]"; | 				code += "]"; | ||||||
|  | @ -988,8 +1050,11 @@ Error ShaderCompilerGLES3::compile(VS::ShaderMode p_mode, const String &p_code, | ||||||
| 	used_name_defines.clear(); | 	used_name_defines.clear(); | ||||||
| 	used_rmode_defines.clear(); | 	used_rmode_defines.clear(); | ||||||
| 	used_flag_pointers.clear(); | 	used_flag_pointers.clear(); | ||||||
|  | 	fragment_varyings.clear(); | ||||||
| 
 | 
 | ||||||
| 	_dump_node_code(parser.get_shader(), 1, r_gen_code, *p_actions, actions[p_mode], false); | 	shader = parser.get_shader(); | ||||||
|  | 	function = nullptr; | ||||||
|  | 	_dump_node_code(shader, 1, r_gen_code, *p_actions, actions[p_mode], false); | ||||||
| 
 | 
 | ||||||
| 	if (r_gen_code.uniform_total_size) { //uniforms used?
 | 	if (r_gen_code.uniform_total_size) { //uniforms used?
 | ||||||
| 		int md = sizeof(float) * 4; | 		int md = sizeof(float) * 4; | ||||||
|  |  | ||||||
|  | @ -75,9 +75,11 @@ private: | ||||||
| 		Map<StringName, String> usage_defines; | 		Map<StringName, String> usage_defines; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	void _dump_function_deps(ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added); | 	void _dump_function_deps(const ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map<StringName, String> &p_func_code, String &r_to_add, Set<StringName> &added); | ||||||
| 	String _dump_node_code(ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope = true); | 	String _dump_node_code(const ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope = true); | ||||||
| 
 | 
 | ||||||
|  | 	const ShaderLanguage::ShaderNode *shader; | ||||||
|  | 	const ShaderLanguage::FunctionNode *function; | ||||||
| 	StringName current_func_name; | 	StringName current_func_name; | ||||||
| 	StringName vertex_name; | 	StringName vertex_name; | ||||||
| 	StringName fragment_name; | 	StringName fragment_name; | ||||||
|  | @ -88,6 +90,7 @@ private: | ||||||
| 	Set<StringName> used_flag_pointers; | 	Set<StringName> used_flag_pointers; | ||||||
| 	Set<StringName> used_rmode_defines; | 	Set<StringName> used_rmode_defines; | ||||||
| 	Set<StringName> internal_functions; | 	Set<StringName> internal_functions; | ||||||
|  | 	Set<StringName> fragment_varyings; | ||||||
| 
 | 
 | ||||||
| 	DefaultIdentifierActions actions[VS::SHADER_MAX]; | 	DefaultIdentifierActions actions[VS::SHADER_MAX]; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2761,6 +2761,72 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const { | ||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message) { | ||||||
|  | 	if (current_function == String("light")) { | ||||||
|  | 		*r_message = RTR("Varying may not be assigned in the 'light' function."); | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 	switch (p_varying.stage) { | ||||||
|  | 		case ShaderNode::Varying::STAGE_UNKNOWN: // first assign
 | ||||||
|  | 			if (current_function == String("vertex")) { | ||||||
|  | 				p_varying.stage = ShaderNode::Varying::STAGE_VERTEX; | ||||||
|  | 			} else if (current_function == String("fragment")) { | ||||||
|  | 				p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		case ShaderNode::Varying::STAGE_VERTEX: | ||||||
|  | 			if (current_function == String("fragment")) { | ||||||
|  | 				*r_message = RTR("Varyings which assigned in 'vertex' function may not be reassigned in 'fragment' or 'light'."); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		case ShaderNode::Varying::STAGE_FRAGMENT: | ||||||
|  | 			if (current_function == String("vertex")) { | ||||||
|  | 				*r_message = RTR("Varyings which assigned in 'fragment' function may not be reassigned in 'vertex' or 'light'."); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, String *r_message) { | ||||||
|  | 	switch (p_varying.stage) { | ||||||
|  | 		case ShaderNode::Varying::STAGE_UNKNOWN: | ||||||
|  | 			*r_message = RTR("Varying must be assigned before using!"); | ||||||
|  | 			return false; | ||||||
|  | 		case ShaderNode::Varying::STAGE_VERTEX: | ||||||
|  | 			if (current_function == String("fragment")) { | ||||||
|  | 				p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT; | ||||||
|  | 			} else if (current_function == String("light")) { | ||||||
|  | 				p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		case ShaderNode::Varying::STAGE_FRAGMENT: | ||||||
|  | 			if (current_function == String("light")) { | ||||||
|  | 				p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT: | ||||||
|  | 			if (current_function == String("light")) { | ||||||
|  | 				*r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'"); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		case ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT: | ||||||
|  | 			if (current_function == String("fragment")) { | ||||||
|  | 				*r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'"); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message) { | bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message) { | ||||||
| 	if (p_node->type == Node::TYPE_OPERATOR) { | 	if (p_node->type == Node::TYPE_OPERATOR) { | ||||||
| 		OperatorNode *op = static_cast<OperatorNode *>(p_node); | 		OperatorNode *op = static_cast<OperatorNode *>(p_node); | ||||||
|  | @ -2793,13 +2859,6 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (shader->varyings.has(var->name) && current_function != String("vertex")) { |  | ||||||
| 			if (r_message) { |  | ||||||
| 				*r_message = RTR("Varyings can only be assigned in vertex function."); |  | ||||||
| 			} |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (shader->constants.has(var->name) || var->is_const) { | 		if (shader->constants.has(var->name) || var->is_const) { | ||||||
| 			if (r_message) { | 			if (r_message) { | ||||||
| 				*r_message = RTR("Constants cannot be modified."); | 				*r_message = RTR("Constants cannot be modified."); | ||||||
|  | @ -2820,13 +2879,6 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (shader->varyings.has(arr->name) && current_function != String("vertex")) { |  | ||||||
| 			if (r_message) { |  | ||||||
| 				*r_message = RTR("Varyings can only be assigned in vertex function."); |  | ||||||
| 			} |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -3419,6 +3471,23 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons | ||||||
| 						return nullptr; | 						return nullptr; | ||||||
| 					} | 					} | ||||||
| 					last_const = is_const; | 					last_const = is_const; | ||||||
|  | 					if (ident_type == IDENTIFIER_VARYING) { | ||||||
|  | 						TkPos prev_pos = _get_tkpos(); | ||||||
|  | 						Token next_token = _get_token(); | ||||||
|  | 						_set_tkpos(prev_pos); | ||||||
|  | 						String error; | ||||||
|  | 						if (next_token.type == TK_OP_ASSIGN) { | ||||||
|  | 							if (!_validate_varying_assign(shader->varyings[identifier], &error)) { | ||||||
|  | 								_set_error(error); | ||||||
|  | 								return nullptr; | ||||||
|  | 							} | ||||||
|  | 						} else { | ||||||
|  | 							if (!_validate_varying_using(shader->varyings[identifier], &error)) { | ||||||
|  | 								_set_error(error); | ||||||
|  | 								return nullptr; | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
| 
 | 
 | ||||||
| 					if (ident_type == IDENTIFIER_FUNCTION) { | 					if (ident_type == IDENTIFIER_FUNCTION) { | ||||||
| 						_set_error("Can't use function as identifier: " + String(identifier)); | 						_set_error("Can't use function as identifier: " + String(identifier)); | ||||||
|  | @ -5695,6 +5764,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct | ||||||
| 					return ERR_PARSE_ERROR; | 					return ERR_PARSE_ERROR; | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  | 				TkPos name_pos = _get_tkpos(); | ||||||
| 				name = tk.text; | 				name = tk.text; | ||||||
| 
 | 
 | ||||||
| 				if (_find_identifier(nullptr, Map<StringName, BuiltInInfo>(), name)) { | 				if (_find_identifier(nullptr, Map<StringName, BuiltInInfo>(), name)) { | ||||||
|  | @ -5867,11 +5937,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct | ||||||
| 						_set_error("Expected ';'"); | 						_set_error("Expected ';'"); | ||||||
| 						return ERR_PARSE_ERROR; | 						return ERR_PARSE_ERROR; | ||||||
| 					} | 					} | ||||||
| 				} else { | 				} else { // varying
 | ||||||
| 					ShaderNode::Varying varying; | 					ShaderNode::Varying varying; | ||||||
| 					varying.type = type; | 					varying.type = type; | ||||||
| 					varying.precision = precision; | 					varying.precision = precision; | ||||||
| 					varying.interpolation = interpolation; | 					varying.interpolation = interpolation; | ||||||
|  | 					varying.tkpos = name_pos; | ||||||
| 
 | 
 | ||||||
| 					tk = _get_token(); | 					tk = _get_token(); | ||||||
| 					if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) { | 					if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) { | ||||||
|  | @ -6238,6 +6309,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct | ||||||
| 		tk = _get_token(); | 		tk = _get_token(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	for (Map<StringName, ShaderNode::Varying>::Element *E = shader->varyings.front(); E; E = E->next()) { | ||||||
|  | 		if (E->get().stage == ShaderNode::Varying::STAGE_VERTEX || E->get().stage == ShaderNode::Varying::STAGE_FRAGMENT) { | ||||||
|  | 			_set_tkpos(E->get().tkpos); | ||||||
|  | 			_set_error(RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'")); | ||||||
|  | 			return ERR_PARSE_ERROR; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return OK; | 	return OK; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -41,6 +41,11 @@ | ||||||
| 
 | 
 | ||||||
| class ShaderLanguage { | class ShaderLanguage { | ||||||
| public: | public: | ||||||
|  | 	struct TkPos { | ||||||
|  | 		int char_idx; | ||||||
|  | 		int tk_line; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
| 	enum TokenType { | 	enum TokenType { | ||||||
| 		TK_EMPTY, | 		TK_EMPTY, | ||||||
| 		TK_IDENTIFIER, | 		TK_IDENTIFIER, | ||||||
|  | @ -580,12 +585,24 @@ public: | ||||||
| 		}; | 		}; | ||||||
| 
 | 
 | ||||||
| 		struct Varying { | 		struct Varying { | ||||||
|  | 			enum Stage { | ||||||
|  | 				STAGE_UNKNOWN, | ||||||
|  | 				STAGE_VERTEX, // transition stage to STAGE_VERTEX_TO_FRAGMENT or STAGE_VERTEX_TO_LIGHT, emits error if they are not used
 | ||||||
|  | 				STAGE_FRAGMENT, // transition stage to STAGE_FRAGMENT_TO_LIGHT, emits error if it's not used
 | ||||||
|  | 				STAGE_VERTEX_TO_FRAGMENT, | ||||||
|  | 				STAGE_VERTEX_TO_LIGHT, | ||||||
|  | 				STAGE_FRAGMENT_TO_LIGHT, | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			Stage stage; | ||||||
| 			DataType type; | 			DataType type; | ||||||
| 			DataInterpolation interpolation; | 			DataInterpolation interpolation; | ||||||
| 			DataPrecision precision; | 			DataPrecision precision; | ||||||
| 			int array_size; | 			int array_size; | ||||||
|  | 			TkPos tkpos; | ||||||
| 
 | 
 | ||||||
| 			Varying() : | 			Varying() : | ||||||
|  | 					stage(STAGE_UNKNOWN), | ||||||
| 					type(TYPE_VOID), | 					type(TYPE_VOID), | ||||||
| 					interpolation(INTERPOLATION_FLAT), | 					interpolation(INTERPOLATION_FLAT), | ||||||
| 					precision(PRECISION_DEFAULT), | 					precision(PRECISION_DEFAULT), | ||||||
|  | @ -734,11 +751,6 @@ private: | ||||||
| 	StringName current_function; | 	StringName current_function; | ||||||
| 	bool last_const = false; | 	bool last_const = false; | ||||||
| 
 | 
 | ||||||
| 	struct TkPos { |  | ||||||
| 		int char_idx; |  | ||||||
| 		int tk_line; |  | ||||||
| 	}; |  | ||||||
| 
 |  | ||||||
| 	TkPos _get_tkpos() { | 	TkPos _get_tkpos() { | ||||||
| 		TkPos tkp; | 		TkPos tkp; | ||||||
| 		tkp.char_idx = char_idx; | 		tkp.char_idx = char_idx; | ||||||
|  | @ -815,6 +827,8 @@ private: | ||||||
| 
 | 
 | ||||||
| 	bool _validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str); | 	bool _validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str); | ||||||
| 	bool _parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg = nullptr); | 	bool _parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg = nullptr); | ||||||
|  | 	bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message); | ||||||
|  | 	bool _validate_varying_using(ShaderNode::Varying &p_varying, String *r_message); | ||||||
| 
 | 
 | ||||||
| 	Node *_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types); | 	Node *_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types); | ||||||
| 	Node *_parse_array_constructor(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, DataType p_type, const StringName &p_struct_name, int p_array_size); | 	Node *_parse_array_constructor(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, DataType p_type, const StringName &p_struct_name, int p_array_size); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lyuma
						Lyuma