package net.anzix.fsz.proceduralterrain;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import com.ardor3d.extension.terrain.client.TextureConfiguration;
import com.ardor3d.extension.terrain.client.TextureSource;
import com.ardor3d.extension.terrain.util.Tile;
import com.ardor3d.image.TextureStoreFormat;
import com.ardor3d.math.ColorRGBA;
import com.ardor3d.math.type.ReadOnlyColorRGBA;
import com.ardor3d.util.geom.BufferUtils;
import com.google.common.collect.Maps;
/**
*
* @author elcsiga
*/
public class ProceduralTextureSource implements TextureSource {
private final NominalHeightGenerator nominalHeightGenerator;
private final LayerStructure layerStructure;
private static final int tileSize = 128;
private static final int availableClipmapLevels = 8;
//private final ReadOnlyColorRGBA[] terrainColors;
private final ReentrantLock textureLock = new ReentrantLock();
private final ThreadLocal<ByteBuffer> tileDataPool = new ThreadLocal<ByteBuffer>() {
@Override
protected ByteBuffer initialValue() {
return BufferUtils.createByteBufferOnHeap(tileSize * tileSize * 3);
}
};
public ProceduralTextureSource(NominalHeightGenerator nominalHeightGenerator, LayerStructure layerStructure) {
this.nominalHeightGenerator = nominalHeightGenerator;
this.layerStructure = layerStructure;
}
@Override
public TextureConfiguration getConfiguration() throws Exception {
final Map<Integer, TextureStoreFormat> textureStoreFormat = Maps.newHashMap();
textureStoreFormat.put(0, TextureStoreFormat.RGB8);
return new TextureConfiguration(availableClipmapLevels, textureStoreFormat, tileSize, 1f, false, false);
}
@Override
public Set<Tile> getValidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
final int numTilesY) throws Exception {
return null;
}
@Override
public Set<Tile> getInvalidTiles(final int clipmapLevel, final int tileX, final int tileY, final int numTilesX,
final int numTilesY) throws Exception {
return null;
}
@Override
public int getContributorId(final int clipmapLevel, final Tile tile) {
return 0;
}
@Override
public ByteBuffer getTile(final int clipmapLevel, final Tile tile) throws Exception {
final ByteBuffer data = tileDataPool.get();
final int tileX = tile.getX();
final int tileY = tile.getY();
final int baseClipmapLevel = availableClipmapLevels - clipmapLevel - 1;
textureLock.lock();
try {
for (int y = 0; y < tileSize; y++) {
for (int x = 0; x < tileSize; x++) {
if (Thread.interrupted()) {
return null;
}
final int heightX = (tileX * tileSize + x);
final int heightY = (tileY * tileSize + y);
float nominalHeight1 = nominalHeightGenerator.getHeight(heightX << baseClipmapLevel, heightY << baseClipmapLevel);
PositionInfo positionInfo1 = layerStructure.getPositionInfo(nominalHeight1, heightX << baseClipmapLevel, heightY << baseClipmapLevel);
float nominalHeight2 = nominalHeightGenerator.getHeight(heightX << baseClipmapLevel, (heightY+1) << baseClipmapLevel);
PositionInfo positionInfo2 = layerStructure.getPositionInfo(nominalHeight2, heightX << baseClipmapLevel, (heightY+1) << baseClipmapLevel);
final float eval1 = positionInfo1.getRealHeight();
final float eval2 = positionInfo2.getRealHeight();
float shadow = ((eval2 - eval1) / (float) (1 << baseClipmapLevel)) * positionInfo1.getLayer().getLightMapShadowColorScale() + 0.5f;
if (shadow < 0.0f) shadow = 0.0f;
else if (shadow > 1.0f) shadow = 1.0f;
final ReadOnlyColorRGBA layerColor = positionInfo1.getLayer().getColor();
final int index = (x + y * tileSize) * 3;
data.put(index, (byte) (layerColor.getRed()*shadow * 255));
data.put(index + 1, (byte) (layerColor.getGreen()*shadow * 255));
data.put(index + 2, (byte) (layerColor.getBlue()*shadow * 255));
}
}
} finally {
textureLock.unlock();
}
return data;
}
}