2 /*******************************************************************************
4 Copyright (c) 2009, Charles McGarvey
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
10 * Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *******************************************************************************/
30 #include <cstdlib> // exit, srand
31 #include <ctime> // time
37 #include "fastevents.h"
43 #include "ModalDialog.hh"
44 #include "Settings.hh"
65 if (settings
.get("rngseed", randomSeed
)) srand(randomSeed
);
68 Scalar timestep
= 80.0;
69 settings
.get("timestep", timestep
);
70 mTimestep
= 1.0 / timestep
;
72 Scalar framerate
= 40.0;
73 settings
.get("framerate", framerate
);
74 mFramerate
= 1.0 / framerate
;
77 settings
.get("showfps", mShowFps
);
82 * The main loop. This just calls dispatchEvents(), update(), and draw()
83 * over and over again. The timing of the update and draw are decoupled.
84 * The actual frame rate is also calculated here. This function will return
85 * the exit code used to stop the loop.
92 Scalar totalTime
= 0.0;
93 Scalar ticks
= Timer::getTicks();
95 Scalar nextUpdate
= ticks
;
96 Scalar nextDraw
= ticks
;
97 Scalar nextSecond
= ticks
+ SCALAR(1.0);
102 const int MAX_FRAMESKIP
= 15;
103 const Scalar inverseTimestep
= SCALAR(1.0) / mTimestep
;
105 ASSERT(video
&& "cannot run core without a current video context");
109 Timer::fireIfExpired();
113 while (nextUpdate
< Timer::getTicks() && i
< MAX_FRAMESKIP
)
115 totalTime
+= mTimestep
;
116 update(totalTime
, mTimestep
);
118 nextUpdate
+= mTimestep
;
122 if (nextDraw
< (ticks
= Timer::getTicks()))
125 draw((ticks
+ mTimestep
- nextUpdate
) * inverseTimestep
);
128 nextDraw
+= mFramerate
;
130 if (mShowFps
&& nextSecond
< ticks
)
135 logInfo
<< mFps
<< " fps" << std::endl
;
137 nextSecond
+= SCALAR(1.0);
141 // be a good citizen and give back what you don't need
144 while (!mStack
.empty());
146 mDispatch
.dispatch("engine.stopping");
150 void dispatchEvents()
154 while (FE_PollEvent(&event
) == 1)
159 if (event
.key
.keysym
.sym
== SDLK_ESCAPE
&&
160 (SDL_GetModState() & KMOD_CTRL
) )
163 logWarning("escape forced");
168 case SDL_VIDEORESIZE
:
169 video
->resize(event
.resize
.w
, event
.resize
.h
);
178 void update(Scalar t
, Scalar dt
)
180 for (mStackIt
= mStack
.begin(); mStackIt
!= mStack
.end(); ++mStackIt
)
182 (*mStackIt
)->update(t
, dt
);
186 void draw(Scalar alpha
)
188 // FIXME - this will crash if the layer being drawn pops itself
189 std::list
<LayerP
>::reverse_iterator it
;
190 for (it
= mStack
.rbegin(); it
!= mStack
.rend(); ++it
)
196 void handleEvent(const Event
& event
)
198 for (mStackIt
= mStack
.begin(); mStackIt
!= mStack
.end(); ++mStackIt
)
200 if ((*mStackIt
)->handleEvent(event
)) break;
205 void push(LayerP layer
)
207 ASSERT(layer
&& "cannot push null layer");
208 mStack
.push_front(layer
);
209 logInfo
<< "stack: " << mStack
.size()
210 << " [pushed " << layer
.get() << "]" << std::endl
;
211 layer
->addedToCore();
217 if (mStack
.begin() == mStackIt
) fixIt
= true;
219 LayerP layer
= mStack
.front();
221 logInfo
<< "stack: " << mStack
.size()
222 << " [popped " << layer
.get() << "]" << std::endl
;
223 layer
->removedFromCore();
225 if (fixIt
) mStackIt
= --mStack
.begin();
230 LayerP
pop(Layer
* layer
)
234 std::list
<LayerP
> layers
;
236 std::list
<LayerP
>::iterator it
;
237 for (it
= mStack
.begin(); it
!= mStack
.end(); ++it
)
239 layers
.push_back(*it
);
241 if (it
== mStackIt
) fixIt
= true;
243 if ((*it
).get() == layer
)
246 mStack
.erase(mStack
.begin(), it
);
248 for (it
= layers
.begin(); it
!= layers
.end(); ++it
)
250 (*it
)->removedFromCore();
251 logInfo
<< "stack: " << mStack
.size()
252 << " [popped " << (*it
).get() << "]" << std::endl
;
255 if (fixIt
) mStackIt
= --mStack
.begin();
257 return layers
.back();
267 mStackIt
= mStack
.begin();
268 logInfo("stack: 0 [cleared]");
276 std::list
<LayerP
> mStack
;
277 std::list
<LayerP
>::iterator mStackIt
;
289 mImpl(new Core::Impl
) {}
299 int Core::getFps() const
305 void Core::push(LayerP layer
)
317 LayerP
Core::pop(Layer
* layer
)
320 return mImpl
->pop(layer
);
329 int Core::getSize() const
331 return mImpl
->mStack
.size();
342 Dispatch::Handler
Core::addHandler(const std::string
& event
,
343 const Dispatch::Function
& callback
)
345 return mImpl
->mDispatch
.addHandler(event
, callback
);
348 Dispatch::Handler
Core::addHandler(const std::string
& event
,
349 const Dispatch::Function
& callback
, Dispatch::Handler handler
)
351 return mImpl
->mDispatch
.addHandler(event
, callback
, handler
);
354 void Core::dispatch(const std::string
& event
,
355 const Dispatch::Message
* message
)
357 mImpl
->mDispatch
.dispatch(event
, message
);
365 typedef boost::shared_ptr
<Backend_
> BackendP
;
375 #if defined(_WIN32) || defined(__WIN32__)
376 if (SDL_Init(SDL_INIT_VIDEO
| SDL_INIT_TIMER
) != 0)
378 if (SDL_Init(SDL_INIT_VIDEO
| SDL_INIT_EVENTTHREAD
) != 0)
381 const char* error
= SDL_GetError();
382 gError
.init(Error::SDL_INIT
, error
);
388 SDL_VideoDriverName(name
, sizeof(name
));
389 logInfo
<< "initialized SDL; using video driver `"
390 << name
<< "'" << std::endl
;
395 const char* error
= FE_GetError();
396 gError
.init(Error::FASTEVENTS_INIT
, error
);
400 mAlDevice
= alcOpenDevice(0);
401 mAlContext
= alcCreateContext(mAlDevice
, 0);
402 if (!mAlDevice
|| !mAlContext
)
404 const char* error
= alcGetString(mAlDevice
,alcGetError(mAlDevice
));
405 gError
.init(Error::OPENAL_INIT
, error
);
410 alcMakeContextCurrent(mAlContext
);
411 logInfo
<< "opened sound device `"
412 << alcGetString(mAlDevice
, ALC_DEFAULT_DEVICE_SPECIFIER
)
416 gError
.init(Error::NONE
);
421 alcMakeContextCurrent(0);
422 alcDestroyContext(mAlContext
);
423 alcCloseDevice(mAlDevice
);
431 if (gRetainCount
++ == 0)
433 gInstance
= BackendP(new Backend_
);
437 static void release()
439 if (--gRetainCount
== 0)
446 static bool check(Error
& error
)
449 return error
.code() == Error::NONE
;
454 ALCdevice
* mAlDevice
;
455 ALCcontext
* mAlContext
;
458 static int gRetainCount
;
459 static BackendP gInstance
;
462 Error
Backend_::gError(Error::UNINITIALIZED
);
463 int Backend_::gRetainCount
= 0;
464 BackendP
Backend_::gInstance
;
477 bool Backend::check(Error
& error
)
479 return Backend_::check(error
);
485 /** vim: set ts=4 sw=4 tw=80: *************************************************/