#include #include #include #include "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)); } void cs_init_lib_math(CsState &cs) { cs.add_command("sin", "f", [](CsValueRange args, CsValue &res) { res.set_float(sin(args[0].get_float() * RAD)); }); cs.add_command("cos", "f", [](CsValueRange args, CsValue &res) { res.set_float(cos(args[0].get_float() * RAD)); }); cs.add_command("tan", "f", [](CsValueRange args, CsValue &res) { res.set_float(tan(args[0].get_float() * RAD)); }); cs.add_command("asin", "f", [](CsValueRange args, CsValue &res) { res.set_float(asin(args[0].get_float()) / RAD); }); cs.add_command("acos", "f", [](CsValueRange args, CsValue &res) { res.set_float(acos(args[0].get_float()) / RAD); }); cs.add_command("atan", "f", [](CsValueRange args, CsValue &res) { res.set_float(atan(args[0].get_float()) / RAD); }); cs.add_command("atan2", "ff", [](CsValueRange args, CsValue &res) { res.set_float(atan2(args[0].get_float(), args[1].get_float()) / RAD); }); cs.add_command("sqrt", "f", [](CsValueRange args, CsValue &res) { res.set_float(sqrt(args[0].get_float())); }); cs.add_command("loge", "f", [](CsValueRange args, CsValue &res) { res.set_float(log(args[0].get_float())); }); cs.add_command("log2", "f", [](CsValueRange args, CsValue &res) { res.set_float(log(args[0].get_float()) / M_LN2); }); cs.add_command("log10", "f", [](CsValueRange args, CsValue &res) { res.set_float(log10(args[0].get_float())); }); cs.add_command("exp", "f", [](CsValueRange args, CsValue &res) { res.set_float(exp(args[0].get_float())); }); cs.add_command("min", "i1V", [](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.add_command("max", "i1V", [](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.add_command("minf", "f1V", [](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.add_command("maxf", "f1V", [](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.add_command("abs", "i", [](CsValueRange args, CsValue &res) { res.set_int(abs(args[0].get_int())); }); cs.add_command("absf", "f", [](CsValueRange args, CsValue &res) { res.set_float(fabs(args[0].get_float())); }); cs.add_command("floor", "f", [](CsValueRange args, CsValue &res) { res.set_float(floor(args[0].get_float())); }); cs.add_command("ceil", "f", [](CsValueRange args, CsValue &res) { res.set_float(ceil(args[0].get_float())); }); cs.add_command("round", "ff", [](CsValueRange args, CsValue &res) { double step = args[1].get_float(); double r = args[0].get_float(); if (step > 0) { r += step * ((r < 0) ? -0.5 : 0.5); r -= fmod(r, step); } else { r = (r < 0) ? ceil(r - 0.5) : floor(r + 0.5); } res.set_float(CsFloat(r)); }); cs.add_command("+", "i1V", [](CsValueRange args, CsValue &res) { cs_mathop(args, res, 0, ostd::Add(), CsMathNoop()); }); cs.add_command("*", "i1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 1, ostd::Multiply(), CsMathNoop() ); }); cs.add_command("-", "i1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::Subtract(), ostd::Negate() ); }); cs.add_command("^", "i1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::BitXor(), [](CsInt val) { return ~val; } ); }); cs.add_command("~", "i1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::BitXor(), [](CsInt val) { return ~val; } ); }); cs.add_command("&", "i1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::BitAnd(), CsMathNoop() ); }); cs.add_command("|", "i1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::BitOr(), CsMathNoop() ); }); /* special combined cases */ cs.add_command("^~", "i1V", [](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.add_command("&~", "i1V", [](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.add_command("|~", "i1V", [](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.add_command("<<", "i1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, [](CsInt val1, CsInt val2) { return (val2 < CsInt(sizeof(CsInt) * CHAR_BIT)) ? (val1 << ostd::max(val2, 0)) : 0; }, CsMathNoop() ); }); cs.add_command(">>", "i1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, [](CsInt val1, CsInt val2) { return val1 >> ostd::clamp( val2, 0, CsInt(sizeof(CsInt) * CHAR_BIT) ); }, CsMathNoop() ); }); cs.add_command("+f", "f1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::Add(), CsMathNoop() ); }); cs.add_command("*f", "f1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 1, ostd::Multiply(), CsMathNoop() ); }); cs.add_command("-f", "f1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, ostd::Subtract(), ostd::Negate() ); }); cs.add_command("div", "i1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, [](CsInt val1, CsInt val2) { if (val2) { return val1 / val2; } return 0; }, CsMathNoop() ); }); cs.add_command("mod", "i1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, [](CsInt val1, CsInt val2) { if (val2) { return val1 % val2; } return 0; }, CsMathNoop() ); }); cs.add_command("divf", "f1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, [](CsFloat val1, CsFloat val2) { if (val2) { return val1 / val2; } return CsFloat(0); }, CsMathNoop() ); }); cs.add_command("modf", "f1V", [](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.add_command("pow", "f1V", [](CsValueRange args, CsValue &res) { cs_mathop( args, res, 0, [](CsFloat val1, CsFloat val2) { return CsFloat(pow(val1, val2)); }, CsMathNoop() ); }); cs.add_command("=", "i1V", [](CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::Equal()); }); cs.add_command("!=", "i1V", [](CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::NotEqual()); }); cs.add_command("<", "i1V", [](CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::Less()); }); cs.add_command(">", "i1V", [](CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::Greater()); }); cs.add_command("<=", "i1V", [](CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::LessEqual()); }); cs.add_command(">=", "i1V", [](CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::GreaterEqual()); }); cs.add_command("=f", "f1V", [](CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::Equal()); }); cs.add_command("!=f", "f1V", [](CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::NotEqual()); }); cs.add_command("(args, res, ostd::Less()); }); cs.add_command(">f", "f1V", [](CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::Greater()); }); cs.add_command("<=f", "f1V", [](CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::LessEqual()); }); cs.add_command(">=f", "f1V", [](CsValueRange args, CsValue &res) { cs_cmpop(args, res, ostd::GreaterEqual()); }); } } /* namespace cscript */