/*
* Copyright 2014 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.core.world.generator.facetProviders;
import java.util.List;
import org.terasology.core.world.CoreBiome;
import org.terasology.core.world.generator.facets.BiomeFacet;
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.rendering.nui.properties.Range;
import org.terasology.utilities.procedural.Noise;
import org.terasology.utilities.procedural.WhiteNoise;
import org.terasology.world.biomes.Biome;
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 = 13)),
@Facet(value = SurfaceHeightFacet.class, border = @FacetBorder(sides = 13 + 1)),
@Facet(value = BiomeFacet.class, border = @FacetBorder(sides = 13))
})
public class DefaultTreeProvider extends SurfaceObjectProvider<Biome, TreeGenerator> implements ConfigurableFacetProvider {
private Noise densityNoiseGen;
private Configuration configuration = new Configuration();
public DefaultTreeProvider() {
register(CoreBiome.MOUNTAINS, Trees.oakTree(), 0.04f);
register(CoreBiome.MOUNTAINS, Trees.pineTree(), 0.02f);
register(CoreBiome.FOREST, Trees.oakTree(), 0.25f);
register(CoreBiome.FOREST, Trees.pineTree(), 0.10f);
register(CoreBiome.FOREST, Trees.birchTree(), 0.10f);
register(CoreBiome.FOREST, Trees.oakVariationTree(), 0.25f);
register(CoreBiome.SNOW, Trees.birchTree(), 0.02f);
register(CoreBiome.SNOW, Trees.pineTree(), 0.10f);
register(CoreBiome.PLAINS, Trees.redTree(), 0.01f);
register(CoreBiome.PLAINS, Trees.birchTree(), 0.01f);
register(CoreBiome.PLAINS, Trees.oakTree(), 0.02f);
register(CoreBiome.DESERT, Trees.cactus(), 0.04f);
}
/**
* @param configuration the default configuration to use
*/
public DefaultTreeProvider(Configuration configuration) {
this();
this.configuration = configuration;
}
@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);
BiomeFacet biome = region.getRegionFacet(BiomeFacet.class);
List<Predicate<Vector3i>> filters = getFilters(region);
// these value are derived from the maximum tree extents as
// computed by the TreeTests class. Birch is the highest with 32
// and Pine has 13 radius.
// These values must be identical in the class annotations.
int maxRad = 13;
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);
}
protected List<Predicate<Vector3i>> getFilters(GeneratingRegion region) {
List<Predicate<Vector3i>> filters = Lists.newArrayList();
SeaLevelFacet seaLevel = region.getRegionFacet(SeaLevelFacet.class);
filters.add(PositionFilters.minHeight(seaLevel.getSeaLevel()));
filters.add(PositionFilters.probability(densityNoiseGen, configuration.density * 0.05f));
SurfaceHeightFacet surface = region.getRegionFacet(SurfaceHeightFacet.class);
filters.add(PositionFilters.flatness(surface, 1, 0));
return filters;
}
@Override
public String getConfigurationName() {
return "Trees";
}
@Override
public Component getConfiguration() {
return configuration;
}
@Override
public void setConfiguration(Component configuration) {
this.configuration = (Configuration) configuration;
}
public static class Configuration implements Component {
@Range(min = 0, max = 1.0f, increment = 0.05f, precision = 2, description = "Define the overall tree density")
public float density = 0.2f;
}
}