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