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