void SpaceStation::Render(const vector3d &viewCoords, const matrix4x4d &viewTransform) { LmrObjParams ¶ms = 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; } RenderLmrModel(viewCoords, viewTransform); /* don't render city if too far away */ if (viewCoords.Length() > 1000000.0) return; // find planet Body* Planet *planet; { Body *_planet = GetFrame()->m_astroBody; if ((!_planet) || !_planet->IsType(Object::PLANET)) { // orbital spaceport -- don't make city turds } else { planet = static_cast<Planet*>(_planet); if (!m_adjacentCity) { m_adjacentCity = new CityOnPlanet(planet, this, m_sbody->seed); } m_adjacentCity->Render(this, viewCoords, viewTransform); } } }
// 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); } }
// 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(); }
void UpdateVBOs() { PROFILE_SCOPED() //create buffer and upload data Graphics::VertexBufferDesc vbd; vbd.attrib[0].semantic = Graphics::ATTRIB_POSITION; vbd.attrib[0].format = Graphics::ATTRIB_FORMAT_FLOAT3; vbd.attrib[1].semantic = Graphics::ATTRIB_NORMAL; vbd.attrib[1].format = Graphics::ATTRIB_FORMAT_FLOAT3; vbd.numVertices = ctx->NUMVERTICES(); vbd.usage = Graphics::BUFFER_USAGE_STATIC; m_vertexBuffer.reset(Pi::renderer->CreateVertexBuffer(vbd)); GasPatchContext::VBOVertex* vtxPtr = m_vertexBuffer->Map<GasPatchContext::VBOVertex>(Graphics::BUFFER_MAP_WRITE); assert(m_vertexBuffer->GetDesc().stride == sizeof(GasPatchContext::VBOVertex)); const Sint32 edgeLen = ctx->edgeLen; const double frac = ctx->frac; for (Sint32 y=0; y<edgeLen; y++) { for (Sint32 x=0; x<edgeLen; x++) { const vector3d p = GetSpherePoint(x*frac, y*frac); const vector3d pSubCentroid = p - clipCentroid; clipRadius = std::max(clipRadius, p.Length()); vtxPtr->pos = vector3f(pSubCentroid); vtxPtr->norm = vector3f(p); ++vtxPtr; // next vertex } } m_vertexBuffer->Unmap(); }
void ProjectileSystem::update(ent_ptr<EntityManager> em, ent_ptr<EventManager> events, double dt) { for (auto entity : em->entities_with_components<ProjectileComponent, FrameComponent>()) { ent_ptr<ProjectileComponent> pc = entity.component<ProjectileComponent>(); pc->lifetime -= dt; if (pc->lifetime < 0) { entity.destroy(); continue; } ent_ptr<PosOrientComponent> poc = entity.component<PosOrientComponent>(); const vector3d vel = pc->baseVel + pc->dirVel; poc->pos += vel * dt; //Collide auto pfc = entity.component<FrameComponent>(); CollisionContact c; pfc->frame->GetCollisionSpace()->TraceRay(poc->pos, vel.Normalized(), vel.Length(), &c, 0); Entity* collEnt = static_cast<Entity*>(c.userData1); if (collEnt && *collEnt != pc->owner) { Entity clonk = *collEnt; //auto gc = clonk.component<CollisionMeshComponent>(); //auto fc = clonk.component<FrameComponent>(); //SDL_assert(gc); //SDL_assert(fc); //clonk.destroy(); entity.destroy(); } } }
// 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 int GetFlipMode(Ship *ship, const vector3d &relpos, const vector3d &relvel) { double dist = relpos.Length(); double vel = relvel.Dot(relpos) / dist; if (vel > 0.0 && vel*vel > 1.7 * ship->GetAccelRev() * dist) return 2; if (dist > 100000000.0) return 1; // arbitrary return 0; }
static void DrawAtmosphereSurface(Graphics::Renderer *renderer, const matrix4x4d &modelView, const vector3d &campos, float rad, Graphics::Material *mat) { const int LAT_SEGS = 20; const int LONG_SEGS = 20; vector3d yaxis = campos.Normalized(); vector3d zaxis = vector3d(1.0,0.0,0.0).Cross(yaxis).Normalized(); vector3d xaxis = yaxis.Cross(zaxis); const matrix4x4d invrot = matrix4x4d::MakeRotMatrix(xaxis, yaxis, zaxis).InverseOf(); renderer->SetTransform(modelView * matrix4x4d::ScaleMatrix(rad, rad, rad) * invrot); // what is this? Well, angle to the horizon is: // acos(planetRadius/viewerDistFromSphereCentre) // and angle from this tangent on to atmosphere is: // acos(planetRadius/atmosphereRadius) ie acos(1.0/1.01244blah) double endAng = acos(1.0/campos.Length())+acos(1.0/rad); double latDiff = endAng / double(LAT_SEGS); double rot = 0.0; float sinCosTable[LONG_SEGS+1][2]; for (int i=0; i<=LONG_SEGS; i++, rot += 2.0*M_PI/double(LONG_SEGS)) { sinCosTable[i][0] = float(sin(rot)); sinCosTable[i][1] = float(cos(rot)); } /* Tri-fan above viewer */ Graphics::VertexArray va(Graphics::ATTRIB_POSITION); va.Add(vector3f(0.f, 1.f, 0.f)); for (int i=0; i<=LONG_SEGS; i++) { va.Add(vector3f( sin(latDiff)*sinCosTable[i][0], cos(latDiff), -sin(latDiff)*sinCosTable[i][1])); } renderer->DrawTriangles(&va, mat, Graphics::TRIANGLE_FAN); /* and wound latitudinal strips */ double lat = latDiff; for (int j=1; j<LAT_SEGS; j++, lat += latDiff) { Graphics::VertexArray v(Graphics::ATTRIB_POSITION); float cosLat = cos(lat); float sinLat = sin(lat); float cosLat2 = cos(lat+latDiff); float sinLat2 = sin(lat+latDiff); for (int i=0; i<=LONG_SEGS; i++) { v.Add(vector3f(sinLat*sinCosTable[i][0], cosLat, -sinLat*sinCosTable[i][1])); v.Add(vector3f(sinLat2*sinCosTable[i][0], cosLat2, -sinLat2*sinCosTable[i][1])); } renderer->DrawTriangles(&v, mat, Graphics::TRIANGLE_STRIP); } }
void SpaceStation::Render(const vector3d &viewCoords, const matrix4x4d &viewTransform) { /* Well this is nice... */ static int poo=0; if (!poo) { poo = 1; LmrGetModelsWithTag("advert", s_advertModels); } // it is silly to do this every render call // // random advert models in pFlag[16 .. 19] // station name in pText[0] // docking port in pText[1] MTRand rand; rand.seed(m_sbody->seed); LmrObjParams ¶ms = GetLmrObjParams(); /* random advert models */ params.argStrings[4] = s_advertModels[rand.Int32(s_advertModels.size())]->GetName(); params.argStrings[5] = s_advertModels[rand.Int32(s_advertModels.size())]->GetName(); params.argStrings[6] = s_advertModels[rand.Int32(s_advertModels.size())]->GetName(); params.argStrings[7] = s_advertModels[rand.Int32(s_advertModels.size())]->GetName(); params.argStrings[0] = GetLabel().c_str(); SetLmrTimeParams(); for (int i=0; i<MAX_DOCKING_PORTS; i++) { params.argDoubles[ARG_STATION_BAY1_STAGE + i] = double(m_shipDocking[i].stage); params.argDoubles[ARG_STATION_BAY1_POS + i] = m_shipDocking[i].stagePos; } RenderLmrModel(viewCoords, viewTransform); /* don't render city if too far away */ if (viewCoords.Length() > 1000000.0) return; // find planet Body* Planet *planet; { Body *_planet = GetFrame()->m_astroBody; if ((!_planet) || !_planet->IsType(Object::PLANET)) { // orbital spaceport -- don't make city turds } else { planet = static_cast<Planet*>(_planet); if (!m_adjacentCity) { m_adjacentCity = new CityOnPlanet(planet, this, m_sbody->seed); } m_adjacentCity->Render(this, viewCoords, viewTransform); } } }
void Space::BodyNearFinder::GetBodiesMaybeNear(const vector3d &pos, double dist, BodyNearList &bodies) const { if (m_bodyDist.empty()) return; const double len = pos.Length(); std::vector<BodyDist>::const_iterator min = std::lower_bound(m_bodyDist.begin(), m_bodyDist.end(), len-dist); std::vector<BodyDist>::const_iterator max = std::upper_bound(min, m_bodyDist.end(), len+dist); while (min != max) { bodies.push_back((*min).body); ++min; } }
/* * Function: SpawnShipNear * * Create a ship and place it in space near the given <Body>. * * > ship = Space.SpawnShip(type, body, min, max, hyperspace) * * Parameters: * * type - the name of the ship * * body - the <Body> near which the ship should be spawned * * min - minimum distance from the body to place the ship, in Km * * max - maximum distance to place the ship * * hyperspace - optional table containing hyperspace entry information. If * this is provided the ship will not spawn directly. Instead, * a hyperspace cloud will be created that the ship will exit * from. The table contains two elements, a <SystemPath> for * the system the ship is travelling from, and the due * date/time that the ship should emerge from the cloud. * * Return: * * ship - a <Ship> object for the new ship * * Example: * * > -- spawn a ship 10km from the player * > local ship = Ship.SpawnNear("viper_police_craft", Game.player, 10, 10) * * Availability: * * alpha 10 * * Status: * * experimental */ static int l_space_spawn_ship_near(lua_State *l) { if (!Pi::game) luaL_error(l, "Game is not started"); LUA_DEBUG_START(l); const char *type = luaL_checkstring(l, 1); if (! ShipType::Get(type)) luaL_error(l, "Unknown ship type '%s'", type); Body *nearbody = LuaObject<Body>::CheckFromLua(2); float min_dist = luaL_checknumber(l, 3); float max_dist = luaL_checknumber(l, 4); SystemPath *path = 0; double due = -1; _unpack_hyperspace_args(l, 5, path, due); Ship *ship = new Ship(type); assert(ship); Body *thing = _maybe_wrap_ship_with_cloud(ship, path, due); // XXX protect against spawning inside the body Frame * newframe = nearbody->GetFrame(); const vector3d newPosition = (MathUtil::RandomPointOnSphere(min_dist, max_dist)* 1000.0) + nearbody->GetPosition(); // If the frame is rotating and the chosen position is too far, use non-rotating parent. // Otherwise the ship will be given a massive initial velocity when it's bumped out of the // rotating frame in the next update if (newframe->IsRotFrame() && newframe->GetRadius() < newPosition.Length()) { assert(newframe->GetParent()); newframe = newframe->GetParent(); } thing->SetFrame(newframe);; thing->SetPosition(newPosition); thing->SetVelocity(vector3d(0,0,0)); Pi::game->GetSpace()->AddBody(thing); LuaObject<Ship>::PushToLua(ship); LUA_DEBUG_END(l, 1); return 1; }
// check whether ship is at risk of colliding with frame body on current path // return values: //0 - no collision //1 - below feature height //2 - unsafe escape from effect radius //3 - unsafe entry to effect radius //4 - probable path intercept static int CheckCollision(Ship *ship, const vector3d &pathdir, double pathdist, const vector3d &tpos, double endvel, double r) { // ship is in obstructor's frame anyway, so is tpos if (pathdist < 100.0) return 0; Body *body = ship->GetFrame()->GetBodyFor(); if (!body) return 0; vector3d spos = ship->GetPosition(); double tlen = tpos.Length(), slen = spos.Length(); double fr = MaxFeatureRad(body); // if target inside, check if direct entry is safe (30 degree) if (tlen < r) { double af = (tlen > fr) ? 0.5 * (1 - (tlen-fr) / (r-fr)) : 0.5; if (pathdir.Dot(tpos) > -af*tlen) if (slen < fr) return 1; else return 3; else return 0; } // if ship inside, check for max feature height and direct escape (30 degree) if (slen < r) { if (slen < fr) return 1; double af = (slen > fr) ? 0.5 * (1 - (slen-fr) / (r-fr)) : 0.5; if (pathdir.Dot(spos) < af*slen) return 2; else return 0; } // now for the intercept calc // find closest point to obstructor double tanlen = -spos.Dot(pathdir); if (tanlen < 0 || tanlen > pathdist) return 0; // closest point outside path vector3d perpdir = (tanlen*pathdir + spos).Normalized(); double perpspeed = ship->GetVelocity().Dot(perpdir); double parspeed = ship->GetVelocity().Dot(pathdir); if (parspeed < 0) parspeed = 0; // shouldn't break any important case if (perpspeed > 0) perpspeed = 0; // prevent attempts to speculatively fly through planets // find time that ship will pass through that point // get velocity as if accelerating from start or end, pick smallest double ivelsqr = endvel*endvel + 2*ship->GetAccelFwd()*(pathdist-tanlen); // could put endvel in here double fvelsqr = parspeed*parspeed + 2*ship->GetAccelFwd()*tanlen; double tanspeed = sqrt(ivelsqr < fvelsqr ? ivelsqr : fvelsqr); double time = tanlen / (0.5 * (parspeed + tanspeed)); // actually correct? double dist = spos.Dot(perpdir) + perpspeed*time; // spos.perpdir should be positive if (dist < r) return 4; return 0; }
void GeoPatch::_UpdateVBOs() { if (m_needUpdateVBOs) { m_needUpdateVBOs = false; if (!m_vbo) glGenBuffersARB(1, &m_vbo); glBindBufferARB(GL_ARRAY_BUFFER, m_vbo); glBufferDataARB(GL_ARRAY_BUFFER, sizeof(GeoPatchContext::VBOVertex)*ctx->NUMVERTICES(), 0, GL_DYNAMIC_DRAW); double xfrac=0.0, yfrac=0.0; double *pHts = heights.Get(); const vector3f *pNorm = &normals[0]; const Color3ub *pColr = &colors[0]; GeoPatchContext::VBOVertex *pData = ctx->vbotemp; for (int y=0; y<ctx->edgeLen; y++) { xfrac = 0.0; for (int x=0; x<ctx->edgeLen; x++) { const double height = *pHts; const vector3d p = (GetSpherePoint(xfrac, yfrac) * (height + 1.0)) - clipCentroid; clipRadius = std::max(clipRadius, p.Length()); pData->x = float(p.x); pData->y = float(p.y); pData->z = float(p.z); ++pHts; // next height pData->nx = pNorm->x; pData->ny = pNorm->y; pData->nz = pNorm->z; ++pNorm; // next normal pData->col[0] = pColr->r; pData->col[1] = pColr->g; pData->col[2] = pColr->b; pData->col[3] = 255; ++pColr; // next colour ++pData; // next vertex xfrac += ctx->frac; } yfrac += ctx->frac; } glBufferDataARB(GL_ARRAY_BUFFER, sizeof(GeoPatchContext::VBOVertex)*ctx->NUMVERTICES(), ctx->vbotemp, GL_DYNAMIC_DRAW); glBindBufferARB(GL_ARRAY_BUFFER, 0); } }
void SystemView::PutOrbit(const Orbit *orbit, const vector3d &offset, const Color &color, double planetRadius) { int num_vertices = 0; vector3f vts[100]; for (int i = 0; i < int(COUNTOF(vts)); ++i) { const double t = double(i) / double(COUNTOF(vts)); const vector3d pos = orbit->EvenSpacedPosTrajectory(t); vts[i] = vector3f(offset + pos * double(m_zoom)); ++num_vertices; if (pos.Length() < planetRadius) break; } if (num_vertices > 1) { // don't close the loop for hyperbolas and parabolas and crashed ellipses if ((orbit->GetEccentricity() > 1.0) || (num_vertices < int(COUNTOF(vts)))) m_renderer->DrawLines(num_vertices, vts, color, LINE_STRIP); else m_renderer->DrawLines(num_vertices, vts, color, LINE_LOOP); } }
void Body::UpdateFrame() { if (!(m_flags & FLAG_CAN_MOVE_FRAME)) return; // falling out of frames if (m_frame->GetRadius() < GetPosition().Length()) { Frame *newFrame = GetFrame()->GetParent(); if (newFrame) { // don't fall out of root frame Output("%s leaves frame %s\n", GetLabel().c_str(), GetFrame()->GetLabel().c_str()); SwitchToFrame(newFrame); return; } } // entering into frames for (Frame* kid : m_frame->GetChildren()) { const vector3d pos = GetPositionRelTo(kid); if (pos.Length() >= kid->GetRadius()) continue; SwitchToFrame(kid); Output("%s enters frame %s\n", GetLabel().c_str(), kid->GetLabel().c_str()); break; } }
void Camera::DrawSpike(double rad, const vector3d &viewCoords, const matrix4x4d &viewTransform) { // draw twinkly star-thing on faraway objects // XXX this seems like a good case for drawing in 2D - use projected position, then the // "face the camera dammit" bits can be skipped if (!m_renderer) return; const double newdist = m_zNear + 0.5f * (m_zFar - m_zNear); const double scale = newdist / viewCoords.Length(); matrix4x4d trans = matrix4x4d::Identity(); trans.Translate(scale*viewCoords.x, scale*viewCoords.y, scale*viewCoords.z); // face the camera dammit vector3d zaxis = viewCoords.Normalized(); vector3d xaxis = vector3d(0,1,0).Cross(zaxis).Normalized(); vector3d yaxis = zaxis.Cross(xaxis); matrix4x4d rot = matrix4x4d::MakeInvRotMatrix(xaxis, yaxis, zaxis); trans = trans * rot; m_renderer->SetDepthTest(false); m_renderer->SetBlendMode(BLEND_ALPHA_ONE); // XXX this is supposed to pick a correct light colour for the object twinkle. // Not quite correct, since it always uses the first light GLfloat col[4]; glGetLightfv(GL_LIGHT0, GL_DIFFUSE, col); col[3] = 1.f; static VertexArray va(ATTRIB_POSITION | ATTRIB_DIFFUSE); va.Clear(); const Color center(col[0], col[1], col[2], col[2]); const Color edges(col[0], col[1], col[2], 0.f); //center va.Add(vector3f(0.f), center); const float spikerad = float(scale*rad); // bezier with (0,0,0) control points { const vector3f p0(0,spikerad,0), p1(spikerad,0,0); float t=0.1f; for (int i=1; i<10; i++, t+= 0.1f) { const vector3f p = (1-t)*(1-t)*p0 + t*t*p1; va.Add(p, edges); } } { const vector3f p0(spikerad,0,0), p1(0,-spikerad,0); float t=0.1f; for (int i=1; i<10; i++, t+= 0.1f) { const vector3f p = (1-t)*(1-t)*p0 + t*t*p1; va.Add(p, edges); } } { const vector3f p0(0,-spikerad,0), p1(-spikerad,0,0); float t=0.1f; for (int i=1; i<10; i++, t+= 0.1f) { const vector3f p = (1-t)*(1-t)*p0 + t*t*p1; va.Add(p, edges); } } { const vector3f p0(-spikerad,0,0), p1(0,spikerad,0); float t=0.1f; for (int i=1; i<10; i++, t+= 0.1f) { const vector3f p = (1-t)*(1-t)*p0 + t*t*p1; va.Add(p, edges); } } glPushMatrix(); m_renderer->SetTransform(trans); m_renderer->DrawTriangles(&va, Graphics::vtxColorMaterial, TRIANGLE_FAN); m_renderer->SetBlendMode(BLEND_SOLID); m_renderer->SetDepthTest(true); glPopMatrix(); }
// 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); } }
void Camera::DrawSpike(double rad, const vector3d &viewCoords, const matrix4x4d &viewTransform) { glPushMatrix(); float znear, zfar; Render::GetNearFarClipPlane(znear, zfar); double newdist = znear + 0.5f * (zfar - znear); double scale = newdist / viewCoords.Length(); glTranslatef(float(scale*viewCoords.x), float(scale*viewCoords.y), float(scale*viewCoords.z)); Render::State::UseProgram(0); // face the camera dammit vector3d zaxis = viewCoords.Normalized(); vector3d xaxis = vector3d(0,1,0).Cross(zaxis).Normalized(); vector3d yaxis = zaxis.Cross(xaxis); matrix4x4d rot = matrix4x4d::MakeInvRotMatrix(xaxis, yaxis, zaxis); glMultMatrixd(&rot[0]); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); // XXX WRONG. need to pick light from appropriate turd. GLfloat col[4]; glGetLightfv(GL_LIGHT0, GL_DIFFUSE, col); glColor4f(col[0], col[1], col[2], 1); glBegin(GL_TRIANGLE_FAN); glVertex3f(0,0,0); glColor4f(col[0], col[1], col[2], 0); const float spikerad = float(scale*rad); // bezier with (0,0,0) control points { vector3f p0(0,spikerad,0), p1(spikerad,0,0); float t=0.1f; for (int i=1; i<10; i++, t+= 0.1f) { vector3f p = (1-t)*(1-t)*p0 + t*t*p1; glVertex3fv(&p[0]); } } { vector3f p0(spikerad,0,0), p1(0,-spikerad,0); float t=0.1f; for (int i=1; i<10; i++, t+= 0.1f) { vector3f p = (1-t)*(1-t)*p0 + t*t*p1; glVertex3fv(&p[0]); } } { vector3f p0(0,-spikerad,0), p1(-spikerad,0,0); float t=0.1f; for (int i=1; i<10; i++, t+= 0.1f) { vector3f p = (1-t)*(1-t)*p0 + t*t*p1; glVertex3fv(&p[0]); } } { vector3f p0(-spikerad,0,0), p1(0,spikerad,0); float t=0.1f; for (int i=1; i<10; i++, t+= 0.1f) { vector3f p = (1-t)*(1-t)*p0 + t*t*p1; glVertex3fv(&p[0]); } } glEnd(); glDisable(GL_BLEND); glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); glPopMatrix(); }
void Planet::DrawAtmosphere(const vector3d &camPos) { Color col; double density; GetSBody()->GetAtmosphereFlavor(&col, &density); const double rad1 = 0.999; const double rad2 = 1.05; glPushMatrix(); // face the camera dammit vector3d zaxis = (-camPos).Normalized(); vector3d xaxis = vector3d(0,1,0).Cross(zaxis).Normalized(); vector3d yaxis = zaxis.Cross(xaxis); matrix4x4d rot = matrix4x4d::MakeInvRotMatrix(xaxis, yaxis, zaxis); glMultMatrixd(&rot[0]); matrix4x4f invViewRot; glGetFloatv(GL_MODELVIEW_MATRIX, &invViewRot[0]); invViewRot.ClearToRotOnly(); invViewRot = invViewRot.InverseOf(); const int numLights = Pi::worldView->GetNumLights(); assert(numLights < 4); vector3f lightDir[4]; float lightCol[4][4]; // only for (int i=0; i<numLights; i++) { float temp[4]; glGetLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lightCol[i]); glGetLightfv(GL_LIGHT0 + i, GL_POSITION, temp); lightDir[i] = (invViewRot * vector3f(temp[0], temp[1], temp[2])).Normalized(); } const double angStep = M_PI/32; // find angle player -> centre -> tangent point // tangent is from player to surface of sphere float tanAng = float(acos(rad1 / camPos.Length())); // then we can put the f*****g atmosphere on the horizon vector3d r1(0.0, 0.0, rad1); vector3d r2(0.0, 0.0, rad2); rot = matrix4x4d::RotateYMatrix(tanAng); r1 = rot * r1; r2 = rot * r2; rot = matrix4x4d::RotateZMatrix(angStep); glDisable(GL_LIGHTING); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glEnable(GL_BLEND); glDisable(GL_CULL_FACE); glBegin(GL_TRIANGLE_STRIP); for (float ang=0; ang<2*M_PI; ang+=float(angStep)) { vector3d norm = r1.Normalized(); glNormal3dv(&norm.x); float _col[4] = { 0,0,0,0 }; for (int lnum=0; lnum<numLights; lnum++) { const float dot = norm.x*lightDir[lnum].x + norm.y*lightDir[lnum].y + norm.z*lightDir[lnum].z; _col[0] += dot*lightCol[lnum][0]; _col[1] += dot*lightCol[lnum][1]; _col[2] += dot*lightCol[lnum][2]; } for (int i=0; i<3; i++) _col[i] = _col[i] * col[i]; _col[3] = col[3]; glColor4fv(_col); glVertex3dv(&r1.x); glColor4f(0,0,0,0); glVertex3dv(&r2.x); r1 = rot * r1; r2 = rot * r2; } glEnd(); glEnable(GL_CULL_FACE); glDisable(GL_BLEND); glEnable(GL_LIGHTING); glPopMatrix(); }
void BaseSphere::DrawAtmosphereSurface(Graphics::Renderer *renderer, const matrix4x4d &modelView, const vector3d &campos, float rad, Graphics::RenderState *rs, Graphics::Material *mat) { using namespace Graphics; const vector3d yaxis = campos.Normalized(); const vector3d zaxis = vector3d(1.0, 0.0, 0.0).Cross(yaxis).Normalized(); const vector3d xaxis = yaxis.Cross(zaxis); const matrix4x4d invrot = matrix4x4d::MakeRotMatrix(xaxis, yaxis, zaxis).Inverse(); renderer->SetTransform(modelView * matrix4x4d::ScaleMatrix(rad, rad, rad) * invrot); // what is this? Well, angle to the horizon is: // acos(planetRadius/viewerDistFromSphereCentre) // and angle from this tangent on to atmosphere is: // acos(planetRadius/atmosphereRadius) ie acos(1.0/1.01244blah) const double endAng = acos(1.0 / campos.Length()) + acos(1.0 / rad); const double latDiff = endAng / double(LAT_SEGS); double rot = 0.0; float sinTable[LONG_SEGS + 1]; float cosTable[LONG_SEGS + 1]; for (int i = 0; i <= LONG_SEGS; i++, rot += 2.0*M_PI / double(LONG_SEGS)) { sinTable[i] = float(sin(rot)); cosTable[i] = float(cos(rot)); } // Tri-fan above viewer if(!m_TriFanAbove.Valid()) { // VertexBuffer VertexBufferDesc vbd; vbd.attrib[0].semantic = ATTRIB_POSITION; vbd.attrib[0].format = ATTRIB_FORMAT_FLOAT3; vbd.numVertices = LONG_SEGS + 2; vbd.usage = BUFFER_USAGE_STATIC; m_TriFanAbove.Reset(renderer->CreateVertexBuffer(vbd)); } #pragma pack(push, 4) struct PosVert { vector3f pos; }; #pragma pack(pop) PosVert* vtxPtr = m_TriFanAbove->Map<PosVert>(Graphics::BUFFER_MAP_WRITE); vtxPtr[0].pos = vector3f(0.f, 1.f, 0.f); for (int i = 0; i <= LONG_SEGS; i++) { vtxPtr[i + 1].pos = vector3f( sin(latDiff)*sinTable[i], cos(latDiff), -sin(latDiff)*cosTable[i]); } m_TriFanAbove->Unmap(); renderer->DrawBuffer(m_TriFanAbove.Get(), rs, mat, Graphics::TRIANGLE_FAN); // and wound latitudinal strips if (!m_LatitudinalStrips[0].Valid()) { VertexBufferDesc vbd; vbd.attrib[0].semantic = ATTRIB_POSITION; vbd.attrib[0].format = ATTRIB_FORMAT_FLOAT3; vbd.numVertices = (LONG_SEGS + 1) * 2; vbd.usage = BUFFER_USAGE_DYNAMIC; for (int j = 0; j < LAT_SEGS; j++) { // VertexBuffer m_LatitudinalStrips[j].Reset(renderer->CreateVertexBuffer(vbd)); } } double lat = latDiff; for (int j=1; j<LAT_SEGS; j++, lat += latDiff) { const float cosLat = cos(lat); const float sinLat = sin(lat); const float cosLat2 = cos(lat+latDiff); const float sinLat2 = sin(lat+latDiff); vtxPtr = m_LatitudinalStrips[j]->Map<PosVert>(Graphics::BUFFER_MAP_WRITE); vtxPtr[0].pos = vector3f(0.f, 1.f, 0.f); for (int i=0; i<=LONG_SEGS; i++) { vtxPtr[(i*2)+0].pos = vector3f(sinLat*sinTable[i], cosLat, -sinLat*cosTable[i]); vtxPtr[(i*2)+1].pos = vector3f(sinLat2*sinTable[i], cosLat2, -sinLat2*cosTable[i]); } m_LatitudinalStrips[j]->Unmap(); renderer->DrawBuffer(m_LatitudinalStrips[j].Get(), rs, mat, Graphics::TRIANGLE_STRIP); } renderer->GetStats().AddToStatCount(Graphics::Stats::STAT_ATMOSPHERES, 1); }
void Planet::DrawAtmosphere(Renderer *renderer, const vector3d &camPos) { //this is the non-shadered atmosphere rendering Color col; double density; GetSystemBody()->GetAtmosphereFlavor(&col, &density); const double rad1 = 0.999; const double rad2 = 1.05; glPushMatrix(); //XXX pass the transform matrix4x4d curTrans; glGetDoublev(GL_MODELVIEW_MATRIX, &curTrans[0]); // face the camera dammit vector3d zaxis = (-camPos).Normalized(); vector3d xaxis = vector3d(0,1,0).Cross(zaxis).Normalized(); vector3d yaxis = zaxis.Cross(xaxis); matrix4x4d rot = matrix4x4d::MakeInvRotMatrix(xaxis, yaxis, zaxis); const matrix4x4d trans = curTrans * rot; matrix4x4d invViewRot = trans; invViewRot.ClearToRotOnly(); invViewRot = invViewRot.InverseOf(); //XXX this is always 1 const int numLights = Pi::worldView->GetNumLights(); assert(numLights < 4); vector3d lightDir[4]; float lightCol[4][4]; // only for (int i=0; i<numLights; i++) { float temp[4]; glGetLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lightCol[i]); glGetLightfv(GL_LIGHT0 + i, GL_POSITION, temp); lightDir[i] = (invViewRot * vector3d(temp[0], temp[1], temp[2])).Normalized(); } const double angStep = M_PI/32; // find angle player -> centre -> tangent point // tangent is from player to surface of sphere float tanAng = float(acos(rad1 / camPos.Length())); // then we can put the f*****g atmosphere on the horizon vector3d r1(0.0, 0.0, rad1); vector3d r2(0.0, 0.0, rad2); rot = matrix4x4d::RotateYMatrix(tanAng); r1 = rot * r1; r2 = rot * r2; rot = matrix4x4d::RotateZMatrix(angStep); VertexArray vts(ATTRIB_POSITION | ATTRIB_DIFFUSE | ATTRIB_NORMAL); for (float ang=0; ang<2*M_PI; ang+=float(angStep)) { const vector3d norm = r1.Normalized(); const vector3f n = vector3f(norm.x, norm.y, norm.z); float _col[4] = { 0,0,0,0 }; for (int lnum=0; lnum<numLights; lnum++) { const float dot = norm.x*lightDir[lnum].x + norm.y*lightDir[lnum].y + norm.z*lightDir[lnum].z; _col[0] += dot*lightCol[lnum][0]; _col[1] += dot*lightCol[lnum][1]; _col[2] += dot*lightCol[lnum][2]; } for (int i=0; i<3; i++) _col[i] = _col[i] * col[i]; _col[3] = col[3]; vts.Add(vector3f(r1.x, r1.y, r1.z), Color(_col[0], _col[1], _col[2], _col[3]), n); vts.Add(vector3f(r2.x, r2.y, r2.z), Color(0.f), n); r1 = rot * r1; r2 = rot * r2; } Material mat; mat.unlit = true; mat.twoSided = true; mat.vertexColors = true; renderer->SetTransform(trans); renderer->SetBlendMode(BLEND_ALPHA_ONE); renderer->DrawTriangles(&vts, &mat, TRIANGLE_STRIP); renderer->SetBlendMode(BLEND_SOLID); glPopMatrix(); }
// 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 ¶ms = 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); } }
void SystemView::PutOrbit(const Orbit *orbit, const vector3d &offset, const Color &color, const double planetRadius, const bool showLagrange) { double maxT = 1.; unsigned short num_vertices = 0; for (unsigned short i = 0; i < N_VERTICES_MAX; ++i) { const double t = double(i) / double(N_VERTICES_MAX); const vector3d pos = orbit->EvenSpacedPosTrajectory(t); if (pos.Length() < planetRadius) { maxT = t; break; } } static const float startTrailPercent = 0.85; static const float fadedColorParameter = 0.1; Uint16 fadingColors = 0; const double tMinust0 = m_time - m_game->GetTime(); for (unsigned short i = 0; i < N_VERTICES_MAX; ++i) { const double t = double(i) / double(N_VERTICES_MAX) * maxT; if(fadingColors == 0 && t >= startTrailPercent * maxT) fadingColors = i; const vector3d pos = orbit->EvenSpacedPosTrajectory(t, tMinust0); m_orbitVts[i] = vector3f(offset + pos * double(m_zoom)); ++num_vertices; if (pos.Length() < planetRadius) break; } const Color fadedColor = color * fadedColorParameter; std::fill_n(m_orbitColors.get(), num_vertices, fadedColor); const Uint16 trailLength = num_vertices - fadingColors; for (Uint16 currentColor = 0; currentColor < trailLength; ++currentColor) { float scalingParameter = fadedColorParameter + static_cast<float>(currentColor) / trailLength * (1.f - fadedColorParameter); m_orbitColors[currentColor + fadingColors] = color * scalingParameter; } if (num_vertices > 1) { m_orbits.SetData(num_vertices, m_orbitVts.get(), m_orbitColors.get()); // don't close the loop for hyperbolas and parabolas and crashed ellipses if (maxT < 1. || (orbit->GetEccentricity() > 1.0)) { m_orbits.Draw(m_renderer, m_lineState, LINE_STRIP); } else { m_orbits.Draw(m_renderer, m_lineState, LINE_LOOP); } } Gui::Screen::EnterOrtho(); vector3d pos; if(Gui::Screen::Project(offset + orbit->Perigeum() * double(m_zoom), pos)) m_periapsisIcon->Draw(Pi::renderer, vector2f(pos.x-3, pos.y-5), vector2f(6,10), color); if(Gui::Screen::Project(offset + orbit->Apogeum() * double(m_zoom), pos)) m_apoapsisIcon->Draw(Pi::renderer, vector2f(pos.x-3, pos.y-5), vector2f(6,10), color); if (showLagrange && m_showL4L5!=LAG_OFF) { const Color LPointColor(0x00d6e2ff); const vector3d posL4 = orbit->EvenSpacedPosTrajectory((1.0 / 360.0) * 60.0, tMinust0); if (Gui::Screen::Project(offset + posL4 * double(m_zoom), pos)) { m_l4Icon->Draw(Pi::renderer, vector2f(pos.x - 2, pos.y - 2), vector2f(4, 4), LPointColor); if(m_showL4L5==LAG_ICONTEXT) m_objectLabels->Add(std::string("L4"), sigc::mem_fun(this, &SystemView::OnClickLagrange), pos.x, pos.y); } const vector3d posL5 = orbit->EvenSpacedPosTrajectory((1.0 / 360.0) * 300.0, tMinust0); if (Gui::Screen::Project(offset + posL5 * double(m_zoom), pos)) { m_l5Icon->Draw(Pi::renderer, vector2f(pos.x - 2, pos.y - 2), vector2f(4, 4), LPointColor); if (m_showL4L5 == LAG_ICONTEXT) m_objectLabels->Add(std::string("L5"), sigc::mem_fun(this, &SystemView::OnClickLagrange), pos.x, pos.y); } } Gui::Screen::LeaveOrtho(); }
void GeoSphere::Render(Graphics::Renderer *renderer, const matrix4x4d &modelView, vector3d campos, const float radius, const float scale, const std::vector<Camera::Shadow> &shadows) { // store this for later usage in the update method. m_tempCampos = campos; m_hasTempCampos = true; if(m_initStage < eDefaultUpdateState) return; matrix4x4d trans = modelView; trans.Translate(-campos.x, -campos.y, -campos.z); renderer->SetTransform(trans); //need to set this for the following line to work Graphics::Frustum frustum = Graphics::Frustum::FromGLState(); // no frustum test of entire geosphere, since Space::Render does this // for each body using its GetBoundingRadius() value //First draw - create materials (they do not change afterwards) if (!m_surfaceMaterial.Valid()) SetUpMaterials(); if (Graphics::AreShadersEnabled()) { //Update material parameters //XXX no need to calculate AP every frame m_materialParameters.atmosphere = m_sbody->CalcAtmosphereParams(); m_materialParameters.atmosphere.center = trans * vector3d(0.0, 0.0, 0.0); m_materialParameters.atmosphere.planetRadius = radius; m_materialParameters.atmosphere.scale = scale; m_materialParameters.shadows = shadows; m_surfaceMaterial->specialParameter0 = &m_materialParameters; if (m_materialParameters.atmosphere.atmosDensity > 0.0) { m_atmosphereMaterial->specialParameter0 = &m_materialParameters; renderer->SetBlendMode(Graphics::BLEND_ALPHA_ONE); renderer->SetDepthWrite(false); // make atmosphere sphere slightly bigger than required so // that the edges of the pixel shader atmosphere j**z doesn't // show ugly polygonal angles DrawAtmosphereSurface(renderer, trans, campos, m_materialParameters.atmosphere.atmosRadius*1.01, m_atmosphereMaterial.Get()); renderer->SetDepthWrite(true); renderer->SetBlendMode(Graphics::BLEND_SOLID); } } Color ambient; Color &emission = m_surfaceMaterial->emissive; // save old global ambient const Color oldAmbient = renderer->GetAmbientColor(); if ((m_sbody->GetSuperType() == SystemBody::SUPERTYPE_STAR) || (m_sbody->type == SystemBody::TYPE_BROWN_DWARF)) { // stars should emit light and terrain should be visible from distance ambient.r = ambient.g = ambient.b = 0.2f; ambient.a = 1.0f; emission.r = StarSystem::starRealColors[m_sbody->type][0]; emission.g = StarSystem::starRealColors[m_sbody->type][1]; emission.b = StarSystem::starRealColors[m_sbody->type][2]; emission.a = 1.f; } else { // give planet some ambient lighting if the viewer is close to it double camdist = campos.Length(); camdist = 0.1 / (camdist*camdist); // why the f**k is this returning 0.1 when we are sat on the planet?? // JJ: Because campos is relative to a unit-radius planet - 1.0 at the surface // XXX oh well, it is the value we want anyway... ambient.r = ambient.g = ambient.b = float(camdist); ambient.a = 1.0f; } renderer->SetAmbientColor(ambient); //#define USE_WIREFRAME #ifdef USE_WIREFRAME renderer->SetWireFrameMode(true); #endif // this is pretty much the only place where a non-renderer is allowed to call Apply() // to be removed when someone rewrites terrain m_surfaceMaterial->Apply(); renderer->SetTransform(modelView); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); for (int i=0; i<NUM_PATCHES; i++) { m_patches[i]->Render(renderer, campos, modelView, frustum); } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); m_surfaceMaterial->Unapply(); renderer->SetAmbientColor(oldAmbient); #ifdef USE_WIREFRAME renderer->SetWireFrameMode(false); #endif }