e00a890a1fb90ed29391e83fc21c7db11ca8dbe3
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file gameengine/GamePlayer/ghost/GPG_Application.cpp
32  *  \ingroup player
33  */
34
35
36 #ifdef WIN32
37         #pragma warning (disable:4786) // suppress stl-MSVC debug info warning
38         #include <windows.h>
39 #endif
40
41 #include "GL/glew.h"
42 #include "GPU_extensions.h"
43
44 #include "GPG_Application.h"
45
46 #include <iostream>
47 #include <MT_assert.h>
48 #include <stdlib.h>
49
50 /**********************************
51  * Begin Blender include block
52  **********************************/
53 #ifdef __cplusplus
54 extern "C"
55 {
56 #endif  // __cplusplus
57 #include "BLI_blenlib.h"
58 #include "BLO_readfile.h"
59 #include "BKE_global.h"
60 #include "BKE_main.h"
61 #include "BKE_sound.h"
62 #include "IMB_imbuf.h"
63 #include "DNA_scene_types.h"
64 #ifdef __cplusplus
65 }
66 #endif // __cplusplus
67 /**********************************
68  * End Blender include block
69  **********************************/
70
71
72 #include "SYS_System.h"
73 #include "KX_KetsjiEngine.h"
74
75 // include files needed by "KX_BlenderSceneConverter.h"
76 #include "GEN_Map.h"
77 #include "SCA_IActuator.h"
78 #include "RAS_MeshObject.h"
79 #include "RAS_OpenGLRasterizer.h"
80 #include "RAS_VAOpenGLRasterizer.h"
81 #include "RAS_ListRasterizer.h"
82 #include "RAS_GLExtensionManager.h"
83 #include "KX_PythonInit.h"
84 #include "KX_PyConstraintBinding.h"
85 #include "BL_Material.h" // MAXTEX
86
87 #include "KX_BlenderSceneConverter.h"
88 #include "NG_LoopBackNetworkDeviceInterface.h"
89
90 #include "GPC_MouseDevice.h"
91 #include "GPC_RenderTools.h"
92 #include "GPG_Canvas.h" 
93 #include "GPG_KeyboardDevice.h"
94 #include "GPG_System.h"
95
96 #include "STR_String.h"
97
98 #include "GHOST_ISystem.h"
99 #include "GHOST_IEvent.h"
100 #include "GHOST_IEventConsumer.h"
101 #include "GHOST_IWindow.h"
102 #include "GHOST_Rect.h"
103
104 static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time);
105
106 static GHOST_ISystem* fSystem = 0;
107 static const int kTimerFreq = 10;
108
109 GPG_Application::GPG_Application(GHOST_ISystem* system)
110         : m_startSceneName(""), 
111           m_startScene(0),
112           m_maggie(0),
113           m_exitRequested(0),
114           m_system(system), 
115           m_mainWindow(0), 
116           m_frameTimer(0), 
117           m_cursor(GHOST_kStandardCursorFirstCursor),
118           m_engineInitialized(0), 
119           m_engineRunning(0), 
120           m_isEmbedded(false),
121           m_ketsjiengine(0),
122           m_kxsystem(0), 
123           m_keyboard(0), 
124           m_mouse(0), 
125           m_canvas(0), 
126           m_rendertools(0), 
127           m_rasterizer(0), 
128           m_sceneconverter(0),
129           m_networkdevice(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 // XXX          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         m_mainWindow->setState(GHOST_kWindowStateFullScreen);
379
380         success = initEngine(m_mainWindow, stereoMode);
381         if (success) {
382                 success = startEngine();
383         }
384         return success;
385 }
386
387
388
389
390 bool GPG_Application::StartGameEngine(int stereoMode)
391 {
392         bool success = initEngine(m_mainWindow, stereoMode);
393         
394         if (success)
395                 success = startEngine();
396
397         return success;
398 }
399
400
401
402 void GPG_Application::StopGameEngine()
403 {
404         exitEngine();
405 }
406
407
408
409 bool GPG_Application::processEvent(GHOST_IEvent* event)
410 {
411         bool handled = true;
412
413         switch (event->getType())
414         {
415                 case GHOST_kEventUnknown:
416                         break;
417
418                 case GHOST_kEventButtonDown:
419                         handled = handleButton(event, true);
420                         break;
421
422                 case GHOST_kEventButtonUp:
423                         handled = handleButton(event, false);
424                         break;
425                         
426                 case GHOST_kEventWheel:
427                         handled = handleWheel(event);
428                         break;
429
430                 case GHOST_kEventCursorMove:
431                         handled = handleCursorMove(event);
432                         break;
433
434                 case GHOST_kEventKeyDown:
435                         handleKey(event, true);
436                         break;
437
438                 case GHOST_kEventKeyUp:
439                         handleKey(event, false);
440                         break;
441
442
443                 case GHOST_kEventWindowClose:
444                         m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
445                         break;
446
447                 case GHOST_kEventWindowActivate:
448                         handled = false;
449                         break;
450                 case GHOST_kEventWindowDeactivate:
451                         handled = false;
452                         break;
453
454                 case GHOST_kEventWindowUpdate:
455                         {
456                                 GHOST_IWindow* window = event->getWindow();
457                                 if (!m_system->validWindow(window)) break;
458                                 // Update the state of the game engine
459                                 if (m_kxsystem && !m_exitRequested)
460                                 {
461                                         // Proceed to next frame
462                                         window->activateDrawingContext();
463
464                                         // first check if we want to exit
465                                         m_exitRequested = m_ketsjiengine->GetExitCode();
466                                         
467                                         // kick the engine
468                                         bool renderFrame = m_ketsjiengine->NextFrame();
469                                         if (renderFrame)
470                                         {
471                                                 // render the frame
472                                                 m_ketsjiengine->Render();
473                                         }
474                                 }
475                                 m_exitString = m_ketsjiengine->GetExitString();
476                         }
477                         break;
478                 
479                 case GHOST_kEventWindowSize:
480                         {
481                         GHOST_IWindow* window = event->getWindow();
482                         if (!m_system->validWindow(window)) break;
483                         if (m_canvas) {
484                                 GHOST_Rect bnds;
485                                 window->getClientBounds(bnds);
486                                 m_canvas->Resize(bnds.getWidth(), bnds.getHeight());
487                         }
488                         }
489                         break;
490                 
491                 default:
492                         handled = false;
493                         break;
494         }
495         return handled;
496 }
497
498
499
500 int GPG_Application::getExitRequested(void)
501 {
502         return m_exitRequested;
503 }
504
505
506
507 const STR_String& GPG_Application::getExitString(void)
508 {
509         return m_exitString;
510 }
511
512
513
514 bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
515 {
516         if (!m_engineInitialized)
517         {
518                 GPU_extensions_init();
519                 bgl::InitExtensions(true);
520
521                 // get and set the preferences
522                 SYS_SystemHandle syshandle = SYS_GetSystem();
523                 if (!syshandle)
524                         return false;
525                 
526                 // SYS_WriteCommandLineInt(syshandle, "fixedtime", 0);
527                 // SYS_WriteCommandLineInt(syshandle, "vertexarrays",1);                
528                 GameData *gm= &m_startScene->gm;
529                 bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
530                 bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
531                 bool fixedFr = (gm->flag & GAME_ENABLE_ALL_FRAMES);
532
533                 bool showPhysics = (gm->flag & GAME_SHOW_PHYSICS);
534                 SYS_WriteCommandLineInt(syshandle, "show_physics", showPhysics);
535
536                 bool fixed_framerate= (SYS_GetCommandLineInt(syshandle, "fixed_framerate", fixedFr) != 0);
537                 bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
538                 bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", gm->flag & GAME_DISPLAY_LISTS) != 0);
539                 bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 1) != 0);
540
541                 if(GLEW_ARB_multitexture && GLEW_VERSION_1_1)
542                         m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0);
543
544                 if(GPU_glsl_support())
545                         m_blenderglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0);
546                 else if(gm->matmode == GAME_MAT_GLSL)
547                         m_blendermat = false;
548
549                 // create the canvas, rasterizer and rendertools
550                 m_canvas = new GPG_Canvas(window);
551                 if (!m_canvas)
552                         return false;
553                                 
554                 m_canvas->Init();
555                 if (gm->flag & GAME_SHOW_MOUSE)
556                         m_canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);                             
557
558                 m_rendertools = new GPC_RenderTools();
559                 if (!m_rendertools)
560                         goto initFailed;
561                 
562                 if(useLists) {
563                         if(GLEW_VERSION_1_1)
564                                 m_rasterizer = new RAS_ListRasterizer(m_canvas, true);
565                         else
566                                 m_rasterizer = new RAS_ListRasterizer(m_canvas);
567                 }
568                 else if (GLEW_VERSION_1_1)
569                         m_rasterizer = new RAS_VAOpenGLRasterizer(m_canvas);
570                 else
571                         m_rasterizer = new RAS_OpenGLRasterizer(m_canvas);
572
573                 /* Stereo parameters - Eye Separation from the UI - stereomode from the command-line/UI */
574                 m_rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) stereoMode);
575                 m_rasterizer->SetEyeSeparation(m_startScene->gm.eyeseparation);
576                 
577                 if (!m_rasterizer)
578                         goto initFailed;
579                                                 
580                 // create the inputdevices
581                 m_keyboard = new GPG_KeyboardDevice();
582                 if (!m_keyboard)
583                         goto initFailed;
584                         
585                 m_mouse = new GPC_MouseDevice();
586                 if (!m_mouse)
587                         goto initFailed;
588                         
589                 // create a networkdevice
590                 m_networkdevice = new NG_LoopBackNetworkDeviceInterface();
591                 if (!m_networkdevice)
592                         goto initFailed;
593                         
594                 sound_init(m_maggie);
595
596                 // create a ketsjisystem (only needed for timing and stuff)
597                 m_kxsystem = new GPG_System (m_system);
598                 if (!m_kxsystem)
599                         goto initFailed;
600                 
601                 // create the ketsjiengine
602                 m_ketsjiengine = new KX_KetsjiEngine(m_kxsystem);
603                 
604                 // set the devices
605                 m_ketsjiengine->SetKeyboardDevice(m_keyboard);
606                 m_ketsjiengine->SetMouseDevice(m_mouse);
607                 m_ketsjiengine->SetNetworkDevice(m_networkdevice);
608                 m_ketsjiengine->SetCanvas(m_canvas);
609                 m_ketsjiengine->SetRenderTools(m_rendertools);
610                 m_ketsjiengine->SetRasterizer(m_rasterizer);
611                 m_ketsjiengine->SetNetworkDevice(m_networkdevice);
612
613                 m_ketsjiengine->SetTimingDisplay(frameRate, false, false);
614 #ifdef WITH_PYTHON
615                 CValue::SetDeprecationWarnings(nodepwarnings);
616 #else
617                 (void)nodepwarnings;
618 #endif
619
620                 m_ketsjiengine->SetUseFixedTime(fixed_framerate);
621                 m_ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
622
623                 m_engineInitialized = true;
624         }
625
626         return m_engineInitialized;
627 initFailed:
628         sound_exit();
629         delete m_kxsystem;
630         delete m_networkdevice;
631         delete m_mouse;
632         delete m_keyboard;
633         delete m_rasterizer;
634         delete m_rendertools;
635         delete m_canvas;
636         m_canvas = NULL;
637         m_rendertools = NULL;
638         m_rasterizer = NULL;
639         m_keyboard = NULL;
640         m_mouse = NULL;
641         m_networkdevice = NULL;
642         m_kxsystem = NULL;
643         return false;
644 }
645
646
647
648 bool GPG_Application::startEngine(void)
649 {
650         if (m_engineRunning) {
651                 return false;
652         }
653         
654         // Temporary hack to disable banner display for NaN approved content.
655         /*
656         m_canvas->SetBannerDisplayEnabled(true);        
657         Camera* cam;
658         cam = (Camera*)scene->camera->data;
659         if (cam) {
660         if (((cam->flag) & 48)==48) {
661         m_canvas->SetBannerDisplayEnabled(false);
662         }
663         }
664         else {
665         showError(CString("Camera data invalid."));
666         return false;
667         }
668         */
669         
670         // create a scene converter, create and convert the stratingscene
671         m_sceneconverter = new KX_BlenderSceneConverter(m_maggie, m_ketsjiengine);
672         if (m_sceneconverter)
673         {
674                 STR_String startscenename = m_startSceneName.Ptr();
675                 m_ketsjiengine->SetSceneConverter(m_sceneconverter);
676
677                 //      if (always_use_expand_framing)
678                 //              sceneconverter->SetAlwaysUseExpandFraming(true);
679                 if(m_blendermat && (m_startScene->gm.matmode != GAME_MAT_TEXFACE))
680                         m_sceneconverter->SetMaterials(true);
681                 if(m_blenderglslmat && (m_startScene->gm.matmode == GAME_MAT_GLSL))
682                         m_sceneconverter->SetGLSLMaterials(true);
683
684                 KX_Scene* startscene = new KX_Scene(m_keyboard,
685                         m_mouse,
686                         m_networkdevice,
687                         startscenename,
688                         m_startScene,
689                         m_canvas);
690                 
691 #ifdef WITH_PYTHON
692                         // some python things
693                         PyObject *gameLogic, *gameLogic_keys;
694                         setupGamePython(m_ketsjiengine, startscene, m_maggie, NULL, &gameLogic, &gameLogic_keys, m_argc, m_argv);
695 #endif // WITH_PYTHON
696
697                 //initialize Dome Settings
698                 if(m_startScene->gm.stereoflag == STEREO_DOME)
699                         m_ketsjiengine->InitDome(m_startScene->gm.dome.res, m_startScene->gm.dome.mode, m_startScene->gm.dome.angle, m_startScene->gm.dome.resbuf, m_startScene->gm.dome.tilt, m_startScene->gm.dome.warptext);
700
701 #ifdef WITH_PYTHON
702                 // Set the GameLogic.globalDict from marshal'd data, so we can
703                 // load new blend files and keep data in GameLogic.globalDict
704                 loadGamePythonConfig(m_pyGlobalDictString, m_pyGlobalDictString_Length);
705 #endif          
706                 m_sceneconverter->ConvertScene(
707                         startscene,
708                         m_rendertools,
709                         m_canvas);
710                 m_ketsjiengine->AddScene(startscene);
711                 
712                 // Create a timer that is used to kick the engine
713                 if (!m_frameTimer) {
714                         m_frameTimer = m_system->installTimer(0, kTimerFreq, frameTimerProc, m_mainWindow);
715                 }
716                 m_rasterizer->Init();
717                 m_ketsjiengine->StartEngine(true);
718                 m_engineRunning = true;
719                 
720                 // Set the animation playback rate for ipo's and actions
721                 // the framerate below should patch with FPS macro defined in blendef.h
722                 // Could be in StartEngine set the framerate, we need the scene to do this
723                 Scene *scene= startscene->GetBlenderScene(); // needed for macro
724                 m_ketsjiengine->SetAnimFrameRate(FPS);
725         }
726         
727         if (!m_engineRunning)
728         {
729                 stopEngine();
730         }
731         
732         return m_engineRunning;
733 }
734
735
736 void GPG_Application::stopEngine()
737 {
738 #ifdef WITH_PYTHON
739         // GameLogic.globalDict gets converted into a buffer, and sorted in
740         // m_pyGlobalDictString so we can restore after python has stopped
741         // and started between .blend file loads.
742         if(m_pyGlobalDictString) {
743                 delete [] m_pyGlobalDictString;
744                 m_pyGlobalDictString = 0;
745         }
746
747         m_pyGlobalDictString_Length = saveGamePythonConfig(&m_pyGlobalDictString);
748         
749         // when exiting the mainloop
750         exitGamePythonScripting();
751 #endif
752         
753         m_ketsjiengine->StopEngine();
754         m_networkdevice->Disconnect();
755
756         if (m_sceneconverter) {
757                 delete m_sceneconverter;
758                 m_sceneconverter = 0;
759         }
760         if (m_system && m_frameTimer) {
761                 m_system->removeTimer(m_frameTimer);
762                 m_frameTimer = 0;
763         }
764         m_engineRunning = false;
765 }
766
767
768 void GPG_Application::exitEngine()
769 {
770         sound_exit();
771         if (m_ketsjiengine)
772         {
773                 stopEngine();
774                 delete m_ketsjiengine;
775                 m_ketsjiengine = 0;
776         }
777         if (m_kxsystem)
778         {
779                 delete m_kxsystem;
780                 m_kxsystem = 0;
781         }
782         if (m_networkdevice)
783         {
784                 delete m_networkdevice;
785                 m_networkdevice = 0;
786         }
787         if (m_mouse)
788         {
789                 delete m_mouse;
790                 m_mouse = 0;
791         }
792         if (m_keyboard)
793         {
794                 delete m_keyboard;
795                 m_keyboard = 0;
796         }
797         if (m_rasterizer)
798         {
799                 delete m_rasterizer;
800                 m_rasterizer = 0;
801         }
802         if (m_rendertools)
803         {
804                 delete m_rendertools;
805                 m_rendertools = 0;
806         }
807         if (m_canvas)
808         {
809                 delete m_canvas;
810                 m_canvas = 0;
811         }
812
813         GPU_extensions_exit();
814
815         m_exitRequested = 0;
816         m_engineInitialized = false;
817 }
818
819 bool GPG_Application::handleWheel(GHOST_IEvent* event)
820 {
821         bool handled = false;
822         MT_assert(event);
823         if (m_mouse) 
824         {
825                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
826                 GHOST_TEventWheelData* wheelData = static_cast<GHOST_TEventWheelData*>(eventData);
827                 GPC_MouseDevice::TButtonId button;
828                 if (wheelData->z > 0)
829                         button = GPC_MouseDevice::buttonWheelUp;
830                 else
831                         button = GPC_MouseDevice::buttonWheelDown;
832                 m_mouse->ConvertButtonEvent(button, true);
833                 handled = true;
834         }
835         return handled;
836 }
837
838 bool GPG_Application::handleButton(GHOST_IEvent* event, bool isDown)
839 {
840         bool handled = false;
841         MT_assert(event);
842         if (m_mouse) 
843         {
844                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
845                 GHOST_TEventButtonData* buttonData = static_cast<GHOST_TEventButtonData*>(eventData);
846                 GPC_MouseDevice::TButtonId button;
847                 switch (buttonData->button)
848                 {
849                 case GHOST_kButtonMaskMiddle:
850                         button = GPC_MouseDevice::buttonMiddle;
851                         break;
852                 case GHOST_kButtonMaskRight:
853                         button = GPC_MouseDevice::buttonRight;
854                         break;
855                 case GHOST_kButtonMaskLeft:
856                 default:
857                         button = GPC_MouseDevice::buttonLeft;
858                         break;
859                 }
860                 m_mouse->ConvertButtonEvent(button, isDown);
861                 handled = true;
862         }
863         return handled;
864 }
865
866
867 bool GPG_Application::handleCursorMove(GHOST_IEvent* event)
868 {
869         bool handled = false;
870         MT_assert(event);
871         if (m_mouse && m_mainWindow)
872         {
873                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
874                 GHOST_TEventCursorData* cursorData = static_cast<GHOST_TEventCursorData*>(eventData);
875                 GHOST_TInt32 x, y;
876                 m_mainWindow->screenToClient(cursorData->x, cursorData->y, x, y);
877                 m_mouse->ConvertMoveEvent(x, y);
878                 handled = true;
879         }
880         return handled;
881 }
882
883
884 bool GPG_Application::handleKey(GHOST_IEvent* event, bool isDown)
885 {
886         bool handled = false;
887         MT_assert(event);
888         if (m_keyboard)
889         {
890                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
891                 GHOST_TEventKeyData* keyData = static_cast<GHOST_TEventKeyData*>(eventData);
892                 //no need for this test
893                 //if (fSystem->getFullScreen()) {
894                         if (keyData->key == GHOST_kKeyEsc && !m_keyboard->m_hookesc && !m_isEmbedded) {
895                                 m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
896                         }
897                 //}
898                 m_keyboard->ConvertEvent(keyData->key, isDown);
899                 handled = true;
900         }
901         return handled;
902 }
903
904
905
906 static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time)
907 {
908         GHOST_IWindow* window = (GHOST_IWindow*)task->getUserData();
909         if (fSystem->validWindow(window)) {
910                 window->invalidate();
911         }
912 }