1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: m_vectors.cpp 4661 2014-03-21 19:14:21Z dr_sean $
5 //
6 // Copyright (C) 1997-2000 by id Software Inc.
7 // Copyright (C) 1998-2006 by Randy Heit (ZDoom).
8 // Copyright (C) 2006-2014 by The Odamex Team.
9 //
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License
12 // as published by the Free Software Foundation; either version 2
13 // of the License, or (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // DESCRIPTION:
21 //	Vector math routines which I took from Quake2's source since they
22 //	make more sense than the way Doom does things. :-)
23 //
24 // [SL] 2012-02-18 - Reworked all of the functions to be more uniform with
25 // the ordering of parameters, based in part on m_vectors.cpp from Eternity
26 // Engine.  Also changed from using an array of floats as the underlying type
27 // to using a struct.
28 //-----------------------------------------------------------------------------
29 
30 
31 #include <stdio.h>
32 
33 #include "m_fixed.h"
34 #include "m_vectors.h"
35 #include "actor.h"
36 #include "tables.h"
37 
38 #include <cmath>
39 
40 #ifndef M_PI
41 #define M_PI 3.14159265358979323846		// matches value in gcc v2 math.h
42 #endif
43 
DEG2RAD(double a)44 static inline double DEG2RAD(double a)
45 {
46 	static const double factor = M_PI / 180.0;
47 	return a * factor;
48 }
49 
50 //
51 // M_SetVec3f
52 //
53 // Sets the components of dest to the values of the parameters x, y, z
54 //
M_SetVec3f(v3float_t * dest,float x,float y,float z)55 void M_SetVec3f(v3float_t *dest, float x, float y, float z)
56 {
57 	dest->x = x;
58 	dest->y = y;
59 	dest->z = z;
60 }
61 
M_SetVec3f(v3float_t * dest,fixed_t x,fixed_t y,fixed_t z)62 void M_SetVec3f(v3float_t *dest, fixed_t x, fixed_t y, fixed_t z)
63 {
64 	dest->x = FIXED2FLOAT(x);
65 	dest->y = FIXED2FLOAT(y);
66 	dest->z = FIXED2FLOAT(z);
67 }
68 
M_SetVec3(v3double_t * dest,double x,double y,double z)69 void M_SetVec3(v3double_t *dest, double x, double y, double z)
70 {
71 	dest->x = x;
72 	dest->y = y;
73 	dest->z = z;
74 }
75 
M_SetVec3(v3double_t * dest,fixed_t x,fixed_t y,fixed_t z)76 void M_SetVec3(v3double_t *dest, fixed_t x, fixed_t y, fixed_t z)
77 {
78 	dest->x = FIXED2DOUBLE(x);
79 	dest->y = FIXED2DOUBLE(y);
80 	dest->z = FIXED2DOUBLE(z);
81 }
82 
M_SetVec2Fixed(v2fixed_t * dest,double x,double y)83 void M_SetVec2Fixed(v2fixed_t *dest, double x, double y)
84 {
85 	dest->x = DOUBLE2FIXED(x);
86 	dest->y = DOUBLE2FIXED(y);
87 }
88 
M_SetVec2Fixed(v2fixed_t * dest,fixed_t x,fixed_t y)89 void M_SetVec2Fixed(v2fixed_t *dest, fixed_t x, fixed_t y)
90 {
91 	dest->x = x;
92 	dest->y = y;
93 }
94 
M_SetVec3Fixed(v3fixed_t * dest,double x,double y,double z)95 void M_SetVec3Fixed(v3fixed_t *dest, double x, double y, double z)
96 {
97 	dest->x = DOUBLE2FIXED(x);
98 	dest->y = DOUBLE2FIXED(y);
99 	dest->z = DOUBLE2FIXED(z);
100 }
101 
M_SetVec3Fixed(v3fixed_t * dest,fixed_t x,fixed_t y,fixed_t z)102 void M_SetVec3Fixed(v3fixed_t *dest, fixed_t x, fixed_t y, fixed_t z)
103 {
104 	dest->x = x;
105 	dest->y = y;
106 	dest->z = z;
107 }
108 
109 
110 //
111 // M_ConvertVec3FixedToVec3f
112 //
113 // Converts the component values of src to floats and stores
114 // in dest
115 //
M_ConvertVec3FixedToVec3f(v3float_t * dest,const v3fixed_t * src)116 void M_ConvertVec3FixedToVec3f(v3float_t *dest, const v3fixed_t *src)
117 {
118 	M_SetVec3f(dest, src->x, src->y, src->z);
119 }
120 
M_ConvertVec3FixedToVec3(v3double_t * dest,const v3fixed_t * src)121 void M_ConvertVec3FixedToVec3(v3double_t *dest, const v3fixed_t *src)
122 {
123 	M_SetVec3(dest, src->x, src->y, src->z);
124 }
125 
M_ConvertVec3fToVec3Fixed(v3fixed_t * dest,const v3float_t * src)126 void M_ConvertVec3fToVec3Fixed(v3fixed_t *dest, const v3float_t *src)
127 {
128 	M_SetVec3Fixed(dest, double(src->x), double(src->y), double(src->z));
129 }
130 
M_ConvertVec3ToVec3Fixed(v3fixed_t * dest,const v3double_t * src)131 void M_ConvertVec3ToVec3Fixed(v3fixed_t *dest, const v3double_t *src)
132 {
133 	M_SetVec3Fixed(dest, src->x, src->y, src->z);
134 }
135 
136 
137 //
138 // M_IsZeroVec3f
139 //
140 // Returns true if the v is the zero or null vector (all components are 0)
141 //
M_IsZeroVec3f(const v3float_t * v)142 bool M_IsZeroVec3f(const v3float_t *v)
143 {
144 	return fabs(v->x) == 0.0f && fabs(v->y) == 0.0f && fabs(v->z) == 0.0f;
145 }
146 
M_IsZeroVec3(const v3double_t * v)147 bool M_IsZeroVec3(const v3double_t *v)
148 {
149 	return fabs(v->x) == 0.0 && fabs(v->y) == 0.0 && fabs(v->z) == 0.0;
150 }
151 
M_IsZeroVec2Fixed(const v2fixed_t * v)152 bool M_IsZeroVec2Fixed(const v2fixed_t *v)
153 {
154 	return v->x == 0 && v->y == 0;
155 }
156 
M_IsZeroVec3Fixed(const v3fixed_t * v)157 bool M_IsZeroVec3Fixed(const v3fixed_t *v)
158 {
159 	return v->x == 0 && v->y == 0 && v->z == 0;
160 }
161 
162 
163 //
164 // M_ZeroVec3f
165 //
166 // Sets all components of v to 0
167 //
M_ZeroVec3f(v3float_t * v)168 void M_ZeroVec3f(v3float_t *v)
169 {
170 	v->x = v->y = v->z = 0.0f;
171 }
172 
M_ZeroVec3(v3double_t * v)173 void M_ZeroVec3(v3double_t *v)
174 {
175 	v->x = v->y = v->z = 0.0;
176 }
177 
M_ZeroVec2Fixed(v2fixed_t * v)178 void M_ZeroVec2Fixed(v2fixed_t *v)
179 {
180 	v->x = v->y = 0;
181 }
182 
M_ZeroVec3Fixed(v3fixed_t * v)183 void M_ZeroVec3Fixed(v3fixed_t *v)
184 {
185 	v->x = v->y = v->z = 0;
186 }
187 
188 
189 //
190 // M_AddVec3f
191 //
192 // Adds v2 to v1 stores in dest
193 //
M_AddVec3f(v3float_t * dest,const v3float_t * v1,const v3float_t * v2)194 void M_AddVec3f(v3float_t *dest, const v3float_t *v1, const v3float_t *v2)
195 {
196 	dest->x = v1->x + v2->x;
197 	dest->y = v1->y + v2->y;
198 	dest->z = v1->z + v2->z;
199 }
200 
201 
M_AddVec3(v3double_t * dest,const v3double_t * v1,const v3double_t * v2)202 void M_AddVec3(v3double_t *dest, const v3double_t *v1, const v3double_t *v2)
203 {
204 	dest->x = v1->x + v2->x;
205 	dest->y = v1->y + v2->y;
206 	dest->z = v1->z + v2->z;
207 }
208 
M_AddVec2Fixed(v2fixed_t * dest,const v2fixed_t * v1,const v2fixed_t * v2)209 void M_AddVec2Fixed(v2fixed_t *dest, const v2fixed_t *v1, const v2fixed_t *v2)
210 {
211 	dest->x = v1->x + v2->x;
212 	dest->y = v1->y + v2->y;
213 }
214 
M_AddVec3Fixed(v3fixed_t * dest,const v3fixed_t * v1,const v3fixed_t * v2)215 void M_AddVec3Fixed(v3fixed_t *dest, const v3fixed_t *v1, const v3fixed_t *v2)
216 {
217 	dest->x = v1->x + v2->x;
218 	dest->y = v1->y + v2->y;
219 	dest->z = v1->z + v2->z;
220 }
221 
222 
223 //
224 // M_SubVec3f
225 //
226 // Subtracts v2 from v1 stores in dest
227 //
M_SubVec3f(v3float_t * dest,const v3float_t * v1,const v3float_t * v2)228 void M_SubVec3f(v3float_t *dest, const v3float_t *v1, const v3float_t *v2)
229 {
230 	dest->x = v1->x - v2->x;
231 	dest->y = v1->y - v2->y;
232 	dest->z = v1->z - v2->z;
233 }
234 
M_SubVec3(v3double_t * dest,const v3double_t * v1,const v3double_t * v2)235 void M_SubVec3(v3double_t *dest, const v3double_t *v1, const v3double_t *v2)
236 {
237 	dest->x = v1->x - v2->x;
238 	dest->y = v1->y - v2->y;
239 	dest->z = v1->z - v2->z;
240 }
241 
M_SubVec2Fixed(v2fixed_t * dest,const v2fixed_t * v1,const v2fixed_t * v2)242 void M_SubVec2Fixed(v2fixed_t *dest, const v2fixed_t *v1, const v2fixed_t *v2)
243 {
244 	dest->x = v1->x - v2->x;
245 	dest->y = v1->y - v2->y;
246 }
247 
M_SubVec3Fixed(v3fixed_t * dest,const v3fixed_t * v1,const v3fixed_t * v2)248 void M_SubVec3Fixed(v3fixed_t *dest, const v3fixed_t *v1, const v3fixed_t *v2)
249 {
250 	dest->x = v1->x - v2->x;
251 	dest->y = v1->y - v2->y;
252 	dest->z = v1->z - v2->z;
253 }
254 
255 
256 //
257 // M_LengthVec3f
258 //
259 // Returns the length of a given vector (relative to the origin).  Taken from
260 // Quake 2, added by CG.
261 //
M_LengthVec3f(const v3float_t * v)262 float M_LengthVec3f(const v3float_t *v)
263 {
264 	return sqrtf(v->x * v->x + v->y * v->y + v->z * v->z);
265 }
266 
M_LengthVec3(const v3double_t * v)267 double M_LengthVec3(const v3double_t *v)
268 {
269 	return sqrt(v->x * v->x + v->y * v->y + v->z * v->z);
270 }
271 
M_LengthVec2Fixed(const v2fixed_t * v)272 fixed_t M_LengthVec2Fixed(const v2fixed_t *v)
273 {
274 	double fx = FIXED2DOUBLE(v->x);
275 	double fy = FIXED2DOUBLE(v->y);
276 
277 	return DOUBLE2FIXED(sqrt(fx * fx + fy * fy));
278 }
279 
M_LengthVec3Fixed(const v3fixed_t * v)280 fixed_t M_LengthVec3Fixed(const v3fixed_t *v)
281 {
282 	double fx = FIXED2DOUBLE(v->x);
283 	double fy = FIXED2DOUBLE(v->y);
284 	double fz = FIXED2DOUBLE(v->z);
285 
286 	return DOUBLE2FIXED(sqrt(fx * fx + fy * fy + fz * fz));
287 }
288 
289 
290 //
291 // M_ScaleVec3f
292 //
293 // Multiplies each element in the vector by scalar value a
294 // and stores in dest
295 //
M_ScaleVec3f(v3float_t * dest,const v3float_t * v,float a)296 void M_ScaleVec3f(v3float_t *dest, const v3float_t *v, float a)
297 {
298 	dest->x = v->x * a;
299 	dest->y = v->y * a;
300 	dest->z = v->z * a;
301 }
302 
M_ScaleVec3(v3double_t * dest,const v3double_t * v,double a)303 void M_ScaleVec3(v3double_t *dest, const v3double_t *v, double a)
304 {
305 	dest->x = v->x * a;
306 	dest->y = v->y * a;
307 	dest->z = v->z * a;
308 }
309 
M_ScaleVec2Fixed(v2fixed_t * dest,const v2fixed_t * v,fixed_t a)310 void M_ScaleVec2Fixed(v2fixed_t *dest, const v2fixed_t *v, fixed_t a)
311 {
312 	dest->x = FixedMul(v->x, a);
313 	dest->y = FixedMul(v->y, a);
314 }
315 
M_ScaleVec3Fixed(v3fixed_t * dest,const v3fixed_t * v,fixed_t a)316 void M_ScaleVec3Fixed(v3fixed_t *dest, const v3fixed_t *v, fixed_t a)
317 {
318 	dest->x = FixedMul(v->x, a);
319 	dest->y = FixedMul(v->y, a);
320 	dest->z = FixedMul(v->z, a);
321 }
322 
323 
324 //
325 // M_ScaleVec3fToLength
326 //
327 // Scales each element in the vector such that the vector length equals a
328 // and stores the resulting vector in dest.
329 //
M_ScaleVec3fToLength(v3float_t * dest,const v3float_t * v,float a)330 void M_ScaleVec3fToLength(v3float_t* dest, const v3float_t* v, float a)
331 {
332 	if (M_IsZeroVec3f(v))
333 		M_ZeroVec3f(dest);
334 	else
335 		M_ScaleVec3f(dest, v, a / M_LengthVec3f(v));
336 }
337 
M_ScaleVec3ToLength(v3double_t * dest,const v3double_t * v,double a)338 void M_ScaleVec3ToLength(v3double_t* dest, const v3double_t* v, double a)
339 {
340 	if (M_IsZeroVec3(v))
341 		M_ZeroVec3(dest);
342 	else
343 		M_ScaleVec3(dest, v, a / M_LengthVec3(v));
344 }
345 
M_ScaleVec2FixedToLength(v2fixed_t * dest,const v2fixed_t * v,fixed_t a)346 void M_ScaleVec2FixedToLength(v2fixed_t* dest, const v2fixed_t* v, fixed_t a)
347 {
348 	if (M_IsZeroVec2Fixed(v))
349 		M_ZeroVec2Fixed(dest);
350 	else
351 		M_ScaleVec2Fixed(dest, v, FixedDiv(a, M_LengthVec2Fixed(v)));
352 }
353 
M_ScaleVec3FixedToLength(v3fixed_t * dest,const v3fixed_t * v,fixed_t a)354 void M_ScaleVec3FixedToLength(v3fixed_t* dest, const v3fixed_t* v, fixed_t a)
355 {
356 	if (M_IsZeroVec3Fixed(v))
357 		M_ZeroVec3Fixed(dest);
358 	else
359 		M_ScaleVec3Fixed(dest, v, FixedDiv(a, M_LengthVec3Fixed(v)));
360 }
361 
362 
363 //
364 // M_DotVec3f
365 //
366 // Returns the dot product of v1 and v2
367 //
M_DotProductVec3f(const v3float_t * v1,const v3float_t * v2)368 float M_DotProductVec3f(const v3float_t *v1, const v3float_t *v2)
369 {
370 	return (v1->x * v2->x) + (v1->y * v2->y) + (v1->z * v2->z);
371 }
372 
M_DotProductVec3(const v3double_t * v1,const v3double_t * v2)373 double M_DotProductVec3(const v3double_t *v1, const v3double_t *v2)
374 {
375 	return (v1->x * v2->x) + (v1->y * v2->y) + (v1->z * v2->z);
376 }
377 
378 
379 //
380 // M_CrossProduct3f
381 //
382 // Gets the cross product of v1 and v2 and stores in dest
383 //
M_CrossProductVec3f(v3float_t * dest,const v3float_t * v1,const v3float_t * v2)384 void M_CrossProductVec3f(v3float_t *dest, const v3float_t *v1, const v3float_t *v2)
385 {
386 	dest->x = (v1->y * v2->z) - (v1->z * v2->y);
387 	dest->y = (v1->z * v2->x) - (v1->x * v2->z);
388 	dest->z = (v1->x * v2->y) - (v1->y * v2->x);
389 }
390 
M_CrossProductVec3(v3double_t * dest,const v3double_t * v1,const v3double_t * v2)391 void M_CrossProductVec3(v3double_t *dest, const v3double_t *v1, const v3double_t *v2)
392 {
393 	dest->x = (v1->y * v2->z) - (v1->z * v2->y);
394 	dest->y = (v1->z * v2->x) - (v1->x * v2->z);
395 	dest->z = (v1->x * v2->y) - (v1->y * v2->x);
396 }
397 
398 
399 //
400 // M_NormalizeVec3f
401 //
402 // Scales v so that its length is 1.0 and stores in dest
403 //
M_NormalizeVec3f(v3float_t * dest,const v3float_t * v)404 void M_NormalizeVec3f(v3float_t *dest, const v3float_t *v)
405 {
406 	M_ScaleVec3fToLength(dest, v, 1.0f);
407 }
408 
M_NormalizeVec3(v3double_t * dest,const v3double_t * v)409 void M_NormalizeVec3(v3double_t *dest, const v3double_t *v)
410 {
411 	M_ScaleVec3ToLength(dest, v, 1.0);
412 }
413 
M_NormalizeVec2Fixed(v2fixed_t * dest,const v2fixed_t * v)414 void M_NormalizeVec2Fixed(v2fixed_t *dest, const v2fixed_t *v)
415 {
416 	M_ScaleVec2FixedToLength(dest, v, 1*FRACUNIT);
417 }
418 
M_NormalizeVec3Fixed(v3fixed_t * dest,const v3fixed_t * v)419 void M_NormalizeVec3Fixed(v3fixed_t *dest, const v3fixed_t *v)
420 {
421 	M_ScaleVec3FixedToLength(dest, v, 1*FRACUNIT);
422 }
423 
424 
425 //
426 // M_ActorToVec3f
427 //
428 // Stores thing's position in the vector dest
429 //
M_ActorPositionToVec3f(v3float_t * dest,const AActor * thing)430 void M_ActorPositionToVec3f(v3float_t *dest, const AActor *thing)
431 {
432 	dest->x = FIXED2FLOAT(thing->x);
433 	dest->y = FIXED2FLOAT(thing->y);
434 	dest->z = FIXED2FLOAT(thing->z);
435 }
436 
M_ActorPositionToVec3(v3double_t * dest,const AActor * thing)437 void M_ActorPositionToVec3(v3double_t *dest, const AActor *thing)
438 {
439 	dest->x = FIXED2DOUBLE(thing->x);
440 	dest->y = FIXED2DOUBLE(thing->y);
441 	dest->z = FIXED2DOUBLE(thing->z);
442 }
443 
M_ActorPositionToVec2Fixed(v2fixed_t * dest,const AActor * thing)444 void M_ActorPositionToVec2Fixed(v2fixed_t *dest, const AActor *thing)
445 {
446 	dest->x = thing->x;
447 	dest->y = thing->y;
448 }
449 
M_ActorPositionToVec3Fixed(v3fixed_t * dest,const AActor * thing)450 void M_ActorPositionToVec3Fixed(v3fixed_t *dest, const AActor *thing)
451 {
452 	dest->x = thing->x;
453 	dest->y = thing->y;
454 	dest->z = thing->z;
455 }
456 
457 
458 //
459 // M_ActorMomentumToVec3f
460 //
461 // Stores thing's momentum in the vector dest
462 //
M_ActorMomentumToVec3f(v3float_t * dest,const AActor * thing)463 void M_ActorMomentumToVec3f(v3float_t *dest, const AActor *thing)
464 {
465 	dest->x = FIXED2FLOAT(thing->momx);
466 	dest->y = FIXED2FLOAT(thing->momy);
467 	dest->z = FIXED2FLOAT(thing->momz);
468 }
469 
M_ActorMomentumToVec3(v3double_t * dest,const AActor * thing)470 void M_ActorMomentumToVec3(v3double_t *dest, const AActor *thing)
471 {
472 	dest->x = FIXED2DOUBLE(thing->momx);
473 	dest->y = FIXED2DOUBLE(thing->momy);
474 	dest->z = FIXED2DOUBLE(thing->momz);
475 }
476 
M_ActorMomentumToVec2Fixed(v2fixed_t * dest,const AActor * thing)477 void M_ActorMomentumToVec2Fixed(v2fixed_t *dest, const AActor *thing)
478 {
479 	dest->x = thing->momx;
480 	dest->y = thing->momy;
481 }
482 
M_ActorMomentumToVec3Fixed(v3fixed_t * dest,const AActor * thing)483 void M_ActorMomentumToVec3Fixed(v3fixed_t *dest, const AActor *thing)
484 {
485 	dest->x = thing->momx;
486 	dest->y = thing->momy;
487 	dest->z = thing->momz;
488 }
489 
490 
491 //
492 // M_AngleToVec3f
493 //
494 // Calculates the normalized direction vector from ang and pitch
495 //
M_AngleToVec3f(v3float_t * dest,angle_t ang,int pitch)496 void M_AngleToVec3f(v3float_t *dest, angle_t ang, int pitch)
497 {
498 	dest->x = FIXED2FLOAT(finecosine[ang >> ANGLETOFINESHIFT]);
499 	dest->y = FIXED2FLOAT(finesine[ang >> ANGLETOFINESHIFT]);
500 	dest->z = FIXED2FLOAT(finetangent[FINEANGLES/4 - (pitch >> ANGLETOFINESHIFT)]);
501 	M_NormalizeVec3f(dest, dest);
502 }
503 
M_AngleToVec3(v3double_t * dest,angle_t ang,int pitch)504 void M_AngleToVec3(v3double_t *dest, angle_t ang, int pitch)
505 {
506 	dest->x = FIXED2DOUBLE(finecosine[ang >> ANGLETOFINESHIFT]);
507 	dest->y = FIXED2DOUBLE(finesine[ang >> ANGLETOFINESHIFT]) ;
508 	dest->z = FIXED2DOUBLE(finetangent[FINEANGLES/4 - (pitch >> ANGLETOFINESHIFT)]);
509 	M_NormalizeVec3(dest, dest);
510 }
511 
512 
513 //
514 // M_ProjectPointOnPlane
515 //
516 //
517 //
M_ProjectPointOnPlane(v3double_t * dest,const v3double_t * p,const v3double_t * normal)518 void M_ProjectPointOnPlane(v3double_t *dest, const v3double_t *p, const v3double_t *normal)
519 {
520 	if (M_IsZeroVec3(normal))
521 	{
522 		// Assume that a normal of zero length is bad input and bail
523 		M_ZeroVec3(dest);
524 		return;
525 	}
526 
527 	double inv_denom = 1.0 / M_DotProductVec3(normal, normal);
528 	double d = M_DotProductVec3(normal, p) * inv_denom;
529 
530 	v3double_t n;
531 	M_ScaleVec3(&n, normal, inv_denom * d);
532 	M_SubVec3(dest, p, &n);
533 }
534 
535 //
536 // M_PerpendicularVec3
537 //
538 // Assumes that src is a normalized vector
539 //
M_PerpendicularVec3(v3double_t * dest,const v3double_t * src)540 void M_PerpendicularVec3(v3double_t *dest, const v3double_t *src)
541 {
542 	// find the smallest component of the vector src
543 	v3double_t tempvec;
544 	double minelem = src->x;
545 	double *mincomponent = &(tempvec.x);
546 	if (abs(src->y) < minelem)
547 	{
548 		minelem = abs(src->y);
549 		mincomponent = &(tempvec.y);
550 	}
551 	if (abs(src->z) < minelem)
552 	{
553 		minelem = abs(src->z);
554 		mincomponent = &(tempvec.z);
555 	}
556 
557 	// make tempvec the identity vector along the axis of the smallest component
558 	M_ZeroVec3(&tempvec);
559 	*mincomponent = 1.0;
560 
561 	M_ProjectPointOnPlane(dest, &tempvec, src);
562 	M_NormalizeVec3(dest, dest);
563 }
564 
565 
M_ConcatRotations(double out[3][3],const double in1[3][3],const double in2[3][3])566 static void M_ConcatRotations(double out[3][3], const double in1[3][3], const double in2[3][3])
567 {
568 	out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
569 				in1[0][2] * in2[2][0];
570 	out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
571 				in1[0][2] * in2[2][1];
572 	out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
573 				in1[0][2] * in2[2][2];
574 	out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
575 				in1[1][2] * in2[2][0];
576 	out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
577 				in1[1][2] * in2[2][1];
578 	out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
579 				in1[1][2] * in2[2][2];
580 	out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
581 				in1[2][2] * in2[2][0];
582 	out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
583 				in1[2][2] * in2[2][1];
584 	out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
585 				in1[2][2] * in2[2][2];
586 }
587 
588 #ifdef _MSC_VER
589 #pragma optimize( "", off )
590 #endif
591 
M_RotatePointAroundVector(v3double_t * dest,const v3double_t * dir,const v3double_t * point,float degrees)592 void M_RotatePointAroundVector(v3double_t *dest, const v3double_t *dir, const v3double_t *point, float degrees)
593 {
594 
595 	double	m[3][3], im[3][3], zrot[3][3], tmpmat[3][3], rot[3][3];
596 	v3double_t vr, vup, vf;
597 
598 	vf.x = dir->x;
599 	vf.y = dir->y;
600 	vf.z = dir->z;
601 
602 	M_PerpendicularVec3(&vr, dir);
603 	M_CrossProductVec3(&vup, &vr, &vf);
604 
605 	m[0][0] = vr.x;
606 	m[1][0] = vr.y;
607 	m[2][0] = vr.z;
608 
609 	m[0][1] = vup.x;
610 	m[1][1] = vup.y;
611 	m[2][1] = vup.z;
612 
613 	m[0][2] = vf.x;
614 	m[1][2] = vf.y;
615 	m[2][2] = vf.z;
616 
617 	memcpy( im, m, sizeof( im ) );
618 
619 	im[0][1] = m[1][0];
620 	im[0][2] = m[2][0];
621 	im[1][0] = m[0][1];
622 	im[1][2] = m[2][1];
623 	im[2][0] = m[0][2];
624 	im[2][1] = m[1][2];
625 
626 	memset( zrot, 0, sizeof( zrot ) );
627 	zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0;
628 
629 	zrot[0][0] = (float)cos(DEG2RAD(degrees));
630 	zrot[0][1] = (float)sin(DEG2RAD(degrees));
631 	zrot[1][0] = (float)-sin(DEG2RAD(degrees));
632 	zrot[1][1] = (float)cos(DEG2RAD(degrees));
633 
634 	M_ConcatRotations(tmpmat, m, zrot);
635 	M_ConcatRotations(rot, tmpmat, im);
636 
637 	dest->x = rot[0][0] * point->x + rot[0][1] * point->y + rot[0][2] * point->z;
638 	dest->y = rot[1][0] * point->x + rot[1][1] * point->y + rot[1][2] * point->z;
639 	dest->z = rot[2][0] * point->x + rot[2][1] * point->y + rot[2][2] * point->z;
640 }
641 
642 #ifdef _MSC_VER
643 #pragma optimize( "", on )
644 #endif
645 
646 //
647 // M_TranslateVec3f
648 //
649 // Translates the given vector (in doom's coordinate system) to the camera
650 // space (in right-handed coordinate system) This function is used for slopes.
651 //
M_TranslateVec3f(v3float_t * vec,const v3float_t * origin,angle_t ang)652 void M_TranslateVec3f(v3float_t *vec, const v3float_t *origin, angle_t ang)
653 {
654 	float tx, ty, tz;
655 
656 	float viewcosf = FIXED2FLOAT(finecosine[ang >> ANGLETOFINESHIFT]);
657 	float viewsinf = FIXED2FLOAT(finesine[ang >> ANGLETOFINESHIFT]);
658 
659 	tx = vec->x - origin->x;
660 	ty = origin->z - vec->y;
661 	tz = vec->z - origin->y;
662 
663 	vec->x = (tx * viewcosf) - (tz * viewsinf);
664 	vec->z = (tz * viewcosf) + (tx * viewsinf);
665 	vec->y = ty;
666 }
667 
M_TranslateVec3(v3double_t * vec,const v3double_t * origin,angle_t ang)668 void M_TranslateVec3 (v3double_t *vec, const v3double_t *origin, angle_t ang)
669 {
670 	double tx, ty, tz;
671 
672 	double viewcosf = FIXED2DOUBLE(finecosine[ang >> ANGLETOFINESHIFT]);
673 	double viewsinf = FIXED2DOUBLE(finesine[ang >> ANGLETOFINESHIFT]);
674 
675 	tx = vec->x - origin->x;
676 	ty = origin->z - vec->y;
677 	tz = vec->z - origin->y;
678 
679 	vec->x = (tx * viewcosf) - (tz * viewsinf);
680 	vec->z = (tz * viewcosf) + (tx * viewsinf);
681 	vec->y = ty;
682 }
683 
684 
685 VERSION_CONTROL (m_vectors_cpp, "$Id: m_vectors.cpp 4661 2014-03-21 19:14:21Z dr_sean $")
686 
687