- some rework of vectors.h, mostly to remove all those silenced double->float conversions.

This commit is contained in:
Christoph Oelckers 2016-03-10 22:36:28 +01:00
parent f8ebfb541e
commit 9843f16cc0
6 changed files with 100 additions and 94 deletions

View file

@ -44,7 +44,6 @@
#include "tarray.h" #include "tarray.h"
#include "name.h" #include "name.h"
#include "zstring.h" #include "zstring.h"
#include "vectors.h"
class PClassActor; class PClassActor;
typedef TMap<int, PClassActor *> FClassMap; typedef TMap<int, PClassActor *> FClassMap;
@ -240,10 +239,13 @@ enum ESSType
SS_BGRA SS_BGRA
}; };
#ifndef M_PI // always use our own definition for consistency.
#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h #ifdef M_PI
#undef M_PI
#endif #endif
const double M_PI = 3.14159265358979323846; // matches value in gcc v2 math.h
template <typename T, size_t N> template <typename T, size_t N>
char ( &_ArraySizeHelper( T (&array)[N] ))[N]; char ( &_ArraySizeHelper( T (&array)[N] ))[N];

View file

@ -1,5 +1,6 @@
// HEADER FILES ------------------------------------------------------------ // HEADER FILES ------------------------------------------------------------
#include <math.h>
#include "m_joy.h" #include "m_joy.h"
#include "gameconfigfile.h" #include "gameconfigfile.h"
#include "d_event.h" #include "d_event.h"

View file

@ -37,6 +37,7 @@
* Cleaned up the source * Cleaned up the source
*/ */
#include <math.h>
#ifdef _WIN32 #ifdef _WIN32
#include <dos.h> #include <dos.h>
#include <conio.h> #include <conio.h>
@ -45,7 +46,7 @@
#include "opl.h" #include "opl.h"
#include "c_cvars.h" #include "c_cvars.h"
#define HALF_PI (PI*0.5) const double HALF_PI = (M_PI*0.5);
EXTERN_CVAR(Int, opl_core) EXTERN_CVAR(Int, opl_core)
extern int current_opl_core; extern int current_opl_core;

View file

@ -35,6 +35,7 @@
#define __V_VIDEO_H__ #define __V_VIDEO_H__
#include "doomtype.h" #include "doomtype.h"
#include "vectors.h"
#include "doomdef.h" #include "doomdef.h"
#include "dobject.h" #include "dobject.h"

View file

@ -42,16 +42,14 @@
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include "m_fixed.h"
#ifndef PI
#define PI 3.14159265358979323846 // matches value in gcc v2 math.h
#endif
#define EQUAL_EPSILON (1/65536.f) #define EQUAL_EPSILON (1/65536.f)
#define DEG2RAD(d) ((d)*PI/180.f) //#define DEG2RAD(d) ((d)*M_PI/180.)
#define RAD2DEG(r) ((r)*180.f/PI) //#define RAD2DEG(r) ((r)*180./M_PI)
template<class vec_t> struct TVector3; template<class vec_t> struct TVector3;
template<class vec_t> struct TRotator; template<class vec_t> struct TRotator;
@ -66,8 +64,8 @@ struct TVector2
{ {
} }
TVector2 (double a, double b) TVector2 (vec_t a, vec_t b)
: X(vec_t(a)), Y(vec_t(b)) : X(a), Y(b)
{ {
} }
@ -81,6 +79,9 @@ struct TVector2
{ {
} }
TVector2(const TRotator<vec_t> &rot);
void Zero() void Zero()
{ {
Y = X = 0; Y = X = 0;
@ -102,12 +103,12 @@ struct TVector2
// Access X and Y as an array // Access X and Y as an array
vec_t &operator[] (int index) vec_t &operator[] (int index)
{ {
return *(&X + index); return index == 0 ? X : Y;
} }
const vec_t &operator[] (int index) const const vec_t &operator[] (int index) const
{ {
return *(&X + index); return index == 0 ? X : Y;
} }
// Test for equality // Test for equality
@ -147,53 +148,53 @@ struct TVector2
return *this; return *this;
} }
friend TVector2 operator+ (const TVector2 &v, double scalar) friend TVector2 operator+ (const TVector2 &v, vec_t scalar)
{ {
return TVector2(v.X + scalar, v.Y + scalar); return TVector2(v.X + scalar, v.Y + scalar);
} }
friend TVector2 operator+ (double scalar, const TVector2 &v) friend TVector2 operator+ (vec_t scalar, const TVector2 &v)
{ {
return TVector2(v.X + scalar, v.Y + scalar); return TVector2(v.X + scalar, v.Y + scalar);
} }
// Scalar subtraction // Scalar subtraction
TVector2 &operator-= (double scalar) TVector2 &operator-= (vec_t scalar)
{ {
X -= scalar, Y -= scalar; X -= scalar, Y -= scalar;
return *this; return *this;
} }
TVector2 operator- (double scalar) const TVector2 operator- (vec_t scalar) const
{ {
return TVector2(X - scalar, Y - scalar); return TVector2(X - scalar, Y - scalar);
} }
// Scalar multiplication // Scalar multiplication
TVector2 &operator*= (double scalar) TVector2 &operator*= (vec_t scalar)
{ {
X *= scalar, Y *= scalar; X *= scalar, Y *= scalar;
return *this; return *this;
} }
friend TVector2 operator* (const TVector2 &v, double scalar) friend TVector2 operator* (const TVector2 &v, vec_t scalar)
{ {
return TVector2(v.X * scalar, v.Y * scalar); return TVector2(v.X * scalar, v.Y * scalar);
} }
friend TVector2 operator* (double scalar, const TVector2 &v) friend TVector2 operator* (vec_t scalar, const TVector2 &v)
{ {
return TVector2(v.X * scalar, v.Y * scalar); return TVector2(v.X * scalar, v.Y * scalar);
} }
// Scalar division // Scalar division
TVector2 &operator/= (double scalar) TVector2 &operator/= (vec_t scalar)
{ {
scalar = 1 / scalar, X *= scalar, Y *= scalar; scalar = 1 / scalar, X *= scalar, Y *= scalar;
return *this; return *this;
} }
TVector2 operator/ (double scalar) const TVector2 operator/ (vec_t scalar) const
{ {
scalar = 1 / scalar; scalar = 1 / scalar;
return TVector2(X * scalar, Y * scalar); return TVector2(X * scalar, Y * scalar);
@ -224,12 +225,12 @@ struct TVector2
} }
// Vector length // Vector length
double Length() const vec_t Length() const
{ {
return sqrt (X*X + Y*Y); return (vec_t)sqrt (X*X + Y*Y);
} }
double LengthSquared() const vec_t LengthSquared() const
{ {
return X*X + Y*Y; return X*X + Y*Y;
} }
@ -237,15 +238,15 @@ struct TVector2
// Return a unit vector facing the same direction as this one // Return a unit vector facing the same direction as this one
TVector2 Unit() const TVector2 Unit() const
{ {
double len = Length(); vec_t len = Length();
if (len != 0) len = 1 / len; if (len != 0) len = 1 / len;
return *this * len; return *this * len;
} }
// Scales this vector into a unit vector. Returns the old length // Scales this vector into a unit vector. Returns the old length
double MakeUnit() vec_t MakeUnit()
{ {
double len, ilen; vec_t len, ilen;
len = ilen = Length(); len = ilen = Length();
if (ilen != 0) ilen = 1 / ilen; if (ilen != 0) ilen = 1 / ilen;
*this *= ilen; *this *= ilen;
@ -296,8 +297,8 @@ struct TVector3
{ {
} }
TVector3 (double a, double b, double c) TVector3 (vec_t a, vec_t b, vec_t c)
: X(vec_t(a)), Y(vec_t(b)), Z(vec_t(c)) : X(a), Y(b), Z(c)
{ {
} }
@ -306,7 +307,7 @@ struct TVector3
{ {
} }
TVector3 (const Vector2 &xy, double z) TVector3 (const Vector2 &xy, vec_t z)
: X(xy.X), Y(xy.Y), Z(z) : X(xy.X), Y(xy.Y), Z(z)
{ {
} }
@ -327,12 +328,12 @@ struct TVector3
// Access X and Y and Z as an array // Access X and Y and Z as an array
vec_t &operator[] (int index) vec_t &operator[] (int index)
{ {
return *(&X + index); return index == 0 ? X : index == 1 ? Y : Z;
} }
const vec_t &operator[] (int index) const const vec_t &operator[] (int index) const
{ {
return *(&X + index); return index == 0 ? X : index == 1 ? Y : Z;
} }
// Test for equality // Test for equality
@ -366,59 +367,59 @@ struct TVector3
} }
// Scalar addition // Scalar addition
TVector3 &operator+= (double scalar) TVector3 &operator+= (vec_t scalar)
{ {
X += scalar, Y += scalar, Z += scalar; X += scalar, Y += scalar, Z += scalar;
return *this; return *this;
} }
friend TVector3 operator+ (const TVector3 &v, double scalar) friend TVector3 operator+ (const TVector3 &v, vec_t scalar)
{ {
return TVector3(v.X + scalar, v.Y + scalar, v.Z + scalar); return TVector3(v.X + scalar, v.Y + scalar, v.Z + scalar);
} }
friend TVector3 operator+ (double scalar, const TVector3 &v) friend TVector3 operator+ (vec_t scalar, const TVector3 &v)
{ {
return TVector3(v.X + scalar, v.Y + scalar, v.Z + scalar); return TVector3(v.X + scalar, v.Y + scalar, v.Z + scalar);
} }
// Scalar subtraction // Scalar subtraction
TVector3 &operator-= (double scalar) TVector3 &operator-= (vec_t scalar)
{ {
X -= scalar, Y -= scalar, Z -= scalar; X -= scalar, Y -= scalar, Z -= scalar;
return *this; return *this;
} }
TVector3 operator- (double scalar) const TVector3 operator- (vec_t scalar) const
{ {
return TVector3(X - scalar, Y - scalar, Z - scalar); return TVector3(X - scalar, Y - scalar, Z - scalar);
} }
// Scalar multiplication // Scalar multiplication
TVector3 &operator*= (double scalar) TVector3 &operator*= (vec_t scalar)
{ {
X = vec_t(X *scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar); X = vec_t(X *scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar);
return *this; return *this;
} }
friend TVector3 operator* (const TVector3 &v, double scalar) friend TVector3 operator* (const TVector3 &v, vec_t scalar)
{ {
return TVector3(v.X * scalar, v.Y * scalar, v.Z * scalar); return TVector3(v.X * scalar, v.Y * scalar, v.Z * scalar);
} }
friend TVector3 operator* (double scalar, const TVector3 &v) friend TVector3 operator* (vec_t scalar, const TVector3 &v)
{ {
return TVector3(v.X * scalar, v.Y * scalar, v.Z * scalar); return TVector3(v.X * scalar, v.Y * scalar, v.Z * scalar);
} }
// Scalar division // Scalar division
TVector3 &operator/= (double scalar) TVector3 &operator/= (vec_t scalar)
{ {
scalar = 1 / scalar, X = vec_t(X * scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar); scalar = 1 / scalar, X = vec_t(X * scalar), Y = vec_t(Y * scalar), Z = vec_t(Z * scalar);
return *this; return *this;
} }
TVector3 operator/ (double scalar) const TVector3 operator/ (vec_t scalar) const
{ {
scalar = 1 / scalar; scalar = 1 / scalar;
return TVector3(X * scalar, Y * scalar, Z * scalar); return TVector3(X * scalar, Y * scalar, Z * scalar);
@ -754,16 +755,11 @@ struct TAngle
{ {
} }
TAngle (float amt) TAngle (vec_t amt)
: Degrees(amt) : Degrees(amt)
{ {
} }
TAngle (double amt)
: Degrees(vec_t(amt))
{
}
TAngle (int amt) TAngle (int amt)
: Degrees(vec_t(amt)) : Degrees(vec_t(amt))
{ {
@ -786,8 +782,7 @@ struct TAngle
return *this; return *this;
} }
operator float() const { return Degrees; } operator vec_t() const { return Degrees; }
operator double() const { return Degrees; }
TAngle operator- () const TAngle operator- () const
{ {
@ -838,53 +833,53 @@ struct TAngle
return Degrees / other.Degrees; return Degrees / other.Degrees;
} }
TAngle &operator+= (double other) TAngle &operator+= (vec_t other)
{ {
Degrees = vec_t(Degrees + other); Degrees = Degrees + other;
return *this; return *this;
} }
TAngle &operator-= (double other) TAngle &operator-= (vec_t other)
{ {
Degrees = vec_t(Degrees - other); Degrees = Degrees - other;
return *this; return *this;
} }
TAngle &operator*= (double other) TAngle &operator*= (vec_t other)
{ {
Degrees = vec_t(Degrees * other); Degrees = Degrees * other;
return *this; return *this;
} }
TAngle &operator/= (double other) TAngle &operator/= (vec_t other)
{ {
Degrees = vec_t(Degrees / other); Degrees = Degrees / other;
return *this; return *this;
} }
TAngle operator+ (double other) const TAngle operator+ (vec_t other) const
{ {
return Degrees + other; return Degrees + other;
} }
TAngle operator- (double other) const TAngle operator- (vec_t other) const
{ {
return Degrees - other; return Degrees - other;
} }
friend TAngle operator- (double o1, TAngle o2) friend TAngle operator- (vec_t o1, TAngle o2)
{ {
return TAngle(o1 - o2.Degrees); return TAngle(o1 - o2.Degrees);
} }
TAngle operator* (double other) const TAngle operator* (vec_t other) const
{ {
return Degrees * vec_t(other); return Degrees * other;
} }
TAngle operator/ (double other) const TAngle operator/ (vec_t other) const
{ {
return Degrees / vec_t(other); return Degrees / other;
} }
// Should the comparisons consider an epsilon value? // Should the comparisons consider an epsilon value?
@ -918,32 +913,32 @@ struct TAngle
return Degrees != other.Degrees; return Degrees != other.Degrees;
} }
bool operator< (double other) const bool operator< (vec_t other) const
{ {
return Degrees < other; return Degrees < other;
} }
bool operator> (double other) const bool operator> (vec_t other) const
{ {
return Degrees > other; return Degrees > other;
} }
bool operator<= (double other) const bool operator<= (vec_t other) const
{ {
return Degrees <= other; return Degrees <= other;
} }
bool operator>= (double other) const bool operator>= (vec_t other) const
{ {
return Degrees >= other; return Degrees >= other;
} }
bool operator== (double other) const bool operator== (vec_t other) const
{ {
return Degrees == other; return Degrees == other;
} }
bool operator!= (double other) const bool operator!= (vec_t other) const
{ {
return Degrees != other; return Degrees != other;
} }
@ -951,49 +946,47 @@ struct TAngle
// Ensure the angle is between [0.0,360.0) degrees // Ensure the angle is between [0.0,360.0) degrees
TAngle &Normalize360() TAngle &Normalize360()
{ {
// Normalizing the angle converts it to a BAM, masks it, and converts it back to a float. // Normalizing the angle converts it to a BAM, which masks it, and converts it back to a float.
// Note: We MUST use xs_Float here because it is the only method that guarantees reliable wraparound.
// This could have been kept entirely in floating point using fmod(), but the MSVCRT has lots Degrees = (vec_t)ANGLE2DBL((unsigned int)FLOAT2ANGLE(Degrees));
// of overhead for that function, despite the x87 offering the FPREM instruction which does
// exactly what fmod() is supposed to do. So fmod ends up being an order of magnitude slower
// than casting to and from an int.
// Casting Degrees to a volatile ensures that the compiler will not try to evaluate an expression
// such as "TAngle a(360*100+24); a.Normalize360();" at compile time. Normally, it would see that
// this expression is constant and attempt to remove the Normalize360() call entirely and store
// the result of the function in the TAngle directly. Unfortunately, it does not do the casting
// properly and will overflow, producing an incorrect result. So we need to make sure it always
// evaluates Normalize360 at run time and never at compile time. (This applies to VC++. I don't
// know if other compilers suffer similarly).
Degrees = vec_t((int(*(volatile vec_t *)&Degrees * ((1<<30)/360.0)) & ((1<<30)-1)) * (360.f/(1<<30)));
return *this; return *this;
} }
// Ensures the angle is between (-180.0,180.0] degrees // Ensures the angle is between (-180.0,180.0] degrees
TAngle &Normalize180() TAngle &Normalize180()
{ {
Degrees = vec_t((((int(*(volatile vec_t *)&Degrees * ((1<<30)/360.0))+(1<<29)-1) & ((1<<30)-1)) - (1<<29)+1) * (360.f/(1<<30))); Degrees = (vec_t)ANGLE2DBL((signed int)FLOAT2ANGLE(Degrees));
return *this; return *this;
} }
// Like Normalize360(), except the integer value is not converted back to a float. // Like Normalize360(), except the integer value is not converted back to a float.
// The steps parameter must be a power of 2. // The steps parameter must be a power of 2.
int Quantize(int steps) int Quantize(int steps) const
{ {
return int(*(volatile vec_t *)&Degrees * (steps/360.0)) & (steps-1); return xs_CRoundToInt((Degrees * (steps/360.0)) & (steps-1));
}
vec_t Radians() const
{
return Degrees * (M_PI / 180.0);
}
unsigned BAM() const
{
return FLOAT2ANGLE(Degrees);
} }
}; };
template<class T> template<class T>
inline double ToRadians (const TAngle<T> &deg) inline double ToRadians (const TAngle<T> &deg)
{ {
return double(deg.Degrees * (PI / 180.0)); return double(deg.Degrees * (M_PI / 180.0));
} }
template<class T> template<class T>
inline TAngle<T> ToDegrees (double rad) inline TAngle<T> ToDegrees (double rad)
{ {
return TAngle<T> (double(rad * (180.0 / PI))); return TAngle<T> (T(rad * (180.0 / M_PI)));
} }
template<class T> template<class T>
@ -1023,13 +1016,13 @@ inline TAngle<T> fabs (const TAngle<T> &deg)
template<class T> template<class T>
inline TAngle<T> vectoyaw (const TVector2<T> &vec) inline TAngle<T> vectoyaw (const TVector2<T> &vec)
{ {
return atan2(vec.Y, vec.X) * (180.0 / PI); return (vec_t)atan2(vec.Y, vec.X) * (180.0 / M_PI);
} }
template<class T> template<class T>
inline TAngle<T> vectoyaw (const TVector3<T> &vec) inline TAngle<T> vectoyaw (const TVector3<T> &vec)
{ {
return atan2(vec.Y, vec.X) * (180.0 / PI); return (vec_t)atan2(vec.Y, vec.X) * (180.0 / M_PI);
} }
// Much of this is copied from TVector3. Is all that functionality really appropriate? // Much of this is copied from TVector3. Is all that functionality really appropriate?
@ -1203,6 +1196,13 @@ inline TVector3<T>::TVector3 (const TRotator<T> &rot)
{ {
} }
template<class T>
inline TVector2<T>::TVector2(const TRotator<T> &rot)
: X(cos(rot.Yaw)), Y(sin(rot.Yaw))
{
}
template<class T> template<class T>
inline TMatrix3x3<T>::TMatrix3x3(const TVector3<T> &axis, TAngle<T> degrees) inline TMatrix3x3<T>::TMatrix3x3(const TVector3<T> &axis, TAngle<T> degrees)
{ {

View file

@ -1,3 +1,4 @@
#include <math.h>
#include "dobject.h" #include "dobject.h"
#include "sc_man.h" #include "sc_man.h"
#include "c_console.h" #include "c_console.h"