2008-06-24 03:17:31 -07:00
|
|
|
#include "libs.h"
|
|
|
|
#include "Space.h"
|
|
|
|
#include "Body.h"
|
|
|
|
#include "Frame.h"
|
|
|
|
#include "Star.h"
|
|
|
|
#include "Planet.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <functional>
|
|
|
|
#include "Pi.h"
|
|
|
|
#include "Player.h"
|
|
|
|
#include "StarSystem.h"
|
2008-09-10 14:28:48 -07:00
|
|
|
#include "SpaceStation.h"
|
2008-09-18 07:00:12 -07:00
|
|
|
#include "Serializer.h"
|
2008-10-07 08:37:18 -07:00
|
|
|
#include "collider/collider.h"
|
2009-10-30 16:22:10 -07:00
|
|
|
#include "Missile.h"
|
2009-11-04 07:06:36 -08:00
|
|
|
#include "HyperspaceCloud.h"
|
2011-08-20 08:12:27 -07:00
|
|
|
#include "render/Render.h"
|
2011-03-05 09:27:47 -08:00
|
|
|
#include "WorldView.h"
|
2011-07-03 15:24:16 -07:00
|
|
|
#include "SectorView.h"
|
2011-09-30 18:52:04 -07:00
|
|
|
#include "Lang.h"
|
2011-11-12 03:34:11 -08:00
|
|
|
#include "SpaceManager.h"
|
2011-11-15 13:34:49 -08:00
|
|
|
#include "MathUtil.h"
|
2008-06-24 03:17:31 -07:00
|
|
|
|
2011-11-09 00:36:15 -08:00
|
|
|
Space::Space()
|
|
|
|
{
|
2011-11-16 00:21:00 -08:00
|
|
|
m_rootFrame.Reset(new Frame(0, Lang::SYSTEM));
|
2011-11-16 00:03:11 -08:00
|
|
|
m_rootFrame->SetRadius(FLT_MAX);
|
2011-11-09 00:36:15 -08:00
|
|
|
}
|
2011-11-08 13:25:58 -08:00
|
|
|
|
|
|
|
Space::Space(const SystemPath &path)
|
2008-06-24 03:17:31 -07:00
|
|
|
{
|
2011-11-08 13:25:58 -08:00
|
|
|
m_starSystem = StarSystem::GetCached(path);
|
|
|
|
|
|
|
|
// XXX set radius in constructor
|
2011-11-16 00:21:00 -08:00
|
|
|
m_rootFrame.Reset(new Frame(0, Lang::SYSTEM));
|
2011-11-16 00:03:11 -08:00
|
|
|
m_rootFrame->SetRadius(FLT_MAX);
|
2011-11-08 13:25:58 -08:00
|
|
|
|
2011-11-16 00:21:00 -08:00
|
|
|
GenBody(m_starSystem->rootBody, m_rootFrame.Get());
|
2011-11-16 00:03:11 -08:00
|
|
|
m_rootFrame->UpdateOrbitRails();
|
2008-06-24 03:17:31 -07:00
|
|
|
}
|
|
|
|
|
2011-11-08 13:25:58 -08:00
|
|
|
Space::Space(Serializer::Reader &rd)
|
2011-10-08 21:05:09 -07:00
|
|
|
{
|
2011-11-08 13:25:58 -08:00
|
|
|
assert(0);
|
2011-10-08 21:05:09 -07:00
|
|
|
}
|
|
|
|
|
2011-11-08 13:25:58 -08:00
|
|
|
Space::~Space()
|
2008-06-24 03:17:31 -07:00
|
|
|
{
|
2011-11-13 14:00:15 -08:00
|
|
|
UpdateBodies(); // make sure anything waiting to be removed gets removed before we go and kill everything else
|
2011-11-09 04:10:26 -08:00
|
|
|
for (std::list<Body*>::iterator i = m_bodies.begin(); i != m_bodies.end(); ++i)
|
2011-11-08 14:22:54 -08:00
|
|
|
KillBody(*i);
|
2011-11-12 03:34:11 -08:00
|
|
|
UpdateBodies();
|
2008-06-24 03:17:31 -07:00
|
|
|
}
|
|
|
|
|
2011-11-08 13:25:58 -08:00
|
|
|
void Space::AddBody(Body *b)
|
2010-10-20 11:29:52 -07:00
|
|
|
{
|
2011-11-13 13:50:46 -08:00
|
|
|
m_bodies.push_back(b);
|
2011-11-08 13:25:58 -08:00
|
|
|
}
|
2010-10-20 11:29:52 -07:00
|
|
|
|
2011-11-08 13:25:58 -08:00
|
|
|
void Space::RemoveBody(Body *b)
|
|
|
|
{
|
2011-11-12 03:34:11 -08:00
|
|
|
m_removeBodies.push_back(b);
|
2011-11-08 13:25:58 -08:00
|
|
|
}
|
2010-10-20 11:29:52 -07:00
|
|
|
|
2011-11-08 13:25:58 -08:00
|
|
|
void Space::KillBody(Body* b)
|
|
|
|
{
|
|
|
|
if (!b->IsDead()) {
|
|
|
|
b->MarkDead();
|
2011-11-08 14:22:54 -08:00
|
|
|
|
|
|
|
// player needs to stay alive so things like the death animation
|
|
|
|
// (which uses a camera positioned relative to the player) can
|
|
|
|
// continue to work. it will be cleaned up with the space is torn down
|
|
|
|
// XXX this seems like the wrong way to do it. since its still "alive"
|
|
|
|
// it still collides, moves, etc. better to just snapshot its position
|
|
|
|
// elsewhere
|
2011-11-09 04:10:26 -08:00
|
|
|
if (b != Pi::player)
|
2011-11-12 03:34:11 -08:00
|
|
|
m_killBodies.push_back(b);
|
2010-10-20 11:29:52 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-15 14:02:05 -08:00
|
|
|
vector3d Space::GetHyperspaceExitPoint(const SystemPath &source)
|
2011-11-08 13:25:58 -08:00
|
|
|
{
|
2011-11-15 14:02:05 -08:00
|
|
|
assert(m_starSystem);
|
|
|
|
assert(source.IsSystemPath());
|
|
|
|
|
|
|
|
const SystemPath &dest = m_starSystem->GetPath();
|
|
|
|
|
|
|
|
Sector source_sec(source.sectorX, source.sectorY, source.sectorZ);
|
|
|
|
Sector dest_sec(dest.sectorX, dest.sectorY, dest.sectorZ);
|
|
|
|
|
|
|
|
Sector::System source_sys = source_sec.m_systems[source.systemIndex];
|
|
|
|
Sector::System dest_sys = dest_sec.m_systems[dest.systemIndex];
|
|
|
|
|
|
|
|
const vector3d sourcePos = vector3d(source_sys.p) + vector3d(source.sectorX, source.sectorY, source.sectorZ);
|
|
|
|
const vector3d destPos = vector3d(dest_sys.p) + vector3d(dest.sectorX, dest.sectorY, dest.sectorZ);
|
|
|
|
|
2011-11-15 13:34:49 -08:00
|
|
|
return (sourcePos - destPos).Normalized() * 11.0*AU + MathUtil::RandomPointOnSphere(5.0,20.0)*1000.0; // "hyperspace zone": 11 AU from primary
|
2009-10-30 16:22:10 -07:00
|
|
|
}
|
|
|
|
|
2011-11-08 13:25:58 -08:00
|
|
|
Body *Space::FindNearestTo(const Body *b, Object::Type t)
|
|
|
|
{
|
|
|
|
Body *nearest = 0;
|
|
|
|
double dist = FLT_MAX;
|
2011-11-09 04:10:26 -08:00
|
|
|
for (std::list<Body*>::iterator i = m_bodies.begin(); i != m_bodies.end(); ++i) {
|
2011-11-08 13:25:58 -08:00
|
|
|
if ((*i)->IsDead()) continue;
|
|
|
|
if ((*i)->IsType(t)) {
|
|
|
|
double d = (*i)->GetPositionRelTo(b).Length();
|
|
|
|
if (d < dist) {
|
|
|
|
dist = d;
|
|
|
|
nearest = *i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nearest;
|
|
|
|
}
|
|
|
|
|
|
|
|
Body *Space::FindBodyForPath(const SystemPath *path)
|
|
|
|
{
|
|
|
|
// it is a bit dumb that currentSystem is not part of Space...
|
2011-11-12 03:34:11 -08:00
|
|
|
SBody *body = m_starSystem->GetBodyByPath(path);
|
2011-11-08 13:25:58 -08:00
|
|
|
|
|
|
|
if (!body) return 0;
|
|
|
|
|
2011-11-09 04:10:26 -08:00
|
|
|
for (BodyIterator i = m_bodies.begin(); i != m_bodies.end(); ++i) {
|
2011-11-08 13:25:58 -08:00
|
|
|
if ((*i)->GetSBody() == body) return *i;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2010-05-22 10:26:25 -07:00
|
|
|
void Serialize(Serializer::Writer &wr)
|
2008-09-18 07:00:12 -07:00
|
|
|
{
|
2010-08-03 03:28:18 -07:00
|
|
|
Serializer::Writer wr2;
|
2011-11-16 00:03:11 -08:00
|
|
|
Frame::Serialize(wr2, m_rootFrame);
|
2010-08-03 03:28:18 -07:00
|
|
|
wr.WrSection("Frames", wr2.GetData());
|
|
|
|
|
2011-11-09 04:10:26 -08:00
|
|
|
wr.Int32(m_bodies.size());
|
|
|
|
for (BodyIterator i = m_bodies.begin(); i != m_bodies.end(); ++i) {
|
2009-09-12 10:25:15 -07:00
|
|
|
//printf("Serializing %s\n", (*i)->GetLabel().c_str());
|
2010-05-22 10:26:25 -07:00
|
|
|
(*i)->Serialize(wr);
|
2008-09-18 07:00:12 -07:00
|
|
|
}
|
2010-05-22 10:26:25 -07:00
|
|
|
wr.Int32(storedArrivalClouds.size());
|
2009-11-05 06:49:26 -08:00
|
|
|
for (std::list<HyperspaceCloud*>::iterator i = storedArrivalClouds.begin();
|
|
|
|
i != storedArrivalClouds.end(); ++i) {
|
2010-05-22 10:26:25 -07:00
|
|
|
(*i)->Serialize(wr);
|
2009-11-05 06:49:26 -08:00
|
|
|
}
|
2009-08-08 04:56:41 -07:00
|
|
|
if (hyperspacingTo == 0) {
|
2010-05-22 10:26:25 -07:00
|
|
|
wr.Byte(0);
|
2009-08-08 04:56:41 -07:00
|
|
|
} else {
|
2010-05-22 10:26:25 -07:00
|
|
|
wr.Byte(1);
|
|
|
|
hyperspacingTo->Serialize(wr);
|
|
|
|
wr.Float(hyperspaceAnim);
|
2011-04-22 00:07:42 -07:00
|
|
|
wr.Double(hyperspaceDuration);
|
2010-05-22 10:26:25 -07:00
|
|
|
wr.Double(hyperspaceEndTime);
|
2009-08-08 04:56:41 -07:00
|
|
|
}
|
2008-09-18 07:00:12 -07:00
|
|
|
}
|
2011-11-08 13:25:58 -08:00
|
|
|
*/
|
2008-09-18 07:00:12 -07:00
|
|
|
|
2011-11-08 13:25:58 -08:00
|
|
|
/*
|
2010-05-22 10:26:25 -07:00
|
|
|
void Unserialize(Serializer::Reader &rd)
|
2008-09-18 07:00:12 -07:00
|
|
|
{
|
2011-11-15 01:21:47 -08:00
|
|
|
Serializer::IndexSystemm_bodies(Pi::spaceManager->GetSpace()->GetStarSystem().Get());
|
2010-08-03 03:28:18 -07:00
|
|
|
|
|
|
|
Serializer::Reader rd2 = rd.RdSection("Frames");
|
2011-11-16 00:03:11 -08:00
|
|
|
m_rootFrame = Frame::Unserialize(rd2, 0);
|
2010-08-03 03:28:18 -07:00
|
|
|
|
2010-05-22 10:26:25 -07:00
|
|
|
// XXX not needed. done in Pi::Unserialize
|
2008-09-18 07:00:12 -07:00
|
|
|
Serializer::IndexFrames();
|
2011-11-09 04:10:26 -08:00
|
|
|
int num_m_bodies = rd.Int32();
|
|
|
|
//printf("%d m_bodies to read\n", num_m_bodies);
|
|
|
|
for (int i=0; i<num_m_bodies; i++) {
|
2010-05-22 10:26:25 -07:00
|
|
|
Body *b = Body::Unserialize(rd);
|
2011-11-09 04:10:26 -08:00
|
|
|
if (b) m_bodies.push_back(b);
|
2008-09-18 07:00:12 -07:00
|
|
|
}
|
2011-11-09 04:10:26 -08:00
|
|
|
num_m_bodies = rd.Int32();
|
|
|
|
for (int i=0; i<num_m_bodies; i++) {
|
2010-08-03 03:28:18 -07:00
|
|
|
Body *b = Body::Unserialize(rd);
|
|
|
|
if (b) storedArrivalClouds.push_back(static_cast<HyperspaceCloud*>(b));
|
2009-11-05 06:49:26 -08:00
|
|
|
}
|
|
|
|
|
2009-08-08 04:56:41 -07:00
|
|
|
hyperspaceAnim = 0;
|
2010-05-22 10:26:25 -07:00
|
|
|
if (rd.Byte()) {
|
2011-06-26 23:54:46 -07:00
|
|
|
hyperspacingTo = new SystemPath(SystemPath::Unserialize(rd));
|
2010-05-22 10:26:25 -07:00
|
|
|
hyperspaceAnim = rd.Float();
|
2011-04-22 00:07:42 -07:00
|
|
|
hyperspaceDuration = rd.Double();
|
2010-05-22 10:26:25 -07:00
|
|
|
hyperspaceEndTime = rd.Double();
|
2009-08-08 04:56:41 -07:00
|
|
|
}
|
2011-11-09 04:10:26 -08:00
|
|
|
// m_bodies with references to others must fix these up
|
|
|
|
Serializer::Indexm_bodies();
|
|
|
|
for (BodyIterator i = m_bodies.begin(); i != m_bodies.end(); ++i) {
|
2008-09-18 19:23:48 -07:00
|
|
|
(*i)->PostLoadFixup();
|
|
|
|
}
|
2011-11-16 00:03:11 -08:00
|
|
|
Frame::PostUnserializeFixup(m_rootFrame);
|
2008-09-18 07:00:12 -07:00
|
|
|
}
|
2011-11-08 13:25:58 -08:00
|
|
|
*/
|
2008-09-18 07:00:12 -07:00
|
|
|
|
2009-02-18 16:49:20 -08:00
|
|
|
static Frame *find_frame_with_sbody(Frame *f, const SBody *b)
|
|
|
|
{
|
|
|
|
if (f->m_sbody == b) return f;
|
|
|
|
else {
|
|
|
|
for (std::list<Frame*>::iterator i = f->m_children.begin();
|
|
|
|
i != f->m_children.end(); ++i) {
|
|
|
|
|
|
|
|
Frame *found = find_frame_with_sbody(*i, b);
|
|
|
|
if (found) return found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-08 13:25:58 -08:00
|
|
|
Frame *Space::GetFrameWithSBody(const SBody *b)
|
2009-02-18 16:49:20 -08:00
|
|
|
{
|
2011-11-16 00:21:00 -08:00
|
|
|
return find_frame_with_sbody(m_rootFrame.Get(), b);
|
2009-02-18 16:49:20 -08:00
|
|
|
}
|
|
|
|
|
2010-12-01 07:07:59 -08:00
|
|
|
static void SetFrameOrientationFromSBodyAxialTilt(Frame *f, const SBody *sbody)
|
|
|
|
{
|
|
|
|
matrix4x4d rot = matrix4x4d::RotateXMatrix(sbody->axialTilt.ToDouble());
|
2011-02-13 13:28:52 -08:00
|
|
|
f->SetRotationOnly(rot);
|
2010-12-01 07:07:59 -08:00
|
|
|
}
|
|
|
|
|
2009-02-17 16:09:05 -08:00
|
|
|
static Frame *MakeFrameFor(SBody *sbody, Body *b, Frame *f)
|
2008-08-15 18:00:14 -07:00
|
|
|
{
|
|
|
|
Frame *orbFrame, *rotFrame;
|
2008-08-25 03:04:29 -07:00
|
|
|
double frameRadius;
|
2008-08-15 18:00:14 -07:00
|
|
|
|
|
|
|
if (!sbody->parent) {
|
2008-08-25 03:04:29 -07:00
|
|
|
if (b) b->SetFrame(f);
|
|
|
|
f->m_sbody = sbody;
|
|
|
|
f->m_astroBody = b;
|
2008-08-15 18:00:14 -07:00
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2009-02-17 16:09:05 -08:00
|
|
|
if (sbody->type == SBody::TYPE_GRAVPOINT) {
|
2008-08-25 03:04:29 -07:00
|
|
|
orbFrame = new Frame(f, sbody->name.c_str());
|
|
|
|
orbFrame->m_sbody = sbody;
|
|
|
|
orbFrame->m_astroBody = b;
|
|
|
|
orbFrame->SetRadius(sbody->GetMaxChildOrbitalDistance()*1.1);
|
|
|
|
return orbFrame;
|
|
|
|
}
|
|
|
|
|
2009-02-17 16:09:05 -08:00
|
|
|
SBody::BodySuperType supertype = sbody->GetSuperType();
|
2008-08-25 03:04:29 -07:00
|
|
|
|
2009-02-17 16:09:05 -08:00
|
|
|
if ((supertype == SBody::SUPERTYPE_GAS_GIANT) ||
|
|
|
|
(supertype == SBody::SUPERTYPE_ROCKY_PLANET)) {
|
2008-08-15 18:00:14 -07:00
|
|
|
// for planets we want an non-rotating frame for a few radii
|
2010-04-02 10:18:55 -07:00
|
|
|
// and a rotating frame in the same position but with maybe 1.05*radius,
|
2008-08-15 18:00:14 -07:00
|
|
|
// which actually contains the object.
|
2011-02-15 17:23:32 -08:00
|
|
|
frameRadius = std::max(4.0*sbody->GetRadius(), sbody->GetMaxChildOrbitalDistance()*1.05);
|
2008-08-25 03:04:29 -07:00
|
|
|
orbFrame = new Frame(f, sbody->name.c_str());
|
|
|
|
orbFrame->m_sbody = sbody;
|
2011-08-18 18:56:35 -07:00
|
|
|
orbFrame->SetRadius(frameRadius);
|
2010-11-01 07:48:30 -07:00
|
|
|
//printf("\t\t\t%s has frame size %.0fkm, body radius %.0fkm\n", sbody->name.c_str(),
|
|
|
|
// (frameRadius ? frameRadius : 10*sbody->GetRadius())*0.001f,
|
|
|
|
// sbody->GetRadius()*0.001f);
|
2008-08-25 03:04:29 -07:00
|
|
|
|
2011-08-18 18:56:35 -07:00
|
|
|
assert(sbody->rotationPeriod != 0);
|
2008-08-25 03:04:29 -07:00
|
|
|
rotFrame = new Frame(orbFrame, sbody->name.c_str());
|
2009-11-08 12:09:57 -08:00
|
|
|
// rotating frame has size of GeoSphere terrain bounding sphere
|
|
|
|
rotFrame->SetRadius(b->GetBoundingRadius());
|
2008-08-25 03:04:29 -07:00
|
|
|
rotFrame->SetAngVelocity(vector3d(0,2*M_PI/sbody->GetRotationPeriod(),0));
|
|
|
|
rotFrame->m_astroBody = b;
|
2010-12-01 07:07:59 -08:00
|
|
|
SetFrameOrientationFromSBodyAxialTilt(rotFrame, sbody);
|
2008-08-25 03:04:29 -07:00
|
|
|
b->SetFrame(rotFrame);
|
|
|
|
return orbFrame;
|
|
|
|
}
|
2009-02-17 16:09:05 -08:00
|
|
|
else if (supertype == SBody::SUPERTYPE_STAR) {
|
2008-08-15 18:00:14 -07:00
|
|
|
// stars want a single small non-rotating frame
|
2008-08-25 03:04:29 -07:00
|
|
|
orbFrame = new Frame(f, sbody->name.c_str());
|
|
|
|
orbFrame->m_sbody = sbody;
|
|
|
|
orbFrame->m_astroBody = b;
|
|
|
|
orbFrame->SetRadius(sbody->GetMaxChildOrbitalDistance()*1.1);
|
|
|
|
b->SetFrame(orbFrame);
|
|
|
|
return orbFrame;
|
2008-09-10 14:28:48 -07:00
|
|
|
}
|
2009-02-17 16:09:05 -08:00
|
|
|
else if (sbody->type == SBody::TYPE_STARPORT_ORBITAL) {
|
2008-09-10 14:28:48 -07:00
|
|
|
// space stations want non-rotating frame to some distance
|
|
|
|
// and a much closer rotating frame
|
|
|
|
frameRadius = 1000000.0; // XXX NFI!
|
|
|
|
orbFrame = new Frame(f, sbody->name.c_str());
|
|
|
|
orbFrame->m_sbody = sbody;
|
2011-02-27 20:46:48 -08:00
|
|
|
// orbFrame->SetRadius(10*sbody->GetRadius());
|
2011-08-18 18:56:35 -07:00
|
|
|
orbFrame->SetRadius(frameRadius);
|
2008-09-10 14:28:48 -07:00
|
|
|
|
2011-08-18 18:56:35 -07:00
|
|
|
assert(sbody->rotationPeriod != 0);
|
2008-09-10 14:28:48 -07:00
|
|
|
rotFrame = new Frame(orbFrame, sbody->name.c_str());
|
2011-02-27 20:46:48 -08:00
|
|
|
rotFrame->SetRadius(1000.0);
|
|
|
|
// rotFrame->SetRadius(1.1*sbody->GetRadius()); // enough for collisions?
|
2011-05-10 17:57:37 -07:00
|
|
|
rotFrame->SetAngVelocity(vector3d(0.0,double(static_cast<SpaceStation*>(b)->GetDesiredAngVel()),0.0));
|
2011-02-19 22:23:44 -08:00
|
|
|
rotFrame->m_astroBody = b; // hope this doesn't break anything
|
2008-09-10 14:28:48 -07:00
|
|
|
b->SetFrame(rotFrame);
|
|
|
|
return orbFrame;
|
2009-02-17 16:09:05 -08:00
|
|
|
} else if (sbody->type == SBody::TYPE_STARPORT_SURFACE) {
|
2008-09-15 03:56:01 -07:00
|
|
|
// just put body into rotating frame of planet, not in its own frame
|
|
|
|
// (because collisions only happen between objects in same frame,
|
|
|
|
// and we want collisions on starport and on planet itself)
|
|
|
|
Frame *frame = *f->m_children.begin();
|
|
|
|
b->SetFrame(frame);
|
2009-03-18 13:36:54 -07:00
|
|
|
assert(frame->m_astroBody->IsType(Object::PLANET));
|
|
|
|
Planet *planet = static_cast<Planet*>(frame->m_astroBody);
|
2009-09-09 10:20:26 -07:00
|
|
|
|
|
|
|
/* position on planet surface */
|
|
|
|
double height;
|
|
|
|
int tries;
|
|
|
|
matrix4x4d rot;
|
|
|
|
vector3d pos;
|
|
|
|
// first try suggested position
|
|
|
|
rot = sbody->orbit.rotMatrix;
|
|
|
|
pos = rot * vector3d(0,1,0);
|
2011-08-18 18:56:35 -07:00
|
|
|
if (planet->GetTerrainHeight(pos) - planet->GetSBody()->GetRadius() <= 0.0) {
|
2009-09-09 10:20:26 -07:00
|
|
|
MTRand r(sbody->seed);
|
|
|
|
// position is under water. try some random ones
|
|
|
|
for (tries=0; tries<100; tries++) {
|
|
|
|
// used for orientation on planet surface
|
2011-02-08 21:24:43 -08:00
|
|
|
double r2 = r.Double(); // function parameter evaluation order is implementation-dependent
|
|
|
|
double r1 = r.Double(); // can't put two rands in the same expression
|
2011-02-09 16:24:10 -08:00
|
|
|
rot = matrix4x4d::RotateZMatrix(2*M_PI*r1)
|
|
|
|
* matrix4x4d::RotateYMatrix(2*M_PI*r2);
|
2009-09-09 10:20:26 -07:00
|
|
|
pos = rot * vector3d(0,1,0);
|
2009-11-08 12:09:57 -08:00
|
|
|
height = planet->GetTerrainHeight(pos) - planet->GetSBody()->GetRadius();
|
2009-09-09 10:20:26 -07:00
|
|
|
// don't want to be under water
|
|
|
|
if (height > 0.0) break;
|
|
|
|
}
|
|
|
|
}
|
2009-03-18 13:36:54 -07:00
|
|
|
b->SetPosition(pos * planet->GetTerrainHeight(pos));
|
2009-09-09 10:20:26 -07:00
|
|
|
b->SetRotMatrix(rot);
|
2008-09-15 03:56:01 -07:00
|
|
|
return frame;
|
2008-09-10 14:28:48 -07:00
|
|
|
} else {
|
|
|
|
assert(0);
|
|
|
|
}
|
2011-06-02 10:33:41 -07:00
|
|
|
return NULL;
|
2008-08-15 18:00:14 -07:00
|
|
|
}
|
|
|
|
|
2011-11-08 13:25:58 -08:00
|
|
|
void Space::GenBody(SBody *sbody, Frame *f)
|
2008-06-24 03:17:31 -07:00
|
|
|
{
|
2008-08-25 03:04:29 -07:00
|
|
|
Body *b = 0;
|
|
|
|
|
2009-02-17 16:09:05 -08:00
|
|
|
if (sbody->type != SBody::TYPE_GRAVPOINT) {
|
|
|
|
if (sbody->GetSuperType() == SBody::SUPERTYPE_STAR) {
|
2008-08-25 03:04:29 -07:00
|
|
|
Star *star = new Star(sbody);
|
|
|
|
b = star;
|
2009-07-02 04:39:14 -07:00
|
|
|
} else if ((sbody->type == SBody::TYPE_STARPORT_ORBITAL) ||
|
|
|
|
(sbody->type == SBody::TYPE_STARPORT_SURFACE)) {
|
|
|
|
SpaceStation *ss = new SpaceStation(sbody);
|
2008-09-15 03:56:01 -07:00
|
|
|
b = ss;
|
2008-08-25 03:04:29 -07:00
|
|
|
} else {
|
|
|
|
Planet *planet = new Planet(sbody);
|
|
|
|
b = planet;
|
|
|
|
}
|
|
|
|
b->SetLabel(sbody->name.c_str());
|
|
|
|
b->SetPosition(vector3d(0,0,0));
|
|
|
|
AddBody(b);
|
2008-06-24 03:17:31 -07:00
|
|
|
}
|
2008-08-15 18:00:14 -07:00
|
|
|
f = MakeFrameFor(sbody, b, f);
|
2008-06-24 03:17:31 -07:00
|
|
|
|
2009-02-17 16:09:05 -08:00
|
|
|
for (std::vector<SBody*>::iterator i = sbody->children.begin(); i != sbody->children.end(); ++i) {
|
2008-08-12 09:38:23 -07:00
|
|
|
GenBody(*i, f);
|
2008-06-24 03:17:31 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-27 06:34:55 -07:00
|
|
|
static bool OnCollision(Object *o1, Object *o2, CollisionContact *c, double relativeVel)
|
2008-06-24 03:17:31 -07:00
|
|
|
{
|
2008-11-12 09:57:34 -08:00
|
|
|
Body *pb1 = static_cast<Body*>(o1);
|
|
|
|
Body *pb2 = static_cast<Body*>(o2);
|
2009-08-21 10:08:11 -07:00
|
|
|
/* Not always a Body (could be CityOnPlanet, which is a nasty exception I should eradicate) */
|
|
|
|
if (o1->IsType(Object::BODY)) {
|
2009-10-21 08:54:01 -07:00
|
|
|
if (pb1 && !pb1->OnCollision(o2, c->geomFlag, relativeVel)) return false;
|
2009-08-21 10:08:11 -07:00
|
|
|
}
|
|
|
|
if (o2->IsType(Object::BODY)) {
|
2009-10-21 08:54:01 -07:00
|
|
|
if (pb2 && !pb2->OnCollision(o1, c->geomFlag, relativeVel)) return false;
|
2009-08-21 10:08:11 -07:00
|
|
|
}
|
2008-10-07 08:38:18 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-10-07 08:37:18 -07:00
|
|
|
static void hitCallback(CollisionContact *c)
|
|
|
|
{
|
2008-11-11 12:12:00 -08:00
|
|
|
//printf("OUCH! %x (depth %f)\n", SDL_GetTicks(), c->depth);
|
2008-10-07 08:37:18 -07:00
|
|
|
|
2008-10-10 04:11:12 -07:00
|
|
|
Object *po1 = static_cast<Object*>(c->userData1);
|
|
|
|
Object *po2 = static_cast<Object*>(c->userData2);
|
2008-11-11 07:05:29 -08:00
|
|
|
|
2008-11-11 10:48:23 -08:00
|
|
|
const bool po1_isDynBody = po1->IsType(Object::DYNAMICBODY);
|
|
|
|
const bool po2_isDynBody = po2->IsType(Object::DYNAMICBODY);
|
|
|
|
// collision response
|
|
|
|
assert(po1_isDynBody || po2_isDynBody);
|
2008-10-07 08:38:18 -07:00
|
|
|
|
2008-11-11 10:48:23 -08:00
|
|
|
if (po1_isDynBody && po2_isDynBody) {
|
2008-11-11 12:12:00 -08:00
|
|
|
DynamicBody *b1 = static_cast<DynamicBody*>(po1);
|
|
|
|
DynamicBody *b2 = static_cast<DynamicBody*>(po2);
|
2009-08-25 05:47:00 -07:00
|
|
|
const vector3d linVel1 = b1->GetVelocity();
|
|
|
|
const vector3d linVel2 = b2->GetVelocity();
|
|
|
|
const vector3d angVel1 = b1->GetAngVelocity();
|
|
|
|
const vector3d angVel2 = b2->GetAngVelocity();
|
|
|
|
|
|
|
|
const double coeff_rest = 0.5;
|
|
|
|
// step back
|
|
|
|
// mover->UndoTimestep();
|
|
|
|
|
2008-11-11 12:12:00 -08:00
|
|
|
const double invMass1 = 1.0 / b1->GetMass();
|
|
|
|
const double invMass2 = 1.0 / b2->GetMass();
|
2009-08-25 05:47:00 -07:00
|
|
|
const vector3d hitPos1 = c->pos - b1->GetPosition();
|
|
|
|
const vector3d hitPos2 = c->pos - b2->GetPosition();
|
2011-02-17 19:11:10 -08:00
|
|
|
const vector3d hitVel1 = linVel1 + angVel1.Cross(hitPos1);
|
|
|
|
const vector3d hitVel2 = linVel2 + angVel2.Cross(hitPos2);
|
2011-02-17 17:01:00 -08:00
|
|
|
const double relVel = (hitVel1 - hitVel2).Dot(c->normal);
|
2009-08-25 05:47:00 -07:00
|
|
|
// moving away so no collision
|
|
|
|
if (relVel > 0) return;
|
2009-08-27 06:34:55 -07:00
|
|
|
if (!OnCollision(po1, po2, c, -relVel)) return;
|
2009-08-25 05:47:00 -07:00
|
|
|
const double invAngInert1 = 1.0 / b1->GetAngularInertia();
|
|
|
|
const double invAngInert2 = 1.0 / b2->GetAngularInertia();
|
|
|
|
const double numerator = -(1.0 + coeff_rest) * relVel;
|
|
|
|
const double term1 = invMass1;
|
|
|
|
const double term2 = invMass2;
|
2011-02-17 19:11:10 -08:00
|
|
|
const double term3 = c->normal.Dot((hitPos1.Cross(c->normal)*invAngInert1).Cross(hitPos1));
|
|
|
|
const double term4 = c->normal.Dot((hitPos2.Cross(c->normal)*invAngInert2).Cross(hitPos2));
|
2009-08-25 05:47:00 -07:00
|
|
|
|
|
|
|
const double j = numerator / (term1 + term2 + term3 + term4);
|
|
|
|
const vector3d force = j * c->normal;
|
|
|
|
|
|
|
|
b1->SetVelocity(linVel1 + force*invMass1);
|
2011-02-17 19:11:10 -08:00
|
|
|
b1->SetAngVelocity(angVel1 + hitPos1.Cross(force)*invAngInert1);
|
2009-08-25 05:47:00 -07:00
|
|
|
b2->SetVelocity(linVel2 - force*invMass2);
|
2011-02-17 19:11:10 -08:00
|
|
|
b2->SetAngVelocity(angVel2 - hitPos2.Cross(force)*invAngInert2);
|
2008-11-11 10:48:23 -08:00
|
|
|
} else {
|
|
|
|
// one body is static
|
|
|
|
vector3d hitNormal;
|
|
|
|
DynamicBody *mover;
|
2009-08-27 06:34:55 -07:00
|
|
|
|
2008-11-11 12:12:00 -08:00
|
|
|
if (po1_isDynBody) {
|
|
|
|
mover = static_cast<DynamicBody*>(po1);
|
|
|
|
hitNormal = c->normal;
|
|
|
|
} else {
|
|
|
|
mover = static_cast<DynamicBody*>(po2);
|
|
|
|
hitNormal = -c->normal;
|
|
|
|
}
|
2008-11-11 10:48:23 -08:00
|
|
|
|
2008-11-12 09:57:04 -08:00
|
|
|
const double coeff_rest = 0.5;
|
2009-08-25 05:47:00 -07:00
|
|
|
const vector3d linVel1 = mover->GetVelocity();
|
|
|
|
const vector3d angVel1 = mover->GetAngVelocity();
|
|
|
|
|
2008-11-11 10:48:23 -08:00
|
|
|
// step back
|
2009-08-25 05:47:00 -07:00
|
|
|
// mover->UndoTimestep();
|
2008-11-12 09:57:04 -08:00
|
|
|
|
|
|
|
const double invMass1 = 1.0 / mover->GetMass();
|
|
|
|
const vector3d hitPos1 = c->pos - mover->GetPosition();
|
2011-02-17 19:11:10 -08:00
|
|
|
const vector3d hitVel1 = linVel1 + angVel1.Cross(hitPos1);
|
2011-02-17 17:01:00 -08:00
|
|
|
const double relVel = hitVel1.Dot(c->normal);
|
2009-08-25 05:47:00 -07:00
|
|
|
// moving away so no collision
|
2011-02-26 11:27:09 -08:00
|
|
|
if (relVel > 0 && !c->geomFlag) return;
|
2009-08-27 06:34:55 -07:00
|
|
|
if (!OnCollision(po1, po2, c, -relVel)) return;
|
2009-08-25 05:47:00 -07:00
|
|
|
const double invAngInert = 1.0 / mover->GetAngularInertia();
|
|
|
|
const double numerator = -(1.0 + coeff_rest) * relVel;
|
|
|
|
const double term1 = invMass1;
|
2011-02-17 19:11:10 -08:00
|
|
|
const double term3 = c->normal.Dot((hitPos1.Cross(c->normal)*invAngInert).Cross(hitPos1));
|
2009-08-25 05:47:00 -07:00
|
|
|
|
|
|
|
const double j = numerator / (term1 + term3);
|
|
|
|
const vector3d force = j * c->normal;
|
|
|
|
|
|
|
|
mover->SetVelocity(linVel1 + force*invMass1);
|
2011-02-17 19:11:10 -08:00
|
|
|
mover->SetAngVelocity(angVel1 + hitPos1.Cross(force)*invAngInert);
|
2008-11-11 10:48:23 -08:00
|
|
|
}
|
2008-10-07 08:37:18 -07:00
|
|
|
}
|
2008-11-12 09:57:34 -08:00
|
|
|
|
2011-11-08 13:25:58 -08:00
|
|
|
void Space::CollideFrame(Frame *f)
|
2008-06-24 03:17:31 -07:00
|
|
|
{
|
2011-09-05 15:18:09 -07:00
|
|
|
if (f->m_astroBody && (f->m_astroBody->IsType(Object::TERRAINBODY))) {
|
2009-03-18 13:36:54 -07:00
|
|
|
// this is pretty retarded
|
2011-11-09 04:10:26 -08:00
|
|
|
for (BodyIterator i = m_bodies.begin(); i!=m_bodies.end(); ++i) {
|
2009-03-18 13:36:54 -07:00
|
|
|
if ((*i)->GetFrame() != f) continue;
|
|
|
|
if (!(*i)->IsType(Object::DYNAMICBODY)) continue;
|
2011-05-10 17:57:37 -07:00
|
|
|
DynamicBody *dynBody = static_cast<DynamicBody*>(*i);
|
2009-08-25 05:47:00 -07:00
|
|
|
|
|
|
|
Aabb aabb;
|
|
|
|
dynBody->GetAabb(aabb);
|
|
|
|
const matrix4x4d &trans = dynBody->GetGeom()->GetTransform();
|
|
|
|
|
|
|
|
const vector3d aabbCorners[8] = {
|
|
|
|
vector3d(aabb.min.x, aabb.min.y, aabb.min.z),
|
|
|
|
vector3d(aabb.min.x, aabb.min.y, aabb.max.z),
|
|
|
|
vector3d(aabb.min.x, aabb.max.y, aabb.min.z),
|
|
|
|
vector3d(aabb.min.x, aabb.max.y, aabb.max.z),
|
|
|
|
vector3d(aabb.max.x, aabb.min.y, aabb.min.z),
|
|
|
|
vector3d(aabb.max.x, aabb.min.y, aabb.max.z),
|
|
|
|
vector3d(aabb.max.x, aabb.max.y, aabb.min.z),
|
|
|
|
vector3d(aabb.max.x, aabb.max.y, aabb.max.z)
|
|
|
|
};
|
|
|
|
|
|
|
|
CollisionContact c;
|
|
|
|
|
2011-05-15 07:47:59 -07:00
|
|
|
for (int j=0; j<8; j++) {
|
|
|
|
const vector3d &s = aabbCorners[j];
|
2009-08-25 05:47:00 -07:00
|
|
|
vector3d pos = trans * s;
|
|
|
|
double terrain_height = static_cast<Planet*>(f->m_astroBody)->GetTerrainHeight(pos.Normalized());
|
|
|
|
double altitude = pos.Length();
|
|
|
|
double hitDepth = terrain_height - altitude;
|
2009-08-27 06:34:55 -07:00
|
|
|
if (altitude < terrain_height) {
|
2009-08-25 05:47:00 -07:00
|
|
|
c.pos = pos;
|
|
|
|
c.normal = pos.Normalized();
|
|
|
|
c.depth = hitDepth;
|
|
|
|
c.userData1 = static_cast<void*>(dynBody);
|
|
|
|
c.userData2 = static_cast<void*>(f->m_astroBody);
|
2009-08-27 06:34:55 -07:00
|
|
|
hitCallback(&c);
|
2009-08-25 05:47:00 -07:00
|
|
|
}
|
|
|
|
}
|
2009-03-18 13:36:54 -07:00
|
|
|
}
|
|
|
|
}
|
2008-10-07 08:37:18 -07:00
|
|
|
f->GetCollisionSpace()->Collide(&hitCallback);
|
2008-06-24 03:17:31 -07:00
|
|
|
for (std::list<Frame*>::iterator i = f->m_children.begin(); i != f->m_children.end(); ++i) {
|
|
|
|
CollideFrame(*i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-17 04:28:25 -07:00
|
|
|
|
2011-11-08 13:25:58 -08:00
|
|
|
void Space::TimeStep(float step)
|
2008-06-24 03:17:31 -07:00
|
|
|
{
|
|
|
|
// XXX does not need to be done this often
|
2011-11-16 00:21:00 -08:00
|
|
|
CollideFrame(m_rootFrame.Get());
|
2011-02-27 20:46:48 -08:00
|
|
|
|
|
|
|
// update frames of reference
|
2011-11-12 03:34:11 -08:00
|
|
|
for (BodyIterator i = m_bodies.begin(); i != m_bodies.end(); ++i)
|
2011-02-27 20:46:48 -08:00
|
|
|
(*i)->UpdateFrame();
|
|
|
|
|
2011-11-04 19:31:54 -07:00
|
|
|
// AI acts here, then move all bodies and frames
|
2011-11-12 03:34:11 -08:00
|
|
|
for (BodyIterator i = m_bodies.begin(); i != m_bodies.end(); ++i)
|
2011-11-04 19:31:54 -07:00
|
|
|
(*i)->StaticUpdate(step);
|
|
|
|
|
2011-11-16 00:03:11 -08:00
|
|
|
m_rootFrame->UpdateOrbitRails();
|
2011-02-27 20:46:48 -08:00
|
|
|
|
2011-11-12 03:34:11 -08:00
|
|
|
for (BodyIterator i = m_bodies.begin(); i != m_bodies.end(); ++i)
|
2011-02-16 21:41:14 -08:00
|
|
|
(*i)->TimeStepUpdate(step);
|
2011-11-03 01:39:23 -07:00
|
|
|
|
2011-11-12 13:39:52 -08:00
|
|
|
// XXX don't emit events in hyperspace. this is mostly to maintain the
|
|
|
|
// status quo. in particular without this onEnterSystem will fire in the
|
|
|
|
// frame immediately before the player leaves hyperspace and the system is
|
|
|
|
// invalid when Lua goes and queries for it. we need to consider whether
|
|
|
|
// there's anything useful that can be done with events in hyperspace
|
|
|
|
if (m_starSystem) {
|
|
|
|
Pi::luaOnEnterSystem->Emit();
|
|
|
|
Pi::luaOnLeaveSystem->Emit();
|
|
|
|
Pi::luaOnFrameChanged->Emit();
|
|
|
|
Pi::luaOnShipHit->Emit();
|
|
|
|
Pi::luaOnShipCollided->Emit();
|
|
|
|
Pi::luaOnShipDestroyed->Emit();
|
|
|
|
Pi::luaOnShipDocked->Emit();
|
|
|
|
Pi::luaOnShipAlertChanged->Emit();
|
|
|
|
Pi::luaOnShipUndocked->Emit();
|
|
|
|
Pi::luaOnShipLanded->Emit();
|
|
|
|
Pi::luaOnShipTakeOff->Emit();
|
|
|
|
Pi::luaOnJettison->Emit();
|
|
|
|
Pi::luaOnAICompleted->Emit();
|
|
|
|
Pi::luaOnCreateBB->Emit();
|
|
|
|
Pi::luaOnUpdateBB->Emit();
|
|
|
|
Pi::luaOnShipFlavourChanged->Emit();
|
|
|
|
Pi::luaOnShipEquipmentChanged->Emit();
|
|
|
|
|
|
|
|
Pi::luaTimer->Tick();
|
|
|
|
}
|
|
|
|
|
2011-11-12 03:34:11 -08:00
|
|
|
UpdateBodies();
|
2011-11-09 04:10:26 -08:00
|
|
|
}
|
|
|
|
|
2011-11-12 03:34:11 -08:00
|
|
|
void Space::UpdateBodies()
|
2011-11-09 04:10:26 -08:00
|
|
|
{
|
2011-11-14 13:58:22 -08:00
|
|
|
for (BodyIterator b = m_removeBodies.begin(); b != m_removeBodies.end(); ++b) {
|
|
|
|
(*b)->SetFrame(0);
|
2011-11-14 14:09:29 -08:00
|
|
|
for (BodyIterator i = m_bodies.begin(); i != m_bodies.end(); ++i)
|
|
|
|
(*i)->NotifyRemoved(*b);
|
2011-11-12 03:34:11 -08:00
|
|
|
m_bodies.remove(*b);
|
2011-11-14 13:58:22 -08:00
|
|
|
}
|
2011-11-12 03:34:11 -08:00
|
|
|
m_removeBodies.clear();
|
|
|
|
|
|
|
|
for (BodyIterator b = m_killBodies.begin(); b != m_killBodies.end(); ++b) {
|
2011-11-09 04:10:26 -08:00
|
|
|
for (BodyIterator i = m_bodies.begin(); i != m_bodies.end(); ++i)
|
2011-11-14 14:09:29 -08:00
|
|
|
(*i)->NotifyRemoved(*b);
|
2011-11-09 04:10:26 -08:00
|
|
|
m_bodies.remove(*b);
|
|
|
|
delete *b;
|
|
|
|
}
|
2011-11-12 03:34:11 -08:00
|
|
|
m_killBodies.clear();
|
2008-07-07 15:19:53 -07:00
|
|
|
}
|