1 #include "engine.h"
2 #include "random.h"
3 #include "gameEntity.h"
4 #include "Updatable.h"
5 #include "collisionable.h"
6 
7 #ifdef DEBUG
8 #include <typeinfo>
9 int DEBUG_PobjCount;
10 PObject* DEBUG_PobjListStart;
11 #endif
12 
13 #ifdef WIN32
14 #include <windows.h>
15 
16 namespace
17 {
18     HINSTANCE exchndl = nullptr;
19 }
20 #endif
21 
22 Engine* engine;
23 
Engine()24 Engine::Engine()
25 {
26     engine = this;
27 
28 #ifdef WIN32
29     // Setup crash reporter (Dr. MinGW) if available.
30     exchndl = LoadLibrary(TEXT("exchndl.dll"));
31 
32     if (exchndl)
33     {
34         auto pfnExcHndlInit = GetProcAddress(exchndl, "ExcHndlInit");
35 
36         if (pfnExcHndlInit)
37         {
38             pfnExcHndlInit();
39             LOG(INFO) << "Crash Reporter ON";
40         }
41         else
42         {
43             LOG(WARNING) << "Failed to initialize Crash Reporter";
44             FreeLibrary(exchndl);
45             exchndl = nullptr;
46         }
47     }
48 #endif // WIN32
49 
50     initRandom();
51     windowManager = nullptr;
52     CollisionManager::initialize();
53     InputHandler::initialize();
54     gameSpeed = 1.0;
55     running = true;
56     elapsedTime = 0.0;
57     soundManager = new SoundManager();
58 }
~Engine()59 Engine::~Engine()
60 {
61     if (windowManager)
62         windowManager->close();
63     delete soundManager;
64     soundManager = nullptr;
65 
66 #ifdef WIN32
67     if (exchndl)
68     {
69         FreeLibrary(exchndl);
70         exchndl = nullptr;
71     }
72 #endif // WIN32
73 }
74 
registerObject(string name,P<PObject> obj)75 void Engine::registerObject(string name, P<PObject> obj)
76 {
77     objectMap[name] = obj;
78 }
79 
getObject(string name)80 P<PObject> Engine::getObject(string name)
81 {
82     if (!objectMap[name])
83         return NULL;
84     return objectMap[name];
85 }
86 
runMainLoop()87 void Engine::runMainLoop()
88 {
89     windowManager = dynamic_cast<WindowManager*>(*getObject("windowManager"));
90     if (!windowManager)
91     {
92         sf::Clock frameTimeClock;
93         while(running)
94         {
95             float delta = frameTimeClock.getElapsedTime().asSeconds();
96             frameTimeClock.restart();
97             if (delta > 0.5f)
98                 delta = 0.5f;
99             if (delta < 0.001f)
100                 delta = 0.001f;
101             delta *= gameSpeed;
102 
103             entityList.update();
104             foreach(Updatable, u, updatableList)
105                 u->update(delta);
106             elapsedTime += delta;
107             CollisionManager::handleCollisions(delta);
108             ScriptObject::clearDestroyedObjects();
109             soundManager->updateTick();
110 
111             sf::sleep(sf::seconds(1.f/60.f - delta));
112             //if (elapsedTime > 2.0)
113             //    break;
114         }
115     }else{
116         sf::Clock frameTimeClock;
117 #ifdef DEBUG
118         sf::Clock debugOutputClock;
119 #endif
120         while(running && windowManager->window.isOpen())
121         {
122             InputHandler::preEventsUpdate();
123             // Handle events
124             sf::Event event;
125             while (windowManager->window.pollEvent(event))
126             {
127                 handleEvent(event);
128             }
129             InputHandler::postEventsUpdate();
130 
131 #ifdef DEBUG
132             if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape) && windowManager->hasFocus())
133                 running = false;
134 
135             if (debugOutputClock.getElapsedTime().asSeconds() > 1.0)
136             {
137                 printf("Object count: %4d %4zd %4zd\n", DEBUG_PobjCount, updatableList.size(), entityList.size());
138                 debugOutputClock.restart();
139             }
140 #endif
141 
142             float delta = frameTimeClock.restart().asSeconds();
143             if (delta > 0.5f)
144                 delta = 0.5f;
145             if (delta < 0.001f)
146                 delta = 0.001f;
147             delta *= gameSpeed;
148 #ifdef DEBUG
149             if (sf::Keyboard::isKeyPressed(sf::Keyboard::Tab))
150                 delta /= 5.f;
151             if (sf::Keyboard::isKeyPressed(sf::Keyboard::Tilde))
152                 delta *= 5.f;
153 #endif
154             EngineTiming engine_timing;
155 
156             sf::Clock engine_timing_clock;
157             entityList.update();
158             foreach(Updatable, u, updatableList)
159                 u->update(delta);
160             elapsedTime += delta;
161             engine_timing.update = engine_timing_clock.restart().asSeconds();
162             CollisionManager::handleCollisions(delta);
163             engine_timing.collision = engine_timing_clock.restart().asSeconds();
164             ScriptObject::clearDestroyedObjects();
165             soundManager->updateTick();
166 
167             // Clear the window
168             windowManager->render();
169             engine_timing.render = engine_timing_clock.restart().asSeconds();
170             engine_timing.server_update = 0.0f;
171             if (game_server)
172                 engine_timing.server_update = game_server->getUpdateTime();
173 
174             last_engine_timing = engine_timing;
175         }
176         soundManager->stopMusic();
177     }
178 }
179 
handleEvent(sf::Event & event)180 void Engine::handleEvent(sf::Event& event)
181 {
182     // Window closed: exit
183     if (event.type == sf::Event::Closed)
184         running = false;
185     if (event.type == sf::Event::GainedFocus)
186         windowManager->windowHasFocus = true;
187     if (event.type == sf::Event::LostFocus)
188         windowManager->windowHasFocus = false;
189 #ifdef DEBUG
190     if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::L))
191     {
192         int n = 0;
193         printf("------------------------\n");
194         std::unordered_map<string,int> totals;
195         for(PObject* obj = DEBUG_PobjListStart; obj; obj = obj->DEBUG_PobjListNext)
196         {
197             printf("%c%4d: %4d: %s\n", obj->isDestroyed() ? '>' : ' ', n++, obj->getRefCount(), typeid(*obj).name());
198             if (!obj->isDestroyed())
199             {
200                 totals[typeid(*obj).name()]=totals[typeid(*obj).name()]+1;
201             }
202         }
203         printf("--non-destroyed totals--\n");
204         int grand_total=0;
205         for (auto entry : totals)
206         {
207             printf("%4d %s\n", entry.second, entry.first.c_str());
208             grand_total+=entry.second;
209         }
210         printf("%4d %s\n",grand_total,"All PObjects");
211         printf("------------------------\n");
212     }
213 #endif
214     InputHandler::handleEvent(event);
215     if (event.type == sf::Event::Resized)
216         windowManager->setupView();
217 #ifdef __ANDROID__
218     //Focus lost and focus gained events are used when the application window is created and destroyed.
219     if (event.type == sf::Event::LostFocus)
220         running = false;
221 
222     //The MouseEntered and MouseLeft events are received when the activity needs to pause or resume.
223     if (event.type == sf::Event::MouseLeft)
224     {
225         //Pause is when a small popup is on top of the window. So keep running.
226         while(windowManager->window.isOpen() && windowManager->window.waitEvent(event))
227         {
228             if (event.type != sf::Event::MouseLeft)
229                 handleEvent(event);
230             if (event.type == sf::Event::MouseEntered)
231                 break;
232         }
233     }
234 #endif//__ANDROID__
235 }
236 
setGameSpeed(float speed)237 void Engine::setGameSpeed(float speed)
238 {
239     gameSpeed = speed;
240 }
241 
getGameSpeed()242 float Engine::getGameSpeed()
243 {
244     return gameSpeed;
245 }
246 
getElapsedTime()247 float Engine::getElapsedTime()
248 {
249     return elapsedTime;
250 }
251 
getEngineTiming()252 Engine::EngineTiming Engine::getEngineTiming()
253 {
254     return last_engine_timing;
255 }
256 
shutdown()257 void Engine::shutdown()
258 {
259     running = false;
260 }
261