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(); }