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 \class SoShaderObject SoShaderObject.h Inventor/nodes/SoShaderObject.h
35 \brief The SoShaderObject class is the superclass for all shader classes in Coin.
36
37 See \ref coin_shaders "Shaders in Coin" for more information
38 on how to set up a scene graph with shaders.
39
40 \ingroup shaders
41
42 \sa SoShaderProgram
43 */
44
45 /*!
46 \var SoSFBool SoShaderObject::isActive
47
48 Enabled/disables the shader. Default value is TRUE.
49 */
50
51 /*!
52 \var SoSFString SoShaderObject::sourceProgram
53
54 The shader program, or a file name if the shader should be loaded from a file.
55 If the shader is loaded from a file, the shader type is identified by the
56 file extension. .glsl for GLSL shaders, .cg for Cg shaders, and .vp and .fp
57 for ARB shaders.
58 */
59
60
61 /*!
62 \var SoSFEnum SoShaderObject::sourceType
63
64 The type of shader.
65 */
66
67
68 /*!
69 \enum SoShaderObject::SourceType
70
71 Used for enumerating the shader types in sourceProgram.
72 */
73
74 /*!
75 \var SoShaderObject::SourceType SoShaderObject::ARB_PROGRAM
76
77 Specifies an ARB shader.
78 */
79
80 /*!
81 \var SoShaderObject::SourceType SoShaderObject::CG_PROGRAM
82
83 Specifies a Cg shader program.
84 */
85
86 /*!
87 \var SoShaderObject::SourceType SoShaderObject::GLSL_PROGRAM
88
89 Specifies a GLSL program.
90 */
91
92 /*!
93 \var SoShaderObject::SourceType SoShaderObject::FILENAME
94
95 Shader should be loaded from the file in sourceProgram.
96 */
97
98
99 /*!
100 \var SoMFNode SoShaderObject::parameter
101
102 The shader program parameters.
103 */
104
105 #include <Inventor/nodes/SoShaderObject.h>
106
107 #include <cassert>
108
109 #include <Inventor/actions/SoGLRenderAction.h>
110 #include <Inventor/actions/SoSearchAction.h>
111 #include <Inventor/elements/SoGLCacheContextElement.h>
112 #include <Inventor/elements/SoGLShaderProgramElement.h>
113 #include <Inventor/elements/SoGLMultiTextureImageElement.h>
114 #include <Inventor/elements/SoLazyElement.h>
115 #include <Inventor/misc/SoContextHandler.h>
116 #include <Inventor/misc/SoGLDriverDatabase.h>
117 #include <Inventor/errors/SoDebugError.h>
118 #include <Inventor/nodes/SoFragmentShader.h>
119 #include <Inventor/nodes/SoShaderParameter.h>
120 #include <Inventor/nodes/SoVertexShader.h>
121 #include <Inventor/nodes/SoGeometryShader.h>
122 #include <Inventor/sensors/SoNodeSensor.h>
123 #include <Inventor/SoInput.h>
124 #include <Inventor/lists/SbStringList.h>
125
126 #include "nodes/SoSubNodeP.h"
127 #include "misc/SbHash.h"
128 #include "shaders/SoGLARBShaderObject.h"
129 #include "shaders/SoGLCgShaderObject.h"
130 #include "shaders/SoGLSLShaderObject.h"
131 #include "shaders/SoGLShaderProgram.h"
132
133 // *************************************************************************
134
135 class SoShaderObjectP
136 {
137 public:
138 SoShaderObjectP(SoShaderObject *ownerptr);
139 ~SoShaderObjectP();
140
141 void GLRender(SoGLRenderAction *action);
142
getGLShaderObject(const uint32_t cachecontext)143 SoGLShaderObject * getGLShaderObject(const uint32_t cachecontext) {
144 SoGLShaderObject * obj = NULL;
145 if (this->glshaderobjects.get(cachecontext, obj)) return obj;
146 return NULL;
147 }
setGLShaderObject(SoGLShaderObject * obj,const uint32_t cachecontext)148 void setGLShaderObject(SoGLShaderObject * obj, const uint32_t cachecontext) {
149 SoGLShaderObject * oldshader;
150 if (this->glshaderobjects.get(cachecontext, oldshader)) {
151 SoGLCacheContextElement::scheduleDeleteCallback(oldshader->getCacheContext(),
152 really_delete_object, oldshader);
153 }
154 (void) this->glshaderobjects.put(cachecontext, obj);
155 }
deleteGLShaderObjects(void)156 void deleteGLShaderObjects(void) {
157 SbList <uint32_t> keylist;
158 this->glshaderobjects.makeKeyList(keylist);
159 for (int i = 0; i < keylist.getLength(); i++) {
160 SoGLShaderObject * glshader = NULL;
161 (void) this->glshaderobjects.get(keylist[i], glshader);
162 SoGLCacheContextElement::scheduleDeleteCallback(glshader->getCacheContext(),
163 really_delete_object, glshader);
164 }
165 this->glshaderobjects.clear();
166 }
167 //
168 // Callback from SoGLCacheContextElement
169 //
really_delete_object(void * closure,uint32_t COIN_UNUSED_ARG (contextid))170 static void really_delete_object(void * closure, uint32_t COIN_UNUSED_ARG(contextid)) {
171 SoGLShaderObject * obj = (SoGLShaderObject*) closure;
172 delete obj;
173 }
174 //
175 // callback from SoContextHandler
176 //
context_destruction_cb(uint32_t cachecontext,void * userdata)177 static void context_destruction_cb(uint32_t cachecontext, void * userdata) {
178 SoShaderObjectP * thisp = (SoShaderObjectP*) userdata;
179
180 SoGLShaderObject * oldshader;
181 if (thisp->glshaderobjects.get(cachecontext, oldshader)) {
182 // just delete immediately. The context is current
183 delete oldshader;
184 thisp->glshaderobjects.erase(cachecontext);
185 }
186 }
187
invalidateParameters(void)188 void invalidateParameters(void) {
189 SbList <uint32_t> keylist;
190 this->glshaderobjects.makeKeyList(keylist);
191 for (int i = 0; i < keylist.getLength(); i++) {
192 SoGLShaderObject * glshader = NULL;
193 (void) this->glshaderobjects.get(keylist[i], glshader);
194 glshader->setParametersDirty(TRUE);
195 }
196 }
197
198 SoShaderObject * owner;
199 SoShaderObject::SourceType cachedSourceType;
200 SbString cachedSourceProgram;
201 SbBool didSetSearchDirectories;
202 SbBool shouldload;
203 SoNodeSensor *sensor;
204
205 void updateParameters(const uint32_t cachecontext, int start, int num);
206 void updateAllParameters(const uint32_t cachecontext);
207 void updateCoinParameters(const uint32_t cachecontext, SoState * state);
208 void updateStateMatrixParameters(const uint32_t cachecontext, SoState * state);
209 SbBool containStateMatrixParameters(void) const;
210 void setSearchDirectories(const SbStringList & list);
211
212 private:
213 static void sensorCB(void *data, SoSensor *);
214
215 SbStringList searchdirectories;
216 SbHash<uint32_t, SoGLShaderObject *> glshaderobjects;
217
218 void checkType(void); // sets cachedSourceType
219 void readSource(void); // sets cachedSourceProgram depending on sourceType
220
221 SbBool isSupported(SoShaderObject::SourceType sourceType, const cc_glglue * glue);
222
223 #if defined(SOURCE_HINT)
224 SbString getSourceHint(void) const;
225 #endif
226 };
227
228 #define PRIVATE(obj) ((obj)->pimpl)
229
230 // *************************************************************************
231
232 SO_NODE_ABSTRACT_SOURCE(SoShaderObject);
233
234 // *************************************************************************
235
236 // doc from parent
initClass(void)237 void SoShaderObject::initClass(void)
238 {
239 SO_NODE_INTERNAL_INIT_ABSTRACT_CLASS(SoShaderObject,
240 SO_FROM_COIN_2_5|SO_FROM_INVENTOR_5_0);
241 }
242
243 /*!
244 Constructor.
245 */
SoShaderObject(void)246 SoShaderObject::SoShaderObject(void)
247 {
248 SO_NODE_INTERNAL_CONSTRUCTOR(SoShaderObject);
249
250 SO_NODE_ADD_FIELD(isActive, (TRUE));
251
252 SO_NODE_DEFINE_ENUM_VALUE(SourceType, ARB_PROGRAM);
253 SO_NODE_DEFINE_ENUM_VALUE(SourceType, CG_PROGRAM);
254 SO_NODE_DEFINE_ENUM_VALUE(SourceType, GLSL_PROGRAM);
255 SO_NODE_DEFINE_ENUM_VALUE(SourceType, FILENAME);
256
257 SO_NODE_ADD_FIELD(sourceType, (FILENAME));
258 SO_NODE_SET_SF_ENUM_TYPE(sourceType, SourceType);
259
260 SO_NODE_ADD_FIELD(sourceProgram, (""));
261 SO_NODE_ADD_FIELD(parameter, (NULL));
262 this->parameter.setNum(0);
263 this->parameter.setDefault(TRUE);
264
265 PRIVATE(this) = new SoShaderObjectP(this);
266 }
267
268 /*!
269 Destructor
270 */
~SoShaderObject()271 SoShaderObject::~SoShaderObject()
272 {
273 delete PRIVATE(this);
274 }
275
276 // doc from parent
277 void
GLRender(SoGLRenderAction * action)278 SoShaderObject::GLRender(SoGLRenderAction * action)
279 {
280 PRIVATE(this)->GLRender(action);
281 }
282
283 // doc from parent
284 void
search(SoSearchAction * action)285 SoShaderObject::search(SoSearchAction * action)
286 {
287 // Include this node in the search.
288 SoNode::search(action);
289 if (action->isFound()) return;
290
291 // we really can't do this since this node hasn't got an SoChildList
292 // instance
293 #if 0 // disabled, not possible to search under this node
294 int numindices;
295 const int * indices;
296 if (action->getPathCode(numindices, indices) == SoAction::IN_PATH) {
297 // FIXME: not implemented -- 20050129 martin
298 }
299 else { // traverse all shader parameter
300 int num = this->parameter.getNum();
301 for (int i=0; i<num; i++) {
302 SoNode * node = this->parameter[i];
303 action->pushCurPath(i, node);
304 SoNodeProfiling profiling;
305 profiling.preTraversal(action);
306 node->search(action);
307 profiling.postTraversal(action);
308 action->popCurPath();
309 if (action->isFound()) return;
310 }
311 }
312 #endif // disabled
313 }
314
315 // doc from parent
316 SbBool
readInstance(SoInput * in,unsigned short flags)317 SoShaderObject::readInstance(SoInput * in, unsigned short flags)
318 {
319 PRIVATE(this)->sensor->detach();
320 PRIVATE(this)->deleteGLShaderObjects();
321
322 SbBool ret = inherited::readInstance(in, flags);
323 if (ret) {
324 PRIVATE(this)->setSearchDirectories(SoInput::getDirectories());
325 }
326 PRIVATE(this)->sensor->attach(this);
327
328 return ret;
329 }
330
331 /*!
332 Returns the shader type detected in sourceProgram.
333 */
334 SoShaderObject::SourceType
getSourceType(void) const335 SoShaderObject::getSourceType(void) const
336 {
337 return PRIVATE(this)->cachedSourceType;
338 }
339
340 /*!
341 Returns the actual shader program.
342 */
getSourceProgram(void) const343 SbString SoShaderObject::getSourceProgram(void) const
344 {
345 return PRIVATE(this)->cachedSourceProgram;
346 }
347
348 /*!
349 Used internally to update shader paramters.
350 */
351 void
updateParameters(SoState * state)352 SoShaderObject::updateParameters(SoState * state)
353 {
354 const uint32_t cachecontext = SoGLCacheContextElement::get(state);
355 PRIVATE(this)->updateAllParameters(cachecontext);
356 PRIVATE(this)->updateStateMatrixParameters(cachecontext, state);
357 PRIVATE(this)->updateCoinParameters(cachecontext, state);
358 }
359
360 /* ***************************************************************************
361 * *** private implementation of SoShaderObjectP ***
362 * ***************************************************************************/
363
SoShaderObjectP(SoShaderObject * ownerptr)364 SoShaderObjectP::SoShaderObjectP(SoShaderObject * ownerptr)
365 {
366 this->owner = ownerptr;
367 this->sensor = new SoNodeSensor(SoShaderObjectP::sensorCB, this);
368 this->sensor->setPriority(0);
369 this->sensor->attach(ownerptr);
370
371 this->cachedSourceType = SoShaderObject::FILENAME;
372 this->didSetSearchDirectories = FALSE;
373 this->shouldload = TRUE;
374
375 SoContextHandler::addContextDestructionCallback(context_destruction_cb, this);
376 }
377
~SoShaderObjectP()378 SoShaderObjectP::~SoShaderObjectP()
379 {
380 SoContextHandler::removeContextDestructionCallback(context_destruction_cb, this);
381
382 this->deleteGLShaderObjects();
383
384 SbStringList empty;
385 this->setSearchDirectories(empty);
386 delete this->sensor;
387 }
388
389 void
GLRender(SoGLRenderAction * action)390 SoShaderObjectP::GLRender(SoGLRenderAction * action)
391 {
392 SbBool isactive = this->owner->isActive.getValue();
393 if (!isactive) return;
394
395 SoState * state = action->getState();
396
397 SoGLShaderProgram * shaderProgram = SoGLShaderProgramElement::get(state);
398 if (!shaderProgram) {
399 SoDebugError::postWarning("SoShaderObject::GLRender",
400 "SoShaderObject seems to not be under a SoShaderProgram node");
401 return;
402 }
403
404 const uint32_t cachecontext = SoGLCacheContextElement::get(state);
405 const cc_glglue * glue = cc_glglue_instance(cachecontext);
406
407 SoGLShaderObject * shaderobject = this->getGLShaderObject(cachecontext);
408
409 if (this->owner->sourceProgram.isDefault() ||
410 this->owner->sourceProgram.getValue().getLength() == 0) { return; }
411
412 if (shaderobject == NULL) {
413 if (this->shouldload) {
414 this->checkType(); // set this->cachedSourceType
415 this->readSource(); // set this->cachedSourceProgram
416 this->shouldload = FALSE;
417 }
418 // if file could not be read
419 if (this->cachedSourceType == SoShaderObject::FILENAME) return;
420
421 if (!this->isSupported(this->cachedSourceType, glue)) {
422 SbString s;
423 switch (this->cachedSourceType) {
424 case SoShaderObject::ARB_PROGRAM: s = "ARB_PROGRAM"; break;
425 case SoShaderObject::CG_PROGRAM: s = "CG_PROGRAM"; break;
426 case SoShaderObject::GLSL_PROGRAM: s = "GLSL_PROGRAM"; break;
427 default: assert(FALSE && "unknown shader");
428 }
429 SoDebugError::postWarning("SoShaderObjectP::GLRender",
430 "%s is not supported", s.getString());
431 return;
432 }
433
434 switch (this->cachedSourceType) {
435 case SoShaderObject::ARB_PROGRAM:
436 shaderobject = new SoGLARBShaderObject(cachecontext);
437 break;
438 case SoShaderObject::CG_PROGRAM:
439 shaderobject = new SoGLCgShaderObject(cachecontext);
440 break;
441 case SoShaderObject::GLSL_PROGRAM:
442 shaderobject = new SoGLSLShaderObject(cachecontext);
443 break;
444 default:
445 assert(FALSE && "This shouldn't happen!");
446 }
447
448 if (this->owner->isOfType(SoVertexShader::getClassTypeId())) {
449 shaderobject->setShaderType(SoGLShaderObject::VERTEX);
450 }
451 else if (this->owner->isOfType(SoFragmentShader::getClassTypeId())) {
452 shaderobject->setShaderType(SoGLShaderObject::FRAGMENT);
453 }
454 else {
455 assert(this->owner->isOfType(SoGeometryShader::getClassTypeId()));
456 shaderobject->setShaderType(SoGLShaderObject::GEOMETRY);
457
458 //SoGeometryShader * geomshader = (SoGeometryShader*) this->owner;
459
460 }
461
462 #if defined(SOURCE_HINT)
463 shaderobject->sourceHint = getSourceHint();
464 #endif
465 shaderobject->load(this->cachedSourceProgram.getString());
466 this->setGLShaderObject(shaderobject, cachecontext);
467 }
468 if (shaderobject) {
469 shaderProgram->addShaderObject(shaderobject);
470 shaderobject->setIsActive(isactive);
471 }
472 }
473
474 // sets this->cachedSourceType to [ARB|CG|GLSL]_PROGRAM
475 // this->cachedSourceType will be set to FILENAME, if sourceType is unknown
476 void
checkType(void)477 SoShaderObjectP::checkType(void)
478 {
479 this->cachedSourceType =
480 (SoShaderObject::SourceType)this->owner->sourceType.getValue();
481
482 if (this->cachedSourceType != SoShaderObject::FILENAME) return;
483
484 // determine sourceType from file extension
485 SbString fileName = this->owner->sourceProgram.getValue();
486 int len = fileName.getLength();
487 if (len > 5) {
488 SbString subStr = fileName.getSubString(len-5);
489 if (subStr == ".glsl" || subStr == ".vert" || subStr == ".frag") {
490 this->cachedSourceType = SoShaderObject::GLSL_PROGRAM;
491 return;
492 }
493 }
494 if (len > 3) {
495 SbString subStr = fileName.getSubString(len-3);
496 if (subStr == ".cg") {
497 this->cachedSourceType = SoShaderObject::CG_PROGRAM;
498 return;
499 }
500 if (subStr == ".fp") {
501 this->cachedSourceType = this->owner->isOfType(SoVertexShader::getClassTypeId())
502 ? SoShaderObject::FILENAME : SoShaderObject::ARB_PROGRAM;
503 return;
504 }
505 if (subStr==".vp") {
506 this->cachedSourceType = this->owner->isOfType(SoVertexShader::getClassTypeId())
507 ? SoShaderObject::ARB_PROGRAM : SoShaderObject::FILENAME;
508 return;
509 }
510 }
511 SoDebugError::postWarning("SoShaderObjectP::checkType",
512 "Could not determine shader type of file '%s'!\n"
513 "Following file extensions are supported:\n"
514 "*.fp -> ARB_PROGRAM (fragment)\n"
515 "*.vp -> ARB_PROGRAM (vertex)\n"
516 "*.cg -> CG_PROGRAM (fragment|vertex)\n"
517 "*.glsl *.vert *.frag -> GLSL_PROGRAM (fragment|vertex)\n",
518 fileName.getString());
519 // error: could not determine SourceType
520 this->cachedSourceType = SoShaderObject::FILENAME;
521 }
522
523 // read the file if neccessary and assign content to this->cachedSourceProgram
524 void
readSource(void)525 SoShaderObjectP::readSource(void)
526 {
527 SoShaderObject::SourceType srcType =
528 (SoShaderObject::SourceType)this->owner->sourceType.getValue();
529
530 this->cachedSourceProgram.makeEmpty();
531
532 if (this->owner->sourceProgram.isDefault())
533 return;
534 else if (srcType != SoShaderObject::FILENAME)
535 this->cachedSourceProgram = this->owner->sourceProgram.getValue();
536 else {
537 if (this->cachedSourceType != SoShaderObject::FILENAME) {
538
539 SbStringList subdirs;
540 subdirs.append(new SbString("shader"));
541 subdirs.append(new SbString("shaders"));
542 SbString fileName = SoInput::searchForFile(this->owner->sourceProgram.getValue(),
543 this->searchdirectories,
544 subdirs);
545 // delete allocated subdirs before continuing
546 delete subdirs[0];
547 delete subdirs[1];
548
549 if (fileName.getLength() <= 0) {
550 SoDebugError::postWarning("SoShaderObjectP::readSource",
551 "Shader file not found: '%s'",
552 this->owner->sourceProgram.getValue().getString());
553 this->cachedSourceType = SoShaderObject::FILENAME;
554 return;
555 }
556
557 FILE * f = fopen(fileName.getString(), "rb");
558 SbBool readok = FALSE;
559 if (f) {
560 if (fseek(f, 0L, SEEK_END) == 0) {
561 const long length = ftell(f);
562 if ((length > 0) && (fseek(f, 0L, SEEK_SET) == 0)) {
563 char * srcstr = new char[length+1];
564 size_t readlen = fread(srcstr, 1, length, f);
565 if (readlen == (size_t) length) {
566 srcstr[length] = '\0';
567 this->cachedSourceProgram = srcstr;
568 readok = TRUE;
569 }
570 delete[] srcstr;
571 }
572 }
573 fclose(f);
574 }
575 if (!readok) {
576 this->cachedSourceType = SoShaderObject::FILENAME;
577 SoDebugError::postWarning("SoShaderObjectP::readSource",
578 "Could not read shader file '%s'",
579 fileName.getString());
580 }
581 }
582 }
583 }
584
585 SbBool
isSupported(SoShaderObject::SourceType sourceType,const cc_glglue * glue)586 SoShaderObjectP::isSupported(SoShaderObject::SourceType sourceType, const cc_glglue * glue)
587 {
588 if (this->owner->isOfType(SoVertexShader::getClassTypeId())) {
589 // don't call this function. It's not context safe. pederb, 20051103
590 // return SoVertexShader::isSupported(sourceType);
591
592 if (sourceType == SoShaderObject::ARB_PROGRAM) {
593 return SoGLDriverDatabase::isSupported(glue, SO_GL_ARB_VERTEX_PROGRAM);
594 }
595 else if (sourceType == SoShaderObject::GLSL_PROGRAM) {
596 return SoGLDriverDatabase::isSupported(glue, SO_GL_ARB_SHADER_OBJECT);
597 }
598 // FIXME: Add support for detecting missing Cg support
599 // (20050427 handegar)
600 else if (sourceType == SoShaderObject::CG_PROGRAM) return TRUE;
601 return FALSE;
602 }
603 else if (this->owner->isOfType(SoFragmentShader::getClassTypeId())) {
604 // don't call this function. It's not context safe. pederb, 20051103
605 // return SoFragmentShader::isSupported(sourceType);
606
607 if (sourceType == SoShaderObject::ARB_PROGRAM) {
608 return SoGLDriverDatabase::isSupported(glue, SO_GL_ARB_FRAGMENT_PROGRAM);
609 }
610 else if (sourceType == SoShaderObject::GLSL_PROGRAM) {
611 return SoGLDriverDatabase::isSupported(glue, SO_GL_ARB_SHADER_OBJECT);
612 }
613 // FIXME: Add support for detecting missing Cg support (20050427
614 // handegar)
615 else if (sourceType == SoShaderObject::CG_PROGRAM) return TRUE;
616 return FALSE;
617 }
618 else {
619 assert(this->owner->isOfType(SoGeometryShader::getClassTypeId()));
620 if (sourceType == SoShaderObject::GLSL_PROGRAM) {
621 return
622 SoGLDriverDatabase::isSupported(glue, "GL_EXT_geometry_shader4") &&
623 SoGLDriverDatabase::isSupported(glue, SO_GL_ARB_SHADER_OBJECT);
624 }
625 return FALSE;
626 }
627 }
628
629 void
updateParameters(const uint32_t cachecontext,int start,int num)630 SoShaderObjectP::updateParameters(const uint32_t cachecontext, int start, int num)
631 {
632
633 if (!this->owner->isActive.getValue()) return;
634 if (start < 0 || num < 0) return;
635
636 SoGLShaderObject * shaderobject = this->getGLShaderObject(cachecontext);
637 if ((shaderobject == NULL) || !shaderobject->getParametersDirty()) return;
638
639 int cnt = this->owner->parameter.getNum();
640 int end = start+num;
641
642 end = (end > cnt) ? cnt : end;
643 for (int i=start; i<end; i++) {
644 SoUniformShaderParameter * param =
645 (SoUniformShaderParameter*)this->owner->parameter[i];
646 param->updateParameter(shaderobject);
647 }
648 }
649
650 void
updateCoinParameters(const uint32_t cachecontext,SoState * state)651 SoShaderObjectP::updateCoinParameters(const uint32_t cachecontext, SoState * state)
652 {
653 int i, cnt = this->owner->parameter.getNum();
654
655 SoGLShaderObject * shaderobject = this->getGLShaderObject(cachecontext);
656
657 for (i = 0; i < cnt; i++) {
658 SoUniformShaderParameter * param =
659 (SoUniformShaderParameter*)this->owner->parameter[i];
660 SbName name = param->name.getValue();
661
662 if (strncmp(name.getString(), "coin_", 5) == 0) {
663 if (name == "coin_texunit0_model") {
664 SoMultiTextureImageElement::Model model;
665 SbColor dummy;
666 SbBool tex = SoGLMultiTextureImageElement::get(state, model, dummy) != NULL;
667 shaderobject->updateCoinParameter(state, name, NULL, tex ? model : 0);
668 }
669 else if (name == "coin_texunit1_model") {
670 SoMultiTextureImageElement::Model model;
671 SbColor dummy;
672 SbBool tex = SoGLMultiTextureImageElement::get(state, 1, model, dummy) != NULL;
673 shaderobject->updateCoinParameter(state, name, NULL, tex ? model : 0);
674 }
675 else if (name == "coin_texunit2_model") {
676 SoMultiTextureImageElement::Model model;
677 SbColor dummy;
678 SbBool tex = SoGLMultiTextureImageElement::get(state, 2, model, dummy) != NULL;
679 shaderobject->updateCoinParameter(state, name, NULL, tex ? model : 0);
680 }
681 else if (name == "coin_texunit3_model") {
682 SoMultiTextureImageElement::Model model;
683 SbColor dummy;
684 SbBool tex = SoGLMultiTextureImageElement::get(state, 3, model, dummy) != NULL;
685 shaderobject->updateCoinParameter(state, name, NULL, tex ? model : 0);
686 }
687 else if (name == "coin_light_model") {
688 shaderobject->updateCoinParameter(state, name, NULL, SoLazyElement::getLightModel(state));
689 }
690 else if (name == "coin_two_sided_lighting") {
691 shaderobject->updateCoinParameter(state, name, NULL, SoLazyElement::getTwoSidedLighting(state));
692 }
693 }
694 }
695 }
696
697
698 void
updateAllParameters(const uint32_t cachecontext)699 SoShaderObjectP::updateAllParameters(const uint32_t cachecontext)
700 {
701 if (!this->owner->isActive.getValue()) return;
702
703 SoGLShaderObject * shaderobject = this->getGLShaderObject(cachecontext);
704 if ((shaderobject == NULL) || !shaderobject->getParametersDirty()) return;
705
706 int i, cnt = this->owner->parameter.getNum();
707
708 for (i=0; i<cnt; i++) {
709 SoUniformShaderParameter *param =
710 (SoUniformShaderParameter*)this->owner->parameter[i];
711 param->updateParameter(shaderobject);
712 }
713 shaderobject->setParametersDirty(FALSE);
714 }
715
716 // Update state matrix paramaters
717 void
updateStateMatrixParameters(const uint32_t cachecontext,SoState * state)718 SoShaderObjectP::updateStateMatrixParameters(const uint32_t cachecontext, SoState *state)
719 {
720 #define STATE_PARAM SoShaderStateMatrixParameter
721 if (!this->owner->isActive.getValue()) return;
722
723 SoGLShaderObject * shaderobject = this->getGLShaderObject(cachecontext);
724 if (shaderobject == NULL) return;
725
726 int i, cnt = this->owner->parameter.getNum();
727 for (i= 0; i <cnt; i++) {
728 STATE_PARAM * param = (STATE_PARAM*)this->owner->parameter[i];
729 if (param->isOfType(STATE_PARAM::getClassTypeId())) {
730 param->updateValue(state);
731 param->updateParameter(shaderobject);
732 }
733 }
734 #undef STATE_PARAM
735 }
736
737 SbBool
containStateMatrixParameters(void) const738 SoShaderObjectP::containStateMatrixParameters(void) const
739 {
740 #define STATE_PARAM SoShaderStateMatrixParameter
741 int i, cnt = this->owner->parameter.getNum();
742 for (i = 0; i < cnt; i++) {
743 if (this->owner->parameter[i]->isOfType(STATE_PARAM::getClassTypeId()))
744 return TRUE;
745 }
746 #undef STATE_PARAM
747 return FALSE;
748 }
749
750 #if defined(SOURCE_HINT)
751 SbString
getSourceHint(void) const752 SoShaderObjectP::getSourceHint(void) const
753 {
754 SoShaderObject::SourceType srcType =
755 (SoShaderObject::SourceType)this->owner->sourceType.getValue();
756
757 if (srcType == SoShaderObject::FILENAME)
758 return this->owner->sourceProgram.getValue();
759 else
760 return ""; // FIXME: should return first line of shader source code
761 }
762 #endif
763
764 void
sensorCB(void * data,SoSensor * sensor)765 SoShaderObjectP::sensorCB(void *data, SoSensor *sensor)
766 {
767 SoShaderObjectP * thisp = (SoShaderObjectP*) data;
768 SoField * field = ((SoNodeSensor *)sensor)->getTriggerField();
769
770 if (field == &thisp->owner->sourceProgram ||
771 field == &thisp->owner->sourceType) {
772 thisp->deleteGLShaderObjects();
773 thisp->shouldload = TRUE;
774 }
775 else if (field == &thisp->owner->parameter) {
776 thisp->invalidateParameters();
777 }
778 if (!thisp->didSetSearchDirectories) {
779 thisp->setSearchDirectories(SoInput::getDirectories());
780 }
781 }
782
783 void
setSearchDirectories(const SbStringList & list)784 SoShaderObjectP::setSearchDirectories(const SbStringList & list)
785 {
786 int i;
787 for (i = 0; i< this->searchdirectories.getLength(); i++) {
788 delete this->searchdirectories[i];
789 }
790
791 for (i = 0; i < list.getLength(); i++) {
792 this->searchdirectories.append(new SbString(*(list[i])));
793 }
794 this->didSetSearchDirectories = TRUE;
795 }
796
797 #undef PRIVATE
798