Skip to content

Commit

Permalink
Tilengine 2.15.3
Browse files Browse the repository at this point in the history
* Fixes bug with multiple tilesets per tilemap when not correlative
* Expands nº of tilesets per tilemap up to 16
* Palettes always allocate 256 colors. Avoids crash when assigning a palette with less colors than used by the tileset
* Mode7.c: fixes wrong type for some objects
* closes #113, #120
  • Loading branch information
megamarc committed Sep 29, 2024
1 parent eab1387 commit d4f8737
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 69 deletions.
14 changes: 9 additions & 5 deletions include/Tilengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
/* version */
#define TILENGINE_VER_MAJ 2
#define TILENGINE_VER_MIN 15
#define TILENGINE_VER_REV 2
#define TILENGINE_VER_REV 3
#define TILENGINE_HEADER_VERSION ((TILENGINE_VER_MAJ << 16) | (TILENGINE_VER_MIN << 8) | TILENGINE_VER_REV)

#define BITVAL(n) (1<<(n))
Expand All @@ -74,8 +74,8 @@ typedef enum
FLAG_ROTATE = BITVAL(13), /*!< row/column flip (unsupported, Tiled compatibility) */
FLAG_PRIORITY = BITVAL(12), /*!< tile goes in front of sprite layer */
FLAG_MASKED = BITVAL(11), /*!< sprite won't be drawn inside masked region */
FLAG_TILESET = (7 << 8), /*!< tileset index (0 - 7) */
FLAG_PALETTE = (7 << 5), /*!< palette index (0 - 7) */
FLAG_TILESET = (15 << 7), /*!< tileset index (0 - 15) */
FLAG_PALETTE = (7 << 4), /*!< palette index (0 - 7) */
}
TLN_TileFlags;

Expand Down Expand Up @@ -132,14 +132,18 @@ typedef union Tile
uint16_t flags; /*!< attributes (FLAG_FLIPX, FLAG_FLIPY, FLAG_PRIORITY) */
struct
{
uint8_t unused : 5;
uint8_t unused : 4;
uint8_t palette : 3;
uint8_t tileset : 3;
uint8_t tileset : 4;

// COMPILER ERROR: although whole struct fits in 32 bits, compiler expands to 64, causing addressing errors
/*
bool masked : 1;
bool priority : 1;
bool rotated : 1;
bool flipy : 1;
bool flipx : 1;
*/
};
};
};
Expand Down
2 changes: 1 addition & 1 deletion samples/Mode7.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ int inc_background[6] = {0};

fix_t x,y,s,a;

static TLN_Tileset road, horizon;
static TLN_Tilemap road, horizon;
static int angle;

static void raster_callback (int line);
Expand Down
14 changes: 7 additions & 7 deletions src/Draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,10 +364,10 @@ static bool DrawTiledScanline(int nlayer, uint32_t* dstpixel, int nscan, int tx1
int width = x1 - x;

/* paint if not empty tile */
if (tile->index)
if (tile->index != 0)
{
const TLN_Tileset tileset = tilemap->tilesets[tile->tileset];
const uint16_t tile_index = tileset->tiles[tile->index];
const uint16_t tile_index = tileset->tiles[tile->index] - 1;

/* selects suitable palette */
TLN_Palette palette = tileset->palette;
Expand Down Expand Up @@ -460,10 +460,10 @@ static bool DrawTiledScanlineScaling(int nlayer, uint32_t* dstpixel, int nscan,
int width = x1 - x;

/* paint if tile is not empty */
if (tile->index)
if (tile->index != 0)
{
const TLN_Tileset tileset = tilemap->tilesets[tile->tileset];
const uint16_t tile_index = tileset->tiles[tile->index];
const uint16_t tile_index = tileset->tiles[tile->index] - 1;

/* selects suitable palette */
TLN_Palette palette = tileset->palette;
Expand Down Expand Up @@ -547,7 +547,7 @@ static bool DrawTiledScanlineAffine(int nlayer, uint32_t* dstpixel, int nscan, i
if (tile->index != 0)
{
const TLN_Tileset tileset = tilemap->tilesets[tile->tileset];
const uint16_t tile_index = tileset->tiles[tile->index];
const uint16_t tile_index = tileset->tiles[tile->index] - 1;

/* process flip & rotation flags */
if ((tile->flags & (FLAG_FLIPX + FLAG_FLIPY + FLAG_ROTATE)) != 0)
Expand Down Expand Up @@ -599,10 +599,10 @@ static bool DrawTiledScanlinePixelMapping(int nlayer, uint32_t* dstpixel, int ns
TLN_Tile tile = &tilemap->tiles[ytile*tilemap->cols + xtile];

/* paint if not empty tile */
if (tile->index)
if (tile->index != 0)
{
const TLN_Tileset tileset = tilemap->tilesets[tile->tileset];
const uint16_t tile_index = tileset->tiles[tile->index];
const uint16_t tile_index = tileset->tiles[tile->index] - 1;

/* process flip & rotation flags */
if ((tile->flags & (FLAG_FLIPX + FLAG_FLIPY + FLAG_ROTATE)) != 0)
Expand Down
15 changes: 6 additions & 9 deletions src/LoadTMX.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,20 +194,17 @@ bool TMXLoad(const char* filename, TMXInfo* info)
return retval;
}

/* returns index of suitable tileset acoording to gid range */
int TMXGetSuitableTileset(TMXInfo* info, int gid, TMXTileset* tmxtilesets)
/* returns index of suitable tileset acoording to gid range, -1 if not valid tileset found */
int TMXGetSuitableTileset(TMXInfo* info, int gid, TLN_Tileset* tilesets)
{
/* if no tilesets list provided, use internal one */
if (tmxtilesets == NULL)
tmxtilesets = info->tilesets;

int c;
for (c = 0; c < info->num_tilesets; c += 1, tmxtilesets += 1)
for (c = 0; c < info->num_tilesets; c += 1)
{
if (gid >= tmxtilesets->firstgid && (gid < tmxtilesets[1].firstgid || tmxtilesets[1].firstgid == 0))
const int first = info->tilesets[c].firstgid;
if (gid >= first && gid < first + tilesets[c]->numtiles)
return c;
}
return c;
return -1;
}

/*returns first layer of requested type */
Expand Down
2 changes: 1 addition & 1 deletion src/LoadTMX.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ typedef struct
TMXInfo;

bool TMXLoad(const char* filename, TMXInfo* info);
int TMXGetSuitableTileset(TMXInfo* info, int gid, TMXTileset* tmxtilesets);
int TMXGetSuitableTileset(TMXInfo* info, int gid, TLN_Tileset* tilesets);
TMXLayer* TMXGetFirstLayer(TMXInfo* info, TLN_LayerType type);
TMXLayer* TMXGetLayer(TMXInfo* info, const char* name);

Expand Down
51 changes: 18 additions & 33 deletions src/LoadTilemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ TLN_Tilemap TLN_LoadTilemap (const char *filename, const char *layername)
uint8_t *data;
TLN_Tilemap tilemap = NULL;
TMXInfo tmxinfo = { 0 };
uint32_t c;

/* load map info */
if (!TMXLoad(filename, &tmxinfo))
Expand Down Expand Up @@ -215,54 +216,38 @@ TLN_Tilemap TLN_LoadTilemap (const char *filename, const char *layername)
simpleXmlDestroyParser(parser);
free (data);

/* load referenced tilesets */
TLN_Tileset tilesets[TMX_MAX_TILESET] = { 0 };
for (c = 0; c < tmxinfo.num_tilesets; c += 1)
tilesets[c] = load_tileset(&tmxinfo, filename, c);

if (loader.data != NULL)
{
Tile* tile;
uint32_t c;

/* build map of actually used tilesets */
bool _tilesets[TMX_MAX_TILESET] = { 0 };
tile = (Tile*)loader.data;
for (c = 0; c < loader.numtiles; c += 1, tile += 1)
{
if (tile->index > 0)
{
int index = TMXGetSuitableTileset(&tmxinfo, tile->index, NULL);
_tilesets[index] = true;
}
}

/* build list of used tilesets */
TLN_Tileset tilesets[MAX_TILESETS] = { 0 };
TMXTileset used_tilesets[MAX_TILESETS] = { 0 };
uint32_t used_index = 0;
for (c = 0; c < TMX_MAX_TILESET; c += 1)
{
if (_tilesets[c] && used_index < MAX_TILESETS - 1)
{
tilesets[used_index] = load_tileset(&tmxinfo, filename, c);
memcpy(&used_tilesets[used_index], &tmxinfo.tilesets[c], sizeof(TMXTileset));
used_index += 1;
}
}

/* correct with firstgid */
tile = (Tile*)loader.data;
Tile* tile = (Tile*)loader.data;
for (c = 0; c < loader.numtiles; c += 1, tile += 1)
{
if (tile->index > 0)
{
tile->tileset = TMXGetSuitableTileset(&tmxinfo, tile->index, used_tilesets);
tile->index = tile->index - used_tilesets[tile->tileset].firstgid + 1;
int suitable = TMXGetSuitableTileset(&tmxinfo, tile->index, tilesets);
if (suitable != -1 && suitable < MAX_TILESETS)
{
tile->tileset = suitable;
tile->index = tile->index - tmxinfo.tilesets[suitable].firstgid + 1;
}
else
tile->index = 0;
}
}

/* create */
tilemap = TLN_CreateTilemap(loader.layer->height, loader.layer->width, (Tile*)loader.data, tmxinfo.bgcolor, NULL);
tilemap->id = loader.layer->id;
tilemap->visible = loader.layer->visible;
memcpy(tilemap->tilesets, tilesets, sizeof(TLN_Tileset)*MAX_TILESETS);
tilemap->num_tilesets = tmxinfo.num_tilesets < MAX_TILESETS ? tmxinfo.num_tilesets : MAX_TILESETS;
memcpy(tilemap->tilesets, tilesets, sizeof(TLN_Tileset)*tilemap->num_tilesets);
}

return tilemap;
}

Expand Down
8 changes: 5 additions & 3 deletions src/LoadTileset.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,8 @@ TLN_Tileset TLN_LoadTileset (const char* filename)
dy = loader.tileheight + loader.spacing;
htiles = (TLN_GetBitmapWidth(bitmap) - loader.margin * 2 + loader.spacing) / dx;
vtiles = (TLN_GetBitmapHeight(bitmap) - loader.margin * 2 + loader.spacing) / dy;
tileset = TLN_CreateTileset(htiles*vtiles, loader.tilewidth, loader.tileheight, TLN_ClonePalette(TLN_GetBitmapPalette(bitmap)), loader.sp, loader.attributes);
int tilecount = loader.tilecount != 0 ? loader.tilecount : htiles * vtiles;
tileset = TLN_CreateTileset(tilecount, loader.tilewidth, loader.tileheight, TLN_ClonePalette(TLN_GetBitmapPalette(bitmap)), loader.sp, loader.attributes);
if (tileset == NULL)
{
TLN_SetLastError(TLN_ERR_OUT_OF_MEMORY);
Expand All @@ -334,12 +335,13 @@ TLN_Tileset TLN_LoadTileset (const char* filename)

/* load tile data */
pitch = TLN_GetBitmapPitch(bitmap);
for (id = 1, y = 0; y < vtiles; y++)
for (id = 0, y = 0; y < vtiles; y++)
{
for (x = 0; x < htiles; x++, id++)
{
uint8_t *srcptr = TLN_GetBitmapPtr(bitmap, loader.margin + x * dx, loader.margin + y * dy);
TLN_SetTilesetPixels(tileset, id, srcptr, pitch);
if (id < tilecount)
TLN_SetTilesetPixels(tileset, id, srcptr, pitch);
}
}
tileset->tiles_per_row = htiles;
Expand Down
24 changes: 19 additions & 5 deletions src/ObjectList.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,31 +289,45 @@ TLN_ObjectList TLN_LoadObjectList(const char* filename, const char* layername)

if (loader.objects != NULL)
{
TLN_Tileset tileset = NULL;
TMXTileset* tmxtileset;
struct _Object* item;
int gid = 0;
int c;

/* find suitable tileset */
item = loader.objects->list;
while (item && gid == 0)
while (item != NULL && gid == 0)
{
if (item->gid > 0)
gid = item->gid;
item = item->next;
}
tmxtileset = &tmxinfo.tilesets[TMXGetSuitableTileset(&tmxinfo, gid, NULL)];
tileset = TLN_LoadTileset(tmxtileset->source);

/* load referenced tilesets */
TLN_Tileset tilesets[TMX_MAX_TILESET] = { 0 };
for (c = 0; c < tmxinfo.num_tilesets; c += 1)
tilesets[c] = TLN_LoadTileset(tmxinfo.tilesets[c].source);

int suitable = TMXGetSuitableTileset(&tmxinfo, gid, tilesets);
tmxtileset = &tmxinfo.tilesets[suitable];

/* correct with firstgid */
item = loader.objects->list;
while (item)
while (item != NULL)
{
if (item->gid > 0)
item->gid = item->gid - tmxtileset->firstgid;
item = item->next;
}

/* delete unused tilesets */
for (c = 0; c < tmxinfo.num_tilesets; c += 1)
{
if (c != suitable)
TLN_DeleteTileset(tilesets[c]);
}

TLN_Tileset tileset = tilesets[suitable];
loader.objects->tileset = tileset;
loader.objects->width = tmxinfo.width*tmxinfo.tilewidth;
loader.objects->height = tmxinfo.height*tmxinfo.tileheight;
Expand Down
2 changes: 1 addition & 1 deletion src/Palette.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
TLN_Palette TLN_CreatePalette (int entries)
{
TLN_Palette palette;
int size = sizeof(struct Palette) + (4*entries);
int size = sizeof(struct Palette) + 1024; // always alloc 256 colors, to avoid crash when tileset uses more colors than the palette

palette = (TLN_Palette)CreateBaseObject(OT_PALETTE, size);
if (palette)
Expand Down
3 changes: 2 additions & 1 deletion src/Tilemap.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include "Object.h"
#include "Tileset.h"

#define MAX_TILESETS 8
#define MAX_TILESETS 16

/* mapa */
struct Tilemap
Expand All @@ -26,6 +26,7 @@ struct Tilemap
int id; /* id property */
bool visible; /* visible property */
struct Tileset* tilesets[MAX_TILESETS]; /* attached tilesets */
int num_tilesets; /* actual amount of tilesets */
Tile tiles[];
};

Expand Down
5 changes: 2 additions & 3 deletions src/Tileset.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ TLN_Tileset TLN_CreateTileset (int numtiles, int width, int height, TLN_Palette
return NULL;
}

numtiles++;
size_tiles = width * height * numtiles;
size = sizeof(struct Tileset) + size_tiles;
tileset = (TLN_Tileset)CreateBaseObject (OT_TILESET, size);
Expand Down Expand Up @@ -177,7 +176,7 @@ bool TLN_SetTilesetPixels (TLN_Tileset tileset, int entry, uint8_t* srcdata, int
if (!CheckBaseObject (tileset, OT_TILESET))
return false;

if (tileset->tstype != TILESET_TILES || entry<1 || entry>tileset->numtiles)
if (tileset->tstype != TILESET_TILES || entry>tileset->numtiles)
{
TLN_SetLastError(TLN_ERR_IDX_PICTURE);
return false;
Expand Down Expand Up @@ -258,7 +257,7 @@ TLN_Tileset TLN_CloneTileset (TLN_Tileset src)
*/
bool TLN_DeleteTileset (TLN_Tileset tileset)
{
// TODO fix crash on exit, only on Release build, can't be debugged
// TODO: implement refcount on cached tilesets, avoid deleting a cached instance
return true;

if (CheckBaseObject (tileset, OT_TILESET))
Expand Down

0 comments on commit d4f8737

Please sign in to comment.