@@ -7,7 +7,8 @@ libcommon_a_SOURCES = \ | |||||
game.cpp game.h tiler.cpp tiler.h tileset.cpp tileset.h \ | game.cpp game.h tiler.cpp tiler.h tileset.cpp tileset.h \ | ||||
scene.cpp scene.h font.cpp font.h layer.cpp layer.h map.cpp map.h \ | 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 \ | joystick.cpp joystick.h asset.cpp asset.h ticker.cpp ticker.h \ | ||||
video.cpp video.h | |||||
forge.cpp forge.h video.cpp video.h \ | |||||
debugfps.cpp debugfps.h | |||||
libcommon_a_CXXFLAGS = `pkg-config --cflags sdl gl SDL_image` | libcommon_a_CXXFLAGS = `pkg-config --cflags sdl gl SDL_image` | ||||
test_map_SOURCES = test-map.cpp sdlinput.cpp sdlinput.h | test_map_SOURCES = test-map.cpp sdlinput.cpp sdlinput.h | ||||
@@ -27,7 +27,7 @@ Asset::Asset() : | |||||
Asset::~Asset() | Asset::~Asset() | ||||
{ | { | ||||
#if !defined FINAL_RELEASE | |||||
#if !FINAL_RELEASE | |||||
if (!destroy) | if (!destroy) | ||||
fprintf(stderr, "ERROR: asset destructor called directly\n"); | fprintf(stderr, "ERROR: asset destructor called directly\n"); | ||||
#endif | #endif | ||||
@@ -0,0 +1,61 @@ | |||||
// | |||||
// Deus Hax (working title) | |||||
// Copyright (c) 2010 Sam Hocevar <sam@hocevar.net> | |||||
// | |||||
#if defined HAVE_CONFIG_H | |||||
# include "config.h" | |||||
#endif | |||||
#include <cstdio> | |||||
#include "debugfps.h" | |||||
#include "forge.h" | |||||
/* | |||||
* DebugFps implementation class | |||||
*/ | |||||
class DebugFpsData | |||||
{ | |||||
friend class DebugFps; | |||||
private: | |||||
Font *font; | |||||
int frame; | |||||
}; | |||||
/* | |||||
* Public DebugFps class | |||||
*/ | |||||
DebugFps::DebugFps() | |||||
{ | |||||
data = new DebugFpsData(); | |||||
data->font = Forge::GetFont("gfx/font/ascii.png"); | |||||
data->frame = 0; | |||||
} | |||||
Asset::Group DebugFps::GetGroup() | |||||
{ | |||||
return GROUP_AFTER; | |||||
} | |||||
void DebugFps::TickRender(float delta_time) | |||||
{ | |||||
Asset::TickGame(delta_time); | |||||
char buf[1024]; | |||||
sprintf(buf, "%3.2f fps (%i)", 1000.0f / delta_time, data->frame++); | |||||
data->font->Print(10, 10, buf); | |||||
data->font->Print(11, 10, buf); | |||||
data->font->Print(10, 11, buf); | |||||
} | |||||
DebugFps::~DebugFps() | |||||
{ | |||||
Forge::ReleaseFont(data->font); | |||||
delete data; | |||||
} | |||||
@@ -0,0 +1,33 @@ | |||||
// | |||||
// Deus Hax (working title) | |||||
// Copyright (c) 2010 Sam Hocevar <sam@hocevar.net> | |||||
// | |||||
// | |||||
// The DebugFps class | |||||
// ------------------ | |||||
// | |||||
#if !defined __DH_DEBUGFPS_H__ | |||||
#define __DH_DEBUGFPS_H__ | |||||
#include "asset.h" | |||||
class DebugFpsData; | |||||
class DebugFps : public Asset | |||||
{ | |||||
public: | |||||
DebugFps(); | |||||
virtual ~DebugFps(); | |||||
protected: | |||||
virtual Group GetGroup(); | |||||
virtual void TickRender(float delta_time); | |||||
private: | |||||
DebugFpsData *data; | |||||
}; | |||||
#endif // __DH_DEBUGFPS_H__ | |||||
@@ -32,6 +32,8 @@ class FontData | |||||
friend class Font; | friend class Font; | ||||
private: | private: | ||||
char *name; | |||||
SDL_Surface *img; | SDL_Surface *img; | ||||
GLuint texture[1]; | GLuint texture[1]; | ||||
}; | }; | ||||
@@ -43,6 +45,7 @@ private: | |||||
Font::Font(char const *path) | Font::Font(char const *path) | ||||
{ | { | ||||
data = new FontData(); | data = new FontData(); | ||||
data->name = strdup(path); | |||||
data->img = NULL; | data->img = NULL; | ||||
for (char const *name = path; *name; name++) | for (char const *name = path; *name; name++) | ||||
@@ -73,6 +76,21 @@ Font::~Font() | |||||
delete data; | delete data; | ||||
} | } | ||||
Asset::Group Font::GetGroup() | |||||
{ | |||||
return GROUP_BEFORE; | |||||
} | |||||
void Font::TickRender(float delta_time) | |||||
{ | |||||
Asset::TickRender(delta_time); | |||||
} | |||||
char const *Font::GetName() | |||||
{ | |||||
return data->name; | |||||
} | |||||
void Font::Print(int x, int y, char const *str) | void Font::Print(int x, int y, char const *str) | ||||
{ | { | ||||
int w = data->img->w / 16; | int w = data->img->w / 16; | ||||
@@ -11,14 +11,25 @@ | |||||
#if !defined __DH_FONT_H__ | #if !defined __DH_FONT_H__ | ||||
#define __DH_FONT_H__ | #define __DH_FONT_H__ | ||||
#include "asset.h" | |||||
class FontData; | class FontData; | ||||
class Font | |||||
class Font : public Asset | |||||
{ | { | ||||
public: | public: | ||||
Font(char const *path); | Font(char const *path); | ||||
~Font(); | ~Font(); | ||||
protected: | |||||
/* Inherited from Asset */ | |||||
virtual Group GetGroup(); | |||||
virtual void TickRender(float delta_time); | |||||
public: | |||||
/* New methods */ | |||||
char const *GetName(); | |||||
void Print(int x, int y, char const *str); | void Print(int x, int y, char const *str); | ||||
private: | private: | ||||
@@ -0,0 +1,98 @@ | |||||
// | |||||
// Deus Hax (working title) | |||||
// Copyright (c) 2010 Sam Hocevar <sam@hocevar.net> | |||||
// | |||||
#if defined HAVE_CONFIG_H | |||||
# include "config.h" | |||||
#endif | |||||
#include <cstring> | |||||
#include <cstdio> | |||||
#include <cstdlib> | |||||
#include "forge.h" | |||||
#if defined WIN32 | |||||
# define strcasecmp _stricmp | |||||
#endif | |||||
/* | |||||
* Forge implementation class | |||||
*/ | |||||
static class ForgeData | |||||
{ | |||||
friend class Forge; | |||||
public: | |||||
ForgeData() : | |||||
fonts(0), | |||||
nfonts(0) | |||||
{ | |||||
/* Nothing to do */ | |||||
} | |||||
~ForgeData() | |||||
{ | |||||
if (nfonts) | |||||
fprintf(stderr, "ERROR: still %i fonts in forge\n", nfonts); | |||||
free(fonts); | |||||
} | |||||
private: | |||||
Font **fonts; | |||||
int nfonts; | |||||
} | |||||
forgedata; | |||||
static ForgeData * const data = &forgedata; | |||||
/* | |||||
* Public Forge class | |||||
*/ | |||||
Font *Forge::GetFont(char const *path) | |||||
{ | |||||
int id, empty = -1; | |||||
/* If the font is already registered, remember its ID. Look for an | |||||
* empty slot at the same time. */ | |||||
for (id = 0; id < data->nfonts; id++) | |||||
{ | |||||
Font *t = data->fonts[id]; | |||||
if (!t) | |||||
empty = id; | |||||
else if (!strcasecmp(path, t->GetName())) | |||||
break; | |||||
} | |||||
/* If this is a new font, create a new one. */ | |||||
if (id == data->nfonts) | |||||
{ | |||||
if (empty == -1) | |||||
{ | |||||
empty = data->nfonts++; | |||||
data->fonts = (Font **)realloc(data->fonts, | |||||
data->nfonts * sizeof(Font *)); | |||||
} | |||||
data->fonts[empty] = new Font(path); | |||||
id = empty; | |||||
} | |||||
data->fonts[id]->Ref(); | |||||
return data->fonts[id]; | |||||
} | |||||
void Forge::ReleaseFont(Font *font) | |||||
{ | |||||
if (font->Unref() == 0) | |||||
for (int id = 0; id < data->nfonts; id++) | |||||
if (font == data->fonts[id]) | |||||
{ | |||||
data->fonts[id] = NULL; | |||||
break; | |||||
} | |||||
} | |||||
@@ -0,0 +1,25 @@ | |||||
// | |||||
// Deus Hax (working title) | |||||
// Copyright (c) 2010 Sam Hocevar <sam@hocevar.net> | |||||
// | |||||
// | |||||
// The Forge class | |||||
// --------------- | |||||
// The Forge is a static class that manages fonts. | |||||
// | |||||
#if !defined __DH_FORGE_H__ | |||||
#define __DH_FORGE_H__ | |||||
#include "font.h" | |||||
class Forge | |||||
{ | |||||
public: | |||||
static Font *GetFont(char const *path); | |||||
static void ReleaseFont(Font *font); | |||||
}; | |||||
#endif // __DH_FORGE_H__ | |||||
@@ -11,7 +11,6 @@ | |||||
#include "game.h" | #include "game.h" | ||||
#include "map.h" | #include "map.h" | ||||
#include "font.h" | |||||
/* | /* | ||||
* Game implementation class | * Game implementation class | ||||
@@ -23,7 +22,6 @@ class GameData | |||||
private: | private: | ||||
Map *map; | Map *map; | ||||
Font *font; | |||||
int x, y; | int x, y; | ||||
int mousex, mousey; | int mousex, mousey; | ||||
int done; | int done; | ||||
@@ -39,7 +37,6 @@ Game::Game(char const *mapname) | |||||
{ | { | ||||
data = new GameData(); | data = new GameData(); | ||||
data->map = new Map(mapname); | data->map = new Map(mapname); | ||||
data->font = new Font("gfx/font/ascii.png"); | |||||
data->x = data->y = 0; | data->x = data->y = 0; | ||||
data->done = 0; | data->done = 0; | ||||
data->frame = 0; | data->frame = 0; | ||||
@@ -47,7 +44,6 @@ Game::Game(char const *mapname) | |||||
Game::~Game() | Game::~Game() | ||||
{ | { | ||||
delete data->font; | |||||
delete data->map; | delete data->map; | ||||
delete data; | delete data; | ||||
} | } | ||||
@@ -72,10 +68,6 @@ void Game::TickRender(float delta_time) | |||||
scene->Render(); | scene->Render(); | ||||
delete scene; | delete scene; | ||||
char buf[1024]; | |||||
sprintf(buf, "Frame %i", data->frame++); | |||||
data->font->Print(10, 10, buf); | |||||
} | } | ||||
void Game::SetMouse(int x, int y) | void Game::SetMouse(int x, int y) | ||||
@@ -15,6 +15,7 @@ | |||||
#include <gtkgl/gtkglarea.h> | #include <gtkgl/gtkglarea.h> | ||||
#include "ticker.h" | #include "ticker.h" | ||||
#include "debugfps.h" | |||||
#include "video.h" | #include "video.h" | ||||
#include "game.h" | #include "game.h" | ||||
@@ -146,6 +147,7 @@ int main(int argc, char **argv) | |||||
// FIXME: detect when the game is killed | // FIXME: detect when the game is killed | ||||
new Game("maps/testmap.tmx"); | new Game("maps/testmap.tmx"); | ||||
new DebugFps(); | |||||
//gtk_idle_add(tick, glarea); | //gtk_idle_add(tick, glarea); | ||||
gtk_timeout_add(33, tick, glarea); | gtk_timeout_add(33, tick, glarea); | ||||
@@ -13,6 +13,7 @@ | |||||
#include <SDL.h> | #include <SDL.h> | ||||
#include "sdlinput.h" | #include "sdlinput.h" | ||||
#include "debugfps.h" | |||||
#include "game.h" | #include "game.h" | ||||
#include "ticker.h" | #include "ticker.h" | ||||
#include "video.h" | #include "video.h" | ||||
@@ -49,8 +50,9 @@ int main(int argc, char **argv) | |||||
/* Create a game */ | /* Create a game */ | ||||
Game *game = new Game("maps/testmap.tmx"); | Game *game = new Game("maps/testmap.tmx"); | ||||
/* Register an input driver */ | |||||
/* Register an input driver and some debug stuff */ | |||||
new SdlInput(game); | new SdlInput(game); | ||||
new DebugFps(); | |||||
while (!game->Finished()) | while (!game->Finished()) | ||||
{ | { | ||||
@@ -24,6 +24,7 @@ static class TickerData | |||||
public: | public: | ||||
TickerData() : | TickerData() : | ||||
todo(0), | |||||
nassets(0) | nassets(0) | ||||
{ | { | ||||
for (int i = 0; i < Asset::GROUP_COUNT; i++) | for (int i = 0; i < Asset::GROUP_COUNT; i++) | ||||
@@ -32,11 +33,14 @@ public: | |||||
~TickerData() | ~TickerData() | ||||
{ | { | ||||
#if !FINAL_RELEASE | |||||
if (nassets) | if (nassets) | ||||
fprintf(stderr, "ERROR: still %i assets in ticker\n", nassets); | fprintf(stderr, "ERROR: still %i assets in ticker\n", nassets); | ||||
#endif | |||||
} | } | ||||
private: | private: | ||||
Asset *todo; | |||||
Asset *list[Asset::GROUP_COUNT]; | Asset *list[Asset::GROUP_COUNT]; | ||||
int nassets; | int nassets; | ||||
} | } | ||||
@@ -50,14 +54,27 @@ static TickerData * const data = &tickerdata; | |||||
void Ticker::Register(Asset *asset) | void Ticker::Register(Asset *asset) | ||||
{ | { | ||||
int i = asset->GetGroup(); | |||||
asset->next = data->list[i]; | |||||
data->list[i] = asset; | |||||
data->nassets++; | |||||
/* If we are called from its constructor, the object's vtable is not | |||||
* ready yet, so we do not know which group this asset belongs to. Wait | |||||
* until the first tick. */ | |||||
asset->next = data->todo; | |||||
data->todo = asset; | |||||
} | } | ||||
void Ticker::TickGame(float delta_time) | void Ticker::TickGame(float delta_time) | ||||
{ | { | ||||
/* Insert waiting objects in the appropriate lists */ | |||||
while (data->todo) | |||||
{ | |||||
Asset *a = data->todo; | |||||
data->todo = a->next; | |||||
int i = a->GetGroup(); | |||||
a->next = data->list[i]; | |||||
data->list[i] = a; | |||||
data->nassets++; | |||||
} | |||||
/* Garbage collect objects that can be destroyed */ | /* Garbage collect objects that can be destroyed */ | ||||
for (int i = 0; i < Asset::GROUP_COUNT; i++) | for (int i = 0; i < Asset::GROUP_COUNT; i++) | ||||
for (Asset *a = data->list[i], *prev = NULL; a; prev = a, a = a->next) | for (Asset *a = data->list[i], *prev = NULL; a; prev = a, a = a->next) | ||||