mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2024-11-26 02:03:48 +00:00
bd5b2b3495
class Element is completely gone. (The files are still there but no longer compiled in. Will delete later) Broken still: - support for vertical flip - the editor - culling
240 lines
5.3 KiB
C++
240 lines
5.3 KiB
C++
#include "Tileset.h"
|
|
#include "SimpleIStringStream.h"
|
|
#include "Base.h"
|
|
#include "ttvfs_stdio.h"
|
|
#include "TextureMgr.h"
|
|
#include "Core.h"
|
|
|
|
Tileset::Tileset()
|
|
{
|
|
}
|
|
|
|
Tileset::~Tileset()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
bool Tileset::loadFile(const char *fn, const unsigned char *usedIdx, size_t usedIdxLen)
|
|
{
|
|
elementTemplates.clear();
|
|
|
|
InStream in(fn);
|
|
if(!in)
|
|
return false;
|
|
|
|
bool warn = false;
|
|
std::string line, gfx;
|
|
while (std::getline(in, line))
|
|
{
|
|
gfx.clear();
|
|
int idx=-1, w=0, h=0;
|
|
SimpleIStringStream is(line.c_str(), SimpleIStringStream::REUSE);
|
|
is >> idx >> gfx >> w >> h;
|
|
if(idx >= 0 && !gfx.empty())
|
|
{
|
|
if(idx < 1024)
|
|
{
|
|
ElementTemplate t;
|
|
t.idx = idx;
|
|
t.gfx = gfx;
|
|
t.w = w;
|
|
t.h = h;
|
|
elementTemplates.push_back(t);
|
|
}
|
|
else
|
|
warn = true;
|
|
}
|
|
}
|
|
in.close();
|
|
|
|
if(warn)
|
|
errorLog("Tileset indices of 1024 and above are reserved; ignored during load");
|
|
|
|
std::sort(elementTemplates.begin(), elementTemplates.end());
|
|
|
|
// begin preloading textures
|
|
|
|
std::vector<std::string> usedTex;
|
|
usedTex.reserve(elementTemplates.size()); // optimistically assume all textures in the tileset are used
|
|
|
|
for (size_t i = 0; i < elementTemplates.size(); i++)
|
|
{
|
|
size_t idx = elementTemplates[i].idx;
|
|
if (!usedIdx || (idx < usedIdxLen && usedIdx[idx]))
|
|
usedTex.push_back(elementTemplates[i].gfx);
|
|
}
|
|
std::sort(usedTex.begin(), usedTex.end());
|
|
// drop duplicates
|
|
usedTex.resize(std::distance(usedTex.begin(), std::unique(usedTex.begin(), usedTex.end())));
|
|
|
|
{
|
|
std::ostringstream os;
|
|
os << "Loading " << usedTex.size()
|
|
<< " used textures out of the " << elementTemplates.size() << " tileset entries";
|
|
debugLog(os.str());
|
|
}
|
|
|
|
// preload all used textures
|
|
size_t loaded = 0;
|
|
if(usedTex.size())
|
|
loaded = core->texmgr.loadBatch(NULL, &usedTex[0], usedTex.size());
|
|
|
|
{
|
|
std::ostringstream os;
|
|
os << "Loaded " << loaded << " textures successfully";
|
|
debugLog(os.str());
|
|
}
|
|
|
|
// finalize
|
|
size_t nfailed = 0;
|
|
std::ostringstream failed;
|
|
for (size_t i = 0; i < elementTemplates.size(); i++)
|
|
{
|
|
ElementTemplate& et = elementTemplates[i];
|
|
// only check those that are actualy loaded; otherwise this would load in textures
|
|
// that we didn't bother to batch-load above
|
|
if(!usedIdx || (et.idx < usedIdxLen && usedIdx[et.idx]))
|
|
{
|
|
if(!et.getTexture()) // assigns width/height and caches texture pointer
|
|
{
|
|
++nfailed;
|
|
failed << et.gfx << " ";
|
|
}
|
|
}
|
|
}
|
|
|
|
if(nfailed)
|
|
{
|
|
std::ostringstream os;
|
|
os << "The following " << nfailed << " textures failed to load and would be used by tiles:";
|
|
debugLog(os.str());
|
|
debugLog(failed.str());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Tileset::clear()
|
|
{
|
|
for(size_t i = 0; i < dummies.size(); ++i)
|
|
delete dummies[i];
|
|
dummies.clear();
|
|
elementTemplates.clear();
|
|
}
|
|
|
|
const ElementTemplate *Tileset::getByIdx(size_t idx)
|
|
{
|
|
for (size_t i = 0; i < elementTemplates.size(); i++)
|
|
{
|
|
ElementTemplate& et = elementTemplates[i];
|
|
if (et.idx == idx)
|
|
{
|
|
et.getTexture(); // HACK: make sure the texture is loaded before this gets used
|
|
return &et;
|
|
}
|
|
}
|
|
|
|
// a tile that gets an ET attached must remember its tileset id even if the entry is not present
|
|
// in the tileset. since the tile does not store the idx as an integer, we need to return a dummy element.
|
|
for (size_t i = 0; i < dummies.size(); i++)
|
|
{
|
|
ElementTemplate *et = dummies[i];
|
|
if (et->idx == idx)
|
|
return et;
|
|
}
|
|
|
|
{
|
|
std::ostringstream os;
|
|
os << "Tileset idx " << idx << " not found, creating dummy";
|
|
debugLog(os.str());
|
|
}
|
|
|
|
ElementTemplate *dummy = new ElementTemplate;
|
|
dummy->idx = idx;
|
|
dummies.push_back(dummy);
|
|
|
|
return dummy;
|
|
}
|
|
|
|
const ElementTemplate* Tileset::getAdjacent(size_t idx, int direction, bool wraparound)
|
|
{
|
|
ElementTemplate *et = _getAdjacent(idx, direction, wraparound);
|
|
if(et)
|
|
et->getTexture(); // load just in case
|
|
return et;
|
|
}
|
|
|
|
Texture* ElementTemplate::getTexture()
|
|
{
|
|
if(loaded)
|
|
return tex.content();
|
|
|
|
loaded = true;
|
|
tex = core->getTexture(gfx); // may end up NULL
|
|
if(tex)
|
|
{
|
|
if(!w)
|
|
w = tex->width;
|
|
if(!h)
|
|
h = tex->height;
|
|
}
|
|
else
|
|
{
|
|
if(!w)
|
|
w = 64;
|
|
if(!h)
|
|
h = 64;
|
|
}
|
|
|
|
return tex.content();
|
|
|
|
}
|
|
|
|
ElementTemplate * Tileset::_getAdjacent(size_t idx, int direction, bool wraparound)
|
|
{
|
|
assert(direction == 1 || direction == -1);
|
|
const size_t maxn = elementTemplates.size();
|
|
size_t closest = 0;
|
|
int mindiff = 0;
|
|
for (size_t i = 0; i < maxn; i++)
|
|
{
|
|
if (elementTemplates[i].idx == idx)
|
|
{
|
|
if(wraparound)
|
|
{
|
|
if(!i && direction < 0)
|
|
return &elementTemplates.back();
|
|
if(i + direction >= maxn)
|
|
return &elementTemplates[0];
|
|
}
|
|
else
|
|
|
|
i += direction; // may underflow
|
|
return i < maxn ? &elementTemplates[i] : NULL;
|
|
}
|
|
int diff = labs((int)elementTemplates[i].idx - (int)idx);
|
|
if(diff < mindiff || !mindiff)
|
|
{
|
|
mindiff = diff;
|
|
closest = i;
|
|
}
|
|
}
|
|
|
|
// not found? pick whatever was closest to the non-existing idx, and go back/forward from there
|
|
|
|
// avoid going "twice" in the given direction
|
|
if(closest < idx && direction < 0)
|
|
direction = 0; // this is already a step back, don't step again
|
|
else if(closest > idx && direction > 0)
|
|
direction = 0; // this is already a step forward, don't step again
|
|
else if(wraparound)
|
|
{
|
|
if(!closest && direction < 0)
|
|
return &elementTemplates.back();
|
|
if(closest + direction >= maxn)
|
|
return &elementTemplates[0];
|
|
}
|
|
|
|
size_t i = closest + direction;
|
|
return i < maxn ? &elementTemplates[i] : NULL;
|
|
}
|