mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-17 15:00:27 +02:00
2334 lines
73 KiB
C
2334 lines
73 KiB
C
/*
|
|
PHYSICS.C
|
|
|
|
symbols in this file:
|
|
0013FF60 0080:
|
|
_pin_fraction (0000)
|
|
0013FFE0 00b0:
|
|
_physics_get_features_in_sphere (0000)
|
|
00140090 0070:
|
|
_code_00140090 (0000)
|
|
00140100 0110:
|
|
_render_debug_physics (0000)
|
|
00140210 0100:
|
|
_physics_instance_new (0000)
|
|
00140310 00a0:
|
|
_physics_test_point (0000)
|
|
001403B0 0120:
|
|
_physics_test_vector (0000)
|
|
001404D0 0150:
|
|
_code_001404d0 (0000)
|
|
00140620 0100:
|
|
_code_00140620 (0000)
|
|
00140720 0b80:
|
|
_physics_compute_new (0000)
|
|
001412A0 0470:
|
|
_code_001412a0 (0000)
|
|
00141710 0490:
|
|
_code_00141710 (0000)
|
|
00141BA0 0180:
|
|
_code_00141ba0 (0000)
|
|
00141D20 01b0:
|
|
_code_00141d20 (0000)
|
|
00141ED0 07c0:
|
|
_physics_update_new (0000)
|
|
00142690 1430:
|
|
_code_00142690 (0000)
|
|
00143AC0 0260:
|
|
_physics_update (0000)
|
|
0028BC20 008d:
|
|
??_C@_0IN@ODNFDOFI@mass_point?9?$DOground_material_type@ (0000)
|
|
0028BCB0 0021:
|
|
??_C@_0CB@OHGIJBLL@c?3?2halo?2SOURCE?2physics?2physics?4c@ (0000)
|
|
0028BCD4 0004:
|
|
__real@45ea6000 (0000)
|
|
0028BCD8 0057:
|
|
??_C@_0FH@DDOACPI@unit_definition?9?$DOunit?4blip_type?$DO@ (0000)
|
|
0028BD30 0015:
|
|
??_C@_0BF@GMDJIBPD@model_instance_valid?$AA@ (0000)
|
|
0028BD48 0010:
|
|
??_C@_0BA@LNKGLGKJ@rotated_forward?$AA@ (0000)
|
|
0028BD58 000b:
|
|
??_C@_0L@GBBDLPMF@rotated_up?$AA@ (0000)
|
|
0028BD64 000f:
|
|
??_C@_0P@OGJNHPDG@up?$CB?$DNrotated_up?$AA@ (0000)
|
|
0028BD74 0019:
|
|
??_C@_0BJ@GEGCJHGH@forward?$CB?$DNrotated_forward?$AA@ (0000)
|
|
0028BD90 0004:
|
|
__real@364c6ce0 (0000)
|
|
0028BD94 0004:
|
|
__real@34a5b36e (0000)
|
|
0028BD98 0004:
|
|
__real@3b33abb1 (0000)
|
|
0028BDA0 0008:
|
|
__real@3f80000000000000 (0000)
|
|
0028BDA8 0012:
|
|
??_C@_0BC@MDPNAJDL@?$CGangular_velocity?$AA@ (0000)
|
|
0028BDBC 0016:
|
|
??_C@_0BG@NPNNHCFI@?$CGangular_acceleration?$AA@ (0000)
|
|
0028BDD4 0011:
|
|
??_C@_0BB@IHCLBKLO@?$CGlinear_velocity?$AA@ (0000)
|
|
0028BDE8 0015:
|
|
??_C@_0BF@LNOJMOGI@?$CGlinear_acceleration?$AA@ (0000)
|
|
0028BE00 001d:
|
|
??_C@_0BN@FOPAIIBD@instance?9?$DOphysics?9?$DOmass?$DO0?40f?$AA@ (0000)
|
|
0028BE20 0018:
|
|
??_C@_0BI@HOJEHDKE@?$CGobject?9?$DOobject?4forward?$AA@ (0000)
|
|
0028BE38 0013:
|
|
??_C@_0BD@JHPMDDBM@?$CGobject?9?$DOobject?4up?$AA@ (0000)
|
|
0028BE4C 001c:
|
|
??_C@_0BM@EKBNDJOG@?$CGtranslational_acceleration?$AA@ (0000)
|
|
0028BE68 000d:
|
|
??_C@_0N@EMPCNLII@magic_torque?$AA@ (0000)
|
|
0028BE78 000c:
|
|
??_C@_0M@LNGNIFCJ@magic_force?$AA@ (0000)
|
|
0030CEB4 002c:
|
|
_global_gravity (0000)
|
|
_global_water_density (0004)
|
|
_global_air_density (0008)
|
|
_global_physics_collision_depth (000c)
|
|
_depths_of_hell (0010)
|
|
0045E01A 0001:
|
|
_debug_physics_disable_penetration_freeze (0000)
|
|
*/
|
|
|
|
/* ---------- headers */
|
|
|
|
#include "cseries.h"
|
|
#include "cseries/errors.h" /* port: error */
|
|
#include "physics.h"
|
|
|
|
#include "collision_features.h"
|
|
#include "collision_models.h"
|
|
#include "collisions.h"
|
|
#include "effects/material_effect_definitions.h"
|
|
#include "game/game.h"
|
|
#include "game/game_globals.h"
|
|
#include "math/real_math.h"
|
|
#include "objects/damage.h"
|
|
#include "objects/object_definitions.h"
|
|
#include "objects/object_types.h"
|
|
#include "objects/objects.h"
|
|
#include "collision_model_definitions.h"
|
|
#include "physics_definitions.h"
|
|
#include "render/render_debug.h"
|
|
#include "scenario/scenario.h"
|
|
#include "structures/structure_bsp_definitions.h"
|
|
#include "units/bipeds.h"
|
|
#include "units/unit_definitions.h"
|
|
#include "units/vehicles.h"
|
|
|
|
/* ---------- constants */
|
|
|
|
enum
|
|
{
|
|
_collision_surface_two_sided_bit = 0,
|
|
_collision_surface_invisible_bit,
|
|
_collision_surface_climbable_bit,
|
|
_collision_surface_breakable_bit,
|
|
};
|
|
|
|
enum
|
|
{
|
|
_friction_type_point = 0,
|
|
_friction_type_forward,
|
|
_friction_type_left,
|
|
_friction_type_up,
|
|
NUMBER_OF_FRICTION_TYPES
|
|
};
|
|
|
|
enum
|
|
{
|
|
_point_at_rest_bit = 0,
|
|
_point_on_ground_bit,
|
|
_point_on_volatile_surface_bit,
|
|
_point_in_water_bit,
|
|
_point_antigraving_bit,
|
|
NUMBER_OF_MASS_POINT_FLAGS
|
|
};
|
|
|
|
enum
|
|
{
|
|
_powered_mass_point_ground_friction_bit = 0,
|
|
_powered_mass_point_water_friction_bit,
|
|
_powered_mass_point_air_friction_bit,
|
|
_powered_mass_point_water_lift_bit,
|
|
_powered_mass_point_air_lift_bit,
|
|
_powered_mass_point_thrust_bit,
|
|
_powered_mass_point_antigrav_bit,
|
|
NUMBER_OF_POWERED_MASS_POINT_FLAGS
|
|
};
|
|
|
|
/* ---------- macros */
|
|
|
|
/* January's physics.c expands point_from_line3d in place for points and
|
|
* vectors alike; this scalar expansion preserves that inline schedule without
|
|
* selecting the external point_from_line3d COMDAT for this object (the same
|
|
* emitted-symbol invariant as COLLISION_POINT_FROM_LINE3D in collisions.c). */
|
|
#define PHYSICS_POINT_FROM_LINE3D(point, vector, distance, result) \
|
|
do \
|
|
{ \
|
|
real *line_result = (result)->n; \
|
|
real line_distance = (distance); \
|
|
real const *line_vector = (vector)->n; \
|
|
real const *line_point = (point)->n; \
|
|
line_result[0] = line_vector[0] * line_distance + line_point[0]; \
|
|
line_result[1] = line_vector[1] * line_distance + line_point[1]; \
|
|
line_result[2] = line_vector[2] * line_distance + line_point[2]; \
|
|
} while (0)
|
|
|
|
/* ---------- structures */
|
|
|
|
struct powered_mass_point_definition
|
|
{
|
|
char name[32];
|
|
unsigned long flags;
|
|
real antigrav_strength;
|
|
real antigrav_offset;
|
|
real antigrav_height;
|
|
real antigrav_damp_fraction;
|
|
real antigrav_normal_k1;
|
|
real antigrav_normal_k0;
|
|
real unused[17];
|
|
};
|
|
|
|
#include "friction_datum.h"
|
|
|
|
#include "powered_mass_point_datum.h"
|
|
|
|
#include "mass_point_datum.h"
|
|
|
|
#include "units/vehicle_datum.h"
|
|
|
|
/* TU-local copy: no shared header declares the game globals falling-damage
|
|
* block yet; identical complete copies live in objects/damage.c and
|
|
* units/bipeds.c. */
|
|
struct game_globals_falling_damage
|
|
{
|
|
long unused0[2];
|
|
real falling_distance_lower_bound;
|
|
real falling_distance_upper_bound;
|
|
struct tag_reference falling_damage;
|
|
long terminal_velocity_unused[2];
|
|
real maximum_distance;
|
|
struct tag_reference maximum_distance_damage;
|
|
struct tag_reference vehicle_hit_environment_damage_effect;
|
|
struct tag_reference vehicle_killed_unit_damage_effect;
|
|
struct tag_reference vehicle_collision_damage;
|
|
struct tag_reference flaming_death_damage;
|
|
long unused7c[4];
|
|
real runtime_maximum_falling_velocity;
|
|
real runtime_minimum_damage_velocity;
|
|
real runtime_maximum_damage_velocity;
|
|
};
|
|
|
|
typedef char game_globals_falling_damage_size_assert[
|
|
sizeof(struct game_globals_falling_damage) == 0x98 ? 1 : -1];
|
|
|
|
typedef char powered_mass_point_definition_size_assert[
|
|
sizeof(struct powered_mass_point_definition) == 0x80 ? 1 : -1];
|
|
typedef char powered_mass_point_datum_size_assert[
|
|
sizeof(struct powered_mass_point_datum) == 0x60 ? 1 : -1];
|
|
typedef char mass_point_datum_size_assert[
|
|
sizeof(struct mass_point_datum) == 0x130 ? 1 : -1];
|
|
|
|
/* ---------- prototypes */
|
|
|
|
static short physics_mass_point_count(
|
|
struct physics_definition const *physics);
|
|
static short physics_powered_mass_point_count(
|
|
struct physics_definition const *physics);
|
|
static short physics_powered_mass_point_index(
|
|
struct physics_definition const *physics,
|
|
struct mass_point_definition const *mass_point_definition);
|
|
static short get_material_type(
|
|
long object_index,
|
|
short material_index);
|
|
static void compute_ground_plane(
|
|
long object_index,
|
|
struct mass_point_datum *mass_point,
|
|
struct mass_point_definition const *mass_point_definition);
|
|
static void friction_evaluate(
|
|
short friction_type,
|
|
real parallel_scale,
|
|
real perpendicular_scale,
|
|
struct friction_datum *friction,
|
|
real_vector3d const *forward,
|
|
real_vector3d const *up);
|
|
static boolean physics_compute_biped_collision(
|
|
struct collision_model_instance *instance,
|
|
long biped_index);
|
|
static boolean physics_compute_vehicle_collision(
|
|
struct physics_instance const *instance0,
|
|
struct physics_instance const *instance1);
|
|
static void physics_compute_unit_collisions(
|
|
long vehicle_index);
|
|
void physics_update_new(
|
|
struct physics_instance const *instance,
|
|
struct powered_mass_point_datum const *powered_mass_points,
|
|
struct mass_point_datum const *mass_points,
|
|
real_vector3d const *total_force,
|
|
real_vector3d const *total_torque);
|
|
static void physics_update_old(
|
|
long object_index,
|
|
struct powered_mass_point_datum *powered_mass_points,
|
|
struct mass_point_datum *mass_points,
|
|
real_vector3d const *magic_force,
|
|
real_vector3d const *magic_torque);
|
|
static void rotate_vectors3d_by_angular_velocity(
|
|
real_vector3d const *forward,
|
|
real_vector3d const *up,
|
|
real_vector3d const *angular_velocity,
|
|
real_vector3d *rotated_forward,
|
|
real_vector3d *rotated_up);
|
|
|
|
/* ---------- globals */
|
|
|
|
real global_gravity = 0.0035651792f;
|
|
real global_water_density = 1.0f;
|
|
real global_air_density = 0.0011f;
|
|
real global_physics_collision_depth = 0.2f;
|
|
real_plane3d depths_of_hell =
|
|
{
|
|
{ 0.0f, 0.0f, 1.0f },
|
|
-256.0f
|
|
};
|
|
|
|
boolean debug_physics_disable_penetration_freeze = FALSE;
|
|
|
|
/* port: whether a map's malformed physics was reported (once) */
|
|
static boolean warned_about_physics_mass_points;
|
|
static boolean warned_about_physics_inertial_matrix;
|
|
|
|
/* ---------- public code */
|
|
|
|
real pin_fraction(
|
|
real value,
|
|
real begin,
|
|
real end)
|
|
{
|
|
if (begin < end)
|
|
{
|
|
if (value <= begin)
|
|
return 0.0f;
|
|
else if (value >= end)
|
|
return 1.0f;
|
|
else
|
|
return (value - begin) / (end - begin);
|
|
}
|
|
else
|
|
{
|
|
if (value <= end)
|
|
return 1.0f;
|
|
else if (value >= begin)
|
|
return 0.0f;
|
|
else
|
|
return (begin - value) / (begin - end);
|
|
}
|
|
}
|
|
|
|
/* port: how many of a physics' mass points (from the map) are used: at
|
|
most MAXIMUM_MASS_POINTS_PER_PHYSICS (the rest are not, reported once) */
|
|
static short physics_mass_point_count(
|
|
struct physics_definition const *physics)
|
|
{
|
|
long count = physics->mass_points.count;
|
|
|
|
if (count > MAXIMUM_MASS_POINTS_PER_PHYSICS)
|
|
{
|
|
if (!warned_about_physics_mass_points)
|
|
{
|
|
error(_error_silent, "a physics has %ld mass points (maximum %d)",
|
|
count,
|
|
MAXIMUM_MASS_POINTS_PER_PHYSICS);
|
|
warned_about_physics_mass_points = TRUE;
|
|
}
|
|
count = MAXIMUM_MASS_POINTS_PER_PHYSICS;
|
|
}
|
|
|
|
return (short)MAX(count, 0);
|
|
}
|
|
|
|
/* port: (as physics_mass_point_count, with
|
|
MAXIMUM_POWERED_MASS_POINTS_PER_PHYSICS) */
|
|
static short physics_powered_mass_point_count(
|
|
struct physics_definition const *physics)
|
|
{
|
|
long count = physics->powered_mass_points.count;
|
|
|
|
if (count > MAXIMUM_POWERED_MASS_POINTS_PER_PHYSICS)
|
|
{
|
|
if (!warned_about_physics_mass_points)
|
|
{
|
|
error(_error_silent, "a physics has %ld powered mass points (maximum %d)",
|
|
count,
|
|
MAXIMUM_POWERED_MASS_POINTS_PER_PHYSICS);
|
|
warned_about_physics_mass_points = TRUE;
|
|
}
|
|
count = MAXIMUM_POWERED_MASS_POINTS_PER_PHYSICS;
|
|
}
|
|
|
|
return (short)MAX(count, 0);
|
|
}
|
|
|
|
/* port: a mass point's powered mass point (from the map), NONE if it
|
|
names none of the physics' used ones (physics_powered_mass_point_count) */
|
|
static short physics_powered_mass_point_index(
|
|
struct physics_definition const *physics,
|
|
struct mass_point_definition const *mass_point_definition)
|
|
{
|
|
short powered_mass_point_index = mass_point_definition->powered_mass_point_index;
|
|
|
|
if (powered_mass_point_index != NONE &&
|
|
(powered_mass_point_index < 0 ||
|
|
powered_mass_point_index >= physics_powered_mass_point_count(physics)))
|
|
{
|
|
if (!warned_about_physics_mass_points)
|
|
{
|
|
error(_error_silent, "a mass point's powered mass point #%d is not one of its physics' %ld",
|
|
powered_mass_point_index,
|
|
physics->powered_mass_points.count);
|
|
warned_about_physics_mass_points = TRUE;
|
|
}
|
|
powered_mass_point_index = NONE;
|
|
}
|
|
|
|
return powered_mass_point_index;
|
|
}
|
|
|
|
boolean physics_get_features_in_sphere(
|
|
struct physics_instance const *instance,
|
|
real_point3d const *center,
|
|
real radius,
|
|
real height,
|
|
real width,
|
|
struct collision_feature_list *features)
|
|
{
|
|
short mass_point_index;
|
|
real scaled_radius;
|
|
/* port: (physics_mass_point_count) */
|
|
short mass_point_count = physics_mass_point_count(instance->physics);
|
|
|
|
for (mass_point_index = 0;
|
|
mass_point_index < mass_point_count;
|
|
mass_point_index++)
|
|
{
|
|
struct mass_point_definition const *mass_point = TAG_BLOCK_GET_ELEMENT(
|
|
&instance->physics->mass_points,
|
|
mass_point_index,
|
|
struct mass_point_definition);
|
|
real_point3d point;
|
|
|
|
matrix4x3_transform_point(&instance->world_matrix, &mass_point->position, &point);
|
|
|
|
scaled_radius = mass_point->radius * instance->world_matrix.scale;
|
|
|
|
collision_features_from_point(
|
|
&point,
|
|
height,
|
|
scaled_radius + width,
|
|
instance->object_index,
|
|
NONE,
|
|
0,
|
|
NONE,
|
|
NONE,
|
|
features);
|
|
}
|
|
|
|
return features->count[_collision_feature_sphere] ||
|
|
features->count[_collision_feature_cylinder] ||
|
|
features->count[_collision_feature_prism];
|
|
}
|
|
|
|
static short get_material_type(
|
|
long object_index,
|
|
short material_index)
|
|
{
|
|
short material_type = NONE;
|
|
|
|
if (material_index != NONE)
|
|
{
|
|
if (object_index != NONE)
|
|
{
|
|
struct object_datum *object = object_get(object_index);
|
|
struct object_definition *definition = object_definition_get(object->definition_index);
|
|
|
|
/* port: (as in collision_model_get_material_type) */
|
|
if (definition->object.collision_model.index != NONE)
|
|
{
|
|
material_type = (short)collision_model_get_material_type(
|
|
collision_model_definition_get(definition->object.collision_model.index),
|
|
material_index);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
struct structure_bsp *structure_bsp = global_structure_bsp_get();
|
|
|
|
/* port: a material (from the map) that is no material of the
|
|
bsp, or whose type is no material type, is none */
|
|
if (material_index >= 0 && material_index < structure_bsp->collision_materials.count)
|
|
{
|
|
material_type = TAG_BLOCK_GET_ELEMENT(
|
|
&structure_bsp->collision_materials,
|
|
material_index,
|
|
struct structure_collision_material)->runtime_physics_material_type;
|
|
}
|
|
if (material_type < 0 || material_type >= NUMBER_OF_MATERIAL_TYPES)
|
|
{
|
|
material_type = NONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return material_type;
|
|
}
|
|
|
|
void render_debug_physics(
|
|
struct physics_instance *instance)
|
|
{
|
|
struct object_datum *object = object_get(instance->object_index);
|
|
struct object_definition *definition = object_definition_get(object->definition_index);
|
|
real_point3d center_of_mass;
|
|
short mass_point_index;
|
|
/* port: (physics_mass_point_count) */
|
|
short mass_point_count = physics_mass_point_count(instance->physics);
|
|
|
|
matrix4x3_transform_point(
|
|
&instance->world_matrix,
|
|
&instance->physics->center_of_mass,
|
|
¢er_of_mass);
|
|
|
|
render_debug_vectors(
|
|
TRUE,
|
|
¢er_of_mass,
|
|
&instance->world_matrix.forward,
|
|
&instance->world_matrix.up,
|
|
definition->object.bounding_radius);
|
|
|
|
for (mass_point_index = 0;
|
|
mass_point_index < mass_point_count;
|
|
mass_point_index++)
|
|
{
|
|
struct mass_point_definition const *mass_point = TAG_BLOCK_GET_ELEMENT(
|
|
&instance->physics->mass_points,
|
|
mass_point_index,
|
|
struct mass_point_definition);
|
|
real_point3d position;
|
|
real_vector3d forward;
|
|
real_vector3d up;
|
|
|
|
matrix4x3_transform_point(
|
|
&instance->world_matrix,
|
|
&mass_point->position,
|
|
&position);
|
|
matrix4x3_transform_normal(
|
|
&instance->world_matrix,
|
|
&mass_point->forward,
|
|
&forward);
|
|
matrix4x3_transform_normal(
|
|
&instance->world_matrix,
|
|
&mass_point->up,
|
|
&up);
|
|
|
|
render_debug_sphere(
|
|
TRUE,
|
|
&position,
|
|
mass_point->radius,
|
|
global_real_argb_white);
|
|
render_debug_vectors(
|
|
TRUE,
|
|
&position,
|
|
&forward,
|
|
&up,
|
|
mass_point->radius * 0.5f);
|
|
}
|
|
}
|
|
|
|
boolean physics_instance_new(
|
|
struct physics_instance *instance,
|
|
long object_index)
|
|
{
|
|
struct object_datum *object = object_get(object_index);
|
|
struct object_definition *definition = object_definition_get(object->definition_index);
|
|
real_point3d center_of_mass;
|
|
|
|
if (definition->object.physics.index != NONE)
|
|
{
|
|
instance->object_index = object_index;
|
|
instance->physics = physics_definition_get(definition->object.physics.index);
|
|
|
|
instance->world_matrix.scale = 1.0f;
|
|
object_get_origin(object_index, &instance->world_matrix.position);
|
|
object_get_orientation(object_index, &instance->world_matrix.forward, &instance->world_matrix.up);
|
|
cross_product3d(&instance->world_matrix.up, &instance->world_matrix.forward, &instance->world_matrix.left);
|
|
|
|
set_real_point3d(¢er_of_mass,
|
|
-instance->physics->center_of_mass.x,
|
|
-instance->physics->center_of_mass.y,
|
|
-instance->physics->center_of_mass.z);
|
|
matrix4x3_transform_point(&instance->world_matrix, ¢er_of_mass, ¢er_of_mass);
|
|
instance->world_matrix.position = center_of_mass;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
boolean physics_test_point(
|
|
struct physics_instance const *instance,
|
|
real_point3d const *point)
|
|
{
|
|
real_point3d local_point;
|
|
struct physics_definition const *physics;
|
|
short mass_point_index;
|
|
short mass_point_count;
|
|
|
|
matrix4x3_inverse_transform_point(&instance->world_matrix, point, &local_point);
|
|
physics = instance->physics;
|
|
|
|
/* port: (physics_mass_point_count) */
|
|
mass_point_count = physics_mass_point_count(physics);
|
|
for (mass_point_index = 0;
|
|
mass_point_index < mass_point_count;
|
|
mass_point_index++)
|
|
{
|
|
struct mass_point_definition const *mass_point = TAG_BLOCK_GET_ELEMENT(
|
|
&physics->mass_points,
|
|
mass_point_index,
|
|
struct mass_point_definition);
|
|
|
|
if (point_in_sphere(&local_point, &mass_point->position, mass_point->radius))
|
|
return TRUE;
|
|
|
|
physics = instance->physics;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
boolean physics_test_vector(
|
|
struct physics_instance const *instance,
|
|
real_point3d const *point,
|
|
real_vector3d const *vector,
|
|
struct physics_test_vector_result *result)
|
|
{
|
|
boolean hit = FALSE;
|
|
real_point3d local_point;
|
|
real_vector3d local_vector;
|
|
real_vector3d normal;
|
|
short mass_point_index;
|
|
short mass_point_count;
|
|
|
|
result->t = REAL_MAX;
|
|
|
|
matrix4x3_inverse_transform_point(&instance->world_matrix, point, &local_point);
|
|
matrix4x3_inverse_transform_vector(&instance->world_matrix, vector, &local_vector);
|
|
|
|
/* port: (physics_mass_point_count) */
|
|
mass_point_count = physics_mass_point_count(instance->physics);
|
|
for (mass_point_index = 0;
|
|
mass_point_index < mass_point_count;
|
|
mass_point_index++)
|
|
{
|
|
struct mass_point_definition const *mass_point = TAG_BLOCK_GET_ELEMENT(
|
|
&instance->physics->mass_points,
|
|
mass_point_index,
|
|
struct mass_point_definition);
|
|
real t;
|
|
|
|
if (sphere_test_vector3d(
|
|
&mass_point->position,
|
|
mass_point->radius,
|
|
&local_point,
|
|
&local_vector,
|
|
&t,
|
|
&normal) &&
|
|
result->t > t)
|
|
{
|
|
real_point3d intersection;
|
|
|
|
result->t = t;
|
|
// Preserve the January inline schedule without emitting a point_from_line3d COMDAT.
|
|
intersection.x = local_vector.i*t + local_point.x;
|
|
intersection.y = local_vector.j*t + local_point.y;
|
|
intersection.z = local_vector.k*t + local_point.z;
|
|
plane3d_from_point_and_normal(
|
|
&result->plane,
|
|
&intersection,
|
|
&normal);
|
|
hit = TRUE;
|
|
}
|
|
}
|
|
|
|
if (hit)
|
|
matrix4x3_transform_plane(&instance->world_matrix, &result->plane, &result->plane);
|
|
|
|
return hit;
|
|
}
|
|
|
|
static void compute_ground_plane(
|
|
long object_index,
|
|
struct mass_point_datum *mass_point,
|
|
struct mass_point_definition const *mass_point_definition)
|
|
{
|
|
struct collision_feature_list features;
|
|
struct collision_plane collision;
|
|
|
|
mass_point->ground_plane = depths_of_hell;
|
|
mass_point->ground_material_type = NONE;
|
|
mass_point->ground_depth = mass_point_definition->radius -
|
|
plane3d_distance_to_point(&mass_point->ground_plane, &mass_point->position);
|
|
|
|
if (collision_get_features_in_sphere(
|
|
_collision_test_for_bipeds_dead_flags,
|
|
&mass_point->position,
|
|
mass_point_definition->radius,
|
|
0.0f,
|
|
mass_point_definition->radius,
|
|
object_index,
|
|
&features) &&
|
|
collision_features_test_point(&features, &mass_point->position, &collision))
|
|
{
|
|
mass_point->ground_plane = collision.plane;
|
|
mass_point->ground_depth = collision.t;
|
|
mass_point->ground_material_type = get_material_type(
|
|
collision.object_index,
|
|
collision.material_index);
|
|
|
|
SET_FLAG(
|
|
mass_point->flags,
|
|
_point_on_volatile_surface_bit,
|
|
TEST_FLAG(collision.flags, _collision_surface_breakable_bit) ||
|
|
(collision.object_index != NONE &&
|
|
!TEST_FLAG(_object_mask_scenery, object_get_type(collision.object_index))));
|
|
|
|
if (collision.object_index != NONE)
|
|
object_deplete_shield(collision.object_index);
|
|
}
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
338,
|
|
mass_point->ground_material_type==NONE || (mass_point->ground_material_type>=0 && mass_point->ground_material_type<NUMBER_OF_MATERIAL_TYPES));
|
|
|
|
return;
|
|
}
|
|
|
|
static void friction_evaluate(
|
|
short friction_type,
|
|
real parallel_scale,
|
|
real perpendicular_scale,
|
|
struct friction_datum *friction,
|
|
real_vector3d const *forward,
|
|
real_vector3d const *up)
|
|
{
|
|
real_vector3d left;
|
|
|
|
if (friction_type == _friction_type_point)
|
|
{
|
|
friction->parallel = friction->friction;
|
|
set_real_vector3d(&friction->perpendicular, 0.0f, 0.0f, 0.0f);
|
|
return;
|
|
}
|
|
|
|
switch (friction_type)
|
|
{
|
|
case _friction_type_forward:
|
|
component_vectors_from_normal3d(
|
|
&friction->friction,
|
|
forward,
|
|
&friction->parallel,
|
|
&friction->perpendicular);
|
|
break;
|
|
|
|
case _friction_type_left:
|
|
cross_product3d(up, forward, &left);
|
|
component_vectors_from_normal3d(
|
|
&friction->friction,
|
|
&left,
|
|
&friction->parallel,
|
|
&friction->perpendicular);
|
|
break;
|
|
|
|
case _friction_type_up:
|
|
component_vectors_from_normal3d(
|
|
&friction->friction,
|
|
up,
|
|
&friction->parallel,
|
|
&friction->perpendicular);
|
|
break;
|
|
|
|
default:
|
|
match_vassert("c:\\halo\\SOURCE\\physics\\physics.c", 383, FALSE, NULL);
|
|
break;
|
|
}
|
|
|
|
scale_vector3d(&friction->parallel, parallel_scale, &friction->parallel);
|
|
scale_vector3d(&friction->perpendicular, perpendicular_scale, &friction->perpendicular);
|
|
add_vectors3d(&friction->parallel, &friction->perpendicular, &friction->friction);
|
|
|
|
return;
|
|
}
|
|
|
|
void physics_compute_new(
|
|
struct physics_instance const *instance,
|
|
struct powered_mass_point_datum const *powered_mass_points,
|
|
struct mass_point_datum *mass_points,
|
|
real_vector3d *total_force,
|
|
real_vector3d *total_torque)
|
|
{
|
|
struct object_datum *object = object_get(instance->object_index);
|
|
struct physics_definition const *physics = instance->physics;
|
|
real gravity = physics->gravity_scale*global_gravity;
|
|
short mass_point_index;
|
|
/* port: no more mass points than the caller's arrays hold, nor a
|
|
powered one the physics does not have (physics_mass_point_count,
|
|
physics_powered_mass_point_index) */
|
|
short mass_point_count = physics_mass_point_count(physics);
|
|
|
|
set_real_vector3d(total_force, 0.0f, 0.0f, -physics->mass*gravity);
|
|
set_real_vector3d(total_torque, 0.0f, 0.0f, 0.0f);
|
|
|
|
memset(mass_points, 0, sizeof(struct mass_point_datum)*mass_point_count);
|
|
|
|
for (mass_point_index = 0;
|
|
mass_point_index < mass_point_count;
|
|
mass_point_index++)
|
|
{
|
|
struct mass_point_definition const *mass_point_definition = TAG_BLOCK_GET_ELEMENT(
|
|
&physics->mass_points,
|
|
mass_point_index,
|
|
struct mass_point_definition);
|
|
struct mass_point_datum *mass_point = mass_points + mass_point_index;
|
|
struct powered_mass_point_definition const *powered_mass_point_definition = NULL;
|
|
struct powered_mass_point_datum const *powered_mass_point = NULL;
|
|
real_vector3d powered_velocity;
|
|
short powered_mass_point_index = physics_powered_mass_point_index(physics, mass_point_definition);
|
|
|
|
if (powered_mass_point_index != NONE && powered_mass_points)
|
|
{
|
|
powered_mass_point_definition = TAG_BLOCK_GET_ELEMENT(
|
|
&physics->powered_mass_points,
|
|
powered_mass_point_index,
|
|
struct powered_mass_point_definition);
|
|
powered_mass_point = powered_mass_points + powered_mass_point_index;
|
|
}
|
|
|
|
mass_point->flags = 0;
|
|
matrix4x3_transform_point(
|
|
&instance->world_matrix,
|
|
&mass_point_definition->position,
|
|
&mass_point->position);
|
|
if (powered_mass_point)
|
|
{
|
|
real_matrix4x3 powered_world_matrix;
|
|
|
|
matrix4x3_multiply(&instance->world_matrix, &powered_mass_point->rotation_matrix, &powered_world_matrix);
|
|
matrix4x3_transform_normal(&powered_world_matrix, &mass_point_definition->forward, &mass_point->forward);
|
|
matrix4x3_transform_normal(&powered_world_matrix, &mass_point_definition->up, &mass_point->up);
|
|
}
|
|
else
|
|
{
|
|
matrix4x3_transform_normal(&instance->world_matrix, &mass_point_definition->forward, &mass_point->forward);
|
|
matrix4x3_transform_normal(&instance->world_matrix, &mass_point_definition->up, &mass_point->up);
|
|
}
|
|
scenario_location_from_point(&mass_point->location, &mass_point->position);
|
|
|
|
vector_from_points3d(&object->object.position, &mass_point->position, &mass_point->radius);
|
|
cross_product3d(&object->object.angular_velocity, &mass_point->radius, &mass_point->velocity);
|
|
add_vectors3d(&object->object.translational_velocity, &mass_point->velocity, &mass_point->velocity);
|
|
|
|
compute_ground_plane(instance->object_index, mass_point, mass_point_definition);
|
|
mass_point->water_depth = scenario_location_water_depth(&mass_point->location, &mass_point->position);
|
|
|
|
if (mass_point->ground_depth > 0.0f)
|
|
{
|
|
struct material_definition const *material = scenario_material_definition_get(
|
|
mass_point->ground_material_type);
|
|
real ground_friction = physics->ground_friction;
|
|
real ground_normal_k1 = physics->ground_normal_k1;
|
|
real ground_normal_k0 = physics->ground_normal_k0;
|
|
real ground_depth = physics->ground_depth;
|
|
real ground_damp_fraction = physics->ground_damp_fraction;
|
|
real normal_velocity;
|
|
real ground_scale;
|
|
|
|
if (material->physics_ground_friction_scale > 0.0f && physics->mass <= 7500.0f)
|
|
ground_friction *= material->physics_ground_friction_scale;
|
|
if (material->physics_ground_friction_normal_k1_scale > 0.0f)
|
|
ground_normal_k1 *= material->physics_ground_friction_normal_k1_scale;
|
|
if (material->physics_ground_friction_normal_k0_scale > 0.0f)
|
|
ground_normal_k0 *= material->physics_ground_friction_normal_k0_scale;
|
|
if (material->physics_ground_depth_scale > 0.0f)
|
|
ground_depth *= material->physics_ground_depth_scale;
|
|
if (material->physics_ground_damp_fraction_scale > 0.0f)
|
|
ground_damp_fraction *= material->physics_ground_damp_fraction_scale;
|
|
|
|
normal_velocity = dot_product3d(&mass_point->velocity, &mass_point->ground_plane.n);
|
|
mass_point->normal_force_magnitude = physics->mass*
|
|
(global_gravity/ground_depth*mass_point->ground_depth - normal_velocity*ground_damp_fraction);
|
|
scale_vector3d(&mass_point->ground_plane.n, mass_point->normal_force_magnitude, &mass_point->normal_force);
|
|
|
|
scale_vector3d(&mass_point->ground_plane.n, -normal_velocity, &mass_point->velocity_relative_to_ground);
|
|
add_vectors3d(&mass_point->velocity_relative_to_ground, &mass_point->velocity, &mass_point->velocity_relative_to_ground);
|
|
|
|
ground_scale = -mass_point_definition->mass*ground_friction;
|
|
scale_vector3d(&mass_point->velocity_relative_to_ground, ground_scale, &mass_point->ground_friction.friction);
|
|
|
|
if (powered_mass_point_definition &&
|
|
TEST_FLAG(powered_mass_point_definition->flags, _powered_mass_point_ground_friction_bit) &&
|
|
powered_mass_point->ground_friction_velocity != 0.0f)
|
|
{
|
|
real fraction = pin_fraction(mass_point->ground_plane.n.k, ground_normal_k0, ground_normal_k1);
|
|
real alignment = PIN(dot_product3d(&mass_point->up, &mass_point->ground_plane.n), 0.0f, 1.0f);
|
|
real weight = alignment*alignment*fraction*fraction*ground_scale;
|
|
real_vector3d projected_velocity;
|
|
|
|
scale_vector3d(&mass_point->forward, -powered_mass_point->ground_friction_velocity, &powered_velocity);
|
|
scale_vector3d(
|
|
&mass_point->ground_plane.n,
|
|
-dot_product3d(&powered_velocity, &mass_point->ground_plane.n),
|
|
&projected_velocity);
|
|
add_vectors3d(&projected_velocity, &powered_velocity, &projected_velocity);
|
|
add_vectors3d(&mass_point->velocity_relative_to_ground, &projected_velocity, &mass_point->velocity_relative_to_ground);
|
|
scale_vector3d(&projected_velocity, weight, &projected_velocity);
|
|
add_vectors3d(&mass_point->ground_friction.friction, &projected_velocity, &mass_point->ground_friction.friction);
|
|
}
|
|
|
|
friction_evaluate(
|
|
mass_point_definition->friction_type,
|
|
mass_point_definition->friction_parallel_scale,
|
|
mass_point_definition->friction_perpendicular_scale,
|
|
&mass_point->ground_friction,
|
|
&mass_point->forward,
|
|
&mass_point->up);
|
|
}
|
|
|
|
if (mass_point->water_depth > 0.0f)
|
|
{
|
|
real depth_fraction = mass_point->water_depth < physics->water_depth ?
|
|
mass_point->water_depth/physics->water_depth : 1.0f;
|
|
real water_scale = -mass_point_definition->mass*physics->water_friction;
|
|
|
|
if (mass_point_definition->density > 0.0f && physics->water_depth > 0.0f)
|
|
{
|
|
mass_point->water_pressure_magnitude = mass_point_definition->mass/mass_point_definition->density*
|
|
physics->water_density*depth_fraction*gravity;
|
|
set_real_vector3d(&mass_point->water_pressure, 0.0f, 0.0f, mass_point->water_pressure_magnitude);
|
|
}
|
|
|
|
if (powered_mass_point_definition &&
|
|
TEST_FLAG(powered_mass_point_definition->flags, _powered_mass_point_water_friction_bit) &&
|
|
powered_mass_point->water_friction_velocity != 0.0f)
|
|
{
|
|
scale_vector3d(&mass_point->forward, -powered_mass_point->water_friction_velocity, &powered_velocity);
|
|
add_vectors3d(&powered_velocity, &mass_point->velocity, &powered_velocity);
|
|
scale_vector3d(&powered_velocity, water_scale, &mass_point->water_friction.friction);
|
|
}
|
|
else
|
|
{
|
|
scale_vector3d(&mass_point->velocity, water_scale, &mass_point->water_friction.friction);
|
|
}
|
|
|
|
friction_evaluate(
|
|
mass_point_definition->friction_type,
|
|
mass_point_definition->friction_parallel_scale,
|
|
mass_point_definition->friction_perpendicular_scale,
|
|
&mass_point->water_friction,
|
|
&mass_point->forward,
|
|
&mass_point->up);
|
|
|
|
if (powered_mass_point_definition &&
|
|
TEST_FLAG(powered_mass_point_definition->flags, _powered_mass_point_water_lift_bit) &&
|
|
powered_mass_point->water_lift_ratio != 0.0f)
|
|
{
|
|
real lift = fabs(dot_product3d(&mass_point->forward, &mass_point->velocity))*
|
|
powered_mass_point->water_lift_ratio*physics->mass*depth_fraction;
|
|
real_vector3d lift_force;
|
|
|
|
scale_vector3d(&mass_point->up, lift, &lift_force);
|
|
add_vectors3d(&mass_point->powered_force, &lift_force, &mass_point->powered_force);
|
|
}
|
|
}
|
|
|
|
{
|
|
real air_scale = -mass_point_definition->mass*physics->air_friction;
|
|
|
|
if (powered_mass_point_definition &&
|
|
TEST_FLAG(powered_mass_point_definition->flags, _powered_mass_point_air_friction_bit) &&
|
|
powered_mass_point->air_friction_velocity != 0.0f)
|
|
{
|
|
scale_vector3d(&mass_point->forward, -powered_mass_point->air_friction_velocity, &powered_velocity);
|
|
add_vectors3d(&powered_velocity, &mass_point->velocity, &powered_velocity);
|
|
scale_vector3d(&powered_velocity, air_scale, &mass_point->air_friction.friction);
|
|
}
|
|
else
|
|
{
|
|
scale_vector3d(&mass_point->velocity, air_scale, &mass_point->air_friction.friction);
|
|
}
|
|
|
|
friction_evaluate(
|
|
mass_point_definition->friction_type,
|
|
mass_point_definition->friction_parallel_scale,
|
|
mass_point_definition->friction_perpendicular_scale,
|
|
&mass_point->air_friction,
|
|
&mass_point->forward,
|
|
&mass_point->up);
|
|
|
|
if (powered_mass_point_definition &&
|
|
TEST_FLAG(powered_mass_point_definition->flags, _powered_mass_point_air_lift_bit) &&
|
|
powered_mass_point->air_lift_ratio != 0.0f)
|
|
{
|
|
real lift = fabs(dot_product3d(&mass_point->forward, &mass_point->velocity))*
|
|
physics->mass*powered_mass_point->air_lift_ratio;
|
|
real_vector3d lift_force;
|
|
|
|
scale_vector3d(&mass_point->up, lift, &lift_force);
|
|
add_vectors3d(&mass_point->powered_force, &lift_force, &mass_point->powered_force);
|
|
}
|
|
}
|
|
|
|
SET_FLAG(mass_point->flags, _point_at_rest_bit, magnitude_squared3d(&mass_point->velocity) < 0.0011111111f);
|
|
SET_FLAG(mass_point->flags, _point_on_ground_bit, mass_point->ground_depth > 0.0f);
|
|
SET_FLAG(mass_point->flags, _point_in_water_bit, mass_point->water_depth > 0.0f);
|
|
|
|
if (powered_mass_point_definition)
|
|
{
|
|
if (TEST_FLAG(powered_mass_point_definition->flags, _powered_mass_point_thrust_bit))
|
|
{
|
|
real_vector3d thrust;
|
|
|
|
scale_vector3d(&mass_point->forward, powered_mass_point->thrust_fraction*physics->mass, &thrust);
|
|
add_vectors3d(&mass_point->powered_force, &thrust, &mass_point->powered_force);
|
|
}
|
|
|
|
if (TEST_FLAG(powered_mass_point_definition->flags, _powered_mass_point_antigrav_bit))
|
|
{
|
|
real probe_length = mass_point_definition->radius + powered_mass_point_definition->antigrav_height;
|
|
real_point3d point = mass_point->position;
|
|
real_vector3d probe_vector;
|
|
struct collision_result collision;
|
|
|
|
scale_vector3d(global_down3d, probe_length, &probe_vector);
|
|
|
|
if (collision_test_vector(
|
|
_collision_test_for_bipeds_dead_flags,
|
|
&point,
|
|
&probe_vector,
|
|
instance->object_index,
|
|
&collision))
|
|
{
|
|
real height = probe_length*collision.t - mass_point_definition->radius;
|
|
real alignment = pin_fraction(
|
|
mass_point->up.k,
|
|
powered_mass_point_definition->antigrav_normal_k0,
|
|
powered_mass_point_definition->antigrav_normal_k1);
|
|
real ground_effect = height > 0.0f ?
|
|
1.0f - height/powered_mass_point_definition->antigrav_height : 1.0f;
|
|
real magnitude = (ground_effect*ground_effect*global_gravity -
|
|
dot_product3d(&collision.plane.n, &mass_point->velocity)*
|
|
powered_mass_point_definition->antigrav_damp_fraction)*
|
|
powered_mass_point->antigrav_fraction*
|
|
powered_mass_point_definition->antigrav_strength*
|
|
physics->mass*alignment;
|
|
real_vector3d antigrav_force;
|
|
|
|
scale_vector3d(&collision.plane.n, magnitude, &antigrav_force);
|
|
add_vectors3d(&mass_point->powered_force, &antigrav_force, &mass_point->powered_force);
|
|
SET_FLAG(mass_point->flags, _point_antigraving_bit, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
add_vectors3d(&mass_point->normal_force, &mass_point->ground_friction.friction, &mass_point->force);
|
|
add_vectors3d(&mass_point->force, &mass_point->water_pressure, &mass_point->force);
|
|
add_vectors3d(&mass_point->force, &mass_point->water_friction.friction, &mass_point->force);
|
|
add_vectors3d(&mass_point->force, &mass_point->air_friction.friction, &mass_point->force);
|
|
add_vectors3d(&mass_point->force, &mass_point->powered_force, &mass_point->force);
|
|
cross_product3d(&mass_point->radius, &mass_point->force, &mass_point->torque);
|
|
|
|
add_vectors3d(total_force, &mass_point->force, total_force);
|
|
add_vectors3d(total_torque, &mass_point->torque, total_torque);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static boolean physics_compute_biped_collision(
|
|
struct collision_model_instance *instance,
|
|
long biped_index)
|
|
{
|
|
static real scales[] = { 0.5f, 0.25f, 1.0f };
|
|
boolean collision = FALSE;
|
|
real_point3d base;
|
|
real height;
|
|
real width;
|
|
|
|
biped_get_physics_pill(biped_index, &base, &height, &width);
|
|
|
|
if (collision_model_test_point(instance, &base))
|
|
{
|
|
collision = TRUE;
|
|
}
|
|
else
|
|
{
|
|
struct collision_feature_list features;
|
|
struct collision_plane collision_plane;
|
|
real_point3d center;
|
|
real radius;
|
|
real feature_width;
|
|
|
|
collision_features_new(&features);
|
|
set_real_point3d(¢er, base.x, base.y, base.z + height*0.5f);
|
|
radius = height*0.5f + width;
|
|
feature_width = MAX(width - 0.015625f, 0.015625f);
|
|
collision_model_get_features_in_sphere(
|
|
instance,
|
|
¢er,
|
|
radius,
|
|
height,
|
|
feature_width,
|
|
&features);
|
|
if (collision_features_test_point(&features, &base, &collision_plane))
|
|
collision = TRUE;
|
|
}
|
|
|
|
if (collision)
|
|
{
|
|
struct unit_datum *vehicle = vehicle_get(instance->object_index);
|
|
struct biped_datum *biped = biped_get(biped_index);
|
|
real vehicle_speed = magnitude3d(&vehicle->object.translational_velocity);
|
|
real_vector3d acceleration;
|
|
real_point3d new_position;
|
|
boolean cause_damage = TRUE;
|
|
|
|
vector_from_points3d(
|
|
&vehicle->object.bounding_sphere_center,
|
|
&biped->object.bounding_sphere_center,
|
|
&acceleration);
|
|
normalize3d(&acceleration);
|
|
acceleration.k += 0.8f;
|
|
normalize3d(&acceleration);
|
|
scale_vector3d(&acceleration, MAX(vehicle_speed, 0.1f), &acceleration);
|
|
add_vectors3d(&acceleration, &vehicle->object.translational_velocity, &acceleration);
|
|
scale_vector3d(&acceleration, 0.5f, &acceleration);
|
|
biped_accelerate(biped_index, &acceleration);
|
|
|
|
base.x += acceleration.i*2.0f;
|
|
base.y += acceleration.j*2.0f;
|
|
base.z += acceleration.k*2.0f;
|
|
|
|
if (collision_fix_pill(
|
|
_collision_test_for_bipeds_living_flags,
|
|
&base,
|
|
width*2.0f,
|
|
height,
|
|
width,
|
|
biped_index,
|
|
&new_position))
|
|
{
|
|
new_position.z -= width;
|
|
object_translate(biped_index, &new_position, NULL);
|
|
|
|
cause_damage =
|
|
(instance->object_index != biped->unit.last_vehicle_index ||
|
|
game_time_get() > biped->unit.game_time_at_last_vehicle_exit + 90) &&
|
|
(vehicle_speed > 0.06666667f ||
|
|
distance_squared3d(
|
|
(real_point3d const *)&vehicle->object.translational_velocity,
|
|
(real_point3d const *)&biped->object.translational_velocity) > 0.0011111111f);
|
|
}
|
|
|
|
if (cause_damage)
|
|
{
|
|
struct game_globals_falling_damage *falling_damage = TAG_BLOCK_GET_ELEMENT(
|
|
&scenario_get_game_globals()->falling_damage,
|
|
0,
|
|
struct game_globals_falling_damage);
|
|
|
|
if (falling_damage->vehicle_collision_damage.index != NONE)
|
|
{
|
|
long responsible_object_index = instance->object_index;
|
|
struct object_datum *responsible_object = (struct object_datum *)vehicle;
|
|
struct damage_data damage;
|
|
|
|
if (vehicle->unit.driver_object_index != NONE)
|
|
{
|
|
responsible_object_index = vehicle->unit.driver_object_index;
|
|
responsible_object = object_get(responsible_object_index);
|
|
}
|
|
|
|
damage_data_new(&damage, falling_damage->vehicle_collision_damage.index);
|
|
damage.scale = 1.0f;
|
|
SET_FLAG(damage.flags, _damage_area_of_effect_bit, TRUE);
|
|
damage.owner_player_index = responsible_object->object.owner_player_index;
|
|
damage.owner_object_index = responsible_object->object.owner_object_index != NONE ?
|
|
responsible_object->object.owner_object_index : responsible_object_index;
|
|
damage.owner_team_index = responsible_object->object.owner_team_index;
|
|
damage.origin = biped->object.bounding_sphere_center;
|
|
damage.epicenter = vehicle->object.bounding_sphere_center;
|
|
damage.direction = acceleration;
|
|
normalize3d(&damage.direction);
|
|
object_cause_damage(&damage, biped_index, NONE, NONE, NONE, NULL);
|
|
}
|
|
|
|
if (falling_damage->vehicle_killed_unit_damage_effect.index != NONE)
|
|
{
|
|
struct unit_definition *unit_definition = unit_definition_get(biped->definition_index);
|
|
struct damage_data damage;
|
|
|
|
damage_data_new(&damage, falling_damage->vehicle_killed_unit_damage_effect.index);
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
830,
|
|
unit_definition->unit.blip_type>=0 && unit_definition->unit.blip_type<NUMBEROF(scales));
|
|
damage.scale = scales[unit_definition->unit.blip_type];
|
|
damage.origin = biped->object.bounding_sphere_center;
|
|
scale_vector3d(&acceleration, -1.0f, &damage.direction);
|
|
object_cause_damage(&damage, instance->object_index, NONE, NONE, NONE, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
return collision;
|
|
}
|
|
|
|
static boolean physics_compute_vehicle_collision(
|
|
struct physics_instance const *instance0,
|
|
struct physics_instance const *instance1)
|
|
{
|
|
boolean collision = FALSE;
|
|
struct vehicle_datum *object0 = vehicle_datum_get(instance0->object_index);
|
|
struct vehicle_datum *object1 = vehicle_datum_get(instance1->object_index);
|
|
real mass_scale = square_root(instance0->physics->mass * instance1->physics->mass);
|
|
real_vector3d force0;
|
|
real_vector3d force1;
|
|
real_vector3d torque0;
|
|
real_vector3d torque1;
|
|
short mass_point0_index;
|
|
short mass_point0_count;
|
|
short mass_point1_count;
|
|
|
|
set_real_vector3d(&force0, 0.0f, 0.0f, 0.0f);
|
|
set_real_vector3d(&force1, 0.0f, 0.0f, 0.0f);
|
|
set_real_vector3d(&torque0, 0.0f, 0.0f, 0.0f);
|
|
set_real_vector3d(&torque1, 0.0f, 0.0f, 0.0f);
|
|
|
|
/* port: (physics_mass_point_count) */
|
|
mass_point0_count = physics_mass_point_count(instance0->physics);
|
|
mass_point1_count = physics_mass_point_count(instance1->physics);
|
|
for (mass_point0_index = 0;
|
|
mass_point0_index < mass_point0_count;
|
|
mass_point0_index++)
|
|
{
|
|
struct mass_point_definition const *mass_point0 = TAG_BLOCK_GET_ELEMENT(
|
|
&instance0->physics->mass_points,
|
|
mass_point0_index,
|
|
struct mass_point_definition);
|
|
real_point3d point0;
|
|
short mass_point1_index;
|
|
|
|
matrix4x3_transform_point(&instance0->world_matrix, &mass_point0->position, &point0);
|
|
|
|
for (mass_point1_index = 0;
|
|
mass_point1_index < mass_point1_count;
|
|
mass_point1_index++)
|
|
{
|
|
struct mass_point_definition const *mass_point1 = TAG_BLOCK_GET_ELEMENT(
|
|
&instance1->physics->mass_points,
|
|
mass_point1_index,
|
|
struct mass_point_definition);
|
|
real radius = mass_point0->radius + mass_point1->radius;
|
|
real_point3d point1;
|
|
real_vector3d direction;
|
|
real distance;
|
|
|
|
matrix4x3_transform_point(&instance1->world_matrix, &mass_point1->position, &point1);
|
|
vector_from_points3d(&point0, &point1, &direction);
|
|
distance = normalize3d(&direction);
|
|
|
|
if (distance < radius && distance > 0.0f)
|
|
{
|
|
real penetration = (radius - distance) * 0.5f;
|
|
real force_magnitude = 2.0f * mass_scale * global_gravity /
|
|
global_physics_collision_depth * penetration;
|
|
real_vector3d collision_force0;
|
|
real_vector3d collision_force1;
|
|
real_point3d collision_point;
|
|
real_vector3d radius0;
|
|
real_vector3d radius1;
|
|
real_vector3d collision_torque0;
|
|
real_vector3d collision_torque1;
|
|
|
|
scale_vector3d(&direction, -force_magnitude, &collision_force0);
|
|
scale_vector3d(&direction, force_magnitude, &collision_force1);
|
|
point_from_line3d(&point0, &direction, mass_point0->radius - penetration, &collision_point);
|
|
vector_from_points3d(&object0->object.position, &collision_point, &radius0);
|
|
vector_from_points3d(&object1->object.position, &collision_point, &radius1);
|
|
cross_product3d(&radius0, &collision_force0, &collision_torque0);
|
|
cross_product3d(&radius1, &collision_force1, &collision_torque1);
|
|
add_vectors3d(&force0, &collision_force0, &force0);
|
|
add_vectors3d(&force1, &collision_force1, &force1);
|
|
add_vectors3d(&torque0, &collision_torque0, &torque0);
|
|
add_vectors3d(&torque1, &collision_torque1, &torque1);
|
|
collision = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (collision)
|
|
{
|
|
add_vectors3d(&object0->vehicle.collision_force, &force0, &object0->vehicle.collision_force);
|
|
add_vectors3d(&object0->vehicle.collision_torque, &torque0, &object0->vehicle.collision_torque);
|
|
SET_FLAG(object0->object.flags, _object_at_rest_bit, FALSE);
|
|
|
|
if (!(instance1->physics->radius > 0.0f))
|
|
{
|
|
add_vectors3d(&object1->vehicle.collision_force, &force1, &object1->vehicle.collision_force);
|
|
add_vectors3d(&object1->vehicle.collision_torque, &torque1, &object1->vehicle.collision_torque);
|
|
SET_FLAG(object1->object.flags, _object_at_rest_bit, FALSE);
|
|
}
|
|
}
|
|
|
|
return collision;
|
|
}
|
|
|
|
static void physics_compute_unit_collisions(
|
|
long vehicle_index)
|
|
{
|
|
struct collision_model_instance collision_instance;
|
|
struct physics_instance vehicle_physics;
|
|
long object_indices[2048];
|
|
boolean model_instance_valid = collision_model_instance_new(
|
|
&collision_instance,
|
|
vehicle_index);
|
|
struct unit_datum *vehicle;
|
|
short object_count;
|
|
short object_number;
|
|
|
|
if (!physics_instance_new(&vehicle_physics, vehicle_index))
|
|
return;
|
|
|
|
vehicle = vehicle_get(vehicle_index);
|
|
object_count = objects_in_sphere(
|
|
_object_mask_biped,
|
|
_object_mask_vehicle + (model_instance_valid ? _object_mask_biped : 0),
|
|
&vehicle->object.location,
|
|
&vehicle->object.bounding_sphere_center,
|
|
vehicle->object.bounding_sphere_radius,
|
|
object_indices,
|
|
NUMBEROF(object_indices));
|
|
|
|
for (object_number = 0; object_number < object_count; object_number++)
|
|
{
|
|
long object_index = object_indices[object_number];
|
|
struct object_header_datum *object_header = object_header_get(object_index);
|
|
|
|
switch (object_header->type)
|
|
{
|
|
case _object_type_biped:
|
|
{
|
|
struct biped_datum *biped = biped_get(object_index);
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
669,
|
|
model_instance_valid);
|
|
if (!TEST_FLAG(biped->object.damage_flags, _object_dead_bit))
|
|
physics_compute_biped_collision(&collision_instance, object_index);
|
|
break;
|
|
}
|
|
|
|
case _object_type_vehicle:
|
|
{
|
|
if (object_index != vehicle_index)
|
|
{
|
|
struct physics_instance other_physics;
|
|
|
|
if (physics_instance_new(&other_physics, object_index))
|
|
{
|
|
struct unit_datum *other_vehicle = vehicle_get(object_index);
|
|
|
|
if (DATUM_INDEX_TO_ABSOLUTE_INDEX(object_index) <
|
|
DATUM_INDEX_TO_ABSOLUTE_INDEX(vehicle_index) ||
|
|
TEST_FLAG(other_vehicle->object.flags, _object_at_rest_bit) ||
|
|
other_physics.physics->radius > 0.0f)
|
|
{
|
|
physics_compute_vehicle_collision(&vehicle_physics, &other_physics);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void rotate_vectors3d_by_angular_velocity(
|
|
real_vector3d const *forward,
|
|
real_vector3d const *up,
|
|
real_vector3d const *angular_velocity,
|
|
real_vector3d *rotated_forward,
|
|
real_vector3d *rotated_up)
|
|
{
|
|
real_vector3d axis = *angular_velocity;
|
|
real magnitude = normalize3d(&axis);
|
|
|
|
match_assert("c:\\halo\\SOURCE\\physics\\physics.c", 944, forward!=rotated_forward);
|
|
match_assert("c:\\halo\\SOURCE\\physics\\physics.c", 945, up!=rotated_up);
|
|
|
|
if (magnitude != 0.0f)
|
|
{
|
|
real_matrix4x3 rotation;
|
|
real dot;
|
|
|
|
matrix4x3_rotation_from_axis_and_angle(
|
|
&rotation,
|
|
&axis,
|
|
sine(magnitude),
|
|
cosine(magnitude));
|
|
matrix4x3_transform_vector(&rotation, forward, rotated_forward);
|
|
matrix4x3_transform_vector(&rotation, up, rotated_up);
|
|
normalize3d(rotated_forward);
|
|
|
|
dot = -dot_product3d(rotated_up, rotated_forward);
|
|
rotated_up->i += dot*rotated_forward->i;
|
|
rotated_up->j += dot*rotated_forward->j;
|
|
rotated_up->k += dot*rotated_forward->k;
|
|
normalize3d(rotated_up);
|
|
}
|
|
else
|
|
{
|
|
*rotated_forward = *forward;
|
|
*rotated_up = *up;
|
|
}
|
|
|
|
match_assert_valid_real_vector3d_axes2(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
965,
|
|
rotated_forward,
|
|
rotated_up);
|
|
|
|
return;
|
|
}
|
|
|
|
void physics_update_new(
|
|
struct physics_instance const *instance,
|
|
struct powered_mass_point_datum const *powered_mass_points,
|
|
struct mass_point_datum const *mass_points,
|
|
real_vector3d const *total_force,
|
|
real_vector3d const *total_torque)
|
|
{
|
|
struct vehicle_datum *vehicle = vehicle_datum_get(instance->object_index);
|
|
real_vector3d linear_acceleration;
|
|
real_vector3d linear_velocity;
|
|
real_point3d position;
|
|
real_vector3d angular_acceleration;
|
|
real_vector3d angular_velocity;
|
|
real_vector3d forward;
|
|
real_vector3d up;
|
|
short mass_point_index;
|
|
/* port: (as in physics_compute_new) */
|
|
short mass_point_count = physics_mass_point_count(instance->physics);
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
986,
|
|
instance->physics->mass>0.0f);
|
|
|
|
scale_vector3d(total_force, 1.0f/instance->physics->mass, &linear_acceleration);
|
|
match_assert_valid_real_vector3d(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
990,
|
|
&linear_acceleration);
|
|
|
|
add_vectors3d(&linear_acceleration, &vehicle->object.translational_velocity, &linear_velocity);
|
|
match_assert_valid_real_vector3d(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
994,
|
|
&linear_velocity);
|
|
|
|
position.x = vehicle->object.position.x + linear_velocity.i;
|
|
position.y = vehicle->object.position.y + linear_velocity.j;
|
|
position.z = vehicle->object.position.z + linear_velocity.k;
|
|
|
|
/* port: a physics (from the map) without its inverse inertia matrix
|
|
(the second of its two; the retail ones all have both) turns no faster */
|
|
if (instance->physics->inertial_matrix.count < 2)
|
|
{
|
|
if (!warned_about_physics_inertial_matrix)
|
|
{
|
|
error(_error_silent, "a physics has %ld inertial matrices (2 expected)",
|
|
instance->physics->inertial_matrix.count);
|
|
warned_about_physics_inertial_matrix = TRUE;
|
|
}
|
|
set_real_vector3d(&angular_acceleration, 0.0f, 0.0f, 0.0f);
|
|
}
|
|
else
|
|
{
|
|
real_matrix3x3 frame;
|
|
real_matrix3x3 world_inverse_inertia;
|
|
|
|
matrix3x3_from_forward_and_up(
|
|
&frame,
|
|
&vehicle->object.forward,
|
|
&vehicle->object.up);
|
|
matrix3x3_multiply(
|
|
&frame,
|
|
TAG_BLOCK_GET_ELEMENT(
|
|
&instance->physics->inertial_matrix,
|
|
1,
|
|
real_matrix3x3),
|
|
&world_inverse_inertia);
|
|
matrix3x3_multiply(
|
|
&world_inverse_inertia,
|
|
matrix3x3_transpose(&frame, &frame),
|
|
&world_inverse_inertia);
|
|
matrix3x3_transform_vector(
|
|
&world_inverse_inertia,
|
|
total_torque,
|
|
&angular_acceleration);
|
|
}
|
|
|
|
match_assert_valid_real_vector3d(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
1008,
|
|
&angular_acceleration);
|
|
|
|
add_vectors3d(&angular_acceleration, &vehicle->object.angular_velocity, &angular_velocity);
|
|
match_assert_valid_real_vector3d(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
1012,
|
|
&angular_velocity);
|
|
|
|
rotate_vectors3d_by_angular_velocity(
|
|
&vehicle->object.forward,
|
|
&vehicle->object.up,
|
|
&angular_velocity,
|
|
&forward,
|
|
&up);
|
|
|
|
vehicle->object.translational_velocity = linear_velocity;
|
|
vehicle->object.angular_velocity = angular_velocity;
|
|
|
|
if (debug_physics_disable_penetration_freeze)
|
|
{
|
|
object_set_position(instance->object_index, &position, &forward, &up);
|
|
}
|
|
else
|
|
{
|
|
short passes_remaining = 4;
|
|
unsigned long stuck_mass_point_flags;
|
|
|
|
while (passes_remaining-- > 0)
|
|
{
|
|
boolean found_collision = FALSE;
|
|
real_vector3d worst_delta;
|
|
struct collision_result worst_collision;
|
|
real_matrix4x3 world_matrix;
|
|
real_point3d center_of_mass;
|
|
|
|
stuck_mass_point_flags = 0;
|
|
matrix4x3_from_point_and_vectors(&world_matrix, &position, &forward, &up);
|
|
set_real_point3d(¢er_of_mass,
|
|
-instance->physics->center_of_mass.x,
|
|
-instance->physics->center_of_mass.y,
|
|
-instance->physics->center_of_mass.z);
|
|
matrix4x3_transform_point(&world_matrix, ¢er_of_mass, ¢er_of_mass);
|
|
world_matrix.position = center_of_mass;
|
|
|
|
for (mass_point_index = 0;
|
|
mass_point_index < mass_point_count;
|
|
mass_point_index++)
|
|
{
|
|
struct mass_point_definition const *mass_point_definition = TAG_BLOCK_GET_ELEMENT(
|
|
&instance->physics->mass_points,
|
|
mass_point_index,
|
|
struct mass_point_definition);
|
|
struct mass_point_datum const *mass_point = mass_points + mass_point_index;
|
|
real_point3d swept_position;
|
|
real_vector3d delta;
|
|
struct collision_result collision;
|
|
|
|
matrix4x3_transform_point(
|
|
&world_matrix,
|
|
&mass_point_definition->position,
|
|
&swept_position);
|
|
vector_from_points3d(&mass_point->position, &swept_position, &delta);
|
|
|
|
if (collision_test_vector(
|
|
_collision_test_for_vehicles_flags |
|
|
FLAG(_collision_test_front_facing_surfaces_bit),
|
|
&mass_point->position,
|
|
&delta,
|
|
instance->object_index,
|
|
&collision))
|
|
{
|
|
SET_FLAG(stuck_mass_point_flags, mass_point_index, TRUE);
|
|
|
|
if (!found_collision || worst_collision.t > collision.t)
|
|
{
|
|
found_collision = TRUE;
|
|
worst_delta = delta;
|
|
worst_collision = collision;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!found_collision)
|
|
{
|
|
object_set_position(instance->object_index, &position, &forward, &up);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
real normal_dot_delta = dot_product3d(&worst_delta, &worst_collision.plane.n);
|
|
real epsilon = (real)(normal_dot_delta != 0.0f ?
|
|
0.0078125/fabs(normal_dot_delta) : 0.03125);
|
|
real t = MAX(worst_collision.t - epsilon, 0.0f);
|
|
real normal_dot_velocity = dot_product3d(&worst_collision.plane.n, &linear_velocity);
|
|
|
|
if (normal_dot_velocity < 0.0f)
|
|
{
|
|
PHYSICS_POINT_FROM_LINE3D(
|
|
&linear_velocity,
|
|
&worst_collision.plane.n,
|
|
(t - 1.0f)*normal_dot_velocity,
|
|
&linear_velocity);
|
|
vehicle->object.translational_velocity = linear_velocity;
|
|
position.x = vehicle->object.position.x + linear_velocity.i;
|
|
position.y = vehicle->object.position.y + linear_velocity.j;
|
|
position.z = vehicle->object.position.z + linear_velocity.k;
|
|
}
|
|
|
|
scale_vector3d(&angular_velocity, t, &angular_velocity);
|
|
vehicle->object.angular_velocity = angular_velocity;
|
|
rotate_vectors3d_by_angular_velocity(
|
|
&vehicle->object.forward,
|
|
&vehicle->object.up,
|
|
&angular_velocity,
|
|
&forward,
|
|
&up);
|
|
}
|
|
}
|
|
|
|
vehicle->vehicle.stuck_mass_point_flags = stuck_mass_point_flags;
|
|
}
|
|
|
|
{
|
|
short at_rest_count = 0;
|
|
short on_ground_count = 0;
|
|
short on_volatile_surface_count = 0;
|
|
short in_water_count = 0;
|
|
|
|
for (mass_point_index = 0;
|
|
mass_point_index < mass_point_count;
|
|
mass_point_index++)
|
|
{
|
|
struct mass_point_datum const *mass_point = mass_points + mass_point_index;
|
|
|
|
at_rest_count += TEST_FLAG(mass_point->flags, _point_at_rest_bit);
|
|
on_ground_count += TEST_FLAG(mass_point->flags, _point_on_ground_bit);
|
|
on_volatile_surface_count += TEST_FLAG(mass_point->flags, _point_on_volatile_surface_bit);
|
|
in_water_count += TEST_FLAG(mass_point->flags, _point_in_water_bit);
|
|
}
|
|
|
|
SET_FLAG(
|
|
vehicle->object.flags,
|
|
_object_at_rest_bit,
|
|
at_rest_count == mass_point_count &&
|
|
on_ground_count >= 3 &&
|
|
on_volatile_surface_count == 0 &&
|
|
magnitude_squared3d(&linear_velocity) <= 0.0011111111f &&
|
|
magnitude_squared3d(&angular_velocity) <= 0.0027415568f &&
|
|
magnitude_squared3d(&linear_acceleration) <= 0.00000030864197f &&
|
|
magnitude_squared3d(&angular_acceleration) <= 0.0000030461742f);
|
|
SET_FLAG(vehicle->object.flags, _object_on_ground_bit, on_ground_count > 0);
|
|
SET_FLAG(vehicle->object.flags, _object_on_media_bit, in_water_count > 0);
|
|
SET_FLAG(vehicle->object.flags, _object_partially_under_media_bit, in_water_count > 0);
|
|
SET_FLAG(
|
|
vehicle->object.flags,
|
|
_object_wholly_under_media_bit,
|
|
in_water_count == mass_point_count);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* NonMatching: the owner-safe natural reconstruction is 0x1500 bytes with 116
|
|
* relocations versus the January target's 0x1430 bytes and 115 relocations.
|
|
* Its final axes predicate also falls out of line after the earlier codegen
|
|
* divergence, so this coherent candidate is parked without schedule tuning. */
|
|
static void physics_update_old(
|
|
long object_index,
|
|
struct powered_mass_point_datum *powered_mass_points,
|
|
struct mass_point_datum *mass_points,
|
|
real_vector3d const *magic_force,
|
|
real_vector3d const *magic_torque)
|
|
{
|
|
struct object_datum *object = object_get(object_index);
|
|
struct object_definition const *object_definition = object_definition_get(object->definition_index);
|
|
struct physics_definition const *physics = physics_definition_get(
|
|
object_definition->object.physics.index);
|
|
real gravity = physics->gravity_scale*global_gravity;
|
|
real_matrix4x3 world_matrix;
|
|
real_vector3d total_force = { 0.0f, 0.0f, -physics->mass*gravity };
|
|
real_vector3d total_torque = { 0.0f, 0.0f, 0.0f };
|
|
real_vector3d translational_acceleration = { 0.0f, 0.0f, 0.0f };
|
|
real_vector3d angular_acceleration = { 0.0f, 0.0f, 0.0f };
|
|
short stopped_mass_point_count = 0;
|
|
short grounded_mass_point_count = 0;
|
|
short volatile_mass_point_count = 0;
|
|
short submerged_mass_point_count = 0;
|
|
short mass_point_index;
|
|
/* port: (as in physics_compute_new) */
|
|
short mass_point_count = physics_mass_point_count(physics);
|
|
|
|
matrix4x3_from_point_and_vectors(
|
|
&world_matrix,
|
|
&object->object.position,
|
|
&object->object.forward,
|
|
&object->object.up);
|
|
|
|
if (powered_mass_points)
|
|
{
|
|
short powered_mass_point_index;
|
|
|
|
/* port: (physics_powered_mass_point_count) */
|
|
for (powered_mass_point_index = 0;
|
|
powered_mass_point_index < physics_powered_mass_point_count(physics);
|
|
powered_mass_point_index++)
|
|
{
|
|
struct powered_mass_point_datum *powered_mass_point =
|
|
powered_mass_points + powered_mass_point_index;
|
|
|
|
matrix4x3_rotation_from_quaternion(
|
|
&powered_mass_point->rotation_matrix,
|
|
&powered_mass_point->rotation);
|
|
matrix4x3_transpose(&powered_mass_point->rotation_matrix);
|
|
}
|
|
}
|
|
|
|
memset(mass_points, 0, sizeof(struct mass_point_datum)*mass_point_count);
|
|
|
|
if (magic_force)
|
|
{
|
|
match_assert_valid_real_vector3d(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
1255,
|
|
magic_force);
|
|
add_vectors3d(&total_force, magic_force, &total_force);
|
|
}
|
|
if (magic_torque)
|
|
{
|
|
match_assert_valid_real_vector3d(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
1261,
|
|
magic_torque);
|
|
total_torque = *magic_torque;
|
|
}
|
|
|
|
for (mass_point_index = 0;
|
|
mass_point_index < mass_point_count;
|
|
mass_point_index++)
|
|
{
|
|
struct mass_point_definition const *mass_point_definition = TAG_BLOCK_GET_ELEMENT(
|
|
&physics->mass_points,
|
|
mass_point_index,
|
|
struct mass_point_definition);
|
|
struct mass_point_datum *mass_point = mass_points + mass_point_index;
|
|
struct powered_mass_point_definition const *powered_mass_point_definition = NULL;
|
|
struct powered_mass_point_datum *powered_mass_point = NULL;
|
|
real_point3d local_position;
|
|
/* port: (physics_powered_mass_point_index) */
|
|
short powered_mass_point_index = physics_powered_mass_point_index(physics, mass_point_definition);
|
|
|
|
if (powered_mass_point_index != NONE && powered_mass_points)
|
|
{
|
|
powered_mass_point_definition = TAG_BLOCK_GET_ELEMENT(
|
|
&physics->powered_mass_points,
|
|
powered_mass_point_index,
|
|
struct powered_mass_point_definition);
|
|
if (powered_mass_point_definition)
|
|
{
|
|
powered_mass_point =
|
|
powered_mass_points + powered_mass_point_index;
|
|
}
|
|
}
|
|
|
|
mass_point->flags = 0;
|
|
local_position.x = mass_point_definition->position.x - physics->center_of_mass.x;
|
|
local_position.y = mass_point_definition->position.y - physics->center_of_mass.y;
|
|
local_position.z = mass_point_definition->position.z - physics->center_of_mass.z;
|
|
matrix4x3_transform_point(&world_matrix, &local_position, &mass_point->position);
|
|
|
|
if (powered_mass_point)
|
|
{
|
|
real_matrix4x3 powered_world_matrix;
|
|
|
|
matrix4x3_multiply(
|
|
&world_matrix,
|
|
&powered_mass_point->rotation_matrix,
|
|
&powered_world_matrix);
|
|
matrix4x3_transform_normal(
|
|
&powered_world_matrix,
|
|
&mass_point_definition->forward,
|
|
&mass_point->forward);
|
|
matrix4x3_transform_normal(
|
|
&powered_world_matrix,
|
|
&mass_point_definition->up,
|
|
&mass_point->up);
|
|
}
|
|
else
|
|
{
|
|
matrix4x3_transform_normal(
|
|
&world_matrix,
|
|
&mass_point_definition->forward,
|
|
&mass_point->forward);
|
|
matrix4x3_transform_normal(
|
|
&world_matrix,
|
|
&mass_point_definition->up,
|
|
&mass_point->up);
|
|
}
|
|
|
|
scenario_location_from_point(&mass_point->location, &mass_point->position);
|
|
vector_from_points3d(&object->object.position, &mass_point->position, &mass_point->radius);
|
|
cross_product3d(&object->object.angular_velocity, &mass_point->radius, &mass_point->velocity);
|
|
add_vectors3d(
|
|
&object->object.translational_velocity,
|
|
&mass_point->velocity,
|
|
&mass_point->velocity);
|
|
|
|
compute_ground_plane(object_index, mass_point, mass_point_definition);
|
|
mass_point->water_depth = scenario_location_water_depth(
|
|
&mass_point->location,
|
|
&mass_point->position);
|
|
|
|
if (mass_point->ground_depth > 0.0f && physics->ground_depth > 0.0f)
|
|
{
|
|
real normal_velocity = dot_product3d(
|
|
&mass_point->velocity,
|
|
&mass_point->ground_plane.n);
|
|
real ground_scale = -mass_point_definition->mass*physics->ground_friction;
|
|
|
|
mass_point->normal_force_magnitude = physics->mass*(
|
|
global_gravity/physics->ground_depth*mass_point->ground_depth -
|
|
normal_velocity*physics->ground_damp_fraction);
|
|
scale_vector3d(
|
|
&mass_point->ground_plane.n,
|
|
mass_point->normal_force_magnitude,
|
|
&mass_point->normal_force);
|
|
scale_vector3d(
|
|
&mass_point->ground_plane.n,
|
|
-normal_velocity,
|
|
&mass_point->velocity_relative_to_ground);
|
|
add_vectors3d(
|
|
&mass_point->velocity_relative_to_ground,
|
|
&mass_point->velocity,
|
|
&mass_point->velocity_relative_to_ground);
|
|
scale_vector3d(
|
|
&mass_point->velocity_relative_to_ground,
|
|
ground_scale,
|
|
&mass_point->ground_friction.friction);
|
|
|
|
if (powered_mass_point_definition &&
|
|
TEST_FLAG(
|
|
powered_mass_point_definition->flags,
|
|
_powered_mass_point_ground_friction_bit) &&
|
|
powered_mass_point->ground_friction_velocity != 0.0f)
|
|
{
|
|
real fraction = pin_fraction(
|
|
mass_point->ground_plane.n.k,
|
|
physics->ground_normal_k0,
|
|
physics->ground_normal_k1);
|
|
real alignment = PIN(
|
|
dot_product3d(&mass_point->up, &mass_point->ground_plane.n),
|
|
0.0f,
|
|
1.0f);
|
|
real weight = alignment*alignment*fraction*fraction*ground_scale;
|
|
real_vector3d powered_velocity;
|
|
real_vector3d projected_velocity;
|
|
|
|
scale_vector3d(
|
|
&mass_point->forward,
|
|
-powered_mass_point->ground_friction_velocity,
|
|
&powered_velocity);
|
|
scale_vector3d(
|
|
&mass_point->ground_plane.n,
|
|
-dot_product3d(&powered_velocity, &mass_point->ground_plane.n),
|
|
&projected_velocity);
|
|
add_vectors3d(&projected_velocity, &powered_velocity, &projected_velocity);
|
|
add_vectors3d(
|
|
&mass_point->velocity_relative_to_ground,
|
|
&projected_velocity,
|
|
&mass_point->velocity_relative_to_ground);
|
|
scale_vector3d(&projected_velocity, weight, &projected_velocity);
|
|
add_vectors3d(
|
|
&mass_point->ground_friction.friction,
|
|
&projected_velocity,
|
|
&mass_point->ground_friction.friction);
|
|
}
|
|
|
|
if (mass_point->ground_material_type == _material_ice)
|
|
{
|
|
friction_evaluate(
|
|
mass_point_definition->friction_type,
|
|
mass_point_definition->friction_parallel_scale*0.125f,
|
|
mass_point_definition->friction_perpendicular_scale*0.125f,
|
|
&mass_point->ground_friction,
|
|
&mass_point->forward,
|
|
&mass_point->up);
|
|
}
|
|
else
|
|
{
|
|
friction_evaluate(
|
|
mass_point_definition->friction_type,
|
|
mass_point_definition->friction_parallel_scale,
|
|
mass_point_definition->friction_perpendicular_scale,
|
|
&mass_point->ground_friction,
|
|
&mass_point->forward,
|
|
&mass_point->up);
|
|
}
|
|
}
|
|
|
|
if (mass_point->water_depth > 0.0f)
|
|
{
|
|
real depth_fraction = mass_point->water_depth < physics->water_depth ?
|
|
mass_point->water_depth/physics->water_depth : 1.0f;
|
|
real water_scale = -mass_point_definition->mass*physics->water_friction;
|
|
|
|
if (mass_point_definition->density > 0.0f && physics->water_depth > 0.0f)
|
|
{
|
|
mass_point->water_pressure_magnitude =
|
|
mass_point_definition->mass/mass_point_definition->density*
|
|
physics->water_density*depth_fraction*gravity;
|
|
set_real_vector3d(
|
|
&mass_point->water_pressure,
|
|
0.0f,
|
|
0.0f,
|
|
mass_point->water_pressure_magnitude);
|
|
}
|
|
|
|
if (powered_mass_point_definition &&
|
|
TEST_FLAG(
|
|
powered_mass_point_definition->flags,
|
|
_powered_mass_point_water_friction_bit) &&
|
|
powered_mass_point->water_friction_velocity != 0.0f)
|
|
{
|
|
real_vector3d powered_velocity;
|
|
|
|
scale_vector3d(
|
|
&mass_point->forward,
|
|
-powered_mass_point->water_friction_velocity,
|
|
&powered_velocity);
|
|
add_vectors3d(&powered_velocity, &mass_point->velocity, &powered_velocity);
|
|
scale_vector3d(
|
|
&powered_velocity,
|
|
water_scale,
|
|
&mass_point->water_friction.friction);
|
|
}
|
|
else
|
|
{
|
|
scale_vector3d(
|
|
&mass_point->velocity,
|
|
water_scale,
|
|
&mass_point->water_friction.friction);
|
|
}
|
|
|
|
friction_evaluate(
|
|
mass_point_definition->friction_type,
|
|
mass_point_definition->friction_parallel_scale,
|
|
mass_point_definition->friction_perpendicular_scale,
|
|
&mass_point->water_friction,
|
|
&mass_point->forward,
|
|
&mass_point->up);
|
|
|
|
if (powered_mass_point_definition &&
|
|
TEST_FLAG(
|
|
powered_mass_point_definition->flags,
|
|
_powered_mass_point_water_lift_bit) &&
|
|
powered_mass_point->water_lift_ratio != 0.0f)
|
|
{
|
|
real lift = fabs(dot_product3d(&mass_point->forward, &mass_point->velocity))*
|
|
powered_mass_point->water_lift_ratio*physics->mass*depth_fraction;
|
|
real_vector3d lift_force;
|
|
|
|
scale_vector3d(&mass_point->up, lift, &lift_force);
|
|
add_vectors3d(&mass_point->powered_force, &lift_force, &mass_point->powered_force);
|
|
}
|
|
}
|
|
|
|
{
|
|
real air_scale = -mass_point_definition->mass*physics->air_friction;
|
|
|
|
if (powered_mass_point_definition &&
|
|
TEST_FLAG(
|
|
powered_mass_point_definition->flags,
|
|
_powered_mass_point_air_friction_bit) &&
|
|
powered_mass_point->air_friction_velocity != 0.0f)
|
|
{
|
|
real_vector3d powered_velocity;
|
|
|
|
scale_vector3d(
|
|
&mass_point->forward,
|
|
-powered_mass_point->air_friction_velocity,
|
|
&powered_velocity);
|
|
add_vectors3d(&powered_velocity, &mass_point->velocity, &powered_velocity);
|
|
scale_vector3d(
|
|
&powered_velocity,
|
|
air_scale,
|
|
&mass_point->air_friction.friction);
|
|
}
|
|
else
|
|
{
|
|
scale_vector3d(
|
|
&mass_point->velocity,
|
|
air_scale,
|
|
&mass_point->air_friction.friction);
|
|
}
|
|
|
|
friction_evaluate(
|
|
mass_point_definition->friction_type,
|
|
mass_point_definition->friction_parallel_scale,
|
|
mass_point_definition->friction_perpendicular_scale,
|
|
&mass_point->air_friction,
|
|
&mass_point->forward,
|
|
&mass_point->up);
|
|
|
|
if (powered_mass_point_definition &&
|
|
TEST_FLAG(
|
|
powered_mass_point_definition->flags,
|
|
_powered_mass_point_air_lift_bit) &&
|
|
powered_mass_point->air_lift_ratio != 0.0f)
|
|
{
|
|
real lift = fabs(dot_product3d(&mass_point->forward, &mass_point->velocity))*
|
|
powered_mass_point->air_lift_ratio*physics->mass;
|
|
real_vector3d lift_force;
|
|
|
|
scale_vector3d(&mass_point->up, lift, &lift_force);
|
|
add_vectors3d(&mass_point->powered_force, &lift_force, &mass_point->powered_force);
|
|
}
|
|
}
|
|
|
|
SET_FLAG(
|
|
mass_point->flags,
|
|
_point_at_rest_bit,
|
|
magnitude_squared3d(&mass_point->velocity) < 0.0011111111f);
|
|
SET_FLAG(mass_point->flags, _point_on_ground_bit, mass_point->ground_depth > 0.0f);
|
|
SET_FLAG(mass_point->flags, _point_in_water_bit, mass_point->water_depth > 0.0f);
|
|
stopped_mass_point_count += TEST_FLAG(mass_point->flags, _point_at_rest_bit);
|
|
grounded_mass_point_count += TEST_FLAG(mass_point->flags, _point_on_ground_bit);
|
|
volatile_mass_point_count += TEST_FLAG(
|
|
mass_point->flags,
|
|
_point_on_volatile_surface_bit);
|
|
submerged_mass_point_count += TEST_FLAG(mass_point->flags, _point_in_water_bit);
|
|
|
|
if (powered_mass_point_definition)
|
|
{
|
|
if (TEST_FLAG(
|
|
powered_mass_point_definition->flags,
|
|
_powered_mass_point_thrust_bit))
|
|
{
|
|
real_vector3d thrust;
|
|
|
|
scale_vector3d(
|
|
&mass_point->forward,
|
|
powered_mass_point->thrust_fraction*physics->mass,
|
|
&thrust);
|
|
add_vectors3d(&mass_point->powered_force, &thrust, &mass_point->powered_force);
|
|
}
|
|
|
|
if (TEST_FLAG(
|
|
powered_mass_point_definition->flags,
|
|
_powered_mass_point_antigrav_bit))
|
|
{
|
|
real probe_length =
|
|
mass_point_definition->radius + powered_mass_point_definition->antigrav_height;
|
|
real_point3d point = mass_point->position;
|
|
real_vector3d probe_vector;
|
|
struct collision_result collision;
|
|
|
|
scale_vector3d(global_down3d, probe_length, &probe_vector);
|
|
if (collision_test_vector(
|
|
_collision_test_for_bipeds_dead_flags,
|
|
&point,
|
|
&probe_vector,
|
|
object_index,
|
|
&collision))
|
|
{
|
|
real height = probe_length*collision.t - mass_point_definition->radius;
|
|
real alignment = pin_fraction(
|
|
mass_point->up.k,
|
|
powered_mass_point_definition->antigrav_normal_k0,
|
|
powered_mass_point_definition->antigrav_normal_k1);
|
|
real ground_effect = height > 0.0f ?
|
|
1.0f - height/powered_mass_point_definition->antigrav_height : 1.0f;
|
|
real magnitude = (ground_effect*ground_effect*global_gravity -
|
|
dot_product3d(&collision.plane.n, &mass_point->velocity)*
|
|
powered_mass_point_definition->antigrav_damp_fraction)*
|
|
powered_mass_point->antigrav_fraction*
|
|
powered_mass_point_definition->antigrav_strength*
|
|
physics->mass*alignment;
|
|
real_vector3d antigrav_force;
|
|
|
|
scale_vector3d(&collision.plane.n, magnitude, &antigrav_force);
|
|
add_vectors3d(
|
|
&mass_point->powered_force,
|
|
&antigrav_force,
|
|
&mass_point->powered_force);
|
|
}
|
|
}
|
|
}
|
|
|
|
add_vectors3d(&mass_point->normal_force, &mass_point->ground_friction.friction, &mass_point->force);
|
|
add_vectors3d(&mass_point->force, &mass_point->water_pressure, &mass_point->force);
|
|
add_vectors3d(&mass_point->force, &mass_point->water_friction.friction, &mass_point->force);
|
|
add_vectors3d(&mass_point->force, &mass_point->air_friction.friction, &mass_point->force);
|
|
add_vectors3d(&mass_point->force, &mass_point->powered_force, &mass_point->force);
|
|
cross_product3d(&mass_point->radius, &mass_point->force, &mass_point->torque);
|
|
add_vectors3d(&total_force, &mass_point->force, &total_force);
|
|
add_vectors3d(&total_torque, &mass_point->torque, &total_torque);
|
|
}
|
|
|
|
if (physics->mass != 0.0f)
|
|
scale_vector3d(&total_force, 1.0f/physics->mass, &translational_acceleration);
|
|
|
|
{
|
|
real_vector3d torque_axis = total_torque;
|
|
real torque_magnitude = normalize3d(&torque_axis);
|
|
|
|
if (torque_magnitude != 0.0f)
|
|
{
|
|
real moment_of_inertia = 0.0f;
|
|
|
|
for (mass_point_index = 0;
|
|
mass_point_index < mass_point_count;
|
|
mass_point_index++)
|
|
{
|
|
struct mass_point_definition const *mass_point_definition = TAG_BLOCK_GET_ELEMENT(
|
|
&physics->mass_points,
|
|
mass_point_index,
|
|
struct mass_point_definition);
|
|
struct mass_point_datum const *mass_point = mass_points + mass_point_index;
|
|
real projection = -dot_product3d(&mass_point->radius, &torque_axis);
|
|
real_vector3d perpendicular_radius;
|
|
|
|
scale_vector3d(&torque_axis, projection, &perpendicular_radius);
|
|
add_vectors3d(
|
|
&perpendicular_radius,
|
|
&mass_point->radius,
|
|
&perpendicular_radius);
|
|
moment_of_inertia += (
|
|
magnitude_squared3d(&perpendicular_radius) +
|
|
mass_point_definition->radius*mass_point_definition->radius*0.4f)*
|
|
mass_point_definition->mass*physics->moment;
|
|
}
|
|
|
|
if (moment_of_inertia != 0.0f)
|
|
{
|
|
scale_vector3d(
|
|
&total_torque,
|
|
1.0f/moment_of_inertia,
|
|
&angular_acceleration);
|
|
}
|
|
}
|
|
}
|
|
|
|
match_assert_valid_real_vector3d(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
1539,
|
|
&translational_acceleration);
|
|
add_vectors3d(
|
|
&object->object.translational_velocity,
|
|
&translational_acceleration,
|
|
&object->object.translational_velocity);
|
|
match_assert_valid_real_vector3d(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
1543,
|
|
&angular_acceleration);
|
|
add_vectors3d(
|
|
&object->object.angular_velocity,
|
|
&angular_acceleration,
|
|
&object->object.angular_velocity);
|
|
|
|
{
|
|
real_point3d new_position;
|
|
struct location new_location;
|
|
real_vector3d rotation_axis;
|
|
real angular_speed;
|
|
|
|
new_position.x = object->object.position.x + object->object.translational_velocity.i;
|
|
new_position.y = object->object.position.y + object->object.translational_velocity.j;
|
|
new_position.z = object->object.position.z + object->object.translational_velocity.k;
|
|
scenario_location_from_line(
|
|
&new_location,
|
|
&object->object.location,
|
|
&object->object.position,
|
|
&new_position);
|
|
object_translate(object_index, &new_position, &new_location);
|
|
|
|
rotation_axis = object->object.angular_velocity;
|
|
angular_speed = normalize3d(&rotation_axis);
|
|
if (angular_speed != 0.0f)
|
|
{
|
|
real sine_value = sine(angular_speed);
|
|
real cosine_value = cosine(angular_speed);
|
|
real orthogonalization;
|
|
|
|
rotate_vector_about_axis(
|
|
&object->object.forward,
|
|
&rotation_axis,
|
|
sine_value,
|
|
cosine_value);
|
|
rotate_vector_about_axis(
|
|
&object->object.up,
|
|
&rotation_axis,
|
|
sine_value,
|
|
cosine_value);
|
|
normalize3d(&object->object.forward);
|
|
orthogonalization = -dot_product3d(
|
|
&object->object.up,
|
|
&object->object.forward);
|
|
object->object.up.i += orthogonalization*object->object.forward.i;
|
|
object->object.up.j += orthogonalization*object->object.forward.j;
|
|
object->object.up.k += orthogonalization*object->object.forward.k;
|
|
normalize3d(&object->object.up);
|
|
}
|
|
}
|
|
|
|
SET_FLAG(
|
|
object->object.flags,
|
|
_object_at_rest_bit,
|
|
stopped_mass_point_count == mass_point_count &&
|
|
grounded_mass_point_count >= 3 &&
|
|
volatile_mass_point_count == 0 &&
|
|
magnitude_squared3d(&object->object.translational_velocity) <= 0.0011111111f &&
|
|
magnitude_squared3d(&object->object.angular_velocity) <= 0.0027415568f &&
|
|
magnitude_squared3d(&translational_acceleration) <= 0.00000030864197f &&
|
|
magnitude_squared3d(&angular_acceleration) <= 0.0000030461742f);
|
|
SET_FLAG(object->object.flags, _object_on_ground_bit, grounded_mass_point_count > 0);
|
|
SET_FLAG(object->object.flags, _object_on_media_bit, submerged_mass_point_count > 0);
|
|
SET_FLAG(object->object.flags, _object_partially_under_media_bit, submerged_mass_point_count > 0);
|
|
SET_FLAG(
|
|
object->object.flags,
|
|
_object_wholly_under_media_bit,
|
|
submerged_mass_point_count == mass_point_count);
|
|
match_assert_valid_real_vector3d_axes2(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
1595,
|
|
&object->object.forward,
|
|
&object->object.up);
|
|
|
|
return;
|
|
}
|
|
|
|
void physics_update(
|
|
long object_index,
|
|
struct powered_mass_point_datum *powered_mass_points,
|
|
struct mass_point_datum *mass_points,
|
|
real_vector3d const *magic_force,
|
|
real_vector3d const *magic_torque)
|
|
{
|
|
struct object_datum *object = object_get(object_index);
|
|
struct object_definition *object_definition = object_definition_get(object->definition_index);
|
|
struct physics_definition *physics = physics_definition_get(
|
|
object_definition->object.physics.index);
|
|
struct physics_instance instance;
|
|
real_vector3d total_force;
|
|
real_vector3d total_torque;
|
|
short powered_mass_point_index;
|
|
|
|
if (physics->radius > 0.0f)
|
|
{
|
|
physics_update_old(
|
|
object_index,
|
|
powered_mass_points,
|
|
mass_points,
|
|
magic_force,
|
|
magic_torque);
|
|
return;
|
|
}
|
|
|
|
physics_instance_new(&instance, object_index);
|
|
if (powered_mass_points)
|
|
{
|
|
/* port: (physics_powered_mass_point_count) */
|
|
for (powered_mass_point_index = 0;
|
|
powered_mass_point_index < physics_powered_mass_point_count(physics);
|
|
powered_mass_point_index++)
|
|
{
|
|
struct powered_mass_point_datum *powered_mass_point =
|
|
powered_mass_points + powered_mass_point_index;
|
|
|
|
matrix4x3_rotation_from_quaternion(
|
|
&powered_mass_point->rotation_matrix,
|
|
&powered_mass_point->rotation);
|
|
matrix4x3_transpose(&powered_mass_point->rotation_matrix);
|
|
}
|
|
}
|
|
|
|
physics_compute_new(
|
|
&instance,
|
|
powered_mass_points,
|
|
mass_points,
|
|
&total_force,
|
|
&total_torque);
|
|
|
|
{
|
|
struct vehicle_datum *vehicle = vehicle_datum_get(object_index);
|
|
|
|
total_force.i += vehicle->vehicle.collision_force.i;
|
|
total_force.j += vehicle->vehicle.collision_force.j;
|
|
total_force.k += vehicle->vehicle.collision_force.k;
|
|
total_torque.i += vehicle->vehicle.collision_torque.i;
|
|
total_torque.j += vehicle->vehicle.collision_torque.j;
|
|
total_torque.k += vehicle->vehicle.collision_torque.k;
|
|
vehicle->vehicle.collision_force.i = 0.0f;
|
|
vehicle->vehicle.collision_force.j = 0.0f;
|
|
vehicle->vehicle.collision_force.k = 0.0f;
|
|
vehicle->vehicle.collision_torque.i = 0.0f;
|
|
vehicle->vehicle.collision_torque.j = 0.0f;
|
|
vehicle->vehicle.collision_torque.k = 0.0f;
|
|
}
|
|
|
|
if (magic_force)
|
|
{
|
|
match_assert_valid_real_vector3d(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
270,
|
|
magic_force);
|
|
total_force.i += magic_force->i;
|
|
total_force.j += magic_force->j;
|
|
total_force.k += magic_force->k;
|
|
}
|
|
if (magic_torque)
|
|
{
|
|
match_assert_valid_real_vector3d(
|
|
"c:\\halo\\SOURCE\\physics\\physics.c",
|
|
276,
|
|
magic_torque);
|
|
total_torque.i += magic_torque->i;
|
|
total_torque.j += magic_torque->j;
|
|
total_torque.k += magic_torque->k;
|
|
}
|
|
|
|
physics_update_new(
|
|
&instance,
|
|
powered_mass_points,
|
|
mass_points,
|
|
&total_force,
|
|
&total_torque);
|
|
physics_compute_unit_collisions(object_index);
|
|
|
|
return;
|
|
}
|
|
|
|
/* ---------- private code */
|