/* _____ __ ___ __ ____ _ __ / ___/__ ___ _ ___ / |/ /__ ___ / /_____ __ __/ __/_______(_)__ / /_ / (_ / _ `/ ' \/ -_) /|_/ / _ \/ _ \/ '_/ -_) // /\ \/ __/ __/ / _ \/ __/ \___/\_,_/_/_/_/\__/_/ /_/\___/_//_/_/\_\\__/\_, /___/\__/_/ /_/ .__/\__/ /___/ /_/ See Copyright Notice in gmMachine.h */ #include "gmConfig.h" #include "gmMathLib.h" #include "gmThread.h" #include "gmMachine.h" #include "gmHelpers.h" #include "gmUtil.h" #include // // Conversion // int GM_CDECL gmfToString(gmThread * a_thread) { const gmVariable * var = a_thread->GetThis(); if(GM_INT == var->m_type) { char numberAsStringBuffer[64]; sprintf(numberAsStringBuffer, "%d", var->m_value.m_int); // this won't be > 64 chars a_thread->PushNewString(numberAsStringBuffer); } else if (GM_FLOAT == var->m_type) { char numberAsStringBuffer[64]; sprintf(numberAsStringBuffer, "%f", var->m_value.m_float); // this won't be > 64 chars a_thread->PushNewString(numberAsStringBuffer); } else if (GM_STRING == var->m_type) { a_thread->PushString( (gmStringObject *) GM_OBJECT(var->m_value.m_ref) ); } else { return GM_EXCEPTION; } return GM_OK; } int GM_CDECL gmfToFloat(gmThread * a_thread) { const gmVariable * var = a_thread->GetThis(); if(GM_INT == var->m_type) { a_thread->PushFloat((float)var->m_value.m_int); } else if (GM_FLOAT == var->m_type) { a_thread->PushFloat(var->m_value.m_float); } else if (GM_STRING == var->m_type) { gmStringObject * strObj = (gmStringObject *) GM_OBJECT(var->m_value.m_ref); const char * cstr = * strObj; a_thread->PushFloat( (float)atof(cstr) ); } else { //a_thread->PushFloat( 0.0f ); return GM_EXCEPTION; } return GM_OK; } int GM_CDECL gmfToInt(gmThread * a_thread) { const gmVariable * var = a_thread->GetThis(); if(GM_INT == var->m_type) { a_thread->PushInt(var->m_value.m_int); } else if (GM_FLOAT == var->m_type) { a_thread->PushInt( (int)var->m_value.m_float); } else if (GM_STRING == var->m_type) { gmStringObject * strObj = (gmStringObject *) GM_OBJECT(var->m_value.m_ref); const char * cstr = * strObj; a_thread->PushInt( atoi(cstr) ); } else { //a_thread->PushInt( 0 ); return GM_EXCEPTION; } return GM_OK; } // // Math // // int randint(int a_min, int a_max); // returned number is >= a_min and < a_max (exclusive of max) static int GM_CDECL gmfRandInt(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(2); GM_CHECK_INT_PARAM(min, 0); GM_CHECK_INT_PARAM(max, 1); a_thread->PushInt( gmRandomInt(min, max) ); return GM_OK; } // float randfloat(float a_min, float a_max); // returned number is >= a_min and < a_max (exclusive of max) static int GM_CDECL gmfRandFloat(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(2); GM_CHECK_FLOAT_PARAM(min, 0); GM_CHECK_FLOAT_PARAM(max, 1); a_thread->PushFloat( gmRandomFloat(min, max) ); return GM_OK; } // void randseed(int a_seed); static int GM_CDECL gmfRandSeed(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); GM_CHECK_INT_PARAM(seed, 0); srand(seed); return GM_OK; } static int GM_CDECL gmfAbs(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); if(a_thread->ParamType(0) == GM_INT) { int intValue = a_thread->Param(0).m_value.m_int; a_thread->PushInt(abs(intValue)); return GM_OK; } else if(a_thread->ParamType(0) == GM_FLOAT) { float floatValue = a_thread->Param(0).m_value.m_float; a_thread->PushFloat((float)fabsf(floatValue)); return GM_OK; } return GM_EXCEPTION; } static int GM_CDECL gmfSqrt(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); if(a_thread->ParamType(0) == GM_INT) { int intValue = a_thread->Param(0).m_value.m_int; a_thread->PushInt((int)sqrtf((float)intValue)); return GM_OK; } else if(a_thread->ParamType(0) == GM_FLOAT) { float floatValue = a_thread->Param(0).m_value.m_float; a_thread->PushFloat(sqrtf(floatValue)); return GM_OK; } return GM_EXCEPTION; } static int GM_CDECL gmfPower(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(2); int minType = gmMin(a_thread->ParamType(0), a_thread->ParamType(1)); if(minType < GM_INT) { return GM_EXCEPTION; } int maxType = gmMax(a_thread->ParamType(0), a_thread->ParamType(1)); if(maxType == GM_INT) { int valX = a_thread->Param(0).m_value.m_int; int valY = a_thread->Param(1).m_value.m_int; a_thread->PushInt((int)pow((float)valX, (float)valY)); return GM_OK; } else if(maxType == GM_FLOAT) { float valX = gmGetFloatOrIntParamAsFloat(a_thread, 0); float valY = gmGetFloatOrIntParamAsFloat(a_thread, 1); a_thread->PushFloat((float)pow(valX, valY)); return GM_OK; } else { return GM_EXCEPTION; } } static int GM_CDECL gmfFloor(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); if(a_thread->ParamType(0) == GM_INT) //Do nothing if Int { int intValue = a_thread->Param(0).m_value.m_int; a_thread->PushInt(intValue); return GM_OK; } else if(a_thread->ParamType(0) == GM_FLOAT) { float floatValue = a_thread->Param(0).m_value.m_float; a_thread->PushFloat(floorf(floatValue)); return GM_OK; } return GM_EXCEPTION; } static int GM_CDECL gmfCeil(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); if(a_thread->ParamType(0) == GM_INT) //Do nothing if Int { int intValue = a_thread->Param(0).m_value.m_int; a_thread->PushInt(intValue); return GM_OK; } else if(a_thread->ParamType(0) == GM_FLOAT) { float floatValue = a_thread->Param(0).m_value.m_float; a_thread->PushFloat(ceilf(floatValue)); return GM_OK; } return GM_EXCEPTION; } static int GM_CDECL gmfRound(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); if(a_thread->ParamType(0) == GM_INT) //Do nothing if Int { int intValue = a_thread->Param(0).m_value.m_int; a_thread->PushInt(intValue); return GM_OK; } else if(a_thread->ParamType(0) == GM_FLOAT) { float floatValue = a_thread->Param(0).m_value.m_float; a_thread->PushFloat(floorf(floatValue + 0.5f)); return GM_OK; } return GM_EXCEPTION; } static int GM_CDECL gmfDegToRad(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); float floatValue; if(a_thread->ParamType(0) == GM_INT) { floatValue = (float) a_thread->Param(0).m_value.m_int; } else if(a_thread->ParamType(0) == GM_FLOAT) { floatValue = a_thread->Param(0).m_value.m_float; } else { return GM_EXCEPTION; } a_thread->PushFloat( floatValue * (GM_PI_VALUE / 180.0f) ); return GM_OK; } static int GM_CDECL gmfRadToDeg(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); float floatValue; if(a_thread->ParamType(0) == GM_INT) { floatValue = (float) a_thread->Param(0).m_value.m_int; } else if(a_thread->ParamType(0) == GM_FLOAT) { floatValue = a_thread->Param(0).m_value.m_float; } else { return GM_EXCEPTION; } a_thread->PushFloat( floatValue * (180.0f / GM_PI_VALUE) ); return GM_OK; } static int GM_CDECL gmfSin(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); float floatValue; if(a_thread->ParamType(0) == GM_INT) { floatValue = (float) a_thread->Param(0).m_value.m_int; } else if(a_thread->ParamType(0) == GM_FLOAT) { floatValue = a_thread->Param(0).m_value.m_float; } else { return GM_EXCEPTION; } a_thread->PushFloat(sinf(floatValue)); return GM_OK; } static int GM_CDECL gmfASin(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); float floatValue; if(a_thread->ParamType(0) == GM_INT) { floatValue = (float) a_thread->Param(0).m_value.m_int; } else if(a_thread->ParamType(0) == GM_FLOAT) { floatValue = a_thread->Param(0).m_value.m_float; } else { return GM_EXCEPTION; } a_thread->PushFloat(asinf(floatValue)); return GM_OK; } static int GM_CDECL gmfCos(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); float floatValue; if(a_thread->ParamType(0) == GM_INT) { floatValue = (float) a_thread->Param(0).m_value.m_int; } else if(a_thread->ParamType(0) == GM_FLOAT) { floatValue = a_thread->Param(0).m_value.m_float; } else { return GM_EXCEPTION; } a_thread->PushFloat(cosf(floatValue)); return GM_OK; } static int GM_CDECL gmfACos(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); float floatValue; if(a_thread->ParamType(0) == GM_INT) { floatValue = (float) a_thread->Param(0).m_value.m_int; } else if(a_thread->ParamType(0) == GM_FLOAT) { floatValue = a_thread->Param(0).m_value.m_float; } else { return GM_EXCEPTION; } a_thread->PushFloat(acosf(floatValue)); return GM_OK; } static int GM_CDECL gmfTan(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); float floatValue; if(a_thread->ParamType(0) == GM_INT) { floatValue = (float) a_thread->Param(0).m_value.m_int; } else if(a_thread->ParamType(0) == GM_FLOAT) { floatValue = a_thread->Param(0).m_value.m_float; } else { return GM_EXCEPTION; } a_thread->PushFloat(tanf(floatValue)); return GM_OK; } static int GM_CDECL gmfATan(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(1); float floatValue; if(a_thread->ParamType(0) == GM_INT) { floatValue = (float) a_thread->Param(0).m_value.m_int; } else if(a_thread->ParamType(0) == GM_FLOAT) { floatValue = a_thread->Param(0).m_value.m_float; } else { return GM_EXCEPTION; } a_thread->PushFloat(atanf(floatValue)); return GM_OK; } //returns the arctangent of y/x static int GM_CDECL gmfATan2(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(2); float floatValueY; float floatValueX; if(a_thread->ParamType(0) == GM_INT) {floatValueY = (float) a_thread->Param(0).m_value.m_int;} else if(a_thread->ParamType(0) == GM_FLOAT) {floatValueY = a_thread->Param(0).m_value.m_float;} else {return GM_EXCEPTION;} if(a_thread->ParamType(1) == GM_INT) {floatValueX = (float) a_thread->Param(1).m_value.m_int;} else if(a_thread->ParamType(1) == GM_FLOAT) {floatValueX = a_thread->Param(1).m_value.m_float;} else {return GM_EXCEPTION;} a_thread->PushFloat(atan2f(floatValueY, floatValueX)); return GM_OK; } static int GM_CDECL gmfLog(gmThread * a_thread) { int numParams = GM_THREAD_ARG->GetNumParams(); if(numParams == 1) //Natural log { if(a_thread->ParamType(0) == GM_INT) { float floatValue = (float) a_thread->Param(0).m_value.m_int; a_thread->PushInt( (int) log(floatValue) ); return GM_OK; } else if(a_thread->ParamType(0) == GM_FLOAT) { float floatValue = (float) a_thread->Param(0).m_value.m_float; a_thread->PushFloat( logf(floatValue) ); return GM_OK; } else {return GM_EXCEPTION;} } else if(numParams == 2) //Log to base params: base, value { int minType = gmMin(a_thread->ParamType(0), a_thread->ParamType(1)); if(minType < GM_INT) { return GM_EXCEPTION; } int maxType = gmMax(a_thread->ParamType(0), a_thread->ParamType(1)); if(maxType == GM_INT) { int base = a_thread->Param(0).m_value.m_int; int value = a_thread->Param(1).m_value.m_int; a_thread->PushInt( (int)( log10f((float)value) / log10f((float)base) ) ); return GM_OK; } else if(maxType == GM_FLOAT) { float base = gmGetFloatOrIntParamAsFloat(a_thread, 0); float value = gmGetFloatOrIntParamAsFloat(a_thread, 1); a_thread->PushFloat( (float)( log10(value) / log10(base) ) ); return GM_OK; } else { return GM_EXCEPTION; } } else { return GM_EXCEPTION; } } static int GM_CDECL gmfMin(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(2); int minType = gmMin(a_thread->ParamType(0), a_thread->ParamType(1)); if(minType < GM_INT) { return GM_EXCEPTION; } int maxType = gmMax(a_thread->ParamType(0), a_thread->ParamType(1)); if(maxType == GM_INT) { int valX = a_thread->Param(0).m_value.m_int; int valY = a_thread->Param(1).m_value.m_int; a_thread->PushInt( gmMin(valX, valY) ); return GM_OK; } else if(maxType == GM_FLOAT) { float valX = gmGetFloatOrIntParamAsFloat(a_thread, 0); float valY = gmGetFloatOrIntParamAsFloat(a_thread, 1); a_thread->PushFloat( gmMin(valX, valY) ); return GM_OK; } else { return GM_EXCEPTION; } } static int GM_CDECL gmfMax(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(2); int minType = gmMin(a_thread->ParamType(0), a_thread->ParamType(1)); if(minType < GM_INT) { return GM_EXCEPTION; } int maxType = gmMax(a_thread->ParamType(0), a_thread->ParamType(1)); if(maxType == GM_INT) { int valX = a_thread->Param(0).m_value.m_int; int valY = a_thread->Param(1).m_value.m_int; a_thread->PushInt( gmMax(valX, valY) ); return GM_OK; } else if(maxType == GM_FLOAT) { float valX = gmGetFloatOrIntParamAsFloat(a_thread, 0); float valY = gmGetFloatOrIntParamAsFloat(a_thread, 1); a_thread->PushFloat( gmMax(valX, valY) ); return GM_OK; } else { return GM_EXCEPTION; } } static int GM_CDECL gmfClamp(gmThread * a_thread) { GM_CHECK_NUM_PARAMS(3); //params: min, value, max int minType = gmMin3(a_thread->ParamType(0), a_thread->ParamType(1), a_thread->ParamType(2)); if(minType < GM_INT) { return GM_EXCEPTION; } int maxType = gmMax3(a_thread->ParamType(0), a_thread->ParamType(1), a_thread->ParamType(2)); if(maxType == GM_INT) { int limitMin = a_thread->Param(0).m_value.m_int; int value = a_thread->Param(1).m_value.m_int; int limitMax = a_thread->Param(2).m_value.m_int; a_thread->PushInt( gmClamp(limitMin, value, limitMax) ); return GM_OK; } else if(maxType == GM_FLOAT) { float limitMin = gmGetFloatOrIntParamAsFloat(a_thread, 0); float value = gmGetFloatOrIntParamAsFloat(a_thread, 1); float limitMax = gmGetFloatOrIntParamAsFloat(a_thread, 2); a_thread->PushFloat( gmClamp(limitMin, value, limitMax) ); return GM_OK; } else { return GM_EXCEPTION; } } // // Libs and bindings // static gmFunctionEntry s_mathLib[] = { /*gm \lib math */ /*gm \function abs \brief abs will return the absolute value of the passed int \ float \param int\float \return int\float abs(param) */ {"abs", gmfAbs}, /*gm \function sqrt \brief sqrt will return the square root of the passed int \ float \param int\float \return int\float sqrt(param) */ {"sqrt", gmfSqrt}, /*gm \function sqrt \brief sqrt will return the square root of the passed int \ float \param int\float A \param int\float B \return int\float A to the power of B */ {"power", gmfPower}, /*gm \function floor \brief floor \param float A \return float floor(A) */ {"floor", gmfFloor}, /*gm \function ceil \brief ceil \param float A \return float ceil(A) */ {"ceil", gmfCeil}, /*gm \function round \brief round \param float A \return float round(A) */ {"round", gmfRound}, /*gm \function degtorad \brief degtorad will convert degrees to radians \param float\int deg \return float */ {"degtorad", gmfDegToRad}, /*gm \function radtodeg \brief radtodeg will convert radians to degrees \param float\int rad \return float */ {"radtodeg", gmfRadToDeg}, /*gm \function cos \brief cos will return the radian cosine \param float \return float */ {"cos", gmfCos}, /*gm \function sin \brief sin will return the radian sine \param float \return float */ {"sin", gmfSin}, /*gm \function tan \brief tan will return the radian tan (sin/cos) \param float \return float */ {"tan", gmfTan}, /*gm \function acos \brief acos will return the radian arc cosine \param float \return float */ {"acos", gmfACos}, /*gm \function asin \brief asin will return the radian arc sine \param float \return float */ {"asin", gmfASin}, /*gm \function atan \brief atan will return the radian arc tangent \param float \return float */ {"atan", gmfATan}, /*gm \function atan \brief atan will return the radian arc tangent of x / y \param float x \param float y \return float */ {"atan2", gmfATan2}, /*gm \function log \brief log will return the natural logarithm of 1 parameter, or (base, value) the logarithm to base \param float natural \ base \param float value (optional) \return float */ {"log", gmfLog}, /*gm \function min \brief min will return the min of the 2 passed values \param float\int A \param float\int B \return float \ int min(A, B) */ {"min", gmfMin}, /*gm \function max \brief max will return the max of the 2 passed values \param float\int A \param float\int B \return float \ int max(A, B) */ {"max", gmfMax}, /*gm \function clamp \brief clamp will return the clamed value. clamp(min, val, max) \param float\int MIN \param float\int VALUE \param float\int MAX \return float\int value clamped to min, max */ {"clamp", gmfClamp}, /*gm \function randint \brief randint will return a random int from lower inclusive to upper. \param int lower inclusive \param int upper \return int */ {"randint", gmfRandInt}, /*gm \function randfloat \brief randfloat will return a random float from lower inclusive to upper. \param float lower inclusive \param float upper \return float */ {"randfloat", gmfRandFloat}, /*gm \function randseed \brief randseed will seed the random number generator \param int seed */ {"randseed", gmfRandSeed}, }; static gmFunctionEntry s_intLib[] = { {"String", gmfToString}, {"Float", gmfToFloat}, {"Int", gmfToInt}, }; static gmFunctionEntry s_floatLib[] = { {"String", gmfToString}, {"Float", gmfToFloat}, {"Int", gmfToInt}, }; void gmBindMathLib(gmMachine * a_machine) { a_machine->RegisterLibrary(s_mathLib, sizeof(s_mathLib) / sizeof(s_mathLib[0])); a_machine->RegisterTypeLibrary(GM_INT, s_intLib, sizeof(s_intLib) / sizeof(s_intLib[0])); a_machine->RegisterTypeLibrary(GM_FLOAT, s_floatLib, sizeof(s_floatLib) / sizeof(s_floatLib[0])); }