mirror of
https://github.com/rwengine/openrw.git
synced 2024-09-15 06:52:34 +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:
parent
095073e667
commit
ba7eb63941
@ -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)
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)));
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 )
|
||||
|
@ -1,5 +1,8 @@
|
||||
add_executable(rwgame
|
||||
main.cpp
|
||||
|
||||
State.cpp
|
||||
|
||||
loadingstate.cpp
|
||||
ingamestate.cpp
|
||||
pausestate.cpp
|
||||
|
9
rwgame/State.cpp
Normal file
9
rwgame/State.cpp
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
127
rwgame/main.cpp
127
rwgame/main.cpp
@ -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 ¢er, 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";
|
||||
|
@ -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);
|
||||
|
@ -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 ) );
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user