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