1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-03 09:09:47 +02:00

Refactor and cleanup camera control.

rwengine
+ Make renderWorld() take a ViewCamera parameter.
+ add rotation and getView to ViewCamera
+ correct directions for vehicle and character movement.

rwgame
+ Remove GenericState
+ Add State::getCamera() to control the ViewCamera used for rendering
+ Clean up state camera control
+ Remove now unused view parameters from main
This commit is contained in:
Daniel Evans 2014-08-12 21:15:26 +01:00
parent 095073e667
commit ba7eb63941
19 changed files with 250 additions and 269 deletions

View File

@ -66,6 +66,9 @@ struct GameState
TextDisplayData nextText;
std::vector<TextDisplayData> texts;
/** The camera near value currently set by the script */
float cameraNear;
GameState() :
maxProgress(1),
numMissions(0),
@ -88,7 +91,8 @@ struct GameState
minute(0),
osTextStyle(0),
osTextStart(0.f),
osTextTime(0.f)
osTextTime(0.f),
cameraNear(0.1f)
{}
};

View File

@ -134,12 +134,13 @@ private:
/** Particles in flight */
std::vector<FXParticle> _particles;
/** Camera values passed to renderWorld() */
ViewCamera _camera;
public:
GameRenderer(GameWorld*);
ViewCamera camera;
/** Number of issued draw calls */
size_t rendered;
/** Number of culling events */
@ -165,14 +166,15 @@ public:
GLuint debugTex;
/**
* Draws the world:
* Renders the world using the parameters of the passed Camera.
* Note: The camera's near and far planes are overriden by weather effects.
*
* - draws all objects (instances, vehicles etc.)
* - draws particles
* - draws water surfaces
* - draws the skybox
*/
void renderWorld(float alpha);
void renderWorld(const ViewCamera &camera, float alpha);
/**
* @brief draws a CharacterObject and any item they are holding.

View File

@ -9,13 +9,23 @@ public:
ViewFrustum frustum;
glm::vec3 worldPos;
glm::vec3 position;
glm::quat rotation;
ViewCamera()
: frustum({0.1f, 5000.f, (-45.f / 180.f) * 3.1415f, 1.f})
ViewCamera(const glm::vec3& pos = {}, const glm::quat& rot = {})
: frustum({0.1f, 5000.f, glm::radians(45.f), 1.f}),
position(pos), rotation(rot)
{
}
glm::mat4 getView()
{
auto up = rotation * glm::vec3(0.f, 0.f, 1.f);
return glm::lookAt(position,
position + rotation * glm::vec3(1.f, 0.f, 0.f),
up);
}
};
#endif

View File

@ -18,9 +18,7 @@ public:
float far;
float fov;
float aspectRatio;
glm::mat4 view;
ViewPlane planes[6];
ViewFrustum(float near, float far, float fov, float aspect)

View File

@ -79,10 +79,10 @@ void PlayerController::update(float dt)
}
if( character->getCurrentVehicle() ) {
character->getCurrentVehicle()->setSteeringAngle(_rawDirection.x);
character->getCurrentVehicle()->setSteeringAngle(_rawDirection.y);
// TODO what is handbraking.
character->getCurrentVehicle()->setThrottle(-_rawDirection.y);
character->getCurrentVehicle()->setThrottle(_rawDirection.x);
}
else if( glm::length(direction) > 0.001f ) {
character->rotation = cameraRotation * glm::quat(glm::vec3(0.f, 0.f, -atan2(direction.x, direction.y)));

View File

@ -310,10 +310,13 @@ float mix(uint8_t a, uint8_t b, float num)
if(errc != GL_NO_ERROR) std::cout << __LINE__ << ": " << errc << std::endl;\
}
void GameRenderer::renderWorld(float alpha)
void GameRenderer::renderWorld(const ViewCamera &camera, float alpha)
{
_renderAlpha = alpha;
// Store the input camera,
_camera = camera;
glBindVertexArray( vao );
float tod = engine->state.hour + engine->state.minute/60.f;
@ -334,12 +337,14 @@ void GameRenderer::renderWorld(float alpha)
cos(theta),
};
sunDirection = glm::normalize(sunDirection);
camera.frustum.far = weather.farClipping;
_camera.frustum.near = engine->state.cameraNear;
_camera.frustum.far = weather.farClipping;
glUseProgram(worldProgram);
auto view = camera.frustum.view;
auto proj = camera.frustum.projection();
auto view = _camera.getView();
auto proj = _camera.frustum.projection();
uploadUBO<SceneUniformData>(
uboScene,
@ -349,7 +354,7 @@ void GameRenderer::renderWorld(float alpha)
glm::vec4{ambient, 0.0f},
glm::vec4{dynamic, 0.0f},
glm::vec4(skyBottom, 1.f),
glm::vec4(camera.worldPos, 0.f),
glm::vec4(camera.position, 0.f),
weather.fogStart,
camera.frustum.far
});
@ -357,7 +362,7 @@ void GameRenderer::renderWorld(float alpha)
glClearColor(skyBottom.r, skyBottom.g, skyBottom.b, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
camera.frustum.update(proj * view);
_camera.frustum.update(proj * view);
rendered = culled = geoms = frames = 0;
@ -416,7 +421,7 @@ void GameRenderer::renderWorld(float alpha)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, waterTex.texName);
auto camposFlat = glm::vec2(camera.worldPos);
auto camposFlat = glm::vec2(camera.position);
glBindVertexArray( waterHQDraw.getVAOName() );
@ -655,7 +660,7 @@ void GameRenderer::renderInstance(InstanceObject *instance)
for (size_t g = 0; g < instance->model->model->geometries.size(); g++)
{
RW::BSGeometryBounds& bounds = instance->model->model->geometries[g]->geometryBounds;
mindist = std::min(mindist, glm::length((glm::vec3(matrixModel[3])+bounds.center) - camera.worldPos) - bounds.radius);
mindist = std::min(mindist, glm::length((glm::vec3(matrixModel[3])+bounds.center) - _camera.position) - bounds.radius);
}
Model* model = nullptr;
@ -784,7 +789,7 @@ void GameRenderer::renderCutsceneObject(CutsceneObject *cutscene)
for (size_t g = 0; g < cutscene->model->model->geometries.size(); g++)
{
RW::BSGeometryBounds& bounds = cutscene->model->model->geometries[g]->geometryBounds;
mindist = std::min(mindist, glm::length((glm::vec3(matrixModel[3])+bounds.center) - camera.worldPos) - bounds.radius);
mindist = std::min(mindist, glm::length((glm::vec3(matrixModel[3])+bounds.center) - _camera.position) - bounds.radius);
}
if( cutscene->getParentActor() ) {
@ -832,7 +837,7 @@ void GameRenderer::renderWheel(Model* model, const glm::mat4 &matrix, const std:
for( auto& g : firstLod->getGeometries() ) {
RW::BSGeometryBounds& bounds = model->geometries[g]->geometryBounds;
if(! camera.frustum.intersects(bounds.center + glm::vec3(matrix[3]), bounds.radius)) {
if(! _camera.frustum.intersects(bounds.center + glm::vec3(matrix[3]), bounds.radius)) {
culled++;
continue;
}
@ -896,8 +901,8 @@ void GameRenderer::renderParticles()
glUseProgram( particleProgram );
glBindVertexArray( particleDraw.getVAOName() );
auto cpos = camera.worldPos;
auto cfwd = glm::normalize(glm::inverse(glm::mat3(camera.frustum.view)) * glm::vec3(0.f, 1.f, 0.f));
auto cpos = _camera.position;
auto cfwd = glm::normalize(glm::inverse(_camera.rotation) * glm::vec3(0.f, 1.f, 0.f));
std::sort( _particles.begin(), _particles.end(),
[&](const FXParticle& a, const FXParticle& b) {
@ -980,7 +985,7 @@ bool GameRenderer::renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix,
/// @todo fix culling animating objects?
glm::vec3 boundpos = bounds.center + glm::vec3(matrix[3]);
if( (!object || !object->animator) && ! camera.frustum.intersects(boundpos, bounds.radius)) {
if( (!object || !object->animator) && ! _camera.frustum.intersects(boundpos, bounds.radius)) {
continue;
}

View File

@ -608,7 +608,7 @@ VM_OPCODE_DEF( 0x0408 )
VM_OPCODE_DEF( 0x041D )
{
m->getWorld()->renderer.camera.frustum.near = p->at(0).real;
m->getWorld()->state.cameraNear = p->at(0).real;
}
VM_OPCODE_DEF( 0x042C )

View File

@ -1,5 +1,8 @@
add_executable(rwgame
main.cpp
State.cpp
loadingstate.cpp
ingamestate.cpp
pausestate.cpp

9
rwgame/State.cpp Normal file
View File

@ -0,0 +1,9 @@
#include "State.hpp"
// This serves as the "initial" camera position.
ViewCamera defaultView({-250.f, -550.f, 75.f}, glm::angleAxis(glm::radians(5.f), glm::vec3(0.f, 1.f, 0.f)));
const ViewCamera& State::getCamera()
{
return defaultView;
}

View File

@ -3,7 +3,9 @@
#include <functional>
#include <queue>
#include <SFML/Graphics/RenderWindow.hpp>
#include <render/ViewCamera.hpp>
#include "MenuSystem.hpp"
#include <glm/gtc/quaternion.hpp>
struct State
{
@ -76,32 +78,8 @@ struct State
default: break;
};
}
};
struct GenericState : public State
{
typedef std::function<void (State*)> StateChange;
typedef std::function<void (State*, float)> Tick;
typedef std::function<void (State*, const sf::Event&)> Event;
StateChange enter_lambda;
Tick tick_lambda;
StateChange exit_lambda;
Event event_lambda;
GenericState(StateChange start, Tick think, StateChange end, Event event)
: enter_lambda(start), tick_lambda(think),
exit_lambda(end), event_lambda(event) {}
virtual void enter() { enter_lambda(this); }
virtual void exit() { exit_lambda(this); }
virtual void tick(float dt) { tick_lambda(this, dt); }
virtual void handleEvent(const sf::Event& event) {
event_lambda(this, event);
State::handleEvent(event);
}
virtual const ViewCamera& getCamera();
};
struct StateManager

View File

@ -1,9 +1,10 @@
#include "debugstate.hpp"
#include "game.hpp"
#include <ai/PlayerController.hpp>
#include <objects/CharacterObject.hpp>
#include <objects/VehicleObject.hpp>
DebugState::DebugState()
DebugState::DebugState(const glm::vec3& vp, const glm::quat& vd)
: _freeLook( false ), _sonicMode( false )
{
Menu *m = new Menu(getFont());
@ -18,7 +19,7 @@ DebugState::DebugState()
spawnVehicle(it->first);
}, entryHeight));
m->addEntry(Menu::lambda("Open All Doors/Flaps", [this] {
auto pc = getPlayerCharacter();
auto pc = getWorld()->state.player->getCharacter();
auto pv = pc->getCurrentVehicle();
if( pv ) {
for(auto& it : pv->_hingedObjects) {
@ -51,12 +52,12 @@ DebugState::DebugState()
}
this->enterMenu(m);
_debugCam.position = vp;
_debugCam.rotation = vd;
}
void DebugState::enter()
{
_debugPos = getViewPosition();
_debugAngles = getViewAngles();
}
void DebugState::exit()
@ -102,21 +103,19 @@ void DebugState::tick(float dt)
sf::Vector2i deltaMouse = mousePos - screenCenter;
sf::Mouse::setPosition(screenCenter, getWindow());
_debugAngles.x += deltaMouse.x / 100.0;
_debugAngles.y += deltaMouse.y / 100.0;
_debugLook.x -= deltaMouse.x / 100.0f;
_debugLook.y += deltaMouse.y / 100.0f;
if (_debugAngles.y > qpi)
_debugAngles.y = qpi;
else if (_debugAngles.y < -qpi)
_debugAngles.y = -qpi;
if (_debugLook.y > qpi)
_debugLook.y = qpi;
else if (_debugLook.y < -qpi)
_debugLook.y = -qpi;
glm::quat vR = glm::normalize(glm::angleAxis(_debugAngles.x, glm::vec3{0.f, 0.f, 1.f}));
vR = vR * glm::angleAxis(_debugAngles.y, glm::vec3(1.f, 0.f, 0.f));
_debugCam.rotation = glm::angleAxis(_debugLook.x, glm::vec3(0.f, 0.f, 1.f))
* glm::angleAxis(_debugLook.y, glm::vec3(0.f, 1.f, 0.f));
_debugPos += vR * _movement * dt * (_sonicMode ? 100.f : 10.f);
_debugCam.position += _debugCam.rotation * _movement * dt * (_sonicMode ? 100.f : 10.f);
}
setViewParameters( _debugPos, _debugAngles );
}
void DebugState::handleEvent(const sf::Event &e)
@ -129,17 +128,17 @@ void DebugState::handleEvent(const sf::Event &e)
StateManager::get().exit();
break;
case sf::Keyboard::W:
_movement.y =-1.f;
break;
case sf::Keyboard::S:
_movement.y = 1.f;
break;
case sf::Keyboard::A:
_movement.x = 1.f;
break;
case sf::Keyboard::D:
case sf::Keyboard::S:
_movement.x =-1.f;
break;
case sf::Keyboard::A:
_movement.y = 1.f;
break;
case sf::Keyboard::D:
_movement.y =-1.f;
break;
case sf::Keyboard::F:
_freeLook = !_freeLook;
break;
@ -152,11 +151,11 @@ void DebugState::handleEvent(const sf::Event &e)
switch(e.key.code) {
case sf::Keyboard::W:
case sf::Keyboard::S:
_movement.y = 0.f;
_movement.x = 0.f;
break;
case sf::Keyboard::A:
case sf::Keyboard::D:
_movement.x = 0.f;
_movement.y = 0.f;
break;
case sf::Keyboard::LShift:
_sonicMode = false;
@ -170,7 +169,7 @@ void DebugState::handleEvent(const sf::Event &e)
void DebugState::spawnVehicle(unsigned int id)
{
auto ch = getPlayerCharacter();
auto ch = getWorld()->state.player->getCharacter();
if(! ch) return;
glm::vec3 fwd = ch->rotation * glm::vec3(0.f, 1.f, 0.f);
@ -181,3 +180,8 @@ void DebugState::spawnVehicle(unsigned int id)
getWorld()->createVehicle(id, spawnpos, glm::quat());
}
}
const ViewCamera &DebugState::getCamera()
{
return _debugCam;
}

View File

@ -5,13 +5,13 @@
class DebugState : public State
{
glm::vec3 _debugPos;
ViewCamera _debugCam;
glm::vec3 _movement;
glm::vec2 _debugAngles;
glm::vec2 _debugLook;
bool _freeLook;
bool _sonicMode;
public:
DebugState();
DebugState(const glm::vec3& vp = {}, const glm::quat& vd = {});
virtual void enter();
virtual void exit();
@ -21,6 +21,8 @@ public:
virtual void handleEvent(const sf::Event& event);
void spawnVehicle(unsigned int id);
const ViewCamera& getCamera();
};
#endif // DEBUGSTATE_HPP

View File

@ -18,19 +18,9 @@ bool hitWorldRay(const glm::vec3& start, const glm::vec3& direction,
sf::Window& getWindow();
GameWorld* getWorld();
CharacterObject* getPlayerCharacter();
void setPlayerCharacter(CharacterObject* playerCharacter);
sf::Font& getFont();
/**
Set view parameters.
*/
void setViewParameters(const glm::vec3& center, const glm::vec2 &angles);
glm::vec3& getViewPosition();
glm::vec2& getViewAngles();
void skipTime(float time);
#endif // GAME_HPP

View File

@ -2,6 +2,8 @@
#include "game.hpp"
#include "pausestate.hpp"
#include "debugstate.hpp"
#include <ai/PlayerController.hpp>
#include <objects/CharacterObject.hpp>
#include <objects/VehicleObject.hpp>
#include <objects/ItemPickup.hpp>
@ -9,7 +11,6 @@
#include <items/WeaponItem.hpp>
IngameState::IngameState(bool test)
: _player(nullptr), _playerCharacter(nullptr)
{
if( test ) {
startTest();
@ -21,10 +22,10 @@ IngameState::IngameState(bool test)
void IngameState::startTest()
{
_playerCharacter = getWorld()->createPedestrian(1, {-1000.f, -990.f, 13.f});
_player = new PlayerController(_playerCharacter);
auto playerChar = getWorld()->createPedestrian(1, {-1000.f, -990.f, 13.f});
auto player = new PlayerController(playerChar);
setPlayerCharacter( _playerCharacter );
getWorld()->state.player = player;
/*auto bat = new WeaponItem(getWorld()->gameData.weaponData["ak47"]);
_playerCharacter->addToInventory(bat);
@ -60,13 +61,11 @@ void IngameState::startTest()
carPos -= glm::vec3( 2.f + v->info->handling.dimensions.x, 0.f, 0.f);
}
}
getWorld()->renderer.camera.frustum.fov = -2.f * glm::quarter_pi<float>();
}
void IngameState::spawnPlayerVehicle()
{
if(! _player) return;
if(! getWorld()->state.player ) return;
glm::vec3 hit, normal;
if(hitWorldRay(hit, normal)) {
@ -80,7 +79,8 @@ void IngameState::spawnPlayerVehicle()
auto spawnpos = hit + normal;
auto vehicle = getWorld()->createVehicle(it->first, spawnpos,
glm::quat(glm::vec3(0.f, 0.f, -_lookAngles.x * PiOver180)));
_playerCharacter->enterVehicle(vehicle, 0);
getWorld()->state.player->getCharacter()->enterVehicle(vehicle, 0);
}
}
@ -104,7 +104,7 @@ void IngameState::updateView()
float localX = -_lookAngles.x;
float viewDistance = 2.f;
if( _playerCharacter->getCurrentVehicle() ) {
/*if( _playerCharacter->getCurrentVehicle() ) {
auto model = _playerCharacter->getCurrentVehicle()->model;
for(auto& g : model->model->geometries) {
viewDistance = std::max(
@ -150,9 +150,12 @@ void IngameState::updateView()
viewFraction = allrr.m_hitFractions[i] * 0.9f;
}
}
}
}*/
}
setViewParameters( (viewPos + glm::vec3(0.f, 0.f, 0.75f)) + localview * viewFraction, {localX, _lookAngles.y} );
PlayerController *IngameState::getPlayer()
{
return getWorld()->state.player;
}
void IngameState::enter()
@ -167,18 +170,58 @@ void IngameState::exit()
void IngameState::tick(float dt)
{
if( getWorld()->state.player ) {
_player = getWorld()->state.player;
_playerCharacter = _player->getCharacter();
}
auto player = getPlayer();
if( player )
{
float qpi = glm::half_pi<float>();
if( _player ) {
updateView();
sf::Vector2i screenCenter{sf::Vector2i{getWindow().getSize()} / 2};
sf::Vector2i mousePos = sf::Mouse::getPosition(getWindow());
sf::Vector2i deltaMouse = mousePos - screenCenter;
sf::Mouse::setPosition(screenCenter, getWindow());
_lookAngles.x += deltaMouse.x / 100.0;
_lookAngles.y += deltaMouse.y / 100.0;
if (_lookAngles.y > qpi)
_lookAngles.y = qpi;
else if (_lookAngles.y < -qpi)
_lookAngles.y = -qpi;
auto angle = glm::angleAxis(-_lookAngles.x, glm::vec3(0.f, 0.f, 1.f));
player->updateMovementDirection(angle * _movement, _movement);
auto position = player->getCharacter()->getPosition();
float viewDistance = 2.5f;
auto vehicle = player->getCharacter()->getCurrentVehicle();
if( vehicle ) {
auto model = vehicle->model;
for(auto& g : model->model->geometries) {
viewDistance = std::max(
(glm::length(g->geometryBounds.center) + g->geometryBounds.radius) * 2.0f,
viewDistance);
}
position = player->getCharacter()->getCurrentVehicle()->getPosition();
}
// Move back from the character
position += angle * glm::vec3(-viewDistance, 0.f, 1.f);
// Tilt the final look angle down a tad.
angle *= glm::angleAxis(glm::radians(5.f), glm::vec3(0.f, 1.f, 0.f));
_look.position = position;
_look.rotation = angle;
}
}
void IngameState::handleEvent(const sf::Event &event)
{
auto player = getPlayer();
switch(event.type) {
case sf::Event::KeyPressed:
switch(event.key.code) {
@ -186,35 +229,35 @@ void IngameState::handleEvent(const sf::Event &event)
StateManager::get().enter(new PauseState);
break;
case sf::Keyboard::M:
StateManager::get().enter(new DebugState);
StateManager::get().enter(new DebugState(_look.position, _look.rotation));
break;
case sf::Keyboard::Space:
if(_playerCharacter) {
_playerCharacter->jump();
if( player ) {
player->getCharacter()->jump();
}
break;
case sf::Keyboard::W:
_movement.y =-1.f;
break;
case sf::Keyboard::S:
_movement.y = 1.f;
break;
case sf::Keyboard::A:
_movement.x = 1.f;
break;
case sf::Keyboard::D:
case sf::Keyboard::S:
_movement.x =-1.f;
break;
case sf::Keyboard::A:
_movement.y = 1.f;
break;
case sf::Keyboard::D:
_movement.y =-1.f;
break;
case sf::Keyboard::LShift:
_player->setRunning(true);
player->setRunning(true);
break;
case sf::Keyboard::F:
if(_playerCharacter) {
if(_playerCharacter->getCurrentVehicle()) {
_player->exitVehicle();
if( player ) {
if( player->getCharacter()->getCurrentVehicle()) {
player->exitVehicle();
}
else {
_player->enterNearestVehicle();
player->enterNearestVehicle();
}
}
break;
@ -225,14 +268,14 @@ void IngameState::handleEvent(const sf::Event &event)
switch(event.key.code) {
case sf::Keyboard::W:
case sf::Keyboard::S:
_movement.y = 0.f;
_movement.x = 0.f;
break;
case sf::Keyboard::A:
case sf::Keyboard::D:
_movement.x = 0.f;
_movement.y = 0.f;
break;
case sf::Keyboard::LShift:
_player->setRunning(false);
player->setRunning(false);
break;
case sf::Keyboard::F12:
skipTime(10.f);
@ -243,7 +286,7 @@ void IngameState::handleEvent(const sf::Event &event)
case sf::Event::MouseButtonPressed:
switch(event.mouseButton.button) {
case sf::Mouse::Left:
_player->useItem(true, true);
player->useItem(true, true);
break;
default: break;
}
@ -251,15 +294,20 @@ void IngameState::handleEvent(const sf::Event &event)
case sf::Event::MouseButtonReleased:
switch(event.mouseButton.button) {
case sf::Mouse::Left:
_player->useItem(false, true);
player->useItem(false, true);
break;
default: break;
}
break;
case sf::Event::MouseWheelMoved:
_playerCharacter->cycleInventory(event.mouseWheel.delta > 0);
player->getCharacter()->cycleInventory(event.mouseWheel.delta > 0);
break;
default: break;
}
State::handleEvent(event);
}
const ViewCamera &IngameState::getCamera()
{
return _look;
}

View File

@ -3,13 +3,11 @@
#include "State.hpp"
#include <ai/PlayerController.hpp>
class PlayerController;
class IngameState : public State
{
PlayerController* _player;
CharacterObject* _playerCharacter;
ViewCamera _look;
glm::vec2 _lookAngles;
glm::vec3 _movement;
public:
@ -20,12 +18,17 @@ public:
void updateView();
/** shortcut for getWorld()->state.player->getCharacter() */
PlayerController* getPlayer();
virtual void enter();
virtual void exit();
virtual void tick(float dt);
virtual void handleEvent(const sf::Event& event);
const ViewCamera& getCamera();
};
#endif // INGAMESTATE_HPP

View File

@ -8,7 +8,7 @@
#include <objects/VehicleObject.hpp>
#include <objects/CharacterObject.hpp>
#include <objects/InstanceObject.hpp>
#include <ai/CharacterController.hpp>
#include <ai/PlayerController.hpp>
#include <script/ScriptMachine.hpp>
@ -36,38 +36,18 @@ constexpr int WIDTH = 800,
sf::RenderWindow window;
GameWorld* gta = nullptr;
CharacterObject* player = nullptr;
DebugDraw* debugDrawer = nullptr;
bool inFocus = true;
int debugMode = 0;
float accum = 0.f;
// Camera poisitions to interpolate between ticks.
ViewCamera lastCam, nextCam;
sf::Font font;
glm::vec3 viewPosition { -260.f, -151.5f, 9.f }, lastViewPosition;
glm::vec2 viewAngles { -0.3f, 0.05f }, lastViewAngles;
void setViewParameters(const glm::vec3 &center, const glm::vec2 &angles)
{
lastViewPosition = viewPosition;
lastViewAngles = viewAngles;
viewPosition = center;
viewAngles = angles;
}
glm::vec3& getViewPosition()
{
return viewPosition;
}
glm::vec2& getViewAngles()
{
return viewAngles;
}
sf::Window& getWindow()
{
return window;
@ -83,16 +63,6 @@ sf::Font& getFont()
return font;
}
void setPlayerCharacter(CharacterObject *playerCharacter)
{
player = playerCharacter;
}
CharacterObject* getPlayerCharacter()
{
return player;
}
void skipTime(float time)
{
accum += time;
@ -100,13 +70,11 @@ void skipTime(float time)
bool hitWorldRay(glm::vec3 &hit, glm::vec3 &normal, GameObject** object)
{
glm::mat4 view;
view = glm::rotate(view, -90.f, glm::vec3(1, 0, 0));
view = glm::rotate(view, viewAngles.y, glm::vec3(1, 0, 0));
view = glm::rotate(view, viewAngles.x, glm::vec3(0, 0, 1));
glm::vec3 dir = glm::inverse(glm::mat3(view)) * glm::vec3(0.f, 0.f, 1.f) * -50.f;
auto from = btVector3(viewPosition.x, viewPosition.y, viewPosition.z);
auto to = btVector3(viewPosition.x+dir.x, viewPosition.y+dir.y, viewPosition.z+dir.z);
const ViewCamera& vc = StateManager::get().states.back()->getCamera();
btVector3 from(vc.position.x, vc.position.y, vc.position.z);
glm::vec3 tmp = vc.rotation * glm::vec3(1000.f, 0.f, 0.f);
btVector3 to(from.x() + tmp.x, from.y() + tmp.y, from.x() + tmp.z);
btCollisionWorld::ClosestRayResultCallback ray(from, to);
gta->dynamicsWorld->rayTest(from, to, ray);
if( ray.hasHit() )
@ -221,7 +189,7 @@ void init(std::string gtapath)
debugDrawer->setDebugMode(btIDebugDraw::DBG_DrawWireframe);
gta->dynamicsWorld->setDebugDrawer(debugDrawer);
setViewParameters( { -260.f, -151.5f, 9.f }, { -0.3f, 0.05f } );
//setViewParameters( { -260.f, -151.5f, 9.f }, { -0.3f, 0.05f } );
std::cout << "Loaded "
<< gta->gameData.models.size() << " models, "
@ -270,24 +238,17 @@ void update(float dt)
}
}
}
// render() needs two cameras to smoothly interpolate between ticks.
lastCam = nextCam;
nextCam = StateManager::get().states.back()->getCamera();
}
void render(float alpha)
{
float qpi = glm::half_pi<float>();
glm::mat4 view;
/// @todo this probably doesn't belong in main.cpp
if( gta->state.currentCutscene == nullptr || gta->state.cutsceneStartTime <= 0.f ) {
view = glm::translate(view, glm::mix(lastViewPosition, viewPosition, alpha));
auto va = glm::mix(lastViewAngles, viewAngles, alpha);
view = glm::rotate(view, va.x, glm::vec3(0, 0, 1));
view = glm::rotate(view, va.y - qpi, glm::vec3(1, 0, 0));
view = glm::inverse(view);
gta->renderer.camera.worldPos = viewPosition;
}
else {
ViewCamera viewCam;
if( gta->state.currentCutscene != nullptr && gta->state.cutsceneStartTime >= 0.f )
{
auto cutscene = gta->state.currentCutscene;
float cutsceneTime = std::min(gta->gameTime - gta->state.cutsceneStartTime,
cutscene->tracks.duration);
@ -295,33 +256,47 @@ void render(float alpha)
glm::vec3 cameraPos = cutscene->tracks.getPositionAt(cutsceneTime),
targetPos = cutscene->tracks.getTargetAt(cutsceneTime);
float zoom = cutscene->tracks.getZoomAt(cutsceneTime);
gta->renderer.camera.frustum.fov = glm::radians(-zoom);
viewCam.frustum.fov = glm::radians(zoom);
float tilt = cutscene->tracks.getRotationAt(cutsceneTime);
auto d = glm::normalize(targetPos-cameraPos);
auto qtilt = glm::rotate(glm::quat(), glm::radians(tilt), d);
auto direction = glm::normalize(targetPos - cameraPos);
auto right = glm::normalize(glm::cross(glm::vec3(0.f, 0.f, 1.f), direction));
auto up = glm::normalize(glm::cross(direction, right));
glm::mat3 m;
m[0][0] = direction.x;
m[0][1] = right.x;
m[0][2] = up.x;
m[1][0] = direction.y;
m[1][1] = right.y;
m[1][2] = up.y;
m[2][0] = direction.z;
m[2][1] = right.z;
m[2][2] = up.z;
auto qtilt = glm::angleAxis(glm::radians(tilt), direction);
cameraPos += cutscene->meta.sceneOffset;
targetPos += cutscene->meta.sceneOffset;
// Update the internal values
lastViewPosition = viewPosition = cameraPos;
view = glm::lookAt(cameraPos, targetPos, qtilt * glm::vec3(0.f, 0.f, -1.f));
gta->renderer.camera.worldPos = cameraPos;
viewCam.position = cameraPos;
viewCam.rotation = glm::inverse(glm::quat_cast(m)) * qtilt;
}
else
{
// There's no cutscene playing - use the camera returned by the State.
viewCam.position = glm::mix(lastCam.position, nextCam.position, alpha);
viewCam.rotation = glm::slerp(lastCam.rotation, nextCam.rotation, alpha);
}
gta->renderer.camera.frustum.view = view;
// Update aspect ratio..
gta->renderer.camera.frustum.aspectRatio = window.getSize().x / (float) window.getSize().y;
viewCam.frustum.aspectRatio = window.getSize().x / (float) window.getSize().y;
glEnable(GL_DEPTH_TEST);
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
//glEnable(GL_CULL_FACE);
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
gta->renderer.renderWorld(alpha);
gta->renderer.renderWorld(viewCam, alpha);
switch( debugMode ) {
case 0: break;
@ -357,12 +332,12 @@ void render(float alpha)
std::stringstream ss;
ss << std::setfill('0') << "Time: " << std::setw(2) << gta->getHour()
<< ":" << std::setw(2) << gta->getMinute() << " (" << gta->gameTime << "s)\n";
ss << "View: " << viewPosition.x << " " << viewPosition.y << " " << viewPosition.z << "\n";
ss << "View: " << viewCam.position.x << " " << viewCam.position.y << " " << viewCam.position.z << "\n";
ss << "Drawn " << gta->renderer.rendered << " / " << gta->renderer.culled << " Culled " << " " << gta->renderer.frames << " " << gta->renderer.geoms << "\n";
if( player ) {
if( gta->state.player ) {
ss << "Activity: ";
if( player->controller->getCurrentActivity() ) {
ss << player->controller->getCurrentActivity()->name();
if( gta->state.player->getCurrentActivity() ) {
ss << gta->state.player->getCurrentActivity()->name();
}
else {
ss << "Idle";

View File

@ -66,11 +66,6 @@ void ViewerWidget::paintGL()
if( gworld == nullptr ) return;
auto& r = gworld->renderer;
r.camera.frustum.far = 500.f;
r.camera.frustum.near = 0.1f;
r.camera.frustum.fov = 90.f;
r.camera.frustum.aspectRatio = width()/(height()*1.f);
if(dummyObject && dummyObject->animator) {
dummyObject->animator->tick(1.f/60.f);
@ -91,12 +86,19 @@ void ViewerWidget::paintGL()
glUseProgram(r.worldProgram);
glm::mat4 proj = r.camera.frustum.projection();
ViewCamera vc;
vc.frustum.far = 500.f;
vc.frustum.near = 0.1f;
vc.frustum.fov = 90.f;
vc.frustum.aspectRatio = width()/(height()*1.f);
glm::mat4 proj = vc.frustum.projection();
glm::vec3 eye(sin(viewAngles.x) * cos(viewAngles.y), cos(viewAngles.x) * cos(viewAngles.y), sin(viewAngles.y));
glm::mat4 view = glm::lookAt(eye * viewDistance, glm::vec3(0.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f));
r.uploadUBO<SceneUniformData>(r.uboScene,
{ proj, view, glm::vec4(1.f), glm::vec4(1.f), glm::vec4(1.f), glm::vec4(0.f), 90.f, r.camera.frustum.far });
{ proj, view, glm::vec4(1.f), glm::vec4(1.f), glm::vec4(1.f), glm::vec4(0.f), 90.f, vc.frustum.far });
if( dummyObject->model->model ) {
gworld->renderer.renderModel(dummyObject->model->model, m, dummyObject);

View File

@ -8,8 +8,8 @@ BOOST_AUTO_TEST_CASE(frustum_test_visible)
{
{
ViewFrustum f(0.1f, 100.f, glm::half_pi<float>(), 1.f);
f.view = glm::lookAt(glm::vec3{0.f, 0.f, 0.f}, {1.f, 0.f, 0.f}, {0.f, 0.f, 1.f});
f.update(f.projection() * f.view);
f.update(f.projection());
BOOST_CHECK( f.intersects({10.f, 0.f, 0.f}, 1.f ) );
BOOST_CHECK(!f.intersects({-10.f, 0.f, 0.f}, 1.f ) );

View File

@ -4,56 +4,4 @@
BOOST_AUTO_TEST_SUITE(StateUnitTests)
BOOST_AUTO_TEST_CASE(state_test_generic)
{
bool entered = false;
bool exited = false;
bool ticked = false;
GenericState ls(
[&](State*) { entered = true; },
[&](State*, float) { ticked = true; },
[&](State*) { exited = true; },
[](State*, const sf::Event&){}
);
ls.enter();
BOOST_CHECK( entered );
ls.tick(1.f);
BOOST_CHECK( ticked );
ls.exit();
BOOST_CHECK( exited );
}
BOOST_AUTO_TEST_CASE(state_test_switch)
{
bool entered = false;
bool exited = false;
bool ticked = false;
GenericState ls(
[&](State*) { entered = true; },
[&](State*, float) { ticked = true; },
[&](State*) { exited = true; },
[](State*, const sf::Event&){}
);
StateManager::get().enter(&ls);
BOOST_CHECK( entered );
StateManager::get().tick(1.f);
BOOST_CHECK( ticked );
StateManager::get().exit();
BOOST_CHECK( exited );
}
BOOST_AUTO_TEST_SUITE_END()