initial commit
This commit is contained in:
347
add_on/scriptmath/scriptmath.cpp
Normal file
347
add_on/scriptmath/scriptmath.cpp
Normal file
@@ -0,0 +1,347 @@
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
#include "scriptmath.h"
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#include <cmath>
|
||||
|
||||
// The C++Builder RTL doesn't pull the *f functions into the global namespace per default.
|
||||
using namespace std;
|
||||
|
||||
#if __BORLANDC__ < 0x580
|
||||
// C++Builder 6 and earlier don't come with any *f variants of the math functions at all.
|
||||
inline float cosf (float arg) { return std::cos (arg); }
|
||||
inline float sinf (float arg) { return std::sin (arg); }
|
||||
inline float tanf (float arg) { return std::tan (arg); }
|
||||
inline float atan2f (float y, float x) { return std::atan2 (y, x); }
|
||||
inline float logf (float arg) { return std::log (arg); }
|
||||
inline float powf (float x, float y) { return std::pow (x, y); }
|
||||
inline float sqrtf (float arg) { return std::sqrt (arg); }
|
||||
#endif
|
||||
|
||||
// C++Builder doesn't define most of the non-standard float-specific math functions with
|
||||
// "*f" suffix; instead it provides overloads for the standard math functions which take
|
||||
// "float" arguments.
|
||||
inline float acosf (float arg) { return std::acos (arg); }
|
||||
inline float asinf (float arg) { return std::asin (arg); }
|
||||
inline float atanf (float arg) { return std::atan (arg); }
|
||||
inline float coshf (float arg) { return std::cosh (arg); }
|
||||
inline float sinhf (float arg) { return std::sinh (arg); }
|
||||
inline float tanhf (float arg) { return std::tanh (arg); }
|
||||
inline float log10f (float arg) { return std::log10 (arg); }
|
||||
inline float ceilf (float arg) { return std::ceil (arg); }
|
||||
inline float fabsf (float arg) { return std::fabs (arg); }
|
||||
inline float floorf (float arg) { return std::floor (arg); }
|
||||
|
||||
// C++Builder doesn't define a non-standard "modff" function but rather an overload of "modf"
|
||||
// for float arguments. However, BCC's float overload of fmod() is broken (QC #74816; fixed
|
||||
// in C++Builder 2010).
|
||||
inline float modff (float x, float *y)
|
||||
{
|
||||
double d;
|
||||
float f = (float) modf((double) x, &d);
|
||||
*y = (float) d;
|
||||
return f;
|
||||
}
|
||||
#endif
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// Determine whether the float version should be registered, or the double version
|
||||
#ifndef AS_USE_FLOAT
|
||||
#if !defined(_WIN32_WCE) // WinCE doesn't have the float versions of the math functions
|
||||
#define AS_USE_FLOAT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// The modf function doesn't seem very intuitive, so I'm writing this
|
||||
// function that simply returns the fractional part of the float value
|
||||
#if AS_USE_FLOAT
|
||||
float fractionf(float v)
|
||||
{
|
||||
float intPart;
|
||||
return modff(v, &intPart);
|
||||
}
|
||||
#else
|
||||
double fraction(double v)
|
||||
{
|
||||
double intPart;
|
||||
return modf(v, &intPart);
|
||||
}
|
||||
#endif
|
||||
|
||||
// As AngelScript doesn't allow bitwise manipulation of float types we'll provide a couple of
|
||||
// functions for converting float values to IEEE 754 formatted values etc. This also allow us to
|
||||
// provide a platform agnostic representation to the script so the scripts don't have to worry
|
||||
// about whether the CPU uses IEEE 754 floats or some other representation
|
||||
float fpFromIEEE(asUINT raw)
|
||||
{
|
||||
// TODO: Identify CPU family to provide proper conversion
|
||||
// if the CPU doesn't natively use IEEE style floats
|
||||
return *reinterpret_cast<float*>(&raw);
|
||||
}
|
||||
asUINT fpToIEEE(float fp)
|
||||
{
|
||||
return *reinterpret_cast<asUINT*>(&fp);
|
||||
}
|
||||
double fpFromIEEE(asQWORD raw)
|
||||
{
|
||||
return *reinterpret_cast<double*>(&raw);
|
||||
}
|
||||
asQWORD fpToIEEE(double fp)
|
||||
{
|
||||
return *reinterpret_cast<asQWORD*>(&fp);
|
||||
}
|
||||
|
||||
// closeTo() is used to determine if the binary representation of two numbers are
|
||||
// relatively close to each other. Numerical errors due to rounding errors build
|
||||
// up over many operations, so it is almost impossible to get exact numbers and
|
||||
// this is where closeTo() comes in.
|
||||
//
|
||||
// It shouldn't be used to determine if two numbers are mathematically close to
|
||||
// each other.
|
||||
//
|
||||
// ref: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
|
||||
// ref: http://www.gamedev.net/topic/653449-scriptmath-and-closeto/
|
||||
bool closeTo(float a, float b, float epsilon)
|
||||
{
|
||||
// Equal numbers and infinity will return immediately
|
||||
if( a == b ) return true;
|
||||
|
||||
// When very close to 0, we can use the absolute comparison
|
||||
float diff = fabsf(a - b);
|
||||
if( (a == 0 || b == 0) && (diff < epsilon) )
|
||||
return true;
|
||||
|
||||
// Otherwise we need to use relative comparison to account for precision
|
||||
return diff / (fabs(a) + fabs(b)) < epsilon;
|
||||
}
|
||||
|
||||
bool closeTo(double a, double b, double epsilon)
|
||||
{
|
||||
if( a == b ) return true;
|
||||
|
||||
double diff = fabs(a - b);
|
||||
if( (a == 0 || b == 0) && (diff < epsilon) )
|
||||
return true;
|
||||
|
||||
return diff / (fabs(a) + fabs(b)) < epsilon;
|
||||
}
|
||||
|
||||
void RegisterScriptMath_Native(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
// Conversion between floating point and IEEE bits representations
|
||||
r = engine->RegisterGlobalFunction("float fpFromIEEE(uint)", asFUNCTIONPR(fpFromIEEE, (asUINT), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("uint fpToIEEE(float)", asFUNCTIONPR(fpToIEEE, (float), asUINT), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double fpFromIEEE(uint64)", asFUNCTIONPR(fpFromIEEE, (asQWORD), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("uint64 fpToIEEE(double)", asFUNCTIONPR(fpToIEEE, (double), asQWORD), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Close to comparison with epsilon
|
||||
r = engine->RegisterGlobalFunction("bool closeTo(float, float, float = 0.00001f)", asFUNCTIONPR(closeTo, (float, float, float), bool), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("bool closeTo(double, double, double = 0.0000000001)", asFUNCTIONPR(closeTo, (double, double, double), bool), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
#if AS_USE_FLOAT
|
||||
// Trigonometric functions
|
||||
r = engine->RegisterGlobalFunction("float cos(float)", asFUNCTIONPR(cosf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float sin(float)", asFUNCTIONPR(sinf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float tan(float)", asFUNCTIONPR(tanf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterGlobalFunction("float acos(float)", asFUNCTIONPR(acosf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float asin(float)", asFUNCTIONPR(asinf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float atan(float)", asFUNCTIONPR(atanf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTIONPR(atan2f, (float, float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Hyberbolic functions
|
||||
r = engine->RegisterGlobalFunction("float cosh(float)", asFUNCTIONPR(coshf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float sinh(float)", asFUNCTIONPR(sinhf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float tanh(float)", asFUNCTIONPR(tanhf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Exponential and logarithmic functions
|
||||
r = engine->RegisterGlobalFunction("float log(float)", asFUNCTIONPR(logf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float log10(float)", asFUNCTIONPR(log10f, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Power functions
|
||||
r = engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTIONPR(powf, (float, float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTIONPR(sqrtf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Nearest integer, absolute value, and remainder functions
|
||||
r = engine->RegisterGlobalFunction("float ceil(float)", asFUNCTIONPR(ceilf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float abs(float)", asFUNCTIONPR(fabsf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float floor(float)", asFUNCTIONPR(floorf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float fraction(float)", asFUNCTIONPR(fractionf, (float), float), asCALL_CDECL); assert( r >= 0 );
|
||||
|
||||
// Don't register modf because AngelScript already supports the % operator
|
||||
#else
|
||||
// double versions of the same
|
||||
r = engine->RegisterGlobalFunction("double cos(double)", asFUNCTIONPR(cos, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double sin(double)", asFUNCTIONPR(sin, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double tan(double)", asFUNCTIONPR(tan, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double acos(double)", asFUNCTIONPR(acos, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double asin(double)", asFUNCTIONPR(asin, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double atan(double)", asFUNCTIONPR(atan, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTIONPR(atan2, (double, double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double cosh(double)", asFUNCTIONPR(cosh, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double sinh(double)", asFUNCTIONPR(sinh, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double tanh(double)", asFUNCTIONPR(tanh, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double log(double)", asFUNCTIONPR(log, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double log10(double)", asFUNCTIONPR(log10, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTIONPR(pow, (double, double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTIONPR(sqrt, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double ceil(double)", asFUNCTIONPR(ceil, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double abs(double)", asFUNCTIONPR(fabs, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTIONPR(floor, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTIONPR(fraction, (double), double), asCALL_CDECL); assert( r >= 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
#if AS_USE_FLOAT
|
||||
// This macro creates simple generic wrappers for functions of type 'float func(float)'
|
||||
#define GENERICff(x) \
|
||||
void x##_generic(asIScriptGeneric *gen) \
|
||||
{ \
|
||||
float f = *(float*)gen->GetAddressOfArg(0); \
|
||||
*(float*)gen->GetAddressOfReturnLocation() = x(f); \
|
||||
}
|
||||
|
||||
GENERICff(cosf)
|
||||
GENERICff(sinf)
|
||||
GENERICff(tanf)
|
||||
GENERICff(acosf)
|
||||
GENERICff(asinf)
|
||||
GENERICff(atanf)
|
||||
GENERICff(coshf)
|
||||
GENERICff(sinhf)
|
||||
GENERICff(tanhf)
|
||||
GENERICff(logf)
|
||||
GENERICff(log10f)
|
||||
GENERICff(sqrtf)
|
||||
GENERICff(ceilf)
|
||||
GENERICff(fabsf)
|
||||
GENERICff(floorf)
|
||||
GENERICff(fractionf)
|
||||
|
||||
void powf_generic(asIScriptGeneric *gen)
|
||||
{
|
||||
float f1 = *(float*)gen->GetAddressOfArg(0);
|
||||
float f2 = *(float*)gen->GetAddressOfArg(1);
|
||||
*(float*)gen->GetAddressOfReturnLocation() = powf(f1, f2);
|
||||
}
|
||||
void atan2f_generic(asIScriptGeneric *gen)
|
||||
{
|
||||
float f1 = *(float*)gen->GetAddressOfArg(0);
|
||||
float f2 = *(float*)gen->GetAddressOfArg(1);
|
||||
*(float*)gen->GetAddressOfReturnLocation() = atan2f(f1, f2);
|
||||
}
|
||||
|
||||
#else
|
||||
// This macro creates simple generic wrappers for functions of type 'double func(double)'
|
||||
#define GENERICdd(x) \
|
||||
void x##_generic(asIScriptGeneric *gen) \
|
||||
{ \
|
||||
double f = *(double*)gen->GetAddressOfArg(0); \
|
||||
*(double*)gen->GetAddressOfReturnLocation() = x(f); \
|
||||
}
|
||||
|
||||
GENERICdd(cos)
|
||||
GENERICdd(sin)
|
||||
GENERICdd(tan)
|
||||
GENERICdd(acos)
|
||||
GENERICdd(asin)
|
||||
GENERICdd(atan)
|
||||
GENERICdd(cosh)
|
||||
GENERICdd(sinh)
|
||||
GENERICdd(tanh)
|
||||
GENERICdd(log)
|
||||
GENERICdd(log10)
|
||||
GENERICdd(sqrt)
|
||||
GENERICdd(ceil)
|
||||
GENERICdd(fabs)
|
||||
GENERICdd(floor)
|
||||
GENERICdd(fraction)
|
||||
|
||||
void pow_generic(asIScriptGeneric *gen)
|
||||
{
|
||||
double f1 = *(double*)gen->GetAddressOfArg(0);
|
||||
double f2 = *(double*)gen->GetAddressOfArg(1);
|
||||
*(double*)gen->GetAddressOfReturnLocation() = pow(f1, f2);
|
||||
}
|
||||
void atan2_generic(asIScriptGeneric *gen)
|
||||
{
|
||||
double f1 = *(double*)gen->GetAddressOfArg(0);
|
||||
double f2 = *(double*)gen->GetAddressOfArg(1);
|
||||
*(double*)gen->GetAddressOfReturnLocation() = atan2(f1, f2);
|
||||
}
|
||||
#endif
|
||||
void RegisterScriptMath_Generic(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
#if AS_USE_FLOAT
|
||||
// Trigonometric functions
|
||||
r = engine->RegisterGlobalFunction("float cos(float)", asFUNCTION(cosf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float sin(float)", asFUNCTION(sinf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float tan(float)", asFUNCTION(tanf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
r = engine->RegisterGlobalFunction("float acos(float)", asFUNCTION(acosf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float asin(float)", asFUNCTION(asinf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float atan(float)", asFUNCTION(atanf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTION(atan2f_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Hyberbolic functions
|
||||
r = engine->RegisterGlobalFunction("float cosh(float)", asFUNCTION(coshf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float sinh(float)", asFUNCTION(sinhf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float tanh(float)", asFUNCTION(tanhf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Exponential and logarithmic functions
|
||||
r = engine->RegisterGlobalFunction("float log(float)", asFUNCTION(logf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float log10(float)", asFUNCTION(log10f_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Power functions
|
||||
r = engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTION(powf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTION(sqrtf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Nearest integer, absolute value, and remainder functions
|
||||
r = engine->RegisterGlobalFunction("float ceil(float)", asFUNCTION(ceilf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float abs(float)", asFUNCTION(fabsf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float floor(float)", asFUNCTION(floorf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("float fraction(float)", asFUNCTION(fractionf_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
|
||||
// Don't register modf because AngelScript already supports the % operator
|
||||
#else
|
||||
// double versions of the same
|
||||
r = engine->RegisterGlobalFunction("double cos(double)", asFUNCTION(cos_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double sin(double)", asFUNCTION(sin_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double tan(double)", asFUNCTION(tan_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double acos(double)", asFUNCTION(acos_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double asin(double)", asFUNCTION(asin_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double atan(double)", asFUNCTION(atan_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTION(atan2_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double cosh(double)", asFUNCTION(cosh_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double sinh(double)", asFUNCTION(sinh_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double tanh(double)", asFUNCTION(tanh_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double log(double)", asFUNCTION(log_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double log10(double)", asFUNCTION(log10_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTION(pow_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTION(sqrt_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double ceil(double)", asFUNCTION(ceil_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double abs(double)", asFUNCTION(fabs_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTION(floor_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTION(fraction_generic), asCALL_GENERIC); assert( r >= 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
void RegisterScriptMath(asIScriptEngine *engine)
|
||||
{
|
||||
if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
|
||||
RegisterScriptMath_Generic(engine);
|
||||
else
|
||||
RegisterScriptMath_Native(engine);
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
||||
26
add_on/scriptmath/scriptmath.h
Normal file
26
add_on/scriptmath/scriptmath.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef SCRIPTMATH_H
|
||||
#define SCRIPTMATH_H
|
||||
|
||||
#ifndef ANGELSCRIPT_H
|
||||
// Avoid having to inform include path if header is already include before
|
||||
#include <angelscript.h>
|
||||
#endif
|
||||
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// This function will determine the configuration of the engine
|
||||
// and use one of the two functions below to register the math functions
|
||||
void RegisterScriptMath(asIScriptEngine *engine);
|
||||
|
||||
// Call this function to register the math functions
|
||||
// using native calling conventions
|
||||
void RegisterScriptMath_Native(asIScriptEngine *engine);
|
||||
|
||||
// Use this one instead if native calling conventions
|
||||
// are not supported on the target platform
|
||||
void RegisterScriptMath_Generic(asIScriptEngine *engine);
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
222
add_on/scriptmath/scriptmathcomplex.cpp
Normal file
222
add_on/scriptmath/scriptmathcomplex.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
#include <assert.h>
|
||||
#include <string.h> // strstr
|
||||
#include <new> // new()
|
||||
#include <math.h>
|
||||
#include "scriptmathcomplex.h"
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
// C++Builder doesn't define a non-standard "sqrtf" function but rather an overload of "sqrt"
|
||||
// for float arguments.
|
||||
inline float sqrtf (float x) { return sqrt (x); }
|
||||
#endif
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
Complex::Complex()
|
||||
{
|
||||
r = 0;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
Complex::Complex(const Complex &other)
|
||||
{
|
||||
r = other.r;
|
||||
i = other.i;
|
||||
}
|
||||
|
||||
Complex::Complex(float _r, float _i)
|
||||
{
|
||||
r = _r;
|
||||
i = _i;
|
||||
}
|
||||
|
||||
bool Complex::operator==(const Complex &o) const
|
||||
{
|
||||
return (r == o.r) && (i == o.i);
|
||||
}
|
||||
|
||||
bool Complex::operator!=(const Complex &o) const
|
||||
{
|
||||
return !(*this == o);
|
||||
}
|
||||
|
||||
Complex &Complex::operator=(const Complex &other)
|
||||
{
|
||||
r = other.r;
|
||||
i = other.i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Complex &Complex::operator+=(const Complex &other)
|
||||
{
|
||||
r += other.r;
|
||||
i += other.i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Complex &Complex::operator-=(const Complex &other)
|
||||
{
|
||||
r -= other.r;
|
||||
i -= other.i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Complex &Complex::operator*=(const Complex &other)
|
||||
{
|
||||
*this = *this * other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Complex &Complex::operator/=(const Complex &other)
|
||||
{
|
||||
*this = *this / other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
float Complex::squaredLength() const
|
||||
{
|
||||
return r*r + i*i;
|
||||
}
|
||||
|
||||
float Complex::length() const
|
||||
{
|
||||
return sqrtf(squaredLength());
|
||||
}
|
||||
|
||||
Complex Complex::operator+(const Complex &other) const
|
||||
{
|
||||
return Complex(r + other.r, i + other.i);
|
||||
}
|
||||
|
||||
Complex Complex::operator-(const Complex &other) const
|
||||
{
|
||||
return Complex(r - other.r, i + other.i);
|
||||
}
|
||||
|
||||
Complex Complex::operator*(const Complex &other) const
|
||||
{
|
||||
return Complex(r*other.r - i*other.i, r*other.i + i*other.r);
|
||||
}
|
||||
|
||||
Complex Complex::operator/(const Complex &other) const
|
||||
{
|
||||
float squaredLen = other.squaredLength();
|
||||
if( squaredLen == 0 ) return Complex(0,0);
|
||||
|
||||
return Complex((r*other.r + i*other.i)/squaredLen, (i*other.r - r*other.i)/squaredLen);
|
||||
}
|
||||
|
||||
//-----------------------
|
||||
// Swizzle operators
|
||||
//-----------------------
|
||||
|
||||
Complex Complex::get_ri() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
Complex Complex::get_ir() const
|
||||
{
|
||||
return Complex(r,i);
|
||||
}
|
||||
void Complex::set_ri(const Complex &o)
|
||||
{
|
||||
*this = o;
|
||||
}
|
||||
void Complex::set_ir(const Complex &o)
|
||||
{
|
||||
r = o.i;
|
||||
i = o.r;
|
||||
}
|
||||
|
||||
//-----------------------
|
||||
// AngelScript functions
|
||||
//-----------------------
|
||||
|
||||
static void ComplexDefaultConstructor(Complex *self)
|
||||
{
|
||||
new(self) Complex();
|
||||
}
|
||||
|
||||
static void ComplexCopyConstructor(const Complex &other, Complex *self)
|
||||
{
|
||||
new(self) Complex(other);
|
||||
}
|
||||
|
||||
static void ComplexConvConstructor(float r, Complex *self)
|
||||
{
|
||||
new(self) Complex(r);
|
||||
}
|
||||
|
||||
static void ComplexInitConstructor(float r, float i, Complex *self)
|
||||
{
|
||||
new(self) Complex(r,i);
|
||||
}
|
||||
|
||||
static void ComplexListConstructor(float *list, Complex *self)
|
||||
{
|
||||
new(self) Complex(list[0], list[1]);
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
// Registration
|
||||
//-------------------------------------
|
||||
|
||||
static void RegisterScriptMathComplex_Native(asIScriptEngine *engine)
|
||||
{
|
||||
int r;
|
||||
|
||||
// Register the type
|
||||
#if AS_CAN_USE_CPP11
|
||||
// With C++11 it is possible to use asGetTypeTraits to determine the correct flags to represent the C++ class, except for the asOBJ_APP_CLASS_ALLFLOATS
|
||||
r = engine->RegisterObjectType("complex", sizeof(Complex), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<Complex>() | asOBJ_APP_CLASS_ALLFLOATS); assert( r >= 0 );
|
||||
#else
|
||||
r = engine->RegisterObjectType("complex", sizeof(Complex), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK | asOBJ_APP_CLASS_ALLFLOATS); assert( r >= 0 );
|
||||
#endif
|
||||
|
||||
// Register the object properties
|
||||
r = engine->RegisterObjectProperty("complex", "float r", asOFFSET(Complex, r)); assert( r >= 0 );
|
||||
r = engine->RegisterObjectProperty("complex", "float i", asOFFSET(Complex, i)); assert( r >= 0 );
|
||||
|
||||
// Register the constructors
|
||||
r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ComplexDefaultConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f(const complex &in)", asFUNCTION(ComplexCopyConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f(float)", asFUNCTION(ComplexConvConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f(float, float)", asFUNCTION(ComplexInitConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
r = engine->RegisterObjectBehaviour("complex", asBEHAVE_LIST_CONSTRUCT, "void f(const int &in) {float, float}", asFUNCTION(ComplexListConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
|
||||
|
||||
// Register the operator overloads
|
||||
r = engine->RegisterObjectMethod("complex", "complex &opAddAssign(const complex &in)", asMETHODPR(Complex, operator+=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("complex", "complex &opSubAssign(const complex &in)", asMETHODPR(Complex, operator-=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("complex", "complex &opMulAssign(const complex &in)", asMETHODPR(Complex, operator*=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("complex", "complex &opDivAssign(const complex &in)", asMETHODPR(Complex, operator/=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("complex", "bool opEquals(const complex &in) const", asMETHODPR(Complex, operator==, (const Complex &) const, bool), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("complex", "complex opAdd(const complex &in) const", asMETHODPR(Complex, operator+, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("complex", "complex opSub(const complex &in) const", asMETHODPR(Complex, operator-, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("complex", "complex opMul(const complex &in) const", asMETHODPR(Complex, operator*, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("complex", "complex opDiv(const complex &in) const", asMETHODPR(Complex, operator/, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
// Register the object methods
|
||||
r = engine->RegisterObjectMethod("complex", "float abs() const", asMETHOD(Complex,length), asCALL_THISCALL); assert( r >= 0 );
|
||||
|
||||
// Register the swizzle operators
|
||||
r = engine->RegisterObjectMethod("complex", "complex get_ri() const property", asMETHOD(Complex, get_ri), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("complex", "complex get_ir() const property", asMETHOD(Complex, get_ir), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("complex", "void set_ri(const complex &in) property", asMETHOD(Complex, set_ri), asCALL_THISCALL); assert( r >= 0 );
|
||||
r = engine->RegisterObjectMethod("complex", "void set_ir(const complex &in) property", asMETHOD(Complex, set_ir), asCALL_THISCALL); assert( r >= 0 );
|
||||
}
|
||||
|
||||
void RegisterScriptMathComplex(asIScriptEngine *engine)
|
||||
{
|
||||
if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
|
||||
{
|
||||
assert( false );
|
||||
// TODO: implement support for generic calling convention
|
||||
// RegisterScriptMathComplex_Generic(engine);
|
||||
}
|
||||
else
|
||||
RegisterScriptMathComplex_Native(engine);
|
||||
}
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
|
||||
61
add_on/scriptmath/scriptmathcomplex.h
Normal file
61
add_on/scriptmath/scriptmathcomplex.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef SCRIPTMATHCOMPLEX_H
|
||||
#define SCRIPTMATHCOMPLEX_H
|
||||
|
||||
#ifndef ANGELSCRIPT_H
|
||||
// Avoid having to inform include path if header is already include before
|
||||
#include <angelscript.h>
|
||||
#endif
|
||||
|
||||
|
||||
BEGIN_AS_NAMESPACE
|
||||
|
||||
// This class implements complex numbers and the common
|
||||
// operations that can be done with it.
|
||||
//
|
||||
// Ref: http://mathworld.wolfram.com/ComplexNumber.html
|
||||
|
||||
struct Complex
|
||||
{
|
||||
Complex();
|
||||
Complex(const Complex &other);
|
||||
Complex(float r, float i = 0);
|
||||
|
||||
// Assignment operator
|
||||
Complex &operator=(const Complex &other);
|
||||
|
||||
// Compound assigment operators
|
||||
Complex &operator+=(const Complex &other);
|
||||
Complex &operator-=(const Complex &other);
|
||||
Complex &operator*=(const Complex &other);
|
||||
Complex &operator/=(const Complex &other);
|
||||
|
||||
float length() const;
|
||||
float squaredLength() const;
|
||||
|
||||
// Swizzle operators
|
||||
Complex get_ri() const;
|
||||
void set_ri(const Complex &in);
|
||||
Complex get_ir() const;
|
||||
void set_ir(const Complex &in);
|
||||
|
||||
// Comparison
|
||||
bool operator==(const Complex &other) const;
|
||||
bool operator!=(const Complex &other) const;
|
||||
|
||||
// Math operators
|
||||
Complex operator+(const Complex &other) const;
|
||||
Complex operator-(const Complex &other) const;
|
||||
Complex operator*(const Complex &other) const;
|
||||
Complex operator/(const Complex &other) const;
|
||||
|
||||
float r;
|
||||
float i;
|
||||
};
|
||||
|
||||
// This function will determine the configuration of the engine
|
||||
// and use one of the two functions below to register the string type
|
||||
void RegisterScriptMathComplex(asIScriptEngine *engine);
|
||||
|
||||
END_AS_NAMESPACE
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user