void Ship::AIAccelToModelRelativeVelocity(const vector3d &v) { vector3d difVel = v - GetVelocity() * GetOrient(); // required change in velocity vector3d maxThrust = GetMaxThrust(difVel); vector3d maxFrameAccel = maxThrust * (Pi::game->GetTimeStep() / GetMass()); SetThrusterState(0, is_zero_exact(maxFrameAccel.x) ? 0.0 : difVel.x / maxFrameAccel.x); SetThrusterState(1, is_zero_exact(maxFrameAccel.y) ? 0.0 : difVel.y / maxFrameAccel.y); SetThrusterState(2, is_zero_exact(maxFrameAccel.z) ? 0.0 : difVel.z / maxFrameAccel.z); // use clamping }
void SpaceStation::TimeStepUpdate(const float timeStep) { // rotate the thing double len = m_type->angVel * timeStep; if (!is_zero_exact(len)) { matrix3x3d r = matrix3x3d::RotateY(-len); // RotateY is backwards SetOrient(r * GetOrient()); } m_oldAngDisplacement = len; // reposition the ships that are docked or docking here for (int i=0; i<m_type->numDockingPorts; i++) { const shipDocking_t &dt = m_shipDocking[i]; if (!dt.ship) { //free m_navLights->SetColor(i+1, NavLights::NAVLIGHT_GREEN); continue; } if (dt.stage == 1) //reserved m_navLights->SetColor(i+1, NavLights::NAVLIGHT_YELLOW); if (dt.ship->GetFlightState() == Ship::FLYING) continue; PositionDockedShip(dt.ship, i); m_navLights->SetColor(i+1, NavLights::NAVLIGHT_RED); //docked } if (m_doorAnimation) GetModel()->UpdateAnimations(); }
void Frame::UpdateOrbitRails(double time, double timestep) { m_oldPos = m_pos; m_oldAngDisplacement = m_angSpeed * timestep; // update frame position and velocity if (m_parent && m_sbody && !IsRotFrame()) { m_pos = m_sbody->orbit.OrbitalPosAtTime(time); vector3d pos2 = m_sbody->orbit.OrbitalPosAtTime(time+timestep); m_vel = (pos2 - m_pos) / timestep; } // temporary test thing else m_pos = m_pos + m_vel * timestep; // update frame rotation double ang = m_angSpeed * timestep; // hmm. cumulative inaccuracy? worse! if (!is_zero_exact(ang)) { // frequently used with e^-10 etc matrix3x3d rot = matrix3x3d::RotateY(-ang); // RotateY is backwards m_orient = m_orient * rot; // angvel always +y } UpdateRootRelativeVars(); // update root-relative pos/vel/orient for (ChildIterator it = m_children.begin(); it != m_children.end(); ++it) (*it)->UpdateOrbitRails(time, timestep); }
void Frame::UpdateOrbitRails(double time, double timestep) { m_oldPos = m_pos; m_oldAngDisplacement = m_angSpeed * timestep; // update frame position and velocity if (m_parent && m_sbody && !IsRotFrame()) { m_pos = m_sbody->GetOrbit().OrbitalPosAtTime(time); vector3d pos2 = m_sbody->GetOrbit().OrbitalPosAtTime(time+timestep); m_vel = (pos2 - m_pos) / timestep; } // temporary test thing else m_pos = m_pos + m_vel * timestep; // update frame rotation double ang = fmod(m_angSpeed * time, 2.0 * M_PI); if (!is_zero_exact(ang)) { // frequently used with e^-10 etc matrix3x3d rot = matrix3x3d::RotateY(-ang); // RotateY is backwards m_orient = m_initialOrient * rot; // angvel always +y } UpdateRootRelativeVars(); // update root-relative pos/vel/orient for (Frame* kid : m_children) kid->UpdateOrbitRails(time, timestep); }
bool Frustum::ProjectPoint(const vector3d &in, vector3d &out) const { // see the OpenGL documentation // or http://www.songho.ca/opengl/gl_transform.html // or http://cgit.freedesktop.org/mesa/glu/tree/src/libutil/project.c (gluProject implementation from Mesa) const double * const M = m_modelMatrix.Data(); const double * const P = m_projMatrix.Data(); const double vcam[4] = { // camera space in.x*M[0] + in.y*M[4] + in.z*M[ 8] + M[12], in.x*M[1] + in.y*M[5] + in.z*M[ 9] + M[13], in.x*M[2] + in.y*M[6] + in.z*M[10] + M[14], in.x*M[3] + in.y*M[7] + in.z*M[11] + M[15] }; const double vclip[4] = { // clip space vcam[0]*P[0] + vcam[1]*P[4] + vcam[2]*P[ 8] + vcam[3]*P[12], vcam[0]*P[1] + vcam[1]*P[5] + vcam[2]*P[ 9] + vcam[3]*P[13], vcam[0]*P[2] + vcam[1]*P[6] + vcam[2]*P[10] + vcam[3]*P[14], vcam[0]*P[3] + vcam[1]*P[7] + vcam[2]*P[11] + vcam[3]*P[15] }; if (is_zero_exact(vclip[3])) { return false; } const double w = vclip[3]; out.x = (vclip[0] / w) * 0.5 + 0.5; out.y = (vclip[1] / w) * 0.5 + 0.5; out.z = (vclip[2] / w) * 0.5 + 0.5; return true; }
// returns direction in ship's frame from this ship to target lead position vector3d Ship::AIGetLeadDir(const Body *target, const vector3d& targaccel, int gunindex) { assert(target); if (ScopedTable(m_equipSet).CallMethod<int>("OccupiedSpace", "laser_front") == 0) return target->GetPositionRelTo(this).Normalized(); const vector3d targpos = target->GetPositionRelTo(this); const vector3d targvel = target->GetVelocityRelTo(this); // todo: should adjust targpos for gunmount offset double projspeed = 0; Properties().Get(gunindex?"laser_rear_speed":"laser_front_speed", projspeed); vector3d leadpos; // avoid a divide-by-zero floating point exception (very nearly zero is ok) if( !is_zero_exact(projspeed) ) { // first attempt double projtime = targpos.Length() / projspeed; leadpos = targpos + targvel*projtime + 0.5*targaccel*projtime*projtime; // second pass projtime = leadpos.Length() / projspeed; leadpos = targpos + targvel*projtime + 0.5*targaccel*projtime*projtime; } else { // default leadpos = targpos; } return leadpos.Normalized(); }
// Input: direction in ship's frame, doesn't need to be normalized // Approximate positive angular velocity at match point // Applies thrust directly // old: returns whether it can reach that direction in this frame // returns angle to target double Ship::AIFaceDirection(const vector3d &dir, double av) { double maxAccel = m_type->angThrust / GetAngularInertia(); // should probably be in stats anyway vector3d head = (dir * GetOrient()).Normalized(); // create desired object-space heading vector3d dav(0.0, 0.0, 0.0); // desired angular velocity double ang = 0.0; if (head.z > -0.99999999) { ang = acos (Clamp(-head.z, -1.0, 1.0)); // scalar angle from head to curhead double iangvel = av + calc_ivel_pos(ang, 0.0, maxAccel); // ideal angvel at current time // Normalize (head.x, head.y) to give desired angvel direction if (head.z > 0.999999) head.x = 1.0; double head2dnorm = 1.0 / sqrt(head.x*head.x + head.y*head.y); // NAN fix shouldn't be necessary if inputs are normalized dav.x = head.y * head2dnorm * iangvel; dav.y = -head.x * head2dnorm * iangvel; } const vector3d cav = GetAngVelocity() * GetOrient(); // current obj-rel angvel const double frameAccel = maxAccel * Pi::game->GetTimeStep(); vector3d diff = is_zero_exact(frameAccel) ? vector3d(0.0) : (dav - cav) / frameAccel; // find diff between current & desired angvel // If the player is pressing a roll key, don't override roll. // XXX this really shouldn't be here. a better way would be to have a // field in Ship describing the wanted angvel adjustment from input. the // baseclass version in Ship would always be 0. the version in Player // would be constructed from user input. that adjustment could then be // considered by this method when computing the required change if (IsType(Object::PLAYER) && (KeyBindings::rollLeft.IsActive() || KeyBindings::rollRight.IsActive())) diff.z = m_angThrusters.z; SetAngThrusterState(diff); return ang; }
// returns direction in ship's frame from this ship to target lead position vector3d Ship::AIGetLeadDir(const Body *target, const vector3d& targaccel, int gunindex) { assert(target); if (m_equipment.Get(Equip::SLOT_LASER) == Equip::NONE) return target->GetPositionRelTo(this).Normalized(); const vector3d targpos = target->GetPositionRelTo(this); const vector3d targvel = target->GetVelocityRelTo(this); // todo: should adjust targpos for gunmount offset const int laser = Equip::types[m_equipment.Get(Equip::SLOT_LASER, gunindex)].tableIndex; const double projspeed = Equip::lasers[laser].speed; vector3d leadpos; // avoid a divide-by-zero floating point exception (very nearly zero is ok) if( !is_zero_exact(projspeed) ) { // first attempt double projtime = targpos.Length() / projspeed; leadpos = targpos + targvel*projtime + 0.5*targaccel*projtime*projtime; // second pass projtime = leadpos.Length() / projspeed; leadpos = targpos + targvel*projtime + 0.5*targaccel*projtime*projtime; } else { // default leadpos = targpos; } return leadpos.Normalized(); }
static void set_master_volume(const bool muted, const float volume) { Sound::Pause(muted || is_zero_exact(volume)); Sound::SetMasterVolume(volume); Pi::config->SetFloat("MasterVolume", volume); Pi::config->SetInt("MasterMuted", muted ? 1 : 0); Pi::config->Save(); }
static void set_music_volume(const bool muted, const float volume) { Pi::GetMusicPlayer().SetEnabled(!(muted || is_zero_exact(volume))); Pi::GetMusicPlayer().SetVolume(volume); Pi::config->SetFloat("MusicVolume", volume); Pi::config->SetInt("MusicMuted", muted ? 1 : 0); Pi::config->Save(); }
void SpaceStation::UpdateInterpTransform(double alpha) { double len = m_oldAngDisplacement * (1.0-alpha); if (!is_zero_exact(len)) { matrix3x3d rot = matrix3x3d::RotateY(len); // RotateY is backwards m_interpOrient = rot * GetOrient(); } else m_interpOrient = GetOrient(); m_interpPos = GetPosition(); }
CargoBody::CargoBody(const LuaRef& cargo, float selfdestructTimer): m_cargo(cargo) { SetModel("cargo"); Init(); SetMass(1.0); m_selfdestructTimer = selfdestructTimer; // number of seconds to live if (is_zero_exact(selfdestructTimer)) // turn off self destruct m_hasSelfdestruct = false; }
void Frame::SetOrient(const matrix3x3d &m, double time) { m_orient = m; double ang = fmod(m_angSpeed * time, 2.0 * M_PI); if (!is_zero_exact(ang)) { // frequently used with e^-10 etc matrix3x3d rot = matrix3x3d::RotateY(ang); // RotateY is backwards m_initialOrient = m_orient * rot; // angvel always +y } else { m_initialOrient = m_orient; } }
void SpaceStation::TimeStepUpdate(const float timeStep) { // rotate the thing double len = m_type->angVel * timeStep; if (!is_zero_exact(len)) { matrix3x3d r = matrix3x3d::RotateY(-len); // RotateY is backwards SetOrient(r * GetOrient()); } m_oldAngDisplacement = len; // reposition the ships that are docked or docking here for (int i=0; i<m_type->numDockingPorts; i++) { const shipDocking_t &dt = m_shipDocking[i]; if (!dt.ship || dt.stage == 1) continue; if (dt.ship->GetFlightState() == Ship::FLYING) continue; PositionDockedShip(dt.ship, i); } }
void Frame::UpdateInterpTransform(double alpha) { m_interpPos = alpha*m_pos + (1.0-alpha)*m_oldPos; double len = m_oldAngDisplacement * (1.0-alpha); if (!is_zero_exact(len)) { // very small values are normal here matrix3x3d rot = matrix3x3d::RotateY(len); // RotateY is backwards m_interpOrient = m_orient * rot; } else m_interpOrient = m_orient; if (!m_parent) ClearMovement(); else { m_rootInterpPos = m_parent->m_rootInterpOrient * m_interpPos + m_parent->m_rootInterpPos; m_rootInterpOrient = m_parent->m_rootInterpOrient * m_interpOrient; } for (ChildIterator it = m_children.begin(); it != m_children.end(); ++it) (*it)->UpdateInterpTransform(alpha); }
void Frame::UpdateInterpTransform(double alpha) { PROFILE_SCOPED() m_interpPos = alpha*m_pos + (1.0-alpha)*m_oldPos; double len = m_oldAngDisplacement * (1.0-alpha); if (!is_zero_exact(len)) { // very small values are normal here matrix3x3d rot = matrix3x3d::RotateY(len); // RotateY is backwards m_interpOrient = m_orient * rot; } else m_interpOrient = m_orient; if (!m_parent) ClearMovement(); else { m_rootInterpPos = m_parent->m_rootInterpOrient * m_interpPos + m_parent->m_rootInterpPos; m_rootInterpOrient = m_parent->m_rootInterpOrient * m_interpOrient; } for (Frame* kid : m_children) kid->UpdateInterpTransform(alpha); }
bool Screen::Project(const vector3d &in, vector3d &out) { PROFILE_SCOPED() // implements gluProject (see the OpenGL documentation or the Mesa implementation of gluProject) const float * const M = modelMatrix.Data(); const float * const P = projMatrix.Data(); const double vcam[4] = { // camera space in.x*M[0] + in.y*M[4] + in.z*M[ 8] + M[12], in.x*M[1] + in.y*M[5] + in.z*M[ 9] + M[13], in.x*M[2] + in.y*M[6] + in.z*M[10] + M[14], in.x*M[3] + in.y*M[7] + in.z*M[11] + M[15] }; const double vclip[4] = { // clip space vcam[0]*P[0] + vcam[1]*P[4] + vcam[2]*P[ 8] + vcam[3]*P[12], vcam[0]*P[1] + vcam[1]*P[5] + vcam[2]*P[ 9] + vcam[3]*P[13], vcam[0]*P[2] + vcam[1]*P[6] + vcam[2]*P[10] + vcam[3]*P[14], vcam[0]*P[3] + vcam[1]*P[7] + vcam[2]*P[11] + vcam[3]*P[15] }; if (is_zero_exact(vclip[3])) { return false; } const double w = vclip[3]; const double v[3] = { (vclip[0] / w) * 0.5 + 0.5, (vclip[1] / w) * 0.5 + 0.5, (vclip[2] / w) * 0.5 + 0.5 }; out.x = v[0] * viewport[2] + viewport[0]; out.y = v[1] * viewport[3] + viewport[1]; out.z = v[2]; // map to pixels out.x = out.x * width * invRealWidth; out.y = GetHeight() - out.y * height * invRealHeight; return true; }
static bool ShipIsUnbuyable(const std::string &id) { const ShipType &t = ShipType::types[id]; return is_zero_exact(t.baseprice); }