1 /*
2 WORLD.C
3 
4 	Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
5 	and the "Aleph One" developers.
6 
7 	This program is free software; you can redistribute it and/or modify
8 	it under the terms of the GNU General Public License as published by
9 	the Free Software Foundation; either version 3 of the License, or
10 	(at your option) any later version.
11 
12 	This program is distributed in the hope that it will be useful,
13 	but WITHOUT ANY WARRANTY; without even the implied warranty of
14 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 	GNU General Public License for more details.
16 
17 	This license is contained in the file "COPYING",
18 	which is included with this source code; it is available online at
19 	http://www.gnu.org/licenses/gpl.html
20 
21 Sunday, May 31, 1992 3:57:12 PM
22 
23 Friday, January 15, 1993 9:59:14 AM
24 	added arctangent function.
25 Thursday, January 21, 1993 9:46:24 PM
26 	fixed arctangent function.  normalize_angle() could stand to be improved.
27 Saturday, January 23, 1993 9:46:34 PM
28 	fixed arctangent, hopefully for the last time.  normalize_angle() is a little faster.
29 Monday, January 25, 1993 3:01:47 PM
30 	arctangent works (tested at 0.5� increments against SANE�s tan), the only anomoly was
31 	apparently arctan(0)==180�.
32 Wednesday, January 27, 1993 3:49:04 PM
33 	final fix to arctangent, we swear.  recall lim(arctan(x)) as x approaches �/2 or 3�/4 is ��,
34 	depending on which side we come from.  because we didn't realize this, arctan failed in the
35 	case where x was very close to but slightly below �/2.  i think we�ve seen the last monster
36 	suddenly �panic� and bolt directly into a wall.
37 Sunday, July 25, 1993 11:51:42 PM
38 	the arctan of 0/0 is now (arbitrairly) �/2 because we�re sick of assert(y) failing.
39 Monday, June 20, 1994 4:15:06 PM
40 	bug fix in translate_point3d().
41 
42 Feb 10, 2000 (Loren Petrich):
43 	Fixed range check in translate_point3d()
44 
45 Feb 14, 2000 (Loren Petrich):
46 	Doing some arithmetic as long values instead of short ones, so as to avoid annoying long-distance wraparound.
47 
48 Feb 17, 2000 (Loren Petrich):
49 	Fixed arctangent() so that it gets the values into the right octants, and then does a binary search
50 
51 Jul 1, 2000 (Loren Petrich):
52 	Inlined the angle normalization; doing it automatically for all the functions that work with angles
53 */
54 
55 #include "cseries.h"
56 #include "world.h"
57 #include "FilmProfile.h"
58 
59 #include <stdlib.h>
60 #include <math.h>
61 #include <limits.h>
62 
63 
64 
65 
66 /* ---------- globals */
67 
68 int16 *cosine_table;
69 int16 *sine_table;
70 static int32 *tangent_table;
71 
72 static uint16 random_seed= 0x1;
73 static uint16 local_random_seed= 0x1;
74 
75 /* ---------- code */
76 
77 /*
78 angle normalize_angle(
79 	angle theta)
80 {
81 	while (theta<0) theta+= NUMBER_OF_ANGLES;
82 	while (theta>=NUMBER_OF_ANGLES) theta-= NUMBER_OF_ANGLES;
83 
84 	return theta;
85 }
86 */
87 
88 /* remember this is not wholly accurate, both distance or the sine/cosine values could be
89 	negative, and the shift can�t make negative numbers zero; this is probably ok because
90 	we�ll have -1/1024th instead of zero, which is basically our margin for error anyway ... */
translate_point2d(world_point2d * point,world_distance distance,angle theta)91 world_point2d *translate_point2d(
92 	world_point2d *point,
93 	world_distance distance,
94 	angle theta)
95 {
96 	// LP change: idiot-proofed this
97 	theta = normalize_angle(theta);
98 	fc_assert(cosine_table[0]==TRIG_MAGNITUDE);
99 
100 	point->x+= (distance*cosine_table[theta])>>TRIG_SHIFT;
101 	point->y+= (distance*sine_table[theta])>>TRIG_SHIFT;
102 
103 	return point;
104 }
105 
106 /* same comment as above */
translate_point3d(world_point3d * point,world_distance distance,angle theta,angle phi)107 world_point3d *translate_point3d(
108 	world_point3d *point,
109 	world_distance distance,
110 	angle theta,
111 	angle phi)
112 {
113 	world_distance transformed_distance;
114 
115 	// LP change: idiot-proofed this
116 	theta = normalize_angle(theta);
117 	phi = normalize_angle(phi);
118 
119 	transformed_distance= (distance*cosine_table[phi])>>TRIG_SHIFT;
120 	point->x+= (transformed_distance*cosine_table[theta])>>TRIG_SHIFT;
121 	point->y+= (transformed_distance*sine_table[theta])>>TRIG_SHIFT;
122 	point->z+= (distance*sine_table[phi])>>TRIG_SHIFT;
123 
124 	return point;
125 }
126 
rotate_point2d(world_point2d * point,world_point2d * origin,angle theta)127 world_point2d *rotate_point2d(
128 	world_point2d *point,
129 	world_point2d *origin,
130 	angle theta)
131 {
132 	// LP change: lengthening the values for more precise calculations
133 	long_vector2d temp;
134 
135 	theta = normalize_angle(theta);
136 	fc_assert(cosine_table[0]==TRIG_MAGNITUDE);
137 
138 	temp.i= int32(point->x)-int32(origin->x);
139 	temp.j= int32(point->y)-int32(origin->y);
140 
141 	point->x= ((temp.i*cosine_table[theta])>>TRIG_SHIFT) + ((temp.j*sine_table[theta])>>TRIG_SHIFT) +
142 		origin->x;
143 	point->y= ((temp.j*cosine_table[theta])>>TRIG_SHIFT) - ((temp.i*sine_table[theta])>>TRIG_SHIFT) +
144 		origin->y;
145 
146 	return point;
147 }
148 
transform_point2d(world_point2d * point,world_point2d * origin,angle theta)149 world_point2d *transform_point2d(
150 	world_point2d *point,
151 	world_point2d *origin,
152 	angle theta)
153 {
154 	// LP change: lengthening the values for more precise calculations
155 	long_vector2d temp;
156 
157 	theta = normalize_angle(theta);
158 	fc_assert(cosine_table[0]==TRIG_MAGNITUDE);
159 
160 	temp.i= int32(point->x)-int32(origin->x);
161 	temp.j= int32(point->y)-int32(origin->y);
162 
163 	point->x= ((temp.i*cosine_table[theta])>>TRIG_SHIFT) + ((temp.j*sine_table[theta])>>TRIG_SHIFT);
164 	point->y= ((temp.j*cosine_table[theta])>>TRIG_SHIFT) - ((temp.i*sine_table[theta])>>TRIG_SHIFT);
165 
166 	return point;
167 }
168 
transform_point3d(world_point3d * point,world_point3d * origin,angle theta,angle phi)169 world_point3d *transform_point3d(
170 	world_point3d *point,
171 	world_point3d *origin,
172 	angle theta,
173 	angle phi)
174 {
175 	// LP change: lengthening the values for more precise calculations
176 	long_vector3d temporary;
177 
178 	temporary.i= int32(point->x)-int32(origin->x);
179 	temporary.j= int32(point->y)-int32(origin->y);
180 	temporary.k= int32(point->z)-int32(origin->z);
181 
182 	/* do theta rotation (in x-y plane) */
183 	point->x= ((temporary.i*cosine_table[theta])>>TRIG_SHIFT) + ((temporary.j*sine_table[theta])>>TRIG_SHIFT);
184 	point->y= ((temporary.j*cosine_table[theta])>>TRIG_SHIFT) - ((temporary.i*sine_table[theta])>>TRIG_SHIFT);
185 
186 	/* do phi rotation (in x-z plane) */
187 	if (phi)
188 	{
189 		temporary.i= point->x;
190 		/* temporary.z is already set */
191 
192 		point->x= ((temporary.i*cosine_table[phi])>>TRIG_SHIFT) + ((temporary.k*sine_table[phi])>>TRIG_SHIFT);
193 		point->z= ((temporary.k*cosine_table[phi])>>TRIG_SHIFT) - ((temporary.i*sine_table[phi])>>TRIG_SHIFT);
194 		/* y-coordinate is unchanged */
195 	}
196 	else
197 	{
198 		point->z= temporary.k;
199 	}
200 
201 	return point;
202 }
203 
build_trig_tables(void)204 void build_trig_tables(
205 	void)
206 {
207 	short i;
208 	double two_pi= 8.0*atan(1.0);
209 	double theta;
210 
211 	sine_table= (int16 *) malloc(sizeof(int16)*NUMBER_OF_ANGLES);
212 	cosine_table= (int16 *) malloc(sizeof(int16)*NUMBER_OF_ANGLES);
213 	tangent_table= (int32 *) malloc(sizeof(int32)*NUMBER_OF_ANGLES);
214 	fc_assert(sine_table&&cosine_table&&tangent_table);
215 
216 	for (i=0;i<NUMBER_OF_ANGLES;++i)
217 	{
218 		theta= two_pi*(double)i/(double)NUMBER_OF_ANGLES;
219 
220 		cosine_table[i]= (short) ((double)TRIG_MAGNITUDE*cos(theta)+0.5);
221 		sine_table[i]= (short) ((double)TRIG_MAGNITUDE*sin(theta)+0.5);
222 
223 		if (i==0) sine_table[i]= 0, cosine_table[i]= TRIG_MAGNITUDE;
224 		if (i==QUARTER_CIRCLE) sine_table[i]= TRIG_MAGNITUDE, cosine_table[i]= 0;
225 		if (i==HALF_CIRCLE) sine_table[i]= 0, cosine_table[i]= -TRIG_MAGNITUDE;
226 		if (i==THREE_QUARTER_CIRCLE) sine_table[i]= -TRIG_MAGNITUDE, cosine_table[i]= 0;
227 
228 		/* what we care about here is NOT accuracy, rather we�re concerned with matching the
229 			ratio of the existing sine and cosine tables as exactly as possible */
230 		if (cosine_table[i])
231 		{
232 			tangent_table[i]= ((TRIG_MAGNITUDE*sine_table[i])/cosine_table[i]);
233 		}
234 		else
235 		{
236 			/* we always take -�, even though the limit is ��, depending on which side you
237 				approach it from.  this is because of the direction we traverse the circle
238 				looking for matches during arctan. */
239 			tangent_table[i]= INT32_MIN;
240 		}
241 	}
242 }
243 
m2_arctangent(int32 xx,int32 yy)244 static angle m2_arctangent(
245 	int32 xx,
246 	int32 yy)
247 {
248 	// the original Marathon 2 function took world_distance parameters
249 	world_distance x = xx;
250 	world_distance y = yy;
251 
252 	long tangent;
253 	long last_difference, new_difference;
254 	angle search_arc, theta;
255 
256 	if (x)
257 	{
258 		tangent= (TRIG_MAGNITUDE*y)/x;
259 
260 		if (tangent)
261 		{
262 			theta= (y>0) ? 1 : HALF_CIRCLE+1;
263 			if (tangent<0) theta+= QUARTER_CIRCLE;
264 
265 			last_difference= tangent-tangent_table[theta-1];
266 			for (search_arc=QUARTER_CIRCLE-1;search_arc;search_arc--,theta++)
267 			{
268 				new_difference= tangent-tangent_table[theta];
269 
270 				if ((last_difference<=0&&new_difference>=0) || (last_difference>=0&&new_difference<=0))
271 				{
272 					if (ABS(last_difference)<ABS(new_difference))
273 					{
274 						return theta-1;
275 					}
276 					else
277 					{
278 						return theta;
279 					}
280 				}
281 
282 				last_difference= new_difference;
283 			}
284 
285 			return theta==NUMBER_OF_ANGLES ? 0 : theta;
286 		}
287 		else
288 		{
289 			return x<0 ? HALF_CIRCLE : 0;
290 		}
291 	}
292 	else
293 	{
294 		/* so arctan(0,0)==�/2 (bill me) */
295 		return y<0 ? THREE_QUARTER_CIRCLE : QUARTER_CIRCLE;
296 	}
297 }
298 /* one day we�ll come back here and actually make this run fast */
299 // LP change: made this long-distance friendly
300 //
a1_arctangent(int32 x,int32 y)301 static angle a1_arctangent(
302 	int32 x, // world_distance x,
303 	int32 y) // world_distance y)
304 {
305 	int32 tangent;
306 	angle theta;
307 
308 	// LP change: reworked everything in here
309 
310 	// Intermediate transformed values
311 	int32 xtfm = x, ytfm = y;
312 
313 	// Initial angle:
314 	theta = 0;
315 
316 	// Reduce 2nd/3rd quadrant to 1st/4th quadrant
317 	if (xtfm < 0)
318 	{
319 		xtfm = -xtfm;
320 		ytfm = -ytfm;
321 		theta += HALF_CIRCLE;
322 	}
323 
324 	// Reduce 4th quadrant to 1st quadrant
325 	if (ytfm < 0)
326 	{
327 		int32 temp = ytfm;
328 		ytfm = xtfm;
329 		xtfm = - temp;
330 		theta += THREE_QUARTER_CIRCLE;
331 	}
332 
333 	// The 1st quadrant has two octants; which one to choose?
334 	bool other_octant = false;
335 	if (ytfm > xtfm)
336 	{
337 		// Choosing the second octant instead of the first one..
338 		other_octant = true;
339 		int32 temp = ytfm;
340 		ytfm = xtfm;
341 		xtfm = temp;
342 	}
343 
344 	// Find the tangent; exit if both xtfm and ytfm are 0
345 	if (xtfm == 0) return 0;
346 	tangent= (TRIG_MAGNITUDE*ytfm)/xtfm;
347 
348 	// Find the search endpoints and test them:
349 	angle dtheta = 0, dth0 = 0, dth1 = EIGHTH_CIRCLE;
350 	int32 tan0 = tangent_table[dth0];
351 	int32 tan1 = tangent_table[dth1];
352 	if (tangent <= tan0) dtheta = dth0;
353 	else if (tangent >= tan1) dtheta = dth1;
354 	else
355 	{
356 		// Do binary search
357 		bool exact_hit = false;
358 		while(dth1 > dth0+1)
359 		{
360 			// Divide the interval in half
361 			angle dthnew = (dth0 + dth1) >> 1;
362 			// Where's the point?
363 			int32 tannew = tangent_table[dthnew];
364 			if (tangent > tannew)
365 			{
366 				dth0 = dthnew;
367 				tan0 = tannew;
368 			}
369 			else if (tangent < tannew)
370 			{
371 				dth1 = dthnew;
372 				tan1 = tannew;
373 			}
374 			else
375 			{
376 				dtheta = dthnew;
377 				exact_hit = true;
378 				break;
379 			}
380 		}
381 		// If didn't hit exactly, find the closest one
382 		if (!exact_hit)
383 		{
384 			if ((tan1 - tangent) < (tangent - tan0))
385 				dtheta = dth1;
386 			else
387 				dtheta = dth0;
388 		}
389 	}
390 
391 	// Adjust the octant and add in
392 	if (other_octant) dtheta = QUARTER_CIRCLE - dtheta;
393 	theta += dtheta;
394 
395 	// Idiot-proofed exit
396 	return NORMALIZE_ANGLE(theta);
397 }
398 
arctangent(int32 x,int32 y)399 angle arctangent(int32 x, int32 y)
400 {
401 	if (film_profile.long_distance_physics)
402 	{
403 		return a1_arctangent(x, y);
404 	}
405 	else
406 	{
407 		return m2_arctangent(x, y);
408 	}
409 }
410 
set_random_seed(uint16 seed)411 void set_random_seed(
412 	uint16 seed)
413 {
414 	random_seed= seed ? seed : DEFAULT_RANDOM_SEED;
415 }
416 
get_random_seed(void)417 uint16 get_random_seed(
418 	void)
419 {
420 	return random_seed;
421 }
422 
global_random(void)423 uint16 global_random(
424 	void)
425 {
426 	uint16 seed= random_seed;
427 
428 	if (seed&1)
429 	{
430 		seed= (seed>>1)^0xb400;
431 	}
432 	else
433 	{
434 		seed>>= 1;
435 	}
436 
437 	return (random_seed= seed);
438 }
439 
local_random(void)440 uint16 local_random(
441 	void)
442 {
443 	uint16 seed= local_random_seed;
444 
445 	if (seed&1)
446 	{
447 		seed= (seed>>1)^0xb400;
448 	}
449 	else
450 	{
451 		seed>>= 1;
452 	}
453 
454 	return (local_random_seed= seed);
455 }
456 
guess_distance2d(world_point2d * p0,world_point2d * p1)457 world_distance guess_distance2d(
458 	world_point2d *p0,
459 	world_point2d *p1)
460 {
461 	int32 dx= (int32)p0->x - p1->x;
462 	int32 dy= (int32)p0->y - p1->y;
463 	int32 distance;
464 
465 	if (dx<0) dx= -dx;
466 	if (dy<0) dy= -dy;
467 	distance= GUESS_HYPOTENUSE(dx, dy);
468 
469 	return distance>INT16_MAX ? INT16_MAX : distance;
470 }
471 
472 // Return min(round(distance), INT16_MAX)
distance3d(world_point3d * p0,world_point3d * p1)473 world_distance distance3d(
474 	world_point3d *p0,
475 	world_point3d *p1)
476 {
477 	int32 dx= (int32)p0->x - p1->x;
478 	int32 dy= (int32)p0->y - p1->y;
479 	int32 dz= (int32)p0->z - p1->z;
480 	const Sint64 dist_squared = 1LL*dx*dx + 1LL*dy*dy + 1LL*dz*dz; // [0, ~2^33.6]
481 	return dist_squared < 1L*INT16_MAX*INT16_MAX ? isqrt(dist_squared) : INT16_MAX;
482 }
483 
484 // Return round(distance) if distance < 65536, else nonsense value round(sqrt(distance^2 - 2^32)); output in [0, 65536]
m2_distance2d_int32(const world_point2d * p0,const world_point2d * p1)485 static int32 m2_distance2d_int32(
486 	const world_point2d* p0,
487 	const world_point2d* p1)
488 {
489 	const int32 dx = 1L*p1->x - p0->x; // [-65535, 65535]
490 	const int32 dy = 1L*p1->y - p0->y; // [-65535, 65535]
491 	const Sint64 dist_squared = 1LL*dx*dx + 1LL*dy*dy; // [0, ~2^33]
492 	return isqrt(uint32(dist_squared));
493 }
494 
m2_distance2d(world_point2d * p0,world_point2d * p1)495 static world_distance m2_distance2d(
496         world_point2d *p0,
497         world_point2d *p1)
498 {
499 	return int16(m2_distance2d_int32(p0, p1));
500 }
501 
a1_distance2d(world_point2d * p0,world_point2d * p1)502 static world_distance a1_distance2d(
503 	world_point2d *p0,
504 	world_point2d *p1)
505 {
506 	const int32 distance = m2_distance2d_int32(p0, p1);
507 	return distance>INT16_MAX ? INT16_MAX : distance;
508 }
509 
distance2d(world_point2d * p0,world_point2d * p1)510 world_distance distance2d(
511 	world_point2d *p0,
512 	world_point2d *p1)
513 {
514 	if (film_profile.long_distance_physics)
515 	{
516 		return a1_distance2d(p0, p1);
517 	}
518 	else
519 	{
520 		return m2_distance2d(p0, p1);
521 	}
522 }
523 
524 /*
525  * It requires more space to describe this implementation of the manual
526  * square root algorithm than it did to code it.  The basic idea is that
527  * the square root is computed one bit at a time from the high end.  Because
528  * the original number is 32 bits (unsigned), the root cannot exceed 16 bits
529  * in length, so we start with the 0x8000 bit.
530  *
531  * Let "x" be the value whose root we desire, "t" be the square root
532  * that we desire, and "s" be a bitmask.  A simple way to compute
533  * the root is to set "s" to 0x8000, and loop doing the following:
534  *
535  *      t = 0;
536  *      s = 0x8000;
537  *      do {
538  *              if ((t + s) * (t + s) <= x)
539  *                      t += s;
540  *              s >>= 1;
541  *      while (s != 0);
542  *
543  * The primary disadvantage to this approach is the multiplication.  To
544  * eliminate this, we begin simplying.  First, we observe that
545  *
546  *      (t + s) * (t + s) == (t * t) + (2 * t * s) + (s * s)
547  *
548  * Therefore, if we redefine "x" to be the original argument minus the
549  * current value of (t * t), we can determine if we should add "s" to
550  * the root if
551  *
552  *      (2 * t * s) + (s * s) <= x
553  *
554  * If we define a new temporary "nr", we can express this as
555  *
556  *      t = 0;
557  *      s = 0x8000;
558  *      do {
559  *              nr = (2 * t * s) + (s * s);
560  *              if (nr <= x) {
561  *                      x -= nr;
562  *                      t += s;
563  *              }
564  *              s >>= 1;
565  *      while (s != 0);
566  *
567  * We can improve the performance of this by noting that "s" is always a
568  * power of two, so multiplication by "s" is just a shift.  Also, because
569  * "s" changes in a predictable manner (shifted right after each iteration)
570  * we can precompute (0x8000 * t) and (0x8000 * 0x8000) and then adjust
571  * them by shifting after each step.  First, we let "m" hold the value
572  * (s * s) and adjust it after each step by shifting right twice.  We
573  * also introduce "r" to hold (2 * t * s) and adjust it after each step
574  * by shifting right once.  When we update "t" we must also update "r",
575  * and we do so by noting that (2 * (old_t + s) * s) is the same as
576  * (2 * old_t * s) + (2 * s * s).  Noting that (s * s) is "m" and that
577  * (r + 2 * m) == ((r + m) + m) == (nr + m):
578  *
579  *      t = 0;
580  *      s = 0x8000;
581  *      m = 0x40000000;
582  *      r = 0;
583  *      do {
584  *              nr = r + m;
585  *              if (nr <= x) {
586  *                      x -= nr;
587  *                      t += s;
588  *                      r = nr + m;
589  *              }
590  *              s >>= 1;
591  *              r >>= 1;
592  *              m >>= 2;
593  *      } while (s != 0);
594  *
595  * Finally, we note that, if we were using fractional arithmetic, after
596  * 16 iterations "s" would be a binary 0.5, so the value of "r" when
597  * the loop terminates is (2 * t * 0.5) or "t".  Because the values in
598  * "t" and "r" are identical after the loop terminates, and because we
599  * do not otherwise use "t"  explicitly within the loop, we can omit it.
600  * When we do so, there is no need for "s" except to terminate the loop,
601  * but we observe that "m" will become zero at the same time as "s",
602  * so we can use it instead.
603  *
604  * The result we have at this point is the floor of the square root.  If
605  * we want to round to the nearest integer, we need to consider whether
606  * the remainder in "x" is greater than or equal to the difference
607  * between ((r + 0.5) * (r + 0.5)) and (r * r).  Noting that the former
608  * quantity is (r * r + r + 0.25), we want to check if the remainder is
609  * greater than or equal to (r + 0.25).  Because we are dealing with
610  * integers, we can't have equality, so we round up if "x" is strictly
611  * greater than "r":
612  *
613  *      if (x > r)
614  *              r++;
615  */
616 
isqrt(uint32 x)617 int32 isqrt(uint32 x)
618 {
619 	uint32 r, nr, m;
620 
621 	r= 0;
622 	m= 0x40000000;
623 
624 	do
625 	{
626 		nr= r + m;
627 		if (nr<=x)
628 		{
629 			x-= nr;
630 			r= nr + m;
631 		}
632 		r>>= 1;
633 		m>>= 2;
634 	}
635 	while (m!=0);
636 
637 	if (x>r) r+= 1;
638 	return r;
639 }
640 
641 // LP additions: stuff for handling long-distance views
642 
long_to_overflow_short_2d(long_vector2d & LVec,world_point2d & WVec,uint16 & flags)643 void long_to_overflow_short_2d(long_vector2d& LVec, world_point2d& WVec, uint16& flags)
644 {
645 	// Clear upper byte of flags
646 	flags &= 0x00ff;
647 
648 	// Extract upper digits and put them into place
649 	uint16 xupper = uint16(LVec.i >> 16) & 0x000f;
650 	uint16 yupper = uint16(LVec.j >> 16) & 0x000f;
651 
652 	// Put them into place
653 	flags |= xupper << 12;
654 	flags |= yupper << 8;
655 
656 	// Move lower values
657 	WVec.x = LVec.i;
658 	WVec.y = LVec.j;
659 }
660 
overflow_short_to_long_2d(world_point2d & WVec,uint16 & flags,long_vector2d & LVec)661 void overflow_short_to_long_2d(world_point2d& WVec, uint16& flags, long_vector2d& LVec)
662 {
663 	// Move lower values
664 	LVec.i = int32(WVec.x) & 0x0000ffff;
665 	LVec.j = int32(WVec.y) & 0x0000ffff;
666 
667 	// Extract upper digits
668 	uint16 xupper = (flags >> 12) & 0x000f;
669 	uint16 yupper = (flags >> 8) & 0x000f;
670 
671 	// Sign-extend them
672 	if (xupper & 0x0008) xupper |= 0xfff0;
673 	if (yupper & 0x0008) yupper |= 0xfff0;
674 
675 	// Put them into place
676 	LVec.i |= int32(xupper) << 16;
677 	LVec.j |= int32(yupper) << 16;
678 }
679 
680 
transform_overflow_point2d(world_point2d * point,world_point2d * origin,angle theta,uint16 * flags)681 world_point2d *transform_overflow_point2d(
682 	world_point2d *point,
683 	world_point2d *origin,
684 	angle theta,
685 	uint16 *flags)
686 {
687 	// LP change: lengthening the values for more precise calculations
688 	long_vector2d temp, tempr;
689 
690 	theta = normalize_angle(theta);
691 	fc_assert(cosine_table[0]==TRIG_MAGNITUDE);
692 
693 	temp.i= int32(point->x)-int32(origin->x);
694 	temp.j= int32(point->y)-int32(origin->y);
695 
696 	tempr.i= ((temp.i*cosine_table[theta])>>TRIG_SHIFT) + ((temp.j*sine_table[theta])>>TRIG_SHIFT);
697 	tempr.j= ((temp.j*cosine_table[theta])>>TRIG_SHIFT) - ((temp.i*sine_table[theta])>>TRIG_SHIFT);
698 
699 	long_to_overflow_short_2d(tempr,*point,*flags);
700 
701 	return point;
702 }
703