State system reimplemented, overhaul of much of Core/Kernel/Task arch

This commit is contained in:
James Turk 2005-08-07 07:12:46 +00:00
parent 84e61a622d
commit 0b64a143b4
20 changed files with 958 additions and 908 deletions

View File

@ -1,37 +1,38 @@
Changelog for Photon Changelog for Photon
$Id: CHANGELOG.txt,v 1.2 2005/07/19 18:35:20 cozman Exp $ $Id: CHANGELOG.txt,v 1.3 2005/08/07 07:12:46 cozman Exp $
0.1.0 (Massachusetts) - Initial Release 0.0.1
* Kernel/Task design that allows easy creation of graphical + State-based design that allows easy creation of applications by simply
games/applications without sacrificing control deriving from a basic 'State' class.
* Extensive Log system that allows full control over logging including + Kernel/Task system allowing full control over game loop.
+ Extensive Log system that allows full control over logging including
various log levels and three built in forms of output, with the ability various log levels and three built in forms of output, with the ability
to add custom output formats. to add custom output formats.
* A wide variety of helper utilities for tasks such as filesystem + A wide variety of helper utilities for tasks such as filesystem
navigation, FileBuffer capable of reading from archives, random number navigation, FileBuffer capable of reading from archives, random number
generation, versioning, and timing generation, versioning, and timing
* Powerful input system allowing for direct access to keyboard/mouse status + Powerful input system allowing for direct access to keyboard/mouse status
or passive listeners which are notified of events when they occur. or passive listeners which are notified of events when they occur.
* Resource Management system including the ability to load resources from + Resource Management system including the ability to load resources from
specified directories or archives. specified directories or archives.
* Variety of math classes including Circle, Rectangle, and Vector classes + Variety of math classes including Circle, Rectangle, and Vector classes
convinient for game use convinient for game use
* ConfigFile class for reading/writing INI-style files for game settings + ConfigFile class for reading/writing INI-style files for game settings
* OpenGL management including ability to set video mode, and easy management + OpenGL management including ability to set video mode, and easy management
of multiple viewports of multiple viewports
* Resource-managed Texture class allowing for loading of textures for use in + Resource-managed Texture class allowing for loading of textures for use in
OpenGL OpenGL
* Image class that extends Texture class, allowing for hardware accellerated + Image class that extends Texture class, allowing for hardware accellerated
drawing, rotation, scaling, and blending of images for use in 2D drawing, rotation, scaling, and blending of images for use in 2D
environments environments
* Resource-managed Font class allowing for the rendering of text using + Resource-managed Font class allowing for the rendering of text using
TrueType fonts TrueType fonts
* Primitive-drawing Pen class allowing for drawing of various geometric + Primitive-drawing Pen class allowing for drawing of various geometric
shapes, lines, and vectors. shapes, lines, and vectors.
* OpenAL based sound system* + OpenAL based sound system*
* Entire library is built in a highly-modular fashion with extensibility in + Entire library is built in a highly-modular fashion with extensibility in
mind. Use of modern programming techniques like templates and exceptions mind. Use of modern programming techniques like templates and exceptions
contributes to ease of use and ease of development. contributes to ease of use and ease of development.
* 13 demo programs showing features and ease of use of various components. + 12 demo programs showing features and ease of use of various components.

View File

@ -1,5 +1,5 @@
IfAQ (Infrequently Asked Questions) IfAQ (Infrequently Asked Questions)
$Id: IFAQ.txt,v 1.1 2005/07/17 22:41:03 cozman Exp $ $Id: IFAQ.txt,v 1.2 2005/08/07 07:12:46 cozman Exp $
--basic questions-- --basic questions--
@ -70,6 +70,12 @@ Q. Does Photon use proprietary libraries like DirectX?
A. Photon only uses free open source libraries, so that by using Photon you are A. Photon only uses free open source libraries, so that by using Photon you are
not subjected to any proprietary licensing terms. not subjected to any proprietary licensing terms.
Q. When will features X, Y, and Z be completed?
A. When I get to them, I can only work on Photon in my spare time, if you have a
specific request let me know and I can give you an estimate of when I plan
on getting to it. There's always the option that you help out and then the
feature will be added sooner rather than later.
Q. What if I have something to add? Q. What if I have something to add?
A. Feel free to contribute to Photon, bugfixes are greatly appreciated. Not A. Feel free to contribute to Photon, bugfixes are greatly appreciated. Not
all submitted features can be accepted, but I'll usually at least add a all submitted features can be accepted, but I'll usually at least add a

View File

@ -1,256 +1 @@
//This file is part of Photon (http://photon.sourceforge.net)
//Copyright (C) 2004-2005 James Turk
//
// Author:
// James Turk (jpt2433@rit.edu)
//
// Version:
// $Id: AppCore.hpp,v 1.9 2005/08/02 23:07:51 cozman Exp $
#ifndef PHOTON_APPCORE_HPP
#define PHOTON_APPCORE_HPP
#include "types.hpp"
#include "util/VersionInfo.hpp"
#include "Task.hpp"
#include "InputListener.hpp"
#include <vector>
namespace photon
{
// Class: AppCore
// Photon's core for application behavior. Defines the interface through which
// all "application" related functions are performed. This means input,
// display creation, etc.
//
// AppCore is the Core that essentially represents the window management,
// input, and timing systems.
class AppCore
{
public:
AppCore();
~AppCore();
void init();
void shutdown();
// Group: Video
public:
// Function: createDisplay
// This function attempts to create a display with the given parameters.
//
// Parameters:
// width - desired width of display
// height - desired height of display
// redBits - desired bits per pixel for red value
// greenBits - desired bits per pixel for green value
// blueBits - desired bits per pixel for blue value
// alphaBits - desired bits per pixel for alpha value
// depthBits - desired bitdepth of depth buffer
// stencilBits - desired bitdepth of stencil buffer
// fullscreen - true: fullscreen, false: windowed
// [title - title of application, optional]
void createDisplay(uint width, uint height,
uint redBits, uint greenBits, uint blueBits,
uint alphaBits, uint depthBits, uint stencilBits,
bool fullscreen, const std::string& title="Photon App");
// Function: createDisplay
// This function attempts to create a display with the given parameters.
//
// Parameters:
// width - desired width of display
// height - desired height of display
// bpp - desired bits per pixel (aka bitdepth) of display
// depthBits - desired bitdepth of depth buffer
// stencilBits - desired bitdepth of stencil buffer
// fullscreen - true: fullscreen, false: windowed
// [title - title of application, optional]
void createDisplay(uint width, uint height, uint bpp,
uint depthBits, uint stencilBits, bool fullscreen,
const std::string& title="Photon App");
// Group: Input
public:
// Function: keyPressed
// Check if a given key is currently pressed.
//
// Parameters:
// key - <KeyCode> of key to determine status of.
//
// Returns:
// true: key is pressed, false: key isn't pressed
bool keyPressed(KeyCode key);
// Function: getPressedKeys
// Obtain a list of all keys which are currently pressed.
//
// Returns:
// std::vector of <KeyCodes> of any pressed keys.
std::vector<KeyCode> getPressedKeys();
// Function: mouseButtonPressed
// Check if a given mouse button is currently pressed.
//
// Parameters:
// button - <MouseButton> to determine status of.
//
// Returns:
// true: button is pressed, false: button isn't pressed
bool mouseButtonPressed(MouseButton button);
// Function: getMouseX
// Gets current x location of mouse with respect to screen coordinates.
//
// Returns:
// Mouse x-coordinate, with respect to screen coordinates.
int getMouseX();
// Function: getMouseY
// Gets current y location of mouse with respect to screen coordinates.
//
// Returns:
// Mouse y-coordinate, with respect to screen coordinates.
int getMouseY();
// Function: getMouseWheelPos
// Gets current location of mouse wheel, treated as if wheel describes a
// third axis of movement for the mouse.
//
// Returns:
// Mouse wheel position, zero assumed to be starting position.
int getMouseWheelPos();
// Group: Input Listeners
public:
// Function: addInputListener
// Registers an <InputListener> to listen for any input events so that it
// is notified when they occur.
//
// Parameters:
// listener - Pointer to <InputListener> to add.
static void addInputListener(InputListener *listener);
// Function: removeInputListener
// Removes an <InputListener> from the list of active listeners.
//
// Parameters:
// listener - Pointer to <InputListener> to remove.
static void removeInputListener(InputListener *listener);
static void GLFWCALL keyCallback(int key, int action);
//static void GLFWCALL charCallback(int character, int action);
static void GLFWCALL mouseButtonCallback(int button, int action);
static void GLFWCALL mouseMoveCallback(int x, int y);
//static void GLFWCALL mouseWheelCallback(int pos);
// Group: Timing
public:
// Function: getTime
// Get time, in seconds, that application has been running.
//
// Returns:
// Time, represented as a floating-point number in seconds, application has
// been running.
scalar getTime();
// Group: General
public:
// Function: setTitle
// Sets title of application that shows up in title bar.
//
// Parameters:
// title - New title of application.
void setTitle(const std::string& title);
// Function: isActive
// Checks if application is active, which on most systems simply means it
// has focus.
//
// Returns:
// True if application is active, false otherwise.
bool isActive();
// Function: getElapsedTime
// Finds the amount of time passed between frames, useful for time-based
// movement.
//
// Returns:
// Time between current frame and last frame. (1/<getFramerate>())
double getElapsedTime();
// Function: getFramerate
// Gets number of frames per second the application is currently processing
//
// Returns:
// Current frames per second.
double getFramerate();
// Group: Accessors
public:
// Function: getDisplayWidth
// Get the width of the display.
//
// Returns:
// Width of display in pixels.
uint getDisplayWidth();
// Function: getDisplayHeight
// Get the height of the display.
//
// Returns:
// Height of display in pixels.
uint getDisplayHeight();
// UpdateTask, does the updating work of AppCore, registered as a Task
// so that user need not call something akin to AppCore::update() every
// frame
class UpdateTask : public Task
{
friend class AppCore;
public:
UpdateTask();
void update();
private:
int mouseX_;
int mouseY_;
bool active_;
bool timerPaused_;
bool unpauseOnActive_;
scalar lastPause_;
scalar pausedTime_;
scalar secPerFrame_;
scalar lastUpdate_;
};
// data members
private:
uint dispWidth_;
uint dispHeight_;
shared_ptr<UpdateTask> task_;
// input monitoring variables
static std::vector<InputListener*> listeners_;
static std::vector<KeyCode> pressedKeys_;
// API initialization
private:
util::VersionInfo initGLFW();
};
}
#endif //PHOTON_APPCORE_HPP

View File

@ -5,12 +5,13 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: Application.hpp,v 1.10 2005/08/02 23:07:51 cozman Exp $ // $Id: Application.hpp,v 1.11 2005/08/07 07:12:46 cozman Exp $
#ifndef PHOTON_APPLICATION_HPP #ifndef PHOTON_APPLICATION_HPP
#define PHOTON_APPLICATION_HPP #define PHOTON_APPLICATION_HPP
#include <vector> #include <vector>
#include <map>
#include <string> #include <string>
#include <boost/utility.hpp> #include <boost/utility.hpp>
@ -19,77 +20,368 @@
#include "util/VersionInfo.hpp" #include "util/VersionInfo.hpp"
#include "Task.hpp" #include "Task.hpp"
#include "Kernel.hpp" #include "Kernel.hpp"
#include "AppCore.hpp" #include "InputListener.hpp"
#include "video/VideoCore.hpp" #include "video/VideoCore.hpp"
#include "audio/AudioCore.hpp" #include "audio/AudioCore.hpp"
#include "util/Singleton.hpp"
#include <vector>
namespace photon namespace photon
{ {
class State
{
public:
State() { };
virtual ~State() { };
public:
virtual void enterState() { };
virtual void exitState() { };
public:
virtual void update()=0;
virtual void render()=0;
};
// Class: Application // Class: Application
// Abstract main class, all photon applications should derive from Application. // Abstract main class, all photon applications should derive from Application.
// //
// Derived classes are made entrypoint via <ENTRYPOINT>. // Derived classes are made entrypoint via <ENTRYPOINT>.
class Application class Application : public util::Singleton<Application>
{ {
// Group: (Con/De)structors // Group: (Con/De)structors
public: public:
// Function: Application // Function: Application
// Default constructor, initializes the internal state & dependencies. // Default constructor, initializes the internal state & dependencies.
Application(); Application(const std::string& arg0);
// Function: ~Application // Function: ~Application
// Default destructor, shuts down dependencies. // Default destructor, shuts down dependencies.
virtual ~Application(); virtual ~Application();
// Group: Main // Group: Video
public: public:
// Function: main
// Pure virtual, must be defined by derived class, using some preprocessor // Function: createDisplay
// magic (<MAINCLASS>) on the derived class // This function attempts to create a display with the given parameters.
// this becomes the entry point for a Photon application.
// //
// Parameters: // Parameters:
// args - <ArgList> containing arguments passed to program. // width - desired width of display
// height - desired height of display
// redBits - desired bits per pixel for red value
// greenBits - desired bits per pixel for green value
// blueBits - desired bits per pixel for blue value
// alphaBits - desired bits per pixel for alpha value
// depthBits - desired bitdepth of depth buffer
// stencilBits - desired bitdepth of stencil buffer
// fullscreen - true: fullscreen, false: windowed
// [title - title of application, optional]
void createDisplay(uint width, uint height,
uint redBits, uint greenBits, uint blueBits,
uint alphaBits, uint depthBits, uint stencilBits,
bool fullscreen, const std::string& title="Photon App");
// Function: createDisplay
// This function attempts to create a display with the given parameters.
// //
// Returns: 0 upon success, other upon failure. // Parameters:
// (Same as main in Standard C/C++). // width - desired width of display
// height - desired height of display
// bpp - desired bits per pixel (aka bitdepth) of display
// depthBits - desired bitdepth of depth buffer
// stencilBits - desired bitdepth of stencil buffer
// fullscreen - true: fullscreen, false: windowed
// [title - title of application, optional]
void createDisplay(uint width, uint height, uint bpp,
uint depthBits, uint stencilBits, bool fullscreen,
const std::string& title="Photon App");
// Group: Input
public:
// Function: keyPressed
// Check if a given key is currently pressed.
// //
// See Also: // Parameters:
// <ENTRYPOINT> // key - <KeyCode> of key to determine status of.
virtual int main(const StrVec& args)=0; //
// Returns:
// true: key is pressed, false: key isn't pressed
bool keyPressed(KeyCode key);
// Function: getPressedKeys
// Obtain a list of all keys which are currently pressed.
//
// Returns:
// std::vector of <KeyCodes> of any pressed keys.
std::vector<KeyCode> getPressedKeys();
// Function: mouseButtonPressed
// Check if a given mouse button is currently pressed.
//
// Parameters:
// button - <MouseButton> to determine status of.
//
// Returns:
// true: button is pressed, false: button isn't pressed
bool mouseButtonPressed(MouseButton button);
// Function: getMouseX
// Gets current x location of mouse with respect to screen coordinates.
//
// Returns:
// Mouse x-coordinate, with respect to screen coordinates.
int getMouseX();
// Function: getMouseY
// Gets current y location of mouse with respect to screen coordinates.
//
// Returns:
// Mouse y-coordinate, with respect to screen coordinates.
int getMouseY();
// Function: getMouseWheelPos
// Gets current location of mouse wheel, treated as if wheel describes a
// third axis of movement for the mouse.
//
// Returns:
// Mouse wheel position, zero assumed to be starting position.
int getMouseWheelPos();
// Group: Input Listeners
public:
// Function: addInputListener
// Registers an <InputListener> to listen for any input events so that it
// is notified when they occur.
//
// Parameters:
// listener - Pointer to <InputListener> to add.
static void addInputListener(InputListener *listener);
// Function: removeInputListener
// Removes an <InputListener> from the list of active listeners.
//
// Parameters:
// listener - Pointer to <InputListener> to remove.
static void removeInputListener(InputListener *listener);
static void GLFWCALL keyCallback(int key, int action);
//static void GLFWCALL charCallback(int character, int action);
static void GLFWCALL mouseButtonCallback(int button, int action);
static void GLFWCALL mouseMoveCallback(int x, int y);
//static void GLFWCALL mouseWheelCallback(int pos);
// Group: Timing
public:
// Function: getTime
// Get time, in seconds, that application has been running.
//
// Returns:
// Time, represented as a floating-point number in seconds, application has
// been running.
scalar getTime();
// Group: General
public:
// Function: setTitle
// Sets title of application that shows up in title bar.
//
// Parameters:
// title - New title of application.
void setTitle(const std::string& title);
// Function: isActive
// Checks if application is active, which on most systems simply means it
// has focus.
//
// Returns:
// True if application is active, false otherwise.
bool isActive();
// Function: isRunning
// Checks if application is running, which means that no quit has been
// requested.
//
// Returns:
// True if application is running, false otherwise.
bool isRunning();
// Function: getElapsedTime
// Finds the amount of time passed between frames, useful for time-based
// movement.
//
// Returns:
// Time between current frame and last frame. (1/<getFramerate>())
double getElapsedTime();
// Function: getFramerate
// Gets number of frames per second the application is currently processing
//
// Returns:
// Current frames per second.
double getFramerate();
// Group: State Management
public:
// Function: registerState
// Register a new <State> type.
//
// Arguments:
// stateName - Name of new <State>.
//
// Template Parameters:
// StateT - Class derived from <State> to register.
template<class StateT>
void registerState(const std::string& stateName);
// TODO: why would someone want to unregister a state?
// Function: unregisterState
// Unregister a registered <State> type.
//
// Arguments:
// stateName - Name of <State> to unregister.
void unregisterState(const std::string& stateName);
// Function: setCurrentState
// Set the current Application <State>.
//
// Arguments:
// stateName - Name of <State> to make active
void setCurrentState(const std::string& stateName);
// Group: Core Access // Group: Core Access
public: public:
static Kernel& getKernel(); video::VideoCore& getVideoCore();
static AppCore& getAppCore(); audio::AudioCore& getAudioCore();
static video::VideoCore& getVideoCore(); void initVideoCore(uint width, uint height);
static audio::AudioCore& getAudioCore(); void initAudioCore(const std::string& deviceName);
static void initVideoCore(uint width, uint height);
static void initAudioCore(const std::string& deviceName);
// behind the scenes // Group: Accessors
public: public:
static void setInitOptions(const char* arg0); // Function: getDisplayWidth
// Get the width of the display.
//
// Returns:
// Width of display in pixels.
uint getDisplayWidth();
// Function: getDisplayHeight
// Get the height of the display.
//
// Returns:
// Height of display in pixels.
uint getDisplayHeight();
// Group: API Initialization // Group: API Initialization
private: private:
util::VersionInfo initPhysFS(); util::VersionInfo initPhysFS(const std::string& arg0);
util::VersionInfo initGLFW();
// UpdateTask, does the updating work of AppCore, registered as a Task
// so that user need not call something akin to AppCore::update() every
// frame
class UpdateTask : public Task
{
friend class Application;
public:
UpdateTask();
void update();
private:
int mouseX_;
int mouseY_;
bool active_;
bool timerPaused_;
bool unpauseOnActive_;
scalar lastPause_;
scalar pausedTime_;
scalar secPerFrame_;
scalar lastUpdate_;
bool quitRequested_;
};
// State system
typedef shared_ptr<State> StatePtr;
typedef std::map<std::string, StatePtr> StateMap;
// StateUpdate
class StateUpdate : public Task
{
friend class Application;
public:
StateUpdate();
void update();
private:
StatePtr state_;
};
// StateRender
class StateRender : public Task
{
friend class Application;
public:
StateRender();
void update();
private:
StatePtr state_;
};
private: private:
// version number for photon // version number for photon
util::VersionInfo photonVer_; util::VersionInfo photonVer_;
// Cores and Kernel uint dispWidth_;
static Kernel kernel_; uint dispHeight_;
static AppCore appCore_; shared_ptr<UpdateTask> updateTask_;
static std::auto_ptr<video::VideoCore> videoCore_; shared_ptr<StateUpdate> stateUpdate_;
static std::auto_ptr<audio::AudioCore> audioCore_; shared_ptr<StateRender> stateRender_;
static std::string arg0_; // State system
StateMap stateMap_;
// input monitoring variables
static std::vector<InputListener*> listeners_;
static std::vector<KeyCode> pressedKeys_;
// Cores and Kernel
std::auto_ptr<video::VideoCore> videoCore_;
std::auto_ptr<audio::AudioCore> audioCore_;
}; };
template<class StateT>
void Application::registerState(const std::string& stateName)
{
StateMap::iterator it( stateMap_.find(stateName) );
if(it != stateMap_.end())
{
throw PreconditionException("Application::registerState called twice "
"with same name: \"" + stateName + "\"");
}
stateMap_[stateName] = StatePtr(new StateT);
}
} }
#endif //PHOTON_APPLICATION_HPP #endif //PHOTON_APPLICATION_HPP

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: Kernel.hpp,v 1.2 2005/08/02 23:07:52 cozman Exp $ // $Id: Kernel.hpp,v 1.3 2005/08/07 07:12:46 cozman Exp $
#ifndef PHOTON_KERNEL_HPP #ifndef PHOTON_KERNEL_HPP
#define PHOTON_KERNEL_HPP #define PHOTON_KERNEL_HPP
@ -13,6 +13,7 @@
#include <list> #include <list>
#include <algorithm> #include <algorithm>
#include "util/Singleton.hpp"
#include "Task.hpp" #include "Task.hpp"
namespace photon namespace photon
@ -26,7 +27,7 @@ namespace photon
// - (1) Add any tasks (should be derived from <Task>) // - (1) Add any tasks (should be derived from <Task>)
// - (2) call <Kernel::run> // - (2) call <Kernel::run>
// - (3) in order to avoid running forever, all tasks should eventually die // - (3) in order to avoid running forever, all tasks should eventually die
class Kernel class Kernel : public util::Singleton<Kernel>
{ {
// Group: (Con/De)structors // Group: (Con/De)structors
@ -41,11 +42,18 @@ public:
// Group: Running // Group: Running
public: public:
// Function: step
// Steps the kernel, calling each active task once.
//
// Each 'step' all tasks are run in order of their priorities, if two
// tasks have the same priority, they are run in the order they were added.
void step();
// Function: run // Function: run
// Runs tasks until all tasks are asleep or dead. // Runs tasks until all tasks are asleep or dead.
// //
// Each 'frame' all tasks are run in order of their priorities, if two // See Also:
// tasks have the same priority, they are run in the order they were added. // <step>
void run(); void run();
// Group: Task Management // Group: Task Management

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: Task.hpp,v 1.3 2005/07/20 06:12:54 cozman Exp $ // $Id: Task.hpp,v 1.4 2005/08/07 07:12:46 cozman Exp $
#ifndef PHOTON_TASK_HPP #ifndef PHOTON_TASK_HPP
#define PHOTON_TASK_HPP #define PHOTON_TASK_HPP
@ -17,17 +17,29 @@
namespace photon namespace photon
{ {
// Title: Task // Type: TaskPriority
enum PriorityLevel
{
PRI_APP_UPDATE, // special priority for Application updating (first)
// Group: Helper Types // user-level priorities all lie in logic area
PRI_HIGHEST,
PRI_HIGH,
PRI_NORMAL,
PRI_LOW,
PRI_LOWEST,
class Task; PRI_VIDEO_UPDATE, // special priority for clearing screen/video buffers
class Kernel; PRI_RENDER // special priority for rendering (right after clear)
// Type: TaskPtr // It is also important that no priorities fall between render/app update
// Pointer to a task, used since Task is abstract and will always be accessed // so that flow of applications is:
// via a pointer. // 1) Update & SwapBuffers
typedef shared_ptr<Task> TaskPtr; // 2) Logic & User Level tasks
// 3) Clear screen/buffers
// 4) Render
// 5) SwapBuffers again (see step 1)
};
// Class: Task // Class: Task
// Abstract class for tasks, which are runnable classes for use with <Kernel>. // Abstract class for tasks, which are runnable classes for use with <Kernel>.
@ -44,10 +56,8 @@ public:
// name - Name for task, must be unique! // name - Name for task, must be unique!
// priority - Optional argument for desired priority for the Task, // priority - Optional argument for desired priority for the Task,
// controls order in which tasks are run by the <Kernel>. // controls order in which tasks are run by the <Kernel>.
// Tasks are executed starting with the lowest number for // Default Priority is PRI_NORMAL
// priority, meaning a task with priority=0 will execute first. Task(const std::string& name, PriorityLevel priority=PRI_NORMAL);
// Default priority is 5000.
Task(const std::string& name, uint priority=5000);
// Function: ~Task // Function: ~Task
// Virtual destructor, exists simply to make inheritance safe. // Virtual destructor, exists simply to make inheritance safe.
@ -124,11 +134,16 @@ public:
// data members // data members
private: private:
std::string name_; // all tasks need a unique name std::string name_; // all tasks need a unique name
uint priority_; // priority determines ordering of tasks PriorityLevel priority_; // priority determines ordering of tasks
bool alive_; // if false, task will be pruned bool alive_; // if false, task will be pruned
bool paused_; // if false task won't be executed bool paused_; // if false task won't be executed
}; };
// Type: TaskPtr
// Pointer to a task, used since Task is abstract and will always be accessed
// via a pointer.
typedef shared_ptr<Task> TaskPtr;
} }
#endif //PHOTON_TASK_HPP #endif //PHOTON_TASK_HPP

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: AudioCore.hpp,v 1.10 2005/08/02 23:07:52 cozman Exp $ // $Id: AudioCore.hpp,v 1.11 2005/08/07 07:12:47 cozman Exp $
#ifdef PHOTON_USE_OPENAL #ifdef PHOTON_USE_OPENAL
@ -15,7 +15,6 @@
#include "AL/al.h" #include "AL/al.h"
#include "AL/alc.h" #include "AL/alc.h"
#include "util/Singleton.hpp"
#include "util/VersionInfo.hpp" #include "util/VersionInfo.hpp"
namespace photon namespace photon

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: entrypoint.hpp,v 1.6 2005/07/19 01:31:37 cozman Exp $ // $Id: entrypoint.hpp,v 1.7 2005/08/07 07:12:46 cozman Exp $
#ifndef PHOTON_ENTRYPOINT_HPP #ifndef PHOTON_ENTRYPOINT_HPP
@ -15,54 +15,41 @@
// Title: Entrypoint // Title: Entrypoint
// Macro: ENTRYPOINT int PhotonMain(const photon::StrVec& args);
// A macro which is used to specify the class containing the entrypoint.
// For example, if the class PongGame is the class derived from <Application>
// which implements main, in the file defining PongGame it is important to
// include ENTRYPOINT(PongGame) so that the entry point becomes PongGame::main.
#define ENTRYPOINT(className) int main(int argc, const char** argv) \ int main(int argc, const char** argv)
{ return photon::mainclass<className>(argc,argv); }
namespace photon
{
// function which does all the work of ENTRYPOINT
template<class App>
int mainclass(int argc, const char** argv)
{ {
// logging of uncaught exceptions to console // logging of uncaught exceptions to console
Log log; photon::Log log;
log.addSink(LogSinkPtr(new photon::ConsoleSink("out"))); log.addSink(photon::LogSinkPtr(new photon::ConsoleSink("out")));
try try
{ {
App::setInitOptions(argv[0]); new photon::Application(argv[0]);
App app;
// push arguments into StrVec // push arguments into StrVec
StrVec args; photon::StrVec args;
for(int i=0; i < argc; ++i) for(int i=0; i < argc; ++i)
{ {
args.push_back(argv[i]); args.push_back(argv[i]);
} }
// hand arguments to Application::main and return what main returns int retVal = PhotonMain(args);
return app.main(args);
photon::Application::destroy();
return retVal;
} }
catch(Exception &e) // log exceptions as errors (wow that's confusing) catch(photon::Exception &e) // log exceptions as errors (confusing?)
{ {
log.error() << e; log.error() << e;
return 1; return 1;
} }
catch(Error &e) // log errors as critical errors catch(photon::Error &e) // log errors as critical errors
{ {
log.critical() << e; log.critical() << e;
return 1; return 1;
} }
} }
}
#endif //PHOTON_ENTRYPOINT_HPP #endif //PHOTON_ENTRYPOINT_HPP

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: Timer.hpp,v 1.2 2005/07/18 06:18:51 cozman Exp $ // $Id: Timer.hpp,v 1.3 2005/08/07 07:12:47 cozman Exp $
#ifndef PHOTON_UTIL_TIMER_HPP #ifndef PHOTON_UTIL_TIMER_HPP
#define PHOTON_UTIL_TIMER_HPP #define PHOTON_UTIL_TIMER_HPP
@ -76,7 +76,6 @@ private:
// data members // data members
private: private:
AppCore& appCore_;
bool appTimeLinked_; bool appTimeLinked_;
bool paused_; bool paused_;
double pausedTime_; double pausedTime_;

193
photon.mm
View File

@ -3,9 +3,40 @@
<node ID="Freemind_Link_1676542623" TEXT="Photon"> <node ID="Freemind_Link_1676542623" TEXT="Photon">
<cloud/> <cloud/>
<font BOLD="true" NAME="SansSerif" SIZE="12"/> <font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node ID="Freemind_Link_682620075" POSITION="right" TEXT="0.1 Release"> <node ID="Freemind_Link_682620075" POSITION="right" TEXT="0.1 Series">
<font BOLD="true" NAME="SansSerif" SIZE="12"/> <font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node ID="Freemind_Link_1746871436" TEXT="remaining features"> <node ID="Freemind_Link_1125660603" TEXT="0.0.1">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node ID="Freemind_Link_700471537" TEXT="dependencies / licensing clarification">
<icon BUILTIN="button_ok"/>
</node>
<node ID="Freemind_Link_1010220321" TEXT="0.0.1 final tests">
<node ID="Freemind_Link_674240959" TEXT="convert">
<icon BUILTIN="pencil"/>
</node>
<node ID="Freemind_Link_885668051" TEXT="test"/>
</node>
<node ID="Freemind_Link_1939341405" TEXT="evaluate status of Cores"/>
<node FOLDED="true" ID="Freemind_Link_1153941464" TEXT="test compilation on fresh systems">
<node ID="Freemind_Link_1403005191" TEXT="test compilation on clean linux system"/>
<node ID="Freemind_Link_617919930" TEXT="test compilation on windows system">
<node ID="Freemind_Link_962964571" TEXT="MingW"/>
<node ID="Freemind_Link_601778960" TEXT="visual c++"/>
</node>
<node ID="Freemind_Link_510637" TEXT="OSX tester?">
<node ID="Freemind_Link_1837644449" TEXT="gamedev"/>
<node ID="Freemind_Link_867673431" TEXT="OSX dev community"/>
<node COLOR="#ff0300" ID="Freemind_Link_1465392887" TEXT="delay until 0.1.x">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="help"/>
</node>
</node>
</node>
</node>
<node ID="Freemind_Link_115594103" TEXT="0.1">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node FOLDED="true" ID="Freemind_Link_1746871436" TEXT="features">
<icon BUILTIN="button_ok"/>
<node FOLDED="true" ID="Freemind_Link_40954797" TEXT="improved input handling "> <node FOLDED="true" ID="Freemind_Link_40954797" TEXT="improved input handling ">
<icon BUILTIN="button_ok"/> <icon BUILTIN="button_ok"/>
<node ID="_" TEXT="amph listener system"> <node ID="_" TEXT="amph listener system">
@ -15,104 +46,42 @@
<icon BUILTIN="button_ok"/> <icon BUILTIN="button_ok"/>
</node> </node>
</node> </node>
<node ID="Freemind_Link_261923672" TEXT="change way Audio is enabled">
<icon BUILTIN="button_ok"/>
<node ID="Freemind_Link_1100203457" TEXT="fixed ~AudioCore"/>
</node>
</node>
<node COLOR="#010101" ID="Freemind_Link_1806925741" TEXT="resource finalization">
<icon BUILTIN="button_ok"/>
</node>
<node ID="Freemind_Link_1166438127" TEXT="test release candidate"/>
<node FOLDED="true" ID="Freemind_Link_1870184326" TEXT="example game">
<node COLOR="#000000" ID="Freemind_Link_597173063" TEXT="Asteroids"/>
<node ID="Freemind_Link_719722821" TEXT="Lunar Lander"/>
<node ID="Freemind_Link_173048174" TEXT="Missile Command"/>
<node COLOR="#010101" ID="Freemind_Link_1447936394" TEXT="Frogger"/>
</node>
<node ID="Freemind_Link_1716705807" TEXT="clean up naturaldocs"/>
</node>
<node FOLDED="true" ID="Freemind_Link_1151493849" TEXT="0.1.x">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node ID="Freemind_Link_540349165" TEXT="static-LGPL Free OpenAL on Windows">
<font NAME="SansSerif" SIZE="12"/>
<node ID="Freemind_Link_968837931" TEXT="drop alut"/>
<node ID="Freemind_Link_831588763" TEXT="write own wav-loader"/>
</node>
</node>
</node>
<node FOLDED="true" ID="Freemind_Link_486829238" POSITION="right" TEXT="0.2 Release">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node ID="Freemind_Link_103747781" TEXT="New Features">
<font NAME="SansSerif" SIZE="12"/>
<node ID="Freemind_Link_1825420810" TEXT="Music"> <node ID="Freemind_Link_1825420810" TEXT="Music">
<icon BUILTIN="stop"/> <icon BUILTIN="stop"/>
<node COLOR="#ff0300" ID="Freemind_Link_1961333678" TEXT="delay until 0.1.x"> <node COLOR="#ff0300" ID="Freemind_Link_1961333678" TEXT="delay until 0.1.x">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/> <font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node> </node>
</node> </node>
<node ID="Freemind_Link_261923672" TEXT="change way Audio is enabled">
<icon BUILTIN="button_ok"/>
<node ID="Freemind_Link_1100203457" TEXT="fixed ~AudioCore"/>
</node>
<node ID="Freemind_Link_1694084951" TEXT="work on making Task more user friendly">
<font NAME="SansSerif" SIZE="12"/>
<node ID="Freemind_Link_1066242768" TEXT="&quot;State&quot; system">
<font NAME="SansSerif" SIZE="12"/>
</node>
<node ID="Freemind_Link_854288636" TEXT="hide Kernel">
<font NAME="SansSerif" SIZE="12"/>
</node>
</node>
</node>
<node ID="Freemind_Link_700471537" TEXT="dependencies / licensing clarification">
<icon BUILTIN="button_ok"/>
</node>
<node ID="Freemind_Link_1153941464" TEXT="test compilation on fresh systems">
<node ID="Freemind_Link_1403005191" TEXT="test compilation on clean linux system"/>
<node ID="Freemind_Link_617919930" TEXT="test compilation on windows system">
<node ID="Freemind_Link_962964571" TEXT="MingW"/>
<node ID="Freemind_Link_601778960" TEXT="visual c++"/>
</node>
<node ID="Freemind_Link_510637" TEXT="OSX tester?">
<node ID="Freemind_Link_1837644449" TEXT="gamedev"/>
<node ID="Freemind_Link_867673431" TEXT="OSX dev community"/>
<node ID="Freemind_Link_1722199385" TEXT="sourceforge">
<node ID="Freemind_Link_518828740" TEXT="job posting"/>
<node ID="Freemind_Link_997339944" TEXT="compile farm">
<icon BUILTIN="button_cancel"/>
</node>
</node>
<node COLOR="#ff0300" ID="Freemind_Link_1465392887" TEXT="delay until 0.1.x">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="help"/>
</node>
</node>
</node>
<node ID="Freemind_Link_1716705807" TEXT="clean up naturaldocs"/>
<node ID="Freemind_Link_1870184326" TEXT="example game">
<node COLOR="#000000" ID="Freemind_Link_597173063" TEXT="Asteroids"/>
<node ID="Freemind_Link_719722821" TEXT="Lunar Lander"/>
<node ID="Freemind_Link_173048174" TEXT="Missile Command"/>
<node COLOR="#010101" ID="Freemind_Link_1447936394" TEXT="Frogger"/>
<node COLOR="#010101" ID="Freemind_Link_1789291917" TEXT="LaserGame">
<font NAME="SansSerif" SIZE="12"/>
</node>
</node>
<node FOLDED="true" ID="Freemind_Link_1010220321" TEXT="clean/test all tests">
<icon BUILTIN="button_ok"/>
<node ID="Freemind_Link_129725390" TEXT="Audio">
<icon BUILTIN="button_ok"/>
</node>
<node ID="Freemind_Link_543532536" TEXT="ConfigFile">
<icon BUILTIN="button_ok"/>
</node>
<node ID="Freemind_Link_1037234161" TEXT="Font">
<icon BUILTIN="button_ok"/>
</node>
<node ID="Freemind_Link_1574983928" TEXT="Image">
<icon BUILTIN="button_ok"/>
</node>
<node ID="Freemind_Link_83171017" TEXT="Input">
<icon BUILTIN="button_ok"/>
</node>
<node ID="Freemind_Link_714170273" TEXT="Log">
<icon BUILTIN="button_ok"/>
</node>
<node ID="Freemind_Link_1336661607" TEXT="Pen">
<icon BUILTIN="button_ok"/>
</node>
<node ID="Freemind_Link_26290657" TEXT="RandGen">
<icon BUILTIN="button_ok"/>
</node>
<node ID="Freemind_Link_1563035547" TEXT="Texture">
<icon BUILTIN="button_ok"/>
</node>
<node ID="Freemind_Link_120826083" TEXT="filesys">
<icon BUILTIN="button_ok"/>
</node>
<node ID="Freemind_Link_1985120655" TEXT="math">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#010101" ID="Freemind_Link_1806925741" TEXT="resource finalization">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node FOLDED="true" ID="Freemind_Link_486829238" POSITION="right" TEXT="0.2 Release">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node FOLDED="true" ID="Freemind_Link_103747781" TEXT="New Features">
<font NAME="SansSerif" SIZE="12"/>
<node COLOR="#000000" ID="Freemind_Link_420721466" TEXT="XML/XSLT sink"/> <node COLOR="#000000" ID="Freemind_Link_420721466" TEXT="XML/XSLT sink"/>
<node ID="Freemind_Link_1298931281" TEXT="XML resource files"/> <node ID="Freemind_Link_1298931281" TEXT="XML resource files"/>
<node ID="Freemind_Link_1070201117" TEXT="Transitions"> <node ID="Freemind_Link_1070201117" TEXT="Transitions">
@ -133,7 +102,7 @@
<node ID="Freemind_Link_1362733907" TEXT="investigate dropping Corona"/> <node ID="Freemind_Link_1362733907" TEXT="investigate dropping Corona"/>
</node> </node>
</node> </node>
<node FOLDED="true" ID="Freemind_Link_1111954089" POSITION="right" TEXT="Long Term"> <node ID="Freemind_Link_1111954089" POSITION="right" TEXT="Long Term">
<font BOLD="true" NAME="SansSerif" SIZE="12"/> <font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node FOLDED="true" ID="Freemind_Link_1066996987" TEXT="New Features"> <node FOLDED="true" ID="Freemind_Link_1066996987" TEXT="New Features">
<font NAME="SansSerif" SIZE="12"/> <font NAME="SansSerif" SIZE="12"/>
@ -144,25 +113,41 @@
<node FOLDED="true" ID="Freemind_Link_304523376" TEXT="network::"> <node FOLDED="true" ID="Freemind_Link_304523376" TEXT="network::">
<node ID="Freemind_Link_717482997" TEXT="wrap enet?"/> <node ID="Freemind_Link_717482997" TEXT="wrap enet?"/>
</node> </node>
<node ID="Freemind_Link_21483700" TEXT="python interface"> <node FOLDED="true" ID="Freemind_Link_1766405270" TEXT="scripting">
<node ID="Freemind_Link_918658782" TEXT="lua"/>
<node ID="Freemind_Link_1079584283" TEXT="python"/>
<node ID="Freemind_Link_512949260" TEXT="angelscript"/>
<node ID="Freemind_Link_1813241804" TEXT="custom"/>
<node ID="Freemind_Link_1220379011" TEXT="other"/>
</node>
</node>
<node FOLDED="true" ID="Freemind_Link_1067043723" TEXT="allow for alternate backends ">
<node ID="Freemind_Link_1997175841" TEXT="audiere for audio">
<node ID="Freemind_Link_1142976123" TEXT="is there a point?">
<node ID="Freemind_Link_396200365" TEXT="compatibility?"/>
</node>
</node>
<node ID="Freemind_Link_961284194" TEXT="SDL backend">
<icon BUILTIN="help"/> <icon BUILTIN="help"/>
</node> </node>
<node ID="Freemind_Link_1045478290" TEXT="lua integration"> </node>
<node FOLDED="true" ID="Freemind_Link_1036629371" TEXT="other languages">
<node ID="Freemind_Link_21483700" TEXT="python interface">
<icon BUILTIN="help"/> <icon BUILTIN="help"/>
</node> </node>
<node ID="Freemind_Link_1083759822" TEXT="java interface"> <node ID="Freemind_Link_1083759822" TEXT="java interface">
<icon BUILTIN="help"/> <icon BUILTIN="help"/>
</node> </node>
</node> </node>
<node FOLDED="true" ID="Freemind_Link_1067043723" TEXT="allow for alternate backends ">
<node ID="Freemind_Link_1997175841" TEXT="audiere for audio"/>
<node ID="Freemind_Link_961284194" TEXT="SDL backend">
<icon BUILTIN="help"/>
</node> </node>
</node> <node COLOR="#147f1e" ID="Freemind_Link_438641521" POSITION="left" TEXT="Version: $Id: photon.mm,v 1.24 2005/08/07 07:12:46 cozman Exp $">
</node>
<node COLOR="#147f1e" ID="Freemind_Link_438641521" POSITION="left" TEXT="Version: $Id: photon.mm,v 1.23 2005/08/02 23:07:51 cozman Exp $">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/> <font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node> </node>
<node ID="Freemind_Link_853483912" POSITION="left" TEXT="Current Problems">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node ID="Freemind_Link_3809219" TEXT="check if fullscreen works in Windows">
<font NAME="SansSerif" SIZE="12"/>
</node>
</node>
</node> </node>
</map> </map>

View File

@ -1,343 +1 @@
//This file is part of Photon (http://photon.sourceforge.net)
//Copyright (C) 2004-2005 James Turk
//
// Author:
// James Turk (jpt2433@rit.edu)
//
// Version:
// $Id: AppCore.cpp,v 1.14 2005/08/02 23:07:52 cozman Exp $
#include "AppCore.hpp"
#include <boost/lexical_cast.hpp>
#include "GL/glfw.h" //This file depends on glfw
#include "Application.hpp"
#include "Kernel.hpp"
#include "exceptions.hpp"
#include "video/VideoCore.hpp"
namespace photon
{
// static initializer
std::vector<InputListener*> AppCore::listeners_;
std::vector<KeyCode> AppCore::pressedKeys_;
AppCore::AppCore() :
dispWidth_(0), dispHeight_(0),
task_(new UpdateTask())
{ }
AppCore::~AppCore()
{
}
void AppCore::init()
{
util::VersionInfo glfwReq(2,4,2); // requires GLFW 2.4.2
util::ensureVersion("GLFW", initGLFW(), glfwReq);
Application::getKernel().addTask(task_); // add updater task
}
void AppCore::shutdown()
{
if(dispWidth_ && dispHeight_)
{
glfwCloseWindow(); //close GLFW window
}
glfwTerminate(); //shutdown GLFW
}
void AppCore::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.");
}
// register the callbacks (after a window is open)
glfwSetKeyCallback(AppCore::keyCallback);
//glfwSetCharCallback(AppCore::charCallback);
glfwSetMouseButtonCallback(AppCore::mouseButtonCallback);
glfwSetMousePosCallback(AppCore::mouseMoveCallback);
//glfwSetMouseWheelCallback(AppCore::mouseWheelCallback);
Application::initVideoCore(width, height);
dispWidth_ = width;
dispHeight_ = height;
glfwSetWindowTitle(title.c_str()); // title is set separately
}
void AppCore::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 AppCore::keyPressed(KeyCode key)
{
return glfwGetKey(key) == GLFW_PRESS;
}
std::vector<KeyCode> AppCore::getPressedKeys()
{
return pressedKeys_;
}
bool AppCore::mouseButtonPressed(MouseButton button)
{
return glfwGetMouseButton(button) == GLFW_PRESS;
}
int AppCore::getMouseX()
{
return task_->mouseX_;
}
int AppCore::getMouseY()
{
return task_->mouseY_;
}
int AppCore::getMouseWheelPos()
{
return glfwGetMouseWheel();
}
void AppCore::addInputListener(InputListener *listener)
{
// should never happen since listeners add themselves with a this pointer
if(!listener)
{
throw ArgumentException("Null pointer in AppCore::addInputListener");
}
// add the listener
listeners_.push_back(listener);
}
void AppCore::removeInputListener(InputListener *listener)
{
// should never happen since listeners remove themselves with a this pointer
if(!listener)
{
throw ArgumentException("Null pointer in AppCore::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 AppCore::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 AppCore::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 AppCore::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)));
}
}
}
scalar AppCore::getTime()
{
return glfwGetTime() - task_->pausedTime_;
}
void AppCore::setTitle(const std::string& title)
{
glfwSetWindowTitle(title.c_str());
}
bool AppCore::isActive()
{
return task_->active_;
}
double AppCore::getElapsedTime()
{
return task_->secPerFrame_;
}
double AppCore::getFramerate()
{
return 1/task_->secPerFrame_;
}
uint AppCore::getDisplayWidth()
{
return dispWidth_;
}
uint AppCore::getDisplayHeight()
{
return dispHeight_;
}
util::VersionInfo AppCore::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);
}
AppCore::UpdateTask::UpdateTask() :
Task("AppCore::UpdateTask", 10),
mouseX_(0), mouseY_(0),
active_(false), timerPaused_(false),
unpauseOnActive_(false), lastPause_(0), pausedTime_(0),
secPerFrame_(0), lastUpdate_(0)
{
}
void AppCore::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')) ) )
{
Application::getKernel().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;
}
}
}

View File

@ -5,18 +5,19 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: Application.cpp,v 1.14 2005/08/02 23:07:52 cozman Exp $ // $Id: Application.cpp,v 1.15 2005/08/07 07:12:47 cozman Exp $
#include "Application.hpp" #include "Application.hpp"
#include "physfs.h" #include "physfs.h"
#include "GL/gl.h" #include "GL/gl.h"
#include "GL/glfw.h" //This file depends on glfw
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include "exceptions.hpp" #include "exceptions.hpp"
#include "Log.hpp" #include "Log.hpp"
#include "Kernel.hpp" #include "Kernel.hpp"
#include "AppCore.hpp" #include "Application.hpp"
#include "video/VideoCore.hpp" #include "video/VideoCore.hpp"
#include "audio/AudioCore.hpp" #include "audio/AudioCore.hpp"
#include "util/filesys/filesys.hpp" #include "util/filesys/filesys.hpp"
@ -25,36 +26,248 @@
namespace photon namespace photon
{ {
Kernel Application::kernel_; std::vector<InputListener*> Application::listeners_;
AppCore Application::appCore_; std::vector<KeyCode> Application::pressedKeys_;
std::auto_ptr<video::VideoCore> Application::videoCore_;
std::auto_ptr<audio::AudioCore> Application::audioCore_;
std::string Application::arg0_;
Application::Application() : Application::Application(const std::string& arg0) :
photonVer_(0,0,1) // this is the current version photonVer_(0,0,1), // this is the current version
dispWidth_(0), dispHeight_(0),
updateTask_(new UpdateTask()),
stateUpdate_(new StateUpdate()),
stateRender_(new StateRender())
{ {
util::VersionInfo physfsReq(1,0,0); // requires PhysFS 1.0.0 util::VersionInfo physfsReq(1,0,0); // requires PhysFS 1.0.0
util::ensureVersion("PhysFS", initPhysFS(), physfsReq); util::ensureVersion("PhysFS", initPhysFS(arg0), physfsReq);
appCore_.init(); // init appcore util::VersionInfo glfwReq(2,4,2); // requires GLFW 2.4.2
util::ensureVersion("GLFW", initGLFW(), glfwReq);
new Kernel; // create Kernel before it is used
Kernel::getInstance().addTask(updateTask_); // add updater task
Kernel::getInstance().addTask(stateUpdate_); // add state updater task
Kernel::getInstance().addTask(stateRender_); // add state renderer task
} }
Application::~Application() Application::~Application()
{ {
appCore_.shutdown(); // shutdown appcore if(dispWidth_ && dispHeight_)
{
glfwCloseWindow(); //close GLFW window
}
PHYSFS_deinit(); // shutdown PhysFS glfwTerminate(); //shutdown GLFW
PHYSFS_deinit(); // shutdown PhysFS
Kernel::destroy();
} }
Kernel& Application::getKernel() 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)
{ {
return kernel_; 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.");
}
// 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
} }
AppCore& Application::getAppCore() void Application::createDisplay(uint width, uint height, uint bpp,
uint depthBits, uint stencilBits, bool fullscreen,
const std::string &title)
{ {
return appCore_; // 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)));
}
}
}
scalar Application::getTime()
{
return glfwGetTime() - updateTask_->pausedTime_;
}
void Application::setTitle(const std::string& title)
{
glfwSetWindowTitle(title.c_str());
} }
video::VideoCore& Application::getVideoCore() video::VideoCore& Application::getVideoCore()
@ -105,18 +318,155 @@ void Application::initAudioCore(const std::string& deviceName)
} }
} }
void Application::setInitOptions(const char* arg0) bool Application::isActive()
{ {
arg0_ = arg0; return updateTask_->active_;
} }
util::VersionInfo Application::initPhysFS() bool Application::isRunning()
{
return !updateTask_->quitRequested_;
}
double Application::getElapsedTime()
{
return updateTask_->secPerFrame_;
}
double Application::getFramerate()
{
return 1/updateTask_->secPerFrame_;
}
void Application::unregisterState(const std::string& stateName)
{
StateMap::iterator it( stateMap_.find(stateName) );
if(it == stateMap_.end())
{
throw PreconditionException("Application::unregisterState called with "
"non-existant state name: \"" + stateName + "\"");
}
stateMap_.erase(stateName);
}
void Application::setCurrentState(const std::string& stateName)
{
StateMap::iterator it( stateMap_.find(stateName) );
if(it == stateMap_.end())
{
throw PreconditionException("Application::setCurrentState called with "
"non-existant state name: \"" + stateName + "\"");
}
if(stateUpdate_->state_.get() != 0)
{
stateUpdate_->state_->exitState();
}
stateRender_->state_ = stateUpdate_->state_ = stateMap_[stateName];
stateUpdate_->state_->enterState();
}
uint Application::getDisplayWidth()
{
return dispWidth_;
}
uint Application::getDisplayHeight()
{
return dispHeight_;
}
util::VersionInfo Application::initPhysFS(const std::string& arg0)
{ {
PHYSFS_Version ver; PHYSFS_Version ver;
PHYSFS_init(arg0_.c_str()); PHYSFS_init(arg0.c_str());
PHYSFS_addToSearchPath(PHYSFS_getBaseDir(),0); PHYSFS_addToSearchPath(PHYSFS_getBaseDir(),0);
PHYSFS_getLinkedVersion(&ver); PHYSFS_getLinkedVersion(&ver);
return util::VersionInfo(ver.major, ver.minor, ver.patch); 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();
}
} }

View File

@ -5,11 +5,11 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: InputListener.cpp,v 1.1 2005/07/19 05:45:24 cozman Exp $ // $Id: InputListener.cpp,v 1.2 2005/08/07 07:12:47 cozman Exp $
#include "InputListener.hpp" #include "InputListener.hpp"
#include "AppCore.hpp" #include "Application.hpp"
namespace photon namespace photon
{ {
@ -17,12 +17,12 @@ namespace photon
InputListener::InputListener() : InputListener::InputListener() :
active_(true) active_(true)
{ {
AppCore::addInputListener(this); Application::addInputListener(this);
} }
InputListener::~InputListener() InputListener::~InputListener()
{ {
AppCore::removeInputListener(this); Application::removeInputListener(this);
} }
void InputListener::setActive(bool active) void InputListener::setActive(bool active)

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: Kernel.cpp,v 1.3 2005/07/20 06:12:54 cozman Exp $ // $Id: Kernel.cpp,v 1.4 2005/08/07 07:12:47 cozman Exp $
#include "Kernel.hpp" #include "Kernel.hpp"
@ -22,6 +22,41 @@ Kernel::Kernel()
Kernel::~Kernel() Kernel::~Kernel()
{ {
killAllTasks();
}
void Kernel::step()
{
std::list<TaskPtr>::iterator it;
// loop through active tasks, updating each one
for(it = tasks_.begin(); it != tasks_.end(); ++it)
{
TaskPtr& task(*it);
// only update alive, non-paused tasks
if(task->isAlive() && !task->isPaused())
{
task->update();
}
}
// loop through tasks, removing any dead tasks
for(it = tasks_.begin(); it != tasks_.end(); )
{
TaskPtr& task(*it);
// remove dead tasks
if(!task->isAlive())
{
task->onKill(); // symmetry with onStart, clean up act
it = tasks_.erase(it);
}
else
{
++it; //advance iterator, if not deleting
}
}
} }
void Kernel::run() void Kernel::run()
@ -29,36 +64,7 @@ void Kernel::run()
// loop on activeTasks // loop on activeTasks
while(!tasks_.empty()) while(!tasks_.empty())
{ {
std::list<TaskPtr>::iterator it; step();
// loop through active tasks, updating each one
for(it = tasks_.begin(); it != tasks_.end(); ++it)
{
TaskPtr& task(*it);
// only update alive, non-paused tasks
if(task->isAlive() && !task->isPaused())
{
task->update();
}
}
// loop through tasks, removing any dead tasks
for(it = tasks_.begin(); it != tasks_.end(); )
{
TaskPtr& task(*it);
// remove dead tasks
if(!task->isAlive())
{
task->onKill(); // symmetry with onStart, clean up act
it = tasks_.erase(it);
}
else
{
++it; //advance iterator, if not deleting
}
}
} }
} }

View File

@ -5,14 +5,14 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: Task.cpp,v 1.3 2005/07/20 06:12:54 cozman Exp $ // $Id: Task.cpp,v 1.4 2005/08/07 07:12:47 cozman Exp $
#include "Task.hpp" #include "Task.hpp"
namespace photon namespace photon
{ {
Task::Task(const std::string& name, uint priority) : Task::Task(const std::string& name, PriorityLevel priority) :
name_(name), priority_(priority), alive_(true), paused_(false) name_(name), priority_(priority), alive_(true), paused_(false)
{ {
} }

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: Timer.cpp,v 1.4 2005/08/02 23:07:52 cozman Exp $ // $Id: Timer.cpp,v 1.5 2005/08/07 07:12:48 cozman Exp $
#include "util/Timer.hpp" #include "util/Timer.hpp"
#include "Application.hpp" #include "Application.hpp"
@ -16,7 +16,6 @@ namespace util
{ {
Timer::Timer(bool appTimeLinked) : Timer::Timer(bool appTimeLinked) :
appCore_(Application::getAppCore()),
appTimeLinked_(appTimeLinked) appTimeLinked_(appTimeLinked)
{ {
reset(); //initializes other members reset(); //initializes other members
@ -74,7 +73,8 @@ double Timer::getTimeInternal() const
{ {
if(appTimeLinked_) if(appTimeLinked_)
{ {
return appCore_.getTime(); // get from AppCore timer if linked // get from Application timer if linked
return Application::getInstance().getTime();
} }
else else
{ {

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: VideoCore.cpp,v 1.9 2005/08/02 23:07:53 cozman Exp $ // $Id: VideoCore.cpp,v 1.10 2005/08/07 07:12:48 cozman Exp $
#include "video/VideoCore.hpp" #include "video/VideoCore.hpp"
@ -29,7 +29,7 @@ VideoCore::VideoCore(uint width, uint height) :
setOrthoView(); setOrthoView();
//add updater task //add updater task
Application::getKernel().addTask(shared_ptr<Task>(new UpdateTask())); Kernel::getInstance().addTask(shared_ptr<Task>(new UpdateTask()));
} }
VideoCore::~VideoCore() VideoCore::~VideoCore()
@ -114,8 +114,8 @@ void VideoCore::initOpenGL()
glShadeModel(GL_SMOOTH); glShadeModel(GL_SMOOTH);
// Setup depth checking. // Setup depth checking.
glDepthFunc(GL_LEQUAL); //glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST); //glEnable(GL_DEPTH_TEST);
//setup hints //setup hints
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
@ -148,7 +148,7 @@ uint VideoCore::getDisplayHeight()
} }
VideoCore::UpdateTask::UpdateTask() : VideoCore::UpdateTask::UpdateTask() :
Task("VideoCore::UpdateTask", 20) Task("VideoCore::UpdateTask", PRI_VIDEO_UPDATE)
{ {
} }

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: Audio_test.cpp,v 1.8 2005/08/02 23:07:53 cozman Exp $ // $Id: Audio_test.cpp,v 1.9 2005/08/07 07:12:48 cozman Exp $
#include "photon.hpp" #include "photon.hpp"
using namespace photon; using namespace photon;

View File

@ -11,8 +11,8 @@ class FPSDisplayTask : public photon::Task
{ {
public: public:
FPSDisplayTask() : FPSDisplayTask() :
Task("FPSDisplayTask", 1000000), // extremely low priority Task("FPSDisplayTask"),
app(photon::Application::getAppCore()), app(Application::getInstance()),
lastUpdate(0) lastUpdate(0)
{ } { }
@ -28,7 +28,7 @@ public:
} }
private: private:
photon::AppCore& app; Application& app;
double lastUpdate; double lastUpdate;
}; };

View File

@ -5,23 +5,24 @@
// James Turk (jpt2433@rit.edu) // James Turk (jpt2433@rit.edu)
// //
// Version: // Version:
// $Id: Image_test.cpp,v 1.8 2005/08/02 23:07:53 cozman Exp $ // $Id: Image_test.cpp,v 1.9 2005/08/07 07:12:48 cozman Exp $
#include "photon.hpp" #include "photon.hpp"
using namespace photon; using namespace photon;
#include "FPSDisplayTask.hpp" // used to display FPS in title bar #include "FPSDisplayTask.hpp" // used to display FPS in title bar
class MainTask : public Task
class MainState : public State
{ {
public: public:
MainTask() : MainState() :
Task("MainTask"), app(Application::getInstance())
app(Application::getAppCore()), { }
video(Application::getVideoCore())
{
video.setOrthoView(800,600);
void enterState()
{
// load the images // load the images
video::Image::addResource("data/icon.png"); video::Image::addResource("data/icon.png");
video::Texture::addResource("robo","data/robo.png"); video::Texture::addResource("robo","data/robo.png");
@ -40,6 +41,10 @@ public:
} }
void update() void update()
{
}
void render()
{ {
// draw in top left corner // draw in top left corner
img[0].draw(0,0); img[0].draw(0,0);
@ -57,27 +62,21 @@ public:
private: private:
video::Image img[3]; video::Image img[3];
AppCore& app; Application& app;
video::VideoCore& video;
}; };
// standard application, creates window, registers task and runs int PhotonMain(const StrVec& args)
class ImageTest : public Application
{ {
public: Application::getInstance().createDisplay(800,600,32,0,0,true);
int main(const StrVec& args) // be sure to add FPSDisplayTask
{ Kernel::getInstance().addTask(TaskPtr(new FPSDisplayTask()));
Application::getAppCore().createDisplay(800,600,32,0,0,false);
// be sure to add FPSDisplayTask Application::getInstance().registerState<MainState>("main");
Application::getKernel().addTask(TaskPtr(new FPSDisplayTask())); Application::getInstance().setCurrentState("main");
Application::getKernel().addTask(TaskPtr(new MainTask()));
Application::getKernel().run(); Kernel::getInstance().run();
return 0; return 0;
} }
};
ENTRYPOINT(ImageTest)