/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.pepsoft.worldpainter.panels; import org.pepsoft.minecraft.Constants; import org.pepsoft.worldpainter.Dimension; import org.pepsoft.worldpainter.Terrain; import org.pepsoft.worldpainter.layers.Annotations; import org.pepsoft.worldpainter.layers.Biome; import org.pepsoft.worldpainter.layers.FloodWithLava; import org.pepsoft.worldpainter.layers.Layer; import org.pepsoft.worldpainter.operations.Filter; import org.pepsoft.worldpainter.selection.SelectionBlock; import org.pepsoft.worldpainter.selection.SelectionChunk; import static org.pepsoft.worldpainter.layers.Layer.DataSize.*; /** * * @author pepijn */ public final class DefaultFilter implements Filter { public DefaultFilter(Dimension dimension, boolean inSelection, boolean outsideSelection, int aboveLevel, int belowLevel, boolean feather, Object onlyOn, Object exceptOn, int aboveDegrees, boolean slopeIsAbove) { this.dimension = dimension; this.inSelection = inSelection; this.outsideSelection = outsideSelection; if (inSelection && outsideSelection) { throw new IllegalArgumentException("inSelection and outsideSelection are mutually exclusive"); } this.aboveLevel = aboveLevel; this.belowLevel = belowLevel; if (aboveLevel >= 0) { checkLevel = true; if (belowLevel >= 0) { // Above and below are checked if (belowLevel >= aboveLevel) { levelType = LevelType.BETWEEN; } else { levelType = LevelType.OUTSIDE; } } else { // Only above checked levelType = LevelType.ABOVE; } } else if (belowLevel >= 0) { // Only below checked checkLevel = true; levelType = LevelType.BELOW; } else { // Neither checked checkLevel = false; levelType = null; } this.feather = feather; if (onlyOn instanceof Terrain) { this.onlyOn = true; onlyOnObjectType = ObjectType.TERRAIN; onlyOnTerrain = (Terrain) onlyOn; onlyOnLayer = null; onlyOnValue = -1; } else if (onlyOn instanceof Layer) { this.onlyOn = true; if ((((Layer) onlyOn).getDataSize() == BIT) || (((Layer) onlyOn).getDataSize() == BIT_PER_CHUNK)) { onlyOnObjectType = ObjectType.BIT_LAYER; } else { onlyOnObjectType = ObjectType.INT_LAYER_ANY; } onlyOnTerrain = null; onlyOnLayer = (Layer) onlyOn; onlyOnValue = -1; } else if (onlyOn instanceof LayerValue) { this.onlyOn = true; LayerValue layerValue = (LayerValue) onlyOn; if (layerValue.layer instanceof Biome) { if (layerValue.value < 0) { onlyOnObjectType = ObjectType.AUTO_BIOME; onlyOnTerrain = null; onlyOnLayer = null; onlyOnValue = -layerValue.value; } else { onlyOnObjectType = ObjectType.BIOME; onlyOnTerrain = null; onlyOnLayer = null; onlyOnValue = layerValue.value; } } else if (layerValue.layer instanceof Annotations) { if (layerValue.condition == null) { onlyOnObjectType = ObjectType.ANNOTATION_ANY; onlyOnTerrain = null; onlyOnLayer = null; onlyOnValue = -1; } else { onlyOnObjectType = ObjectType.ANNOTATION; onlyOnTerrain = null; onlyOnLayer = null; onlyOnValue = layerValue.value; } } else if ((layerValue.layer.getDataSize() != BIT) && (layerValue.layer.getDataSize() != BIT_PER_CHUNK) && (layerValue.layer.getDataSize() != NONE)) { if (layerValue.condition == null) { onlyOnObjectType = ObjectType.INT_LAYER_ANY; onlyOnTerrain = null; onlyOnLayer = null; onlyOnValue = -1; } else { switch (layerValue.condition) { case EQUAL: onlyOnObjectType = ObjectType.INT_LAYER_EQUAL; break; case HIGHER_THAN_OR_EQUAL: onlyOnObjectType = ObjectType.INT_LAYER_EQUAL_OR_HIGHER; break; case LOWER_THAN_OR_EQUAL: onlyOnObjectType = ObjectType.INT_LAYER_EQUAL_OR_LOWER; break; default: throw new InternalError(); } onlyOnTerrain = null; onlyOnLayer = null; onlyOnValue = layerValue.value; } } else { throw new IllegalArgumentException("Layer value of type " + layerValue.layer.getClass().getSimpleName() + " not supported"); } } else if (WATER.equals(onlyOn)) { this.onlyOn = true; onlyOnObjectType = ObjectType.WATER; onlyOnTerrain = null; onlyOnLayer = null; onlyOnValue = -1; } else if (LAVA.equals(onlyOn)) { this.onlyOn = true; onlyOnObjectType = ObjectType.LAVA; onlyOnTerrain = null; onlyOnLayer = null; onlyOnValue = -1; } else if (LAND.equals(onlyOn)) { this.onlyOn = true; onlyOnObjectType = ObjectType.LAND; onlyOnTerrain = null; onlyOnLayer = null; onlyOnValue = -1; } else if (AUTO_BIOMES.equals(onlyOn)) { this.onlyOn = true; onlyOnObjectType = ObjectType.BIOME; onlyOnTerrain = null; onlyOnLayer = null; onlyOnValue = 255; } else { this.onlyOn = false; onlyOnObjectType = null; onlyOnTerrain = null; onlyOnLayer = null; onlyOnValue = -1; } if (exceptOn instanceof Terrain) { this.exceptOn = true; exceptOnObjectType = ObjectType.TERRAIN; exceptOnTerrain = (Terrain) exceptOn; exceptOnLayer = null; exceptOnValue = -1; } else if (exceptOn instanceof Layer) { this.exceptOn = true; if ((((Layer) exceptOn).getDataSize() == BIT) || (((Layer) exceptOn).getDataSize() == BIT_PER_CHUNK)) { exceptOnObjectType = ObjectType.BIT_LAYER; } else { exceptOnObjectType = ObjectType.INT_LAYER_ANY; } exceptOnTerrain = null; exceptOnLayer = (Layer) exceptOn; exceptOnValue = -1; } else if (exceptOn instanceof LayerValue) { this.exceptOn = true; LayerValue layerValue = (LayerValue) exceptOn; if (layerValue.layer instanceof Biome) { if (layerValue.value < 0) { exceptOnObjectType = ObjectType.AUTO_BIOME; exceptOnTerrain = null; exceptOnLayer = null; exceptOnValue = -layerValue.value; } else { exceptOnObjectType = ObjectType.BIOME; exceptOnTerrain = null; exceptOnLayer = null; exceptOnValue = layerValue.value; } } else if (layerValue.layer instanceof Annotations) { if (layerValue.condition == null) { exceptOnObjectType = ObjectType.ANNOTATION_ANY; exceptOnTerrain = null; exceptOnLayer = null; exceptOnValue = -1; } else { exceptOnObjectType = ObjectType.ANNOTATION; exceptOnTerrain = null; exceptOnLayer = null; exceptOnValue = layerValue.value; } } else if ((layerValue.layer.getDataSize() != BIT) && (layerValue.layer.getDataSize() != BIT_PER_CHUNK) && (layerValue.layer.getDataSize() != NONE)) { if (layerValue.condition == null) { exceptOnObjectType = ObjectType.INT_LAYER_ANY; exceptOnTerrain = null; exceptOnLayer = null; exceptOnValue = -1; } else { switch (layerValue.condition) { case EQUAL: exceptOnObjectType = ObjectType.INT_LAYER_EQUAL; break; case HIGHER_THAN_OR_EQUAL: exceptOnObjectType = ObjectType.INT_LAYER_EQUAL_OR_HIGHER; break; case LOWER_THAN_OR_EQUAL: exceptOnObjectType = ObjectType.INT_LAYER_EQUAL_OR_LOWER; break; default: throw new InternalError(); } exceptOnTerrain = null; exceptOnLayer = null; exceptOnValue = layerValue.value; } } else { throw new IllegalArgumentException("Layer value of type " + layerValue.layer.getClass().getSimpleName() + " not supported"); } } else if (WATER.equals(exceptOn)) { this.exceptOn = true; exceptOnObjectType = ObjectType.WATER; exceptOnTerrain = null; exceptOnLayer = null; exceptOnValue = -1; } else if (LAVA.equals(exceptOn)) { this.exceptOn = true; exceptOnObjectType = ObjectType.LAVA; exceptOnTerrain = null; exceptOnLayer = null; exceptOnValue = -1; } else if (LAND.equals(exceptOn)) { this.exceptOn = true; exceptOnObjectType = ObjectType.LAND; exceptOnTerrain = null; exceptOnLayer = null; exceptOnValue = -1; } else if (AUTO_BIOMES.equals(exceptOn)) { this.exceptOn = true; exceptOnObjectType = ObjectType.BIOME; exceptOnTerrain = null; exceptOnLayer = null; exceptOnValue = 255; } else { this.exceptOn = false; exceptOnObjectType = null; exceptOnTerrain = null; exceptOnLayer = null; exceptOnValue = -1; } this.degrees = aboveDegrees; checkSlope = aboveDegrees >= 0; if (checkSlope) { this.slope = (float) Math.tan(aboveDegrees / (180 / Math.PI)); // System.out.println(degrees + "° -> " + slope); } else { slope = 0.0f; } this.slopeIsAbove = slopeIsAbove; } public int getAboveLevel() { return aboveLevel; } public int getBelowLevel() { return belowLevel; } public Dimension getDimension() { return dimension; } public void setDimension(Dimension dimension) { this.dimension = dimension; } public boolean isInSelection() { return inSelection; } // Filter @Override public float modifyStrength(int x, int y, float strength) { if (strength > 0.0f) { if (inSelection && (! dimension.getBitLayerValueAt(SelectionChunk.INSTANCE, x, y)) && (! dimension.getBitLayerValueAt(SelectionBlock.INSTANCE, x, y))) { return 0.0f; } else if (outsideSelection && (dimension.getBitLayerValueAt(SelectionChunk.INSTANCE, x, y) || dimension.getBitLayerValueAt(SelectionBlock.INSTANCE, x, y))) { return 0.0f; } if (exceptOn) { switch (exceptOnObjectType) { case BIOME: if (dimension.getLayerValueAt(Biome.INSTANCE, x, y) == exceptOnValue) { return 0.0f; } break; case AUTO_BIOME: if (dimension.getAutoBiome(x, y) == exceptOnValue) { return 0.0f; } break; case BIT_LAYER: if (dimension.getBitLayerValueAt(exceptOnLayer, x, y)) { return 0.0f; } break; case INT_LAYER_ANY: if (dimension.getLayerValueAt(exceptOnLayer, x, y) != 0) { return 0.0f; } break; case INT_LAYER_EQUAL: if (dimension.getLayerValueAt(exceptOnLayer, x, y) != exceptOnValue) { return 0.0f; } break; case INT_LAYER_EQUAL_OR_HIGHER: if (dimension.getLayerValueAt(exceptOnLayer, x, y) < exceptOnValue) { return 0.0f; } break; case INT_LAYER_EQUAL_OR_LOWER: if (dimension.getLayerValueAt(exceptOnLayer, x, y) > exceptOnValue) { return 0.0f; } break; case TERRAIN: if (dimension.getTerrainAt(x, y) == exceptOnTerrain) { return 0.0f; } break; case WATER: if ((dimension.getWaterLevelAt(x, y) > dimension.getIntHeightAt(x, y)) && (! dimension.getBitLayerValueAt(FloodWithLava.INSTANCE, x, y))) { return 0.0f; } break; case LAVA: if ((dimension.getWaterLevelAt(x, y) > dimension.getIntHeightAt(x, y)) && dimension.getBitLayerValueAt(FloodWithLava.INSTANCE, x, y)) { return 0.0f; } break; case LAND: if (dimension.getWaterLevelAt(x, y) <= dimension.getIntHeightAt(x, y)) { return 0.0f; } break; case ANNOTATION_ANY: if (dimension.getLayerValueAt(Annotations.INSTANCE, x, y) > 0) { return 0.0f; } break; case ANNOTATION: if (dimension.getLayerValueAt(Annotations.INSTANCE, x, y) == exceptOnValue) { return 0.0f; } break; } } if (onlyOn) { switch (onlyOnObjectType) { case BIOME: if (dimension.getLayerValueAt(Biome.INSTANCE, x, y) != onlyOnValue) { return 0.0f; } break; case AUTO_BIOME: if ((dimension.getLayerValueAt(Biome.INSTANCE, x, y) != 255) || (dimension.getAutoBiome(x, y) != onlyOnValue)) { return 0.0f; } break; case BIT_LAYER: if (!dimension.getBitLayerValueAt(onlyOnLayer, x, y)) { return 0.0f; } break; case INT_LAYER_ANY: if (dimension.getLayerValueAt(onlyOnLayer, x, y) == 0) { return 0.0f; } break; case INT_LAYER_EQUAL: if (dimension.getLayerValueAt(onlyOnLayer, x, y) == onlyOnValue) { return 0.0f; } break; case INT_LAYER_EQUAL_OR_HIGHER: if (dimension.getLayerValueAt(onlyOnLayer, x, y) >= onlyOnValue) { return 0.0f; } break; case INT_LAYER_EQUAL_OR_LOWER: if (dimension.getLayerValueAt(onlyOnLayer, x, y) <= onlyOnValue) { return 0.0f; } break; case TERRAIN: if (dimension.getTerrainAt(x, y) != onlyOnTerrain) { return 0.0f; } break; case WATER: if ((dimension.getWaterLevelAt(x, y) <= dimension.getIntHeightAt(x, y)) || dimension.getBitLayerValueAt(FloodWithLava.INSTANCE, x, y)) { return 0.0f; } break; case LAVA: if ((dimension.getWaterLevelAt(x, y) <= dimension.getIntHeightAt(x, y)) || (! dimension.getBitLayerValueAt(FloodWithLava.INSTANCE, x, y))) { return 0.0f; } break; case LAND: if (dimension.getWaterLevelAt(x, y) > dimension.getIntHeightAt(x, y)) { return 0.0f; } break; case ANNOTATION_ANY: if (dimension.getLayerValueAt(Annotations.INSTANCE, x, y) == 0) { return 0.0f; } break; case ANNOTATION: if (dimension.getLayerValueAt(Annotations.INSTANCE, x, y) != onlyOnValue) { return 0.0f; } break; } } if (checkLevel) { final int terrainLevel = dimension.getIntHeightAt(x, y); switch (levelType) { case ABOVE: if (terrainLevel < aboveLevel) { return feather ? Math.max((1 - (aboveLevel - terrainLevel) / 4.0f) * strength, 0.0f) : 0.0f; } break; case BELOW: if (terrainLevel > belowLevel) { return feather ? Math.max((1 - (terrainLevel - belowLevel) / 4.0f) * strength, 0.0f) : 0.0f; } break; case BETWEEN: if ((terrainLevel < aboveLevel) || (terrainLevel > belowLevel)) { return feather ? Math.max(Math.min((1 - (aboveLevel - terrainLevel) / 4.0f), (1 - (terrainLevel - belowLevel) / 4.0f)) * strength, 0.0f) : 0.0f; } break; case OUTSIDE: if ((terrainLevel > belowLevel) && (terrainLevel < aboveLevel)) { return feather ? Math.max(Math.max((1 - (terrainLevel - belowLevel) / 4.0f), (1 - (aboveLevel - terrainLevel) / 4.0f)) * strength, 0.0f) : 0.0f; } break; } } if (checkSlope) { float terrainSlope = dimension.getSlope(x, y); if (slopeIsAbove ? (terrainSlope < slope) : (terrainSlope > slope)) { return 0.0f; } } return strength; } else { return 0.0f; } } // Object @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("DefaultFilter{"); if (inSelection) { sb.append("in selection"); } else if (outsideSelection) { sb.append("outside selection"); } if (onlyOn) { if (inSelection || outsideSelection) { sb.append(" and "); } sb.append("only on "); append(sb, onlyOnObjectType, onlyOnValue, onlyOnLayer, onlyOnTerrain); } if (exceptOn) { if (inSelection || outsideSelection || onlyOn) { sb.append(' '); } sb.append("except on "); append(sb, exceptOnObjectType, exceptOnValue, exceptOnLayer, exceptOnTerrain); } if (checkLevel) { if (inSelection || outsideSelection || onlyOn || exceptOn) { sb.append(" and "); } sb.append("height "); switch (levelType) { case ABOVE: sb.append("at or above ").append(aboveLevel); break; case BELOW: sb.append("at or below ").append(belowLevel); break; case BETWEEN: sb.append("between ").append(aboveLevel).append(" and ").append(belowLevel); break; case OUTSIDE: sb.append("not between ").append(aboveLevel).append(" and ").append(belowLevel); break; } } if (checkSlope) { if (inSelection || outsideSelection || onlyOn || exceptOn || checkLevel) { sb.append(" and "); } sb.append("gradient ").append(slopeIsAbove ? "above " : "below ").append(slope); } sb.append('}'); return sb.toString(); } private void append(StringBuilder sb, ObjectType objectType, int value, Layer layer, Terrain terrain) { switch (objectType) { case BIOME: sb.append("biome ").append(value); break; case AUTO_BIOME: sb.append("auto biome ").append(value); break; case BIT_LAYER: case INT_LAYER_ANY: sb.append("layer ").append(layer.getName().toLowerCase()); break; case INT_LAYER_EQUAL: sb.append("layer ").append(layer).append(" is ").append(value); break; case INT_LAYER_EQUAL_OR_HIGHER: sb.append("layer ").append(layer).append(" >= ").append(value); break; case INT_LAYER_EQUAL_OR_LOWER: sb.append("layer ").append(layer).append(" <= ").append(value); break; case TERRAIN: sb.append("terrain ").append(terrain.name().toLowerCase()); break; case WATER: sb.append("water"); break; case LAVA: sb.append("lava"); break; case LAND: sb.append("land"); break; case ANNOTATION_ANY: sb.append("annotations"); break; case ANNOTATION: sb.append(Constants.COLOUR_NAMES[value].toLowerCase()).append(" annotations"); break; } } final boolean checkLevel, onlyOn, exceptOn, feather, checkSlope, slopeIsAbove, inSelection, outsideSelection; final LevelType levelType; final ObjectType onlyOnObjectType, exceptOnObjectType; final int aboveLevel, belowLevel, onlyOnValue, exceptOnValue, degrees; final Terrain onlyOnTerrain, exceptOnTerrain; final Layer onlyOnLayer, exceptOnLayer; final float slope; Dimension dimension; public static final String LAND = "Land"; public static final String WATER = "Water"; public static final String LAVA = "Lava"; public static final String AUTO_BIOMES = "Automatic Biomes"; public enum LevelType { BETWEEN, OUTSIDE, ABOVE, BELOW } public enum ObjectType { TERRAIN, BIT_LAYER, INT_LAYER_ANY, INT_LAYER_EQUAL, INT_LAYER_EQUAL_OR_HIGHER, INT_LAYER_EQUAL_OR_LOWER, BIOME, WATER, LAND, LAVA, AUTO_BIOME, ANNOTATION_ANY, ANNOTATION } public enum Condition { EQUAL, LOWER_THAN_OR_EQUAL, HIGHER_THAN_OR_EQUAL } public static class LayerValue { public LayerValue(Layer layer) { this.layer = layer; value = -1; condition = null; } public LayerValue(Layer layer, int value) { this(layer, value, Condition.EQUAL); } public LayerValue(Layer layer, int value, Condition condition) { switch (layer.getDataSize()) { case BIT_PER_CHUNK: case BIT: if ((value < -1) || (value > 1)) { throw new IllegalArgumentException("value " + value); } break; case NIBBLE: if ((value < -15) || (value > 15)) { throw new IllegalArgumentException("value " + value); } break; case BYTE: if ((value < -255) || (value > 255)) { throw new IllegalArgumentException("value " + value); } break; default: throw new IllegalArgumentException("Data size " + layer.getDataSize() + " not supported"); } this.layer = layer; this.value = value; this.condition = condition; } public final Layer layer; public final int value; public final Condition condition; } }