diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index daa4c53a1d9..15ff1f79b2e 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -210,7 +210,7 @@ static String get_constant_text(SL::DataType p_type, const Vector &p_func_code, StringBuilder &r_to_add, Set &r_added) { +void ShaderCompilerGLES2::_dump_function_deps(const SL::ShaderNode *p_node, const StringName &p_for_func, const Map &p_func_code, StringBuilder &r_to_add, Set &r_added) { int fidx = -1; 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; switch (p_node->type) { @@ -378,7 +378,14 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener // varyings + List> var_frag_to_light; + for (Map::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(E->key(), E->get())); + fragment_varyings.insert(E->key()); + continue; + } StringBuffer<> varying_code; varying_code += "varying "; @@ -399,6 +406,21 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener fragment_global += final_code; } + if (var_frag_to_light.size() > 0) { + String gcode = "\n\nstruct {\n"; + for (List>::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 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++) { SL::FunctionNode *fnode = snode->functions[i].function; + function = fnode; 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 = nullptr; } Set 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++) { SL::FunctionNode *fnode = snode->functions[i].function; + function = fnode; + current_func_name = fnode->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); r_gen_code.light = function_code[light_name]; } + + function = nullptr; } 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: { 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)) { *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)) { code += p_default_actions.renames[var_node->name]; + } else if (use_fragment_varying) { + code += "frag_to_light." + _mkid(var_node->name); } else { code += _mkid(var_node->name); } @@ -605,6 +648,23 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener } break; case SL::Node::TYPE_ARRAY: { 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)) { *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)) { code += p_default_actions.renames[arr_node->name]; + } else if (use_fragment_varying) { + code += "frag_to_light." + _mkid(arr_node->name); } else { 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 += "."; code += member_node->name; - if (member_node->index_expression != NULL) { + if (member_node->index_expression != nullptr) { code += "["; code += _dump_node_code(member_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += "]"; @@ -947,8 +1009,11 @@ Error ShaderCompilerGLES2::compile(VS::ShaderMode p_mode, const String &p_code, used_name_defines.clear(); used_rmode_defines.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; } diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h index 845f6cd613f..e5a1c880c96 100644 --- a/drivers/gles2/shader_compiler_gles2.h +++ b/drivers/gles2/shader_compiler_gles2.h @@ -73,9 +73,11 @@ private: Map usage_defines; }; - void _dump_function_deps(ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map &p_func_code, StringBuilder &r_to_add, Set &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); + void _dump_function_deps(const ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map &p_func_code, StringBuilder &r_to_add, Set &r_added); + 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 vertex_name; StringName fragment_name; @@ -86,6 +88,7 @@ private: Set used_flag_pointers; Set used_rmode_defines; Set internal_functions; + Set fragment_varyings; DefaultIdentifierActions actions[VS::SHADER_MAX]; diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 8794367bf30..0fad0e2f0de 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -331,7 +331,7 @@ static String get_constant_text(SL::DataType p_type, const Vector &p_func_code, String &r_to_add, Set &added) { +void ShaderCompilerGLES3::_dump_function_deps(const SL::ShaderNode *p_node, const StringName &p_for_func, const Map &p_func_code, String &r_to_add, Set &added) { int fidx = -1; 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; 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; } + List> var_frag_to_light; + for (Map::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(E->key(), E->get())); + fragment_varyings.insert(E->key()); + continue; + } String vcode; String interp_mode = _interpstr(E->get().interpolation); 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; } + if (var_frag_to_light.size() > 0) { + String gcode = "\n\nstruct {\n"; + for (List>::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++) { String gcode; gcode += "const "; @@ -559,8 +581,10 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener //code for functions for (int i = 0; i < pnode->functions.size(); i++) { SL::FunctionNode *fnode = pnode->functions[i].function; + function = fnode; 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 = nullptr; } //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++) { SL::FunctionNode *fnode = pnode->functions[i].function; + function = fnode; + current_func_name = fnode->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); r_gen_code.light = function_code[light_name]; } + + function = nullptr; } //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; case SL::Node::TYPE_VARIABLE: { 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)) { *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)) { code = p_default_actions.renames[vnode->name]; + } else if (use_fragment_varying) { + code = "frag_to_light." + _mkid(vnode->name); } else { code = _mkid(vnode->name); } @@ -751,6 +794,23 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener } break; case SL::Node::TYPE_ARRAY: { 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)) { *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)) { code = p_default_actions.renames[anode->name]; + } else if (use_fragment_varying) { + code = "frag_to_light." + _mkid(anode->name); } else { code = _mkid(anode->name); } @@ -783,7 +845,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener code += "["; code += _dump_node_code(anode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += "]"; - } else if (anode->assign_expression != NULL) { + } else if (anode->assign_expression != nullptr) { code += "="; 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: { 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; - if (mnode->index_expression != NULL) { + if (mnode->index_expression != nullptr) { code += "["; code += _dump_node_code(mnode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += "]"; @@ -988,8 +1050,11 @@ Error ShaderCompilerGLES3::compile(VS::ShaderMode p_mode, const String &p_code, used_name_defines.clear(); used_rmode_defines.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? int md = sizeof(float) * 4; diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h index 4bd5af40223..a97703a6955 100644 --- a/drivers/gles3/shader_compiler_gles3.h +++ b/drivers/gles3/shader_compiler_gles3.h @@ -75,9 +75,11 @@ private: Map usage_defines; }; - void _dump_function_deps(ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map &p_func_code, String &r_to_add, Set &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); + void _dump_function_deps(const ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map &p_func_code, String &r_to_add, Set &added); + 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 vertex_name; StringName fragment_name; @@ -88,6 +90,7 @@ private: Set used_flag_pointers; Set used_rmode_defines; Set internal_functions; + Set fragment_varyings; DefaultIdentifierActions actions[VS::SHADER_MAX]; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 3e5f341c5da..a042640a5df 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -2761,6 +2761,72 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const { 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 &p_builtin_types, String *r_message) { if (p_node->type == Node::TYPE_OPERATOR) { OperatorNode *op = static_cast(p_node); @@ -2793,13 +2859,6 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Mapvaryings.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 (r_message) { *r_message = RTR("Constants cannot be modified."); @@ -2820,13 +2879,6 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Mapvaryings.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; } @@ -3419,6 +3471,23 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons return nullptr; } 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) { _set_error("Can't use function as identifier: " + String(identifier)); @@ -5695,6 +5764,7 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct return ERR_PARSE_ERROR; } + TkPos name_pos = _get_tkpos(); name = tk.text; if (_find_identifier(nullptr, Map(), name)) { @@ -5867,11 +5937,12 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct _set_error("Expected ';'"); return ERR_PARSE_ERROR; } - } else { + } else { // varying ShaderNode::Varying varying; varying.type = type; varying.precision = precision; varying.interpolation = interpolation; + varying.tkpos = name_pos; tk = _get_token(); if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) { @@ -6238,6 +6309,14 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct tk = _get_token(); } + for (Map::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; } diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index 8936e523ef6..5167a26b0d7 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -41,6 +41,11 @@ class ShaderLanguage { public: + struct TkPos { + int char_idx; + int tk_line; + }; + enum TokenType { TK_EMPTY, TK_IDENTIFIER, @@ -580,12 +585,24 @@ public: }; 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; DataInterpolation interpolation; DataPrecision precision; int array_size; + TkPos tkpos; Varying() : + stage(STAGE_UNKNOWN), type(TYPE_VOID), interpolation(INTERPOLATION_FLAT), precision(PRECISION_DEFAULT), @@ -734,11 +751,6 @@ private: StringName current_function; bool last_const = false; - struct TkPos { - int char_idx; - int tk_line; - }; - TkPos _get_tkpos() { TkPos tkp; 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 _parse_function_arguments(BlockNode *p_block, const Map &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 &p_builtin_types); Node *_parse_array_constructor(BlockNode *p_block, const Map &p_builtin_types, DataType p_type, const StringName &p_struct_name, int p_array_size);