• 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 
33 package com.jme3.terrain.heightmap;
34 
35 import java.nio.ByteBuffer;
36 import com.jme3.math.ColorRGBA;
37 import com.jme3.texture.Image;
38 import java.nio.ShortBuffer;
39 
40 /**
41  * <code>ImageBasedHeightMap</code> is a height map created from the grayscale
42  * conversion of an image. The image used currently must have an equal height
43  * and width, although future work could scale an incoming image to a specific
44  * height and width.
45  *
46  * @author Mike Kienenberger
47  * @version $id$
48  */
49 public class ImageBasedHeightMap extends AbstractHeightMap implements ImageHeightmap {
50 
51 
52     protected Image colorImage;
53 
54 
setImage(Image image)55     public void setImage(Image image) {
56         this.colorImage = image;
57     }
58 
59     /**
60      * Creates a HeightMap from an Image. The image will be converted to
61      * grayscale, and the grayscale values will be used to generate the height
62      * map. White is highest point while black is lowest point.
63      *
64      * Currently, the Image used must be square (width == height), but future
65      * work could rescale the image.
66      *
67      * @param colorImage
68      *            Image to map to the height map.
69      */
ImageBasedHeightMap(Image colorImage)70     public ImageBasedHeightMap(Image colorImage) {
71         this.colorImage = colorImage;
72     }
73 
ImageBasedHeightMap(Image colorImage, float heightScale)74     public ImageBasedHeightMap(Image colorImage, float heightScale) {
75     	this.colorImage = colorImage;
76         this.heightScale = heightScale;
77     }
78 
79     /**
80      * Loads the image data from top left to bottom right
81      */
load()82     public boolean load() {
83         return load(false, false);
84     }
85 
86     /**
87      * Get the grayscale value, or override in your own sub-classes
88      */
calculateHeight(float red, float green, float blue)89     protected float calculateHeight(float red, float green, float blue) {
90         return (float) (0.299 * red + 0.587 * green + 0.114 * blue);
91     }
92 
load(boolean flipX, boolean flipY)93     public boolean load(boolean flipX, boolean flipY) {
94 
95         int imageWidth = colorImage.getWidth();
96         int imageHeight = colorImage.getHeight();
97 
98         if (imageWidth != imageHeight)
99                 throw new RuntimeException("imageWidth: " + imageWidth
100                         + " != imageHeight: " + imageHeight);
101 
102         size = imageWidth;
103 
104         ByteBuffer buf = colorImage.getData(0);
105 
106         heightData = new float[(imageWidth * imageHeight)];
107 
108         ColorRGBA colorStore = new ColorRGBA();
109 
110         int index = 0;
111         if (flipY) {
112             for (int h = 0; h < imageHeight; ++h) {
113                 if (flipX) {
114                     for (int w = imageWidth - 1; w >= 0; --w) {
115                         int baseIndex = (h * imageWidth)+ w;
116                         heightData[index++] = getHeightAtPostion(buf, colorImage, baseIndex, colorStore)*heightScale;
117                     }
118                 } else {
119                     for (int w = 0; w < imageWidth; ++w) {
120                         int baseIndex = (h * imageWidth)+ w;
121                         heightData[index++] = getHeightAtPostion(buf, colorImage, baseIndex, colorStore)*heightScale;
122                     }
123                 }
124             }
125         } else {
126             for (int h = imageHeight - 1; h >= 0; --h) {
127                 if (flipX) {
128                     for (int w = imageWidth - 1; w >= 0; --w) {
129                         int baseIndex = (h * imageWidth)+ w;
130                         heightData[index++] = getHeightAtPostion(buf, colorImage, baseIndex, colorStore)*heightScale;
131                     }
132                 } else {
133                     for (int w = 0; w < imageWidth; ++w) {
134                         int baseIndex = (h * imageWidth)+ w;
135                         heightData[index++] = getHeightAtPostion(buf, colorImage, baseIndex, colorStore)*heightScale;
136                     }
137                 }
138             }
139         }
140 
141         return true;
142     }
143 
getHeightAtPostion(ByteBuffer buf, Image image, int position, ColorRGBA store)144     protected float getHeightAtPostion(ByteBuffer buf, Image image, int position, ColorRGBA store) {
145         switch (image.getFormat()){
146             case RGBA8:
147                 buf.position( position * 4 );
148                 store.set(byte2float(buf.get()), byte2float(buf.get()), byte2float(buf.get()), byte2float(buf.get()));
149                 return calculateHeight(store.r, store.g, store.b);
150             case ABGR8:
151                 buf.position( position * 4 );
152                 float a = byte2float(buf.get());
153                 float b = byte2float(buf.get());
154                 float g = byte2float(buf.get());
155                 float r = byte2float(buf.get());
156                 store.set(r,g,b,a);
157                 return calculateHeight(store.r, store.g, store.b);
158             case RGB8:
159                 buf.position( position * 3 );
160                 store.set(byte2float(buf.get()), byte2float(buf.get()), byte2float(buf.get()), 1);
161                 return calculateHeight(store.r, store.g, store.b);
162             case Luminance8:
163                 buf.position( position );
164                 return byte2float(buf.get())*255*heightScale;
165             case Luminance16:
166                 ShortBuffer sbuf = buf.asShortBuffer();
167                 sbuf.position( position );
168                 return (sbuf.get() & 0xFFFF) / 65535f * 255f * heightScale;
169             default:
170                 throw new UnsupportedOperationException("Image format: "+image.getFormat());
171         }
172     }
173 
byte2float(byte b)174     private float byte2float(byte b){
175         return ((float)(b & 0xFF)) / 255f;
176     }
177 }