pioneer/src/Intro.cpp

163 lines
5.1 KiB
C++

// Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
#include "Intro.h"
#include "Easing.h"
#include "Lang.h"
#include "Pi.h"
#include "galaxy/Galaxy.h"
#include "graphics/Graphics.h"
#include "graphics/Renderer.h"
#include "graphics/TextureBuilder.h"
#include "scenegraph/ModelSkin.h"
#include "scenegraph/SceneGraph.h"
#include <algorithm>
class PiRngWrapper {
public:
PiRngWrapper(size_t maxValue) :
maxVal(maxValue) {}
typedef unsigned int result_type;
static constexpr unsigned int min() { return 0; }
static constexpr unsigned int max() { return std::numeric_limits<uint32_t>::max(); }
unsigned int operator()()
{
return Pi::rng.Int32(maxVal);
}
private:
const int32_t maxVal;
};
Intro::Intro(Graphics::Renderer *r, int width, int height) :
Cutscene(r, width, height)
{
using Graphics::Light;
m_background.reset(new Background::Container(r, Pi::rng, nullptr, RefCountedPtr<Galaxy>()));
m_ambientColor = Color::BLANK;
const Color one = Color::WHITE;
const Color two = Color(77, 77, 204, 0);
m_lights.push_back(Light(Graphics::Light::LIGHT_DIRECTIONAL, vector3f(0.f, 0.3f, 1.f), one, one));
m_lights.push_back(Light(Graphics::Light::LIGHT_DIRECTIONAL, vector3f(0.f, -1.f, 0.f), two, Color::BLACK));
m_skin.SetDecal("pioneer");
m_skin.SetLabel(Lang::PIONEER);
for (auto i : ShipType::player_ships) {
SceneGraph::Model *model = Pi::FindModel(ShipType::types[i].modelName)->MakeInstance();
model->SetThrust(vector3f(0.f, 0.f, -0.6f), vector3f(0.f));
if (ShipType::types[i].isGlobalColorDefined) model->SetThrusterColor(ShipType::types[i].globalThrusterColor);
for (int j = 0; j < THRUSTER_MAX; j++) {
if (!ShipType::types[i].isDirectionColorDefined[j]) continue;
vector3f dir;
switch (j) {
case THRUSTER_FORWARD: dir = vector3f(0.0, 0.0, 1.0); break;
case THRUSTER_REVERSE: dir = vector3f(0.0, 0.0, -1.0); break;
case THRUSTER_LEFT: dir = vector3f(1.0, 0.0, 0.0); break;
case THRUSTER_RIGHT: dir = vector3f(-1.0, 0.0, 0.0); break;
case THRUSTER_UP: dir = vector3f(1.0, 0.0, 0.0); break;
case THRUSTER_DOWN: dir = vector3f(-1.0, 0.0, 0.0); break;
}
model->SetThrusterColor(dir, ShipType::types[i].directionThrusterColor[j]);
}
const Uint32 numMats = model->GetNumMaterials();
for (Uint32 m = 0; m < numMats; m++) {
RefCountedPtr<Graphics::Material> mat = model->GetMaterialByIndex(m);
mat->specialParameter0 = nullptr;
}
m_models.push_back(model);
}
std::shuffle(m_models.begin(), m_models.end(), PiRngWrapper(m_models.size()));
m_modelIndex = 0;
const int w = Graphics::GetScreenWidth();
const int h = Graphics::GetScreenHeight();
// double-width viewport, centred, then offset 1/6th to centre on the left
// 2/3rds of the screen, to the left of the menu
m_spinnerLeft = int(float(w) * -.5f - float(w) / 6.f);
m_spinnerWidth = w * 2;
m_spinnerRatio = w * 2.f / h;
m_needReset = true;
}
Intro::~Intro()
{
for (std::vector<SceneGraph::Model *>::iterator i = m_models.begin(); i != m_models.end(); ++i)
delete (*i);
}
void Intro::Reset()
{
m_model = m_models[m_modelIndex++];
if (m_modelIndex == m_models.size()) m_modelIndex = 0;
m_skin.SetRandomColors(Pi::rng);
m_skin.Apply(m_model);
if (m_model->SupportsPatterns())
m_model->SetPattern(Pi::rng.Int32(0, m_model->GetNumPatterns() - 1));
m_zoomBegin = -10000.0f;
m_zoomEnd = -m_model->GetDrawClipRadius() * 1.7f;
m_dist = m_zoomBegin;
m_startTime = Pi::GetApp()->GetTime();
m_needReset = false;
}
// stage end times
static const float ZOOM_IN_END = 2.0f;
static const float WAIT_END = 12.0f;
static const float ZOOM_OUT_END = 14.0f;
void Intro::Draw(float deltaTime)
{
if (m_needReset)
Reset();
// FIXME: add a better interface for retrieving a global time source
float duration = Pi::GetApp()->GetTime() - m_startTime;
// zoom in
if (duration < ZOOM_IN_END)
m_dist = Clamp(Easing::Quad::EaseOut(duration, m_zoomBegin, m_zoomEnd - m_zoomBegin, 2.0f), m_zoomBegin, m_zoomEnd);
// wait
else if (duration < WAIT_END) {
m_dist = m_zoomEnd;
}
// zoom out
else if (duration < ZOOM_OUT_END)
m_dist = Clamp(Easing::Quad::EaseIn(duration - WAIT_END, m_zoomEnd, m_zoomBegin - m_zoomEnd, 2.0f), m_zoomBegin, m_zoomEnd);
// done
else
m_needReset = true;
Graphics::Renderer::StateTicket ticket(m_renderer);
m_renderer->SetPerspectiveProjection(75, m_aspectRatio, 1.f, 10000.f);
m_renderer->SetTransform(matrix4x4f::Identity());
m_renderer->SetAmbientColor(m_ambientColor);
m_renderer->SetLights(m_lights.size(), &m_lights[0]);
// XXX all this stuff will be gone when intro uses a Camera
// rotate background by time, and a bit extra Z so it's not so flat
matrix4x4d brot = matrix4x4d::RotateXMatrix(-0.25 * Pi::GetApp()->GetTime()) * matrix4x4d::RotateZMatrix(0.6);
m_renderer->ClearDepthBuffer();
m_background->Draw(brot);
m_renderer->SetViewport({ m_spinnerLeft, 0, m_spinnerWidth, Graphics::GetScreenHeight() });
m_renderer->SetPerspectiveProjection(75, m_spinnerRatio, 1.f, 10000.f);
matrix4x4f trans =
matrix4x4f::Translation(0, 0, m_dist) *
matrix4x4f::RotateXMatrix(DEG2RAD(-15.0f)) *
matrix4x4f::RotateYMatrix(duration);
m_model->Render(trans);
}