[GameEngine] Commit all Kester's changes made to the gameengine to restore 2.25 like...
[blender.git] / source / gameengine / GamePlayer / ghost / GPG_Application.cpp
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  * GHOST Blender Player application implementation file.
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #ifdef WIN32
39         #pragma warning (disable:4786) // suppress stl-MSVC debug info warning
40 #endif
41
42 #include "GPG_Application.h"
43
44 #include <iostream>
45 #include <assert.h>
46
47 /**********************************
48  * Begin Blender include block
49  **********************************/
50 #ifdef __cplusplus
51 extern "C"
52 {
53 #endif  // __cplusplus
54 #include "BLI_blenlib.h"
55 #include "BLO_readfile.h"
56 #ifdef __cplusplus
57 }
58 #endif // __cplusplus
59 /**********************************
60  * End Blender include block
61  **********************************/
62
63
64 #include "SYS_System.h"
65 #include "KX_KetsjiEngine.h"
66
67 // include files needed by "KX_BlenderSceneConverter.h"
68 #include "GEN_Map.h"
69 #include "SCA_IActuator.h"
70 #include "RAS_MeshObject.h"
71 #include "RAS_OpenGLRasterizer.h"
72 #include "KX_PythonInit.h"
73 #include "KX_PyConstraintBinding.h"
74
75 #include "KX_BlenderSceneConverter.h"
76 #include "NG_LoopBackNetworkDeviceInterface.h"
77 #include "SND_DeviceManager.h"
78
79 #include "GPC_MouseDevice.h"
80 #include "GPC_RenderTools.h"
81 #include "GPG_Canvas.h" 
82 #include "GPG_KeyboardDevice.h"
83 #include "GPG_System.h"
84
85 #include "STR_String.h"
86
87 #include "GHOST_ISystem.h"
88 #include "GHOST_IEvent.h"
89 #include "GHOST_IEventConsumer.h"
90 #include "GHOST_IWindow.h"
91 #include "GHOST_Rect.h"
92
93
94 static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time);
95
96 static GHOST_ISystem* fSystem = 0;
97 static const int kTimerFreq = 10;
98
99 GPG_Application::GPG_Application(GHOST_ISystem* system, struct Main *maggie, STR_String startSceneName)
100         : m_maggie(maggie), m_startSceneName(startSceneName), m_exitRequested(0),
101           m_system(system), m_mainWindow(0), m_frameTimer(0), m_cursor(GHOST_kStandardCursorFirstCursor),
102           m_mouse(0), m_keyboard(0), m_rasterizer(0), m_canvas(0), m_rendertools(0), m_kxsystem(0), m_networkdevice(0), m_audiodevice(0), m_sceneconverter(0),
103           m_engineInitialized(0), m_engineRunning(0), m_ketsjiengine(0)
104 {
105         fSystem = system;
106 }
107
108
109
110 GPG_Application::~GPG_Application(void)
111 {
112         exitEngine();
113         fSystem->disposeWindow(m_mainWindow);
114 }
115
116
117
118 bool GPG_Application::SetGameEngineData(struct Main *maggie, STR_String startSceneName)
119 {
120         bool result = false;
121
122         if (maggie != NULL && startSceneName != "")
123         {
124                 m_maggie = maggie;
125                 m_startSceneName = startSceneName;
126                 result = true;
127         }
128
129         return result;
130 }
131
132
133
134 bool GPG_Application::startWindow(STR_String& title,
135         int windowLeft,
136         int windowTop,
137         int windowWidth,
138         int windowHeight,
139         const bool stereoVisual,
140         const int stereoMode)
141 {
142         bool success;
143         // Create the main window
144         //STR_String title ("Blender Player - GHOST");
145         m_mainWindow = fSystem->createWindow(title, windowLeft, windowTop, windowWidth, windowHeight, GHOST_kWindowStateNormal,
146                 GHOST_kDrawingContextTypeOpenGL, stereoVisual);
147     if (!m_mainWindow) {
148                 printf("error: could not create main window\n");
149         exit(-1);
150     }
151
152         /* Check the size of the client rectangle of the window and resize the window
153          * so that the client rectangle has the size requested.
154          */
155         m_mainWindow->setClientSize(windowWidth, windowHeight);
156         m_mainWindow->setCursorVisibility(false);
157
158         success = initEngine(m_mainWindow, stereoMode);
159         if (success) {
160                 success = startEngine();
161         }
162         return success;
163 }
164
165
166
167 bool GPG_Application::startFullScreen(
168                 int width,
169                 int height,
170                 int bpp,int frequency,
171                 const bool stereoVisual,
172                 const int stereoMode)
173 {
174         bool success;
175         // Create the main window
176         GHOST_DisplaySetting setting;
177         setting.xPixels = width;
178         setting.yPixels = height;
179         setting.bpp = bpp;
180         setting.frequency = frequency;
181
182         fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual);
183         m_mainWindow->setCursorVisibility(false);
184
185         success = initEngine(m_mainWindow, stereoMode);
186         if (success) {
187                 success = startEngine();
188         }
189         return success;
190 }
191
192
193
194 bool GPG_Application::StartGameEngine(int stereoMode)
195 {
196         bool success = initEngine(m_mainWindow, stereoMode);
197         
198         if (success)
199                 success = startEngine();
200
201         return success;
202 }
203
204
205
206 void GPG_Application::StopGameEngine()
207 {
208         exitEngine();
209 }
210
211
212
213 bool GPG_Application::processEvent(GHOST_IEvent* event)
214 {
215         bool handled = true;
216
217         switch (event->getType())
218         {
219                 case GHOST_kEventUnknown:
220                         break;
221
222                 case GHOST_kEventButtonDown:
223                         handled = handleButton(event, true);
224                         break;
225
226                 case GHOST_kEventButtonUp:
227                         handled = handleButton(event, false);
228                         break;
229
230                 case GHOST_kEventCursorMove:
231                         handled = handleCursorMove(event);
232                         break;
233
234                 case GHOST_kEventKeyDown:
235                         handleKey(event, true);
236                         break;
237
238                 case GHOST_kEventKeyUp:
239                         handleKey(event, false);
240                         break;
241
242
243                 case GHOST_kEventWindowClose:
244                         m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
245                         break;
246
247                 case GHOST_kEventWindowActivate:
248                         handled = false;
249                         break;
250                 case GHOST_kEventWindowDeactivate:
251                         handled = false;
252                         break;
253
254                 case GHOST_kEventWindowUpdate:
255                         {
256                                 GHOST_IWindow* window = event->getWindow();
257                                 if (!m_system->validWindow(window)) break;
258                                 // Update the state of the game engine
259                                 if (m_kxsystem && !m_exitRequested)
260                                 {
261                                         // Proceed to next frame
262                                         window->activateDrawingContext();
263
264                                         // first check if we want to exit
265                                         m_exitRequested = m_ketsjiengine->GetExitCode();
266                                         
267                                         // kick the engine
268                                         m_ketsjiengine->NextFrame();
269                                         
270                                         // render the frame
271                                         m_ketsjiengine->Render();
272                                 }
273                                 m_exitString = m_ketsjiengine->GetExitString();
274                         }
275                         break;
276                 
277                 case GHOST_kEventWindowSize:
278                         {
279                         GHOST_IWindow* window = event->getWindow();
280                         if (!m_system->validWindow(window)) break;
281                         if (m_canvas) {
282                                 GHOST_Rect bnds;
283                                 window->getClientBounds(bnds);
284                                 m_canvas->Resize(bnds.getWidth(), bnds.getHeight());
285                         }
286                         }
287                         break;
288                 
289                 default:
290                         handled = false;
291                         break;
292         }
293         return handled;
294 }
295
296
297
298 int GPG_Application::getExitRequested(void)
299 {
300         return m_exitRequested;
301 }
302
303
304
305 const STR_String& GPG_Application::getExitString(void)
306 {
307         return m_exitString;
308 }
309
310
311
312 bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
313 {
314         if (!m_engineInitialized)
315         {
316                 // get and set the preferences
317                 SYS_SystemHandle syshandle = SYS_GetSystem();
318                 if (syshandle)
319                 {
320                         // SYS_WriteCommandLineInt(syshandle, "fixedtime", 0);
321                         SYS_WriteCommandLineInt(syshandle, "vertexarrays",1);           
322                         //bool properties       = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
323                         //bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
324                         //bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
325                         
326                         // create the canvas, rasterizer and rendertools
327                         m_canvas = new GPG_Canvas(window);
328                         if (m_canvas)
329                         {
330                                 m_canvas->Init();                               
331                                 m_rendertools = new GPC_RenderTools();
332                                 if (m_rendertools)
333                                 {
334                                         m_rasterizer = new RAS_OpenGLRasterizer(m_canvas);
335                                         m_rasterizer->SetStereoMode(stereoMode);
336                                         if (m_rasterizer)
337                                         {
338                                                 // create the inputdevices
339                                                 m_keyboard = new GPG_KeyboardDevice();
340                                                 if (m_keyboard)
341                                                 {
342                                                         m_mouse = new GPC_MouseDevice();
343                                                         if (m_mouse)
344                                                         {
345                                                                 // create a networkdevice
346                                                                 m_networkdevice = new NG_LoopBackNetworkDeviceInterface();
347                                                                 if (m_networkdevice)
348                                                                 {
349                                                                         // get an audiodevice
350                                                                         SND_DeviceManager::Subscribe();
351                                                                         m_audiodevice = SND_DeviceManager::Instance();
352                                                                         if (m_audiodevice)
353                                                                         {
354                                                                                 m_audiodevice->UseCD();
355                                                                                 // create a ketsjisystem (only needed for timing and stuff)
356                                                                                 m_kxsystem = new GPG_System (m_system);
357                                                                                 if (m_kxsystem)
358                                                                                 {
359                                                                                         // create the ketsjiengine
360                                                                                         m_ketsjiengine = new KX_KetsjiEngine(m_kxsystem);
361                                                                                         
362                                                                                         // set the devices
363                                                                                         m_ketsjiengine->SetKeyboardDevice(m_keyboard);
364                                                                                         m_ketsjiengine->SetMouseDevice(m_mouse);
365                                                                                         m_ketsjiengine->SetNetworkDevice(m_networkdevice);
366                                                                                         m_ketsjiengine->SetCanvas(m_canvas);
367                                                                                         m_ketsjiengine->SetRenderTools(m_rendertools);
368                                                                                         m_ketsjiengine->SetRasterizer(m_rasterizer);
369                                                                                         m_ketsjiengine->SetNetworkDevice(m_networkdevice);
370                                                                                         m_ketsjiengine->SetAudioDevice(m_audiodevice);
371
372                                                                                         m_ketsjiengine->SetUseFixedTime(false);
373                                                                                         //m_ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
374
375                                                                                         m_engineInitialized = true;
376                                                                                 }
377                                                                         }
378                                                                 }
379                                                         }
380                                                 } 
381                                         }
382                                 }
383                         }
384                 }
385         }
386
387         return m_engineInitialized;
388 }
389
390
391
392 bool GPG_Application::startEngine(void)
393 {
394         if (m_engineRunning) {
395                 return false;
396         }
397         
398         // Temporary hack to disable banner display for NaN approved content.
399         /*
400         m_canvas->SetBannerDisplayEnabled(true);        
401         Camera* cam;
402         cam = (Camera*)G.scene->camera->data;
403         if (cam) {
404         if (((cam->flag) & 48)==48) {
405         m_canvas->SetBannerDisplayEnabled(false);
406         }
407         }
408         else {
409         showError(CString("Camera data invalid."));
410         return false;
411         }
412         */
413         
414         // create a scene converter, create and convert the stratingscene
415         m_sceneconverter = new KX_BlenderSceneConverter(m_maggie, m_ketsjiengine);
416         if (m_sceneconverter)
417         {
418                 STR_String startscenename = m_startSceneName.Ptr();
419                 m_ketsjiengine->SetSceneConverter(m_sceneconverter);
420                 
421                 //      if (always_use_expand_framing)
422                 //              sceneconverter->SetAlwaysUseExpandFraming(true);
423                 
424
425                 KX_Scene* startscene = new KX_Scene(m_keyboard,
426                         m_mouse,
427                         m_networkdevice,
428                         m_audiodevice,
429                         startscenename);
430                 
431                 // some python things
432                 PyObject* m_dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest);
433                 m_ketsjiengine->SetPythonDictionary(m_dictionaryobject);
434                 initRasterizer(m_rasterizer, m_canvas);
435                 initGameLogic(startscene);
436                 initGameKeys();
437                 initPythonConstraintBinding();
438                 
439                 m_sceneconverter->ConvertScene(
440                         startscenename,
441                         startscene,
442                         m_dictionaryobject,
443                         m_keyboard,
444                         m_rendertools,
445                         m_canvas);
446                 m_ketsjiengine->AddScene(startscene);
447                 
448                 // Create a timer that is used to kick the engine
449                 if (!m_frameTimer) {
450                         m_frameTimer = m_system->installTimer(0, kTimerFreq, frameTimerProc, m_mainWindow);
451                 }
452                 m_rasterizer->Init();
453                 m_ketsjiengine->StartEngine();
454                 m_engineRunning = true;
455                 
456         }
457         
458         if (!m_engineRunning)
459         {
460                 stopEngine();
461         }
462         
463         return m_engineRunning;
464 }
465
466
467 void GPG_Application::stopEngine()
468 {
469         // when exiting the mainloop
470         exitGamePythonScripting();
471         m_ketsjiengine->StopEngine();
472         m_networkdevice->Disconnect();
473
474         if (m_sceneconverter) {
475                 delete m_sceneconverter;
476                 m_sceneconverter = 0;
477         }
478         if (m_system && m_frameTimer) {
479                 m_system->removeTimer(m_frameTimer);
480                 m_frameTimer = 0;
481         }
482         m_engineRunning = false;
483 }
484
485
486 void GPG_Application::exitEngine()
487 {
488         if (m_ketsjiengine)
489         {
490                 stopEngine();
491                 delete m_ketsjiengine;
492                 m_ketsjiengine = 0;
493         }
494         if (m_kxsystem)
495         {
496                 delete m_kxsystem;
497                 m_kxsystem = 0;
498         }
499         if (m_audiodevice)
500         {
501                 SND_DeviceManager::Unsubscribe();
502                 m_audiodevice = 0;
503         }
504         if (m_networkdevice)
505         {
506                 delete m_networkdevice;
507                 m_networkdevice = 0;
508         }
509         if (m_mouse)
510         {
511                 delete m_mouse;
512                 m_mouse = 0;
513         }
514         if (m_keyboard)
515         {
516                 delete m_keyboard;
517                 m_keyboard = 0;
518         }
519         if (m_rasterizer)
520         {
521                 delete m_rasterizer;
522                 m_rasterizer = 0;
523         }
524         if (m_rendertools)
525         {
526                 delete m_rendertools;
527                 m_rendertools = 0;
528         }
529         if (m_canvas)
530         {
531                 delete m_canvas;
532                 m_canvas = 0;
533         }
534
535         m_exitRequested = 0;
536         m_engineInitialized = false;
537 }
538
539
540 bool GPG_Application::handleButton(GHOST_IEvent* event, bool isDown)
541 {
542         bool handled = false;
543         assert(event);
544         if (m_mouse) 
545         {
546                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
547                 GHOST_TEventButtonData* buttonData = static_cast<GHOST_TEventButtonData*>(eventData);
548                 GPC_MouseDevice::TButtonId button;
549                 switch (buttonData->button)
550                 {
551                 case GHOST_kButtonMaskMiddle:
552                         button = GPC_MouseDevice::buttonMiddle;
553                         break;
554                 case GHOST_kButtonMaskRight:
555                         button = GPC_MouseDevice::buttonRight;
556                         break;
557                 case GHOST_kButtonMaskLeft:
558                 default:
559                         button = GPC_MouseDevice::buttonLeft;
560                         break;
561                 }
562                 m_mouse->ConvertButtonEvent(button, isDown);
563                 handled = true;
564         }
565         return handled;
566 }
567
568
569 bool GPG_Application::handleCursorMove(GHOST_IEvent* event)
570 {
571         bool handled = false;
572         assert(event);
573         if (m_mouse && m_mainWindow)
574         {
575                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
576                 GHOST_TEventCursorData* cursorData = static_cast<GHOST_TEventCursorData*>(eventData);
577                 GHOST_TInt32 x, y;
578                 m_mainWindow->screenToClient(cursorData->x, cursorData->y, x, y);
579                 m_mouse->ConvertMoveEvent(x, y);
580                 handled = true;
581         }
582         return handled;
583 }
584
585
586 bool GPG_Application::handleKey(GHOST_IEvent* event, bool isDown)
587 {
588         bool handled = false;
589         assert(event);
590         if (m_keyboard)
591         {
592                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
593                 GHOST_TEventKeyData* keyData = static_cast<GHOST_TEventKeyData*>(eventData);
594                 if (fSystem->getFullScreen()) {
595                         if (keyData->key == GHOST_kKeyEsc) {
596                                 m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
597                         }
598                 }
599                 m_keyboard->ConvertEvent(keyData->key, isDown);
600                 handled = true;
601         }
602         return handled;
603 }
604
605
606
607 static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time)
608 {
609         GHOST_IWindow* window = (GHOST_IWindow*)task->getUserData();
610         if (fSystem->validWindow(window)) {
611                 window->invalidate();
612         }
613 }