forked from Mirrors/openclonk
Merge default into floating-point
commit
61627c7a31
|
@ -80,6 +80,7 @@ set(CMAKE_REQUIRED_FLAGS ${OC_REQUIRED_FLAGS})
|
|||
CHECK_CXX_SOURCE_COMPILES("void f(struct D&&); int main() { return 0; }" HAVE_RVALUE_REF)
|
||||
CHECK_CXX_SOURCE_COMPILES("int main() { void *d = nullptr; }" HAVE_NULLPTR)
|
||||
set(CMAKE_REQUIRED_FLAGS "${SAFE_CMAKE_REQUIRED_FLAGS}")
|
||||
CHECK_CXX_SOURCE_COMPILES("int main() { static_assert(true, \"\"); }" HAVE_STATIC_ASSERT)
|
||||
|
||||
if(MSVC_VERSION GREATER 1499)
|
||||
# Activate minimal rebuild
|
||||
|
@ -345,6 +346,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
|
||||
|
|
|
@ -120,6 +120,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 you have support for nullptr. */
|
||||
#cmakedefine HAVE_NULLPTR 1
|
||||
|
||||
/* Define to 1 if your compiler supports static_assert */
|
||||
#cmakedefine HAVE_STATIC_ASSERT 1
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
|
||||
<!DOCTYPE funcs SYSTEM "../../../clonk.dtd">
|
||||
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
|
||||
<funcs>
|
||||
<func>
|
||||
<title>float<title>
|
||||
<category>Arithmetik</category>
|
||||
<version>4.10.0.0 OC</version>
|
||||
<syntax>
|
||||
<rtype>float</rtype>
|
||||
<params>
|
||||
<param><type>int</type><name>i</name><desc>Die Ganzzahl, die in eine Fließkommazahl konvertiert werden soll.</desc></param>
|
||||
</params>
|
||||
</syntax>
|
||||
<desc>Wandelt eine Ganzzahl in eine Fließkommazahl um. Ist der Wert von <em>i</em> nicht exakt darstellbar, wird der darstellbare Wert zurückgegeben, der die geringste Abweichung vom tatsächlichen Wert hat.</desc>
|
||||
<examples>
|
||||
<example>
|
||||
<code>float(2)</code>
|
||||
<text>Gibt die Zahl 2.0 zurück.</text>
|
||||
</example>
|
||||
</examples>
|
||||
</func>
|
||||
<related>
|
||||
<funclink>int</funclink>
|
||||
<funclink>C4Id</funclink>
|
||||
</related>
|
||||
<author>isilkor</author><date>2010-07-10</date>
|
||||
</funcs>
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
|
||||
<!DOCTYPE funcs SYSTEM "../../../clonk.dtd">
|
||||
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
|
||||
<funcs>
|
||||
<func>
|
||||
<title>int</title>
|
||||
<category>Arithmetik</category>
|
||||
<version>4.10.0.0 OC</version>
|
||||
<syntax>
|
||||
<rtype>int</rtype>
|
||||
<params>
|
||||
<param><type>float</type><name>f</name><desc>Die Fließkommazahl, die in eine Ganzzahl konvertiert werden soll.</desc></param>
|
||||
</params>
|
||||
</syntax>
|
||||
<desc>Wandelt eine Fließkommazahl in eine Ganzzahl um. Dabei werden Nachkommastellen abgeschnitten. Ist der Wert von <em>f</em> außerhalb des Wertebereichs einer vorzeichenbehafteten 32-bit-Ganzzahl, so ist der Rückgabewert <em>nil</em>.</desc>
|
||||
<examples>
|
||||
<example>
|
||||
<code>int(2.5)</code>
|
||||
<text>Gibt die Zahl 2 zurück.</text>
|
||||
</example>
|
||||
</examples>
|
||||
</func>
|
||||
<related>
|
||||
<funclink>float</funclink>
|
||||
<funclink>C4Id</funclink>
|
||||
</related>
|
||||
<author>isilkor</author><date>2010-07-10</date>
|
||||
</funcs>
|
|
@ -69,6 +69,7 @@ C4Application::~C4Application()
|
|||
bool C4Application::DoInit()
|
||||
{
|
||||
assert(AppState == C4AS_None);
|
||||
|
||||
// Config overwrite by parameter
|
||||
StdStrBuf sConfigFilename;
|
||||
char szParameter[_MAX_PATH+1];
|
||||
|
@ -107,6 +108,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(C4REVISION);
|
||||
|
||||
// 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;
|
||||
|
|
|
@ -1529,7 +1529,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);
|
||||
|
|
|
@ -262,7 +262,7 @@ void C4Object::DoMovement()
|
|||
{
|
||||
// Horizontal movement - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Move to target
|
||||
while (Abs<C4Real>(fix_x - ctcox) > C4REAL10(5))
|
||||
while (Abs<C4Real>(fix_x - ctcox) >= C4Real(1))
|
||||
{
|
||||
// Next step
|
||||
int step = Sign<C4Real>(new_x - fix_x);
|
||||
|
@ -286,7 +286,7 @@ void C4Object::DoMovement()
|
|||
VerticalBounds(new_y);
|
||||
ctcoy=fixtoi(new_y);
|
||||
// Move to target
|
||||
while (Abs<C4Real>(fix_y - ctcoy) > C4REAL10(5))
|
||||
while (Abs<C4Real>(fix_y - ctcoy) >= C4Real(1))
|
||||
{
|
||||
// Next step
|
||||
int step = Sign<C4Real>(new_y - fix_y);
|
||||
|
|
|
@ -3510,6 +3510,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)
|
||||
|
@ -5889,6 +5890,18 @@ static Nillable<C4String *> FnGetConstantNameByValue(C4AulContext *ctx, int valu
|
|||
return C4VNull;
|
||||
}
|
||||
|
||||
static Nillable<int> FnInt(C4AulContext *ctx, C4Real f)
|
||||
{
|
||||
if (f < std::numeric_limits<int>::min() || f > std::numeric_limits<int>::max())
|
||||
return C4VNull;
|
||||
return f;
|
||||
}
|
||||
|
||||
static C4Real FnFloat(C4AulContext *ctx, int i)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
//=========================== C4Script Function Map ===================================
|
||||
|
||||
// defined function class
|
||||
|
@ -6402,6 +6415,8 @@ void InitFunctionMap(C4AulScriptEngine *pEngine)
|
|||
AddFunc(pEngine, "GetConstantNameByValue", FnGetConstantNameByValue, false);
|
||||
|
||||
AddFunc(pEngine, "Translate", FnTranslate);
|
||||
AddFunc(pEngine, "int", FnInt);
|
||||
AddFunc(pEngine, "float", FnFloat);
|
||||
}
|
||||
|
||||
C4ScriptConstDef C4ScriptConstMap[]=
|
||||
|
|
9045
src/lib/C4Real.cpp
9045
src/lib/C4Real.cpp
File diff suppressed because it is too large
Load Diff
414
src/lib/C4Real.h
414
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,320 +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; };
|
||||
|
||||
inline C4Fixed operator + (float iVal2) const { return C4Fixed(*this) += iVal2; }
|
||||
inline C4Fixed operator - (float iVal2) const { return C4Fixed(*this) -= iVal2; }
|
||||
inline C4Fixed operator * (float iVal2) const { return C4Fixed(*this) *= iVal2; }
|
||||
inline C4Fixed operator / (float iVal2) const { return C4Fixed(*this) /= iVal2; }
|
||||
typedef StorageTypeSelector<C4RealImpl, typename boost::is_class<C4RealImpl>::type> StorageType;
|
||||
static_assert(boost::is_pod<StorageType>::value, "C4RealBase: StorageType is not a POD type");
|
||||
|
||||
#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
|
||||
|
||||
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)); }
|
||||
|
||||
inline bool operator == (float iVal2) const { return operator == (C4Fixed(iVal2)); }
|
||||
inline bool operator < (float iVal2) const { return operator < (C4Fixed(iVal2)); }
|
||||
inline bool operator > (float iVal2) const { return operator > (C4Fixed(iVal2)); }
|
||||
inline bool operator <= (float iVal2) const { return operator <= (C4Fixed(iVal2)); }
|
||||
inline bool operator >= (float iVal2) const { return operator >= (C4Fixed(iVal2)); }
|
||||
inline bool operator != (float 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_cvttss_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)))
|
||||
|
|
|
@ -522,6 +522,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);
|
||||
|
@ -705,6 +710,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);
|
||||
|
|
|
@ -181,6 +181,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_CPROPLIST, // constant: proplist
|
||||
|
@ -230,6 +231,7 @@ struct C4AulBCC
|
|||
union
|
||||
{
|
||||
int32_t i;
|
||||
C4Real::StorageType fl;
|
||||
C4String * s;
|
||||
C4PropList * p;
|
||||
C4ValueArray * a;
|
||||
|
|
|
@ -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;
|
||||
|
@ -298,7 +302,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->SetInt(pPar1->_getInt() / pPar2->_getInt());
|
||||
*pPar1 /= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -306,7 +310,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
pPar1->SetInt(pPar1->_getInt() * pPar2->_getInt());
|
||||
*pPar1 *= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -325,7 +329,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
pPar1->SetInt(pPar1->_getInt() - pPar2->_getInt());
|
||||
*pPar1 -= *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
|
@ -333,7 +337,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
{
|
||||
CheckOpPars(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
pPar1->SetInt(pPar1->_getInt() + 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"
|
||||
|
@ -439,11 +440,11 @@ C4ScriptOpDef C4ScriptOpMap[] =
|
|||
|
||||
// postfix
|
||||
{ 14, "**", AB_Pow, AB_ERR, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 13, "/", AB_Div, AB_ERR, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 13, "*", AB_Mul, AB_ERR, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 13, "/", AB_Div, AB_ERR, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
|
||||
{ 13, "*", AB_Mul, AB_ERR, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
|
||||
{ 13, "%", AB_Mod, AB_ERR, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 12, "-", AB_Sub, AB_ERR, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 12, "+", AB_Sum, AB_ERR, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 12, "-", AB_Sub, AB_ERR, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
|
||||
{ 12, "+", AB_Sum, AB_ERR, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
|
||||
{ 11, "<<", AB_LeftShift, AB_ERR, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 11, ">>", AB_RightShift, AB_ERR, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 10, "<", AB_LessThan, AB_ERR, 1, 0, 0, C4V_Bool, C4V_Int, C4V_Int},
|
||||
|
@ -549,6 +550,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
|
||||
|
@ -575,6 +581,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
|
||||
};
|
||||
|
@ -719,6 +726,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'))
|
||||
{
|
||||
|
@ -751,6 +765,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
|
||||
|
@ -1025,6 +1050,7 @@ int C4AulParseState::GetStackValue(C4AulBCCType eType, intptr_t X)
|
|||
switch (eType)
|
||||
{
|
||||
case AB_INT:
|
||||
case AB_FLOAT:
|
||||
case AB_BOOL:
|
||||
case AB_STRING:
|
||||
case AB_CPROPLIST:
|
||||
|
@ -2500,6 +2526,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()));
|
||||
|
@ -2540,6 +2572,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);
|
||||
|
|
|
@ -107,6 +107,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:
|
||||
|
@ -130,6 +132,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_PropList:
|
||||
|
@ -157,6 +161,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':
|
||||
|
@ -186,17 +192,21 @@ bool C4Value::FnCnvObject() const
|
|||
if (dynamic_cast<C4Object *>(Data.PropList)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Type conversion table
|
||||
#define CnvOK C4VCnvFn::CnvOK, false // allow conversion by same value
|
||||
#define CnvOK0 C4VCnvFn::CnvOK0, true
|
||||
#define CnvError C4VCnvFn::CnvError, true
|
||||
#define CnvObject C4VCnvFn::CnvObject, false
|
||||
#define CnvI2F C4VCnvFn::CnvI2F, false // convert int->C4Real
|
||||
#define CnvF2I C4VCnvFn::CnvF2I, false // convert C4Real->int
|
||||
|
||||
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
|
||||
|
@ -206,15 +216,27 @@ 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
|
||||
{ CnvOK0 }, // String only if 0
|
||||
{ CnvOK0 }, // Array only if 0
|
||||
},
|
||||
{ // 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
|
||||
},
|
||||
{ // C4V_Bool
|
||||
{ CnvOK }, // any
|
||||
{ CnvOK }, // int might be used
|
||||
{ CnvI2F }, // float
|
||||
{ CnvOK }, // Bool same
|
||||
{ CnvError }, // PropList NEVER!
|
||||
{ CnvError }, // C4Object NEVER!
|
||||
|
@ -224,6 +246,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
|
||||
|
@ -233,6 +256,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
|
||||
|
@ -242,6 +266,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!
|
||||
|
@ -251,6 +276,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!
|
||||
|
@ -261,6 +287,8 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
|
|||
|
||||
#undef CnvOK
|
||||
#undef CnvOK0
|
||||
#undef CnvI2F
|
||||
#undef CnvF2I
|
||||
#undef CnvError
|
||||
#undef CnvObject
|
||||
|
||||
|
@ -273,6 +301,8 @@ StdStrBuf C4Value::GetDataString() const
|
|||
{
|
||||
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:
|
||||
|
@ -397,6 +427,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:
|
||||
|
@ -494,20 +530,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,16 +33,17 @@ 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_Any, // nil
|
||||
C4V_Int,
|
||||
C4V_Float,
|
||||
C4V_Bool,
|
||||
C4V_PropList,
|
||||
C4V_C4Object,
|
||||
C4V_String,
|
||||
C4V_Array, // 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_Array
|
||||
|
@ -52,6 +54,7 @@ C4V_Type GetC4VFromID(char C4VID);
|
|||
|
||||
union C4V_Data
|
||||
{
|
||||
C4Real::StorageType Float;
|
||||
intptr_t Int;
|
||||
C4Object * Obj;
|
||||
C4PropList * PropList;
|
||||
|
@ -66,7 +69,7 @@ union C4V_Data
|
|||
// converter function, used in converter table
|
||||
struct C4VCnvFn
|
||||
{
|
||||
enum { CnvOK, CnvOK0, CnvError, CnvObject } Function;
|
||||
enum { CnvOK, CnvOK0, CnvError, CnvObject, CnvF2I, CnvI2F } Function;
|
||||
bool Warn;
|
||||
};
|
||||
|
||||
|
@ -85,6 +88,8 @@ public:
|
|||
{ Data.Int = data; }
|
||||
explicit C4Value(int32_t data): Type(C4V_Int), NextRef(NULL)
|
||||
{ Data.Int = data; }
|
||||
explicit C4Value(C4Real data): Type(C4V_Float), NextRef(NULL)
|
||||
{ Data.Float = data; AddDataRef(); }
|
||||
explicit C4Value(C4Object *pObj): Type(pObj ? C4V_C4Object : C4V_Any), NextRef(NULL)
|
||||
{ Data.Obj = pObj; AddDataRef(); }
|
||||
explicit C4Value(C4String *pStr): Type(pStr ? C4V_String : C4V_Any), NextRef(NULL)
|
||||
|
@ -99,8 +104,25 @@ public:
|
|||
~C4Value() { DelDataRef(Data, Type, NextRef); }
|
||||
|
||||
// Checked getters
|
||||
int32_t getInt() const { return ConvertTo(C4V_Int) ? Data.Int : 0; }
|
||||
int32_t getInt() const
|
||||
{
|
||||
if (!ConvertTo(C4V_Int))
|
||||
return 0;
|
||||
else if (Type == C4V_Float)
|
||||
return C4Real(Data.Float);
|
||||
else
|
||||
return Data.Int;
|
||||
}
|
||||
bool getBool() const { return ConvertTo(C4V_Bool) ? !! Data : 0; }
|
||||
C4Real getFloat() const
|
||||
{
|
||||
if (!ConvertTo(C4V_Float))
|
||||
return C4Real(0);
|
||||
else if (Type == C4V_Float)
|
||||
return Data.Float;
|
||||
else
|
||||
return static_cast<int32_t>(Data.Int);
|
||||
}
|
||||
C4ID getC4ID() const;
|
||||
C4Object * getObj() const { return ConvertTo(C4V_C4Object) ? Data.Obj : NULL; }
|
||||
C4PropList * getPropList() const { return ConvertTo(C4V_PropList) ? Data.PropList : NULL; }
|
||||
|
@ -109,6 +131,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; }
|
||||
|
@ -125,6 +148,8 @@ public:
|
|||
void Set(const C4Value &nValue) { if (this != &nValue) Set(nValue.Data, nValue.Type); }
|
||||
|
||||
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); }
|
||||
void SetString(C4String * Str) { C4V_Data d; d.Str = Str; Set(d, C4V_String); }
|
||||
|
@ -135,19 +160,70 @@ public:
|
|||
bool operator == (const C4Value& Value2) const;
|
||||
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) { Data.Int += by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator -= (int32_t by) { Data.Int -= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator *= (int32_t by) { Data.Int *= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator /= (int32_t by) { Data.Int /= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator %= (int32_t by) { Data.Int %= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator &= (int32_t by) { Data.Int &= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator ^= (int32_t by) { Data.Int ^= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator |= (int32_t by) { Data.Int |= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator ++ () { Data.Int++; Type=C4V_Int; return *this; }
|
||||
C4Value operator ++ (int) { C4Value old = *this; ++(*this); return old; }
|
||||
C4Value & operator -- () { Data.Int--; Type=C4V_Int; return *this; }
|
||||
C4Value operator -- (int) { C4Value old = *this; --(*this); return old; }
|
||||
#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 = rhs.getFloat(); \
|
||||
SetFloat(lhsf op##= rhsf); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
Data.Int op##= rhs.Data.Int; \
|
||||
Type=C4V_Int; \
|
||||
} \
|
||||
return *this; \
|
||||
}
|
||||
C4VALUE_ARITHMETIC_OPERATOR(+)
|
||||
C4VALUE_ARITHMETIC_OPERATOR(-)
|
||||
C4VALUE_ARITHMETIC_OPERATOR(*)
|
||||
C4VALUE_ARITHMETIC_OPERATOR(/)
|
||||
#undef C4VALUE_ARITHMETIC_OPERATOR
|
||||
|
||||
C4Value &operator++()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case C4V_Int:
|
||||
case C4V_Bool:
|
||||
++Data.Int; Type = C4V_Int; break;
|
||||
case C4V_Float:
|
||||
SetFloat(getFloat() + 1.0f); break;
|
||||
default:
|
||||
assert(!"Can't increment a non-numeric value");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
C4Value operator++(int)
|
||||
{
|
||||
C4Value nrv(*this);
|
||||
operator++();
|
||||
return nrv;
|
||||
}
|
||||
C4Value &operator--()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case C4V_Int:
|
||||
case C4V_Bool:
|
||||
--Data.Int; Type = C4V_Int; break;
|
||||
case C4V_Float:
|
||||
SetFloat(getFloat() - 1.0f); break;
|
||||
default:
|
||||
assert(!"Can't decrement a non-numeric value");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
C4Value operator--(int)
|
||||
{
|
||||
C4Value nrv(*this);
|
||||
operator--();
|
||||
return nrv;
|
||||
}
|
||||
|
||||
// getters
|
||||
C4V_Data GetData() const { return Data; }
|
||||
|
@ -168,6 +244,8 @@ public:
|
|||
case C4VCnvFn::CnvOK0: return !*this;
|
||||
case C4VCnvFn::CnvError: return false;
|
||||
case C4VCnvFn::CnvObject: return FnCnvObject();
|
||||
case C4VCnvFn::CnvF2I: return Type == C4V_Float && (vtToType == C4V_Int || vtToType == C4V_Bool);
|
||||
case C4VCnvFn::CnvI2F: return (Type == C4V_Int || Type == C4V_Bool) && vtToType == C4V_Float;
|
||||
}
|
||||
assert(!"C4Value::ConvertTo: Invalid conversion function specified");
|
||||
return false;
|
||||
|
@ -181,7 +259,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
|
||||
|
@ -213,6 +291,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); }
|
||||
|
@ -231,6 +310,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