1 /*
2  * Copyright 2011-2013 Arx Libertatis Team (see the AUTHORS file)
3  *
4  * This file is part of Arx Libertatis.
5  *
6  * Arx Libertatis is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Arx Libertatis is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Arx Libertatis.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 /* Based on:
20 ===========================================================================
21 ARX FATALIS GPL Source Code
22 Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
23 
24 This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
25 
26 Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
27 License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
28 
29 Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
30 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31 
32 You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code.  If not, see
33 <http://www.gnu.org/licenses/>.
34 
35 In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
36 additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
37 Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
38 
39 If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
40 ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
41 ===========================================================================
42 */
43 // Code: Cyril Meynier
44 //
45 // Copyright (c) 1999 ARKANE Studios SA. All rights reserved
46 
47 #ifndef ARX_GRAPHICS_MATH_H
48 #define ARX_GRAPHICS_MATH_H
49 
50 #include <algorithm>
51 #include <cstdlib>
52 #include <cstring>
53 
54 #include <boost/numeric/conversion/cast.hpp>
55 #include <boost/static_assert.hpp>
56 
57 using std::min;
58 using std::max;
59 
60 #include "graphics/GraphicsTypes.h"
61 #include "graphics/data/Mesh.h"
62 
63 // RANDOM Sequences Funcs/Defs
rnd()64 inline float rnd() {
65 	return rand() * (1.0f / RAND_MAX);
66 }
67 
68 /*!
69  * Generate a random vertor with independently unform distributed components.
70  *
71  * @param min minimum value for all components (default: 0.f)
72  * @param max maximum value for all components (default: 1.f)
73  */
74 inline Vec3f randomVec(float min = 0.f, float max = 1.f) {
75 	float range = max - min;
76 	return Vec3f(rnd() * range + min, rnd() * range + min, rnd() * range + min);
77 }
78 
79 //Approximative Methods
80 #define EEcos(val)  (float)cos((float)val)
81 #define EEsin(val)  (float)sin((float)val)
82 #define EEfabs(val) (float)fabs(val)
83 
In3DBBoxTolerance(const Vec3f * pos,const EERIE_3D_BBOX * bbox,const float tolerance)84 inline bool In3DBBoxTolerance(const Vec3f * pos, const EERIE_3D_BBOX * bbox, const float tolerance) {
85 	return ((pos->x >= bbox->min.x - tolerance)
86 	        && (pos->x <= bbox->max.x + tolerance)
87 	        && (pos->y >= bbox->min.y - tolerance)
88 	        && (pos->y <= bbox->max.y + tolerance)
89 	        && (pos->z >= bbox->min.z - tolerance)
90 	        && (pos->z <= bbox->max.z + tolerance));
91 }
92 
93 //! Clamp a positive value to the range [0, 255]
clipByte255(int value)94 inline u8 clipByte255(int value) {
95 
96 	// clamp larger values to 255
97 	value |= (-(int)(value > 255));
98 	value &= 255;
99 
100 	return static_cast<u8>(value);
101 }
102 
103 //! Clamp a value to the range [0, 255]
clipByte(int value)104 inline u8 clipByte(int value) {
105 
106 	// clamp negative values to zero
107 	value &= -(int)!(value < 0);
108 
109 	return clipByte255(value);
110 }
111 
F2L_RoundUp(float val)112 inline long F2L_RoundUp(float val) {
113 	return static_cast<long>(ceil(val));
114 }
115 
116 bool CylinderInCylinder(const EERIE_CYLINDER * cyl1, const EERIE_CYLINDER * cyl2);
117 bool SphereInCylinder(const EERIE_CYLINDER * cyl1, const EERIE_SPHERE * s);
118 
119 template <class T, class O>
reinterpret(O v)120 inline T reinterpret(O v) {
121 	BOOST_STATIC_ASSERT(sizeof(T) == sizeof(O));
122 	T t;
123 	memcpy(&t, &v, sizeof(T));
124 	return t;
125 }
126 
ffsqrt(float f)127 inline float ffsqrt(float f) {
128 	return reinterpret<f32, u32>(((reinterpret<u32, f32>(f) - 0x3f800000) >> 1) + 0x3f800000);
129 }
130 
131 /*!
132  * Obtain the approximated inverse of the square root of a float.
133  * @brief  This code compute a fast 1 / sqrtf(v) approximation.
134  * @note   Originaly from Matthew Jones (Infogrames).
135  * @param  pValue  a float, the number we want the square root.
136  * @return The square root of \a fValue, as a float.
137  */
FastRSqrt(float value)138 inline float FastRSqrt(float value) {
139 
140 	s32 intval = reinterpret<s32, f32>(value);
141 
142 	const int MAGIC_NUMBER = 0x5f3759df;
143 
144 	float half = value * 0.5f;
145 	intval = MAGIC_NUMBER - (intval >> 1);
146 
147 	value = reinterpret<f32, s32>(intval);
148 
149 	return value * (1.5f - half * value * value);
150 }
151 
IsPowerOf2(unsigned int n)152 inline bool IsPowerOf2(unsigned int n) {
153 	return (n & (n - 1)) == 0;
154 }
155 
GetNextPowerOf2(unsigned int n)156 inline unsigned int GetNextPowerOf2(unsigned int n) {
157 
158 	--n;
159 	n |= n >> 1;
160 	n |= n >> 2;
161 	n |= n >> 4;
162 	n |= n >> 8;
163 	n |= n >> 16;
164 
165 	return ++n;
166 }
167 
168 // Rotations
169 
ZRotatePoint(Vec3f * in,Vec3f * out,float c,float s)170 inline void ZRotatePoint(Vec3f * in, Vec3f * out, float c, float s) {
171 	*out = Vec3f(in->x * c + in->y * s, in->y * c - in->x * s, in->z);
172 }
173 
YRotatePoint(Vec3f * in,Vec3f * out,float c,float s)174 inline void YRotatePoint(Vec3f * in, Vec3f * out, float c, float s) {
175 	*out = Vec3f(in->x * c + in->z * s, in->y, in->z * c - in->x * s);
176 }
177 
XRotatePoint(Vec3f * in,Vec3f * out,float c,float s)178 inline void XRotatePoint(Vec3f * in, Vec3f * out, float c, float s) {
179 	*out = Vec3f(in->x, in->y * c - in->z * s, in->y * s + in->z * c);
180 }
181 
182 //! Normalizes a Vector approximately. Returns its approcimate length before normalization.
fnormalize(Vec3f & v)183 inline float fnormalize(Vec3f & v) {
184 	float len = ffsqrt(v.lengthSqr());
185 	v *= 1 / len;
186 	return len;
187 }
188 
189 // Matrix functions
190 
191 void MatrixSetByVectors(EERIEMATRIX * m, const Vec3f * d, const Vec3f * u);
192 void MatrixReset(EERIEMATRIX * mat);
193 void MatrixMultiply(EERIEMATRIX * q, const EERIEMATRIX * a, const EERIEMATRIX * b);
194 void VectorMatrixMultiply(Vec3f * vDest, const Vec3f * vSrc, const EERIEMATRIX * mat);
195 void GenerateMatrixUsingVector(EERIEMATRIX * matrix, const Vec3f * vect, float rollDegrees);
196 
197 // Rotation Functions
198 
YXZRotatePoint(Vec3f * in,Vec3f * out,EERIE_CAMERA * cam)199 inline void YXZRotatePoint(Vec3f * in, Vec3f * out, EERIE_CAMERA * cam) {
200 	float tempy;
201 	out->z = (in->z * cam->Ycos) - (in->x * cam->Ysin);
202 	out->y = (in->x * cam->Ycos) + (in->z * cam->Ysin);
203 	tempy = (in->y * cam->Xcos) - (out->z * cam->Xsin);
204 	out->x = (out->y * cam->Zcos) + (tempy * cam->Zsin);
205 	out->y = (tempy * cam->Zcos) - (out->y * cam->Zsin);
206 	out->z = (in->y * cam->Xsin) + (out->z * cam->Xcos);
207 }
208 
209 // QUATERNION Funcs/Defs
210 
211 //! Copy a quaternion into another
Quat_Copy(EERIE_QUAT * dest,const EERIE_QUAT * src)212 inline void Quat_Copy(EERIE_QUAT * dest, const EERIE_QUAT * src) {
213 	dest->x = src->x;
214 	dest->y = src->y;
215 	dest->z = src->z;
216 	dest->w = src->w;
217 }
218 
219 //! Quaternion Initialization
220 //!  quat -> quaternion to init
221 inline void Quat_Init(EERIE_QUAT * quat, float x = 0, float y = 0, float z = 0, float w = 1) {
222 	quat->x = x;
223 	quat->y = y;
224 	quat->z = z;
225 	quat->w = w;
226 }
227 
228 // Transforms a Vertex by a matrix
TransformVertexMatrix(EERIEMATRIX * mat,Vec3f * vertexin,Vec3f * vertexout)229 inline void TransformVertexMatrix(EERIEMATRIX * mat, Vec3f * vertexin, Vec3f * vertexout) {
230 	vertexout->x = vertexin->x * mat->_11 + vertexin->y * mat->_21 + vertexin->z * mat->_31;
231 	vertexout->y = vertexin->x * mat->_12 + vertexin->y * mat->_22 + vertexin->z * mat->_32;
232 	vertexout->z = vertexin->x * mat->_13 + vertexin->y * mat->_23 + vertexin->z * mat->_33;
233 }
234 
235 // Transforms a Vertex by a quaternion
TransformVertexQuat(EERIE_QUAT * quat,Vec3f * vertexin,Vec3f * vertexout)236 inline void TransformVertexQuat(EERIE_QUAT * quat, Vec3f * vertexin, Vec3f * vertexout) {
237 
238 	float rx = vertexin->x * quat->w - vertexin->y * quat->z + vertexin->z * quat->y;
239 	float ry = vertexin->y * quat->w - vertexin->z * quat->x + vertexin->x * quat->z;
240 	float rz = vertexin->z * quat->w - vertexin->x * quat->y + vertexin->y * quat->x;
241 	float rw = vertexin->x * quat->x + vertexin->y * quat->y + vertexin->z * quat->z;
242 
243 	vertexout->x = quat->w * rx + quat->x * rw + quat->y * rz - quat->z * ry;
244 	vertexout->y = quat->w * ry + quat->y * rw + quat->z * rx - quat->x * rz;
245 	vertexout->z = quat->w * rz + quat->z * rw + quat->x * ry - quat->y * rx;
246 }
247 
248 void TransformInverseVertexQuat(const EERIE_QUAT * quat, const Vec3f * vertexin, Vec3f * vertexout);
249 void Quat_Divide(EERIE_QUAT * dest, const EERIE_QUAT * q1, const EERIE_QUAT * q2);
250 void Quat_Multiply(EERIE_QUAT * dest , const EERIE_QUAT * q1, const EERIE_QUAT * q2);
251 
252 void Quat_Slerp(EERIE_QUAT * result, const EERIE_QUAT * from, EERIE_QUAT * to, float t);
253 void Quat_Reverse(EERIE_QUAT * quat);
254 
255 // VECTORS Functions
256 
257 void Vector_RotateY(Vec3f * dest, const Vec3f * src, const float angle);
258 void Vector_RotateZ(Vec3f * dest, const Vec3f * src, const float angle);
259 void VRotateX(Vec3f * v1, const float angle);
260 void VRotateY(Vec3f * v1, const float angle);
261 void VRotateZ(Vec3f * v1, const float angle);
262 void QuatFromMatrix(EERIE_QUAT & quat, EERIEMATRIX & mat);
263 
264 void CalcFaceNormal(EERIEPOLY * ep, const TexturedVertex * v);
265 void CalcObjFaceNormal(const Vec3f * v0, const Vec3f * v1, const Vec3f * v2, EERIE_FACE * ef);
266 bool Triangles_Intersect(const EERIE_TRI * v, const EERIE_TRI * u);
267 void MatrixFromQuat(EERIEMATRIX * mat, const EERIE_QUAT * q);
268 
square(float x)269 inline float square(float x) {
270 	return x * x;
271 }
272 
273 /*!
274  * Compute (approximate) Distance between two 3D points
275  * may use an approximative way of computing sqrt !
276  */
fdist(const Vec3f & from,const Vec3f & to)277 inline float fdist(const Vec3f & from, const Vec3f & to) {
278 	return ffsqrt(distSqr(from, to));
279 }
280 
281 /*!
282  * Compute (approximate) Distance between two 2D points
283  * may use an approximative way of computing sqrt !
284  */
fdist(const Vec2f & from,const Vec2f & to)285 inline float fdist(const Vec2f & from, const Vec2f & to) {
286 	return ffsqrt(distSqr(from, to));
287 }
288 
PointInCylinder(const EERIE_CYLINDER * cyl,const Vec3f * pt)289 inline bool PointInCylinder(const EERIE_CYLINDER * cyl, const Vec3f * pt) {
290 
291 	float pos1 = cyl->origin.y + cyl->height;
292 
293 	if(pt->y < min(cyl->origin.y, pos1)) {
294 		return false;
295 	}
296 
297 	if(pt->y > max(cyl->origin.y, pos1)) {
298 		return false;
299 	}
300 
301 	if(!fartherThan(Vec2f(cyl->origin.x, cyl->origin.z), Vec2f(pt->x, pt->z), cyl->radius)) {
302 		return true;
303 	}
304 
305 	return false;
306 }
307 
PointInUnderCylinder(const EERIE_CYLINDER * cyl,const Vec3f * pt)308 inline long PointInUnderCylinder(const EERIE_CYLINDER * cyl, const Vec3f * pt) {
309 
310 	float pos1 = cyl->origin.y + cyl->height;
311 
312 	if(pt->y < min(cyl->origin.y, pos1)) {
313 		return 0;
314 	}
315 
316 	if(!fartherThan(Vec2f(cyl->origin.x, cyl->origin.z), Vec2f(pt->x, pt->z), cyl->radius)) {
317 		return (pt->y > max(cyl->origin.y, pos1)) ? 1 : 2;
318 	}
319 
320 	return 0;
321 }
322 
323 // ANGLES Functions
324 
325 void QuatFromAngles(EERIE_QUAT * q, const Anglef * angle);
326 
327 void specialEE_RT(TexturedVertex * in, Vec3f * out);
328 void specialEE_P(Vec3f * in, TexturedVertex * out);
329 
330 template <class T1, class T2, class T3>
clamp(T1 value,T2 min,T3 max)331 inline T1 clamp(T1 value, T2 min, T3 max) {
332 	return (value <= min) ? min : ((value >= max) ? max : value);
333 }
334 
335 #ifdef ARX_DEBUG
336 #define checked_range_cast boost::numeric_cast
337 #else
338 #define checked_range_cast static_cast
339 #endif
340 
341 #endif // ARX_GRAPHICS_MATH_H
342