/*
3D C++ Toolkit (TDT)
Application Class
Copyright (c) 2008
John Ryland
*/
#include <TDT/application.h>
#include <GLUT/glut.h>
#include <unistd.h>
//#define DEBUG_CALLBACKS(s) printf(s "\n")
#define DEBUG_CALLBACKS(s)
namespace TDT
{
static void glutDisplayCallback(void)
{
DEBUG_CALLBACKS("glutDisplayCallback");
Application::instance()->dispatchEvent(Event(Event::Paint));
}
static void glutReshapeCallback(int width, int height)
{
DEBUG_CALLBACKS("glutReshapeCallback");
Application::instance()->dispatchEvent(Event(Event::Resize, width, height));
}
static void glutKeyboardCallback(unsigned char key, int x, int y)
{
DEBUG_CALLBACKS("glutKeyboardCallback");
Application::instance()->dispatchEvent(Event(Event::KeyPress, x, y, key));
}
static void glutKeyboardUpCallback(unsigned char key, int x, int y)
{
DEBUG_CALLBACKS("glutKeyboardUpCallback");
Application::instance()->dispatchEvent(Event(Event::KeyRelease, x, y, key));
}
static void glutMouseCallback(int button, int state, int x, int y)
{
DEBUG_CALLBACKS("glutMouseCallback");
if ( state == 0 ) {
Application::instance()->dispatchEvent(Event(Event::MousePress, x, y, button));
} else {
Application::instance()->dispatchEvent(Event(Event::MouseRelease, x, y, button));
}
}
static void glutMotionCallback(int x, int y)
{
DEBUG_CALLBACKS("glutMotionCallback");
Application::instance()->dispatchEvent(Event(Event::MouseMove, x, y));
}
static void glutPassiveMotionCallback(int x, int y)
{
DEBUG_CALLBACKS("glutPassiveMotionCallback");
Application::instance()->dispatchEvent(Event(Event::MouseMove, x, y));
}
static void glutEntryCallback(int state)
{
DEBUG_CALLBACKS("glutEntryCallback");
if ( state == 0 ) {
Application::instance()->dispatchEvent(Event(Event::FocusOut));
} else {
Application::instance()->dispatchEvent(Event(Event::FocusIn));
}
}
static void glutVisibilityCallback(int state)
{
DEBUG_CALLBACKS("glutVisibilityCallback");
if ( state == 0 ) {
Application::instance()->dispatchEvent(Event(Event::Hide));
} else {
Application::instance()->dispatchEvent(Event(Event::Show));
}
}
static void glutIdleCallback(void)
{
DEBUG_CALLBACKS("glutIdleCallback");
Application::instance()->dispatchEvent(Event(Event::Idle));
}
static void glutTimerCallback(int timerId)
{
DEBUG_CALLBACKS("glutTimerCallback");
Application::instance()->dispatchEvent(Event(Event::Timer, timerId));
}
static void glutOverlayDisplayCallback(void)
{
DEBUG_CALLBACKS("glutOverlayDisplayCallback");
Application::instance()->dispatchEvent(Event(Event::OverlayDisplay));
}
static void glutCloseCallback(void)
{
DEBUG_CALLBACKS("glutCloseCallback");
Application::instance()->dispatchEvent(Event(Event::Close));
}
Application *Application::app = 0;
Application::Application(int argc, char *argv[])
{
if ( app ) {
printf("Error: you should only construct one Application instance, typically in main.c\n");
return;
} else {
app = this;
}
init(argc, argv);
installCallbacks();
}
Application::~Application()
{
}
void Application::init(int argc, char *argv[])
{
glutInit(&argc, argv);
}
void Application::installCallbacks()
{
glutDisplayFunc(glutDisplayCallback);
glutReshapeFunc(glutReshapeCallback);
glutKeyboardFunc(glutKeyboardCallback);
glutKeyboardUpFunc(glutKeyboardUpCallback);
glutMouseFunc(glutMouseCallback);
glutMotionFunc(glutMotionCallback);
glutPassiveMotionFunc(glutPassiveMotionCallback);
glutEntryFunc(glutEntryCallback);
glutVisibilityFunc(glutVisibilityCallback);
glutIdleFunc(glutIdleCallback);
glutOverlayDisplayFunc(glutOverlayDisplayCallback);
#if (GLUT_MACOSX_IMPLEMENTATION >= 2)
glutWMCloseFunc(glutCloseCallback);
#elif defined(FREEGLUT)
glutCloseFunc(glutCloseCallback);
#endif
}
Application *Application::instance()
{
if (!app) {
printf("Warning, it appears that you are calling Application::instance() before constructing one, usually this means a programming error\n");
new Application(0,0);
}
return app;
}
int Application::exec()
{
glutMainLoop();
return 0;
}
void Application::insertWindow(Window *win)
{
windows.push_back(win);
}
void Application::removeWindow(Window *win)
{
std::list<Window*>::iterator i = windows.begin();
while (i != windows.end())
{
if (*i == win) {
windows.erase(i);
return;
}
i++;
}
}
void Application::addTimer(int milliSec, Window *win)
{
glutTimerFunc(milliSec, glutTimerCallback, win->winId());
}
bool Application::eventFilter(Event event)
{
return false;
}
void Application::dispatchEvent(Event event)
{
if (eventFilter(event))
return;
int winId = glutGetWindow();
std::list<Window*>::iterator i = windows.begin();
while (i != windows.end())
{
if ((*i)->winId() == winId) {
(*i)->event(event);
return; /* Assuming that only one window will match the winId */
}
i++;
}
}
};