forked from Mirrors/openclonk
Merge default into floating-point
commit
77b9c47cf8
|
@ -73,6 +73,7 @@ if(HAVE_NULLPTR)
|
|||
CHECK_CXX_SOURCE_COMPILES("#include <cstddef>
|
||||
template<class T> void f(T &&); template<> void f(std::nullptr_t &&) {} int main() { f(NULL); }" NULL_IS_NULLPTR_T)
|
||||
endif()
|
||||
CHECK_CXX_SOURCE_COMPILES("int main() { static_assert(true, \"\"); }" HAVE_STATIC_ASSERT)
|
||||
|
||||
if(MSVC_VERSION GREATER 1499)
|
||||
# Activate minimal rebuild
|
||||
|
@ -348,6 +349,11 @@ set(OC_CLONK_SOURCES
|
|||
src/lib/C4Random.h
|
||||
src/lib/C4Real.cpp
|
||||
src/lib/C4Real.h
|
||||
src/lib/C4RealImpl_Fixed.cpp
|
||||
src/lib/C4RealImpl_Fixed.h
|
||||
src/lib/C4RealImpl_FPU.h
|
||||
src/lib/C4RealImpl_SSE.cpp
|
||||
src/lib/C4RealImpl_SSE.h
|
||||
src/lib/C4Rect.cpp
|
||||
src/lib/C4Rect.h
|
||||
src/lib/C4RTF.cpp
|
||||
|
|
|
@ -99,6 +99,11 @@ src/lib/C4Random.cpp \
|
|||
src/lib/C4Random.h \
|
||||
src/lib/C4Real.cpp \
|
||||
src/lib/C4Real.h \
|
||||
src/lib/C4RealImpl_Fixed.cpp \
|
||||
src/lib/C4RealImpl_Fixed.h \
|
||||
src/lib/C4RealImpl_FPU.h \
|
||||
src/lib/C4RealImpl_SSE.cpp \
|
||||
src/lib/C4RealImpl_SSE.h \
|
||||
src/lib/C4Rect.cpp \
|
||||
src/lib/C4Rect.h \
|
||||
src/lib/C4RTF.cpp \
|
||||
|
|
|
@ -191,3 +191,6 @@
|
|||
/* Define to 1 if your NULL is an instance of std::nullptr_t. */
|
||||
#cmakedefine NULL_IS_NULLPTR_T 1
|
||||
|
||||
/* Define to 1 if your compiler supports static_assert */
|
||||
#cmakedefine HAVE_STATIC_ASSERT 1
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ C4Application::~C4Application()
|
|||
bool C4Application::DoInit()
|
||||
{
|
||||
assert(AppState == C4AS_None);
|
||||
|
||||
// Config overwrite by parameter
|
||||
StdStrBuf sConfigFilename;
|
||||
char szParameter[_MAX_PATH+1];
|
||||
|
@ -120,6 +121,27 @@ bool C4Application::DoInit()
|
|||
// Open log
|
||||
OpenLog();
|
||||
|
||||
// Check for SSE support
|
||||
bool has_sse = false;
|
||||
struct registers
|
||||
{
|
||||
int eax, ebx, ecx, edx;
|
||||
} regs = {0};
|
||||
const uint32_t CPUID_EDX_HAS_SSE_FLAG = 1 << 25;
|
||||
#if defined _MSC_VER
|
||||
__cpuid(reinterpret_cast<int*>(®s), 1);
|
||||
#elif defined __GNUC__
|
||||
__asm__ __volatile__("cpuid":"=d"(regs.edx):"a"(1):"%ebx","%ecx");
|
||||
#endif
|
||||
has_sse = (regs.edx & CPUID_EDX_HAS_SSE_FLAG) != 0;
|
||||
if (!has_sse)
|
||||
{
|
||||
const char *message = "Your CPU does not support the SSE instruction set that is required by this program.";
|
||||
Log(message);
|
||||
MessageDialog(message);
|
||||
return false;
|
||||
}
|
||||
|
||||
Revision.Ref(OC_HG_REVISION);
|
||||
|
||||
// init system group
|
||||
|
|
|
@ -328,6 +328,17 @@ void C4PXSSystem::Cast(int32_t mat, int32_t num, int32_t tx, int32_t ty, int32_t
|
|||
itofix(Random(level+1)-level)/10);
|
||||
}
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
namespace
|
||||
{
|
||||
struct C4PXSSystem_Chunk
|
||||
{
|
||||
int32_t mat;
|
||||
float x,y,xdir,ydir;
|
||||
};
|
||||
BOOST_STATIC_ASSERT(sizeof(C4PXSSystem_Chunk) == 4 + 4*4);
|
||||
}
|
||||
|
||||
bool C4PXSSystem::Save(C4Group &hGroup)
|
||||
{
|
||||
unsigned int cnt;
|
||||
|
@ -349,17 +360,23 @@ bool C4PXSSystem::Save(C4Group &hGroup)
|
|||
CStdFile hTempFile;
|
||||
if (!hTempFile.Create(Config.AtTempPath(C4CFN_TempPXS)))
|
||||
return false;
|
||||
#ifdef C4REAL_USE_FIXNUM
|
||||
int32_t iNumFormat = 1;
|
||||
#else
|
||||
int32_t iNumFormat = 2;
|
||||
#endif
|
||||
if (!hTempFile.Write(&iNumFormat, sizeof (iNumFormat)))
|
||||
return false;
|
||||
|
||||
for (cnt=0; cnt<PXSMaxChunk; cnt++)
|
||||
if (Chunk[cnt]) // must save all chunks in order to keep order consistent on all clients
|
||||
if (!hTempFile.Write(Chunk[cnt],PXSChunkSize * sizeof(C4PXS)))
|
||||
{
|
||||
// Serialize chunk
|
||||
C4PXSSystem_Chunk serialize_buffer[PXSChunkSize];
|
||||
for (size_t chunk_idx = 0; chunk_idx < PXSChunkSize; ++chunk_idx)
|
||||
{
|
||||
serialize_buffer[chunk_idx].mat = Chunk[cnt][chunk_idx].Mat;
|
||||
serialize_buffer[chunk_idx].x = Chunk[cnt][chunk_idx].x;
|
||||
serialize_buffer[chunk_idx].y = Chunk[cnt][chunk_idx].y;
|
||||
serialize_buffer[chunk_idx].xdir = Chunk[cnt][chunk_idx].xdir;
|
||||
serialize_buffer[chunk_idx].ydir = Chunk[cnt][chunk_idx].ydir;
|
||||
}
|
||||
if (!hTempFile.Write(&serialize_buffer, sizeof(serialize_buffer)))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hTempFile.Close())
|
||||
return false;
|
||||
|
@ -380,36 +397,29 @@ bool C4PXSSystem::Load(C4Group &hGroup)
|
|||
if (!hGroup.AccessEntry(C4CFN_PXS,&iBinSize)) return false;
|
||||
// clear previous
|
||||
Clear();
|
||||
// using C4Real or float?
|
||||
int32_t iNumForm = 1;
|
||||
if (iBinSize % iChunkSize == 4)
|
||||
{
|
||||
if (!hGroup.Read(&iNumForm, sizeof (iNumForm))) return false;
|
||||
if (!Inside<int32_t>(iNumForm, 1, 2)) return false;
|
||||
iBinSize -= 4;
|
||||
}
|
||||
// old pxs-files have no tag for the number format
|
||||
else if (iBinSize % iChunkSize != 0) return false;
|
||||
// calc chunk count
|
||||
iChunkNum = iBinSize / iChunkSize;
|
||||
if (iChunkNum > PXSMaxChunk) return false;
|
||||
for (uint32_t cnt=0; cnt<iChunkNum; cnt++)
|
||||
{
|
||||
if (!(Chunk[cnt]=new C4PXS[PXSChunkSize])) return false;
|
||||
if (!hGroup.Read(Chunk[cnt],iChunkSize)) return false;
|
||||
Chunk[cnt] = new C4PXS[PXSChunkSize];
|
||||
// De-serialize chunk
|
||||
C4PXSSystem_Chunk serialize_buffer[PXSChunkSize];
|
||||
if (!hGroup.Read(&serialize_buffer, sizeof(serialize_buffer))) return false;
|
||||
for (size_t chunk_idx = 0; chunk_idx < PXSChunkSize; ++chunk_idx)
|
||||
{
|
||||
Chunk[cnt][chunk_idx].Mat = serialize_buffer[chunk_idx].mat;
|
||||
Chunk[cnt][chunk_idx].x = serialize_buffer[chunk_idx].x;
|
||||
Chunk[cnt][chunk_idx].y = serialize_buffer[chunk_idx].y;
|
||||
Chunk[cnt][chunk_idx].xdir = serialize_buffer[chunk_idx].xdir;
|
||||
Chunk[cnt][chunk_idx].ydir = serialize_buffer[chunk_idx].ydir;
|
||||
}
|
||||
// count the PXS, Peter!
|
||||
// convert num format, if neccessary
|
||||
C4PXS *pxp; iChunkPXS[cnt]=0;
|
||||
for (cnt2=0,pxp=Chunk[cnt]; cnt2<PXSChunkSize; cnt2++,pxp++)
|
||||
if (pxp->Mat != MNone)
|
||||
{
|
||||
++iChunkPXS[cnt];
|
||||
// convert number format
|
||||
#ifdef C4REAL_USE_FIXNUM
|
||||
if (iNumForm == 2) { FLOAT_TO_FIXED(&pxp->x); FLOAT_TO_FIXED(&pxp->y); FLOAT_TO_FIXED(&pxp->xdir); FLOAT_TO_FIXED(&pxp->ydir); }
|
||||
#else
|
||||
if (iNumForm == 1) { FIXED_TO_FLOAT(&pxp->x); FIXED_TO_FLOAT(&pxp->y); FIXED_TO_FLOAT(&pxp->xdir); FIXED_TO_FLOAT(&pxp->ydir); }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -1535,7 +1535,7 @@ bool C4Command::InitEvaluation()
|
|||
case C4CMD_MoveTo:
|
||||
{
|
||||
// Target coordinates by Target
|
||||
if (Target) { Tx+=Target->GetX(); Ty+=Target->GetY(); Target=NULL; }
|
||||
if (Target) { Tx+=C4VInt(Target->GetX()); Ty+=Target->GetY(); Target=NULL; }
|
||||
// Adjust coordinates
|
||||
int32_t iTx = Tx._getInt();
|
||||
if (~Data.getInt() & C4CMD_MoveTo_NoPosAdjust) AdjustMoveToTarget(iTx,Ty,FreeMoveTo(cObj),cObj->Shape.Hgt);
|
||||
|
|
|
@ -3528,6 +3528,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte) { if (haveCompleteMatch()) if (!iEntryNr--) { int32_t i=rByte; ProcessInt(i); rByte =i; } }
|
||||
virtual void Boolean(bool &rBool) { if (haveCompleteMatch()) if (!iEntryNr--) ProcessBool(rBool); }
|
||||
virtual void Character(char &rChar) { if (haveCompleteMatch()) if (!iEntryNr--) ProcessChar(rChar); }
|
||||
virtual void Float(float &flt) { assert(!"Can't compile/decompile float from structure"); }
|
||||
|
||||
// The C4ID-Adaptor will set RCT_ID for it's strings (see C4Id.h), so we don't have to guess the type.
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType)
|
||||
|
|
9045
src/lib/C4Real.cpp
9045
src/lib/C4Real.cpp
File diff suppressed because it is too large
Load Diff
402
src/lib/C4Real.h
402
src/lib/C4Real.h
|
@ -5,6 +5,7 @@
|
|||
* Copyright (c) 2002, 2005 Sven Eberhardt
|
||||
* Copyright (c) 2002, 2004-2005, 2007 Peter Wortmann
|
||||
* Copyright (c) 2005, 2007 Günther Brammer
|
||||
* Copyright (c) 2010 Nicolas Hake
|
||||
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
||||
*
|
||||
* Portions might be copyrighted by other authors who have contributed
|
||||
|
@ -28,7 +29,7 @@
|
|||
because floating point calculations are not guaranteed to be network
|
||||
safe...however, it can be solved as a data type with operator
|
||||
overloading, automatic type conversions, etc now - Sven2 */
|
||||
/* After some time with synchronous float use, C4Fixed is used again to
|
||||
/* After some time with synchronous float use, C4Real is used again to
|
||||
work around the problem that different compilers produce different
|
||||
floating point code, leading to desyncs between linux and windows
|
||||
engines. */
|
||||
|
@ -36,308 +37,159 @@
|
|||
#ifndef INC_C4Real
|
||||
#define INC_C4Real
|
||||
|
||||
#include <math.h>
|
||||
// C4RealBase modes:
|
||||
// C4REAL_MODE_SOFTWARE: fixpoint math, all operations emulated by
|
||||
// software
|
||||
// C4REAL_MODE_SOFT_FLOAT: floating-point math, all operations emulated by
|
||||
// software
|
||||
// C4REAL_MODE_FPU_FLOAT: floating-point math, all operations run on FPU
|
||||
// C4REAL_MODE_SSE_FLOAT: floating-point math, all operations run on SSE
|
||||
// unit (which is usually the FPU as well, but w/o
|
||||
// extended precision)
|
||||
#define C4REAL_MODE_SOFTWARE 1
|
||||
//#define C4REAL_MODE_SOFT_FLOAT 2
|
||||
#define C4REAL_MODE_FPU_FLOAT 3
|
||||
#define C4REAL_MODE_SSE_FLOAT 4
|
||||
|
||||
// activate to switch to classic fixed-point math
|
||||
#define C4REAL_USE_FIXNUM 1
|
||||
#define inline ALWAYS_INLINE
|
||||
#define FIXED_EMULATE_64BIT
|
||||
|
||||
// note: C4Fixed has to be defined even though it isn't used
|
||||
// any more. It is used to convert old-format fixed values
|
||||
// to the new-format float ones.
|
||||
|
||||
#ifdef C4REAL_USE_FIXNUM
|
||||
extern long SineTable[9001]; // external table of sine values
|
||||
#ifndef C4REAL_MODE
|
||||
#define C4REAL_MODE C4REAL_MODE_SSE_FLOAT
|
||||
#endif
|
||||
|
||||
// fixpoint shift (check 64 bit emulation before changing!)
|
||||
#define FIXED_SHIFT 16
|
||||
// fixpoint factor
|
||||
#define FIXED_FPF int32_t(1 << FIXED_SHIFT)
|
||||
#include <boost/type_traits/is_class.hpp>
|
||||
#include <boost/type_traits/is_pod.hpp>
|
||||
|
||||
class C4Fixed
|
||||
template<class C4RealImpl>
|
||||
class C4RealBase
|
||||
{
|
||||
#ifdef C4REAL_USE_FIXNUM
|
||||
friend int fixtoi(const C4Fixed &x);
|
||||
friend int fixtoi(const C4Fixed &x, int32_t prec);
|
||||
friend C4Fixed itofix(int32_t x);
|
||||
friend C4Fixed itofix(int32_t x, int32_t prec);
|
||||
friend float fixtof(const C4Fixed &x);
|
||||
friend C4Fixed ftofix(float x);
|
||||
#else
|
||||
friend void FIXED_TO_FLOAT(float *pVal);
|
||||
#endif
|
||||
friend void CompileFunc(C4Fixed &rValue, StdCompiler *pComp);
|
||||
C4RealImpl value;
|
||||
|
||||
friend C4RealBase Sin(const C4RealBase &);
|
||||
friend C4RealBase Cos(const C4RealBase &);
|
||||
|
||||
public:
|
||||
int32_t val; // internal value
|
||||
inline C4RealBase(int32_t val = 0) : value(val) { }
|
||||
inline C4RealBase(float val) : value(val) {}
|
||||
inline C4RealBase(int32_t val, int32_t prec) : value(val) { operator/=(C4RealBase(prec)); }
|
||||
// Conversion between different implementations of C4RealBase
|
||||
template<class T>
|
||||
inline C4RealBase(const C4RealBase<T> &val) : value(static_cast<float>(val)) { }
|
||||
|
||||
public:
|
||||
// constructors
|
||||
inline C4Fixed () { /*val=0;*/ } // why initialize?
|
||||
inline C4Fixed (const C4Fixed &rCpy): val(rCpy.val) { }
|
||||
|
||||
// Conversion must be done by the conversion routines itofix, fixtoi, ftofix and fixtof
|
||||
// in order to be backward compatible, so everything is private.
|
||||
private:
|
||||
explicit inline C4Fixed(int32_t iVal)
|
||||
: val (iVal * FIXED_FPF)
|
||||
{ }
|
||||
explicit inline C4Fixed(int32_t iVal, int32_t iPrec)
|
||||
: val( iPrec < FIXED_FPF
|
||||
? iVal * (FIXED_FPF / iPrec) + (iVal * (FIXED_FPF % iPrec)) / iPrec
|
||||
: int32_t( int64_t(iVal) * FIXED_FPF / iPrec )
|
||||
)
|
||||
{ }
|
||||
explicit inline C4Fixed(float fVal)
|
||||
: val(static_cast<int32_t>(fVal * float(FIXED_FPF)))
|
||||
{ }
|
||||
|
||||
// round to int
|
||||
int32_t to_int() const
|
||||
{
|
||||
int32_t r = val;
|
||||
// be careful not to overflow
|
||||
r += (val <= 0x7fffffff - FIXED_FPF / 2) * FIXED_FPF / 2;
|
||||
// ensure that -x.50 is rounded to -(x+1)
|
||||
r -= (val < 0);
|
||||
r >>= FIXED_SHIFT;
|
||||
// round 32767.5 to 32768 (not that anybody cares)
|
||||
r += (val > 0x7fffffff - FIXED_FPF / 2);
|
||||
return r;
|
||||
}
|
||||
int32_t to_int(int32_t prec) const
|
||||
{
|
||||
int64_t r = val;
|
||||
r *= prec;
|
||||
r += FIXED_FPF / 2;
|
||||
r -= (val < 0);
|
||||
r >>= FIXED_SHIFT;
|
||||
return int32_t(r);
|
||||
}
|
||||
// convert to floating point value
|
||||
float to_float() const
|
||||
{
|
||||
return float(val) / float(FIXED_FPF);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// set integer (allowed for historic reasons)
|
||||
inline C4Fixed &operator = (int32_t x) { return *this = C4Fixed(x); }
|
||||
|
||||
// test value
|
||||
inline operator bool () const { return !! val; }
|
||||
inline bool operator ! () const { return ! val; }
|
||||
// Copy ctor and assignment
|
||||
inline C4RealBase(const C4RealBase &rhs) : value(rhs.value) {}
|
||||
inline C4RealBase &operator = (const C4RealBase &rhs) { value = rhs.value; return *this; }
|
||||
inline C4RealBase &operator = (float rhs) { value = C4RealImpl(rhs); return *this; }
|
||||
inline C4RealBase &operator = (int rhs) { value = C4RealImpl(rhs); return *this; }
|
||||
|
||||
// arithmetic operations
|
||||
inline C4Fixed &operator += (const C4Fixed &fVal2)
|
||||
{
|
||||
val += fVal2.val;
|
||||
return *this;
|
||||
}
|
||||
inline C4Fixed &operator -= (const C4Fixed &fVal2)
|
||||
{
|
||||
val -= fVal2.val;
|
||||
return *this;
|
||||
}
|
||||
inline C4Fixed &operator *= (const C4Fixed &fVal2)
|
||||
{
|
||||
#ifndef FIXED_EMULATE_64BIT
|
||||
val = int32_t( (int64_t(val) * fVal2.val) / FIXED_FPF );
|
||||
#else
|
||||
int32_t x0 = val & (FIXED_FPF - 1),
|
||||
x1 = val >> FIXED_SHIFT;
|
||||
int32_t y0 = fVal2.val & (FIXED_FPF - 1),
|
||||
y1 = fVal2.val >> FIXED_SHIFT;
|
||||
val = x0*y0/FIXED_FPF + x0*y1 + x1*y0 + x1*y1*FIXED_FPF;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
inline C4Fixed &operator *= (int32_t iVal2)
|
||||
{
|
||||
val *= iVal2;
|
||||
return *this;
|
||||
}
|
||||
inline C4Fixed &operator /= (const C4Fixed &fVal2)
|
||||
{
|
||||
val = int32_t( (int64_t(val) * FIXED_FPF) / fVal2.val );
|
||||
return *this;
|
||||
}
|
||||
inline C4Fixed &operator /= (int32_t iVal2)
|
||||
{
|
||||
val /= iVal2;
|
||||
return *this;
|
||||
}
|
||||
inline C4Fixed operator - () const
|
||||
{
|
||||
C4Fixed fr; fr.val=-val; return fr;
|
||||
}
|
||||
inline C4Fixed operator + () const
|
||||
{
|
||||
return *this;
|
||||
#define C4REAL_ARITHMETIC_OPERATOR(op) \
|
||||
/* combined arithmetic and assignment ops */ \
|
||||
inline C4RealBase &operator op##= (const C4RealBase &rhs) { value op##= rhs.value; return *this; } \
|
||||
inline C4RealBase &operator op##= (float rhs) { return *this op##= C4RealBase(rhs); } \
|
||||
inline C4RealBase &operator op##= (int rhs) { return *this op##= C4RealBase(rhs); } \
|
||||
/* arithmetic operations on copies */ \
|
||||
inline C4RealBase operator op (const C4RealBase &rhs) const { C4RealBase nrv(*this); nrv op##= rhs; return nrv; } \
|
||||
inline C4RealBase operator op (float rhs) const { C4RealBase nrv(*this); nrv op##= rhs; return nrv; } \
|
||||
inline C4RealBase operator op (int rhs) const { C4RealBase nrv(*this); nrv op##= rhs; return nrv; } \
|
||||
/* arithmetic operations on copies, right-hand C4Real */ \
|
||||
/* friends defined in the class are implicitly inline */ \
|
||||
friend C4RealBase operator op (float lhs, const C4RealBase &rhs) { C4RealBase nrv(lhs); nrv op##= rhs; return nrv; } \
|
||||
friend C4RealBase operator op (int lhs, const C4RealBase &rhs) { C4RealBase nrv(lhs); nrv op##= rhs; return nrv; }
|
||||
|
||||
C4REAL_ARITHMETIC_OPERATOR(+)
|
||||
C4REAL_ARITHMETIC_OPERATOR(-)
|
||||
C4REAL_ARITHMETIC_OPERATOR(*)
|
||||
C4REAL_ARITHMETIC_OPERATOR(/)
|
||||
#undef C4REAL_ARITHMETIC_OPERATOR
|
||||
|
||||
inline C4RealBase operator + () const { return *this; }
|
||||
inline C4RealBase operator - () const
|
||||
{
|
||||
C4RealBase nrv(*this);
|
||||
nrv.value = -nrv.value;
|
||||
return nrv;
|
||||
}
|
||||
|
||||
inline bool operator == (const C4Fixed &fVal2) const { return val==fVal2.val; }
|
||||
inline bool operator < (const C4Fixed &fVal2) const { return val<fVal2.val; }
|
||||
inline bool operator > (const C4Fixed &fVal2) const { return val>fVal2.val; }
|
||||
inline bool operator <= (const C4Fixed &fVal2) const { return val<=fVal2.val; }
|
||||
inline bool operator >= (const C4Fixed &fVal2) const { return val>=fVal2.val; }
|
||||
inline bool operator != (const C4Fixed &fVal2) const { return val!=fVal2.val; }
|
||||
#define C4REAL_COMPARISON_OPERATOR(op) \
|
||||
inline bool operator op (const C4RealBase &rhs) const { return value op rhs.value; } \
|
||||
inline bool operator op (float rhs) const { return *this op C4RealBase(rhs); } \
|
||||
inline bool operator op (int rhs) const { return *this op C4RealBase(rhs); }
|
||||
C4REAL_COMPARISON_OPERATOR(<)
|
||||
C4REAL_COMPARISON_OPERATOR(<=)
|
||||
C4REAL_COMPARISON_OPERATOR(==)
|
||||
C4REAL_COMPARISON_OPERATOR(>=)
|
||||
C4REAL_COMPARISON_OPERATOR(>)
|
||||
C4REAL_COMPARISON_OPERATOR(!=)
|
||||
#undef C4REAL_COMPARISON_OPERATOR
|
||||
|
||||
// and wrappers
|
||||
inline C4Fixed &operator += (int32_t iVal2) { return operator += (C4Fixed(iVal2)); }
|
||||
inline C4Fixed &operator -= (int32_t iVal2) { return operator -= (C4Fixed(iVal2)); }
|
||||
// Conversion
|
||||
inline operator int() const { return value; }
|
||||
inline operator float() const { return value; }
|
||||
|
||||
inline C4Fixed operator + (const C4Fixed &fVal2) const { return C4Fixed(*this) += fVal2; }
|
||||
inline C4Fixed operator - (const C4Fixed &fVal2) const { return C4Fixed(*this) -= fVal2; }
|
||||
inline C4Fixed operator * (const C4Fixed &fVal2) const { return C4Fixed(*this) *= fVal2; }
|
||||
inline C4Fixed operator / (const C4Fixed &fVal2) const { return C4Fixed(*this) /= fVal2; }
|
||||
// Boolean operators
|
||||
// Not using safe-bool-idiom here, because we already define conversions
|
||||
// to integer, which is why we don't need to worry about unwanted con-
|
||||
// versions via operator bool
|
||||
inline operator bool() const { return static_cast<bool>(value); }
|
||||
inline bool operator !() const { return !operator bool(); }
|
||||
|
||||
inline C4Fixed operator + (int32_t iVal2) const { return C4Fixed(*this) += iVal2; }
|
||||
inline C4Fixed operator - (int32_t iVal2) const { return C4Fixed(*this) -= iVal2; }
|
||||
inline C4Fixed operator * (int32_t iVal2) const { return C4Fixed(*this) *= iVal2; }
|
||||
inline C4Fixed operator / (int32_t iVal2) const { return C4Fixed(*this) /= iVal2; }
|
||||
// C++03 doesn't support explicitly defaulted ctors, so C4RealBase can't
|
||||
// be a POD, so we can't directly store it into unions. Find a type that
|
||||
// allows this.
|
||||
template<class T, class IsPOD> struct StorageTypeSelector;
|
||||
template<class T>
|
||||
struct StorageTypeSelector<T, boost::false_type> { T v; };
|
||||
template<class T>
|
||||
struct StorageTypeSelector<T, boost::true_type> { typename T::StorageType v; };
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
inline C4Fixed operator + (int iVal2) const { return operator + (int32_t(iVal2)); }
|
||||
inline C4Fixed operator - (int iVal2) const { return operator - (int32_t(iVal2)); }
|
||||
inline C4Fixed operator * (int iVal2) const { return operator * (int32_t(iVal2)); }
|
||||
inline C4Fixed operator / (int iVal2) const { return operator / (int32_t(iVal2)); }
|
||||
#endif
|
||||
typedef StorageTypeSelector<C4RealImpl, typename boost::is_class<C4RealImpl>::type> StorageType;
|
||||
static_assert(boost::is_pod<StorageType>::value, "C4RealBase: StorageType is not a POD type");
|
||||
|
||||
inline bool operator == (int32_t iVal2) const { return operator == (C4Fixed(iVal2)); }
|
||||
inline bool operator < (int32_t iVal2) const { return operator < (C4Fixed(iVal2)); }
|
||||
inline bool operator > (int32_t iVal2) const { return operator > (C4Fixed(iVal2)); }
|
||||
inline bool operator <= (int32_t iVal2) const { return operator <= (C4Fixed(iVal2)); }
|
||||
inline bool operator >= (int32_t iVal2) const { return operator >= (C4Fixed(iVal2)); }
|
||||
inline bool operator != (int32_t iVal2) const { return operator != (C4Fixed(iVal2)); }
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
inline bool operator == (int iVal2) const { return operator == (C4Fixed(int32_t(iVal2))); }
|
||||
inline bool operator < (int iVal2) const { return operator < (C4Fixed(int32_t(iVal2))); }
|
||||
inline bool operator > (int iVal2) const { return operator > (C4Fixed(int32_t(iVal2))); }
|
||||
inline bool operator <= (int iVal2) const { return operator <= (C4Fixed(int32_t(iVal2))); }
|
||||
inline bool operator >= (int iVal2) const { return operator >= (C4Fixed(int32_t(iVal2))); }
|
||||
inline bool operator != (int iVal2) const { return operator != (C4Fixed(int32_t(iVal2))); }
|
||||
#endif
|
||||
|
||||
#ifdef C4REAL_USE_FIXNUM
|
||||
C4Fixed sin_deg() const
|
||||
{
|
||||
// adjust angle
|
||||
int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=18000-v; v%=36000;
|
||||
// get sine
|
||||
C4Fixed fr;
|
||||
switch (v/9000)
|
||||
{
|
||||
case 0: fr.val=+SineTable[v]; break;
|
||||
case 1: fr.val=+SineTable[18000-v]; break;
|
||||
case 2: fr.val=-SineTable[v-18000]; break;
|
||||
case 3: fr.val=-SineTable[36000-v]; break;
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
C4Fixed cos_deg() const
|
||||
{
|
||||
// adjust angle
|
||||
int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=-v; v%=36000;
|
||||
// get cosine
|
||||
C4Fixed fr;
|
||||
switch (v/9000)
|
||||
{
|
||||
case 0: fr.val=+SineTable[9000-v]; break;
|
||||
case 1: fr.val=-SineTable[v-9000]; break;
|
||||
case 2: fr.val=-SineTable[27000-v]; break;
|
||||
case 3: fr.val=+SineTable[v-27000]; break;
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
#endif
|
||||
friend bool operator==(StorageType lhs, StorageType rhs) { return lhs.v == rhs.v; }
|
||||
|
||||
C4RealBase(StorageType rhs) : value(rhs.v) {}
|
||||
operator StorageType() const { StorageType nrv = {value}; return nrv; }
|
||||
};
|
||||
|
||||
#ifdef C4REAL_USE_FIXNUM
|
||||
typedef C4RealBase<class C4RealImpl_Fixed> C4Real_Fixed;
|
||||
typedef C4RealBase<float> C4Real_FPU_Float;
|
||||
typedef C4RealBase<class C4RealImpl_SSE> C4Real_SSE_Float;
|
||||
|
||||
typedef C4Fixed C4Real;
|
||||
#include "C4RealImpl_Fixed.h"
|
||||
#include "C4RealImpl_FPU.h"
|
||||
#include "C4RealImpl_SSE.h"
|
||||
|
||||
// *** wrap C4Real to requested C4RealBase instantiation
|
||||
|
||||
#if C4REAL_MODE == C4REAL_MODE_SOFTWARE
|
||||
typedef C4Real_Fixed C4Real;
|
||||
#elif C4REAL_MODE == C4REAL_MODE_FPU_FLOAT
|
||||
typedef C4Real_FPU_Float C4Real;
|
||||
#elif C4REAL_MODE == C4REAL_MODE_SSE_FLOAT
|
||||
typedef C4Real_SSE_Float C4Real;
|
||||
#endif
|
||||
|
||||
// Instantiate other C4RealBases as well
|
||||
template class C4RealBase<C4RealImpl_Fixed>;
|
||||
template class C4RealBase<float>;
|
||||
template class C4RealBase<C4RealImpl_SSE>;
|
||||
|
||||
// conversion
|
||||
inline float fixtof(const C4Fixed &x) { return x.to_float(); }
|
||||
inline C4Fixed ftofix(float x) { return C4Fixed(x); }
|
||||
inline int fixtoi(const C4Fixed &x) { return x.to_int(); }
|
||||
inline int fixtoi(const C4Fixed &x, int32_t prec) { return x.to_int(prec); }
|
||||
inline C4Fixed itofix(int32_t x) { return C4Fixed(x); }
|
||||
inline C4Fixed itofix(int32_t x, int32_t prec) { return C4Fixed(x, prec); }
|
||||
inline float fixtof(const C4Real &x) { return static_cast<float>(x); }
|
||||
inline C4Real ftofix(float x) { return C4Real(x); }
|
||||
inline int fixtoi(const C4Real &x) { return static_cast<int>(x); }
|
||||
inline int fixtoi(const C4Real &x, int32_t prec) { return static_cast<int>(x * prec); }
|
||||
inline C4Real itofix(int32_t x) { return C4Real(x); }
|
||||
inline C4Real itofix(int32_t x, int32_t prec) { return C4Real(x, prec); }
|
||||
|
||||
// additional functions
|
||||
inline C4Real Sin(const C4Real &fAngle) { return fAngle.sin_deg(); }
|
||||
inline C4Real Cos(const C4Real &fAngle) { return fAngle.cos_deg(); }
|
||||
inline C4Real C4REAL100(int x) { return itofix(x, 100); }
|
||||
//inline C4Real C4REAL256(int x) { return itofix(x, 256); }
|
||||
inline C4Real C4REAL256(int x) { C4Fixed r; r.val = x * FIXED_FPF / 256; return r; }
|
||||
inline C4Real C4REAL10(int x) { return itofix(x, 10); }
|
||||
inline C4Real C4REAL100(int x) { C4Real nrv(x); nrv /= 100; return nrv; }
|
||||
inline C4Real C4REAL256(int x) { C4Real nrv(x); nrv /= 256; return nrv; }
|
||||
inline C4Real C4REAL10(int x) { C4Real nrv(x); nrv /= 10; return nrv; }
|
||||
|
||||
#else
|
||||
|
||||
// *** wrap C4Real to float
|
||||
|
||||
typedef float C4Real;
|
||||
|
||||
// fixtoi: use asm fistp, round up
|
||||
inline int fixtoi(C4Real x)
|
||||
{
|
||||
int e;
|
||||
#ifdef _MSC_VER
|
||||
float y = x;
|
||||
_asm
|
||||
{
|
||||
or y,1;
|
||||
fld y;
|
||||
fistp e;
|
||||
}
|
||||
#else
|
||||
asm ("or $1, %0" : "+rom" (x));
|
||||
asm ("fistp%z0 %0" : "=om" (e) : "t" (x) : "st");
|
||||
#endif
|
||||
return e;
|
||||
}
|
||||
|
||||
// conversion
|
||||
inline int fixtoi(const C4Real &x, int32_t prec) { return fixtoi(x*prec); }
|
||||
inline C4Real itofix(int x) { return static_cast<C4Real>(x); }
|
||||
inline C4Real itofix(int x, int prec) { return static_cast<C4Real>(x) / prec; }
|
||||
inline float fixtof(const C4Real &x) { return x; }
|
||||
inline C4Real ftofix(float x) { return x; }
|
||||
|
||||
// additional functions
|
||||
inline C4Real Sin(C4Real x) { return float(sin(x * 3.141592f / 180)); }
|
||||
inline C4Real Cos(C4Real x) { return float(cos(x * 3.141592f / 180)); }
|
||||
inline C4Real C4REAL100(int x) { return float(x) / 100; }
|
||||
inline C4Real C4REAL256(int x) { return float(x) / 256; }
|
||||
inline C4Real C4REAL10(int x) { return float(x) / 10; }
|
||||
|
||||
#endif
|
||||
// define 0
|
||||
const C4Real Fix0 = itofix(0);
|
||||
|
||||
// conversion...
|
||||
// note: keep out! really dirty casts!
|
||||
#ifdef C4REAL_USE_FIXNUM
|
||||
inline void FLOAT_TO_FIXED(C4Real *pVal)
|
||||
{
|
||||
*pVal = ftofix (*reinterpret_cast<float *>(pVal));
|
||||
}
|
||||
#else
|
||||
inline void FIXED_TO_FLOAT(C4Real *pVal)
|
||||
{
|
||||
*pVal = reinterpret_cast<C4Fixed *>(pVal)->to_float();
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef inline
|
||||
const C4Real Fix0 = C4Real(0);
|
||||
|
||||
// CompileFunc for C4Real
|
||||
void CompileFunc(C4Real &rValue, StdCompiler *pComp);
|
||||
|
||||
#endif //FIXED_H_INC
|
||||
#endif //C4REAL_H_INC
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* OpenClonk, http://www.openclonk.org
|
||||
*
|
||||
* Copyright (c) 2010 Nicolas Hake
|
||||
*
|
||||
* Portions might be copyrighted by other authors who have contributed
|
||||
* to OpenClonk.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
* See isc_license.txt for full license and disclaimer.
|
||||
*
|
||||
* "Clonk" is a registered trademark of Matthes Bender.
|
||||
* See clonk_trademark_license.txt for full license.
|
||||
*/
|
||||
|
||||
/* Fixed point math extracted from ALLEGRO by Shawn Hargreaves */
|
||||
|
||||
#ifndef INC_RealImpl_FPU
|
||||
#define INC_RealImpl_FPU
|
||||
|
||||
#ifndef INC_C4Real
|
||||
#error C4RealImpl_FPU.h must not be included by itself; include C4Real.h instead
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define _USE_MATH_DEFINES
|
||||
#endif
|
||||
#include <cmath>
|
||||
|
||||
inline C4Real_FPU_Float Sin(const C4Real_FPU_Float &real)
|
||||
{
|
||||
return C4Real_FPU_Float(std::sin(real.value * static_cast<float>(M_PI) / 180.0f));
|
||||
}
|
||||
inline C4Real_FPU_Float Cos(const C4Real_FPU_Float &real)
|
||||
{
|
||||
return C4Real_FPU_Float(std::cos(real.value * static_cast<float>(M_PI) / 180.0f));
|
||||
}
|
||||
|
||||
// Overload to avoid conversion warning
|
||||
template<>
|
||||
inline C4Real_FPU_Float::operator bool () const
|
||||
{
|
||||
return value != 0.0f;
|
||||
}
|
||||
|
||||
// C4Real_Fixed rounds up. Why?
|
||||
#ifdef _M_X64
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
template<>
|
||||
inline C4Real_FPU_Float::operator int () const
|
||||
{
|
||||
float y = value;
|
||||
#if defined _M_X64
|
||||
*reinterpret_cast<int*>(&y) |= 1;
|
||||
return _mm_cvtss_si32(_mm_load_ss(&y));
|
||||
#elif defined _MSC_VER
|
||||
int e;
|
||||
_asm
|
||||
{
|
||||
or y,1;
|
||||
fld y;
|
||||
fistp e;
|
||||
}
|
||||
return e;
|
||||
#elif defined __GNUC__
|
||||
int e;
|
||||
asm ("or $1, %0" : "+rom" (y));
|
||||
asm ("fistp%z0 %0" : "=om" (e) : "t" (y) : "st");
|
||||
return e;
|
||||
#else
|
||||
#error Unknown processor; implement rounding here
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* OpenClonk, http://www.openclonk.org
|
||||
*
|
||||
* Copyright (c) 1998-2000 Matthes Bender
|
||||
* Copyright (c) 2002, 2005 Sven Eberhardt
|
||||
* Copyright (c) 2002, 2004-2005, 2007 Peter Wortmann
|
||||
* Copyright (c) 2005, 2007 Günther Brammer
|
||||
* Copyright (c) 2010 Nicolas Hake
|
||||
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
||||
*
|
||||
* Portions might be copyrighted by other authors who have contributed
|
||||
* to OpenClonk.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
* See isc_license.txt for full license and disclaimer.
|
||||
*
|
||||
* "Clonk" is a registered trademark of Matthes Bender.
|
||||
* See clonk_trademark_license.txt for full license.
|
||||
*/
|
||||
|
||||
/* Fixed point math extracted from ALLEGRO by Shawn Hargreaves */
|
||||
|
||||
#ifndef INC_RealImpl_Fixed
|
||||
#define INC_RealImpl_Fixed
|
||||
|
||||
#ifndef INC_C4Real
|
||||
#error C4RealImpl_Fixed.h must not be included by itself; include C4Real.h instead
|
||||
#endif
|
||||
|
||||
#define FIXED_EMULATE_64BIT
|
||||
|
||||
#include <boost/operators.hpp>
|
||||
class C4RealImpl_Fixed
|
||||
: boost::totally_ordered<C4RealImpl_Fixed,
|
||||
boost::equivalent<C4RealImpl_Fixed
|
||||
> >
|
||||
{
|
||||
// fixpoint shift (check 64 bit emulation before changing!)
|
||||
static const int32_t FIXED_SHIFT = 16;
|
||||
static const int32_t FIXED_FPF = 1 << FIXED_SHIFT;
|
||||
|
||||
int32_t val; // Internal value
|
||||
static long SineTable[9001]; // external table of sine values
|
||||
|
||||
public:
|
||||
struct StorageType { int32_t v; };
|
||||
friend bool operator==(StorageType lhs, StorageType rhs) { return lhs.v == rhs.v; }
|
||||
|
||||
inline C4RealImpl_Fixed() : val(0) {}
|
||||
inline C4RealImpl_Fixed(const C4RealImpl_Fixed &rhs) : val(rhs.val) {}
|
||||
explicit inline C4RealImpl_Fixed(int32_t iVal) : val (iVal * FIXED_FPF) { }
|
||||
explicit inline C4RealImpl_Fixed(int32_t iVal, int32_t iPrec)
|
||||
: val( iPrec < FIXED_FPF
|
||||
? iVal * (FIXED_FPF / iPrec) + (iVal * (FIXED_FPF % iPrec)) / iPrec
|
||||
: int32_t( int64_t(iVal) * FIXED_FPF / iPrec )
|
||||
)
|
||||
{ }
|
||||
explicit inline C4RealImpl_Fixed(float fVal)
|
||||
: val(static_cast<int32_t>(fVal * float(FIXED_FPF)))
|
||||
{ }
|
||||
inline C4RealImpl_Fixed(StorageType rhs) : val(rhs.v) {}
|
||||
operator StorageType() const { StorageType nrv = {val}; return nrv; }
|
||||
|
||||
int32_t to_int() const
|
||||
{
|
||||
int32_t r = val;
|
||||
// be careful not to overflow
|
||||
r += (val <= 0x7fffffff - FIXED_FPF / 2) * FIXED_FPF / 2;
|
||||
// ensure that -x.50 is rounded to -(x+1)
|
||||
r -= (val < 0);
|
||||
r >>= FIXED_SHIFT;
|
||||
// round 32767.5 to 32768 (not that anybody cares)
|
||||
r += (val > 0x7fffffff - FIXED_FPF / 2);
|
||||
return r;
|
||||
}
|
||||
int32_t to_int(int32_t prec) const
|
||||
{
|
||||
int64_t r = val;
|
||||
r *= prec;
|
||||
r += FIXED_FPF / 2;
|
||||
r -= (val < 0);
|
||||
r >>= FIXED_SHIFT;
|
||||
return int32_t(r);
|
||||
}
|
||||
|
||||
// convert to floating point value
|
||||
float to_float() const
|
||||
{
|
||||
return float(val) / float(FIXED_FPF);
|
||||
}
|
||||
|
||||
// Arithmetics.
|
||||
C4RealImpl_Fixed &operator += (const C4RealImpl_Fixed &rhs)
|
||||
{
|
||||
val += rhs.val;
|
||||
return *this;
|
||||
}
|
||||
C4RealImpl_Fixed &operator -= (const C4RealImpl_Fixed &rhs)
|
||||
{
|
||||
val -= rhs.val;
|
||||
return *this;
|
||||
}
|
||||
C4RealImpl_Fixed &operator *= (const C4RealImpl_Fixed &rhs)
|
||||
{
|
||||
#ifndef FIXED_EMULATE_64BIT
|
||||
val = int32_t( (int64_t(val) * rhs.val) / FIXED_FPF );
|
||||
#else
|
||||
int32_t x0 = val & (FIXED_FPF - 1),
|
||||
x1 = val >> FIXED_SHIFT;
|
||||
int32_t y0 = rhs.val & (FIXED_FPF - 1),
|
||||
y1 = rhs.val >> FIXED_SHIFT;
|
||||
val = x0*y0/FIXED_FPF + x0*y1 + x1*y0 + x1*y1*FIXED_FPF;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
C4RealImpl_Fixed &operator /= (const C4RealImpl_Fixed &rhs)
|
||||
{
|
||||
val = int32_t( (int64_t(val) * FIXED_FPF) / rhs.val );
|
||||
return *this;
|
||||
}
|
||||
C4RealImpl_Fixed operator - ()
|
||||
{
|
||||
C4RealImpl_Fixed nrv(*this);
|
||||
nrv.val = -nrv.val;
|
||||
return nrv;
|
||||
}
|
||||
|
||||
C4RealImpl_Fixed sin_deg() const
|
||||
{
|
||||
// adjust angle
|
||||
int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=18000-v; v%=36000;
|
||||
// get sine
|
||||
C4RealImpl_Fixed fr;
|
||||
switch (v/9000)
|
||||
{
|
||||
case 0: fr.val=+SineTable[v]; break;
|
||||
case 1: fr.val=+SineTable[18000-v]; break;
|
||||
case 2: fr.val=-SineTable[v-18000]; break;
|
||||
case 3: fr.val=-SineTable[36000-v]; break;
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
C4RealImpl_Fixed cos_deg() const
|
||||
{
|
||||
// adjust angle
|
||||
int32_t v=int32_t((int64_t(val)*100)/FIXED_FPF); if (v<0) v=-v; v%=36000;
|
||||
// get cosine
|
||||
C4RealImpl_Fixed fr;
|
||||
switch (v/9000)
|
||||
{
|
||||
case 0: fr.val=+SineTable[9000-v]; break;
|
||||
case 1: fr.val=-SineTable[v-9000]; break;
|
||||
case 2: fr.val=-SineTable[27000-v]; break;
|
||||
case 3: fr.val=+SineTable[v-27000]; break;
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
|
||||
// Comparison
|
||||
bool operator < (const C4RealImpl_Fixed &rhs) const { return val < rhs.val; }
|
||||
|
||||
operator bool () const { return val != 0; }
|
||||
|
||||
// Conversion
|
||||
operator float () const { return to_float(); }
|
||||
operator int () const { return to_int(); }
|
||||
};
|
||||
|
||||
// Avoid overflowing
|
||||
template<>
|
||||
inline C4RealBase<C4RealImpl_Fixed>::C4RealBase(int32_t val, int32_t prec)
|
||||
: value(val, prec)
|
||||
{}
|
||||
|
||||
inline C4Real_Fixed Sin(const C4Real_Fixed &real)
|
||||
{
|
||||
C4Real_Fixed nrv;
|
||||
nrv.value = real.value.sin_deg();
|
||||
return nrv;
|
||||
}
|
||||
inline C4Real_Fixed Cos(const C4Real_Fixed &real)
|
||||
{
|
||||
C4Real_Fixed nrv;
|
||||
nrv.value = real.value.cos_deg();
|
||||
return nrv;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* OpenClonk, http://www.openclonk.org
|
||||
*
|
||||
* Copyright (c) 2010 Nicolas Hake
|
||||
*
|
||||
* Portions might be copyrighted by other authors who have contributed
|
||||
* to OpenClonk.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
* See isc_license.txt for full license and disclaimer.
|
||||
*
|
||||
* "Clonk" is a registered trademark of Matthes Bender.
|
||||
* See clonk_trademark_license.txt for full license.
|
||||
*/
|
||||
|
||||
#include "C4Include.h"
|
||||
#include "C4Real.h"
|
||||
|
||||
// Constants required for sine approximation
|
||||
const __m128 C4RealImpl_SSE::cephes_deg2rad = _mm_set_ps1(0.017453292f); // pi/180
|
||||
const __m128 C4RealImpl_SSE::cephes_FOPI = _mm_set_ps1(1.27323954473516f); // 4/pi
|
||||
const __m128 C4RealImpl_SSE::cephes_scaling_factors[3] = {
|
||||
_mm_set_ps1(0.78515625f), _mm_set_ps1(2.4187564849853515625e-4f), _mm_set_ps1(3.77489497744594108e-8f)
|
||||
};
|
||||
const __m128 C4RealImpl_SSE::cephes_appx_coeffs[3] = {
|
||||
_mm_set_ps(-1.9515295891e-4f, 2.443315711809948e-5f, 2.443315711809948e-5f, -1.9515295891e-4f),
|
||||
_mm_set_ps(8.3321608736e-3f, -1.388731625493765e-3f, -1.388731625493765e-3f, 8.3321608736e-3f),
|
||||
_mm_set_ps(-1.6666654611e-1f, 4.166664568298827e-2f, 4.166664568298827e-2f, -1.6666654611e-1f)
|
||||
};
|
||||
const __m128 C4RealImpl_SSE::iee754_sign_mask = _mm_set_ps1(-0.0f);
|
||||
|
||||
// Branchless approximation of sine and cosine values
|
||||
C4RealImpl_SSE C4RealImpl_SSE::SinCos(bool cosine) const
|
||||
{
|
||||
// NOTE: Consider storing radians directly instead of degrees to avoid
|
||||
// precision loss due to conversion
|
||||
__m128 radian = _mm_mul_ps(value, cephes_deg2rad);
|
||||
#ifndef NDEBUG
|
||||
float float_radians; _mm_store_ss(&float_radians, radian);
|
||||
#endif
|
||||
// put rad into all parts of the xmm register
|
||||
radian = _mm_shuffle_ps(radian, radian, 0);
|
||||
|
||||
// cephes library sine/cosine implementation
|
||||
// This calculates a Taylor approximation of rank 7 with slightly
|
||||
// modified coefficients to achieve better precision on the reduced
|
||||
// input range -pi/4..pi/4.
|
||||
|
||||
union m128extract {
|
||||
float f[4];
|
||||
uint32_t i[4];
|
||||
__m128 v;
|
||||
};
|
||||
|
||||
// Store sign and take absolute value of input
|
||||
__m128 sign = _mm_and_ps(radian, iee754_sign_mask);
|
||||
radian = _mm_xor_ps(radian, sign);
|
||||
m128extract sign_bits;
|
||||
sign_bits.v = sign;
|
||||
|
||||
// Select octant of the unit circle
|
||||
__m128 scaling = _mm_mul_ps(radian, C4RealImpl_SSE::cephes_FOPI);
|
||||
int octant = _mm_cvttss_si32(scaling);
|
||||
octant = (octant + 1) & ~1;
|
||||
scaling = _mm_cvtsi32_ss(scaling, octant);
|
||||
scaling = _mm_shuffle_ps(scaling, scaling, 0);
|
||||
uint32_t flip_sign_sine = ((octant & 4) << 29);
|
||||
octant &= 3;
|
||||
uint32_t flip_sign_cosine = flip_sign_sine ^ ((octant & 2) << 30);
|
||||
flip_sign_sine ^= sign_bits.i[0];
|
||||
|
||||
// map input to +-pi/4
|
||||
// note that this get more and more imprecise for abs(radian) > 8192
|
||||
radian = _mm_sub_ps(radian, _mm_mul_ps(scaling, cephes_scaling_factors[0]));
|
||||
radian = _mm_sub_ps(radian, _mm_mul_ps(scaling, cephes_scaling_factors[1]));
|
||||
radian = _mm_sub_ps(radian, _mm_mul_ps(scaling, cephes_scaling_factors[2]));
|
||||
|
||||
// run approximation, calculating four octants at once; correct result
|
||||
// will be selected later
|
||||
__m128 radiansq = _mm_mul_ps(radian, radian);
|
||||
__m128 result = cephes_appx_coeffs[0];
|
||||
result = _mm_mul_ps(result, radiansq);
|
||||
result = _mm_add_ps(result, cephes_appx_coeffs[1]);
|
||||
result = _mm_mul_ps(result, radiansq);
|
||||
result = _mm_add_ps(result, cephes_appx_coeffs[2]);
|
||||
result = _mm_mul_ps(result, radiansq);
|
||||
|
||||
radiansq = _mm_shuffle_ps(radiansq, radian, _MM_SHUFFLE(0,0,0,0));
|
||||
radiansq = _mm_shuffle_ps(radiansq, radiansq, _MM_SHUFFLE(2,0,0,2));
|
||||
result = _mm_mul_ps(result, radiansq);
|
||||
|
||||
radiansq = _mm_mul_ps(radiansq, _mm_set_ps(1.0f, -0.5f, -0.5f, 1.0f));
|
||||
result = _mm_add_ps(result, radiansq);
|
||||
result = _mm_add_ps(result, _mm_set_ps(0.0f, 1.0f, 1.0f, 0.0f));
|
||||
|
||||
// Select correct octant
|
||||
m128extract rv;
|
||||
rv.v = result;
|
||||
int sinidx = octant;
|
||||
int cosidx = octant ^ 2;
|
||||
|
||||
// adjust sign
|
||||
rv.i[sinidx] ^= flip_sign_sine;
|
||||
rv.i[cosidx] ^= flip_sign_cosine;
|
||||
|
||||
// relative error less than 1.1e-6 for input values between -360 deg
|
||||
// and 360 deg
|
||||
// relative error less than 1.2e-7 between -260 deg and 260 deg.
|
||||
// absolute error less than 6.0e-8 between -4.2e7 and 4.2e7 deg.
|
||||
assert(float_radians == 0.0f || std::abs((rv.f[sinidx] - std::sinf(float_radians)) / std::sinf(float_radians)) < 1.1e-6f);
|
||||
assert(float_radians == 0.0f || std::abs((rv.f[cosidx] - std::cosf(float_radians)) / std::cosf(float_radians)) < 1.1e-6f);
|
||||
|
||||
uint32_t cosine_mask = cosine * ~0;
|
||||
int idx = (cosine_mask & cosidx) | (~cosine_mask & sinidx);
|
||||
return rv.f[idx];
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* OpenClonk, http://www.openclonk.org
|
||||
*
|
||||
* Copyright (c) 2010 Nicolas Hake
|
||||
*
|
||||
* Portions might be copyrighted by other authors who have contributed
|
||||
* to OpenClonk.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
* See isc_license.txt for full license and disclaimer.
|
||||
*
|
||||
* "Clonk" is a registered trademark of Matthes Bender.
|
||||
* See clonk_trademark_license.txt for full license.
|
||||
*/
|
||||
|
||||
#ifndef INC_RealImpl_SSE
|
||||
#define INC_RealImpl_SSE
|
||||
|
||||
#ifndef INC_C4Real
|
||||
#error C4RealImpl_SSE.h must not be included by itself; include C4Real.h instead
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
class C4RealImpl_SSE
|
||||
{
|
||||
friend C4Real_SSE_Float Sin(const C4Real_SSE_Float &);
|
||||
friend C4Real_SSE_Float Cos(const C4Real_SSE_Float &);
|
||||
__m128 value;
|
||||
|
||||
static const __m128 iee754_sign_mask; // -0.0
|
||||
static const __m128 cephes_FOPI; // 4/pi
|
||||
static const __m128 cephes_deg2rad; // pi/180
|
||||
static const __m128 cephes_appx_coeffs[3]; // approximation coefficients
|
||||
static const __m128 cephes_scaling_factors[3]; // factors for quick scaling to -pi/4..pi/4
|
||||
C4RealImpl_SSE SinCos(bool cosine) const; // approximation of sine and cosine
|
||||
|
||||
public:
|
||||
inline C4RealImpl_SSE()
|
||||
: value(_mm_setzero_ps())
|
||||
{}
|
||||
inline C4RealImpl_SSE(const C4RealImpl_SSE &rhs)
|
||||
: value(rhs.value)
|
||||
{}
|
||||
inline C4RealImpl_SSE(int32_t iVal)
|
||||
: value(_mm_cvtsi32_ss(value, iVal))
|
||||
{}
|
||||
inline C4RealImpl_SSE(float fVal)
|
||||
: value(_mm_set_ss(fVal))
|
||||
{}
|
||||
|
||||
operator int () const
|
||||
{
|
||||
return _mm_cvtss_si32(value);
|
||||
}
|
||||
operator float () const
|
||||
{
|
||||
float f;
|
||||
_mm_store_ss(&f, value);
|
||||
return f;
|
||||
}
|
||||
|
||||
// To store C4RealImpl_SSE into unions, we're using an anonymous struct
|
||||
// to distinguish types, and an int32_t inside that struct to avoid passing
|
||||
// parameters via the x87 stack.
|
||||
struct StorageType { int32_t v; };
|
||||
friend bool operator==(StorageType lhs, StorageType rhs) { return lhs.v == rhs.v; }
|
||||
inline C4RealImpl_SSE(StorageType rhs)
|
||||
: value(_mm_load_ss(reinterpret_cast<float*>(&rhs.v)))
|
||||
{}
|
||||
operator StorageType() const
|
||||
{
|
||||
StorageType nrv;
|
||||
_mm_store_ss(reinterpret_cast<float*>(&nrv.v), value);
|
||||
return nrv;
|
||||
}
|
||||
|
||||
// Arithmetics
|
||||
// We're using _ps intrinsics for everything except division because they
|
||||
// have the same latency as their _ss counterparts, but their representa-
|
||||
// tion is one byte shorter (0F xx instead of F3 0F xx).
|
||||
// DIVPS is about half as fast as DIVSS, so we use the scalar instruction
|
||||
// here.
|
||||
C4RealImpl_SSE &operator += (const C4RealImpl_SSE &rhs) { value = _mm_add_ps(value, rhs.value); return *this; }
|
||||
C4RealImpl_SSE &operator -= (const C4RealImpl_SSE &rhs) { value = _mm_sub_ps(value, rhs.value); return *this; }
|
||||
C4RealImpl_SSE &operator *= (const C4RealImpl_SSE &rhs) { value = _mm_mul_ps(value, rhs.value); return *this; }
|
||||
C4RealImpl_SSE &operator /= (const C4RealImpl_SSE &rhs) { value = _mm_div_ss(value, rhs.value); return *this; }
|
||||
|
||||
// Negation
|
||||
C4RealImpl_SSE operator - () const
|
||||
{
|
||||
C4RealImpl_SSE nrv;
|
||||
nrv -= *this;
|
||||
return nrv;
|
||||
}
|
||||
|
||||
// Comparison
|
||||
// COMISS is faster on newer CPUs than CMPSS, also we get a nice return
|
||||
// value from the intrinsic instead of having to store parts of the XMM
|
||||
// register to a variable to read.
|
||||
bool operator < (const C4RealImpl_SSE &rhs) const { return _mm_comilt_ss(value, rhs.value) != 0; }
|
||||
bool operator <= (const C4RealImpl_SSE &rhs) const { return _mm_comile_ss(value, rhs.value) != 0; }
|
||||
bool operator == (const C4RealImpl_SSE &rhs) const { return _mm_comieq_ss(value, rhs.value) != 0; }
|
||||
bool operator >= (const C4RealImpl_SSE &rhs) const { return _mm_comige_ss(value, rhs.value) != 0; }
|
||||
bool operator > (const C4RealImpl_SSE &rhs) const { return _mm_comigt_ss(value, rhs.value) != 0; }
|
||||
bool operator != (const C4RealImpl_SSE &rhs) const { return _mm_comineq_ss(value, rhs.value) != 0; }
|
||||
|
||||
operator bool () const { return _mm_comineq_ss(value, _mm_setzero_ps()) != 0; }
|
||||
bool operator ! () const { return _mm_comieq_ss(value, _mm_setzero_ps()) != 0; }
|
||||
};
|
||||
|
||||
inline C4Real_SSE_Float Sin(const C4Real_SSE_Float &real)
|
||||
{
|
||||
return C4Real_SSE_Float(static_cast<float>(real.value.SinCos(false)));
|
||||
}
|
||||
inline C4Real_SSE_Float Cos(const C4Real_SSE_Float &real)
|
||||
{
|
||||
return C4Real_SSE_Float(static_cast<float>(real.value.SinCos(true)));
|
||||
}
|
||||
|
||||
#endif
|
|
@ -70,6 +70,7 @@ void StdCompilerBinWrite::Byte(int8_t &rByte) { WriteValue(rByte); }
|
|||
void StdCompilerBinWrite::Byte(uint8_t &rByte) { WriteValue(rByte); }
|
||||
void StdCompilerBinWrite::Boolean(bool &rBool) { WriteValue(rBool); }
|
||||
void StdCompilerBinWrite::Character(char &rChar) { WriteValue(rChar); }
|
||||
void StdCompilerBinWrite::Float(float &val) { WriteValue(val); }
|
||||
void StdCompilerBinWrite::String(char *szString, size_t iMaxLength, RawCompileType eType)
|
||||
{
|
||||
WriteData(szString, strlen(szString) + 1);
|
||||
|
@ -128,6 +129,7 @@ void StdCompilerBinRead::Byte(int8_t &rByte) { ReadValue(rByte); }
|
|||
void StdCompilerBinRead::Byte(uint8_t &rByte) { ReadValue(rByte); }
|
||||
void StdCompilerBinRead::Boolean(bool &rBool) { ReadValue(rBool); }
|
||||
void StdCompilerBinRead::Character(char &rChar) { ReadValue(rChar); }
|
||||
void StdCompilerBinRead::Float(float &val) { ReadValue(val); }
|
||||
void StdCompilerBinRead::String(char *szString, size_t iMaxLength, RawCompileType eType)
|
||||
{
|
||||
// At least one byte data needed
|
||||
|
@ -281,6 +283,12 @@ void StdCompilerINIWrite::Character(char &rChar)
|
|||
PrepareForValue();
|
||||
Buf.AppendFormat("%c", rChar);
|
||||
}
|
||||
void StdCompilerINIWrite::Float(float &val)
|
||||
{
|
||||
PrepareForValue();
|
||||
Buf.AppendFormat("%f", val);
|
||||
}
|
||||
|
||||
|
||||
void StdCompilerINIWrite::String(char *szString, size_t iMaxLength, RawCompileType eType)
|
||||
{
|
||||
|
@ -613,6 +621,31 @@ void StdCompilerINIRead::Character(char &rChar)
|
|||
{ notFound("Character"); return; }
|
||||
rChar = *pPos++;
|
||||
}
|
||||
void StdCompilerINIRead::Float(float &val)
|
||||
{
|
||||
if (!pPos)
|
||||
{ notFound("Float"); return; }
|
||||
// Skip whitespace
|
||||
SkipWhitespace();
|
||||
// Read number.
|
||||
const char *pnPos = pPos;
|
||||
double num = strtod(pPos, const_cast<char **>(&pnPos));
|
||||
// Could not read?
|
||||
if (!num && pnPos == pPos)
|
||||
{ notFound("Float"); return; }
|
||||
if (num < std::numeric_limits<float>::min() || num > std::numeric_limits<float>::max())
|
||||
{
|
||||
Warn("number out of range (%f to %f): %f ",
|
||||
static_cast<double>(std::numeric_limits<float>::min()),
|
||||
static_cast<double>(std::numeric_limits<float>::max()),
|
||||
num);
|
||||
if (num < std::numeric_limits<float>::min()) num = std::numeric_limits<float>::min();
|
||||
else if (num > std::numeric_limits<float>::max()) num = std::numeric_limits<float>::max();
|
||||
}
|
||||
// Get over it
|
||||
pPos = pnPos;
|
||||
val = num;
|
||||
}
|
||||
void StdCompilerINIRead::String(char *szString, size_t iMaxLength, RawCompileType eType)
|
||||
{
|
||||
// Read data
|
||||
|
|
|
@ -139,6 +139,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte) = 0; // Needs separator!
|
||||
virtual void Boolean(bool &rBool) = 0;
|
||||
virtual void Character(char &rChar) = 0; // Alphanumerical only!
|
||||
virtual void Float(float &val) = 0;
|
||||
|
||||
|
||||
// Compile raw data (strings)
|
||||
|
@ -177,6 +178,7 @@ public:
|
|||
void Value(int8_t &rInt) { Byte(rInt); }
|
||||
void Value(uint8_t &rInt) { Byte(rInt); }
|
||||
void Value(bool &rBool) { Boolean(rBool); }
|
||||
void Value(float &val) { Float(val); }
|
||||
|
||||
// Compiling/Decompiling (may throw a data format exception!)
|
||||
template <class T> inline void Compile(T RREF rStruct)
|
||||
|
@ -434,6 +436,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte) { }
|
||||
virtual void Boolean(bool &rBool) { }
|
||||
virtual void Character(char &rChar) { }
|
||||
virtual void Float(float &val) { }
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped) { }
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped) { }
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped) { }
|
||||
|
@ -466,6 +469,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte);
|
||||
virtual void Boolean(bool &rBool);
|
||||
virtual void Character(char &rChar);
|
||||
virtual void Float(float &val);
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
||||
|
@ -506,6 +510,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte);
|
||||
virtual void Boolean(bool &rBool);
|
||||
virtual void Character(char &rChar);
|
||||
virtual void Float(float &val);
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
||||
|
@ -584,6 +589,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte);
|
||||
virtual void Boolean(bool &rBool);
|
||||
virtual void Character(char &rChar);
|
||||
virtual void Float(float &val);
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
||||
|
@ -655,6 +661,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte);
|
||||
virtual void Boolean(bool &rBool);
|
||||
virtual void Character(char &rChar);
|
||||
virtual void Float(float &val);
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
||||
|
|
|
@ -136,6 +136,13 @@ typedef ptrdiff_t ssize_t;
|
|||
|
||||
|
||||
|
||||
#ifndef HAVE_STATIC_ASSERT
|
||||
#include <boost/static_assert.hpp>
|
||||
#define static_assert(x, y) BOOST_STATIC_ASSERT(x)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
// Allow checks for correct printf-usage
|
||||
#define GNUC_FORMAT_ATTRIBUTE __attribute__ ((format (printf, 1, 2)))
|
||||
|
|
|
@ -516,6 +516,11 @@ void StdCompilerConfigWrite::Raw(void *pData, size_t iSize, RawCompileType eType
|
|||
excCorrupt("Raw values aren't supported for registry compilers!");
|
||||
}
|
||||
|
||||
void StdCompilerConfigWrite::Float(float &val)
|
||||
{
|
||||
excCorrupt(0, "Float values aren't supported for registry compilers!");
|
||||
}
|
||||
|
||||
void StdCompilerConfigWrite::Begin()
|
||||
{
|
||||
assert(!iDepth);
|
||||
|
@ -699,6 +704,11 @@ void StdCompilerConfigRead::Raw(void *pData, size_t iSize, RawCompileType eType)
|
|||
excCorrupt(0, "Raw values aren't supported for registry compilers!");
|
||||
}
|
||||
|
||||
void StdCompilerConfigRead::Float(float &val)
|
||||
{
|
||||
excCorrupt(0, "Float values aren't supported for registry compilers!");
|
||||
}
|
||||
|
||||
void StdCompilerConfigRead::Begin()
|
||||
{
|
||||
assert(!iDepth);
|
||||
|
|
|
@ -106,6 +106,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte);
|
||||
virtual void Boolean(bool &rBool);
|
||||
virtual void Character(char &rChar);
|
||||
virtual void Float(float &val);
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
||||
|
@ -162,6 +163,7 @@ public:
|
|||
virtual void Byte(uint8_t &rByte);
|
||||
virtual void Boolean(bool &rBool);
|
||||
virtual void Character(char &rChar);
|
||||
virtual void Float(float &val);
|
||||
virtual void String(char *szString, size_t iMaxLength, RawCompileType eType = RCT_Escaped);
|
||||
virtual void String(char **pszString, RawCompileType eType = RCT_Escaped);
|
||||
virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped);
|
||||
|
|
|
@ -192,6 +192,7 @@ enum C4AulBCCType
|
|||
AB_CALLFS, // failsafe direct call
|
||||
AB_STACK, // push nulls / pop
|
||||
AB_INT, // constant: int
|
||||
AB_FLOAT, // constant: float
|
||||
AB_BOOL, // constant: bool
|
||||
AB_STRING, // constant: string
|
||||
AB_C4ID, // constant: C4ID
|
||||
|
@ -238,6 +239,7 @@ struct C4AulBCC
|
|||
union
|
||||
{
|
||||
int32_t i;
|
||||
C4Real::StorageType fl;
|
||||
C4String * s;
|
||||
C4AulFunc * f;
|
||||
intptr_t X;
|
||||
|
|
|
@ -173,6 +173,10 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
PushValue(C4VInt(pCPos->Par.i));
|
||||
break;
|
||||
|
||||
case AB_FLOAT:
|
||||
PushValue(C4VFloat(pCPos->Par.fl));
|
||||
break;
|
||||
|
||||
case AB_BOOL:
|
||||
PushValue(C4VBool(!! pCPos->Par.i));
|
||||
break;
|
||||
|
@ -274,7 +278,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
if (!pPar2->_getInt())
|
||||
throw new C4AulExecError(pCurCtx->Obj, "Division by zero");
|
||||
pPar1->SetInt(pPar1->_getInt() / pPar2->_getInt());
|
||||
pPar1->Deref();
|
||||
*pPar1 /= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -282,7 +287,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
pPar1->SetInt(pPar1->_getInt() * pPar2->_getInt());
|
||||
pPar1->Deref();
|
||||
*pPar1 *= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -301,7 +307,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
pPar1->SetInt(pPar1->_getInt() - pPar2->_getInt());
|
||||
pPar1->Deref();
|
||||
*pPar1 -= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -309,7 +316,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
pPar1->SetInt(pPar1->_getInt() + pPar2->_getInt());
|
||||
pPar1->Deref();
|
||||
*pPar1 += *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -405,7 +413,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
*pPar1 *= pPar2 ->_getInt();
|
||||
*pPar1 *= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -415,7 +423,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
if (!pPar2->_getInt())
|
||||
throw new C4AulExecError(pCurCtx->Obj, "Division by zero");
|
||||
*pPar1 /= pPar2->_getInt();
|
||||
*pPar1 /= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -433,7 +441,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
*pPar1 += pPar2 ->_getInt();
|
||||
*pPar1 += *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -441,7 +449,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
*pPar1 -= pPar2 ->_getInt();
|
||||
*pPar1 -= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -96,6 +96,7 @@ enum C4AulTokenType
|
|||
ATT_DIR, // directive
|
||||
ATT_IDTF, // identifier
|
||||
ATT_INT, // integer constant
|
||||
ATT_FLOAT, // floating point constant
|
||||
ATT_BOOL, // boolean constant
|
||||
ATT_STRING, // string constant
|
||||
ATT_NIL, // "nil"
|
||||
|
@ -436,11 +437,11 @@ C4ScriptOpDef C4ScriptOpMap[] =
|
|||
|
||||
// postfix
|
||||
{ 14, "**", AB_Pow, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 13, "/", AB_Div, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 13, "*", AB_Mul, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 13, "/", AB_Div, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
|
||||
{ 13, "*", AB_Mul, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
|
||||
{ 13, "%", AB_Mod, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 12, "-", AB_Sub, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 12, "+", AB_Sum, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 12, "-", AB_Sub, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
|
||||
{ 12, "+", AB_Sum, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
|
||||
{ 11, "<<", AB_LeftShift, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 11, ">>", AB_RightShift, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 10, "<", AB_LessThan, 1, 0, 0, C4V_Bool, C4V_Int, C4V_Int},
|
||||
|
@ -454,11 +455,11 @@ C4ScriptOpDef C4ScriptOpMap[] =
|
|||
{ 6, "|", AB_BitOr, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 5, "&&", AB_JUMPAND, 1, 0, 0, C4V_Bool, C4V_Bool, C4V_Bool},
|
||||
{ 4, "||", AB_JUMPOR, 1, 0, 0, C4V_Bool, C4V_Bool, C4V_Bool},
|
||||
{ 2, "*=", AB_MulIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "/=", AB_DivIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "*=", AB_MulIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
|
||||
{ 2, "/=", AB_DivIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
|
||||
{ 2, "%=", AB_ModIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "+=", AB_Inc, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "-=", AB_Dec, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "+=", AB_Inc, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
|
||||
{ 2, "-=", AB_Dec, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
|
||||
{ 2, "&=", AB_AndIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "|=", AB_OrIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "^=", AB_XOrIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
|
@ -545,6 +546,11 @@ static int32_t StrToI32(char *s, int base, char **scan_end)
|
|||
return result;
|
||||
}
|
||||
|
||||
static float StrToF32(const char *s, char **scan_end)
|
||||
{
|
||||
return strtod(s, scan_end);
|
||||
}
|
||||
|
||||
void C4AulParseState::ClearToken()
|
||||
{
|
||||
// if last token was a string, make sure its ref is deleted
|
||||
|
@ -571,6 +577,7 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
|
|||
TGS_Ident, // getting identifier
|
||||
TGS_Int, // getting integer
|
||||
TGS_IntHex, // getting hexadecimal integer
|
||||
TGS_Float, // getting floating point value
|
||||
TGS_String, // getting string
|
||||
TGS_Dir // getting directive
|
||||
};
|
||||
|
@ -709,6 +716,13 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
|
|||
break;
|
||||
|
||||
case TGS_Int: // integer: parse until non-number is found
|
||||
if (C == '.')
|
||||
{
|
||||
State = TGS_Float;
|
||||
break;
|
||||
}
|
||||
else
|
||||
// Fall through
|
||||
case TGS_IntHex:
|
||||
if ((C < '0') || (C > '9'))
|
||||
{
|
||||
|
@ -741,6 +755,17 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
|
|||
}
|
||||
break;
|
||||
|
||||
case TGS_Float: // float (after decimal point): parse until non-numeric
|
||||
if ((C < '0') || (C > '9'))
|
||||
{
|
||||
Len = Min(Len, C4AUL_MAX_Identifier);
|
||||
SCopy(SPos0, pToken, Len);
|
||||
float value = StrToF32(pToken, 0);
|
||||
*pInt = *reinterpret_cast<int*>(&value);
|
||||
return ATT_FLOAT;
|
||||
}
|
||||
break;
|
||||
|
||||
case TGS_String: // string: parse until '"'; check for eof!
|
||||
|
||||
// string end
|
||||
|
@ -1020,6 +1045,7 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
|
|||
switch (eType)
|
||||
{
|
||||
case AB_INT:
|
||||
case AB_FLOAT:
|
||||
case AB_BOOL:
|
||||
case AB_STRING:
|
||||
case AB_C4ID:
|
||||
|
@ -2439,6 +2465,12 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
|
|||
switch (val.GetType())
|
||||
{
|
||||
case C4V_Int: AddBCC(AB_INT, val.GetData().Int); break;
|
||||
case C4V_Float:
|
||||
{
|
||||
C4Real::StorageType f = val.getFloat();
|
||||
AddBCC(AB_FLOAT, *reinterpret_cast<intptr_t*>(&f));
|
||||
break;
|
||||
}
|
||||
case C4V_Bool: AddBCC(AB_BOOL, val.GetData().Int); break;
|
||||
case C4V_String:
|
||||
AddBCC(AB_STRING, reinterpret_cast<intptr_t>(val._getStr()));
|
||||
|
@ -2474,6 +2506,12 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
|
|||
Shift();
|
||||
break;
|
||||
}
|
||||
case ATT_FLOAT: // constant in cInt
|
||||
{
|
||||
AddBCC(AB_FLOAT, cInt);
|
||||
Shift();
|
||||
break;
|
||||
}
|
||||
case ATT_BOOL: // constant in cInt
|
||||
{
|
||||
AddBCC(AB_BOOL, cInt);
|
||||
|
|
|
@ -284,6 +284,8 @@ const char* GetC4VName(const C4V_Type Type)
|
|||
return "nil";
|
||||
case C4V_Int:
|
||||
return "int";
|
||||
case C4V_Float:
|
||||
return "float";
|
||||
case C4V_Bool:
|
||||
return "bool";
|
||||
case C4V_C4Object:
|
||||
|
@ -309,6 +311,8 @@ char GetC4VID(const C4V_Type Type)
|
|||
return 'A';
|
||||
case C4V_Int:
|
||||
return 'i';
|
||||
case C4V_Float:
|
||||
return 'f';
|
||||
case C4V_Bool:
|
||||
return 'b';
|
||||
case C4V_C4Object:
|
||||
|
@ -338,6 +342,8 @@ C4V_Type GetC4VFromID(const char C4VID)
|
|||
return C4V_Any;
|
||||
case 'i':
|
||||
return C4V_Int;
|
||||
case 'f':
|
||||
return C4V_Float;
|
||||
case 'b':
|
||||
return C4V_Bool;
|
||||
case 'o':
|
||||
|
@ -400,9 +406,27 @@ bool C4Value::FnCnvObject(C4Value *Val, C4V_Type toType)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool FnI2F(C4Value *val, C4V_Type toType)
|
||||
{
|
||||
assert(val->GetType() == C4V_Int || val->GetType() == C4V_Bool);
|
||||
assert(toType == C4V_Float);
|
||||
val->SetFloat(val->_getInt());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool FnF2I(C4Value *val, C4V_Type toType)
|
||||
{
|
||||
assert(toType == C4V_Int || toType == C4V_Bool);
|
||||
assert(val->GetType() == C4V_Float);
|
||||
val->SetInt(val->_getFloat());
|
||||
return val->ConvertTo(toType);
|
||||
}
|
||||
|
||||
// Type conversion table
|
||||
#define CnvOK 0, false // allow conversion by same value
|
||||
#define CnvOK0 FnOk0, true
|
||||
#define CnvI2F FnI2F, false // convert int->C4Real
|
||||
#define CnvF2I FnF2I, false // convert C4Real->int
|
||||
#define CnvError FnCnvError, true
|
||||
#define CnvDeref FnCnvDeref, false
|
||||
#define CnvPLR FnCnvPLR, false
|
||||
|
@ -413,6 +437,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_Any - is always 0, convertible to everything
|
||||
{ CnvOK }, // any same
|
||||
{ CnvOK }, // int
|
||||
{ CnvOK }, // float
|
||||
{ CnvOK }, // Bool
|
||||
{ CnvOK }, // PropList
|
||||
{ CnvOK }, // C4Object
|
||||
|
@ -424,6 +449,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_Int
|
||||
{ CnvOK }, // any
|
||||
{ CnvOK }, // int same
|
||||
{ CnvI2F }, // float
|
||||
{ CnvOK }, // Bool
|
||||
{ CnvOK0 }, // PropList only if 0
|
||||
{ CnvOK0 }, // C4Object only if 0
|
||||
|
@ -432,9 +458,22 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ CnvError }, // Ref
|
||||
{ CnvError }, // PropListRef
|
||||
},
|
||||
{ // C4V_Float
|
||||
{ CnvOK }, // any
|
||||
{ CnvF2I }, // int
|
||||
{ CnvOK }, // float same
|
||||
{ CnvF2I }, // Bool
|
||||
{ CnvOK0 }, // PropList only if 0
|
||||
{ CnvOK0 }, // C4Object only if 0
|
||||
{ CnvOK0 }, // String only if 0
|
||||
{ CnvOK0 }, // Array only if 0
|
||||
{ CnvError }, // Ref
|
||||
{ CnvError }, // PropListRef
|
||||
},
|
||||
{ // C4V_Bool
|
||||
{ CnvOK }, // any
|
||||
{ CnvOK }, // int might be used
|
||||
{ CnvI2F }, // float
|
||||
{ CnvOK }, // Bool same
|
||||
{ CnvError }, // PropList NEVER!
|
||||
{ CnvError }, // C4Object NEVER!
|
||||
|
@ -446,6 +485,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_PropList
|
||||
{ CnvOK }, // any
|
||||
{ CnvError }, // int NEVER!
|
||||
{ CnvError }, // float
|
||||
{ CnvOK }, // Bool
|
||||
{ CnvOK }, // PropList same
|
||||
{ CnvObject }, // C4Object
|
||||
|
@ -457,6 +497,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_Object
|
||||
{ CnvOK }, // any
|
||||
{ CnvError }, // int NEVER!
|
||||
{ CnvError }, // float
|
||||
{ CnvOK }, // Bool
|
||||
{ CnvOK }, // PropList
|
||||
{ CnvOK }, // C4Object same
|
||||
|
@ -468,6 +509,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_String
|
||||
{ CnvOK }, // any
|
||||
{ CnvError }, // int NEVER!
|
||||
{ CnvError }, // float
|
||||
{ CnvOK }, // Bool
|
||||
{ CnvError }, // PropList NEVER!
|
||||
{ CnvError }, // C4Object NEVER!
|
||||
|
@ -479,6 +521,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_Array
|
||||
{ CnvOK }, // any
|
||||
{ CnvError }, // int NEVER!
|
||||
{ CnvError }, // float
|
||||
{ CnvOK }, // Bool
|
||||
{ CnvError }, // PropList NEVER!
|
||||
{ CnvError }, // C4Object NEVER!
|
||||
|
@ -490,6 +533,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_Ref - resolve reference and retry type check
|
||||
{ CnvDeref }, // any
|
||||
{ CnvDeref }, // int
|
||||
{ CnvDeref }, // float
|
||||
{ CnvDeref }, // Bool
|
||||
{ CnvDeref }, // PropList
|
||||
{ CnvDeref }, // C4Object
|
||||
|
@ -501,6 +545,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
{ // C4V_Ref - resolve reference and retry type check
|
||||
{ CnvPLR }, // any
|
||||
{ CnvPLR }, // int
|
||||
{ CnvPLR }, // float
|
||||
{ CnvPLR }, // Bool
|
||||
{ CnvPLR }, // PropList
|
||||
{ CnvPLR }, // C4Object
|
||||
|
@ -513,6 +558,8 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
|
||||
#undef CnvOK
|
||||
#undef CnvOK0
|
||||
#undef CnvI2F
|
||||
#undef CnvF2I
|
||||
#undef CnvError
|
||||
#undef CnvDeref
|
||||
#undef CnvPLR
|
||||
|
@ -529,6 +576,8 @@ StdStrBuf C4Value::GetDataString()
|
|||
{
|
||||
case C4V_Int:
|
||||
return FormatString("%ld", static_cast<long>(Data.Int));
|
||||
case C4V_Float:
|
||||
return FormatString("%f", static_cast<float>(C4Real(Data.Float)));
|
||||
case C4V_Bool:
|
||||
return StdStrBuf(Data ? "true" : "false");
|
||||
case C4V_C4Object:
|
||||
|
@ -671,6 +720,12 @@ void C4Value::CompileFunc(StdCompiler *pComp)
|
|||
Data.Int = iTmp;
|
||||
|
||||
break;
|
||||
case C4V_Float:
|
||||
{
|
||||
C4Real val = Data.Float;
|
||||
pComp->Value(val);
|
||||
Data.Float = val;
|
||||
}
|
||||
|
||||
// object: save object number instead
|
||||
case C4V_C4Object: case C4V_PropList:
|
||||
|
@ -761,20 +816,25 @@ bool C4Value::operator == (const C4Value& Value2) const
|
|||
assert(!Data);
|
||||
return Value2.Type == Type;
|
||||
case C4V_Int:
|
||||
switch (Value2.Type)
|
||||
{
|
||||
case C4V_Int:
|
||||
case C4V_Bool:
|
||||
return Data == Value2.Data;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case C4V_Bool:
|
||||
switch (Value2.Type)
|
||||
{
|
||||
case C4V_Int:
|
||||
case C4V_Bool:
|
||||
return Data == Value2.Data;
|
||||
case C4V_Float:
|
||||
return C4Real(Value2.Data.Float) == static_cast<int>(Data.Int);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case C4V_Float:
|
||||
switch (Value2.Type)
|
||||
{
|
||||
case C4V_Int:
|
||||
case C4V_Bool:
|
||||
return C4Real(Data.Float) == static_cast<int>(Data.Int);
|
||||
case C4V_Float:
|
||||
return Data.Float == Value2.Data.Float;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define INC_C4Value
|
||||
|
||||
#include "C4Id.h"
|
||||
#include "C4Real.h"
|
||||
|
||||
// class declarations
|
||||
class C4Value;
|
||||
|
@ -32,18 +33,19 @@ class C4ValueArray;
|
|||
// C4Value type
|
||||
enum C4V_Type
|
||||
{
|
||||
C4V_Any=0, // nil
|
||||
C4V_Int=1,
|
||||
C4V_Bool=2,
|
||||
C4V_PropList=3,
|
||||
C4V_C4Object=4,
|
||||
C4V_String=5,
|
||||
C4V_Array=6,
|
||||
C4V_Ref=7, // reference to a value (variable)
|
||||
C4V_PropListRef=8, // reference to an entry in a proplist
|
||||
C4V_Any, // nil
|
||||
C4V_Int,
|
||||
C4V_Float,
|
||||
C4V_Bool,
|
||||
C4V_PropList,
|
||||
C4V_C4Object,
|
||||
C4V_String,
|
||||
C4V_Array,
|
||||
C4V_Ref, // reference to a value (variable)
|
||||
C4V_PropListRef, // reference to an entry in a proplist
|
||||
|
||||
C4V_C4ObjectEnum=9, // enumerated object
|
||||
C4V_C4DefEnum=10 // enumerated object
|
||||
C4V_C4ObjectEnum, // enumerated object
|
||||
C4V_C4DefEnum // enumerated object
|
||||
};
|
||||
|
||||
#define C4V_Last (int) C4V_PropListRef
|
||||
|
@ -54,6 +56,7 @@ C4V_Type GetC4VFromID(char C4VID);
|
|||
|
||||
union C4V_Data
|
||||
{
|
||||
C4Real::StorageType Float;
|
||||
intptr_t Int;
|
||||
C4Object * Obj;
|
||||
C4PropList * PropList;
|
||||
|
@ -88,6 +91,8 @@ public:
|
|||
{ Data.Int = data; AddDataRef(); }
|
||||
explicit C4Value(int32_t data): NextRef(NULL), FirstRef(NULL), Type(C4V_Int), HasBaseArray(false)
|
||||
{ Data.Int = data; AddDataRef(); }
|
||||
explicit C4Value(C4Real data): NextRef(NULL), FirstRef(NULL), Type(C4V_Float), HasBaseArray(false)
|
||||
{ Data.Float = data; AddDataRef(); }
|
||||
explicit C4Value(C4Object *pObj): NextRef(NULL), FirstRef(NULL), Type(pObj ? C4V_C4Object : C4V_Any), HasBaseArray(false)
|
||||
{ Data.Obj = pObj; AddDataRef(); }
|
||||
explicit C4Value(C4String *pStr): NextRef(NULL), FirstRef(NULL), Type(pStr ? C4V_String : C4V_Any), HasBaseArray(false)
|
||||
|
@ -105,6 +110,7 @@ public:
|
|||
|
||||
// Checked getters
|
||||
int32_t getInt() { return ConvertTo(C4V_Int) ? Data.Int : 0; }
|
||||
C4Real getFloat() { return ConvertTo(C4V_Float) ? Data.Float : C4Real(0); }
|
||||
bool getBool() { return ConvertTo(C4V_Bool) ? !! Data : 0; }
|
||||
C4ID getC4ID();
|
||||
C4Object * getObj() { return ConvertTo(C4V_C4Object) ? Data.Obj : NULL; }
|
||||
|
@ -115,6 +121,7 @@ public:
|
|||
|
||||
// Unchecked getters
|
||||
int32_t _getInt() const { return Data.Int; }
|
||||
C4Real _getFloat() const { return Data.Float; }
|
||||
bool _getBool() const { return !! Data.Int; }
|
||||
C4Object *_getObj() const { return Data.Obj; }
|
||||
C4String *_getStr() const { return Data.Str; }
|
||||
|
@ -133,6 +140,8 @@ public:
|
|||
|
||||
void SetInt(int i) { C4V_Data d; d.Int = i; Set(d, C4V_Int); }
|
||||
|
||||
void SetFloat(C4Real f) { C4V_Data d; d.Float = f; Set(d, C4V_Float); }
|
||||
|
||||
void SetBool(bool b) { C4V_Data d; d.Int = b; Set(d, C4V_Bool); }
|
||||
|
||||
void SetObject(C4Object * Obj) { C4V_Data d; d.Obj = Obj; Set(d, C4V_C4Object); }
|
||||
|
@ -153,10 +162,29 @@ public:
|
|||
bool operator != (const C4Value& Value2) const;
|
||||
|
||||
// Change and set Type to int in case it was any before (avoids GuessType())
|
||||
C4Value & operator += (int32_t by) { GetData().Int += by; GetRefVal().Type=C4V_Int; return *this; }
|
||||
C4Value & operator -= (int32_t by) { GetData().Int -= by; GetRefVal().Type=C4V_Int; return *this; }
|
||||
C4Value & operator *= (int32_t by) { GetData().Int *= by; GetRefVal().Type=C4V_Int; return *this; }
|
||||
C4Value & operator /= (int32_t by) { GetData().Int /= by; GetRefVal().Type=C4V_Int; return *this; }
|
||||
#define C4VALUE_ARITHMETIC_OPERATOR(op) \
|
||||
/* combined arithmetic and assignment op */ \
|
||||
C4Value &operator op##= (const C4Value &rhs) \
|
||||
{ \
|
||||
/* Promote numeric values to float if any operand is float */ \
|
||||
if (rhs.GetType() == C4V_Float || GetType() == C4V_Float) \
|
||||
{ \
|
||||
C4Real lhsf = getFloat(); \
|
||||
C4Real rhsf = C4Value(rhs).getFloat(); \
|
||||
SetFloat(lhsf op##= rhsf); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
GetData().Int op##= rhs.GetData().Int; \
|
||||
GetRefVal().Type=C4V_Int; \
|
||||
} \
|
||||
return *this; \
|
||||
}
|
||||
C4VALUE_ARITHMETIC_OPERATOR(+)
|
||||
C4VALUE_ARITHMETIC_OPERATOR(-)
|
||||
C4VALUE_ARITHMETIC_OPERATOR(*)
|
||||
C4VALUE_ARITHMETIC_OPERATOR(/)
|
||||
#undef C4VALUE_ARITHMETIC_OPERATOR
|
||||
C4Value & operator %= (int32_t by) { GetData().Int %= by; GetRefVal().Type=C4V_Int; return *this; }
|
||||
C4Value & operator &= (int32_t by) { GetData().Int &= by; GetRefVal().Type=C4V_Int; return *this; }
|
||||
C4Value & operator ^= (int32_t by) { GetData().Int ^= by; GetRefVal().Type=C4V_Int; return *this; }
|
||||
|
@ -215,7 +243,7 @@ public:
|
|||
void CompileFunc(StdCompiler *pComp);
|
||||
|
||||
static inline bool IsNullableType(C4V_Type Type)
|
||||
{ return Type == C4V_Int || Type == C4V_Bool; }
|
||||
{ return Type == C4V_Int || Type == C4V_Float || Type == C4V_Bool; }
|
||||
|
||||
protected:
|
||||
// data
|
||||
|
@ -269,6 +297,7 @@ protected:
|
|||
|
||||
// converter
|
||||
inline C4Value C4VInt(int32_t iVal) { C4V_Data d; d.Int = iVal; return C4Value(d, C4V_Int); }
|
||||
inline C4Value C4VFloat(C4Real f) { return C4Value(f); }
|
||||
inline C4Value C4VBool(bool fVal) { C4V_Data d; d.Int = fVal; return C4Value(d, C4V_Bool); }
|
||||
C4Value C4VID(C4ID iVal);
|
||||
inline C4Value C4VObj(C4Object *pObj) { return C4Value(pObj); }
|
||||
|
@ -288,6 +317,13 @@ template <> struct C4ValueConv<int32_t>
|
|||
inline static int32_t _FromC4V(C4Value &v) { return v._getInt(); }
|
||||
inline static C4Value ToC4V(int32_t v) { return C4VInt(v); }
|
||||
};
|
||||
template <> struct C4ValueConv<C4Real>
|
||||
{
|
||||
inline static C4V_Type Type() { return C4V_Float; }
|
||||
inline static C4Real FromC4V(C4Value &v) { return v.getFloat(); }
|
||||
inline static C4Real _FromC4V(C4Value &v) { return v._getFloat(); }
|
||||
inline static C4Value ToC4V(C4Real v) { return C4VFloat(v); }
|
||||
};
|
||||
template <> struct C4ValueConv<bool>
|
||||
{
|
||||
inline static C4V_Type Type() { return C4V_Bool; }
|
||||
|
|
Loading…
Reference in New Issue