zicodxx reports thatf7d0c85
made the thief bot passive and timid. His analysis suggests that the problem is becausef7d0c85
changed find_connected_distance to return vm_distance::maximum_value() in places where it previously returned magic values that were not maximum (caching a distance of F1_0*1000 and returning a distance of -1). Rather than try to fix the underlying code that relied on these magic values, revert those return paths to return these unusual values. Move the unusual values to named constants in file scope so that they are easier to find and correlate. Reported-by: zicodxx <https://github.com/dxx-rebirth/dxx-rebirth/issues/286> Analyzed-by: zicodxx Fixes:f7d0c853ba
("Use special types for distance/magnitude")
415 lines
12 KiB
C++
415 lines
12 KiB
C++
/*
|
|
* Portions of this file are copyright Rebirth contributors and licensed as
|
|
* described in COPYING.txt.
|
|
* Portions of this file are copyright Parallax Software and licensed
|
|
* according to the Parallax license below.
|
|
* See COPYING.txt for license details.
|
|
|
|
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
|
|
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
|
|
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
|
|
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
|
|
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
|
|
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
|
|
FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
|
|
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
|
|
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
|
|
COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|
*/
|
|
|
|
/*
|
|
*
|
|
* Header file for vector/matrix library
|
|
*
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#ifdef __cplusplus
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <utility>
|
|
#include "fwd-vecmat.h"
|
|
|
|
namespace dcx {
|
|
|
|
//The basic fixed-point vector. Access elements by name or position
|
|
struct vms_vector
|
|
{
|
|
fix x, y, z;
|
|
};
|
|
|
|
class vm_distance
|
|
{
|
|
public:
|
|
fix d;
|
|
/* Default constructor only required because Fcd_cache,SoundObjects
|
|
* have global scope instances of vm_distance. They should be
|
|
* converted to construct as needed, then the default constructor
|
|
* should be removed.
|
|
*/
|
|
constexpr vm_distance() : d(0) {}
|
|
constexpr explicit vm_distance(const fix &f) :
|
|
d(f)
|
|
{
|
|
}
|
|
template <typename T>
|
|
vm_distance &operator+=(const T &rhs)
|
|
{
|
|
return *this = (*this + rhs);
|
|
}
|
|
template <typename T>
|
|
vm_distance &operator*=(const T &rhs)
|
|
{
|
|
return *this = (*this * rhs);
|
|
}
|
|
template <typename T>
|
|
vm_distance &operator/=(const T &rhs)
|
|
{
|
|
return *this = (*this / rhs);
|
|
}
|
|
constexpr vm_distance operator+(const vm_distance &rhs) const
|
|
{
|
|
return vm_distance{d + rhs.d};
|
|
}
|
|
constexpr vm_distance operator*(const int &f) const
|
|
{
|
|
return vm_distance{d * f};
|
|
}
|
|
constexpr vm_distance operator/(const int &f) const
|
|
{
|
|
return vm_distance{d / f};
|
|
}
|
|
constexpr bool operator<(const fix &f) const
|
|
{
|
|
return d < f;
|
|
}
|
|
constexpr bool operator<(const vm_distance &rhs) const
|
|
{
|
|
return d < rhs.d;
|
|
}
|
|
/* Clang chokes using a template operator> to swap the arguments.
|
|
* Use a non-template operator> for the one needed type.
|
|
*/
|
|
constexpr bool operator>(const fix &f) const
|
|
{
|
|
return d > f;
|
|
}
|
|
template <typename T>
|
|
bool operator>(const T &t) const = delete;
|
|
constexpr explicit operator bool() const { return d; }
|
|
#ifndef __clang__
|
|
/* When this catch-all overload is defined, clang becomes confused
|
|
* and treats all arithmetic operations as ambiguous because it
|
|
* cannot choose between the deleted template function and the
|
|
* non-deleted operator fix().
|
|
*/
|
|
template <typename T>
|
|
operator T() const = delete;
|
|
#endif
|
|
constexpr operator fix() const
|
|
{
|
|
return d;
|
|
}
|
|
constexpr vm_distance_squared operator*(const vm_distance &) const;
|
|
};
|
|
|
|
class vm_magnitude : public vm_distance
|
|
{
|
|
public:
|
|
constexpr explicit vm_magnitude(const uint32_t &f) :
|
|
vm_distance(f)
|
|
{
|
|
}
|
|
};
|
|
|
|
class vm_distance_squared
|
|
{
|
|
public:
|
|
fix64 d2;
|
|
constexpr explicit vm_distance_squared(const fix64 &f2) :
|
|
d2(f2)
|
|
{
|
|
}
|
|
constexpr bool operator<(const vm_distance_squared &rhs) const
|
|
{
|
|
return d2 < rhs.d2;
|
|
}
|
|
constexpr bool operator>(const vm_distance_squared &rhs) const
|
|
{
|
|
return d2 > rhs.d2;
|
|
}
|
|
constexpr bool operator>=(const vm_distance_squared &rhs) const
|
|
{
|
|
return !(*this < rhs);
|
|
}
|
|
template <typename T>
|
|
vm_distance_squared &operator-=(const T &rhs)
|
|
{
|
|
return *this = (*this - rhs);
|
|
}
|
|
constexpr vm_distance_squared operator-(const fix &) const = delete;
|
|
constexpr vm_distance_squared operator-(const fix64 &f2) const
|
|
{
|
|
return vm_distance_squared{d2 - f2};
|
|
}
|
|
explicit operator bool() const { return d2; }
|
|
template <typename T>
|
|
constexpr operator T() const = delete;
|
|
constexpr operator fix64() const
|
|
{
|
|
return d2;
|
|
}
|
|
static constexpr vm_distance_squared maximum_value()
|
|
{
|
|
return vm_distance_squared{0x7fffffffffffffff};
|
|
}
|
|
static constexpr vm_distance_squared minimum_value()
|
|
{
|
|
return vm_distance_squared{0};
|
|
}
|
|
};
|
|
|
|
class vm_magnitude_squared : public vm_distance_squared
|
|
{
|
|
public:
|
|
constexpr explicit vm_magnitude_squared(const uint64_t &f2) :
|
|
vm_distance_squared(f2)
|
|
{
|
|
}
|
|
};
|
|
|
|
constexpr vm_distance_squared vm_distance::operator*(const vm_distance &rhs) const
|
|
{
|
|
return vm_distance_squared{static_cast<fix64>(static_cast<fix>(*this)) * static_cast<fix64>(static_cast<fix>(rhs))};
|
|
}
|
|
|
|
#define DEFINE_SERIAL_VMS_VECTOR_TO_MESSAGE() \
|
|
DEFINE_SERIAL_UDT_TO_MESSAGE(vms_vector, v, (v.x, v.y, v.z)); \
|
|
ASSERT_SERIAL_UDT_MESSAGE_SIZE(vms_vector, 12)
|
|
|
|
//Angle vector. Used to store orientations
|
|
struct vms_angvec
|
|
{
|
|
fixang p, b, h;
|
|
};
|
|
|
|
|
|
//A 3x3 rotation matrix. Sorry about the numbering starting with one.
|
|
//Ordering is across then down, so <m1,m2,m3> is the first row
|
|
struct vms_matrix
|
|
{
|
|
vms_vector rvec, uvec, fvec;
|
|
};
|
|
|
|
// Quaternion structure
|
|
struct vms_quaternion
|
|
{
|
|
signed short w, x, y, z;
|
|
};
|
|
|
|
|
|
//Macros/functions to fill in fields of structures
|
|
|
|
//macro to set a vector to zero. we could do this with an in-line assembly
|
|
//macro, but it's probably better to let the compiler optimize it.
|
|
//Note: NO RETURN VALUE
|
|
static inline void vm_vec_zero(vms_vector &v)
|
|
{
|
|
v = {};
|
|
}
|
|
|
|
//macro set set a matrix to the identity. Note: NO RETURN VALUE
|
|
|
|
// DPH (18/9/98): Begin mod to fix linefeed problem under linux. Uses an
|
|
// inline function instead of a multi-line macro to fix CR/LF problems.
|
|
|
|
// DPH (19/8/98): End changes.
|
|
|
|
//Global constants
|
|
|
|
//Here's a handy constant
|
|
|
|
//negate a vector
|
|
static inline void vm_vec_negate(vms_vector &v)
|
|
{
|
|
v.x = -v.x;
|
|
v.y = -v.y;
|
|
v.z = -v.z;
|
|
}
|
|
|
|
static inline vms_vector vm_vec_negated(vms_vector v) __attribute_warn_unused_result;
|
|
static inline vms_vector vm_vec_negated(vms_vector v)
|
|
{
|
|
return vm_vec_negate(v), v;
|
|
}
|
|
|
|
//Functions in library
|
|
|
|
//adds two vectors, fills in dest, returns ptr to dest
|
|
//ok for dest to equal either source, but should use vm_vec_add2() if so
|
|
static inline vms_vector vm_vec_add (const vms_vector &src0, const vms_vector &src1) __attribute_warn_unused_result;
|
|
static inline vms_vector vm_vec_add (const vms_vector &src0, const vms_vector &src1)
|
|
{
|
|
vms_vector dest;
|
|
return vm_vec_add(dest, src0, src1), dest;
|
|
}
|
|
|
|
|
|
//subs two vectors, fills in dest, returns ptr to dest
|
|
//ok for dest to equal either source, but should use vm_vec_sub2() if so
|
|
static inline vms_vector &vm_vec_sub(vms_vector &dest, const vms_vector &src0, const vms_vector &src1)
|
|
{
|
|
#ifdef DXX_CONSTANT_TRUE
|
|
if (DXX_CONSTANT_TRUE(&src0 == &src1))
|
|
DXX_ALWAYS_ERROR_FUNCTION(vm_vec_sub_same_op, "vm_vec_sub with &src0 == &src1");
|
|
else if (DXX_CONSTANT_TRUE(src0.x == src1.x && src0.y == src1.y && src0.z == src1.z))
|
|
DXX_ALWAYS_ERROR_FUNCTION(vm_vec_sub_same_values, "vm_vec_sub with equal value inputs");
|
|
#endif
|
|
return _vm_vec_sub(dest, src0, src1);
|
|
}
|
|
|
|
__attribute_warn_unused_result
|
|
static inline vms_vector vm_vec_sub (const vms_vector &src0, const vms_vector &src1)
|
|
{
|
|
vms_vector dest;
|
|
return vm_vec_sub(dest, src0, src1), dest;
|
|
}
|
|
|
|
//averages two vectors. returns ptr to dest
|
|
//dest can equal either source
|
|
static inline vms_vector vm_vec_avg (const vms_vector &src0, const vms_vector &src1) __attribute_warn_unused_result;
|
|
static inline vms_vector vm_vec_avg (const vms_vector &src0, const vms_vector &src1)
|
|
{
|
|
vms_vector dest;
|
|
return vm_vec_avg(dest, src0, src1), dest;
|
|
}
|
|
|
|
//scales and copies a vector. returns ptr to dest
|
|
#define vm_vec_copy_scale(A,B,...) vm_vec_copy_scale(A, ## __VA_ARGS__, B)
|
|
static inline vms_vector vm_vec_copy_scale(vms_vector src, fix s) __attribute_warn_unused_result;
|
|
static inline vms_vector vm_vec_copy_scale(vms_vector src, fix s)
|
|
{
|
|
return vm_vec_scale(src, s), src;
|
|
}
|
|
|
|
//scales a vector, adds it to another, and stores in a 3rd vector
|
|
//dest = src1 + k * src2
|
|
static inline vms_vector vm_vec_scale_add(const vms_vector &src1, const vms_vector &src2, fix k) __attribute_warn_unused_result;
|
|
static inline vms_vector vm_vec_scale_add(const vms_vector &src1, const vms_vector &src2, fix k)
|
|
{
|
|
vms_vector dest;
|
|
return vm_vec_scale_add(dest, src1, src2, k), dest;
|
|
}
|
|
|
|
static inline vms_vector vm_vec_normalized(vms_vector v) __attribute_warn_unused_result;
|
|
static inline vms_vector vm_vec_normalized(vms_vector v)
|
|
{
|
|
return vm_vec_normalize(v), v;
|
|
}
|
|
|
|
static inline vms_vector vm_vec_normalized_quick(vms_vector v) __attribute_warn_unused_result;
|
|
static inline vms_vector vm_vec_normalized_quick(vms_vector v)
|
|
{
|
|
return vm_vec_normalize_quick(v), v;
|
|
}
|
|
|
|
static inline vms_vector vm_vec_cross(const vms_vector &src0, const vms_vector &src1) __attribute_warn_unused_result;
|
|
static inline vms_vector vm_vec_cross(const vms_vector &src0, const vms_vector &src1)
|
|
{
|
|
vms_vector dest;
|
|
return vm_vec_cross(dest, src0, src1), dest;
|
|
}
|
|
|
|
static inline vms_vector vm_vec_normal(const vms_vector &p0, const vms_vector &p1, const vms_vector &p2) __attribute_warn_unused_result;
|
|
static inline vms_vector vm_vec_normal(const vms_vector &p0, const vms_vector &p1, const vms_vector &p2)
|
|
{
|
|
vms_vector dest;
|
|
return vm_vec_normal(dest, p0, p1, p2), dest;
|
|
}
|
|
|
|
static inline vms_vector vm_vec_perp (const vms_vector &p0, const vms_vector &p1, const vms_vector &p2) __attribute_warn_unused_result;
|
|
static inline vms_vector vm_vec_perp (const vms_vector &p0, const vms_vector &p1, const vms_vector &p2)
|
|
{
|
|
vms_vector dest;
|
|
return vm_vec_perp(dest, p0, p1, p2), dest;
|
|
}
|
|
|
|
static inline vms_matrix vm_angles_2_matrix (const vms_angvec &a) __attribute_warn_unused_result;
|
|
static inline vms_matrix vm_angles_2_matrix (const vms_angvec &a)
|
|
{
|
|
vms_matrix m;
|
|
return vm_angles_2_matrix(m, a), m;
|
|
}
|
|
|
|
static inline vms_matrix vm_vector_2_matrix (const vms_vector &fvec, const vms_vector *uvec, const vms_vector *rvec) __attribute_warn_unused_result;
|
|
static inline vms_matrix vm_vector_2_matrix (const vms_vector &fvec, const vms_vector *uvec, const vms_vector *rvec)
|
|
{
|
|
vms_matrix m;
|
|
return vm_vector_2_matrix(m, fvec, uvec, rvec), m;
|
|
}
|
|
|
|
static inline vms_vector vm_vec_rotate (const vms_vector &src, const vms_matrix &m) __attribute_warn_unused_result;
|
|
static inline vms_vector vm_vec_rotate (const vms_vector &src, const vms_matrix &m)
|
|
{
|
|
vms_vector dest;
|
|
return vm_vec_rotate(dest, src, m), dest;
|
|
}
|
|
|
|
//transpose a matrix in place. returns ptr to matrix
|
|
static inline void vm_transpose_matrix(vms_matrix &m)
|
|
{
|
|
using std::swap;
|
|
swap(m.uvec.x, m.rvec.y);
|
|
swap(m.fvec.x, m.rvec.z);
|
|
swap(m.fvec.y, m.uvec.z);
|
|
}
|
|
|
|
static inline vms_matrix vm_transposed_matrix(vms_matrix m) __attribute_warn_unused_result;
|
|
static inline vms_matrix vm_transposed_matrix(vms_matrix m)
|
|
{
|
|
vm_transpose_matrix(m);
|
|
return m;
|
|
}
|
|
|
|
//mulitply 2 matrices, fill in dest. returns ptr to dest
|
|
static inline void vm_matrix_x_matrix(vms_matrix &dest, const vms_matrix &src0, const vms_matrix &src1)
|
|
{
|
|
#ifdef DXX_CONSTANT_TRUE
|
|
if (DXX_CONSTANT_TRUE(&dest == &src0))
|
|
DXX_ALWAYS_ERROR_FUNCTION(vm_matrix_x_matrix_dest_src0, "vm_matrix_x_matrix with &dest == &src0");
|
|
else if (DXX_CONSTANT_TRUE(&dest == &src1))
|
|
DXX_ALWAYS_ERROR_FUNCTION(vm_matrix_x_matrix_dest_src1, "vm_matrix_x_matrix with &dest == &src1");
|
|
#endif
|
|
assert(&dest != &src0);
|
|
assert(&dest != &src1);
|
|
return _vm_matrix_x_matrix(dest, src0, src1);
|
|
}
|
|
|
|
static inline vms_matrix vm_matrix_x_matrix(const vms_matrix &src0, const vms_matrix &src1) __attribute_warn_unused_result;
|
|
static inline vms_matrix vm_matrix_x_matrix(const vms_matrix &src0, const vms_matrix &src1)
|
|
{
|
|
vms_matrix dest;
|
|
vm_matrix_x_matrix(dest, src0, src1);
|
|
return dest;
|
|
}
|
|
|
|
static inline vms_angvec vm_extract_angles_matrix (const vms_matrix &m) __attribute_warn_unused_result;
|
|
static inline vms_angvec vm_extract_angles_matrix (const vms_matrix &m)
|
|
{
|
|
vms_angvec a;
|
|
return vm_extract_angles_matrix(a, m), a;
|
|
}
|
|
|
|
//fills in fields of an angle vector
|
|
static inline void vm_angvec_make(vms_angvec *v, fixang p, fixang b, fixang h)
|
|
{
|
|
v->p = p;
|
|
v->b = b;
|
|
v->h = h;
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|