New lightweight minimap format, finish #15

This commit is contained in:
Eduardo Bart
2013-01-27 14:06:47 -02:00
parent cf0ecf418d
commit e81dd31ae3
14 changed files with 261 additions and 124 deletions

View File

@@ -27,40 +27,17 @@
#include <framework/graphics/texture.h>
#include <framework/graphics/painter.h>
#include <framework/graphics/framebuffermanager.h>
#include <framework/core/resourcemanager.h>
#include <framework/core/filestream.h>
#include <boost/concept_check.hpp>
#include <zlib.h>
Minimap g_minimap;
void MinimapBlock::updateImage()
{
if(!m_image)
m_image = ImagePtr(new Image(Size(MMBLOCK_SIZE, MMBLOCK_SIZE)));
else
m_image->resize(Size(MMBLOCK_SIZE, MMBLOCK_SIZE));
for(int x=0;x<MMBLOCK_SIZE;++x)
for(int y=0;y<MMBLOCK_SIZE;++y)
m_image->setPixel(x, y, Color::from8bit(getTile(x, y).color).rgba());
}
void MinimapBlock::updateTexture()
{
if(!m_image)
return;
if(!m_texture) {
m_texture = TexturePtr(new Texture(m_image, true));
} else {
m_texture->uploadPixels(m_image, true);
}
}
void MinimapBlock::clean()
{
m_tiles.fill(MinimapTile());
m_image.reset();
m_texture.reset();
m_shouldDraw = false;
m_mustUpdate = false;
}
@@ -69,28 +46,40 @@ void MinimapBlock::update()
if(!m_mustUpdate)
return;
if(m_shouldDraw) {
updateImage();
updateTexture();
ImagePtr image(new Image(Size(MMBLOCK_SIZE, MMBLOCK_SIZE)));
bool shouldDraw = false;
for(int x=0;x<MMBLOCK_SIZE;++x) {
for(int y=0;y<MMBLOCK_SIZE;++y) {
uint32 col = Color::from8bit(getTile(x, y).color).rgba();
image->setPixel(x, y, col);
if(col != 0)
shouldDraw = true;
}
}
if(shouldDraw) {
if(!m_texture) {
m_texture = TexturePtr(new Texture(image, true));
} else {
m_texture->uploadPixels(image, true);
}
} else
m_texture.reset();
m_mustUpdate = false;
}
void MinimapBlock::updateTile(int x, int y, const MinimapTile& tile)
{
if(tile.color != 0)
m_shouldDraw = true;
if(m_tiles[getTileIndex(x,y)].color != tile.color)
m_mustUpdate = true;
m_tiles[getTileIndex(x,y)] = tile;
}
void Minimap::init()
{
}
void Minimap::terminate()
@@ -141,13 +130,17 @@ void Minimap::draw(const Rect& screenRect, const Position& mapCenter, float scal
if(x < 0 || x >= 65536 - MMBLOCK_SIZE)
continue;
Position blockPos(x, y, mapCenter.z);
if(!hasBlock(blockPos))
continue;
MinimapBlock& block = getBlock(Position(x, y, mapCenter.z));
block.update();
if(block.shouldDraw()) {
const TexturePtr& tex = block.getTexture();
if(tex) {
Rect src(0, 0, MMBLOCK_SIZE, MMBLOCK_SIZE);
Rect dest(Point(xs,ys), src.size() * scale);
const TexturePtr& tex = block.getTexture();
tex->setSmooth(scale < 1.0f);
g_painter->drawTexturedRect(dest, tex, src);
@@ -186,36 +179,151 @@ Position Minimap::getPosition(const Point& point, const Rect& screenRect, const
void Minimap::updateTile(const Position& pos, const TilePtr& tile)
{
MinimapBlock& block = getBlock(pos);
Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
MinimapTile minimapTile;
if(tile) {
minimapTile.color = tile->getMinimapColorByte();
if(tile->isWalkable())
minimapTile.flags |= MinimapTileWalkable;
if(tile->isPathable())
minimapTile.flags |= MinimapTilePathable;
if(tile->changesFloor())
minimapTile.flags |= MinimapTileChangesFloor;
minimapTile.flags |= MinimapTileWasSeen;
if(!tile->isWalkable(true))
minimapTile.flags |= MinimapTileNotWalkable;
if(!tile->isPathable())
minimapTile.flags |= MinimapTileNotPathable;
minimapTile.speed = std::min((int)std::ceil(tile->getGroundSpeed() / 10.0f), 255);
}
block.updateTile(pos.x - offsetPos.x, pos.y - offsetPos.y, minimapTile);
if(minimapTile != MinimapTile()) {
MinimapBlock& block = getBlock(pos);
Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
block.updateTile(pos.x - offsetPos.x, pos.y - offsetPos.y, minimapTile);
}
}
bool Minimap::checkTileProperty(const Position& pos, int flags)
const MinimapTile& Minimap::getTile(const Position& pos)
{
MinimapBlock& block = getBlock(pos);
Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
return block.getTile(pos.x - offsetPos.x, pos.y - offsetPos.y).flags & flags;
static MinimapTile nulltile;
if(pos.z <= Otc::MAX_Z && hasBlock(pos)) {
MinimapBlock& block = getBlock(pos);
Point offsetPos = getBlockOffset(Point(pos.x, pos.y));
return block.getTile(pos.x - offsetPos.x, pos.y - offsetPos.y);
}
return nulltile;
}
void Minimap::loadOtmm(const std::string& fileName)
bool Minimap::loadOtmm(const std::string& fileName)
{
try {
FileStreamPtr fin = g_resources.openFile(fileName);
if(!fin)
stdext::throw_exception("unable to open file");
fin->cache();
uint32 signature = fin->getU32();
if(signature != OTMM_SIGNATURE)
stdext::throw_exception("invalid OTMM file");
uint16 start = fin->getU16();
uint16 version = fin->getU16();
fin->getU32(); // flags
switch(version) {
case 1: {
fin->getString(); // description
break;
}
default:
stdext::throw_exception("OTMM version not supported");
}
fin->seek(start);
uint blockSize = MMBLOCK_SIZE * MMBLOCK_SIZE * sizeof(MinimapTile);
std::vector<uchar> compressBuffer(compressBound(blockSize));
while(true) {
Position pos;
pos.x = fin->getU16();
pos.y = fin->getU16();
pos.z = fin->getU8();
// end of file
if(!pos.isValid())
break;
MinimapBlock& block = getBlock(pos);
ulong len = fin->getU16();
ulong destLen = blockSize;
fin->read(compressBuffer.data(), len);
int ret = uncompress((uchar*)&block.getTiles(), &destLen, compressBuffer.data(), len);
assert(ret == Z_OK);
assert(destLen == blockSize);
block.mustUpdate();
}
fin->close();
return true;
} catch(stdext::exception& e) {
g_logger.error(stdext::format("failed to load OTMM minimap: %s", e.what()));
return false;
}
}
void Minimap::saveOtmm(const std::string& fileName)
{
try {
stdext::timer saveTimer;
FileStreamPtr fin = g_resources.createFile(fileName);
fin->cache();
//TODO: compression flag with zlib
uint32 flags = 0;
// header
fin->addU32(OTMM_SIGNATURE);
fin->addU16(0); // data start, will be overwritten later
fin->addU16(OTMM_VERSION);
fin->addU32(flags);
// version 1 header
fin->addString("OTMM 1.0"); // description
// go back and rewrite where the map data starts
uint32 start = fin->tell();
fin->seek(4);
fin->addU16(start);
fin->seek(start);
uint blockSize = MMBLOCK_SIZE * MMBLOCK_SIZE * sizeof(MinimapTile);
std::vector<uchar> compressBuffer(compressBound(blockSize));
const int COMPRESS_LEVEL = 3;
for(uint8_t z = 0; z <= Otc::MAX_Z; ++z) {
for(auto& it : m_tileBlocks[z]) {
int index = it.first;
MinimapBlock& block = it.second;
Position pos = getIndexPosition(index, z);
fin->addU16(pos.x);
fin->addU16(pos.y);
fin->addU8(pos.z);
ulong len = blockSize;
int ret = compress2(compressBuffer.data(), &len, (uchar*)&block.getTiles(), blockSize, COMPRESS_LEVEL);
assert(ret == Z_OK);
fin->addU16(len);
fin->write(compressBuffer.data(), len);
}
}
// end of file
Position invalidPos;
fin->addU16(invalidPos.x);
fin->addU16(invalidPos.y);
fin->addU8(invalidPos.z);
fin->flush();
fin->close();
} catch(stdext::exception& e) {
g_logger.error(stdext::format("failed to save OTMM minimap: %s", e.what()));
}
}