diff options
Diffstat (limited to 'servers/visual/shader_language.cpp')
-rw-r--r-- | servers/visual/shader_language.cpp | 157 |
1 files changed, 146 insertions, 11 deletions
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 639946916d..42b9f19d9d 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -132,6 +132,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = { "TYPE_SAMPLERCUBE", "INTERPOLATION_FLAT", "INTERPOLATION_SMOOTH", + "CONST", "PRECISION_LOW", "PRECISION_MID", "PRECISION_HIGH", @@ -271,6 +272,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_TYPE_SAMPLERCUBE, "samplerCube" }, { TK_INTERPOLATION_FLAT, "flat" }, { TK_INTERPOLATION_SMOOTH, "smooth" }, + { TK_CONST, "const" }, { TK_PRECISION_LOW, "lowp" }, { TK_PRECISION_MID, "mediump" }, { TK_PRECISION_HIGH, "highp" }, @@ -616,7 +618,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { else tk.type = TK_INT_CONSTANT; - tk.constant = str.to_double(); //wont work with hex + tk.constant = str.to_double(); //won't work with hex tk.line = tk_line; return tk; @@ -920,6 +922,16 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<String return true; } + if (shader->constants.has(p_identifier)) { + if (r_data_type) { + *r_data_type = shader->constants[p_identifier].type; + } + if (r_type) { + *r_type = IDENTIFIER_CONSTANT; + } + return true; + } + for (int i = 0; i < shader->functions.size(); i++) { if (!shader->functions[i].callable) @@ -2075,7 +2087,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p for (int i = 0; i < argcount; i++) { if (get_scalar_type(args[i]) == args[i] && p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[i + 1]), builtin_func_defs[idx].args[i])) { - //all good + //all good, but needs implicit conversion later } else if (args[i] != builtin_func_defs[idx].args[i]) { fail = true; break; @@ -2121,6 +2133,24 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p outarg_idx++; } + //implicitly convert values if possible + for (int i = 0; i < argcount; i++) { + + if (get_scalar_type(args[i]) != args[i] || args[i] == builtin_func_defs[idx].args[i] || p_func->arguments[i + 1]->type != Node::TYPE_CONSTANT) { + //can't do implicit conversion here + continue; + } + + //this is an implicit conversion + ConstantNode *constant = static_cast<ConstantNode *>(p_func->arguments[i + 1]); + ConstantNode *conversion = alloc_node<ConstantNode>(); + + conversion->datatype = builtin_func_defs[idx].args[i]; + conversion->values.resize(1); + + convert_constant(constant, builtin_func_defs[idx].args[i], conversion->values.ptrw()); + p_func->arguments.write[i + 1] = conversion; + } if (r_ret_type) *r_ret_type = builtin_func_defs[idx].rettype; @@ -2187,7 +2217,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p for (int j = 0; j < args.size(); j++) { if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) { - //all good + //all good, but it needs implicit conversion later } else if (args[j] != pfunc->arguments[j].type) { fail = true; break; @@ -2195,6 +2225,26 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p } if (!fail) { + + //implicitly convert values if possible + for (int k = 0; k < args.size(); k++) { + + if (get_scalar_type(args[k]) != args[k] || args[k] == pfunc->arguments[k].type || p_func->arguments[k + 1]->type != Node::TYPE_CONSTANT) { + //can't do implicit conversion here + continue; + } + + //this is an implicit conversion + ConstantNode *constant = static_cast<ConstantNode *>(p_func->arguments[k + 1]); + ConstantNode *conversion = alloc_node<ConstantNode>(); + + conversion->datatype = pfunc->arguments[k].type; + conversion->values.resize(1); + + convert_constant(constant, pfunc->arguments[k].type, conversion->values.ptrw()); + p_func->arguments.write[k + 1] = conversion; + } + if (r_ret_type) *r_ret_type = pfunc->return_type; return true; @@ -2661,6 +2711,12 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI return false; } + if (shader->constants.has(var->name)) { + if (r_message) + *r_message = RTR("Constants cannot be modified."); + return false; + } + if (!(p_builtin_types.has(var->name) && p_builtin_types[var->name].constant)) { return true; } @@ -2930,6 +2986,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons member_type = DataType(dt - 1); } else if (l == 2) { member_type = dt; + } else if (l == 3) { + member_type = DataType(dt + 1); + } else if (l == 4) { + member_type = DataType(dt + 2); } else { ok = false; break; @@ -2963,6 +3023,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons member_type = DataType(dt - 1); } else if (l == 3) { member_type = dt; + } else if (l == 4) { + member_type = DataType(dt + 1); } else { ok = false; break; @@ -3582,7 +3644,8 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha case TYPE_FLOAT: { nv.real = -cn->values[i].real; } break; - default: {} + default: { + } } values.push_back(nv); @@ -3948,7 +4011,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui } else { - //nothng else, so expression + //nothing else, so expression _set_tkpos(pos); //rollback Node *expr = _parse_and_reduce_expression(p_block, p_builtin_types); if (!expr) @@ -4277,24 +4340,30 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } break; default: { - //function + //function or constant variable + bool is_constant = false; DataPrecision precision = PRECISION_DEFAULT; DataType type; StringName name; + if (tk.type == TK_CONST) { + is_constant = true; + tk = _get_token(); + } + if (is_token_precision(tk.type)) { precision = get_token_precision(tk.type); tk = _get_token(); } if (!is_token_datatype(tk.type)) { - _set_error("Expected function, uniform or varying "); + _set_error("Expected constant, function, uniform or varying "); return ERR_PARSE_ERROR; } if (!is_token_variable_datatype(tk.type)) { - _set_error("Invalid data type for function return (samplers not allowed)"); + _set_error("Invalid data type for constants or function return (samplers not allowed)"); return ERR_PARSE_ERROR; } @@ -4314,8 +4383,73 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (tk.type != TK_PARENTHESIS_OPEN) { - _set_error("Expected '(' after identifier"); - return ERR_PARSE_ERROR; + if (type == TYPE_VOID) { + _set_error("Expected '(' after function identifier"); + return ERR_PARSE_ERROR; + } + + //variable + + while (true) { + ShaderNode::Constant constant; + constant.type = type; + constant.precision = precision; + constant.initializer = NULL; + + if (tk.type == TK_OP_ASSIGN) { + + if (!is_constant) { + _set_error("Expected 'const' keyword before constant definition"); + return ERR_PARSE_ERROR; + } + + //variable created with assignment! must parse an expression + Node *expr = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>()); + if (!expr) + return ERR_PARSE_ERROR; + + if (expr->type != Node::TYPE_CONSTANT) { + _set_error("Expected constant expression after '='"); + return ERR_PARSE_ERROR; + } + + constant.initializer = static_cast<ConstantNode *>(expr); + + if (type != expr->get_datatype()) { + _set_error("Invalid assignment of '" + get_datatype_name(expr->get_datatype()) + "' to '" + get_datatype_name(type) + "'"); + return ERR_PARSE_ERROR; + } + tk = _get_token(); + } else { + _set_error("Expected initialization of constant"); + return ERR_PARSE_ERROR; + } + + shader->constants[name] = constant; + if (tk.type == TK_COMMA) { + tk = _get_token(); + if (tk.type != TK_IDENTIFIER) { + _set_error("Expected identifier after type"); + return ERR_PARSE_ERROR; + } + + name = tk.text; + if (_find_identifier(NULL, Map<StringName, BuiltInInfo>(), name)) { + _set_error("Redefinition of '" + String(name) + "'"); + return ERR_PARSE_ERROR; + } + + tk = _get_token(); + + } else if (tk.type == TK_SEMICOLON) { + break; + } else { + _set_error("Expected ',' or ';' after constant"); + return ERR_PARSE_ERROR; + } + } + + break; } Map<StringName, BuiltInInfo> builtin_types; @@ -4784,7 +4918,8 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct case TYPE_MAT2: limit = 2; break; case TYPE_MAT3: limit = 3; break; case TYPE_MAT4: limit = 4; break; - default: {} + default: { + } } for (int i = 0; i < limit; i++) { |