1 /**************************************************************************\
2 * Copyright (c) Kongsberg Oil & Gas Technologies AS
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 notice,
10 * 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 the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software 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
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32
33 #include <Inventor/engines/SoHeightMapToNormalMap.h>
34
35 #include <boost/scoped_array.hpp>
36
37 #include <Inventor/SbVec3f.h>
38 #include <Inventor/SbImage.h>
39 #include "engines/SoSubEngineP.h"
40
41 /*!
42 \class SoHeightMapToNormalMap SoHeightMapToNormalMap.h Inventor/engines/SoHeightMapToNormalMap.h
43 \brief Engine for computing a normal map from a height map.
44
45 This engine will create a normal map texture from a height map texture.
46 You can use it in an Inventor file like this:
47
48 \code
49 Texture2 {
50 image = HeightMapToNormalMap {
51 sourceImage = Texture2 { filename "HeightMap.jpg" } . image
52 } . image
53 }
54 \endcode
55
56 Be aware that the field connections will remain active, so both
57 Texture2 nodes and the HeightMapToNormalMap engine will be kept resident
58 in memory (unless you intervene manually and detach the engine) even
59 though only the "outer" Texture2 node is needed. This can give quite
60 a big memory use overhead.
61
62 \ingroup engines
63 \COIN_CLASS_EXTENSION
64 \since Coin 3.0
65 */
66
67 /*!
68 \enum SoHeightMapToNormalMap::NormalMapFormat
69 Enumeration of available normal map formats.
70 */
71
72 /*!
73 \var SoHeightMapToNormalMap::NormalMapFormat SoHeightMapToNormalMap::INT8
74 Encode the normals as a 3 component byte texture.
75 This is the only option for now, as long as float textures are not conveniently
76 supported in Coin.
77 */
78
79 /*!
80 \var SoMFEnum SoHeightMapToNormalMap::format
81 This setting decides what kind of normal map is generated. For now, only the
82 INT8 format is available, and it is the default value.
83 */
84
85 SO_ENGINE_SOURCE(SoHeightMapToNormalMap);
86
87 /*!
88 Class initializer.
89 */
90 void
initClass(void)91 SoHeightMapToNormalMap::initClass(void)
92 {
93 SO_ENGINE_INTERNAL_INIT_CLASS(SoHeightMapToNormalMap);
94 }
95
96 /*!
97 Constructor.
98 */
SoHeightMapToNormalMap(void)99 SoHeightMapToNormalMap::SoHeightMapToNormalMap(void)
100 {
101 SO_ENGINE_INTERNAL_CONSTRUCTOR(SoHeightMapToNormalMap);
102
103 SO_ENGINE_ADD_INPUT(format, (INT8));
104
105 SO_ENGINE_DEFINE_ENUM_VALUE(NormalMapFormat, INT8);
106 SO_ENGINE_SET_SF_ENUM_TYPE(format, NormalMapFormat);
107 }
108
109 /*!
110 Static function for computing a normal map from a height map.
111 This function can be used directly without any engine instantiation.
112 */
113 void
convert(const unsigned char * srcptr,SbVec2s size,int nc,SbImage & dst_out)114 SoHeightMapToNormalMap::convert(const unsigned char * srcptr, SbVec2s size, int nc, SbImage & dst_out)
115 {
116 float dx, dy;
117 int width = size[0];
118 int height = size[1];
119 boost::scoped_array<unsigned char> dstarray(new unsigned char[width*height*3]);
120 unsigned char * dstptr = dstarray.get();
121 unsigned char red;
122 SbVec3f n;
123
124 #define GET_PIXEL_RED(x_, y_) \
125 srcptr[(y_)*width*nc + (x_)*nc]
126
127 for (int y = 0; y < height; y++) {
128 for (int x = 0; x < width; x++) {
129 // do Y Sobel filter
130 red = GET_PIXEL_RED((x-1+width) % width, (y+1) % height);
131 dy = static_cast<float>(red) / 255.0f * -1.0f;
132
133 red = GET_PIXEL_RED(x % width, (y+1) % height);
134 dy += static_cast<float>(red) / 255.0f * -2.0f;
135
136 red = GET_PIXEL_RED((x+1) % width, (y+1) % height);
137 dy += static_cast<float>(red) / 255.0f * -1.0f;
138
139 red = GET_PIXEL_RED((x-1+width) % width, (y-1+height) % height);
140 dy += static_cast<float>(red) / 255.0f * 1.0f;
141
142 red = GET_PIXEL_RED(x % width, (y-1+height) % height);
143 dy += static_cast<float>(red) / 255.0f * 2.0f;
144
145 red = GET_PIXEL_RED((x+1) % width, (y-1+height) % height);
146 dy += static_cast<float>(red) / 255.0f * 1.0f;
147
148 // Do X Sobel filter
149 red = GET_PIXEL_RED((x-1+width) % width, (y-1+height) % height);
150 dx = static_cast<float>(red) / 255.0f * -1.0f;
151
152 red = GET_PIXEL_RED((x-1+width) % width, y % height);
153 dx += static_cast<float>(red) / 255.0f * -2.0f;
154
155 red = GET_PIXEL_RED((x-1+width) % width, (y+1) % height);
156 dx += static_cast<float>(red) / 255.0f * -1.0f;
157
158 red = GET_PIXEL_RED((x+1) % width, (y-1+height) % height);
159 dx += static_cast<float>(red) / 255.0f * 1.0f;
160
161 red = GET_PIXEL_RED((x+1) % width, y % height);
162 dx += static_cast<float>(red) / 255.0f * 2.0f;
163
164 red = GET_PIXEL_RED((x+1) % width, (y+1) % height);
165 dx += static_cast<float>(red) / 255.0f * 1.0f;
166
167 n[0] = -dx;
168 n[1] = -dy;
169 n[2] = 1.0f;
170 (void) n.normalize();
171
172 *dstptr++ = static_cast<unsigned char>(SbMin((n[0]+1.0f) * 128.0f, 255.0f));
173 *dstptr++ = static_cast<unsigned char>(SbMin((n[1]+1.0f) * 128.0f, 255.0f));
174 *dstptr++ = static_cast<unsigned char>(SbMin((n[2]+1.0f) * 128.0f, 255.0f));
175 }
176 }
177 #undef GET_PIXEL_RED
178 dst_out.setValue(size, 3, dstarray.get());
179 }
180
181 void
inputChanged(SoField * which)182 SoHeightMapToNormalMap::inputChanged(SoField * which)
183 {
184 // in case we need to override later
185 inherited::inputChanged(which);
186 }
187
188 void
evaluate(void)189 SoHeightMapToNormalMap::evaluate(void)
190 {
191 SbVec2s size;
192 int nc;
193 const unsigned char * ptr =
194 static_cast<const unsigned char *>(sourceImage.getValue(size, nc));
195
196 SbImage targetimg;
197 SoHeightMapToNormalMap::convert(ptr, size, nc, targetimg);
198
199 ptr = static_cast<const unsigned char *>(targetimg.getValue(size, nc));
200 SO_ENGINE_OUTPUT(image, SoSFImage, setValue(size, nc, ptr));
201 }
202