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
34 /*!
35 \page coin_shaders Shaders in Coin
36
37 Coin 2.5 added support for shaders. The main nodes used are SoShaderProgram,
38 SoVertexShader, SoFragmentShader, and SoGeometryShader. A typical scene graph
39 with shaders will look something like this:
40
41 \code
42
43 Separator {
44 ShaderProgram {
45 shaderObject [
46 VertexShader {
47 sourceProgram "myvertexshader.glsl"
48 parameter [
49 ShaderParameter1f { name "myvertexparam" value 1.0 }
50 ]
51 }
52 FragmentShader {
53 sourceProgram "myfragmentshader.glsl"
54 parameter [
55 ShaderParameter1f { name "myfragmentparam" value 2.0 }
56 ]
57 }
58 ]
59 }
60 Cube { }
61 }
62
63 \endcode
64
65 This will render the Cube with the vertex and fragment shaders
66 specified in myvertexshader.glsl and myfragmentshader.glsl. Coin
67 also supports ARB shaders and Cg shaders (if the Cg library is
68 installed). However, we recommend using GLSL since we will focus
69 mostly on support this shader language.
70
71 Coin defines some named parameters that can be added by the
72 application programmer, and which will be automatically updated by
73 Coin while traversing the scene graph.
74
75 \li coin_texunit[n]_model - Set to 0 when texturing is disabled, and
76 to SoTextureImageElement::Model if there's a current texture on the state
77 for unit \a n.
78
79 \li coin_light_model - Set to 1 for PHONG, 0 for BASE_COLOR lighting.
80
81 \li coin_two_sided_lighting - Set to 1 for two-sided, 0 for normal
82
83 Example scene graph that renders per-fragment OpenGL Phong lighting
84 for one light source. The shaders assume the first light source is a
85 directional light. This is the case if you open the file in a standard
86 examiner viewer.
87
88 The iv-file:
89 \code
90 Separator {
91 ShaderProgram {
92 shaderObject [
93 VertexShader {
94 sourceProgram "perpixel_vertex.glsl"
95 }
96 FragmentShader {
97 sourceProgram "perpixel_fragment.glsl"
98 }
99 ]
100 }
101 Complexity { value 1.0 }
102 Material { diffuseColor 1 0 0 specularColor 1 1 1 shininess 0.9 }
103 Sphere { }
104
105 Translation { translation 3 0 0 }
106 Material { diffuseColor 0 1 0 specularColor 1 1 1 shininess 0.9 }
107 Cone { }
108
109 Translation { translation 3 0 0 }
110 Material { diffuseColor 0.8 0.4 0.1 specularColor 1 1 1 shininess 0.9 }
111 Cylinder { }
112 }
113 \endcode
114
115 The vertex shader (perpixel_vertex.glsl):
116 \code
117 varying vec3 ecPosition3;
118 varying vec3 fragmentNormal;
119
120 void main(void)
121 {
122 vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex;
123 ecPosition3 = ecPosition.xyz / ecPosition.w;
124 fragmentNormal = normalize(gl_NormalMatrix * gl_Normal);
125
126 gl_Position = ftransform();
127 gl_FrontColor = gl_Color;
128 }
129 \endcode
130
131 The fragment shader (perpixel_fragment.glsl):
132 \code
133 varying vec3 ecPosition3;
134 varying vec3 fragmentNormal;
135
136 void DirectionalLight(in int i,
137 in vec3 normal,
138 inout vec4 ambient,
139 inout vec4 diffuse,
140 inout vec4 specular)
141 {
142 float nDotVP; // normal . light direction
143 float nDotHV; // normal . light half vector
144 float pf; // power factor
145
146 nDotVP = max(0.0, dot(normal, normalize(vec3(gl_LightSource[i].position))));
147 nDotHV = max(0.0, dot(normal, vec3(gl_LightSource[i].halfVector)));
148
149 if (nDotVP == 0.0)
150 pf = 0.0;
151 else
152 pf = pow(nDotHV, gl_FrontMaterial.shininess);
153
154 ambient += gl_LightSource[i].ambient;
155 diffuse += gl_LightSource[i].diffuse * nDotVP;
156 specular += gl_LightSource[i].specular * pf;
157 }
158
159 void main(void)
160 {
161 vec3 eye = -normalize(ecPosition3);
162 vec4 ambient = vec4(0.0);
163 vec4 diffuse = vec4(0.0);
164 vec4 specular = vec4(0.0);
165 vec3 color;
166
167 DirectionalLight(0, normalize(fragmentNormal), ambient, diffuse, specular);
168
169 color =
170 gl_FrontLightModelProduct.sceneColor.rgb +
171 ambient.rgb * gl_FrontMaterial.ambient.rgb +
172 diffuse.rgb * gl_Color.rgb +
173 specular.rgb * gl_FrontMaterial.specular.rgb;
174
175 gl_FragColor = vec4(color, gl_Color.a);
176 }
177 \endcode
178 */
179
180 #include "shaders/SoShader.h"
181
182 #include <cassert>
183 #include <cstdio>
184 #include <cstdlib>
185
186 #include <Inventor/nodes/SoShaderProgram.h>
187 #include <Inventor/nodes/SoShaderObject.h>
188 #include <Inventor/nodes/SoFragmentShader.h>
189 #include <Inventor/nodes/SoVertexShader.h>
190 #include <Inventor/nodes/SoGeometryShader.h>
191 #include <Inventor/nodes/SoShaderParameter.h>
192 #include <Inventor/elements/SoGLShaderProgramElement.h>
193 #include <Inventor/C/tidbits.h>
194 #include <Inventor/errors/SoDebugError.h>
195
196 #include "glue/cg.h"
197 #include "misc/SbHash.h"
198 #include "tidbitsp.h"
199
200 // *************************************************************************
201
202 #include <data/shaders/lights/SpotLight.h>
203 #include <data/shaders/lights/PointLight.h>
204 #include <data/shaders/lights/DirectionalLight.h>
205 #include <data/shaders/lights/DirSpotLight.h>
206 #include <data/shaders/vsm/VsmLookup.h>
207
208 // *************************************************************************
209
210 static const char * SO_SHADER_DIR = NULL;
211 static SbHash<const char *, char *> * shader_dict = NULL;
212 static SbHash<const char *, char *> * shader_builtin_dict = NULL;
213
214 static void
soshader_cleanup(void)215 soshader_cleanup(void)
216 {
217 for(
218 SbHash<const char *, char *>::const_iterator iter =
219 shader_dict->const_begin();
220 iter!=shader_dict->const_end();
221 ++iter
222 ) {
223 delete[] iter->obj;
224 }
225 delete shader_dict;
226
227 // no need to apply on objects since strings are compiled into the
228 // library and should not be deleted
229 delete shader_builtin_dict;
230 }
231
232 void
init(void)233 SoShader::init(void)
234 {
235 // Trigger loading and init of Cg library glue.
236 //
237 // FIXME: this function should rather be used from the relevant
238 // class(es), so it is loaded only on demand. 20050125 mortene.
239 (void)cc_cgglue_available();
240
241 // --- initialization of elements (must be done first) ---------------
242 if (SoGLShaderProgramElement::getClassTypeId() == SoType::badType())
243 SoGLShaderProgramElement::initClass();
244
245 // --- initialization of shader nodes --------------------------------
246 if (SoShaderProgram::getClassTypeId() == SoType::badType())
247 SoShaderProgram::initClass();
248 if (SoShaderObject::getClassTypeId() == SoType::badType())
249 SoShaderObject::initClass();
250 if (SoFragmentShader::getClassTypeId() == SoType::badType())
251 SoFragmentShader::initClass();
252 if (SoVertexShader::getClassTypeId() == SoType::badType())
253 SoVertexShader::initClass();
254 if (SoGeometryShader::getClassTypeId() == SoType::badType())
255 SoGeometryShader::initClass();
256
257 // --- initialization of parameter nodes -----------------------------
258 if (SoShaderParameter::getClassTypeId() == SoType::badType())
259 SoShaderParameter::initClass();
260 if (SoUniformShaderParameter::getClassTypeId() == SoType::badType())
261 SoUniformShaderParameter::initClass();
262
263 // float vector parameter nodes
264 if (SoShaderParameter1f::getClassTypeId() == SoType::badType())
265 SoShaderParameter1f::initClass();
266 if (SoShaderParameter2f::getClassTypeId() == SoType::badType())
267 SoShaderParameter2f::initClass();
268 if (SoShaderParameter3f::getClassTypeId() == SoType::badType())
269 SoShaderParameter3f::initClass();
270 if (SoShaderParameter4f::getClassTypeId() == SoType::badType())
271 SoShaderParameter4f::initClass();
272
273 // float vector array parameter nodes
274 if (SoShaderParameterArray1f::getClassTypeId() == SoType::badType())
275 SoShaderParameterArray1f::initClass();
276 if (SoShaderParameterArray2f::getClassTypeId() == SoType::badType())
277 SoShaderParameterArray2f::initClass();
278 if (SoShaderParameterArray3f::getClassTypeId() == SoType::badType())
279 SoShaderParameterArray3f::initClass();
280 if (SoShaderParameterArray4f::getClassTypeId() == SoType::badType())
281 SoShaderParameterArray4f::initClass();
282
283 // matrix parameter nodes
284 if (SoShaderStateMatrixParameter::getClassTypeId() == SoType::badType())
285 SoShaderStateMatrixParameter::initClass();
286 if (SoShaderParameterMatrix::getClassTypeId() == SoType::badType())
287 SoShaderParameterMatrix::initClass();
288 if (SoShaderParameterMatrixArray::getClassTypeId() == SoType::badType())
289 SoShaderParameterMatrixArray::initClass();
290
291 // int32 support
292 if (SoShaderParameter1i::getClassTypeId() == SoType::badType())
293 SoShaderParameter1i::initClass();
294
295 // FIXME: Do we need int32 support (like in TGS)? 20040924 martin
296 #if 1
297 if (SoShaderParameter2i::getClassTypeId() == SoType::badType())
298 SoShaderParameter2i::initClass();
299 if (SoShaderParameter3i::getClassTypeId() == SoType::badType())
300 SoShaderParameter3i::initClass();
301 if (SoShaderParameter4i::getClassTypeId() == SoType::badType())
302 SoShaderParameter4i::initClass();
303 if (SoShaderParameterArray1i::getClassTypeId() == SoType::badType())
304 SoShaderParameterArray1i::initClass();
305 if (SoShaderParameterArray2i::getClassTypeId() == SoType::badType())
306 SoShaderParameterArray2i::initClass();
307 if (SoShaderParameterArray3i::getClassTypeId() == SoType::badType())
308 SoShaderParameterArray3i::initClass();
309 if (SoShaderParameterArray4i::getClassTypeId() == SoType::badType())
310 SoShaderParameterArray4i::initClass();
311 #endif
312
313 SO_SHADER_DIR = coin_getenv("SO_SHADER_DIR");
314 shader_dict = new SbHash<const char *, char *>;
315 shader_builtin_dict = new SbHash<const char *, char *>;
316 setupBuiltinShaders();
317
318 coin_atexit((coin_atexit_f*) soshader_cleanup, CC_ATEXIT_NORMAL);
319 }
320
321
322
323
324 const char *
getNamedScript(const SbName & name,const Type type)325 SoShader::getNamedScript(const SbName & name, const Type type)
326 {
327 char * shader = NULL;
328
329 if (SO_SHADER_DIR) {
330 SbString filename(SO_SHADER_DIR);
331 filename += "/";
332 filename += name.getString();
333
334 switch (type) {
335 case ARB_SHADER:
336 filename += ".arb";
337 break;
338 case CG_SHADER:
339 filename += ".cg";
340 break;
341 case GLSL_SHADER:
342 filename += ".glsl";
343 break;
344 default:
345 assert(0 && "unknown shader type");
346 break;
347 }
348
349 SbName shadername(filename.getString());
350
351 if (!shader_dict->get(shadername.getString(), shader)) {
352 FILE * fp = fopen(filename.getString(), "rb");
353 if (fp) {
354 (void) fseek(fp, 0, SEEK_END);
355 size_t size = (size_t) ftell(fp);
356 (void) fseek(fp, 0, SEEK_SET);
357
358 shader = new char[size+1];
359 shader[size] = 0;
360 shader_dict->put(shadername, shader);
361
362 if (!(fread(shader, size, 1, fp) == 1)) {
363 SoDebugError::postWarning("SoShader::getNamedScript",
364 "Unable to read shader: %s",
365 filename.getString());
366 }
367 fclose(fp);
368 }
369 else {
370 shader_dict->put(shadername, NULL);
371 SoDebugError::postWarning("SoShader::getNamedScript",
372 "Unable to find shader: %s",
373 filename.getString());
374 }
375 }
376 }
377 if (!shader) {
378 // try builtin shaders
379 if (!shader_builtin_dict->get(name.getString(), shader)) {
380 SoDebugError::postWarning("SoShader::getNamedScript",
381 "Unable to find builtin shader: %s",
382 name.getString());
383 }
384 }
385
386 return shader;
387 }
388
389 void
setupBuiltinShaders(void)390 SoShader::setupBuiltinShaders(void)
391 {
392 shader_builtin_dict->put(SbName("lights/PointLight").getString(), (char*) POINTLIGHT_shadersource);
393 shader_builtin_dict->put(SbName("lights/SpotLight").getString(), (char*) SPOTLIGHT_shadersource);
394 shader_builtin_dict->put(SbName("lights/DirectionalLight").getString(), (char*) DIRECTIONALLIGHT_shadersource);
395 shader_builtin_dict->put(SbName("lights/DirSpotLight").getString(), (char*) DIRSPOTLIGHT_shadersource);
396 shader_builtin_dict->put(SbName("vsm/VsmLookup").getString(), (char*) VSMLOOKUP_shadersource);
397 }
398