Beispiel #1
0
/*
 * Method: GetGroundPosition
 *
 * Get latitude, longitude and altitude of a dynamic body close to the ground or nil the body is not a dynamic body
 * or is not close to the ground.
 *
 * > latitude, longitude, altitude = body:GetGroundPosition()
 *
 * Returns:
 *
 *   latitude - the latitude of the body in radians
 *   longitude - the longitude of the body in radians
 *   altitude - altitude above the ground in meters
 *
 * Examples:
 *
 * > -- Get ground position of the player
 * > local lat, long, alt = Game.player:GetGroundPosition()
 * > lat = math.rad2deg(lat)
 * > long = math.rad2deg(long)
 *
 * Availability:
 *
 *   July 2013
 *
 * Status:
 *
 *   experimental
 */
static int l_body_get_ground_position(lua_State *l)
{
	Body *b = LuaObject<Body>::CheckFromLua(1);
	if (!b->IsType(Object::DYNAMICBODY)) {
		lua_pushnil(l);
		return 1;
	}

	Frame *f = b->GetFrame();
	if (!f->IsRotFrame())
		return 0;

	vector3d pos = b->GetPosition();
	double latitude = atan2(pos.y, sqrt(pos.x * pos.x + pos.z * pos.z));
	double longitude = atan2(pos.x, pos.z);
	lua_pushnumber(l, latitude);
	lua_pushnumber(l, longitude);
	Body *astro = f->GetBody();
	if (astro->IsType(Object::TERRAINBODY)) {
		double radius = static_cast<TerrainBody *>(astro)->GetTerrainHeight(pos.Normalized());
		double altitude = pos.Length() - radius;
		lua_pushnumber(l, altitude);
	} else {
		lua_pushnil(l);
	}
	return 3;
}
Beispiel #2
0
void ObjectViewerView::Update()
{
	if (Pi::KeyState(SDLK_EQUALS)) viewingDist *= 0.99f;
	if (Pi::KeyState(SDLK_MINUS)) viewingDist *= 1.01f;
	viewingDist = Clamp(viewingDist, 10.0f, 1e12f);

	char buf[128];
	Body *body = Pi::player->GetNavTarget();
	if(body && (body != lastTarget)) {
		// Reset view distance for new target.
		viewingDist = body->GetBoundingRadius() * 2.0f;
		lastTarget = body;

		if (body->IsType(Object::TERRAINBODY)) {
			TerrainBody *tbody = static_cast<TerrainBody*>(body);
			const SystemBody *sbody = tbody->GetSystemBody();
			m_sbodyVolatileGas->SetText(stringf("%0{f.3}", sbody->m_volatileGas.ToFloat()));
			m_sbodyVolatileLiquid->SetText(stringf("%0{f.3}", sbody->m_volatileLiquid.ToFloat()));
			m_sbodyVolatileIces->SetText(stringf("%0{f.3}", sbody->m_volatileIces.ToFloat()));
			m_sbodyLife->SetText(stringf("%0{f.3}", sbody->m_life.ToFloat()));
			m_sbodyVolcanicity->SetText(stringf("%0{f.3}", sbody->m_volcanicity.ToFloat()));
			m_sbodyMetallicity->SetText(stringf("%0{f.3}", sbody->m_metallicity.ToFloat()));
			m_sbodySeed->SetText(stringf("%0{i}", int(sbody->seed)));
			m_sbodyMass->SetText(stringf("%0{f}", sbody->mass.ToFloat()));
			m_sbodyRadius->SetText(stringf("%0{f}", sbody->radius.ToFloat()));
		}
	}
	snprintf(buf, sizeof(buf), "View dist: %s     Object: %s", format_distance(viewingDist).c_str(), (body ? body->GetLabel().c_str() : "<none>"));
	m_infoLabel->SetText(buf);

	if (body && body->IsType(Object::TERRAINBODY)) m_vbox->ShowAll();
	else m_vbox->HideAll();
}
Beispiel #3
0
/*
 * Method: AIEnterHighOrbit
 *
 * Fly to and enter a high orbit around a given planet or star
 *
 * > ship:AIEnterHighOrbit(target)
 *
 * Parameters:
 *
 *   target - the <Star> or <Planet> to orbit
 *
 * Availability:
 *
 *  alpha 10
 *
 * Status:
 *
 *  experimental
 */
static int l_ship_ai_enter_high_orbit(lua_State *l)
{
    Ship *s = LuaObject<Ship>::CheckFromLua(1);
    if (s->GetFlightState() == Ship::HYPERSPACE)
        return luaL_error(l, "Ship:AIEnterHighOrbit() cannot be called on a ship in hyperspace");
    Body *target = LuaObject<Body>::CheckFromLua(2);
    if (!target->IsType(Object::PLANET) && !target->IsType(Object::STAR))
        luaL_argerror(l, 2, "expected a Planet or a Star");
    s->AIOrbit(target, 3.2);
    return 0;
}
Beispiel #4
0
void ObjectViewerView::OnChangeTerrain()
{
	const fixed volatileGas = fixed(65536.0*atof(m_sbodyVolatileGas->GetText().c_str()), 65536);
	const fixed volatileLiquid = fixed(65536.0*atof(m_sbodyVolatileLiquid->GetText().c_str()), 65536);
	const fixed volatileIces = fixed(65536.0*atof(m_sbodyVolatileIces->GetText().c_str()), 65536);
	const fixed life = fixed(65536.0*atof(m_sbodyLife->GetText().c_str()), 65536);
	const fixed volcanicity = fixed(65536.0*atof(m_sbodyVolcanicity->GetText().c_str()), 65536);
	const fixed metallicity = fixed(65536.0*atof(m_sbodyMetallicity->GetText().c_str()), 65536);
	const fixed mass = fixed(65536.0*atof(m_sbodyMass->GetText().c_str()), 65536);
	const fixed radius = fixed(65536.0*atof(m_sbodyRadius->GetText().c_str()), 65536);

	// XXX this is horrendous, but probably safe for the moment. all bodies,
	// terrain, whatever else holds a const pointer to the same toplevel
	// sbody. one day objectviewer should be far more contained and not
	// actually modify the space
	Body *body = Pi::player->GetNavTarget();
	SBody *sbody = const_cast<SBody*>(body->GetSBody());

	sbody->seed = atoi(m_sbodySeed->GetText().c_str());
	sbody->radius = radius;
	sbody->mass = mass;
	sbody->m_metallicity = metallicity;
	sbody->m_volatileGas = volatileGas;
	sbody->m_volatileLiquid = volatileLiquid;
	sbody->m_volatileIces = volatileIces;
	sbody->m_volcanicity = volcanicity;
	sbody->m_life = life;

	// force reload
	if (body->IsType(Object::TERRAINBODY))
		static_cast<TerrainBody*>(body)->GetGeoSphere()->OnChangeDetailLevel();
}
Beispiel #5
0
void SpaceStation::Render(Graphics::Renderer *r, const Camera *camera, const vector3d &viewCoords, const matrix4x4d &viewTransform)
{
	Body *b = GetFrame()->GetBody();
	assert(b);

	if (!b->IsType(Object::PLANET)) {
		// orbital spaceport -- don't make city turds or change lighting based on atmosphere
		RenderModel(r, camera, viewCoords, viewTransform);
		r->GetStats().AddToStatCount(Graphics::Stats::STAT_SPACESTATIONS, 1);
	} else {
		// don't render city if too far away
		if (viewCoords.LengthSqr() >= SQRMAXCITYDIST) {
			return;
		}
		std::vector<Graphics::Light> oldLights;
		Color oldAmbient;
		SetLighting(r, camera, oldLights, oldAmbient);

		if (!m_adjacentCity) {
			m_adjacentCity = new CityOnPlanet(static_cast<Planet*>(b), this, m_sbody->GetSeed());
		}
		m_adjacentCity->Render(r, camera->GetContext()->GetFrustum(), this, viewCoords, viewTransform);

		RenderModel(r, camera, viewCoords, viewTransform, false);

		ResetLighting(r, oldLights, oldAmbient);

		r->GetStats().AddToStatCount(Graphics::Stats::STAT_GROUNDSTATIONS, 1);
	}
}
Beispiel #6
0
// Renders space station and adjacent city if applicable
// For orbital starports: renders as normal
// For surface starports:
//	Lighting: Calculates available light for model and splits light between directly and ambiently lit
//            Lighting is done by manipulating global lights or setting uniforms in atmospheric models shader
void SpaceStation::Render(Graphics::Renderer *r, const Camera *camera, const vector3d &viewCoords, const matrix4x4d &viewTransform)
{
	Body *b = GetFrame()->GetBody();
	assert(b);

	if (!b->IsType(Object::PLANET)) {
		// orbital spaceport -- don't make city turds or change lighting based on atmosphere
		RenderModel(r, camera, viewCoords, viewTransform);
	}

	else {
		std::vector<Graphics::Light> oldLights;
		Color oldAmbient;
		SetLighting(r, camera, oldLights, oldAmbient);

		Planet *planet = static_cast<Planet*>(b);
		/* don't render city if too far away */
		if (viewCoords.Length() < 1000000.0){
			if (!m_adjacentCity) {
				m_adjacentCity = new CityOnPlanet(planet, this, m_sbody->seed);
			}
			m_adjacentCity->Render(r, camera, this, viewCoords, viewTransform);
		}

		RenderModel(r, camera, viewCoords, viewTransform, false);

		ResetLighting(r, oldLights, oldAmbient);
	}
}
Beispiel #7
0
void ObjectViewerView::Draw3D()
{
	m_renderer->ClearScreen();
	float znear, zfar;
	m_renderer->GetNearFarRange(znear, zfar);
	m_renderer->SetPerspectiveProjection(75.f, Pi::GetScrAspect(), znear, zfar);
	m_renderer->SetTransform(matrix4x4f::Identity());

	Graphics::Light light;
	light.SetType(Graphics::Light::LIGHT_DIRECTIONAL);

	if (Pi::MouseButtonState(SDL_BUTTON_RIGHT)) {
		int m[2];
		Pi::GetMouseMotion(m);
		m_camRot = matrix4x4d::RotateXMatrix(-0.002*m[1]) *
				matrix4x4d::RotateYMatrix(-0.002*m[0]) * m_camRot;
	}

	Body *body = Pi::player->GetNavTarget();
	if (body) {
		if (body->IsType(Object::STAR))
			light.SetPosition(vector3f(0.f));
		else {
			light.SetPosition(vector3f(0.577f));
		}
		m_renderer->SetLights(1, &light);

		body->Render(m_renderer, 0, vector3d(0,0,-viewingDist), m_camRot);
	}
}
Beispiel #8
0
void DynamicBody::CalcExternalForce()
{
	// gravity
	if (!GetFrame()) return;			// no external force if not in a frame
	Body *body = GetFrame()->GetBody();
	if (body && !body->IsType(Object::SPACESTATION)) {	// they ought to have mass though...
		vector3d b1b2 = GetPosition();
		double m1m2 = GetMass() * body->GetMass();
		double invrsqr = 1.0 / b1b2.LengthSqr();
		double force = G*m1m2 * invrsqr;
		m_externalForce = -b1b2 * sqrt(invrsqr) * force;
	}
	else m_externalForce = vector3d(0.0);
	m_gravityForce = m_externalForce;

	// atmospheric drag
	if (body && GetFrame()->IsRotFrame() && body->IsType(Object::PLANET))
	{
		Planet *planet = static_cast<Planet*>(body);
		double dist = GetPosition().Length();
		double speed = m_vel.Length();
		double pressure, density;
		planet->GetAtmosphericState(dist, &pressure, &density);
		const double radius = GetClipRadius();		// bogus, preserving behaviour
		const double AREA = radius;
		// ^^^ yes that is as stupid as it looks
		const double DRAG_COEFF = 0.1; // 'smooth sphere'
		vector3d dragDir = -m_vel.NormalizedSafe();
		vector3d fDrag = 0.5*density*speed*speed*AREA*DRAG_COEFF*dragDir;

		// make this a bit less daft at high time accel
		// only allow atmosForce to increase by .1g per frame
		vector3d f1g = m_atmosForce + dragDir * GetMass();
		if (fDrag.LengthSqr() > f1g.LengthSqr()) m_atmosForce = f1g;
		else m_atmosForce = fDrag;

		m_externalForce += m_atmosForce;
	}
	else m_atmosForce = vector3d(0.0);

	// centrifugal and coriolis forces for rotating frames
	if (GetFrame()->IsRotFrame()) {
		vector3d angRot(0, GetFrame()->GetAngSpeed(), 0);
		m_externalForce -= m_mass * angRot.Cross(angRot.Cross(GetPosition()));	// centrifugal
		m_externalForce -= 2 * m_mass * angRot.Cross(GetVelocity());			// coriolis
	}
}
/// Calculates acceleration due to gravity at given position
static double GetGravityAtPos(Frame *target_frame, const vector3d &position)
{
	Body *body = target_frame->GetBody();
	if (!body || body->IsType(Object::SPACESTATION)) {
		return 0.0;
	}
	return G * body->GetMass() / position.LengthSqr(); // inverse is: sqrt(G * m1m2 / thrust)	
}
Beispiel #10
0
// returns acceleration due to gravity at that point
static double GetGravityAtPos(Frame *targframe, const vector3d &posoff)
{
	Body *body = targframe->GetBodyFor();
	if (!body || body->IsType(Object::SPACESTATION)) return 0;
	double rsqr = posoff.LengthSqr();
	return G * body->GetMass() / rsqr;
	// inverse is: sqrt(G * m1m2 / thrust)
}
Beispiel #11
0
// check for collision course with frame body
// tandir is normal vector from planet to target pos or dir
static bool CheckSuicide(Ship *ship, const vector3d &tandir)
{
	Body *body = ship->GetFrame()->GetBodyFor();
	if (!body || !body->IsType(Object::TERRAINBODY)) return false;

	double vel = ship->GetVelocity().Dot(tandir);		// vel towards is negative
	double dist = ship->GetPosition().Length() - MaxFeatureRad(body);
	if (vel < -1.0 && vel*vel > 2.0*ship->GetAccelMin()*dist)
		return true;
	return false;
}
Beispiel #12
0
/*
 * Attribute: frameBody
 *
 * The non-dynamic body attached to the frame this dynamic body is in.
 *
 * Only valid for dynamic <Bodies>. For non-dynamic bodies <frameBody> will be
 * nil.
 *
 * <frameBody> can also be nil if this dynamic body is in a frame with no
 * non-dynamic body. This most commonly occurs when the player is in
 * hyperspace.
 *
 * Availability:
 *
 *   alpha 12
 *
 * Status:
 *
 *   experimental
 */
static int l_body_attr_frame_body(lua_State *l)
{
	Body *b = LuaObject<Body>::CheckFromLua(1);
	if (!b->IsType(Object::DYNAMICBODY)) {
		lua_pushnil(l);
		return 1;
	}

	Frame *f = b->GetFrame();
	LuaObject<Body>::PushToLua(f->GetBody());
	return 1;
}
Beispiel #13
0
/*
 * Attribute: frameRotating
 *
 * Whether the frame this dynamic body is in is a rotating frame.
 *
 * Only valid for dynamic <Bodies>. For non-dynamic bodies <frameRotating>
 * will be nil.
 *
 * Availability:
 *
 *   alpha 12
 *
 * Status:
 *
 *   experimental
 */
static int l_body_attr_frame_rotating(lua_State *l)
{
	Body *b = LuaObject<Body>::CheckFromLua(1);
	if (!b->IsType(Object::DYNAMICBODY)) {
		lua_pushnil(l);
		return 1;
	}

	Frame *f = b->GetFrame();
	lua_pushboolean(l, f->IsRotFrame());
	return 1;
}
Beispiel #14
0
void DynamicBody::CalcExternalForce()
{
    // gravity
    if (!GetFrame()) return;			// no external force if not in a frame
    Body *body = GetFrame()->GetBody();
    if (body && !body->IsType(Object::SPACESTATION)) {	// they ought to have mass though...
        vector3d b1b2 = GetPosition();
        double m1m2 = GetMass() * body->GetMass();
        double invrsqr = 1.0 / b1b2.LengthSqr();
        double force = G*m1m2 * invrsqr;
        m_externalForce = -b1b2 * sqrt(invrsqr) * force;
    }
    else m_externalForce = vector3d(0.0);
    m_gravityForce = m_externalForce;

    // atmospheric drag
    if (body && GetFrame()->IsRotFrame() && body->IsType(Object::PLANET))
    {
        vector3d dragDir = -m_vel.NormalizedSafe();
        vector3d fDrag = CalcAtmosphericForce(m_dragCoeff)*dragDir;

        // make this a bit less daft at high time accel
        // only allow atmosForce to increase by .1g per frame
        vector3d f1g = m_atmosForce + dragDir * GetMass();
        if (fDrag.LengthSqr() > f1g.LengthSqr()) m_atmosForce = f1g;
        else m_atmosForce = fDrag;

        m_externalForce += m_atmosForce;
    }
    else m_atmosForce = vector3d(0.0);

    // centrifugal and coriolis forces for rotating frames
    if (GetFrame()->IsRotFrame()) {
        vector3d angRot(0, GetFrame()->GetAngSpeed(), 0);
        m_externalForce -= m_mass * angRot.Cross(angRot.Cross(GetPosition()));	// centrifugal
        m_externalForce -= 2 * m_mass * angRot.Cross(GetVelocity());			// coriolis
    }
}
// Checks ship path to destination for obstacles.
// clear_angle is angle
// returns true if path is clear, false if there is an obstacle.
static bool CheckClearPath(Ship* ship, Frame* destination_frame, vector3d destination_pos, float clear_angle = 0.0f)
{
	Body* sbody = ship->GetFrame()->GetBody();
	if (sbody == nullptr) {
		return true;
	}
	if (sbody->IsType(Object::PLANET) 
		|| (sbody->IsType(Object::SPACESTATION) && ship->GetFrame() != destination_frame)) 
	{
		vector3d ship_pos = ship->GetPositionRelTo(destination_frame);
		vector3d body_pos = sbody->GetPositionRelTo(destination_frame);
		double radius = GetTransitRadius(sbody);
		if (sbody->IsType(Object::PLANET)) {
			radius += 5000.0;
		}
		double ship_to_body_distance;
		vector3d ship_to_body_dir = (body_pos - ship_pos).Normalized(ship_to_body_distance);
		double ship_to_destination_distance;
		vector3d ship_to_destination_dir = (destination_pos - ship_pos).Normalized(ship_to_destination_distance);
		double cos = ship_to_destination_dir.Dot(ship_to_body_dir);
		if (cos > clear_angle) { // Path might be unclear
			double ship_to_closest_distance = cos * ship_to_body_distance;
			vector3d closest_point = ship_pos + (ship_to_destination_dir * ship_to_closest_distance);
			double closest_distance = (closest_point - body_pos).Length();
			if (closest_distance < radius && ship_to_closest_distance < ship_to_destination_distance) {
				return false;
			} else {
				return true;
			}
		} else {
			return true;
		}
	} else {
		return true;
	}
}
Beispiel #16
0
double DynamicBody::CalcAtmosphericForce(double dragCoeff) const
{
    Body *body = GetFrame()->GetBody();
    if (!body || !GetFrame()->IsRotFrame() || !body->IsType(Object::PLANET))
        return 0.0;
    Planet *planet = static_cast<Planet*>(body);
    double dist = GetPosition().Length();
    double speed = m_vel.Length();
    double pressure, density;
    planet->GetAtmosphericState(dist, &pressure, &density);
    const double radius = GetClipRadius();		// bogus, preserving behaviour
    const double area = radius;
    // ^^^ yes that is as stupid as it looks
    return 0.5*density*speed*speed*area*dragCoeff;
}
Beispiel #17
0
static int l_body_get_atmospheric_state(lua_State *l) {
	Body *b = LuaObject<Body>::CheckFromLua(1);
	//	const SystemBody *sb = b->GetSystemBody();
	vector3d pos = Pi::player->GetPosition();
	double center_dist = pos.Length();
	if (b->IsType(Object::PLANET)) {
		double pressure, density;
		static_cast<Planet*>(b)->GetAtmosphericState(center_dist, &pressure, &density);
		lua_pushnumber(l, pressure);
		lua_pushnumber(l, density);
		return 2;
	} else {
		return 0;
	}
}
Beispiel #18
0
void Projectile::StaticUpdate(const float timeStep)
{
	CollisionContact c;
	vector3d vel = (m_baseVel+m_dirVel) * timeStep;
	GetFrame()->GetCollisionSpace()->TraceRay(GetPosition(), vel.Normalized(), vel.Length(), &c, 0);
	
	if (c.userData1) {
		Object *o = static_cast<Object*>(c.userData1);

		if (o->IsType(Object::CITYONPLANET)) {
			Pi::game->GetSpace()->KillBody(this);
		}
		else if (o->IsType(Object::BODY)) {
			Body *hit = static_cast<Body*>(o);
			if (hit != m_parent) {
				hit->OnDamage(m_parent, GetDamage());
				Pi::game->GetSpace()->KillBody(this);
				if (hit->IsType(Object::SHIP))
					Pi::luaOnShipHit->Queue(dynamic_cast<Ship*>(hit), dynamic_cast<Body*>(m_parent));
			}
		}
	}
	if (Equip::lasers[m_type].flags & Equip::LASER_MINING) {
		// need to test for terrain hit
		if (GetFrame()->m_astroBody && GetFrame()->m_astroBody->IsType(Object::PLANET)) {
			Planet *const planet = static_cast<Planet*>(GetFrame()->m_astroBody);
			const SBody *b = planet->GetSBody();
			vector3d pos = GetPosition();
			double terrainHeight = planet->GetTerrainHeight(pos.Normalized());
			if (terrainHeight > pos.Length()) {
				// hit the f****r
				if (b->type == SBody::TYPE_PLANET_ASTEROID) {
					vector3d n = GetPosition().Normalized();
					MiningLaserSpawnTastyStuff(planet->GetFrame(), b, n*terrainHeight + 5.0*n);
					Sfx::Add(this, Sfx::TYPE_EXPLOSION);
				}
				Pi::game->GetSpace()->KillBody(this);
			}
		}
	}
}
void ObjectViewerView::Draw3D()
{
	PROFILE_SCOPED()
	m_renderer->ClearScreen();
	float znear, zfar;
	m_renderer->GetNearFarRange(znear, zfar);
	m_renderer->SetPerspectiveProjection(75.f, m_renderer->GetDisplayAspect(), znear, zfar);
	m_renderer->SetTransform(matrix4x4f::Identity());

	Graphics::Light light;
	light.SetType(Graphics::Light::LIGHT_DIRECTIONAL);

	const int btnState = Pi::MouseButtonState(SDL_BUTTON_RIGHT);
	if (btnState) {
		int m[2];
		Pi::GetMouseMotion(m);
		m_camRot = matrix4x4d::RotateXMatrix(-0.002*m[1]) *
				matrix4x4d::RotateYMatrix(-0.002*m[0]) * m_camRot;
		m_cameraContext->SetPosition(Pi::player->GetInterpPosition() + vector3d(0, 0, viewingDist));
		m_cameraContext->BeginFrame();
		m_camera->Update();
	}

	Body *body = Pi::player->GetNavTarget();
	if (body) {
		if (body->IsType(Object::STAR))
			light.SetPosition(vector3f(0.f));
		else {
			light.SetPosition(vector3f(0.577f));
		}
		m_renderer->SetLights(1, &light);

		body->Render(m_renderer, m_camera.get(), vector3d(0,0,-viewingDist), m_camRot);
	}

	UIView::Draw3D();
	if (btnState) {
		m_cameraContext->EndFrame();
	}
}
Beispiel #20
0
void ObjectViewerView::Draw3D()
{
	static float rot;
	rot += 0.1;
	glClearColor(0,0,0,0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	float znear, zfar;
	Pi::worldView->GetNearFarClipPlane(&znear, &zfar);
	float fracH = znear / Pi::GetScrAspect();
	glFrustum(-znear, znear, -fracH, fracH, znear, zfar);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glEnable(GL_LIGHT0);

	Render::State::SetZnearZfar(znear, zfar);

	if (Pi::MouseButtonState(SDL_BUTTON_RIGHT)) {
		int m[2];
		Pi::GetMouseMotion(m);
		m_camRot = matrix4x4d::RotateXMatrix(-0.002*m[1]) *
				matrix4x4d::RotateYMatrix(-0.002*m[0]) * m_camRot;
	}
		
	Body *body = Pi::player->GetNavTarget();
	if (body) {
		float lightPos[4];
		if (body->IsType(Object::STAR))
			lightPos[0] = lightPos[1] = lightPos[2] = lightPos[3] = 0;
		else {
			lightPos[0] = lightPos[1] = lightPos[2] = 0.577f;
			lightPos[3] = 0;
		}
		glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
	
		body->Render(vector3d(0,0,-viewingDist), m_camRot);
	}
}
Beispiel #21
0
void ObjectViewerView::OnChangeGeoSphereStyle()
{
	SBody sbody;

	const fixed volatileGas = fixed(65536.0*atof(m_sbodyVolatileGas->GetText().c_str()), 65536);
	const fixed volatileLiquid = fixed(65536.0*atof(m_sbodyVolatileLiquid->GetText().c_str()), 65536);
	const fixed volatileIces = fixed(65536.0*atof(m_sbodyVolatileIces->GetText().c_str()), 65536);
	const fixed life = fixed(65536.0*atof(m_sbodyLife->GetText().c_str()), 65536);
	const fixed volcanicity = fixed(65536.0*atof(m_sbodyVolcanicity->GetText().c_str()), 65536);
	const fixed metallicity = fixed(65536.0*atof(m_sbodyMetallicity->GetText().c_str()), 65536);
	const fixed mass = fixed(65536.0*atof(m_sbodyMass->GetText().c_str()), 65536);
	const fixed radius = fixed(65536.0*atof(m_sbodyRadius->GetText().c_str()), 65536);

	sbody.parent = 0;
	sbody.name = "Test";
	/* These should be the only SBody attributes GeoSphereStyle uses */
	sbody.type = SBody::TYPE_PLANET_TERRESTRIAL;
	sbody.seed = atoi(m_sbodySeed->GetText().c_str());
	sbody.radius = radius;
	sbody.mass = mass;
	sbody.averageTemp = 273;
	sbody.m_metallicity = metallicity;
	sbody.m_volatileGas = volatileGas;
	sbody.m_volatileLiquid = volatileLiquid;
	sbody.m_volatileIces = volatileIces;
	sbody.m_volcanicity = volcanicity;
	sbody.m_life = life;
	sbody.heightMapFilename = 0;

	Body *body = Pi::player->GetNavTarget();
	if (body->IsType(Object::PLANET)) {
		Planet *planet = static_cast<Planet*>(body);
		GeoSphere *gs = planet->GetGeoSphere();
		gs->m_style = GeoSphereStyle(&sbody);
		// force rebuild
		gs->OnChangeDetailLevel();
	}
}
Beispiel #22
0
static int l_get_gps(lua_State *l)
{
	Player *player = LuaObject<Player>::CheckFromLua(1);
	vector3d pos = Pi::player->GetPosition();
	double center_dist = pos.Length();
	auto frame = player->GetFrame();
	if(frame) {
		Body *astro = frame->GetBody();
		if(astro && astro->IsType(Object::TERRAINBODY)) {
			TerrainBody* terrain = static_cast<TerrainBody*>(astro);
			if (!frame->IsRotFrame())
				frame = frame->GetRotFrame();
			vector3d surface_pos = pos.Normalized();
			double radius = 0.0;
			if (center_dist <= 3.0 * terrain->GetMaxFeatureRadius()) {
				radius = terrain->GetTerrainHeight(surface_pos);
			}
			double altitude = center_dist - radius;
			vector3d velocity = player->GetVelocity();
			double vspeed = velocity.Dot(surface_pos);
			if (fabs(vspeed) < 0.05) vspeed = 0.0; // Avoid alternating between positive/negative zero

			//			RefreshHeadingPitch();

			if (altitude < 0) altitude = 0;
			LuaPush(l, altitude);
			LuaPush(l, vspeed);
			const float lat = RAD2DEG(asin(surface_pos.y));
			const float lon = RAD2DEG(atan2(surface_pos.x, surface_pos.z));
			LuaPush(l, lat);
			LuaPush(l, lon);
			return 4;
			//				}
		}
	}
	return 0;
}
Beispiel #23
0
void AmbientSounds::Update()
{
	float v_env = (Pi::worldView->GetActiveCamera()->IsExternal() ? 1.0f : 0.5f) * Sound::GetSfxVolume();

	if (Pi::player->GetFlightState() == Ship::DOCKED) {
		if (starNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			starNoise.VolumeAnimate(target, dv_dt);
			starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
		if (atmosphereNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			atmosphereNoise.VolumeAnimate(target, dv_dt);
			atmosphereNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
		if (planetSurfaceNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			planetSurfaceNoise.VolumeAnimate(target, dv_dt);
			planetSurfaceNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}

		if (!stationNoise.IsPlaying()) {
			const char *sounds[] = {
				"Large_Station_ambient",
				"Medium_Station_ambient",
				"Small_Station_ambient"
			};
			// just use a random station noise until we have a
			// concept of 'station size'
			stationNoise.Play(sounds[Pi::player->GetDockedWith()->GetSystemBody()->seed % 3],
					0.3f*v_env, 0.3f*v_env, Sound::OP_REPEAT);
		}
	} else if (Pi::player->GetFlightState() == Ship::LANDED) {
		/* Planet surface noise on rough-landing */
		if (starNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			starNoise.VolumeAnimate(target, dv_dt);
			starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
		if (atmosphereNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			atmosphereNoise.VolumeAnimate(target, dv_dt);
			atmosphereNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
		if (stationNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			stationNoise.VolumeAnimate(target, dv_dt);
			stationNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}

		// lets try something random for the time being
		if (!planetSurfaceNoise.IsPlaying()) {
			SystemBody *sbody = Pi::player->GetFrame()->GetSystemBodyFor();
			assert(sbody);
			const char *sample = NULL;

			if (sbody->m_life > fixed(1,5)) {
				const char *s[] = {
					"Wind", "Thunder_1", "Thunder_2", "Thunder_3",
					"Thunder_4", "Storm", "Rain_Light", "River",
					"RainForestIntroducedNight", "RainForestIntroduced",
					"NormalForestIntroduced"
				};
				sample = s[sbody->seed % 11];
			}
			else if (sbody->m_volatileGas > fixed(1,2)) {
				const char *s[] = {
					"Wind", "Thunder_1", "Thunder_2", "Thunder_3",
					"Thunder_4", "Storm"
				};
				sample = s[sbody->seed % 6];
			}
			else if (sbody->m_volatileGas > fixed(1,10)) {
				sample = "Wind";
			}

			if (sample) {
				planetSurfaceNoise.Play(sample, 0.3f*v_env, 0.3f*v_env, Sound::OP_REPEAT);
			}
		}
    } else if (planetSurfaceNoise.IsPlaying()) {
        // planetSurfaceNoise.IsPlaying() - if we are out of the atmosphere then stop playing
        if (Pi::player->GetFrame()->m_astroBody) {
            Body *astro = Pi::player->GetFrame()->m_astroBody;
            if (astro->IsType(Object::PLANET)) {
                double dist = Pi::player->GetPosition().Length();
                double pressure, density;
                static_cast<Planet*>(astro)->GetAtmosphericState(dist, &pressure, &density);
                if (pressure < 0.001) {
                    // Stop playing surface noise once out of the atmosphere
                    planetSurfaceNoise.Stop();
                }
            }
        }
    } else {
		if (stationNoise.IsPlaying()) {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			stationNoise.VolumeAnimate(target, dv_dt);
			stationNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
		{
			if (Pi::game->IsNormalSpace()) {
				StarSystem *s = Pi::game->GetSpace()->GetStarSystem().Get();
				if (astroNoiseSeed != s->GetSeed()) {
					// change sound!
					astroNoiseSeed = s->GetSeed();
					float target[2] = {0.0f,0.0f};
					float dv_dt[2] = {0.1f,0.1f};
					starNoise.VolumeAnimate(target, dv_dt);
					starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
					// XXX the way Sound::Event works isn't totally obvious.
					// to destroy the object doesn't stop the sound. it is
					// really just a sound event reference
					starNoise = Sound::Event();
				}
			}
		}
		// when all the sounds are in we can use the body we are in frame of reference to
		if (!starNoise.IsPlaying()) {
			Frame *f = Pi::player->GetFrame();
			if (!f) return; // When player has no frame (game abort) then get outta here!!
			const SystemBody *sbody = f->GetSystemBodyFor();
			const char *sample = 0;
			for (; sbody && !sample; sbody = f->GetSystemBodyFor()) {
				switch (sbody->type) {
					case SystemBody::TYPE_BROWN_DWARF: sample = "Brown_Dwarf_Substellar_Object"; break;
					case SystemBody::TYPE_STAR_M: sample = "M_Red_Star"; break;
					case SystemBody::TYPE_STAR_K: sample = "K_Star"; break;
					case SystemBody::TYPE_WHITE_DWARF: sample = "White_Dwarf_Star"; break;
					case SystemBody::TYPE_STAR_G: sample = "G_Star"; break;
					case SystemBody::TYPE_STAR_F: sample = "F_Star"; break;
					case SystemBody::TYPE_STAR_A: sample = "A_Star"; break;
					case SystemBody::TYPE_STAR_B: sample = "B_Hot_Blue_STAR"; break;
					case SystemBody::TYPE_STAR_O: sample = "Blue_Super_Giant"; break;
					case SystemBody::TYPE_PLANET_GAS_GIANT: {
							if (sbody->mass > fixed(400,1)) {
								sample = "Very_Large_Gas_Giant";
							} else if (sbody->mass > fixed(80,1)) {
								sample = "Large_Gas_Giant";
							} else if (sbody->mass > fixed(20,1)) {
								sample = "Medium_Gas_Giant";
							} else {
								sample = "Small_Gas_Giant";
							}
						}
						break;
					default: sample = 0; break;
				}
				if (sample) {
					starNoise.Play(sample, 0.0f, 0.0f, Sound::OP_REPEAT);
					starNoise.VolumeAnimate(.3f*v_env, .3f*v_env, .05f, .05f);
				} else {
					// go up orbital hierarchy tree to see if we can find a sound
					f = f->m_parent;
					if (f == 0) break;
				}
			}
		}

		Body *astro;
		if ((astro = Pi::player->GetFrame()->m_astroBody) && (astro->IsType(Object::PLANET))) {
			double dist = Pi::player->GetPosition().Length();
			double pressure, density;
			static_cast<Planet*>(astro)->GetAtmosphericState(dist, &pressure, &density);
			// maximum volume at around 2km/sec at earth density, pressure
			float volume = float(density * Pi::player->GetVelocity().Length() * 0.0005);
			volume = Clamp(volume, 0.0f, 1.0f) * v_env;
			if (atmosphereNoise.IsPlaying()) {
				float target[2] = {volume, volume};
				float dv_dt[2] = {1.0f,1.0f};
				atmosphereNoise.VolumeAnimate(target, dv_dt);
			} else {
				atmosphereNoise.Play("Atmosphere_Flying", volume, volume, Sound::OP_REPEAT);
			}
		} else {
			float target[2] = {0.0f,0.0f};
			float dv_dt[2] = {1.0f,1.0f};
			atmosphereNoise.VolumeAnimate(target, dv_dt);
			atmosphereNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME);
		}
	}
}
Beispiel #24
0
void Ship::StaticUpdate(const float timeStep)
{
	// do player sounds before dead check, so they also turn off
	if (IsType(Object::PLAYER)) DoThrusterSounds();

	if (IsDead()) return;

	if (m_controller) m_controller->StaticUpdate(timeStep);

	if (GetHullTemperature() > 1.0)
		Explode();

	UpdateAlertState();

	/* FUEL SCOOPING!!!!!!!!! */
	int capacity = 0;
	Properties().Get("fuel_scoop_cap", capacity);
	if (m_flightState == FLYING && capacity > 0) {
		Body *astro = GetFrame()->GetBody();
		if (astro && astro->IsType(Object::PLANET)) {
			Planet *p = static_cast<Planet*>(astro);
			if (p->GetSystemBody()->IsScoopable()) {
				double dist = GetPosition().Length();
				double pressure, density;
				p->GetAtmosphericState(dist, &pressure, &density);

				double speed = GetVelocity().Length();
				vector3d vdir = GetVelocity().Normalized();
				vector3d pdir = -GetOrient().VectorZ();
				double dot = vdir.Dot(pdir);
				if ((m_stats.free_capacity) && (dot > 0.95) && (speed > 2000.0) && (density > 1.0)) {
					double rate = speed*density*0.00000333f*double(capacity);
					if (Pi::rng.Double() < rate) {
						lua_State *l = Lua::manager->GetLuaState();
						pi_lua_import(l, "Equipment");
						LuaTable hydrogen = LuaTable(l, -1).Sub("cargo").Sub("hydrogen");
						LuaObject<Ship>::CallMethod(this, "AddEquip", hydrogen);
						UpdateEquipStats();
						if (this->IsType(Object::PLAYER)) {
							Pi::game->log->Add(stringf(Lang::FUEL_SCOOP_ACTIVE_N_TONNES_H_COLLECTED,
									formatarg("quantity", LuaObject<Ship>::CallMethod<int>(this, "CountEquip", hydrogen))));
						}
						lua_pop(l, 3);
					}
				}
			}
		}
	}

	// Cargo bay life support
	capacity = 0;
	Properties().Get("cargo_life_support_cap", capacity);
	if (!capacity) {
		// Hull is pressure-sealed, it just doesn't provide
		// temperature regulation and breathable atmosphere

		// kill stuff roughly every 5 seconds
		if ((!m_dockedWith) && (5.0*Pi::rng.Double() < timeStep)) {
			std::string t(Pi::rng.Int32(2) ? "live_animals" : "slaves");

			lua_State *l = Lua::manager->GetLuaState();
			pi_lua_import(l, "Equipment");
			LuaTable cargo = LuaTable(l, -1).Sub("cargo");
			if (LuaObject<Ship>::CallMethod<int>(this, "RemoveEquip", cargo.Sub(t))) {
				LuaObject<Ship>::CallMethod<int>(this, "AddEquip", cargo.Sub("fertilizer"));
				if (this->IsType(Object::PLAYER)) {
					Pi::game->log->Add(Lang::CARGO_BAY_LIFE_SUPPORT_LOST);
				}
				lua_pop(l, 4);
			}
			else
				lua_pop(l, 3);
		}
	}

	if (m_flightState == FLYING)
		m_launchLockTimeout -= timeStep;
	if (m_launchLockTimeout < 0) m_launchLockTimeout = 0;
	if (m_flightState == JUMPING || m_flightState == HYPERSPACE)
		m_launchLockTimeout = 0;

	// lasers
	for (int i=0; i<ShipType::GUNMOUNT_MAX; i++) {
		m_gun[i].recharge -= timeStep;
		float rateCooling = 0.01f;
		float cooler = 1.0f;
		Properties().Get("laser_cooler_cap", cooler);
		rateCooling *= cooler;
		m_gun[i].temperature -= rateCooling*timeStep;
		if (m_gun[i].temperature < 0.0f) m_gun[i].temperature = 0;
		if (m_gun[i].recharge < 0.0f) m_gun[i].recharge = 0;

		if (!m_gun[i].state) continue;
		if (m_gun[i].recharge > 0.0f) continue;
		if (m_gun[i].temperature > 1.0) continue;

		FireWeapon(i);
	}

	if (m_ecmRecharge > 0.0f) {
		m_ecmRecharge = std::max(0.0f, m_ecmRecharge - timeStep);
	}

	if (m_shieldCooldown > 0.0f) {
		m_shieldCooldown = std::max(0.0f, m_shieldCooldown - timeStep);
	}

	if (m_stats.shield_mass_left < m_stats.shield_mass) {
		// 250 second recharge
		float recharge_rate = 0.004f;
		float booster = 1.0f;
		Properties().Get("shield_energy_booster_cap", booster);
		recharge_rate *= booster;
		m_stats.shield_mass_left = Clamp(m_stats.shield_mass_left + m_stats.shield_mass * recharge_rate * timeStep, 0.0f, m_stats.shield_mass);
		Properties().Set("shieldMassLeft", m_stats.shield_mass_left);
	}

	if (m_wheelTransition) {
		m_wheelState += m_wheelTransition*0.3f*timeStep;
		m_wheelState = Clamp(m_wheelState, 0.0f, 1.0f);
		if (is_equal_exact(m_wheelState, 0.0f) || is_equal_exact(m_wheelState, 1.0f))
			m_wheelTransition = 0;
	}

	if (m_testLanded) TestLanded();

	capacity = 0;
	Properties().Get("hull_autorepair_cap", capacity);
	if (capacity) {
		m_stats.hull_mass_left = std::min(m_stats.hull_mass_left + 0.1f*timeStep, float(m_type->hullMass));
		Properties().Set("hullMassLeft", m_stats.hull_mass_left);
		Properties().Set("hullPercent", 100.0f * (m_stats.hull_mass_left / float(m_type->hullMass)));
	}

	// After calling StartHyperspaceTo this Ship must not spawn objects
	// holding references to it (eg missiles), as StartHyperspaceTo
	// removes the ship from Space::bodies and so the missile will not
	// have references to this cleared by NotifyRemoved()
	if (m_hyperspace.now) {
		m_hyperspace.now = false;
		EnterHyperspace();
	}

	if (m_hyperspace.countdown > 0.0f) {
		// Check the Lua function
		bool abort = false;
		lua_State * l = m_hyperspace.checks.GetLua();
		if (l) {
			m_hyperspace.checks.PushCopyToStack();
			if (lua_isfunction(l, -1)) {
				lua_call(l, 0, 1);
				abort = !lua_toboolean(l, -1);
				lua_pop(l, 1);
			}
		}
		if (abort) {
			AbortHyperjump();
		} else {
			m_hyperspace.countdown = m_hyperspace.countdown - timeStep;
			if (!abort && m_hyperspace.countdown <= 0.0f) {
				m_hyperspace.countdown = 0;
				m_hyperspace.now = true;
				SetFlightState(JUMPING);

				// We have to fire it here, because the event isn't actually fired until
				// after the whole physics update, which means the flight state on next
				// step would be HYPERSPACE, thus breaking quite a few things.
				LuaEvent::Queue("onLeaveSystem", this);
			}
		}
	}

	//Add smoke trails for missiles on thruster state
	static double s_timeAccum = 0.0;
	s_timeAccum += timeStep;
	if (m_type->tag == ShipType::TAG_MISSILE && !is_equal_exact(m_thrusters.LengthSqr(), 0.0) && (s_timeAccum > 4 || 0.1*Pi::rng.Double() < timeStep)) {
		s_timeAccum = 0.0;
		const vector3d pos = GetOrient() * vector3d(0, 0 , 5);
		const float speed = std::min(10.0*GetVelocity().Length()*std::max(1.0,fabs(m_thrusters.z)),100.0);
		SfxManager::AddThrustSmoke(this, speed, pos);
	}
}
Beispiel #25
0
/*
 * Method: IsDynamic
 *
 * Determine if the body is a dynamic body
 *
 * > isdynamic = body:IsDynamic()
 *
 * A dynamic body is one that is not part of the generated system. Currently
 * <Ships> and <CargoBodies> are dynamic bodies. <Stars>, <Planets> and
 * <SpaceStations> are not.
 *
 * Being a dynamic body generally means that there is no way to reference the
 * body outside of the context of the current system. A planet, for example,
 * can always be referenced by its <SystemPath> (available via <Body.path>),
 * even from outside the system. A <Ship> however can not be referenced in
 * this way. If a script needs to retain information about a ship that is no
 * longer in the <Player's> current system it must manage this itself.
 *
 * The above list of static/dynamic bodies may change in the future. Scripts
 * should use this method to determine the difference rather than checking
 * types directly.
 *
 * Availability:
 *
 *   alpha 10
 *
 * Status:
 *
 *   stable
 */
static int l_body_is_dynamic(lua_State *l)
{
	Body *b = LuaObject<Body>::CheckFromLua(1);
	lua_pushboolean(l, b->IsType(Object::DYNAMICBODY));
	return 1;
}
Beispiel #26
0
void Camera::Draw(Renderer *renderer, const Body *excludeBody)
{
	if (!m_camFrame) return;
	if (!renderer) return;

	m_renderer = renderer;

	glPushAttrib(GL_ALL_ATTRIB_BITS & (~GL_POINT_BIT));

	m_renderer->SetPerspectiveProjection(m_fovAng, m_width/m_height, m_zNear, m_zFar);
	m_renderer->SetTransform(matrix4x4f::Identity());
	m_renderer->ClearScreen();

	matrix4x4d trans2bg;
	Frame::GetFrameRenderTransform(Pi::game->GetSpace()->GetRootFrame(), m_camFrame, trans2bg);
	trans2bg.ClearToRotOnly();

	// Pick up to four suitable system light sources (stars)
	m_lightSources.clear();
	m_lightSources.reserve(4);
	position_system_lights(m_camFrame, Pi::game->GetSpace()->GetRootFrame(), m_lightSources);

	if (m_lightSources.empty()) {
		// no lights means we're somewhere weird (eg hyperspace). fake one
		const Color col(1.f);
		m_lightSources.push_back(LightSource(0, Graphics::Light(Graphics::Light::LIGHT_DIRECTIONAL, vector3f(0.f), col, col)));
	}

	//fade space background based on atmosphere thickness and light angle
	float bgIntensity = 1.f;
	if (m_camFrame->GetParent() && m_camFrame->GetParent()->IsRotFrame()) {
		//check if camera is near a planet
		Body *camParentBody = m_camFrame->GetParent()->GetBody();
		if (camParentBody && camParentBody->IsType(Object::PLANET)) {
			Planet *planet = static_cast<Planet*>(camParentBody);
			const vector3f relpos(planet->GetInterpPositionRelTo(m_camFrame));
			double altitude(relpos.Length());
			double pressure, density;
			planet->GetAtmosphericState(altitude, &pressure, &density);
			if (pressure >= 0.001)
			{
				//go through all lights to calculate something resembling light intensity
				float angle = 0.f;
				for(std::vector<LightSource>::const_iterator it = m_lightSources.begin();
					it != m_lightSources.end(); ++it) {
					const vector3f lightDir(it->GetLight().GetPosition().Normalized());
					angle += std::max(0.f, lightDir.Dot(-relpos.Normalized())) * it->GetLight().GetDiffuse().GetLuminance();
				}
				//calculate background intensity with some hand-tweaked fuzz applied
				bgIntensity = Clamp(1.f - std::min(1.f, powf(density, 0.25f)) * (0.3f + powf(angle, 0.25f)), 0.f, 1.f);
			}
		}
	}

	Pi::game->GetSpace()->GetBackground().SetIntensity(bgIntensity);
	Pi::game->GetSpace()->GetBackground().Draw(renderer, trans2bg);

	{
		std::vector<Graphics::Light> rendererLights;
		for (size_t i = 0; i < m_lightSources.size(); i++)
			rendererLights.push_back(m_lightSources[i].GetLight());
		renderer->SetLights(rendererLights.size(), &rendererLights[0]);
	}

	for (std::list<BodyAttrs>::iterator i = m_sortedBodies.begin(); i != m_sortedBodies.end(); ++i) {
		BodyAttrs *attrs = &(*i);

		// explicitly exclude a single body if specified (eg player)
		if (attrs->body == excludeBody)
			continue;

		double rad = attrs->body->GetClipRadius();
		if (!m_frustum.TestPointInfinite((*i).viewCoords, rad))
			continue;

		// draw spikes for far objects
		double screenrad = 500 * rad / attrs->camDist;      // approximate pixel size
		if (attrs->body->IsType(Object::PLANET) && screenrad < 2) {
			// absolute bullshit
			double spikerad = (7 + 1.5*log10(screenrad)) * rad / screenrad;
			DrawSpike(spikerad, attrs->viewCoords, attrs->viewTransform);
		}
		else if (screenrad >= 2 || attrs->body->IsType(Object::STAR) ||
					(attrs->body->IsType(Object::PROJECTILE) && screenrad > 0.25))
			attrs->body->Render(renderer, this, attrs->viewCoords, attrs->viewTransform);
	}

	Sfx::RenderAll(renderer, Pi::game->GetSpace()->GetRootFrame(), m_camFrame);

	m_frame->RemoveChild(m_camFrame);
	delete m_camFrame;
	m_camFrame = 0;

	glPopAttrib();
}
Beispiel #27
0
// Calculates the ambiently and directly lit portions of the lighting model taking into account the atmosphere and sun positions at a given location
// 1. Calculates the amount of direct illumination available taking into account
//    * multiple suns
//    * sun positions relative to up direction i.e. light is dimmed as suns set
//    * Thickness of the atmosphere overhead i.e. as atmospheres get thicker light starts dimming earlier as sun sets, without atmosphere the light switches off at point of sunset
// 2. Calculates the split between ambient and directly lit portions taking into account
//    * Atmosphere density (optical thickness) of the sky dome overhead
//        as optical thickness increases the fraction of ambient light increases
//        this takes altitude into account automatically
//    * As suns set the split is biased towards ambient
void ModelBody::CalcLighting(double &ambient, double &direct, const Camera *camera)
{
	const double minAmbient = 0.05;
	ambient = minAmbient;
	direct = 1.0;
	Body *astro = GetFrame()->GetBody();
	if ( ! (astro && astro->IsType(Object::PLANET)) )
		return;

	Planet *planet = static_cast<Planet*>(astro);

	// position relative to the rotating frame of the planet
	vector3d upDir = GetInterpPositionRelTo(planet->GetFrame());
	const double planetRadius = planet->GetSystemBody()->GetRadius();
	const double dist = std::max(planetRadius, upDir.Length());
	upDir = upDir.Normalized();

	double pressure, density;
	planet->GetAtmosphericState(dist, &pressure, &density);
	double surfaceDensity;
	Color cl;
	planet->GetSystemBody()->GetAtmosphereFlavor(&cl, &surfaceDensity);

	// approximate optical thickness fraction as fraction of density remaining relative to earths
	double opticalThicknessFraction = density/EARTH_ATMOSPHERE_SURFACE_DENSITY;

	// tweak optical thickness curve - lower exponent ==> higher altitude before ambient level drops
	// Commenting this out, since it leads to a sharp transition at
	// atmosphereRadius, where density is suddenly 0
	//opticalThicknessFraction = pow(std::max(0.00001,opticalThicknessFraction),0.15); //max needed to avoid 0^power

	if (opticalThicknessFraction < 0.0001)
		return;

	//step through all the lights and calculate contributions taking into account sun position
	double light = 0.0;
	double light_clamped = 0.0;

	const std::vector<Camera::LightSource> &lightSources = camera->GetLightSources();
	for(std::vector<Camera::LightSource>::const_iterator l = lightSources.begin();
			l != lightSources.end(); ++l) {

		double sunAngle;
		// calculate the extent the sun is towards zenith
		if (l->GetBody()){
			// relative to the rotating frame of the planet
			const vector3d lightDir = (l->GetBody()->GetInterpPositionRelTo(planet->GetFrame()).Normalized());
			sunAngle = lightDir.Dot(upDir);
		} else {
			// light is the default light for systems without lights
			sunAngle = 1.0;
		}

		const double critAngle = -sqrt(dist*dist-planetRadius*planetRadius)/dist;

		//0 to 1 as sunangle goes from critAngle to 1.0
		double sunAngle2 = (Clamp(sunAngle, critAngle, 1.0)-critAngle)/(1.0-critAngle);

		// angle at which light begins to fade on Earth
		const double surfaceStartAngle = 0.3;
		// angle at which sun set completes, which should be after sun has dipped below the horizon on Earth
		const double surfaceEndAngle = -0.18;

		const double start = std::min((surfaceStartAngle*opticalThicknessFraction),1.0);
		const double end = std::max((surfaceEndAngle*opticalThicknessFraction),-0.2);

		sunAngle = (Clamp(sunAngle-critAngle, end, start)-end)/(start-end);

		light += sunAngle;
		light_clamped += sunAngle2;
	}

	light_clamped /= lightSources.size();
	light /= lightSources.size();

	// brightness depends on optical depth and intensity of light from all the stars
	direct = 1.0 -  Clamp((1.0 - light),0.0,1.0) * Clamp(opticalThicknessFraction,0.0,1.0);

	// ambient light fraction
	// alter ratio between directly and ambiently lit portions towards ambiently lit as sun sets
	const double fraction = ( 0.2 + 0.8 * (1.0-light_clamped) ) * Clamp(opticalThicknessFraction,0.0,1.0);

	// fraction of light left over to be lit directly
	direct = (1.0-fraction)*direct;

	// scale ambient by amount of light
	ambient = fraction*(Clamp((light),0.0,1.0))*0.25;

	ambient = std::max(minAmbient, ambient);
}
Beispiel #28
0
void Ship::StaticUpdate(const float timeStep)
{
	AITimeStep(timeStep);		// moved to correct place, maybe

	if (GetHullTemperature() > 1.0) {
		Space::KillBody(this);
	}

	UpdateAlertState();

	/* FUEL SCOOPING!!!!!!!!! */
	if (m_equipment.Get(Equip::SLOT_FUELSCOOP) != Equip::NONE) {
		Body *astro = GetFrame()->m_astroBody;
		if (astro && astro->IsType(Object::PLANET)) {
			Planet *p = static_cast<Planet*>(astro);
			if (p->IsSuperType(SBody::SUPERTYPE_GAS_GIANT)) {
				double dist = GetPosition().Length();
				double pressure, density;
				p->GetAtmosphericState(dist, &pressure, &density);
			
				double speed = GetVelocity().Length();
				vector3d vdir = GetVelocity().Normalized();
				matrix4x4d rot;
				GetRotMatrix(rot);
				vector3d pdir = -vector3d(rot[8], rot[9], rot[10]).Normalized();
				double dot = vdir.Dot(pdir);
				if ((m_stats.free_capacity) && (dot > 0.95) && (speed > 2000.0) && (density > 1.0)) {
					double rate = speed*density*0.00001f;
					if (Pi::rng.Double() < rate) {
						m_equipment.Add(Equip::HYDROGEN);
						if (this == reinterpret_cast<Ship*>(Pi::player)) {
							Pi::Message(stringf(Lang::FUEL_SCOOP_ACTIVE_N_TONNES_H_COLLECTED,
									formatarg("quantity", m_equipment.Count(Equip::SLOT_CARGO, Equip::HYDROGEN))));
						}
						UpdateMass();
					}
				}
			}
		}
	}

	// Cargo bay life support
	if (m_equipment.Get(Equip::SLOT_CARGOLIFESUPPORT) != Equip::CARGO_LIFE_SUPPORT) {
		// Hull is pressure-sealed, it just doesn't provide
		// temperature regulation and breathable atmosphere
		
		// kill stuff roughly every 5 seconds
		if ((!m_dockedWith) && (5.0*Pi::rng.Double() < timeStep)) {
			Equip::Type t = (Pi::rng.Int32(2) ? Equip::LIVE_ANIMALS : Equip::SLAVES);
			
			if (m_equipment.Remove(t, 1)) {
				m_equipment.Add(Equip::FERTILIZER);
				if (this == reinterpret_cast<Ship*>(Pi::player)) {
					Pi::Message(Lang::CARGO_BAY_LIFE_SUPPORT_LOST);
				}
			}
		}
	}
	
	if (m_flightState == FLYING)
		m_launchLockTimeout -= timeStep;
	if (m_launchLockTimeout < 0) m_launchLockTimeout = 0;
	/* can't orient ships in SetDockedWith() because it gets
	 * called from collision handler, and collision system gets a bit
	 * weirded out if bodies are moved in the middle of collision detection
	 */
	if (m_dockedWith) m_dockedWith->OrientDockedShip(this, m_dockedWithPort);

	// lasers
	for (int i=0; i<ShipType::GUNMOUNT_MAX; i++) {
		m_gunRecharge[i] -= timeStep;
		float rateCooling = 0.01f;
		if (m_equipment.Get(Equip::SLOT_LASERCOOLER) != Equip::NONE)  {
			rateCooling *= float(EquipType::types[ m_equipment.Get(Equip::SLOT_LASERCOOLER) ].pval);
		}
		m_gunTemperature[i] -= rateCooling*timeStep;
		if (m_gunTemperature[i] < 0.0f) m_gunTemperature[i] = 0;
		if (m_gunRecharge[i] < 0.0f) m_gunRecharge[i] = 0;

		if (!m_gunState[i]) continue;
		if (m_gunRecharge[i] > 0.0f) continue;
		if (m_gunTemperature[i] > 1.0) continue;

		FireWeapon(i);
	}

	if (m_ecmRecharge > 0.0f) {
		m_ecmRecharge = std::max(0.0f, m_ecmRecharge - timeStep);
	}

	if (m_stats.shield_mass_left < m_stats.shield_mass) {
		// 250 second recharge
		float recharge_rate = 0.004f;
		if (m_equipment.Get(Equip::SLOT_ENERGYBOOSTER) != Equip::NONE) {
			recharge_rate *= float(EquipType::types[ m_equipment.Get(Equip::SLOT_ENERGYBOOSTER) ].pval);
		}
		m_stats.shield_mass_left += m_stats.shield_mass * recharge_rate * timeStep;
	}
	m_stats.shield_mass_left = Clamp(m_stats.shield_mass_left, 0.0f, m_stats.shield_mass);

	if (m_wheelTransition) {
		m_wheelState += m_wheelTransition*0.3f*timeStep;
		m_wheelState = Clamp(m_wheelState, 0.0f, 1.0f);
		if (float_equal_exact(m_wheelState, 0.0f) || float_equal_exact(m_wheelState, 1.0f))
			m_wheelTransition = 0;
	}

	if (m_testLanded) TestLanded();

	if (m_equipment.Get(Equip::SLOT_HULLAUTOREPAIR) == Equip::HULL_AUTOREPAIR) {
		const ShipType &stype = GetShipType();
		m_stats.hull_mass_left = std::min(m_stats.hull_mass_left + 0.1f*timeStep, float(stype.hullMass));
	}

	// After calling StartHyperspaceTo this Ship must not spawn objects
	// holding references to it (eg missiles), as StartHyperspaceTo
	// removes the ship from Space::bodies and so the missile will not
	// have references to this cleared by NotifyDeleted()
	if (m_hyperspace.countdown > 0.0f) {
		m_hyperspace.countdown = m_hyperspace.countdown - timeStep;
		if (m_hyperspace.countdown <= 0.0f) {
			m_hyperspace.countdown = 0;
			m_hyperspace.now = true;
		}
	}

	if (m_hyperspace.now) {
		m_hyperspace.now = false;
		Space::StartHyperspaceTo(this, &m_hyperspace.dest);
	}
}
Beispiel #29
0
// Renders space station and adjacent city if applicable
// For orbital starports: renders as normal
// For surface starports:
//	Lighting: Calculates available light for model and splits light between directly and ambiently lit
//            Lighting is done by manipulating global lights or setting uniforms in atmospheric models shader
void SpaceStation::Render(Graphics::Renderer *r, const Camera *camera, const vector3d &viewCoords, const matrix4x4d &viewTransform)
{
	Body *b = GetFrame()->GetBody();
	assert(b);

	if (!b->IsType(Object::PLANET)) {
		// orbital spaceport -- don't make city turds or change lighting based on atmosphere
		RenderModel(r, viewCoords, viewTransform);
	}

	else {
		Planet *planet = static_cast<Planet*>(b);

		// calculate lighting
		// available light is calculated and split between directly (diffusely/specularly) lit and ambiently lit
		const std::vector<Camera::LightSource> &lightSources = camera->GetLightSources();
		double ambient, intensity;

		CalcLighting(planet, ambient, intensity, lightSources);
		ambient = std::max(0.05, ambient);

		std::vector<Graphics::Light> origLights, newLights;

		for(size_t i = 0; i < lightSources.size(); i++) {
			Graphics::Light light(lightSources[i].GetLight());

			origLights.push_back(light);

			Color c = light.GetDiffuse();
			Color cs = light.GetSpecular();
			c.r*=float(intensity);
			c.g*=float(intensity);
			c.b*=float(intensity);
			cs.r*=float(intensity);
			cs.g*=float(intensity);
			cs.b*=float(intensity);
			light.SetDiffuse(c);
			light.SetSpecular(cs);

			newLights.push_back(light);
		}

		const Color oldAmbient = r->GetAmbientColor();
		r->SetAmbientColor(Color(ambient));
		r->SetLights(newLights.size(), &newLights[0]);

		/* don't render city if too far away */
		if (viewCoords.Length() < 1000000.0){
			if (!m_adjacentCity) {
				m_adjacentCity = new CityOnPlanet(planet, this, m_sbody->seed);
			}
			m_adjacentCity->Render(r, camera, this, viewCoords, viewTransform);
		}

		RenderModel(r, viewCoords, viewTransform);

		// restore old lights & ambient
		r->SetLights(origLights.size(), &origLights[0]);
		r->SetAmbientColor(oldAmbient);
	}
}
Beispiel #30
0
// Renders space station and adjacent city if applicable
// For orbital starports: renders as normal
// For surface starports: 
//	Lighting: Calculates available light for model and splits light between directly and ambiently lit
//            Lighting is done by manipulating global lights or setting uniforms in atmospheric models shader
//            Adds an ambient light at close ranges if dark by manipulating the global ambient level
void SpaceStation::Render(Graphics::Renderer *r, const Camera *camera, const vector3d &viewCoords, const matrix4x4d &viewTransform)
{
	LmrObjParams &params = GetLmrObjParams();
	params.label = GetLabel().c_str();
	SetLmrTimeParams();

	for (int i=0; i<MAX_DOCKING_PORTS; i++) {
		params.animStages[ANIM_DOCKING_BAY_1 + i] = m_shipDocking[i].stage;
		params.animValues[ANIM_DOCKING_BAY_1 + i] = m_shipDocking[i].stagePos;
	}

	Body *b = GetFrame()->m_astroBody;
	assert(b);

	if (!b->IsType(Object::PLANET)) {
		// orbital spaceport -- don't make city turds or change lighting based on atmosphere
		RenderLmrModel(r, viewCoords, viewTransform);
	}
	
	else {
		Planet *planet = static_cast<Planet*>(b);
		
		// calculate lighting
		// available light is calculated and split between directly (diffusely/specularly) lit and ambiently lit
		const std::vector<Camera::LightSource> &lightSources = camera->GetLightSources();
		double ambient, intensity;
		CalcLighting(planet, ambient, intensity, lightSources);

		std::vector<Graphics::Light> origLights, newLights;
		
		for(size_t i = 0; i < lightSources.size(); i++) {
			Graphics::Light light(lightSources[i].GetLight());

			origLights.push_back(light);

			Color c = light.GetDiffuse();
			Color ca = light.GetAmbient();
			Color cs = light.GetSpecular();
			ca.r = c.r * float(ambient);
			ca.g = c.g * float(ambient);
			ca.b = c.b * float(ambient);
			c.r*=float(intensity);
			c.g*=float(intensity);
			c.b*=float(intensity);
			cs.r*=float(intensity);
			cs.g*=float(intensity);
			cs.b*=float(intensity);
			light.SetDiffuse(c);
			light.SetAmbient(ca);
			light.SetSpecular(cs);

			newLights.push_back(light);
		}

		r->SetLights(newLights.size(), &newLights[0]);

		double overallLighting = ambient+intensity;

		// turn off global ambient color
		const Color oldAmbient = r->GetAmbientColor();
		r->SetAmbientColor(Color::BLACK);

		// as the camera gets close adjust scene ambient so that intensity+ambient = minIllumination
		double fadeInEnd, fadeInLength, minIllumination;
		if (Graphics::AreShadersEnabled()) {
			minIllumination = 0.125;
			fadeInEnd = 800.0;
			fadeInLength = 2000.0;
		}
		else {
			minIllumination = 0.25;
			fadeInEnd = 1500.0;
			fadeInLength = 3000.0;
		}

		/* don't render city if too far away */
		if (viewCoords.Length() < 1000000.0){
			r->SetAmbientColor(Color::BLACK);
			if (!m_adjacentCity) {
				m_adjacentCity = new CityOnPlanet(planet, this, m_sbody->seed);
			}
			m_adjacentCity->Render(r, camera, this, viewCoords, viewTransform, overallLighting, minIllumination);
		} 

		r->SetAmbientColor(Color::BLACK);

		FadeInModelIfDark(r, GetCollMesh()->GetBoundingRadius(),
							viewCoords.Length(), fadeInEnd, fadeInLength, overallLighting, minIllumination);

		RenderLmrModel(r, viewCoords, viewTransform);

		// restore old lights
		r->SetLights(origLights.size(), &origLights[0]);

		// restore old ambient color
		r->SetAmbientColor(oldAmbient);
	}
}