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
;
373 #if defined(_WIN32) || defined(__WIN32__)
374 if (SDL_Init(SDL_INIT_VIDEO
| SDL_INIT_TIMER
) != 0)
376 if (SDL_Init(SDL_INIT_VIDEO
| SDL_INIT_EVENTTHREAD
) != 0)
379 const char* error
= SDL_GetError();
380 gError
.init(Error::SDL_INIT
, error
);
386 SDL_VideoDriverName(name
, sizeof(name
));
387 logInfo
<< "initialized SDL; using video driver `"
388 << name
<< "'" << std::endl
;
393 const char* error
= FE_GetError();
394 gError
.init(Error::FASTEVENTS_INIT
, error
);
398 mAlDevice
= alcOpenDevice(0);
399 mAlContext
= alcCreateContext(mAlDevice
, 0);
400 if (!mAlDevice
|| !mAlContext
)
402 const char* error
= alcGetString(mAlDevice
,alcGetError(mAlDevice
));
403 gError
.init(Error::OPENAL_INIT
, error
);
408 alcMakeContextCurrent(mAlContext
);
409 logInfo
<< "opened sound device `"
410 << alcGetString(mAlDevice
, ALC_DEFAULT_DEVICE_SPECIFIER
)
414 gError
.init(Error::NONE
);
419 alcMakeContextCurrent(0);
420 alcDestroyContext(mAlContext
);
421 alcCloseDevice(mAlDevice
);
429 if (gRetainCount
++ == 0)
431 gInstance
= BackendP(new Backend_
);
436 static void release()
438 if (--gRetainCount
== 0)
445 static bool check(Error
& error
)
448 return error
.code() == Error::NONE
;
453 ALCdevice
* mAlDevice
;
454 ALCcontext
* mAlContext
;
457 static int gRetainCount
;
458 static BackendP gInstance
;
461 Error
Backend_::gError(Error::UNINITIALIZED
);
462 int Backend_::gRetainCount
= 0;
463 BackendP
Backend_::gInstance
;
476 bool Backend::check(Error
& error
)
478 return Backend_::check(error
);
484 /** vim: set ts=4 sw=4 tw=80: *************************************************/