diff --git a/GNUmakefile b/GNUmakefile index e250f9b97..3561db628 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -201,6 +201,8 @@ engine_objs := \ mhk.cpp \ pngwrite.cpp \ miniz.c \ + fix16.c \ + fix16_str.c \ engine_editor_objs := \ build.cpp \ diff --git a/platform/Windows/eduke32.vcxproj b/platform/Windows/eduke32.vcxproj index a2987ee02..050b28bc9 100644 --- a/platform/Windows/eduke32.vcxproj +++ b/platform/Windows/eduke32.vcxproj @@ -103,6 +103,8 @@ + + @@ -263,6 +265,8 @@ + + diff --git a/platform/Windows/eduke32.vcxproj.filters b/platform/Windows/eduke32.vcxproj.filters index 7e2ce7fd5..d4dce160b 100644 --- a/platform/Windows/eduke32.vcxproj.filters +++ b/platform/Windows/eduke32.vcxproj.filters @@ -567,6 +567,12 @@ glad\headers\glad + + build\headers + + + build\headers + @@ -989,6 +995,12 @@ glad\source + + build\source + + + build\source + diff --git a/platform/Windows/msvc.mak b/platform/Windows/msvc.mak index beeb5f235..d21119b36 100644 --- a/platform/Windows/msvc.mak +++ b/platform/Windows/msvc.mak @@ -184,7 +184,9 @@ ENGINE_OBJS= \ $(ENGINE_OBJ)\screenshot.$o \ $(ENGINE_OBJ)\mhk.$o \ $(ENGINE_OBJ)\pngwrite.$o \ - $(ENGINE_OBJ)\miniz.$o + $(ENGINE_OBJ)\miniz.$o \ + $(ENGINE_OBJ)\fix16.$o \ + $(ENGINE_OBJ)\fix16_str.$o ENGINE_EDITOR_OBJS=$(ENGINE_OBJ)\build.$o \ diff --git a/source/build/Dependencies.mak b/source/build/Dependencies.mak index 618eb7483..65397e598 100644 --- a/source/build/Dependencies.mak +++ b/source/build/Dependencies.mak @@ -29,8 +29,8 @@ $(ENGINE_OBJ)/textfont.$o: $(ENGINE_SRC)/textfont.cpp $(ENGINE_OBJ)/smalltextfont.$o: $(ENGINE_SRC)/smalltextfont.cpp $(ENGINE_OBJ)/glbuild.$o: $(ENGINE_SRC)/glbuild.cpp $(ENGINE_INC)/glbuild.h $(ENGINE_INC)/baselayer.h $(GLAD_INC)/glad/glad.h $(ENGINE_OBJ)/kplib.$o: $(ENGINE_SRC)/kplib.cpp $(ENGINE_INC)/compat.h $(ENGINE_INC)/kplib.h -$(ENGINE_OBJ)/lz4.$o: $(ENGINE_SRC)/lz4.c $(ENGINE_INC)/lz4.h $(ENGINE_OBJ)/md4.$o: $(ENGINE_SRC)/md4.cpp $(ENGINE_INC)/md4.h +$(ENGINE_OBJ)/lz4.$o: $(ENGINE_SRC)/lz4.c $(ENGINE_INC)/lz4.h $(ENGINE_OBJ)/osd.$o: $(ENGINE_SRC)/osd.cpp $(ENGINE_INC)/build.h $(ENGINE_INC)/buildtypes.h $(ENGINE_INC)/osd.h $(ENGINE_INC)/compat.h $(ENGINE_INC)/baselayer.h $(ENGINE_OBJ)/pragmas.$o: $(ENGINE_SRC)/pragmas.cpp $(ENGINE_INC)/compat.h $(ENGINE_OBJ)/scriptfile.$o: $(ENGINE_SRC)/scriptfile.cpp $(ENGINE_INC)/scriptfile.h $(ENGINE_INC)/cache1d.h $(ENGINE_INC)/compat.h @@ -46,6 +46,8 @@ $(ENGINE_OBJ)/winbits.$o: $(ENGINE_SRC)/winbits.cpp $(ENGINE_INC)/winbits.h $(ENGINE_OBJ)/xxhash.$o: $(ENGINE_SRC)/xxhash.c $(ENGINE_INC)/xxhash.h $(ENGINE_OBJ)/pngwrite.$o: $(ENGINE_SRC)/pngwrite.cpp $(ENGINE_INC)/pngwrite.h $(ENGINE_OBJ)/miniz.$o: $(ENGINE_SRC)/miniz.c $(ENGINE_INC)/miniz.h +$(ENGINE_OBJ)/fix16.$o: $(ENGINE_SRC)/fix16.c $(ENGINE_INC)/fix16.h +$(ENGINE_OBJ)/fix16_str.$o: $(ENGINE_SRC)/fix16_str.c $(ENGINE_INC)/fix16.h $(ENGINE_OBJ)/lunatic.$o: $(ENGINE_SRC)/lunatic.cpp $(ENGINE_INC)/lunatic.h $(ENGINE_INC)/cache1d.h $(ENGINE_INC)/osd.h diff --git a/source/build/include/compat.h b/source/build/include/compat.h index c0b876186..36005b3bc 100644 --- a/source/build/include/compat.h +++ b/source/build/include/compat.h @@ -1241,6 +1241,7 @@ static inline void maybe_grow_buffer(char ** const buffer, int32_t * const buffe #define LIBDIVIDE_NONAMESPACE #define LIBDIVIDE_NOINLINE #include "libdivide.h" +#include "fix16.h" /* End dependence on compat.o object. */ diff --git a/source/build/include/fix16.h b/source/build/include/fix16.h new file mode 100644 index 000000000..03a64f8e2 --- /dev/null +++ b/source/build/include/fix16.h @@ -0,0 +1,318 @@ +#ifndef __libfixmath_fix16_h__ +#define __libfixmath_fix16_h__ + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/* These options may let the optimizer to remove some calls to the functions. + * Refer to http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html + */ +#ifndef FIXMATH_FUNC_ATTRS +# ifdef __GNUC__ +# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) +# define FIXMATH_FUNC_ATTRS __attribute__((leaf, nothrow, const)) +# else +# define FIXMATH_FUNC_ATTRS __attribute__((nothrow, const)) +# endif +# else +# define FIXMATH_FUNC_ATTRS +# endif +#endif + +#include + +typedef int32_t fix16_t; + +static const fix16_t FOUR_DIV_PI = 0x145F3; /*!< Fix16 value of 4/PI */ +static const fix16_t _FOUR_DIV_PI2 = 0xFFFF9840; /*!< Fix16 value of -4/PIĀ² */ +static const fix16_t X4_CORRECTION_COMPONENT = 0x399A; /*!< Fix16 value of 0.225 */ +static const fix16_t PI_DIV_4 = 0x0000C90F; /*!< Fix16 value of PI/4 */ +static const fix16_t THREE_PI_DIV_4 = 0x00025B2F; /*!< Fix16 value of 3PI/4 */ + +static const fix16_t fix16_maximum = 0x7FFFFFFF; /*!< the maximum value of fix16_t */ +static const fix16_t fix16_minimum = 0x80000000; /*!< the minimum value of fix16_t */ +static const fix16_t fix16_overflow = 0x80000000; /*!< the value used to indicate overflows when FIXMATH_NO_OVERFLOW is not specified */ + +static const fix16_t fix16_pi = 205887; /*!< fix16_t value of pi */ +static const fix16_t fix16_e = 178145; /*!< fix16_t value of e */ +static const fix16_t fix16_one = 0x00010000; /*!< fix16_t value of 1 */ + +/* Conversion functions between fix16_t and float/integer. + * These are inlined to allow compiler to optimize away constant numbers + */ +static inline fix16_t fix16_from_int(int a) { return a * fix16_one; } +static inline float fix16_to_float(fix16_t a) { return (float)a / fix16_one; } +static inline double fix16_to_dbl(fix16_t a) { return (double)a / fix16_one; } + +static inline int fix16_to_int(fix16_t a) +{ +#ifdef FIXMATH_NO_ROUNDING + return (a >> 16); +#else + if (a >= 0) + return (a + (fix16_one >> 1)) / fix16_one; + return (a - (fix16_one >> 1)) / fix16_one; +#endif +} + +static inline fix16_t fix16_from_float(float a) +{ + float temp = a * fix16_one; +#ifndef FIXMATH_NO_ROUNDING + temp += (temp >= 0) ? 0.5f : -0.5f; +#endif + return (fix16_t)temp; +} + +static inline fix16_t fix16_from_dbl(double a) +{ + double temp = a * fix16_one; +#ifndef FIXMATH_NO_ROUNDING + temp += (temp >= 0) ? 0.5f : -0.5f; +#endif + return (fix16_t)temp; +} + +/* Macro for defining fix16_t constant values. + The functions above can't be used from e.g. global variable initializers, + and their names are quite long also. This macro is useful for constants + springled alongside code, e.g. F16(1.234). + + Note that the argument is evaluated multiple times, and also otherwise + you should only use this for constant values. For runtime-conversions, + use the functions above. +*/ +#define F16(x) ((fix16_t)(((x) >= 0) ? ((x) * 65536.0 + 0.5) : ((x) * 65536.0 - 0.5))) + +static inline fix16_t fix16_abs(fix16_t x) + { return (x < 0 ? -x : x); } +static inline fix16_t fix16_floor(fix16_t x) + { return (x & 0xFFFF0000UL); } +static inline fix16_t fix16_ceil(fix16_t x) + { return (x & 0xFFFF0000UL) + (x & 0x0000FFFFUL ? fix16_one : 0); } +static inline fix16_t fix16_min(fix16_t x, fix16_t y) + { return (x < y ? x : y); } +static inline fix16_t fix16_max(fix16_t x, fix16_t y) + { return (x > y ? x : y); } +static inline fix16_t fix16_clamp(fix16_t x, fix16_t lo, fix16_t hi) + { return fix16_min(fix16_max(x, lo), hi); } + +/* Subtraction and addition with (optional) overflow detection. */ +#ifdef FIXMATH_NO_OVERFLOW + +static inline fix16_t fix16_add(fix16_t inArg0, fix16_t inArg1) { return (inArg0 + inArg1); } +static inline fix16_t fix16_sub(fix16_t inArg0, fix16_t inArg1) { return (inArg0 - inArg1); } + +#else + +extern fix16_t fix16_add(fix16_t a, fix16_t b) FIXMATH_FUNC_ATTRS; +extern fix16_t fix16_sub(fix16_t a, fix16_t b) FIXMATH_FUNC_ATTRS; + +/* Saturating arithmetic */ +extern fix16_t fix16_sadd(fix16_t a, fix16_t b) FIXMATH_FUNC_ATTRS; +extern fix16_t fix16_ssub(fix16_t a, fix16_t b) FIXMATH_FUNC_ATTRS; + +#endif + +/*! Multiplies the two given fix16_t's and returns the result. +*/ +extern fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1) FIXMATH_FUNC_ATTRS; + +/*! Divides the first given fix16_t by the second and returns the result. +*/ +extern fix16_t fix16_div(fix16_t inArg0, fix16_t inArg1) FIXMATH_FUNC_ATTRS; + +#ifndef FIXMATH_NO_OVERFLOW +/*! Performs a saturated multiplication (overflow-protected) of the two given fix16_t's and returns the result. +*/ +extern fix16_t fix16_smul(fix16_t inArg0, fix16_t inArg1) FIXMATH_FUNC_ATTRS; + +/*! Performs a saturated division (overflow-protected) of the first fix16_t by the second and returns the result. +*/ +extern fix16_t fix16_sdiv(fix16_t inArg0, fix16_t inArg1) FIXMATH_FUNC_ATTRS; +#endif + +/*! Divides the first given fix16_t by the second and returns the result. +*/ +extern fix16_t fix16_mod(fix16_t x, fix16_t y) FIXMATH_FUNC_ATTRS; + + + +/*! Returns the linear interpolation: (inArg0 * (1 - inFract)) + (inArg1 * inFract) +*/ +extern fix16_t fix16_lerp8(fix16_t inArg0, fix16_t inArg1, uint8_t inFract) FIXMATH_FUNC_ATTRS; +extern fix16_t fix16_lerp16(fix16_t inArg0, fix16_t inArg1, uint16_t inFract) FIXMATH_FUNC_ATTRS; +extern fix16_t fix16_lerp32(fix16_t inArg0, fix16_t inArg1, uint32_t inFract) FIXMATH_FUNC_ATTRS; + + + +/*! Returns the sine of the given fix16_t. +*/ +extern fix16_t fix16_sin_parabola(fix16_t inAngle) FIXMATH_FUNC_ATTRS; + +/*! Returns the sine of the given fix16_t. +*/ +extern fix16_t fix16_sin(fix16_t inAngle) FIXMATH_FUNC_ATTRS; + +/*! Returns the cosine of the given fix16_t. +*/ +extern fix16_t fix16_cos(fix16_t inAngle) FIXMATH_FUNC_ATTRS; + +/*! Returns the tangent of the given fix16_t. +*/ +extern fix16_t fix16_tan(fix16_t inAngle) FIXMATH_FUNC_ATTRS; + +/*! Returns the arcsine of the given fix16_t. +*/ +extern fix16_t fix16_asin(fix16_t inValue) FIXMATH_FUNC_ATTRS; + +/*! Returns the arccosine of the given fix16_t. +*/ +extern fix16_t fix16_acos(fix16_t inValue) FIXMATH_FUNC_ATTRS; + +/*! Returns the arctangent of the given fix16_t. +*/ +extern fix16_t fix16_atan(fix16_t inValue) FIXMATH_FUNC_ATTRS; + +/*! Returns the arctangent of inY/inX. +*/ +extern fix16_t fix16_atan2(fix16_t inY, fix16_t inX) FIXMATH_FUNC_ATTRS; + +static const fix16_t fix16_rad_to_deg_mult = 3754936; +static inline fix16_t fix16_rad_to_deg(fix16_t radians) + { return fix16_mul(radians, fix16_rad_to_deg_mult); } + +static const fix16_t fix16_deg_to_rad_mult = 1144; +static inline fix16_t fix16_deg_to_rad(fix16_t degrees) + { return fix16_mul(degrees, fix16_deg_to_rad_mult); } + + + +/*! Returns the square root of the given fix16_t. +*/ +extern fix16_t fix16_sqrt(fix16_t inValue) FIXMATH_FUNC_ATTRS; + +/*! Returns the square of the given fix16_t. +*/ +static inline fix16_t fix16_sq(fix16_t x) + { return fix16_mul(x, x); } + +/*! Returns the exponent (e^) of the given fix16_t. +*/ +extern fix16_t fix16_exp(fix16_t inValue) FIXMATH_FUNC_ATTRS; + +/*! Returns the natural logarithm of the given fix16_t. + */ +extern fix16_t fix16_log(fix16_t inValue) FIXMATH_FUNC_ATTRS; + +/*! Returns the base 2 logarithm of the given fix16_t. + */ +extern fix16_t fix16_log2(fix16_t x) FIXMATH_FUNC_ATTRS; + +/*! Returns the saturated base 2 logarithm of the given fix16_t. + */ +extern fix16_t fix16_slog2(fix16_t x) FIXMATH_FUNC_ATTRS; + +/*! Convert fix16_t value to a string. + * Required buffer length for largest values is 13 bytes. + */ +extern void fix16_to_str(fix16_t value, char *buf, int decimals); + +/*! Convert string to a fix16_t value + * Ignores spaces at beginning and end. Returns fix16_overflow if + * value is too large or there were garbage characters. + */ +extern fix16_t fix16_from_str(const char *buf); + +/** Helper macro for F16C. Replace token with its number of characters/digits. */ +#define FIXMATH_TOKLEN(token) ( sizeof( #token ) - 1 ) + +/** Helper macro for F16C. Handles pow(10, n) for n from 0 to 8. */ +#define FIXMATH_CONSTANT_POW10(times) ( \ + (times == 0) ? 1ULL \ + : (times == 1) ? 10ULL \ + : (times == 2) ? 100ULL \ + : (times == 3) ? 1000ULL \ + : (times == 4) ? 10000ULL \ + : (times == 5) ? 100000ULL \ + : (times == 6) ? 1000000ULL \ + : (times == 7) ? 10000000ULL \ + : 100000000ULL \ +) + + +/** Helper macro for F16C, the type uint64_t is only used at compile time and + * shouldn't be visible in the generated code. + * + * @note We do not use fix16_one instead of 65536ULL, because the + * "use of a const variable in a constant expression is nonstandard in C". + */ +#define FIXMATH_CONVERT_MANTISSA(m) \ +( (unsigned) \ + ( \ + ( \ + ( \ + (uint64_t)( ( ( 1 ## m ## ULL ) - FIXMATH_CONSTANT_POW10(FIXMATH_TOKLEN(m)) ) * FIXMATH_CONSTANT_POW10(5 - FIXMATH_TOKLEN(m)) ) \ + * 100000ULL * 65536ULL \ + ) \ + + 5000000000ULL /* rounding: + 0.5 */ \ + ) \ + / \ + 10000000000LL \ + ) \ +) + + +#define FIXMATH_COMBINE_I_M(i, m) \ +( \ + ( \ + ( i ) \ + << 16 \ + ) \ + | \ + ( \ + FIXMATH_CONVERT_MANTISSA(m) \ + & 0xFFFF \ + ) \ +) + + +/** Create int16_t (Q16.16) constant from separate integer and mantissa part. + * + * Only tested on 32-bit ARM Cortex-M0 / x86 Intel. + * + * This macro is needed when compiling with options like "--fpu=none", + * which forbid all and every use of float and related types and + * would thus make it impossible to have fix16_t constants. + * + * Just replace uses of F16() with F16C() like this: + * F16(123.1234) becomes F16C(123,1234) + * + * @warning Specification of any value outside the mentioned intervals + * WILL result in undefined behavior! + * + * @note Regardless of the specified minimum and maximum values for i and m below, + * the total value of the number represented by i and m MUST be in the interval + * ]-32768.00000:32767.99999[ else usage with this macro will yield undefined behavior. + * + * @param i Signed integer constant with a value in the interval ]-32768:32767[. + * @param m Positive integer constant in the interval ]0:99999[ (fractional part/mantissa). + */ +#define F16C(i, m) \ +( (fix16_t) \ + ( \ + (( #i[0] ) == '-') \ + ? -FIXMATH_COMBINE_I_M((unsigned)( ( (i) * -1) ), m) \ + : FIXMATH_COMBINE_I_M((unsigned)i, m) \ + ) \ +) + +#ifdef __cplusplus +} +#include "fix16.hpp" +#endif + +#endif diff --git a/source/build/include/fix16.hpp b/source/build/include/fix16.hpp new file mode 100644 index 000000000..1fbc5e2f6 --- /dev/null +++ b/source/build/include/fix16.hpp @@ -0,0 +1,154 @@ +#ifndef __libfixmath_fix16_hpp__ +#define __libfixmath_fix16_hpp__ + +#include "fix16.h" + +class Fix16 { + public: + fix16_t value; + + Fix16() { value = 0; } + Fix16(const Fix16 &inValue) { value = inValue.value; } + Fix16(const fix16_t inValue) { value = inValue; } + Fix16(const float inValue) { value = fix16_from_float(inValue); } + Fix16(const double inValue) { value = fix16_from_dbl(inValue); } + Fix16(const int16_t inValue) { value = fix16_from_int(inValue); } + + operator fix16_t() const { return value; } + operator double() const { return fix16_to_dbl(value); } + operator float() const { return fix16_to_float(value); } + operator int16_t() const { return fix16_to_int(value); } + + Fix16 & operator=(const Fix16 &rhs) { value = rhs.value; return *this; } + Fix16 & operator=(const fix16_t rhs) { value = rhs; return *this; } + Fix16 & operator=(const double rhs) { value = fix16_from_dbl(rhs); return *this; } + Fix16 & operator=(const float rhs) { value = fix16_from_float(rhs); return *this; } + Fix16 & operator=(const int16_t rhs) { value = fix16_from_int(rhs); return *this; } + + Fix16 & operator+=(const Fix16 &rhs) { value += rhs.value; return *this; } + Fix16 & operator+=(const fix16_t rhs) { value += rhs; return *this; } + Fix16 & operator+=(const double rhs) { value += fix16_from_dbl(rhs); return *this; } + Fix16 & operator+=(const float rhs) { value += fix16_from_float(rhs); return *this; } + Fix16 & operator+=(const int16_t rhs) { value += fix16_from_int(rhs); return *this; } + + Fix16 & operator-=(const Fix16 &rhs) { value -= rhs.value; return *this; } + Fix16 & operator-=(const fix16_t rhs) { value -= rhs; return *this; } + Fix16 & operator-=(const double rhs) { value -= fix16_from_dbl(rhs); return *this; } + Fix16 & operator-=(const float rhs) { value -= fix16_from_float(rhs); return *this; } + Fix16 & operator-=(const int16_t rhs) { value -= fix16_from_int(rhs); return *this; } + + Fix16 & operator*=(const Fix16 &rhs) { value = fix16_mul(value, rhs.value); return *this; } + Fix16 & operator*=(const fix16_t rhs) { value = fix16_mul(value, rhs); return *this; } + Fix16 & operator*=(const double rhs) { value = fix16_mul(value, fix16_from_dbl(rhs)); return *this; } + Fix16 & operator*=(const float rhs) { value = fix16_mul(value, fix16_from_float(rhs)); return *this; } + Fix16 & operator*=(const int16_t rhs) { value *= rhs; return *this; } + + Fix16 & operator/=(const Fix16 &rhs) { value = fix16_div(value, rhs.value); return *this; } + Fix16 & operator/=(const fix16_t rhs) { value = fix16_div(value, rhs); return *this; } + Fix16 & operator/=(const double rhs) { value = fix16_div(value, fix16_from_dbl(rhs)); return *this; } + Fix16 & operator/=(const float rhs) { value = fix16_div(value, fix16_from_float(rhs)); return *this; } + Fix16 & operator/=(const int16_t rhs) { value /= rhs; return *this; } + + const Fix16 operator+(const Fix16 &other) const { Fix16 ret = *this; ret += other; return ret; } + const Fix16 operator+(const fix16_t other) const { Fix16 ret = *this; ret += other; return ret; } + const Fix16 operator+(const double other) const { Fix16 ret = *this; ret += other; return ret; } + const Fix16 operator+(const float other) const { Fix16 ret = *this; ret += other; return ret; } + const Fix16 operator+(const int16_t other) const { Fix16 ret = *this; ret += other; return ret; } + +#ifndef FIXMATH_NO_OVERFLOW + const Fix16 sadd(const Fix16 &other) const { Fix16 ret = fix16_sadd(value, other.value); return ret; } + const Fix16 sadd(const fix16_t other) const { Fix16 ret = fix16_sadd(value, other); return ret; } + const Fix16 sadd(const double other) const { Fix16 ret = fix16_sadd(value, fix16_from_dbl(other)); return ret; } + const Fix16 sadd(const float other) const { Fix16 ret = fix16_sadd(value, fix16_from_float(other)); return ret; } + const Fix16 sadd(const int16_t other) const { Fix16 ret = fix16_sadd(value, fix16_from_int(other)); return ret; } +#endif + + const Fix16 operator-(const Fix16 &other) const { Fix16 ret = *this; ret -= other; return ret; } + const Fix16 operator-(const fix16_t other) const { Fix16 ret = *this; ret -= other; return ret; } + const Fix16 operator-(const double other) const { Fix16 ret = *this; ret -= other; return ret; } + const Fix16 operator-(const float other) const { Fix16 ret = *this; ret -= other; return ret; } + const Fix16 operator-(const int16_t other) const { Fix16 ret = *this; ret -= other; return ret; } + +#ifndef FIXMATH_NO_OVERFLOW + const Fix16 ssub(const Fix16 &other) const { Fix16 ret = fix16_sadd(value, -other.value); return ret; } + const Fix16 ssub(const fix16_t other) const { Fix16 ret = fix16_sadd(value, -other); return ret; } + const Fix16 ssub(const double other) const { Fix16 ret = fix16_sadd(value, -fix16_from_dbl(other)); return ret; } + const Fix16 ssub(const float other) const { Fix16 ret = fix16_sadd(value, -fix16_from_float(other)); return ret; } + const Fix16 ssub(const int16_t other) const { Fix16 ret = fix16_sadd(value, -fix16_from_int(other)); return ret; } +#endif + + const Fix16 operator*(const Fix16 &other) const { Fix16 ret = *this; ret *= other; return ret; } + const Fix16 operator*(const fix16_t other) const { Fix16 ret = *this; ret *= other; return ret; } + const Fix16 operator*(const double other) const { Fix16 ret = *this; ret *= other; return ret; } + const Fix16 operator*(const float other) const { Fix16 ret = *this; ret *= other; return ret; } + const Fix16 operator*(const int16_t other) const { Fix16 ret = *this; ret *= other; return ret; } + +#ifndef FIXMATH_NO_OVERFLOW + const Fix16 smul(const Fix16 &other) const { Fix16 ret = fix16_smul(value, other.value); return ret; } + const Fix16 smul(const fix16_t other) const { Fix16 ret = fix16_smul(value, other); return ret; } + const Fix16 smul(const double other) const { Fix16 ret = fix16_smul(value, fix16_from_dbl(other)); return ret; } + const Fix16 smul(const float other) const { Fix16 ret = fix16_smul(value, fix16_from_float(other)); return ret; } + const Fix16 smul(const int16_t other) const { Fix16 ret = fix16_smul(value, fix16_from_int(other)); return ret; } +#endif + + const Fix16 operator/(const Fix16 &other) const { Fix16 ret = *this; ret /= other; return ret; } + const Fix16 operator/(const fix16_t other) const { Fix16 ret = *this; ret /= other; return ret; } + const Fix16 operator/(const double other) const { Fix16 ret = *this; ret /= other; return ret; } + const Fix16 operator/(const float other) const { Fix16 ret = *this; ret /= other; return ret; } + const Fix16 operator/(const int16_t other) const { Fix16 ret = *this; ret /= other; return ret; } + +#ifndef FIXMATH_NO_OVERFLOW + const Fix16 sdiv(const Fix16 &other) const { Fix16 ret = fix16_sdiv(value, other.value); return ret; } + const Fix16 sdiv(const fix16_t other) const { Fix16 ret = fix16_sdiv(value, other); return ret; } + const Fix16 sdiv(const double other) const { Fix16 ret = fix16_sdiv(value, fix16_from_dbl(other)); return ret; } + const Fix16 sdiv(const float other) const { Fix16 ret = fix16_sdiv(value, fix16_from_float(other)); return ret; } + const Fix16 sdiv(const int16_t other) const { Fix16 ret = fix16_sdiv(value, fix16_from_int(other)); return ret; } +#endif + + int operator==(const Fix16 &other) const { return (value == other.value); } + int operator==(const fix16_t other) const { return (value == other); } + int operator==(const double other) const { return (value == fix16_from_dbl(other)); } + int operator==(const float other) const { return (value == fix16_from_float(other)); } + int operator==(const int16_t other) const { return (value == fix16_from_int(other)); } + + int operator!=(const Fix16 &other) const { return (value != other.value); } + int operator!=(const fix16_t other) const { return (value != other); } + int operator!=(const double other) const { return (value != fix16_from_dbl(other)); } + int operator!=(const float other) const { return (value != fix16_from_float(other)); } + int operator!=(const int16_t other) const { return (value != fix16_from_int(other)); } + + int operator<=(const Fix16 &other) const { return (value <= other.value); } + int operator<=(const fix16_t other) const { return (value <= other); } + int operator<=(const double other) const { return (value <= fix16_from_dbl(other)); } + int operator<=(const float other) const { return (value <= fix16_from_float(other)); } + int operator<=(const int16_t other) const { return (value <= fix16_from_int(other)); } + + int operator>=(const Fix16 &other) const { return (value >= other.value); } + int operator>=(const fix16_t other) const { return (value >= other); } + int operator>=(const double other) const { return (value >= fix16_from_dbl(other)); } + int operator>=(const float other) const { return (value >= fix16_from_float(other)); } + int operator>=(const int16_t other) const { return (value >= fix16_from_int(other)); } + + int operator< (const Fix16 &other) const { return (value < other.value); } + int operator< (const fix16_t other) const { return (value < other); } + int operator< (const double other) const { return (value < fix16_from_dbl(other)); } + int operator< (const float other) const { return (value < fix16_from_float(other)); } + int operator< (const int16_t other) const { return (value < fix16_from_int(other)); } + + int operator> (const Fix16 &other) const { return (value > other.value); } + int operator> (const fix16_t other) const { return (value > other); } + int operator> (const double other) const { return (value > fix16_from_dbl(other)); } + int operator> (const float other) const { return (value > fix16_from_float(other)); } + int operator> (const int16_t other) const { return (value > fix16_from_int(other)); } + + Fix16 sin() const { return Fix16(fix16_sin(value)); } + Fix16 cos() const { return Fix16(fix16_cos(value)); } + Fix16 tan() const { return Fix16(fix16_tan(value)); } + Fix16 asin() const { return Fix16(fix16_asin(value)); } + Fix16 acos() const { return Fix16(fix16_acos(value)); } + Fix16 atan() const { return Fix16(fix16_atan(value)); } + Fix16 atan2(const Fix16 &inY) const { return Fix16(fix16_atan2(value, inY.value)); } + Fix16 sqrt() const { return Fix16(fix16_sqrt(value)); } +}; + +#endif diff --git a/source/build/include/int64.h b/source/build/include/int64.h new file mode 100644 index 000000000..9f09f5c12 --- /dev/null +++ b/source/build/include/int64.h @@ -0,0 +1,162 @@ +#ifndef __libfixmath_int64_h__ +#define __libfixmath_int64_h__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef FIXMATH_NO_64BIT +static inline int64_t int64_const(int32_t hi, uint32_t lo) { return (((int64_t)hi << 32) | lo); } +static inline int64_t int64_from_int32(int32_t x) { return (int64_t)x; } +static inline int32_t int64_hi(int64_t x) { return (x >> 32); } +static inline uint32_t int64_lo(int64_t x) { return (x & ((1ULL << 32) - 1)); } + +static inline int64_t int64_add(int64_t x, int64_t y) { return (x + y); } +static inline int64_t int64_neg(int64_t x) { return (-x); } +static inline int64_t int64_sub(int64_t x, int64_t y) { return (x - y); } +static inline int64_t int64_shift(int64_t x, int8_t y) { return (y < 0 ? (x >> -y) : (x << y)); } + +static inline int64_t int64_mul_i32_i32(int32_t x, int32_t y) { return (x * y); } +static inline int64_t int64_mul_i64_i32(int64_t x, int32_t y) { return (x * y); } + +static inline int64_t int64_div_i64_i32(int64_t x, int32_t y) { return (x / y); } + +static inline int int64_cmp_eq(int64_t x, int64_t y) { return (x == y); } +static inline int int64_cmp_ne(int64_t x, int64_t y) { return (x != y); } +static inline int int64_cmp_gt(int64_t x, int64_t y) { return (x > y); } +static inline int int64_cmp_ge(int64_t x, int64_t y) { return (x >= y); } +static inline int int64_cmp_lt(int64_t x, int64_t y) { return (x < y); } +static inline int int64_cmp_le(int64_t x, int64_t y) { return (x <= y); } +#else + +typedef struct { + int32_t hi; + uint32_t lo; +} __int64_t; + +static inline __int64_t int64_const(int32_t hi, uint32_t lo) { return (__int64_t){ hi, lo }; } +static inline __int64_t int64_from_int32(int32_t x) { return (__int64_t){ (x < 0 ? -1 : 0), x }; } +static inline int32_t int64_hi(__int64_t x) { return x.hi; } +static inline uint32_t int64_lo(__int64_t x) { return x.lo; } + +static inline int int64_cmp_eq(__int64_t x, __int64_t y) { return ((x.hi == y.hi) && (x.lo == y.lo)); } +static inline int int64_cmp_ne(__int64_t x, __int64_t y) { return ((x.hi != y.hi) || (x.lo != y.lo)); } +static inline int int64_cmp_gt(__int64_t x, __int64_t y) { return ((x.hi > y.hi) || ((x.hi == y.hi) && (x.lo > y.lo))); } +static inline int int64_cmp_ge(__int64_t x, __int64_t y) { return ((x.hi > y.hi) || ((x.hi == y.hi) && (x.lo >= y.lo))); } +static inline int int64_cmp_lt(__int64_t x, __int64_t y) { return ((x.hi < y.hi) || ((x.hi == y.hi) && (x.lo < y.lo))); } +static inline int int64_cmp_le(__int64_t x, __int64_t y) { return ((x.hi < y.hi) || ((x.hi == y.hi) && (x.lo <= y.lo))); } + +static inline __int64_t int64_add(__int64_t x, __int64_t y) { + __int64_t ret; + ret.hi = x.hi + y.hi; + ret.lo = x.lo + y.lo; + if((ret.lo < x.lo) || (ret.hi < y.hi)) + ret.hi++; + return ret; +} + +static inline __int64_t int64_neg(__int64_t x) { + __int64_t ret; + ret.hi = ~x.hi; + ret.lo = ~x.lo + 1; + if(ret.lo == 0) + ret.hi++; + return ret; +} + +static inline __int64_t int64_sub(__int64_t x, __int64_t y) { + return int64_add(x, int64_neg(y)); +} + +static inline __int64_t int64_shift(__int64_t x, int8_t y) { + __int64_t ret; + if(y > 0) { + if(y >= 32) + return (__int64_t){ 0, 0 }; + ret.hi = (x.hi << y) | (x.lo >> (32 - y)); + ret.lo = (x.lo << y); + } else { + y = -y; + if(y >= 32) + return (__int64_t){ 0, 0 }; + ret.lo = (x.lo >> y) | (x.hi << (32 - y)); + ret.hi = (x.hi >> y); + } + return ret; +} + +static inline __int64_t int64_mul_i32_i32(int32_t x, int32_t y) { + int16_t hi[2] = { (x >> 16), (y >> 16) }; + uint16_t lo[2] = { (x & 0xFFFF), (y & 0xFFFF) }; + + int32_t r_hi = hi[0] * hi[1]; + int32_t r_md = (hi[0] * lo[1]) + (hi[1] * lo[0]); + uint32_t r_lo = lo[0] * lo[1]; + + r_hi += (r_md >> 16); + r_lo += (r_md << 16); + + return (__int64_t){ r_hi, r_lo }; +} + +static inline __int64_t int64_mul_i64_i32(__int64_t x, int32_t y) { + int neg = ((x.hi ^ y) < 0); + if(x.hi < 0) + x = int64_neg(x); + if(y < 0) + y = -y; + + uint32_t _x[4] = { (x.hi >> 16), (x.hi & 0xFFFF), (x.lo >> 16), (x.lo & 0xFFFF) }; + uint32_t _y[2] = { (y >> 16), (y & 0xFFFF) }; + + uint32_t r[4]; + r[0] = (_x[0] * _y[0]); + r[1] = (_x[1] * _y[0]) + (_x[0] * _y[1]); + r[2] = (_x[1] * _y[1]) + (_x[2] * _y[0]); + r[3] = (_x[2] * _y[0]) + (_x[1] * _y[1]); + + __int64_t ret; + ret.lo = r[0] + (r[1] << 16); + ret.hi = (r[3] << 16) + r[2] + (r[1] >> 16); + return (neg ? int64_neg(ret) : ret); +} + +static inline __int64_t int64_div_i64_i32(__int64_t x, int32_t y) { + int neg = ((x.hi ^ y) < 0); + if(x.hi < 0) + x = int64_neg(x); + if(y < 0) + y = -y; + + __int64_t ret = { (x.hi / y) , (x.lo / y) }; + x.hi = x.hi % y; + x.lo = x.lo % y; + + __int64_t _y = int64_from_int32(y); + + __int64_t i; + for(i = int64_from_int32(1); int64_cmp_lt(_y, x); _y = int64_shift(_y, 1), i = int64_shift(i, 1)); + + while(x.hi) { + _y = int64_shift(_y, -1); + i = int64_shift(i, -1); + if(int64_cmp_ge(x, _y)) { + x = int64_sub(x, _y); + ret = int64_add(ret, i); + } + } + + ret = int64_add(ret, int64_from_int32(x.lo / y)); + return (neg ? int64_neg(ret) : ret); +} + +#define int64_t __int64_t + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/build/src/engine.cpp b/source/build/src/engine.cpp index 368382ee5..63a27d65a 100644 --- a/source/build/src/engine.cpp +++ b/source/build/src/engine.cpp @@ -214,7 +214,7 @@ static void scansector(int16_t startsectnum); static void draw_rainbow_background(void); int16_t editstatus = 0; -static int32_t global100horiz; // (-100..300)-scale horiz (the one passed to drawrooms) +static fix16_t global100horiz; // (-100..300)-scale horiz (the one passed to drawrooms) ////////// YAX ////////// @@ -874,7 +874,7 @@ void yax_drawrooms(void (*SpriteAnimFunc)(int32_t,int32_t,int32_t,int32_t), { static uint8_t havebunch[YAX_MAXBUNCHES>>3]; - const int32_t horiz = global100horiz; + const fix16_t horiz = global100horiz; int32_t i, j, k, lev, cf, nmp; int32_t bnchcnt, bnchnum[2] = {0,0}, maxlev[2]; @@ -1386,6 +1386,7 @@ static int32_t xsi[8], ysi[8], horizycent; static int32_t *horizlookup=0, *horizlookup2=0; int32_t globalposx, globalposy, globalposz, globalhoriz; +fix16_t qglobalhoriz; float fglobalposx, fglobalposy, fglobalposz; int16_t globalang, globalcursectnum; int32_t globalpal, cosglobalang, singlobalang; @@ -7911,7 +7912,7 @@ void set_globalang(int16_t ang) // drawrooms // int32_t drawrooms(int32_t daposx, int32_t daposy, int32_t daposz, - int16_t daang, int32_t dahoriz, int16_t dacursectnum) + int16_t daang, fix16_t dahoriz, int16_t dacursectnum) { int32_t i, j, /*cz, fz,*/ closest; int16_t *shortptr1, *shortptr2; @@ -7927,7 +7928,8 @@ int32_t drawrooms(int32_t daposx, int32_t daposy, int32_t daposz, // xdimenscale is scale(xdimen,yxaspect,320); // normalization by viewingrange so that center-of-aim doesn't depend on it - globalhoriz = mulscale16(dahoriz-100,divscale16(xdimenscale,viewingrange))+(ydimen>>1); + globalhoriz = mulscale16(fix16_to_int(dahoriz)-100,divscale16(xdimenscale,viewingrange))+(ydimen>>1); + qglobalhoriz = mulscale16(dahoriz-F16(100), divscale16(xdimenscale, viewingrange))+fix16_from_int(ydimen>>1); globaluclip = (0-globalhoriz)*xdimscale; globaldclip = (ydimen-globalhoriz)*xdimscale; diff --git a/source/build/src/engine_priv.h b/source/build/src/engine_priv.h index dd6672818..d9a7f2dfc 100644 --- a/source/build/src/engine_priv.h +++ b/source/build/src/engine_priv.h @@ -205,6 +205,7 @@ extern int32_t xdimen, xdimenrecip, halfxdimen, xdimenscale, xdimscale, ydimen; extern float fxdimen; extern intptr_t frameoffset; extern int32_t globalposx, globalposy, globalposz, globalhoriz; +extern fix16_t qglobalhoriz; extern float fglobalposx, fglobalposy, fglobalposz; extern int16_t globalang, globalcursectnum; extern int32_t globalpal, cosglobalang, singlobalang; diff --git a/source/build/src/fix16.c b/source/build/src/fix16.c new file mode 100644 index 000000000..7c73499d6 --- /dev/null +++ b/source/build/src/fix16.c @@ -0,0 +1,260 @@ +#include "fix16.h" +#include "int64.h" + +/* Subtraction and addition with overflow detection. + * The versions without overflow detection are inlined in the header. + */ +#ifndef FIXMATH_NO_OVERFLOW +fix16_t fix16_add(fix16_t a, fix16_t b) +{ + // Use unsigned integers because overflow with signed integers is + // an undefined operation (http://www.airs.com/blog/archives/120). + uint32_t _a = a, _b = b; + uint32_t sum = _a + _b; + + // Overflow can only happen if sign of a == sign of b, and then + // it causes sign of sum != sign of a. + if (!((_a ^ _b) & 0x80000000) && ((_a ^ sum) & 0x80000000)) + return fix16_overflow; + + return sum; +} + +fix16_t fix16_sub(fix16_t a, fix16_t b) +{ + uint32_t _a = a, _b = b; + uint32_t diff = _a - _b; + + // Overflow can only happen if sign of a != sign of b, and then + // it causes sign of diff != sign of a. + if (((_a ^ _b) & 0x80000000) && ((_a ^ diff) & 0x80000000)) + return fix16_overflow; + + return diff; +} + +/* Saturating arithmetic */ +fix16_t fix16_sadd(fix16_t a, fix16_t b) +{ + fix16_t result = fix16_add(a, b); + + if (result == fix16_overflow) + return (a >= 0) ? fix16_maximum : fix16_minimum; + + return result; +} + +fix16_t fix16_ssub(fix16_t a, fix16_t b) +{ + fix16_t result = fix16_sub(a, b); + + if (result == fix16_overflow) + return (a >= 0) ? fix16_maximum : fix16_minimum; + + return result; +} +#endif + + + +/* 64-bit implementation for fix16_mul. Fastest version for e.g. ARM Cortex M3. + * Performs a 32*32 -> 64bit multiplication. The middle 32 bits are the result, + * bottom 16 bits are used for rounding, and upper 16 bits are used for overflow + * detection. + */ + +fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1) +{ + int64_t product = (int64_t)inArg0 * inArg1; + + #ifndef FIXMATH_NO_OVERFLOW + // The upper 17 bits should all be the same (the sign). + uint32_t upper = (product >> 47); + #endif + + if (product < 0) + { + #ifndef FIXMATH_NO_OVERFLOW + if (~upper) + return fix16_overflow; + #endif + + #ifndef FIXMATH_NO_ROUNDING + // This adjustment is required in order to round -1/2 correctly + product--; + #endif + } + else + { + #ifndef FIXMATH_NO_OVERFLOW + if (upper) + return fix16_overflow; + #endif + } + + #ifdef FIXMATH_NO_ROUNDING + return product >> 16; + #else + fix16_t result = product >> 16; + result += (product & 0x8000) >> 15; + + return result; + #endif +} + +#ifndef FIXMATH_NO_OVERFLOW +/* Wrapper around fix16_mul to add saturating arithmetic. */ +fix16_t fix16_smul(fix16_t inArg0, fix16_t inArg1) +{ + fix16_t result = fix16_mul(inArg0, inArg1); + + if (result == fix16_overflow) + { + if ((inArg0 >= 0) == (inArg1 >= 0)) + return fix16_maximum; + else + return fix16_minimum; + } + + return result; +} +#endif + +/* 32-bit implementation of fix16_div. Fastest version for e.g. ARM Cortex M3. + * Performs 32-bit divisions repeatedly to reduce the remainder. For this to + * be efficient, the processor has to have 32-bit hardware division. + */ +#ifdef __GNUC__ +// Count leading zeros, using processor-specific instruction if available. +#define clz(x) (__builtin_clzl(x) - (8 * sizeof(long) - 32)) +#else +static uint8_t clz(uint32_t x) +{ + uint8_t result = 0; + if (x == 0) return 32; + while (!(x & 0xF0000000)) { result += 4; x <<= 4; } + while (!(x & 0x80000000)) { result += 1; x <<= 1; } + return result; +} +#endif + +fix16_t fix16_div(fix16_t a, fix16_t b) +{ + // This uses a hardware 32/32 bit division multiple times, until we have + // computed all the bits in (a<<17)/b. Usually this takes 1-3 iterations. + + if (b == 0) + return fix16_minimum; + + uint32_t remainder = (a >= 0) ? a : (-a); + uint32_t divider = (b >= 0) ? b : (-b); + uint32_t quotient = 0; + int bit_pos = 17; + + // Kick-start the division a bit. + // This improves speed in the worst-case scenarios where N and D are large + // It gets a lower estimate for the result by N/(D >> 17 + 1). + if (divider & 0xFFF00000) + { + uint32_t shifted_div = ((divider >> 17) + 1); + quotient = remainder / shifted_div; + remainder -= ((uint64_t)quotient * divider) >> 17; + } + + // If the divider is divisible by 2^n, take advantage of it. + while (!(divider & 0xF) && bit_pos >= 4) + { + divider >>= 4; + bit_pos -= 4; + } + + while (remainder && bit_pos >= 0) + { + // Shift remainder as much as we can without overflowing + int shift = clz(remainder); + if (shift > bit_pos) shift = bit_pos; + remainder <<= shift; + bit_pos -= shift; + + uint32_t div = remainder / divider; + remainder = remainder % divider; + quotient += div << bit_pos; + + #ifndef FIXMATH_NO_OVERFLOW + if (div & ~(0xFFFFFFFF >> bit_pos)) + return fix16_overflow; + #endif + + remainder <<= 1; + bit_pos--; + } + + #ifndef FIXMATH_NO_ROUNDING + // Quotient is always positive so rounding is easy + quotient++; + #endif + + fix16_t result = quotient >> 1; + + // Figure out the sign of the result + if ((a ^ b) & 0x80000000) + { + #ifndef FIXMATH_NO_OVERFLOW + if (result == fix16_minimum) + return fix16_overflow; + #endif + + result = -result; + } + + return result; +} + +#ifndef FIXMATH_NO_OVERFLOW +/* Wrapper around fix16_div to add saturating arithmetic. */ +fix16_t fix16_sdiv(fix16_t inArg0, fix16_t inArg1) +{ + fix16_t result = fix16_div(inArg0, inArg1); + + if (result == fix16_overflow) + { + if ((inArg0 >= 0) == (inArg1 >= 0)) + return fix16_maximum; + else + return fix16_minimum; + } + + return result; +} +#endif + +fix16_t fix16_mod(fix16_t x, fix16_t y) { return x %= y; } + + +#ifndef FIXMATH_NO_64BIT + +fix16_t fix16_lerp8(fix16_t inArg0, fix16_t inArg1, uint8_t inFract) +{ + int64_t tempOut = int64_mul_i32_i32(inArg0, ((1 << 8) - inFract)); + tempOut = int64_add(tempOut, int64_mul_i32_i32(inArg1, inFract)); + tempOut = int64_shift(tempOut, -8); + return (fix16_t)int64_lo(tempOut); +} + +fix16_t fix16_lerp16(fix16_t inArg0, fix16_t inArg1, uint16_t inFract) +{ + int64_t tempOut = int64_mul_i32_i32(inArg0, (((int32_t)1 << 16) - inFract)); + tempOut = int64_add(tempOut, int64_mul_i32_i32(inArg1, inFract)); + tempOut = int64_shift(tempOut, -16); + return (fix16_t)int64_lo(tempOut); +} + +fix16_t fix16_lerp32(fix16_t inArg0, fix16_t inArg1, uint32_t inFract) +{ + int64_t tempOut; + tempOut = ((int64_t)inArg0 * (0 - inFract)); + tempOut += ((int64_t)inArg1 * inFract); + tempOut >>= 32; + return (fix16_t)tempOut; +} +#endif diff --git a/source/build/src/fix16_str.c b/source/build/src/fix16_str.c new file mode 100644 index 000000000..eff906f63 --- /dev/null +++ b/source/build/src/fix16_str.c @@ -0,0 +1,114 @@ +#include "fix16.h" +#include +#include + +static const uint32_t scales[8] = { + /* 5 decimals is enough for full fix16_t precision */ + 1, 10, 100, 1000, 10000, 100000, 100000, 100000 +}; + +static char *itoa_loop(char *buf, uint32_t scale, uint32_t value, bool skip) +{ + while (scale) + { + unsigned digit = (value / scale); + + if (!skip || digit || scale == 1) + { + skip = false; + *buf++ = '0' + digit; + value %= scale; + } + + scale /= 10; + } + return buf; +} + +void fix16_to_str(fix16_t value, char *buf, int decimals) +{ + uint32_t uvalue = (value >= 0) ? value : -value; + if (value < 0) + *buf++ = '-'; + + /* Separate the integer and decimal parts of the value */ + unsigned intpart = uvalue >> 16; + uint32_t fracpart = uvalue & 0xFFFF; + uint32_t scale = scales[decimals & 7]; + fracpart = fix16_mul(fracpart, scale); + + if (fracpart >= scale) + { + /* Handle carry from decimal part */ + intpart++; + fracpart -= scale; + } + + /* Format integer part */ + buf = itoa_loop(buf, 10000, intpart, true); + + /* Format decimal part (if any) */ + if (scale != 1) + { + *buf++ = '.'; + buf = itoa_loop(buf, scale / 10, fracpart, false); + } + + *buf = '\0'; +} + +fix16_t fix16_from_str(const char *buf) +{ + while (isspace(*buf)) + buf++; + + /* Decode the sign */ + bool negative = (*buf == '-'); + if (*buf == '+' || *buf == '-') + buf++; + + /* Decode the integer part */ + uint32_t intpart = 0; + int count = 0; + while (isdigit(*buf)) + { + intpart *= 10; + intpart += *buf++ - '0'; + count++; + } + + if (count == 0 || count > 5 + || intpart > 32768 || (!negative && intpart > 32767)) + return fix16_overflow; + + fix16_t value = intpart << 16; + + /* Decode the decimal part */ + if (*buf == '.' || *buf == ',') + { + buf++; + + uint32_t fracpart = 0; + uint32_t scale = 1; + while (isdigit(*buf) && scale < 100000) + { + scale *= 10; + fracpart *= 10; + fracpart += *buf++ - '0'; + } + + value += fix16_div(fracpart, scale); + } + + /* Verify that there is no garbage left over */ + while (*buf != '\0') + { + if (!isdigit(*buf) && !isspace(*buf)) + return fix16_overflow; + + buf++; + } + + return negative ? -value : value; +} + diff --git a/source/build/src/polymost.cpp b/source/build/src/polymost.cpp index baf8c43ea..45b92b20e 100644 --- a/source/build/src/polymost.cpp +++ b/source/build/src/polymost.cpp @@ -4630,7 +4630,7 @@ void polymost_drawrooms() gsinang2 = gsinang * (fviewingrange * (1.0f/65536.f)); ghalfx = (float)(xdimen>>1); grhalfxdown10 = 1.f/(ghalfx*1024.f); - ghoriz = (float)globalhoriz; + ghoriz = fix16_to_float(qglobalhoriz); gvisibility = ((float)globalvisibility)*FOGSCALE; diff --git a/source/duke3d/src/actors.cpp b/source/duke3d/src/actors.cpp index dd5c1c4ce..e144d33f0 100644 --- a/source/duke3d/src/actors.cpp +++ b/source/duke3d/src/actors.cpp @@ -2611,7 +2611,7 @@ ACTOR_STATIC void A_DoProjectileBounce(int const spriteNum) ACTOR_STATIC void P_HandleBeingSpitOn(DukePlayer_t * const ps) { - ps->horiz += 32; + ps->qhoriz += F16(32); ps->return_to_center = 8; if (ps->loogcnt) @@ -4303,7 +4303,7 @@ ACTOR_STATIC void G_MoveActors(void) DELETE_SPRITE_AND_CONTINUE(spriteNum); } - pSprite->z = pPlayer->pos.z + pPlayer->pyoff - pData[2] + ZOFFSET3 + ((100 - pPlayer->horiz) << 4); + pSprite->z = pPlayer->pos.z + pPlayer->pyoff - pData[2] + ZOFFSET3 + (fix16_to_int(F16(100) - pPlayer->qhoriz) << 4); if (pData[2] > 512) pData[2] -= 128; diff --git a/source/duke3d/src/game.cpp b/source/duke3d/src/game.cpp index 49bdcdd06..2448523da 100644 --- a/source/duke3d/src/game.cpp +++ b/source/duke3d/src/game.cpp @@ -334,7 +334,7 @@ static void M32_drawdebug(void) #endif -static int32_t G_DoThirdPerson(const DukePlayer_t *pp, vec3_t *vect, int16_t *vsectnum, int32_t ang, int32_t horiz) +static int32_t G_DoThirdPerson(const DukePlayer_t *pp, vec3_t *vect, int16_t *vsectnum, int32_t ang, fix16_t qhoriz) { spritetype *sp = &sprite[pp->i]; int32_t i, hx, hy; @@ -344,7 +344,7 @@ static int32_t G_DoThirdPerson(const DukePlayer_t *pp, vec3_t *vect, int16_t *vs vec3_t n = { sintable[(ang+1536)&2047]>>4, sintable[(ang+1024)&2047]>>4, - (horiz-100)*128 + fix16_mul(qhoriz-F16(100), F16(128)) }; updatesectorz(vect->x,vect->y,vect->z,vsectnum); @@ -522,7 +522,7 @@ static void G_SE40(int32_t smoothratio) polymer_setanimatesprites(G_DoSpriteAnimations, CAMERA(pos.x), CAMERA(pos.y), CAMERA(ang), smoothratio); #endif drawrooms(sprite[sprite2].x + x, sprite[sprite2].y + y, - z + renderz, CAMERA(ang), CAMERA(horiz), sect); + z + renderz, CAMERA(ang), CAMERA(qhoriz), sect); drawing_ror = 1 + level; if (drawing_ror == 2) // viewing from top @@ -555,7 +555,7 @@ static void G_SE40(int32_t smoothratio) } #endif -void G_HandleMirror(int32_t x, int32_t y, int32_t z, int32_t a, int32_t horiz, int32_t smoothratio) +void G_HandleMirror(int32_t x, int32_t y, int32_t z, int32_t a, fix16_t qhoriz, int32_t smoothratio) { if ((gotpic[MIRROR>>3]&(1<<(MIRROR&7))) #ifdef POLYMER @@ -616,12 +616,12 @@ void G_HandleMirror(int32_t x, int32_t y, int32_t z, int32_t a, int32_t horiz, i int32_t didmirror; yax_preparedrawrooms(); - didmirror = drawrooms(tposx,tposy,z,tang,horiz,g_mirrorSector[i]+MAXSECTORS); + didmirror = drawrooms(tposx,tposy,z,tang,qhoriz,g_mirrorSector[i]+MAXSECTORS); yax_drawrooms(G_DoSpriteAnimations, g_mirrorSector[i], didmirror, smoothratio); } #ifdef USE_OPENGL else - drawrooms(tposx,tposy,z,tang,horiz,g_mirrorSector[i]+MAXSECTORS); + drawrooms(tposx,tposy,z,tang,qhoriz,g_mirrorSector[i]+MAXSECTORS); // XXX: Sprites don't get drawn with TROR/Polymost #endif display_mirror = 1; @@ -910,8 +910,8 @@ void G_DrawRooms(int32_t playerNum, int32_t smoothRatio) CAMERA(pos) = camVect; CAMERA(ang) = pPlayer->oang + mulscale16(((pPlayer->ang + 1024 - pPlayer->oang) & 2047) - 1024, smoothRatio); CAMERA(ang) += pPlayer->look_ang; - CAMERA(horiz) = pPlayer->ohoriz + pPlayer->ohorizoff - + mulscale16((pPlayer->horiz + pPlayer->horizoff - pPlayer->ohoriz - pPlayer->ohorizoff), smoothRatio); + CAMERA(qhoriz) = pPlayer->oqhoriz + pPlayer->oqhorizoff + + mulscale16((pPlayer->qhoriz + pPlayer->qhorizoff - pPlayer->oqhoriz - pPlayer->oqhorizoff), smoothRatio); if (ud.viewbob) { @@ -927,10 +927,10 @@ void G_DrawRooms(int32_t playerNum, int32_t smoothRatio) { CAMERA(pos.z) -= 3072; - if (G_DoThirdPerson(pPlayer, &CAMERA(pos), &CAMERA(sect), CAMERA(ang), CAMERA(horiz)) < 0) + if (G_DoThirdPerson(pPlayer, &CAMERA(pos), &CAMERA(sect), CAMERA(ang), CAMERA(qhoriz)) < 0) { CAMERA(pos.z) += 3072; - G_DoThirdPerson(pPlayer, &CAMERA(pos), &CAMERA(sect), CAMERA(ang), CAMERA(horiz)); + G_DoThirdPerson(pPlayer, &CAMERA(pos), &CAMERA(sect), CAMERA(ang), CAMERA(qhoriz)); } } } @@ -941,7 +941,7 @@ void G_DrawRooms(int32_t playerNum, int32_t smoothRatio) // looking through viewscreen CAMERA(pos) = camVect; CAMERA(ang) = pPlayer->ang + pPlayer->look_ang; - CAMERA(horiz) = 100 + sprite[pPlayer->newowner].shade; + CAMERA(qhoriz) = fix16_from_int(100 + sprite[pPlayer->newowner].shade); CAMERA(sect) = sprite[pPlayer->newowner].sectnum; } @@ -1005,7 +1005,7 @@ void G_DrawRooms(int32_t playerNum, int32_t smoothRatio) // like showview must cope with that situation or bail out! int const noDraw = VM_OnEventWithReturn(EVENT_DISPLAYROOMS, pPlayer->i, playerNum, 0); - CAMERA(horiz) = clamp(CAMERA(horiz), HORIZ_MIN, HORIZ_MAX); + CAMERA(qhoriz) = fix16_clamp(CAMERA(qhoriz), F16(HORIZ_MIN), F16(HORIZ_MAX)); if (noDraw != 1) // event return values other than 0 and 1 are reserved { @@ -1015,7 +1015,7 @@ void G_DrawRooms(int32_t playerNum, int32_t smoothRatio) "other values are reserved.\n"); */ - G_HandleMirror(CAMERA(pos.x), CAMERA(pos.y), CAMERA(pos.z), CAMERA(ang), CAMERA(horiz), smoothRatio); + G_HandleMirror(CAMERA(pos.x), CAMERA(pos.y), CAMERA(pos.z), CAMERA(ang), CAMERA(qhoriz), smoothRatio); #ifdef LEGACY_ROR G_SE40(smoothRatio); #endif @@ -1030,7 +1030,7 @@ void G_DrawRooms(int32_t playerNum, int32_t smoothRatio) gotpic[MIRROR>>3] |= (1<<(MIRROR&7)); #else yax_preparedrawrooms(); - drawrooms(CAMERA(pos.x),CAMERA(pos.y),CAMERA(pos.z),CAMERA(ang),CAMERA(horiz),CAMERA(sect)); + drawrooms(CAMERA(pos.x),CAMERA(pos.y),CAMERA(pos.z),CAMERA(ang),CAMERA(qhoriz),CAMERA(sect)); yax_drawrooms(G_DoSpriteAnimations, CAMERA(sect), 0, smoothRatio); #ifdef LEGACY_ROR if ((unsigned)ror_sprite < MAXSPRITES && drawing_ror == 1) // viewing from bottom @@ -2118,7 +2118,7 @@ int A_Spawn(int spriteNum, int tileNum) T1(newSprite) = krand() & 1; - pSprite->z = (3 << 8) + pPlayer->pyoff + pPlayer->pos.z - ((pPlayer->horizoff + pPlayer->horiz - 100) << 4); + pSprite->z = (3 << 8) + pPlayer->pyoff + pPlayer->pos.z - (fix16_to_int((pPlayer->qhorizoff + pPlayer->qhoriz - F16(100))) << 4); if (pSprite->picnum == SHOTGUNSHELL) pSprite->z += (3 << 8); @@ -6858,7 +6858,7 @@ int G_DoMoveThings(void) sprite[g_player[i].ps->holoduke_on].cstat ^= 256; hitscan((vec3_t *)pPlayer, pPlayer->cursectnum, sintable[(pPlayer->ang + 512) & 2047], sintable[pPlayer->ang & 2047], - (100 - pPlayer->horiz - pPlayer->horizoff) << 11, &hitData, 0xffff0030); + fix16_to_int(F16(100) - pPlayer->qhoriz - pPlayer->qhorizoff) << 11, &hitData, 0xffff0030); for (bssize_t TRAVERSE_CONNECT(i)) if (g_player[i].ps->holoduke_on != -1) diff --git a/source/duke3d/src/game.h b/source/duke3d/src/game.h index 6ba96156c..7c8e2513f 100644 --- a/source/duke3d/src/game.h +++ b/source/duke3d/src/game.h @@ -29,6 +29,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "premap.h" // XXX #endif +#include "fix16.h" + #ifdef __cplusplus extern "C" { #endif @@ -127,7 +129,8 @@ static inline int32_t G_GetLogoFlags(void) typedef struct { vec3_t pos; int32_t dist, clock; - int16_t ang, horiz, sect; + fix16_t qhoriz; + int16_t ang, sect; } camera_t; extern camera_t g_camera; @@ -189,7 +192,8 @@ typedef struct { int32_t returnvar[MAX_RETURN_VALUES-1]; #if !defined LUNATIC - int16_t cameraang, camerasect, camerahoriz; + int16_t cameraang, camerasect; + fix16_t cameraqhoriz; #endif int16_t pause_on,from_bonus; int16_t camerasprite,last_camsprite; @@ -367,7 +371,7 @@ void G_DisplayRest(int32_t smoothratio); void G_DoSpriteAnimations(int32_t ourx, int32_t oury, int32_t oura, int32_t smoothratio); void G_DrawBackground(void); void G_DrawFrags(void); -void G_HandleMirror(int32_t x, int32_t y, int32_t z, int32_t a, int32_t horiz, int32_t smoothratio); +void G_HandleMirror(int32_t x, int32_t y, int32_t z, int32_t a, fix16_t horiz, int32_t smoothratio); void G_DrawRooms(int32_t snum,int32_t smoothratio); void G_DrawTXDigiNumZ(int32_t starttile,int32_t x,int32_t y,int32_t n,int32_t s,int32_t pal,int32_t cs,int32_t x1,int32_t y1,int32_t x2,int32_t y2,int32_t z); int G_FPSLimit(void); diff --git a/source/duke3d/src/gameexec.cpp b/source/duke3d/src/gameexec.cpp index a15763dc6..37feb474a 100644 --- a/source/duke3d/src/gameexec.cpp +++ b/source/duke3d/src/gameexec.cpp @@ -285,7 +285,7 @@ GAMEEXEC_STATIC GAMEEXEC_INLINE void P_ForceAngle(DukePlayer_t *pPlayer) { int const nAngle = 128-(krand()&255); - pPlayer->horiz += 64; + pPlayer->qhoriz += F16(64); pPlayer->return_to_center = 9; pPlayer->rotscrnang = nAngle >> 1; pPlayer->look_ang = pPlayer->rotscrnang; diff --git a/source/duke3d/src/gamestructures.cpp b/source/duke3d/src/gamestructures.cpp index 048505a70..a96d47485 100644 --- a/source/duke3d/src/gamestructures.cpp +++ b/source/duke3d/src/gamestructures.cpp @@ -539,9 +539,9 @@ int32_t __fastcall VM_GetPlayer(int32_t const playerNum, int32_t labelNum, int32 case PLAYER_POSX: labelNum = ps->pos.x; break; case PLAYER_POSY: labelNum = ps->pos.y; break; case PLAYER_POSZ: labelNum = ps->pos.z; break; - case PLAYER_HORIZ: labelNum = ps->horiz; break; - case PLAYER_OHORIZ: labelNum = ps->ohoriz; break; - case PLAYER_OHORIZOFF: labelNum = ps->ohorizoff; break; + case PLAYER_HORIZ: labelNum = fix16_to_int(ps->qhoriz); break; + case PLAYER_OHORIZ: labelNum = fix16_to_int(ps->oqhoriz); break; + case PLAYER_OHORIZOFF: labelNum = fix16_to_int(ps->oqhorizoff); break; case PLAYER_INVDISPTIME: labelNum = ps->invdisptime; break; case PLAYER_BOBPOSX: labelNum = ps->bobpos.x; break; case PLAYER_BOBPOSY: labelNum = ps->bobpos.y; break; @@ -578,7 +578,7 @@ int32_t __fastcall VM_GetPlayer(int32_t const playerNum, int32_t labelNum, int32 case PLAYER_CURR_WEAPON: labelNum = ps->curr_weapon; break; case PLAYER_LAST_WEAPON: labelNum = ps->last_weapon; break; case PLAYER_TIPINCS: labelNum = ps->tipincs; break; - case PLAYER_HORIZOFF: labelNum = ps->horizoff; break; + case PLAYER_HORIZOFF: labelNum = fix16_to_int(ps->qhorizoff); break; case PLAYER_WANTWEAPONFIRE: labelNum = ps->wantweaponfire; break; case PLAYER_HOLODUKE_AMOUNT: labelNum = ps->inv_amount[GET_HOLODUKE]; break; case PLAYER_NEWOWNER: labelNum = ps->newowner; break; @@ -723,9 +723,9 @@ void __fastcall VM_SetPlayer(int32_t const playerNum, int32_t const labelNum, in case PLAYER_POSX: ps->pos.x = iSet; break; case PLAYER_POSY: ps->pos.y = iSet; break; case PLAYER_POSZ: ps->pos.z = iSet; break; - case PLAYER_HORIZ: ps->horiz = iSet; break; - case PLAYER_OHORIZ: ps->ohoriz = iSet; break; - case PLAYER_OHORIZOFF: ps->ohorizoff = iSet; break; + case PLAYER_HORIZ: ps->qhoriz = fix16_from_int(iSet); break; + case PLAYER_OHORIZ: ps->oqhoriz = fix16_from_int(iSet); break; + case PLAYER_OHORIZOFF: ps->oqhorizoff = fix16_from_int(iSet); break; case PLAYER_INVDISPTIME: ps->invdisptime = iSet; break; case PLAYER_BOBPOSX: ps->bobpos.x = iSet; break; case PLAYER_BOBPOSY: ps->bobpos.y = iSet; break; @@ -762,7 +762,7 @@ void __fastcall VM_SetPlayer(int32_t const playerNum, int32_t const labelNum, in case PLAYER_CURR_WEAPON: ps->curr_weapon = iSet; break; case PLAYER_LAST_WEAPON: ps->last_weapon = iSet; break; case PLAYER_TIPINCS: ps->tipincs = iSet; break; - case PLAYER_HORIZOFF: ps->horizoff = iSet; break; + case PLAYER_HORIZOFF: ps->qhorizoff = fix16_from_int(iSet); break; case PLAYER_WANTWEAPONFIRE: ps->wantweaponfire = iSet; break; case PLAYER_HOLODUKE_AMOUNT: ps->inv_amount[GET_HOLODUKE] = iSet; break; case PLAYER_NEWOWNER: ps->newowner = iSet; break; @@ -907,7 +907,7 @@ int32_t __fastcall VM_GetPlayerInput(int32_t const playerNum, int32_t labelNum) switch (labelNum) { case INPUT_AVEL: labelNum = i->avel; break; - case INPUT_HORZ: labelNum = i->horz; break; + case INPUT_HORZ: labelNum = fix16_to_int(i->qhorz); break; case INPUT_FVEL: labelNum = i->fvel; break; case INPUT_SVEL: labelNum = i->svel; break; case INPUT_BITS: labelNum = i->bits; break; @@ -931,7 +931,7 @@ void __fastcall VM_SetPlayerInput(int32_t const playerNum, int32_t const labelNu switch (labelNum) { case INPUT_AVEL: i->avel = iSet; break; - case INPUT_HORZ: i->horz = iSet; break; + case INPUT_HORZ: i->qhorz = fix16_from_int(iSet); break; case INPUT_FVEL: i->fvel = iSet; break; case INPUT_SVEL: i->svel = iSet; break; case INPUT_BITS: i->bits = iSet; break; diff --git a/source/duke3d/src/gamevars.cpp b/source/duke3d/src/gamevars.cpp index 760dbbf6e..f9fecf797 100644 --- a/source/duke3d/src/gamevars.cpp +++ b/source/duke3d/src/gamevars.cpp @@ -1544,7 +1544,7 @@ static void Gv_AddSystemVars(void) Gv_NewVar("cameray",(intptr_t)&ud.camerapos.y, GAMEVAR_SYSTEM | GAMEVAR_INT32PTR); Gv_NewVar("cameraz",(intptr_t)&ud.camerapos.z, GAMEVAR_SYSTEM | GAMEVAR_INT32PTR); Gv_NewVar("cameraang",(intptr_t)&ud.cameraang, GAMEVAR_SYSTEM | GAMEVAR_INT16PTR); - Gv_NewVar("camerahoriz",(intptr_t)&ud.camerahoriz, GAMEVAR_SYSTEM | GAMEVAR_INT16PTR); + Gv_NewVar("camerahoriz",(intptr_t)&ud.cameraqhoriz, GAMEVAR_SYSTEM | GAMEVAR_INT16PTR); // XXX FIXME Gv_NewVar("camerasect",(intptr_t)&ud.camerasect, GAMEVAR_SYSTEM | GAMEVAR_INT16PTR); Gv_NewVar("cameradist",(intptr_t)&g_cameraDistance, GAMEVAR_SYSTEM | GAMEVAR_INT32PTR); Gv_NewVar("cameraclock",(intptr_t)&g_cameraClock, GAMEVAR_SYSTEM | GAMEVAR_INT32PTR); @@ -1701,7 +1701,7 @@ void Gv_RefreshPointers(void) aGameVars[Gv_GetVarIndex("cameray")].global = (intptr_t)&ud.camerapos.y; aGameVars[Gv_GetVarIndex("cameraz")].global = (intptr_t)&ud.camerapos.z; aGameVars[Gv_GetVarIndex("cameraang")].global = (intptr_t)&ud.cameraang; - aGameVars[Gv_GetVarIndex("camerahoriz")].global = (intptr_t)&ud.camerahoriz; + aGameVars[Gv_GetVarIndex("camerahoriz")].global = (intptr_t)&ud.cameraqhoriz; // XXX FIXME aGameVars[Gv_GetVarIndex("camerasect")].global = (intptr_t)&ud.camerasect; aGameVars[Gv_GetVarIndex("cameradist")].global = (intptr_t)&g_cameraDistance; aGameVars[Gv_GetVarIndex("cameraclock")].global = (intptr_t)&g_cameraClock; diff --git a/source/duke3d/src/net.cpp b/source/duke3d/src/net.cpp index 22133e80f..b71a96539 100644 --- a/source/duke3d/src/net.cpp +++ b/source/duke3d/src/net.cpp @@ -1442,8 +1442,8 @@ void Net_FillPlayerUpdate(playerupdate_t *update, int32_t player) update->opos = g_player[player].ps->opos; update->vel = g_player[player].ps->vel; update->ang = g_player[player].ps->ang; - update->horiz = g_player[player].ps->horiz; - update->horizoff = g_player[player].ps->horizoff; + update->horiz = g_player[player].ps->qhoriz; + update->horizoff = g_player[player].ps->qhorizoff; update->ping = g_player[player].ping; update->deadflag = g_player[player].ps->dead_flag; update->playerquitflag = g_player[player].playerquitflag; @@ -1459,8 +1459,8 @@ void Net_ExtractPlayerUpdate(playerupdate_t *update, int32_t type) g_player[playerindex].ps->opos = update->opos; g_player[playerindex].ps->vel = update->vel; g_player[playerindex].ps->ang = update->ang; - g_player[playerindex].ps->horiz = update->horiz; - g_player[playerindex].ps->horizoff = update->horizoff; + g_player[playerindex].ps->qhoriz = update->horiz; + g_player[playerindex].ps->qhorizoff = update->horizoff; } if (type == PACKET_MASTER_TO_SLAVE) diff --git a/source/duke3d/src/player.cpp b/source/duke3d/src/player.cpp index 161e6a40b..78fce8619 100644 --- a/source/duke3d/src/player.cpp +++ b/source/duke3d/src/player.cpp @@ -289,7 +289,7 @@ static int A_FindTargetSprite(const spritetype *pSprite, int projAng, int projec if (pSprite->picnum == APLAYER) { const DukePlayer_t *const ps = g_player[P_GetP(pSprite)].ps; - onScreen = (klabs(scale(SZ(spriteNum)-pSprite->z,10,spriteDist)-(ps->horiz+ps->horizoff-100)) < 100); + onScreen = (klabs(scale(SZ(spriteNum)-pSprite->z,10,spriteDist)-fix16_to_int(ps->qhoriz+ps->qhorizoff-F16(100))) < 100); } int const canSee = (PN(spriteNum) == ORGANTIC || PN(spriteNum) == ROTATEGUN) @@ -480,7 +480,7 @@ static void P_PreFireHitscan(int spriteNum, int playerNum, int projecTile, vec3_ { hitdata_t hitData; - *zvel = A_GetShootZvel((100-pPlayer->horiz-pPlayer->horizoff)<<5); + *zvel = A_GetShootZvel(fix16_to_int(F16(100)-pPlayer->qhoriz-pPlayer->qhorizoff)<<5); hitscan(srcVect, sprite[spriteNum].sectnum, sintable[(*shootAng + 512) & 2047], sintable[*shootAng & 2047], *zvel << 6, &hitData, CLIPMASK1); @@ -503,7 +503,7 @@ static void P_PreFireHitscan(int spriteNum, int playerNum, int projecTile, vec3_ if (aimSprite == -1) // no target { notarget: - *zvel = (100-pPlayer->horiz-pPlayer->horizoff)<<5; + *zvel = fix16_to_int(F16(100)-pPlayer->qhoriz-pPlayer->qhorizoff)<<5; } Proj_MaybeAddSpread(doSpread, zvel, shootAng, zRange, angRange); @@ -917,7 +917,7 @@ static int A_ShootCustom(int const spriteNum, int const projecTile, int shootAng otherSprite = GetAutoAimAng(spriteNum, playerNum, projecTile, 8<<8, 0+2, startPos, pProj->vel, &zvel, &shootAng); if (otherSprite < 0) - zvel = (100-pPlayer->horiz-pPlayer->horizoff)*(pProj->vel/8); + zvel = fix16_to_int(F16(100)-pPlayer->qhoriz-pPlayer->qhorizoff)*(pProj->vel/8); if (pProj->sound >= 0) A_PlaySound(pProj->sound, spriteNum); @@ -976,7 +976,7 @@ static int A_ShootCustom(int const spriteNum, int const projecTile, int shootAng case PROJECTILE_KNEE: if (playerNum >= 0) { - zvel = (100 - pPlayer->horiz - pPlayer->horizoff) << 5; + zvel = fix16_to_int(F16(100) - pPlayer->qhoriz - pPlayer->qhorizoff) << 5; startPos->z += (6 << 8); shootAng += 15; } @@ -1095,7 +1095,7 @@ static int32_t A_ShootHardcoded(int spriteNum, int projecTile, int shootAng, vec { if (playerNum >= 0) { - Zvel = (100 - pPlayer->horiz - pPlayer->horizoff) << 5; + Zvel = fix16_to_int(F16(100) - pPlayer->qhoriz - pPlayer->qhorizoff) << 5; startPos.z += (6 << 8); shootAng += 15; } @@ -1239,7 +1239,7 @@ static int32_t A_ShootHardcoded(int spriteNum, int projecTile, int shootAng, vec if (playerNum >= 0) { if (GetAutoAimAng(spriteNum, playerNum, projecTile, -ZOFFSET4, 0, &startPos, vel, &Zvel, &shootAng) < 0) - Zvel = (100 - pPlayer->horiz - pPlayer->horizoff) * 98; + Zvel = fix16_to_int(F16(100) - pPlayer->qhoriz - pPlayer->qhorizoff) * 98; } else { @@ -1306,7 +1306,7 @@ static int32_t A_ShootHardcoded(int spriteNum, int projecTile, int shootAng, vec j = GetAutoAimAng(spriteNum, playerNum, projecTile, 8 << 8, 0 + 2, &startPos, vel, &Zvel, &shootAng); if (j < 0) - Zvel = (100 - pPlayer->horiz - pPlayer->horizoff) * 81; + Zvel = fix16_to_int(F16(100) - pPlayer->qhoriz - pPlayer->qhorizoff) * 81; if (projecTile == RPG) A_PlaySound(RPG_SHOOT, spriteNum); @@ -1413,7 +1413,7 @@ static int32_t A_ShootHardcoded(int spriteNum, int projecTile, int shootAng, vec case HANDHOLDINGLASER__STATIC: { int const zOffset = (playerNum >= 0) ? g_player[playerNum].ps->pyoff : 0; - Zvel = (playerNum >= 0) ? (100 - pPlayer->horiz - pPlayer->horizoff) * 32 : 0; + Zvel = (playerNum >= 0) ? fix16_to_int(F16(100) - pPlayer->qhoriz - pPlayer->qhorizoff) * 32 : 0; startPos.z -= zOffset; Proj_DoHitscan(spriteNum, 0, &startPos, Zvel, shootAng, &hitData); @@ -1513,7 +1513,7 @@ static int32_t A_ShootHardcoded(int spriteNum, int projecTile, int shootAng, vec if (playerNum >= 0) { if (GetAutoAimAng(spriteNum, playerNum, projecTile, ZOFFSET6, 0, &startPos, 768, &Zvel, &shootAng) < 0) - Zvel = (100 - pPlayer->horiz - pPlayer->horizoff) * 98; + Zvel = fix16_to_int(F16(100) - pPlayer->qhoriz - pPlayer->qhorizoff) * 98; } else if (pSprite->statnum != STAT_EFFECTOR) { @@ -1831,7 +1831,7 @@ static int P_DisplayKnee(int kneeShade) kneePal = ps->palookup; G_DrawTileScaled(105+(g_player[screenpeek].inputBits->avel>>5)-(ps->look_ang>>1)+(knee_y[ps->knee_incs]>>2), - kneeY+280-((ps->horiz-ps->horizoff)>>4),KNEE,kneeShade,4+DRAWEAP_CENTER,kneePal); + kneeY+280-(fix16_to_int(ps->qhoriz-ps->qhorizoff)>>4),KNEE,kneeShade,4+DRAWEAP_CENTER,kneePal); return 1; } @@ -1861,7 +1861,7 @@ static int P_DisplayKnuckles(int knuckleShade) int const knucklePal = P_GetHudPal(pPlayer); G_DrawTileScaled(160 + (g_player[screenpeek].inputBits->avel >> 5) - (pPlayer->look_ang >> 1), - knuckleY + 180 - ((pPlayer->horiz - pPlayer->horizoff) >> 4), + knuckleY + 180 - (fix16_to_int(pPlayer->qhoriz - pPlayer->qhorizoff) >> 4), CRACKKNUCKLES + knuckleFrames[pPlayer->knuckle_incs >> 1], knuckleShade, 4 + DRAWEAP_CENTER, knucklePal); @@ -2016,7 +2016,7 @@ static int P_DisplayTip(int tipShade) guniqhudid = 201; G_DrawTileScaled(170 + (g_player[screenpeek].inputBits->avel >> 5) - (pPlayer->look_ang >> 1), - tipYOffset + tipY + 240 - ((pPlayer->horiz - pPlayer->horizoff) >> 4), + tipYOffset + tipY + 240 - (fix16_to_int(pPlayer->qhoriz - pPlayer->qhorizoff) >> 4), TIP + ((26 - pPlayer->tipincs) >> 4), tipShade, DRAWEAP_CENTER, tipPal); guniqhudid = 0; @@ -2049,13 +2049,13 @@ static int P_DisplayAccess(int accessShade) if ((pSprite->access_incs - 3) > 0 && (pSprite->access_incs - 3) >> 3) { G_DrawTileScaled(170 + (g_player[screenpeek].inputBits->avel >> 5) - (pSprite->look_ang >> 1) + accessX, - accessY + 266 - ((pSprite->horiz - pSprite->horizoff) >> 4), + accessY + 266 - (fix16_to_int(pSprite->qhoriz - pSprite->qhorizoff) >> 4), HANDHOLDINGLASER + (pSprite->access_incs >> 3), accessShade, DRAWEAP_CENTER, accessPal); } else { G_DrawTileScaled(170 + (g_player[screenpeek].inputBits->avel >> 5) - (pSprite->look_ang >> 1) + accessX, - accessY + 266 - ((pSprite->horiz - pSprite->horizoff) >> 4), HANDHOLDINGACCESS, accessShade, + accessY + 266 - (fix16_to_int(pSprite->qhoriz - pSprite->qhorizoff) >> 4), HANDHOLDINGACCESS, accessShade, 4 + DRAWEAP_CENTER, accessPal); } @@ -2886,7 +2886,7 @@ void P_GetInput(int playerNum) // JBF: Run key behaviour is selectable int const playerRunning = (ud.runkey_mode) ? (BUTTON(gamefunc_Run) | ud.auto_run) : (ud.auto_run ^ BUTTON(gamefunc_Run)); - staticInput.svel = staticInput.fvel = staticInput.avel = staticInput.horz = 0; + staticInput.svel = staticInput.fvel = staticInput.avel = staticInput.qhorz = 0; if (BUTTON(gamefunc_Strafe)) { @@ -2900,9 +2900,10 @@ void P_GetInput(int playerNum) info[1].dyaw = (info[1].dyaw + info[0].dyaw) % 32; } - staticInput.horz = (ud.mouseflip) ? -(info[0].dpitch + info[1].dpitch) / (314 - 128) : (info[0].dpitch + info[1].dpitch) / (314 - 128); + staticInput.qhorz = fix16_div(fix16_from_int(info[0].dpitch), F16(512)); + + if (ud.mouseflip) staticInput.qhorz = -staticInput.qhorz; - info[1].dpitch = (info[1].dpitch + info[0].dpitch) % (314 - 128); staticInput.svel -= info[0].dx; info[1].dz = info[0].dz % (1 << 6); staticInput.fvel = -info[0].dz >> 6; @@ -2950,7 +2951,7 @@ void P_GetInput(int playerNum) staticInput.fvel = clamp(staticInput.fvel, -MAXVEL, MAXVEL); staticInput.svel = clamp(staticInput.svel, -MAXSVEL, MAXSVEL); staticInput.avel = clamp(staticInput.avel, -MAXANGVEL, MAXANGVEL); - staticInput.horz = clamp(staticInput.horz, -MAXHORIZ, MAXHORIZ); + staticInput.qhorz = fix16_clamp(staticInput.qhorz, F16(-MAXHORIZ), F16(MAXHORIZ)); int weaponSelection; @@ -3050,7 +3051,7 @@ void P_GetInput(int playerNum) localInput.fvel = 0; localInput.svel = 0; localInput.avel = 0; - localInput.horz = 0; + localInput.qhorz = 0; return; } @@ -3063,7 +3064,7 @@ void P_GetInput(int playerNum) pPlayer->fric.y; localInput.avel = staticInput.avel; - localInput.horz = staticInput.horz; + localInput.qhorz = staticInput.qhorz; } static int32_t P_DoCounters(int playerNum) @@ -3917,7 +3918,7 @@ static void P_ProcessWeapon(int playerNum) hitdata_t hitData; hitscan((const vec3_t *)pPlayer, pPlayer->cursectnum, sintable[(pPlayer->ang + 512) & 2047], - sintable[pPlayer->ang & 2047], (100 - pPlayer->horiz - pPlayer->horizoff) * 32, &hitData, + sintable[pPlayer->ang & 2047], fix16_to_int(F16(100) - pPlayer->qhoriz - pPlayer->qhorizoff) * 32, &hitData, CLIPMASK1); if ((hitData.sect < 0 || hitData.sprite >= 0) || @@ -4015,12 +4016,12 @@ static void P_ProcessWeapon(int playerNum) if (pPlayer->on_ground && TEST_SYNC_KEY(playerBits, SK_CROUCH)) { pipeBombFwdVel = 15; - pipeBombZvel = ((pPlayer->horiz + pPlayer->horizoff - 100) * 20); + pipeBombZvel = (fix16_to_int(pPlayer->qhoriz + pPlayer->qhorizoff - F16(100)) * 20); } else { pipeBombFwdVel = 140; - pipeBombZvel = -512 - ((pPlayer->horiz + pPlayer->horizoff - 100) * 20); + pipeBombZvel = -512 - (fix16_to_int(pPlayer->qhoriz + pPlayer->qhorizoff - F16(100)) * 20); } int pipeSpriteNum = A_InsertSprite(pPlayer->cursectnum, @@ -4513,8 +4514,8 @@ static void P_Dead(int const playerNum, int const sectorLotag, int const floorZ, pPlayer->oang = pPlayer->ang; pPlayer->opyoff = pPlayer->pyoff; - pPlayer->horiz = 100; - pPlayer->horizoff = 0; + pPlayer->qhoriz = F16(100); + pPlayer->qhorizoff = 0; updatesector(pPlayer->pos.x, pPlayer->pos.y, &pPlayer->cursectnum); @@ -4605,8 +4606,8 @@ void P_ProcessInput(int playerNum) actor[pPlayer->i].floorz = floorZ; actor[pPlayer->i].ceilingz = ceilZ; - pPlayer->ohoriz = pPlayer->horiz; - pPlayer->ohorizoff = pPlayer->horizoff; + pPlayer->oqhoriz = pPlayer->qhoriz; + pPlayer->oqhorizoff = pPlayer->qhorizoff; // calculates automatic view angle for playing without a mouse if (pPlayer->aim_mode == 0 && pPlayer->on_ground && sectorLotag != ST_2_UNDERWATER @@ -4623,14 +4624,14 @@ void P_ProcessInput(int playerNum) int const slopeZ = getflorzofslope(pPlayer->cursectnum, adjustedPlayer.x, adjustedPlayer.y); if ((pPlayer->cursectnum == curSectNum) || (klabs(getflorzofslope(curSectNum, adjustedPlayer.x, adjustedPlayer.y) - slopeZ) <= ZOFFSET6)) - pPlayer->horizoff += mulscale16(trueFloorZ - slopeZ, 160); + pPlayer->qhorizoff += fix16_from_int(mulscale16(trueFloorZ - slopeZ, 160)); } } - if (pPlayer->horizoff > 0) - pPlayer->horizoff -= ((pPlayer->horizoff >> 3) + 1); - else if (pPlayer->horizoff < 0) - pPlayer->horizoff += (((-pPlayer->horizoff) >> 3) + 1); + if (pPlayer->qhorizoff > 0) + pPlayer->qhorizoff -= ((pPlayer->qhorizoff >> 3) + fix16_one); + else if (pPlayer->qhorizoff < 0) + pPlayer->qhorizoff += (((-pPlayer->qhorizoff) >> 3) + fix16_one); if (highZhit >= 0 && (highZhit&49152) == 49152) { @@ -5317,7 +5318,7 @@ HORIZONLY:; if (VM_OnEvent(EVENT_LOOKUP,pPlayer->i,playerNum) == 0) { pPlayer->return_to_center = 9; - pPlayer->horiz += 12<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN)); + pPlayer->qhoriz += fix16_from_int(12<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN))); centerHoriz++; } } @@ -5327,7 +5328,7 @@ HORIZONLY:; if (VM_OnEvent(EVENT_LOOKDOWN,pPlayer->i,playerNum) == 0) { pPlayer->return_to_center = 9; - pPlayer->horiz -= 12<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN)); + pPlayer->qhoriz -= fix16_from_int(12<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN))); centerHoriz++; } } @@ -5336,7 +5337,7 @@ HORIZONLY:; { if (VM_OnEvent(EVENT_AIMUP,pPlayer->i,playerNum) == 0) { - pPlayer->horiz += 6<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN)); + pPlayer->qhoriz += fix16_from_int(6<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN))); centerHoriz++; } } @@ -5345,7 +5346,7 @@ HORIZONLY:; { if (VM_OnEvent(EVENT_AIMDOWN,pPlayer->i,playerNum) == 0) { - pPlayer->horiz -= 6<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN)); + pPlayer->qhoriz -= fix16_from_int(6<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN))); centerHoriz++; } } @@ -5353,23 +5354,23 @@ HORIZONLY:; if (pPlayer->return_to_center > 0 && !TEST_SYNC_KEY(playerBits, SK_LOOK_UP) && !TEST_SYNC_KEY(playerBits, SK_LOOK_DOWN)) { pPlayer->return_to_center--; - pPlayer->horiz += 33-(pPlayer->horiz/3); + pPlayer->qhoriz += F16(33)-fix16_div(pPlayer->qhoriz, F16(3)); centerHoriz++; } if (pPlayer->hard_landing > 0) { pPlayer->hard_landing--; - pPlayer->horiz -= (pPlayer->hard_landing<<4); + pPlayer->qhoriz -= fix16_from_int(pPlayer->hard_landing<<4); } if (centerHoriz) { - if (pPlayer->horiz > 95 && pPlayer->horiz < 105) pPlayer->horiz = 100; - if (pPlayer->horizoff > -5 && pPlayer->horizoff < 5) pPlayer->horizoff = 0; + if (pPlayer->qhoriz > F16(95) && pPlayer->qhoriz < F16(105)) pPlayer->qhoriz = F16(100); + if (pPlayer->qhorizoff > F16(-5) && pPlayer->qhorizoff < F16(5)) pPlayer->qhorizoff = 0; } - pPlayer->horiz = clamp(pPlayer->horiz + g_player[playerNum].inputBits->horz, HORIZ_MIN, HORIZ_MAX); + pPlayer->qhoriz = fix16_clamp(pPlayer->qhoriz + g_player[playerNum].inputBits->qhorz, F16(HORIZ_MIN), F16(HORIZ_MAX)); //Shooting code/changes @@ -5391,7 +5392,7 @@ HORIZONLY:; if (pPlayer->knee_incs > 0) { - pPlayer->horiz -= 48; + pPlayer->qhoriz -= F16(48); pPlayer->return_to_center = 9; if (++pPlayer->knee_incs > 15) diff --git a/source/duke3d/src/player.h b/source/duke3d/src/player.h index 770c16b13..bd1760bfe 100644 --- a/source/duke3d/src/player.h +++ b/source/duke3d/src/player.h @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define player_h_ #include "inv.h" +#include "fix16.h" #ifdef __cplusplus extern "C" { @@ -119,7 +120,8 @@ typedef struct { typedef struct { uint32_t bits; int16_t fvel, svel, avel; - int8_t horz, extbits; + fix16_t qhorz; + int8_t extbits; } input_t; #pragma pack(push,1) @@ -155,7 +157,7 @@ typedef struct { int16_t max_ammo_amount[MAX_WEAPONS], ammo_amount[MAX_WEAPONS], inv_amount[GET_MAX]; int16_t wackedbyactor, pyoff, opyoff; - int16_t horiz, horizoff, ohoriz, ohorizoff; + fix16_t qhoriz, qhorizoff, oqhoriz, oqhorizoff; int16_t newowner, jumping_counter, airleft; int16_t fta, ftq, access_wallnum, access_spritenum; int16_t got_access, weapon_ang, visibility; diff --git a/source/duke3d/src/premap.cpp b/source/duke3d/src/premap.cpp index d56b80d89..0f6803c7c 100644 --- a/source/duke3d/src/premap.cpp +++ b/source/duke3d/src/premap.cpp @@ -712,10 +712,10 @@ void P_ResetPlayer(int playerNum) pPlayer->last_extra = pSprite->extra = pPlayer->max_player_health; pPlayer->wantweaponfire = -1; - pPlayer->horiz = 100; + pPlayer->qhoriz = F16(100); pPlayer->on_crane = -1; pPlayer->frag_ps = playerNum; - pPlayer->horizoff = 0; + pPlayer->qhorizoff = 0; pPlayer->opyoff = 0; pPlayer->wackedbyactor = -1; pPlayer->inv_amount[GET_SHIELD] = g_startArmorAmount; @@ -790,9 +790,9 @@ void P_ResetStatus(int playerNum) pPlayer->footprintpal = 0; pPlayer->footprintshade = 0; pPlayer->jumping_toggle = 0; - pPlayer->ohoriz = 140; - pPlayer->horiz = 140; - pPlayer->horizoff = 0; + pPlayer->oqhoriz = F16(140); + pPlayer->qhoriz = F16(140); + pPlayer->qhorizoff = 0; pPlayer->bobcounter = 0; pPlayer->on_ground = 0; pPlayer->player_par = 0; diff --git a/source/duke3d/src/screens.cpp b/source/duke3d/src/screens.cpp index 0087fc95b..779404cfe 100644 --- a/source/duke3d/src/screens.cpp +++ b/source/duke3d/src/screens.cpp @@ -639,7 +639,10 @@ static void G_PrintCoords(int32_t snum) } Bsprintf(tempbuf, "XYZ= (%d, %d, %d)", ps->pos.x, ps->pos.y, ps->pos.z); printext256(x, y, COLOR_WHITE, -1, tempbuf, 0); - Bsprintf(tempbuf, "A/H/HO= %d, %d, %d", ps->ang, ps->horiz, ps->horizoff); + char horiz[16], horizoff[16]; + fix16_to_str(ps->qhoriz, horiz, 2); + fix16_to_str(ps->qhorizoff, horizoff, 2); + Bsprintf(tempbuf, "A/H/HO= %d, %s, %s", ps->ang, horiz, horizoff); printext256(x, y+9, COLOR_WHITE, -1, tempbuf, 0); Bsprintf(tempbuf, "VEL= (%d, %d, %d) + (%d, %d, 0)", ps->vel.x>>14, ps->vel.y>>14, ps->vel.z, ps->fric.x>>5, ps->fric.y>>5);