| 624 | } |
| 625 | |
| 626 | WorldTemplate::BlockInfo WorldTemplate::getBlockInfo(uint32_t x, uint32_t y) const { |
| 627 | return m_blockCache.get(Vector<uint32_t, 2>(x, y), [this, x, y](Vector<uint32_t, 2>) { |
| 628 | BlockInfo blockInfo; |
| 629 | |
| 630 | if (!m_layout) |
| 631 | return blockInfo; |
| 632 | |
| 633 | // The environment biome is calculated with weighting based on the flat coordinates. |
| 634 | List<WorldLayout::RegionWeighting> flatWeighting = m_layout->getWeighting(x, y); |
| 635 | |
| 636 | // The block biome is calculated optionally with higher frequency noise |
| 637 | // added to prevent straight lines appearing on the boundaries of |
| 638 | // regions. |
| 639 | |
| 640 | int blendNoiseOffset = 0; |
| 641 | if (auto const& blendNoise = m_layout->blendNoise()) |
| 642 | blendNoiseOffset = (int)blendNoise->get(x, y); |
| 643 | |
| 644 | Vec2I blockPos; |
| 645 | List<WorldLayout::RegionWeighting> blockWeighting; |
| 646 | List<WorldLayout::RegionWeighting> transitionWeighting; |
| 647 | if (auto const& blockNoise = m_layout->blockNoise()) { |
| 648 | blockPos = blockNoise->apply(Vec2I(x, y), m_geometry.size()); |
| 649 | blockWeighting = m_layout->getWeighting(blockPos[0] + blendNoiseOffset, blockPos[1]); |
| 650 | transitionWeighting = m_layout->getWeighting(blockPos[0], blockPos[1]); |
| 651 | } else { |
| 652 | blockPos = Vec2I(x, y); |
| 653 | blockWeighting = flatWeighting; |
| 654 | transitionWeighting = flatWeighting; |
| 655 | } |
| 656 | |
| 657 | if (flatWeighting.empty() || blockWeighting.empty()) |
| 658 | return blockInfo; |
| 659 | |
| 660 | auto const& primaryFlatWeighting = flatWeighting.first(); |
| 661 | auto const& primaryBlockWeighting = blockWeighting.first(); |
| 662 | |
| 663 | blockInfo.blockBiomeIndex = primaryBlockWeighting.region->blockBiomeIndex; |
| 664 | blockInfo.environmentBiomeIndex = primaryFlatWeighting.region->environmentBiomeIndex; |
| 665 | |
| 666 | blockInfo.biomeTransition = transitionWeighting.first().weight < m_templateConfig.getFloat("biomeTransitionThreshold", 0); |
| 667 | |
| 668 | float terrainSelect = 0.0f; |
| 669 | float foregroundCaveSelect = 0.0f; |
| 670 | float backgroundCaveSelect = 0.0f; |
| 671 | |
| 672 | // Terrain weighting uses the flat weighting, and weights each selector |
| 673 | // to blend among them. |
| 674 | for (auto const& weighting : flatWeighting) { |
| 675 | if (weighting.region->terrainSelectorIndex != NullTerrainSelectorIndex) { |
| 676 | auto const& terrainSelector = m_layout->getTerrainSelector(weighting.region->terrainSelectorIndex); |
| 677 | float select = terrainSelector->get(weighting.xValue, y) * weighting.weight; |
| 678 | terrainSelect += select; |
| 679 | } |
| 680 | } |
| 681 | |
| 682 | // This is a bit of a cheat. Since customTerrainWeighting is always flat, |
| 683 | // there are some odd effects that come from linearly interpolating from |