| @@ -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 | all: test-map | ||||
| @@ -1,4 +1,6 @@ | |||||
| #include <stdlib.h> | |||||
| #include "layer.h" | #include "layer.h" | ||||
| Layer::Layer(int w, int h, int in_z, uint32_t *in_data) | 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() | 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() | int Layer::GetZ() | ||||
| @@ -18,6 +18,8 @@ public: | |||||
| int GetZ(); | int GetZ(); | ||||
| unsigned int GetTile(int x, int y); | unsigned int GetTile(int x, int y); | ||||
| void Draw(); | |||||
| private: | private: | ||||
| int width, height, z; | int width, height, z; | ||||
| uint32_t *data; | uint32_t *data; | ||||
| @@ -7,15 +7,40 @@ | |||||
| #include "map.h" | #include "map.h" | ||||
| #include "layer.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]; | 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"); | FILE *fp = fopen(path, "r"); | ||||
| @@ -28,16 +53,34 @@ Map::Map(char const *path) : | |||||
| int i, j, k; | int i, j, k; | ||||
| char a, b; | char a, b; | ||||
| /* Read a line, then decide what to do with it. */ | |||||
| fgets(tmp, BUFSIZ, fp); | fgets(tmp, BUFSIZ, fp); | ||||
| if (data) | |||||
| if (tiles) | |||||
| { | { | ||||
| /* We are in the process of reading layer data. Only stop | /* We are in the process of reading layer data. Only stop | ||||
| * when we have read the expected number of tiles. */ | * when we have read the expected number of tiles. */ | ||||
| char const *parser = tmp; | char const *parser = tmp; | ||||
| while (ntiles < width * height) | 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)) | while (isdigit(*parser)) | ||||
| parser++; | parser++; | ||||
| if (*parser == ',') | if (*parser == ',') | ||||
| @@ -48,31 +91,33 @@ Map::Map(char const *path) : | |||||
| if (ntiles == width * height) | 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, " <tileset firstgid=\"%i\"", &i) == 1) | else if (sscanf(tmp, " <tileset firstgid=\"%i\"", &i) == 1) | ||||
| { | { | ||||
| /* This is a tileset description. Remember its firstgid value. */ | |||||
| firstgid = i; | |||||
| /* This is a tileset description. Remember its first gid value. */ | |||||
| gids[data->ntilers] = i; | |||||
| } | } | ||||
| else if (sscanf(tmp, " <image source=\"%[^\"]\"", str) == 1) | else if (sscanf(tmp, " <image source=\"%[^\"]\"", str) == 1) | ||||
| { | { | ||||
| /* This is a tileset image file. Associate it with firstgid. */ | /* This is a tileset image file. Associate it with firstgid. */ | ||||
| data->tilers[data->ntilers] = Tiler::Register(str); | |||||
| data->ntilers++; | |||||
| } | } | ||||
| else if (sscanf(tmp, " <layer name=\"%c%i%c%*[^\"]\" " | else if (sscanf(tmp, " <layer name=\"%c%i%c%*[^\"]\" " | ||||
| "width=\"%i\" height=\"%i\"", &a, &i, &b, &j, &k) == 5) | "width=\"%i\" height=\"%i\"", &a, &i, &b, &j, &k) == 5) | ||||
| { | { | ||||
| /* This is a layer description. Prepare to read the data. */ | /* This is a layer description. Prepare to read the data. */ | ||||
| layers = (Layer **)realloc(layers, | |||||
| sizeof(Layer **) * (nlayers + 1)); | |||||
| data->layers = (Layer **)realloc(data->layers, | |||||
| sizeof(Layer **) * (data->nlayers + 1)); | |||||
| orientation = toupper(a) == 'V' ? 1 : 0; | orientation = toupper(a) == 'V' ? 1 : 0; | ||||
| width = j; | width = j; | ||||
| height = k; | height = k; | ||||
| tiles = (uint32_t *)malloc(width * height * sizeof(uint32_t)); | |||||
| ntiles = 0; | ntiles = 0; | ||||
| data = (uint32_t *)malloc(width * height * sizeof(uint32_t)); | |||||
| } | } | ||||
| } | } | ||||
| @@ -81,20 +126,17 @@ Map::Map(char const *path) : | |||||
| Map::~Map() | 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(); | |||||
| } | } | ||||
| @@ -9,7 +9,8 @@ | |||||
| #include <cstdio> | #include <cstdio> | ||||
| #include "layer.h" | #include "layer.h" | ||||
| #include "tileset.h" | |||||
| class MapData; | |||||
| class Map | class Map | ||||
| { | { | ||||
| @@ -17,11 +18,10 @@ public: | |||||
| Map(char const *path); | Map(char const *path); | ||||
| ~Map(); | ~Map(); | ||||
| void Draw(Tileset *tileset); | |||||
| void Draw(); | |||||
| private: | private: | ||||
| Layer **layers; | |||||
| int nlayers; | |||||
| MapData *data; | |||||
| }; | }; | ||||
| #endif // __DH_MAP_H__ | #endif // __DH_MAP_H__ | ||||
| @@ -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; | |||||
| } | |||||
| @@ -0,0 +1,25 @@ | |||||
| /* | |||||
| * The scene object | |||||
| */ | |||||
| #if !defined __DH_SCENE_H__ | |||||
| #define __DH_SCENE_H__ | |||||
| #include <cstdio> | |||||
| #include <stdint.h> | |||||
| class SceneData; | |||||
| class Scene | |||||
| { | |||||
| public: | |||||
| Scene(); | |||||
| ~Scene(); | |||||
| private: | |||||
| SceneData *data; | |||||
| }; | |||||
| #endif // __DH_SCENE_H__ | |||||
| @@ -6,20 +6,19 @@ | |||||
| #include <math.h> | #include <math.h> | ||||
| #include "video.h" | #include "video.h" | ||||
| #include "tileset.h" | |||||
| #include "tiler.h" | |||||
| #include "map.h" | #include "map.h" | ||||
| int main(int argc, char **argv) | int main(int argc, char **argv) | ||||
| { | { | ||||
| Video *video = new Video("Deus Hax", 640, 480); | Video *video = new Video("Deus Hax", 640, 480); | ||||
| Tileset *tileset = new Tileset(); | |||||
| Map *map = new Map("maps/testmap-grass.tmx"); | Map *map = new Map("maps/testmap-grass.tmx"); | ||||
| for (int done = 0; !done; ) | for (int done = 0; !done; ) | ||||
| { | { | ||||
| video->Clear(); | video->Clear(); | ||||
| map->Draw(tileset); | |||||
| //map->Draw(tiler); | |||||
| /* Test stuff */ | /* Test stuff */ | ||||
| int playerx, playery; | int playerx, playery; | ||||
| @@ -27,9 +26,9 @@ int main(int argc, char **argv) | |||||
| playerx = playerx * (640 - 32) / 640; | playerx = playerx * (640 - 32) / 640; | ||||
| playery = playery * (480 - 32) / 480; | 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); | video->Refresh(33.33333f); | ||||
| /* This could go in a separate function */ | /* This could go in a separate function */ | ||||
| @@ -49,7 +48,6 @@ int main(int argc, char **argv) | |||||
| } | } | ||||
| delete map; | delete map; | ||||
| delete tileset; | |||||
| delete video; | delete video; | ||||
| return EXIT_SUCCESS; | return EXIT_SUCCESS; | ||||
| @@ -0,0 +1,85 @@ | |||||
| #include <cstring> | |||||
| #include <cstdio> | |||||
| #include <stdlib.h> | |||||
| #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; | |||||
| } | |||||
| } | |||||
| @@ -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__ | |||||
| @@ -19,12 +19,12 @@ | |||||
| #include "tileset.h" | #include "tileset.h" | ||||
| /* | /* | ||||
| * Tileset implementation class | |||||
| * TileSet implementation class | |||||
| */ | */ | ||||
| class TilesetData | |||||
| class TileSetData | |||||
| { | { | ||||
| friend class Tileset; | |||||
| friend class TileSet; | |||||
| private: | private: | ||||
| static int Compare(void const *p1, void const *p2) | 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]); | return n1[2] + 32 * n1[3] - (n2[2] + 32 * n2[3]); | ||||
| } | } | ||||
| char *name; | |||||
| int ref; | |||||
| int *tiles; | int *tiles; | ||||
| int ntiles; | 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->tiles = NULL; | ||||
| data->ntiles = 0; | data->ntiles = 0; | ||||
| /* One tile texture */ | /* 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) | if (!img) | ||||
| { | { | ||||
| @@ -61,7 +69,7 @@ Tileset::Tileset() | |||||
| exit(1); | exit(1); | ||||
| } | } | ||||
| glGenTextures(1, &data->texture[0]); | |||||
| glGenTextures(1, data->texture); | |||||
| glBindTexture(GL_TEXTURE_2D, data->texture[0]); | glBindTexture(GL_TEXTURE_2D, data->texture[0]); | ||||
| glTexImage2D(GL_TEXTURE_2D, 0, 4, img->w, img->h, 0, | glTexImage2D(GL_TEXTURE_2D, 0, 4, img->w, img->h, 0, | ||||
| @@ -74,13 +82,32 @@ Tileset::Tileset() | |||||
| glGenBuffers(3, data->buflist); | glGenBuffers(3, data->buflist); | ||||
| } | } | ||||
| Tileset::~Tileset() | |||||
| TileSet::~TileSet() | |||||
| { | { | ||||
| glDeleteTextures(1, data->texture); | |||||
| glDeleteBuffers(3, data->buflist); | |||||
| free(data->tiles); | free(data->tiles); | ||||
| free(data->name); | |||||
| delete data; | 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) | if ((data->ntiles % 1024) == 0) | ||||
| { | { | ||||
| @@ -96,10 +123,10 @@ void Tileset::AddTile(int n, int x, int y, int z) | |||||
| data->ntiles++; | data->ntiles++; | ||||
| } | } | ||||
| void Tileset::Render() | |||||
| void TileSet::Render() | |||||
| { | { | ||||
| /* Sort tiles */ | /* 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 */ | /* Texture coord buffer */ | ||||
| float uvs[8 * data->ntiles]; | float uvs[8 * data->ntiles]; | ||||
| @@ -3,24 +3,29 @@ | |||||
| * The tile manager | * 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: | 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 AddTile(int n, int x, int y, int z); | ||||
| void Render(); | void Render(); | ||||
| private: | private: | ||||
| TilesetData *data; | |||||
| TileSetData *data; | |||||
| }; | }; | ||||
| #endif // __DH_TILER_H__ | |||||
| #endif // __DH_TILESET_H__ | |||||