00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "SoShadowLight.h"
00033 #include "SoShadowVolume.h"
00034
00035
00036
00037
00038
00045 GLboolean SoShadowLight::CheckExtension( char * extName )
00046 {
00047
00048
00049
00050
00051
00052
00053 char *p = (char *) glGetString(GL_EXTENSIONS);
00054 char *end = NULL;
00055 int extNameLen;
00056
00057 extNameLen = (int)strlen(extName);
00058 end = p + strlen(p);
00059
00060 while (p < end) {
00061 int n = (int)strcspn(p, " ");
00062 if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) {
00063 return GL_TRUE;
00064 }
00065 p += (n + 1);
00066 }
00067 return GL_FALSE;
00068 }
00069
00070
00071 GLenum SoShadowLight::incValue = GL_INCR;
00072 GLenum SoShadowLight::decValue = GL_DECR;
00073
00074 float SoShadowLight::envIntensity = 0.0f;
00075
00076
00080 void SoShadowLight::checkStencilExt()
00081 {
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 if ( CheckExtension("GL_EXT_stencil_wrap") )
00097 {
00098 incValue = GL_INCR_WRAP_EXT;
00099 decValue = GL_DECR_WRAP_EXT;
00100 }
00101 else
00102 {
00103 incValue = GL_INCR;
00104 decValue = GL_DECR;
00105 }
00106
00107 }
00108
00115 SoShadowLight::SoShadowLight(CShadowManager * sm, SoLight * l)
00116 : manager(sm),
00117 light(l)
00118 {
00119 nameIndex = -1;
00120 status = TRUE;
00121
00122 pstatus = &this->status;
00123
00124 lightRenderRoot = new SoSeparator;
00125 lightRenderRoot->setName("lightRenderRoot");
00126 lightRenderRoot->ref();
00127
00128
00129
00130 volumesRoot = new SoSeparator;
00131 volumesRoot->setName("volumesRoot");
00132 volumesRoot->ref();
00133
00134 init();
00135 }
00136
00137
00141 SoShadowLight::~SoShadowLight()
00142 {
00143
00144 this->sensor->detach();
00145 this->removeAllChildren();
00146
00147 lightRenderRoot->unref();
00148
00149 volumesRoot->unref();
00150 }
00151
00152
00158 void SoShadowLight::init()
00159 {
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 this->addChild(lightRenderRoot);
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198 SoPolygonOffset * pOffset = new SoPolygonOffset;
00199
00200 pOffset->factor.setValue(0.1f);
00201 pOffset->units.setValue(50.0f);
00202
00203 pOffset->styles.setValue(SoPolygonOffset::FILLED);
00204
00205
00206 SoCallback * incrementStencilCallback = new SoCallback;
00207 incrementStencilCallback->setCallback(incrementStencilCB, this->manager->getAlgorithm() );
00208
00209 SoCallback * decrementStencilCallback = new SoCallback;
00210 decrementStencilCallback->setCallback(decrementStencilCB, this->manager->getAlgorithm() );
00211
00212 SoCallback * shadowCallback = new SoCallback;
00213
00214 struct TLightInfo * linfo = new struct TLightInfo;
00215 linfo->light = this->light;
00216 linfo->status = this->pstatus;
00217 linfo->globEnv = this->manager->getEnvironmentNode();
00218 shadowCallback->setCallback(litStencilCB, linfo);
00219
00220 SoCallback * finishStencilCallback = new SoCallback;
00221 finishStencilCallback->setCallback(finishStencilCB, linfo);
00222
00223
00224
00225
00226
00227
00228
00229
00230 if ( this->manager->readSettings()->dropShadows )
00231 {
00232 this->lightRenderRoot->addChild(incrementStencilCallback);
00233 this->lightRenderRoot->addChild(pOffset);
00234 this->lightRenderRoot->addChild(this->volumesRoot);
00235 this->lightRenderRoot->addChild(decrementStencilCallback);
00236 this->lightRenderRoot->addChild(this->volumesRoot);
00237 this->lightRenderRoot->addChild(shadowCallback);
00238 this->lightRenderRoot->addChild(this->manager->getSceneRoot());
00239 this->lightRenderRoot->addChild(finishStencilCallback);
00240 }
00241 else
00242 {
00243 this->lightRenderRoot->addChild(this->manager->getSceneRoot());
00244 this->lightRenderRoot->addChild(pOffset);
00245 this->lightRenderRoot->addChild(this->volumesRoot);
00246 }
00247 }
00248
00249
00255 CShadowManager * SoShadowLight::getManager()
00256 {
00257 return this->manager;
00258 }
00259
00260
00266 SoLight * SoShadowLight::getLight()
00267 {
00268 return this->light;
00269 }
00270
00271
00277 void SoShadowLight::setLightName(int lightIndex)
00278 {
00279 SbString index(lightIndex);
00280 SbString name = "Light_";
00281 name += index;
00282 ONDEBUG( printf("-- light name: %s\n",name.getString()) );
00283 this->nameIndex = lightIndex;
00284 this->setName(name);
00285 }
00286
00287
00293 int SoShadowLight::getLightName()
00294 {
00295 return this->nameIndex;
00296 }
00297
00298
00304 void SoShadowLight::setSensor(SoNodeSensor * sensor)
00305 {
00306 this->sensor = sensor;
00307 }
00308
00309
00315 SoNodeSensor * SoShadowLight::getSensor()
00316 {
00317 return this->sensor;
00318 }
00319
00320
00321
00327 void SoShadowLight::addVolume(SoSeparator * volume)
00328 {
00329 ONDEBUG( printf("--SoShadowLight::addVolume()\n") );
00330 this->volumesRoot->addChild(volume);
00331 }
00332
00333
00337 void SoShadowLight::deleteVolumes()
00338 {
00339 ONDEBUG( printf("--SoShadowLight::deleteVolumes()\n") );
00340 this->volumesRoot->removeAllChildren();
00341 }
00342
00343
00349 void SoShadowLight::deleteVolume(int casterName)
00350 {
00351 ONDEBUG( printf("--SoShadowLight::deleteVolume()\n") );
00352 int cnt = this->volumesRoot->getNumChildren();
00353 if ( cnt > 0 )
00354 {
00355 for ( int j = 0; j < cnt; j++ )
00356 {
00357 SoShadowVolume * volume = static_cast<SoShadowVolume *> (this->volumesRoot->getChild(j));
00358 if (volume->getCasterName() == casterName)
00359 {
00360 this->volumesRoot->removeChild(j);
00361 }
00362 }
00363 }
00364
00365 }
00366
00367
00373 int SoShadowLight::getNumVolumes()
00374 {
00375 return this->volumesRoot->getNumChildren();
00376 }
00377
00378
00386 SoSeparator * SoShadowLight::getVolume(int i)
00387 {
00388 SoSeparator * volume = static_cast<SoSeparator *> (this->volumesRoot->getChild(i));
00389 return volume;
00390 }
00391
00392
00396 void SoShadowLight::createShadowVolumes()
00397 {
00398 ONDEBUG( printf("--SoShadowLight::createShadowVolumes()\n") );
00399
00400
00401 int cnt = this->volumesRoot->getNumChildren();
00402 ONDEBUG( printf("--SoShadowLight:: vol. root cnt: %d\n",cnt) );
00403 for (int i = 0; i < cnt; i++)
00404 {
00405 SoShadowVolume * volume = static_cast<SoShadowVolume *>(this->volumesRoot->getChild(i));
00406 volume->create();
00407 }
00408
00409 }
00410
00416 void SoShadowLight::createShadowVolumes(int caster)
00417 {
00418 ONDEBUG( printf("--SoShadowLight::createShadowVolumes()\n") );
00419
00420
00421 int cnt = this->volumesRoot->getNumChildren();
00422 ONDEBUG( printf("--SoShadowLight:: vol. root cnt: %d\n",cnt) );
00423 for (int i = 0; i < cnt; i++)
00424 {
00425 SoShadowVolume * volume = static_cast<SoShadowVolume *>(this->getChild(i));
00426 if (volume->getCasterName() == caster )
00427 {
00428 volume->create();
00429 break;
00430 }
00431 }
00432
00433 }
00434
00435
00437
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00483 void SoShadowLight::incrementStencilCB(void *userdata, SoAction *action)
00484 {
00485 if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00486 ONDEBUG(printf("incrementStencilCB\n"));
00487
00488
00489 checkStencilExt();
00490
00491
00492 glPopAttrib();
00493
00494 glPushAttrib(GL_ALL_ATTRIB_BITS);
00495
00496 glClear( GL_STENCIL_BUFFER_BIT );
00497
00498 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
00499 glShadeModel(GL_FLAT);
00500 glDepthMask(GL_FALSE);
00501 glDepthFunc(GL_LESS);
00502 glEnable(GL_STENCIL_TEST);
00503
00504 enum TShadowAlgorithm * algorithm = (TShadowAlgorithm *) userdata;
00505 if ( *algorithm == zfailAlg ) {
00506 ONDEBUG(printf("incrementStencilCB: zfail\n"));
00507
00508
00509 glStencilFunc(GL_ALWAYS, 0, ~0);
00510
00511 glStencilOp(GL_KEEP, incValue, GL_KEEP);
00512 glCullFace(GL_FRONT);
00513 } else {
00514 ONDEBUG(printf("incrementStencilCB: zpass\n"));
00515
00516
00517 glStencilFunc(GL_ALWAYS, 0, ~0);
00518
00519 glStencilOp(GL_KEEP, GL_KEEP, incValue);
00520 glCullFace(GL_BACK);
00521 }
00522 }
00523 }
00524
00525
00534 void SoShadowLight::decrementStencilCB(void *userdata, SoAction *action)
00535 {
00536 if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00537 ONDEBUG(printf("decrementStencilCB\n"));
00538
00539 enum TShadowAlgorithm * algorithm = (TShadowAlgorithm *) userdata;
00540 if ( *algorithm == zfailAlg ) {
00541 ONDEBUG(printf("decrementStencilCB: zfail\n"));
00542
00543
00544
00545 glStencilOp(GL_KEEP, decValue, GL_KEEP);
00546 glCullFace(GL_BACK);
00547 } else {
00548 ONDEBUG(printf("decrementStencilCB: zpass\n"));
00549
00550
00551
00552 glStencilOp(GL_KEEP, GL_KEEP, decValue);
00553 glCullFace(GL_FRONT);
00554 }
00555 }
00556 }
00557
00558
00570 void SoShadowLight::litStencilCB(void *userdata, SoAction *action)
00571 {
00572 if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00573
00574 ONDEBUG(printf("litStencilCB\n"));
00575
00576 glPopAttrib();
00577
00578
00579
00580 glPushAttrib(GL_ENABLE_BIT);
00581
00582 struct TLightInfo * linfo = (struct TLightInfo * ) userdata;
00583
00584
00585
00586 if ( linfo->globEnv != NULL )
00587 {
00588 linfo->globEnv->ambientIntensity.enableNotify(FALSE);
00589 envIntensity = linfo->globEnv->ambientIntensity.getValue();
00590 linfo->globEnv->ambientIntensity.setValue(0.0f);
00591 linfo->globEnv->ambientIntensity.enableNotify(TRUE);
00592 }
00593
00594
00595 linfo->light->enableNotify(FALSE);
00596 linfo->light->on = *linfo->status;
00597 linfo->light->enableNotify(TRUE);
00598
00599 glEnable(GL_LIGHTING);
00600
00601 glBlendFunc(GL_ONE, GL_ONE);
00602 glEnable(GL_BLEND);
00603
00604
00605 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00606 glDepthFunc(GL_EQUAL);
00607 glStencilFunc(GL_EQUAL, 0, ~0);
00608 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
00609 glEnable(GL_STENCIL_TEST);
00610
00611 }
00612 }
00613
00614
00624 void SoShadowLight::finishStencilCB(void *userdata, SoAction *action)
00625 {
00626 if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00627 ONDEBUG(printf("finishStencilCB\n"));
00628
00629 glPopAttrib();
00630
00631 glDisable(GL_LIGHTING);
00632
00633 glDisable(GL_STENCIL_TEST);
00634
00635 glDisable(GL_BLEND);
00636
00637 glPushAttrib(GL_ENABLE_BIT);
00638
00639 struct TLightInfo * linfo = (struct TLightInfo * ) userdata;
00640
00641
00642 if ( linfo->globEnv != NULL )
00643 {
00644 linfo->globEnv->ambientIntensity.enableNotify(FALSE);
00645 linfo->globEnv->ambientIntensity.setValue(envIntensity);
00646 linfo->globEnv->ambientIntensity.enableNotify(TRUE);
00647 }
00648
00649
00650 linfo->light->enableNotify(FALSE);
00651 linfo->light->on = FALSE;
00652 linfo->light->enableNotify(TRUE);
00653 }
00654 }
00655