mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-17 23:00:26 +02:00
Integrate coherent B3, P2/K17 prerequisites, completed K1-K16 + S, and the independent profile/effects rulings. Five gains and two explicitly approved B3 debits: net +3 strict functions, +2770 meaningful/+2800 padded bytes (+2774 progress credit). No additional losses; Halo objects 394 to 396 and data unchanged. Clean rebuild, identical 8252-row stable sweep, 68 valid parks, admission/provider checks, 467-unit warning comparison, unchanged fake scan, and 1318 tests passed. Preserve canonical helper recoveries and unrelated work. Full evidence and disclosures in docs/object_matching_logs/astra_five_function_reconciliation_20260928.md.
3202 lines
68 KiB
C
3202 lines
68 KiB
C
/*
|
|
REAL_MATH.C
|
|
*/
|
|
|
|
/* ---------- headers */
|
|
|
|
#include "cseries.h"
|
|
#include "real_math.h"
|
|
#include "periodic_functions.h"
|
|
|
|
/* ---------- constants */
|
|
|
|
/* ---------- macros */
|
|
|
|
/* ---------- structures */
|
|
|
|
/* ---------- prototypes */
|
|
|
|
static __inline real magnitude_squared3d_right_associated(
|
|
real_vector3d const *vector)
|
|
{
|
|
return
|
|
vector->i * vector->i +
|
|
(vector->j * vector->j + vector->k * vector->k);
|
|
}
|
|
|
|
/* ---------- globals */
|
|
|
|
static real_matrix4x3 const private_identity4x3 =
|
|
{
|
|
1.f,
|
|
{
|
|
{ 1.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f }
|
|
},
|
|
};
|
|
|
|
static real_matrix4x3 const private_negative_identity4x3 =
|
|
{
|
|
1.f,
|
|
{
|
|
{ -1.f, 0.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f, -1.f, 0.f, 0.f, 0.f }
|
|
},
|
|
};
|
|
|
|
static real_quaternion const private_identity_quaternion =
|
|
{
|
|
{ { 0.f, 0.f, 0.f } },
|
|
1.f,
|
|
};
|
|
|
|
static real_rectangle3d const private_null_rectangle =
|
|
{
|
|
{ REAL_MAX, REAL_MIN, REAL_MAX, REAL_MIN, REAL_MAX, REAL_MIN },
|
|
};
|
|
|
|
short const global_projection3d_mappings[3][2][2] =
|
|
{
|
|
{
|
|
{ 2, 1 },
|
|
{ 1, 2 },
|
|
},
|
|
{
|
|
{ 0, 2 },
|
|
{ 2, 0 },
|
|
},
|
|
{
|
|
{ 1, 0 },
|
|
{ 0, 1 },
|
|
}
|
|
};
|
|
|
|
const real_point2d *global_origin2d = (const real_point2d *)&private_identity4x3.up;
|
|
const real_point2d *global_x_axis2d = (const real_point2d *)&private_identity4x3.forward;
|
|
const real_point2d *global_y_axis2d = (const real_point2d *)&private_identity4x3.left;
|
|
const real_point2d *global_negative_x_axis2d = (const real_point2d *)&private_negative_identity4x3.forward;
|
|
const real_point2d *global_negative_y_axis2d = (const real_point2d *)&private_negative_identity4x3.left;
|
|
|
|
const real_vector2d *global_zero_vector2d = (const real_vector2d *)&private_identity4x3.up;
|
|
const real_vector2d *global_forward2d = (const real_vector2d *)&private_identity4x3.forward;
|
|
const real_vector2d *global_left2d = (const real_vector2d *)&private_identity4x3.left;
|
|
const real_vector2d *global_backward2d = (const real_vector2d *)&private_negative_identity4x3.forward;
|
|
const real_vector2d *global_right2d = (const real_vector2d *)&private_negative_identity4x3.left;
|
|
|
|
const real_point3d *global_origin3d = (const real_point3d *)&private_identity4x3.position;
|
|
|
|
const real_point3d *global_x_axis3d = (const real_point3d *)&private_identity4x3.forward;
|
|
const real_point3d *global_y_axis3d = (const real_point3d *)&private_identity4x3.left;
|
|
const real_point3d *global_z_axis3d = (const real_point3d *)&private_identity4x3.up;
|
|
const real_point3d *global_negative_x_axis3d = (const real_point3d *)&private_negative_identity4x3.forward;
|
|
const real_point3d *global_negative_y_axis3d = (const real_point3d *)&private_negative_identity4x3.left;
|
|
const real_point3d *global_negative_z_axis3d = (const real_point3d *)&private_negative_identity4x3.up;
|
|
|
|
const real_vector3d *global_zero_vector3d = (const real_vector3d *)&private_identity4x3.position;
|
|
|
|
const real_vector3d *global_forward3d = (const real_vector3d *)&private_identity4x3.forward;
|
|
const real_vector3d *global_left3d = (const real_vector3d *)&private_identity4x3.left;
|
|
const real_vector3d *global_up3d = (const real_vector3d *)&private_identity4x3.up;
|
|
|
|
const real_vector3d *global_backward3d = (const real_vector3d *)&private_negative_identity4x3.forward;
|
|
const real_vector3d *global_right3d = (const real_vector3d *)&private_negative_identity4x3.left;
|
|
const real_vector3d *global_down3d = (const real_vector3d *)&private_negative_identity4x3.up;
|
|
|
|
const real_euler_angles2d *global_zero_angles2d = (const real_euler_angles2d *)&private_identity4x3.up;
|
|
const real_euler_angles3d *global_zero_angles3d = (const real_euler_angles3d *)&private_identity4x3.up;
|
|
const real_quaternion *global_identity_quaternion = &private_identity_quaternion;
|
|
const real_matrix4x3 *global_identity4x3 = &private_identity4x3;
|
|
const real_matrix4x3 *global_negative_identity4x3 = &private_negative_identity4x3;
|
|
const real_rectangle2d *global_null_rectangle2d = (const real_rectangle2d *)&private_null_rectangle;
|
|
const real_rectangle3d *global_null_rectangle3d = &private_null_rectangle;
|
|
|
|
/* ---------- public code */
|
|
|
|
void real_math_initialize(
|
|
void)
|
|
{
|
|
random_math_initialize();
|
|
periodic_functions_initialize();
|
|
return;
|
|
}
|
|
|
|
void real_math_dispose(
|
|
void)
|
|
{
|
|
random_math_dispose();
|
|
periodic_functions_dispose();
|
|
return;
|
|
}
|
|
|
|
void real_math_reset_precision(
|
|
void)
|
|
{
|
|
_control87(CW_DEFAULT, 0xFFFFF);
|
|
return;
|
|
}
|
|
|
|
real_vector2d *perpendicular2d(
|
|
real_vector2d const *a,
|
|
real_vector2d *result)
|
|
{
|
|
result->i = -a->j;
|
|
result->j = a->i;
|
|
return result;
|
|
}
|
|
|
|
real_vector3d *perpendicular3d(
|
|
real_vector3d const *a,
|
|
real_vector3d *result)
|
|
{
|
|
real i = fabs(a->i);
|
|
real j = fabs(a->j);
|
|
real k = fabs(a->k);
|
|
|
|
if (i <= j && i <= k)
|
|
{
|
|
result->i = 0.f;
|
|
result->j = a->k;
|
|
result->k = -a->j;
|
|
}
|
|
else
|
|
{
|
|
if (j <= k)
|
|
{
|
|
result->i = -a->k;
|
|
result->j = 0.f;
|
|
result->k = a->i;
|
|
}
|
|
else
|
|
{
|
|
result->i = a->j;
|
|
result->j = -a->i;
|
|
result->k = 0.f;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
real_vector4d *perpendicular4d(
|
|
real_vector4d const *a,
|
|
real_vector4d *result)
|
|
{
|
|
result->i = a->k;
|
|
result->j = a->l;
|
|
result->k = -a->i;
|
|
result->l = -a->j;
|
|
return result;
|
|
}
|
|
|
|
real_vector3d *rotate_vector_about_axis(
|
|
real_vector3d *v,
|
|
real_vector3d const *n,
|
|
real sine,
|
|
real cosine)
|
|
{
|
|
real one_minus_cosine_times_v_dot_n = dot_product3d(n, v) * (1-cosine);
|
|
|
|
real v_cross_n_i = n->k*v->j - v->k*n->j;
|
|
real v_cross_n_j = n->i*v->k - v->i*n->k;
|
|
real v_cross_n_k = n->j*v->i - v->j*n->i;
|
|
|
|
v->i = cosine*v->i + one_minus_cosine_times_v_dot_n*n->i - sine*v_cross_n_i;
|
|
v->j = cosine*v->j + one_minus_cosine_times_v_dot_n*n->j - sine*v_cross_n_j;
|
|
v->k = cosine*v->k + one_minus_cosine_times_v_dot_n*n->k - sine*v_cross_n_k;
|
|
|
|
return v;
|
|
}
|
|
|
|
void vectors_interpolate(
|
|
real_vector3d const *a,
|
|
real_vector3d const *b,
|
|
real t,
|
|
real_vector3d *result)
|
|
{
|
|
real one_minus_t = 1-t;
|
|
result->i = one_minus_t*a->i + t*b->i;
|
|
result->j = one_minus_t*a->j + t*b->j;
|
|
result->k = one_minus_t*a->k + t*b->k;
|
|
return;
|
|
}
|
|
|
|
void points_interpolate(
|
|
real_point3d const *a,
|
|
real_point3d const *b,
|
|
real t,
|
|
real_point3d *result)
|
|
{
|
|
real one_minus_t = 1-t;
|
|
result->x = one_minus_t*a->x + t*b->x;
|
|
result->y = one_minus_t*a->y + t*b->y;
|
|
result->z = one_minus_t*a->z + t*b->z;
|
|
return;
|
|
}
|
|
|
|
void scalars_interpolate(
|
|
real a,
|
|
real b,
|
|
real t,
|
|
real *result)
|
|
{
|
|
*result = (1-t) * a+b * t;
|
|
return;
|
|
}
|
|
|
|
void scalars_interpolate_and_clamp_0_to_1(
|
|
real a,
|
|
real b,
|
|
real t,
|
|
real *result)
|
|
{
|
|
*result = PIN((1.f-t)*a + t*b, 0.f, 1.f);
|
|
return;
|
|
}
|
|
|
|
void component_vectors_from_normal3d(
|
|
real_vector3d const *vector,
|
|
real_vector3d const *normal,
|
|
real_vector3d *parallel,
|
|
real_vector3d *perpendicular)
|
|
{
|
|
real_vector3d storage;
|
|
real vn = dot_product3d(vector, normal);
|
|
|
|
if (parallel== NULL)
|
|
{
|
|
parallel = &storage;
|
|
}
|
|
|
|
scale_vector3d(normal, vn, parallel);
|
|
|
|
if (perpendicular!= NULL)
|
|
{
|
|
subtract_vectors3d(vector, parallel, perpendicular);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void component_vectors_from_direction3d(
|
|
real_vector3d const *vector,
|
|
real_vector3d const *direction,
|
|
real_vector3d *parallel,
|
|
real_vector3d *perpendicular)
|
|
{
|
|
real dd = dot_product3d(direction, direction);
|
|
if (dd != 0.f)
|
|
{
|
|
real vd_dd = dot_product3d(vector, direction) / dd;
|
|
scale_vector3d(direction, vd_dd, parallel);
|
|
subtract_vectors3d(vector, parallel, perpendicular);
|
|
}
|
|
else
|
|
{
|
|
set_real_vector3d(parallel, 0.f, 0.f, 0.f);
|
|
*perpendicular = *vector;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void quaternions_multiply(
|
|
real_quaternion const *q0,
|
|
real_quaternion const *q1,
|
|
real_quaternion *result)
|
|
{
|
|
real_quaternion temporary;
|
|
|
|
if (q0== result)
|
|
{
|
|
temporary = *q0;
|
|
q0= &temporary;
|
|
}
|
|
|
|
if (q1== result)
|
|
{
|
|
temporary = *q1;
|
|
q1= &temporary;
|
|
}
|
|
|
|
result->v.i =
|
|
+ q0->v.j*q1->v.k
|
|
+ q0->v.i*q1->w
|
|
+ q0->w *q1->v.i
|
|
- q0->v.k*q1->v.j
|
|
;
|
|
|
|
result->v.j =
|
|
+ q0->w *q1->v.j
|
|
+ q0->v.j*q1->w
|
|
+ q0->v.k*q1->v.i
|
|
- q0->v.i*q1->v.k
|
|
;
|
|
|
|
result->v.k =
|
|
+ q0->v.k*q1->w
|
|
+ q0->v.i*q1->v.j
|
|
+ q0->w *q1->v.k
|
|
- q0->v.j*q1->v.i
|
|
;
|
|
|
|
result->w =
|
|
+ q0->w *q1->w
|
|
- q0->v.i*q1->v.i
|
|
- q0->v.j*q1->v.j
|
|
- q0->v.k*q1->v.k
|
|
;
|
|
|
|
return;
|
|
}
|
|
|
|
void quaternions_interpolate(
|
|
real_quaternion const *q0,
|
|
real_quaternion const *q1,
|
|
real t,
|
|
real_quaternion *result)
|
|
{
|
|
real v = 1.f-t;
|
|
|
|
if (q0->v.i*q1->v.i + q0->v.j*q1->v.j + q0->v.k*q1->v.k + q0->w*q1->w < 0.f)
|
|
{
|
|
t = -t;
|
|
}
|
|
|
|
result->v.i = q0->v.i*v + q1->v.i*t;
|
|
result->v.j = q0->v.j*v + q1->v.j*t;
|
|
result->v.k = q0->v.k*v + q1->v.k*t;
|
|
result->w = q0->w*v + q1->w*t;
|
|
return;
|
|
}
|
|
|
|
void quaternion_transform_point(
|
|
real_quaternion const *q,
|
|
real_point3d const *p,
|
|
real_point3d *result)
|
|
{
|
|
|
|
real w_squared = q->w*q->w;
|
|
real two_w_squared_minus_one = 2.f * w_squared - 1.f;
|
|
real v_dot_p = (q->v.i*p->x + q->v.k*p->z + q->v.j*p->y);
|
|
|
|
real two_v_dot_p = v_dot_p+v_dot_p;
|
|
real two_w = q->w+q->w;
|
|
|
|
real v_cross_r_i = (q->v.k*p->x) - (p->z*q->v.i);
|
|
real v_cross_r_j = (q->v.i*p->y) - (q->v.j*p->x);
|
|
real v_cross_r_k = (q->v.j*p->z) - (q->v.k*p->y);
|
|
|
|
result->x = v_cross_r_k * two_w+two_v_dot_p*q->v.i + two_w_squared_minus_one*p->x;
|
|
result->y = two_v_dot_p*q->v.j + two_w_squared_minus_one*p->y + v_cross_r_i*two_w;
|
|
result->z = two_v_dot_p*q->v.k + two_w_squared_minus_one*p->z + v_cross_r_j*two_w;
|
|
return;
|
|
}
|
|
|
|
void vectors3d_from_euler_angles3d(
|
|
real_vector3d *forward,
|
|
real_vector3d *up,
|
|
real_euler_angles3d const *angles)
|
|
{
|
|
real_matrix4x3 matrix;
|
|
real_point3d dummy;
|
|
|
|
match_assert("c:\\halo\\SOURCE\\math\\real_math.c", 832, forward);
|
|
match_assert("c:\\halo\\SOURCE\\math\\real_math.c", 833, up);
|
|
match_assert("c:\\halo\\SOURCE\\math\\real_math.c", 834, angles);
|
|
|
|
matrix4x3_rotation_from_angles(&matrix, angles->yaw, angles->pitch, angles->roll);
|
|
matrix4x3_to_point_and_vectors(&matrix, &dummy, forward, up);
|
|
return;
|
|
}
|
|
|
|
boolean fast_vector_intersects_sphere(
|
|
real_point3d const *point,
|
|
real_vector3d const *vector,
|
|
real_point3d const *center,
|
|
real radius)
|
|
{
|
|
real_point3d p = {point->x-center->x, point->y-center->y, point->z - center->z};
|
|
real c = (p.x*p.x) + (p.y*p.y) + (p.z*p.z) - (radius*radius);
|
|
real_vector3d direction;
|
|
|
|
if (c < 0.f)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
real b;
|
|
|
|
direction = *vector;
|
|
b = direction.i*p.x + direction.j*p.y + direction.k*p.z;
|
|
|
|
if (b >= 0.f)
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
real a =
|
|
direction.i*direction.i +
|
|
direction.j*direction.j +
|
|
direction.k*direction.k;
|
|
real disc = b * b - a * c;
|
|
|
|
if (disc <= 0.f)
|
|
{
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
real neg_a_minus_b = -a - b;
|
|
|
|
if (neg_a_minus_b < 0.f)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return neg_a_minus_b * neg_a_minus_b < disc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
real fast_vector_intersection_with_sphere(
|
|
real_point3d const *point,
|
|
real_vector3d const *vector,
|
|
real_point3d const *center,
|
|
real radius)
|
|
{
|
|
real_point3d p =
|
|
{
|
|
point->x - center->x,
|
|
point->y - center->y,
|
|
point->z - center->z
|
|
};
|
|
real c = p.x * p.x + p.y * p.y + p.z * p.z - radius * radius;
|
|
real_vector3d direction;
|
|
real b;
|
|
real a;
|
|
real discriminant;
|
|
|
|
if (c < 0.0f)
|
|
return 0.0f;
|
|
|
|
direction = *vector;
|
|
b =
|
|
direction.i * p.x +
|
|
direction.j * p.y +
|
|
direction.k * p.z;
|
|
if (b >= 0.0f)
|
|
return REAL_MAX;
|
|
|
|
a =
|
|
direction.i * direction.i +
|
|
direction.j * direction.j +
|
|
direction.k * direction.k;
|
|
discriminant = b * b - a * c;
|
|
if (discriminant <= 0.0f)
|
|
return REAL_MAX;
|
|
|
|
return (-b - square_root(discriminant)) / a;
|
|
}
|
|
|
|
boolean point_in_rectangle2d(
|
|
real_point2d const *point,
|
|
real_rectangle2d const *bounds)
|
|
{
|
|
return point->x >= bounds->x0
|
|
&& point->x <= bounds->x1
|
|
&& point->y >= bounds->y0
|
|
&& point->y <= bounds->y1;
|
|
}
|
|
|
|
boolean point_in_rectangle3d(
|
|
real_point3d const *point,
|
|
real_rectangle3d const *bounds)
|
|
{
|
|
return point->x >= bounds->x0
|
|
&& point->x <= bounds->x1
|
|
&& point->y >= bounds->y0
|
|
&& point->y <= bounds->y1
|
|
&& point->z >= bounds->z0
|
|
&& point->z <= bounds->z1;
|
|
}
|
|
|
|
boolean circle_intersects_rectangle2d(
|
|
real_point2d const *center,
|
|
real radius,
|
|
real_rectangle2d const *bounds)
|
|
{
|
|
real dx;
|
|
real dy;
|
|
|
|
if (center->x <= bounds->x1)
|
|
{
|
|
if (center->x < bounds->x0)
|
|
{
|
|
dx = bounds->x0 - center->x;
|
|
}
|
|
else
|
|
{
|
|
dx = 0.f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dx = center->x - bounds->x1;
|
|
}
|
|
|
|
if (center->y <= bounds->y1)
|
|
{
|
|
if (center->y < bounds->y0)
|
|
{
|
|
dy = bounds->y0 - center->y;
|
|
}
|
|
else
|
|
{
|
|
dy = 0.f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dy = center->y - bounds->y1;
|
|
}
|
|
|
|
return dx * dx + dy * dy <= radius * radius;
|
|
}
|
|
|
|
boolean point_in_cone2d(
|
|
real_point2d const *point,
|
|
real_point2d const *center,
|
|
real_vector2d const *direction,
|
|
real length,
|
|
real cosine)
|
|
{
|
|
real_vector2d offset;
|
|
real projection;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
1375,
|
|
cosine>=0.0f);
|
|
|
|
vector_from_points2d(center, point, &offset);
|
|
projection = dot_product2d(&offset, direction);
|
|
|
|
return (boolean)(projection >= 0.f &&
|
|
projection <= length &&
|
|
projection * projection >= magnitude_squared2d(&offset) * cosine * cosine);
|
|
}
|
|
|
|
boolean point_in_cone3d(
|
|
real_point3d const *point,
|
|
real_point3d const *center,
|
|
real_vector3d const *direction,
|
|
real length,
|
|
real cosine)
|
|
{
|
|
real_vector3d offset;
|
|
real projection;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
1404,
|
|
cosine>=0.0f);
|
|
|
|
vector_from_points3d(center, point, &offset);
|
|
projection = dot_product3d(&offset, direction);
|
|
|
|
return (boolean)(projection >= 0.f &&
|
|
projection <= length &&
|
|
projection * projection >= magnitude_squared3d(&offset) * cosine * cosine);
|
|
}
|
|
|
|
boolean point_in_sector2d(
|
|
real_point2d const *point,
|
|
real_point2d const *center,
|
|
real_vector2d const *direction,
|
|
real radius,
|
|
real cosine)
|
|
{
|
|
real_vector2d offset;
|
|
real distance_squared;
|
|
real projection;
|
|
boolean result;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
1433,
|
|
cosine>=0.0f);
|
|
|
|
vector_from_points2d(center, point, &offset);
|
|
distance_squared = magnitude_squared2d(&offset);
|
|
if (distance_squared <= radius * radius)
|
|
{
|
|
projection = dot_product2d(&offset, direction);
|
|
if (projection >= 0.f &&
|
|
projection * projection >= distance_squared * cosine * cosine)
|
|
{
|
|
result = TRUE;
|
|
}
|
|
else
|
|
{
|
|
result = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = FALSE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean point_in_sector3d(
|
|
real_point3d const *point,
|
|
real_point3d const *center,
|
|
real_vector3d const *direction,
|
|
real radius,
|
|
real cosine)
|
|
{
|
|
real_vector3d offset;
|
|
real distance_squared;
|
|
real projection;
|
|
boolean result;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
1462,
|
|
cosine>=0.0f);
|
|
|
|
vector_from_points3d(center, point, &offset);
|
|
distance_squared = magnitude_squared3d(&offset);
|
|
if (distance_squared <= radius * radius)
|
|
{
|
|
projection = dot_product3d(&offset, direction);
|
|
if (projection >= 0.f &&
|
|
projection * projection >= distance_squared * cosine * cosine)
|
|
{
|
|
result = TRUE;
|
|
}
|
|
else
|
|
{
|
|
result = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = FALSE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean circle_intersects_cone2d(
|
|
real_point2d const *circle_center,
|
|
real circle_radius,
|
|
real_point2d const *cone_center,
|
|
real_vector2d const *cone_direction,
|
|
real cone_length,
|
|
real sine,
|
|
real cosine)
|
|
{
|
|
real_vector2d offset;
|
|
real distance_squared;
|
|
real projection;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
2167,
|
|
sine>0.0f && cosine>=0.0f);
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
2168,
|
|
valid_realcmp(sine * sine + cosine * cosine, 1.0f),
|
|
csprintf(
|
|
temporary,
|
|
"%s, %s: assert_valid_real_sine_cosine(%f, %f)",
|
|
"sine",
|
|
"cosine",
|
|
sine,
|
|
cosine));
|
|
|
|
vector_from_points2d(cone_center, circle_center, &offset);
|
|
projection = dot_product2d(&offset, cone_direction);
|
|
distance_squared = offset.j * offset.j;
|
|
distance_squared += offset.i * offset.i;
|
|
|
|
return (boolean)(
|
|
projection >= -circle_radius &&
|
|
projection <= circle_radius + cone_length &&
|
|
(circle_radius * sine * 2.0f + projection) * projection +
|
|
circle_radius * circle_radius >=
|
|
distance_squared * cosine * cosine);
|
|
}
|
|
|
|
boolean circle_intersects_sector2d(
|
|
real_point2d const *circle_center,
|
|
real circle_radius,
|
|
real_point2d const *sector_center,
|
|
real_vector2d const *sector_direction,
|
|
real sector_radius,
|
|
real sine,
|
|
real cosine)
|
|
{
|
|
real_vector2d offset;
|
|
real_point2d adjusted_center;
|
|
real projection;
|
|
real adjustment;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
2231,
|
|
sine>0.0f && cosine>=0.0f);
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
2232,
|
|
valid_realcmp(sine * sine + cosine * cosine, 1.0f),
|
|
csprintf(
|
|
temporary,
|
|
"%s, %s: assert_valid_real_sine_cosine(%f, %f)",
|
|
"sine",
|
|
"cosine",
|
|
sine,
|
|
cosine));
|
|
|
|
vector_from_points2d(sector_center, circle_center, &offset);
|
|
projection = dot_product2d(&offset, sector_direction);
|
|
if (projection >= -circle_radius &&
|
|
projection <= circle_radius + sector_radius)
|
|
{
|
|
adjustment = circle_radius / sine;
|
|
point_from_line2d(
|
|
sector_center,
|
|
sector_direction,
|
|
-adjustment,
|
|
&adjusted_center);
|
|
if (point_in_sector2d(
|
|
circle_center,
|
|
&adjusted_center,
|
|
sector_direction,
|
|
sector_radius + circle_radius + adjustment,
|
|
cosine))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
boolean sphere_intersects_cone3d(
|
|
real_point3d const *sphere_center,
|
|
real sphere_radius,
|
|
real_point3d const *cone_center,
|
|
real_vector3d const *cone_direction,
|
|
real cone_length,
|
|
real sine,
|
|
real cosine)
|
|
{
|
|
real_vector3d offset;
|
|
real distance_squared;
|
|
real projection;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
2199,
|
|
sine>0.0f && cosine>=0.0f);
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
2200,
|
|
valid_realcmp(sine * sine + cosine * cosine, 1.0f),
|
|
csprintf(
|
|
temporary,
|
|
"%s, %s: assert_valid_real_sine_cosine(%f, %f)",
|
|
"sine",
|
|
"cosine",
|
|
sine,
|
|
cosine));
|
|
|
|
vector_from_points3d(cone_center, sphere_center, &offset);
|
|
projection = offset.k * cone_direction->k;
|
|
projection += offset.j * cone_direction->j;
|
|
projection += offset.i * cone_direction->i;
|
|
distance_squared = offset.k * offset.k;
|
|
distance_squared += offset.j * offset.j;
|
|
distance_squared += offset.i * offset.i;
|
|
|
|
return (boolean)(
|
|
projection >= -sphere_radius &&
|
|
projection <= sphere_radius + cone_length &&
|
|
(sphere_radius * sine * 2.0f + projection) * projection +
|
|
sphere_radius * sphere_radius >=
|
|
distance_squared * cosine * cosine);
|
|
}
|
|
|
|
boolean sphere_intersects_sector3d(
|
|
real_point3d const *sphere_center,
|
|
real sphere_radius,
|
|
real_point3d const *sector_center,
|
|
real_vector3d const *sector_direction,
|
|
real sector_radius,
|
|
real sine,
|
|
real cosine)
|
|
{
|
|
real_vector3d offset;
|
|
real_point3d adjusted_center;
|
|
real projection;
|
|
real adjustment;
|
|
real negative_adjustment;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
2269,
|
|
sine>0.0f && cosine>=0.0f);
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
2270,
|
|
valid_realcmp(sine * sine + cosine * cosine, 1.0f),
|
|
csprintf(
|
|
temporary,
|
|
"%s, %s: assert_valid_real_sine_cosine(%f, %f)",
|
|
"sine",
|
|
"cosine",
|
|
sine,
|
|
cosine));
|
|
|
|
vector_from_points3d(sector_center, sphere_center, &offset);
|
|
projection =
|
|
offset.k * sector_direction->k +
|
|
offset.i * sector_direction->i;
|
|
projection += offset.j * sector_direction->j;
|
|
if (projection >= -sphere_radius &&
|
|
projection <= sphere_radius + sector_radius)
|
|
{
|
|
adjustment = sphere_radius / sine;
|
|
negative_adjustment = -adjustment;
|
|
adjusted_center.x =
|
|
sector_direction->i * negative_adjustment + sector_center->x;
|
|
adjusted_center.y =
|
|
sector_direction->j * negative_adjustment + sector_center->y;
|
|
if (point_in_sector3d(
|
|
sphere_center,
|
|
&adjusted_center,
|
|
sector_direction,
|
|
(adjusted_center.z =
|
|
sector_direction->k * negative_adjustment + sector_center->z,
|
|
sector_radius + sphere_radius + adjustment),
|
|
cosine))
|
|
{
|
|
return (boolean)TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
boolean point_in_triangle2d(
|
|
real_point2d const *point,
|
|
real_point2d const *triangle0,
|
|
real_point2d const *triangle1,
|
|
real_point2d const *triangle2,
|
|
real *t0,
|
|
real *t1)
|
|
{
|
|
real_vector2d edge0;
|
|
real_vector2d edge1;
|
|
real_vector2d offset;
|
|
real cross0;
|
|
real cross1;
|
|
real determinant;
|
|
boolean result;
|
|
|
|
vector_from_points2d(triangle0, triangle1, &edge0);
|
|
vector_from_points2d(triangle0, point, &offset);
|
|
cross0 = cross_product2d(&edge0, &offset);
|
|
if (cross0 >= 0.f)
|
|
{
|
|
vector_from_points2d(triangle0, triangle2, &edge1);
|
|
cross1 = cross_product2d(&offset, &edge1);
|
|
if (cross1 >= 0.f)
|
|
{
|
|
determinant = cross_product2d(&edge0, &edge1);
|
|
if (cross0 + cross1 <= determinant)
|
|
{
|
|
real inverse_determinant = 1.f / determinant;
|
|
*t0 = cross1 * inverse_determinant;
|
|
*t1 = cross0 * inverse_determinant;
|
|
result = TRUE;
|
|
}
|
|
else
|
|
{
|
|
result = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = FALSE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean point_in_triangle3d(
|
|
real_point3d const *point,
|
|
real_point3d const *triangle0,
|
|
real_point3d const *triangle1,
|
|
real_point3d const *triangle2,
|
|
real *t0,
|
|
real *t1)
|
|
{
|
|
real_vector3d edge0;
|
|
real_vector3d edge1;
|
|
real_vector3d offset;
|
|
real_vector3d normal;
|
|
real_point2d projected_edge0;
|
|
real_point2d projected_edge1;
|
|
real_point2d projected_offset;
|
|
real plane_distance;
|
|
real cross0;
|
|
real cross1;
|
|
real determinant;
|
|
boolean result;
|
|
short projection;
|
|
boolean projection_sign;
|
|
|
|
vector_from_points3d(triangle0, point, &offset);
|
|
vector_from_points3d(triangle0, triangle1, &edge0);
|
|
vector_from_points3d(triangle0, triangle2, &edge1);
|
|
cross_product3d(&edge0, &edge1, &normal);
|
|
plane_distance = dot_product3d(&normal, &offset);
|
|
if (plane_distance * plane_distance <
|
|
magnitude_squared3d(&normal) * _real_epsilon)
|
|
{
|
|
projection = projection_from_vector3d(&normal);
|
|
projection_sign = projection_sign_from_vector3d(&normal, projection);
|
|
project_point3d(
|
|
(real_point3d const *)&edge0,
|
|
projection,
|
|
projection_sign,
|
|
&projected_edge0);
|
|
project_point3d(
|
|
(real_point3d const *)&offset,
|
|
projection,
|
|
projection_sign,
|
|
&projected_offset);
|
|
cross0 = cross_product2d(
|
|
(real_vector2d const *)&projected_edge0,
|
|
(real_vector2d const *)&projected_offset);
|
|
if (cross0 >= 0.0f)
|
|
{
|
|
project_point3d(
|
|
(real_point3d const *)&edge1,
|
|
projection,
|
|
projection_sign,
|
|
&projected_edge1);
|
|
cross1 = cross_product2d(
|
|
(real_vector2d const *)&projected_offset,
|
|
(real_vector2d const *)&projected_edge1);
|
|
if (cross1 >= 0.0f)
|
|
{
|
|
determinant = cross_product2d(
|
|
(real_vector2d const *)&projected_edge0,
|
|
(real_vector2d const *)&projected_edge1);
|
|
if (cross0 + cross1 <= determinant)
|
|
{
|
|
real inverse_determinant;
|
|
|
|
inverse_determinant = 1.0f / determinant;
|
|
*t0 = cross1 * inverse_determinant;
|
|
*t1 = cross0 * inverse_determinant;
|
|
result = TRUE;
|
|
}
|
|
else
|
|
{
|
|
result = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = FALSE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean circle_intersects_triangle2d(
|
|
real_point2d const *center,
|
|
real radius,
|
|
real_point2d const *triangle0,
|
|
real_point2d const *triangle1,
|
|
real_point2d const *triangle2)
|
|
{
|
|
real_vector2d edge;
|
|
real_vector2d offset;
|
|
boolean result = TRUE;
|
|
|
|
vector_from_points2d(triangle0, center, &offset);
|
|
vector_from_points2d(triangle0, triangle1, &edge);
|
|
if (cross_product2d(&offset, &edge) > 0.0f)
|
|
{
|
|
if (point_in_pill2d(center, triangle0, &edge, radius))
|
|
return TRUE;
|
|
result = FALSE;
|
|
}
|
|
|
|
vector_from_points2d(triangle1, center, &offset);
|
|
vector_from_points2d(triangle1, triangle2, &edge);
|
|
if (cross_product2d(&offset, &edge) < 0.0f)
|
|
{
|
|
if (point_in_pill2d(center, triangle1, &edge, radius))
|
|
return TRUE;
|
|
result = FALSE;
|
|
}
|
|
|
|
vector_from_points2d(triangle2, center, &offset);
|
|
vector_from_points2d(triangle2, triangle0, &edge);
|
|
if (cross_product2d(&offset, &edge) > 0.0f)
|
|
{
|
|
if (point_in_pill2d(center, triangle2, &edge, radius))
|
|
return TRUE;
|
|
result = FALSE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean pill_intersects_triangle2d(
|
|
real_point2d const *pill_base,
|
|
real_vector2d const *pill_height,
|
|
real pill_width,
|
|
real_point2d const *triangle0,
|
|
real_point2d const *triangle1,
|
|
real_point2d const *triangle2)
|
|
{
|
|
real_vector2d edge;
|
|
real_vector2d offset;
|
|
boolean result = TRUE;
|
|
|
|
vector_from_points2d(triangle0, pill_base, &offset);
|
|
vector_from_points2d(triangle0, triangle1, &edge);
|
|
if (cross_product2d(&offset, &edge) > 0.0f)
|
|
{
|
|
if (vector_intersects_pill2d(
|
|
triangle0,
|
|
&edge,
|
|
pill_base,
|
|
pill_height,
|
|
pill_width))
|
|
{
|
|
return TRUE;
|
|
}
|
|
result = FALSE;
|
|
}
|
|
|
|
vector_from_points2d(triangle1, pill_base, &offset);
|
|
vector_from_points2d(triangle1, triangle2, &edge);
|
|
if (cross_product2d(&offset, &edge) > 0.0f)
|
|
{
|
|
if (vector_intersects_pill2d(
|
|
triangle1,
|
|
&edge,
|
|
pill_base,
|
|
pill_height,
|
|
pill_width))
|
|
{
|
|
return TRUE;
|
|
}
|
|
result = FALSE;
|
|
}
|
|
|
|
vector_from_points2d(triangle2, pill_base, &offset);
|
|
vector_from_points2d(triangle2, triangle0, &edge);
|
|
if (cross_product2d(&offset, &edge) > 0.0f)
|
|
{
|
|
if (vector_intersects_pill2d(
|
|
triangle2,
|
|
&edge,
|
|
pill_base,
|
|
pill_height,
|
|
pill_width))
|
|
{
|
|
return TRUE;
|
|
}
|
|
result = FALSE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean pill_intersects_rectangle2d(
|
|
real_point2d const *pill_base,
|
|
real_vector2d const *pill_height,
|
|
real pill_width,
|
|
real_rectangle2d const *bounds)
|
|
{
|
|
real_point2d edge_base;
|
|
real_vector2d edge_height;
|
|
boolean result;
|
|
|
|
result = TRUE;
|
|
if (pill_base->x < bounds->x0)
|
|
{
|
|
set_real_point2d(&edge_base, bounds->x0, bounds->y0);
|
|
set_real_vector2d(&edge_height, 0.0f, bounds->y1 - bounds->y0);
|
|
if (vector_intersects_pill2d(
|
|
&edge_base,
|
|
&edge_height,
|
|
pill_base,
|
|
pill_height,
|
|
pill_width))
|
|
{
|
|
return (boolean)TRUE;
|
|
}
|
|
result = FALSE;
|
|
}
|
|
if (pill_base->y < bounds->y0)
|
|
{
|
|
edge_base.x = bounds->x0;
|
|
edge_base.y = bounds->y0;
|
|
edge_height.i = bounds->x1 - bounds->x0;
|
|
edge_height.j = 0.0f;
|
|
if (vector_intersects_pill2d(
|
|
&edge_base,
|
|
&edge_height,
|
|
pill_base,
|
|
pill_height,
|
|
pill_width))
|
|
{
|
|
return TRUE;
|
|
}
|
|
result = FALSE;
|
|
}
|
|
if (pill_base->x > bounds->x1)
|
|
{
|
|
set_real_point2d(&edge_base, bounds->x1, bounds->y0);
|
|
set_real_vector2d(&edge_height, 0.0f, bounds->y1 - bounds->y0);
|
|
if (vector_intersects_pill2d(
|
|
&edge_base,
|
|
&edge_height,
|
|
pill_base,
|
|
pill_height,
|
|
pill_width))
|
|
{
|
|
return TRUE;
|
|
}
|
|
result = FALSE;
|
|
}
|
|
if (pill_base->y > bounds->y1)
|
|
{
|
|
edge_base.x = bounds->x0;
|
|
edge_base.y = bounds->y1;
|
|
edge_height.i = bounds->x1 - bounds->x0;
|
|
edge_height.j = 0.0f;
|
|
if (vector_intersects_pill2d(
|
|
&edge_base,
|
|
&edge_height,
|
|
pill_base,
|
|
pill_height,
|
|
pill_width))
|
|
{
|
|
return TRUE;
|
|
}
|
|
result = FALSE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
boolean sphere_intersects_rectangle3d(
|
|
real_point3d const *center,
|
|
real radius,
|
|
real_rectangle3d const *bounds)
|
|
{
|
|
real dx;
|
|
real dy;
|
|
real dz;
|
|
|
|
if (center->x <= bounds->x1)
|
|
{
|
|
if (center->x < bounds->x0)
|
|
{
|
|
dx = bounds->x0 - center->x;
|
|
}
|
|
else
|
|
{
|
|
dx = 0.f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dx = center->x - bounds->x1;
|
|
}
|
|
|
|
if (center->y <= bounds->y1)
|
|
{
|
|
if (center->y < bounds->y0)
|
|
{
|
|
dy = bounds->y0 - center->y;
|
|
}
|
|
else
|
|
{
|
|
dy = 0.f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dy = center->y - bounds->y1;
|
|
}
|
|
|
|
if (center->z <= bounds->z1)
|
|
{
|
|
if (center->z < bounds->z0)
|
|
{
|
|
dz = bounds->z0 - center->z;
|
|
}
|
|
else
|
|
{
|
|
dz = 0.f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dz = center->z - bounds->z1;
|
|
}
|
|
|
|
return dx * dx + dy * dy + dz * dz < radius * radius;
|
|
}
|
|
|
|
boolean sphere_intersects_triangle3d(
|
|
real_point3d const *center,
|
|
real radius,
|
|
real_point3d const *p0,
|
|
real_point3d const *p1,
|
|
real_point3d const *p2)
|
|
{
|
|
real_vector3d v;
|
|
real_vector3d e0;
|
|
real_vector3d e1;
|
|
real_vector3d e2;
|
|
real_vector3d n;
|
|
real plane_dot;
|
|
real normal_magnitude_squared;
|
|
boolean result;
|
|
|
|
result = TRUE;
|
|
vector_from_points3d(p0, center, &v);
|
|
vector_from_points3d(p0, p1, &e0);
|
|
vector_from_points3d(p1, p2, &e1);
|
|
cross_product3d(&e0, &e1, &n);
|
|
plane_dot = dot_product3d(&n, &v);
|
|
normal_magnitude_squared = magnitude_squared3d(&n);
|
|
if (plane_dot * plane_dot > normal_magnitude_squared * radius * radius)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (triple_product3d(&v, &e0, &n) > 0.0f)
|
|
{
|
|
if (fast_vector_intersects_sphere(p0, &e0, center, radius))
|
|
{
|
|
return TRUE;
|
|
}
|
|
result = FALSE;
|
|
}
|
|
|
|
vector_from_points3d(p1, center, &v);
|
|
if (triple_product3d(&v, &e1, &n) > 0.0f)
|
|
{
|
|
if (fast_vector_intersects_sphere(p1, &e1, center, radius))
|
|
{
|
|
return TRUE;
|
|
}
|
|
result = FALSE;
|
|
}
|
|
|
|
vector_from_points3d(p2, center, &v);
|
|
vector_from_points3d(p2, p0, &e2);
|
|
if (triple_product3d(&v, &e2, &n) < 0.0f)
|
|
{
|
|
if (fast_vector_intersects_sphere(p2, &e2, center, radius))
|
|
{
|
|
return TRUE;
|
|
}
|
|
result = FALSE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean pill_intersects_triangle3d(
|
|
real_point3d const *base,
|
|
real_vector3d const *height,
|
|
real width,
|
|
real_point3d const *p0,
|
|
real_point3d const *p1,
|
|
real_point3d const *p2)
|
|
{
|
|
real_vector3d e0;
|
|
real_vector3d e1;
|
|
real_vector3d e2;
|
|
real_vector3d v;
|
|
real_vector3d n;
|
|
real_point3d p;
|
|
real t;
|
|
real closest_t;
|
|
real plane_distance;
|
|
boolean outside = FALSE;
|
|
|
|
vector_from_points3d(p0, p1, &e0);
|
|
vector_from_points3d(p1, p2, &e1);
|
|
vector_from_points3d(base, p0, &v);
|
|
cross_product3d(&e0, &e1, &n);
|
|
t = dot_product3d(&n, &v) / dot_product3d(&n, height);
|
|
|
|
if (t < 0.0f)
|
|
{
|
|
closest_t = 0.0f;
|
|
}
|
|
else if (t > 1.0f)
|
|
{
|
|
closest_t = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
closest_t = t;
|
|
}
|
|
point_from_line3d(base, height, closest_t, &p);
|
|
vector_from_points3d(p0, &p, &v);
|
|
|
|
if (triple_product3d(&e0, &v, &n) < 0.0f)
|
|
{
|
|
if ((boolean)vector_intersects_pill3d(
|
|
p0,
|
|
&e0,
|
|
base,
|
|
height,
|
|
width))
|
|
{
|
|
return TRUE;
|
|
}
|
|
outside = TRUE;
|
|
}
|
|
|
|
vector_from_points3d(p1, &p, &v);
|
|
if (triple_product3d(&e1, &v, &n) < 0.0f)
|
|
{
|
|
if ((boolean)vector_intersects_pill3d(
|
|
p1,
|
|
&e1,
|
|
base,
|
|
height,
|
|
width))
|
|
{
|
|
return TRUE;
|
|
}
|
|
outside = TRUE;
|
|
}
|
|
|
|
vector_from_points3d(p2, p0, &e2);
|
|
vector_from_points3d(p2, &p, &v);
|
|
if (triple_product3d(&e2, &v, &n) < 0.0f)
|
|
{
|
|
if ((boolean)vector_intersects_pill3d(
|
|
p2,
|
|
&e2,
|
|
base,
|
|
height,
|
|
width))
|
|
{
|
|
return TRUE;
|
|
}
|
|
outside = TRUE;
|
|
}
|
|
|
|
if (outside)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (t > 0.0f && t < 1.0f)
|
|
{
|
|
return TRUE;
|
|
}
|
|
plane_distance = dot_product3d(&n, &v);
|
|
return plane_distance * plane_distance <=
|
|
magnitude_squared3d(&n) * width * width;
|
|
}
|
|
|
|
|
|
boolean vector_intersects_rectangle2d(
|
|
real_point2d const *point,
|
|
real_vector2d const *vector,
|
|
real_rectangle2d const *bounds)
|
|
{
|
|
real t_in = -FLT_MAX;
|
|
real t_out = FLT_MAX;
|
|
|
|
if (!(fabs(vector->i) < _real_epsilon))
|
|
{
|
|
real ooi = 1.f / vector->i;
|
|
real t0 = (bounds->x0-point->x) * ooi;
|
|
real t1 = (bounds->x1-point->x) * ooi;
|
|
|
|
if (vector->i > 0.f)
|
|
{
|
|
if (t_in < t0) t_in = t0;
|
|
if (t_out > t1) t_out = t1;
|
|
}
|
|
else
|
|
{
|
|
if (t_in < t1) t_in = t1;
|
|
if (t_out > t0) t_out = t0;
|
|
}
|
|
|
|
if (t_in > t_out)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (point->x < bounds->x0 || point->x > bounds->x1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (!(fabs(vector->j) < _real_epsilon))
|
|
{
|
|
real ooj = 1.f / vector->j;
|
|
real t0 = (bounds->y0-point->y) * ooj;
|
|
real t1 = (bounds->y1-point->y) * ooj;
|
|
|
|
if (vector->j > 0.f)
|
|
{
|
|
if (t_in < t0) t_in = t0;
|
|
if (t_out > t1) t_out = t1;
|
|
}
|
|
else
|
|
{
|
|
if (t_in < t1) t_in = t1;
|
|
if (t_out > t0) t_out = t0;
|
|
}
|
|
|
|
if (t_in > t_out)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (point->y < bounds->y0 || point->y > bounds->y1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return t_out >= 0.f && t_in <= 1.f;
|
|
}
|
|
|
|
boolean vector_intersects_pill2d(
|
|
real_point2d const *point,
|
|
real_vector2d const *vector,
|
|
real_point2d const *pill_base,
|
|
real_vector2d const *pill_height,
|
|
real pill_width)
|
|
{
|
|
real_vector2d offset;
|
|
real cross;
|
|
real dot;
|
|
real vector_magnitude_squared;
|
|
real pill_magnitude_squared;
|
|
real inverse_cross;
|
|
real inverse_vector_magnitude_squared;
|
|
real inverse_pill_magnitude_squared;
|
|
real t0;
|
|
real t1;
|
|
real t0_start;
|
|
real t0_end;
|
|
real t1_start;
|
|
real t1_end;
|
|
real clamped_t0;
|
|
real clamped_t1;
|
|
real_point2d closest_point0;
|
|
real_point2d closest_point1;
|
|
real_vector2d closest_offset;
|
|
boolean t0_out_of_range;
|
|
boolean t1_out_of_range;
|
|
|
|
vector_from_points2d(point, pill_base, &offset);
|
|
cross = cross_product2d(vector, pill_height);
|
|
if (!(fabs(cross) < _real_epsilon))
|
|
{
|
|
inverse_cross = 1.0f / cross;
|
|
t0 = cross_product2d(&offset, pill_height) * inverse_cross;
|
|
t1 = cross_product2d(&offset, vector) * inverse_cross;
|
|
t0_out_of_range = t0 < 0.0f || t0 > 1.0f;
|
|
t1_out_of_range = t1 < 0.0f || t1 > 1.0f;
|
|
if (!t0_out_of_range && !t1_out_of_range)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (t0_out_of_range)
|
|
{
|
|
if (t0 < 0.0f)
|
|
clamped_t0 = 0.0f;
|
|
else
|
|
clamped_t0 = 1.0f;
|
|
point_from_line2d(point, vector, clamped_t0, &closest_point0);
|
|
}
|
|
|
|
if (t1_out_of_range)
|
|
{
|
|
if (t1 < 0.0f)
|
|
clamped_t1 = 0.0f;
|
|
else
|
|
clamped_t1 = 1.0f;
|
|
point_from_line2d(pill_base, pill_height, clamped_t1, &closest_point1);
|
|
}
|
|
|
|
return !((!t0_out_of_range ||
|
|
point_in_pill2d(
|
|
&closest_point0,
|
|
pill_base,
|
|
pill_height,
|
|
pill_width) == FALSE) &&
|
|
(!t1_out_of_range ||
|
|
point_in_pill2d(
|
|
&closest_point1,
|
|
point,
|
|
vector,
|
|
pill_width) == FALSE));
|
|
}
|
|
|
|
dot = dot_product2d(vector, pill_height);
|
|
vector_magnitude_squared = magnitude_squared2d(vector);
|
|
if (vector_magnitude_squared > _real_epsilon)
|
|
{
|
|
inverse_vector_magnitude_squared = 1.0f / vector_magnitude_squared;
|
|
t0_start =
|
|
dot_product2d(&offset, vector) *
|
|
inverse_vector_magnitude_squared;
|
|
t0_end =
|
|
inverse_vector_magnitude_squared * dot +
|
|
t0_start;
|
|
t0 =
|
|
(PIN(t0_start, 0.0f, 1.0f) +
|
|
PIN(t0_end, 0.0f, 1.0f)) *
|
|
0.5f;
|
|
}
|
|
else
|
|
{
|
|
t0 = 0.0f;
|
|
}
|
|
|
|
pill_magnitude_squared = magnitude_squared2d(pill_height);
|
|
if (pill_magnitude_squared > _real_epsilon)
|
|
{
|
|
inverse_pill_magnitude_squared = 1.0f / pill_magnitude_squared;
|
|
t1_start =
|
|
-dot_product2d(&offset, pill_height) *
|
|
inverse_pill_magnitude_squared;
|
|
t1_end =
|
|
inverse_pill_magnitude_squared * dot +
|
|
t1_start;
|
|
t1 =
|
|
(PIN(t1_start, 0.0f, 1.0f) +
|
|
PIN(t1_end, 0.0f, 1.0f)) *
|
|
0.5f;
|
|
}
|
|
else
|
|
{
|
|
t1 = 0.0f;
|
|
}
|
|
|
|
point_from_line2d(point, vector, t0, &closest_point0);
|
|
point_from_line2d(pill_base, pill_height, t1, &closest_point1);
|
|
vector_from_points2d(&closest_point0, &closest_point1, &closest_offset);
|
|
return magnitude_squared2d(&closest_offset) <= pill_width * pill_width;
|
|
}
|
|
|
|
long vector_intersects_pill3d(
|
|
real_point3d const *point,
|
|
real_vector3d const *vector,
|
|
real_point3d const *pill_base,
|
|
real_vector3d const *pill_height,
|
|
real pill_width)
|
|
{
|
|
real_vector3d offset;
|
|
real_vector3d cross;
|
|
real_vector3d numerator_cross;
|
|
real denominator;
|
|
real inverse_denominator;
|
|
real dot;
|
|
real vector_magnitude_squared;
|
|
real pill_magnitude_squared;
|
|
real inverse_vector_magnitude_squared;
|
|
real inverse_pill_magnitude_squared;
|
|
real t0;
|
|
real t1;
|
|
real t0_start;
|
|
real t0_end;
|
|
real t1_start;
|
|
real t1_end;
|
|
real clamped_t0;
|
|
real clamped_t1;
|
|
real_point3d closest_point0;
|
|
real_point3d closest_point1;
|
|
real_vector3d closest_offset;
|
|
boolean t0_out_of_range;
|
|
boolean t1_out_of_range;
|
|
|
|
vector_from_points3d(point, pill_base, &offset);
|
|
cross_product3d(vector, pill_height, &cross);
|
|
denominator = magnitude_squared3d_right_associated(&cross);
|
|
if (!(fabs(denominator) < _real_epsilon))
|
|
{
|
|
inverse_denominator = 1.0f / denominator;
|
|
scale_vector3d(&cross, inverse_denominator, &cross);
|
|
cross_product3d(&offset, pill_height, &numerator_cross);
|
|
t0 = dot_product3d(&numerator_cross, &cross);
|
|
cross_product3d(&offset, vector, &numerator_cross);
|
|
t1 = dot_product3d(&numerator_cross, &cross);
|
|
t0_out_of_range = t0 < 0.0f || t0 > 1.0f;
|
|
t1_out_of_range = t1 < 0.0f || t1 > 1.0f;
|
|
if (!t0_out_of_range && !t1_out_of_range)
|
|
goto closest_distance;
|
|
|
|
if (t0_out_of_range)
|
|
{
|
|
clamped_t0 = t0 < 0.0f ? 0.0f : 1.0f;
|
|
point_from_line3d(point, vector, clamped_t0, &closest_point0);
|
|
}
|
|
if (t1_out_of_range)
|
|
{
|
|
clamped_t1 = t1 < 0.0f ? 0.0f : 1.0f;
|
|
point_from_line3d(pill_base, pill_height, clamped_t1, &closest_point1);
|
|
}
|
|
if (t0_out_of_range &&
|
|
fast_vector_intersects_sphere(
|
|
pill_base,
|
|
pill_height,
|
|
&closest_point0,
|
|
pill_width))
|
|
{
|
|
goto intersection;
|
|
}
|
|
if (t1_out_of_range &&
|
|
fast_vector_intersects_sphere(
|
|
point,
|
|
vector,
|
|
&closest_point1,
|
|
pill_width))
|
|
{
|
|
goto intersection;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
dot = dot_product3d(vector, pill_height);
|
|
vector_magnitude_squared = magnitude_squared3d(vector);
|
|
if (vector_magnitude_squared > _real_epsilon)
|
|
{
|
|
inverse_vector_magnitude_squared = 1.0f / vector_magnitude_squared;
|
|
t0_start = offset.k * vector->k;
|
|
t0_start += offset.j * vector->j;
|
|
t0_start += offset.i * vector->i;
|
|
t0_start *= inverse_vector_magnitude_squared;
|
|
t0_end =
|
|
inverse_vector_magnitude_squared * dot +
|
|
t0_start;
|
|
t0 =
|
|
(PIN(t0_start, 0.0f, 1.0f) +
|
|
PIN(t0_end, 0.0f, 1.0f)) *
|
|
0.5f;
|
|
}
|
|
else
|
|
{
|
|
t0 = 0.0f;
|
|
}
|
|
|
|
pill_magnitude_squared = magnitude_squared3d(pill_height);
|
|
if (pill_magnitude_squared > _real_epsilon)
|
|
{
|
|
inverse_pill_magnitude_squared = 1.0f / pill_magnitude_squared;
|
|
t1_start =
|
|
-dot_product3d(&offset, pill_height) *
|
|
inverse_pill_magnitude_squared;
|
|
t1_end =
|
|
inverse_pill_magnitude_squared * dot +
|
|
t1_start;
|
|
t1 =
|
|
(PIN(t1_start, 0.0f, 1.0f) +
|
|
PIN(t1_end, 0.0f, 1.0f)) *
|
|
0.5f;
|
|
}
|
|
else
|
|
{
|
|
t1 = 0.0f;
|
|
}
|
|
|
|
closest_distance:
|
|
point_from_line3d(point, vector, t0, &closest_point0);
|
|
point_from_line3d(pill_base, pill_height, t1, &closest_point1);
|
|
vector_from_points3d(&closest_point0, &closest_point1, &closest_offset);
|
|
if (!(magnitude_squared3d(&closest_offset) <= pill_width * pill_width))
|
|
return FALSE;
|
|
|
|
intersection:
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#define VECTOR_INTERSECTS_LINE2D(point, vector, line_point, line_endpoint, t_in, t_out) \
|
|
do \
|
|
{ \
|
|
real_vector2d offset; \
|
|
real_vector2d line_vector; \
|
|
real numerator; \
|
|
real divisor; \
|
|
real t; \
|
|
vector_from_points2d((line_point), (point), &offset); \
|
|
vector_from_points2d((line_point), (line_endpoint), &line_vector); \
|
|
numerator = offset.i * line_vector.j - offset.j * line_vector.i; \
|
|
divisor = line_vector.i * (vector)->j - line_vector.j * (vector)->i; \
|
|
if (!(fabs(divisor) < _real_epsilon)) \
|
|
{ \
|
|
t = numerator / divisor; \
|
|
if (divisor > 0.0f) \
|
|
{ \
|
|
if (*(t_in) < t) \
|
|
*(t_in) = t; \
|
|
} \
|
|
else \
|
|
{ \
|
|
if (*(t_out) > t) \
|
|
*(t_out) = t; \
|
|
} \
|
|
if (*(t_in) > *(t_out)) \
|
|
return FALSE; \
|
|
} \
|
|
else if (numerator > 0.0f) \
|
|
{ \
|
|
return FALSE; \
|
|
} \
|
|
} while (0)
|
|
|
|
boolean vector_intersects_triangle2d(
|
|
real_point2d const *point,
|
|
real_vector2d const *vector,
|
|
real_point2d const *triangle0,
|
|
real_point2d const *triangle1,
|
|
real_point2d const *triangle2)
|
|
{
|
|
real t_in = 0.0f;
|
|
real t_out = 1.0f;
|
|
|
|
VECTOR_INTERSECTS_LINE2D(
|
|
point,
|
|
vector,
|
|
triangle0,
|
|
triangle1,
|
|
&t_in,
|
|
&t_out);
|
|
|
|
VECTOR_INTERSECTS_LINE2D(
|
|
point,
|
|
vector,
|
|
triangle1,
|
|
triangle2,
|
|
&t_in,
|
|
&t_out);
|
|
|
|
VECTOR_INTERSECTS_LINE2D(
|
|
point,
|
|
vector,
|
|
triangle2,
|
|
triangle0,
|
|
&t_in,
|
|
&t_out);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#undef VECTOR_INTERSECTS_LINE2D
|
|
|
|
boolean vector_intersects_triangle3d(
|
|
real_point3d const *point,
|
|
real_vector3d const *vector,
|
|
real_point3d const *triangle0,
|
|
real_point3d const *triangle1,
|
|
real_point3d const *triangle2,
|
|
real *result)
|
|
{
|
|
real_vector3d edge0;
|
|
real_vector3d edge1;
|
|
real_vector3d normal;
|
|
real_vector3d offset;
|
|
real_vector3d cross;
|
|
real denominator;
|
|
real inverse_denominator;
|
|
real t;
|
|
real t0;
|
|
real t1;
|
|
boolean intersects = FALSE;
|
|
|
|
vector_from_points3d(triangle0, triangle1, &edge0);
|
|
vector_from_points3d(triangle0, triangle2, &edge1);
|
|
cross_product3d(&edge0, &edge1, &normal);
|
|
denominator = dot_product3d(&normal, vector);
|
|
if (!(fabs(denominator) < _real_epsilon))
|
|
{
|
|
inverse_denominator = 1.0f / denominator;
|
|
vector_from_points3d(point, triangle0, &offset);
|
|
t = dot_product3d(&offset, &normal) * inverse_denominator;
|
|
if (t >= 0.0f && t <= 1.0f)
|
|
{
|
|
cross_product3d(&offset, vector, &cross);
|
|
t0 = dot_product3d(&cross, &edge1) * inverse_denominator;
|
|
if (t0 >= 0.0f && t0 <= 1.0f)
|
|
{
|
|
t1 = -dot_product3d(&cross, &edge0) * inverse_denominator;
|
|
if (t1 >= 0.0f && t0 + t1 <= 1.0f)
|
|
{
|
|
*result = t;
|
|
intersects = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return intersects;
|
|
}
|
|
|
|
boolean vector_intersects_rectangle3d(
|
|
real_point3d const *point,
|
|
real_vector3d const *vector,
|
|
real_rectangle3d const *bounds)
|
|
{
|
|
real t_in = -FLT_MAX;
|
|
real t_out = FLT_MAX;
|
|
|
|
if (!(fabs(vector->i) < _real_epsilon))
|
|
{
|
|
real ooi = 1.f / vector->i;
|
|
real t0 = (bounds->x0-point->x) * ooi;
|
|
real t1 = (bounds->x1-point->x) * ooi;
|
|
|
|
if (vector->i > 0.f)
|
|
{
|
|
if (t_in < t0) t_in = t0;
|
|
if (t_out > t1) t_out = t1;
|
|
}
|
|
else
|
|
{
|
|
if (t_in < t1) t_in = t1;
|
|
if (t_out > t0) t_out = t0;
|
|
}
|
|
|
|
if (t_in > t_out)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (point->x < bounds->x0 || point->x > bounds->x1)
|
|
return FALSE;
|
|
}
|
|
|
|
if (!(fabs(vector->j) < _real_epsilon))
|
|
{
|
|
real ooj = 1.f / vector->j;
|
|
real t0 = (bounds->y0-point->y) * ooj;
|
|
real t1 = (bounds->y1-point->y) * ooj;
|
|
|
|
if (vector->j > 0.f)
|
|
{
|
|
if (t_in < t0) t_in = t0;
|
|
if (t_out > t1) t_out = t1;
|
|
}
|
|
else
|
|
{
|
|
if (t_in < t1) t_in = t1;
|
|
if (t_out > t0) t_out = t0;
|
|
}
|
|
|
|
if (t_in > t_out)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (point->y < bounds->y0 || point->y > bounds->y1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (!(fabs(vector->k) < _real_epsilon))
|
|
{
|
|
real ook = 1 / vector->k;
|
|
real t0 = (bounds->z0-point->z) * ook;
|
|
real t1 = (bounds->z1-point->z) * ook;
|
|
|
|
if (vector->k > 0.f)
|
|
{
|
|
if (t_in < t0) t_in = t0;
|
|
if (t_out > t1) t_out = t1;
|
|
}
|
|
else
|
|
{
|
|
if (t_in < t1) t_in = t1;
|
|
if (t_out > t0) t_out = t0;
|
|
}
|
|
|
|
if (t_in > t_out)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (point->z < bounds->z0 || point->z > bounds->z1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return t_out >= 0.f && t_in <= 1.f;
|
|
}
|
|
|
|
boolean pill_intersects_rectangle3d(
|
|
real_point3d const *base,
|
|
real_vector3d const *height,
|
|
real width,
|
|
real_rectangle3d const *bounds)
|
|
{
|
|
/* originally stubbed */
|
|
return FALSE;
|
|
}
|
|
|
|
real_vector2d *fast_normalize2d(
|
|
real_vector2d *v)
|
|
{
|
|
real magnitude_squared = magnitude_squared2d(v);
|
|
|
|
if (magnitude_squared != 0.f)
|
|
{
|
|
scale_vector2d(v, 1.f / square_root(magnitude_squared), v);
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
real_vector3d *fast_normalize3d(
|
|
real_vector3d *v)
|
|
{
|
|
real magnitude_squared = magnitude_squared3d(v);
|
|
|
|
if (magnitude_squared != 0.f)
|
|
{
|
|
scale_vector3d(v, 1.f / square_root(magnitude_squared), v);
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
real cross_product_magnitude3d(
|
|
real_vector3d const *a,
|
|
real_vector3d const *b)
|
|
{
|
|
real_vector3d c;
|
|
cross_product3d(a, b, &c);
|
|
return magnitude3d(&c);
|
|
}
|
|
|
|
real dequantize_byte_to_real(
|
|
real min,
|
|
real max,
|
|
byte value)
|
|
{
|
|
if (value == UNSIGNED_CHAR_MAX)
|
|
{
|
|
return max;
|
|
}
|
|
|
|
return (max-min) * ((real)value / 255.f) + min;
|
|
}
|
|
|
|
byte quantize_real_to_byte_lower_bound(
|
|
real min,
|
|
real max,
|
|
real value)
|
|
{
|
|
real range;
|
|
byte test;
|
|
|
|
range = max - min;
|
|
test = (byte)(long)(((value - min) / range) * 255.f);
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
2803,
|
|
min - _real_epsilon <= value &&
|
|
value <= max + _real_epsilon,
|
|
csprintf(
|
|
temporary,
|
|
"%lf is not between %lf and %lf",
|
|
value,
|
|
min,
|
|
max));
|
|
|
|
while (test > 0 &&
|
|
value < dequantize_byte_to_real(min, max, test))
|
|
{
|
|
test--;
|
|
}
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
2809,
|
|
dequantize_byte_to_real(min, max, test) <= value ||
|
|
(test == 0 &&
|
|
dequantize_byte_to_real(min, max, test) <= value + _real_epsilon),
|
|
"dequantize_byte_to_real(min, max, test)<=value || (test==0 && dequantize_byte_to_real(min, max, test)<=value+_real_epsilon)");
|
|
|
|
return test;
|
|
}
|
|
|
|
byte quantize_real_to_byte_upper_bound(
|
|
real min,
|
|
real max,
|
|
real value)
|
|
{
|
|
real range;
|
|
byte test;
|
|
|
|
range = max - min;
|
|
test = (byte)(long)(((value - min) / range) * 255.f);
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
2823,
|
|
min - _real_epsilon <= value &&
|
|
value <= max + _real_epsilon,
|
|
csprintf(
|
|
temporary,
|
|
"%lf is not between %lf and %lf",
|
|
value,
|
|
min,
|
|
max));
|
|
|
|
while (test < UNSIGNED_CHAR_MAX &&
|
|
value > dequantize_byte_to_real(min, max, test))
|
|
{
|
|
test++;
|
|
}
|
|
|
|
match_vassert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
2829,
|
|
dequantize_byte_to_real(min, max, test) >= value ||
|
|
(test == UNSIGNED_CHAR_MAX &&
|
|
dequantize_byte_to_real(min, max, test) >= value - _real_epsilon),
|
|
"dequantize_byte_to_real(min, max, test)>=value || (test==UNSIGNED_CHAR_MAX && dequantize_byte_to_real(min, max, test)>=value-_real_epsilon)");
|
|
|
|
return test;
|
|
}
|
|
|
|
byte_rectangle3d *quantize_real_to_byte_rectangle3d(
|
|
real_rectangle3d const *parent,
|
|
real_rectangle3d const *rectangle,
|
|
byte_rectangle3d *result)
|
|
{
|
|
if (rectangle->x0 == REAL_MAX)
|
|
{
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
2843,
|
|
rectangle->x1==REAL_MIN && rectangle->y0==REAL_MAX && rectangle->y1==REAL_MIN && rectangle->z0==REAL_MAX && rectangle->z1==REAL_MIN);
|
|
|
|
csmemset(result, 0, sizeof(*result));
|
|
}
|
|
else
|
|
{
|
|
result->x0 = quantize_real_to_byte_lower_bound(parent->x0, parent->x1, rectangle->x0);
|
|
result->x1 = quantize_real_to_byte_upper_bound(parent->x0, parent->x1, rectangle->x1);
|
|
result->y0 = quantize_real_to_byte_lower_bound(parent->y0, parent->y1, rectangle->y0);
|
|
result->y1 = quantize_real_to_byte_upper_bound(parent->y0, parent->y1, rectangle->y1);
|
|
result->z0 = quantize_real_to_byte_lower_bound(parent->z0, parent->z1, rectangle->z0);
|
|
result->z1 = quantize_real_to_byte_upper_bound(parent->z0, parent->z1, rectangle->z1);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
real signed_angle_between_vectors2d(
|
|
real_vector2d const *a,
|
|
real_vector2d const *b)
|
|
{
|
|
real dot_product = dot_product2d(a, b);
|
|
real result = arccosine(PIN(dot_product, -1.f, 1.f));
|
|
|
|
if ((a->i*b->j) - (a->j*b->i) < 0.f)
|
|
{
|
|
result = -result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
real angle_between_vectors2d(
|
|
real_vector2d const *a,
|
|
real_vector2d const *b)
|
|
{
|
|
real angle = 0.f;
|
|
real aa_bb = (a->i*a->i + a->j*a->j) * (b->i*b->i + b->j*b->j);
|
|
|
|
if (aa_bb != 0.f)
|
|
{
|
|
real ab = dot_product2d(a, b);
|
|
real c = PIN((ab/aa_bb*ab) + (ab/aa_bb*ab) - 1.f, -1.f, 1.f);
|
|
|
|
angle = arccosine(c) * 0.5f;
|
|
|
|
if (ab < 0.f)
|
|
{
|
|
angle = _pi - angle;
|
|
}
|
|
}
|
|
|
|
return angle;
|
|
}
|
|
|
|
real angle_between_vectors3d(
|
|
real_vector3d const *a,
|
|
real_vector3d const *b)
|
|
{
|
|
|
|
real angle = 0.f;
|
|
real aa_bb = (a->i*a->i + a->j*a->j + a->k*a->k) * (b->i*b->i + b->j*b->j + b->k*b->k);
|
|
|
|
if (aa_bb != 0.f)
|
|
{
|
|
real ab = dot_product3d(a, b);
|
|
real c = PIN((ab/aa_bb*ab) + (ab/aa_bb*ab) - 1.f, -1.f, 1.f);
|
|
|
|
angle = arccosine(c) * 0.5f;
|
|
|
|
if (ab < 0.f)
|
|
{
|
|
angle = _pi - angle;
|
|
}
|
|
}
|
|
|
|
return angle;
|
|
}
|
|
|
|
real angle_between_normals3d(
|
|
real_vector3d const *a,
|
|
real_vector3d const *b)
|
|
{
|
|
real result = 0.f;
|
|
|
|
if ((*(long *)&a->i) == (*(long *)&b->i)
|
|
&& (*(long *)&a->j) == (*(long *)&b->j)
|
|
&& (*(long *)&a->k) == (*(long *)&b->k))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
result = PIN(dot_product3d(a, b), -1.f, 1.f);
|
|
return arccosine(result);
|
|
}
|
|
|
|
void yaw_vectors(
|
|
real_vector3d *forward,
|
|
real_vector3d const *up,
|
|
real sine,
|
|
real cosine)
|
|
{
|
|
real_vector3d cross;
|
|
cross_product3d(up, forward, &cross);
|
|
|
|
forward->i = forward->i*cosine + cross.i*sine;
|
|
forward->j = forward->j*cosine + cross.j*sine;
|
|
forward->k = forward->k*cosine + cross.k*sine;
|
|
return;
|
|
}
|
|
|
|
void pitch_vectors(
|
|
real_vector3d *forward,
|
|
real_vector3d *up,
|
|
real sine,
|
|
real cosine)
|
|
{
|
|
real_vector3d backward;
|
|
negate_vector3d(forward, &backward);
|
|
|
|
forward->i = forward->i*cosine + up->i*sine;
|
|
forward->j = forward->j*cosine + up->j*sine;
|
|
forward->k = forward->k*cosine + up->k*sine;
|
|
|
|
up->i = up->i*cosine + backward.i*sine;
|
|
up->j = up->j*cosine + backward.j*sine;
|
|
up->k = up->k*cosine + backward.k*sine;
|
|
return;
|
|
}
|
|
|
|
void fast_normals_interpolate(
|
|
real_vector3d const *a,
|
|
real_vector3d const *b,
|
|
real t,
|
|
real_vector3d *result)
|
|
{
|
|
real one_minus_t = 1-t;
|
|
result->i = t*b->i + one_minus_t * a->i;
|
|
result->j = t*b->j + one_minus_t * a->j;
|
|
result->k = t*b->k + one_minus_t * a->k;
|
|
fast_normalize3d(result);
|
|
return;
|
|
}
|
|
|
|
void normals_interpolate(
|
|
real_vector3d const *a,
|
|
real_vector3d const *b,
|
|
real t,
|
|
real_vector3d *result)
|
|
{
|
|
real angle;
|
|
real_vector3d c;
|
|
|
|
angle = angle_between_vectors3d(a, b);
|
|
|
|
if (t <= 0.5f)
|
|
{
|
|
angle *= t;
|
|
cross_product3d(a, b, &c);
|
|
*result = *a;
|
|
}
|
|
else
|
|
{
|
|
angle *= (1-t);
|
|
cross_product3d(b, a, &c);
|
|
*result = *b;
|
|
}
|
|
|
|
if (normalize3d(&c) != 0.0f)
|
|
{
|
|
rotate_vector_about_axis(result, &c, sine(angle), cosine(angle));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
boolean pin_normal_to_cone3d(
|
|
real_vector3d const *normal,
|
|
real_vector3d const *direction,
|
|
real sine,
|
|
real cosine,
|
|
real_vector3d *result)
|
|
{
|
|
real_vector3d axis;
|
|
boolean pinned;
|
|
|
|
match_assert_valid_real_normal3d("c:\\halo\\SOURCE\\math\\real_math.c", 515, normal);
|
|
match_assert_valid_real_normal3d("c:\\halo\\SOURCE\\math\\real_math.c", 516, direction);
|
|
|
|
if (dot_product3d(normal, direction) >= cosine)
|
|
{
|
|
*result = *normal;
|
|
pinned = FALSE;
|
|
}
|
|
else
|
|
{
|
|
cross_product3d(direction, normal, &axis);
|
|
if (normalize3d(&axis) == 0.f)
|
|
{
|
|
perpendicular3d(direction, &axis);
|
|
normalize3d(&axis);
|
|
}
|
|
|
|
*result = *direction;
|
|
rotate_vector_about_axis(result, &axis, sine, cosine);
|
|
pinned = TRUE;
|
|
}
|
|
|
|
match_assert_valid_real_normal3d("c:\\halo\\SOURCE\\math\\real_math.c", 540, result);
|
|
return pinned;
|
|
}
|
|
|
|
real_vector3d *reflect_vector3d(
|
|
real_vector3d const *incident,
|
|
real_vector3d const *normal,
|
|
real_vector3d *reflection)
|
|
{
|
|
real incident_dot_normal = dot_product3d(incident, normal);
|
|
real twice_incident_dot_normal = incident_dot_normal + incident_dot_normal;
|
|
reflection->i = incident->i - normal->i*twice_incident_dot_normal;
|
|
reflection->j = incident->j - normal->j*twice_incident_dot_normal;
|
|
reflection->k = incident->k - normal->k*twice_incident_dot_normal;
|
|
return reflection;
|
|
}
|
|
|
|
real_vector3d *refract_vector3d(
|
|
real_vector3d const *incident,
|
|
real_vector3d const *normal,
|
|
real coefficient_of_refraction,
|
|
real_vector3d *refraction)
|
|
{
|
|
real refraction_scale;
|
|
|
|
real incident_magnitude = magnitude3d(incident);
|
|
real one_over_incident_magnitude = 1.f / incident_magnitude;
|
|
|
|
real sine_incident = cross_product_magnitude3d(incident, normal) * one_over_incident_magnitude;
|
|
real cosine_incident = dot_product3d(incident, normal) * one_over_incident_magnitude;
|
|
real sine_refraction = coefficient_of_refraction * sine_incident;
|
|
|
|
real cosine_refraction = square_root(1.f - sine_refraction * sine_refraction);
|
|
|
|
real delta = (sine_incident * cosine_refraction + cosine_incident * sine_refraction) / sine_refraction;
|
|
|
|
refraction->i = delta * normal->i + incident->i;
|
|
refraction->j = delta * normal->j + incident->j;
|
|
refraction->k = delta * normal->k + incident->k;
|
|
|
|
refraction_scale = incident_magnitude / magnitude3d(refraction);
|
|
|
|
refraction->i *= refraction_scale;
|
|
refraction->j *= refraction_scale;
|
|
refraction->k *= refraction_scale;
|
|
|
|
return refraction;
|
|
}
|
|
|
|
void quaternion_normalize(
|
|
real_quaternion *q)
|
|
{
|
|
real magnitude_squared = q->v.i*q->v.i + q->v.j*q->v.j + q->v.k*q->v.k + q->w*q->w;
|
|
if (magnitude_squared > 0.f)
|
|
{
|
|
real one_over_magnitude = reciprocal_square_root(magnitude_squared);
|
|
set_real_quaternion(q, one_over_magnitude*q->v.i, one_over_magnitude*q->v.j, one_over_magnitude*q->v.k, one_over_magnitude*q->w);
|
|
}
|
|
else
|
|
{
|
|
set_real_quaternion(q, 0.f, 0.f, 0.f, 1.f);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void quaternion_from_angle_and_vector(
|
|
real_quaternion *q,
|
|
real a,
|
|
real_vector3d const *v)
|
|
{
|
|
real half_angle = a * 0.5f;
|
|
real sine_half_angle = sine(half_angle);
|
|
|
|
q->w = cosine(half_angle);
|
|
q->v.i = sine_half_angle*v->i;
|
|
q->v.j = sine_half_angle*v->j;
|
|
q->v.k = sine_half_angle*v->k;
|
|
|
|
return;
|
|
}
|
|
|
|
void quaternion_to_angle_and_vector(
|
|
real_quaternion const *q,
|
|
real *a,
|
|
real_vector3d *v)
|
|
{
|
|
*v = q->v;
|
|
*a = 2 * arctangent(normalize3d(v), q->w) ;
|
|
|
|
if (*a > _pi)
|
|
{
|
|
negate_vector3d(v, v);
|
|
*a = _pi * 2.0f - *a;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void quaternions_interpolate_and_normalize(
|
|
real_quaternion const *q0,
|
|
real_quaternion const *q1,
|
|
real t,
|
|
real_quaternion *result)
|
|
{
|
|
quaternions_interpolate(q0, q1, t, result);
|
|
quaternion_normalize(result);
|
|
return;
|
|
}
|
|
|
|
void orientations_interpolate(
|
|
real_orientation const *a,
|
|
real_orientation const *b,
|
|
real t,
|
|
real_orientation *result)
|
|
{
|
|
quaternions_interpolate(&a->rotation, &b->rotation, t, &result->rotation);
|
|
quaternion_normalize(&result->rotation);
|
|
|
|
result->translation.x = a->translation.x*(1.f - t) + b->translation.x*t;
|
|
result->translation.y = a->translation.y*(1.f - t) + b->translation.y*t;
|
|
result->translation.z = a->translation.z*(1.f - t) + b->translation.z*t;
|
|
result->scale = a->scale*(1.f - t) + b->scale*t;
|
|
return;
|
|
}
|
|
|
|
real_euler_angles2d *euler_angles2d_from_vector3d(
|
|
real_euler_angles2d *angles,
|
|
real_vector3d const *vector)
|
|
{
|
|
angles->yaw = arctangent(vector->j, vector->i);
|
|
angles->pitch = arctangent(vector->k, square_root(vector->i*vector->i+vector->j*vector->j));
|
|
return angles;
|
|
}
|
|
|
|
real_vector3d *vector3d_from_angle(
|
|
real_vector3d *vector,
|
|
real angle)
|
|
{
|
|
vector->k = 0.f;
|
|
vector->i = cosine(angle);
|
|
vector->j = sine(angle);
|
|
return vector;
|
|
}
|
|
|
|
real_vector3d *vector3d_from_euler_angles2d(
|
|
real_vector3d *vector,
|
|
real_euler_angles2d const *angles)
|
|
{
|
|
real cosine_pitch = cosine(angles->pitch);
|
|
vector->i = cosine(angles->yaw)* cosine_pitch;
|
|
vector->j = sine(angles->yaw)* cosine_pitch;
|
|
vector->k = sine(angles->pitch);
|
|
return vector;
|
|
}
|
|
|
|
boolean point_in_pill2d(
|
|
real_point2d const *point,
|
|
real_point2d const *base,
|
|
real_vector2d const *height,
|
|
real width)
|
|
{
|
|
real_vector2d v;
|
|
real height_magnitude_squared;
|
|
real t;
|
|
|
|
vector_from_points2d(base, point, &v);
|
|
height_magnitude_squared = dot_product2d(&v, height) / magnitude_squared2d(height);
|
|
t = -PIN(height_magnitude_squared, 0.f, 1.f);
|
|
point_from_line2d((real_point2d *)&v, height, t, (real_point2d *)&v);
|
|
|
|
return magnitude_squared2d(&v)<=width*width;
|
|
}
|
|
|
|
real point_to_line_distance_squared3d(
|
|
real_point3d const *point,
|
|
real_point3d const *base,
|
|
real_vector3d const *height)
|
|
{
|
|
real t;
|
|
real distance_squared;
|
|
real_vector3d v;
|
|
|
|
vector_from_points3d(base, point, &v);
|
|
t = PIN(dot_product3d(&v, height) / magnitude_squared3d(height), 0.f, 1.f);
|
|
point_from_line3d((real_point3d *)&v, height, -t, (real_point3d *)&v);
|
|
distance_squared = magnitude_squared3d(&v);
|
|
|
|
return distance_squared;
|
|
}
|
|
|
|
real vector_to_line_distance_squared3d(
|
|
real_point3d const *point,
|
|
real_vector3d const *vector,
|
|
real_point3d const *line_point,
|
|
real_vector3d const *line_vector)
|
|
{
|
|
real_vector3d offset;
|
|
real_vector3d cross;
|
|
real_vector3d numerator_cross0;
|
|
real_vector3d numerator_cross1;
|
|
real denominator;
|
|
real inverse_denominator;
|
|
real dot;
|
|
real vector_magnitude_squared;
|
|
real line_magnitude_squared;
|
|
real inverse_vector_magnitude_squared;
|
|
real inverse_line_magnitude_squared;
|
|
real t0;
|
|
real t1;
|
|
real t0_start;
|
|
real t0_end;
|
|
real t1_start;
|
|
real t1_end;
|
|
real clamped_t0;
|
|
real clamped_t1;
|
|
real d1;
|
|
real d0;
|
|
real_point3d closest_point0;
|
|
real_point3d closest_point1;
|
|
real_vector3d closest_offset;
|
|
boolean t0_out_of_range;
|
|
boolean t1_out_of_range;
|
|
|
|
vector_from_points3d(point, line_point, &offset);
|
|
cross_product3d(vector, line_vector, &cross);
|
|
denominator = magnitude_squared3d_right_associated(&cross);
|
|
if (!(fabs(denominator) < _real_epsilon))
|
|
{
|
|
inverse_denominator = 1.0f / denominator;
|
|
scale_vector3d(&cross, inverse_denominator, &cross);
|
|
cross_product3d(&offset, line_vector, &numerator_cross0);
|
|
t0 = dot_product3d(&numerator_cross0, &cross);
|
|
cross_product3d(&offset, vector, &numerator_cross1);
|
|
t1 = dot_product3d(&numerator_cross1, &cross);
|
|
t0_out_of_range = t0 < 0.0f || t0 > 1.0f;
|
|
t1_out_of_range = t1 < 0.0f || t1 > 1.0f;
|
|
if (t0_out_of_range || t1_out_of_range)
|
|
{
|
|
d0 = REAL_MAX;
|
|
d1 = REAL_MAX;
|
|
if (t0_out_of_range)
|
|
{
|
|
clamped_t0 = t0 < 0.0f ? 0.0f : 1.0f;
|
|
point_from_line3d(point, vector, clamped_t0, &closest_point0);
|
|
d0 = point_to_line_distance_squared3d(
|
|
&closest_point0,
|
|
line_point,
|
|
line_vector);
|
|
}
|
|
if (t1_out_of_range)
|
|
{
|
|
clamped_t1 = t1 < 0.0f ? 0.0f : 1.0f;
|
|
point_from_line3d(line_point, line_vector, clamped_t1, &closest_point1);
|
|
d1 = point_to_line_distance_squared3d(
|
|
&closest_point1,
|
|
point,
|
|
vector);
|
|
}
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
942,
|
|
(d0 < REAL_MAX) || (d1 < REAL_MAX));
|
|
return d0 > d1 ? d1 : d0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dot = dot_product3d(vector, line_vector);
|
|
vector_magnitude_squared = magnitude_squared3d(vector);
|
|
if (vector_magnitude_squared > _real_epsilon)
|
|
{
|
|
inverse_vector_magnitude_squared = 1.0f / vector_magnitude_squared;
|
|
t0_start = offset.k * vector->k;
|
|
t0_start += offset.j * vector->j;
|
|
t0_start += offset.i * vector->i;
|
|
t0_start *= inverse_vector_magnitude_squared;
|
|
t0_end =
|
|
inverse_vector_magnitude_squared * dot +
|
|
t0_start;
|
|
t0 =
|
|
(PIN(t0_start, 0.0f, 1.0f) +
|
|
PIN(t0_end, 0.0f, 1.0f)) *
|
|
0.5f;
|
|
}
|
|
else
|
|
{
|
|
t0 = 0.0f;
|
|
}
|
|
|
|
line_magnitude_squared = magnitude_squared3d(line_vector);
|
|
if (line_magnitude_squared > _real_epsilon)
|
|
{
|
|
inverse_line_magnitude_squared = 1.0f / line_magnitude_squared;
|
|
t1_start =
|
|
-dot_product3d(&offset, line_vector) *
|
|
inverse_line_magnitude_squared;
|
|
t1_end =
|
|
inverse_line_magnitude_squared * dot +
|
|
t1_start;
|
|
t1 =
|
|
(PIN(t1_start, 0.0f, 1.0f) +
|
|
PIN(t1_end, 0.0f, 1.0f)) *
|
|
0.5f;
|
|
}
|
|
else
|
|
{
|
|
t1 = 0.0f;
|
|
}
|
|
}
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
986,
|
|
(t0 >= 0.0f) && (t0 <= 1.0f));
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\math\\real_math.c",
|
|
987,
|
|
(t1 >= 0.0f) && (t1 <= 1.0f));
|
|
point_from_line3d(point, vector, t0, &closest_point0);
|
|
point_from_line3d(line_point, line_vector, t1, &closest_point1);
|
|
vector_from_points3d(&closest_point0, &closest_point1, &closest_offset);
|
|
return magnitude_squared3d(&closest_offset);
|
|
}
|
|
|
|
|
|
boolean sphere_test_vector3d(
|
|
real_point3d const *center,
|
|
real radius,
|
|
real_point3d const *point,
|
|
real_vector3d const *vector,
|
|
real *t,
|
|
real_vector3d *normal)
|
|
{
|
|
real_vector3d x;
|
|
real xv;
|
|
|
|
vector_from_points3d(center, point, &x);
|
|
xv = dot_product3d(&x, vector);
|
|
|
|
if (xv < 0)
|
|
{
|
|
real xx = magnitude_squared3d(&x);
|
|
real xx_rr = xx - radius*radius;
|
|
|
|
if (xx_rr <= 0)
|
|
{
|
|
*t = 0;
|
|
scale_vector3d(&x, reciprocal_square_root(xx), normal);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
real d = vector->i*vector->i + vector->j*vector->j + vector->k*vector->k;
|
|
real vv = xv*xv - d*xx_rr;
|
|
|
|
if (vv >= 0)
|
|
{
|
|
real n = -(square_root(vv) + xv);
|
|
|
|
if (n <= d)
|
|
{
|
|
*t = n/d;
|
|
fast_normalize3d((real_vector3d *)point_from_line3d((real_point3d *)&x, vector, *t, (real_point3d *)normal));
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
boolean pill_test_vector3d(
|
|
real_point3d const *base,
|
|
real height,
|
|
real radius,
|
|
real_point3d const *point,
|
|
real_vector3d const *vector,
|
|
real *t,
|
|
real_vector3d *normal)
|
|
{
|
|
real_vector2d x;
|
|
real xv;
|
|
real xx_rr;
|
|
real d;
|
|
real vv;
|
|
real n;
|
|
real height_fraction;
|
|
real top_z;
|
|
real_point3d top;
|
|
boolean result = FALSE;
|
|
|
|
x.i = point->x - base->x;
|
|
x.j = point->y - base->y;
|
|
xv = x.i * vector->i + x.j * vector->j;
|
|
xx_rr = x.i * x.i + x.j * x.j - radius * radius;
|
|
if (xx_rr <= 0.0f)
|
|
{
|
|
n = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
d = vector->i * vector->i + vector->j * vector->j;
|
|
vv = xv * xv - d * xx_rr;
|
|
if (vv >= 0.0f)
|
|
{
|
|
n = -(square_root(vv) + xv);
|
|
if (n <= d)
|
|
{
|
|
n = n / d;
|
|
}
|
|
else
|
|
{
|
|
goto done;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
result = TRUE;
|
|
height_fraction =
|
|
(point->z - base->z + n * vector->k) / (height * height);
|
|
if (height_fraction < 0.0f)
|
|
{
|
|
result = sphere_test_vector3d(base, radius, point, vector, t, normal);
|
|
}
|
|
else if (height_fraction > 1.0f)
|
|
{
|
|
top_z = base->z + height;
|
|
top.x = base->x;
|
|
top.y = base->y;
|
|
top.z = top_z;
|
|
result = sphere_test_vector3d(&top, radius, point, vector, t, normal);
|
|
}
|
|
else if (xv < 0.0f)
|
|
{
|
|
*t = n;
|
|
normal->i = x.i + n * vector->i;
|
|
normal->j = x.j + n * vector->j;
|
|
fast_normalize2d((real_vector2d *)normal);
|
|
normal->k = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
result = FALSE;
|
|
}
|
|
|
|
if (result && dot_product3d(normal, vector) > 0.0f)
|
|
{
|
|
result = FALSE;
|
|
}
|
|
|
|
done:
|
|
return result;
|
|
}
|
|
|
|
boolean point_from_planes3d(
|
|
real_plane3d const *plane0,
|
|
real_plane3d const *plane1,
|
|
real_plane3d const *plane2,
|
|
real_point3d *point)
|
|
{
|
|
real_vector3d cross;
|
|
real determinant;
|
|
real distance;
|
|
|
|
cross_product3d(&plane0->n, &plane1->n, &cross);
|
|
determinant = dot_product3d(&cross, &plane2->n);
|
|
if (!(fabs(determinant) < _real_epsilon))
|
|
{
|
|
cross_product3d(&plane1->n, &plane2->n, &cross);
|
|
distance = plane0->d;
|
|
point->x = cross.i * distance;
|
|
point->y = cross.j * distance;
|
|
point->z = cross.k * distance;
|
|
|
|
distance =
|
|
(cross_product3d(&plane2->n, &plane0->n, &cross),
|
|
plane1->d);
|
|
point->x = cross.i * distance + point->x;
|
|
point->y = cross.j * distance + point->y;
|
|
point->z = cross.k * distance + point->z;
|
|
|
|
distance =
|
|
(cross_product3d(&plane0->n, &plane1->n, &cross),
|
|
plane2->d);
|
|
determinant = 1.0f / determinant;
|
|
point->x = (cross.i * distance + point->x) * determinant;
|
|
point->y = (cross.j * distance + point->y) * determinant;
|
|
point->z = (cross.k * distance + point->z) * determinant;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
boolean line_from_planes3d(
|
|
real_plane3d const *plane0,
|
|
real_plane3d const *plane1,
|
|
real_point3d *point,
|
|
real_vector3d *direction)
|
|
{
|
|
real_vector3d local_direction;
|
|
real determinant;
|
|
real inverse_determinant;
|
|
real distance;
|
|
|
|
cross_product3d(&plane0->n, &plane1->n, direction);
|
|
determinant = magnitude_squared3d(direction);
|
|
if (!(fabs(determinant) < _real_epsilon))
|
|
{
|
|
cross_product3d(&plane1->n, direction, &local_direction);
|
|
distance = plane0->d;
|
|
point->x = local_direction.i * distance;
|
|
point->y = local_direction.j * distance;
|
|
point->z = local_direction.k * distance;
|
|
|
|
distance =
|
|
(cross_product3d(direction, &plane0->n, &local_direction),
|
|
plane1->d);
|
|
inverse_determinant = 1.0f / determinant;
|
|
point->x =
|
|
(local_direction.i * distance + point->x) *
|
|
inverse_determinant;
|
|
point->y =
|
|
(local_direction.j * distance + point->y) *
|
|
inverse_determinant;
|
|
point->z =
|
|
(local_direction.k * distance + point->z) *
|
|
inverse_determinant;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void angular_accelerate_to_position(
|
|
real_vector3d *position,
|
|
real_vector3d const *position_desired,
|
|
real_vector3d *angular_velocity,
|
|
real angular_velocity_magnitude_maximum,
|
|
real angular_acceleration_magnitude_maximum)
|
|
{
|
|
real cosine_value;
|
|
real speed;
|
|
real speed_squared;
|
|
real_vector3d axis;
|
|
real_vector3d delta;
|
|
real delta_magnitude_squared;
|
|
real angle;
|
|
|
|
if (angular_acceleration_magnitude_maximum <= 0.0f &&
|
|
angular_velocity_magnitude_maximum <= 0.0f)
|
|
{
|
|
*angular_velocity = *global_zero_vector3d;
|
|
*position = *position_desired;
|
|
return;
|
|
}
|
|
|
|
cosine_value = dot_product3d(position, position_desired);
|
|
if (cosine_value < -1.0f)
|
|
{
|
|
cosine_value = -1.0f;
|
|
}
|
|
else if (cosine_value > 1.0f)
|
|
{
|
|
cosine_value = 1.0f;
|
|
}
|
|
|
|
speed_squared = arccosine(cosine_value);
|
|
speed_squared =
|
|
speed_squared * angular_acceleration_magnitude_maximum +
|
|
speed_squared * angular_acceleration_magnitude_maximum;
|
|
if (speed_squared >=
|
|
angular_velocity_magnitude_maximum *
|
|
angular_velocity_magnitude_maximum)
|
|
{
|
|
speed = angular_velocity_magnitude_maximum;
|
|
}
|
|
else
|
|
{
|
|
speed = square_root(speed_squared);
|
|
}
|
|
|
|
cross_product3d(position, position_desired, &axis);
|
|
normalize3d(&axis);
|
|
|
|
scale_vector3d(&axis, speed, &axis);
|
|
subtract_vectors3d(&axis, angular_velocity, &delta);
|
|
delta_magnitude_squared = magnitude_squared3d(&delta);
|
|
if (delta_magnitude_squared <
|
|
angular_acceleration_magnitude_maximum *
|
|
angular_acceleration_magnitude_maximum)
|
|
{
|
|
if (speed < 1.0000001e-6f)
|
|
{
|
|
*angular_velocity = *global_zero_vector3d;
|
|
*position = *position_desired;
|
|
return;
|
|
}
|
|
*angular_velocity = axis;
|
|
}
|
|
else
|
|
{
|
|
angular_acceleration_magnitude_maximum =
|
|
angular_acceleration_magnitude_maximum /
|
|
square_root(delta_magnitude_squared);
|
|
angular_velocity->i =
|
|
delta.i * angular_acceleration_magnitude_maximum +
|
|
angular_velocity->i;
|
|
angular_velocity->j =
|
|
delta.j * angular_acceleration_magnitude_maximum +
|
|
angular_velocity->j;
|
|
angular_velocity->k =
|
|
delta.k * angular_acceleration_magnitude_maximum +
|
|
angular_velocity->k;
|
|
}
|
|
|
|
axis = *angular_velocity;
|
|
angle = normalize3d(&axis);
|
|
if (angle != 0.0f)
|
|
{
|
|
rotate_vector_about_axis(position, &axis, sine(angle), cosine(angle));
|
|
normalize3d(position);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
boolean accelerate_to_velocity3d(
|
|
real_vector3d *velocity,
|
|
real_vector3d const *target_velocity,
|
|
real acceleration)
|
|
{
|
|
real_vector3d delta;
|
|
boolean result;
|
|
|
|
subtract_vectors3d(target_velocity, velocity, &delta);
|
|
if (limit3d(&delta, acceleration))
|
|
{
|
|
add_vectors3d(velocity, &delta, velocity);
|
|
result = FALSE;
|
|
}
|
|
else
|
|
{
|
|
*velocity = *target_velocity;
|
|
result = TRUE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean accerate_to_position3d(
|
|
real_point3d *position,
|
|
real_vector3d *velocity,
|
|
real_point3d const *target_position,
|
|
long unused,
|
|
real maximum_length)
|
|
{
|
|
volatile real delta[3];
|
|
real magnitude;
|
|
real scale;
|
|
|
|
delta[0] = target_position->x - position->x;
|
|
delta[1] = target_position->y - position->y;
|
|
delta[2] = target_position->z - position->z;
|
|
magnitude = normalize3d((real_vector3d *)(real *)delta);
|
|
if (magnitude == 0.0f)
|
|
{
|
|
delta[0] = 0.0f;
|
|
delta[1] = 0.0f;
|
|
delta[2] = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
scale = square_root(
|
|
magnitude * maximum_length +
|
|
magnitude * maximum_length);
|
|
delta[0] = delta[0] * scale;
|
|
delta[1] = delta[1] * scale;
|
|
delta[2] = delta[2] * scale;
|
|
}
|
|
|
|
if (accelerate_to_velocity3d(
|
|
velocity,
|
|
(real_vector3d *)(real *)delta,
|
|
maximum_length) &&
|
|
magnitude == 0.0f)
|
|
{
|
|
*position = *target_position;
|
|
return TRUE;
|
|
}
|
|
|
|
position->x = position->x + velocity->i;
|
|
position->y = velocity->j + position->y;
|
|
position->z = velocity->k + position->z;
|
|
return FALSE;
|
|
}
|
|
|
|
boolean accelerate_to_position(
|
|
real *position,
|
|
real *velocity,
|
|
real target_position,
|
|
real maximum_velocity,
|
|
real acceleration,
|
|
real minimum_position,
|
|
real maximum_position,
|
|
boolean periodic)
|
|
{
|
|
real current_position;
|
|
real current_velocity;
|
|
real delta;
|
|
real half_range;
|
|
real limit;
|
|
real speed;
|
|
real braking_distance;
|
|
real step_clamped;
|
|
real new_position;
|
|
real output_position;
|
|
real acceleration_squared;
|
|
boolean result;
|
|
|
|
current_position = *position;
|
|
current_velocity = *velocity;
|
|
acceleration_squared = acceleration * acceleration;
|
|
result = FALSE;
|
|
delta = target_position - current_position;
|
|
|
|
if (periodic)
|
|
{
|
|
half_range = (maximum_position - minimum_position) * 0.5f;
|
|
if (delta > half_range)
|
|
{
|
|
delta = delta - (half_range + half_range);
|
|
}
|
|
else if (delta < -half_range)
|
|
{
|
|
delta = half_range + half_range + delta;
|
|
}
|
|
}
|
|
|
|
limit = MIN(maximum_velocity, acceleration);
|
|
|
|
if (fabs(delta - current_velocity) <= limit)
|
|
{
|
|
current_velocity = 0.0f;
|
|
output_position = target_position;
|
|
if (target_position < minimum_position)
|
|
output_position = minimum_position;
|
|
else if (target_position > maximum_position)
|
|
output_position = maximum_position;
|
|
result = TRUE;
|
|
}
|
|
else
|
|
{
|
|
braking_distance = (maximum_velocity + maximum_velocity) * fabs(delta);
|
|
if (braking_distance >= acceleration_squared)
|
|
speed = acceleration;
|
|
else
|
|
speed = square_root(braking_distance);
|
|
if (delta < 0.0f)
|
|
speed = -speed;
|
|
step_clamped = speed - current_velocity;
|
|
if (fabs(step_clamped) > maximum_velocity)
|
|
{
|
|
if (step_clamped < 0.0f)
|
|
step_clamped = -maximum_velocity;
|
|
else
|
|
step_clamped = maximum_velocity;
|
|
}
|
|
current_velocity = current_velocity + step_clamped;
|
|
new_position = step_clamped * 0.5f + current_velocity + current_position;
|
|
if (periodic)
|
|
{
|
|
if (new_position < minimum_position)
|
|
new_position = maximum_position - minimum_position + new_position;
|
|
else if (new_position > maximum_position)
|
|
new_position = new_position - (maximum_position - minimum_position);
|
|
}
|
|
if (new_position < minimum_position)
|
|
new_position = minimum_position;
|
|
else if (new_position > maximum_position)
|
|
new_position = maximum_position;
|
|
output_position = new_position;
|
|
}
|
|
|
|
*velocity = current_velocity;
|
|
*position = output_position;
|
|
return result;
|
|
}
|
|
|
|
void accelerate_to_velocity(
|
|
real *position,
|
|
real *velocity,
|
|
real acceleration,
|
|
real target_velocity,
|
|
real minimum_position,
|
|
real maximum_position,
|
|
boolean periodic)
|
|
{
|
|
if (periodic)
|
|
{
|
|
real new_position = *position;
|
|
real new_velocity = *velocity;
|
|
real delta = target_velocity - new_velocity;
|
|
|
|
if (fabs(delta) > acceleration)
|
|
{
|
|
if (delta < 0.0f)
|
|
delta = -acceleration;
|
|
else
|
|
delta = acceleration;
|
|
}
|
|
|
|
new_velocity += delta;
|
|
new_position += new_velocity + delta * 0.5f;
|
|
if (new_position < minimum_position || new_position > maximum_position)
|
|
{
|
|
new_position = fmod(
|
|
new_position - minimum_position,
|
|
maximum_position - minimum_position) - minimum_position;
|
|
}
|
|
|
|
*position = new_position;
|
|
*velocity = new_velocity;
|
|
}
|
|
else
|
|
{
|
|
accelerate_to_position(
|
|
position,
|
|
velocity,
|
|
target_velocity < 0.0f ? minimum_position : maximum_position,
|
|
acceleration,
|
|
fabs(target_velocity),
|
|
minimum_position,
|
|
maximum_position,
|
|
FALSE);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
boolean valid_real_sine_cosine(
|
|
real sine,
|
|
real cosine)
|
|
{
|
|
return valid_realcmp(sine * sine + cosine * cosine, 1.0f);
|
|
}
|
|
|
|
/* ---------- private code */
|