TerrainGridTest is running smooth now using 257x257 sized TerrainQuads with fractal based heightmaps calculated on the fly. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7529 75d07b2b-3a1a-0410-a2c5-0572b91ccdca3.0
parent
1fbd05a3ca
commit
58ede837c6
Binary file not shown.
@ -0,0 +1,62 @@ |
||||
package com.jme3.terrain; |
||||
|
||||
import java.awt.image.BufferedImage; |
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.nio.FloatBuffer; |
||||
import java.util.logging.Logger; |
||||
|
||||
import javax.imageio.ImageIO; |
||||
|
||||
import org.novyon.noise.ShaderUtils; |
||||
|
||||
public class MapUtils { |
||||
|
||||
public static FloatBuffer clip(FloatBuffer src, int origSize, int newSize, int offset) { |
||||
FloatBuffer result = FloatBuffer.allocate(newSize * newSize); |
||||
|
||||
float[] orig = src.array(); |
||||
for (int i = offset; i < offset + newSize; i++) { |
||||
result.put(orig, i * origSize + offset, newSize); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
public static BufferedImage toGrayscale16Image(FloatBuffer buff, int size) { |
||||
BufferedImage retval = new BufferedImage(size, size, BufferedImage.TYPE_USHORT_GRAY); |
||||
buff.rewind(); |
||||
for (int y = 0; y < size; y++) { |
||||
for (int x = 0; x < size; x++) { |
||||
short c = (short) (ShaderUtils.clamp(buff.get(), 0, 1) * 65532); |
||||
retval.getRaster().setDataElements(x, y, new short[] { c }); |
||||
} |
||||
} |
||||
return retval; |
||||
} |
||||
|
||||
public static BufferedImage toGrayscaleRGBImage(FloatBuffer buff, int size) { |
||||
BufferedImage retval = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); |
||||
buff.rewind(); |
||||
for (int y = 0; y < size; y++) { |
||||
for (int x = 0; x < size; x++) { |
||||
int c = (int) (ShaderUtils.clamp(buff.get(), 0, 1) * 255); |
||||
retval.setRGB(x, y, 0xFF000000 | c << 16 | c << 8 | c); |
||||
} |
||||
} |
||||
return retval; |
||||
} |
||||
|
||||
public static void saveImage(BufferedImage im, String file) { |
||||
MapUtils.saveImage(im, new File(file)); |
||||
} |
||||
|
||||
public static void saveImage(BufferedImage im, File file) { |
||||
try { |
||||
ImageIO.write(im, "PNG", file); |
||||
Logger.getLogger(MapUtils.class.getCanonicalName()).info("Saved image as : " + file.getAbsolutePath()); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,124 @@ |
||||
package com.jme3.terrain.geomipmap; |
||||
|
||||
// Copyright 2007 Christian d'Heureuse, Inventec Informatik AG, Zurich,
|
||||
// Switzerland
|
||||
// www.source-code.biz, www.inventec.ch/chdh
|
||||
//
|
||||
// This module is multi-licensed and may be used under the terms
|
||||
// of any of the following licenses:
|
||||
//
|
||||
// EPL, Eclipse Public License, V1.0 or later, http://www.eclipse.org/legal
|
||||
// LGPL, GNU Lesser General Public License, V2 or later,
|
||||
// http://www.gnu.org/licenses/lgpl.html
|
||||
// GPL, GNU General Public License, V2 or later,
|
||||
// http://www.gnu.org/licenses/gpl.html
|
||||
// AL, Apache License, V2.0 or later, http://www.apache.org/licenses
|
||||
// BSD, BSD License, http://www.opensource.org/licenses/bsd-license.php
|
||||
//
|
||||
// Please contact the author if you need another license.
|
||||
// This module is provided "as is", without warranties of any kind.
|
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* An LRU cache, based on <code>LinkedHashMap</code>. |
||||
* |
||||
* <p> |
||||
* This cache has a fixed maximum number of elements (<code>cacheSize</code>). |
||||
* If the cache is full and another entry is added, the LRU (least recently |
||||
* used) entry is dropped. |
||||
* |
||||
* <p> |
||||
* This class is thread-safe. All methods of this class are synchronized. |
||||
* |
||||
* <p> |
||||
* Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br> |
||||
* Multi-licensed: EPL / LGPL / GPL / AL / BSD. |
||||
*/ |
||||
public class LRUCache<K, V> { |
||||
|
||||
private static final float hashTableLoadFactor = 0.75f; |
||||
|
||||
private LinkedHashMap<K, V> map; |
||||
private int cacheSize; |
||||
|
||||
/** |
||||
* Creates a new LRU cache. |
||||
* |
||||
* @param cacheSize |
||||
* the maximum number of entries that will be kept in this cache. |
||||
*/ |
||||
public LRUCache(int cacheSize) { |
||||
this.cacheSize = cacheSize; |
||||
int hashTableCapacity = (int) Math.ceil(cacheSize / LRUCache.hashTableLoadFactor) + 1; |
||||
this.map = new LinkedHashMap<K, V>(hashTableCapacity, LRUCache.hashTableLoadFactor, true) { |
||||
// (an anonymous inner class)
|
||||
private static final long serialVersionUID = 1; |
||||
|
||||
@Override |
||||
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { |
||||
return this.size() > LRUCache.this.cacheSize; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Retrieves an entry from the cache.<br> |
||||
* The retrieved entry becomes the MRU (most recently used) entry. |
||||
* |
||||
* @param key |
||||
* the key whose associated value is to be returned. |
||||
* @return the value associated to this key, or null if no value with this |
||||
* key exists in the cache. |
||||
*/ |
||||
public synchronized V get(K key) { |
||||
return this.map.get(key); |
||||
} |
||||
|
||||
/** |
||||
* Adds an entry to this cache. |
||||
* The new entry becomes the MRU (most recently used) entry. |
||||
* If an entry with the specified key already exists in the cache, it is |
||||
* replaced by the new entry. |
||||
* If the cache is full, the LRU (least recently used) entry is removed from |
||||
* the cache. |
||||
* |
||||
* @param key |
||||
* the key with which the specified value is to be associated. |
||||
* @param value |
||||
* a value to be associated with the specified key. |
||||
*/ |
||||
public synchronized void put(K key, V value) { |
||||
this.map.put(key, value); |
||||
} |
||||
|
||||
/** |
||||
* Clears the cache. |
||||
*/ |
||||
public synchronized void clear() { |
||||
this.map.clear(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of used entries in the cache. |
||||
* |
||||
* @return the number of entries currently in the cache. |
||||
*/ |
||||
public synchronized int usedEntries() { |
||||
return this.map.size(); |
||||
} |
||||
|
||||
/** |
||||
* Returns a <code>Collection</code> that contains a copy of all cache |
||||
* entries. |
||||
* |
||||
* @return a <code>Collection</code> with a copy of the cache content. |
||||
*/ |
||||
public synchronized Collection<Map.Entry<K, V>> getAll() { |
||||
return new ArrayList<Map.Entry<K, V>>(this.map.entrySet()); |
||||
} |
||||
|
||||
} // end class LRUCache
|
@ -0,0 +1,75 @@ |
||||
package com.jme3.terrain.heightmap; |
||||
|
||||
import java.awt.image.BufferedImage; |
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.nio.FloatBuffer; |
||||
|
||||
import javax.imageio.ImageIO; |
||||
|
||||
import org.novyon.noise.Basis; |
||||
|
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.terrain.MapUtils; |
||||
|
||||
public class FractalHeightMapGrid implements HeightMapGrid { |
||||
|
||||
public class FloatBufferHeightMap extends AbstractHeightMap { |
||||
|
||||
private final FloatBuffer buffer; |
||||
|
||||
public FloatBufferHeightMap(FloatBuffer buffer) { |
||||
this.buffer = buffer; |
||||
} |
||||
|
||||
@Override |
||||
public boolean load() { |
||||
this.heightData = this.buffer.array(); |
||||
return true; |
||||
} |
||||
|
||||
} |
||||
|
||||
private int size; |
||||
private final Basis base; |
||||
private final String cacheDir; |
||||
private final float heightScale; |
||||
|
||||
public FractalHeightMapGrid(Basis base, String cacheDir, float heightScale) { |
||||
this.base = base; |
||||
this.cacheDir = cacheDir; |
||||
this.heightScale = heightScale; |
||||
} |
||||
|
||||
@Override |
||||
public HeightMap getHeightMapAt(Vector3f location) { |
||||
AbstractHeightMap heightmap = null; |
||||
if (this.cacheDir != null && new File(this.cacheDir, "terrain_" + (int) location.x + "_" + (int) location.z + ".png").exists()) { |
||||
try { |
||||
BufferedImage im = null; |
||||
im = ImageIO.read(new File(this.cacheDir, "terrain_" + (int) location.x + "_" + (int) location.z + ".png")); |
||||
heightmap = new Grayscale16BitHeightMap(im); |
||||
heightmap.setHeightScale(256); |
||||
} catch (IOException e) {} |
||||
} else { |
||||
FloatBuffer buffer = this.base.getBuffer(location.x * (this.size - 1), location.z * (this.size - 1), 0, this.size); |
||||
if (this.cacheDir != null) { |
||||
MapUtils.saveImage(MapUtils.toGrayscale16Image(buffer, this.size), new File(this.cacheDir, "terrain_" + (int) location.x |
||||
+ "_" + (int) location.z + ".png")); |
||||
} |
||||
float[] arr = buffer.array(); |
||||
for (int i = 0; i < arr.length; i++) { |
||||
arr[i] = arr[i] * this.heightScale; |
||||
} |
||||
heightmap = new FloatBufferHeightMap(buffer); |
||||
} |
||||
heightmap.load(); |
||||
return heightmap; |
||||
} |
||||
|
||||
@Override |
||||
public void setSize(int size) { |
||||
this.size = size; |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue