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);