diff options
Diffstat (limited to 'nGenEx/Physical.cpp')
-rw-r--r-- | nGenEx/Physical.cpp | 1575 |
1 files changed, 800 insertions, 775 deletions
diff --git a/nGenEx/Physical.cpp b/nGenEx/Physical.cpp index c1a3874..d58afbd 100644 --- a/nGenEx/Physical.cpp +++ b/nGenEx/Physical.cpp @@ -1,775 +1,800 @@ -/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: nGenEx.lib
- FILE: Physical.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Abstract Physical Object
-*/
-
-#include "MemDebug.h"
-#include "Physical.h"
-#include "Graphic.h"
-#include "Light.h"
-#include "Director.h"
-
-// +--------------------------------------------------------------------+
-
-int Physical::id_key = 1;
-double Physical::sub_frame = 1.0 / 60.0;
-
-static const double GRAV = 6.673e-11;
-
-// +--------------------------------------------------------------------+
-
-Physical::Physical()
-: id(id_key++), obj_type(0), rep(0), light(0),
-thrust(0.0f), drag(0.0f), lat_thrust(false),
-trans_x(0.0f), trans_y(0.0f), trans_z(0.0f), straight(false),
-roll(0.0f), pitch(0.0f), yaw(0.0f), dr(0.0f), dp(0.0f), dy(0.0f),
-dr_acc(0.0f), dp_acc(0.0f), dy_acc(0.0f),
-dr_drg(0.0f), dp_drg(0.0f), dy_drg(0.0f),
-flight_path_yaw(0.0f), flight_path_pitch(0.0f), primary_mass(0),
-roll_rate(1.0f), pitch_rate(1.0f), yaw_rate(1.0f), shake(0.0f),
-radius(0.0f), mass(1.0f), integrity(1.0f), life(-1), dir(0),
-g_accel(0.0f), Do(0.0f), CL(0.0f), CD(0.0f), alpha(0.0f), stall(0.0f)
-{
- strcpy_s(name, "unknown object");
-}
-
-// +--------------------------------------------------------------------+
-
-Physical::Physical(const char* n, int t)
-: id(id_key++), obj_type(t), rep(0), light(0),
-thrust(0.0f), drag(0.0f), lat_thrust(false),
-trans_x(0.0f), trans_y(0.0f), trans_z(0.0f), straight(false),
-roll(0.0f), pitch(0.0f), yaw(0.0f), dr(0.0f), dp(0.0f), dy(0.0f),
-dr_acc(0.0f), dp_acc(0.0f), dy_acc(0.0f),
-dr_drg(0.0f), dp_drg(0.0f), dy_drg(0.0f),
-flight_path_yaw(0.0f), flight_path_pitch(0.0f), primary_mass(0),
-roll_rate(1.0f), pitch_rate(1.0f), yaw_rate(1.0f), shake(0.0f),
-radius(0.0f), mass(1.0f), integrity(1.0f), life(-1), dir(0),
-g_accel(0.0f), Do(0.0f), CL(0.0f), CD(0.0f), alpha(0.0f), stall(0.0f)
-{
- strncpy_s(name, n, NAMELEN-1);
- name[NAMELEN-1] = 0;
-}
-
-// +--------------------------------------------------------------------+
-
-Physical::~Physical()
-{
- // inform graphic rep and light that we are leaving:
- GRAPHIC_DESTROY(rep);
- LIGHT_DESTROY(light);
-
- // we own the director
- delete dir;
- dir = 0;
-}
-
-// +--------------------------------------------------------------------+
-
-inline double random() { return rand()-16384; }
-
-void
-Physical::ExecFrame(double s)
-{
- Point orig_velocity = Velocity();
- arcade_velocity = Point();
-
- // if this object is under direction,
- // but doesn't need subframe accuracy,
- // update the control parameters:
- if (dir && !dir->Subframe())
- dir->ExecFrame(s);
-
- // decrement life before destroying the frame time:
- if (life > 0)
- life -= s;
-
- // integrate equations
- // using slices no larger
- // than sub_frame:
-
- double seconds = s;
-
- while (s > 0.0) {
- if (s > sub_frame)
- seconds = sub_frame;
- else
- seconds = s;
-
- // if the director needs subframe accuracy, run it now:
- if (dir && dir->Subframe())
- dir->ExecFrame(seconds);
-
- if (!straight)
- AngularFrame(seconds);
-
- // LINEAR MOVEMENT ----------------------------
- Point pos = cam.Pos();
-
- // if the object is thrusting,
- // accelerate along the camera normal:
- if (thrust) {
- Point thrustvec = cam.vpn();
- thrustvec *= ((thrust/mass) * seconds);
- velocity += thrustvec;
- }
-
- LinearFrame(seconds);
-
- // move the position by the (time-frame scaled) velocity:
- pos += velocity * seconds;
- cam.MoveTo(pos);
-
- s -= seconds;
- }
-
- alpha = 0.0f;
-
- // now update the graphic rep and light sources:
- if (rep) {
- rep->MoveTo(cam.Pos());
- rep->SetOrientation(cam.Orientation());
- }
-
- if (light) {
- light->MoveTo(cam.Pos());
- }
-
- if (!straight)
- CalcFlightPath();
-
- accel = (Velocity() - orig_velocity) * (1/seconds);
- if (!_finite(accel.x) || !_finite(accel.y) || !_finite(accel.z))
- accel = Point();
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Physical::AeroFrame(double s)
-{
- arcade_velocity = Point();
-
- // if this object is under direction,
- // but doesn't need subframe accuracy,
- // update the control parameters:
- if (dir && !dir->Subframe())
- dir->ExecFrame(s);
-
- // decrement life before destroying the frame time:
- if (life > 0)
- life -= s;
-
- // integrate equations
- // using slices no larger
- // than sub_frame:
-
- double seconds = s;
-
- while (s > 0.0) {
- if (s > sub_frame)
- seconds = sub_frame;
- else
- seconds = s;
-
- // if the director needs subframe accuracy, run it now:
- if (dir && dir->Subframe())
- dir->ExecFrame(seconds);
-
- AngularFrame(seconds);
-
- // LINEAR MOVEMENT ----------------------------
- Point pos = cam.Pos();
-
- // if the object is thrusting,
- // accelerate along the camera normal:
- if (thrust) {
- Point thrustvec = cam.vpn();
- thrustvec *= ((thrust/mass) * seconds);
- velocity += thrustvec;
- }
-
- // AERODYNAMICS ------------------------------
-
- if (lat_thrust)
- LinearFrame(seconds);
-
- // if no thrusters, do constant gravity:
- else if (g_accel > 0)
- velocity += Point(0, -g_accel, 0) * seconds;
-
- // compute alpha, rho, drag, and lift:
-
- Point vfp = velocity;
- double v = vfp.Normalize();
- double v_2 = 0;
- double rho = GetDensity();
- double lift = 0;
-
- if (v > 150) {
- v_2 = (v-150) * (v-150);
-
- Point vfp1 = vfp - cam.vrt() * (vfp * cam.vrt());
- vfp1.Normalize();
-
- double cos_alpha = vfp1 * cam.vpn();
-
- if (cos_alpha >= 1) {
- alpha = 0.0f;
- }
- else {
- alpha = (float) acos(cos_alpha);
- }
-
- // if flight path is above nose, alpha is negative:
- if (vfp1 * cam.vup() > 0)
- alpha = -alpha;
-
- if (alpha <= stall) {
- lift = CL * alpha * rho * v_2;
- }
- else {
- lift = CL * (2*stall - alpha) * rho * v_2;
- }
-
- // add lift to velocity:
- if (_finite(lift))
- velocity += cam.vup() * lift * seconds;
- else
- lift = 0;
-
- // if drag applies, decellerate:
- double alpha_2 = alpha*alpha;
- double drag_eff = (drag + (CD * alpha_2)) * rho * v_2;
-
- Point vn = velocity;
- vn.Normalize();
-
- velocity += vn * -drag_eff * seconds;
- }
- else {
- velocity *= exp(-drag * seconds);
- }
-
- // move the position by the (time-frame scaled) velocity:
- pos += velocity * seconds;
- cam.MoveTo(pos);
-
- s -= seconds;
- }
-
- // now update the graphic rep and light sources:
- if (rep) {
- rep->MoveTo(cam.Pos());
- rep->SetOrientation(cam.Orientation());
- }
-
- if (light) {
- light->MoveTo(cam.Pos());
- }
-}
-
-double
-Physical::GetDensity() const
-{
- double alt = cam.Pos().y;
- double rho = 0.75 * Do * (250e3-alt)/250e3;
-
- return rho;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Physical::ArcadeFrame(double s)
-{
- // if this object is under direction,
- // but doesn't need subframe accuracy,
- // update the control parameters:
- if (dir && !dir->Subframe())
- dir->ExecFrame(s);
-
- // decrement life before destroying the frame time:
- if (life > 0)
- life -= s;
-
- // integrate equations
- // using slices no larger
- // than sub_frame:
-
- double seconds = s;
-
- while (s > 0.0) {
- if (s > sub_frame)
- seconds = sub_frame;
- else
- seconds = s;
-
- // if the director needs subframe accuracy, run it now:
- if (dir && dir->Subframe())
- dir->ExecFrame(seconds);
-
- if (!straight)
- AngularFrame(seconds);
-
- Point pos = cam.Pos();
-
- // ARCADE FLIGHT MODEL:
- // arcade_velocity vector is always in line with heading
-
- double speed = arcade_velocity.Normalize();
- double bleed = arcade_velocity * cam.vpn();
-
- speed *= pow(bleed, 30);
- arcade_velocity = cam.vpn() * speed;
-
- if (thrust) {
- Point thrustvec = cam.vpn();
- thrustvec *= ((thrust/mass) * seconds);
- arcade_velocity += thrustvec;
- }
-
- if (drag)
- arcade_velocity *= exp(-drag * seconds);
-
- LinearFrame(seconds);
-
- // move the position by the (time-frame scaled) velocity:
- pos += arcade_velocity * seconds +
- velocity * seconds;
-
- cam.MoveTo(pos);
-
- s -= seconds;
- }
-
- alpha = 0.0f;
-
- // now update the graphic rep and light sources:
- if (rep) {
- rep->MoveTo(cam.Pos());
- rep->SetOrientation(cam.Orientation());
- }
-
- if (light) {
- light->MoveTo(cam.Pos());
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Physical::AngularFrame(double seconds)
-{
- if (!straight) {
- dr += (float) (dr_acc * seconds);
- dy += (float) (dy_acc * seconds);
- dp += (float) (dp_acc * seconds);
-
- dr *= (float) exp(-dr_drg * seconds);
- dy *= (float) exp(-dy_drg * seconds);
- dp *= (float) exp(-dp_drg * seconds);
-
- roll = (float) (dr * seconds);
- pitch = (float) (dp * seconds);
- yaw = (float) (dy * seconds);
-
- if (shake > 0.01) {
- vibration = Point(random(), random(), random());
- vibration.Normalize();
- vibration *= (float) (shake * seconds);
-
- shake *= (float) exp(-1.5 * seconds);
- }
- else {
- vibration.x = vibration.y = vibration.z = 0.0f;
- shake = 0.0f;
- }
-
- cam.Aim(roll, pitch, yaw);
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Physical::LinearFrame(double seconds)
-{
- // deal with lateral thrusters:
-
- if (trans_x) { // side-to-side
- Point transvec = cam.vrt();
- transvec *= ((trans_x/mass) * seconds);
-
- velocity += transvec;
- }
-
- if (trans_y) { // fore-and-aft
- Point transvec = cam.vpn();
- transvec *= ((trans_y/mass) * seconds);
-
- velocity += transvec;
- }
-
- if (trans_z) { // up-and-down
- Point transvec = cam.vup();
- transvec *= ((trans_z/mass) * seconds);
-
- velocity += transvec;
- }
-
- // if gravity applies, attract:
- if (primary_mass > 0) {
- Point g = primary_loc - cam.Pos();
- double r = g.Normalize();
-
- g *= GRAV * primary_mass / (r*r);
-
- velocity += g * seconds;
- }
-
- // constant gravity:
- else if (g_accel > 0)
- velocity += Point(0, -g_accel, 0) * seconds;
-
- // if drag applies, decellerate:
- if (drag)
- velocity *= exp(-drag * seconds);
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Physical::CalcFlightPath()
-{
- flight_path_yaw = 0.0f;
- flight_path_pitch = 0.0f;
-
- // transform flight path into camera frame:
- Point flight_path = velocity;
- if (flight_path.Normalize() < 1)
- return;
-
- Point tmp = flight_path;
- flight_path.x = tmp * cam.vrt();
- flight_path.y = tmp * cam.vup();
- flight_path.z = tmp * cam.vpn();
-
- if (flight_path.z < 0.1)
- return;
-
- // first, compute azimuth:
- flight_path_yaw = (float) atan(flight_path.x / flight_path.z);
- if (flight_path.z < 0) flight_path_yaw -= (float) PI;
- if (flight_path_yaw < -PI) flight_path_yaw += (float) (2*PI);
-
- // then, rotate path into azimuth frame to compute elevation:
- Camera yaw_cam;
- yaw_cam.Clone(cam);
- yaw_cam.Yaw(flight_path_yaw);
-
- flight_path.x = tmp * yaw_cam.vrt();
- flight_path.y = tmp * yaw_cam.vup();
- flight_path.z = tmp * yaw_cam.vpn();
-
- flight_path_pitch = (float) atan(flight_path.y / flight_path.z);
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Physical::MoveTo(const Point& new_loc)
-{
- cam.MoveTo(new_loc);
-}
-
-void
-Physical::TranslateBy(const Point& ref)
-{
- Point new_loc = cam.Pos() - ref;
- cam.MoveTo(new_loc);
-}
-
-void
-Physical::ApplyForce(const Point& force)
-{
- velocity += force/mass;
-}
-
-void
-Physical::ApplyTorque(const Point& torque)
-{
- dr += (float) (torque.x/mass);
- dp += (float) (torque.y/mass);
- dy += (float) (torque.z/mass);
-}
-
-void
-Physical::SetThrust(double t)
-{
- thrust = (float) t;
-}
-
-void
-Physical::SetTransX(double t)
-{
- trans_x = (float) t;
-}
-
-void
-Physical::SetTransY(double t)
-{
- trans_y = (float) t;
-}
-
-void
-Physical::SetTransZ(double t)
-{
- trans_z = (float) t;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Physical::SetHeading(double r, double p, double y)
-{
- roll = (float) r;
- pitch = (float) p;
- yaw = (float) y;
-
- cam.Aim(roll, pitch, yaw);
-}
-
-void
-Physical::LookAt(const Point& dst)
-{
- cam.LookAt(dst);
-}
-
-void
-Physical::CloneCam(const Camera& c)
-{
- cam.Clone(c);
-}
-
-void
-Physical::SetAbsoluteOrientation(double r, double p, double y)
-{
- roll = (float) r;
- pitch = (float) p;
- yaw = (float) y;
-
- Camera work(Location().x, Location().y, Location().z);
- work.Aim(r,p,y);
- cam.Clone(work);
-}
-
-void
-Physical::ApplyRoll(double r)
-{
- if (r > 1) r = 1;
- else if (r < -1) r = -1;
-
- dr_acc = (float) r * roll_rate;
-}
-
-void
-Physical::ApplyPitch(double p)
-{
- if (p > 1) p = 1;
- else if (p < -1) p = -1;
-
- dp_acc = (float) p * pitch_rate;
-}
-
-void
-Physical::ApplyYaw(double y)
-{
- if (y > 1) y = 1;
- else if (y < -1) y = -1;
-
- dy_acc = (float) y * yaw_rate;
-}
-
-void
-Physical::SetAngularRates(double r, double p, double y)
-{
- roll_rate = (float) r;
- pitch_rate = (float) p;
- yaw_rate = (float) y;
-}
-
-void
-Physical::GetAngularRates(double& r, double& p, double& y)
-{
- r = roll_rate;
- p = pitch_rate;
- y = yaw_rate;
-}
-
-void
-Physical::SetAngularDrag(double r, double p, double y)
-{
- dr_drg = (float) r;
- dp_drg = (float) p;
- dy_drg = (float) y;
-}
-
-void
-Physical::GetAngularDrag(double& r, double& p, double& y)
-{
- r = dr_drg;
- p = dp_drg;
- y = dy_drg;
-}
-
-void
-Physical::GetAngularThrust(double& r, double& p, double& y)
-{
- r = 0;
- p = 0;
- y = 0;
-
- if (dr_acc > 0.05 * roll_rate) r = 1;
- else if (dr_acc < -0.05 * roll_rate) r = -1;
- else if (dr > 0.01 * roll_rate) r = -1;
- else if (dr < -0.01 * roll_rate) r = 1;
-
- if (dy_acc > 0.05 * yaw_rate) y = 1;
- else if (dy_acc < -0.05 * yaw_rate) y = -1;
- else if (dy > 0.01 * yaw_rate) y = -1;
- else if (dy < -0.01 * yaw_rate) y = 1;
-
- if (dp_acc > 0.05 * pitch_rate) p = 1;
- else if (dp_acc < -0.05 * pitch_rate) p = -1;
- else if (dp > 0.01 * pitch_rate) p = -1;
- else if (dp < -0.01 * pitch_rate) p = 1;
-}
-
-
-void
-Physical::SetPrimary(const Point& l, double m)
-{
- primary_loc = l;
- primary_mass = m;
-}
-
-void
-Physical::SetGravity(double g)
-{
- if (g >= 0)
- g_accel = (float) g;
-}
-
-void
-Physical::SetBaseDensity(double d)
-{
- if (d >= 0)
- Do = (float) d;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Physical::InflictDamage(double damage, int /*type*/)
-{
- integrity -= (float) damage;
-
- if (integrity < 1.0f)
- integrity = 0.0f;
-}
-
-// +--------------------------------------------------------------------+
-
-int
-Physical::CollidesWith(Physical& o)
-{
- // representation collision test (will do bounding spheres first):
- if (rep && o.rep)
- return rep->CollidesWith(*o.rep);
-
- Point delta_loc = Location() - o.Location();
-
- // bounding spheres test:
- if (delta_loc.length() > radius + o.radius)
- return 0;
-
- // assume collision:
- return 1;
-}
-
-
-// +--------------------------------------------------------------------+
-
-void
-Physical::ElasticCollision(Physical& a, Physical& b)
-{
- double mass_sum = a.mass + b.mass;
- double mass_delta = a.mass - b.mass;
-
- Point vel_a = (Point(b.velocity) * (2 * b.mass) + Point(a.velocity) * mass_delta) * (1/mass_sum);
- Point vel_b = (Point(a.velocity) * (2 * a.mass) - Point(b.velocity) * mass_delta) * (1/mass_sum);
-
- a.velocity = vel_a;
- b.velocity = vel_b;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Physical::InelasticCollision(Physical& a, Physical& b)
-{
- double mass_sum = a.mass + b.mass;
-
- Point vel_a = (Point(a.velocity) * a.mass + Point(b.velocity) * b.mass) * (1/mass_sum);
-
- a.velocity = vel_a;
- b.velocity = vel_a;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-Physical::SemiElasticCollision(Physical& a, Physical& b)
-{
- double mass_sum = a.mass + b.mass;
- double mass_delta = a.mass - b.mass;
-
- Point avel = a.Velocity();
- Point bvel = b.Velocity();
- Point dv = avel - bvel;
-
- // low delta-v: stick
- if (dv.length() < 20) {
- if (a.mass > b.mass) {
- b.velocity = a.velocity;
- }
-
- else {
- a.velocity = b.velocity;
- }
- }
-
- // high delta-v: bounce
- else {
- Point Ve_a = (bvel * (2 * b.mass) + avel * mass_delta) * (1/mass_sum) * 0.65;
- Point Ve_b = (avel * (2 * a.mass) - bvel * mass_delta) * (1/mass_sum) * 0.65;
- Point Vi_ab = (avel * a.mass + bvel * b.mass) * (1/mass_sum) * 0.35;
-
- a.arcade_velocity = Point();
- b.arcade_velocity = Point();
-
- a.velocity = Ve_a + Vi_ab;
- b.velocity = Ve_b + Vi_ab;
- }
-}
-
+/* Starshatter OpenSource Distribution + Copyright (c) 1997-2004, Destroyer Studios LLC. + All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name "Destroyer Studios" nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + SUBSYSTEM: nGenEx.lib + FILE: Physical.cpp + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Abstract Physical Object +*/ + +#include "MemDebug.h" +#include "Physical.h" +#include "Graphic.h" +#include "Light.h" +#include "Director.h" + +// +--------------------------------------------------------------------+ + +int Physical::id_key = 1; +double Physical::sub_frame = 1.0 / 60.0; + +static const double GRAV = 6.673e-11; + +// +--------------------------------------------------------------------+ + +Physical::Physical() + : id(id_key++), obj_type(0), rep(0), light(0), + thrust(0.0f), drag(0.0f), lat_thrust(false), + trans_x(0.0f), trans_y(0.0f), trans_z(0.0f), straight(false), + roll(0.0f), pitch(0.0f), yaw(0.0f), dr(0.0f), dp(0.0f), dy(0.0f), + dr_acc(0.0f), dp_acc(0.0f), dy_acc(0.0f), + dr_drg(0.0f), dp_drg(0.0f), dy_drg(0.0f), + flight_path_yaw(0.0f), flight_path_pitch(0.0f), primary_mass(0), + roll_rate(1.0f), pitch_rate(1.0f), yaw_rate(1.0f), shake(0.0f), + radius(0.0f), mass(1.0f), integrity(1.0f), life(-1), dir(0), + g_accel(0.0f), Do(0.0f), CL(0.0f), CD(0.0f), alpha(0.0f), stall(0.0f) +{ + strcpy_s(name, "unknown object"); +} + +// +--------------------------------------------------------------------+ + +Physical::Physical(const char* n, int t) + : id(id_key++), obj_type(t), rep(0), light(0), + thrust(0.0f), drag(0.0f), lat_thrust(false), + trans_x(0.0f), trans_y(0.0f), trans_z(0.0f), straight(false), + roll(0.0f), pitch(0.0f), yaw(0.0f), dr(0.0f), dp(0.0f), dy(0.0f), + dr_acc(0.0f), dp_acc(0.0f), dy_acc(0.0f), + dr_drg(0.0f), dp_drg(0.0f), dy_drg(0.0f), + flight_path_yaw(0.0f), flight_path_pitch(0.0f), primary_mass(0), + roll_rate(1.0f), pitch_rate(1.0f), yaw_rate(1.0f), shake(0.0f), + radius(0.0f), mass(1.0f), integrity(1.0f), life(-1), dir(0), + g_accel(0.0f), Do(0.0f), CL(0.0f), CD(0.0f), alpha(0.0f), stall(0.0f) +{ + strncpy_s(name, n, NAMELEN-1); + name[NAMELEN-1] = 0; +} + +// +--------------------------------------------------------------------+ + +Physical::~Physical() +{ + // inform graphic rep and light that we are leaving: + GRAPHIC_DESTROY(rep); + LIGHT_DESTROY(light); + + // we own the director + delete dir; + dir = 0; +} + +// +--------------------------------------------------------------------+ + +inline double random() { return rand()-16384; } + +void +Physical::ExecFrame(double s) +{ + Point orig_velocity = Velocity(); + arcade_velocity = Point(); + + // if this object is under direction, + // but doesn't need subframe accuracy, + // update the control parameters: + if (dir && !dir->Subframe()) + dir->ExecFrame(s); + + // decrement life before destroying the frame time: + if (life > 0) + life -= s; + + // integrate equations + // using slices no larger + // than sub_frame: + + double seconds = s; + + while (s > 0.0) { + if (s > sub_frame) + seconds = sub_frame; + else + seconds = s; + + // if the director needs subframe accuracy, run it now: + if (dir && dir->Subframe()) + dir->ExecFrame(seconds); + + if (!straight) + AngularFrame(seconds); + + // LINEAR MOVEMENT ---------------------------- + Point pos = cam.Pos(); + + // if the object is thrusting, + // accelerate along the camera normal: + if (thrust) { + Point thrustvec = cam.vpn(); + thrustvec *= ((thrust/mass) * seconds); + velocity += thrustvec; + } + + LinearFrame(seconds); + + // move the position by the (time-frame scaled) velocity: + pos += velocity * seconds; + cam.MoveTo(pos); + + s -= seconds; + } + + alpha = 0.0f; + + // now update the graphic rep and light sources: + if (rep) { + rep->MoveTo(cam.Pos()); + rep->SetOrientation(cam.Orientation()); + } + + if (light) { + light->MoveTo(cam.Pos()); + } + + if (!straight) + CalcFlightPath(); + + accel = (Velocity() - orig_velocity) * (1/seconds); + if (!_finite(accel.x) || !_finite(accel.y) || !_finite(accel.z)) + accel = Point(); +} + +// +--------------------------------------------------------------------+ + +void +Physical::AeroFrame(double s) +{ + arcade_velocity = Point(); + + // if this object is under direction, + // but doesn't need subframe accuracy, + // update the control parameters: + if (dir && !dir->Subframe()) + dir->ExecFrame(s); + + // decrement life before destroying the frame time: + if (life > 0) + life -= s; + + // integrate equations + // using slices no larger + // than sub_frame: + + double seconds = s; + + while (s > 0.0) { + if (s > sub_frame) + seconds = sub_frame; + else + seconds = s; + + // if the director needs subframe accuracy, run it now: + if (dir && dir->Subframe()) + dir->ExecFrame(seconds); + + AngularFrame(seconds); + + // LINEAR MOVEMENT ---------------------------- + Point pos = cam.Pos(); + + // if the object is thrusting, + // accelerate along the camera normal: + if (thrust) { + Point thrustvec = cam.vpn(); + thrustvec *= ((thrust/mass) * seconds); + velocity += thrustvec; + } + + // AERODYNAMICS ------------------------------ + + if (lat_thrust) + LinearFrame(seconds); + + // if no thrusters, do constant gravity: + else if (g_accel > 0) + velocity += Point(0, -g_accel, 0) * seconds; + + // compute alpha, rho, drag, and lift: + + Point vfp = velocity; + double v = vfp.Normalize(); + double v_2 = 0; + double rho = GetDensity(); + double lift = 0; + + if (v > 150) { + v_2 = (v-150) * (v-150); + + Point vfp1 = vfp - cam.vrt() * (vfp * cam.vrt()); + vfp1.Normalize(); + + double cos_alpha = vfp1 * cam.vpn(); + + if (cos_alpha >= 1) { + alpha = 0.0f; + } + else { + alpha = (float) acos(cos_alpha); + } + + // if flight path is above nose, alpha is negative: + if (vfp1 * cam.vup() > 0) + alpha = -alpha; + + if (alpha <= stall) { + lift = CL * alpha * rho * v_2; + } + else { + lift = CL * (2*stall - alpha) * rho * v_2; + } + + // add lift to velocity: + if (_finite(lift)) + velocity += cam.vup() * lift * seconds; + else + lift = 0; + + // if drag applies, decellerate: + double alpha_2 = alpha*alpha; + double drag_eff = (drag + (CD * alpha_2)) * rho * v_2; + + Point vn = velocity; + vn.Normalize(); + + velocity += vn * -drag_eff * seconds; + } + else { + velocity *= exp(-drag * seconds); + } + + // move the position by the (time-frame scaled) velocity: + pos += velocity * seconds; + cam.MoveTo(pos); + + s -= seconds; + } + + // now update the graphic rep and light sources: + if (rep) { + rep->MoveTo(cam.Pos()); + rep->SetOrientation(cam.Orientation()); + } + + if (light) { + light->MoveTo(cam.Pos()); + } +} + +double +Physical::GetDensity() const +{ + double alt = cam.Pos().y; + double rho = 0.75 * Do * (250e3-alt)/250e3; + + return rho; +} + +// +--------------------------------------------------------------------+ + +void +Physical::ArcadeFrame(double s) +{ + // if this object is under direction, + // but doesn't need subframe accuracy, + // update the control parameters: + if (dir && !dir->Subframe()) + dir->ExecFrame(s); + + // decrement life before destroying the frame time: + if (life > 0) + life -= s; + + // integrate equations + // using slices no larger + // than sub_frame: + + double seconds = s; + + while (s > 0.0) { + if (s > sub_frame) + seconds = sub_frame; + else + seconds = s; + + // if the director needs subframe accuracy, run it now: + if (dir && dir->Subframe()) + dir->ExecFrame(seconds); + + if (!straight) + AngularFrame(seconds); + + Point pos = cam.Pos(); + + // ARCADE FLIGHT MODEL: + // arcade_velocity vector is always in line with heading + + double speed = arcade_velocity.Normalize(); + double bleed = arcade_velocity * cam.vpn(); + + speed *= pow(bleed, 30); + arcade_velocity = cam.vpn() * speed; + + if (thrust) { + Point thrustvec = cam.vpn(); + thrustvec *= ((thrust/mass) * seconds); + arcade_velocity += thrustvec; + } + + if (drag) + arcade_velocity *= exp(-drag * seconds); + + LinearFrame(seconds); + + // move the position by the (time-frame scaled) velocity: + pos += arcade_velocity * seconds + + velocity * seconds; + + cam.MoveTo(pos); + + s -= seconds; + } + + alpha = 0.0f; + + // now update the graphic rep and light sources: + if (rep) { + rep->MoveTo(cam.Pos()); + rep->SetOrientation(cam.Orientation()); + } + + if (light) { + light->MoveTo(cam.Pos()); + } +} + +// +--------------------------------------------------------------------+ + +void +Physical::AngularFrame(double seconds) +{ + if (!straight) { + dr += (float) (dr_acc * seconds); + dy += (float) (dy_acc * seconds); + dp += (float) (dp_acc * seconds); + + dr *= (float) exp(-dr_drg * seconds); + dy *= (float) exp(-dy_drg * seconds); + dp *= (float) exp(-dp_drg * seconds); + + roll = (float) (dr * seconds); + pitch = (float) (dp * seconds); + yaw = (float) (dy * seconds); + + if (shake > 0.01) { + vibration = Point(random(), random(), random()); + vibration.Normalize(); + vibration *= (float) (shake * seconds); + + shake *= (float) exp(-1.5 * seconds); + } + else { + vibration.x = vibration.y = vibration.z = 0.0f; + shake = 0.0f; + } + + cam.Aim(roll, pitch, yaw); + } +} + +// +--------------------------------------------------------------------+ + +void +Physical::LinearFrame(double seconds) +{ + // deal with lateral thrusters: + + if (trans_x) { // side-to-side + Point transvec = cam.vrt(); + transvec *= ((trans_x/mass) * seconds); + + velocity += transvec; + } + + if (trans_y) { // fore-and-aft + Point transvec = cam.vpn(); + transvec *= ((trans_y/mass) * seconds); + + velocity += transvec; + } + + if (trans_z) { // up-and-down + Point transvec = cam.vup(); + transvec *= ((trans_z/mass) * seconds); + + velocity += transvec; + } + + // if gravity applies, attract: + if (primary_mass > 0) { + Point g = primary_loc - cam.Pos(); + double r = g.Normalize(); + + g *= GRAV * primary_mass / (r*r); + + velocity += g * seconds; + } + + // constant gravity: + else if (g_accel > 0) { + velocity += Point(0, -g_accel, 0) * seconds; + } + + // if drag applies, decellerate: + if (drag) + velocity *= exp(-drag * seconds); +} + +// +--------------------------------------------------------------------+ + +void +Physical::CalcFlightPath() +{ + flight_path_yaw = 0.0f; + flight_path_pitch = 0.0f; + + // transform flight path into camera frame: + Point flight_path = velocity; + if (flight_path.Normalize() < 1) + return; + + Point tmp = flight_path; + flight_path.x = tmp * cam.vrt(); + flight_path.y = tmp * cam.vup(); + flight_path.z = tmp * cam.vpn(); + + if (flight_path.z < 0.1) + return; + + // first, compute azimuth: + flight_path_yaw = (float) atan(flight_path.x / flight_path.z); + if (flight_path.z < 0) flight_path_yaw -= (float) PI; + if (flight_path_yaw < -PI) flight_path_yaw += (float) (2*PI); + + // then, rotate path into azimuth frame to compute elevation: + Camera yaw_cam; + yaw_cam.Clone(cam); + yaw_cam.Yaw(flight_path_yaw); + + flight_path.x = tmp * yaw_cam.vrt(); + flight_path.y = tmp * yaw_cam.vup(); + flight_path.z = tmp * yaw_cam.vpn(); + + flight_path_pitch = (float) atan(flight_path.y / flight_path.z); +} + +// +--------------------------------------------------------------------+ + +void +Physical::MoveTo(const Point& new_loc) +{ + cam.MoveTo(new_loc); +} + +void +Physical::TranslateBy(const Point& ref) +{ + Point new_loc = cam.Pos() - ref; + cam.MoveTo(new_loc); +} + +void +Physical::ApplyForce(const Point& force) +{ + velocity += force/mass; +} + +void +Physical::ApplyTorque(const Point& torque) +{ + dr += (float) (torque.x/mass); + dp += (float) (torque.y/mass); + dy += (float) (torque.z/mass); +} + +void +Physical::SetThrust(double t) +{ + thrust = (float) t; +} + +void +Physical::SetTransX(double t) +{ + trans_x = (float) t; +} + +void +Physical::SetTransY(double t) +{ + trans_y = (float) t; +} + +void +Physical::SetTransZ(double t) +{ + trans_z = (float) t; +} + +// +--------------------------------------------------------------------+ + +void +Physical::SetHeading(double r, double p, double y) +{ + roll = (float) r; + pitch = (float) p; + yaw = (float) y; + + cam.Aim(roll, pitch, yaw); +} + +void +Physical::LookAt(const Point& dst) +{ + cam.LookAt(dst); +} + +void +Physical::CloneCam(const Camera& c) +{ + cam.Clone(c); +} + +void +Physical::SetAbsoluteOrientation(double r, double p, double y) +{ + roll = (float) r; + pitch = (float) p; + yaw = (float) y; + + Camera work(Location().x, Location().y, Location().z); + work.Aim(r,p,y); + cam.Clone(work); +} + +void +Physical::ApplyRoll(double r) +{ + if (r > 1) r = 1; + else if (r < -1) r = -1; + + dr_acc = (float) r * roll_rate; +} + +void +Physical::ApplyPitch(double p) +{ + if (p > 1) p = 1; + else if (p < -1) p = -1; + + dp_acc = (float) p * pitch_rate; +} + +void +Physical::ApplyYaw(double y) +{ + if (y > 1) y = 1; + else if (y < -1) y = -1; + + dy_acc = (float) y * yaw_rate; +} + +void +Physical::SetAngularRates(double r, double p, double y) +{ + roll_rate = (float) r; + pitch_rate = (float) p; + yaw_rate = (float) y; +} + +void +Physical::GetAngularRates(double& r, double& p, double& y) +{ + r = roll_rate; + p = pitch_rate; + y = yaw_rate; +} + +void +Physical::SetAngularDrag(double r, double p, double y) +{ + dr_drg = (float) r; + dp_drg = (float) p; + dy_drg = (float) y; +} + +void +Physical::GetAngularDrag(double& r, double& p, double& y) +{ + r = dr_drg; + p = dp_drg; + y = dy_drg; +} + +void +Physical::GetAngularThrust(double& r, double& p, double& y) +{ + r = 0; + p = 0; + y = 0; + + if (dr_acc > 0.05 * roll_rate) r = 1; + else if (dr_acc < -0.05 * roll_rate) r = -1; + else if (dr > 0.01 * roll_rate) r = -1; + else if (dr < -0.01 * roll_rate) r = 1; + + if (dy_acc > 0.05 * yaw_rate) y = 1; + else if (dy_acc < -0.05 * yaw_rate) y = -1; + else if (dy > 0.01 * yaw_rate) y = -1; + else if (dy < -0.01 * yaw_rate) y = 1; + + if (dp_acc > 0.05 * pitch_rate) p = 1; + else if (dp_acc < -0.05 * pitch_rate) p = -1; + else if (dp > 0.01 * pitch_rate) p = -1; + else if (dp < -0.01 * pitch_rate) p = 1; +} + + +void +Physical::SetPrimary(const Point& l, double m) +{ + primary_loc = l; + primary_mass = m; +} + +void +Physical::SetGravity(double g) +{ + if (g >= 0) + g_accel = (float) g; +} + +void +Physical::SetBaseDensity(double d) +{ + if (d >= 0) + Do = (float) d; +} + +// +--------------------------------------------------------------------+ + +void +Physical::InflictDamage(double damage, int /*type*/) +{ + integrity -= (float) damage; + + if (integrity < 1.0f) + integrity = 0.0f; +} + +// +--------------------------------------------------------------------+ + +int +Physical::CollidesWith(Physical& o) +{ + // representation collision test (will do bounding spheres first): + if (rep && o.rep) + return rep->CollidesWith(*o.rep); + + Point delta_loc = Location() - o.Location(); + + // bounding spheres test: + if (delta_loc.length() > radius + o.radius) + return 0; + + // assume collision: + return 1; +} + + +// +--------------------------------------------------------------------+ + +void +Physical::ElasticCollision(Physical& a, Physical& b) +{ + double mass_sum = a.mass + b.mass; + double mass_delta = a.mass - b.mass; + + Point vel_a = (Point(b.velocity) * (2 * b.mass) + Point(a.velocity) * mass_delta) * (1/mass_sum); + Point vel_b = (Point(a.velocity) * (2 * a.mass) - Point(b.velocity) * mass_delta) * (1/mass_sum); + + a.velocity = vel_a; + b.velocity = vel_b; +} + +// +--------------------------------------------------------------------+ + +void +Physical::InelasticCollision(Physical& a, Physical& b) +{ + double mass_sum = a.mass + b.mass; + + Point vel_a = (Point(a.velocity) * a.mass + Point(b.velocity) * b.mass) * (1/mass_sum); + + a.velocity = vel_a; + b.velocity = vel_a; +} + +// +--------------------------------------------------------------------+ + +void +Physical::SemiElasticCollision(Physical& a, Physical& b) +{ + double mass_sum = a.mass + b.mass; + double mass_delta = a.mass - b.mass; + + Point avel = a.Velocity(); + Point bvel = b.Velocity(); + Point dv = avel - bvel; + + // low delta-v: stick + if (dv.length() < 20) { + if (a.mass > b.mass) { + b.velocity = a.velocity; + } + + else { + a.velocity = b.velocity; + } + } + + // high delta-v: bounce + else { + Point Ve_a = (bvel * (2 * b.mass) + avel * mass_delta) * (1/mass_sum) * 0.65; + Point Ve_b = (avel * (2 * a.mass) - bvel * mass_delta) * (1/mass_sum) * 0.65; + Point Vi_ab = (avel * a.mass + bvel * b.mass) * (1/mass_sum) * 0.35; + + a.arcade_velocity = Point(); + b.arcade_velocity = Point(); + + a.velocity = Ve_a + Vi_ab; + b.velocity = Ve_b + Vi_ab; + } +} + |