/*
* Copyright 2015 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.terasology.polyworld.flora;
import java.util.List;
import org.terasology.core.world.generator.facetProviders.PositionFilters;
import org.terasology.core.world.generator.facetProviders.SurfaceObjectProvider;
import org.terasology.core.world.generator.facets.TreeFacet;
import org.terasology.core.world.generator.trees.TreeGenerator;
import org.terasology.core.world.generator.trees.Trees;
import org.terasology.entitySystem.Component;
import org.terasology.math.geom.Vector3i;
import org.terasology.polyworld.biome.WhittakerBiome;
import org.terasology.polyworld.biome.WhittakerBiomeFacet;
import org.terasology.rendering.nui.properties.Range;
import org.terasology.utilities.procedural.Noise;
import org.terasology.utilities.procedural.WhiteNoise;
import org.terasology.world.generation.Border3D;
import org.terasology.world.generation.ConfigurableFacetProvider;
import org.terasology.world.generation.Facet;
import org.terasology.world.generation.FacetBorder;
import org.terasology.world.generation.GeneratingRegion;
import org.terasology.world.generation.Produces;
import org.terasology.world.generation.Requires;
import org.terasology.world.generation.facets.SeaLevelFacet;
import org.terasology.world.generation.facets.SurfaceHeightFacet;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
/**
* Determines where trees can be placed. Will put trees one block above the surface.
*/
@Produces(TreeFacet.class)
@Requires({
@Facet(value = SeaLevelFacet.class, border = @FacetBorder(sides = 12)),
@Facet(value = SurfaceHeightFacet.class, border = @FacetBorder(sides = 12 + 1)),
@Facet(value = WhittakerBiomeFacet.class, border = @FacetBorder(sides = 12))
})
public class TreeProvider extends SurfaceObjectProvider<WhittakerBiome, TreeGenerator> implements ConfigurableFacetProvider {
private Noise densityNoiseGen;
private TreeProviderConfiguration configuration = new TreeProviderConfiguration();
public TreeProvider() {
register(WhittakerBiome.TEMPERATE_RAIN_FOREST, Trees.oakTree(), 0.05f);
register(WhittakerBiome.TEMPERATE_RAIN_FOREST, Trees.pineTree(), 0.03f);
register(WhittakerBiome.TEMPERATE_RAIN_FOREST, Trees.redTree(), 0.05f);
register(WhittakerBiome.TEMPERATE_DECIDUOUS_FOREST, Trees.pineTree(), 0.08f);
register(WhittakerBiome.TEMPERATE_DECIDUOUS_FOREST, Trees.redTree(), 0.05f);
register(WhittakerBiome.TROPICAL_RAIN_FOREST, Trees.pineTree(), 0.07f);
register(WhittakerBiome.TROPICAL_RAIN_FOREST, Trees.redTree(), 0.08f);
register(WhittakerBiome.TROPICAL_SEASONAL_FOREST, Trees.oakVariationTree(), 0.15f);
register(WhittakerBiome.LAKESHORE, Trees.oakTree(), 0.15f);
register(WhittakerBiome.LAKESHORE, Trees.redTree(), 0.1f);
register(WhittakerBiome.SHRUBLAND, Trees.birchTree(), 0.02f);
register(WhittakerBiome.TAIGA, Trees.pineTree(), 0.08f);
register(WhittakerBiome.TUNDRA, Trees.birchTree(), 0.01f);
register(WhittakerBiome.TUNDRA, Trees.pineTree(), 0.01f);
register(WhittakerBiome.GRASSLAND, Trees.oakTree(), 0.03f);
register(WhittakerBiome.SUBTROPICAL_DESERT, Trees.cactus(), 0.02f);
register(WhittakerBiome.TEMPERATE_DESERT, Trees.cactus(), 0.04f);
}
@Override
public void setSeed(long seed) {
super.setSeed(seed);
densityNoiseGen = new WhiteNoise(seed);
}
@Override
public void process(GeneratingRegion region) {
SurfaceHeightFacet surface = region.getRegionFacet(SurfaceHeightFacet.class);
WhittakerBiomeFacet biome = region.getRegionFacet(WhittakerBiomeFacet.class);
SeaLevelFacet seaLevel = region.getRegionFacet(SeaLevelFacet.class);
List<Predicate<Vector3i>> filters = Lists.newArrayList();
filters.add(PositionFilters.minHeight(seaLevel.getSeaLevel()));
filters.add(PositionFilters.probability(densityNoiseGen, configuration.density * 0.1f));
filters.add(PositionFilters.flatness(surface, 1, 1));
int maxRad = 12;
int maxHeight = 32;
Border3D borderForTreeFacet = region.getBorderForFacet(TreeFacet.class);
TreeFacet facet = new TreeFacet(region.getRegion(), borderForTreeFacet.extendBy(0, maxHeight, maxRad));
populateFacet(facet, surface, biome, filters);
region.setRegionFacet(TreeFacet.class, facet);
}
@Override
public String getConfigurationName() {
return "Trees";
}
@Override
public Component getConfiguration() {
return configuration;
}
@Override
public void setConfiguration(Component configuration) {
this.configuration = (TreeProviderConfiguration) configuration;
}
private static class TreeProviderConfiguration implements Component {
@Range(min = 0, max = 1.0f, increment = 0.05f, precision = 2, description = "Define the overall tree density")
private float density = 0.4f;
}
}