diff --git a/amxmodx/float.cpp b/amxmodx/float.cpp index 1fa30510..32f1a2aa 100755 --- a/amxmodx/float.cpp +++ b/amxmodx/float.cpp @@ -4,93 +4,378 @@ * Written by Greg Garner (gmg@artran.com) * This file may be freely used. No warranties of any kind. * + * CHANGES - + * 2002-08-27: Basic conversion of source from C++ to C by Adam D. Moss + * + * 2003-08-29: Removal of the dynamic memory allocation and replacing two + * type conversion functions by macros, by Thiadmer Riemersma + * 2003-09-22: Moved the type conversion macros to AMX.H, and simplifications + * of some routines, by Thiadmer Riemersma + * 2003-11-24: A few more native functions (geometry), plus minor modifications, + * mostly to be compatible with dynamically loadable extension + * modules, by Thiadmer Riemersma */ - +#include /* for atof() */ +#include /* for NULL */ +#include #include -#include -#include -#include -#include "amxmod.h" +#include "amx.h" -inline cell FloatToCell(float fValue) { - return *(cell *)((void *)&fValue); +/* + #if defined __BORLANDC__ + #pragma resource "amxFloat.res" + #endif +*/ + +#define PI 3.1415926535897932384626433832795 + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +static cell AMX_NATIVE_CALL n_float(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = long value to convert to a float + */ + float fValue; + + /* Convert to a float. Calls the compilers long to float conversion. */ + fValue = (float) params[1]; + + /* Return the cell. */ + return amx_ftoc(fValue); } -inline float CellToFloat(cell cellValue){ - return *(float *)((void *)&cellValue); +/******************************************************************/ +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +static cell AMX_NATIVE_CALL n_floatstr(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = virtual string address to convert to a float + */ + char szSource[60]; + cell *pString; + float fNum; + int nLen; + + /* They should have sent us 1 cell. */ + assert(params[0]/sizeof(cell)==1); + + /* Get the real address of the string. */ + amx_GetAddr(amx,params[1],&pString); + + /* Find out how long the string is in characters. */ + amx_StrLen(pString, &nLen); + if (nLen == 0 || nLen >= sizeof szSource) + return 0; + + /* Now convert the Small String into a C type null terminated string */ + amx_GetString(szSource, pString); + + /* Now convert this to a float. */ + fNum = (float)atof(szSource); + + return amx_ftoc(fNum); } -static cell _float(AMX *,cell *params){ - return FloatToCell((float)params[1]); +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +static cell AMX_NATIVE_CALL n_floatmul(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = float operand 1 + * params[2] = float operand 2 + */ + float fRes = amx_ctof(params[1]) * amx_ctof(params[2]); + return amx_ftoc(fRes); } -static cell _floatstr(AMX *amx,cell *params){ - int len; - return FloatToCell((float)atof(get_amxstring(amx,params[1],0,len))); +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +static cell AMX_NATIVE_CALL n_floatdiv(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = float dividend (top) + * params[2] = float divisor (bottom) + */ + float fRes = amx_ctof(params[1]) / amx_ctof(params[2]); + return amx_ftoc(fRes); } -static cell _floatmul(AMX *,cell *params){ - return FloatToCell(CellToFloat(params[1]) * CellToFloat(params[2])); +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +static cell AMX_NATIVE_CALL n_floatadd(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = float operand 1 + * params[2] = float operand 2 + */ + float fRes = amx_ctof(params[1]) + amx_ctof(params[2]); + return amx_ftoc(fRes); } -static cell _floatdiv(AMX *,cell *params){ - return FloatToCell(CellToFloat(params[1]) / CellToFloat(params[2])); +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +static cell AMX_NATIVE_CALL n_floatsub(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = float operand 1 + * params[2] = float operand 2 + */ + float fRes = amx_ctof(params[1]) - amx_ctof(params[2]); + return amx_ftoc(fRes); } -static cell _floatadd(AMX *,cell *params){ - return FloatToCell(CellToFloat(params[1]) + CellToFloat(params[2])); +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +/* Return fractional part of float */ +static cell AMX_NATIVE_CALL n_floatfract(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = float operand + */ + float fA = amx_ctof(params[1]); + fA = fA - (float)(floor((double)fA)); + return amx_ftoc(fA); } -static cell _floatsub(AMX *,cell *params){ - return FloatToCell(CellToFloat(params[1]) - CellToFloat(params[2])); +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +/* Return integer part of float, rounded */ +static cell AMX_NATIVE_CALL n_floatround(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = float operand + * params[2] = Type of rounding (long) + */ + float fA = amx_ctof(params[1]); + + switch (params[2]) + { + case 1: /* round downwards (truncate) */ + fA = (float)(floor((double)fA)); + break; + case 2: /* round upwards */ + fA = (float)(ceil((double)fA)); + break; + case 3: /* round towards zero */ + if ( fA>=0.0 ) + fA = (float)(floor((double)fA)); + else + fA = (float)(ceil((double)fA)); + break; + default: /* standard, round to nearest */ + fA = (float)(floor((double)fA+.5)); + break; + } + + return (long)fA; } -static cell _floatfract(AMX *,cell *params){ - float fA = CellToFloat(params[1]); - fA -= (float)(floor((double)fA)); - return FloatToCell(fA); +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +static cell AMX_NATIVE_CALL n_floatcmp(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = float operand 1 + * params[2] = float operand 2 + */ + float fA, fB; + + fA = amx_ctof(params[1]); + fB = amx_ctof(params[2]); + if (fA == fB) + return 0; + else if (fA>fB) + return 1; + else + return -1; + } -static cell _floatround(AMX *,cell *params){ - float fA = CellToFloat(params[1]); - switch (params[2]) { - case 1: - fA = (float)(floor((double)fA)); - break; - case 2: - float fValue; - fValue = (float)(floor((double)fA)); - if ( (fA>=0) && ((fA-fValue)!=0) ) - fValue++; - fA = fValue; - break; - default: - fA = (float)(floor((double)fA+.5)); - break; - } - return (long)fA; +/******************************************************************/ +static cell AMX_NATIVE_CALL n_floatsqroot(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = float operand + */ + float fA = amx_ctof(params[1]); + fA = (float)sqrt(fA); + if (fA < 0) + return amx_RaiseError(amx, AMX_ERR_DOMAIN); + return amx_ftoc(fA); } -static cell _floatcmp(AMX *,cell *params){ - float fA = CellToFloat(params[1]); - float fB = CellToFloat(params[2]); - if (fA == fB) - return 0; - else if (fA > fB) - return 1; - else - return -1; +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +static cell AMX_NATIVE_CALL n_floatpower(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = float operand 1 (base) + * params[2] = float operand 2 (exponent) + */ + float fA = amx_ctof(params[1]); + float fB = amx_ctof(params[2]); + fA = (float)pow(fA, fB); + return amx_ftoc(fA); +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +static cell AMX_NATIVE_CALL n_floatlog(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = float operand 1 (value) + * params[2] = float operand 2 (base) + */ + float fValue = amx_ctof(params[1]); + float fBase = amx_ctof(params[2]); + if (fValue <= 0.0 || fBase <= 0) + return amx_RaiseError(amx, AMX_ERR_DOMAIN); + if (fBase == 10.0) // ??? epsilon + fValue = (float)log10(fValue); + else + fValue = (float)(log(fValue) / log(fBase)); + return amx_ftoc(fValue); +} + +static float ToRadians(float angle, int radix) +{ + switch (radix) + { + case 1: /* degrees, sexagesimal system (technically: degrees/minutes/seconds) */ + return (float)(angle * PI / 180.0); + case 2: /* grades, centesimal system */ + return (float)(angle * PI / 200.0); + default: /* assume already radian */ + return angle; + } /* switch */ +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +static cell AMX_NATIVE_CALL n_floatsin(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = float operand 1 (angle) + * params[2] = float operand 2 (radix) + */ + float fA = amx_ctof(params[1]); + fA = ToRadians(fA, params[2]); + fA = sinf(fA); // PM: using the float version of sin + return amx_ftoc(fA); +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +static cell AMX_NATIVE_CALL n_floatcos(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = float operand 1 (angle) + * params[2] = float operand 2 (radix) + */ + float fA = amx_ctof(params[1]); + fA = ToRadians(fA, params[2]); + fA = cosf(fA); // PM: using the float version of cos + return amx_ftoc(fA); +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +static cell AMX_NATIVE_CALL n_floattan(AMX *amx,cell *params) +{ + /* + * params[0] = number of bytes + * params[1] = float operand 1 (angle) + * params[2] = float operand 2 (radix) + */ + float fA = amx_ctof(params[1]); + fA = ToRadians(fA, params[2]); + fA = tanf(fA); // PM: using the float version of tan + return amx_ftoc(fA); +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +/******************************************************************/ +static cell AMX_NATIVE_CALL n_floatabs(AMX *amx,cell *params) +{ + float fA = amx_ctof(params[1]); + fA = (fA >= 0) ? fA : -fA; + return amx_ftoc(fA); } AMX_NATIVE_INFO float_Natives[] = { - { "float", _float }, - { "floatstr", _floatstr }, - { "floatmul", _floatmul }, - { "floatdiv", _floatdiv }, - { "floatadd", _floatadd }, - { "floatsub", _floatsub }, - { "floatfract", _floatfract}, - { "floatround", _floatround}, - { "floatcmp", _floatcmp}, - { NULL, NULL } -}; \ No newline at end of file + { "float", n_float }, + { "floatstr", n_floatstr }, + { "floatmul", n_floatmul }, + { "floatdiv", n_floatdiv }, + { "floatadd", n_floatadd }, + { "floatsub", n_floatsub }, + { "floatfract", n_floatfract }, + { "floatround", n_floatround }, + { "floatcmp", n_floatcmp }, + { "floatsqroot", n_floatsqroot}, + { "floatpower", n_floatpower }, + { "floatlog", n_floatlog }, + { "floatsin", n_floatsin }, + { "floatcos", n_floatcos }, + { "floattan", n_floattan }, + { "floatabs", n_floatabs }, + { NULL, NULL } /* terminator */ +}; + +int AMXEXPORT amx_FloatInit(AMX *amx) +{ + return amx_Register(amx,float_Natives,-1); +} + +#if defined __BORLANDC__ || defined __WATCOMC__ + #pragma argsused +#endif +int AMXEXPORT amx_FloatCleanup(AMX *amx) +{ + return AMX_ERR_NONE; +}