Backport dd0874e "Allow passing varying from fragment to light shader function" to 3.4

This commit is contained in:
Lyuma 2021-04-21 17:55:27 -07:00
parent 0c028ad96e
commit fba6b62054
6 changed files with 262 additions and 33 deletions

View file

@ -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<StringName, BuiltInInfo> &p_builtin_types, String *r_message) {
if (p_node->type == Node::TYPE_OPERATOR) {
OperatorNode *op = static_cast<OperatorNode *>(p_node);
@ -2793,13 +2859,6 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
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 (r_message) {
*r_message = RTR("Constants cannot be modified.");
@ -2820,13 +2879,6 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
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;
}
@ -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<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
TkPos name_pos = _get_tkpos();
name = tk.text;
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 ';'");
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<StringName, FunctionInfo> &p_funct
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;
}