#include /* c++ versions for overloaded math */ #include #include #include "cubescript/cubescript.hh" namespace cscript { static constexpr CsFloat PI = 3.14159265358979f; static constexpr CsFloat RAD = PI / 180.0f; template struct CsMathVal; template<> struct CsMathVal { static CsInt get(CsValue &tv) { return tv.get_int(); } static void set(CsValue &res, CsInt val) { res.set_int(val); } }; template<> struct CsMathVal { static CsFloat get(CsValue &tv) { return tv.get_float(); } static void set(CsValue &res, CsFloat val) { res.set_float(val); } }; template struct CsMathNoop { T operator()(T arg) { return arg; } }; template static inline void cs_mathop( CsValueRange args, CsValue &res, T initval, F1 binop, F2 unop ) { T val; if (args.size() >= 2) { val = binop(CsMathVal::get(args[0]), CsMathVal::get(args[1])); for (ostd::Size i = 2; i < args.size(); ++i) { val = binop(val, CsMathVal::get(args[i])); } } else { val = unop(!args.empty() ? CsMathVal::get(args[0]) : initval); } CsMathVal::set(res, val); } template static inline void cs_cmpop(CsValueRange args, CsValue &res, F cmp) { bool val; if (args.size() >= 2) { val = cmp(CsMathVal::get(args[0]), CsMathVal::get(args[1])); for (ostd::Size i = 2; (i < args.size()) && val; ++i) { val = cmp(val, CsMathVal::get(args[i])); } } else { val = cmp(!args.empty() ? CsMathVal::get(args[0]) : T(0), T(0)); } res.set_int(CsInt(val)); } /* overloads for various float types */ inline auto cs_sin(float f) { return sinf(f); } inline auto cs_sin(double f) { return sin(f); } inline auto cs_sin(long double f) { return sinl(f); } inline auto cs_cos(float f) { return cosf(f); } inline auto cs_cos(double f) { return cos(f); } inline auto cs_cos(long double f) { return cosl(f); } inline auto cs_tan(float f) { return tanf(f); } inline auto cs_tan(double f) { return tan(f); } inline auto cs_tan(long double f) { return tanl(f); } inline auto cs_asin(float f) { return asinf(f); } inline auto cs_asin(double f) { return asin(f); } inline auto cs_asin(long double f) { return asinl(f); } inline auto cs_acos(float f) { return acosf(f); } inline auto cs_acos(double f) { return acos(f); } inline auto cs_acos(long double f) { return acosl(f); } inline auto cs_atan(float f) { return atanf(f); } inline auto cs_atan(double f) { return atan(f); } inline auto cs_atan(long double f) { return atanl(f); } inline auto cs_atan2(float f, float f2) { return atan2f(f, f2); } inline auto cs_atan2(double f, double f2) { return atan2(f, f2); } inline auto cs_atan2(long double f, long double f2) { return atan2l(f, f2); } inline auto cs_sqrt(float f) { return sqrtf(f); } inline auto cs_sqrt(double f) { return sqrt(f); } inline auto cs_sqrt(long double f) { return sqrtl(f); } inline auto cs_log(float f) { return logf(f); } inline auto cs_log(double f) { return log(f); } inline auto cs_log(long double f) { return logl(f); } inline auto cs_log10(float f) { return log10f(f); } inline auto cs_log10(double f) { return log10(f); } inline auto cs_log10(long double f) { return log10l(f); } inline auto cs_exp(float f) { return expf(f); } inline auto cs_exp(double f) { return exp(f); } inline auto cs_exp(long double f) { return expl(f); } inline int cs_abs(int i) { return abs(i); } inline long cs_abs(long i) { return labs(i); } inline long long cs_abs(long long i) { return llabs(i); } inline auto cs_abs(float f) { return fabsf(f); } inline auto cs_abs(double f) { return fabs(f); } inline auto cs_abs(long double f) { return fabsl(f); } inline auto cs_floor(float f) { return floorf(f); } inline auto cs_floor(double f) { return floor(f); } inline auto cs_floor(long double f) { return floorl(f); } inline auto cs_ceil(float f) { return ceilf(f); } inline auto cs_ceil(double f) { return ceil(f); } inline auto cs_ceil(long double f) { return ceill(f); } inline auto cs_fmod(float f, float f2) { return fmodf(f, f2); } inline auto cs_fmod(double f, double f2) { return fmod(f, f2); } inline auto cs_fmod(long double f, long double f2) { return fmodl(f, f2); } void cs_init_lib_math(CsState &cs) { cs.new_command("sin", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_sin(args[0].get_float() * RAD)); }); cs.new_command("cos", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_cos(args[0].get_float() * RAD)); }); cs.new_command("tan", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_tan(args[0].get_float() * RAD)); }); cs.new_command("asin", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_asin(args[0].get_float()) / RAD); }); cs.new_command("acos", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_acos(args[0].get_float()) / RAD); }); cs.new_command("atan", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_atan(args[0].get_float()) / RAD); }); cs.new_command("atan2", "ff", []( CsState &, CsValueRange args, CsValue &res ) { res.set_float(cs_atan2(args[0].get_float(), args[1].get_float()) / RAD); }); cs.new_command("sqrt", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_sqrt(args[0].get_float())); }); cs.new_command("loge", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_log(args[0].get_float())); }); cs.new_command("log2", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_log(args[0].get_float()) / M_LN2); }); cs.new_command("log10", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_log10(args[0].get_float())); }); cs.new_command("exp", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_exp(args[0].get_float())); }); cs.new_command("min", "i1V", [](CsState &, CsValueRange args, CsValue &res) { CsInt v = (!args.empty() ? args[0].get_int() : 0); for (ostd::Size i = 1; i < args.size(); ++i) { v = ostd::min(v, args[i].get_int()); } res.set_int(v); }); cs.new_command("max", "i1V", [](CsState &, CsValueRange args, CsValue &res) { CsInt v = (!args.empty() ? args[0].get_int() : 0); for (ostd::Size i = 1; i < args.size(); ++i) { v = ostd::max(v, args[i].get_int()); } res.set_int(v); }); cs.new_command("minf", "f1V", []( CsState &, CsValueRange args, CsValue &res ) { CsFloat v = (!args.empty() ? args[0].get_float() : 0); for (ostd::Size i = 1; i < args.size(); ++i) { v = ostd::min(v, args[i].get_float()); } res.set_float(v); }); cs.new_command("maxf", "f1V", []( CsState &, CsValueRange args, CsValue &res ) { CsFloat v = (!args.empty() ? args[0].get_float() : 0); for (ostd::Size i = 1; i < args.size(); ++i) { v = ostd::max(v, args[i].get_float()); } res.set_float(v); }); cs.new_command("abs", "i", [](CsState &, CsValueRange args, CsValue &res) { res.set_int(cs_abs(args[0].get_int())); }); cs.new_command("absf", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_abs(args[0].get_float())); }); cs.new_command("floor", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_floor(args[0].get_float())); }); cs.new_command("ceil", "f", [](CsState &, CsValueRange args, CsValue &res) { res.set_float(cs_ceil(args[0].get_float())); }); cs.new_command("round", "ff", []( CsState &, CsValueRange args, CsValue &res ) { CsFloat step = args[1].get_float(); CsFloat r = args[0].get_float(); if (step > 0) { r += step * ((r < 0) ? -0.5 : 0.5); r -= cs_fmod(r, step); } else { r = (r < 0) ? cs_ceil(r - 0.5) : cs_floor(r + 0.5); } res.set_float(r); }); cs.new_command("+", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop(args, res, 0, ostd::Add(), CsMathNoop()); }); cs.new_command("*", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 1, ostd::Multiply(), CsMathNoop() ); }); cs.new_command("-", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::Subtract(), ostd::Negate() ); }); cs.new_command("^", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::BitXor(), [](CsInt val) { return ~val; } ); }); cs.new_command("~", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::BitXor(), [](CsInt val) { return ~val; } ); }); cs.new_command("&", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::BitAnd(), CsMathNoop() ); }); cs.new_command("|", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::BitOr(), CsMathNoop() ); }); /* special combined cases */ cs.new_command("^~", "i1V", [](CsState &, CsValueRange args, CsValue &res) { CsInt val; if (args.size() >= 2) { val = args[0].get_int() ^ ~args[1].get_int(); for (ostd::Size i = 2; i < args.size(); ++i) { val ^= ~args[i].get_int(); } } else { val = !args.empty() ? args[0].get_int() : 0; } res.set_int(val); }); cs.new_command("&~", "i1V", [](CsState &, CsValueRange args, CsValue &res) { CsInt val; if (args.size() >= 2) { val = args[0].get_int() & ~args[1].get_int(); for (ostd::Size i = 2; i < args.size(); ++i) { val &= ~args[i].get_int(); } } else { val = !args.empty() ? args[0].get_int() : 0; } res.set_int(val); }); cs.new_command("|~", "i1V", [](CsState &, CsValueRange args, CsValue &res) { CsInt val; if (args.size() >= 2) { val = args[0].get_int() | ~args[1].get_int(); for (ostd::Size i = 2; i < args.size(); ++i) { val |= ~args[i].get_int(); } } else { val = !args.empty() ? args[0].get_int() : 0; } res.set_int(val); }); cs.new_command("<<", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, [](CsInt val1, CsInt val2) { return (val2 < CsInt(sizeof(CsInt) * CHAR_BIT)) ? (val1 << ostd::max(val2, CsInt(0))) : 0; }, CsMathNoop() ); }); cs.new_command(">>", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, [](CsInt val1, CsInt val2) { return val1 >> ostd::clamp( val2, CsInt(0), CsInt(sizeof(CsInt) * CHAR_BIT) ); }, CsMathNoop() ); }); cs.new_command("+f", "f1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::Add(), CsMathNoop() ); }); cs.new_command("*f", "f1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 1, ostd::Multiply(), CsMathNoop() ); }); cs.new_command("-f", "f1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::Subtract(), ostd::Negate() ); }); cs.new_command("div", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, [](CsInt val1, CsInt val2) { if (val2) { return val1 / val2; } return CsInt(0); }, CsMathNoop() ); }); cs.new_command("mod", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, [](CsInt val1, CsInt val2) { if (val2) { return val1 % val2; } return CsInt(0); }, CsMathNoop() ); }); cs.new_command("divf", "f1V", []( CsState &, CsValueRange args, CsValue &res ) { cs_mathop( args, res, 0, [](CsFloat val1, CsFloat val2) { if (val2) { return val1 / val2; } return CsFloat(0); }, CsMathNoop() ); }); cs.new_command("modf", "f1V", []( CsState &, CsValueRange args, CsValue &res ) { cs_mathop( args, res, 0, [](CsFloat val1, CsFloat val2) { if (val2) { return CsFloat(fmod(val1, val2)); } return CsFloat(0); }, CsMathNoop() ); }); cs.new_command("pow", "f1V", [](CsState &, CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, [](CsFloat val1, CsFloat val2) { return CsFloat(pow(val1, val2)); }, CsMathNoop() ); }); cs.new_command("=", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::Equal()); }); cs.new_command("!=", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::NotEqual()); }); cs.new_command("<", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::Less()); }); cs.new_command(">", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::Greater()); }); cs.new_command("<=", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::LessEqual()); }); cs.new_command(">=", "i1V", [](CsState &, CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::GreaterEqual()); }); cs.new_command("=f", "f1V", [](CsState &, CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::Equal()); }); cs.new_command("!=f", "f1V", [](CsState &, CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::NotEqual()); }); cs.new_command("(args, res, ostd::Less()); }); cs.new_command(">f", "f1V", [](CsState &, CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::Greater()); }); cs.new_command("<=f", "f1V", [](CsState &, CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::LessEqual()); }); cs.new_command(">=f", "f1V", [](CsState &, CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::GreaterEqual()); }); } } /* namespace cscript */