Files
RCBASIC4/rcbasic_runtime/rc_tilelib.h
2025-07-08 21:17:11 -05:00

463 lines
12 KiB
C
Executable File

#ifndef RC_TILELIB_H_INCLUDED
#define RC_TILELIB_H_INCLUDED
#ifdef RC_ANDROID
#include "SDL.h"
#else
#include <SDL2/SDL.h>
#endif // _IRR_ANDROID_PLATFORM_
#include "rc_tilemap.h"
#include "rc_gfx_core.h"
int rc_createTileSet(int img_id, int tile_w, int tile_h)
{
if(img_id < 0 || img_id >= rc_image.size())
return -1;
if(!rc_image[img_id].image)
return -1;
rc_tileset_obj tset;
tset.active = true;
tset.img_id = img_id;
tset.tile_width = tile_w;
tset.tile_height = tile_h;
int num_tiles = ((int)rc_image[img_id].image->getSize().Width / tile_w) * ((int)rc_image[img_id].image->getSize().Height / tile_h);
tset.tiles.resize(num_tiles);
for(int i = 0; i < tset.tiles.size(); i++)
{
tset.tiles[i].frames.push_back(i);
tset.tiles[i].fps = 0;
tset.tiles[i].frame_swap_time = 0;
tset.tiles[i].frame_start_time = 0;
}
int tset_id = rc_tileset.size();
if(rc_deleted_tileset.size() > 0)
{
tset_id = rc_deleted_tileset[0];
rc_deleted_tileset.erase(rc_deleted_tileset.begin());
rc_tileset[tset_id] = tset;
}
else
rc_tileset.push_back(tset);
return tset_id;
}
void rc_deleteTileSet(int tileset)
{
if(tileset < 0 || tileset >= rc_tileset.size())
return;
if(!rc_tileset[tileset].active)
return;
rc_tileset[tileset].tiles.clear();
rc_tileset[tileset].img_id = -1;
rc_tileset[tileset].active = false;
rc_deleted_tileset.push_back(tileset);
}
bool rc_tileSetExists(int tileset)
{
if(tileset < 0 || tileset >= rc_tileset.size())
return false;
return rc_tileset[tileset].active;
}
void rc_setTileAnimationLength(int tileset, int base_tile, int num_frames)
{
if(tileset < 0 || tileset >= rc_tileset.size())
return;
if(!rc_tileset[tileset].active)
return;
if(base_tile < 0 || base_tile >= rc_tileset[tileset].tiles.size())
return;
rc_tileset[tileset].tiles[base_tile].frames.resize(num_frames);
rc_tileset[tileset].tiles[base_tile].num_frames = num_frames;
}
int rc_getTileAnimationLength(int tileset, int base_tile)
{
if(tileset < 0 || tileset >= rc_tileset.size())
return 0;
if(!rc_tileset[tileset].active)
return 0;
if(base_tile < 0 || base_tile >= rc_tileset[tileset].tiles.size())
return 0;
return rc_tileset[tileset].tiles[base_tile].num_frames;
}
void rc_setTileAnimationFrame(int tileset, int base_tile, int anim_frame, int tile_frame)
{
if(tileset < 0 || tileset >= rc_tileset.size())
return;
if(!rc_tileset[tileset].active)
return;
if(base_tile < 0 || base_tile >= rc_tileset[tileset].tiles.size())
return;
rc_tileset[tileset].tiles[base_tile].frames[anim_frame] = tile_frame;
}
int rc_getTileAnimationFrame(int tileset, int base_tile, int anim_frame)
{
if(tileset < 0 || tileset >= rc_tileset.size())
return -1;
if(!rc_tileset[tileset].active)
return -1;
if(base_tile < 0 || base_tile >= rc_tileset[tileset].tiles.size())
return -1;
return rc_tileset[tileset].tiles[base_tile].frames[anim_frame];
}
void rc_setTileAnimationSpeed(int tileset, int base_tile, double speed)
{
if(tileset < 0 || tileset >= rc_tileset.size())
return;
if(!rc_tileset[tileset].active)
return;
if(base_tile < 0 || base_tile >= rc_tileset[tileset].tiles.size())
return;
rc_tileset[tileset].tiles[base_tile].fps = speed;
rc_tileset[tileset].tiles[base_tile].frame_swap_time = 1000/speed;
}
double rc_getTileAnimationSpeed(int tileset, int base_tile)
{
if(tileset < 0 || tileset >= rc_tileset.size())
return 0;
if(!rc_tileset[tileset].active)
return 0;
if(base_tile < 0 || base_tile >= rc_tileset[tileset].tiles.size())
return 0;
return rc_tileset[tileset].tiles[base_tile].fps;
}
//--------------------------------------TILEMAP-----------------------------------------------
int rc_createTileMap(int tileset, int widthInTiles, int heightInTiles)
{
if(tileset < 0 || tileset >= rc_tileset.size())
return -1;
if(!rc_tileset[tileset].active)
return -1;
rc_tilemap_obj tilemap;
tilemap.active = true;
tilemap.texture = NULL;
tilemap.tileset = tileset;
tilemap.num_tiles_across = widthInTiles;
tilemap.num_tiles_down = heightInTiles;
tilemap.rows.resize(heightInTiles);
for(int i = 0; i < tilemap.rows.size(); i++)
{
tilemap.rows[i].tile.resize(widthInTiles);
}
int tm_id = rc_tilemap.size();
if(rc_deleted_tilemap.size() > 0)
{
tm_id = rc_deleted_tilemap[0];
rc_deleted_tilemap.erase(rc_deleted_tilemap.begin());
rc_tilemap[tm_id] = tilemap;
}
else
rc_tilemap.push_back(tilemap);
return tm_id;
}
void rc_deleteTileMap(int tilemap)
{
if(tilemap < 0 || tilemap >= rc_tilemap.size())
return;
if(!rc_tilemap[tilemap].active)
return;
rc_tilemap[tilemap].rows.clear();
rc_tilemap[tilemap].num_tiles_across = 0;
rc_tilemap[tilemap].num_tiles_down = 0;
rc_tilemap[tilemap].texture = NULL;
rc_tilemap[tilemap].tileset = -1;
rc_tilemap[tilemap].active = false;
rc_deleted_tilemap.push_back(tilemap);
}
bool rc_tileMapExists(int tilemap)
{
if(tilemap < 0 || tilemap >= rc_tilemap.size())
return false;
return rc_tilemap[tilemap].active;
}
void rc_setTileMapSize(int tilemap, int widthInTiles, int heightInTiles)
{
if(tilemap < 0 || tilemap >= rc_tilemap.size())
return;
if(!rc_tilemap[tilemap].active)
return;
rc_tilemap[tilemap].num_tiles_across = widthInTiles;
rc_tilemap[tilemap].num_tiles_down = heightInTiles;
rc_tilemap[tilemap].rows.resize(heightInTiles);
for(int i = 0; i < rc_tilemap[tilemap].rows.size(); i++)
{
rc_tilemap[tilemap].rows[i].tile.resize(widthInTiles);
}
}
void rc_getTileMapSize(int tilemap, double* widthInTiles, double* heightInTiles)
{
if(tilemap < 0 || tilemap >= rc_tilemap.size())
return;
if(!rc_tilemap[tilemap].active)
return;
*widthInTiles = rc_tilemap[tilemap].num_tiles_across;
*heightInTiles = rc_tilemap[tilemap].num_tiles_down;
}
void rc_setTile(int tilemap, int tile, int x, int y)
{
if(tilemap < 0 || tilemap >= rc_tilemap.size())
return;
if(!rc_tilemap[tilemap].active)
return;
int tileset = rc_tilemap[tilemap].tileset;
//if tilemap exists, then its safe to assume tileset is in range since tilemap can't be created if its not
if(!rc_tileset[tileset].active)
return;
int num_tset_tiles = rc_tileset[tileset].tiles.size();
if(tile < 0 || tile >= num_tset_tiles)
tile = -1;
if( (x < 0 || x >= rc_tilemap[tilemap].num_tiles_across) || (y < 0 || y >= rc_tilemap[tilemap].num_tiles_down) )
return;
rc_tilemap[tilemap].rows[y].tile[x] = tile;
}
int rc_getTile(int tilemap, int x, int y)
{
if(tilemap < 0 || tilemap >= rc_tilemap.size())
return -1;
if(!rc_tilemap[tilemap].active)
return -1;
if( (x < 0 || x >= rc_tilemap[tilemap].num_tiles_across) || (y < 0 || y >= rc_tilemap[tilemap].num_tiles_down) )
return -1;
return rc_tilemap[tilemap].rows[y].tile[x];
}
void rc_fillTile(int tilemap, int tile, int x, int y, int widthInTiles, int heightInTiles)
{
if(tilemap < 0 || tilemap >= rc_tilemap.size())
return;
if(!rc_tilemap[tilemap].active)
return;
int tileset = rc_tilemap[tilemap].tileset;
//if tilemap exists, then its safe to assume tileset is in range since tilemap can't be created if its not
if(!rc_tileset[tileset].active)
return;
int num_tset_tiles = rc_tileset[tileset].tiles.size();
if(tile < 0 || tile >= num_tset_tiles)
tile = -1;
if( (x < 0 || x >= rc_tilemap[tilemap].num_tiles_across) || (y < 0 || y >= rc_tilemap[tilemap].num_tiles_down) )
return;
if( ( (x+widthInTiles) < 0 || (x+widthInTiles) > rc_tilemap[tilemap].num_tiles_across) || ( (y+heightInTiles) < 0 || (y+heightInTiles) > rc_tilemap[tilemap].num_tiles_down) )
return;
for(int iy = 0; iy < heightInTiles; iy++)
for(int ix = 0; ix < widthInTiles; ix++)
rc_tilemap[tilemap].rows[y+iy].tile[x+ix] = tile;
}
void getTileInTileset(int tileset, int tile, int* x, int* y)
{
int img_w = rc_image[ rc_tileset[tileset].img_id ].image->getSize().Width;
int img_h = rc_image[ rc_tileset[tileset].img_id ].image->getSize().Height;
int tile_w = rc_tileset[tileset].tile_width;
int tile_h = rc_tileset[tileset].tile_height;
int widthInTiles = img_w / tile_w;
*x = (tile%widthInTiles) * tile_w;
*y = (tile/widthInTiles) * tile_h;
}
int getNumTilesInTileset(int tileset)
{
int img_w = rc_image[ rc_tileset[tileset].img_id ].image->getSize().Width;
int img_h = rc_image[ rc_tileset[tileset].img_id ].image->getSize().Height;
int tile_w = rc_tileset[tileset].tile_width;
int tile_h = rc_tileset[tileset].tile_height;
int widthInTiles = img_w / tile_w;
int heightInTiles = img_h / tile_h;
return (widthInTiles*heightInTiles);
}
void updateTileset(int tileset)
{
Uint32 current_time_ms = SDL_GetTicks();
for(int i = 0; i < rc_tileset[tileset].tiles.size(); i++)
{
if( (current_time_ms-rc_tileset[tileset].tiles[i].frame_start_time) >= rc_tileset[tileset].tiles[i].frame_swap_time )
{
rc_tileset[tileset].tiles[i].current_frame++;
if(rc_tileset[tileset].tiles[i].current_frame >= rc_tileset[tileset].tiles[i].num_frames)
rc_tileset[tileset].tiles[i].current_frame = 0;
rc_tileset[tileset].tiles[i].frame_start_time = current_time_ms;
}
}
}
void rc_drawTileMap(int tilemap, int x, int y, int w, int h, int offset_x, int offset_y)
{
if(tilemap < 0 || tilemap >= rc_tilemap.size())
return;
if(!rc_tilemap[tilemap].active)
return;
if(rc_active_canvas < 0 || rc_active_canvas >= rc_canvas.size())
return;
if(!rc_canvas[rc_active_canvas].type == RC_CANVAS_TYPE_2D)
return;
if(!rc_canvas[rc_active_canvas].texture)
return;
rc_tilemap[tilemap].texture = VideoDriver->addRenderTargetTexture(irr::core::dimension2d<u32>(w,h), "rt", ECF_A8R8G8B8);
VideoDriver->setRenderTarget(rc_tilemap[tilemap].texture, true, true, irr::video::SColor(0,0,0,0));
int tileset = rc_tilemap[tilemap].tileset;
updateTileset(tileset);
int vp_widthInTiles = w/rc_tileset[tileset].tile_width;
int vp_heightInTiles = h/rc_tileset[tileset].tile_height;
int tset_img_id = rc_tileset[tileset].img_id;
int src_w = rc_tileset[tileset].tile_width;
int src_h = rc_tileset[tileset].tile_height;
int tile_offset_x = offset_x / src_w;
int tile_offset_y = offset_y / src_h;
int screen_offset_x = 0 - (offset_x % src_w);
int screen_offset_y = 0 - (offset_y % src_h);
int num_tiles_in_tset = getNumTilesInTileset(tileset);
for(int iy = 0; iy < vp_heightInTiles+2; iy++)
{
for(int ix = 0; ix < vp_widthInTiles+2; ix++)
{
int current_frame = 0; //TODO: ADD TIMING
int map_x = tile_offset_x + ix;
int map_y = tile_offset_y + iy;
if(map_x < 0 || map_x >= rc_tilemap[tilemap].num_tiles_across || map_y < 0 || map_y >= rc_tilemap[tilemap].num_tiles_down)
continue;
int tile = rc_tilemap[tilemap].rows[map_y].tile[map_x];
if(tile < 0 || tile >= num_tiles_in_tset)
continue;
current_frame = rc_tileset[tileset].tiles[tile].current_frame;
tile = rc_tileset[tileset].tiles[tile].frames[current_frame];
if(tile < 0 || tile >= num_tiles_in_tset)
continue;
int src_x = 0;
int src_y = 0;
getTileInTileset(tileset, tile, &src_x, &src_y);
irr::core::rect<irr::s32> sourceRect( irr::core::vector2d<irr::s32>(src_x, src_y), irr::core::dimension2d<irr::s32>(src_w, src_h));
irr::video::SColor color(rc_image[tset_img_id].alpha,
rc_image[tset_img_id].color_mod.getRed(),
rc_image[tset_img_id].color_mod.getGreen(),
rc_image[tset_img_id].color_mod.getBlue());
int dst_x = screen_offset_x + (ix*src_w);
int dst_y = screen_offset_y + (iy*src_h);
irr::core::rect<irr::s32> dest( irr::core::vector2d<irr::s32>(dst_x, dst_y), irr::core::dimension2d<irr::s32>(src_w, src_h));
VideoDriver->draw2DImage(rc_image[tset_img_id].image, dest, sourceRect, 0, 0, true);
}
}
VideoDriver->setRenderTarget(rc_canvas[rc_active_canvas].texture, false, false);
irr::core::rect<irr::s32> sourceRect( irr::core::vector2d<irr::s32>(0, 0), irr::core::dimension2d<irr::s32>(w, h));
irr::core::rect<irr::s32> dest( irr::core::vector2d<irr::s32>(x, y), irr::core::dimension2d<irr::s32>(w, h));
VideoDriver->draw2DImage(rc_tilemap[tilemap].texture, dest, sourceRect, 0, 0, true);
VideoDriver->removeTexture(rc_tilemap[tilemap].texture);
rc_tilemap[tilemap].texture = NULL;
//draw2DImage(VideoDriver, rc_tilemap[tilemap].texture, src, pos,)
}
#endif // RC_TILELIB_H_INCLUDED