/* * 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.world.viewer.layers; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DataBufferInt; import java.math.RoundingMode; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; import org.terasology.math.TeraMath; import org.terasology.rendering.nui.Color; import org.terasology.rendering.nui.properties.Range; import org.terasology.world.generation.Region; import org.terasology.world.generation.facets.base.FieldFacet2D; import org.terasology.world.viewer.color.ColorBlender; import org.terasology.world.viewer.color.ColorBlenders; import org.terasology.world.viewer.color.ColorModels; import com.google.common.base.Preconditions; import com.google.common.math.DoubleMath; /** * Provides info about an {@link FieldFacet2D}. */ public abstract class FieldFacetLayer extends AbstractFacetLayer { private static final List<Color> GRAYS = IntStream .range(0, 256) .mapToObj(i -> new Color(i, i, i)) .collect(Collectors.toList()); private final Class<? extends FieldFacet2D> clazz; private Config config = new Config(); /** * @param clazz the target FieldFacet2D class * @param config the layer configuration info */ public FieldFacetLayer(Class<? extends FieldFacet2D> clazz, Config config) { Preconditions.checkArgument(clazz != null, "clazz must not be null"); Preconditions.checkArgument(config != null, "config must not be null"); this.clazz = clazz; this.config = config; } public FieldFacetLayer(Class<? extends FieldFacet2D> clazz, double offset, double scale) { Preconditions.checkArgument(clazz != null, "clazz must not be null"); this.clazz = clazz; this.config.offset = offset; this.config.scale = scale; } @Override public String getWorldText(Region region, int wx, int wy) { FieldFacet2D facet = region.getFacet(clazz); double value = facet.getWorld(wx, wy); return String.format("%.2f", value); } @Override public void render(BufferedImage img, Region region) { FieldFacet2D facet = region.getFacet(clazz); int width = img.getWidth(); int height = img.getHeight(); ColorModel colorModel = img.getColorModel(); ColorBlender blender = ColorBlenders.forColorModel(ColorModels.RGBA, colorModel); DataBufferInt dataBuffer = (DataBufferInt) img.getRaster().getDataBuffer(); for (int z = 0; z < height; z++) { for (int x = 0; x < width; x++) { Color col = getColor(facet, x, z); int src = col.rgba(); int dst = dataBuffer.getElem(z * width + x); int mix = blender.add(src, dst); dataBuffer.setElem(z * width + x, mix); } } } /** * Computes the color of the facet at a given world coordinate. * @param facet the underlying facet * @param x the world x coordinate * @param z the world z coordinate * @return the color at the given world coords. Never <code>null</code>. */ protected Color getColor(FieldFacet2D facet, int x, int z) { double value = facet.get(x, z); if (Double.isFinite(value)) { int round = DoubleMath.roundToInt(config.offset + config.scale * value, RoundingMode.HALF_UP); int idx = TeraMath.clamp(round, 0, 255); return GRAYS.get(idx); } else { return MISSING; } } public double getOffset() { return config.offset; } public double getScale() { return config.scale; } /** * @param scale the new scale factor */ public void setScale(double scale) { if (scale != config.scale) { config.scale = scale; notifyObservers(); } } /** * @param offset the new offset */ public void setOffset(double offset) { if (offset != config.offset) { config.offset = offset; notifyObservers(); } } @Override public FacetLayerConfig getConfig() { return config; } /** * Persistent data */ protected static class Config implements FacetLayerConfig { @Range(min = -100, max = 100, increment = 1f, precision = 1) private double offset; @Range(min = 0, max = 100, increment = 0.1f, precision = 1) private double scale; } }