1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-03 17:19:46 +02:00
openrw/rwgame/RWGame.cpp

377 lines
9.2 KiB
C++
Raw Normal View History

#include "RWGame.hpp"
#include "State.hpp"
#include "loadingstate.hpp"
#include "DrawUI.hpp"
#include <engine/GameObject.hpp>
2014-12-16 20:17:22 +01:00
#include <engine/GameState.hpp>
2015-02-07 23:55:06 +01:00
#include <engine/GameWorld.hpp>
#include <render/GameRenderer.hpp>
#include <render/DebugDraw.hpp>
#include <script/ScriptMachine.hpp>
#include <data/CutsceneData.hpp>
#include <ai/PlayerController.hpp>
#include <objects/CharacterObject.hpp>
#include <objects/VehicleObject.hpp>
DebugDraw* debug;
RWGame::RWGame(const std::string& gamepath, int argc, char* argv[])
: engine(nullptr), inFocus(true),
2014-12-16 04:30:51 +01:00
accum(0.f), timescale(1.f)
{
size_t w = GAME_WINDOW_WIDTH, h = GAME_WINDOW_HEIGHT;
2015-01-30 11:07:53 +01:00
bool fullscreen = false;
for( int i = 1; i < argc; ++i )
{
if( strcasecmp( "-w", argv[i] ) == 0 && i+1 < argc )
{
w = std::atoi(argv[i+1]);
}
if( strcasecmp( "-h", argv[i] ) == 0 && i+1 < argc )
{
h = std::atoi(argv[i+1]);
}
2015-01-30 11:07:53 +01:00
if( strcasecmp( "-f", argv[i] ) == 0 )
{
fullscreen = true;
}
}
sf::Uint32 style = sf::Style::Default;
if( fullscreen )
{
style |= sf::Style::Fullscreen;
}
sf::ContextSettings cs;
cs.depthBits = 32;
2015-01-30 11:07:53 +01:00
window.create(sf::VideoMode(w, h), "", style, cs);
window.setVerticalSyncEnabled(true);
window.setMouseCursorVisible(false);
glewExperimental = GL_TRUE;
glewInit();
engine = new GameWorld(gamepath);
// Initalize all the archives.
engine->gameData.loadIMG("/models/gta3");
engine->gameData.loadIMG("/models/txd");
engine->gameData.loadIMG("/anim/cuts");
2015-02-07 23:55:06 +01:00
// Set up text renderer
engine->renderer.text.setFontTexture(0, "pager");
engine->renderer.text.setFontTexture(1, "font1");
engine->renderer.text.setFontTexture(2, "font2");
/// @TODO expand this here.
engine->load();
debug = new DebugDraw;
debug->setDebugMode(btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawConstraints | btIDebugDraw::DBG_DrawConstraintLimits);
engine->dynamicsWorld->setDebugDrawer(debug);
engine->gameData.loadDynamicObjects(gamepath + "/data/object.dat");
/// @TODO language choices.
engine->gameData.loadGXT("english.gxt");
for(int m = 0; m < MAP_BLOCK_SIZE; ++m)
{
std::string num = (m < 10 ? "0" : "");
std::string name = "radar" + num + std::to_string(m);
engine->gameData.loadTXD(name + ".txd");
}
StateManager::get().enter(new LoadingState(this));
engine->logInfo("Started");
}
RWGame::~RWGame()
{
delete engine;
}
int RWGame::run()
{
clock.restart();
// Loop until the window is closed or we run out of state.
while (window.isOpen() && StateManager::get().states.size()) {
sf::Event event;
while (window.pollEvent(event)) {
switch (event.type) {
case sf::Event::GainedFocus:
inFocus = true;
break;
case sf::Event::LostFocus:
inFocus = false;
break;
case sf::Event::KeyPressed:
globalKeyEvent(event);
default: break;
}
StateManager::get().states.back()->handleEvent(event);
}
if(! window.isOpen() )
{
break;
}
accum += clock.restart().asSeconds() * timescale;
while ( accum >= GAME_TIMESTEP ) {
2015-02-04 18:16:46 +01:00
if( ! getWorld()->isPaused() )
{
StateManager::get().tick(GAME_TIMESTEP);
2015-02-04 18:16:46 +01:00
tick(GAME_TIMESTEP);
}
accum -= GAME_TIMESTEP;
}
float alpha = accum / GAME_TIMESTEP;
render(alpha);
2015-02-07 23:55:06 +01:00
StateManager::get().draw(&engine->renderer);
window.display();
}
return 0;
}
void RWGame::tick(float dt)
{
// Clear out any per-tick state.
engine->clearTickData();
// Process the Engine's background work.
engine->_work->update();
static float clockAccumulator = 0.f;
if (inFocus) {
engine->gameTime += dt;
clockAccumulator += dt;
while( clockAccumulator >= 1.f ) {
engine->state.minute ++;
if( engine->state.minute >= 60 ) {
engine->state.minute = 0;
engine->state.hour ++;
if( engine->state.hour >= 24 ) {
engine->state.hour = 0;
}
}
clockAccumulator -= 1.f;
}
for( GameObject* object : engine->objects ) {
object->_updateLastTransform();
object->tick(dt);
}
engine->destroyQueuedObjects();
engine->state.texts.clear();
engine->dynamicsWorld->stepSimulation(dt, 2, dt);
if( engine->script ) {
try {
engine->script->execute(dt);
}
catch( SCMException& ex ) {
std::cerr << ex.what() << std::endl;
engine->logError( ex.what() );
throw;
}
}
}
// render() needs two cameras to smoothly interpolate between ticks.
lastCam = nextCam;
nextCam = StateManager::get().states.back()->getCamera();
}
void RWGame::render(float alpha)
{
2015-02-07 23:55:06 +01:00
auto size = getWindow().getSize();
engine->renderer.getRenderer()->setViewport({size.x, size.y});
ViewCamera viewCam;
if( engine->state.currentCutscene != nullptr && engine->state.cutsceneStartTime >= 0.f )
{
auto cutscene = engine->state.currentCutscene;
float cutsceneTime = std::min(engine->gameTime - engine->state.cutsceneStartTime,
cutscene->tracks.duration);
cutsceneTime += GAME_TIMESTEP * alpha;
glm::vec3 cameraPos = cutscene->tracks.getPositionAt(cutsceneTime),
targetPos = cutscene->tracks.getTargetAt(cutsceneTime);
float zoom = cutscene->tracks.getZoomAt(cutsceneTime);
viewCam.frustum.fov = glm::radians(zoom);
float tilt = cutscene->tracks.getRotationAt(cutsceneTime);
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;
viewCam.position = cameraPos;
viewCam.rotation = glm::inverse(glm::quat_cast(m)) * qtilt;
}
2014-12-16 20:17:22 +01:00
else if( engine->state.cameraFixed )
{
viewCam.position = engine->state.cameraPosition;
viewCam.rotation = engine->state.cameraRotation;
}
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);
}
viewCam.frustum.aspectRatio = window.getSize().x / (float) window.getSize().y;
if ( engine->state.isCinematic )
{
float cinematicAspect = 19.f/10.f;
2015-02-04 18:16:46 +01:00
viewCam.frustum.fov *= viewCam.frustum.aspectRatio;
}
glEnable(GL_DEPTH_TEST);
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
engine->renderer.renderWorld(viewCam, alpha);
2015-01-23 13:25:40 +01:00
#if 0
debug->setShaderProgram(engine->renderer.worldProg);
if( engine->state.player )
{
if( engine->state.player->getCharacter()->getCurrentVehicle() )
{
auto v = engine->state.player->getCharacter()->getCurrentVehicle();
for( auto& p : v->dynamicParts )
{
if( p.second.body )
{
engine->dynamicsWorld->debugDrawObject(p.second.body->getWorldTransform(), p.second.body->getCollisionShape(), btVector3(1.f, 0.f, 0.f));
engine->dynamicsWorld->debugDrawConstraint(p.second.constraint);
}
}
}
}
debug->flush(&engine->renderer);
2015-01-23 13:25:40 +01:00
#endif
/*std::stringstream ss;
ss << std::setfill('0') << "Time: " << std::setw(2) << engine->getHour()
<< ":" << std::setw(2) << engine->getMinute() << " (" << engine->gameTime << "s)\n";
ss << "View: " << viewCam.position.x << " " << viewCam.position.y << " " << viewCam.position.z << "\n";
ss << "Drawn " << engine->renderer.rendered << " / " << engine->renderer.culled << " Culled " << " " << engine->renderer.frames << " " << engine->renderer.geoms << "\n";
if( engine->state.player ) {
ss << "Activity: ";
if( engine->state.player->getCurrentActivity() ) {
ss << engine->state.player->getCurrentActivity()->name();
}
else {
ss << "Idle";
}
ss << std::endl;
}*/
2015-02-07 23:55:06 +01:00
TextRenderer::TextInfo ti;
//ti.text = ss.str();
2015-02-07 23:55:06 +01:00
ti.font = 2;
ti.screenPosition = glm::vec2( 10.f, 10.f );
ti.size = 20.f;
//engine->renderer.text.renderText(ti);
/*while( engine->log.size() > 0 && engine->log.front().time + 10.f < engine->gameTime ) {
engine->log.pop_front();
}
2015-02-07 23:55:06 +01:00
ti.screenPosition = glm::vec2( 10.f, 500.f );
ti.size = 15.f;
for(auto it = engine->log.begin(); it != engine->log.end(); ++it) {
2015-02-07 23:55:06 +01:00
ti.text = it->message;
switch(it->type) {
case GameWorld::LogEntry::Error:
2015-02-07 23:55:06 +01:00
ti.baseColour = glm::vec3(1.f, 0.f, 0.f);
break;
case GameWorld::LogEntry::Warning:
2015-02-07 23:55:06 +01:00
ti.baseColour = glm::vec3(1.f, 1.f, 0.f);
break;
default:
2015-02-07 23:55:06 +01:00
ti.baseColour = glm::vec3(1.f, 1.f, 1.f);
break;
}
// Interpolate the color
2015-02-07 23:55:06 +01:00
// c.a = (engine->gameTime - it->time > 5.f) ? 255 - (((engine->gameTime - it->time) - 5.f)/5.f) * 255 : 255;
// text.setColor(c);
2015-02-07 23:55:06 +01:00
engine->renderer.text.renderText(ti);
ti.screenPosition.y -= ti.size;
}*/
2014-12-16 20:17:22 +01:00
for( int i = 0; i < engine->state.text.size(); )
{
if( engine->gameTime > engine->state.text[i].osTextStart + engine->state.text[i].osTextTime )
{
engine->state.text.erase(engine->state.text.begin() + i);
}
else
{
i++;
}
}
drawOnScreenText(engine);
}
void RWGame::globalKeyEvent(const sf::Event& event)
{
switch (event.key.code) {
case sf::Keyboard::LBracket:
engine->state.minute -= 30.f;
break;
case sf::Keyboard::RBracket:
engine->state.minute += 30.f;
break;
2014-12-13 01:59:09 +01:00
case sf::Keyboard::Num9:
timescale *= 0.5f;
break;
case sf::Keyboard::Num0:
timescale *= 2.0f;
break;
}
}