Browse Source

- Fixed a few bugs related to the terrain view generation - Updated CMakeLists in /test(copy resources if no source files has been changed too)

beegee1 12 năm trước cách đây
mục cha
commit
23f7be2a54

+ 27 - 21
config/terrainViewPatterns.json

@@ -48,30 +48,33 @@
 			"id" : "s1",
 			"data" :
 			[
-				"?", "?", "T",
-				"?", "N", "N",
+				"T,N-1", "T,N-2", "T,N-3",
+				"T,N-2", "N", "N",
 				"T", "N", "N"
 			],
+			"maxPoints" : 3,
 			"mapping" : "0-3, 20-23"
 		},
 		{
 			"id" : "s2",
 			"data" :
 			[
-				"?", "N", "N",
-				"T", "N", "N",
-				"?", "N", "N"
+				"D-1,S-2,N", "N", "N",
+				"T,D-2", "N", "N",
+				"D-1,S-2,N", "N", "N"
 			],
+			"maxPoints" : 4,
 			"mapping" : "4-7, 24-27"
 		},
 		{
 			"id" : "s3",
 			"data" :
 			[
-				"?", "T", "?",
+				"D-1,S-2,N", "T,D-2", "D-1,S-2,N",
 				"N", "N", "N",
 				"N", "N", "N"
 			],
+			"maxPoints" : 4,
 			"mapping" : "8-11, 28-31"
 		},
 		{
@@ -79,18 +82,19 @@
 			"data" :
 			[
 				"N", "N", "N",
-				"N", "N", "N",
-				"N", "N", "T"
+				"N", "N", "s3-1",
+				"N", "s2-1", "T"
 			],
-			"mapping" : "12-15, 32-35"
+			"mapping" : "12-15, 32-35",
+			"minPoints" : 2
 		},
 		{
 			"id" : "s5",
 			"data" :
 			[
-				"T", "T", "s5-1,?",
-				"T", "N", "N",
-				"s5-1,?", "N", "N"
+				"T", "T", "?",
+				"T", "N", "s6-1,m1-1,m2-1,N",
+				"?", "s6-1,m1-1,m2-1,N", "N"
 			],
 			"mapping" : "16-17, 36-37",
 			"minPoints" : 1
@@ -133,7 +137,7 @@
 			[
 				"N", "N", "D,N",
 				"N", "N", "D",
-				"S", "D", "D,N"
+				"S", "D,N", "D,N"
 			],
 			"mapping" : "43"
 		},
@@ -151,7 +155,7 @@
 			"id" : "m5",
 			"data" :
 			[
-				"N", "N", "D,N",
+				"N", "N", "D",
 				"N", "N", "D",
 				"N", "N", "S"
 			],
@@ -171,10 +175,11 @@
 			"id" : "m7",
 			"data" :
 			[
-				"N", "N", "D,S,N",
+				"N", "N", "?",
 				"N", "N", "S",
-				"D", "D", "D,S,N"
+				"D-1,N", "D-1,N", "?"
 			],
+			"minPoints" : 1,
 			"mapping" : "47"
 		},
 		{
@@ -183,7 +188,7 @@
 			[
 				"N", "N", "D",
 				"N", "N", "D",
-				"D,S,N", "S", "D,S,N"
+				"?", "S", "?"
 			],
 			"mapping" : "48"
 		},
@@ -237,8 +242,8 @@
 			"data" :
 			[
 				"D", "D", "D",
-				"D", "N", "N",
-				"D", "N", "S"
+				"D", "N", "?",
+				"D", "?", "S"
 			],
 			"mapping" : "12-15"
 		},
@@ -347,11 +352,12 @@
 			"id" : "s5",
 			"data" :
 			[
-				"S", "S", "N",
+				"S", "S", "N,S-1",
 				"S", "N", "N",
-				"N", "N", "N"
+				"N,S-1", "N", "N"
 			],
 			"mapping" : "16-17",
+			"maxPoints" : 1
 		},
 		{
 			"id" : "s6",

+ 59 - 43
lib/mapping/CMapEditManager.cpp

@@ -301,7 +301,10 @@ CTerrainViewPatternConfig::CTerrainViewPatternConfig()
 
 			// Read optional attributes
 			pattern.id = ptrnNode["id"].String();
+			assert(!pattern.id.empty());
 			pattern.minPoints = static_cast<int>(ptrnNode["minPoints"].Float());
+			pattern.maxPoints = static_cast<int>(ptrnNode["maxPoints"].Float());
+			if(pattern.maxPoints == 0) pattern.maxPoints = std::numeric_limits<int>::max();
 			pattern.flipMode = ptrnNode["flipMode"].String();
 			if(pattern.flipMode.empty())
 			{
@@ -388,65 +391,59 @@ std::string CDrawTerrainOperation::getLabel() const
 
 void CDrawTerrainOperation::updateTerrainViews(const MapRect & rect)
 {
-	for(int i = rect.x; i < rect.x + rect.width; ++i)
+	for(int x = rect.x; x < rect.x + rect.width; ++x)
 	{
-		for(int j = rect.y; j < rect.y + rect.height; ++j)
+		for(int y = rect.y; y < rect.y + rect.height; ++y)
 		{
 			const auto & patterns =
-					CTerrainViewPatternConfig::get().getPatternsForGroup(getTerrainGroup(map->getTile(int3(i, j, rect.z)).terType));
+					CTerrainViewPatternConfig::get().getPatternsForGroup(getTerrainGroup(map->getTile(int3(x, y, rect.z)).terType));
 
 			// Detect a pattern which fits best
-			int bestPattern = -1, bestFlip = -1;
-			std::string transitionReplacement;
+			int bestPattern = -1;
+			ValidationResult valRslt(false);
 			for(int k = 0; k < patterns.size(); ++k)
 			{
 				const auto & pattern = patterns[k];
-
-				for(int flip = 0; flip < 4; ++flip)
+				valRslt = validateTerrainView(int3(x, y, rect.z), pattern);
+				if(valRslt.result)
 				{
-					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.z << ": P-Nr. " << k
-							  << ", Flip " << flip << ", Repl. " << valRslt.transitionReplacement;
-
-						bestPattern = k;
-						bestFlip = flip;
-						transitionReplacement = valRslt.transitionReplacement;
-						break;
-					}
+					logGlobal->debugStream() << "Pattern detected at pos " << x << "x" << y << "x" << rect.z << ": P-Nr. " << pattern.id
+						  << ", Flip " << valRslt.flip << ", Repl. " << valRslt.transitionReplacement;
+					bestPattern = k;
+					break;
 				}
 			}
+			//assert(bestPattern != -1);
 			if(bestPattern == -1)
 			{
 				// This shouldn't be the case
-				logGlobal->warnStream() << "No pattern detected at pos " << i << "x" << j << "x" << rect.z;
+				logGlobal->warnStream() << "No pattern detected at pos " << x << "x" << y << "x" << rect.z;
 				continue;
 			}
 
 			// Get mapping
 			const TerrainViewPattern & pattern = patterns[bestPattern];
 			std::pair<int, int> mapping;
-			if(transitionReplacement.empty())
+			if(valRslt.transitionReplacement.empty())
 			{
 				mapping = pattern.mapping[0];
 			}
 			else
 			{
-				mapping = transitionReplacement == TerrainViewPattern::RULE_DIRT ? pattern.mapping[0] : pattern.mapping[1];
+				mapping = valRslt.transitionReplacement == TerrainViewPattern::RULE_DIRT ? pattern.mapping[0] : pattern.mapping[1];
 			}
 
 			// Set terrain view
-			auto & tile = map->getTile(int3(i, j, rect.z));
+			auto & tile = map->getTile(int3(x, y, rect.z));
 			if(pattern.flipMode == TerrainViewPattern::FLIP_MODE_SAME_IMAGE)
 			{
 				tile.terView = gen->getInteger(mapping.first, mapping.second);
-				tile.extTileFlags = bestFlip;
+				tile.extTileFlags = valRslt.flip;
 			}
 			else
 			{
 				const int framesPerRot = 2;
-				int firstFrame = mapping.first + bestFlip * framesPerRot;
+				int firstFrame = mapping.first + valRslt.flip * framesPerRot;
 				tile.terView = gen->getInteger(firstFrame, firstFrame + framesPerRot - 1);
 				tile.extTileFlags =	0;
 			}
@@ -472,6 +469,20 @@ ETerrainGroup::ETerrainGroup CDrawTerrainOperation::getTerrainGroup(ETerrainType
 }
 
 CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainView(const int3 & pos, const TerrainViewPattern & pattern, int recDepth /*= 0*/) const
+{
+	for(int flip = 0; flip < 4; ++flip)
+	{
+		auto valRslt = validateTerrainViewInner(pos, flip > 0 ? getFlippedPattern(pattern, flip) : pattern, recDepth);
+		if(valRslt.result)
+		{
+			valRslt.flip = flip;
+			return valRslt;
+		}
+	}
+	return ValidationResult(false);
+}
+
+CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainViewInner(const int3 & pos, const TerrainViewPattern & pattern, int recDepth /*= 0*/) const
 {
 	ETerrainType centerTerType = map->getTile(pos).terType;
 	int totalPoints = 0;
@@ -488,15 +499,16 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
 		// Get terrain group of the current cell
 		int cx = pos.x + (i % 3) - 1;
 		int cy = pos.y + (i / 3) - 1;
+		int3 currentPos(cx, cy, pos.z);
 		bool isAlien = false;
 		ETerrainType terType;
-		if(cx < 0 || cx >= map->width || cy < 0 || cy >= map->height)
+		if(!map->isInTheMap(currentPos))
 		{
 			terType = centerTerType;
 		}
 		else
 		{
-			terType = map->getTile(int3(cx, cy, pos.z)).terType;
+			terType = map->getTile(currentPos).terType;
 			if(terType != centerTerType)
 			{
 				isAlien = true;
@@ -512,17 +524,13 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
 			{
 				if(recDepth == 0)
 				{
-					const auto & patternForRule = CTerrainViewPatternConfig::get().getPatternById(pattern.terGroup, rule.name);
-					auto rslt = validateTerrainView(int3(cx, cy, pos.z), patternForRule, 1);
-					if(!rslt.result)
-					{
-						return ValidationResult(false);
-					}
-					else
+					if(map->isInTheMap(currentPos) && terType == centerTerType)
 					{
-						topPoints = std::max(topPoints, rule.points);
-						continue;
+						const auto & patternForRule = CTerrainViewPatternConfig::get().getPatternById(pattern.terGroup, rule.name);
+						auto rslt = validateTerrainView(currentPos, patternForRule, 1);
+						if(rslt.result) topPoints = std::max(topPoints, rule.points);
 					}
+					continue;
 				}
 				else
 				{
@@ -549,14 +557,20 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
 						|| rule.name == TerrainViewPattern::RULE_ANY)
 						&& isSandType(terType);
 
-				if(transitionReplacement.empty() && (rule.name == TerrainViewPattern::RULE_TRANSITION
-					|| rule.name == TerrainViewPattern::RULE_ANY) && (dirtTestOk || sandTestOk))
+				if(transitionReplacement.empty() && rule.name == TerrainViewPattern::RULE_TRANSITION
+						&& (dirtTestOk || sandTestOk))
 				{
 					transitionReplacement = dirtTestOk ? TerrainViewPattern::RULE_DIRT : TerrainViewPattern::RULE_SAND;
 				}
-				applyValidationRslt((dirtTestOk && transitionReplacement != TerrainViewPattern::RULE_SAND)
-						|| (sandTestOk && transitionReplacement != TerrainViewPattern::RULE_DIRT)
-						|| nativeTestOk);
+				if(rule.name == TerrainViewPattern::RULE_TRANSITION)
+				{
+					applyValidationRslt((dirtTestOk && transitionReplacement != TerrainViewPattern::RULE_SAND) ||
+							(sandTestOk && transitionReplacement != TerrainViewPattern::RULE_DIRT));
+				}
+				else
+				{
+					applyValidationRslt(dirtTestOk || sandTestOk || nativeTestOk);
+				}
 			}
 			else if(pattern.terGroup == ETerrainGroup::DIRT)
 			{
@@ -593,12 +607,14 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
 		}
 	}
 
-	if(pattern.minPoints > totalPoints)
+	if(totalPoints >= pattern.minPoints && totalPoints <= pattern.maxPoints)
+	{
+		return ValidationResult(true, transitionReplacement);
+	}
+	else
 	{
 		return ValidationResult(false);
 	}
-
-	return ValidationResult(true, transitionReplacement);
 }
 
 bool CDrawTerrainOperation::isSandType(ETerrainType terType) const

+ 6 - 3
lib/mapping/CMapEditManager.h

@@ -190,8 +190,8 @@ struct DLL_LINKAGE TerrainViewPattern
 	/// std::pair   -> 1st value: lower range, 2nd value: upper range
 	std::vector<std::pair<int, int> > mapping;
 
-	/// The minimum points to reach to to validate the pattern successfully.
-	int minPoints;
+	/// The minimum and maximum points to reach to validate the pattern successfully.
+	int minPoints, maxPoints;
 
 	/// Describes if flipping is required and which mapping should be used.
 	std::string flipMode;
@@ -236,12 +236,15 @@ private:
 		bool result;
 		/// The replacement of a T rule, either D or S.
 		std::string transitionReplacement;
+		int flip;
 	};
 
 	void updateTerrainViews(const MapRect & rect);
 	ETerrainGroup::ETerrainGroup getTerrainGroup(ETerrainType terType) const;
-	/// Validates the terrain view of the given position and with the given pattern.
+	/// Validates the terrain view of the given position and with the given pattern. The first method wraps the
+	/// second method to validate the terrain view with the given pattern in all four flip directions(horizontal, vertical).
 	ValidationResult validateTerrainView(const int3 & pos, const TerrainViewPattern & pattern, int recDepth = 0) const;
+	ValidationResult validateTerrainViewInner(const int3 & pos, const TerrainViewPattern & pattern, int recDepth = 0) const;
 	/// Tests whether the given terrain type is a sand type. Sand types are: Water, Sand and Rock
 	bool isSandType(ETerrainType terType) const;
 	TerrainViewPattern getFlippedPattern(const TerrainViewPattern & pattern, int flip) const;

+ 4 - 3
test/CMakeLists.txt

@@ -14,14 +14,15 @@ 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
+# Files to copy to the build directory
+add_custom_target(vcmitestFiles ALL)
 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>
+		add_custom_command(TARGET vcmitestFiles POST_BUILD
+				COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/${file}" ${CMAKE_CURRENT_BINARY_DIR}
 	)
 endforeach()

+ 1 - 1
test/terrainViewMappings.json

@@ -26,7 +26,7 @@
 			"pattern" : "normal.s6"
 		},
 		{
-			"pos" : [ [ 21,20,1 ], [ 28,27,1 ] ],
+			"pos" : [ [ 21,20,1 ], [ 28,27,0 ] ],
 			"pattern" : "normal.m1"
 		},
 		{