Skip to content

Commit

Permalink
Refactor|Client|Server: Removed loop callbacks, added BusyWidget
Browse files Browse the repository at this point in the history
Instead of loop callbacks from LegacyCore, the equivalent functionality
is now handled as part of the CanvasWindow's widget tree. In the case
of the server, which has no UI, loop iteration is run in ServerSystem.

At present time, the best way to model the client UI is to have two
root widgets, one for the normal UI and one for the busy UI.

Todo for later: Merge the busy mode visualization into BusyWidget.
  • Loading branch information
skyjake committed Feb 25, 2013
1 parent 75f04ae commit d28d443
Show file tree
Hide file tree
Showing 21 changed files with 399 additions and 257 deletions.
2 changes: 2 additions & 0 deletions doomsday/client/client.pro
Expand Up @@ -340,6 +340,7 @@ DENG_HEADERS += \
include/ui/b_main.h \
include/ui/b_util.h \
include/ui/busyvisual.h \
include/ui/busywidget.h \
include/ui/canvas.h \
include/ui/canvaswindow.h \
include/ui/dd_input.h \
Expand Down Expand Up @@ -620,6 +621,7 @@ SOURCES += \
src/ui/b_main.cpp \
src/ui/b_util.cpp \
src/ui/busyvisual.cpp \
src/ui/busywidget.cpp \
src/ui/canvas.cpp \
src/ui/canvaswindow.cpp \
src/ui/dd_input.cpp \
Expand Down
8 changes: 1 addition & 7 deletions doomsday/client/include/busymode.h
Expand Up @@ -37,10 +37,6 @@

#include "dd_share.h"

#ifdef __cplusplus
extern "C" {
#endif

/// @return @c true if specified thread is the current busy task worker.
boolean BusyMode_IsWorkerThread(uint threadId);

Expand All @@ -50,8 +46,6 @@ boolean BusyMode_InWorkerThread(void);
/// @return Current busy task, else @c NULL.
BusyTask* BusyMode_CurrentTask(void);

#ifdef __cplusplus
} // extern "C"
#endif
void BusyMode_Loop(void);

#endif /// LIBDENG_CORE_BUSYMODE_H
3 changes: 3 additions & 0 deletions doomsday/client/include/clientapp.h
Expand Up @@ -38,6 +38,9 @@ class ClientApp : public de::GuiApp
*/
void initialize();

void preFrame();
void postFrame();

public:
static ClientApp &app();
static ServerLink &serverLink();
Expand Down
5 changes: 0 additions & 5 deletions doomsday/client/include/dd_loop.h
Expand Up @@ -42,11 +42,6 @@ void DD_RegisterLoop(void);
*/
int DD_GameLoop(void);

/**
* Called periodically while the game loop is running.
*/
void DD_GameLoopCallback(void);

/**
* Runs one or more tics depending on how much time has passed since the
* previous call to this function. This gets called once per each main loop
Expand Down
41 changes: 41 additions & 0 deletions doomsday/client/include/ui/busywidget.h
@@ -0,0 +1,41 @@
/** @file busywidget.h
*
* @authors Copyright (c) 2013 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

#ifndef CLIENT_BUSYWIDGET_H
#define CLIENT_BUSYWIDGET_H

#include "guiwidget.h"

/**
* Widget that takes care of the UI while busy mode is active.
*/
class BusyWidget : public GuiWidget
{
public:
BusyWidget(de::String const &name = "");
~BusyWidget();

void update();
void draw();
bool handleEvent(de::Event const &event);

private:
DENG2_PRIVATE(d)
};

#endif // CLIENT_BUSYWIDGET_H
11 changes: 7 additions & 4 deletions doomsday/client/include/ui/canvas.h
Expand Up @@ -26,10 +26,13 @@
# error "canvas.h requires __CLIENT__"
#endif

struct image_s; // see image.h
#include <de/Observers>
#include <de/libdeng2.h>

#include <QGLWidget>
#include <de/libdeng2.h>

struct image_s; // see image.h
class CanvasWindow;

#ifdef Q_WS_X11
//# define LIBDENG_CANVAS_TRACK_WITH_MOUSE_MOVE_EVENTS
Expand All @@ -52,7 +55,7 @@ class Canvas : public QGLWidget
Q_OBJECT

public:
explicit Canvas(QWidget *parent = 0, QGLWidget* shared = 0);
explicit Canvas(CanvasWindow *parent, QGLWidget* shared = 0);
~Canvas();

/**
Expand All @@ -72,7 +75,7 @@ class Canvas : public QGLWidget
*
* @param canvasDrawFunc Callback.
*/
void setDrawFunc(void (*canvasDrawFunc)(Canvas&));
//void setDrawFunc(void (*canvasDrawFunc)(Canvas&));

/**
* Sets the callback function that is called when the window's focus state changes.
Expand Down
32 changes: 32 additions & 0 deletions doomsday/client/include/ui/canvaswindow.h
Expand Up @@ -39,12 +39,29 @@ class CanvasWindow : public QMainWindow
{
Q_OBJECT

public:
enum Mode
{
Normal,
Busy
};

public:
explicit CanvasWindow(QWidget *parent = 0);
~CanvasWindow();

de::RootWidget &root();

/**
* Sets the operating mode of the window. In Busy mode, the normal
* widgets of the window will be replaced with a single BusyWidget.
*
* @param mode Mode.
*/
void setMode(Mode const &mode);

float frameRate() const;

/**
* Recreates the contained Canvas with an update GL format.
* The context is shared with the old Canvas.
Expand Down Expand Up @@ -73,6 +90,21 @@ class CanvasWindow : public QMainWindow
void resizeEvent(QResizeEvent *);
void hideEvent(QHideEvent *);

/**
* Called from Canvas when it is ready for OpenGL drawing (visible).
*
* @param canvas Canvas.
*/
void canvasReady(Canvas &canvas);

/**
* Called from Canvas when a GL draw is requested. The UI widgets will be
* rendered onto the canvas.
*
* @param canvas Canvas to paint.
*/
void paintCanvas(Canvas &canvas);

/**
* Must be called before any canvas windows are created. Defines the
* default OpenGL format settings for the contained canvases.
Expand Down
2 changes: 2 additions & 0 deletions doomsday/client/include/ui/window.h
Expand Up @@ -218,13 +218,15 @@ void Window_Show(Window* wnd, boolean show);
*/
boolean Window_ChangeAttributes(Window* wnd, int* attribs);

#if 0
/**
* Sets the function who will draw the contents of the window when needed.
*
* @param win Window instance.
* @param drawFunc Callback function.
*/
void Window_SetDrawFunc(Window* win, void (*drawFunc)(void));
#endif

/**
* Request drawing the contents of the window as soon as possible.
Expand Down
43 changes: 13 additions & 30 deletions doomsday/client/src/busymode.cpp
Expand Up @@ -37,7 +37,8 @@

#ifdef __CLIENT__

static void BusyMode_Loop(void);
#include "clientapp.h"

static void BusyMode_Exit(void);

static QEventLoop* eventLoop;
Expand Down Expand Up @@ -150,11 +151,6 @@ static void beginTask(BusyTask* task)
busyThread = Sys_StartThread(busyTask->worker, busyTask->workerData);
Thread_SetCallback(busyThread, busyWorkerTerminated);

// Switch the engine loop and window to the busy mode.
LegacyCore_SetLoopFunc(BusyMode_Loop);

Window_SetDrawFunc(Window_Main(), BusyVisual_Render);

busyTask->_startTime = Timer_RealSeconds();
}

Expand All @@ -171,9 +167,6 @@ static void endTask(BusyTask* task)
Con_Message("Con_Busy: Was busy for %.2lf seconds.\n", busyTime);
}

// The window drawer will be restored later to the appropriate function.
Window_SetDrawFunc(Window_Main(), 0);

if(busyTaskEndedWithError)
{
Con_AbnormalShutdown(busyError);
Expand Down Expand Up @@ -245,17 +238,14 @@ static void preBusySetup(int initialMode)

busyWasIgnoringInput = DD_IgnoreInput(true);

// Save the present loop.
LegacyCore_PushLoop();

// Set up loop for busy mode.
LegacyCore_SetLoopRate(60);
LegacyCore_SetLoopFunc(NULL); // don't call main loop's func while busy

BusyVisual_PrepareFont();
BusyVisual_LoadTextures();

Window_SetDrawFunc(Window_Main(), 0);
// Limit frame rate to 60, no point pushing it any faster while busy.
ClientApp::app().loop().setRate(60);

// Switch the window to busy mode UI.
Window_CanvasWindow(Window_Main())->setMode(CanvasWindow::Busy);

#else
DENG_UNUSED(initialMode);
Expand All @@ -271,11 +261,11 @@ static void postBusyCleanup(void)

BusyVisual_ReleaseTextures();

// Restore old loop.
LegacyCore_PopLoop();
// Back to unlimited frame rate.
ClientApp::app().loop().setRate(0);

// Resume drawing with the game loop drawer.
Window_SetDrawFunc(Window_Main(), !Sys_IsShuttingDown()? DD_GameLoopDrawer : 0);
// Switch the window to normal UI.
Window_CanvasWindow(Window_Main())->setMode(CanvasWindow::Normal);
#endif
}

Expand Down Expand Up @@ -407,7 +397,7 @@ static void stopEventLoopWithValue(int result)
{
// After the event loop is gone, we don't want any loop callbacks until the
// busy state has been properly torn down.
LegacyCore_SetLoopFunc(0);
//LegacyCore_SetLoopFunc(0);

DENG_ASSERT(eventLoop != 0);
eventLoop->exit(result);
Expand Down Expand Up @@ -438,16 +428,11 @@ static void BusyMode_Exit(void)
* The busy loop callback function. Called periodically in the main (UI) thread
* while the busy worker is running.
*/
static void BusyMode_Loop(void)
void BusyMode_Loop(void)
{
boolean canUpload = !(busyTask->mode & BUSYF_NO_UPLOADS);
timespan_t oldTime;

Garbage_Recycle();

// Make sure the audio system gets regularly updated.
S_StartFrame();

// Post and discard all input events.
DD_ProcessEvents(0);
DD_ProcessSharpEvents(0);
Expand All @@ -460,8 +445,6 @@ static void BusyMode_Loop(void)
GL_ProcessDeferredTasks(15);
}

S_EndFrame();

// We accumulate time in the busy loop so that the animation of a task
// sequence doesn't jump around but remains continuous.
oldTime = busyTime;
Expand Down

0 comments on commit d28d443

Please sign in to comment.