merge runk 16887:16950
[blender.git] / source / gameengine / BlenderRoutines / BL_KetsjiEmbedStart.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  * Blender's Ketsji startpoint
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #include <signal.h>
36 #include <stdlib.h>
37
38 #ifdef WIN32
39 // don't show stl-warnings
40 #pragma warning (disable:4786)
41 #endif
42
43 #include "GL/glew.h"
44
45 #include "KX_BlenderGL.h"
46 #include "KX_BlenderCanvas.h"
47 #include "KX_BlenderKeyboardDevice.h"
48 #include "KX_BlenderMouseDevice.h"
49 #include "KX_BlenderRenderTools.h"
50 #include "KX_BlenderSystem.h"
51 #include "BL_Material.h"
52
53 #include "KX_KetsjiEngine.h"
54 #include "KX_BlenderSceneConverter.h"
55 #include "KX_PythonInit.h"
56 #include "KX_PyConstraintBinding.h"
57
58 #include "RAS_GLExtensionManager.h"
59 #include "RAS_OpenGLRasterizer.h"
60 #include "RAS_VAOpenGLRasterizer.h"
61 #include "RAS_ListRasterizer.h"
62
63 #include "NG_LoopBackNetworkDeviceInterface.h"
64 #include "SND_DeviceManager.h"
65
66 #include "SYS_System.h"
67
68         /***/
69
70 #include "DNA_view3d_types.h"
71 #include "DNA_screen_types.h"
72 #include "BKE_global.h"
73 #include "BIF_screen.h"
74 #include "BIF_scrarea.h"
75
76 #include "BKE_main.h"   
77 #include "BLI_blenlib.h"
78 #include "BLO_readfile.h"
79 #include "DNA_scene_types.h"
80         /***/
81
82 #include "GPU_extensions.h"
83
84 #ifdef __cplusplus
85 extern "C" {
86 #endif
87 #include "BSE_headerbuttons.h"
88 void update_for_newframe();
89 #ifdef __cplusplus
90 }
91 #endif
92
93 static BlendFileData *load_game_data(char *filename) {
94         BlendReadError error;
95         BlendFileData *bfd= BLO_read_from_file(filename, &error);
96         if (!bfd) {
97                 printf("Loading %s failed: %s\n", filename, BLO_bre_as_string(error));
98         }
99         return bfd;
100 }
101
102 extern "C" void StartKetsjiShell(struct ScrArea *area,
103                                                                  char* scenename,
104                                                                  struct Main* maggie1,
105                                                                  struct SpaceIpo *sipo,
106                                                                  int always_use_expand_framing)
107 {
108         int exitrequested = KX_EXIT_REQUEST_NO_REQUEST;
109         
110         Main* blenderdata = maggie1;
111
112         char* startscenename = scenename;
113         char pathname[160];
114         strcpy (pathname, blenderdata->name);
115         STR_String exitstring = "";
116         BlendFileData *bfd= NULL;
117
118         // Acquire Python's GIL (global interpreter lock)
119         // so we can safely run Python code and API calls
120         PyGILState_STATE gilstate = PyGILState_Ensure();
121         
122         PyObject *pyGlobalDict = PyDict_New(); /* python utility storage, spans blend file loading */
123         
124         bgl::InitExtensions(true);
125
126         do
127         {
128                 View3D *v3d= (View3D*) area->spacedata.first;
129
130                 // get some preferences
131                 SYS_SystemHandle syshandle = SYS_GetSystem();
132                 bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
133                 bool usefixed = (SYS_GetCommandLineInt(syshandle, "fixedtime", 0) != 0);
134                 bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
135                 bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
136                 bool game2ipo = (SYS_GetCommandLineInt(syshandle, "game2ipo", 0) != 0);
137                 bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0);
138
139                 // create the canvas, rasterizer and rendertools
140                 RAS_ICanvas* canvas = new KX_BlenderCanvas(area);
141                 canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
142                 RAS_IRenderTools* rendertools = new KX_BlenderRenderTools();
143                 RAS_IRasterizer* rasterizer = NULL;
144                 
145                 if(displaylists) {
146                         if (GLEW_VERSION_1_1)
147                                 rasterizer = new RAS_ListRasterizer(canvas, true, true);
148                         else
149                                 rasterizer = new RAS_ListRasterizer(canvas);
150                 }
151                 else if (GLEW_VERSION_1_1)
152                         rasterizer = new RAS_VAOpenGLRasterizer(canvas, false);
153                 else
154                         rasterizer = new RAS_OpenGLRasterizer(canvas);
155                 
156                 // create the inputdevices
157                 KX_BlenderKeyboardDevice* keyboarddevice = new KX_BlenderKeyboardDevice();
158                 KX_BlenderMouseDevice* mousedevice = new KX_BlenderMouseDevice();
159                 
160                 // create a networkdevice
161                 NG_NetworkDeviceInterface* networkdevice = new
162                         NG_LoopBackNetworkDeviceInterface();
163                 
164                 //
165                 SYS_SystemHandle hSystem = SYS_GetSystem();
166                 bool noaudio = SYS_GetCommandLineInt(hSystem,"noaudio",0);
167
168                 if (noaudio)/*(noaudio) intrr: disable game engine audio (openal) */
169                         SND_DeviceManager::SetDeviceType(snd_e_dummydevice);
170
171                 // get an audiodevice
172                 SND_DeviceManager::Subscribe();
173                 SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
174                 audiodevice->UseCD();
175                 
176                 // create a ketsji/blendersystem (only needed for timing and stuff)
177                 KX_BlenderSystem* kxsystem = new KX_BlenderSystem();
178                 
179                 // create the ketsjiengine
180                 KX_KetsjiEngine* ketsjiengine = new KX_KetsjiEngine(kxsystem);
181                 
182                 // set the devices
183                 ketsjiengine->SetKeyboardDevice(keyboarddevice);
184                 ketsjiengine->SetMouseDevice(mousedevice);
185                 ketsjiengine->SetNetworkDevice(networkdevice);
186                 ketsjiengine->SetCanvas(canvas);
187                 ketsjiengine->SetRenderTools(rendertools);
188                 ketsjiengine->SetRasterizer(rasterizer);
189                 ketsjiengine->SetNetworkDevice(networkdevice);
190                 ketsjiengine->SetAudioDevice(audiodevice);
191                 ketsjiengine->SetUseFixedTime(usefixed);
192                 ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
193
194                 
195         
196                 // some blender stuff
197                 MT_CmMatrix4x4 projmat;
198                 MT_CmMatrix4x4 viewmat;
199                 float camzoom;
200                 int i;
201                 
202                 for (i = 0; i < 16; i++)
203                 {
204                         float *viewmat_linear= (float*) v3d->viewmat;
205                         viewmat.setElem(i, viewmat_linear[i]);
206                 }
207                 for (i = 0; i < 16; i++)
208                 {
209                         float *projmat_linear = (float*) area->winmat;
210                         projmat.setElem(i, projmat_linear[i]);
211                 }
212                 
213                 if(v3d->persp==V3D_CAMOB) {
214                         camzoom = (1.41421 + (v3d->camzoom / 50.0));
215                         camzoom *= camzoom;
216                 }
217                 else
218                         camzoom = 2.0;
219
220                 camzoom = 4.0 / camzoom;
221                 
222                 ketsjiengine->SetDrawType(v3d->drawtype);
223                 ketsjiengine->SetCameraZoom(camzoom);
224                 
225                 // if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file
226                 if (exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME || exitrequested == KX_EXIT_REQUEST_RESTART_GAME)
227                 {
228                         exitrequested = KX_EXIT_REQUEST_NO_REQUEST;
229                         if (bfd) BLO_blendfiledata_free(bfd);
230                         
231                         char basedpath[240];
232                         // base the actuator filename with respect
233                         // to the original file working directory
234                         if (exitstring != "")
235                                 strcpy(basedpath, exitstring.Ptr());
236
237                         BLI_convertstringcode(basedpath, pathname);
238                         bfd = load_game_data(basedpath);
239                         
240                         // if it wasn't loaded, try it forced relative
241                         if (!bfd)
242                         {
243                                 // just add "//" in front of it
244                                 char temppath[242];
245                                 strcpy(temppath, "//");
246                                 strcat(temppath, basedpath);
247                                 
248                                 BLI_convertstringcode(temppath, pathname);
249                                 bfd = load_game_data(temppath);
250                         }
251                         
252                         // if we got a loaded blendfile, proceed
253                         if (bfd)
254                         {
255                                 blenderdata = bfd->main;
256                                 startscenename = bfd->curscene->id.name + 2;
257                         }
258                         // else forget it, we can't find it
259                         else
260                         {
261                                 exitrequested = KX_EXIT_REQUEST_QUIT_GAME;
262                         }
263                 }
264                 
265                 Scene *blscene = NULL;
266                 if (!bfd)
267                 {
268                         blscene = (Scene*) blenderdata->scene.first;
269                         for (Scene *sce= (Scene*) blenderdata->scene.first; sce; sce= (Scene*) sce->id.next)
270                         {
271                                 if (startscenename == (sce->id.name+2))
272                                 {
273                                         blscene = sce;
274                                         break;
275                                 }
276                         }
277                 } else {
278                         blscene = bfd->curscene;
279                 }
280
281                 if (blscene)
282                 {
283                         int startFrame = blscene->r.cfra;
284                         ketsjiengine->SetGame2IpoMode(game2ipo,startFrame);
285                 }
286
287
288                 // Quad buffered needs a special window.
289                 if (blscene->r.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
290                         rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->r.stereomode);
291                 
292                 if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME)
293                 {
294                         if (v3d->persp != V3D_CAMOB)
295                         {
296                                 ketsjiengine->EnableCameraOverride(startscenename);
297                                 ketsjiengine->SetCameraOverrideUseOrtho((v3d->persp == V3D_ORTHO));
298                                 ketsjiengine->SetCameraOverrideProjectionMatrix(projmat);
299                                 ketsjiengine->SetCameraOverrideViewMatrix(viewmat);
300                                 ketsjiengine->SetCameraOverrideClipping(v3d->near, v3d->far);
301                         }
302                         
303                         // create a scene converter, create and convert the startingscene
304                         KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(blenderdata,sipo, ketsjiengine);
305                         ketsjiengine->SetSceneConverter(sceneconverter);
306                         sceneconverter->addInitFromFrame=false;
307                         if (always_use_expand_framing)
308                                 sceneconverter->SetAlwaysUseExpandFraming(true);
309
310                         bool usemat = false, useglslmat = false;
311
312                         if(GLEW_ARB_multitexture && GLEW_VERSION_1_1)
313                                 usemat = true;
314
315                         if(GPU_extensions_minimum_support())
316                                 useglslmat = true;
317                         else if(G.fileflags & G_FILE_GAME_MAT_GLSL)
318                                 usemat = false;
319
320                         sceneconverter->SetMaterials(usemat && (G.fileflags & G_FILE_GAME_MAT));
321                         sceneconverter->SetGLSLMaterials(useglslmat && (G.fileflags & G_FILE_GAME_MAT_GLSL));
322                                         
323                         KX_Scene* startscene = new KX_Scene(keyboarddevice,
324                                 mousedevice,
325                                 networkdevice,
326                                 audiodevice,
327                                 startscenename,
328                                 blscene);
329                         
330                         // some python things
331                         PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest);
332                         ketsjiengine->SetPythonDictionary(dictionaryobject);
333                         initRasterizer(rasterizer, canvas);
334                         PyObject *gameLogic = initGameLogic(ketsjiengine, startscene);
335                         PyDict_SetItemString(PyModule_GetDict(gameLogic), "globalDict", pyGlobalDict); // Same as importing the module.
336                         PyObject *gameLogic_keys = PyDict_Keys(PyModule_GetDict(gameLogic));
337                         PyDict_SetItemString(dictionaryobject, "GameLogic", gameLogic); // Same as importing the module.
338                         
339                         initGameKeys();
340                         initPythonConstraintBinding();
341                         initMathutils();
342
343                         if (sceneconverter)
344                         {
345                                 // convert and add scene
346                                 sceneconverter->ConvertScene(
347                                         startscenename,
348                                         startscene,
349                                         dictionaryobject,
350                                         keyboarddevice,
351                                         rendertools,
352                                         canvas);
353                                 ketsjiengine->AddScene(startscene);
354                                 
355                                 // init the rasterizer
356                                 rasterizer->Init();
357                                 
358                                 // start the engine
359                                 ketsjiengine->StartEngine(true);
360                                 
361
362                                 // Set the animation playback rate for ipo's and actions
363                                 // the framerate below should patch with FPS macro defined in blendef.h
364                                 // Could be in StartEngine set the framerate, we need the scene to do this
365                                 ketsjiengine->SetAnimFrameRate( (((double) blscene->r.frs_sec) / blscene->r.frs_sec_base) );
366                                 
367                                 // the mainloop
368                                 printf("\nBlender Game Engine Started\n\n");
369                                 while (!exitrequested)
370                                 {
371                                         // first check if we want to exit
372                                         exitrequested = ketsjiengine->GetExitCode();
373                                         
374                                         // kick the engine
375                                         bool render = ketsjiengine->NextFrame();
376                                         
377                                         if (render)
378                                         {
379                                                 // render the frame
380                                                 ketsjiengine->Render();
381                                         }
382                                         
383                                         // test for the ESC key
384                                         while (qtest())
385                                         {
386                                                 short val; 
387                                                 unsigned short event = extern_qread(&val);
388                                                 
389                                                 if (keyboarddevice->ConvertBlenderEvent(event,val))
390                                                         exitrequested = KX_EXIT_REQUEST_BLENDER_ESC;
391                                                 
392                                                         /* Coordinate conversion... where
393                                                         * should this really be?
394                                                 */
395                                                 if (event==MOUSEX) {
396                                                         val = val - scrarea_get_win_x(area);
397                                                 } else if (event==MOUSEY) {
398                                                         val = scrarea_get_win_height(area) - (val - scrarea_get_win_y(area)) - 1;
399                                                 }
400                                                 
401                                                 mousedevice->ConvertBlenderEvent(event,val);
402                                         }
403                                 }
404                                 printf("\nBlender Game Engine Finished\n\n");
405                                 exitstring = ketsjiengine->GetExitString();
406                                 
407                                 // when exiting the mainloop
408                                 
409                                 // Clears the dictionary by hand:
410                                 // This prevents, extra references to global variables
411                                 // inside the GameLogic dictionary when the python interpreter is finalized.
412                                 // which allows the scene to safely delete them :)
413                                 // see: (space.c)->start_game
414                                 
415                                 //PyDict_Clear(PyModule_GetDict(gameLogic));
416                                 
417                                 // Keep original items, means python plugins will autocomplete members
418                                 int listIndex;
419                                 PyObject *gameLogic_keys_new = PyDict_Keys(PyModule_GetDict(gameLogic));
420                                 for (listIndex=0; listIndex < PyList_Size(gameLogic_keys_new); listIndex++)  {
421                                         PyObject* item = PyList_GET_ITEM(gameLogic_keys_new, listIndex);
422                                         if (!PySequence_Contains(gameLogic_keys, item)) {
423                                                 PyDict_DelItem( PyModule_GetDict(gameLogic), item);
424                                         }
425                                 }
426                                 Py_DECREF(gameLogic_keys_new);
427                                 gameLogic_keys_new = NULL;
428                                 
429                                 ketsjiengine->StopEngine();
430                                 exitGamePythonScripting();
431                                 networkdevice->Disconnect();
432                         }
433                         if (sceneconverter)
434                         {
435                                 delete sceneconverter;
436                                 sceneconverter = NULL;
437                         }
438                         
439                         Py_DECREF(gameLogic_keys);
440                         gameLogic_keys = NULL;
441                 }
442                 // set the cursor back to normal
443                 canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
444                 
445                 // clean up some stuff
446                 audiodevice->StopCD();
447                 
448                 if (ketsjiengine)
449                 {
450                         delete ketsjiengine;
451                         ketsjiengine = NULL;
452                 }
453                 if (kxsystem)
454                 {
455                         delete kxsystem;
456                         kxsystem = NULL;
457                 }
458                 if (networkdevice)
459                 {
460                         delete networkdevice;
461                         networkdevice = NULL;
462                 }
463                 if (keyboarddevice)
464                 {
465                         delete keyboarddevice;
466                         keyboarddevice = NULL;
467                 }
468                 if (mousedevice)
469                 {
470                         delete mousedevice;
471                         mousedevice = NULL;
472                 }
473                 if (rasterizer)
474                 {
475                         delete rasterizer;
476                         rasterizer = NULL;
477                 }
478                 if (rendertools)
479                 {
480                         delete rendertools;
481                         rendertools = NULL;
482                 }
483                 if (canvas)
484                 {
485                         delete canvas;
486                         canvas = NULL;
487                 }
488                 SND_DeviceManager::Unsubscribe();
489         
490         } while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME);
491
492         if (bfd) BLO_blendfiledata_free(bfd);
493
494         // Release Python's GIL
495         PyGILState_Release(gilstate);
496 }
497
498 extern "C" void StartKetsjiShellSimulation(struct ScrArea *area,
499                                                                  char* scenename,
500                                                                  struct Main* maggie,
501                                                                  struct SpaceIpo *sipo,
502                                                                  int always_use_expand_framing)
503 {
504     int exitrequested = KX_EXIT_REQUEST_NO_REQUEST;
505
506         Main* blenderdata = maggie;
507
508         char* startscenename = scenename;
509         char pathname[160];
510         strcpy (pathname, maggie->name);
511         STR_String exitstring = "";
512         BlendFileData *bfd= NULL;
513
514         // Acquire Python's GIL (global interpreter lock)
515         // so we can safely run Python code and API calls
516         PyGILState_STATE gilstate = PyGILState_Ensure();
517
518         bgl::InitExtensions(true);
519
520         do
521         {
522
523                 // get some preferences
524                 SYS_SystemHandle syshandle = SYS_GetSystem();
525                 bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
526                 bool usefixed = (SYS_GetCommandLineInt(syshandle, "fixedtime", 0) != 0);
527                 bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
528                 bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
529                 bool game2ipo = true;//(SYS_GetCommandLineInt(syshandle, "game2ipo", 0) != 0);
530                 bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0);
531                 bool usemat = false;
532
533                 // create the canvas, rasterizer and rendertools
534                 RAS_ICanvas* canvas = new KX_BlenderCanvas(area);
535                 //canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
536                 RAS_IRenderTools* rendertools = new KX_BlenderRenderTools();
537                 RAS_IRasterizer* rasterizer = NULL;
538
539                 if(displaylists) {
540                         if (GLEW_VERSION_1_1)
541                                 rasterizer = new RAS_ListRasterizer(canvas, true, true);
542                         else
543                                 rasterizer = new RAS_ListRasterizer(canvas);
544                 }
545                 else if (GLEW_VERSION_1_1)
546                         rasterizer = new RAS_VAOpenGLRasterizer(canvas, false);
547                 else
548                         rasterizer = new RAS_OpenGLRasterizer(canvas);
549
550                 // create the inputdevices
551                 KX_BlenderKeyboardDevice* keyboarddevice = new KX_BlenderKeyboardDevice();
552                 KX_BlenderMouseDevice* mousedevice = new KX_BlenderMouseDevice();
553
554                 // create a networkdevice
555                 NG_NetworkDeviceInterface* networkdevice = new
556                         NG_LoopBackNetworkDeviceInterface();
557
558                 // get an audiodevice
559                 SND_DeviceManager::Subscribe();
560                 SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
561                 audiodevice->UseCD();
562
563                 // create a ketsji/blendersystem (only needed for timing and stuff)
564                 KX_BlenderSystem* kxsystem = new KX_BlenderSystem();
565
566                 // create the ketsjiengine
567                 KX_KetsjiEngine* ketsjiengine = new KX_KetsjiEngine(kxsystem);
568
569                 Scene *blscene = NULL;
570                 if (!bfd)
571                 {
572                         blscene = (Scene*) maggie->scene.first;
573                         for (Scene *sce= (Scene*) maggie->scene.first; sce; sce= (Scene*) sce->id.next)
574                         {
575                                 if (startscenename == (sce->id.name+2))
576                                 {
577                                         blscene = sce;
578                                         break;
579                                 }
580                         }
581                 } else {
582                         blscene = bfd->curscene;
583                 }
584         int cframe = 1, startFrame;
585                 if (blscene)
586                 {
587                         cframe=blscene->r.cfra;
588                         startFrame = blscene->r.sfra;
589                         blscene->r.cfra=startFrame;
590                         update_for_newframe();
591                         ketsjiengine->SetGame2IpoMode(game2ipo,startFrame);
592                 }
593
594                 // Quad buffered needs a special window.
595                 if (blscene->r.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
596                         rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->r.stereomode);
597
598                 if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME)
599                 {
600                         // create a scene converter, create and convert the startingscene
601                         KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(maggie,sipo, ketsjiengine);
602                         ketsjiengine->SetSceneConverter(sceneconverter);
603                         sceneconverter->addInitFromFrame=true;
604                         
605                         if (always_use_expand_framing)
606                                 sceneconverter->SetAlwaysUseExpandFraming(true);
607
608                         if(usemat)
609                                 sceneconverter->SetMaterials(true);
610
611                         KX_Scene* startscene = new KX_Scene(keyboarddevice,
612                                 mousedevice,
613                                 networkdevice,
614                                 audiodevice,
615                                 startscenename,
616                                 blscene);
617
618                         // some python things
619                         PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest);
620                         ketsjiengine->SetPythonDictionary(dictionaryobject);
621                         initRasterizer(rasterizer, canvas);
622                         PyObject *gameLogic = initGameLogic(ketsjiengine, startscene);
623                         PyDict_SetItemString(dictionaryobject, "GameLogic", gameLogic); // Same as importing the module
624                         initGameKeys();
625                         initPythonConstraintBinding();
626                         initMathutils();
627
628                         if (sceneconverter)
629                         {
630                                 // convert and add scene
631                                 sceneconverter->ConvertScene(
632                                         startscenename,
633                                         startscene,
634                                         dictionaryobject,
635                                         keyboarddevice,
636                                         rendertools,
637                                         canvas);
638                                 ketsjiengine->AddScene(startscene);
639
640                                 // start the engine
641                                 ketsjiengine->StartEngine(false);
642                                 
643                                 ketsjiengine->SetUseFixedTime(true);
644                                 
645                                 ketsjiengine->SetTicRate(
646                                         (double) blscene->r.frs_sec /
647                                         (double) blscene->r.frs_sec_base);
648
649                                 // the mainloop
650                                 while ((blscene->r.cfra<=blscene->r.efra)&&(!exitrequested))
651                                 {
652                     printf("frame %i\n",blscene->r.cfra);
653                     // first check if we want to exit
654                                         exitrequested = ketsjiengine->GetExitCode();
655         
656                                         // kick the engine
657                                         ketsjiengine->NextFrame();
658                                     blscene->r.cfra=blscene->r.cfra+1;
659                                     update_for_newframe();
660                                         
661                                 }
662                                 exitstring = ketsjiengine->GetExitString();
663                         }
664                         if (sceneconverter)
665                         {
666                                 delete sceneconverter;
667                                 sceneconverter = NULL;
668                         }
669                 }
670                 blscene->r.cfra=cframe;
671                 // set the cursor back to normal
672                 canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
673
674                 // clean up some stuff
675                 audiodevice->StopCD();
676                 if (ketsjiengine)
677                 {
678                         delete ketsjiengine;
679                         ketsjiengine = NULL;
680                 }
681                 if (kxsystem)
682                 {
683                         delete kxsystem;
684                         kxsystem = NULL;
685                 }
686                 if (networkdevice)
687                 {
688                         delete networkdevice;
689                         networkdevice = NULL;
690                 }
691                 if (keyboarddevice)
692                 {
693                         delete keyboarddevice;
694                         keyboarddevice = NULL;
695                 }
696                 if (mousedevice)
697                 {
698                         delete mousedevice;
699                         mousedevice = NULL;
700                 }
701                 SND_DeviceManager::Unsubscribe();
702
703         } while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME);
704         if (bfd) BLO_blendfiledata_free(bfd);
705
706         // Release Python's GIL
707         PyGILState_Release(gilstate);
708 }