OpenGL canvas for Windows, Notifications for main Game, Update checker in Client (+ other client triggered events)

This commit is contained in:
Simon Robertshaw 2012-06-20 13:40:18 +01:00
parent 9769239af6
commit 2be9c92508
18 changed files with 490 additions and 13 deletions

View File

@ -129,6 +129,7 @@ return surface;
int main(int argc, char * argv[]) int main(int argc, char * argv[])
{ {
int elapsedTime = 0, currentTime = 0, lastTime = 0, currentFrame = 0; int elapsedTime = 0, currentTime = 0, lastTime = 0, currentFrame = 0;
unsigned int lastTick = 0;
float fps = 0, delta = 1.0f; float fps = 0, delta = 1.0f;
sdl_scrn = SDLOpen(); sdl_scrn = SDLOpen();
@ -192,6 +193,13 @@ int main(int argc, char * argv[])
engine->Tick(); engine->Tick();
engine->Draw(); engine->Draw();
if(SDL_GetTicks()-lastTick>1000)
{
//Run client tick every second
lastTick = SDL_GetTicks();
Client::Ref().Tick();
}
#ifdef OGLR #ifdef OGLR
blit(); blit();
#else #else

View File

@ -24,8 +24,11 @@
#include "client/SaveInfo.h" #include "client/SaveInfo.h"
#include "ClientListener.h"
Client::Client(): Client::Client():
authUser(0, "") authUser(0, ""),
updateAvailable(false)
{ {
int i = 0; int i = 0;
std::string proxyString(""); std::string proxyString("");
@ -108,6 +111,87 @@ Client::Client():
stampIDs.push_back(data); stampIDs.push_back(data);
} }
stampsLib.close(); stampsLib.close();
//Begin version check
versionCheckRequest = http_async_req_start(NULL, SERVER "/Version.json", NULL, 0, 1);
}
void Client::Tick()
{
//Check status on version check request
if(versionCheckRequest && http_async_req_status(versionCheckRequest))
{
int status;
int dataLength;
char * data = http_async_req_stop(versionCheckRequest, &status, &dataLength);
versionCheckRequest = NULL;
notifyUpdateAvailable();
if(status != 200)
{
if(data)
free(data);
}
else
{
std::istringstream dataStream(data);
try
{
json::Object objDocument;
json::Reader::Read(objDocument, dataStream);
json::Object stableVersion = objDocument["Stable"];
json::Object betaVersion = objDocument["Beta"];
json::Number stableMajor = stableVersion["Major"];
json::Number stableMinor = stableVersion["Minor"];
json::Number stableBuild = stableVersion["Build"];
json::Number betaMajor = betaVersion["Major"];
json::Number betaMinor = betaVersion["Minor"];
json::Number betaBuild = betaVersion["Build"];
#ifdef BETA
if( (betaMajor.Value()>SAVE_VERSION || (betaMinor.Value()>MINOR_VERSION && betaMajor.Value()==SAVE_VERSION) || betaBuild.Value()>BUILD_NUM) ||
(stableMajor.Value()>SAVE_VERSION || (stableMinor.Value()>MINOR_VERSION && stableMajor.Value()==SAVE_VERSION) || stableBuild.Value()>BUILD_NUM))
{
updateAvailable = true;
}
#else
if(stableMajor.Value()>SAVE_VERSION || (stableMinor.Value()>MINOR_VERSION && stableMajor.Value()==SAVE_VERSION) || stableBuild.Value()>BUILD_NUM)
{
updateAvailable = true;
}
#endif
if(updateAvailable)
{
notifyUpdateAvailable();
}
}
catch (json::Exception &e)
{
//Do nothing
}
if(data)
free(data);
}
}
}
void Client::notifyUpdateAvailable()
{
for (std::vector<ClientListener*>::iterator iterator = listeners.begin(), end = listeners.end(); iterator != end; ++iterator)
{
(*iterator)->NotifyUpdateAvailable(this);
}
}
void Client::AddListener(ClientListener * listener)
{
listeners.push_back(listener);
} }
Client::~Client() Client::~Client()

View File

@ -27,8 +27,13 @@ enum RequestStatus {
RequestOkay, RequestFailure RequestOkay, RequestFailure
}; };
class ClientListener;
class Client: public Singleton<Client> { class Client: public Singleton<Client> {
private: private:
void * versionCheckRequest;
bool updateAvailable;
std::string lastError; std::string lastError;
list<string> stampIDs; list<string> stampIDs;
@ -46,13 +51,19 @@ private:
int activeThumbRequestCompleteTimes[IMGCONNS]; int activeThumbRequestCompleteTimes[IMGCONNS];
std::string activeThumbRequestIDs[IMGCONNS]; std::string activeThumbRequestIDs[IMGCONNS];
void updateStamps(); void updateStamps();
void notifyUpdateAvailable();
public: public:
vector<ClientListener*> listeners;
//Config file handle //Config file handle
json::Object configDocument; json::Object configDocument;
Client(); Client();
~Client(); ~Client();
void AddListener(ClientListener * listener);
RequestStatus ExecVote(int saveID, int direction); RequestStatus ExecVote(int saveID, int direction);
RequestStatus UploadSave(SaveInfo * save); RequestStatus UploadSave(SaveInfo * save);
@ -82,6 +93,7 @@ public:
std::string GetLastError() { std::string GetLastError() {
return lastError; return lastError;
} }
void Tick();
}; };
#endif // CLIENT_H #endif // CLIENT_H

View File

@ -0,0 +1,22 @@
/*
* ClientListener.h
*
* Created on: Jun 19, 2012
* Author: Simon
*/
#ifndef CLIENTLISTENER_H_
#define CLIENTLISTENER_H_
class Client;
class ClientListener
{
public:
ClientListener() {}
virtual ~ClientListener() {}
virtual void NotifyUpdateAvailable(Client * sender) {}
};
#endif /* CLIENTLISTENER_H_ */

View File

@ -17,7 +17,7 @@ public:
EllipseBrush(ui::Point size_): EllipseBrush(ui::Point size_):
Brush(size_) Brush(size_)
{ {
SetRadius(size_);
}; };
virtual void GenerateBitmap() virtual void GenerateBitmap()
{ {

View File

@ -12,6 +12,7 @@
#include "dialogues/ErrorMessage.h" #include "dialogues/ErrorMessage.h"
#include "GameModelException.h" #include "GameModelException.h"
#include "simulation/Air.h" #include "simulation/Air.h"
#include "Notification.h"
using namespace std; using namespace std;
@ -132,6 +133,7 @@ GameController::GameController():
//commandInterface->AttachGameModel(gameModel); //commandInterface->AttachGameModel(gameModel);
//sim = new Simulation(); //sim = new Simulation();
Client::Ref().AddListener(this);
} }
GameController::~GameController() GameController::~GameController()
@ -624,3 +626,26 @@ std::string GameController::ElementResolve(int type)
return ""; return "";
} }
void GameController::NotifyUpdateAvailable(Client * sender)
{
class UpdateNotification : public Notification
{
GameController * c;
public:
UpdateNotification(GameController * c, std::string message) : c(c), Notification(message) {}
virtual ~UpdateNotification() {}
virtual void Action()
{
c->RemoveNotification(this);
}
};
gameModel->AddNotification(new UpdateNotification(this, "An Update is available"));
}
void GameController::RemoveNotification(Notification * notification)
{
gameModel->RemoveNotification(notification);
}

View File

@ -16,15 +16,17 @@
//#include "cat/TPTScriptInterface.h" //#include "cat/TPTScriptInterface.h"
#include "cat/LuaScriptInterface.h" #include "cat/LuaScriptInterface.h"
#include "options/OptionsController.h" #include "options/OptionsController.h"
#include "client/ClientListener.h"
#include "Menu.h" #include "Menu.h"
using namespace std; using namespace std;
class Notification;
class GameModel; class GameModel;
class GameView; class GameView;
class CommandInterface; class CommandInterface;
class ConsoleController; class ConsoleController;
class GameController class GameController: public ClientListener
{ {
private: private:
//Simulation * sim; //Simulation * sim;
@ -101,6 +103,10 @@ public:
void LoadClipboard(); void LoadClipboard();
void LoadStamp(); void LoadStamp();
void RemoveNotification(Notification * notification);
virtual void NotifyUpdateAvailable(Client * sender);
}; };
#endif // GAMECONTROLLER_H #endif // GAMECONTROLLER_H

View File

@ -513,6 +513,39 @@ deque<string> GameModel::GetLog()
return consoleLog; return consoleLog;
} }
std::vector<Notification*> GameModel::GetNotifications()
{
return notifications;
}
void GameModel::AddNotification(Notification * notification)
{
notifications.push_back(notification);
notifyNotificationsChanged();
}
void GameModel::RemoveNotification(Notification * notification)
{
for(std::vector<Notification*>::iterator iter = notifications.begin(); iter != notifications.end(); ++iter)
{
if(*iter == notification)
{
notifications.erase(iter);
delete *iter;
break;
}
}
notifyNotificationsChanged();
}
void GameModel::notifyNotificationsChanged()
{
for(std::vector<GameView*>::iterator iter = observers.begin(); iter != observers.end(); ++iter)
{
(*iter)->NotifyNotificationsChanged(this);
}
}
void GameModel::notifyColourSelectorColourChanged() void GameModel::notifyColourSelectorColourChanged()
{ {
for(int i = 0; i < observers.size(); i++) for(int i = 0; i < observers.size(); i++)

View File

@ -10,6 +10,7 @@
#include "GameView.h" #include "GameView.h"
#include "Brush.h" #include "Brush.h"
#include "client/User.h" #include "client/User.h"
#include "Notification.h"
#include "Tool.h" #include "Tool.h"
#include "Menu.h" #include "Menu.h"
@ -32,6 +33,7 @@ public:
class GameModel class GameModel
{ {
private: private:
vector<Notification*> notifications;
//int clipboardSize; //int clipboardSize;
//unsigned char * clipboardData; //unsigned char * clipboardData;
GameSave * stamp; GameSave * stamp;
@ -67,6 +69,7 @@ private:
void notifyPlaceSaveChanged(); void notifyPlaceSaveChanged();
void notifyColourSelectorColourChanged(); void notifyColourSelectorColourChanged();
void notifyColourSelectorVisibilityChanged(); void notifyColourSelectorVisibilityChanged();
void notifyNotificationsChanged();
void notifyLogChanged(string entry); void notifyLogChanged(string entry);
public: public:
GameModel(); GameModel();
@ -120,6 +123,10 @@ public:
GameSave * GetClipboard(); GameSave * GetClipboard();
GameSave * GetStamp(); GameSave * GetStamp();
GameSave * GetPlaceSave(); GameSave * GetPlaceSave();
std::vector<Notification*> GetNotifications();
void AddNotification(Notification * notification);
void RemoveNotification(Notification * notification);
}; };
#endif // GAMEMODEL_H #endif // GAMEMODEL_H

View File

@ -846,6 +846,58 @@ void GameView::DoDraw()
c->Tick(); c->Tick();
} }
void GameView::NotifyNotificationsChanged(GameModel * sender)
{
class NotificationButtonAction : public ui::ButtonAction
{
GameView * v;
Notification * notification;
public:
NotificationButtonAction(GameView * v, Notification * notification) : v(v), notification(notification) { }
void ActionCallback(ui::Button * sender)
{
notification->Action();
//v->c->RemoveNotification(notification);
}
};
class CloseNotificationButtonAction : public ui::ButtonAction
{
GameView * v;
Notification * notification;
public:
CloseNotificationButtonAction(GameView * v, Notification * notification) : v(v), notification(notification) { }
void ActionCallback(ui::Button * sender)
{
v->c->RemoveNotification(notification);
}
};
for(std::vector<ui::Component*>::iterator iter = notificationComponents.begin(); iter != notificationComponents.end(); ++iter) {
RemoveComponent(*iter);
delete *iter;
}
notificationComponents.clear();
std::vector<Notification*> notifications = sender->GetNotifications();
int currentY = YRES-17;
for(std::vector<Notification*>::iterator iter = notifications.begin(); iter != notifications.end(); ++iter)
{
int width = (Graphics::textwidth((*iter)->Message.c_str()))+8;
ui::Button * tempButton = new ui::Button(ui::Point(XRES-width-22, currentY), ui::Point(width, 15), (*iter)->Message);
tempButton->SetActionCallback(new NotificationButtonAction(this, *iter));
AddComponent(tempButton);
notificationComponents.push_back(tempButton);
tempButton = new ui::Button(ui::Point(XRES-20, currentY), ui::Point(15, 15));
tempButton->SetIcon(IconDelete);
tempButton->SetActionCallback(new CloseNotificationButtonAction(this, *iter));
AddComponent(tempButton);
notificationComponents.push_back(tempButton);
currentY -= 17;
}
}
void GameView::NotifyZoomChanged(GameModel * sender) void GameView::NotifyZoomChanged(GameModel * sender)
{ {

View File

@ -43,6 +43,7 @@ private:
//UI Elements //UI Elements
vector<ui::Button*> menuButtons; vector<ui::Button*> menuButtons;
vector<ToolButton*> toolButtons; vector<ToolButton*> toolButtons;
vector<ui::Component*> notificationComponents;
deque<string> logEntries; deque<string> logEntries;
float lastLogEntry; float lastLogEntry;
ui::Button * searchButton; ui::Button * searchButton;
@ -99,6 +100,7 @@ public:
void NotifyColourSelectorVisibilityChanged(GameModel * sender); void NotifyColourSelectorVisibilityChanged(GameModel * sender);
void NotifyColourSelectorColourChanged(GameModel * sender); void NotifyColourSelectorColourChanged(GameModel * sender);
void NotifyPlaceSaveChanged(GameModel * sender); void NotifyPlaceSaveChanged(GameModel * sender);
void NotifyNotificationsChanged(GameModel * sender);
void NotifyLogChanged(GameModel * sender, string entry); void NotifyLogChanged(GameModel * sender, string entry);
virtual void OnMouseMove(int x, int y, int dx, int dy); virtual void OnMouseMove(int x, int y, int dx, int dy);
virtual void OnMouseDown(int x, int y, unsigned button); virtual void OnMouseDown(int x, int y, unsigned button);

23
src/game/Notification.h Normal file
View File

@ -0,0 +1,23 @@
/*
* Notification.h
*
* Created on: Jun 20, 2012
* Author: Simon
*/
#ifndef NOTIFICATION_H_
#define NOTIFICATION_H_
#include <string>
class Notification
{
public:
Notification(std::string message) : Message(message) {}
virtual ~Notification() {};
std::string Message;
virtual void Action() { }
};
#endif /* NOTIFICATION_H_ */

View File

@ -21,7 +21,8 @@ Engine::Engine():
windows(stack<Window*>()), windows(stack<Window*>()),
lastBuffer(NULL), lastBuffer(NULL),
prevBuffers(stack<pixel*>()), prevBuffers(stack<pixel*>()),
windowTargetPosition(0, 0) windowTargetPosition(0, 0),
FrameIndex(0)
{ {
} }
@ -185,6 +186,8 @@ void Engine::Draw()
sprintf(fpsText, "FPS: %.2f, Delta: %.3f", fps, dt); sprintf(fpsText, "FPS: %.2f, Delta: %.3f", fps, dt);
ui::Engine::Ref().g->drawtext(10, 10, fpsText, 255, 255, 255, 255); ui::Engine::Ref().g->drawtext(10, 10, fpsText, 255, 255, 255, 255);
g->Finalise(); g->Finalise();
FrameIndex++;
FrameIndex %= 7200;
} }
void Engine::SetFps(float fps) void Engine::SetFps(float fps)

View File

@ -54,6 +54,8 @@ namespace ui
inline Window* GetWindow() { return state_; } inline Window* GetWindow() { return state_; }
float FpsLimit; float FpsLimit;
Graphics * g; Graphics * g;
unsigned int FrameIndex;
private: private:
float dt; float dt;
float fps; float fps;

View File

@ -0,0 +1,169 @@
#if defined(USE_JNI) && defined(WIN32)
#include "OpenGLCanvasWin32.h"
static jfieldID ctxID = NULL;
int defaultPixelFormat(PIXELFORMATDESCRIPTOR* pfd)
{
::ZeroMemory( pfd, sizeof( PIXELFORMATDESCRIPTOR ) );
pfd->nSize = sizeof( PIXELFORMATDESCRIPTOR );
pfd->nVersion = 1;
pfd->dwFlags = PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd->iPixelType = PFD_TYPE_RGBA;
pfd->cColorBits = 24;
pfd->cDepthBits = 16;
pfd->iLayerType = PFD_MAIN_PLANE;
return 0;
}
HGLRC ensureContext(JAWT_Win32DrawingSurfaceInfo* dsi_win, HGLRC hRC) {
if (!hRC) {
int iFormat;
PIXELFORMATDESCRIPTOR pfd;
defaultPixelFormat(&pfd);
iFormat = ChoosePixelFormat( dsi_win->hdc, &pfd );
SetPixelFormat( dsi_win->hdc, iFormat, &pfd );
hRC = wglCreateContext( dsi_win->hdc );
}
if (1 && wglGetCurrentDC() != dsi_win->hdc) {
wglMakeCurrent( dsi_win->hdc, hRC );
}
return hRC;
}
ContextInfo* getContext(JNIEnv *env, jobject canvas)
{
ContextInfo *ci;
if (!ctxID) {
jclass cls = env->GetObjectClass(canvas);
ctxID = env->GetFieldID(cls, "openGLContext", "J");
}
ci = (ContextInfo *)(long)(env->GetLongField(canvas, ctxID));
if (!ci) {
ci = (ContextInfo *)calloc(sizeof(ContextInfo), 1);
ci->awt = (JAWT *)calloc(sizeof(JAWT), 1);
env->SetLongField(canvas, ctxID, (jlong)(long)ci);
}
return ci;
}
void freeContext(JNIEnv *env, jobject canvas, ContextInfo* ci)
{
if (ci) {
free(ci->awt);
free(ci);
env->SetLongField(canvas, ctxID, 0L);
}
}
JNIEXPORT jboolean JNICALL Java_OpenGLCanvas_beginOpenGL(JNIEnv *env, jobject canvas)
{
jint lock;
ContextInfo *ci = getContext(env, canvas);
// Get the drawing surface. This can be safely cached -- not in win32
// Anything below the DS (DSI, contexts, etc)
// can possibly change/go away and should not be cached.
ci->ds = ci->awt->GetDrawingSurface(env, canvas);
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
}
assert(ci->ds != NULL);
// Lock the drawing surface
// You must lock EACH TIME before drawing
lock = ci->ds->Lock(ci->ds);
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
}
assert((lock & JAWT_LOCK_ERROR) == 0);
// Get the drawing surface info
ci->dsi = ci->ds->GetDrawingSurfaceInfo(ci->ds);
// Check DrawingSurfaceInfo. This can be NULL on Mac OS X
// if the windowing system is not ready
if (ci->dsi != NULL) {
// Get the platform-specific drawing info
// We will use this to get at Cocoa and CoreGraphics
// See <JavaVM/jawt_md.h>
ci->dsi_win = (JAWT_Win32DrawingSurfaceInfo*)ci->dsi->platformInfo;
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
}
// Get the corresponding peer from the caller canvas
ci->hRC = ensureContext(ci->dsi_win, ci->hRC);
return JNI_TRUE;
}
return JNI_FALSE;
}
JNIEXPORT void JNICALL Java_OpenGLCanvas_endOpenGL(JNIEnv *env, jobject canvas)
{
ContextInfo *ci = getContext(env, canvas);
SwapBuffers( ci->dsi_win->hdc );
// Free the DrawingSurfaceInfo
ci->ds->FreeDrawingSurfaceInfo(ci->dsi);
if (env->ExceptionOccurred()){
env->ExceptionDescribe();
}
// Unlock the drawing surface
// You must unlock EACH TIME when done drawing
ci->ds->Unlock(ci->ds);
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
}
// Free the drawing surface (if not caching it)
ci->awt->FreeDrawingSurface(ci->ds);
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
}
}
JNIEXPORT void JNICALL Java_OpenGLCanvas_updateOpenGL(JNIEnv *env, jobject canvas)
{
ContextInfo *ci = getContext(env, canvas);
wglMakeCurrent( ci->dsi_win->hdc, ci->hRC );
}
JNIEXPORT void JNICALL Java_OpenGLCanvas_allocOpenGL(JNIEnv *env, jobject canvas)
{
ContextInfo *ci = getContext(env, canvas);
jboolean result = JNI_FALSE;
// get the AWT
ci->awt->version = JAWT_VERSION_1_4;
result = JAWT_GetAWT(env, ci->awt);
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
}
assert(result != JNI_FALSE);
}
JNIEXPORT void JNICALL Java_OpenGLCanvas_releaseOpenGL(JNIEnv *env, jobject canvas)
{
ContextInfo *ci = getContext(env, canvas);
if (ci->hRC) {
wglDeleteContext(ci->hRC);
}
freeContext(env, canvas, ci);
}
#endif

View File

@ -0,0 +1,35 @@
#ifdef USE_JNI
#import <jawt_md.h>
#include <windows.h>
#include <assert.h>
#include <gl/gl.h>
int defaultPixelFormat(PIXELFORMATDESCRIPTOR* pfd);
HGLRC ensureContext(JAWT_Win32DrawingSurfaceInfo* dsi_win, HGLRC hRC);
typedef struct {
JAWT* awt;
JAWT_DrawingSurface* ds;
JAWT_DrawingSurfaceInfo* dsi;
JAWT_Win32DrawingSurfaceInfo* dsi_win;
HGLRC hRC;
} ContextInfo;
ContextInfo* getContext(JNIEnv *env, jobject canvas);
void freeContext(JNIEnv *env, jobject canvas, ContextInfo* ci);
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jboolean JNICALL Java_OpenGLCanvas_beginOpenGL(JNIEnv *env, jobject canvas);
JNIEXPORT void JNICALL Java_OpenGLCanvas_endOpenGL(JNIEnv *env, jobject canvas);
JNIEXPORT void JNICALL Java_OpenGLCanvas_updateOpenGL(JNIEnv *env, jobject canvas);
JNIEXPORT void JNICALL Java_OpenGLCanvas_allocOpenGL(JNIEnv *env, jobject canvas);
JNIEXPORT void JNICALL Java_OpenGLCanvas_releaseOpenGL(JNIEnv *env, jobject canvas);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,4 +1,4 @@
#if defined(USE_JNI) && defined(MACOSX) #if defined(USE_JNI)
#include <time.h> #include <time.h>
#include <iostream> #include <iostream>
@ -8,9 +8,6 @@
#include "Config.h" #include "Config.h"
#include "PowderToyJava.h" #include "PowderToyJava.h"
#include "Graphics.h" #include "Graphics.h"
#if defined(LIN32) || defined(LIN64)
#include "icon.h"
#endif
#include "game/GameController.h" #include "game/GameController.h"
@ -24,8 +21,6 @@ float fps = 0, delta = 1.0f;
JNIEXPORT void JNICALL Java_PowderToy_initialise(JNIEnv * env, jobject canvas) JNIEXPORT void JNICALL Java_PowderToy_initialise(JNIEnv * env, jobject canvas)
{ {
//InitWindowMac(env, canvas);
ui::Engine::Ref().g = new Graphics(); ui::Engine::Ref().g = new Graphics();
engine = &ui::Engine::Ref(); engine = &ui::Engine::Ref();

View File

@ -1,5 +1,4 @@
//#include </System/Library/Frameworks/JavaVM.framework/Headers/jni.h> #include <jni.h>
#include </System/Library/Frameworks/JavaVM.framework/Headers/jni.h>
#ifndef POWDERTOYJAVA #ifndef POWDERTOYJAVA
#define POWDERTOYJAVA #define POWDERTOYJAVA