diff --git a/Make/makedirdefs b/Make/makedirdefs index fadbb0660..a76df85a9 100644 --- a/Make/makedirdefs +++ b/Make/makedirdefs @@ -168,6 +168,7 @@ EXAMPLE_DIRS = \ osgsimple\ osgshaders\ osgshadowtexture\ + osgdepthshadow\ osgshape\ osgstereoimage\ osgteapot\ diff --git a/VisualStudio/VisualStudio.dsw b/VisualStudio/VisualStudio.dsw index 06c4df5d3..a9d522f35 100644 --- a/VisualStudio/VisualStudio.dsw +++ b/VisualStudio/VisualStudio.dsw @@ -1182,6 +1182,33 @@ Package=<4> ############################################################################### +Project: "Example osgdepthshadow"=.\examples\osgdepthshadow\osgdepthshadow.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name Core osg + End Project Dependency + Begin Project Dependency + Project_Dep_Name Core osgDB + End Project Dependency + Begin Project Dependency + Project_Dep_Name Core osgGA + End Project Dependency + Begin Project Dependency + Project_Dep_Name Core osgProducer + End Project Dependency + Begin Project Dependency + Project_Dep_Name Core osgUtil + End Project Dependency +}}} + +############################################################################### + Project: "Example osgshape"=.\examples\osgshape\osgshape.dsp - Package Owner=<4> Package=<5> diff --git a/VisualStudio/examples/osgdepthshadow/osgshadowtexture.dsp b/VisualStudio/examples/osgdepthshadow/osgshadowtexture.dsp new file mode 100644 index 000000000..4da8e0e1a --- /dev/null +++ b/VisualStudio/examples/osgdepthshadow/osgshadowtexture.dsp @@ -0,0 +1,224 @@ +# Microsoft Developer Studio Project File - Name="Example osgdepthshadow" - Package Owner=<4> + +# Microsoft Developer Studio Generated Build File, Format Version 6.00 + +# ** DO NOT EDIT ** + + + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + + + +CFG=Example osgdepthshadow - Win32 Release + +!MESSAGE This is not a valid makefile. To build this project using NMAKE, + +!MESSAGE use the Export Makefile command and run + +!MESSAGE + +!MESSAGE NMAKE /f "osgdepthshadow.mak". + +!MESSAGE + +!MESSAGE You can specify a configuration when running NMAKE + +!MESSAGE by defining the macro CFG on the command line. For example: + +!MESSAGE + +!MESSAGE NMAKE /f "osgdepthshadow.mak" CFG="Example osgdepthshadow - Win32 Release" + +!MESSAGE + +!MESSAGE Possible choices for configuration are: + +!MESSAGE + +!MESSAGE "Example osgdepthshadow - Win32 Release" (based on "Win32 (x86) Console Application") + +!MESSAGE "Example osgdepthshadow - Win32 Debug" (based on "Win32 (x86) Console Application") + +!MESSAGE + + + +# Begin Project + +# PROP AllowPerConfigDependencies 0 + +# PROP Scc_ProjName "" + +# PROP Scc_LocalPath "" + +CPP=cl.exe + +RSC=rc.exe + + + +!IF "$(CFG)" == "Example osgdepthshadow - Win32 Release" + + + +# PROP BASE Use_MFC 0 + +# PROP BASE Use_Debug_Libraries 0 + +# PROP BASE Output_Dir "Release" + +# PROP BASE Intermediate_Dir "Release" + +# PROP BASE Target_Dir "" + +# PROP Use_MFC 0 + +# PROP Use_Debug_Libraries 0 + +# PROP Output_Dir "Release" + +# PROP Intermediate_Dir "Release" + +# PROP Ignore_Export_Lib 0 + +# PROP Target_Dir "" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c + +# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "../../../include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c + +# ADD BASE RSC /l 0x809 /d "NDEBUG" + +# ADD RSC /l 0x809 /d "NDEBUG" + +BSC32=bscmake.exe + +# ADD BASE BSC32 /nologo + +# ADD BSC32 /nologo + +LINK32=link.exe + +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +# ADD LINK32 opengl32.lib /nologo /subsystem:console /pdb:none /machine:I386 /out:"../../../bin/osgdepthshadow.exe" /libpath:"../../../lib" + + + +!ELSEIF "$(CFG)" == "Example osgdepthshadow - Win32 Debug" + + + +# PROP BASE Use_MFC 0 + +# PROP BASE Use_Debug_Libraries 1 + +# PROP BASE Output_Dir "Debug" + +# PROP BASE Intermediate_Dir "Debug" + +# PROP BASE Target_Dir "" + +# PROP Use_MFC 0 + +# PROP Use_Debug_Libraries 1 + +# PROP Output_Dir "Debug" + +# PROP Intermediate_Dir "Debug" + +# PROP Ignore_Export_Lib 0 + +# PROP Target_Dir "" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c + +# ADD CPP /nologo /MDd /W3 /Gm /vd0 /GR /GX /Zi /Od /I "../../../include" /D "_CONSOLE" /D "_MBCS" /D "FL_DLL" /D "WIN32" /D "_DEBUG" /YX /FD /c + +# SUBTRACT CPP /Fr + +# ADD BASE RSC /l 0x809 /d "_DEBUG" + +# ADD RSC /l 0x809 /d "_DEBUG" + +BSC32=bscmake.exe + +# ADD BASE BSC32 /nologo + +# ADD BSC32 /nologo + +LINK32=link.exe + +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +# ADD LINK32 opengl32.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcmt" /out:"../../../bin/osgdepthshadowd.exe" /pdbtype:sept /libpath:"../../../lib" + +# SUBTRACT LINK32 /incremental:no + + + +!ENDIF + + + +# Begin Target + + + +# Name "Example osgdepthshadow - Win32 Release" + +# Name "Example osgdepthshadow - Win32 Debug" + +# Begin Group "Source Files" + + + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" + +# Begin Source File + + + +SOURCE=..\..\..\examples\osgdepthshadow\osgdepthshadow.cpp + +# End Source File + +# Begin Source File + + + +SOURCE=..\..\..\examples\osgdepthshadow\CreateShadowedScene.cpp + +# End Source File + +# End Group + +# Begin Group "Header Files" + + + +# PROP Default_Filter ";h;hpp;hxx;hm;inl" + +# Begin Source File + + + +SOURCE=..\..\..\examples\osgdepthshadow\CreateShadowedScene.h + +# End Source File + +# End Group + +# Begin Group "Resource Files" + + + +# PROP Default_Filter "" + +# End Group + +# End Target + +# End Project + diff --git a/examples/osgdepthshadow/GNUmakefile b/examples/osgdepthshadow/GNUmakefile new file mode 100644 index 000000000..2810ef7d4 --- /dev/null +++ b/examples/osgdepthshadow/GNUmakefile @@ -0,0 +1,17 @@ +TOPDIR = ../.. +include $(TOPDIR)/Make/makedefs + +CXXFILES =\ + osgdepthshadow.cpp\ + +LIBS += -losgProducer -lProducer -losgText -losgGA -losgDB -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS) + +INSTFILES = \ + $(CXXFILES)\ + GNUmakefile.inst=GNUmakefile + +EXEC = osgdepthshadow + +INC += $(X_INC) + +include $(TOPDIR)/Make/makerules diff --git a/examples/osgdepthshadow/GNUmakefile.inst b/examples/osgdepthshadow/GNUmakefile.inst new file mode 100644 index 000000000..d66431f17 --- /dev/null +++ b/examples/osgdepthshadow/GNUmakefile.inst @@ -0,0 +1,14 @@ +TOPDIR = ../.. +include $(TOPDIR)/Make/makedefs + +CXXFILES =\ + osgdepthshadow.cpp\ + +LIBS += -losgProducer -lProducer -losgText -losgDB -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS) + +EXEC = osgdepthshadow + +INC += $(PRODUCER_INCLUDE_DIR) $(X_INC) +LDFLAGS += $(PRODUCER_LIB_DIR) + +include $(TOPDIR)/Make/makerules diff --git a/examples/osgdepthshadow/osgdepthshadow.cpp b/examples/osgdepthshadow/osgdepthshadow.cpp new file mode 100644 index 000000000..21e1be28c --- /dev/null +++ b/examples/osgdepthshadow/osgdepthshadow.cpp @@ -0,0 +1,421 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace osg; + +const int depth_texture_height = 256; +const int depth_texture_width = 256; + +ref_ptr bias = new RefMatrix(0.5f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.5f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.5f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f); + +class LightTransformCallback: public osg::NodeCallback +{ + +public: + + LightTransformCallback(float angular_velocity, float height, float radius): + _angular_velocity(angular_velocity), + _height(height), + _radius(radius), + _previous_traversal_number(-1), + _previous_time(-1.0f), + _angle(0) + { + } + + void operator()(Node* node, NodeVisitor* nv); + +protected: + + float _angular_velocity; + float _height; + float _radius; + int _previous_traversal_number; + double _previous_time; + float _angle; +}; + + +void +LightTransformCallback::operator()(Node* node, NodeVisitor* nv) +{ + MatrixTransform* transform = dynamic_cast(node); + if (nv && transform) + { + const FrameStamp* fs = nv->getFrameStamp(); + if (!fs) return; // not frame stamp, no handle on the time so can't move. + + double new_time = fs->getReferenceTime(); + if (nv->getTraversalNumber() != _previous_traversal_number) + { + _angle += _angular_velocity * (new_time - _previous_time); + + Matrix matrix = Matrix::rotate(atan(_height / _radius), -X_AXIS) * + Matrix::rotate(PI_2, Y_AXIS) * + Matrix::translate(Vec3(_radius, 0, 0)) * + Matrix::rotate(_angle, Y_AXIS) * + Matrix::translate(Vec3(0, _height, 0)); + + // update the specified transform + transform->setMatrix(matrix); + + _previous_traversal_number = nv->getTraversalNumber(); + } + + _previous_time = new_time; + } + + // must call any nested node callbacks and continue subgraph traversal. + traverse(node,nv); + +} + +class RenderToTextureCallback: public NodeCallback +{ +public: + RenderToTextureCallback(Node* subgraph, + Texture2D* texture, + MatrixTransform* light_transform, + TexGen* tex_gen): + _subgraph(subgraph), + _texture(texture), + _local_stateset(new StateSet), + _viewport(new Viewport), + _light_projection(new RefMatrix), + _light_transform(light_transform), + _tex_gen(tex_gen) + { + _local_stateset->setAttribute(_viewport.get()); + _local_stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + ref_ptr polygon_offset = new PolygonOffset; + polygon_offset->setFactor(2.0f); + polygon_offset->setUnits(6.0f); + _local_stateset->setAttribute(polygon_offset.get(), StateAttribute::ON | StateAttribute::OVERRIDE); + _local_stateset->setMode(GL_POLYGON_OFFSET_FILL, StateAttribute::ON | StateAttribute::OVERRIDE); + + ref_ptr cull_face = new CullFace; + cull_face->setMode(CullFace::BACK); + _local_stateset->setAttribute(cull_face.get(), StateAttribute::ON | StateAttribute::OVERRIDE); + _local_stateset->setMode(GL_CULL_FACE, StateAttribute::ON | StateAttribute::OVERRIDE); + + _viewport->setViewport(0, 0, depth_texture_width, depth_texture_height); + + float znear = 1.0f * _subgraph->getBound().radius(); + float zfar = 3.0f * _subgraph->getBound().radius(); + float top = 0.5f * _subgraph->getBound().radius(); + float right = 0.5f * _subgraph->getBound().radius(); + znear *= 0.8f; + zfar *= 1.2f; + _light_projection->makeFrustum(-right, right, -top, top, znear, zfar); + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + + osgUtil::CullVisitor* cullVisitor = dynamic_cast(nv); + if (cullVisitor && _texture.valid() && _subgraph.valid()) + { + _request_render_to_depth_texture(*node, *cullVisitor); + } + + // must traverse the subgraph + traverse(node,nv); + } + + void _request_render_to_depth_texture(osg::Node& node, osgUtil::CullVisitor& cv); + + ref_ptr _subgraph; + ref_ptr _texture; + ref_ptr _local_stateset; + ref_ptr _viewport; + ref_ptr _light_projection; + ref_ptr _light_transform; + ref_ptr _tex_gen; +}; + +void RenderToTextureCallback::_request_render_to_depth_texture(osg::Node&, osgUtil::CullVisitor& cv) +{ + // create the render to texture stage. + osg::ref_ptr rtts = new osgUtil::RenderToTextureStage; + + // set up lighting. + // currently ignore lights in the scene graph itself.. + // will do later. + osgUtil::RenderStage* previous_stage = cv.getCurrentRenderBin()->_stage; + + // set up the background color and clear mask. + rtts->setClearMask(GL_DEPTH_BUFFER_BIT); + rtts->_colorMask = new ColorMask(false, false, false, false); + + // set up to charge the same RenderStageLighting is the parent previous stage. + rtts->setRenderStageLighting(previous_stage->getRenderStageLighting()); + + + // record the render bin, to be restored after creation + // of the render to text + osgUtil::RenderBin* previousRenderBin = cv.getCurrentRenderBin(); + + osgUtil::CullVisitor::ComputeNearFarMode saved_compute_near_far_mode = cv.getComputeNearFarMode(); + cv.setComputeNearFarMode(osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR); + + // set the current renderbin to be the newly created stage. + cv.setCurrentRenderBin(rtts.get()); + + ref_ptr light_view = new RefMatrix; + light_view->makeLookAt(_light_transform->getMatrix().getTrans(), Vec3(0, 0, 0), Z_AXIS); + Matrix texture_matrix = (*light_view.get()) * (*_light_projection.get()) * (*bias.get()); + _tex_gen->setPlane(TexGen::S, Vec4(texture_matrix(0, 0), + texture_matrix(1, 0), + texture_matrix(2, 0), + texture_matrix(3, 0))); + _tex_gen->setPlane(TexGen::T, Vec4(texture_matrix(0, 1), + texture_matrix(1, 1), + texture_matrix(2, 1), + texture_matrix(3, 1))); + _tex_gen->setPlane(TexGen::R, Vec4(texture_matrix(0, 2), + texture_matrix(1, 2), + texture_matrix(2, 2), + texture_matrix(3, 2))); + _tex_gen->setPlane(TexGen::Q, Vec4(texture_matrix(0, 3), + texture_matrix(1, 3), + texture_matrix(2, 3), + texture_matrix(3, 3))); + + cv.pushProjectionMatrix(_light_projection.get()); + cv.pushModelViewMatrix(light_view.get()); + cv.pushStateSet(_local_stateset.get()); + + // traverse the subgraph + _subgraph->accept(cv); + + cv.popStateSet(); + cv.popModelViewMatrix(); + cv.popProjectionMatrix(); + + cv.setComputeNearFarMode(saved_compute_near_far_mode); + + // restore the previous renderbin. + cv.setCurrentRenderBin(previousRenderBin); + + if (rtts->_renderGraphList.size()==0 && rtts->_bins.size()==0) + { + // getting to this point means that all the subgraph has been + // culled by small feature culling or is beyond LOD ranges. + return; + } + + rtts->setViewport(_viewport.get()); + + // and the render to texture stage to the current stages + // dependancy list. + cv.getCurrentRenderBin()->_stage->addToDependencyList(rtts.get()); + + // if one exist attach texture to the RenderToTextureStage. + rtts->setTexture(_texture.get()); +} + +ref_ptr _create_lights(ref_ptr root_stateset) +{ + ref_ptr transform_0 = new MatrixTransform; + + // create a spot light. + ref_ptr light_0 = new Light; + light_0->setLightNum(0); + light_0->setPosition(Vec4(0, 0, 0, 1.0f)); + light_0->setAmbient(Vec4(0.2f, 0.2f, 0.2f, 1.0f)); + light_0->setDiffuse(Vec4(1.0f, 0.5f, 0.5f, 1.0f)); + light_0->setSpotCutoff(60.0f); + light_0->setSpotExponent(5.0f); + + ref_ptr light_source_0 = new LightSource; + light_source_0->setLight(light_0.get()); + light_source_0->setLocalStateSetModes(StateAttribute::ON); + transform_0->setUpdateCallback(new LightTransformCallback(inDegrees(90.0f), 8, 5)); + transform_0->addChild(light_source_0.get()); + + ref_ptr geode = new Geode; + ref_ptr shape; + ref_ptr hints = new TessellationHints; + hints->setDetailRatio(0.3f); + shape = new ShapeDrawable(new Sphere(Vec3(0.0f, 0.0f, 0.0f), 0.15f), hints.get()); + shape->setColor(Vec4(1.0f, 0.5f, 0.5f, 1.0f)); + geode->addDrawable(shape.get()); + shape = new ShapeDrawable(new Cylinder(Vec3(0.0f, 0.0f, -0.4f), 0.05f, 0.8f), hints.get()); + shape->setColor(Vec4(1.0f, 0.5f, 0.5f, 1.0f)); + geode->addDrawable(shape.get()); + geode->getOrCreateStateSet()->setMode(GL_LIGHTING, StateAttribute::OFF); + transform_0->addChild(geode.get()); + + light_source_0->setStateSetModes(*root_stateset.get(), StateAttribute::ON); + + return transform_0; +} + +ref_ptr _create_scene() +{ + ref_ptr scene = new Group; + ref_ptr geode_1 = new Geode; + scene->addChild(geode_1.get()); + + ref_ptr geode_2 = new Geode; + ref_ptr transform_2 = new MatrixTransform; + transform_2->addChild(geode_2.get()); + transform_2->setUpdateCallback(new osgUtil::TransformCallback(Vec3(0, 0, 0), Y_AXIS, inDegrees(45.0f))); + scene->addChild(transform_2.get()); + + ref_ptr geode_3 = new Geode; + ref_ptr transform_3 = new MatrixTransform; + transform_3->addChild(geode_3.get()); + transform_3->setUpdateCallback(new osgUtil::TransformCallback(Vec3(0, 0, 0), Y_AXIS, inDegrees(-22.5f))); + scene->addChild(transform_3.get()); + + const float radius = 0.8f; + const float height = 1.0f; + ref_ptr hints = new TessellationHints; + hints->setDetailRatio(2.0f); + ref_ptr shape; + + shape = new ShapeDrawable(new Box(Vec3(0.0f, -2.0f, 0.0f), 10, 0.1f, 10), hints.get()); + shape->setColor(Vec4(0.5f, 0.5f, 0.7f, 1.0f)); + geode_1->addDrawable(shape.get()); + + shape = new ShapeDrawable(new Sphere(Vec3(0.0f, 0.0f, 0.0f), radius * 2), hints.get()); + shape->setColor(Vec4(0.8f, 0.4f, 0.4f, 1.0f)); + geode_1->addDrawable(shape.get()); + + shape = new ShapeDrawable(new Sphere(Vec3(-3.0f, 0.0f, 0.0f), radius), hints.get()); + shape->setColor(Vec4(0.6f, 0.8f, 0.8f, 1.0f)); + geode_2->addDrawable(shape.get()); + + shape = new ShapeDrawable(new Box(Vec3(3.0f, 0.0f, 0.0f), 2 * radius), hints.get()); + shape->setColor(Vec4(0.4f, 0.9f, 0.3f, 1.0f)); + geode_2->addDrawable(shape.get()); + + shape = new ShapeDrawable(new Cone(Vec3(0.0f, 0.0f, -3.0f), radius, height), hints.get()); + shape->setColor(Vec4(0.2f, 0.5f, 0.7f, 1.0f)); + geode_2->addDrawable(shape.get()); + + shape = new ShapeDrawable(new Cylinder(Vec3(0.0f, 0.0f, 3.0f), radius, height), hints.get()); + shape->setColor(Vec4(1.0f, 0.3f, 0.3f, 1.0f)); + geode_2->addDrawable(shape.get()); + + shape = new ShapeDrawable(new Box(Vec3(0.0f, 3.0f, 0.0f), 2, 0.1f, 2), hints.get()); + shape->setColor(Vec4(0.8f, 0.8f, 0.4f, 1.0f)); + geode_3->addDrawable(shape.get()); + + return scene; +} + +int main(int argc, char** argv) +{ + // use an ArgumentParser object to manage the program arguments. + ArgumentParser arguments(&argc, argv); + + // set up the usage document, in case we need to print out how to use this program. + arguments.getApplicationUsage()->setDescription(arguments.getApplicationName() + " is the example which demonstrates using of GL_ARB_shadow extension implemented in osg::Texture class"); + arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()); + arguments.getApplicationUsage()->addCommandLineOption("-h or --help", "Display this information"); + + // construct the viewer. + osgProducer::Viewer viewer(arguments); + + // set up the value with sensible default event handlers. + viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS); + + // get details on keyboard and mouse bindings used by the viewer. + viewer.getUsage(*arguments. getApplicationUsage()); + + // if user request help write it out to cout. + if (arguments.read("-h") || arguments.read("--help")) + { + arguments.getApplicationUsage()->write(std::cout); + return 1; + } + + // any option left unread are converted into errors to write out later. + arguments.reportRemainingOptionsAsUnrecognized(); + + // report any errors if they have occured when parsing the program aguments. + if (arguments.errors()) + { + arguments.writeErrorMessages(std::cout); + return 1; + } + + ref_ptr scene = new Group; + ref_ptr shadowed_scene = _create_scene(); + if (!shadowed_scene.valid()) return 1; + scene->addChild(shadowed_scene.get()); + + ref_ptr light_transform = _create_lights(scene->getOrCreateStateSet()); + if (!scene.valid()) return 1; + scene->addChild(light_transform.get()); + + ref_ptr texture = new Texture2D; + texture->setInternalFormat(GL_DEPTH_COMPONENT); + texture->setShadowComparison(true); + texture->setShadowTextureMode(Texture::LUMINANCE); + + ref_ptr tex_env_combine = new TexEnvCombine; + tex_env_combine->setCombine_RGB(TexEnvCombine::INTERPOLATE); + tex_env_combine->setSource0_RGB(TexEnvCombine::PREVIOUS); + tex_env_combine->setOperand0_RGB(TexEnvCombine::SRC_COLOR); + tex_env_combine->setSource1_RGB(TexEnvCombine::TEXTURE); + tex_env_combine->setOperand1_RGB(TexEnvCombine::SRC_COLOR); + tex_env_combine->setSource2_RGB(TexEnvCombine::CONSTANT); + tex_env_combine->setOperand2_RGB(TexEnvCombine::SRC_COLOR); + tex_env_combine->setConstantColor(Vec4(0.8f, 0.8f, 0.8f, 1.0f)); + + ref_ptr tex_gen = new TexGen; + tex_gen->setMode(TexGen::EYE_LINEAR); + shadowed_scene->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get(), StateAttribute::ON); + shadowed_scene->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex_gen.get(), StateAttribute::ON); + shadowed_scene->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex_env_combine.get(), StateAttribute::ON); + + scene->setCullCallback(new RenderToTextureCallback(shadowed_scene.get(), texture.get(), light_transform.get(), tex_gen.get())); + + // add model to viewer. + viewer.setSceneData(scene.get()); + + // create the windows and run the threads. + viewer.realize(); + + while (!viewer.done()) + { + // wait for all cull and draw threads to complete. + viewer.sync(); + + // update the scene by traversing it with the the update visitor which will + // call all node update callbacks and animations. + viewer.update(); + + // fire off the cull and draw traversals of the scene. + viewer.frame(); + } + + // wait for all cull and draw threads to complete before exit. + viewer.sync(); + + return 0; +}