cpp_photon/src/Application.cpp

440 lines
11 KiB
C++
Raw Normal View History

2005-02-07 02:00:48 +00:00
//This file is part of Photon (http://photon.sourceforge.net)
//Copyright (C) 2004-2005 James Turk
//
// Author:
// James Turk (jpt2433@rit.edu)
//
// Version:
2005-08-08 06:50:18 +00:00
// $Id: Application.cpp,v 1.16 2005/08/08 06:50:18 cozman Exp $
2005-02-07 02:00:48 +00:00
2005-02-13 22:12:02 +00:00
#include "Application.hpp"
2005-02-07 02:00:48 +00:00
2005-08-08 06:50:18 +00:00
#include "physfs.h" //This file depends on physfs
#include "GL/glfw.h" //This file depends on glfw
2005-03-15 19:21:51 +00:00
#include <boost/lexical_cast.hpp>
#include "exceptions.hpp"
#include "Log.hpp"
#include "Kernel.hpp"
#include "Application.hpp"
2005-03-15 19:21:51 +00:00
#include "video/VideoCore.hpp"
2005-05-15 02:50:52 +00:00
#include "audio/AudioCore.hpp"
#include "util/filesys/filesys.hpp"
2005-02-07 02:00:48 +00:00
namespace photon
{
std::vector<InputListener*> Application::listeners_;
std::vector<KeyCode> Application::pressedKeys_;
2005-08-02 23:07:51 +00:00
Application::Application(const std::string& arg0) :
photonVer_(0,0,1), // this is the current version
dispWidth_(0), dispHeight_(0),
updateTask_(new UpdateTask()),
stateUpdate_(new StateUpdate()),
stateRender_(new StateRender())
2005-02-07 02:00:48 +00:00
{
2005-02-13 22:12:02 +00:00
util::VersionInfo physfsReq(1,0,0); // requires PhysFS 1.0.0
util::ensureVersion("PhysFS", initPhysFS(arg0), physfsReq);
util::VersionInfo glfwReq(2,4,2); // requires GLFW 2.4.2
util::ensureVersion("GLFW", initGLFW(), glfwReq);
2005-08-08 06:50:18 +00:00
new Kernel; // create Kernel before it is used
2005-08-02 23:07:51 +00:00
2005-08-08 06:50:18 +00:00
Kernel::getInstance().addTask(updateTask_); // add updater task
Kernel::getInstance().addTask(stateUpdate_); // add state updater task
Kernel::getInstance().addTask(stateRender_); // add state renderer task
2005-02-07 02:00:48 +00:00
}
Application::~Application()
{
if(dispWidth_ && dispHeight_)
{
glfwCloseWindow(); //close GLFW window
}
2005-08-08 06:50:18 +00:00
glfwTerminate(); // shutdown GLFW
2005-08-08 06:50:18 +00:00
PHYSFS_deinit(); // shutdown PhysFS
2005-08-08 06:50:18 +00:00
Kernel::destroy(); // destroy Kernel on way out
}
void Application::createDisplay(uint width, uint height,
uint redBits, uint greenBits, uint blueBits,
uint alphaBits, uint depthBits, uint stencilBits,
bool fullscreen, const std::string &title)
{
GLboolean status;
status = glfwOpenWindow(width, height, redBits, greenBits,
blueBits, alphaBits, depthBits, stencilBits,
fullscreen ? GLFW_FULLSCREEN : GLFW_WINDOW);
if(status == GL_FALSE)
{
throw APIError("Failed to create display.");
}
2005-08-02 23:07:51 +00:00
// register the callbacks (after a window is open)
glfwSetKeyCallback(Application::keyCallback);
//glfwSetCharCallback(Application::charCallback);
glfwSetMouseButtonCallback(Application::mouseButtonCallback);
glfwSetMousePosCallback(Application::mouseMoveCallback);
//glfwSetMouseWheelCallback(Application::mouseWheelCallback);
Application::initVideoCore(width, height);
dispWidth_ = width;
dispHeight_ = height;
glfwSetWindowTitle(title.c_str()); // title is set separately
}
void Application::createDisplay(uint width, uint height, uint bpp,
uint depthBits, uint stencilBits, bool fullscreen,
const std::string &title)
{
// call main version of createDisplay with individual values for rgba bits
switch(bpp)
{
case 8:
createDisplay(width, height, 3, 3, 2, 0, depthBits, stencilBits,
fullscreen, title);
break;
case 16:
createDisplay(width, height, 5, 6, 5, 0, depthBits, stencilBits,
fullscreen, title);
break;
case 24:
createDisplay(width, height, 8, 8, 8, 0, depthBits, stencilBits,
fullscreen, title);
break;
case 32:
createDisplay(width, height, 8, 8, 8, 8, depthBits, stencilBits,
fullscreen, title);
break;
default:
throw ArgumentException("bpp argument of createDisplay must be "
"8,16,24, or 32, passed " +
boost::lexical_cast<std::string>(bpp) );
}
}
bool Application::keyPressed(KeyCode key)
{
return glfwGetKey(key) == GLFW_PRESS;
}
std::vector<KeyCode> Application::getPressedKeys()
{
return pressedKeys_;
}
bool Application::mouseButtonPressed(MouseButton button)
{
return glfwGetMouseButton(button) == GLFW_PRESS;
}
int Application::getMouseX()
{
return updateTask_->mouseX_;
}
int Application::getMouseY()
{
return updateTask_->mouseY_;
}
int Application::getMouseWheelPos()
{
return glfwGetMouseWheel();
}
void Application::addInputListener(InputListener *listener)
{
// should never happen since listeners add themselves with a this pointer
if(!listener)
{
throw ArgumentException("Null pointer in "
"Application::addInputListener");
}
// add the listener
listeners_.push_back(listener);
}
void Application::removeInputListener(InputListener *listener)
{
// should never happen since listeners remove themselves with a this pointer
if(!listener)
{
throw ArgumentException("Null pointer in "
"Application::removeInputListener");
}
// find and erase the listener
std::vector<InputListener*>::iterator it;
it = std::find(listeners_.begin(), listeners_.end(), listener);
if(it != listeners_.end())
{
listeners_.erase(it);
}
}
void GLFWCALL Application::keyCallback(int key, int action)
{
// notify all listeners
for(std::vector<InputListener*>::iterator listener = listeners_.begin();
listener != listeners_.end();
++listener)
{
// only active listeners get messages
if((*listener)->isActive())
{
if(action == GLFW_PRESS)
{
(*listener)->onKeyPress(key);
}
else
{
(*listener)->onKeyRelease(key);
}
}
}
// maintain a list of pressed keys
if(action == GLFW_PRESS)
{
pressedKeys_.push_back(static_cast<KeyCode>(key));
}
else
{
// delete a key from the vector
std::vector<KeyCode>::iterator it;
it = std::find(pressedKeys_.begin(), pressedKeys_.end(), key);
if(it != pressedKeys_.end())
{
pressedKeys_.erase(it);
}
}
}
void GLFWCALL Application::mouseButtonCallback(int button, int action)
{
// notify all listeners
for(std::vector<InputListener*>::iterator listener = listeners_.begin();
listener != listeners_.end();
++listener)
{
// only active listeners get messages
if((*listener)->isActive())
{
if(action == GLFW_PRESS)
{
(*listener)->onMouseButtonPress(button);
}
else
{
(*listener)->onMouseButtonRelease(button);
}
}
}
}
void GLFWCALL Application::mouseMoveCallback(int x, int y)
{
// notify all listeners
for(std::vector<InputListener*>::iterator listener = listeners_.begin();
listener != listeners_.end();
++listener)
{
// only active listeners get messages
if((*listener)->isActive())
{
(*listener)->onMouseMove(math::Vector2(static_cast<scalar>(x),
static_cast<scalar>(y)));
}
}
2005-08-02 23:07:51 +00:00
}
2005-03-15 19:21:51 +00:00
scalar Application::getTime()
2005-08-02 23:07:51 +00:00
{
return glfwGetTime() - updateTask_->pausedTime_;
2005-08-02 23:07:51 +00:00
}
void Application::setTitle(const std::string& title)
2005-08-02 23:07:51 +00:00
{
glfwSetWindowTitle(title.c_str());
2005-08-02 23:07:51 +00:00
}
video::VideoCore& Application::getVideoCore()
{
// return VideoCore if it has been created
if(videoCore_.get() == 0)
{
throw PreconditionException("call to Application::getVideoCore() before"
" Application::initAudioDevice");
}
return *videoCore_;
}
audio::AudioCore& Application::getAudioCore()
{
// return AudioCore if it has been created
if(audioCore_.get() == 0)
{
throw PreconditionException("call to Application::getAudioCore() before"
" Application::initAudioDevice");
}
return *audioCore_;
}
void Application::initVideoCore(uint width, uint height)
{
// create VideoCore, avoid double initializaiton
if(videoCore_.get() == 0)
{
videoCore_.reset(new video::VideoCore(width, height));
}
else
{
throw PreconditionException("Attempt to double initialize VideoCore");
}
}
void Application::initAudioCore(const std::string& deviceName)
{
// create AudioCore, avoid double initializaiton
if(audioCore_.get() == 0)
{
audioCore_.reset(new audio::AudioCore(deviceName));
}
else
{
throw PreconditionException("Attempt to double initialize AudioCore");
}
2005-03-15 19:21:51 +00:00
}
bool Application::isActive()
{
return updateTask_->active_;
}
bool Application::isRunning()
{
return !updateTask_->quitRequested_;
}
double Application::getElapsedTime()
{
return updateTask_->secPerFrame_;
}
double Application::getFramerate()
{
return 1/updateTask_->secPerFrame_;
}
uint Application::getDisplayWidth()
{
return dispWidth_;
}
uint Application::getDisplayHeight()
2005-03-15 19:21:51 +00:00
{
return dispHeight_;
2005-02-13 22:12:02 +00:00
}
util::VersionInfo Application::initPhysFS(const std::string& arg0)
2005-02-13 22:12:02 +00:00
{
PHYSFS_Version ver;
PHYSFS_init(arg0.c_str());
PHYSFS_addToSearchPath(PHYSFS_getBaseDir(),0);
2005-02-13 22:12:02 +00:00
PHYSFS_getLinkedVersion(&ver);
return util::VersionInfo(ver.major, ver.minor, ver.patch);
}
util::VersionInfo Application::initGLFW()
{
int maj,min,patch;
if(glfwInit() == GL_FALSE)
{
throw APIError("Initialization of GLFW failed!");
}
glfwGetVersion(&maj,&min,&patch);
return util::VersionInfo(maj,min,patch);
}
Application::UpdateTask::UpdateTask() :
Task("Application::UpdateTask", PRI_APP_UPDATE),
mouseX_(0), mouseY_(0),
active_(false), timerPaused_(false),
unpauseOnActive_(false), lastPause_(0), pausedTime_(0),
secPerFrame_(0), lastUpdate_(0),
quitRequested_(false)
{
}
void Application::UpdateTask::update()
{
scalar curTime = glfwGetTime() - pausedTime_;
// update the display here instead of VideoCore (since it belongs to glfw)
glfwSwapBuffers();
glfwGetMousePos(&mouseX_, &mouseY_);
// keep track of time between frames
secPerFrame_ = curTime-lastUpdate_;
lastUpdate_ = curTime;
// quit on window closing or Alt-F4/Alt-X
if(!glfwGetWindowParam(GLFW_OPENED) ||
( (glfwGetKey(GLFW_KEY_LALT) || glfwGetKey(GLFW_KEY_RALT)) &&
(glfwGetKey(GLFW_KEY_F4) || glfwGetKey('X')) ) )
{
Kernel::getInstance().killAllTasks();
}
// hold active-state
active_ = (glfwGetWindowParam(GLFW_ACTIVE) == GL_TRUE);
// automatically pause/unpause app timer on focus
if(!active_ && !timerPaused_)
{
timerPaused_ = true;
lastPause_ = curTime;
unpauseOnActive_ = true;
}
else if(active_ && unpauseOnActive_)
{
timerPaused_ = true;
pausedTime_ += curTime - lastPause_;
unpauseOnActive_ = false;
}
}
Application::StateUpdate::StateUpdate() :
Task("StateUpdate", PRI_NORMAL)
{
}
void Application::StateUpdate::update()
{
state_->update();
}
Application::StateRender::StateRender() :
Task("StateRender", PRI_RENDER)
{
}
void Application::StateRender::update()
{
state_->render();
}
2005-02-07 02:00:48 +00:00
}