| @@ -8,7 +8,7 @@ libcommon_a_SOURCES = \ | |||
| scene.cpp scene.h font.cpp font.h layer.cpp layer.h map.cpp map.h \ | |||
| joystick.cpp joystick.h asset.cpp asset.h ticker.cpp ticker.h \ | |||
| forge.cpp forge.h video.cpp video.h timer.cpp timer.h \ | |||
| debugfps.cpp debugfps.h | |||
| profiler.cpp profiler.h debugfps.cpp debugfps.h | |||
| libcommon_a_CXXFLAGS = `pkg-config --cflags sdl gl SDL_image` | |||
| test_map_SOURCES = test-map.cpp sdlinput.cpp sdlinput.h | |||
| @@ -11,6 +11,7 @@ | |||
| #include "debugfps.h" | |||
| #include "forge.h" | |||
| #include "profiler.h" | |||
| /* | |||
| * DebugFps implementation class | |||
| @@ -20,10 +21,7 @@ class DebugFpsData | |||
| { | |||
| friend class DebugFps; | |||
| static int const HISTORY = 30; | |||
| private: | |||
| float history[HISTORY]; | |||
| Font *font; | |||
| int frame; | |||
| }; | |||
| @@ -36,8 +34,6 @@ DebugFps::DebugFps() | |||
| { | |||
| data = new DebugFpsData(); | |||
| for (int i = 0; i < DebugFpsData::HISTORY; i++) | |||
| data->history[i] = 0.0f; | |||
| data->font = Forge::GetFont("gfx/font/ascii.png"); | |||
| data->frame = 0; | |||
| } | |||
| @@ -51,24 +47,33 @@ void DebugFps::TickRender(float delta_time) | |||
| { | |||
| Asset::TickGame(delta_time); | |||
| data->history[data->frame % DebugFpsData::HISTORY] = delta_time; | |||
| data->frame++; | |||
| float mean = 0.0f, max = 0.0f; | |||
| for (int i = 0; i < DebugFpsData::HISTORY; i++) | |||
| { | |||
| mean += data->history[i]; | |||
| if (data->history[i] > max) | |||
| max = data->history[i]; | |||
| } | |||
| mean /= DebugFpsData::HISTORY; | |||
| char buf[1024]; | |||
| sprintf(buf, "%3.2f ms (%3.2f fps) -- max %3.2f ms -- #%i", | |||
| 1000.0f * mean, 1.0f / mean, 1000.0f * max, data->frame); | |||
| data->font->Print(10, 10, buf); | |||
| data->font->Print(11, 10, buf); | |||
| data->font->Print(10, 11, buf); | |||
| sprintf(buf, "%2.2f fps (%i)", | |||
| 1.0f / Profiler::GetMean(Profiler::STAT_TICK_FRAME), data->frame); | |||
| data->font->PrintBold(10, 10, buf); | |||
| sprintf(buf, "Game % 7.2f % 7.2f", | |||
| 1e3f * Profiler::GetMean(Profiler::STAT_TICK_GAME), | |||
| 1e3f * Profiler::GetMax(Profiler::STAT_TICK_GAME)); | |||
| data->font->PrintBold(10, 28, buf); | |||
| sprintf(buf, "Render % 7.2f % 7.2f", | |||
| 1e3f * Profiler::GetMean(Profiler::STAT_TICK_RENDER), | |||
| 1e3f * Profiler::GetMax(Profiler::STAT_TICK_RENDER)); | |||
| data->font->PrintBold(10, 46, buf); | |||
| sprintf(buf, "Blit % 7.2f % 7.2f", | |||
| 1e3f * Profiler::GetMean(Profiler::STAT_TICK_BLIT), | |||
| 1e3f * Profiler::GetMax(Profiler::STAT_TICK_BLIT)); | |||
| data->font->PrintBold(10, 64, buf); | |||
| sprintf(buf, "Frame % 7.2f % 7.2f", | |||
| 1e3f * Profiler::GetMean(Profiler::STAT_TICK_FRAME), | |||
| 1e3f * Profiler::GetMax(Profiler::STAT_TICK_FRAME)); | |||
| data->font->PrintBold(10, 82, buf); | |||
| } | |||
| DebugFps::~DebugFps() | |||
| @@ -77,7 +77,8 @@ static gint draw(GtkWidget *widget, GdkEventExpose *event) | |||
| { | |||
| ticking = 0; | |||
| /* Clear the screen, tick the renderer, and show the frame */ | |||
| /* Clear the screen, tick the renderer, show the frame and | |||
| * clamp to desired framerate. */ | |||
| Video::Clear(); | |||
| Ticker::TickRender(); | |||
| gtk_gl_area_swapbuffers(GTK_GL_AREA(widget)); | |||
| @@ -0,0 +1,80 @@ | |||
| // | |||
| // Deus Hax (working title) | |||
| // Copyright (c) 2010 Sam Hocevar <sam@hocevar.net> | |||
| // | |||
| #if defined HAVE_CONFIG_H | |||
| # include "config.h" | |||
| #endif | |||
| #include <cstdlib> | |||
| #include <cstdio> | |||
| #include <stdint.h> | |||
| #include "profiler.h" | |||
| #include "timer.h" | |||
| /* | |||
| * Profiler implementation class | |||
| */ | |||
| static class ProfilerData | |||
| { | |||
| friend class Profiler; | |||
| static int const HISTORY = 30; | |||
| public: | |||
| ProfilerData() | |||
| { | |||
| for (int i = 0; i < HISTORY; i++) | |||
| history[i] = 0.0f; | |||
| frame = 0; | |||
| mean = max = 0.0f; | |||
| } | |||
| private: | |||
| float history[HISTORY]; | |||
| Timer timer; | |||
| int frame; | |||
| float mean, max; | |||
| } | |||
| data[Profiler::STAT_COUNT]; | |||
| /* | |||
| * Profiler public class | |||
| */ | |||
| void Profiler::Start(int id) | |||
| { | |||
| data[id].timer.GetSeconds(); | |||
| } | |||
| void Profiler::Stop(int id) | |||
| { | |||
| float delta_time = data[id].timer.GetSeconds(); | |||
| data[id].history[data->frame % ProfilerData::HISTORY] = delta_time; | |||
| data[id].frame++; | |||
| data[id].mean = 0.0f; | |||
| data[id].max = 0.0f; | |||
| for (int i = 0; i < ProfilerData::HISTORY; i++) | |||
| { | |||
| data[id].mean += data[id].history[i]; | |||
| if (data[id].history[i] > data[id].max) | |||
| data[id].max = data[id].history[i]; | |||
| } | |||
| data[id].mean /= ProfilerData::HISTORY; | |||
| } | |||
| float Profiler::GetMean(int id) | |||
| { | |||
| return data[id].mean; | |||
| } | |||
| float Profiler::GetMax(int id) | |||
| { | |||
| return data[id].max; | |||
| } | |||
| @@ -0,0 +1,36 @@ | |||
| // | |||
| // Deus Hax (working title) | |||
| // Copyright (c) 2010 Sam Hocevar <sam@hocevar.net> | |||
| // | |||
| // | |||
| // The Profiler class | |||
| // ------------------- | |||
| // The Profiler is a static class that collects statistic counters. | |||
| // | |||
| #if !defined __DH_PROFILER_H__ | |||
| #define __DH_PROFILER_H__ | |||
| #include <stdint.h> | |||
| class Profiler | |||
| { | |||
| public: | |||
| enum | |||
| { | |||
| STAT_TICK_FRAME = 0, | |||
| STAT_TICK_GAME, | |||
| STAT_TICK_RENDER, | |||
| STAT_TICK_BLIT, | |||
| STAT_COUNT | |||
| }; | |||
| static void Start(int id); | |||
| static void Stop(int id); | |||
| static float GetMean(int id); | |||
| static float GetMax(int id); | |||
| }; | |||
| #endif // __DH_PROFILER_H__ | |||
| @@ -16,6 +16,7 @@ | |||
| #include "debugfps.h" | |||
| #include "game.h" | |||
| #include "ticker.h" | |||
| #include "profiler.h" | |||
| #include "video.h" | |||
| static float const FPS = 30.0f; | |||
| @@ -56,12 +57,11 @@ int main(int argc, char **argv) | |||
| /* Tick the game */ | |||
| Ticker::TickGame(); | |||
| /* Clear the screen, tick the renderer, and show the frame */ | |||
| /* Clear the screen, tick the renderer, show the frame and | |||
| * clamp to desired framerate. */ | |||
| Video::Clear(); | |||
| Ticker::TickRender(); | |||
| SDL_GL_SwapBuffers(); | |||
| /* Clamp to desired framerate */ | |||
| Ticker::ClampFps(FPS); | |||
| } | |||
| @@ -11,6 +11,7 @@ | |||
| #include <cstdio> | |||
| #include <stdint.h> | |||
| #include "profiler.h" | |||
| #include "ticker.h" | |||
| #include "asset.h" | |||
| #include "timer.h" | |||
| @@ -30,7 +31,6 @@ public: | |||
| { | |||
| for (int i = 0; i < Asset::GROUP_COUNT; i++) | |||
| list[i] = NULL; | |||
| timer = new Timer(); | |||
| bias = 0.0f; | |||
| } | |||
| @@ -40,7 +40,6 @@ public: | |||
| if (nassets) | |||
| fprintf(stderr, "ERROR: still %i assets in ticker\n", nassets); | |||
| #endif | |||
| delete timer; | |||
| } | |||
| private: | |||
| @@ -49,10 +48,9 @@ private: | |||
| Asset *list[Asset::GROUP_COUNT]; | |||
| int nassets; | |||
| /* FPS management */ | |||
| float delta_time; | |||
| Timer *timer; | |||
| float bias; | |||
| /* Fixed framerate management */ | |||
| Timer timer; | |||
| float delta_time, bias; | |||
| } | |||
| tickerdata; | |||
| @@ -73,7 +71,11 @@ void Ticker::Register(Asset *asset) | |||
| void Ticker::TickGame() | |||
| { | |||
| data->delta_time = data->timer->GetSeconds(); | |||
| Profiler::Stop(Profiler::STAT_TICK_FRAME); | |||
| Profiler::Start(Profiler::STAT_TICK_FRAME); | |||
| Profiler::Start(Profiler::STAT_TICK_GAME); | |||
| data->delta_time = data->timer.GetSeconds(); | |||
| data->bias += data->delta_time; | |||
| /* Insert waiting objects in the appropriate lists */ | |||
| @@ -107,22 +109,31 @@ void Ticker::TickGame() | |||
| for (Asset *a = data->list[i]; a; a = a->next) | |||
| if (!a->destroy) | |||
| a->TickGame(data->delta_time); | |||
| Profiler::Stop(Profiler::STAT_TICK_GAME); | |||
| } | |||
| void Ticker::TickRender() | |||
| { | |||
| Profiler::Start(Profiler::STAT_TICK_RENDER); | |||
| /* Tick objects for the render loop */ | |||
| for (int i = 0; i < Asset::GROUP_COUNT; i++) | |||
| for (Asset *a = data->list[i]; a; a = a->next) | |||
| if (!a->destroy) | |||
| a->TickRender(data->delta_time); | |||
| Profiler::Stop(Profiler::STAT_TICK_RENDER); | |||
| Profiler::Start(Profiler::STAT_TICK_BLIT); | |||
| } | |||
| void Ticker::ClampFps(float fps) | |||
| { | |||
| float ideal_time = 1.0f / fps; | |||
| Profiler::Stop(Profiler::STAT_TICK_BLIT); | |||
| data->timer->WaitSeconds(ideal_time - data->bias); | |||
| float ideal_time = 1.0f / fps; | |||
| if (ideal_time > data->bias) | |||
| data->timer.WaitSeconds(ideal_time - data->bias); | |||
| data->bias -= ideal_time; | |||
| } | |||