& button) = 0;
void setInputCaptureCount(int c) {
if ((m_inputCaptureCount > 0) && (c <= 0)) {
// Release mouse
setInputCapture(false);
} else if ((m_inputCaptureCount <= 0) && (c > 0)) {
// Capture mouse
setInputCapture(true);
}
// Set this variable after the setInputCapture statements since
// they corrupt its value.
m_inputCaptureCount = c;
}
/**
If the count is 1 or greater, then the keyboard and mouse focus is captured,
locking the mouse to the client area of this window. The use of a count instead of
an explicit capture/release API allows multiple parts of a program to capture input
without accidentally releasing and enclosing capture.
*/
int inputCaptureCount() const {
return m_inputCaptureCount;
}
virtual void incInputCaptureCount() {
setInputCaptureCount(inputCaptureCount() + 1);
}
virtual void decInputCaptureCount() {
setInputCaptureCount(inputCaptureCount() - 1);
}
void setMouseHideCount(int c) {
if ((m_mouseHideCount > 0) && (c <= 0)) {
// Release mouse
setMouseVisible(true);
} else if ((m_mouseHideCount <= 0) && (c > 0)) {
// Capture mouse
setMouseVisible(false);
}
// Set this variable after the setMouseVisible statements since
// they corrupt its value.
m_mouseHideCount = c;
}
/**
If the count is 1 or greater, then the keyboard and mouse focus is captured,
locking the mouse to the client area of this window. The use of a count instead of
an explicit capture/release API allows multiple parts of a program to capture input
without accidentally releasing and enclosing capture.
*/
int mouseHideCount() const {
return m_mouseHideCount;
}
virtual void incMouseHideCount() {
setMouseHideCount(mouseHideCount() + 1);
}
virtual void decMouseHideCount() {
setMouseHideCount(mouseHideCount() - 1);
}
/** Windows for which this is true require a program
to hand control of the main loop to GWindow::startMainLoop.
The program's functionality may then be implemented through
the "loop body" function.
That is, if requiresMainLoop returns true, you must use
the following structure:
void doEvents() {
GEvent e;
while (window->pollEvent(e)) {
... // Event handling
}
}
void doGraphics() {
renderDevice->beginFrame();
renderDevice->clear(true, true, true);
... // draw stuff
renderDevice->endFrame();
}
void loopBody(void*) {
// all per-frame code; event-handling, physics, networking, AI, etc.
doEvents();
doLogic();
doNetwork();
doAI();
doGraphics();
// To end the program, invoke window->popLoopBody
}
window->pushLoopBody(callback, NULL);
window->runMainLoop(); // doesn't return
When requiresMainLoop returns false, you may use either the
above structure or the following one (which puts you in more
control of when graphics vs. other code is executed):
while (true) {
doEvents();
doLogic();
doNetwork();
doAI();
doGraphics();
}
This design is necessary because some underlying Window APIs
(e.g. ActiveX, GLUT) enforce an event-driven structure.
*/
virtual bool requiresMainLoop() const {
return false;
}
/** Pushes a function onto the stack of functions called by runMainLoop */
virtual void pushLoopBody(void (*body)(void*), void* arg) {
loopBodyStack.push(LoopBody(body, arg));
}
/** Invokes GApplet::beginRun after the applet is on the stack. */
virtual void pushLoopBody(GApp* app);
/** Pops a loop body off the stack. If the loop body was a GApplet,
invokes GApplet::endRun on it. If the loop body was a GApp2,
invokes GApp2::endRun on it.*/
virtual void popLoopBody();
/**
Executes an event loop, invoking callback repeatedly. Put everything
that you want to execute once per frame into the callback function.
It is guaranteed safe to call pollEvents and all other GWindow methods
from the callback function.
The default implementation (for requiresMainLoop() == false GWindows)
just calls the callback continuously. Subclasses should use the
notDone() and executeLoopBody() functions.
*/
virtual void runMainLoop() {
alwaysAssertM(requiresMainLoop() == false,
"This GWindow implementation failed to overwrite runMainLoop "
"even though it requires a main loop.");
while (notDone()) {
executeLoopBody();
}
}
private:
/** Tracks the current GWindow. If back-to-back calls are made to make
the same GWindow current, they are ignored. */
static const GWindow* m_current;
friend class RenderDevice;
class RenderDevice* m_renderDevice;
protected:
GWindow() : m_inputCaptureCount(0), m_mouseHideCount(0), m_renderDevice(NULL) {}
/** Override this with the glMakeCurrent call appropriate for your window.*/
virtual void reallyMakeCurrent() const {
}
public:
/** Closes the window and frees any resources associated with it.
When subclassing, put any shutdown code (e.g. SDL_Quit()) in
your destructor. Put initialization code (e.g. SDL_Init()) in
the constructor. */
virtual ~GWindow() {
if (m_current == this) {
// Once this window is destroyed, there will be no current context.
m_current = NULL;
}
}
/**
If a RenderDevice has been created and initialized for this window,
returns that renderDevice. Otherwise returns NULL.
*/
inline RenderDevice* renderDevice() const {
return m_renderDevice;
}
inline static const GWindow* current() {
return m_current;
}
/**
Makes the OpenGL context of this window current. If you have multiple
windows, call this before rendering to one of them.
beta
*/
inline void makeCurrent() const {
if (m_current != this) {
reallyMakeCurrent();
m_current = this;
}
}
};
}
#endif