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 linfo->sceneType = (int *)this->manager->psceneType;
00219
00220 shadowCallback->setCallback(litStencilCB, linfo);
00221
00222 SoCallback * finishStencilCallback = new SoCallback;
00223 finishStencilCallback->setCallback(finishStencilCB, linfo);
00224
00225
00226
00227
00228
00229
00230
00231
00232 if ( this->manager->readSettings()->dropShadows )
00233 {
00234 this->lightRenderRoot->addChild(incrementStencilCallback);
00235 this->lightRenderRoot->addChild(pOffset);
00236 this->lightRenderRoot->addChild(this->volumesRoot);
00237 this->lightRenderRoot->addChild(decrementStencilCallback);
00238 this->lightRenderRoot->addChild(this->volumesRoot);
00239 this->lightRenderRoot->addChild(shadowCallback);
00240 this->lightRenderRoot->addChild(this->manager->getSceneRoot());
00241 this->lightRenderRoot->addChild(finishStencilCallback);
00242 }
00243 else
00244 {
00245 this->lightRenderRoot->addChild(this->manager->getSceneRoot());
00246 this->lightRenderRoot->addChild(pOffset);
00247 this->lightRenderRoot->addChild(this->volumesRoot);
00248 }
00249 }
00250
00251
00257 CShadowManager * SoShadowLight::getManager()
00258 {
00259 return this->manager;
00260 }
00261
00262
00268 SoLight * SoShadowLight::getLight()
00269 {
00270 return this->light;
00271 }
00272
00273
00279 void SoShadowLight::setLightName(int lightIndex)
00280 {
00281 SbString index(lightIndex);
00282 SbString name = "Light_";
00283 name += index;
00284 ONDEBUG( printf("-- light name: %s\n",name.getString()) );
00285 this->nameIndex = lightIndex;
00286 this->setName(name);
00287 }
00288
00289
00295 int SoShadowLight::getLightName()
00296 {
00297 return this->nameIndex;
00298 }
00299
00300
00306 void SoShadowLight::setSensor(SoNodeSensor * sensor)
00307 {
00308 this->sensor = sensor;
00309 }
00310
00311
00317 SoNodeSensor * SoShadowLight::getSensor()
00318 {
00319 return this->sensor;
00320 }
00321
00322
00323
00329 void SoShadowLight::addVolume(SoSeparator * volume)
00330 {
00331 ONDEBUG( printf("--SoShadowLight::addVolume()\n") );
00332 this->volumesRoot->addChild(volume);
00333 }
00334
00335
00339 void SoShadowLight::deleteVolumes()
00340 {
00341 ONDEBUG( printf("--SoShadowLight::deleteVolumes()\n") );
00342 this->volumesRoot->removeAllChildren();
00343 }
00344
00345
00351 void SoShadowLight::deleteVolume(int casterName)
00352 {
00353 ONDEBUG( printf("--SoShadowLight::deleteVolume()\n") );
00354 int cnt = this->volumesRoot->getNumChildren();
00355 if ( cnt > 0 )
00356 {
00357 for ( int j = 0; j < cnt; j++ )
00358 {
00359 SoShadowVolume * volume = static_cast<SoShadowVolume *> (this->volumesRoot->getChild(j));
00360 if (volume->getCasterName() == casterName)
00361 {
00362 this->volumesRoot->removeChild(j);
00363 }
00364 }
00365 }
00366
00367 }
00368
00369
00375 int SoShadowLight::getNumVolumes()
00376 {
00377 return this->volumesRoot->getNumChildren();
00378 }
00379
00380
00388 SoSeparator * SoShadowLight::getVolume(int i)
00389 {
00390 SoSeparator * volume = static_cast<SoSeparator *> (this->volumesRoot->getChild(i));
00391 return volume;
00392 }
00393
00394
00398 void SoShadowLight::createShadowVolumes()
00399 {
00400 ONDEBUG( printf("--SoShadowLight::createShadowVolumes()\n") );
00401
00402
00403 int cnt = this->volumesRoot->getNumChildren();
00404 ONDEBUG( printf("--SoShadowLight:: vol. root cnt: %d\n",cnt) );
00405 for (int i = 0; i < cnt; i++)
00406 {
00407 SoShadowVolume * volume = static_cast<SoShadowVolume *>(this->volumesRoot->getChild(i));
00408 volume->create();
00409 }
00410
00411 }
00412
00418 void SoShadowLight::createShadowVolumes(int caster)
00419 {
00420 ONDEBUG( printf("--SoShadowLight::createShadowVolumes()\n") );
00421
00422
00423 int cnt = this->volumesRoot->getNumChildren();
00424 ONDEBUG( printf("--SoShadowLight:: vol. root cnt: %d\n",cnt) );
00425 for (int i = 0; i < cnt; i++)
00426 {
00427 SoShadowVolume * volume = static_cast<SoShadowVolume *>(this->getChild(i));
00428 if (volume->getCasterName() == caster )
00429 {
00430 volume->create();
00431 break;
00432 }
00433 }
00434
00435 }
00436
00437
00439
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
00475
00476
00485 void SoShadowLight::incrementStencilCB(void *userdata, SoAction *action)
00486 {
00487 if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00488 ONDEBUG(printf("incrementStencilCB\n"));
00489
00490
00491 checkStencilExt();
00492
00493 glPopAttrib();
00494
00495 glPushAttrib(GL_ALL_ATTRIB_BITS);
00496
00497 glClear(GL_STENCIL_BUFFER_BIT);
00498
00499 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
00500 glShadeModel(GL_FLAT);
00501 glDepthMask(GL_FALSE);
00502 glDepthFunc(GL_LESS);
00503 glEnable(GL_STENCIL_TEST);
00504 glStencilFunc(GL_ALWAYS, 0, ~0);
00505
00506 enum TShadowAlgorithm * algorithm = (TShadowAlgorithm *) userdata;
00507 if ( *algorithm == zfailAlg ) {
00508 ONDEBUG(printf("incrementStencilCB: zfail\n"));
00509
00510
00511
00512 glStencilOp(GL_KEEP, incValue, GL_KEEP);
00513 glCullFace(GL_FRONT);
00514 } else {
00515 ONDEBUG(printf("incrementStencilCB: zpass\n"));
00516
00517
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 glBlendFunc(GL_ONE, GL_ONE);
00601 glEnable(GL_BLEND);
00602
00603
00604 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00605 glDepthFunc(GL_EQUAL);
00606
00607 if ( *linfo->sceneType == 0 )
00608 {
00609 glStencilFunc(GL_EQUAL, 0, ~0);
00610 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
00611 glEnable(GL_STENCIL_TEST);
00612 }
00613
00614 }
00615 }
00616
00617
00627 void SoShadowLight::finishStencilCB(void *userdata, SoAction *action)
00628 {
00629 if (action->isOfType(SoGLRenderAction::getClassTypeId())) {
00630 ONDEBUG(printf("finishStencilCB\n"));
00631
00632 glPopAttrib();
00633
00634 glDisable(GL_LIGHTING);
00635 glDisable(GL_STENCIL_TEST);
00636 glDisable(GL_BLEND);
00637 glPushAttrib(GL_ENABLE_BIT);
00638
00639 struct TLightInfo * linfo = (struct TLightInfo * ) userdata;
00640
00641
00642 if ( linfo->globEnv != NULL )
00643 {
00644
00645
00646 linfo->globEnv->ambientIntensity.enableNotify(FALSE);
00647 linfo->globEnv->ambientIntensity.setValue(envIntensity);
00648 linfo->globEnv->ambientIntensity.enableNotify(TRUE);
00649 }
00650
00651
00652 linfo->light->enableNotify(FALSE);
00653 linfo->light->on = FALSE;
00654 linfo->light->enableNotify(TRUE);
00655 }
00656 }
00657