|
@@ -2037,6 +2037,12 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
|
|
|
|
|
|
};
|
|
|
|
|
|
+const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[] = {
|
|
|
+ //constructors
|
|
|
+ { "modf", 1 },
|
|
|
+ { NULL, 0 }
|
|
|
+};
|
|
|
+
|
|
|
bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p_func, DataType *r_ret_type) {
|
|
|
|
|
|
ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, NULL);
|
|
@@ -2080,6 +2086,41 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, OperatorNode *p
|
|
|
|
|
|
if (!fail) {
|
|
|
|
|
|
+ //make sure its not an out argument used in the wrong way
|
|
|
+ int outarg_idx = 0;
|
|
|
+ while (builtin_func_out_args[outarg_idx].name) {
|
|
|
+
|
|
|
+ if (String(name) == builtin_func_out_args[outarg_idx].name) {
|
|
|
+ int arg_idx = builtin_func_out_args[outarg_idx].argument;
|
|
|
+
|
|
|
+ if (arg_idx < argcount) {
|
|
|
+
|
|
|
+ if (p_func->arguments[arg_idx + 1]->type != Node::TYPE_VARIABLE) {
|
|
|
+ _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ StringName var_name = static_cast<const VariableNode *>(p_func->arguments[arg_idx + 1])->name;
|
|
|
+
|
|
|
+ const BlockNode *b = p_block;
|
|
|
+ bool valid = false;
|
|
|
+ while (b) {
|
|
|
+ if (b->variables.has(var_name)) {
|
|
|
+ valid = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ b = b->parent_block;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!valid) {
|
|
|
+ _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' can only take a local variable");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ outarg_idx++;
|
|
|
+ }
|
|
|
+
|
|
|
if (r_ret_type)
|
|
|
*r_ret_type = builtin_func_defs[idx].rettype;
|
|
|
|