/* * 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 org.terasology.math.Region3i; import org.terasology.math.TeraMath; import org.terasology.math.geom.BaseVector2i; import org.terasology.math.geom.ImmutableVector2i; import org.terasology.math.geom.Rect2i; import org.terasology.world.generation.Facet; import org.terasology.world.generation.FacetProvider; import org.terasology.world.generation.GeneratingRegion; import org.terasology.world.generation.Updates; import org.terasology.world.generation.facets.SurfaceHeightFacet; import com.google.common.base.Preconditions; /** * Flattens the surface in a circular area around a given coordinate. * The area outside this area will be adjusted up to a certain radius to generate a smooth embedding. * <pre> * inner rad. * __________ * / \ * / \ * ~~~~~ outer rad. ~~~~~ * </pre> */ @Updates(@Facet(SurfaceHeightFacet.class)) public class PlateauProvider implements FacetProvider { private final ImmutableVector2i centerPos; private final float targetHeight; private final float innerRadius; private final float outerRadius; /** * @param center the center of the circle-shaped plateau * @param targetHeight the height level of the plateau * @param innerRadius the radius of the flat plateau * @param outerRadius the radius of the affected (smoothened) area */ public PlateauProvider(BaseVector2i center, float targetHeight, float innerRadius, float outerRadius) { Preconditions.checkArgument(innerRadius >= 0, "innerRadius must be >= 0"); Preconditions.checkArgument(outerRadius > innerRadius, "outerRadius must be larger than innerRadius"); this.centerPos = ImmutableVector2i.createOrUse(center); this.targetHeight = targetHeight; this.innerRadius = innerRadius; this.outerRadius = outerRadius; } @Override public void process(GeneratingRegion region) { Region3i reg = region.getRegion(); Rect2i rc = Rect2i.createFromMinAndMax(reg.minX(), reg.minZ(), reg.maxX(), reg.maxZ()); if (rc.distanceSquared(centerPos.x(), centerPos.y()) <= outerRadius * outerRadius) { SurfaceHeightFacet facet = region.getRegionFacet(SurfaceHeightFacet.class); // update the surface height for (BaseVector2i pos : facet.getWorldRegion().contents()) { float originalValue = facet.getWorld(pos); int distSq = pos.distanceSquared(centerPos); if (distSq <= innerRadius * innerRadius) { facet.setWorld(pos, targetHeight); } else if (distSq <= outerRadius * outerRadius) { double dist = pos.distance(centerPos) - innerRadius; float norm = (float) dist / (outerRadius - innerRadius); facet.setWorld(pos, TeraMath.lerp(targetHeight, originalValue, norm)); } } } } }