• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package com.jme3.terrain.heightmap;
33 
34 import com.jme3.math.FastMath;
35 import com.jme3.util.LittleEndien;
36 import java.io.*;
37 import java.net.URL;
38 import java.util.logging.Logger;
39 
40 /**
41  * <code>RawHeightMap</code> creates a height map from a RAW image file. The
42  * greyscale image denotes height based on the value of the pixel for each
43  * point. Where pure black the lowest point and pure white denotes the highest.
44  *
45  * @author Mark Powell
46  * @version $Id$
47  */
48 public class RawHeightMap extends AbstractHeightMap {
49 
50     private static final Logger logger = Logger.getLogger(RawHeightMap.class.getName());
51     /**
52      * Format specification for 8 bit precision heightmaps
53      */
54     public static final int FORMAT_8BIT = 0;
55     /**
56      * Format specification for 16 bit little endian heightmaps
57      */
58     public static final int FORMAT_16BITLE = 1;
59     /**
60      * Format specification for 16 bit big endian heightmaps
61      */
62     public static final int FORMAT_16BITBE = 2;
63     private int format;
64     private boolean swapxy;
65     private InputStream stream;
66 
67     /**
68      * Constructor creates a new <code>RawHeightMap</code> object and loads a
69      * RAW image file to use as a height field. The greyscale image denotes the
70      * height of the terrain, where dark is low point and bright is high point.
71      * The values of the RAW correspond directly with the RAW values or 0 - 255.
72      *
73      * @param filename
74      *            the RAW file to use as the heightmap.
75      * @param size
76      *            the size of the RAW (must be square).
77      * @throws JmeException
78      *             if the filename is null or not RAW, and if the size is 0 or
79      *             less.
80      */
RawHeightMap(String filename, int size)81     public RawHeightMap(String filename, int size) throws Exception {
82         this(filename, size, FORMAT_8BIT, false);
83     }
84 
RawHeightMap(float heightData[])85     public RawHeightMap(float heightData[]) {
86         this.heightData = heightData;
87         this.size = (int) FastMath.sqrt(heightData.length);
88         this.format = FORMAT_8BIT;
89     }
90 
RawHeightMap(String filename, int size, int format, boolean swapxy)91     public RawHeightMap(String filename, int size, int format, boolean swapxy) throws Exception {
92         // varify that filename and size are valid.
93         if (null == filename || size <= 0) {
94             throw new Exception("Must supply valid filename and "
95                     + "size (> 0)");
96         }
97         try {
98             setup(new FileInputStream(filename), size, format, swapxy);
99         } catch (FileNotFoundException e) {
100             throw new Exception("height file not found: " + filename);
101         }
102     }
103 
RawHeightMap(InputStream stream, int size, int format, boolean swapxy)104     public RawHeightMap(InputStream stream, int size, int format, boolean swapxy) throws Exception {
105         setup(stream, size, format, swapxy);
106     }
107 
RawHeightMap(URL resource, int size, int format, boolean swapxy)108     public RawHeightMap(URL resource, int size, int format, boolean swapxy) throws Exception {
109         // varify that resource and size are valid.
110         if (null == resource || size <= 0) {
111             throw new Exception("Must supply valid resource and "
112                     + "size (> 0)");
113         }
114 
115 
116         try {
117             setup(resource.openStream(), size, format, swapxy);
118         } catch (IOException e) {
119             throw new Exception("Unable to open height url: " + resource);
120         }
121     }
122 
setup(InputStream stream, int size, int format, boolean swapxy)123     private void setup(InputStream stream, int size, int format, boolean swapxy) throws Exception {
124         // varify that filename and size are valid.
125         if (null == stream || size <= 0) {
126             throw new Exception("Must supply valid stream and "
127                     + "size (> 0)");
128         }
129 
130 
131         this.stream = stream;
132         this.size = size;
133         this.format = format;
134         this.swapxy = swapxy;
135         load();
136     }
137 
138     /**
139      * <code>load</code> fills the height data array with the appropriate data
140      * from the set RAW image. If the RAW image has not been set a JmeException
141      * will be thrown.
142      *
143      * @return true if the load is successfull, false otherwise.
144      */
145     @Override
load()146     public boolean load() {
147         // confirm data has been set. Redundant check...
148         if (null == stream || size <= 0) {
149             throw new RuntimeException("Must supply valid stream and "
150                     + "size (> 0)");
151         }
152 
153 
154         // clean up
155         if (null != heightData) {
156             unloadHeightMap();
157         }
158 
159 
160         // initialize the height data attributes
161         heightData = new float[size * size];
162 
163 
164         // attempt to connect to the supplied file.
165         BufferedInputStream bis = null;
166 
167 
168         try {
169             bis = new BufferedInputStream(stream);
170             if (format == RawHeightMap.FORMAT_16BITLE) {
171                 LittleEndien dis = new LittleEndien(bis);
172                 int index;
173                 // read the raw file
174                 for (int i = 0; i < size; i++) {
175                     for (int j = 0; j < size; j++) {
176                         if (swapxy) {
177                             index = i + j * size;
178                         } else {
179                             index = (i * size) + j;
180                         }
181                         heightData[index] = dis.readUnsignedShort();
182                     }
183                 }
184                 dis.close();
185             } else {
186                 DataInputStream dis = new DataInputStream(bis);
187                 // read the raw file
188                 for (int i = 0; i < size; i++) {
189                     for (int j = 0; j < size; j++) {
190                         int index;
191                         if (swapxy) {
192                             index = i + j * size;
193                         } else {
194                             index = (i * size) + j;
195                         }
196                         if (format == RawHeightMap.FORMAT_16BITBE) {
197                             heightData[index] = dis.readUnsignedShort();
198                         } else {
199                             heightData[index] = dis.readUnsignedByte();
200                         }
201                     }
202                 }
203                 dis.close();
204             }
205             bis.close();
206         } catch (IOException e1) {
207             logger.warning("Error reading height data from stream.");
208             return false;
209         }
210         return true;
211     }
212 
213     /**
214      * <code>setFilename</code> sets the file to use for the RAW data. A call
215      * to <code>load</code> is required to put the changes into effect.
216      *
217      * @param filename
218      *            the new file to use for the height data.
219      * @throws JmeException
220      *             if the file is null or not RAW.
221      */
setFilename(String filename)222     public void setFilename(String filename) throws Exception {
223         if (null == filename) {
224             throw new Exception("Must supply valid filename.");
225         }
226         try {
227             this.stream = new FileInputStream(filename);
228         } catch (FileNotFoundException e) {
229             throw new Exception("height file not found: " + filename);
230         }
231     }
232 
233     /**
234      * <code>setHeightStream</code> sets the stream to use for the RAW data. A call
235      * to <code>load</code> is required to put the changes into effect.
236      *
237      * @param stream
238      *            the new stream to use for the height data.
239      * @throws JmeException
240      *             if the stream is null or not RAW.
241      */
setHeightStream(InputStream stream)242     public void setHeightStream(InputStream stream) throws Exception {
243         if (null == stream) {
244             throw new Exception("Must supply valid stream.");
245         }
246         this.stream = stream;
247     }
248 }
249