mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-18 17:40:48 +02:00
Showing objects
This commit is contained in:
parent
ea3845e8dd
commit
3c062bae32
@ -62,7 +62,7 @@ QImage BitmapHandler::loadH3PCX(ui8 * pcx, size_t size)
|
||||
{
|
||||
it = 0xC;
|
||||
//auto bitmap = QBitmap::fromData(qsize, pcx + it);
|
||||
QImage image(pcx + it, width, height, QImage::Format_MonoLSB);
|
||||
QImage image(pcx + it, width, height, QImage::Format_Indexed8);
|
||||
|
||||
//palette - last 256*3 bytes
|
||||
QVector<QRgb> colorTable;
|
||||
|
@ -8,6 +8,7 @@ set(editor_SRCS
|
||||
BitmapHandler.cpp
|
||||
maphandler.cpp
|
||||
Animation.cpp
|
||||
graphics.cpp
|
||||
)
|
||||
|
||||
set(editor_HEADERS
|
||||
@ -19,6 +20,7 @@ set(editor_HEADERS
|
||||
BitmapHandler.h
|
||||
maphandler.h
|
||||
Animation.h
|
||||
graphics.h
|
||||
)
|
||||
|
||||
set(editor_FORMS
|
||||
|
359
mapeditor/graphics.cpp
Normal file
359
mapeditor/graphics.cpp
Normal file
@ -0,0 +1,359 @@
|
||||
/*
|
||||
* Graphics.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "graphics.h"
|
||||
|
||||
#include <vcmi/Entity.h>
|
||||
#include <vcmi/ArtifactService.h>
|
||||
#include <vcmi/CreatureService.h>
|
||||
#include <vcmi/FactionService.h>
|
||||
#include <vcmi/HeroTypeService.h>
|
||||
#include <vcmi/SkillService.h>
|
||||
#include <vcmi/spells/Service.h>
|
||||
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/filesystem/CBinaryReader.h"
|
||||
#include "Animation.h"
|
||||
#include "../lib/CThreadHelper.h"
|
||||
#include "../lib/CModHandler.h"
|
||||
#include "../lib/VCMI_Lib.h"
|
||||
#include "../CCallback.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "BitmapHandler.h"
|
||||
#include "../lib/CGameState.h"
|
||||
#include "../lib/JsonNode.h"
|
||||
#include "../lib/vcmi_endian.h"
|
||||
#include "../lib/CStopWatch.h"
|
||||
#include "../lib/mapObjects/CObjectClassesHandler.h"
|
||||
#include "../lib/mapObjects/CObjectHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
#include "CGameInfo.h"
|
||||
|
||||
Graphics * graphics = nullptr;
|
||||
|
||||
void Graphics::loadPaletteAndColors()
|
||||
{
|
||||
auto textFile = CResourceHandler::get()->load(ResourceID("DATA/PLAYERS.PAL"))->readAll();
|
||||
std::string pals((char*)textFile.first.get(), textFile.second);
|
||||
|
||||
playerColorPalette.resize(256);
|
||||
playerColors.resize(PlayerColor::PLAYER_LIMIT_I);
|
||||
int startPoint = 24; //beginning byte; used to read
|
||||
for(int i=0; i<256; ++i)
|
||||
{
|
||||
QColor col;
|
||||
col.setRed(pals[startPoint++]);
|
||||
col.setGreen(pals[startPoint++]);
|
||||
col.setBlue(pals[startPoint++]);
|
||||
col.setAlpha(255);
|
||||
startPoint++;
|
||||
playerColorPalette[i] = col.rgba();
|
||||
}
|
||||
|
||||
neutralColorPalette.resize(32);
|
||||
|
||||
auto stream = CResourceHandler::get()->load(ResourceID("config/NEUTRAL.PAL"));
|
||||
CBinaryReader reader(stream.get());
|
||||
|
||||
for(int i=0; i<32; ++i)
|
||||
{
|
||||
QColor col;
|
||||
col.setRed(reader.readUInt8());
|
||||
col.setGreen(reader.readUInt8());
|
||||
col.setBlue(reader.readUInt8());
|
||||
col.setAlpha(255);
|
||||
reader.readUInt8(); // this is "flags" entry, not alpha
|
||||
neutralColorPalette[i] = col.rgba();
|
||||
}
|
||||
|
||||
//colors initialization
|
||||
QColor colors[] = {
|
||||
{0xff,0, 0, 255},
|
||||
{0x31,0x52,0xff,255},
|
||||
{0x9c,0x73,0x52,255},
|
||||
{0x42,0x94,0x29,255},
|
||||
|
||||
{0xff,0x84,0, 255},
|
||||
{0x8c,0x29,0xa5,255},
|
||||
{0x09,0x9c,0xa5,255},
|
||||
{0xc6,0x7b,0x8c,255}};
|
||||
|
||||
for(int i=0;i<8;i++)
|
||||
{
|
||||
playerColors[i] = colors[i].rgba();
|
||||
}
|
||||
//gray
|
||||
neutralColor = qRgba(0x84, 0x84, 0x84, 0xFF);
|
||||
}
|
||||
|
||||
Graphics::Graphics()
|
||||
{
|
||||
#if 0
|
||||
|
||||
std::vector<Task> tasks; //preparing list of graphics to load
|
||||
tasks += std::bind(&Graphics::loadFonts,this);
|
||||
tasks += std::bind(&Graphics::loadPaletteAndColors,this);
|
||||
tasks += std::bind(&Graphics::initializeBattleGraphics,this);
|
||||
tasks += std::bind(&Graphics::loadErmuToPicture,this);
|
||||
tasks += std::bind(&Graphics::initializeImageLists,this);
|
||||
|
||||
CThreadHelper th(&tasks,std::max((ui32)1,boost::thread::hardware_concurrency()));
|
||||
th.run();
|
||||
#else
|
||||
loadPaletteAndColors();
|
||||
initializeImageLists();
|
||||
#endif
|
||||
|
||||
//(!) do not load any CAnimation here
|
||||
}
|
||||
|
||||
Graphics::~Graphics()
|
||||
{
|
||||
}
|
||||
|
||||
void Graphics::load()
|
||||
{
|
||||
loadHeroAnimations();
|
||||
loadHeroFlagAnimations();
|
||||
}
|
||||
|
||||
void Graphics::loadHeroAnimations()
|
||||
{
|
||||
for(auto & elem : CGI->heroh->classes.objects)
|
||||
{
|
||||
for (auto & templ : VLC->objtypeh->getHandlerFor(Obj::HERO, elem->getIndex())->getTemplates())
|
||||
{
|
||||
if (!heroAnimations.count(templ.animationFile))
|
||||
heroAnimations[templ.animationFile] = loadHeroAnimation(templ.animationFile);
|
||||
}
|
||||
}
|
||||
|
||||
boatAnimations[0] = loadHeroAnimation("AB01_.DEF");
|
||||
boatAnimations[1] = loadHeroAnimation("AB02_.DEF");
|
||||
boatAnimations[2] = loadHeroAnimation("AB03_.DEF");
|
||||
|
||||
|
||||
mapObjectAnimations["AB01_.DEF"] = boatAnimations[0];
|
||||
mapObjectAnimations["AB02_.DEF"] = boatAnimations[1];
|
||||
mapObjectAnimations["AB03_.DEF"] = boatAnimations[2];
|
||||
}
|
||||
void Graphics::loadHeroFlagAnimations()
|
||||
{
|
||||
static const std::vector<std::string> HERO_FLAG_ANIMATIONS =
|
||||
{
|
||||
"AF00", "AF01","AF02","AF03",
|
||||
"AF04", "AF05","AF06","AF07"
|
||||
};
|
||||
|
||||
static const std::vector< std::vector<std::string> > BOAT_FLAG_ANIMATIONS =
|
||||
{
|
||||
{
|
||||
"ABF01L", "ABF01G", "ABF01R", "ABF01D",
|
||||
"ABF01B", "ABF01P", "ABF01W", "ABF01K"
|
||||
},
|
||||
{
|
||||
"ABF02L", "ABF02G", "ABF02R", "ABF02D",
|
||||
"ABF02B", "ABF02P", "ABF02W", "ABF02K"
|
||||
},
|
||||
{
|
||||
"ABF03L", "ABF03G", "ABF03R", "ABF03D",
|
||||
"ABF03B", "ABF03P", "ABF03W", "ABF03K"
|
||||
}
|
||||
};
|
||||
|
||||
for(const auto & name : HERO_FLAG_ANIMATIONS)
|
||||
heroFlagAnimations.push_back(loadHeroFlagAnimation(name));
|
||||
|
||||
for(int i = 0; i < BOAT_FLAG_ANIMATIONS.size(); i++)
|
||||
for(const auto & name : BOAT_FLAG_ANIMATIONS[i])
|
||||
boatFlagAnimations[i].push_back(loadHeroFlagAnimation(name));
|
||||
}
|
||||
|
||||
std::shared_ptr<Animation> Graphics::loadHeroFlagAnimation(const std::string & name)
|
||||
{
|
||||
//first - group number to be rotated, second - group number after rotation
|
||||
static const std::vector<std::pair<int,int> > rotations =
|
||||
{
|
||||
{6,10}, {7,11}, {8,12}, {1,13},
|
||||
{2,14}, {3,15}
|
||||
};
|
||||
|
||||
std::shared_ptr<Animation> anim = std::make_shared<Animation>(name);
|
||||
anim->preload();
|
||||
|
||||
for(const auto & rotation : rotations)
|
||||
{
|
||||
const int sourceGroup = rotation.first;
|
||||
const int targetGroup = rotation.second;
|
||||
|
||||
anim->createFlippedGroup(sourceGroup, targetGroup);
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
std::shared_ptr<Animation> Graphics::loadHeroAnimation(const std::string &name)
|
||||
{
|
||||
//first - group number to be rotated, second - group number after rotation
|
||||
static const std::vector<std::pair<int,int> > rotations =
|
||||
{
|
||||
{6,10}, {7,11}, {8,12}, {1,13},
|
||||
{2,14}, {3,15}
|
||||
};
|
||||
|
||||
std::shared_ptr<Animation> anim = std::make_shared<Animation>(name);
|
||||
anim->preload();
|
||||
|
||||
|
||||
for(const auto & rotation : rotations)
|
||||
{
|
||||
const int sourceGroup = rotation.first;
|
||||
const int targetGroup = rotation.second;
|
||||
|
||||
anim->createFlippedGroup(sourceGroup, targetGroup);
|
||||
}
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
void Graphics::blueToPlayersAdv(QImage * sur, PlayerColor player)
|
||||
{
|
||||
if(sur->format() == QImage::Format_Indexed8)
|
||||
{
|
||||
auto palette = sur->colorTable();
|
||||
if(player < PlayerColor::PLAYER_LIMIT)
|
||||
{
|
||||
for(int i = 0; i < 32; ++i)
|
||||
palette[224 + i] = playerColorPalette[player.getNum() * 32 + i];
|
||||
}
|
||||
else if(player == PlayerColor::NEUTRAL)
|
||||
{
|
||||
palette = neutralColorPalette;
|
||||
}
|
||||
else
|
||||
{
|
||||
logGlobal->error("Wrong player id in blueToPlayersAdv (%s)!", player.getStr());
|
||||
return;
|
||||
}
|
||||
//FIXME: not all player colored images have player palette at last 32 indexes
|
||||
//NOTE: following code is much more correct but still not perfect (bugged with status bar)
|
||||
sur->setColorTable(palette);
|
||||
|
||||
#if 0
|
||||
|
||||
SDL_Color * bluePalette = playerColorPalette + 32;
|
||||
|
||||
SDL_Palette * oldPalette = sur->format->palette;
|
||||
|
||||
SDL_Palette * newPalette = SDL_AllocPalette(256);
|
||||
|
||||
for(size_t destIndex = 0; destIndex < 256; destIndex++)
|
||||
{
|
||||
SDL_Color old = oldPalette->colors[destIndex];
|
||||
|
||||
bool found = false;
|
||||
|
||||
for(size_t srcIndex = 0; srcIndex < 32; srcIndex++)
|
||||
{
|
||||
if(old.b == bluePalette[srcIndex].b && old.g == bluePalette[srcIndex].g && old.r == bluePalette[srcIndex].r)
|
||||
{
|
||||
found = true;
|
||||
newPalette->colors[destIndex] = palette[srcIndex];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
newPalette->colors[destIndex] = old;
|
||||
}
|
||||
|
||||
SDL_SetSurfacePalette(sur, newPalette);
|
||||
|
||||
SDL_FreePalette(newPalette);
|
||||
|
||||
#endif // 0
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: implement. H3 method works only for images with palettes.
|
||||
// Add some kind of player-colored overlay?
|
||||
// Or keep palette approach here and replace only colors of specific value(s)
|
||||
// Or just wait for OpenGL support?
|
||||
logGlobal->warn("Image must have palette to be player-colored!");
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Animation> Graphics::getAnimation(const CGObjectInstance* obj)
|
||||
{
|
||||
return getAnimation(obj->appearance);
|
||||
}
|
||||
|
||||
std::shared_ptr<Animation> Graphics::getAnimation(const ObjectTemplate & info)
|
||||
{
|
||||
//the only(?) invisible object
|
||||
if(info.id == Obj::EVENT)
|
||||
{
|
||||
return std::shared_ptr<Animation>();
|
||||
}
|
||||
|
||||
if(info.animationFile.empty())
|
||||
{
|
||||
logGlobal->warn("Def name for obj (%d,%d) is empty!", info.id, info.subid);
|
||||
return std::shared_ptr<Animation>();
|
||||
}
|
||||
|
||||
std::shared_ptr<Animation> ret = mapObjectAnimations[info.animationFile];
|
||||
|
||||
//already loaded
|
||||
if(ret)
|
||||
{
|
||||
ret->preload();
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = std::make_shared<Animation>(info.animationFile);
|
||||
mapObjectAnimations[info.animationFile] = ret;
|
||||
|
||||
ret->preload();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Graphics::addImageListEntry(size_t index, const std::string & listName, const std::string & imageName)
|
||||
{
|
||||
if (!imageName.empty())
|
||||
{
|
||||
JsonNode entry;
|
||||
entry["frame"].Integer() = index;
|
||||
entry["file"].String() = imageName;
|
||||
|
||||
imageLists["SPRITES/" + listName]["images"].Vector().push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::addImageListEntries(const EntityService * service)
|
||||
{
|
||||
auto cb = std::bind(&Graphics::addImageListEntry, this, _1, _2, _3);
|
||||
|
||||
auto loopCb = [&](const Entity * entity, bool & stop)
|
||||
{
|
||||
entity->registerIcons(cb);
|
||||
};
|
||||
|
||||
service->forEachBase(loopCb);
|
||||
}
|
||||
|
||||
void Graphics::initializeImageLists()
|
||||
{
|
||||
addImageListEntries(CGI->creatures());
|
||||
addImageListEntries(CGI->heroTypes());
|
||||
addImageListEntries(CGI->artifacts());
|
||||
addImageListEntries(CGI->factions());
|
||||
addImageListEntries(CGI->spells());
|
||||
addImageListEntries(CGI->skills());
|
||||
}
|
83
mapeditor/graphics.h
Normal file
83
mapeditor/graphics.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Graphics.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../lib/GameConstants.h"
|
||||
#include <QImage>
|
||||
|
||||
class CGHeroInstance;
|
||||
class CGTownInstance;
|
||||
class CHeroClass;
|
||||
struct InfoAboutHero;
|
||||
struct InfoAboutTown;
|
||||
class CGObjectInstance;
|
||||
class ObjectTemplate;
|
||||
class Animation;
|
||||
class EntityService;
|
||||
class JsonNode;
|
||||
|
||||
/// Handles fonts, hero images, town images, various graphics
|
||||
class Graphics
|
||||
{
|
||||
void addImageListEntry(size_t index, const std::string & listName, const std::string & imageName);
|
||||
|
||||
void addImageListEntries(const EntityService * service);
|
||||
|
||||
void initializeBattleGraphics();
|
||||
void loadPaletteAndColors();
|
||||
|
||||
void loadHeroAnimations();
|
||||
//loads animation and adds required rotated frames
|
||||
std::shared_ptr<Animation> loadHeroAnimation(const std::string &name);
|
||||
|
||||
void loadHeroFlagAnimations();
|
||||
|
||||
//loads animation and adds required rotated frames
|
||||
std::shared_ptr<Animation> loadHeroFlagAnimation(const std::string &name);
|
||||
|
||||
void loadErmuToPicture();
|
||||
void loadFogOfWar();
|
||||
void loadFonts();
|
||||
void initializeImageLists();
|
||||
|
||||
public:
|
||||
//various graphics
|
||||
QVector<QRgb> playerColors; //array [8]
|
||||
QRgb neutralColor;
|
||||
QVector<QRgb> playerColorPalette; //palette to make interface colors good - array of size [256]
|
||||
QVector<QRgb> neutralColorPalette;
|
||||
|
||||
// [hero class def name] //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing
|
||||
std::map< std::string, std::shared_ptr<Animation> > heroAnimations;
|
||||
std::vector< std::shared_ptr<Animation> > heroFlagAnimations;
|
||||
|
||||
// [boat type: 0 .. 2] //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing
|
||||
std::array< std::shared_ptr<Animation>, 3> boatAnimations;
|
||||
|
||||
std::array< std::vector<std::shared_ptr<Animation> >, 3> boatFlagAnimations;
|
||||
|
||||
//all other objects (not hero or boat)
|
||||
std::map< std::string, std::shared_ptr<Animation> > mapObjectAnimations;
|
||||
|
||||
std::map<std::string, JsonNode> imageLists;
|
||||
|
||||
//functions
|
||||
Graphics();
|
||||
~Graphics();
|
||||
|
||||
void load();
|
||||
|
||||
void blueToPlayersAdv(QImage * sur, PlayerColor player); //replaces blue interface colour with a color of player
|
||||
|
||||
std::shared_ptr<Animation> getAnimation(const CGObjectInstance * obj);
|
||||
std::shared_ptr<Animation> getAnimation(const ObjectTemplate & info);
|
||||
};
|
||||
|
||||
extern Graphics * graphics;
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "CGameInfo.h"
|
||||
#include "maphandler.h"
|
||||
#include "graphics.h"
|
||||
|
||||
static CBasicLogConfigurator * logConfig;
|
||||
|
||||
@ -72,6 +73,9 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
CGI = new CGameInfo(); //contains all global informations about game (texts, lodHandlers, map handler etc.)
|
||||
init();
|
||||
|
||||
graphics = new Graphics(); // should be before curh->init()
|
||||
graphics->load();//must be after Content loading but should be in main thread
|
||||
|
||||
|
||||
if(!testFile("DATA/new-menu/Background.png", "Cannot find file"))
|
||||
{
|
||||
@ -128,7 +132,15 @@ void MainWindow::on_actionOpen_triggered()
|
||||
{
|
||||
for(int i = 0; i < map->width; ++i)
|
||||
{
|
||||
mapHandler.drawTerrainTile(i, j, map->getTile((int3(i, j, 0))));
|
||||
mapHandler.drawTerrainTile(i, j, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for(int j = 0; j < map->height; ++j)
|
||||
{
|
||||
for(int i = 0; i < map->width; ++i)
|
||||
{
|
||||
mapHandler.drawObjects(i, j, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,23 @@
|
||||
#include "StdInc.h"
|
||||
#include "maphandler.h"
|
||||
#include "graphics.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../lib/mapObjects/CObjectClassesHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
#include "../lib/CTownHandler.h"
|
||||
#include "../lib/CModHandler.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "../lib/JsonDetail.h"
|
||||
|
||||
const int tileSize = 32;
|
||||
|
||||
static bool objectBlitOrderSorter(const TerrainTileObject & a, const TerrainTileObject & b)
|
||||
{
|
||||
return MapHandler::compareObjectBlitOrder(a.obj, b.obj);
|
||||
}
|
||||
|
||||
MapHandler::MapHandler(const CMap * Map):
|
||||
map(Map), surface(Map->width * tileSize, Map->height * tileSize), painter(&surface)
|
||||
{
|
||||
@ -64,10 +78,13 @@ void MapHandler::initTerrainGraphics()
|
||||
loadFlipped(terrainAnimations, terrainImages, terrainFiles);
|
||||
loadFlipped(roadAnimations, roadImages, ROAD_FILES);
|
||||
loadFlipped(riverAnimations, riverImages, RIVER_FILES);
|
||||
|
||||
ttiles.resize(sizes.x * sizes.y * sizes.z);
|
||||
}
|
||||
|
||||
void MapHandler::drawTerrainTile(int x, int y, const TerrainTile & tinfo)
|
||||
void MapHandler::drawTerrainTile(int x, int y, int z)
|
||||
{
|
||||
auto & tinfo = map->getTile(int3(x, y, z));
|
||||
//Rect destRect(realTileRect);
|
||||
|
||||
ui8 rotation = tinfo.extTileFlags % 4;
|
||||
@ -83,7 +100,7 @@ void MapHandler::drawTerrainTile(int x, int y, const TerrainTile & tinfo)
|
||||
void MapHandler::initObjectRects()
|
||||
{
|
||||
//initializing objects / rects
|
||||
/*for(auto & elem : map->objects)
|
||||
for(auto & elem : map->objects)
|
||||
{
|
||||
const CGObjectInstance *obj = elem;
|
||||
if( !obj
|
||||
@ -104,40 +121,255 @@ void MapHandler::initObjectRects()
|
||||
continue;
|
||||
|
||||
auto image = animation->getImage(0,0);
|
||||
|
||||
bool real = true;
|
||||
for(int fx=0; fx < obj->getWidth(); ++fx)
|
||||
{
|
||||
for(int fy=0; fy < obj->getHeight(); ++fy)
|
||||
{
|
||||
int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z);
|
||||
SDL_Rect cr;
|
||||
cr.w = 32;
|
||||
cr.h = 32;
|
||||
cr.x = image->width() - fx * 32 - 32;
|
||||
cr.y = image->height() - fy * 32 - 32;
|
||||
TerrainTileObject toAdd(obj, cr, obj->visitableAt(currTile.x, currTile.y));
|
||||
QRect cr(image->width() - fx * 32 - 32, image->height() - fy * 32 - 32, image->width(), image->height());
|
||||
TerrainTileObject toAdd(obj, cr, real/*obj->visitableAt(currTile.x, currTile.y)*/);
|
||||
real = false;
|
||||
|
||||
|
||||
if( map->isInTheMap(currTile) && // within map
|
||||
cr.x + cr.w > 0 && // image has data on this tile
|
||||
cr.y + cr.h > 0 &&
|
||||
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
|
||||
)
|
||||
{
|
||||
ttiles[currTile.x][currTile.y][currTile.z].objects.push_back(toAdd);
|
||||
ttiles[currTile.z * (sizes.x * sizes.y) + currTile.y * sizes.x + currTile.x].objects.push_back(toAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int ix=0; ix<ttiles.size()-frameW; ++ix)
|
||||
for(auto & tt : ttiles)
|
||||
{
|
||||
for(int iy=0; iy<ttiles[0].size()-frameH; ++iy)
|
||||
stable_sort(tt.objects.begin(), tt.objects.end(), objectBlitOrderSorter);
|
||||
}
|
||||
}
|
||||
|
||||
bool MapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObjectInstance * b)
|
||||
{
|
||||
if (!a)
|
||||
return true;
|
||||
if (!b)
|
||||
return false;
|
||||
if (a->appearance.printPriority != b->appearance.printPriority)
|
||||
return a->appearance.printPriority > b->appearance.printPriority;
|
||||
|
||||
if(a->pos.y != b->pos.y)
|
||||
return a->pos.y < b->pos.y;
|
||||
|
||||
if(b->ID==Obj::HERO && a->ID!=Obj::HERO)
|
||||
return true;
|
||||
if(b->ID!=Obj::HERO && a->ID==Obj::HERO)
|
||||
return false;
|
||||
|
||||
if(!a->isVisitable() && b->isVisitable())
|
||||
return true;
|
||||
if(!b->isVisitable() && a->isVisitable())
|
||||
return false;
|
||||
if(a->pos.x < b->pos.x)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
TerrainTileObject::TerrainTileObject(const CGObjectInstance * obj_, QRect rect_, bool real_)
|
||||
: obj(obj_),
|
||||
rect(rect_),
|
||||
real(real_)
|
||||
{
|
||||
}
|
||||
|
||||
TerrainTileObject::~TerrainTileObject()
|
||||
{
|
||||
}
|
||||
|
||||
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?
|
||||
{
|
||||
for(int iz=0; iz<ttiles[0][0].size(); ++iz)
|
||||
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
|
||||
{
|
||||
if(!hero)
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
size_t groupSize = animation->size(group);
|
||||
if(groupSize == 0)
|
||||
return nullptr;
|
||||
|
||||
if(moving)
|
||||
return animation->getImage(anim % groupSize, group);
|
||||
else
|
||||
return animation->getImage((anim / 4) % groupSize, group);
|
||||
}
|
||||
|
||||
|
||||
MapHandler::AnimBitmapHolder MapHandler::findObjectBitmap(const CGObjectInstance * obj, int anim) const
|
||||
{
|
||||
if (!obj)
|
||||
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
|
||||
std::shared_ptr<Animation> animation = graphics->getAnimation(obj);
|
||||
size_t groupSize = animation->size();
|
||||
if(groupSize == 0)
|
||||
return MapHandler::AnimBitmapHolder();
|
||||
|
||||
animation->playerColored(obj->tempOwner);
|
||||
auto bitmap = animation->getImage((anim + getPhaseShift(obj)) % groupSize);
|
||||
if(!bitmap)
|
||||
return MapHandler::AnimBitmapHolder();
|
||||
|
||||
return MapHandler::AnimBitmapHolder(bitmap);
|
||||
}
|
||||
|
||||
void MapHandler::drawObjects(int x, int y, int z)
|
||||
{
|
||||
auto & objects = ttiles[z * (sizes.x * sizes.y) + y * sizes.x + x].objects;
|
||||
for(auto & object : objects)
|
||||
{
|
||||
if(!object.real)
|
||||
continue;
|
||||
|
||||
//if(object.visi)
|
||||
const CGObjectInstance * obj = object.obj;
|
||||
if (!obj)
|
||||
{
|
||||
logGlobal->error("Stray map object that isn't fading");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t animationFrame = 0;
|
||||
|
||||
auto objData = findObjectBitmap(obj, animationFrame);
|
||||
if (objData.objBitmap)
|
||||
{
|
||||
QRect srcRect(object.rect.x(), object.rect.y(), tileSize, tileSize);
|
||||
|
||||
painter.drawImage(x * tileSize, y * tileSize, *objData.objBitmap);
|
||||
//drawObject(targetSurf, objData.objBitmap, &srcRect, objData.isMoving);
|
||||
if (objData.flagBitmap)
|
||||
{
|
||||
stable_sort(ttiles[ix][iy][iz].objects.begin(), ttiles[ix][iy][iz].objects.end(), objectBlitOrderSorter);
|
||||
/*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)
|
||||
{
|
||||
Rect dstRect(realPos.x - 2 * tileSize, realPos.y - tileSize, 3 * tileSize, 2 * tileSize);
|
||||
drawHeroFlag(targetSurf, objData.flagBitmap, nullptr, &dstRect, false);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,58 @@
|
||||
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
#include <QRect>
|
||||
|
||||
class CGObjectInstance;
|
||||
class CGBoat;
|
||||
struct PlayerColor;
|
||||
|
||||
struct TerrainTileObject
|
||||
{
|
||||
const CGObjectInstance *obj;
|
||||
QRect rect;
|
||||
bool real;
|
||||
|
||||
TerrainTileObject(const CGObjectInstance *obj_, QRect rect_, bool visitablePos = false);
|
||||
~TerrainTileObject();
|
||||
};
|
||||
|
||||
struct TerrainTile2
|
||||
{
|
||||
std::vector<TerrainTileObject> objects; //pointers to objects being on this tile with rects to be easier to blit this tile on screen
|
||||
};
|
||||
|
||||
class MapHandler
|
||||
{
|
||||
public:
|
||||
struct AnimBitmapHolder
|
||||
{
|
||||
std::shared_ptr<QImage> objBitmap; // main object bitmap
|
||||
std::shared_ptr<QImage> flagBitmap; // flag bitmap for the object (probably only for heroes and boats with heroes)
|
||||
|
||||
AnimBitmapHolder(std::shared_ptr<QImage> objBitmap_ = nullptr, std::shared_ptr<QImage> flagBitmap_ = nullptr)
|
||||
: objBitmap(objBitmap_),
|
||||
flagBitmap(flagBitmap_)
|
||||
{}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
ui8 getHeroFrameGroup(ui8 dir, bool isMoving) const;
|
||||
ui8 getPhaseShift(const CGObjectInstance *object) 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;
|
||||
|
||||
public:
|
||||
|
||||
AnimBitmapHolder findObjectBitmap(const CGObjectInstance * obj, int anim) const;
|
||||
|
||||
enum class EMapCacheType : char
|
||||
{
|
||||
TERRAIN, OBJECTS, ROADS, RIVERS, FOW, HEROES, HERO_FLAGS, FRAME, AFTER_LAST
|
||||
@ -19,6 +67,7 @@ public:
|
||||
void initObjectRects();
|
||||
void initTerrainGraphics();
|
||||
|
||||
std::vector<TerrainTile2> ttiles; //informations about map tiles
|
||||
int3 sizes; //map size (x = width, y = height, z = number of levels)
|
||||
const CMap * map;
|
||||
QPixmap surface;
|
||||
@ -39,7 +88,15 @@ public:
|
||||
TFlippedAnimations riverAnimations;//[river type, rotation]
|
||||
TFlippedCache riverImages;//[river type, view type, rotation]
|
||||
|
||||
void drawTerrainTile(int x, int y, const TerrainTile & tinfo);
|
||||
void drawTerrainTile(int x, int y, int z);
|
||||
/// draws a river segment on current tile
|
||||
//void drawRiver(const TerrainTile & tinfo) const;
|
||||
/// draws a road segment on current tile
|
||||
//void drawRoad(const TerrainTile & tinfo, const TerrainTile * tinfoUpper) const;
|
||||
/// draws all objects on current tile (higher-level logic, unlike other draw*** methods)
|
||||
void drawObjects(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;
|
||||
|
||||
mutable std::map<const CGObjectInstance*, ui8> animationPhase;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user