From 9b58450cb00d3bcd8e5dd35dd44d873bb5ef5356 Mon Sep 17 00:00:00 2001 From: DjWarmonger Date: Fri, 12 Aug 2016 19:16:21 +0200 Subject: [PATCH] Part 3 - first working draft, cut generation time by half. --- lib/mapping/CMapEditManager.cpp | 117 +++++++++++++++++++------------- lib/mapping/CMapEditManager.h | 21 +++--- 2 files changed, 82 insertions(+), 56 deletions(-) diff --git a/lib/mapping/CMapEditManager.cpp b/lib/mapping/CMapEditManager.cpp index f92455eff..acac503e6 100644 --- a/lib/mapping/CMapEditManager.cpp +++ b/lib/mapping/CMapEditManager.cpp @@ -413,12 +413,25 @@ CTerrainViewPatternConfig::CTerrainViewPatternConfig() // Add pattern to the patterns map const auto & terGroup = getTerrainGroup(mappingPair.first); - terrainViewPatterns[terGroup].push_back(terGroupPattern); + std::vector terrainViewPatternFlips; + terrainViewPatternFlips.push_back(terGroupPattern); + + for (int i = 1; i < 4; ++i) + { + flipPattern(pattern, i); //flip original by 90 degrees and push back copy + terrainViewPatternFlips.push_back(pattern); + } + terrainViewPatterns[terGroup].push_back(terrainViewPatternFlips); } } else if(i == 1) { - terrainTypePatterns[pattern.id] = pattern; + terrainTypePatterns[pattern.id].push_back(pattern); + for (int i = 1; i < 4; ++i) + { + flipPattern(pattern, i); //flip original by 90 degrees and push back copy + terrainTypePatterns[pattern.id].push_back(pattern); + } } } } @@ -444,16 +457,17 @@ ETerrainGroup::ETerrainGroup CTerrainViewPatternConfig::getTerrainGroup(const st return it->second; } -const std::vector & CTerrainViewPatternConfig::getTerrainViewPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const +const std::vector> & CTerrainViewPatternConfig::getTerrainViewPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const { return terrainViewPatterns.find(terGroup)->second; } boost::optional CTerrainViewPatternConfig::getTerrainViewPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const { - const std::vector & groupPatterns = getTerrainViewPatternsForGroup(terGroup); - for(const TerrainViewPattern & pattern : groupPatterns) + const std::vector> & groupPatterns = getTerrainViewPatternsForGroup(terGroup); + for (const std::vector & patternFlips : groupPatterns) { + const TerrainViewPattern & pattern = patternFlips.front(); if(id == pattern.id) { return boost::optional(pattern); @@ -461,14 +475,54 @@ boost::optional CTerrainViewPatternConfig::getTerrai } return boost::optional(); } +boost::optional &> CTerrainViewPatternConfig::getTerrainViewPatternsById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const +{ + const std::vector> & groupPatterns = getTerrainViewPatternsForGroup(terGroup); + for (const std::vector & patternFlips : groupPatterns) + { + const TerrainViewPattern & pattern = patternFlips.front(); + if (id == pattern.id) + { + return boost::optional &>(patternFlips); + } + } + return boost::optional &>(); +} -const TerrainViewPattern & CTerrainViewPatternConfig::getTerrainTypePatternById(const std::string & id) const + +const std::vector * CTerrainViewPatternConfig::getTerrainTypePatternById(const std::string & id) const { auto it = terrainTypePatterns.find(id); assert(it != terrainTypePatterns.end()); - return it->second; + return &(it->second); } +void CTerrainViewPatternConfig::flipPattern(TerrainViewPattern & pattern, int flip) const +{ + //flip in place to avoid expensive constructor. Seriously. + + if (flip == 0) + { + return; + } + + //always flip horizontal + for (int i = 0; i < 3; ++i) + { + int y = i * 3; + std::swap(pattern.data[y], pattern.data[y + 2]); + } + //flip vertical only at 2nd step + if (flip == CMapOperation::FLIP_PATTERN_VERTICAL) + { + for (int i = 0; i < 3; ++i) + { + std::swap(pattern.data[i], pattern.data[6 + i]); + } + } +} + + CDrawTerrainOperation::CDrawTerrainOperation(CMap * map, const CTerrainSelection & terrainSel, ETerrainType terType, CRandomGenerator * gen) : CMapOperation(map), terrainSel(terrainSel), terType(terType), gen(gen) { @@ -643,8 +697,7 @@ void CDrawTerrainOperation::updateTerrainViews() { for(const auto & pos : invalidatedTerViews) { - const auto & patterns = - VLC->terviewh->getTerrainViewPatternsForGroup(getTerrainGroup(map->getTile(pos).terType)); + const auto & patterns = VLC->terviewh->getTerrainViewPatternsForGroup(getTerrainGroup(map->getTile(pos).terType)); // Detect a pattern which fits best int bestPattern = -1; @@ -652,7 +705,8 @@ void CDrawTerrainOperation::updateTerrainViews() for(int k = 0; k < patterns.size(); ++k) { const auto & pattern = patterns[k]; - valRslt = validateTerrainView(pos, pattern); + //(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) + valRslt = validateTerrainView(pos, &pattern); if(valRslt.result) { /*logGlobal->debugStream() << boost::format("Pattern detected at pos '%s': Pattern '%s', Flip '%i', Repl. '%s'.") % @@ -671,7 +725,7 @@ void CDrawTerrainOperation::updateTerrainViews() } // Get mapping - const TerrainViewPattern & pattern = patterns[bestPattern]; + const TerrainViewPattern & pattern = patterns[bestPattern].front(); std::pair mapping; if(valRslt.transitionReplacement.empty()) { @@ -717,16 +771,11 @@ ETerrainGroup::ETerrainGroup CDrawTerrainOperation::getTerrainGroup(ETerrainType } } -CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainView(const int3 & pos, const TerrainViewPattern & pattern, int recDepth /*= 0*/) const +CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainView(const int3 & pos, const std::vector * pattern, int recDepth /*= 0*/) const { - //constructor for pattern object is very expensive, but we can't manipulate const object :( - - auto flippedPattern = pattern; //TODO: store cached patterns in 4 positions to avoid very expensive construction for(int flip = 0; flip < 4; ++flip) { - if (flip > 0) - flipPattern (flippedPattern, flip); - auto valRslt = validateTerrainViewInner(pos, flippedPattern, recDepth); + auto valRslt = validateTerrainViewInner(pos, pattern->at(flip), recDepth); if(valRslt.result) { valRslt.flip = flip; @@ -806,10 +855,11 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi { if(terType == centerTerType) { - const auto & patternForRule = VLC->terviewh->getTerrainViewPatternById(getTerrainGroup(centerTerType), rule.name); - if(patternForRule) + const auto & group = getTerrainGroup(centerTerType); + const auto & patternForRule = VLC->terviewh->getTerrainViewPatternsById(group, rule.name); + if(auto p = patternForRule) { - auto rslt = validateTerrainView(currentPos, *patternForRule, 1); + auto rslt = validateTerrainView(currentPos, &(*p), 1); if(rslt.result) topPoints = std::max(topPoints, rule.points); } } @@ -906,31 +956,6 @@ bool CDrawTerrainOperation::isSandType(ETerrainType terType) const } } -void CDrawTerrainOperation::flipPattern(TerrainViewPattern & pattern, int flip) const -{ - //flip in place to avoid expensive constructor. Seriously. - - if(flip == 0) - { - return; - } - - //always flip horizontal - for(int i = 0; i < 3; ++i) - { - int y = i * 3; - std::swap(pattern.data[y], pattern.data[y + 2]); - } - //flip vertical only at 2nd step - if(flip == FLIP_PATTERN_VERTICAL) - { - for(int i = 0; i < 3; ++i) - { - std::swap(pattern.data[i], pattern.data[6 + i]); - } - } -} - void CDrawTerrainOperation::invalidateTerrainViews(const int3 & centerPos) { auto rect = extendTileAroundSafely(centerPos); diff --git a/lib/mapping/CMapEditManager.h b/lib/mapping/CMapEditManager.h index 039d35ee2..0c25e1f72 100644 --- a/lib/mapping/CMapEditManager.h +++ b/lib/mapping/CMapEditManager.h @@ -115,14 +115,14 @@ public: virtual void redo() = 0; virtual std::string getLabel() const = 0; /// Returns a display-able name of the operation. + static const int FLIP_PATTERN_HORIZONTAL = 1; + static const int FLIP_PATTERN_VERTICAL = 2; + static const int FLIP_PATTERN_BOTH = 3; + protected: MapRect extendTileAround(const int3 & centerPos) const; MapRect extendTileAroundSafely(const int3 & centerPos) const; /// doesn't exceed map size - static const int FLIP_PATTERN_HORIZONTAL = 1; - static const int FLIP_PATTERN_VERTICAL = 2; - static const int FLIP_PATTERN_BOTH = 3; - CMap * map; }; @@ -336,14 +336,16 @@ public: CTerrainViewPatternConfig(); ~CTerrainViewPatternConfig(); - const std::vector & getTerrainViewPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const; + const std::vector> & getTerrainViewPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const; boost::optional getTerrainViewPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const; - const TerrainViewPattern & getTerrainTypePatternById(const std::string & id) const; + boost::optional &> getTerrainViewPatternsById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const; + const std::vector * getTerrainTypePatternById(const std::string & id) const; ETerrainGroup::ETerrainGroup getTerrainGroup(const std::string & terGroup) const; + void flipPattern(TerrainViewPattern & pattern, int flip) const; private: - std::map > terrainViewPatterns; - std::map terrainTypePatterns; + std::map > > terrainViewPatterns; + std::map> terrainTypePatterns; }; /// The CDrawTerrainOperation class draws a terrain area on the map. @@ -384,11 +386,10 @@ private: ETerrainGroup::ETerrainGroup getTerrainGroup(ETerrainType terType) const; /// 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 validateTerrainView(const int3 & pos, const std::vector * 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; - void flipPattern(TerrainViewPattern & pattern, int flip) const; CTerrainSelection terrainSel; ETerrainType terType;