1 /**
2  * @file
3  */
4 
5 /*
6 Copyright (C) 1997-2001 Id Software, Inc.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 
23 */
24 
25 #pragma once
26 
27 #include "ufotypes.h"
28 #include "defines.h"
29 #include <algorithm>
30 #include <cmath>
31 
32 #ifndef M_PI
33 #define M_PI 3.14159265358979323846  /* matches value in gcc v2 math.h */
34 #endif
35 
36 #define	EQUAL_EPSILON	0.001
37 
38 bool Q_IsPowerOfTwo(int i);
39 
40 /* Compare floats with custom epsilon error */
41 #define EQUAL2(a,b,epsilon) (fabs((a)-(b))<epsilon)
42 
43 /* microsoft's fabs seems to be ungodly slow... */
44 #define Q_ftol(f) (long) (f)
45 
46 #define torad (M_PI/180.0f)
47 #define todeg (180.0f/M_PI)
48 
49 /* angle indexes */
50 #define PITCH  0   /* rotation around y axis - up / down (-90 up to 90 degree) */
51 #define YAW    1   /* rotation around z axis - left / right (0 up to 360 degree) */
52 #define ROLL   2   /* rotation around x axis - fall over */
53 
54 /* axis */
55 #define	AXIS_FORWARD	0
56 #define	AXIS_RIGHT		1
57 #define	AXIS_UP			2
58 
59 /* earth map data */
60 /* values of sinus and cosinus of earth inclination (23,5 degrees) for faster day and night calculations */
61 #define SIN_ALPHA   0.39875
62 #define COS_ALPHA   0.91706
63 #define HIGH_LAT    +1.0
64 #define LOW_LAT     -1.0
65 #define CENTER_LAT  0.0
66 #define SIZE_LAT    2.0
67 
68 /**
69  * @brief Number of angles from a position (2-dimensional)
70  * @sa dvecs (in q_shared.c) for a description of its use.
71  * @sa AngleToDV.
72  * @sa BASE_DIRECTIONS
73  */
74 #define DIRECTIONS 8
75 
76 /**
77  * @brief Number of direct connected fields for a position
78  * @sa DIRECTIONS.
79  */
80 #define BASE_DIRECTIONS			4			/* Only the standard N,S,E,W directions */
81 
82 /* game/g_ai.c, game/g_spawn.c, common/routing.c, ufo2map/routing.c, client/cl_actor.c, common/cmodel.c, shared/typedefs.h */
83 #define PATHFINDING_DIRECTIONS	40			/* total number of directions */
84 #define CORE_DIRECTIONS			8			/* The standard N,S,E,W directions plus diagonals. */
85 #define FLYING_DIRECTIONS		16			/* starting number of directions available only to fliers */
86 
87 extern const vec4_t dvecs[PATHFINDING_DIRECTIONS];
88 extern const float dvecsn[CORE_DIRECTIONS][2];
89 extern const float directionAngles[CORE_DIRECTIONS];
90 
91 extern const byte dvright[CORE_DIRECTIONS];
92 extern const byte dvleft[CORE_DIRECTIONS];
93 
94 /** @brief Map boundary is +/- MAX_WORLD_WIDTH - to get into the positive area we add the
95  * possible max negative value and divide by the size of a grid unit field */
96 #define VecToPos(v, p) (                  \
97 	(p)[0] = ((int)(v)[0] + MAX_WORLD_WIDTH) / UNIT_SIZE,  \
98 	(p)[1] = ((int)(v)[1] + MAX_WORLD_WIDTH) / UNIT_SIZE,  \
99 	(p)[2] =  std::min((PATHFINDING_HEIGHT - 1), ((int)(v)[2] / UNIT_HEIGHT)) \
100 )
101 /** @brief Pos boundary size is +/- 128 - to get into the positive area we add
102  * the possible max negative value and multiply with the grid unit size to get
103  * back the vector coordinates - now go into the middle of the grid field
104  * by adding the half of the grid unit size to this value
105  * @sa PATHFINDING_WIDTH */
106 #define PosToVec(p, v) ( \
107 	(v)[0] = ((int)(p)[0] - GRID_WIDTH) * UNIT_SIZE   + UNIT_SIZE   / 2, \
108 	(v)[1] = ((int)(p)[1] - GRID_WIDTH) * UNIT_SIZE   + UNIT_SIZE   / 2, \
109 	(v)[2] =  (int)(p)[2]               * UNIT_HEIGHT + UNIT_HEIGHT / 2  \
110 )
111 
112 #include "vector.h"
113 #include "line.h"
114 #include "aabb.h"
115 
116 class GridBox {
117 public:
118 	static const GridBox EMPTY;
119 
GridBox(const pos3_t mini,const pos3_t maxi)120 	GridBox(const pos3_t mini, const pos3_t maxi) {
121 		VectorCopy(mini, mins);
122 		VectorCopy(maxi, maxs);
123 	}
124 
GridBox(const vec3_t mini,const vec3_t maxi)125 	GridBox(const vec3_t mini, const vec3_t maxi) {
126 		VecToPos(mini, mins);
127 		VecToPos(maxi, maxs);
128 	}
129 
GridBox(const AABB & aabb)130 	GridBox(const AABB& aabb) {
131 		VecToPos(aabb.getMins(), mins);
132 		VecToPos(aabb.getMaxs(), maxs);
133 	}
134 
isZero()135 	inline bool isZero() const {
136 		return VectorIntZero(mins) && VectorIntZero(maxs);
137 	}
138 	/** @brief expand the box in four directions, but clip them to the maximum boundaries
139 	 * @note this is pretty much nonsense with the current setting of PATHFINDING_WIDTH
140 	 * and the data type of pos3_t, but who knows the future... */
expandXY(const int byVal)141 	inline void expandXY(const int byVal) {
142 		mins[0] = std::max(mins[0] - byVal, 0);
143 		mins[1] = std::max(mins[1] - byVal, 0);
144 		maxs[0] = std::min(maxs[0] + byVal, PATHFINDING_WIDTH - 1);
145 		maxs[1] = std::min(maxs[1] + byVal, PATHFINDING_WIDTH - 1);
146 	}
addOneZ()147 	inline void addOneZ () {
148 		maxs[2] = std::min(maxs[2] + 1, PATHFINDING_HEIGHT - 1);
149 	}
clipToMaxBoundaries()150 	inline void clipToMaxBoundaries() {
151 		return;	/* do nothing, see above */
152 	}
set(const pos3_t mini,const pos3_t maxi)153 	inline void set(const pos3_t mini, const pos3_t maxi) {
154 		VectorCopy(mini, mins);
155 		VectorCopy(maxi, maxs);
156 	}
157 
158 	pos3_t mins;
159 	pos3_t maxs;
160 };
161 
162 /** @brief  The direction vector tells us where the actor came from (in his previous step).
163  * The pathing table holds about a million of these dvecs, so we save quite some memory by squeezing
164  * three informations into a short value:
165  * - the direction where he came from
166  * - the z-level he came from
167  * - *how* he moved. There are three special crouching conditions
168  * -- autocrouch: standing upright in the previous cell, now crouch and stay crouched
169  * -- autocrouched: being already autocrouched in the previous cell, stand up if you get the chance
170  * -- autodive: we can stand in both cells, but there is just a small hole in the wall between them
171  */
172 typedef short dvec_t;
173 #define DV_FLAGS_BIT_SHIFT	4	/**< This is the bit shift needed to store the 'how' component of a DV value */
174 #define DV_DIR_BIT_SHIFT	8	/**< This is the bit shift needed to store the dir component of a DV value */
175 #define DV_Z_BIT_MASK		0x0007	/**< The mask to retrieve the z component of a  DV value */
176 #define DV_FLAGS_BIT_MASK	0x00F0	/**< The mask to retrieve the 'how' component of a  DV value */
177 #define DV_DIR_BIT_MASK		0xFF00	/**< The mask to retrieve the dir component of a  DV value */
178 
179 #define DV_FLAG_AUTOCROUCH		0x01
180 #define DV_FLAG_AUTOCROUCHED	0x02
181 #define DV_FLAG_AUTODIVE		0x04
182 
183 #define makeDV(dir, z)				(((dir) << DV_DIR_BIT_SHIFT) | ((z) & DV_Z_BIT_MASK))
184 #define setDVz(dv, z)				(((dv) & (~DV_Z_BIT_MASK)) | ((z) & DV_Z_BIT_MASK))
185 #define getDVdir(dv)				((dv) >> DV_DIR_BIT_SHIFT)
186 #define getDVflags(dv)				(((dv) & DV_FLAGS_BIT_MASK) >> DV_FLAGS_BIT_SHIFT)
187 #define getDVz(dv)					((dv) & DV_Z_BIT_MASK)
188 
189 #define PosAddDV(p, crouch, dv)     ((p)[0]+=dvecs[getDVdir(dv)][0], (p)[1]+=dvecs[getDVdir(dv)][1], (p)[2]=getDVz(dv), (crouch)+=dvecs[getDVdir(dv)][3])
190 #define PosSubDV(p, crouch, dv)     ((p)[0]-=dvecs[getDVdir(dv)][0], (p)[1]-=dvecs[getDVdir(dv)][1], (p)[2]=getDVz(dv), (crouch)-=dvecs[getDVdir(dv)][3])
191 
192 int AngleToDir(int angle);
193 #define AngleToDV(x)	(AngleToDir(x) << DV_DIR_BIT_SHIFT)
194 
195 void VectorMA(const vec3_t veca, const float scale, const vec3_t vecb, vec3_t outVector);
196 void VectorClampMA(vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc);
197 void VectorMix(const vec3_t v1, const vec3_t v2, const float mix, vec3_t out);
198 
199 void MatrixMultiply(const vec3_t a[3], const vec3_t b[3], vec3_t c[3]);
200 void GLMatrixAssemble(const vec3_t origin, const vec3_t angles, float* matrix);
201 void GLMatrixMultiply(const float a[16], const float b[16], float c[16]);
202 void GLVectorTransform(const float m[16], const vec4_t in, vec4_t out);
203 void GLPositionTransform(const float m[16], const vec3_t in, vec3_t out);
204 void VectorRotate(vec3_t m[3], const vec3_t va, vec3_t vb);
205 
206 void ClearBounds(vec3_t mins, vec3_t maxs);
207 void AddPointToBounds(const vec3_t v, vec3_t mins, vec3_t maxs);
208 int VectorCompareEps(const vec3_t v1, const vec3_t v2, float epsilon);
209 bool VectorNearer(const vec3_t v1, const vec3_t v2, const vec3_t comp);
210 vec_t VectorLength(const vec3_t v);
211 void CrossProduct(const vec3_t v1, const vec3_t v2, vec3_t cross);
212 vec_t VectorNormalize(vec3_t v);    /* returns vector length */
213 void VectorNormalizeFast(vec3_t v);
214 vec_t VectorNormalize2(const vec3_t v, vec3_t out);
215 void VectorInverse(vec3_t v);
216 void VectorMidpoint(const vec3_t point1, const vec3_t point2, vec3_t midpoint);
217 int Q_log2(int val);
218 
219 double GetDistanceOnGlobe(const vec2_t pos1, const vec2_t pos2);
220 
221 void VectorCenterFromMinsMaxs(const vec3_t mins, const vec3_t maxs, vec3_t center);
222 void VectorCalcMinsMaxs(const vec3_t center, const vec3_t size, vec3_t mins, vec3_t maxs);
223 float VectorAngleBetween(const vec3_t vec1, const vec3_t vec2);
224 
225 void VecToAngles(const vec3_t vec, vec3_t angles);
226 
227 void Print2Vector(const vec2_t v, const char* text);
228 void Print3Vector(const vec3_t v, const char* text);
229 
230 void VecToPolar(const vec3_t v, vec2_t a);
231 void PolarToVec(const vec2_t a, vec3_t v);
232 
233 void CalculateMinsMaxs(const vec3_t angles, const vec3_t mins, const vec3_t maxs, const vec3_t origin, vec3_t absmin, vec3_t absmax);
234 
235 void VectorCreateRotationMatrix(const vec3_t angles, vec3_t matrix[3]);
236 void VectorRotatePoint(vec3_t point, vec3_t matrix[3]);
237 
238 void AngleVectors(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
239 float AngleNormalize360(float angle);
240 float AngleNormalize180(float angle);
241 
242 float LerpAngle(float a1, float a2, float frac);
243 
244 bool FrustumVis(const vec3_t origin, int dir, const vec3_t point);
245 
246 void PerpendicularVector(vec3_t dst, const vec3_t src);
247 void RotatePointAroundVector(vec3_t dst, const vec3_t dir, const vec3_t point, float degrees);
248 
249 float frand(void);              /* 0 to 1 */
250 float crand(void);              /* -1 to 1 */
251 void gaussrand(float* gauss1, float* gauss2);   /* -inf to +inf, median 0, stdev 1 */
252 
253 vec_t Q_rint(const vec_t in);
254 vec_t ColorNormalize(const vec3_t in, vec3_t out);
255 
256 void TangentVectors(const vec3_t normal, const vec3_t sdir, const vec3_t tdir, vec4_t tangent, vec3_t binormal);
257 
258 void Orthogonalize(vec3_t v1, const vec3_t v2);
259 void MatrixTranspose(const vec3_t m[3], vec3_t t[3]);
260 
261 bool RayIntersectAABB(const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs);
262