@@ -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__ | |||||