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
$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
* Kernel/Task design that allows easy creation of graphical
games/applications without sacrificing control
* Extensive Log system that allows full control over logging including
0.0.1
+ State-based design that allows easy creation of applications by simply
deriving from a basic 'State' class.
+ 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
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
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.
* Resource Management system including the ability to load resources from
+ Resource Management system including the ability to load resources from
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
* ConfigFile class for reading/writing INI-style files for game settings
* OpenGL management including ability to set video mode, and easy management
+ ConfigFile class for reading/writing INI-style files for game settings
+ OpenGL management including ability to set video mode, and easy management
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
* 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
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
* Primitive-drawing Pen class allowing for drawing of various geometric
+ Primitive-drawing Pen class allowing for drawing of various geometric
shapes, lines, and vectors.
* OpenAL based sound system*
* Entire library is built in a highly-modular fashion with extensibility in
+ OpenAL based sound system*
+ Entire library is built in a highly-modular fashion with extensibility in
mind. Use of modern programming techniques like templates and exceptions
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)
$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--
@ -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
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?
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

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)
//
// 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
#define PHOTON_APPLICATION_HPP
#include <vector>
#include <map>
#include <string>
#include <boost/utility.hpp>
@ -19,77 +20,368 @@
#include "util/VersionInfo.hpp"
#include "Task.hpp"
#include "Kernel.hpp"
#include "AppCore.hpp"
#include "InputListener.hpp"
#include "video/VideoCore.hpp"
#include "audio/AudioCore.hpp"
#include "util/Singleton.hpp"
#include <vector>
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
// Abstract main class, all photon applications should derive from Application.
//
// Derived classes are made entrypoint via <ENTRYPOINT>.
class Application
class Application : public util::Singleton<Application>
{
// Group: (Con/De)structors
public:
// Function: Application
// Default constructor, initializes the internal state & dependencies.
Application();
Application(const std::string& arg0);
// Function: ~Application
// Default destructor, shuts down dependencies.
virtual ~Application();
// Group: Main
// Group: Video
public:
// Function: main
// Pure virtual, must be defined by derived class, using some preprocessor
// magic (<MAINCLASS>) on the derived class
// this becomes the entry point for a Photon application.
// Function: createDisplay
// This function attempts to create a display with the given 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.
// (Same as main in Standard C/C++).
// 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.
//
// See Also:
// <ENTRYPOINT>
virtual int main(const StrVec& args)=0;
// 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: 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
public:
static Kernel& getKernel();
static AppCore& getAppCore();
static video::VideoCore& getVideoCore();
static audio::AudioCore& getAudioCore();
static void initVideoCore(uint width, uint height);
static void initAudioCore(const std::string& deviceName);
// behind the scenes
video::VideoCore& getVideoCore();
audio::AudioCore& getAudioCore();
void initVideoCore(uint width, uint height);
void initAudioCore(const std::string& deviceName);
// Group: Accessors
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
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:
// version number for photon
util::VersionInfo photonVer_;
uint dispWidth_;
uint dispHeight_;
shared_ptr<UpdateTask> updateTask_;
shared_ptr<StateUpdate> stateUpdate_;
shared_ptr<StateRender> stateRender_;
// State system
StateMap stateMap_;
// input monitoring variables
static std::vector<InputListener*> listeners_;
static std::vector<KeyCode> pressedKeys_;
// Cores and Kernel
static Kernel kernel_;
static AppCore appCore_;
static std::auto_ptr<video::VideoCore> videoCore_;
static std::auto_ptr<audio::AudioCore> audioCore_;
static std::string arg0_;
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

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu)
//
// 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
#define PHOTON_KERNEL_HPP
@ -13,6 +13,7 @@
#include <list>
#include <algorithm>
#include "util/Singleton.hpp"
#include "Task.hpp"
namespace photon
@ -26,7 +27,7 @@ namespace photon
// - (1) Add any tasks (should be derived from <Task>)
// - (2) call <Kernel::run>
// - (3) in order to avoid running forever, all tasks should eventually die
class Kernel
class Kernel : public util::Singleton<Kernel>
{
// Group: (Con/De)structors
@ -41,11 +42,18 @@ public:
// Group: Running
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
// Runs tasks until all tasks are asleep or dead.
//
// Each 'frame' 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.
// See Also:
// <step>
void run();
// Group: Task Management

View File

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

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu)
//
// 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
@ -15,7 +15,6 @@
#include "AL/al.h"
#include "AL/alc.h"
#include "util/Singleton.hpp"
#include "util/VersionInfo.hpp"
namespace photon

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu)
//
// 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
@ -15,54 +15,41 @@
// Title: Entrypoint
// Macro: ENTRYPOINT
// 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.
int PhotonMain(const photon::StrVec& args);
#define ENTRYPOINT(className) 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)
int main(int argc, const char** argv)
{
// logging of uncaught exceptions to console
Log log;
log.addSink(LogSinkPtr(new photon::ConsoleSink("out")));
photon::Log log;
log.addSink(photon::LogSinkPtr(new photon::ConsoleSink("out")));
try
{
App::setInitOptions(argv[0]);
App app;
new photon::Application(argv[0]);
// push arguments into StrVec
StrVec args;
photon::StrVec args;
for(int i=0; i < argc; ++i)
{
args.push_back(argv[i]);
}
int retVal = PhotonMain(args);
photon::Application::destroy();
// hand arguments to Application::main and return what main returns
return app.main(args);
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;
return 1;
return 1;
}
catch(Error &e) // log errors as critical errors
catch(photon::Error &e) // log errors as critical errors
{
log.critical() << e;
return 1;
}
}
}
#endif //PHOTON_ENTRYPOINT_HPP

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu)
//
// 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
#define PHOTON_UTIL_TIMER_HPP
@ -76,7 +76,6 @@ private:
// data members
private:
AppCore& appCore_;
bool appTimeLinked_;
bool paused_;
double pausedTime_;

193
photon.mm
View File

@ -3,9 +3,40 @@
<node ID="Freemind_Link_1676542623" TEXT="Photon">
<cloud/>
<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"/>
<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 ">
<icon BUILTIN="button_ok"/>
<node ID="_" TEXT="amph listener system">
@ -15,104 +46,42 @@
<icon BUILTIN="button_ok"/>
</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">
<icon BUILTIN="stop"/>
<node COLOR="#ff0300" ID="Freemind_Link_1961333678" TEXT="delay until 0.1.x">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</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 ID="Freemind_Link_1298931281" TEXT="XML resource files"/>
<node ID="Freemind_Link_1070201117" TEXT="Transitions">
@ -133,7 +102,7 @@
<node ID="Freemind_Link_1362733907" TEXT="investigate dropping Corona"/>
</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"/>
<node FOLDED="true" ID="Freemind_Link_1066996987" TEXT="New Features">
<font NAME="SansSerif" SIZE="12"/>
@ -144,25 +113,41 @@
<node FOLDED="true" ID="Freemind_Link_304523376" TEXT="network::">
<node ID="Freemind_Link_717482997" TEXT="wrap enet?"/>
</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"/>
</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"/>
</node>
<node ID="Freemind_Link_1083759822" TEXT="java interface">
<icon BUILTIN="help"/>
</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.23 2005/08/02 23:07:51 cozman Exp $">
<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 $">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</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>
</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)
//
// 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 "physfs.h"
#include "GL/gl.h"
#include "GL/glfw.h" //This file depends on glfw
#include <boost/lexical_cast.hpp>
#include "exceptions.hpp"
#include "Log.hpp"
#include "Kernel.hpp"
#include "AppCore.hpp"
#include "Application.hpp"
#include "video/VideoCore.hpp"
#include "audio/AudioCore.hpp"
#include "util/filesys/filesys.hpp"
@ -25,36 +26,248 @@
namespace photon
{
Kernel Application::kernel_;
AppCore Application::appCore_;
std::auto_ptr<video::VideoCore> Application::videoCore_;
std::auto_ptr<audio::AudioCore> Application::audioCore_;
std::string Application::arg0_;
std::vector<InputListener*> Application::listeners_;
std::vector<KeyCode> Application::pressedKeys_;
Application::Application() :
photonVer_(0,0,1) // this is the current version
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())
{
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()
{
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()
@ -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_init(arg0_.c_str());
PHYSFS_init(arg0.c_str());
PHYSFS_addToSearchPath(PHYSFS_getBaseDir(),0);
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();
}
}

View File

@ -5,11 +5,11 @@
// James Turk (jpt2433@rit.edu)
//
// 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 "AppCore.hpp"
#include "Application.hpp"
namespace photon
{
@ -17,12 +17,12 @@ namespace photon
InputListener::InputListener() :
active_(true)
{
AppCore::addInputListener(this);
Application::addInputListener(this);
}
InputListener::~InputListener()
{
AppCore::removeInputListener(this);
Application::removeInputListener(this);
}
void InputListener::setActive(bool active)

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu)
//
// 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"
@ -22,6 +22,41 @@ 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()
@ -29,36 +64,7 @@ void Kernel::run()
// loop on activeTasks
while(!tasks_.empty())
{
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
}
}
step();
}
}

View File

@ -5,14 +5,14 @@
// James Turk (jpt2433@rit.edu)
//
// 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"
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)
{
}

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu)
//
// 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 "Application.hpp"
@ -16,7 +16,6 @@ namespace util
{
Timer::Timer(bool appTimeLinked) :
appCore_(Application::getAppCore()),
appTimeLinked_(appTimeLinked)
{
reset(); //initializes other members
@ -74,7 +73,8 @@ double Timer::getTimeInternal() const
{
if(appTimeLinked_)
{
return appCore_.getTime(); // get from AppCore timer if linked
// get from Application timer if linked
return Application::getInstance().getTime();
}
else
{

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu)
//
// 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"
@ -27,9 +27,9 @@ VideoCore::VideoCore(uint width, uint height) :
{
initOpenGL();
setOrthoView();
//add updater task
Application::getKernel().addTask(shared_ptr<Task>(new UpdateTask()));
Kernel::getInstance().addTask(shared_ptr<Task>(new UpdateTask()));
}
VideoCore::~VideoCore()
@ -114,8 +114,8 @@ void VideoCore::initOpenGL()
glShadeModel(GL_SMOOTH);
// Setup depth checking.
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
//glDepthFunc(GL_LEQUAL);
//glEnable(GL_DEPTH_TEST);
//setup hints
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
@ -148,7 +148,7 @@ uint VideoCore::getDisplayHeight()
}
VideoCore::UpdateTask::UpdateTask() :
Task("VideoCore::UpdateTask", 20)
Task("VideoCore::UpdateTask", PRI_VIDEO_UPDATE)
{
}

View File

@ -5,7 +5,7 @@
// James Turk (jpt2433@rit.edu)
//
// 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"
using namespace photon;
@ -200,14 +200,14 @@ public:
Application::getAppCore().createDisplay(800,600,32,0,0,false);
// create sound device
Application::initAudioCore("OSS");
// be sure to add FPSDisplayTask
Application::getKernel().addTask(TaskPtr(new FPSDisplayTask()));
// add the main task to the Kernel
Application::getKernel().addTask(TaskPtr(new MainTask()));
// run Kernel until task finishes
Application::getKernel().run();
Application::getKernel().run();
return 0;
}
};

View File

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

View File

@ -5,23 +5,24 @@
// James Turk (jpt2433@rit.edu)
//
// 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"
using namespace photon;
#include "FPSDisplayTask.hpp" // used to display FPS in title bar
class MainTask : public Task
class MainState : public State
{
public:
MainTask() :
Task("MainTask"),
app(Application::getAppCore()),
video(Application::getVideoCore())
MainState() :
app(Application::getInstance())
{ }
void enterState()
{
video.setOrthoView(800,600);
// load the images
video::Image::addResource("data/icon.png");
video::Texture::addResource("robo","data/robo.png");
@ -30,20 +31,24 @@ public:
img[0].open("robo");
img[0].setAlpha(128);
img[0].resize(100,200);
// load img[1]
img[1].open("data/icon.png");
// copy img[0] into img[2] and flip it
img[2] = img[0];
img[2].flip(true,true);
}
void update()
{
}
void render()
{
// draw in top left corner
img[0].draw(0,0);
// rotate according to timer
img[1].drawRotated(200,200,app.getTime()*5);
@ -56,28 +61,22 @@ public:
private:
video::Image img[3];
AppCore& app;
video::VideoCore& video;
Application& app;
};
// standard application, creates window, registers task and runs
class ImageTest : public Application
int PhotonMain(const StrVec& args)
{
public:
Application::getInstance().createDisplay(800,600,32,0,0,true);
int main(const StrVec& args)
{
Application::getAppCore().createDisplay(800,600,32,0,0,false);
// be sure to add FPSDisplayTask
Kernel::getInstance().addTask(TaskPtr(new FPSDisplayTask()));
// be sure to add FPSDisplayTask
Application::getKernel().addTask(TaskPtr(new FPSDisplayTask()));
Application::getKernel().addTask(TaskPtr(new MainTask()));
Application::getKernel().run();
Application::getInstance().registerState<MainState>("main");
Application::getInstance().setCurrentState("main");
return 0;
}
};
Kernel::getInstance().run();
return 0;
}
ENTRYPOINT(ImageTest)