소스 검색

Changed Vector3.snap from fmod to stepify, which makes more sense, fixes #6399

Juan Linietsky 9 년 전
부모
커밋
23ababdcd5

+ 3 - 7
core/math/vector3.cpp

@@ -65,13 +65,9 @@ int Vector3::max_axis() const {
 
 void Vector3::snap(float p_val) {
 
-	x+=p_val/2.0;
-	x-=Math::fmod(x,p_val);
-	y+=p_val/2.0;
-	y-=Math::fmod(y,p_val);
-	z+=p_val/2.0;
-	z-=Math::fmod(z,p_val);
-
+	x=Math::stepify(x,p_val);
+	y=Math::stepify(y,p_val);
+	z=Math::stepify(z,p_val);
 }
 Vector3 Vector3::snapped(float p_val) const {
 

+ 2 - 1
modules/visual_script/visual_script.cpp

@@ -1417,7 +1417,8 @@ bool VisualScriptInstance::get(const StringName& p_name, Variant &r_ret) const {
 	if (!E)
 		return false;
 
-	return E->get();
+	r_ret=E->get();
+	return true;
 }
 void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const{
 

+ 405 - 377
modules/visual_script/visual_script_builtin_funcs.cpp

@@ -65,6 +65,21 @@ const char* VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX
 	"bytes2var",
 };
 
+VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::find_function(const String& p_string) {
+
+	for(int i=0;i<FUNC_MAX;i++) {
+		if (p_string==func_name[i])
+			return BuiltinFunc(i);
+	}
+
+	return FUNC_MAX;
+}
+
+String VisualScriptBuiltinFunc::get_func_name(BuiltinFunc p_func) {
+
+	ERR_FAIL_INDEX_V(p_func,FUNC_MAX,String());
+	return func_name[p_func];
+}
 
 
 int VisualScriptBuiltinFunc::get_output_sequence_port_count() const {
@@ -88,10 +103,10 @@ bool VisualScriptBuiltinFunc::has_input_sequence_port() const{
 
 }
 
-int VisualScriptBuiltinFunc::get_input_value_port_count() const{
+int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) {
 
 
-	switch(func) {
+	switch(p_func) {
 
 		case MATH_RANDOMIZE:
 		case MATH_RAND:
@@ -157,6 +172,11 @@ int VisualScriptBuiltinFunc::get_input_value_port_count() const{
 	}
 	return 0;
 }
+
+int VisualScriptBuiltinFunc::get_input_value_port_count() const{
+
+	return get_func_argument_count(func);
+}
 int VisualScriptBuiltinFunc::get_output_value_port_count() const{
 
 	switch(func) {
@@ -560,118 +580,124 @@ VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::get_func() {
 		r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\
 		r_error.argument=m_arg;\
 		r_error.expected=Variant::REAL;\
-		return 0;\
+		return;\
 	}
 
-class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance {
-public:
 
-	VisualScriptBuiltinFunc *node;
-	VisualScriptInstance *instance;
+void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func,const Variant** p_inputs,Variant* r_return,Variant::CallError& r_error,String& r_error_str) {
 
-	VisualScriptBuiltinFunc::BuiltinFunc func;
+	switch(p_func) {
+		case VisualScriptBuiltinFunc::MATH_SIN: {
 
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::sin(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_COS: {
 
-	//virtual int get_working_memory_size() const { return 0; }
-	//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
-	//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::cos(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_TAN: {
 
-	virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::tan(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_SINH: {
 
-		switch(func) {
-			case VisualScriptBuiltinFunc::MATH_SIN: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::sinh(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_COSH: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::sin(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_COS: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::cosh(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_TANH: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::cos(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_TAN: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::tanh(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_ASIN: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::tan(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_SINH: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::asin(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_ACOS: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::sinh(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_COSH: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::acos(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_ATAN: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::cosh(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_TANH: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::atan(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_ATAN2: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::tanh(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_ASIN: {
+			VALIDATE_ARG_NUM(0);
+			VALIDATE_ARG_NUM(1);
+			*r_return=Math::atan2(*p_inputs[0],*p_inputs[1]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_SQRT: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::asin(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_ACOS: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::sqrt(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_FMOD: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::acos(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_ATAN: {
+			VALIDATE_ARG_NUM(0);
+			VALIDATE_ARG_NUM(1);
+			*r_return=Math::fmod(*p_inputs[0],*p_inputs[1]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_FPOSMOD: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::atan(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_ATAN2: {
+			VALIDATE_ARG_NUM(0);
+			VALIDATE_ARG_NUM(1);
+			*r_return=Math::fposmod(*p_inputs[0],*p_inputs[1]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_FLOOR: {
 
-				VALIDATE_ARG_NUM(0);
-				VALIDATE_ARG_NUM(1);
-				*p_outputs[0]=Math::atan2(*p_inputs[0],*p_inputs[1]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_SQRT: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::floor(*p_inputs[0]);
+		  } break;
+		case VisualScriptBuiltinFunc::MATH_CEIL: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::sqrt(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_FMOD: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::ceil(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_ROUND: {
 
-				VALIDATE_ARG_NUM(0);
-				VALIDATE_ARG_NUM(1);
-				*p_outputs[0]=Math::fmod(*p_inputs[0],*p_inputs[1]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_FPOSMOD: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::round(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_ABS: {
 
-				VALIDATE_ARG_NUM(0);
-				VALIDATE_ARG_NUM(1);
-				*p_outputs[0]=Math::fposmod(*p_inputs[0],*p_inputs[1]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_FLOOR: {
+			if (p_inputs[0]->get_type()==Variant::INT) {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::floor(*p_inputs[0]);
-			  } break;
-			case VisualScriptBuiltinFunc::MATH_CEIL: {
+				int64_t i = *p_inputs[0];
+				*r_return=ABS(i);
+			} else if (p_inputs[0]->get_type()==Variant::REAL) {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::ceil(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_ROUND: {
+				real_t r = *p_inputs[0];
+				*r_return=Math::abs(r);
+			} else {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::round(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_ABS: {
+				r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+				r_error.argument=0;
+				r_error.expected=Variant::REAL;
+
+			}
+		} break;
+		case VisualScriptBuiltinFunc::MATH_SIGN: {
 
 				if (p_inputs[0]->get_type()==Variant::INT) {
 
 					int64_t i = *p_inputs[0];
-					*p_outputs[0]=ABS(i);
+					*r_return= i < 0 ? -1 : ( i > 0 ? +1 : 0);
 				} else if (p_inputs[0]->get_type()==Variant::REAL) {
 
 					real_t r = *p_inputs[0];
-					*p_outputs[0]=Math::abs(r);
+					*r_return= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0);
 				} else {
 
 					r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
@@ -679,410 +705,412 @@ public:
 					r_error.expected=Variant::REAL;
 
 				}
-			} break;
-			case VisualScriptBuiltinFunc::MATH_SIGN: {
+		} break;
+		case VisualScriptBuiltinFunc::MATH_POW: {
 
-					if (p_inputs[0]->get_type()==Variant::INT) {
+			VALIDATE_ARG_NUM(0);
+			VALIDATE_ARG_NUM(1);
+			*r_return=Math::pow(*p_inputs[0],*p_inputs[1]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_LOG: {
 
-						int64_t i = *p_inputs[0];
-						*p_outputs[0]= i < 0 ? -1 : ( i > 0 ? +1 : 0);
-					} else if (p_inputs[0]->get_type()==Variant::REAL) {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::log(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_EXP: {
 
-						real_t r = *p_inputs[0];
-						*p_outputs[0]= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0);
-					} else {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::exp(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_ISNAN: {
 
-						r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
-						r_error.argument=0;
-						r_error.expected=Variant::REAL;
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::is_nan(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_ISINF: {
 
-					}
-			} break;
-			case VisualScriptBuiltinFunc::MATH_POW: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::is_inf(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_EASE: {
 
-				VALIDATE_ARG_NUM(0);
-				VALIDATE_ARG_NUM(1);
-				*p_outputs[0]=Math::pow(*p_inputs[0],*p_inputs[1]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_LOG: {
+			VALIDATE_ARG_NUM(0);
+			VALIDATE_ARG_NUM(1);
+			*r_return=Math::ease(*p_inputs[0],*p_inputs[1]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_DECIMALS: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::log(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_EXP: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::step_decimals(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_STEPIFY: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::exp(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_ISNAN: {
+			VALIDATE_ARG_NUM(0);
+			VALIDATE_ARG_NUM(1);
+			*r_return=Math::stepify(*p_inputs[0],*p_inputs[1]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_LERP: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::is_nan(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_ISINF: {
+			VALIDATE_ARG_NUM(0);
+			VALIDATE_ARG_NUM(1);
+			VALIDATE_ARG_NUM(2);
+			*r_return=Math::lerp(*p_inputs[0],*p_inputs[1],*p_inputs[2]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_DECTIME: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::is_inf(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_EASE: {
+			VALIDATE_ARG_NUM(0);
+			VALIDATE_ARG_NUM(1);
+			VALIDATE_ARG_NUM(2);
+			*r_return=Math::dectime(*p_inputs[0],*p_inputs[1],*p_inputs[2]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_RANDOMIZE: {
+			Math::randomize();
 
-				VALIDATE_ARG_NUM(0);
-				VALIDATE_ARG_NUM(1);
-				*p_outputs[0]=Math::ease(*p_inputs[0],*p_inputs[1]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_DECIMALS: {
+		} break;
+		case VisualScriptBuiltinFunc::MATH_RAND: {
+			*r_return=Math::rand();
+		} break;
+		case VisualScriptBuiltinFunc::MATH_RANDF: {
+			*r_return=Math::randf();
+		} break;
+		case VisualScriptBuiltinFunc::MATH_RANDOM: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::step_decimals(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_STEPIFY: {
+			VALIDATE_ARG_NUM(0);
+			VALIDATE_ARG_NUM(1);
+			*r_return=Math::random(*p_inputs[0],*p_inputs[1]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_SEED: {
 
-				VALIDATE_ARG_NUM(0);
-				VALIDATE_ARG_NUM(1);
-				*p_outputs[0]=Math::stepify(*p_inputs[0],*p_inputs[1]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_LERP: {
+			VALIDATE_ARG_NUM(0);
+			uint32_t seed=*p_inputs[0];
+			Math::seed(seed);
 
-				VALIDATE_ARG_NUM(0);
-				VALIDATE_ARG_NUM(1);
-				VALIDATE_ARG_NUM(2);
-				*p_outputs[0]=Math::lerp(*p_inputs[0],*p_inputs[1],*p_inputs[2]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_DECTIME: {
+		} break;
+		case VisualScriptBuiltinFunc::MATH_RANDSEED: {
 
-				VALIDATE_ARG_NUM(0);
-				VALIDATE_ARG_NUM(1);
-				VALIDATE_ARG_NUM(2);
-				*p_outputs[0]=Math::dectime(*p_inputs[0],*p_inputs[1],*p_inputs[2]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_RANDOMIZE: {
-				Math::randomize();
-
-			} break;
-			case VisualScriptBuiltinFunc::MATH_RAND: {
-				*p_outputs[0]=Math::rand();
-			} break;
-			case VisualScriptBuiltinFunc::MATH_RANDF: {
-				*p_outputs[0]=Math::randf();
-			} break;
-			case VisualScriptBuiltinFunc::MATH_RANDOM: {
+			VALIDATE_ARG_NUM(0);
+			uint32_t seed=*p_inputs[0];
+			int ret = Math::rand_from_seed(&seed);
+			Array reta;
+			reta.push_back(ret);
+			reta.push_back(seed);
+			*r_return=reta;
 
-				VALIDATE_ARG_NUM(0);
-				VALIDATE_ARG_NUM(1);
-				*p_outputs[0]=Math::random(*p_inputs[0],*p_inputs[1]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_SEED: {
+		} break;
+		case VisualScriptBuiltinFunc::MATH_DEG2RAD: {
 
-				VALIDATE_ARG_NUM(0);
-				uint32_t seed=*p_inputs[0];
-				Math::seed(seed);
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::deg2rad(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_RAD2DEG: {
 
-			} break;
-			case VisualScriptBuiltinFunc::MATH_RANDSEED: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::rad2deg(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_LINEAR2DB: {
 
-				VALIDATE_ARG_NUM(0);
-				uint32_t seed=*p_inputs[0];
-				int ret = Math::rand_from_seed(&seed);
-				Array reta;
-				reta.push_back(ret);
-				reta.push_back(seed);
-				*p_outputs[0]=reta;
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::linear2db(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::MATH_DB2LINEAR: {
 
-			} break;
-			case VisualScriptBuiltinFunc::MATH_DEG2RAD: {
+			VALIDATE_ARG_NUM(0);
+			*r_return=Math::db2linear(*p_inputs[0]);
+		} break;
+		case VisualScriptBuiltinFunc::LOGIC_MAX: {
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::deg2rad(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_RAD2DEG: {
+			if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) {
 
+				int64_t a = *p_inputs[0];
+				int64_t b = *p_inputs[1];
+				*r_return=MAX(a,b);
+			} else {
 				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::rad2deg(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_LINEAR2DB: {
+				VALIDATE_ARG_NUM(1);
 
-				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::linear2db(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::MATH_DB2LINEAR: {
+				real_t a = *p_inputs[0];
+				real_t b = *p_inputs[1];
+
+				*r_return=MAX(a,b);
+			}
 
+		} break;
+		case VisualScriptBuiltinFunc::LOGIC_MIN: {
+
+			if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) {
+
+				int64_t a = *p_inputs[0];
+				int64_t b = *p_inputs[1];
+				*r_return=MIN(a,b);
+			} else {
 				VALIDATE_ARG_NUM(0);
-				*p_outputs[0]=Math::db2linear(*p_inputs[0]);
-			} break;
-			case VisualScriptBuiltinFunc::LOGIC_MAX: {
+				VALIDATE_ARG_NUM(1);
 
-				if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) {
+				real_t a = *p_inputs[0];
+				real_t b = *p_inputs[1];
 
-					int64_t a = *p_inputs[0];
-					int64_t b = *p_inputs[1];
-					*p_outputs[0]=MAX(a,b);
-				} else {
-					VALIDATE_ARG_NUM(0);
-					VALIDATE_ARG_NUM(1);
+				*r_return=MIN(a,b);
+			}
+		} break;
+		case VisualScriptBuiltinFunc::LOGIC_CLAMP: {
 
-					real_t a = *p_inputs[0];
-					real_t b = *p_inputs[1];
+			if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT && p_inputs[2]->get_type()==Variant::INT) {
 
-					*p_outputs[0]=MAX(a,b);
-				}
+				int64_t a = *p_inputs[0];
+				int64_t b = *p_inputs[1];
+				int64_t c = *p_inputs[2];
+				*r_return=CLAMP(a,b,c);
+			} else {
+				VALIDATE_ARG_NUM(0);
+				VALIDATE_ARG_NUM(1);
+				VALIDATE_ARG_NUM(2);
 
-			} break;
-			case VisualScriptBuiltinFunc::LOGIC_MIN: {
+				real_t a = *p_inputs[0];
+				real_t b = *p_inputs[1];
+				real_t c = *p_inputs[2];
 
-				if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT) {
+				*r_return=CLAMP(a,b,c);
+			}
+		} break;
+		case VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2: {
 
-					int64_t a = *p_inputs[0];
-					int64_t b = *p_inputs[1];
-					*p_outputs[0]=MIN(a,b);
-				} else {
-					VALIDATE_ARG_NUM(0);
-					VALIDATE_ARG_NUM(1);
+			VALIDATE_ARG_NUM(0);
+			int64_t num = *p_inputs[0];
+			*r_return = nearest_power_of_2(num);
+		} break;
+		case VisualScriptBuiltinFunc::OBJ_WEAKREF: {
 
-					real_t a = *p_inputs[0];
-					real_t b = *p_inputs[1];
+			if (p_inputs[0]->get_type()!=Variant::OBJECT) {
 
-					*p_outputs[0]=MIN(a,b);
-				}
-			} break;
-			case VisualScriptBuiltinFunc::LOGIC_CLAMP: {
+				r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+				r_error.argument=0;
+				r_error.expected=Variant::OBJECT;
 
-				if (p_inputs[0]->get_type()==Variant::INT && p_inputs[1]->get_type()==Variant::INT && p_inputs[2]->get_type()==Variant::INT) {
+				return;
 
-					int64_t a = *p_inputs[0];
-					int64_t b = *p_inputs[1];
-					int64_t c = *p_inputs[2];
-					*p_outputs[0]=CLAMP(a,b,c);
-				} else {
-					VALIDATE_ARG_NUM(0);
-					VALIDATE_ARG_NUM(1);
-					VALIDATE_ARG_NUM(2);
+			}
 
-					real_t a = *p_inputs[0];
-					real_t b = *p_inputs[1];
-					real_t c = *p_inputs[2];
+			if (p_inputs[0]->is_ref()) {
 
-					*p_outputs[0]=CLAMP(a,b,c);
+				REF r = *p_inputs[0];
+				if (!r.is_valid()) {
+
+					return;
 				}
-			} break;
-			case VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2: {
 
-				VALIDATE_ARG_NUM(0);
-				int64_t num = *p_inputs[0];
-				*p_outputs[0] = nearest_power_of_2(num);
-			} break;
-			case VisualScriptBuiltinFunc::OBJ_WEAKREF: {
+				Ref<WeakRef> wref = memnew( WeakRef );
+				wref->set_ref(r);
+				*r_return=wref;
+			} else {
+				Object *obj = *p_inputs[0];
+				if (!obj) {
 
-				if (p_inputs[0]->get_type()!=Variant::OBJECT) {
+					return;
+				}
+				Ref<WeakRef> wref = memnew( WeakRef );
+				wref->set_obj(obj);
+				*r_return=wref;
+			}
 
-					r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
-					r_error.argument=0;
-					r_error.expected=Variant::OBJECT;
 
-					return 0;
 
-				}
 
-				if (p_inputs[0]->is_ref()) {
+		} break;
+		case VisualScriptBuiltinFunc::FUNC_FUNCREF: {
 
-					REF r = *p_inputs[0];
-					if (!r.is_valid()) {
+			if (p_inputs[0]->get_type()!=Variant::OBJECT) {
 
-						return 0;
-					}
+				r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+				r_error.argument=0;
+				r_error.expected=Variant::OBJECT;
 
-					Ref<WeakRef> wref = memnew( WeakRef );
-					wref->set_ref(r);
-					*p_outputs[0]=wref;
-				} else {
-					Object *obj = *p_inputs[0];
-					if (!obj) {
-
-						return 0;
-					}
-					Ref<WeakRef> wref = memnew( WeakRef );
-					wref->set_obj(obj);
-					*p_outputs[0]=wref;
-				}
+				return;
 
+			}
+			if (p_inputs[1]->get_type()!=Variant::STRING && p_inputs[1]->get_type()!=Variant::NODE_PATH) {
 
+				r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+				r_error.argument=1;
+				r_error.expected=Variant::STRING;
 
+				return;
 
-			} break;
-			case VisualScriptBuiltinFunc::FUNC_FUNCREF: {
+			}
 
-				if (p_inputs[0]->get_type()!=Variant::OBJECT) {
+			Ref<FuncRef> fr = memnew( FuncRef);
 
-					r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
-					r_error.argument=0;
-					r_error.expected=Variant::OBJECT;
+			fr->set_instance(*p_inputs[0]);
+			fr->set_function(*p_inputs[1]);
 
-					return 0;
+			*r_return=fr;
 
-				}
-				if (p_inputs[1]->get_type()!=Variant::STRING && p_inputs[1]->get_type()!=Variant::NODE_PATH) {
+		} break;
+		case VisualScriptBuiltinFunc::TYPE_CONVERT: {
 
-					r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
-					r_error.argument=1;
-					r_error.expected=Variant::STRING;
+			VALIDATE_ARG_NUM(1);
+			int type=*p_inputs[1];
+			if (type<0 || type>=Variant::VARIANT_MAX) {
 
-					return 0;
+				r_error_str=RTR("Invalid type argument to convert(), use TYPE_* constants.");
+				r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+				r_error.argument=0;
+				r_error.expected=Variant::INT;
+				return;
 
-				}
+			} else {
 
-				Ref<FuncRef> fr = memnew( FuncRef);
 
-				fr->set_instance(*p_inputs[0]);
-				fr->set_function(*p_inputs[1]);
+				*r_return=Variant::construct(Variant::Type(type),p_inputs,1,r_error);
+			}
+		} break;
+		case VisualScriptBuiltinFunc::TYPE_OF: {
 
-				*p_outputs[0]=fr;
 
-			} break;
-			case VisualScriptBuiltinFunc::TYPE_CONVERT: {
+			*r_return = p_inputs[0]->get_type();
 
-				VALIDATE_ARG_NUM(1);
-				int type=*p_inputs[1];
-				if (type<0 || type>=Variant::VARIANT_MAX) {
+		} break;
+		case VisualScriptBuiltinFunc::TYPE_EXISTS: {
 
-					*p_outputs[0]=RTR("Invalid type argument to convert(), use TYPE_* constants.");
-					r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
-					r_error.argument=0;
-					r_error.expected=Variant::INT;
-					return 0;
 
-				} else {
+			*r_return = ObjectTypeDB::type_exists(*p_inputs[0]);
 
+		} break;
+		case VisualScriptBuiltinFunc::TEXT_STR: {
 
-					*p_outputs[0]=Variant::construct(Variant::Type(type),p_inputs,1,r_error);
-				}
-			} break;
-			case VisualScriptBuiltinFunc::TYPE_OF: {
+			String str = *p_inputs[0];
+
+			*r_return=str;
 
+		} break;
+		case VisualScriptBuiltinFunc::TEXT_PRINT: {
 
-				*p_outputs[0] = p_inputs[0]->get_type();
+			String str = *p_inputs[0];
+			print_line(str);
 
-			} break;
-			case VisualScriptBuiltinFunc::TYPE_EXISTS: {
 
+		} break;
 
-				*p_outputs[0] = ObjectTypeDB::type_exists(*p_inputs[0]);
+		case VisualScriptBuiltinFunc::TEXT_PRINTERR: {
 
-			} break;
-			case VisualScriptBuiltinFunc::TEXT_STR: {
+			String str = *p_inputs[0];
 
-				String str = *p_inputs[0];
+			//str+="\n";
+			OS::get_singleton()->printerr("%s\n",str.utf8().get_data());
 
-				*p_outputs[0]=str;
 
-			} break;
-			case VisualScriptBuiltinFunc::TEXT_PRINT: {
+		} break;
+		case VisualScriptBuiltinFunc::TEXT_PRINTRAW: {
+			String str = *p_inputs[0];
 
-				String str = *p_inputs[0];
-				print_line(str);
+			//str+="\n";
+			OS::get_singleton()->print("%s",str.utf8().get_data());
 
 
-			} break;
+		} break;
+		case VisualScriptBuiltinFunc::VAR_TO_STR: {
 
-			case VisualScriptBuiltinFunc::TEXT_PRINTERR: {
+			String vars;
+			VariantWriter::write_to_string(*p_inputs[0],vars);
+			*r_return=vars;
+		} break;
+		case VisualScriptBuiltinFunc::STR_TO_VAR: {
 
-				String str = *p_inputs[0];
+			if (p_inputs[0]->get_type()!=Variant::STRING) {
+				r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+				r_error.argument=0;
+				r_error.expected=Variant::STRING;
 
-				//str+="\n";
-				OS::get_singleton()->printerr("%s\n",str.utf8().get_data());
+				return;
+			}
 
+			VariantParser::StreamString ss;
+			ss.s=*p_inputs[0];
 
-			} break;
-			case VisualScriptBuiltinFunc::TEXT_PRINTRAW: {
-				String str = *p_inputs[0];
+			String errs;
+			int line;
+			Error err = VariantParser::parse(&ss,*r_return,errs,line);
 
-				//str+="\n";
-				OS::get_singleton()->print("%s",str.utf8().get_data());
+			if (err!=OK) {
+				r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+				r_error.argument=0;
+				r_error.expected=Variant::STRING;
+				*r_return="Parse error at line "+itos(line)+": "+errs;
+				return;
+			}
 
+		} break;
+		case VisualScriptBuiltinFunc::VAR_TO_BYTES: {
 
-			} break;
-			case VisualScriptBuiltinFunc::VAR_TO_STR: {
 
-				String vars;
-				VariantWriter::write_to_string(*p_inputs[0],vars);
-				*p_outputs[0]=vars;
-			} break;
-			case VisualScriptBuiltinFunc::STR_TO_VAR: {
+			ByteArray barr;
+			int len;
+			Error err = encode_variant(*p_inputs[0],NULL,len);
+			if (err) {
+				r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+				r_error.argument=0;
+				r_error.expected=Variant::NIL;
+				r_error_str="Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).";
+				return;
+			}
 
-				if (p_inputs[0]->get_type()!=Variant::STRING) {
-					r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
-					r_error.argument=0;
-					r_error.expected=Variant::STRING;
+			barr.resize(len);
+			{
+				ByteArray::Write w = barr.write();
+				encode_variant(*p_inputs[0],w.ptr(),len);
 
-					return 0;
-				}
+			}
+			*r_return=barr;
+		} break;
+		case VisualScriptBuiltinFunc::BYTES_TO_VAR: {
 
-				VariantParser::StreamString ss;
-				ss.s=*p_inputs[0];
+			if (p_inputs[0]->get_type()!=Variant::RAW_ARRAY) {
+				r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+				r_error.argument=0;
+				r_error.expected=Variant::RAW_ARRAY;
 
-				String errs;
-				int line;
-				Error err = VariantParser::parse(&ss,*p_outputs[0],errs,line);
+				return;
+			}
 
+			ByteArray varr=*p_inputs[0];
+			Variant ret;
+			{
+				ByteArray::Read r=varr.read();
+				Error err = decode_variant(ret,r.ptr(),varr.size(),NULL);
 				if (err!=OK) {
+					r_error_str=RTR("Not enough bytes for decoding bytes, or invalid format.");
 					r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
 					r_error.argument=0;
-					r_error.expected=Variant::STRING;
-					*p_outputs[0]="Parse error at line "+itos(line)+": "+errs;
-					return 0;
+					r_error.expected=Variant::RAW_ARRAY;
+					return;
 				}
 
-			} break;
-			case VisualScriptBuiltinFunc::VAR_TO_BYTES: {
+			}
 
+			*r_return=ret;
 
-				ByteArray barr;
-				int len;
-				Error err = encode_variant(*p_inputs[0],NULL,len);
-				if (err) {
-					r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
-					r_error.argument=0;
-					r_error.expected=Variant::NIL;
-					*p_outputs[0]="Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).";
-					return 0;
-				}
+		} break;
+		default: {}
+	}
 
-				barr.resize(len);
-				{
-					ByteArray::Write w = barr.write();
-					encode_variant(*p_inputs[0],w.ptr(),len);
+}
 
-				}
-				*p_outputs[0]=barr;
-			} break;
-			case VisualScriptBuiltinFunc::BYTES_TO_VAR: {
 
-				if (p_inputs[0]->get_type()!=Variant::RAW_ARRAY) {
-					r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
-					r_error.argument=0;
-					r_error.expected=Variant::RAW_ARRAY;
+class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance {
+public:
 
-					return 0;
-				}
+	VisualScriptBuiltinFunc *node;
+	VisualScriptInstance *instance;
 
-				ByteArray varr=*p_inputs[0];
-				Variant ret;
-				{
-					ByteArray::Read r=varr.read();
-					Error err = decode_variant(ret,r.ptr(),varr.size(),NULL);
-					if (err!=OK) {
-						*p_outputs[0]=RTR("Not enough bytes for decoding bytes, or invalid format.");
-						r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
-						r_error.argument=0;
-						r_error.expected=Variant::RAW_ARRAY;
-						return 0;
-					}
+	VisualScriptBuiltinFunc::BuiltinFunc func;
 
-				}
 
-				*p_outputs[0]=ret;
+	//virtual int get_working_memory_size() const { return 0; }
+	//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
+	//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
+
+	virtual int step(const Variant** p_inputs,Variant** p_outputs,StartMode p_start_mode,Variant* p_working_mem,Variant::CallError& r_error,String& r_error_str) {
 
-			} break;
-			default: {}
-		}
+		VisualScriptBuiltinFunc::exec_func(func,p_inputs,p_outputs[0],r_error,r_error_str);
 		return 0;
 	}
 

+ 5 - 0
modules/visual_script/visual_script_builtin_funcs.h

@@ -68,6 +68,11 @@ public:
 		FUNC_MAX
 	};
 
+	static int get_func_argument_count(BuiltinFunc p_func);
+	static String get_func_name(BuiltinFunc p_func);
+	static void exec_func(BuiltinFunc p_func, const Variant** p_inputs, Variant* r_return, Variant::CallError& r_error, String& r_error_str);
+	static BuiltinFunc find_function(const String& p_string);
+
 private:
 	static const char* func_name[FUNC_MAX];
 	BuiltinFunc func;

+ 83 - 0
modules/visual_script/visual_script_expression.cpp

@@ -577,6 +577,13 @@ Error VisualScriptExpression::_get_token(Token& r_token) {
 							}
 						}
 
+						VisualScriptBuiltinFunc::BuiltinFunc bifunc = VisualScriptBuiltinFunc::find_function(id);
+						if (bifunc!=VisualScriptBuiltinFunc::FUNC_MAX) {
+							r_token.type=TK_BUILTIN_FUNC;
+							r_token.value=bifunc;
+							return OK;
+						}
+
 						r_token.type=TK_IDENTIFIER;
 						r_token.value=id;
 					}
@@ -603,6 +610,7 @@ const char* VisualScriptExpression::token_name[TK_MAX]={
 "PARENTHESIS OPEN",
 "PARENTHESIS CLOSE",
 "IDENTIFIER",
+"BUILTIN FUNC",
 "SELF",
 "CONSTANT",
 "BASIC TYPE",
@@ -813,6 +821,53 @@ VisualScriptExpression::ENode* VisualScriptExpression::_parse_expression() {
 
 				expr=constructor;
 
+			} break;
+			case TK_BUILTIN_FUNC: {
+				//builtin function
+
+				Variant::Type bt = Variant::Type(int(tk.value));
+				_get_token(tk);
+				if (tk.type!=TK_PARENTHESIS_OPEN) {
+					_set_error("Expected '('");
+					return NULL;
+				}
+
+				BuiltinFuncNode *bifunc = alloc_node<BuiltinFuncNode>();
+				bifunc->func=VisualScriptBuiltinFunc::BuiltinFunc(int(tk.value));
+
+				while(true) {
+
+					int cofs=str_ofs;
+					_get_token(tk);
+					if (tk.type==TK_PARENTHESIS_CLOSE) {
+						break;
+					}
+					str_ofs=cofs; //revert
+					//parse an expression
+					ENode* expr=_parse_expression();
+					if (!expr)
+						return NULL;
+
+					bifunc->arguments.push_back(expr);
+
+					cofs=str_ofs;
+					_get_token(tk);
+					if (tk.type==TK_COMMA) {
+						//all good
+					} else if (tk.type==TK_PARENTHESIS_CLOSE) {
+						str_ofs=cofs;
+					} else {
+						_set_error("Expected ',' or ')'");
+					}
+				}
+
+				int expected_args = VisualScriptBuiltinFunc::get_func_argument_count(bifunc->func);
+				if (bifunc->arguments.size() != expected_args) {
+					_set_error("Builtin func '"+VisualScriptBuiltinFunc::get_func_name(bifunc->func)+"' expects "+itos(expected_args)+" arguments.");
+				}
+
+				expr=bifunc;
+
 			} break;
 			case TK_OP_SUB: {
 
@@ -1337,6 +1392,34 @@ public:
 				}
 
 
+			} break;
+			case VisualScriptExpression::ENode::TYPE_BUILTIN_FUNC:  {
+
+				const VisualScriptExpression::BuiltinFuncNode *bifunc = static_cast<const VisualScriptExpression::BuiltinFuncNode*>(p_node);
+
+				Vector<Variant> arr;
+				Vector<const Variant*> argp;
+				arr.resize(bifunc->arguments.size());
+				argp.resize(bifunc->arguments.size());
+
+				for (int i=0;i<bifunc->arguments.size();i++) {
+
+					Variant value;
+					bool ret = _execute(p_inputs,bifunc->arguments[i],value,r_error_str,ce);
+					if (ret)
+						return true;
+					arr[i]=value;
+					argp[i]=&arr[i];
+				}
+
+
+				VisualScriptBuiltinFunc::exec_func(bifunc->func,argp.ptr(),&r_ret,ce,r_error_str);
+
+				if (ce.error!=Variant::CallError::CALL_OK) {
+					r_error_str="Builtin Call Failed. "+r_error_str;
+					return true;
+				}
+
 			} break;
 			case VisualScriptExpression::ENode::TYPE_CALL:  {
 

+ 11 - 0
modules/visual_script/visual_script_expression.h

@@ -2,6 +2,7 @@
 #define VISUALSCRIPTEXPRESSION_H
 
 #include "visual_script.h"
+#include "visual_script_builtin_funcs.h"
 
 class VisualScriptExpression : public VisualScriptNode {
 
@@ -35,6 +36,7 @@ friend class VisualScriptNodeInstanceExpression;
 		TK_PARENTHESIS_OPEN,
 		TK_PARENTHESIS_CLOSE,
 		TK_IDENTIFIER,
+		TK_BUILTIN_FUNC,
 		TK_SELF,
 		TK_CONSTANT,
 		TK_BASIC_TYPE,
@@ -101,6 +103,7 @@ friend class VisualScriptNodeInstanceExpression;
 			TYPE_ARRAY,
 			TYPE_DICTIONARY,
 			TYPE_CONSTRUCTOR,
+			TYPE_BUILTIN_FUNC,
 			TYPE_CALL
 		};
 
@@ -214,6 +217,14 @@ friend class VisualScriptNodeInstanceExpression;
 
 	};
 
+	struct BuiltinFuncNode : public ENode {
+		VisualScriptBuiltinFunc::BuiltinFunc func;
+		Vector<ENode*> arguments;
+		BuiltinFuncNode() {
+			type=TYPE_BUILTIN_FUNC;
+		}
+	};
+
 	template<class T>
 	T* alloc_node() {
 		T* node = memnew(T);