From af3be15a7dfe4f6700d363e048001e78c24c7e9e Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Wed, 7 Jul 2010 00:11:16 +0000 Subject: [PATCH] Much better resource allocation and release. Scene manager stub. --- src/Makefile | 2 +- src/layer.cpp | 11 +++++- src/layer.h | 2 + src/map.cpp | 98 ++++++++++++++++++++++++++++++++++-------------- src/map.h | 8 ++-- src/scene.cpp | 29 ++++++++++++++ src/scene.h | 25 ++++++++++++ src/test-map.cpp | 10 ++--- src/tiler.cpp | 85 +++++++++++++++++++++++++++++++++++++++++ src/tiler.h | 17 +++++++++ src/tileset.cpp | 51 +++++++++++++++++++------ src/tileset.h | 21 +++++++---- 12 files changed, 299 insertions(+), 60 deletions(-) create mode 100644 src/scene.cpp create mode 100644 src/scene.h create mode 100644 src/tiler.cpp create mode 100644 src/tiler.h diff --git a/src/Makefile b/src/Makefile index 1e05beac..192d7c93 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,5 @@ -SRC = test-map.cpp video.cpp tileset.cpp layer.cpp map.cpp +SRC = test-map.cpp video.cpp tiler.cpp tileset.cpp scene.cpp layer.cpp map.cpp all: test-map diff --git a/src/layer.cpp b/src/layer.cpp index 77783b77..c7e8b4c6 100644 --- a/src/layer.cpp +++ b/src/layer.cpp @@ -1,4 +1,6 @@ +#include + #include "layer.h" Layer::Layer(int w, int h, int in_z, uint32_t *in_data) @@ -21,7 +23,14 @@ Layer::Layer(int w, int h, int in_z, uint32_t *in_data) Layer::~Layer() { - delete data; + free(data); +} + +void Layer::Draw() +{ + for (int y = 0; y < 32; y++) + for (int x = 0; x < 32; x++) + ;//tileset->AddTile(GetTile(x, y), x * 32, y * 32, z); } int Layer::GetZ() diff --git a/src/layer.h b/src/layer.h index 0fbd6ca1..62548f57 100644 --- a/src/layer.h +++ b/src/layer.h @@ -18,6 +18,8 @@ public: int GetZ(); unsigned int GetTile(int x, int y); + void Draw(); + private: int width, height, z; uint32_t *data; diff --git a/src/map.cpp b/src/map.cpp index 6a247cbe..366ebe60 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -7,15 +7,40 @@ #include "map.h" #include "layer.h" +#include "tiler.h" -Map::Map(char const *path) : - layers(0), - nlayers(0) +#define MAX_TILERS 128 + +/* + * Map implementation class + */ + +class MapData +{ + friend class Map; + +private: + int tilers[MAX_TILERS]; + int ntilers; + Layer **layers; + int nlayers; +}; + +/* + * Public Map class + */ + +Map::Map(char const *path) { + data = new MapData(); + data->ntilers = 0; + data->layers = NULL; + data->nlayers = 0; + char tmp[BUFSIZ]; - uint32_t *data = NULL; - int width = 0, height = 0, level = 0, orientation = 0; - int firstgid = 0, ntiles = 0; + int gids[MAX_TILERS]; + uint32_t *tiles = NULL; + int width = 0, height = 0, level = 0, orientation = 0, ntiles = 0; FILE *fp = fopen(path, "r"); @@ -28,16 +53,34 @@ Map::Map(char const *path) : int i, j, k; char a, b; + /* Read a line, then decide what to do with it. */ fgets(tmp, BUFSIZ, fp); - if (data) + if (tiles) { /* We are in the process of reading layer data. Only stop * when we have read the expected number of tiles. */ char const *parser = tmp; while (ntiles < width * height) { - data[ntiles++] = atoi(parser); + uint32_t code = 0; + int id = atoi(parser); + if (id) + { + for (int n = 0; n < data->ntilers; n++) + { + if (id < gids[n]) + continue; + if (n == data->ntilers - 1 + || id < gids[n + 1]) + { + code = (data->tilers[n] << 16) | (id - 1); + break; + } + } + } + + tiles[ntiles++] = code; while (isdigit(*parser)) parser++; if (*parser == ',') @@ -48,31 +91,33 @@ Map::Map(char const *path) : if (ntiles == width * height) { - layers[nlayers] = new Layer(width, height, level, data); - nlayers++; - data = NULL; + data->layers[data->nlayers] = new Layer(width, height, level, tiles); + data->nlayers++; + tiles = NULL; } } else if (sscanf(tmp, " ntilers] = i; } else if (sscanf(tmp, " tilers[data->ntilers] = Tiler::Register(str); + data->ntilers++; } else if (sscanf(tmp, " layers = (Layer **)realloc(data->layers, + sizeof(Layer **) * (data->nlayers + 1)); orientation = toupper(a) == 'V' ? 1 : 0; width = j; height = k; + tiles = (uint32_t *)malloc(width * height * sizeof(uint32_t)); ntiles = 0; - data = (uint32_t *)malloc(width * height * sizeof(uint32_t)); } } @@ -81,20 +126,17 @@ Map::Map(char const *path) : Map::~Map() { - for (int i = 0; i < nlayers; i++) - delete layers[i]; - free(layers); + for (int i = 0; i < data->ntilers; i++) + Tiler::Deregister(data->tilers[i]); + for (int i = 0; i < data->nlayers; i++) + delete data->layers[i]; + free(data->layers); + delete data; } -void Map::Draw(Tileset *tileset) +void Map::Draw() { - for (int i = 0; i < nlayers; i++) - { - int z = layers[i]->GetZ(); - - for (int y = 0; y < 32; y++) - for (int x = 0; x < 32; x++) - tileset->AddTile(layers[i]->GetTile(x, y), x * 32, y * 32, z); - } + for (int i = 0; i < data->nlayers; i++) + data->layers[i]->Draw(); } diff --git a/src/map.h b/src/map.h index 3abd2d89..c4e69687 100644 --- a/src/map.h +++ b/src/map.h @@ -9,7 +9,8 @@ #include #include "layer.h" -#include "tileset.h" + +class MapData; class Map { @@ -17,11 +18,10 @@ public: Map(char const *path); ~Map(); - void Draw(Tileset *tileset); + void Draw(); private: - Layer **layers; - int nlayers; + MapData *data; }; #endif // __DH_MAP_H__ diff --git a/src/scene.cpp b/src/scene.cpp new file mode 100644 index 00000000..ac622f19 --- /dev/null +++ b/src/scene.cpp @@ -0,0 +1,29 @@ + +#include "scene.h" + +/* + * Scene implementation class + */ + +class SceneData +{ + friend class Scene; + +private: + int dummy; +}; + +/* + * Public Scene class + */ + +Scene::Scene() +{ + data = new SceneData(); +} + +Scene::~Scene() +{ + delete data; +} + diff --git a/src/scene.h b/src/scene.h new file mode 100644 index 00000000..ce04675d --- /dev/null +++ b/src/scene.h @@ -0,0 +1,25 @@ + +/* + * The scene object + */ + +#if !defined __DH_SCENE_H__ +#define __DH_SCENE_H__ + +#include +#include + +class SceneData; + +class Scene +{ +public: + Scene(); + ~Scene(); + +private: + SceneData *data; +}; + +#endif // __DH_SCENE_H__ + diff --git a/src/test-map.cpp b/src/test-map.cpp index b20c459f..5287bdcf 100644 --- a/src/test-map.cpp +++ b/src/test-map.cpp @@ -6,20 +6,19 @@ #include #include "video.h" -#include "tileset.h" +#include "tiler.h" #include "map.h" int main(int argc, char **argv) { Video *video = new Video("Deus Hax", 640, 480); - Tileset *tileset = new Tileset(); Map *map = new Map("maps/testmap-grass.tmx"); for (int done = 0; !done; ) { video->Clear(); - map->Draw(tileset); + //map->Draw(tiler); /* Test stuff */ int playerx, playery; @@ -27,9 +26,9 @@ int main(int argc, char **argv) playerx = playerx * (640 - 32) / 640; playery = playery * (480 - 32) / 480; - tileset->AddTile(50, playerx, playery, 1); + //tiler->AddTile(50, playerx, playery, 1); - tileset->Render(); + //tiler->Render(); video->Refresh(33.33333f); /* This could go in a separate function */ @@ -49,7 +48,6 @@ int main(int argc, char **argv) } delete map; - delete tileset; delete video; return EXIT_SUCCESS; diff --git a/src/tiler.cpp b/src/tiler.cpp new file mode 100644 index 00000000..4dd36d41 --- /dev/null +++ b/src/tiler.cpp @@ -0,0 +1,85 @@ + +#include +#include +#include + +#include "tiler.h" +#include "tileset.h" + +/* + * Tiler implementation class + */ + +static class TilerData +{ + friend class Tiler; + +public: + TilerData() : + tilesets(0), + ntilesets(0) + { + /* Nothing to do */ + } + + ~TilerData() + { + free(tilesets); + } + +private: + TileSet **tilesets; + int ntilesets; +} +tilerdata; + +static TilerData * const data = &tilerdata; + +/* + * Public Tiler class + */ + +int Tiler::Register(char const *path) +{ + int id, empty = -1; + + /* If the tileset is already registered, remember its ID. Look for an + * empty slot at the same time. */ + for (id = 0; id < data->ntilesets; id++) + { + TileSet *t = data->tilesets[id]; + if (!t) + empty = id; + else if (!strcasecmp(path, t->GetName())) + break; + } + + /* If this is a new tileset, create a new one. */ + if (id == data->ntilesets) + { + if (empty == -1) + { + empty = data->ntilesets++; + data->tilesets = (TileSet **)realloc(data->tilesets, + data->ntilesets * sizeof(TileSet *)); + } + + data->tilesets[empty] = new TileSet(path); + id = empty; + } + + data->tilesets[id]->Ref(); + return id + 1; /* ID 0 is for the empty tileset */ +} + +void Tiler::Deregister(int id) +{ + --id; /* ID 0 is for the empty tileset */ + + if (data->tilesets[id]->Unref() == 0) + { + delete data->tilesets[id]; + data->tilesets[id] = NULL; + } +} + diff --git a/src/tiler.h b/src/tiler.h new file mode 100644 index 00000000..64e6a56e --- /dev/null +++ b/src/tiler.h @@ -0,0 +1,17 @@ + +/* + * The tile manager + */ + +#if !defined __DH_TILER_H__ +#define __DH_TILER_H__ + +class Tiler +{ +public: + static int Register(char const *path); + static void Deregister(int id); +}; + +#endif // __DH_TILER_H__ + diff --git a/src/tileset.cpp b/src/tileset.cpp index f85fc738..0c1c0aa0 100644 --- a/src/tileset.cpp +++ b/src/tileset.cpp @@ -19,12 +19,12 @@ #include "tileset.h" /* - * Tileset implementation class + * TileSet implementation class */ -class TilesetData +class TileSetData { - friend class Tileset; + friend class TileSet; private: static int Compare(void const *p1, void const *p2) @@ -35,6 +35,8 @@ private: return n1[2] + 32 * n1[3] - (n2[2] + 32 * n2[3]); } + char *name; + int ref; int *tiles; int ntiles; @@ -43,17 +45,23 @@ private: }; /* - * Public Tileset class + * Public TileSet class */ -Tileset::Tileset() +TileSet::TileSet(char const *path) { - data = new TilesetData(); + SDL_Surface *img = NULL; + + data = new TileSetData(); + data->name = strdup(path); + data->ref = 0; data->tiles = NULL; data->ntiles = 0; /* One tile texture */ - SDL_Surface *img = IMG_Load("art/test/grasstest.png"); + for (char const *name = path; *name; name++) + if ((img = IMG_Load(name))) + break; if (!img) { @@ -61,7 +69,7 @@ Tileset::Tileset() exit(1); } - glGenTextures(1, &data->texture[0]); + glGenTextures(1, data->texture); glBindTexture(GL_TEXTURE_2D, data->texture[0]); glTexImage2D(GL_TEXTURE_2D, 0, 4, img->w, img->h, 0, @@ -74,13 +82,32 @@ Tileset::Tileset() glGenBuffers(3, data->buflist); } -Tileset::~Tileset() +TileSet::~TileSet() { + glDeleteTextures(1, data->texture); + glDeleteBuffers(3, data->buflist); + free(data->tiles); + free(data->name); delete data; } -void Tileset::AddTile(int n, int x, int y, int z) +void TileSet::Ref() +{ + data->ref++; +} + +int TileSet::Unref() +{ + return --data->ref; +} + +char const *TileSet::GetName() +{ + return data->name; +} + +void TileSet::AddTile(int n, int x, int y, int z) { if ((data->ntiles % 1024) == 0) { @@ -96,10 +123,10 @@ void Tileset::AddTile(int n, int x, int y, int z) data->ntiles++; } -void Tileset::Render() +void TileSet::Render() { /* Sort tiles */ - qsort(data->tiles, data->ntiles, 4 * sizeof(int), TilesetData::Compare); + qsort(data->tiles, data->ntiles, 4 * sizeof(int), TileSetData::Compare); /* Texture coord buffer */ float uvs[8 * data->ntiles]; diff --git a/src/tileset.h b/src/tileset.h index 2a9cd369..24f0c26a 100644 --- a/src/tileset.h +++ b/src/tileset.h @@ -3,24 +3,29 @@ * The tile manager */ -#if !defined __DH_TILER_H__ -#define __DH_TILER_H__ +#if !defined __DH_TILESET_H__ +#define __DH_TILESET_H__ -class TilesetData; +class TileSetData; -class Tileset +class TileSet { public: - Tileset(); - ~Tileset(); + TileSet(char const *path); + ~TileSet(); + + void Ref(); + int Unref(); + + char const *GetName(); void AddTile(int n, int x, int y, int z); void Render(); private: - TilesetData *data; + TileSetData *data; }; -#endif // __DH_TILER_H__ +#endif // __DH_TILESET_H__