]> Dogcows Code - chaz/yoink/blob - src/engine.cc
7284799343a1f144d136ac65705f94c0ff54ad67
[chaz/yoink] / src / engine.cc
1
2 /*******************************************************************************
3
4 Copyright (c) 2009, Charles McGarvey
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
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.
15
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.
26
27 *******************************************************************************/
28
29 #include <iostream>
30 #include <cstdlib> // exit
31 #include <string>
32 #include <stdexcept>
33
34 #include <SDL/SDL.h>
35 #include "fastevents.h"
36
37 #include "random.hh"
38 #include "timer.hh"
39 #include "video.hh"
40 #include "settings.hh"
41 #include "dispatcher.hh"
42
43 #include "engine.hh"
44
45
46 namespace dc {
47
48
49 class engine::engine_impl
50 {
51 public:
52 engine_impl(const std::string& name, int argc, char* argv[],
53 const std::string& configFile, engine* outer) :
54 config(argc, argv),
55 interface(outer)
56 {
57 if (SDL_Init(SDL_INIT_EVERYTHING | SDL_INIT_EVENTTHREAD) != 0)
58 {
59 throw std::runtime_error(SDL_GetError());
60 }
61 if (FE_Init() != 0)
62 {
63 throw std::runtime_error(FE_GetError());
64 }
65
66 rng::seed();
67
68 config.loadFromFile(configFile);
69
70 screen = video_ptr(new video(name));
71 screen->makeActive();
72
73 double ts = 0.01;
74 config.get("engine.timestep", ts);
75 timestep = scalar(ts);
76
77 long maxfps = 40;
78 config.getNumber("video.maxfps", maxfps);
79 drawrate = 1.0 / scalar(maxfps);
80
81 printfps = false;
82 config.get("video.printfps", printfps);
83 }
84
85 ~engine_impl()
86 {
87 // The video object must be destroyed before we can shutdown SDL.
88 screen.reset();
89
90 FE_Quit();
91 SDL_Quit();
92 }
93
94
95 /**
96 * The main loop. This just calls dispatchEvents(), update(), and draw()
97 * over and over again. The timing of the update and draw are decoupled.
98 * The actual frame rate is also calculated here. This function will return
99 * with a value of 0 if the member variable running becomes true.
100 */
101
102 int run()
103 {
104 scalar ticksNow = ticks();
105
106 scalar nextStep = ticksNow;
107 scalar nextDraw = ticksNow;
108 scalar nextFPSUpdate = ticksNow + 1.0;
109
110 scalar totalTime = 0.0;
111 scalar deltaTime = 0.0;
112 scalar accumulator = timestep;
113
114 fps = 0;
115 int frameAccum = 0;
116
117 running = true;
118 do
119 {
120 scalar newTicks = ticks();
121 deltaTime = newTicks - ticksNow;
122 ticksNow = newTicks;
123
124 if (deltaTime >= 0.25) deltaTime = 0.25;
125 accumulator += deltaTime;
126
127 while (accumulator >= timestep)
128 {
129 dispatchEvents();
130 interface->update(totalTime, timestep);
131
132 totalTime += timestep;
133 accumulator -= timestep;
134
135 nextStep += timestep;
136 }
137
138 if (ticksNow >= nextDraw)
139 {
140 frameAccum++;
141
142 if (ticksNow >= nextFPSUpdate) // determine the actual fps
143 {
144 fps = frameAccum;
145 frameAccum = 0;
146
147 nextFPSUpdate += 1.0;
148 if (ticksNow >= nextFPSUpdate)
149 {
150 nextFPSUpdate = ticksNow + 1.0;
151 }
152
153 if (printfps)
154 {
155 std::cout << "FPS: " << fps << std::endl;
156 }
157 }
158
159 interface->draw(accumulator / timestep);
160 screen->swap();
161
162 nextDraw += drawrate;
163 if (ticksNow >= nextDraw)
164 {
165 // we missed some scheduled draws, so reset the schedule
166 nextDraw = ticksNow + drawrate;
167 }
168 }
169
170 // be a good citizen and give back what you don't need
171 sleep(std::min(nextStep, nextDraw), true);
172 }
173 while (running);
174
175 return 0;
176 }
177
178
179 void dispatchEvents()
180 {
181 SDL_Event e;
182
183 while (FE_PollEvent(&e) == 1)
184 {
185 switch (e.type)
186 {
187 case SDL_KEYDOWN:
188 if (e.key.keysym.sym == SDLK_ESCAPE &&
189 (SDL_GetModState() & KMOD_CTRL) )
190 {
191 exit(0);
192 }
193 break;
194
195 case SDL_VIDEORESIZE:
196 screen->resize(e.resize.w, e.resize.h);
197 break;
198 }
199
200 interface->handleEvent(e);
201 }
202 }
203
204
205 settings config;
206 dispatcher relay;
207 video_ptr screen;
208
209 bool running;
210
211 scalar timestep;
212 scalar drawrate;
213
214 long fps;
215 bool printfps;
216
217 engine* interface;
218 };
219
220
221 engine::engine(const std::string& name, int argc, char* argv[],
222 const std::string& configFile) :
223 impl(new engine::engine_impl(name, argc, argv, configFile, this)) {}
224
225 engine::~engine() {}
226
227
228 int engine::run()
229 {
230 return impl->run();
231 }
232
233 void engine::stop()
234 {
235 impl->running = false;
236 }
237
238
239 void engine::setTimestep(scalar ts)
240 {
241 impl->timestep = ts;
242 }
243
244 scalar engine::getTimestep()
245 {
246 return impl->timestep;
247 }
248
249 void engine::setMaxFPS(long maxfps)
250 {
251 impl->drawrate = 1.0 / scalar(maxfps);
252 }
253
254 long engine::getMaxFPS()
255 {
256 return long(1.0 / impl->drawrate);
257 }
258
259
260 video& engine::getVideo()
261 {
262 return *impl->screen;
263 }
264
265 long engine::getFPS()
266 {
267 return impl->fps;
268 }
269
270
271 void engine::update(scalar t, scalar dt) {}
272 void engine::draw(scalar alpha) {}
273 void engine::handleEvent(const SDL_Event& e) {}
274
275
276 } // namespace dc
277
278 /** vim: set ts=4 sw=4 tw=80: *************************************************/
279
This page took 0.048643 seconds and 3 git commands to generate.