You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
248 lines
9.0 KiB
248 lines
9.0 KiB
/*
|
|
* Copyright (c) 2009-2012 jMonkeyEngine
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
package com.jme3.terrain.heightmap;
|
|
|
|
import com.jme3.math.FastMath;
|
|
import com.jme3.util.LittleEndien;
|
|
import java.io.*;
|
|
import java.net.URL;
|
|
import java.util.logging.Logger;
|
|
|
|
/**
|
|
* <code>RawHeightMap</code> creates a height map from a RAW image file. The
|
|
* greyscale image denotes height based on the value of the pixel for each
|
|
* point. Where pure black the lowest point and pure white denotes the highest.
|
|
*
|
|
* @author Mark Powell
|
|
* @version $Id$
|
|
*/
|
|
public class RawHeightMap extends AbstractHeightMap {
|
|
|
|
private static final Logger logger = Logger.getLogger(RawHeightMap.class.getName());
|
|
/**
|
|
* Format specification for 8 bit precision heightmaps
|
|
*/
|
|
public static final int FORMAT_8BIT = 0;
|
|
/**
|
|
* Format specification for 16 bit little endian heightmaps
|
|
*/
|
|
public static final int FORMAT_16BITLE = 1;
|
|
/**
|
|
* Format specification for 16 bit big endian heightmaps
|
|
*/
|
|
public static final int FORMAT_16BITBE = 2;
|
|
private int format;
|
|
private boolean swapxy;
|
|
private InputStream stream;
|
|
|
|
/**
|
|
* Constructor creates a new <code>RawHeightMap</code> object and loads a
|
|
* RAW image file to use as a height field. The greyscale image denotes the
|
|
* height of the terrain, where dark is low point and bright is high point.
|
|
* The values of the RAW correspond directly with the RAW values or 0 - 255.
|
|
*
|
|
* @param filename
|
|
* the RAW file to use as the heightmap.
|
|
* @param size
|
|
* the size of the RAW (must be square).
|
|
* @throws JmeException
|
|
* if the filename is null or not RAW, and if the size is 0 or
|
|
* less.
|
|
*/
|
|
public RawHeightMap(String filename, int size) throws Exception {
|
|
this(filename, size, FORMAT_8BIT, false);
|
|
}
|
|
|
|
public RawHeightMap(float heightData[]) {
|
|
this.heightData = heightData;
|
|
this.size = (int) FastMath.sqrt(heightData.length);
|
|
this.format = FORMAT_8BIT;
|
|
}
|
|
|
|
public RawHeightMap(String filename, int size, int format, boolean swapxy) throws Exception {
|
|
// varify that filename and size are valid.
|
|
if (null == filename || size <= 0) {
|
|
throw new Exception("Must supply valid filename and "
|
|
+ "size (> 0)");
|
|
}
|
|
try {
|
|
setup(new FileInputStream(filename), size, format, swapxy);
|
|
} catch (FileNotFoundException e) {
|
|
throw new Exception("height file not found: " + filename);
|
|
}
|
|
}
|
|
|
|
public RawHeightMap(InputStream stream, int size, int format, boolean swapxy) throws Exception {
|
|
setup(stream, size, format, swapxy);
|
|
}
|
|
|
|
public RawHeightMap(URL resource, int size, int format, boolean swapxy) throws Exception {
|
|
// varify that resource and size are valid.
|
|
if (null == resource || size <= 0) {
|
|
throw new Exception("Must supply valid resource and "
|
|
+ "size (> 0)");
|
|
}
|
|
|
|
|
|
try {
|
|
setup(resource.openStream(), size, format, swapxy);
|
|
} catch (IOException e) {
|
|
throw new Exception("Unable to open height url: " + resource);
|
|
}
|
|
}
|
|
|
|
private void setup(InputStream stream, int size, int format, boolean swapxy) throws Exception {
|
|
// varify that filename and size are valid.
|
|
if (null == stream || size <= 0) {
|
|
throw new Exception("Must supply valid stream and "
|
|
+ "size (> 0)");
|
|
}
|
|
|
|
|
|
this.stream = stream;
|
|
this.size = size;
|
|
this.format = format;
|
|
this.swapxy = swapxy;
|
|
load();
|
|
}
|
|
|
|
/**
|
|
* <code>load</code> fills the height data array with the appropriate data
|
|
* from the set RAW image. If the RAW image has not been set a JmeException
|
|
* will be thrown.
|
|
*
|
|
* @return true if the load is successfull, false otherwise.
|
|
*/
|
|
@Override
|
|
public boolean load() {
|
|
// confirm data has been set. Redundant check...
|
|
if (null == stream || size <= 0) {
|
|
throw new RuntimeException("Must supply valid stream and "
|
|
+ "size (> 0)");
|
|
}
|
|
|
|
|
|
// clean up
|
|
if (null != heightData) {
|
|
unloadHeightMap();
|
|
}
|
|
|
|
|
|
// initialize the height data attributes
|
|
heightData = new float[size * size];
|
|
|
|
|
|
// attempt to connect to the supplied file.
|
|
BufferedInputStream bis = null;
|
|
|
|
|
|
try {
|
|
bis = new BufferedInputStream(stream);
|
|
if (format == RawHeightMap.FORMAT_16BITLE) {
|
|
LittleEndien dis = new LittleEndien(bis);
|
|
int index;
|
|
// read the raw file
|
|
for (int i = 0; i < size; i++) {
|
|
for (int j = 0; j < size; j++) {
|
|
if (swapxy) {
|
|
index = i + j * size;
|
|
} else {
|
|
index = (i * size) + j;
|
|
}
|
|
heightData[index] = dis.readUnsignedShort();
|
|
}
|
|
}
|
|
dis.close();
|
|
} else {
|
|
DataInputStream dis = new DataInputStream(bis);
|
|
// read the raw file
|
|
for (int i = 0; i < size; i++) {
|
|
for (int j = 0; j < size; j++) {
|
|
int index;
|
|
if (swapxy) {
|
|
index = i + j * size;
|
|
} else {
|
|
index = (i * size) + j;
|
|
}
|
|
if (format == RawHeightMap.FORMAT_16BITBE) {
|
|
heightData[index] = dis.readUnsignedShort();
|
|
} else {
|
|
heightData[index] = dis.readUnsignedByte();
|
|
}
|
|
}
|
|
}
|
|
dis.close();
|
|
}
|
|
bis.close();
|
|
} catch (IOException e1) {
|
|
logger.warning("Error reading height data from stream.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* <code>setFilename</code> sets the file to use for the RAW data. A call
|
|
* to <code>load</code> is required to put the changes into effect.
|
|
*
|
|
* @param filename
|
|
* the new file to use for the height data.
|
|
* @throws JmeException
|
|
* if the file is null or not RAW.
|
|
*/
|
|
public void setFilename(String filename) throws Exception {
|
|
if (null == filename) {
|
|
throw new Exception("Must supply valid filename.");
|
|
}
|
|
try {
|
|
this.stream = new FileInputStream(filename);
|
|
} catch (FileNotFoundException e) {
|
|
throw new Exception("height file not found: " + filename);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* <code>setHeightStream</code> sets the stream to use for the RAW data. A call
|
|
* to <code>load</code> is required to put the changes into effect.
|
|
*
|
|
* @param stream
|
|
* the new stream to use for the height data.
|
|
* @throws JmeException
|
|
* if the stream is null or not RAW.
|
|
*/
|
|
public void setHeightStream(InputStream stream) throws Exception {
|
|
if (null == stream) {
|
|
throw new Exception("Must supply valid stream.");
|
|
}
|
|
this.stream = stream;
|
|
}
|
|
}
|
|
|