mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-18 17:40:48 +02:00
Merge branch 'cpp-map-editor' into EraseAction
This commit is contained in:
commit
cb09ea9814
@ -4,13 +4,10 @@
|
|||||||
//
|
//
|
||||||
// Created by nordsoft on 29.08.2022.
|
// Created by nordsoft on 29.08.2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "BitmapHandler.h"
|
|
||||||
|
|
||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
|
#include "BitmapHandler.h"
|
||||||
|
|
||||||
#include "../lib/filesystem/Filesystem.h"
|
#include "../lib/filesystem/Filesystem.h"
|
||||||
#include "BitmapHandler.h"
|
|
||||||
|
|
||||||
#include <QBitmap>
|
#include <QBitmap>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
@ -21,152 +18,152 @@ namespace BitmapHandler
|
|||||||
QImage loadH3PCX(ui8 * data, size_t size);
|
QImage loadH3PCX(ui8 * data, size_t size);
|
||||||
|
|
||||||
QImage loadBitmapFromDir(std::string path, std::string fname, bool setKey=true);
|
QImage loadBitmapFromDir(std::string path, std::string fname, bool setKey=true);
|
||||||
}
|
|
||||||
|
|
||||||
bool isPCX(const ui8 *header)//check whether file can be PCX according to header
|
bool isPCX(const ui8 *header)//check whether file can be PCX according to header
|
||||||
{
|
|
||||||
ui32 fSize = read_le_u32(header + 0);
|
|
||||||
ui32 width = read_le_u32(header + 4);
|
|
||||||
ui32 height = read_le_u32(header + 8);
|
|
||||||
return fSize == width*height || fSize == width*height*3;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Epcxformat
|
|
||||||
{
|
|
||||||
PCX8B,
|
|
||||||
PCX24B
|
|
||||||
};
|
|
||||||
|
|
||||||
QImage BitmapHandler::loadH3PCX(ui8 * pcx, size_t size)
|
|
||||||
{
|
|
||||||
//SDL_Surface * ret;
|
|
||||||
|
|
||||||
Epcxformat format;
|
|
||||||
int it=0;
|
|
||||||
|
|
||||||
ui32 fSize = read_le_u32(pcx + it); it+=4;
|
|
||||||
ui32 width = read_le_u32(pcx + it); it+=4;
|
|
||||||
ui32 height = read_le_u32(pcx + it); it+=4;
|
|
||||||
|
|
||||||
if (fSize==width*height*3)
|
|
||||||
format=PCX24B;
|
|
||||||
else if (fSize==width*height)
|
|
||||||
format=PCX8B;
|
|
||||||
else
|
|
||||||
return QImage();
|
|
||||||
|
|
||||||
QSize qsize(width, height);
|
|
||||||
|
|
||||||
if (format==PCX8B)
|
|
||||||
{
|
{
|
||||||
it = 0xC;
|
ui32 fSize = read_le_u32(header + 0);
|
||||||
//auto bitmap = QBitmap::fromData(qsize, pcx + it);
|
ui32 width = read_le_u32(header + 4);
|
||||||
QImage image(pcx + it, width, height, QImage::Format_Indexed8);
|
ui32 height = read_le_u32(header + 8);
|
||||||
|
return fSize == width*height || fSize == width*height*3;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Epcxformat
|
||||||
|
{
|
||||||
|
PCX8B,
|
||||||
|
PCX24B
|
||||||
|
};
|
||||||
|
|
||||||
|
QImage loadH3PCX(ui8 * pcx, size_t size)
|
||||||
|
{
|
||||||
|
//SDL_Surface * ret;
|
||||||
|
|
||||||
//palette - last 256*3 bytes
|
Epcxformat format;
|
||||||
QVector<QRgb> colorTable;
|
int it=0;
|
||||||
it = (int)size-256*3;
|
|
||||||
for (int i=0;i<256;i++)
|
ui32 fSize = read_le_u32(pcx + it); it+=4;
|
||||||
|
ui32 width = read_le_u32(pcx + it); it+=4;
|
||||||
|
ui32 height = read_le_u32(pcx + it); it+=4;
|
||||||
|
|
||||||
|
if (fSize==width*height*3)
|
||||||
|
format=PCX24B;
|
||||||
|
else if (fSize==width*height)
|
||||||
|
format=PCX8B;
|
||||||
|
else
|
||||||
|
return QImage();
|
||||||
|
|
||||||
|
QSize qsize(width, height);
|
||||||
|
|
||||||
|
if (format==PCX8B)
|
||||||
{
|
{
|
||||||
char bytes[3];
|
it = 0xC;
|
||||||
bytes[0] = pcx[it++];
|
//auto bitmap = QBitmap::fromData(qsize, pcx + it);
|
||||||
bytes[1] = pcx[it++];
|
QImage image(pcx + it, width, height, QImage::Format_Indexed8);
|
||||||
bytes[2] = pcx[it++];
|
|
||||||
colorTable.append(qRgb(bytes[0], bytes[1], bytes[2]));
|
//palette - last 256*3 bytes
|
||||||
}
|
QVector<QRgb> colorTable;
|
||||||
image.setColorTable(colorTable);
|
it = (int)size-256*3;
|
||||||
return image;
|
for (int i=0;i<256;i++)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QImage image(pcx + it, width, height, QImage::Format_RGB32);
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage BitmapHandler::loadBitmapFromDir(std::string path, std::string fname, bool setKey)
|
|
||||||
{
|
|
||||||
if(!fname.size())
|
|
||||||
{
|
|
||||||
logGlobal->warn("Call to loadBitmap with void fname!");
|
|
||||||
return QImage();
|
|
||||||
}
|
|
||||||
if (!CResourceHandler::get()->existsResource(ResourceID(path + fname, EResType::IMAGE)))
|
|
||||||
{
|
|
||||||
return QImage();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto fullpath = CResourceHandler::get()->getResourceName(ResourceID(path + fname, EResType::IMAGE));
|
|
||||||
auto readFile = CResourceHandler::get()->load(ResourceID(path + fname, EResType::IMAGE))->readAll();
|
|
||||||
|
|
||||||
if (isPCX(readFile.first.get()))
|
|
||||||
{//H3-style PCX
|
|
||||||
auto image = loadH3PCX(readFile.first.get(), readFile.second);
|
|
||||||
if(!image.isNull())
|
|
||||||
{
|
|
||||||
if(image.bitPlaneCount() == 1 && setKey)
|
|
||||||
{
|
{
|
||||||
QVector<QRgb> colorTable = image.colorTable();
|
char bytes[3];
|
||||||
colorTable[0] = qRgba(255, 255, 255, 0);
|
bytes[0] = pcx[it++];
|
||||||
image.setColorTable(colorTable);
|
bytes[1] = pcx[it++];
|
||||||
|
bytes[2] = pcx[it++];
|
||||||
|
colorTable.append(qRgb(bytes[0], bytes[1], bytes[2]));
|
||||||
}
|
}
|
||||||
|
image.setColorTable(colorTable);
|
||||||
|
return image;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logGlobal->error("Failed to open %s as H3 PCX!", fname);
|
QImage image(pcx + it, width, height, QImage::Format_RGB32);
|
||||||
}
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ //loading via SDL_Image
|
|
||||||
QImage image(QString::fromStdString(fullpath->make_preferred().string()));
|
|
||||||
if(!image.isNull())
|
|
||||||
{
|
|
||||||
if(image.bitPlaneCount() == 1)
|
|
||||||
{
|
|
||||||
//set correct value for alpha\unused channel
|
|
||||||
QVector<QRgb> colorTable = image.colorTable();
|
|
||||||
for(auto & c : colorTable)
|
|
||||||
c = qRgb(qRed(c), qGreen(c), qBlue(c));
|
|
||||||
image.setColorTable(colorTable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logGlobal->error("Failed to open %s via QImage", fname);
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QImage();
|
|
||||||
// When modifying anything here please check two use cases:
|
|
||||||
// 1) Vampire mansion in Necropolis (not 1st color is transparent)
|
|
||||||
// 2) Battle background when fighting on grass/dirt, topmost sky part (NO transparent color)
|
|
||||||
// 3) New objects that may use 24-bit images for icons (e.g. witchking arts)
|
|
||||||
/*if (ret->format->palette)
|
|
||||||
{
|
|
||||||
CSDL_Ext::setDefaultColorKeyPresize(ret);
|
|
||||||
}
|
|
||||||
else if (ret->format->Amask)
|
|
||||||
{
|
|
||||||
SDL_SetSurfaceBlendMode(ret, SDL_BLENDMODE_BLEND);
|
|
||||||
}
|
|
||||||
else // always set
|
|
||||||
{
|
|
||||||
CSDL_Ext::setDefaultColorKey(ret);
|
|
||||||
}
|
|
||||||
return ret;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
QImage BitmapHandler::loadBitmap(std::string fname, bool setKey)
|
QImage loadBitmapFromDir(std::string path, std::string fname, bool setKey)
|
||||||
{
|
|
||||||
QImage image = loadBitmapFromDir("DATA/", fname, setKey);
|
|
||||||
if(image.isNull())
|
|
||||||
{
|
{
|
||||||
image = loadBitmapFromDir("SPRITES/", fname, setKey);
|
if(!fname.size())
|
||||||
|
{
|
||||||
|
logGlobal->warn("Call to loadBitmap with void fname!");
|
||||||
|
return QImage();
|
||||||
|
}
|
||||||
|
if (!CResourceHandler::get()->existsResource(ResourceID(path + fname, EResType::IMAGE)))
|
||||||
|
{
|
||||||
|
return QImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fullpath = CResourceHandler::get()->getResourceName(ResourceID(path + fname, EResType::IMAGE));
|
||||||
|
auto readFile = CResourceHandler::get()->load(ResourceID(path + fname, EResType::IMAGE))->readAll();
|
||||||
|
|
||||||
|
if (isPCX(readFile.first.get()))
|
||||||
|
{//H3-style PCX
|
||||||
|
auto image = BitmapHandler::loadH3PCX(readFile.first.get(), readFile.second);
|
||||||
|
if(!image.isNull())
|
||||||
|
{
|
||||||
|
if(image.bitPlaneCount() == 1 && setKey)
|
||||||
|
{
|
||||||
|
QVector<QRgb> colorTable = image.colorTable();
|
||||||
|
colorTable[0] = qRgba(255, 255, 255, 0);
|
||||||
|
image.setColorTable(colorTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logGlobal->error("Failed to open %s as H3 PCX!", fname);
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //loading via SDL_Image
|
||||||
|
QImage image(QString::fromStdString(fullpath->make_preferred().string()));
|
||||||
|
if(!image.isNull())
|
||||||
|
{
|
||||||
|
if(image.bitPlaneCount() == 1)
|
||||||
|
{
|
||||||
|
//set correct value for alpha\unused channel
|
||||||
|
QVector<QRgb> colorTable = image.colorTable();
|
||||||
|
for(auto & c : colorTable)
|
||||||
|
c = qRgb(qRed(c), qGreen(c), qBlue(c));
|
||||||
|
image.setColorTable(colorTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logGlobal->error("Failed to open %s via QImage", fname);
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QImage();
|
||||||
|
// When modifying anything here please check two use cases:
|
||||||
|
// 1) Vampire mansion in Necropolis (not 1st color is transparent)
|
||||||
|
// 2) Battle background when fighting on grass/dirt, topmost sky part (NO transparent color)
|
||||||
|
// 3) New objects that may use 24-bit images for icons (e.g. witchking arts)
|
||||||
|
/*if (ret->format->palette)
|
||||||
|
{
|
||||||
|
CSDL_Ext::setDefaultColorKeyPresize(ret);
|
||||||
|
}
|
||||||
|
else if (ret->format->Amask)
|
||||||
|
{
|
||||||
|
SDL_SetSurfaceBlendMode(ret, SDL_BLENDMODE_BLEND);
|
||||||
|
}
|
||||||
|
else // always set
|
||||||
|
{
|
||||||
|
CSDL_Ext::setDefaultColorKey(ret);
|
||||||
|
}
|
||||||
|
return ret;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage loadBitmap(std::string fname, bool setKey)
|
||||||
|
{
|
||||||
|
QImage image = loadBitmapFromDir("DATA/", fname, setKey);
|
||||||
if(image.isNull())
|
if(image.isNull())
|
||||||
{
|
{
|
||||||
logGlobal->error("Error: Failed to find file %s", fname);
|
image = loadBitmapFromDir("SPRITES/", fname, setKey);
|
||||||
|
if(image.isNull())
|
||||||
|
{
|
||||||
|
logGlobal->error("Error: Failed to find file %s", fname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return image;
|
||||||
}
|
}
|
||||||
return image;
|
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#define read_le_u16(p) (* reinterpret_cast<const ui16 *>(p))
|
#define read_le_u16(p) (* reinterpret_cast<const ui16 *>(p))
|
||||||
#define read_le_u32(p) (* reinterpret_cast<const ui32 *>(p))
|
#define read_le_u32(p) (* reinterpret_cast<const ui32 *>(p))
|
||||||
|
|
||||||
|
#include <QImage>
|
||||||
|
|
||||||
namespace BitmapHandler
|
namespace BitmapHandler
|
||||||
{
|
{
|
||||||
//Load file from /DATA or /SPRITES
|
//Load file from /DATA or /SPRITES
|
||||||
|
@ -4,9 +4,10 @@
|
|||||||
#include "../lib/spells/CSpellHandler.h"
|
#include "../lib/spells/CSpellHandler.h"
|
||||||
#include "../lib/CRandomGenerator.h"
|
#include "../lib/CRandomGenerator.h"
|
||||||
#include "../lib/mapObjects/CObjectClassesHandler.h"
|
#include "../lib/mapObjects/CObjectClassesHandler.h"
|
||||||
|
#include "../lib/mapping/CMap.h"
|
||||||
|
|
||||||
//===============IMPLEMENT OBJECT INITIALIZATION FUNCTIONS================
|
//===============IMPLEMENT OBJECT INITIALIZATION FUNCTIONS================
|
||||||
Initializer::Initializer(CGObjectInstance * o)
|
Initializer::Initializer(CMap * m, CGObjectInstance * o) : map(m)
|
||||||
{
|
{
|
||||||
///IMPORTANT! initialize order should be from base objects to derived objects
|
///IMPORTANT! initialize order should be from base objects to derived objects
|
||||||
INIT_OBJ_TYPE(CGResource);
|
INIT_OBJ_TYPE(CGResource);
|
||||||
@ -16,14 +17,14 @@ Initializer::Initializer(CGObjectInstance * o)
|
|||||||
INIT_OBJ_TYPE(CGTownInstance);
|
INIT_OBJ_TYPE(CGTownInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize(CArmedInstance * o)
|
void Initializer::initialize(CArmedInstance * o)
|
||||||
{
|
{
|
||||||
if(!o) return;
|
if(!o) return;
|
||||||
|
|
||||||
o->tempOwner = PlayerColor::NEUTRAL;
|
o->tempOwner = PlayerColor::NEUTRAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize(CGTownInstance * o)
|
void Initializer::initialize(CGTownInstance * o)
|
||||||
{
|
{
|
||||||
if(!o) return;
|
if(!o) return;
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ void initialize(CGTownInstance * o)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize(CGArtifact * o)
|
void Initializer::initialize(CGArtifact * o)
|
||||||
{
|
{
|
||||||
if(!o) return;
|
if(!o) return;
|
||||||
|
|
||||||
@ -46,7 +47,7 @@ void initialize(CGArtifact * o)
|
|||||||
std::vector<SpellID> out;
|
std::vector<SpellID> out;
|
||||||
for(auto spell : VLC->spellh->objects) //spellh size appears to be greater (?)
|
for(auto spell : VLC->spellh->objects) //spellh size appears to be greater (?)
|
||||||
{
|
{
|
||||||
if(/*map.isAllowedSpell(spell->id) && spell->level == i + 1*/ true)
|
//if(map->isAllowedSpell(spell->id))
|
||||||
{
|
{
|
||||||
out.push_back(spell->id);
|
out.push_back(spell->id);
|
||||||
}
|
}
|
||||||
@ -56,7 +57,7 @@ void initialize(CGArtifact * o)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize(CGMine * o)
|
void Initializer::initialize(CGMine * o)
|
||||||
{
|
{
|
||||||
if(!o) return;
|
if(!o) return;
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ void initialize(CGMine * o)
|
|||||||
o->producedQuantity = o->defaultResProduction();
|
o->producedQuantity = o->defaultResProduction();
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize(CGResource * o)
|
void Initializer::initialize(CGResource * o)
|
||||||
{
|
{
|
||||||
if(!o) return;
|
if(!o) return;
|
||||||
|
|
||||||
|
@ -18,12 +18,23 @@ void setProperty(x*, const QString &, const QVariant &);
|
|||||||
#define UPDATE_OBJ_PROPERTIES(x) updateProperties(dynamic_cast<x*>(obj))
|
#define UPDATE_OBJ_PROPERTIES(x) updateProperties(dynamic_cast<x*>(obj))
|
||||||
#define SET_PROPERTIES(x) setProperty(dynamic_cast<x*>(obj), key, value)
|
#define SET_PROPERTIES(x) setProperty(dynamic_cast<x*>(obj), key, value)
|
||||||
|
|
||||||
//===============DECLARE MAP OBJECTS======================================
|
|
||||||
DECLARE_OBJ_TYPE(CArmedInstance);
|
class Initializer
|
||||||
DECLARE_OBJ_TYPE(CGTownInstance);
|
{
|
||||||
DECLARE_OBJ_TYPE(CGArtifact);
|
public:
|
||||||
DECLARE_OBJ_TYPE(CGMine);
|
//===============DECLARE MAP OBJECTS======================================
|
||||||
DECLARE_OBJ_TYPE(CGResource);
|
DECLARE_OBJ_TYPE(CArmedInstance);
|
||||||
|
DECLARE_OBJ_TYPE(CGTownInstance);
|
||||||
|
DECLARE_OBJ_TYPE(CGArtifact);
|
||||||
|
DECLARE_OBJ_TYPE(CGMine);
|
||||||
|
DECLARE_OBJ_TYPE(CGResource);
|
||||||
|
|
||||||
|
|
||||||
|
Initializer(CMap *, CGObjectInstance *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CMap * map;
|
||||||
|
};
|
||||||
|
|
||||||
class Inspector
|
class Inspector
|
||||||
{
|
{
|
||||||
@ -90,11 +101,7 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Initializer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Initializer(CGObjectInstance *);
|
|
||||||
};
|
|
||||||
|
|
||||||
class PlayerColorDelegate : public QStyledItemDelegate
|
class PlayerColorDelegate : public QStyledItemDelegate
|
||||||
{
|
{
|
||||||
|
@ -103,7 +103,9 @@ void MapController::sceneForceUpdate(int level)
|
|||||||
|
|
||||||
void MapController::resetMapHandler()
|
void MapController::resetMapHandler()
|
||||||
{
|
{
|
||||||
_mapHandler.reset(new MapHandler(_map.get()));
|
if(!_mapHandler)
|
||||||
|
_mapHandler.reset(new MapHandler());
|
||||||
|
_mapHandler->reset(map());
|
||||||
_scenes[0]->initialize(*this);
|
_scenes[0]->initialize(*this);
|
||||||
_scenes[1]->initialize(*this);
|
_scenes[1]->initialize(*this);
|
||||||
_miniscenes[0]->initialize(*this);
|
_miniscenes[0]->initialize(*this);
|
||||||
@ -141,7 +143,9 @@ void MapController::commitObjectErase(int level)
|
|||||||
}
|
}
|
||||||
else if (selectedObjects.size() == 1)
|
else if (selectedObjects.size() == 1)
|
||||||
{
|
{
|
||||||
_map->getEditManager()->removeObject(*selectedObjects.begin());
|
_map->getEditManager()->removeObject(selectedObjects.front());
|
||||||
|
//invalidate tiles under object
|
||||||
|
_mapHandler->invalidate(_mapHandler->geTilesUnderObject(selectedObjects.front()));
|
||||||
}
|
}
|
||||||
else //nothing to erase - shouldn't be here
|
else //nothing to erase - shouldn't be here
|
||||||
{
|
{
|
||||||
@ -149,8 +153,8 @@ void MapController::commitObjectErase(int level)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_scenes[level]->selectionObjectsView.clear();
|
_scenes[level]->selectionObjectsView.clear();
|
||||||
resetMapHandler();
|
_scenes[level]->objectsView.draw();
|
||||||
_scenes[level]->updateViews();
|
_scenes[level]->selectionObjectsView.draw();
|
||||||
|
|
||||||
_miniscenes[level]->updateViews();
|
_miniscenes[level]->updateViews();
|
||||||
main->mapChanged();
|
main->mapChanged();
|
||||||
@ -201,8 +205,14 @@ void MapController::commitObstacleFill(int level)
|
|||||||
sel.second.placeObstacles(_map.get(), CRandomGenerator::getDefault());
|
sel.second.placeObstacles(_map.get(), CRandomGenerator::getDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
resetMapHandler();
|
for(auto & t : selection)
|
||||||
_scenes[level]->updateViews();
|
{
|
||||||
|
_mapHandler->invalidate(t.x, t.y, t.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
_scenes[level]->selectionTerrainView.clear();
|
||||||
|
_scenes[level]->selectionTerrainView.draw();
|
||||||
|
_scenes[level]->objectsView.draw();
|
||||||
|
|
||||||
_miniscenes[level]->updateViews();
|
_miniscenes[level]->updateViews();
|
||||||
main->mapChanged();
|
main->mapChanged();
|
||||||
@ -210,7 +220,8 @@ void MapController::commitObstacleFill(int level)
|
|||||||
|
|
||||||
void MapController::commitObjectChange(int level)
|
void MapController::commitObjectChange(int level)
|
||||||
{
|
{
|
||||||
resetMapHandler();
|
//for(auto * o : _scenes[level]->selectionObjectsView.getSelection())
|
||||||
|
//_mapHandler->invalidate(o);
|
||||||
_scenes[level]->objectsView.draw();
|
_scenes[level]->objectsView.draw();
|
||||||
_scenes[level]->selectionObjectsView.draw();
|
_scenes[level]->selectionObjectsView.draw();
|
||||||
|
|
||||||
@ -244,16 +255,18 @@ void MapController::commitObjectShiftOrCreate(int level)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
auto prevPositions = _mapHandler->geTilesUnderObject(obj);
|
||||||
_map->getEditManager()->moveObject(obj, pos);
|
_map->getEditManager()->moveObject(obj, pos);
|
||||||
|
_mapHandler->invalidate(prevPositions);
|
||||||
|
_mapHandler->invalidate(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_scenes[level]->selectionObjectsView.newObject = nullptr;
|
_scenes[level]->selectionObjectsView.newObject = nullptr;
|
||||||
_scenes[level]->selectionObjectsView.shift = QPoint(0, 0);
|
_scenes[level]->selectionObjectsView.shift = QPoint(0, 0);
|
||||||
_scenes[level]->selectionObjectsView.selectionMode = 0;
|
_scenes[level]->selectionObjectsView.selectionMode = 0;
|
||||||
|
_scenes[level]->objectsView.draw();
|
||||||
resetMapHandler();
|
_scenes[level]->selectionObjectsView.draw();
|
||||||
_scenes[level]->updateViews();
|
|
||||||
|
|
||||||
_miniscenes[level]->updateViews();
|
_miniscenes[level]->updateViews();
|
||||||
main->mapChanged();
|
main->mapChanged();
|
||||||
@ -264,9 +277,10 @@ void MapController::commitObjectCreate(int level)
|
|||||||
auto * newObj = _scenes[level]->selectionObjectsView.newObject;
|
auto * newObj = _scenes[level]->selectionObjectsView.newObject;
|
||||||
if(!newObj)
|
if(!newObj)
|
||||||
return;
|
return;
|
||||||
Initializer init(newObj);
|
Initializer init(map(), newObj);
|
||||||
|
|
||||||
_map->getEditManager()->insertObject(newObj);
|
_map->getEditManager()->insertObject(newObj);
|
||||||
|
_mapHandler->invalidate(newObj);
|
||||||
main->mapChanged();
|
main->mapChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,26 +13,37 @@
|
|||||||
|
|
||||||
const int tileSize = 32;
|
const int tileSize = 32;
|
||||||
|
|
||||||
static bool objectBlitOrderSorter(const TerrainTileObject & a, const TerrainTileObject & b)
|
static bool objectBlitOrderSorter(const TileObject & a, const TileObject & b)
|
||||||
{
|
{
|
||||||
return MapHandler::compareObjectBlitOrder(a.obj, b.obj);
|
return MapHandler::compareObjectBlitOrder(a.obj, b.obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
MapHandler::MapHandler(const CMap * Map):
|
int MapHandler::index(int x, int y, int z) const
|
||||||
map(Map)
|
|
||||||
{
|
{
|
||||||
init();
|
return z * (sizes.x * sizes.y) + y * sizes.x + x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapHandler::init()
|
int MapHandler::index(const int3 & p) const
|
||||||
{
|
{
|
||||||
|
return index(p.x, p.y, p.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
MapHandler::MapHandler()
|
||||||
|
{
|
||||||
|
initTerrainGraphics();
|
||||||
|
logGlobal->info("\tPreparing terrain, roads, rivers, borders");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapHandler::reset(const CMap * Map)
|
||||||
|
{
|
||||||
|
ttiles.clear();
|
||||||
|
map = Map;
|
||||||
|
|
||||||
//sizes of terrain
|
//sizes of terrain
|
||||||
sizes.x = map->width;
|
sizes.x = map->width;
|
||||||
sizes.y = map->height;
|
sizes.y = map->height;
|
||||||
sizes.z = map->twoLevel ? 2 : 1;
|
sizes.z = map->twoLevel ? 2 : 1;
|
||||||
|
|
||||||
initTerrainGraphics();
|
|
||||||
logGlobal->info("\tPreparing terrain, roads, rivers, borders");
|
|
||||||
initObjectRects();
|
initObjectRects();
|
||||||
logGlobal->info("\tMaking object rects");
|
logGlobal->info("\tMaking object rects");
|
||||||
}
|
}
|
||||||
@ -78,22 +89,17 @@ void MapHandler::initTerrainGraphics()
|
|||||||
loadFlipped(terrainAnimations, terrainImages, terrainFiles);
|
loadFlipped(terrainAnimations, terrainImages, terrainFiles);
|
||||||
loadFlipped(roadAnimations, roadImages, ROAD_FILES);
|
loadFlipped(roadAnimations, roadImages, ROAD_FILES);
|
||||||
loadFlipped(riverAnimations, riverImages, RIVER_FILES);
|
loadFlipped(riverAnimations, riverImages, RIVER_FILES);
|
||||||
|
|
||||||
ttiles.resize(sizes.x * sizes.y * sizes.z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapHandler::drawTerrainTile(QPainter & painter, int x, int y, int z)
|
void MapHandler::drawTerrainTile(QPainter & painter, int x, int y, int z)
|
||||||
{
|
{
|
||||||
auto & tinfo = map->getTile(int3(x, y, z));
|
auto & tinfo = map->getTile(int3(x, y, z));
|
||||||
//Rect destRect(realTileRect);
|
|
||||||
|
|
||||||
ui8 rotation = tinfo.extTileFlags % 4;
|
ui8 rotation = tinfo.extTileFlags % 4;
|
||||||
|
|
||||||
if(terrainImages.at(tinfo.terType).size() <= tinfo.terView)
|
if(terrainImages.at(tinfo.terType).size() <= tinfo.terView)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3);
|
bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3);
|
||||||
|
|
||||||
painter.drawImage(x * tileSize, y * tileSize, terrainImages.at(tinfo.terType)[tinfo.terView]->mirrored(hflip, vflip));
|
painter.drawImage(x * tileSize, y * tileSize, terrainImages.at(tinfo.terType)[tinfo.terView]->mirrored(hflip, vflip));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,24 +108,11 @@ void MapHandler::drawRoad(QPainter & painter, int x, int y, int z)
|
|||||||
auto & tinfo = map->getTile(int3(x, y, z));
|
auto & tinfo = map->getTile(int3(x, y, z));
|
||||||
auto * tinfoUpper = map->isInTheMap(int3(x, y - 1, z)) ? &map->getTile(int3(x, y - 1, z)) : nullptr;
|
auto * tinfoUpper = map->isInTheMap(int3(x, y - 1, z)) ? &map->getTile(int3(x, y - 1, z)) : nullptr;
|
||||||
|
|
||||||
/*if(tinfoUpper && tinfoUpper->roadType != ROAD_NAMES[0])
|
|
||||||
{
|
|
||||||
ui8 rotation = (tinfoUpper->extTileFlags >> 4) % 4;
|
|
||||||
|
|
||||||
bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3);
|
|
||||||
|
|
||||||
if(roadImages.at(tinfoUpper->roadType).size() > tinfoUpper->roadDir)
|
|
||||||
{
|
|
||||||
painter.drawImage(x * tileSize, y * tileSize, roadImages.at(tinfoUpper->roadType)[tinfoUpper->roadDir]->mirrored(hflip, vflip));
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if(tinfo.roadType != ROAD_NAMES[0]) //print road from this tile
|
if(tinfo.roadType != ROAD_NAMES[0]) //print road from this tile
|
||||||
{
|
{
|
||||||
ui8 rotation = (tinfo.extTileFlags >> 4) % 4;
|
ui8 rotation = (tinfo.extTileFlags >> 4) % 4;
|
||||||
|
|
||||||
bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3);
|
bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3);
|
||||||
|
|
||||||
if(roadImages.at(tinfo.roadType).size() > tinfo.roadDir)
|
if(roadImages.at(tinfo.roadType).size() > tinfo.roadDir)
|
||||||
{
|
{
|
||||||
painter.drawImage(x * tileSize, y * tileSize, roadImages.at(tinfo.roadType)[tinfo.roadDir]->mirrored(hflip, vflip));
|
painter.drawImage(x * tileSize, y * tileSize, roadImages.at(tinfo.roadType)[tinfo.roadDir]->mirrored(hflip, vflip));
|
||||||
@ -138,7 +131,6 @@ void MapHandler::drawRiver(QPainter & painter, int x, int y, int z)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ui8 rotation = (tinfo.extTileFlags >> 2) % 4;
|
ui8 rotation = (tinfo.extTileFlags >> 2) % 4;
|
||||||
|
|
||||||
bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3);
|
bool hflip = (rotation == 1 || rotation == 3), vflip = (rotation == 2 || rotation == 3);
|
||||||
|
|
||||||
painter.drawImage(x * tileSize, y * tileSize, riverImages.at(tinfo.riverType)[tinfo.riverDir]->mirrored(hflip, vflip));
|
painter.drawImage(x * tileSize, y * tileSize, riverImages.at(tinfo.riverType)[tinfo.riverDir]->mirrored(hflip, vflip));
|
||||||
@ -162,6 +154,8 @@ void setPlayerColor(QImage * sur, PlayerColor player)
|
|||||||
|
|
||||||
void MapHandler::initObjectRects()
|
void MapHandler::initObjectRects()
|
||||||
{
|
{
|
||||||
|
ttiles.resize(sizes.x * sizes.y * sizes.z);
|
||||||
|
|
||||||
//initializing objects / rects
|
//initializing objects / rects
|
||||||
for(const CGObjectInstance * elem : map->objects)
|
for(const CGObjectInstance * elem : map->objects)
|
||||||
{
|
{
|
||||||
@ -184,16 +178,17 @@ void MapHandler::initObjectRects()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto image = animation->getImage(0,0);
|
auto image = animation->getImage(0,0);
|
||||||
bool real = true;
|
|
||||||
for(int fx=0; fx < obj->getWidth(); ++fx)
|
for(int fx=0; fx < obj->getWidth(); ++fx)
|
||||||
{
|
{
|
||||||
for(int fy=0; fy < obj->getHeight(); ++fy)
|
for(int fy=0; fy < obj->getHeight(); ++fy)
|
||||||
{
|
{
|
||||||
int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z);
|
int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z);
|
||||||
QRect cr(image->width() - fx * 32 - 32, image->height() - fy * 32 - 32, image->width(), image->height());
|
QRect cr(image->width() - fx * tileSize - tileSize,
|
||||||
TerrainTileObject toAdd(obj, cr, real/*obj->visitableAt(currTile.x, currTile.y)*/);
|
image->height() - fy * tileSize - tileSize,
|
||||||
real = false;
|
image->width(),
|
||||||
|
image->height());
|
||||||
|
|
||||||
|
TileObject toAdd(obj, cr);
|
||||||
|
|
||||||
if( map->isInTheMap(currTile) && // within map
|
if( map->isInTheMap(currTile) && // within map
|
||||||
cr.x() + cr.width() > 0 && // image has data on this tile
|
cr.x() + cr.width() > 0 && // image has data on this tile
|
||||||
@ -201,7 +196,7 @@ void MapHandler::initObjectRects()
|
|||||||
obj->coveringAt(currTile.x, currTile.y) // object is visible here
|
obj->coveringAt(currTile.x, currTile.y) // object is visible here
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ttiles[currTile.z * (sizes.x * sizes.y) + currTile.y * sizes.x + currTile.x].objects.push_back(toAdd);
|
ttiles[index(currTile)].push_back(toAdd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,7 +204,7 @@ void MapHandler::initObjectRects()
|
|||||||
|
|
||||||
for(auto & tt : ttiles)
|
for(auto & tt : ttiles)
|
||||||
{
|
{
|
||||||
stable_sort(tt.objects.begin(), tt.objects.end(), objectBlitOrderSorter);
|
stable_sort(tt.begin(), tt.end(), objectBlitOrderSorter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,125 +234,24 @@ bool MapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObje
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TerrainTileObject::TerrainTileObject(CGObjectInstance * obj_, QRect rect_, bool real_)
|
TileObject::TileObject(CGObjectInstance * obj_, QRect rect_)
|
||||||
: obj(obj_),
|
: obj(obj_),
|
||||||
rect(rect_),
|
rect(rect_)
|
||||||
real(real_)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
TerrainTileObject::~TerrainTileObject()
|
TileObject::~TileObject()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ui8 MapHandler::getHeroFrameGroup(ui8 dir, bool isMoving) const
|
|
||||||
{
|
|
||||||
if(isMoving)
|
|
||||||
{
|
|
||||||
static const ui8 frame [] = {0xff, 10, 5, 6, 7, 8, 9, 12, 11};
|
|
||||||
return frame[dir];
|
|
||||||
}
|
|
||||||
else //if(isMoving)
|
|
||||||
{
|
|
||||||
static const ui8 frame [] = {0xff, 13, 0, 1, 2, 3, 4, 15, 14};
|
|
||||||
return frame[dir];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ui8 MapHandler::getPhaseShift(const CGObjectInstance *object) const
|
|
||||||
{
|
|
||||||
auto i = animationPhase.find(object);
|
|
||||||
if(i == animationPhase.end())
|
|
||||||
{
|
|
||||||
ui8 ret = CRandomGenerator::getDefault().nextInt(254);
|
|
||||||
animationPhase[object] = ret;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return i->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
MapHandler::AnimBitmapHolder MapHandler::findHeroBitmap(const CGHeroInstance * hero, int anim) const
|
|
||||||
{
|
|
||||||
if(hero && hero->moveDir && hero->type) //it's hero or boat
|
|
||||||
{
|
|
||||||
if(hero->tempOwner >= PlayerColor::PLAYER_LIMIT) //Neutral hero?
|
|
||||||
{
|
|
||||||
logGlobal->error("A neutral hero (%s) at %s. Should not happen!", hero->name, hero->pos.toString());
|
|
||||||
return MapHandler::AnimBitmapHolder();
|
|
||||||
}
|
|
||||||
|
|
||||||
//pick graphics of hero (or boat if hero is sailing)
|
|
||||||
std::shared_ptr<Animation> animation;
|
|
||||||
if (hero->boat)
|
|
||||||
animation = graphics->boatAnimations[hero->boat->subID];
|
|
||||||
else
|
|
||||||
animation = graphics->heroAnimations[hero->appearance.animationFile];
|
|
||||||
|
|
||||||
bool moving = !hero->isStanding;
|
|
||||||
int group = getHeroFrameGroup(hero->moveDir, moving);
|
|
||||||
|
|
||||||
if(animation->size(group) > 0)
|
|
||||||
{
|
|
||||||
int frame = anim % animation->size(group);
|
|
||||||
auto heroImage = animation->getImage(frame, group);
|
|
||||||
|
|
||||||
//get flag overlay only if we have main image
|
|
||||||
auto flagImage = findFlagBitmap(hero, anim, &hero->tempOwner, group);
|
|
||||||
|
|
||||||
return MapHandler::AnimBitmapHolder(heroImage, flagImage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return MapHandler::AnimBitmapHolder();
|
|
||||||
}
|
|
||||||
|
|
||||||
MapHandler::AnimBitmapHolder MapHandler::findBoatBitmap(const CGBoat * boat, int anim) const
|
|
||||||
{
|
|
||||||
auto animation = graphics->boatAnimations.at(boat->subID);
|
|
||||||
int group = getHeroFrameGroup(boat->direction, false);
|
|
||||||
if(animation->size(group) > 0)
|
|
||||||
return MapHandler::AnimBitmapHolder(animation->getImage(anim % animation->size(group), group));
|
|
||||||
else
|
|
||||||
return MapHandler::AnimBitmapHolder();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<QImage> MapHandler::findFlagBitmap(const CGHeroInstance * hero, int anim, const PlayerColor * color, int group) const
|
std::shared_ptr<QImage> MapHandler::findFlagBitmap(const CGHeroInstance * hero, int anim, const PlayerColor * color, int group) const
|
||||||
{
|
{
|
||||||
if(!hero)
|
if(!hero || hero->boat)
|
||||||
return std::shared_ptr<QImage>();
|
return std::shared_ptr<QImage>();
|
||||||
|
|
||||||
if(hero->boat)
|
|
||||||
return findBoatFlagBitmap(hero->boat, anim, color, group, hero->moveDir);
|
|
||||||
return findHeroFlagBitmap(hero, anim, color, group);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<QImage> MapHandler::findHeroFlagBitmap(const CGHeroInstance * hero, int anim, const PlayerColor * color, int group) const
|
|
||||||
{
|
|
||||||
return findFlagBitmapInternal(graphics->heroFlagAnimations.at(color->getNum()), anim, group, hero->moveDir, !hero->isStanding);
|
return findFlagBitmapInternal(graphics->heroFlagAnimations.at(color->getNum()), anim, group, hero->moveDir, !hero->isStanding);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<QImage> MapHandler::findBoatFlagBitmap(const CGBoat * boat, int anim, const PlayerColor * color, int group, ui8 dir) const
|
|
||||||
{
|
|
||||||
int boatType = boat->subID;
|
|
||||||
if(boatType < 0 || boatType >= graphics->boatFlagAnimations.size())
|
|
||||||
{
|
|
||||||
logGlobal->error("Not supported boat subtype: %d", boat->subID);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto & subtypeFlags = graphics->boatFlagAnimations.at(boatType);
|
|
||||||
|
|
||||||
int colorIndex = color->getNum();
|
|
||||||
|
|
||||||
if(colorIndex < 0 || colorIndex >= subtypeFlags.size())
|
|
||||||
{
|
|
||||||
logGlobal->error("Invalid player color %d", colorIndex);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return findFlagBitmapInternal(subtypeFlags.at(colorIndex), anim, group, dir, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<QImage> MapHandler::findFlagBitmapInternal(std::shared_ptr<Animation> animation, int anim, int group, ui8 dir, bool moving) const
|
std::shared_ptr<QImage> MapHandler::findFlagBitmapInternal(std::shared_ptr<Animation> animation, int anim, int group, ui8 dir, bool moving) const
|
||||||
{
|
{
|
||||||
size_t groupSize = animation->size(group);
|
size_t groupSize = animation->size(group);
|
||||||
@ -370,16 +264,11 @@ std::shared_ptr<QImage> MapHandler::findFlagBitmapInternal(std::shared_ptr<Anima
|
|||||||
return animation->getImage((anim / 4) % groupSize, group);
|
return animation->getImage((anim / 4) % groupSize, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MapHandler::AnimBitmapHolder MapHandler::findObjectBitmap(const CGObjectInstance * obj, int anim) const
|
MapHandler::AnimBitmapHolder MapHandler::findObjectBitmap(const CGObjectInstance * obj, int anim) const
|
||||||
{
|
{
|
||||||
if (!obj)
|
if(!obj || obj->ID == Obj::HERO || obj->ID == Obj::BOAT)
|
||||||
return MapHandler::AnimBitmapHolder();
|
return MapHandler::AnimBitmapHolder();
|
||||||
if (obj->ID == Obj::HERO)
|
|
||||||
return findHeroBitmap(static_cast<const CGHeroInstance*>(obj), anim);
|
|
||||||
if (obj->ID == Obj::BOAT)
|
|
||||||
return findBoatBitmap(static_cast<const CGBoat*>(obj), anim);
|
|
||||||
|
|
||||||
// normal object
|
// normal object
|
||||||
std::shared_ptr<Animation> animation = graphics->getAnimation(obj);
|
std::shared_ptr<Animation> animation = graphics->getAnimation(obj);
|
||||||
size_t groupSize = animation->size();
|
size_t groupSize = animation->size();
|
||||||
@ -387,7 +276,7 @@ MapHandler::AnimBitmapHolder MapHandler::findObjectBitmap(const CGObjectInstance
|
|||||||
return MapHandler::AnimBitmapHolder();
|
return MapHandler::AnimBitmapHolder();
|
||||||
|
|
||||||
animation->playerColored(obj->tempOwner);
|
animation->playerColored(obj->tempOwner);
|
||||||
auto bitmap = animation->getImage((anim + getPhaseShift(obj)) % groupSize);
|
auto bitmap = animation->getImage(anim % groupSize);
|
||||||
if(!bitmap)
|
if(!bitmap)
|
||||||
return MapHandler::AnimBitmapHolder();
|
return MapHandler::AnimBitmapHolder();
|
||||||
|
|
||||||
@ -396,9 +285,9 @@ MapHandler::AnimBitmapHolder MapHandler::findObjectBitmap(const CGObjectInstance
|
|||||||
return MapHandler::AnimBitmapHolder(bitmap);
|
return MapHandler::AnimBitmapHolder(bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<TerrainTileObject> & MapHandler::getObjects(int x, int y, int z)
|
std::vector<TileObject> & MapHandler::getObjects(int x, int y, int z)
|
||||||
{
|
{
|
||||||
return ttiles[z * (sizes.x * sizes.y) + y * sizes.x + x].objects;
|
return ttiles[index(x, y, z)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapHandler::drawObjects(QPainter & painter, int x, int y, int z)
|
void MapHandler::drawObjects(QPainter & painter, int x, int y, int z)
|
||||||
@ -418,33 +307,19 @@ void MapHandler::drawObjects(QPainter & painter, int x, int y, int z)
|
|||||||
if (objData.objBitmap)
|
if (objData.objBitmap)
|
||||||
{
|
{
|
||||||
auto pos = obj->getPosition();
|
auto pos = obj->getPosition();
|
||||||
QRect srcRect(object.rect.x() + pos.x * 32, object.rect.y() + pos.y * 32, tileSize, tileSize);
|
|
||||||
|
|
||||||
painter.drawImage(QPoint(x * 32, y * 32), *objData.objBitmap, object.rect);
|
painter.drawImage(QPoint(x * tileSize, y * tileSize), *objData.objBitmap, object.rect);
|
||||||
//painter.drawImage(pos.x * 32 - object.rect.x(), pos.y * 32 - object.rect.y(), *objData.objBitmap);
|
|
||||||
//drawObject(targetSurf, objData.objBitmap, &srcRect, objData.isMoving);
|
|
||||||
if(objData.flagBitmap)
|
if(objData.flagBitmap)
|
||||||
{
|
{
|
||||||
/*if (objData.isMoving)
|
|
||||||
{
|
|
||||||
srcRect.y += FRAMES_PER_MOVE_ANIM_GROUP * 2 - tileSize;
|
|
||||||
Rect dstRect(realPos.x, realPos.y - tileSize / 2, tileSize, tileSize);
|
|
||||||
drawHeroFlag(targetSurf, objData.flagBitmap, &srcRect, &dstRect, true);
|
|
||||||
}*/
|
|
||||||
if (obj->pos.x == pos.x && obj->pos.y == pos.y)
|
if (obj->pos.x == pos.x && obj->pos.y == pos.y)
|
||||||
{
|
painter.drawImage(QPoint(x * tileSize, y * tileSize), *objData.flagBitmap, object.rect);
|
||||||
//Rect dstRect(realPos.x - 2 * tileSize, realPos.y - tileSize, 3 * tileSize, 2 * tileSize);
|
|
||||||
painter.drawImage(QPoint(x * 32, y * 32), *objData.flagBitmap, object.rect);
|
|
||||||
//drawHeroFlag(targetSurf, objData.flagBitmap, nullptr, &dstRect, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapHandler::drawObject(QPainter & painter, const TerrainTileObject & object)
|
void MapHandler::drawObject(QPainter & painter, const TileObject & object)
|
||||||
{
|
{
|
||||||
//if(object.visi)
|
|
||||||
const CGObjectInstance * obj = object.obj;
|
const CGObjectInstance * obj = object.obj;
|
||||||
if (!obj)
|
if (!obj)
|
||||||
{
|
{
|
||||||
@ -458,24 +333,13 @@ void MapHandler::drawObject(QPainter & painter, const TerrainTileObject & object
|
|||||||
if (objData.objBitmap)
|
if (objData.objBitmap)
|
||||||
{
|
{
|
||||||
auto pos = obj->getPosition();
|
auto pos = obj->getPosition();
|
||||||
QRect srcRect(object.rect.x() + pos.x * 32, object.rect.y() + pos.y * 32, tileSize, tileSize);
|
|
||||||
|
|
||||||
painter.drawImage(pos.x * 32 - object.rect.x(), pos.y * 32 - object.rect.y(), *objData.objBitmap);
|
painter.drawImage(pos.x * tileSize - object.rect.x(), pos.y * tileSize - object.rect.y(), *objData.objBitmap);
|
||||||
//drawObject(targetSurf, objData.objBitmap, &srcRect, objData.isMoving);
|
|
||||||
if (objData.flagBitmap)
|
if (objData.flagBitmap)
|
||||||
{
|
{
|
||||||
/*if (objData.isMoving)
|
|
||||||
{
|
|
||||||
srcRect.y += FRAMES_PER_MOVE_ANIM_GROUP * 2 - tileSize;
|
|
||||||
Rect dstRect(realPos.x, realPos.y - tileSize / 2, tileSize, tileSize);
|
|
||||||
drawHeroFlag(targetSurf, objData.flagBitmap, &srcRect, &dstRect, true);
|
|
||||||
}
|
|
||||||
else */
|
|
||||||
if (obj->pos.x == pos.x && obj->pos.y == pos.y)
|
if (obj->pos.x == pos.x && obj->pos.y == pos.y)
|
||||||
{
|
{
|
||||||
//Rect dstRect(realPos.x - 2 * tileSize, realPos.y - tileSize, 3 * tileSize, 2 * tileSize);
|
painter.drawImage(pos.x * tileSize - object.rect.x(), pos.y * tileSize - object.rect.y(), *objData.flagBitmap);
|
||||||
//drawHeroFlag(targetSurf, objData.flagBitmap, nullptr, &dstRect, false);
|
|
||||||
painter.drawImage(pos.x * 32 - object.rect.x(), pos.y * 32 - object.rect.y(), *objData.flagBitmap);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -538,3 +402,102 @@ void MapHandler::drawMinimapTile(QPainter & painter, int x, int y, int z)
|
|||||||
painter.setPen(getTileColor(x, y, z));
|
painter.setPen(getTileColor(x, y, z));
|
||||||
painter.drawPoint(x, y);
|
painter.drawPoint(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapHandler::invalidate(int x, int y, int z)
|
||||||
|
{
|
||||||
|
auto & objects = getObjects(x, y, z);
|
||||||
|
|
||||||
|
for(auto obj = objects.begin(); obj != objects.end();)
|
||||||
|
{
|
||||||
|
//object was removed
|
||||||
|
if(std::find(map->objects.begin(), map->objects.end(), obj->obj) == map->objects.end())
|
||||||
|
{
|
||||||
|
obj = objects.erase(obj);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//object was moved
|
||||||
|
auto & pos = obj->obj->pos;
|
||||||
|
if(pos.z != z || pos.x < x || pos.y < y || pos.x - obj->obj->getWidth() >= x || pos.y - obj->obj->getHeight() >= y)
|
||||||
|
{
|
||||||
|
obj = objects.erase(obj);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
++obj;
|
||||||
|
//invalidate(obj->obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
stable_sort(objects.begin(), objects.end(), objectBlitOrderSorter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapHandler::invalidate(CGObjectInstance * obj)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Animation> animation = graphics->getAnimation(obj);
|
||||||
|
|
||||||
|
//no animation at all or empty animation
|
||||||
|
if(!animation || animation->size(0) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto image = animation->getImage(0,0);
|
||||||
|
for(int fx=0; fx < obj->getWidth(); ++fx)
|
||||||
|
{
|
||||||
|
for(int fy=0; fy < obj->getHeight(); ++fy)
|
||||||
|
{
|
||||||
|
//object presented on the tile
|
||||||
|
int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z);
|
||||||
|
QRect cr(image->width() - fx * tileSize - tileSize, image->height() - fy * tileSize - tileSize, image->width(), image->height());
|
||||||
|
|
||||||
|
if( map->isInTheMap(currTile) && // within map
|
||||||
|
cr.x() + cr.width() > 0 && // image has data on this tile
|
||||||
|
cr.y() + cr.height() > 0 &&
|
||||||
|
obj->coveringAt(currTile.x, currTile.y) // object is visible here
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto & objects = ttiles[index(currTile)];
|
||||||
|
bool found = false;
|
||||||
|
for(auto & o : objects)
|
||||||
|
{
|
||||||
|
if(o.obj == obj)
|
||||||
|
{
|
||||||
|
o.rect = cr;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!found)
|
||||||
|
objects.emplace_back(obj, cr);
|
||||||
|
|
||||||
|
stable_sort(objects.begin(), objects.end(), objectBlitOrderSorter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int3> MapHandler::geTilesUnderObject(CGObjectInstance * obj) const
|
||||||
|
{
|
||||||
|
std::vector<int3> result;
|
||||||
|
for(int fx=0; fx < obj->getWidth(); ++fx)
|
||||||
|
{
|
||||||
|
for(int fy=0; fy < obj->getHeight(); ++fy)
|
||||||
|
{
|
||||||
|
//object presented on the tile
|
||||||
|
int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z);
|
||||||
|
if(map->isInTheMap(currTile) && // within map
|
||||||
|
obj->coveringAt(currTile.x, currTile.y) // object is visible here
|
||||||
|
)
|
||||||
|
{
|
||||||
|
result.push_back(currTile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapHandler::invalidate(const std::vector<int3> & tiles)
|
||||||
|
{
|
||||||
|
for(auto & currTile : tiles)
|
||||||
|
{
|
||||||
|
invalidate(currTile.x, currTile.y, currTile.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,20 +13,16 @@ class CGObjectInstance;
|
|||||||
class CGBoat;
|
class CGBoat;
|
||||||
class PlayerColor;
|
class PlayerColor;
|
||||||
|
|
||||||
struct TerrainTileObject
|
struct TileObject
|
||||||
{
|
{
|
||||||
CGObjectInstance *obj;
|
CGObjectInstance *obj;
|
||||||
QRect rect;
|
QRect rect;
|
||||||
bool real;
|
|
||||||
|
|
||||||
TerrainTileObject(CGObjectInstance *obj_, QRect rect_, bool visitablePos = false);
|
TileObject(CGObjectInstance *obj_, QRect rect_);
|
||||||
~TerrainTileObject();
|
~TileObject();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TerrainTile2
|
using TileObjects = std::vector<TileObject>; //pointers to objects being on this tile with rects to be easier to blit this tile on screen
|
||||||
{
|
|
||||||
std::vector<TerrainTileObject> objects; //pointers to objects being on this tile with rects to be easier to blit this tile on screen
|
|
||||||
};
|
|
||||||
|
|
||||||
class MapHandler
|
class MapHandler
|
||||||
{
|
{
|
||||||
@ -44,21 +40,30 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
ui8 getHeroFrameGroup(ui8 dir, bool isMoving) const;
|
int index(int x, int y, int z) const;
|
||||||
ui8 getPhaseShift(const CGObjectInstance *object) const;
|
int index(const int3 &) const;
|
||||||
|
|
||||||
// internal helper methods to choose correct bitmap(s) for object; called internally by findObjectBitmap
|
|
||||||
AnimBitmapHolder findHeroBitmap(const CGHeroInstance * hero, int anim) const;
|
|
||||||
AnimBitmapHolder findBoatBitmap(const CGBoat * hero, int anim) const;
|
|
||||||
std::shared_ptr<QImage> findFlagBitmap(const CGHeroInstance * obj, int anim, const PlayerColor * color, int group) const;
|
|
||||||
std::shared_ptr<QImage> findHeroFlagBitmap(const CGHeroInstance * obj, int anim, const PlayerColor * color, int group) const;
|
|
||||||
std::shared_ptr<QImage> findBoatFlagBitmap(const CGBoat * obj, int anim, const PlayerColor * color, int group, ui8 dir) const;
|
|
||||||
std::shared_ptr<QImage> findFlagBitmapInternal(std::shared_ptr<Animation> animation, int anim, int group, ui8 dir, bool moving) const;
|
std::shared_ptr<QImage> findFlagBitmapInternal(std::shared_ptr<Animation> animation, int anim, int group, ui8 dir, bool moving) const;
|
||||||
|
std::shared_ptr<QImage> findFlagBitmap(const CGHeroInstance * obj, int anim, const PlayerColor * color, int group) const;
|
||||||
public:
|
|
||||||
|
|
||||||
AnimBitmapHolder findObjectBitmap(const CGObjectInstance * obj, int anim) const;
|
AnimBitmapHolder findObjectBitmap(const CGObjectInstance * obj, int anim) const;
|
||||||
|
|
||||||
|
//FIXME: unique_ptr should be enough, but fails to compile in MSVS 2013
|
||||||
|
typedef std::map<std::string, std::shared_ptr<Animation>> TFlippedAnimations; //[type, rotation]
|
||||||
|
typedef std::map<std::string, std::vector<std::shared_ptr<QImage>>> TFlippedCache;//[type, view type, rotation]
|
||||||
|
|
||||||
|
TFlippedAnimations terrainAnimations;//[terrain type, rotation]
|
||||||
|
TFlippedCache terrainImages;//[terrain type, view type, rotation]
|
||||||
|
|
||||||
|
TFlippedAnimations roadAnimations;//[road type, rotation]
|
||||||
|
TFlippedCache roadImages;//[road type, view type, rotation]
|
||||||
|
|
||||||
|
TFlippedAnimations riverAnimations;//[river type, rotation]
|
||||||
|
TFlippedCache riverImages;//[river type, view type, rotation]
|
||||||
|
|
||||||
|
std::vector<TileObjects> ttiles; //informations about map tiles
|
||||||
|
int3 sizes; //map size (x = width, y = height, z = number of levels)
|
||||||
|
const CMap * map;
|
||||||
|
|
||||||
enum class EMapCacheType : char
|
enum class EMapCacheType : char
|
||||||
{
|
{
|
||||||
TERRAIN, OBJECTS, ROADS, RIVERS, FOW, HEROES, HERO_FLAGS, FRAME, AFTER_LAST
|
TERRAIN, OBJECTS, ROADS, RIVERS, FOW, HEROES, HERO_FLAGS, FRAME, AFTER_LAST
|
||||||
@ -66,59 +71,34 @@ public:
|
|||||||
|
|
||||||
void initObjectRects();
|
void initObjectRects();
|
||||||
void initTerrainGraphics();
|
void initTerrainGraphics();
|
||||||
|
QRgb getTileColor(int x, int y, int z);
|
||||||
|
|
||||||
|
public:
|
||||||
|
MapHandler();
|
||||||
|
~MapHandler() = default;
|
||||||
|
|
||||||
|
void reset(const CMap * Map);
|
||||||
|
|
||||||
std::vector<TerrainTile2> ttiles; //informations about map tiles
|
void updateWater();
|
||||||
int3 sizes; //map size (x = width, y = height, z = number of levels)
|
|
||||||
const CMap * map;
|
|
||||||
|
|
||||||
//terrain graphics
|
|
||||||
|
|
||||||
//FIXME: unique_ptr should be enough, but fails to compile in MSVS 2013
|
|
||||||
typedef std::map<std::string, std::shared_ptr<Animation>> TFlippedAnimations; //[type, rotation]
|
|
||||||
typedef std::map<std::string, std::vector<std::shared_ptr<QImage>>> TFlippedCache;//[type, view type, rotation]
|
|
||||||
|
|
||||||
TFlippedAnimations terrainAnimations;//[terrain type, rotation]
|
|
||||||
TFlippedCache terrainImages;//[terrain type, view type, rotation]
|
|
||||||
|
|
||||||
TFlippedAnimations roadAnimations;//[road type, rotation]
|
|
||||||
TFlippedCache roadImages;//[road type, view type, rotation]
|
|
||||||
|
|
||||||
TFlippedAnimations riverAnimations;//[river type, rotation]
|
|
||||||
TFlippedCache riverImages;//[river type, view type, rotation]
|
|
||||||
|
|
||||||
void drawTerrainTile(QPainter & painter, int x, int y, int z);
|
void drawTerrainTile(QPainter & painter, int x, int y, int z);
|
||||||
/// draws a river segment on current tile
|
/// draws a river segment on current tile
|
||||||
void drawRiver(QPainter & painter, int x, int y, int z);
|
void drawRiver(QPainter & painter, int x, int y, int z);
|
||||||
/// draws a road segment on current tile
|
/// draws a road segment on current tile
|
||||||
void drawRoad(QPainter & painter, int x, int y, int z);
|
void drawRoad(QPainter & painter, int x, int y, int z);
|
||||||
|
|
||||||
|
void invalidate(int x, int y, int z); //invalidates all objects in particular tile
|
||||||
|
void invalidate(CGObjectInstance *); //invalidates object rects
|
||||||
|
void invalidate(const std::vector<int3> &); //invalidates all tiles
|
||||||
|
std::vector<int3> geTilesUnderObject(CGObjectInstance *) const;
|
||||||
|
|
||||||
/// draws all objects on current tile (higher-level logic, unlike other draw*** methods)
|
/// draws all objects on current tile (higher-level logic, unlike other draw*** methods)
|
||||||
void drawObjects(QPainter & painter, int x, int y, int z);
|
void drawObjects(QPainter & painter, int x, int y, int z);
|
||||||
void drawObject(QPainter & painter, const TerrainTileObject & object);
|
void drawObject(QPainter & painter, const TileObject & object);
|
||||||
void drawObjectAt(QPainter & painter, const CGObjectInstance * object, int x, int y);
|
void drawObjectAt(QPainter & painter, const CGObjectInstance * object, int x, int y);
|
||||||
std::vector<TerrainTileObject> & getObjects(int x, int y, int z);
|
std::vector<TileObject> & getObjects(int x, int y, int z);
|
||||||
//void drawObject(SDL_Surface * targetSurf, std::shared_ptr<IImage> source, SDL_Rect * sourceRect, bool moving) const;
|
|
||||||
//void drawHeroFlag(SDL_Surface * targetSurf, std::shared_ptr<IImage> source, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const;
|
|
||||||
QRgb getTileColor(int x, int y, int z);
|
|
||||||
void drawMinimapTile(QPainter & painter, int x, int y, int z);
|
void drawMinimapTile(QPainter & painter, int x, int y, int z);
|
||||||
|
|
||||||
mutable std::map<const CGObjectInstance*, ui8> animationPhase;
|
|
||||||
|
|
||||||
MapHandler(const CMap * Map);
|
|
||||||
~MapHandler() = default;
|
|
||||||
|
|
||||||
void init();
|
|
||||||
|
|
||||||
//void getTerrainDescr(const int3 & pos, std::string & out, bool isRMB) const; // isRMB = whether Right Mouse Button is clicked
|
|
||||||
//bool printObject(const CGObjectInstance * obj, bool fadein = false); //puts appropriate things to tiles, so obj will be visible on map
|
|
||||||
//bool hideObject(const CGObjectInstance * obj, bool fadeout = false); //removes appropriate things from ttiles, so obj will be no longer visible on map (but still will exist)
|
|
||||||
//bool hasObjectHole(const int3 & pos) const; // Checks if TerrainTile2 tile has a pit remained after digging.
|
|
||||||
|
|
||||||
//EMapAnimRedrawStatus drawTerrainRectNew(SDL_Surface * targetSurface, const MapDrawingInfo * info, bool redrawOnlyAnim = false);
|
|
||||||
void updateWater();
|
|
||||||
/// determines if the map is ready to handle new hero movement (not available during fading animations)
|
|
||||||
//bool canStartHeroMovement();
|
|
||||||
|
|
||||||
//void discardWorldViewCache();
|
|
||||||
|
|
||||||
static bool compareObjectBlitOrder(const CGObjectInstance * a, const CGObjectInstance * b);
|
static bool compareObjectBlitOrder(const CGObjectInstance * a, const CGObjectInstance * b);
|
||||||
};
|
};
|
||||||
|
@ -329,7 +329,6 @@ void ObjectsLayer::setDirty(int x, int y)
|
|||||||
|
|
||||||
void ObjectsLayer::setDirty(const CGObjectInstance * object)
|
void ObjectsLayer::setDirty(const CGObjectInstance * object)
|
||||||
{
|
{
|
||||||
dirty.insert(object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectionObjectsLayer::SelectionObjectsLayer(MapSceneBase * s): AbstractLayer(s), newObject(nullptr)
|
SelectionObjectsLayer::SelectionObjectsLayer(MapSceneBase * s): AbstractLayer(s), newObject(nullptr)
|
||||||
|
@ -109,7 +109,8 @@ public:
|
|||||||
void setDirty(const CGObjectInstance * object);
|
void setDirty(const CGObjectInstance * object);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::set<const CGObjectInstance *> dirty;
|
std::set<const CGObjectInstance *> objDirty;
|
||||||
|
std::set<int3> dirty;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,6 +88,13 @@ void WindowNewMap::on_okButtong_clicked()
|
|||||||
std::unique_ptr<CMap> nmap;
|
std::unique_ptr<CMap> nmap;
|
||||||
if(ui->randomMapCheck->isChecked())
|
if(ui->randomMapCheck->isChecked())
|
||||||
{
|
{
|
||||||
|
//verify map template
|
||||||
|
if(mapGenOptions.getPossibleTemplates().empty())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, "No template", "No template for parameters scecified. Random map cannot be generated.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CMapGenerator generator(mapGenOptions);
|
CMapGenerator generator(mapGenOptions);
|
||||||
//TODO: fix water and roads
|
//TODO: fix water and roads
|
||||||
generator.disableModificator("RoadPlacer");
|
generator.disableModificator("RoadPlacer");
|
||||||
@ -96,9 +103,16 @@ void WindowNewMap::on_okButtong_clicked()
|
|||||||
auto progressBarWnd = new GeneratorProgress(generator, this);
|
auto progressBarWnd = new GeneratorProgress(generator, this);
|
||||||
progressBarWnd->show();
|
progressBarWnd->show();
|
||||||
|
|
||||||
auto f = std::async(std::launch::async, &CMapGenerator::generate, &generator);
|
try
|
||||||
progressBarWnd->update();
|
{
|
||||||
nmap = f.get();
|
auto f = std::async(std::launch::async, &CMapGenerator::generate, &generator);
|
||||||
|
progressBarWnd->update();
|
||||||
|
nmap = f.get();
|
||||||
|
}
|
||||||
|
catch(const std::exception & e)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, "RMG failure", e.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user