This is a modified version of this patch:
[blender.git] / source / gameengine / GamePlayer / ghost / GPG_Application.cpp
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  * GHOST Blender Player application implementation file.
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #ifdef WIN32
39         #pragma warning (disable:4786) // suppress stl-MSVC debug info warning
40         #include <windows.h>
41 #endif
42
43 #ifdef __APPLE__
44 #define GL_GLEXT_LEGACY 1
45 #include <OpenGL/gl.h>
46 #include <OpenGL/glu.h>
47 #else
48 #include <GL/gl.h>
49 #if defined(__sun__) && !defined(__sparc__)
50 #include <mesa/glu.h>
51 #else
52 #include <GL/glu.h>
53 #endif
54 #endif
55
56 #include "GPG_Application.h"
57
58 #include <iostream>
59 #include <MT_assert.h>
60
61 /**********************************
62  * Begin Blender include block
63  **********************************/
64 #ifdef __cplusplus
65 extern "C"
66 {
67 #endif  // __cplusplus
68 #include "BLI_blenlib.h"
69 #include "BLO_readfile.h"
70 #include "BKE_global.h"
71 #include "BKE_main.h"
72 #ifdef __cplusplus
73 }
74 #endif // __cplusplus
75 /**********************************
76  * End Blender include block
77  **********************************/
78
79
80 #include "SYS_System.h"
81 #include "KX_KetsjiEngine.h"
82
83 // include files needed by "KX_BlenderSceneConverter.h"
84 #include "GEN_Map.h"
85 #include "SCA_IActuator.h"
86 #include "RAS_MeshObject.h"
87 #include "RAS_OpenGLRasterizer.h"
88 #include "RAS_VAOpenGLRasterizer.h"
89 #include "RAS_ListRasterizer.h"
90 #include "RAS_GLExtensionManager.h"
91 #include "KX_PythonInit.h"
92 #include "KX_PyConstraintBinding.h"
93 #include "BL_Material.h" // MAXTEX
94
95 #include "KX_BlenderSceneConverter.h"
96 #include "NG_LoopBackNetworkDeviceInterface.h"
97 #include "SND_DeviceManager.h"
98
99 #include "GPC_MouseDevice.h"
100 #include "GPC_RenderTools.h"
101 #include "GPG_Canvas.h" 
102 #include "GPG_KeyboardDevice.h"
103 #include "GPG_System.h"
104
105 #include "STR_String.h"
106
107 #include "GHOST_ISystem.h"
108 #include "GHOST_IEvent.h"
109 #include "GHOST_IEventConsumer.h"
110 #include "GHOST_IWindow.h"
111 #include "GHOST_Rect.h"
112
113
114 static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time);
115
116 static GHOST_ISystem* fSystem = 0;
117 static const int kTimerFreq = 10;
118
119 GPG_Application::GPG_Application(GHOST_ISystem* system, struct Main* maggie, STR_String startSceneName)
120         : m_startSceneName(startSceneName), 
121           m_maggie(maggie),
122           m_exitRequested(0),
123           m_system(system), 
124           m_mainWindow(0), 
125           m_frameTimer(0), 
126           m_cursor(GHOST_kStandardCursorFirstCursor),
127           m_engineInitialized(0), 
128           m_engineRunning(0), 
129           m_ketsjiengine(0),
130           m_kxsystem(0), 
131           m_keyboard(0), 
132           m_mouse(0), 
133           m_canvas(0), 
134           m_rendertools(0), 
135           m_rasterizer(0), 
136           m_sceneconverter(0),
137           m_networkdevice(0), 
138           m_audiodevice(0),
139           m_blendermat(0)
140 {
141         fSystem = system;
142 }
143
144
145
146 GPG_Application::~GPG_Application(void)
147 {
148         exitEngine();
149         fSystem->disposeWindow(m_mainWindow);
150 }
151
152
153
154 bool GPG_Application::SetGameEngineData(struct Main* maggie, STR_String startSceneName)
155 {
156         bool result = false;
157
158         if (maggie != NULL && startSceneName != "")
159         {
160                 G.scene = (Scene*)maggie->scene.first;
161                 m_maggie = maggie;
162                 m_startSceneName = startSceneName;
163                 result = true;
164         }
165
166         return result;
167 }
168
169
170 #ifdef WIN32
171 #define SCR_SAVE_MOUSE_MOVE_THRESHOLD 15
172
173 static HWND found_ghost_window_hwnd;
174 static GHOST_IWindow* ghost_window_to_find;
175 static WNDPROC ghost_wnd_proc;
176 static POINT scr_save_mouse_pos;
177
178 static LRESULT CALLBACK screenSaverWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
179 {
180         BOOL close = FALSE;
181         switch (uMsg)
182         {
183                 case WM_MOUSEMOVE:
184                 { 
185                         POINT pt; 
186                         GetCursorPos(&pt);
187                         LONG dx = scr_save_mouse_pos.x - pt.x;
188                         LONG dy = scr_save_mouse_pos.y - pt.y;
189                         if (abs(dx) > SCR_SAVE_MOUSE_MOVE_THRESHOLD
190                             || abs(dy) > SCR_SAVE_MOUSE_MOVE_THRESHOLD)
191                         {
192                                 close = TRUE;
193                         }
194                         scr_save_mouse_pos = pt;
195                         break;
196                 }
197                 case WM_LBUTTONDOWN: 
198                 case WM_MBUTTONDOWN: 
199                 case WM_RBUTTONDOWN: 
200                 case WM_KEYDOWN:
201                         close = TRUE;
202         }
203         if (close)
204                 PostMessage(hwnd,WM_CLOSE,0,0);
205         return CallWindowProc(ghost_wnd_proc, hwnd, uMsg, wParam, lParam);
206 }
207
208 BOOL CALLBACK findGhostWindowHWNDProc(HWND hwnd, LPARAM lParam)
209 {
210         GHOST_IWindow *p = (GHOST_IWindow*) GetWindowLong(hwnd, GWL_USERDATA);
211         BOOL ret = TRUE;
212         if (p == ghost_window_to_find)
213         {
214                 found_ghost_window_hwnd = hwnd;
215                 ret = FALSE;
216         }
217         return ret;
218 }
219
220 static HWND findGhostWindowHWND(GHOST_IWindow* window)
221 {
222         found_ghost_window_hwnd = NULL;
223         ghost_window_to_find = window;
224         EnumWindows(findGhostWindowHWNDProc, NULL);
225         return found_ghost_window_hwnd;
226 }
227
228 bool GPG_Application::startScreenSaverPreview(
229         HWND parentWindow,
230         const bool stereoVisual,
231         const int stereoMode)
232 {
233         bool success = false;
234
235         RECT rc;
236         if (GetWindowRect(parentWindow, &rc))
237         {
238                 int windowWidth = rc.right - rc.left;
239                 int windowHeight = rc.bottom - rc.top;
240                 STR_String title = "";
241                                                         
242                 m_mainWindow = fSystem->createWindow(title, 0, 0, windowWidth, windowHeight, GHOST_kWindowStateMinimized,
243                         GHOST_kDrawingContextTypeOpenGL, stereoVisual);
244                 if (!m_mainWindow) {
245                         printf("error: could not create main window\n");
246                         exit(-1);
247                 }
248
249                 HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow);
250                 if (!ghost_hwnd) {
251                         printf("error: could find main window\n");
252                         exit(-1);
253                 }
254
255                 SetParent(ghost_hwnd, parentWindow);
256                 LONG style = GetWindowLong(ghost_hwnd, GWL_STYLE);
257                 LONG exstyle = GetWindowLong(ghost_hwnd, GWL_EXSTYLE);
258
259                 RECT adjrc = { 0, 0, windowWidth, windowHeight };
260                 AdjustWindowRectEx(&adjrc, style, FALSE, exstyle);
261
262                 style = (style & (~(WS_POPUP|WS_OVERLAPPEDWINDOW|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_TILEDWINDOW ))) | WS_CHILD;
263                 SetWindowLong(ghost_hwnd, GWL_STYLE, style);
264                 SetWindowPos(ghost_hwnd, NULL, adjrc.left, adjrc.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE);
265
266                 /* Check the size of the client rectangle of the window and resize the window
267                  * so that the client rectangle has the size requested.
268                  */
269                 m_mainWindow->setClientSize(windowWidth, windowHeight);
270
271                 success = initEngine(m_mainWindow, stereoMode);
272                 if (success) {
273                         success = startEngine();
274                 }
275
276         }
277         return success;
278 }
279
280 bool GPG_Application::startScreenSaverFullScreen(
281                 int width,
282                 int height,
283                 int bpp,int frequency,
284                 const bool stereoVisual,
285                 const int stereoMode)
286 {
287         bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode);
288         if (ret)
289         {
290                 HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow);
291                 if (ghost_hwnd != NULL)
292                 {
293                         GetCursorPos(&scr_save_mouse_pos);
294                         ghost_wnd_proc = (WNDPROC) GetWindowLong(ghost_hwnd, GWL_WNDPROC);
295                         SetWindowLong(ghost_hwnd,GWL_WNDPROC, (LONG) screenSaverWindowProc);
296                 }
297         }
298         return ret;
299 }
300
301 #endif
302
303 bool GPG_Application::startWindow(STR_String& title,
304         int windowLeft,
305         int windowTop,
306         int windowWidth,
307         int windowHeight,
308         const bool stereoVisual,
309         const int stereoMode)
310 {
311         bool success;
312         // Create the main window
313         //STR_String title ("Blender Player - GHOST");
314         m_mainWindow = fSystem->createWindow(title, windowLeft, windowTop, windowWidth, windowHeight, GHOST_kWindowStateNormal,
315                 GHOST_kDrawingContextTypeOpenGL, stereoVisual);
316         if (!m_mainWindow) {
317                 printf("error: could not create main window\n");
318                 exit(-1);
319         }
320
321         /* Check the size of the client rectangle of the window and resize the window
322          * so that the client rectangle has the size requested.
323          */
324         m_mainWindow->setClientSize(windowWidth, windowHeight);
325         m_mainWindow->setCursorVisibility(false);
326
327         success = initEngine(m_mainWindow, stereoMode);
328         if (success) {
329                 success = startEngine();
330         }
331         return success;
332 }
333
334
335
336 bool GPG_Application::startFullScreen(
337                 int width,
338                 int height,
339                 int bpp,int frequency,
340                 const bool stereoVisual,
341                 const int stereoMode)
342 {
343         bool success;
344         // Create the main window
345         GHOST_DisplaySetting setting;
346         setting.xPixels = width;
347         setting.yPixels = height;
348         setting.bpp = bpp;
349         setting.frequency = frequency;
350
351         fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual);
352         m_mainWindow->setCursorVisibility(false);
353
354         success = initEngine(m_mainWindow, stereoMode);
355         if (success) {
356                 success = startEngine();
357         }
358         return success;
359 }
360
361
362
363
364 bool GPG_Application::StartGameEngine(int stereoMode)
365 {
366         bool success = initEngine(m_mainWindow, stereoMode);
367         
368         if (success)
369                 success = startEngine();
370
371         return success;
372 }
373
374
375
376 void GPG_Application::StopGameEngine()
377 {
378         exitEngine();
379 }
380
381
382
383 bool GPG_Application::processEvent(GHOST_IEvent* event)
384 {
385         bool handled = true;
386
387         switch (event->getType())
388         {
389                 case GHOST_kEventUnknown:
390                         break;
391
392                 case GHOST_kEventButtonDown:
393                         handled = handleButton(event, true);
394                         break;
395
396                 case GHOST_kEventButtonUp:
397                         handled = handleButton(event, false);
398                         break;
399                         
400                 case GHOST_kEventWheel:
401                         handled = handleWheel(event);
402                         break;
403
404                 case GHOST_kEventCursorMove:
405                         handled = handleCursorMove(event);
406                         break;
407
408                 case GHOST_kEventKeyDown:
409                         handleKey(event, true);
410                         break;
411
412                 case GHOST_kEventKeyUp:
413                         handleKey(event, false);
414                         break;
415
416
417                 case GHOST_kEventWindowClose:
418                         m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
419                         break;
420
421                 case GHOST_kEventWindowActivate:
422                         handled = false;
423                         break;
424                 case GHOST_kEventWindowDeactivate:
425                         handled = false;
426                         break;
427
428                 case GHOST_kEventWindowUpdate:
429                         {
430                                 GHOST_IWindow* window = event->getWindow();
431                                 if (!m_system->validWindow(window)) break;
432                                 // Update the state of the game engine
433                                 if (m_kxsystem && !m_exitRequested)
434                                 {
435                                         // Proceed to next frame
436                                         window->activateDrawingContext();
437
438                                         // first check if we want to exit
439                                         m_exitRequested = m_ketsjiengine->GetExitCode();
440                                         
441                                         // kick the engine
442                                         bool renderFrame = m_ketsjiengine->NextFrame();
443                                         if (renderFrame)
444                                         {
445                                                 // render the frame
446                                                 m_ketsjiengine->Render();
447                                         }
448                                 }
449                                 m_exitString = m_ketsjiengine->GetExitString();
450                         }
451                         break;
452                 
453                 case GHOST_kEventWindowSize:
454                         {
455                         GHOST_IWindow* window = event->getWindow();
456                         if (!m_system->validWindow(window)) break;
457                         if (m_canvas) {
458                                 GHOST_Rect bnds;
459                                 window->getClientBounds(bnds);
460                                 m_canvas->Resize(bnds.getWidth(), bnds.getHeight());
461                         }
462                         }
463                         break;
464                 
465                 default:
466                         handled = false;
467                         break;
468         }
469         return handled;
470 }
471
472
473
474 int GPG_Application::getExitRequested(void)
475 {
476         return m_exitRequested;
477 }
478
479
480
481 const STR_String& GPG_Application::getExitString(void)
482 {
483         return m_exitString;
484 }
485
486
487
488 bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
489 {
490         if (!m_engineInitialized)
491         {
492                 bgl::InitExtensions(1);
493
494                 // get and set the preferences
495                 SYS_SystemHandle syshandle = SYS_GetSystem();
496                 if (!syshandle)
497                         return false;
498                 
499                 // SYS_WriteCommandLineInt(syshandle, "fixedtime", 0);
500                 // SYS_WriteCommandLineInt(syshandle, "vertexarrays",1);                
501                 bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
502                 bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
503                 bool fixedFr = (G.fileflags & G_FILE_ENABLE_ALL_FRAMES);
504
505                 bool showPhysics = (G.fileflags & G_FILE_SHOW_PHYSICS);
506                 SYS_WriteCommandLineInt(syshandle, "show_physics", showPhysics);
507
508                 bool fixed_framerate= (SYS_GetCommandLineInt(syshandle, "fixed_framerate", fixedFr) != 0);
509                 bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
510                 bool useVertexArrays = SYS_GetCommandLineInt(syshandle,"vertexarrays",1) != 0;
511                 bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", G.fileflags & G_FILE_DIAPLAY_LISTS) != 0);
512 #ifdef GL_ARB_multitexture
513                 int gameflag =(G.fileflags & G_FILE_GAME_MAT);
514                 // ----------------------------------
515                 if(bgl::RAS_EXT_support._ARB_multitexture && bgl::QueryVersion(1, 1)) {
516                         m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", gameflag) != 0);
517                         int unitmax=0;
518                         glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&unitmax);
519                         bgl::max_texture_units = MAXTEX>unitmax?unitmax:MAXTEX;
520                         //std::cout << "using(" << bgl::max_texture_units << ") of(" << unitmax << ") texture units." << std::endl;
521                 } else {
522                         bgl::max_texture_units = 0;
523                 }
524 #else
525                 m_blendermat=0;
526 #endif//GL_ARB_multitexture
527                 // ----------------------------------
528         
529                 // create the canvas, rasterizer and rendertools
530                 m_canvas = new GPG_Canvas(window);
531                 if (!m_canvas)
532                         return false;
533                                 
534                 m_canvas->Init();                               
535                 m_rendertools = new GPC_RenderTools();
536                 if (!m_rendertools)
537                         goto initFailed;
538                 
539                 if(useLists)
540                         m_rasterizer = new RAS_ListRasterizer(m_canvas);
541                 else if (useVertexArrays && bgl::QueryVersion(1, 1))
542                         m_rasterizer = new RAS_VAOpenGLRasterizer(m_canvas);
543                 else
544                         m_rasterizer = new RAS_OpenGLRasterizer(m_canvas);
545                 m_rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) stereoMode);
546                 if (!m_rasterizer)
547                         goto initFailed;
548                                                 
549                 // create the inputdevices
550                 m_keyboard = new GPG_KeyboardDevice();
551                 if (!m_keyboard)
552                         goto initFailed;
553                         
554                 m_mouse = new GPC_MouseDevice();
555                 if (!m_mouse)
556                         goto initFailed;
557                         
558                 // create a networkdevice
559                 m_networkdevice = new NG_LoopBackNetworkDeviceInterface();
560                 if (!m_networkdevice)
561                         goto initFailed;
562                         
563                 // get an audiodevice
564                 SND_DeviceManager::Subscribe();
565                 m_audiodevice = SND_DeviceManager::Instance();
566                 if (!m_audiodevice)
567                         goto initFailed;
568                 m_audiodevice->UseCD();
569                 
570                 // create a ketsjisystem (only needed for timing and stuff)
571                 m_kxsystem = new GPG_System (m_system);
572                 if (!m_kxsystem)
573                         goto initFailed;
574                 
575                 // create the ketsjiengine
576                 m_ketsjiengine = new KX_KetsjiEngine(m_kxsystem);
577                 
578                 // set the devices
579                 m_ketsjiengine->SetKeyboardDevice(m_keyboard);
580                 m_ketsjiengine->SetMouseDevice(m_mouse);
581                 m_ketsjiengine->SetNetworkDevice(m_networkdevice);
582                 m_ketsjiengine->SetCanvas(m_canvas);
583                 m_ketsjiengine->SetRenderTools(m_rendertools);
584                 m_ketsjiengine->SetRasterizer(m_rasterizer);
585                 m_ketsjiengine->SetNetworkDevice(m_networkdevice);
586                 m_ketsjiengine->SetAudioDevice(m_audiodevice);
587                 m_ketsjiengine->SetTimingDisplay(frameRate, false, false);
588
589                 m_ketsjiengine->SetUseFixedTime(fixed_framerate);
590                 m_ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
591
592                 m_engineInitialized = true;
593         }
594
595         return m_engineInitialized;
596 initFailed:
597         delete m_kxsystem;
598         delete m_audiodevice;
599         delete m_networkdevice;
600         delete m_mouse;
601         delete m_keyboard;
602         delete m_rasterizer;
603         delete m_rendertools;
604         delete m_canvas;
605         m_canvas = NULL;
606         m_rendertools = NULL;
607         m_rasterizer = NULL;
608         m_keyboard = NULL;
609         m_mouse = NULL;
610         m_networkdevice = NULL;
611         m_audiodevice = NULL;
612         m_kxsystem = NULL;
613         return false;
614 }
615
616
617
618 bool GPG_Application::startEngine(void)
619 {
620         if (m_engineRunning) {
621                 return false;
622         }
623         
624         // Temporary hack to disable banner display for NaN approved content.
625         /*
626         m_canvas->SetBannerDisplayEnabled(true);        
627         Camera* cam;
628         cam = (Camera*)G.scene->camera->data;
629         if (cam) {
630         if (((cam->flag) & 48)==48) {
631         m_canvas->SetBannerDisplayEnabled(false);
632         }
633         }
634         else {
635         showError(CString("Camera data invalid."));
636         return false;
637         }
638         */
639         
640         // create a scene converter, create and convert the stratingscene
641         m_sceneconverter = new KX_BlenderSceneConverter(m_maggie,0, m_ketsjiengine);
642         if (m_sceneconverter)
643         {
644                 STR_String startscenename = m_startSceneName.Ptr();
645                 m_ketsjiengine->SetSceneConverter(m_sceneconverter);
646                 
647                 //      if (always_use_expand_framing)
648                 //              sceneconverter->SetAlwaysUseExpandFraming(true);
649                 if(m_blendermat)
650                         m_sceneconverter->SetMaterials(true);
651
652                 KX_Scene* startscene = new KX_Scene(m_keyboard,
653                         m_mouse,
654                         m_networkdevice,
655                         m_audiodevice,
656                         startscenename);
657                 
658                 
659                 // some python things
660                 PyObject* dictionaryobject = initGamePlayerPythonScripting("Ketsji", psl_Lowest);
661                 m_ketsjiengine->SetPythonDictionary(dictionaryobject);
662                 initRasterizer(m_rasterizer, m_canvas);
663                 PyObject *gameLogic = initGameLogic(startscene);
664                 initGameKeys();
665                 initPythonConstraintBinding();
666
667
668
669
670
671                 m_sceneconverter->ConvertScene(
672                         startscenename,
673                         startscene,
674                         dictionaryobject,
675                         m_keyboard,
676                         m_rendertools,
677                         m_canvas);
678                 m_ketsjiengine->AddScene(startscene);
679                 
680                 // Create a timer that is used to kick the engine
681                 if (!m_frameTimer) {
682                         m_frameTimer = m_system->installTimer(0, kTimerFreq, frameTimerProc, m_mainWindow);
683                 }
684                 m_rasterizer->Init();
685                 m_ketsjiengine->StartEngine(true);
686                 m_engineRunning = true;
687                 
688         }
689         
690         if (!m_engineRunning)
691         {
692                 stopEngine();
693         }
694         
695         return m_engineRunning;
696 }
697
698
699 void GPG_Application::stopEngine()
700 {
701         // when exiting the mainloop
702         exitGamePythonScripting();
703         m_ketsjiengine->StopEngine();
704         m_networkdevice->Disconnect();
705
706         if (m_sceneconverter) {
707                 delete m_sceneconverter;
708                 m_sceneconverter = 0;
709         }
710         if (m_system && m_frameTimer) {
711                 m_system->removeTimer(m_frameTimer);
712                 m_frameTimer = 0;
713         }
714         m_engineRunning = false;
715 }
716
717
718 void GPG_Application::exitEngine()
719 {
720         if (m_ketsjiengine)
721         {
722                 stopEngine();
723                 delete m_ketsjiengine;
724                 m_ketsjiengine = 0;
725         }
726         if (m_kxsystem)
727         {
728                 delete m_kxsystem;
729                 m_kxsystem = 0;
730         }
731         if (m_audiodevice)
732         {
733                 SND_DeviceManager::Unsubscribe();
734                 m_audiodevice = 0;
735         }
736         if (m_networkdevice)
737         {
738                 delete m_networkdevice;
739                 m_networkdevice = 0;
740         }
741         if (m_mouse)
742         {
743                 delete m_mouse;
744                 m_mouse = 0;
745         }
746         if (m_keyboard)
747         {
748                 delete m_keyboard;
749                 m_keyboard = 0;
750         }
751         if (m_rasterizer)
752         {
753                 delete m_rasterizer;
754                 m_rasterizer = 0;
755         }
756         if (m_rendertools)
757         {
758                 delete m_rendertools;
759                 m_rendertools = 0;
760         }
761         if (m_canvas)
762         {
763                 delete m_canvas;
764                 m_canvas = 0;
765         }
766
767         m_exitRequested = 0;
768         m_engineInitialized = false;
769 }
770
771 bool GPG_Application::handleWheel(GHOST_IEvent* event)
772 {
773         bool handled = false;
774         MT_assert(event);
775         if (m_mouse) 
776         {
777                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
778                 GHOST_TEventWheelData* wheelData = static_cast<GHOST_TEventWheelData*>(eventData);
779                 GPC_MouseDevice::TButtonId button;
780                 if (wheelData->z > 0)
781                         button = GPC_MouseDevice::buttonWheelUp;
782                 else
783                         button = GPC_MouseDevice::buttonWheelDown;
784                 m_mouse->ConvertButtonEvent(button, true);
785                 handled = true;
786         }
787         return handled;
788 }
789
790 bool GPG_Application::handleButton(GHOST_IEvent* event, bool isDown)
791 {
792         bool handled = false;
793         MT_assert(event);
794         if (m_mouse) 
795         {
796                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
797                 GHOST_TEventButtonData* buttonData = static_cast<GHOST_TEventButtonData*>(eventData);
798                 GPC_MouseDevice::TButtonId button;
799                 switch (buttonData->button)
800                 {
801                 case GHOST_kButtonMaskMiddle:
802                         button = GPC_MouseDevice::buttonMiddle;
803                         break;
804                 case GHOST_kButtonMaskRight:
805                         button = GPC_MouseDevice::buttonRight;
806                         break;
807                 case GHOST_kButtonMaskLeft:
808                 default:
809                         button = GPC_MouseDevice::buttonLeft;
810                         break;
811                 }
812                 m_mouse->ConvertButtonEvent(button, isDown);
813                 handled = true;
814         }
815         return handled;
816 }
817
818
819 bool GPG_Application::handleCursorMove(GHOST_IEvent* event)
820 {
821         bool handled = false;
822         MT_assert(event);
823         if (m_mouse && m_mainWindow)
824         {
825                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
826                 GHOST_TEventCursorData* cursorData = static_cast<GHOST_TEventCursorData*>(eventData);
827                 GHOST_TInt32 x, y;
828                 m_mainWindow->screenToClient(cursorData->x, cursorData->y, x, y);
829                 m_mouse->ConvertMoveEvent(x, y);
830                 handled = true;
831         }
832         return handled;
833 }
834
835
836 bool GPG_Application::handleKey(GHOST_IEvent* event, bool isDown)
837 {
838         bool handled = false;
839         MT_assert(event);
840         if (m_keyboard)
841         {
842                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
843                 GHOST_TEventKeyData* keyData = static_cast<GHOST_TEventKeyData*>(eventData);
844                 if (fSystem->getFullScreen()) {
845                         if (keyData->key == GHOST_kKeyEsc) {
846                                 m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
847                         }
848                 }
849                 m_keyboard->ConvertEvent(keyData->key, isDown);
850                 handled = true;
851         }
852         return handled;
853 }
854
855
856
857 static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time)
858 {
859         GHOST_IWindow* window = (GHOST_IWindow*)task->getUserData();
860         if (fSystem->validWindow(window)) {
861                 window->invalidate();
862         }
863 }