mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
-Added test subfolder and updated CMakeLists for unit testing - Added a test case for the DrawTerrainOperation class(does not pass all tests successfully, 6 failures left to fix) - Fixed a few bugs
This commit is contained in:
parent
a9cfb4bddb
commit
dd78205ce8
@ -16,6 +16,7 @@ set(VCMI_VERSION_PATCH 0)
|
||||
|
||||
option(DISABLE_ERM "Disable compilation of ERM scripting module" ON)
|
||||
option(ENABLE_EDITOR "Enable compilation of map editor" OFF)
|
||||
option(ENABLE_TEST "Enable compilation of unit tests" OFF)
|
||||
|
||||
############################################
|
||||
# Building section #
|
||||
@ -56,6 +57,10 @@ if (ENABLE_EDITOR)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
endif()
|
||||
|
||||
if(ENABLE_TEST)
|
||||
find_package(Boost 1.46.0 COMPONENTS unit_test_framework REQUIRED)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
set(FFmpeg_FIND_COMPONENTS AVFORMAT SWSCALE)
|
||||
find_package(FFmpeg REQUIRED)
|
||||
@ -125,6 +130,9 @@ endif()
|
||||
if (ENABLE_EDITOR)
|
||||
add_subdirectory(editor)
|
||||
endif()
|
||||
if(ENABLE_TEST)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
#######################################
|
||||
# Installation section #
|
||||
|
@ -45,6 +45,7 @@
|
||||
[
|
||||
// Standard transitions
|
||||
{
|
||||
"id" : "s1",
|
||||
"data" :
|
||||
[
|
||||
"?", "?", "T",
|
||||
@ -54,6 +55,7 @@
|
||||
"mapping" : "0-3, 20-23"
|
||||
},
|
||||
{
|
||||
"id" : "s2",
|
||||
"data" :
|
||||
[
|
||||
"?", "N", "N",
|
||||
@ -63,6 +65,7 @@
|
||||
"mapping" : "4-7, 24-27"
|
||||
},
|
||||
{
|
||||
"id" : "s3",
|
||||
"data" :
|
||||
[
|
||||
"?", "T", "?",
|
||||
@ -72,6 +75,7 @@
|
||||
"mapping" : "8-11, 28-31"
|
||||
},
|
||||
{
|
||||
"id" : "s4",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "N",
|
||||
@ -81,28 +85,30 @@
|
||||
"mapping" : "12-15, 32-35"
|
||||
},
|
||||
{
|
||||
"id" : "s5",
|
||||
"data" :
|
||||
[
|
||||
"T", "T", "a-1,?",
|
||||
"T", "T", "s5-1,?",
|
||||
"T", "N", "N",
|
||||
"a-1,?", "N", "N"
|
||||
"s5-1,?", "N", "N"
|
||||
],
|
||||
"mapping" : "16-17, 36-37",
|
||||
"id" : "a",
|
||||
"minPoints" : 1
|
||||
},
|
||||
{
|
||||
"id" : "s6",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "N",
|
||||
"N", "N", "a-1,N",
|
||||
"N", "a-1,N", "T"
|
||||
"N", "N", "s5-1,N",
|
||||
"N", "s5-1,N", "T"
|
||||
],
|
||||
"mapping" : "18-19, 38-39",
|
||||
"minPoints" : 1
|
||||
},
|
||||
// Mixed transitions
|
||||
{
|
||||
"id" : "m1",
|
||||
"data" :
|
||||
[
|
||||
"T", "N", "N",
|
||||
@ -112,6 +118,7 @@
|
||||
"mapping" : "40, 42"
|
||||
},
|
||||
{
|
||||
"id" : "m2",
|
||||
"data" :
|
||||
[
|
||||
"D", "N", "N",
|
||||
@ -121,6 +128,7 @@
|
||||
"mapping" : "41"
|
||||
},
|
||||
{
|
||||
"id" : "m3",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "D,N",
|
||||
@ -130,6 +138,7 @@
|
||||
"mapping" : "43"
|
||||
},
|
||||
{
|
||||
"id" : "m4",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "S",
|
||||
@ -139,6 +148,7 @@
|
||||
"mapping" : "44"
|
||||
},
|
||||
{
|
||||
"id" : "m5",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "D,N",
|
||||
@ -148,6 +158,7 @@
|
||||
"mapping" : "45"
|
||||
},
|
||||
{
|
||||
"id" : "m6",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "N",
|
||||
@ -157,6 +168,7 @@
|
||||
"mapping" : "46"
|
||||
},
|
||||
{
|
||||
"id" : "m7",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "D,S,N",
|
||||
@ -166,6 +178,7 @@
|
||||
"mapping" : "47"
|
||||
},
|
||||
{
|
||||
"id" : "m8",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "D",
|
||||
@ -176,6 +189,7 @@
|
||||
},
|
||||
// No transition
|
||||
{
|
||||
"id" : "n1",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "N",
|
||||
@ -189,6 +203,7 @@
|
||||
[
|
||||
// Standard transitions
|
||||
{
|
||||
"id" : "s1",
|
||||
"data" :
|
||||
[
|
||||
"?", "S", "S",
|
||||
@ -198,6 +213,7 @@
|
||||
"mapping" : "0-3"
|
||||
},
|
||||
{
|
||||
"id" : "s2",
|
||||
"data" :
|
||||
[
|
||||
"?", "D", "D",
|
||||
@ -207,6 +223,7 @@
|
||||
"mapping" : "4-7"
|
||||
},
|
||||
{
|
||||
"id" : "s3",
|
||||
"data" :
|
||||
[
|
||||
"?", "S", "?",
|
||||
@ -216,6 +233,7 @@
|
||||
"mapping" : "8-11"
|
||||
},
|
||||
{
|
||||
"id" : "s4",
|
||||
"data" :
|
||||
[
|
||||
"D", "D", "D",
|
||||
@ -225,29 +243,30 @@
|
||||
"mapping" : "12-15"
|
||||
},
|
||||
{
|
||||
"id" : "s5",
|
||||
"data" :
|
||||
[
|
||||
"S", "S", "D",
|
||||
"S", "N", "b-1,D",
|
||||
"D", "b-1,D", "D"
|
||||
"S", "N", "s6-1,D",
|
||||
"D", "s6-1,D", "D"
|
||||
],
|
||||
"mapping" : "16-17",
|
||||
"id" : "a",
|
||||
"minPoints" : 1
|
||||
},
|
||||
{
|
||||
"id" : "s6",
|
||||
"data" :
|
||||
[
|
||||
"D", "D", "D",
|
||||
"D", "N", "a-1,D",
|
||||
"D", "a-1,D", "S"
|
||||
"D", "N", "s5-1,D",
|
||||
"D", "s5-1,D", "S"
|
||||
],
|
||||
"mapping" : "18-19",
|
||||
"id" : "b",
|
||||
"minPoints" : 1
|
||||
},
|
||||
// Mixed transition
|
||||
{
|
||||
"id" : "m1",
|
||||
"data" :
|
||||
[
|
||||
"S", "D", "D",
|
||||
@ -258,6 +277,7 @@
|
||||
},
|
||||
// No transition
|
||||
{
|
||||
"id" : "n1",
|
||||
"data" :
|
||||
[
|
||||
"D", "D", "D",
|
||||
@ -270,6 +290,7 @@
|
||||
"sand" :
|
||||
[
|
||||
{
|
||||
"id" : "n1",
|
||||
"data" :
|
||||
[
|
||||
"?", "?", "?",
|
||||
@ -283,6 +304,7 @@
|
||||
[
|
||||
// Standard transitions
|
||||
{
|
||||
"id" : "s1",
|
||||
"data" :
|
||||
[
|
||||
"S", "S", "S",
|
||||
@ -292,6 +314,7 @@
|
||||
"mapping" : "0-3"
|
||||
},
|
||||
{
|
||||
"id" : "s2",
|
||||
"data" :
|
||||
[
|
||||
"?", "N", "N",
|
||||
@ -301,6 +324,7 @@
|
||||
"mapping" : "4-7"
|
||||
},
|
||||
{
|
||||
"id" : "s3",
|
||||
"data" :
|
||||
[
|
||||
"?", "S", "?",
|
||||
@ -310,6 +334,7 @@
|
||||
"mapping" : "8-11"
|
||||
},
|
||||
{
|
||||
"id" : "s4",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "N",
|
||||
@ -319,6 +344,7 @@
|
||||
"mapping" : "12-15"
|
||||
},
|
||||
{
|
||||
"id" : "s5",
|
||||
"data" :
|
||||
[
|
||||
"S", "S", "N",
|
||||
@ -326,20 +352,21 @@
|
||||
"N", "N", "N"
|
||||
],
|
||||
"mapping" : "16-17",
|
||||
"id" : "a"
|
||||
},
|
||||
{
|
||||
"id" : "s6",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "N",
|
||||
"N", "N", "a-1,N",
|
||||
"N", "a-1,N", "S"
|
||||
"N", "N", "s5-1,N",
|
||||
"N", "s5-1,N", "S"
|
||||
],
|
||||
"mapping" : "18-19",
|
||||
"minPoints" : 1
|
||||
},
|
||||
// No transition
|
||||
{
|
||||
"id" : "n1",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "N",
|
||||
@ -353,6 +380,7 @@
|
||||
[
|
||||
// No transition
|
||||
{
|
||||
"id" : "n1",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "N",
|
||||
@ -363,6 +391,7 @@
|
||||
},
|
||||
// Standard transitions
|
||||
{
|
||||
"id" : "s1",
|
||||
"data" :
|
||||
[
|
||||
"?", "S", "?",
|
||||
@ -373,6 +402,7 @@
|
||||
"flipMode" : "diffImages"
|
||||
},
|
||||
{
|
||||
"id" : "s2",
|
||||
"data" :
|
||||
[
|
||||
"?", "N", "N",
|
||||
@ -383,6 +413,7 @@
|
||||
"flipMode" : "diffImages"
|
||||
},
|
||||
{
|
||||
"id" : "s3",
|
||||
"data" :
|
||||
[
|
||||
"?", "S", "?",
|
||||
@ -393,6 +424,7 @@
|
||||
"flipMode" : "diffImages"
|
||||
},
|
||||
{
|
||||
"id" : "s4",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "N",
|
||||
@ -403,6 +435,7 @@
|
||||
"flipMode" : "diffImages"
|
||||
},
|
||||
{
|
||||
"id" : "s5",
|
||||
"data" :
|
||||
[
|
||||
"S", "S", "N",
|
||||
@ -410,15 +443,15 @@
|
||||
"N", "N", "N"
|
||||
],
|
||||
"mapping" : "32-39",
|
||||
"flipMode" : "diffImages",
|
||||
"id" : "a"
|
||||
"flipMode" : "diffImages"
|
||||
},
|
||||
{
|
||||
"id" : "s6",
|
||||
"data" :
|
||||
[
|
||||
"N", "N", "N",
|
||||
"N", "N", "a-1,N",
|
||||
"N", "a-1,N", "S"
|
||||
"N", "N", "s5-1,N",
|
||||
"N", "s5-1,N", "S"
|
||||
],
|
||||
"mapping" : "40-47",
|
||||
"flipMode" : "diffImages",
|
||||
|
@ -258,7 +258,7 @@ public:
|
||||
const CColorMapping & getColorMapping() const;
|
||||
void setColorMapping(const CColorMapping & colorMapping);
|
||||
|
||||
void write(const LogRecord & record);
|
||||
void write(const LogRecord & record) override;
|
||||
|
||||
private:
|
||||
CConsoleHandler * console;
|
||||
@ -281,7 +281,7 @@ public:
|
||||
const CLogFormatter & getFormatter() const;
|
||||
void setFormatter(const CLogFormatter & formatter);
|
||||
|
||||
void write(const LogRecord & record);
|
||||
void write(const LogRecord & record) override;
|
||||
|
||||
private:
|
||||
std::ofstream file;
|
||||
|
@ -5,6 +5,77 @@
|
||||
#include "../filesystem/CResourceLoader.h"
|
||||
#include "../CDefObjInfoHandler.h"
|
||||
|
||||
MapRect::MapRect() : x(0), y(0), z(0), width(0), height(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MapRect::MapRect(int3 pos, si32 width, si32 height) : x(pos.x), y(pos.y), z(pos.z), width(width), height(height)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MapRect MapRect::operator&(const MapRect & rect) const
|
||||
{
|
||||
bool intersect = right() > rect.left() && rect.right() > left() &&
|
||||
bottom() > rect.top() && rect.bottom() > top() &&
|
||||
z == rect.z;
|
||||
if(intersect)
|
||||
{
|
||||
MapRect ret;
|
||||
ret.x = std::max(left(), rect.left());
|
||||
ret.y = std::max(top(), rect.top());
|
||||
ret.z = rect.z;
|
||||
ret.width = std::min(right(), rect.right()) - ret.x;
|
||||
ret.height = std::min(bottom(), rect.bottom()) - ret.y;
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MapRect();
|
||||
}
|
||||
}
|
||||
|
||||
si32 MapRect::left() const
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
si32 MapRect::right() const
|
||||
{
|
||||
return x + width;
|
||||
}
|
||||
|
||||
si32 MapRect::top() const
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
si32 MapRect::bottom() const
|
||||
{
|
||||
return y + height;
|
||||
}
|
||||
|
||||
int3 MapRect::topLeft() const
|
||||
{
|
||||
return int3(x, y, z);
|
||||
}
|
||||
|
||||
int3 MapRect::topRight() const
|
||||
{
|
||||
return int3(right(), y, z);
|
||||
}
|
||||
|
||||
int3 MapRect::bottomLeft() const
|
||||
{
|
||||
return int3(x, bottom(), z);
|
||||
}
|
||||
|
||||
int3 MapRect::bottomRight() const
|
||||
{
|
||||
return int3(right(), bottom(), z);
|
||||
}
|
||||
|
||||
CMapOperation::CMapOperation(CMap * map) : map(map)
|
||||
{
|
||||
|
||||
@ -181,12 +252,11 @@ CTerrainViewPatternConfig & CTerrainViewPatternConfig::get()
|
||||
CTerrainViewPatternConfig::CTerrainViewPatternConfig()
|
||||
{
|
||||
const JsonNode config(ResourceID("config/terrainViewPatterns.json"));
|
||||
const std::map<std::string, ETerrainGroup::ETerrainGroup> terGroups
|
||||
= boost::assign::map_list_of("normal", ETerrainGroup::NORMAL)("dirt", ETerrainGroup::DIRT)
|
||||
("sand", ETerrainGroup::SAND)("water", ETerrainGroup::WATER)("rock", ETerrainGroup::ROCK);
|
||||
BOOST_FOREACH(auto terMapping, terGroups)
|
||||
const auto & groupMap = config.Struct();
|
||||
BOOST_FOREACH(const auto & groupPair, groupMap)
|
||||
{
|
||||
BOOST_FOREACH(const JsonNode & ptrnNode, config[terMapping.first].Vector())
|
||||
auto terGroup = getTerrainGroup(groupPair.first);
|
||||
BOOST_FOREACH(const JsonNode & ptrnNode, groupPair.second.Vector())
|
||||
{
|
||||
TerrainViewPattern pattern;
|
||||
|
||||
@ -238,8 +308,8 @@ CTerrainViewPatternConfig::CTerrainViewPatternConfig()
|
||||
pattern.flipMode = TerrainViewPattern::FLIP_MODE_SAME_IMAGE;
|
||||
}
|
||||
|
||||
pattern.terGroup = terMapping.second;
|
||||
patterns[terMapping.second].push_back(pattern);
|
||||
pattern.terGroup = terGroup;
|
||||
patterns[terGroup].push_back(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -249,6 +319,17 @@ CTerrainViewPatternConfig::~CTerrainViewPatternConfig()
|
||||
|
||||
}
|
||||
|
||||
ETerrainGroup::ETerrainGroup CTerrainViewPatternConfig::getTerrainGroup(const std::string & terGroup) const
|
||||
{
|
||||
static const std::map<std::string, ETerrainGroup::ETerrainGroup> terGroups
|
||||
= boost::assign::map_list_of("normal", ETerrainGroup::NORMAL)("dirt", ETerrainGroup::DIRT)
|
||||
("sand", ETerrainGroup::SAND)("water", ETerrainGroup::WATER)("rock", ETerrainGroup::ROCK);
|
||||
auto it = terGroups.find(terGroup);
|
||||
if(it == terGroups.end()) throw std::runtime_error(boost::str(boost::format("Terrain group '%s' does not exist.") % terGroup));
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<TerrainViewPattern> & CTerrainViewPatternConfig::getPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const
|
||||
{
|
||||
return patterns.find(terGroup)->second;
|
||||
@ -275,18 +356,19 @@ DrawTerrainOperation::DrawTerrainOperation(CMap * map, const MapRect & rect, ETe
|
||||
|
||||
void DrawTerrainOperation::execute()
|
||||
{
|
||||
for(int i = rect.pos.x; i < rect.pos.x + rect.width; ++i)
|
||||
for(int i = rect.x; i < rect.x + rect.width; ++i)
|
||||
{
|
||||
for(int j = rect.pos.y; j < rect.pos.y + rect.height; ++j)
|
||||
for(int j = rect.y; j < rect.y + rect.height; ++j)
|
||||
{
|
||||
map->getTile(int3(i, j, rect.pos.z)).terType = terType;
|
||||
map->getTile(int3(i, j, rect.z)).terType = terType;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO there are situations where more tiles are affected implicitely
|
||||
//TODO add coastal bit to extTileFlags appropriately
|
||||
|
||||
updateTerrainViews(MapRect(int3(rect.pos.x - 1, rect.pos.y - 1, rect.pos.z), rect.width + 2, rect.height + 2));
|
||||
MapRect viewRect(int3(rect.x - 1, rect.y - 1, rect.z), rect.width + 2, rect.height + 2); // Has to overlap 1 tile around
|
||||
updateTerrainViews(viewRect & MapRect(int3(0, 0, viewRect.z), map->width, map->height)); // Rect should not overlap map dimensions
|
||||
}
|
||||
|
||||
void DrawTerrainOperation::undo()
|
||||
@ -306,12 +388,12 @@ std::string DrawTerrainOperation::getLabel() const
|
||||
|
||||
void DrawTerrainOperation::updateTerrainViews(const MapRect & rect)
|
||||
{
|
||||
for(int i = rect.pos.x; i < rect.pos.x + rect.width; ++i)
|
||||
for(int i = rect.x; i < rect.x + rect.width; ++i)
|
||||
{
|
||||
for(int j = rect.pos.y; j < rect.pos.y + rect.height; ++j)
|
||||
for(int j = rect.y; j < rect.y + rect.height; ++j)
|
||||
{
|
||||
const auto & patterns =
|
||||
CTerrainViewPatternConfig::get().getPatternsForGroup(getTerrainGroup(map->getTile(int3(i, j, rect.pos.z)).terType));
|
||||
CTerrainViewPatternConfig::get().getPatternsForGroup(getTerrainGroup(map->getTile(int3(i, j, rect.z)).terType));
|
||||
|
||||
// Detect a pattern which fits best
|
||||
int bestPattern = -1, bestFlip = -1;
|
||||
@ -322,10 +404,10 @@ void DrawTerrainOperation::updateTerrainViews(const MapRect & rect)
|
||||
|
||||
for(int flip = 0; flip < 4; ++flip)
|
||||
{
|
||||
auto valRslt = validateTerrainView(int3(i, j, rect.pos.z), flip > 0 ? getFlippedPattern(pattern, flip) : pattern);
|
||||
auto valRslt = validateTerrainView(int3(i, j, rect.z), flip > 0 ? getFlippedPattern(pattern, flip) : pattern);
|
||||
if(valRslt.result)
|
||||
{
|
||||
logGlobal->debugStream() << "Pattern detected at pos " << i << "x" << j << "x" << rect.pos.z << ": P-Nr. " << k
|
||||
logGlobal->debugStream() << "Pattern detected at pos " << i << "x" << j << "x" << rect.z << ": P-Nr. " << k
|
||||
<< ", Flip " << flip << ", Repl. " << valRslt.transitionReplacement;
|
||||
|
||||
bestPattern = k;
|
||||
@ -338,7 +420,7 @@ void DrawTerrainOperation::updateTerrainViews(const MapRect & rect)
|
||||
if(bestPattern == -1)
|
||||
{
|
||||
// This shouldn't be the case
|
||||
logGlobal->warnStream() << "No pattern detected at pos " << i << "x" << j << "x" << rect.pos.z;
|
||||
logGlobal->warnStream() << "No pattern detected at pos " << i << "x" << j << "x" << rect.z;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -355,7 +437,7 @@ void DrawTerrainOperation::updateTerrainViews(const MapRect & rect)
|
||||
}
|
||||
|
||||
// Set terrain view
|
||||
auto & tile = map->getTile(int3(i, j, rect.pos.z));
|
||||
auto & tile = map->getTile(int3(i, j, rect.z));
|
||||
if(pattern.flipMode == TerrainViewPattern::FLIP_MODE_SAME_IMAGE)
|
||||
{
|
||||
tile.terView = gen->getInteger(mapping.first, mapping.second);
|
||||
@ -363,9 +445,9 @@ void DrawTerrainOperation::updateTerrainViews(const MapRect & rect)
|
||||
}
|
||||
else
|
||||
{
|
||||
int range = (mapping.second - mapping.first) / 4;
|
||||
tile.terView = gen->getInteger(mapping.first + bestFlip * range,
|
||||
mapping.first + (bestFlip + 1) * range - 1);
|
||||
const int framesPerRot = 2;
|
||||
int firstFrame = mapping.first + bestFlip * framesPerRot;
|
||||
tile.terView = gen->getInteger(firstFrame, firstFrame + framesPerRot - 1);
|
||||
tile.extTileFlags = 0;
|
||||
}
|
||||
}
|
||||
|
@ -18,28 +18,30 @@ class CGObjectInstance;
|
||||
class CTerrainViewPatternConfig;
|
||||
struct TerrainViewPattern;
|
||||
|
||||
namespace ETerrainGroup
|
||||
{
|
||||
enum ETerrainGroup
|
||||
{
|
||||
NORMAL,
|
||||
DIRT,
|
||||
SAND,
|
||||
WATER,
|
||||
ROCK
|
||||
};
|
||||
}
|
||||
|
||||
/// Represents a map rectangle.
|
||||
struct DLL_LINKAGE MapRect
|
||||
{
|
||||
MapRect(int3 pos, si32 width, si32 height) : pos(pos), width(width), height(height) { };
|
||||
int3 pos;
|
||||
MapRect();
|
||||
MapRect(int3 pos, si32 width, si32 height);
|
||||
si32 x, y, z;
|
||||
si32 width, height;
|
||||
|
||||
si32 left() const;
|
||||
si32 right() const;
|
||||
si32 top() const;
|
||||
si32 bottom() const;
|
||||
|
||||
int3 topLeft() const; /// Top left corner of this rect.
|
||||
int3 topRight() const; /// Top right corner of this rect.
|
||||
int3 bottomLeft() const; /// Bottom left corner of this rect.
|
||||
int3 bottomRight() const; /// Bottom right corner of this rect.
|
||||
|
||||
/// Returns a MapRect of the intersection of this rectangle and the given one.
|
||||
MapRect operator&(const MapRect & rect) const;
|
||||
};
|
||||
|
||||
/// The abstract base class CMapOperation defines an operation that can be executed, undone and redone.
|
||||
class CMapOperation
|
||||
class DLL_LINKAGE CMapOperation : public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
CMapOperation(CMap * map);
|
||||
@ -55,7 +57,7 @@ protected:
|
||||
};
|
||||
|
||||
/// The CMapUndoManager provides the functionality to save operations and undo/redo them.
|
||||
class CMapUndoManager : boost::noncopyable
|
||||
class DLL_LINKAGE CMapUndoManager : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
CMapUndoManager();
|
||||
@ -77,8 +79,8 @@ public:
|
||||
private:
|
||||
typedef std::list<unique_ptr<CMapOperation> > TStack;
|
||||
|
||||
inline void doOperation(TStack & fromStack, TStack & toStack, bool doUndo);
|
||||
inline const CMapOperation * peek(const TStack & stack) const;
|
||||
void doOperation(TStack & fromStack, TStack & toStack, bool doUndo);
|
||||
const CMapOperation * peek(const TStack & stack) const;
|
||||
|
||||
TStack undoStack;
|
||||
TStack redoStack;
|
||||
@ -113,9 +115,21 @@ private:
|
||||
/* Implementation/Detail classes, Private API */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
|
||||
namespace ETerrainGroup
|
||||
{
|
||||
enum ETerrainGroup
|
||||
{
|
||||
NORMAL,
|
||||
DIRT,
|
||||
SAND,
|
||||
WATER,
|
||||
ROCK
|
||||
};
|
||||
}
|
||||
|
||||
/// The terrain view pattern describes a specific composition of terrain tiles
|
||||
/// in a 3x3 matrix and notes which terrain view frame numbers can be used.
|
||||
struct TerrainViewPattern
|
||||
struct DLL_LINKAGE TerrainViewPattern
|
||||
{
|
||||
struct WeightedRule
|
||||
{
|
||||
@ -186,13 +200,14 @@ struct TerrainViewPattern
|
||||
};
|
||||
|
||||
/// The terrain view pattern config loads pattern data from the filesystem.
|
||||
class CTerrainViewPatternConfig : public boost::noncopyable
|
||||
class DLL_LINKAGE CTerrainViewPatternConfig : public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
static CTerrainViewPatternConfig & get();
|
||||
|
||||
const std::vector<TerrainViewPattern> & getPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const;
|
||||
const TerrainViewPattern & getPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const;
|
||||
ETerrainGroup::ETerrainGroup getTerrainGroup(const std::string & terGroup) const;
|
||||
|
||||
private:
|
||||
CTerrainViewPatternConfig();
|
||||
@ -208,10 +223,10 @@ class DrawTerrainOperation : public CMapOperation
|
||||
public:
|
||||
DrawTerrainOperation(CMap * map, const MapRect & rect, ETerrainType terType, CRandomGenerator * gen);
|
||||
|
||||
void execute();
|
||||
void undo();
|
||||
void redo();
|
||||
std::string getLabel() const;
|
||||
void execute() override;
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
std::string getLabel() const override;
|
||||
|
||||
private:
|
||||
struct ValidationResult
|
||||
@ -246,10 +261,10 @@ class InsertObjectOperation : public CMapOperation
|
||||
public:
|
||||
InsertObjectOperation(CMap * map, const int3 & pos, CGObjectInstance * obj);
|
||||
|
||||
void execute();
|
||||
void undo();
|
||||
void redo();
|
||||
std::string getLabel() const;
|
||||
void execute() override;
|
||||
void undo() override;
|
||||
void redo() override;
|
||||
std::string getLabel() const override;
|
||||
|
||||
private:
|
||||
int3 pos;
|
||||
|
@ -357,7 +357,7 @@ void CMapGenOptions::CPlayerSettings::setPlayerType(EPlayerType::EPlayerType val
|
||||
playerType = value;
|
||||
}
|
||||
|
||||
CMapGenerator::CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed) :
|
||||
CMapGenerator::CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed /*= std::time(nullptr)*/) :
|
||||
mapGenOptions(mapGenOptions), randomSeed(randomSeed)
|
||||
{
|
||||
gen.seed(randomSeed);
|
||||
@ -376,6 +376,7 @@ std::unique_ptr<CMap> CMapGenerator::generate()
|
||||
|
||||
map = make_unique<CMap>();
|
||||
editManager = map->getEditManager();
|
||||
editManager->getUndoManager().setUndoRedoLimit(0);
|
||||
addHeaderInfo();
|
||||
|
||||
genTerrain();
|
||||
@ -472,7 +473,7 @@ void CMapGenerator::addPlayerInfo()
|
||||
|
||||
void CMapGenerator::genTerrain()
|
||||
{
|
||||
map->initTerrain(); //FIXME nicer solution
|
||||
map->initTerrain();
|
||||
editManager->clearTerrain(&gen);
|
||||
editManager->drawTerrain(MapRect(int3(10, 10, 0), 20, 30), ETerrainType::GRASS, &gen);
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ public:
|
||||
class DLL_LINKAGE CMapGenerator
|
||||
{
|
||||
public:
|
||||
CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed);
|
||||
explicit CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed = std::time(nullptr));
|
||||
~CMapGenerator(); // required due to unique_ptr
|
||||
|
||||
std::unique_ptr<CMap> generate();
|
||||
|
27
test/CMakeLists.txt
Normal file
27
test/CMakeLists.txt
Normal file
@ -0,0 +1,27 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
enable_testing()
|
||||
include_directories(${CMAKE_HOME_DIRECTORY} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/test)
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
|
||||
set(test_SRCS
|
||||
StdInc.cpp
|
||||
CVcmiTestConfig.cpp
|
||||
CMapEditManagerTest.cpp
|
||||
)
|
||||
|
||||
add_executable(vcmitest ${test_SRCS})
|
||||
target_link_libraries(vcmitest vcmi ${Boost_LIBRARIES})
|
||||
add_test(vcmitest vcmitest)
|
||||
|
||||
# Files to copy to the build directory after compilation
|
||||
set(vcmitest_FILES
|
||||
TerrainViewTest.h3m
|
||||
terrainViewMappings.json
|
||||
)
|
||||
|
||||
foreach(file ${vcmitest_FILES})
|
||||
add_custom_command(TARGET vcmitest POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/${file}" $<TARGET_FILE_DIR:vcmitest>
|
||||
)
|
||||
endforeach()
|
83
test/CMapEditManagerTest.cpp
Normal file
83
test/CMapEditManagerTest.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
|
||||
/*
|
||||
* CMapEditManagerTest.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 <boost/test/unit_test.hpp>
|
||||
|
||||
#include "../lib/mapping/CMapService.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "../lib/filesystem/CResourceLoader.h"
|
||||
#include "../lib/filesystem/CFilesystemLoader.h"
|
||||
#include "../lib/JsonNode.h"
|
||||
#include "../lib/mapping/CMapEditManager.h"
|
||||
#include "../lib/int3.h"
|
||||
#include "../lib/CRandomGenerator.h"
|
||||
|
||||
BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load maps and json config
|
||||
auto loader = make_shared<CFilesystemLoader>(".");
|
||||
CResourceHandler::get()->addLoader("test/", loader, false);
|
||||
const auto originalMap = CMapService::loadMap("test/TerrainViewTest");
|
||||
auto map = CMapService::loadMap("test/TerrainViewTest");
|
||||
logGlobal->infoStream() << "Loaded test map successfully.";
|
||||
|
||||
// Validate edit manager
|
||||
auto editManager = map->getEditManager();
|
||||
CRandomGenerator gen;
|
||||
const JsonNode viewNode(ResourceID("test/terrainViewMappings", EResType::TEXT));
|
||||
const auto & mappingsNode = viewNode["mappings"].Vector();
|
||||
BOOST_FOREACH(const auto & node, mappingsNode)
|
||||
{
|
||||
// Get terrain group and id
|
||||
const auto & patternStr = node["pattern"].String();
|
||||
std::vector<std::string> patternParts;
|
||||
boost::split(patternParts, patternStr, boost::is_any_of("."));
|
||||
if(patternParts.size() != 2) throw std::runtime_error("A pattern should consist of two parts, the group and the id. Continue with next pattern.");
|
||||
const auto & groupStr = patternParts[0];
|
||||
const auto & id = patternParts[1];
|
||||
auto terGroup = CTerrainViewPatternConfig::get().getTerrainGroup(groupStr);
|
||||
|
||||
// Get mapping range
|
||||
const auto & pattern = CTerrainViewPatternConfig::get().getPatternById(terGroup, id);
|
||||
const auto & mapping = pattern.mapping;
|
||||
|
||||
const auto & positionsNode = node["pos"].Vector();
|
||||
BOOST_FOREACH(const auto & posNode, positionsNode)
|
||||
{
|
||||
const auto & posVector = posNode.Vector();
|
||||
if(posVector.size() != 3) throw std::runtime_error("A position should consist of three values x,y,z. Continue with next position.");
|
||||
int3 pos(posVector[0].Float(), posVector[1].Float(), posVector[2].Float());
|
||||
logGlobal->infoStream() << boost::format("Test pattern '%s' on position x '%d', y '%d', z '%d'.") % patternStr % pos.x % pos.y % pos.z;
|
||||
const auto & originalTile = originalMap->getTile(pos);
|
||||
editManager->drawTerrain(MapRect(pos, 1, 1), originalTile.terType, &gen);
|
||||
const auto & tile = map->getTile(pos);
|
||||
bool isInRange = false;
|
||||
BOOST_FOREACH(const auto & range, mapping)
|
||||
{
|
||||
if(tile.terView >= range.first && tile.terView <= range.second)
|
||||
{
|
||||
isInRange = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BOOST_CHECK(isInRange);
|
||||
if(!isInRange) logGlobal->errorStream() << "No or invalid pattern found for current position.";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(const std::exception & e)
|
||||
{
|
||||
logGlobal-> errorStream() << e.what();
|
||||
}
|
||||
}
|
37
test/CVcmiTestConfig.cpp
Normal file
37
test/CVcmiTestConfig.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
|
||||
/*
|
||||
* CVcmiTestConfig.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 "CVcmiTestConfig.h"
|
||||
|
||||
#include "../lib/CConsoleHandler.h"
|
||||
#include "../lib/logging/CBasicLogConfigurator.h"
|
||||
#include "../lib/VCMIDirs.h"
|
||||
#include "../lib/VCMI_Lib.h"
|
||||
#include "../lib/logging/CLogger.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
|
||||
CVcmiTestConfig::CVcmiTestConfig()
|
||||
{
|
||||
console = new CConsoleHandler;
|
||||
CBasicLogConfigurator logConfig(VCMIDirs::get().localPath() + "/VCMI_Test_log.txt", console);
|
||||
logConfig.configureDefault();
|
||||
preinitDLL(console);
|
||||
settings.init();
|
||||
logConfig.configure();
|
||||
loadDLLClasses();
|
||||
logGlobal->infoStream() << "Initialized global test setup.";
|
||||
}
|
||||
|
||||
CVcmiTestConfig::~CVcmiTestConfig()
|
||||
{
|
||||
std::cout << "Ending global test tear-down." << std::endl;
|
||||
}
|
20
test/CVcmiTestConfig.h
Normal file
20
test/CVcmiTestConfig.h
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
/*
|
||||
* CVcmiTestConfig.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
|
||||
|
||||
/// Global setup/tear down class for unit tests.
|
||||
class CVcmiTestConfig
|
||||
{
|
||||
public:
|
||||
CVcmiTestConfig();
|
||||
~CVcmiTestConfig();
|
||||
};
|
7
test/StdInc.cpp
Normal file
7
test/StdInc.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
// Creates the precompiled header
|
||||
#include "StdInc.h"
|
||||
|
||||
#define BOOST_TEST_MODULE VcmiTest
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include "CVcmiTestConfig.h"
|
||||
BOOST_GLOBAL_FIXTURE(CVcmiTestConfig);
|
8
test/StdInc.h
Normal file
8
test/StdInc.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Global.h"
|
||||
|
||||
#define BOOST_TEST_DYN_LINK
|
||||
|
||||
|
||||
|
BIN
test/TerrainViewTest.h3m
Normal file
BIN
test/TerrainViewTest.h3m
Normal file
Binary file not shown.
161
test/terrainViewMappings.json
Normal file
161
test/terrainViewMappings.json
Normal file
@ -0,0 +1,161 @@
|
||||
{
|
||||
"mappings" : [
|
||||
// Normal type
|
||||
{
|
||||
"pos" : [ [ 14,13,0 ], [ 4,34,0 ] ],
|
||||
"pattern" : "normal.s1"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 14,15,0 ], [ 29,19,0 ] ],
|
||||
"pattern" : "normal.s2"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 16,13,0 ], [ 23,30,0 ] ],
|
||||
"pattern" : "normal.s3"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 16,14,0 ], [ 29,20,0 ] ],
|
||||
"pattern" : "normal.s4"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 5,14,0 ], [ 31,13,0 ] ],
|
||||
"pattern" : "normal.s5"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 9,17,0 ], [ 3,17,0 ] ],
|
||||
"pattern" : "normal.s6"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 21,20,1 ], [ 28,27,1 ] ],
|
||||
"pattern" : "normal.m1"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 22,22,1 ] ],
|
||||
"pattern" : "normal.m2"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 12,31,0 ] ],
|
||||
"pattern" : "normal.m3"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 5,34,0 ] ],
|
||||
"pattern" : "normal.m4"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 12,34,0 ] ],
|
||||
"pattern" : "normal.m5"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 8,25,0 ] ],
|
||||
"pattern" : "normal.m6"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 5,32,0 ] ],
|
||||
"pattern" : "normal.m7"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 28,23,1 ] ],
|
||||
"pattern" : "normal.m8"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 7,23,0 ] ],
|
||||
"pattern" : "normal.n1"
|
||||
},
|
||||
// Dirt type
|
||||
{
|
||||
"pos" : [ [ 22,26,0 ], [ 27,35,0 ] ],
|
||||
"pattern" : "dirt.s1"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 15,33,0 ], [ 19,34,0 ] ],
|
||||
"pattern" : "dirt.s2"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 24,32,0 ], [ 25,26,0 ] ],
|
||||
"pattern" : "dirt.s3"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 19,32,0 ] ],
|
||||
"pattern" : "dirt.s4"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 26,28,1 ] ],
|
||||
"pattern" : "dirt.s5"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 25,28,1 ] ],
|
||||
"pattern" : "dirt.s6"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 9,25,1 ] ],
|
||||
"pattern" : "dirt.m1"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 20,27,1 ] ],
|
||||
"pattern" : "dirt.n1"
|
||||
},
|
||||
// Sand type
|
||||
{
|
||||
"pos" : [ [ 22,27,1 ] ],
|
||||
"pattern" : "sand.n1"
|
||||
},
|
||||
// Water type
|
||||
{
|
||||
"pos" : [ [ 16,17,0 ] ],
|
||||
"pattern" : "water.s1"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 20,15,0 ] ],
|
||||
"pattern" : "water.s2"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 23,18,0 ] ],
|
||||
"pattern" : "water.s3"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 20,11,0 ] ],
|
||||
"pattern" : "water.s4"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 8,14,0 ] ],
|
||||
"pattern" : "water.s5"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 8,13,0 ] ],
|
||||
"pattern" : "water.s6"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 9,13,0 ] ],
|
||||
"pattern" : "water.n1"
|
||||
},
|
||||
// Rock type
|
||||
{
|
||||
"pos" : [ [ 13,12,1 ] ],
|
||||
"pattern" : "rock.n1"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 11,21,1 ] ],
|
||||
"pattern" : "rock.s1"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 8,21,1 ] ],
|
||||
"pattern" : "rock.s2"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 10,12,1 ] ],
|
||||
"pattern" : "rock.s3"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 13,21,1 ] ],
|
||||
"pattern" : "rock.s4"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 10,22,1 ] ],
|
||||
"pattern" : "rock.s5"
|
||||
},
|
||||
{
|
||||
"pos" : [ [ 8,23,1 ] ],
|
||||
"pattern" : "rock.s6"
|
||||
},
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user