contribution from RCRuiz:
[blender.git] / source / gameengine / BlenderRoutines / BL_KetsjiEmbedStart.cpp
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  * Blender's Ketsji startpoint
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #include <signal.h>
39
40 #ifdef WIN32
41 // don't show stl-warnings
42 #pragma warning (disable:4786)
43 #endif
44
45 #ifdef __APPLE__
46 #define GL_GLEXT_LEGACY 1
47 #endif 
48
49 #include "KX_BlenderGL.h"
50 #include "KX_BlenderCanvas.h"
51 #include "KX_BlenderKeyboardDevice.h"
52 #include "KX_BlenderMouseDevice.h"
53 #include "KX_BlenderRenderTools.h"
54 #include "KX_BlenderSystem.h"
55 #include "BL_Material.h"
56
57 #include "KX_KetsjiEngine.h"
58 #include "KX_BlenderSceneConverter.h"
59 #include "KX_PythonInit.h"
60 #include "KX_PyConstraintBinding.h"
61
62 #include "RAS_OpenGLRasterizer.h"
63 #include "RAS_VAOpenGLRasterizer.h"
64 #include "RAS_ListRasterizer.h"
65 #include "RAS_GLExtensionManager.h"
66
67 #include "NG_LoopBackNetworkDeviceInterface.h"
68 #include "SND_DeviceManager.h"
69
70 #include "SYS_System.h"
71
72         /***/
73
74 #include "DNA_view3d_types.h"
75 #include "DNA_screen_types.h"
76 #include "BKE_global.h"
77 #include "BIF_screen.h"
78 #include "BIF_scrarea.h"
79
80 #include "BKE_main.h"   
81 #include "BLI_blenlib.h"
82 #include "BLO_readfile.h"
83 #include "DNA_scene_types.h"
84         /***/
85
86 #ifdef __cplusplus
87 extern "C" {
88 #endif
89 #include "BSE_headerbuttons.h"
90 void update_for_newframe();
91 #ifdef __cplusplus
92 }
93 #endif
94
95 static BlendFileData *load_game_data(char *filename) {
96         BlendReadError error;
97         //this doesn't work anymore for relative paths, so use BLO_read_from_memory instead
98         //BlendFileData *bfd= BLO_read_from_file(filename, &error);
99         FILE* file = fopen(filename,"rb");
100         BlendFileData *bfd  = 0;
101         if (file)
102         {
103                 fseek(file, 0L, SEEK_END);
104                 int len= ftell(file);
105                 fseek(file, 0L, SEEK_SET);      
106                 char* filebuffer= new char[len];//MEM_mallocN(len, "text_buffer");
107                 int sizeread = fread(filebuffer,len,1,file);
108                 if (sizeread==1)
109                 {
110                         bfd = BLO_read_from_memory(filebuffer, len, &error);
111                 }
112                 fclose(file);
113         }
114
115         if (!bfd) {
116                 printf("Loading %s failed: %s\n", filename, BLO_bre_as_string(error));
117         }
118         
119         return bfd;
120 }
121
122 extern "C" void StartKetsjiShell(struct ScrArea *area,
123                                                                  char* scenename,
124                                                                  struct Main* maggie1,
125                                                                  struct SpaceIpo *sipo,
126                                                                  int always_use_expand_framing)
127 {
128         int exitrequested = KX_EXIT_REQUEST_NO_REQUEST;
129         
130         Main* blenderdata = maggie1;
131
132         char* startscenename = scenename;
133         char pathname[160];
134         strcpy (pathname, blenderdata->name);
135         STR_String exitstring = "";
136         BlendFileData *bfd= NULL;
137
138         bgl::InitExtensions(1);
139         
140         do
141         {
142                 View3D *v3d= (View3D*) area->spacedata.first;
143                 
144                 // get some preferences
145                 SYS_SystemHandle syshandle = SYS_GetSystem();
146                 bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
147                 bool usefixed = (SYS_GetCommandLineInt(syshandle, "fixedtime", 0) != 0);
148                 bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
149                 bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
150                 bool game2ipo = (SYS_GetCommandLineInt(syshandle, "game2ipo", 0) != 0);
151                 bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0);
152                 bool usemat = false;
153                 
154                 #ifdef GL_ARB_multitexture
155                 if(bgl::RAS_EXT_support._ARB_multitexture && bgl::QueryVersion(1, 1)) {
156                         usemat = (SYS_GetCommandLineInt(syshandle, "blender_material", 0) != 0);
157                         int unitmax=0;
158                         glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&unitmax);
159                         bgl::max_texture_units = MAXTEX>unitmax?unitmax:MAXTEX;
160                         //std::cout << "using(" << bgl::max_texture_units << ") of(" << unitmax << ") texture units." << std::endl;
161                 } else {
162                         bgl::max_texture_units = 0;
163                 }
164                 #endif
165
166
167                 // create the canvas, rasterizer and rendertools
168                 RAS_ICanvas* canvas = new KX_BlenderCanvas(area);
169                 canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
170                 RAS_IRenderTools* rendertools = new KX_BlenderRenderTools();
171                 RAS_IRasterizer* rasterizer = NULL;
172                 
173                 // let's see if we want to use vertexarrays or not
174                 int usevta = SYS_GetCommandLineInt(syshandle,"vertexarrays",1);
175                 bool useVertexArrays = (usevta > 0);
176                 
177                 bool lock_arrays = (displaylists && useVertexArrays);
178
179                 if(displaylists && !useVertexArrays)
180                         rasterizer = new RAS_ListRasterizer(canvas);
181                 else if (useVertexArrays && bgl::QueryVersion(1, 1))
182                         rasterizer = new RAS_VAOpenGLRasterizer(canvas, lock_arrays);
183                 else
184                         rasterizer = new RAS_OpenGLRasterizer(canvas);
185                 
186                 // create the inputdevices
187                 KX_BlenderKeyboardDevice* keyboarddevice = new KX_BlenderKeyboardDevice();
188                 KX_BlenderMouseDevice* mousedevice = new KX_BlenderMouseDevice();
189                 
190                 // create a networkdevice
191                 NG_NetworkDeviceInterface* networkdevice = new
192                         NG_LoopBackNetworkDeviceInterface();
193                 
194                 // get an audiodevice
195                 SND_DeviceManager::Subscribe();
196                 SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
197                 audiodevice->UseCD();
198                 
199                 // create a ketsji/blendersystem (only needed for timing and stuff)
200                 KX_BlenderSystem* kxsystem = new KX_BlenderSystem();
201                 
202                 // create the ketsjiengine
203                 KX_KetsjiEngine* ketsjiengine = new KX_KetsjiEngine(kxsystem);
204                 
205                 // set the devices
206                 ketsjiengine->SetKeyboardDevice(keyboarddevice);
207                 ketsjiengine->SetMouseDevice(mousedevice);
208                 ketsjiengine->SetNetworkDevice(networkdevice);
209                 ketsjiengine->SetCanvas(canvas);
210                 ketsjiengine->SetRenderTools(rendertools);
211                 ketsjiengine->SetRasterizer(rasterizer);
212                 ketsjiengine->SetNetworkDevice(networkdevice);
213                 ketsjiengine->SetAudioDevice(audiodevice);
214                 ketsjiengine->SetUseFixedTime(usefixed);
215                 ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
216
217                 
218         
219                 // some blender stuff
220                 MT_CmMatrix4x4 projmat;
221                 MT_CmMatrix4x4 viewmat;
222                 int i;
223                 
224                 for (i = 0; i < 16; i++)
225                 {
226                         float *viewmat_linear= (float*) v3d->viewmat;
227                         viewmat.setElem(i, viewmat_linear[i]);
228                 }
229                 for (i = 0; i < 16; i++)
230                 {
231                         float *projmat_linear = (float*) area->winmat;
232                         projmat.setElem(i, projmat_linear[i]);
233                 }
234                 
235                 float camzoom = (1.41421 + (v3d->camzoom / 50.0));
236                 camzoom *= camzoom;
237                 camzoom = 4.0 / camzoom;
238                 
239                 ketsjiengine->SetDrawType(v3d->drawtype);
240                 ketsjiengine->SetCameraZoom(camzoom);
241                 
242                 // if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file
243                 if (exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME || exitrequested == KX_EXIT_REQUEST_RESTART_GAME)
244                 {
245                         exitrequested = KX_EXIT_REQUEST_NO_REQUEST;
246                         if (bfd) BLO_blendfiledata_free(bfd);
247                         
248                         char basedpath[160];
249                         // base the actuator filename with respect
250                         // to the original file working directory
251                         if (exitstring != "")
252                                 strcpy(basedpath, exitstring.Ptr());
253
254                         BLI_convertstringcode(basedpath, pathname, 0);
255                         bfd = load_game_data(basedpath);
256                         
257                         // if it wasn't loaded, try it forced relative
258                         if (!bfd)
259                         {
260                                 // just add "//" in front of it
261                                 char temppath[162];
262                                 strcpy(temppath, "//");
263                                 strcat(temppath, basedpath);
264                                 
265                                 BLI_convertstringcode(temppath, pathname, 0);
266                                 bfd = load_game_data(temppath);
267                         }
268                         
269                         // if we got a loaded blendfile, proceed
270                         if (bfd)
271                         {
272                                 blenderdata = bfd->main;
273                                 startscenename = bfd->curscene->id.name + 2;
274                         }
275                         // else forget it, we can't find it
276                         else
277                         {
278                                 exitrequested = KX_EXIT_REQUEST_QUIT_GAME;
279                         }
280                 }
281                 
282                 Scene *blscene = NULL;
283                 if (!bfd)
284                 {
285                         blscene = (Scene*) blenderdata->scene.first;
286                         for (Scene *sce= (Scene*) blenderdata->scene.first; sce; sce= (Scene*) sce->id.next)
287                         {
288                                 if (startscenename == (sce->id.name+2))
289                                 {
290                                         blscene = sce;
291                                         break;
292                                 }
293                         }
294                 } else {
295                         blscene = bfd->curscene;
296                 }
297
298                 if (blscene)
299                 {
300                         int startFrame = blscene->r.cfra;
301                         ketsjiengine->SetGame2IpoMode(game2ipo,startFrame);
302                 }
303
304
305                 // Quad buffered needs a special window.
306                 if (blscene->r.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
307                         rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->r.stereomode);
308                 
309                 if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME)
310                 {
311                         if (v3d->persp != 2)
312                         {
313                                 ketsjiengine->EnableCameraOverride(startscenename);
314                                 ketsjiengine->SetCameraOverrideUseOrtho((v3d->persp == 0));
315                                 ketsjiengine->SetCameraOverrideProjectionMatrix(projmat);
316                                 ketsjiengine->SetCameraOverrideViewMatrix(viewmat);
317                         }
318                         
319                         // create a scene converter, create and convert the startingscene
320                         KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(blenderdata,sipo, ketsjiengine);
321                         ketsjiengine->SetSceneConverter(sceneconverter);
322                         sceneconverter->addInitFromFrame=false;
323                         if (always_use_expand_framing)
324                                 sceneconverter->SetAlwaysUseExpandFraming(true);
325                         
326                         if(usemat)
327                                 sceneconverter->SetMaterials(true);
328                                         
329                         KX_Scene* startscene = new KX_Scene(keyboarddevice,
330                                 mousedevice,
331                                 networkdevice,
332                                 audiodevice,
333                                 startscenename);
334                         
335                         // some python things
336                         PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest);
337                         ketsjiengine->SetPythonDictionary(dictionaryobject);
338                         initRasterizer(rasterizer, canvas);
339                         PyObject *gameLogic = initGameLogic(startscene);
340                         initGameKeys();
341                         initPythonConstraintBinding();
342
343                         
344                         if (sceneconverter)
345                         {
346                                 // convert and add scene
347                                 sceneconverter->ConvertScene(
348                                         startscenename,
349                                         startscene,
350                                         dictionaryobject,
351                                         keyboarddevice,
352                                         rendertools,
353                                         canvas);
354                                 ketsjiengine->AddScene(startscene);
355                                 
356                                 // init the rasterizer
357                                 rasterizer->Init();
358                                 
359                                 // start the engine
360                                 ketsjiengine->StartEngine(true);
361                                 
362                                 // the mainloop
363                                 while (!exitrequested)
364                                 {
365                                         // first check if we want to exit
366                                         exitrequested = ketsjiengine->GetExitCode();
367                                         
368                                         // kick the engine
369                                         bool render = ketsjiengine->NextFrame();
370                                         
371                                         if (render)
372                                         {
373                                                 // render the frame
374                                                 ketsjiengine->Render();
375                                         }
376                                         
377                                         // test for the ESC key
378                                         while (qtest())
379                                         {
380                                                 short val; 
381                                                 unsigned short event = extern_qread(&val);
382                                                 
383                                                 if (keyboarddevice->ConvertBlenderEvent(event,val))
384                                                         exitrequested = KX_EXIT_REQUEST_BLENDER_ESC;
385                                                 
386                                                         /* Coordinate conversion... where
387                                                         * should this really be?
388                                                 */
389                                                 if (event==MOUSEX) {
390                                                         val = val - scrarea_get_win_x(area);
391                                                 } else if (event==MOUSEY) {
392                                                         val = scrarea_get_win_height(area) - (val - scrarea_get_win_y(area)) - 1;
393                                                 }
394                                                 
395                                                 mousedevice->ConvertBlenderEvent(event,val);
396                                         }
397                                 }
398                                 exitstring = ketsjiengine->GetExitString();
399                                 
400                                 // when exiting the mainloop
401                                 dictionaryClearByHand(gameLogic);
402                                 ketsjiengine->StopEngine();
403                                 exitGamePythonScripting();
404                                 networkdevice->Disconnect();
405                         }
406                         if (sceneconverter)
407                         {
408                                 delete sceneconverter;
409                                 sceneconverter = NULL;
410                         }
411                 }
412                 // set the cursor back to normal
413                 canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
414                 
415                 // clean up some stuff
416                 audiodevice->StopCD();
417                 
418                 if (ketsjiengine)
419                 {
420                         delete ketsjiengine;
421                         ketsjiengine = NULL;
422                 }
423                 if (kxsystem)
424                 {
425                         delete kxsystem;
426                         kxsystem = NULL;
427                 }
428                 if (networkdevice)
429                 {
430                         delete networkdevice;
431                         networkdevice = NULL;
432                 }
433                 if (keyboarddevice)
434                 {
435                         delete keyboarddevice;
436                         keyboarddevice = NULL;
437                 }
438                 if (mousedevice)
439                 {
440                         delete mousedevice;
441                         mousedevice = NULL;
442                 }
443                 if (rasterizer)
444                 {
445                         delete rasterizer;
446                         rasterizer = NULL;
447                 }
448                 if (rendertools)
449                 {
450                         delete rendertools;
451                         rendertools = NULL;
452                 }
453                 if (canvas)
454                 {
455                         delete canvas;
456                         canvas = NULL;
457                 }
458                 SND_DeviceManager::Unsubscribe();
459         
460         } while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME);
461
462         if (bfd) BLO_blendfiledata_free(bfd);
463 }
464
465 extern "C" void StartKetsjiShellSimulation(struct ScrArea *area,
466                                                                  char* scenename,
467                                                                  struct Main* maggie,
468                                                                  struct SpaceIpo *sipo,
469                                                                  int always_use_expand_framing)
470 {
471     int exitrequested = KX_EXIT_REQUEST_NO_REQUEST;
472
473         Main* blenderdata = maggie;
474
475         char* startscenename = scenename;
476         char pathname[160];
477         strcpy (pathname, maggie->name);
478         STR_String exitstring = "";
479         BlendFileData *bfd= NULL;
480
481         bgl::InitExtensions(1);
482
483         do
484         {
485
486                 // get some preferences
487                 SYS_SystemHandle syshandle = SYS_GetSystem();
488                 bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
489                 bool usefixed = (SYS_GetCommandLineInt(syshandle, "fixedtime", 0) != 0);
490                 bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
491                 bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
492                 bool game2ipo = true;//(SYS_GetCommandLineInt(syshandle, "game2ipo", 0) != 0);
493                 bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0);
494                 bool usemat = false;
495
496                 // create the canvas, rasterizer and rendertools
497                 RAS_ICanvas* canvas = new KX_BlenderCanvas(area);
498                 //canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
499                 RAS_IRenderTools* rendertools = new KX_BlenderRenderTools();
500                 RAS_IRasterizer* rasterizer = NULL;
501
502                 // let's see if we want to use vertexarrays or not
503                 int usevta = SYS_GetCommandLineInt(syshandle,"vertexarrays",1);
504                 bool useVertexArrays = (usevta > 0);
505
506                 bool lock_arrays = (displaylists && useVertexArrays);
507
508                 if(displaylists && !useVertexArrays)
509                         rasterizer = new RAS_ListRasterizer(canvas);
510                 else if (useVertexArrays && bgl::QueryVersion(1, 1))
511                         rasterizer = new RAS_VAOpenGLRasterizer(canvas, lock_arrays);
512                 else
513                         rasterizer = new RAS_OpenGLRasterizer(canvas);
514
515                 // create the inputdevices
516                 KX_BlenderKeyboardDevice* keyboarddevice = new KX_BlenderKeyboardDevice();
517                 KX_BlenderMouseDevice* mousedevice = new KX_BlenderMouseDevice();
518
519                 // create a networkdevice
520                 NG_NetworkDeviceInterface* networkdevice = new
521                         NG_LoopBackNetworkDeviceInterface();
522
523                 // get an audiodevice
524                 SND_DeviceManager::Subscribe();
525                 SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
526                 audiodevice->UseCD();
527
528                 // create a ketsji/blendersystem (only needed for timing and stuff)
529                 KX_BlenderSystem* kxsystem = new KX_BlenderSystem();
530
531                 // create the ketsjiengine
532                 KX_KetsjiEngine* ketsjiengine = new KX_KetsjiEngine(kxsystem);
533
534                 int i;
535
536                 Scene *blscene = NULL;
537                 if (!bfd)
538                 {
539                         blscene = (Scene*) maggie->scene.first;
540                         for (Scene *sce= (Scene*) maggie->scene.first; sce; sce= (Scene*) sce->id.next)
541                         {
542                                 if (startscenename == (sce->id.name+2))
543                                 {
544                                         blscene = sce;
545                                         break;
546                                 }
547                         }
548                 } else {
549                         blscene = bfd->curscene;
550                 }
551         int cframe,startFrame;
552                 if (blscene)
553                 {
554                         cframe=blscene->r.cfra;
555                         startFrame = blscene->r.sfra;
556                         blscene->r.cfra=startFrame;
557                         update_for_newframe();
558                         ketsjiengine->SetGame2IpoMode(game2ipo,startFrame);
559                 }
560
561                 // Quad buffered needs a special window.
562                 if (blscene->r.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
563                         rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->r.stereomode);
564
565                 if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME)
566                 {
567                         // create a scene converter, create and convert the startingscene
568                         KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(maggie,sipo, ketsjiengine);
569                         ketsjiengine->SetSceneConverter(sceneconverter);
570                         sceneconverter->addInitFromFrame=true;
571                         
572                         if (always_use_expand_framing)
573                                 sceneconverter->SetAlwaysUseExpandFraming(true);
574
575                         if(usemat)
576                                 sceneconverter->SetMaterials(true);
577
578                         KX_Scene* startscene = new KX_Scene(keyboarddevice,
579                                 mousedevice,
580                                 networkdevice,
581                                 audiodevice,
582                                 startscenename);
583                         // some python things
584                         PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest);
585                         ketsjiengine->SetPythonDictionary(dictionaryobject);
586                         initRasterizer(rasterizer, canvas);
587                         PyObject *gameLogic = initGameLogic(startscene);
588                         initGameKeys();
589                         initPythonConstraintBinding();
590
591                         if (sceneconverter)
592                         {
593                                 // convert and add scene
594                                 sceneconverter->ConvertScene(
595                                         startscenename,
596                                         startscene,
597                                         dictionaryobject,
598                                         keyboarddevice,
599                                         rendertools,
600                                         canvas);
601                                 ketsjiengine->AddScene(startscene);
602
603                                 // start the engine
604                                 ketsjiengine->StartEngine(false);
605
606                                 // the mainloop
607                                 while ((blscene->r.cfra<=blscene->r.efra)&&(!exitrequested))
608                                 {
609                     printf("frame %i\n",blscene->r.cfra);
610                     // first check if we want to exit
611                                         exitrequested = ketsjiengine->GetExitCode();
612                                         /*for (int ix=0;i<geobjs->GetCount();ix++){
613                                                 KX_GameObject* gameobj = (KX_GameObject*) geobjs->GetValue(ix);
614                                                 if (!gameobj->IsDynamic()){
615                                                         //gameobj->UpdateNonDynas();//UpdateIPO((float)blscene->r.cfra,true, true, true);
616                                                         struct Object* blenderobject = sceneconverter->FindBlenderObject(gameobj);
617                                                 }
618                                         }*/
619         
620         
621                                         // kick the engine
622                                         ketsjiengine->NextFrame();
623                                     blscene->r.cfra=blscene->r.cfra+1;
624                                     update_for_newframe();
625                                         
626                                 }
627                                 exitstring = ketsjiengine->GetExitString();
628                         }
629                         if (sceneconverter)
630                         {
631                                 delete sceneconverter;
632                                 sceneconverter = NULL;
633                         }
634                 }
635                 blscene->r.cfra=cframe;
636                 // set the cursor back to normal
637                 canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
638
639                 // clean up some stuff
640                 audiodevice->StopCD();
641                 if (ketsjiengine)
642                 {
643                         delete ketsjiengine;
644                         ketsjiengine = NULL;
645                 }
646                 if (kxsystem)
647                 {
648                         delete kxsystem;
649                         kxsystem = NULL;
650                 }
651                 if (networkdevice)
652                 {
653                         delete networkdevice;
654                         networkdevice = NULL;
655                 }
656                 if (keyboarddevice)
657                 {
658                         delete keyboarddevice;
659                         keyboarddevice = NULL;
660                 }
661                 if (mousedevice)
662                 {
663                         delete mousedevice;
664                         mousedevice = NULL;
665                 }
666                 SND_DeviceManager::Unsubscribe();
667
668         } while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME);
669         if (bfd) BLO_blendfiledata_free(bfd);
670 }