#include <GL/glut.h>
#include "glutint.h"
#include "glutState.h"
#include "glutBlocker.h"
struct GLUTtimer {
GLUTtimer *next; bigtime_t timeout; GLUTtimerCB func; int value; };
static GLUTtimer *__glutTimerList = 0; static GLUTtimer *freeTimerList = 0;
void APIENTRY
glutTimerFunc(unsigned int interval, GLUTtimerCB timerFunc, int value)
{
GLUTtimer *timer, *other;
GLUTtimer **prevptr;
if (!timerFunc)
return;
if (freeTimerList) {
timer = freeTimerList;
freeTimerList = timer->next;
} else {
timer = new GLUTtimer();
if (!timer)
__glutFatalError("out of memory.");
}
timer->func = timerFunc;
timer->value = value;
timer->next = NULL;
timer->timeout = system_time() + (interval*1000); prevptr = &__glutTimerList;
other = *prevptr;
while (other && (other->timeout < timer->timeout)) {
prevptr = &other->next;
other = *prevptr;
}
timer->next = other;
*prevptr = timer;
}
static void
handleTimeouts(void)
{
bigtime_t now;
GLUTtimer *timer;
now = system_time();
while (__glutTimerList->timeout <= now) {
timer = __glutTimerList;
if(gState.currentWindow)
gState.currentWindow->LockGL();
timer->func(timer->value);
if(gState.currentWindow)
gState.currentWindow->UnlockGL();
__glutTimerList = timer->next;
timer->next = freeTimerList;
freeTimerList = timer;
if (!__glutTimerList)
break;
}
}
static void
processEventsAndTimeouts(void)
{
gBlock.WaitEvent(); gBlock.ClearEvents();
if(gState.quitAll)
exit(0);
if (gState.currentWindow)
gState.currentWindow->LockGL();
for(int i=0; i<gState.windowListSize; i++) {
if (gState.windowList[i]) {
GlutWindow *win = gState.windowList[i];
if (win->anyevents) {
win->anyevents = false;
if (win->reshapeEvent) {
win->reshapeEvent = false;
__glutSetWindow(win);
win->reshape(win->m_width, win->m_height);
}
if (!gState.windowList[i])
continue;
if (win->displayEvent) {
win->displayEvent = false;
__glutSetWindow(win);
win->display();
}
if (!gState.windowList[i])
continue;
if (win->mouseEvent) {
win->mouseEvent = false;
__glutSetWindow(win);
if (win->mouse) {
gState.modifierKeys = win->modifierKeys;
win->mouse(win->button, win->mouseState, win->mouseX, win->mouseY);
gState.modifierKeys = ~0;
}
}
if (!gState.windowList[i])
continue;
if (win->menuEvent) {
win->menuEvent = false;
__glutSetWindow(win);
GlutMenu *menu = __glutGetMenuByNum(win->menuNumber);
if (menu) {
gState.currentMenu = menu;
menu->select(win->menuValue);
}
}
if (!gState.windowList[i])
continue;
if (win->statusEvent) {
win->statusEvent = false;
__glutSetWindow(win);
if (gState.menuStatus) {
gState.currentMenu = __glutGetMenuByNum(win->menuNumber);
gState.menuStatus(win->menuStatus, win->statusX, win->statusY);
}
}
if (!gState.windowList[i])
continue;
if (win->motionEvent) {
win->motionEvent = false;
__glutSetWindow(win);
if (win->motion)
win->motion(win->motionX, win->motionY);
}
if (!gState.windowList[i])
continue;
if (win->passiveEvent) {
win->passiveEvent = false;
__glutSetWindow(win);
if (win->passive)
win->passive(win->passiveX, win->passiveY);
}
if (!gState.windowList[i])
continue;
if (win->keybEvent) {
win->keybEvent = false;
__glutSetWindow(win);
if (win->keyboard) {
gState.modifierKeys = win->modifierKeys;
win->keyboard(win->key, win->keyX, win->keyY);
gState.modifierKeys = ~0;
}
}
if (!gState.windowList[i])
continue;
if (win->specialEvent) {
win->specialEvent = false;
__glutSetWindow(win);
if (win->special) {
gState.modifierKeys = win->modifierKeys;
win->special(win->specialKey, win->specialX, win->specialY);
gState.modifierKeys = ~0;
}
}
if (!gState.windowList[i])
continue;
if (win->entryEvent) {
win->entryEvent = false;
__glutSetWindow(win);
if (win->entry)
win->entry(win->entryState);
}
if (!gState.windowList[i])
continue;
if (win->windowStatusEvent) {
win->windowStatusEvent = false;
__glutSetWindow(win);
if (win->windowStatus)
win->windowStatus(win->visState);
}
if (!gState.windowList[i])
continue; }
}
}
if (gState.currentWindow)
gState.currentWindow->UnlockGL();
#if 0
if(gState.debug) {
for(int i=0; i<gState.windowListSize; i++) {
if (gState.windowList[i]) {
gState.windowList[i]->LockGL();
glutReportErrors();
gState.windowList[i]->UnlockGL();
}
}
}
#endif
if (__glutTimerList) {
handleTimeouts();
}
}
static void
waitForSomething(void)
{
bigtime_t timeout = __glutTimerList->timeout;
bigtime_t now = system_time();
if (gBlock.PendingEvent())
goto immediatelyHandleEvent;
if(timeout>now)
gBlock.WaitEvent(timeout-now);
if (gBlock.PendingEvent()) {
immediatelyHandleEvent:
processEventsAndTimeouts();
} else {
if (__glutTimerList)
handleTimeouts();
}
}
static void
idleWait(void)
{
if (gBlock.PendingEvent()) {
processEventsAndTimeouts();
} else {
if (__glutTimerList)
handleTimeouts();
}
if(gState.currentWindow)
gState.currentWindow->LockGL();
if (gState.idle) {
gState.idle();
}
if(gState.currentWindow)
gState.currentWindow->UnlockGL();
}
void glutMainLoop()
{
if (!gState.windowListSize)
__glutFatalUsage("main loop entered with no windows created.");
if(gState.currentWindow)
gState.currentWindow->UnlockGL();
for (;;) {
if (gState.idle) {
idleWait();
} else {
if (__glutTimerList) {
waitForSomething();
} else {
processEventsAndTimeouts();
}
}
}
}
void GlutWindow::KeyDown(const char *s, int32 slen)
{
ulong aChar = s[0];
BGLView::KeyDown(s,slen);
BPoint p;
switch (aChar) {
case B_FUNCTION_KEY:
switch(Window()->CurrentMessage()->FindInt32("key")) {
case B_F1_KEY:
aChar = GLUT_KEY_F1;
goto specialLabel;
case B_F2_KEY:
aChar = GLUT_KEY_F2;
goto specialLabel;
case B_F3_KEY:
aChar = GLUT_KEY_F3;
goto specialLabel;
case B_F4_KEY:
aChar = GLUT_KEY_F4;
goto specialLabel;
case B_F5_KEY:
aChar = GLUT_KEY_F5;
goto specialLabel;
case B_F6_KEY:
aChar = GLUT_KEY_F6;
goto specialLabel;
case B_F7_KEY:
aChar = GLUT_KEY_F7;
goto specialLabel;
case B_F8_KEY:
aChar = GLUT_KEY_F8;
goto specialLabel;
case B_F9_KEY:
aChar = GLUT_KEY_F9;
goto specialLabel;
case B_F10_KEY:
aChar = GLUT_KEY_F10;
goto specialLabel;
case B_F11_KEY:
aChar = GLUT_KEY_F11;
goto specialLabel;
case B_F12_KEY:
aChar = GLUT_KEY_F12;
goto specialLabel;
default:
return;
}
case B_LEFT_ARROW:
aChar = GLUT_KEY_LEFT;
goto specialLabel;
case B_UP_ARROW:
aChar = GLUT_KEY_UP;
goto specialLabel;
case B_RIGHT_ARROW:
aChar = GLUT_KEY_RIGHT;
goto specialLabel;
case B_DOWN_ARROW:
aChar = GLUT_KEY_DOWN;
goto specialLabel;
case B_PAGE_UP:
aChar = GLUT_KEY_PAGE_UP;
goto specialLabel;
case B_PAGE_DOWN:
aChar = GLUT_KEY_PAGE_DOWN;
goto specialLabel;
case B_HOME:
aChar = GLUT_KEY_HOME;
goto specialLabel;
case B_END:
aChar = GLUT_KEY_END;
goto specialLabel;
case B_INSERT:
aChar = GLUT_KEY_INSERT;
specialLabel:
if (special) {
anyevents = specialEvent = true;
GetMouse(&p,&m_buttons);
specialKey = aChar;
specialX = (int)p.x;
specialY = (int)p.y;
goto setModifiers; }
return;
default:
break;
}
if (keyboard) {
anyevents = keybEvent = true;
GetMouse(&p,&m_buttons);
key = aChar;
keyX = (int)p.x;
keyY = (int)p.y;
setModifiers:
modifierKeys = 0;
uint32 beMod = Window()->CurrentMessage()->FindInt32("modifiers");
if(beMod & B_SHIFT_KEY)
modifierKeys |= GLUT_ACTIVE_SHIFT;
if(beMod & B_CONTROL_KEY)
modifierKeys |= GLUT_ACTIVE_CTRL;
if(beMod & B_OPTION_KEY) {
key = Window()->CurrentMessage()->FindInt32("raw_char");
modifierKeys |= GLUT_ACTIVE_ALT;
}
gBlock.NewEvent();
}
}
void GlutWindow::MouseDown(BPoint point)
{
BGLView::MouseDown(point);
MouseCheck();
}
void GlutWindow::MouseCheck()
{
if (mouseEvent)
return;
BPoint point;
uint32 newButtons;
GetMouse(&point, &newButtons);
if (m_buttons != newButtons) {
if (newButtons&B_PRIMARY_MOUSE_BUTTON && !(m_buttons&B_PRIMARY_MOUSE_BUTTON)) {
button = GLUT_LEFT_BUTTON;
mouseState = GLUT_DOWN;
} else if (m_buttons&B_PRIMARY_MOUSE_BUTTON && !(newButtons&B_PRIMARY_MOUSE_BUTTON)) {
button = GLUT_LEFT_BUTTON;
mouseState = GLUT_UP;
} else if (newButtons&B_SECONDARY_MOUSE_BUTTON && !(m_buttons&B_SECONDARY_MOUSE_BUTTON)) {
button = GLUT_RIGHT_BUTTON;
mouseState = GLUT_DOWN;
} else if (m_buttons&B_SECONDARY_MOUSE_BUTTON && !(newButtons&B_SECONDARY_MOUSE_BUTTON)) {
button = GLUT_RIGHT_BUTTON;
mouseState = GLUT_UP;
} else if (newButtons&B_TERTIARY_MOUSE_BUTTON && !(m_buttons&B_TERTIARY_MOUSE_BUTTON)) {
button = GLUT_MIDDLE_BUTTON;
mouseState = GLUT_DOWN;
} else if (m_buttons&B_TERTIARY_MOUSE_BUTTON && !(newButtons&B_TERTIARY_MOUSE_BUTTON)) {
button = GLUT_MIDDLE_BUTTON;
mouseState = GLUT_UP;
}
} else {
return; }
m_buttons = newButtons;
if (mouseState == GLUT_DOWN) {
BWindow *w = Window();
GlutMenu *m = __glutGetMenuByNum(menu[button]);
if (m) {
if (gState.menuStatus) {
anyevents = statusEvent = true;
menuNumber = menu[button];
menuStatus = GLUT_MENU_IN_USE;
statusX = (int)point.x;
statusY = (int)point.y;
gBlock.NewEvent();
}
BRect bounds = w->Frame();
point.x += bounds.left;
point.y += bounds.top;
GlutPopUp *bmenu = static_cast<GlutPopUp*>(m->CreateBMenu()); bmenu->point = point;
bmenu->win = this;
thread_id menu_thread = spawn_thread(MenuThread, "menu thread", B_NORMAL_PRIORITY, bmenu);
resume_thread(menu_thread);
return;
}
}
if (mouse) {
anyevents = mouseEvent = true;
mouseX = (int)point.x;
mouseY = (int)point.y;
modifierKeys = 0;
uint32 beMod = modifiers();
if(beMod & B_SHIFT_KEY)
modifierKeys |= GLUT_ACTIVE_SHIFT;
if(beMod & B_CONTROL_KEY)
modifierKeys |= GLUT_ACTIVE_CTRL;
if(beMod & B_OPTION_KEY) {
modifierKeys |= GLUT_ACTIVE_ALT;
}
gBlock.NewEvent();
}
}
void GlutWindow::MouseMoved(BPoint point,
ulong transit, const BMessage *msg)
{
BGLView::MouseMoved(point,transit,msg);
if(transit != B_INSIDE_VIEW) {
if (entry) {
anyevents = entryEvent = true;
gBlock.NewEvent();
}
if (transit == B_ENTERED_VIEW) {
entryState = GLUT_ENTERED;
MakeFocus(); __glutSetCursor(cursor);
} else
entryState = GLUT_LEFT;
}
MouseCheck();
if(m_buttons) {
if(motion) {
anyevents = motionEvent = true;
motionX = (int)point.x;
motionY = (int)point.y;
gBlock.NewEvent();
}
} else {
if(passive) {
anyevents = passiveEvent = true;
passiveX = (int)point.x;
passiveY = (int)point.y;
gBlock.NewEvent();
}
}
}
void GlutWindow::FrameResized(float width, float height)
{
BGLView::FrameResized(width, height);
if (visible) {
anyevents = reshapeEvent = true;
m_width = (int)(width)+1;
m_height = (int)(height)+1;
gBlock.NewEvent();
}
}
void GlutWindow::Draw(BRect updateRect)
{
BGLView::Draw(updateRect);
BRect frame = Frame();
if (m_width != (frame.Width()+1) || m_height != (frame.Height()+1)) {
FrameResized(frame.Width(), frame.Height());
}
Window()->Lock();
if (visible) {
anyevents = displayEvent = true;
gBlock.NewEvent();
}
Window()->Unlock();
}
void GlutWindow::Pulse()
{
BGLView::Pulse();
if (m_buttons) { MouseCheck();
}
}
void GlutWindow::ErrorCallback(GLenum errorCode) {
__glutWarning("GL error: %s", gluErrorString(errorCode));
}
long GlutWindow::MenuThread(void *m) {
GlutPopUp *bmenu = static_cast<GlutPopUp*>(m);
GlutWindow *win = bmenu->win; GlutBMenuItem *result = (GlutBMenuItem*)bmenu->Go(bmenu->point);
win->Window()->Lock();
win->anyevents = win->statusEvent = true;
win->menuStatus = GLUT_MENU_NOT_IN_USE;
win->menuNumber = bmenu->menu;
BPoint cursor;
uint32 buttons;
win->GetMouse(&cursor, &buttons);
win->statusX = (int)cursor.x;
win->statusY = (int)cursor.y;
if(result && result->menu) {
win->menuEvent = true;
win->menuNumber = result->menu; win->menuValue = result->value;
}
win->Window()->Unlock();
gBlock.NewEvent();
delete bmenu;
return 0;
}