// Initialize GLUT & OpenSG and set up the scene
int main(int argc, char **argv)
{
    // OSG init
    OSG::osgInit(argc,argv);

    // GLUT init
    int winid = setupGLUT(&argc, argv);

    /*
       open a new scope, because the pointers below should go out of scope
       before entering glutMainLoop.
       Otherwise OpenSG will complain about objects being alive after shutdown.
    */
    {
        // the connection between GLUT and OpenSG
        OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
        gwin->setGlutId(winid);
        gwin->init();
    
        /*
           create the scene

           In the previous example, the colors and positions used the same
           indices. That might not always be the preferred way, and it might not
           make sense for other properties, e.g. normals.

           It is possible to assign a different index for every property. See the
           indices section below for details.


           The initial setup is the same as in 06indexgeometry
        */

        OSG::GeoUInt8PropertyRefPtr type = OSG::GeoUInt8Property::create();
        type->addValue(GL_POLYGON  );
        type->addValue(GL_TRIANGLES);
        type->addValue(GL_QUADS    );
    
        OSG::GeoUInt32PropertyRefPtr lens = OSG::GeoUInt32Property::create();
        lens->addValue(4);
        lens->addValue(6);
        lens->addValue(8);
        
        // positions
        OSG::GeoPnt3fPropertyRefPtr pnts = OSG::GeoPnt3fProperty::create();
        // the base
        pnts->addValue(OSG::Pnt3f(-1, -1, -1));
        pnts->addValue(OSG::Pnt3f(-1, -1,  1));
        pnts->addValue(OSG::Pnt3f( 1, -1,  1));
        pnts->addValue(OSG::Pnt3f( 1, -1, -1));
    
        // the roof base
        pnts->addValue(OSG::Pnt3f(-1,  0, -1));
        pnts->addValue(OSG::Pnt3f(-1,  0,  1));
        pnts->addValue(OSG::Pnt3f( 1,  0,  1));
        pnts->addValue(OSG::Pnt3f( 1,  0, -1));
    
        // the gable
        pnts->addValue(OSG::Pnt3f( 0,  1, -1));
        pnts->addValue(OSG::Pnt3f( 0,  1,  1));
    
        // colors
        OSG::GeoVec3fPropertyRefPtr colors = OSG::GeoVec3fProperty::create();
        colors->push_back(OSG::Color3f(1, 1, 0));
        colors->push_back(OSG::Color3f(1, 0, 0));
        colors->push_back(OSG::Color3f(1, 0, 0));
        colors->push_back(OSG::Color3f(1, 1, 0));
        colors->push_back(OSG::Color3f(0, 1, 1));
        colors->push_back(OSG::Color3f(1, 0, 1));
        
        /*
           A new property: normals.

           They are used for lighting calculations and have to point away from the
           surface. Normals are standard vectors.
        */
        
        OSG::GeoVec3fPropertyRefPtr norms = OSG::GeoVec3fProperty::create();
        norms->push_back(OSG::Vec3f(-1,  0,  0));
        norms->push_back(OSG::Vec3f( 1,  0,  0));
        norms->push_back(OSG::Vec3f( 0, -1,  0));
        norms->push_back(OSG::Vec3f( 0,  1,  0));
        norms->push_back(OSG::Vec3f( 0,  0, -1));
        norms->push_back(OSG::Vec3f( 0,  0,  1));
        
        /*
           To use more than one index for a geometry, create multiple
           GeoUInt32Property (or GeoUInt8Property or GeoUInt16Property) objects
           and add them as index for the corresponding property you want to
           index.
        */
        
        OSG::GeoUInt32PropertyRefPtr ind1 = OSG::GeoUInt32Property::create();
        OSG::GeoUInt32PropertyRefPtr ind2 = OSG::GeoUInt32Property::create();
        
        // fill first index (will be used for positions)
        ind1->push_back(0);     // polygon
        ind1->push_back(1);
        ind1->push_back(2);
        ind1->push_back(3);
        
        ind1->push_back(7);     // triangle 1
        ind1->push_back(4);
        ind1->push_back(8);
        ind1->push_back(5);     // triangle 2
        ind1->push_back(6);
        ind1->push_back(9);
        
        ind1->push_back(1);     // quad 1
        ind1->push_back(2);
        ind1->push_back(6);
        ind1->push_back(5);
        ind1->push_back(3);     // quad 2
        ind1->push_back(0);
        ind1->push_back(4);
        ind1->push_back(7);
        
        // fill second index (will be used for colors/normals)
        ind2->push_back(3);     // polygon
        ind2->push_back(3);
        ind2->push_back(3);
        ind2->push_back(3);
        
        ind2->push_back(4);     // triangle 1
        ind2->push_back(4);
        ind2->push_back(4);
        ind2->push_back(5);     // triangle 2
        ind2->push_back(5);
        ind2->push_back(5);
        
        ind2->push_back(5);     // quad 1
        ind2->push_back(5);
        ind2->push_back(5);
        ind2->push_back(5);
        ind2->push_back(4);     // quad 2
        ind2->push_back(4);
        ind2->push_back(4);
        ind2->push_back(4);
        

        /*
            Put it all together into a Geometry NodeCore.
        */
        OSG::GeometryRefPtr geo = OSG::Geometry::create();
        geo->setTypes    (type);
        geo->setLengths  (lens);
        
        /*
           Set the properties and indices used to index them.
           Calling geo->setProperty(pnts, Geometry::PositionsIndex) is the
           same as calling geo->setPositions(pnts), but this way it is
           more obvious which properties and indices go together.
        */
        
        geo->setProperty(pnts,   OSG::Geometry::PositionsIndex);
        geo->setIndex   (ind1,   OSG::Geometry::PositionsIndex);
        
        geo->setProperty(norms,  OSG::Geometry::NormalsIndex  );
        geo->setIndex   (ind2,   OSG::Geometry::NormalsIndex  );
        
        geo->setProperty(colors, OSG::Geometry::ColorsIndex   );
        geo->setIndex   (ind2,   OSG::Geometry::ColorsIndex   );
        
        geo->setMaterial (OSG::getDefaultMaterial());   
        
        // put the geometry core into a node
        OSG::NodeRefPtr n = OSG::Node::create();
        n->setCore(geo);
        
        // add a transformation to make it move     
        OSG::NodeRefPtr scene = OSG::Node::create();
        trans = OSG::Transform::create();
        scene->setCore(trans);
        scene->addChild(n);
    
        OSG::commitChanges();
    
        // create the SimpleSceneManager helper
        mgr = OSG::SimpleSceneManager::create();
    
        // tell the manager what to manage
        mgr->setWindow(gwin );
        mgr->setRoot  (scene);
    
        // show the whole scene
        mgr->showAll();
    }

    // GLUT main loop
    glutMainLoop();

    return 0;
}
Ejemplo n.º 2
0
//
// Initialize GLUT & OpenSG and set up the scene
//
int main(int argc, char **argv)
{
    // OSG init
    OSG::osgInit(argc,argv);

    // GLUT init
    int winid = setupGLUT(&argc, argv);

    // open a new scope, because the pointers below should go out of scope
    // before entering glutMainLoop.
    // Otherwise OpenSG will complain about objects being alive after shutdown.
    {
        // the connection between GLUT and OpenSG
        OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
        gwin->setGlutId(winid);
        gwin->init();
    
        // create the SimpleSceneManager helper
        mgr = OSG::SimpleSceneManager::create();
        mgr->setWindow(gwin);

        // create a pretty simple graph: a Group with two Transforms as children,
        // each of which carries a single Geometry.
        
        // The scene
        
        OSG::NodeRefPtr  scene = OSG::Node::create();
        
        // The cylinder and its transformation
        OSG::NodeRefPtr     cyl    = OSG::Node::create();
        OSG::GeometryRefPtr cylgeo = OSG::makeCylinderGeo( 1.4f, .3f, 24, 
                                                           true, true, true );
        
        cyl->setCore(cylgeo);
    
        cyltrans = OSG::Transform::create();
    
        OSG::NodeRefPtr cyltransnode = OSG::Node::create();
        cyltransnode->setCore (cyltrans);
        cyltransnode->addChild(cyl     );
        
        // add it to the scene
        scene->addChild(cyltransnode);
        
        // The torus and its transformation
        OSG::NodeRefPtr     torus    = OSG::Node::create();
        OSG::GeometryRefPtr torusgeo = OSG::makeTorusGeo( .2f, 1, 24, 36 );
        
        torus->setCore(torusgeo);
            
        tortrans = OSG::Transform::create();
    
        OSG::NodeRefPtr tortransnode = OSG::Node::create();
        tortransnode->setCore (tortrans);
        tortransnode->addChild(torus   );
        
        // add it to the scene
        scene->addChild(tortransnode);

        //
        // create the shader program
        //
        OSG::ShaderProgramChunkRefPtr prog_chunk = OSG::ShaderProgramChunk::create();
        OSG::ShaderProgramRefPtr      vertShader = OSG::ShaderProgram::createVertexShader();
        OSG::ShaderProgramRefPtr      fragShader = OSG::ShaderProgram::createFragmentShader();

        vertShader->setProgram(get_vp_program());
        fragShader->setProgram(get_fp_program());

        //
        // binding the unifrom block to a buffer binding point can be performed 
        // either by calling the shaders's addUniformBlock method or by
        // adding a 'uniform block' variable to a ShaderProgramVariableChunk.
        // In the following we use both variants for illustration.
        //
        fragShader->addUniformBlock("Materials", 1);    // block binding point
        fragShader->addUniformBlock("Lights",    2);    // block binding point

        //
        // The following is replaced by adding ShaderProgramVariableChunk objects
        // to the chunk material. See below...
        //
        // fragShader->addUniformBlock("GeomState", 3);    // block binding point

        prog_chunk->addShader(vertShader);
        prog_chunk->addShader(fragShader);

        //
        // create uniform buffer objects and corresponding materials
        //
        OSG::UniformBufferObjChunkRefPtr ubo_material_database = create_material_database_state(materials);
                                         ubo_light_state       = create_light_state(lights);

        OSG::PolygonChunkRefPtr polygon_chunk = OSG::PolygonChunk::create();
        polygon_chunk->setFrontMode(GL_FILL);
        polygon_chunk->setBackMode(GL_FILL);
        polygon_chunk->setCullFace(GL_NONE);

        OSG::DepthChunkRefPtr depth_chunk = OSG::DepthChunk::create();
        depth_chunk->setEnable(true);

        OSG::ChunkMaterialRefPtr prog_state = OSG::ChunkMaterial::create();
        prog_state->addChunk(ubo_material_database, 1);  // buffer binding point 1
        prog_state->addChunk(ubo_light_state,       2);  // buffer binding point 2
        prog_state->addChunk(prog_chunk);
        prog_state->addChunk(polygon_chunk);
        prog_state->addChunk(depth_chunk);

        OSG::ShaderProgramVariableChunkRefPtr shader_var_chunk = OSG::ShaderProgramVariableChunk::create();
        shader_var_chunk->addUniformBlock("GeomState", 3);

        GeomState geom1; geom1.material_index = dist(generator);
        OSG::ChunkMaterialRefPtr geom1_state = OSG::ChunkMaterial::create();
        ubo_geom_state_1 = create_geometry_material_state(geom1);
        geom1_state->addChunk(ubo_geom_state_1, 3);     // buffer binding point 3
        geom1_state->addChunk(shader_var_chunk);        // block binding point

        GeomState geom2; geom2.material_index = dist(generator);
        OSG::ChunkMaterialRefPtr geom2_state = OSG::ChunkMaterial::create();
        ubo_geom_state_2 = create_geometry_material_state(geom2);
        geom2_state->addChunk(ubo_geom_state_2, 3);     // buffer binding point 3
        geom1_state->addChunk(shader_var_chunk);        // block binding point
       
        cylgeo  ->setMaterial(geom1_state);
        torusgeo->setMaterial(geom2_state);

        OSG::MaterialChunkOverrideGroupRefPtr mgrp = OSG::MaterialChunkOverrideGroup::create();
        mgrp->setMaterial(prog_state);
        scene->setCore(mgrp);

        OSG::commitChanges();
    
        mgr->setRoot(scene);
    
        // show the whole scene
        mgr->showAll();
    }

    // GLUT main loop
    glutMainLoop();

    return 0;
}
Ejemplo n.º 3
0
// Initialize GLUT & OpenSG and set up the scene
int main(int argc, char **argv)
{
    // OSG init
    OSG::osgInit(argc,argv);

    // GLUT init
    int winid = setupGLUT(&argc, argv);

    // open a new scope, because the pointers below should go out of scope
    // before entering glutMainLoop.
    // Otherwise OpenSG will complain about objects being alive after shutdown.
    {
        // the connection between GLUT and OpenSG
        OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
        gwin->setGlutId(winid);
        gwin->init();
    
        // The scene group
        
        OSG::NodeRefPtr  scene = OSG::Node::create();
        OSG::GroupRefPtr g     = OSG::Group::create();
        
        scene->setCore(g);
        
        if(argc < 2)
        {
            FWARNING(("No file given!\n"));
            FWARNING(("Supported file formats:\n"));
            
            std::list<const char*> suffixes;
            OSG::SceneFileHandler::the()->getSuffixList(suffixes);
            
            for(std::list<const char*>::iterator it  = suffixes.begin();
                                                 it != suffixes.end();
                                               ++it)
            {
                FWARNING(("%s\n", *it));
            }
    
            fileroot = OSG::makeTorus(.5, 2, 16, 16);
        }
        else
        {
            fileroot = OSG::SceneFileHandler::the()->read(argv[1]);
            /*
                All scene file loading is handled via the SceneFileHandler.
            */
        }
    
        scene->addChild(fileroot);
        
        // Create a small geometry to show the ray and what was hit
        // Contains a line and a single triangle.
        // The line shows the ray, the triangle whatever was hit.
        
        OSG::SimpleMaterialRefPtr red = OSG::SimpleMaterial::create();
        
        red->setDiffuse     (OSG::Color3f( 1,0,0 ));   
        red->setTransparency(0.5);   
        red->setLit         (false);   
    
        isectPoints = OSG::GeoPnt3fProperty::create();
        isectPoints->addValue(OSG::Pnt3f(0,0,0));
        isectPoints->addValue(OSG::Pnt3f(0,0,0));
        isectPoints->addValue(OSG::Pnt3f(0,0,0));
        isectPoints->addValue(OSG::Pnt3f(0,0,0));
        isectPoints->addValue(OSG::Pnt3f(0,0,0));
    
        OSG::GeoUInt32PropertyRefPtr index = OSG::GeoUInt32Property::create();
        index->addValue(0);
        index->addValue(1);
        index->addValue(2);
        index->addValue(3);
        index->addValue(4);
    
        OSG::GeoUInt32PropertyRefPtr lens = OSG::GeoUInt32Property::create();
        lens->addValue(2);
        lens->addValue(3);
        
        OSG::GeoUInt8PropertyRefPtr type = OSG::GeoUInt8Property::create();
        type->addValue(GL_LINES);
        type->addValue(GL_TRIANGLES);
    
        testgeocore = OSG::Geometry::create();
        testgeocore->setPositions(isectPoints);
        testgeocore->setIndices(index);
        testgeocore->setLengths(lens);
        testgeocore->setTypes(type);
        testgeocore->setMaterial(red);
        
        OSG::NodeRefPtr testgeo = OSG::Node::create();
        testgeo->setCore(testgeocore);
        
        scene->addChild(testgeo);
    
        // create the SimpleSceneManager helper
        mgr = OSG::SimpleSceneManager::create();
    
        // tell the manager what to manage
        mgr->setWindow(gwin );
        mgr->setRoot  (scene);
    
        // show the whole scene
        mgr->showAll();
    
        mgr->getCamera()->setNear(mgr->getCamera()->getNear() / 10);
    
        // Show the bounding volumes? Not for now
        mgr->getRenderAction()->setVolumeDrawing(false);
    
        _idbuff = new IDbuffer();
        _idbuff->setCamera(mgr->getCamera());
        _idbuff->setRoot(scene);
    }
    
    // GLUT main loop
    glutMainLoop();

    return 0;
}
// Initialize GLUT & OpenSG and set up the scene
int main(int argc, char **argv)
{
	OSG::preloadSharedObject("OSGFileIO");
	OSG::preloadSharedObject("OSGTBFileIO");
    OSG::preloadSharedObject("OSGImageFileIO");
    // OSG init
    OSG::osgInit(argc,argv);

    // GLUT init
    int winid = setupGLUT(&argc, argv);

    // open a new scope, because the pointers below should go out of scope
    // before entering glutMainLoop.
    // Otherwise OpenSG will complain about objects being alive after shutdown.
    {
        // the connection between GLUT and OpenSG
        OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
        gwin->setGlutId(winid);
        gwin->init();
    
        // create the scene
        
        // create a pretty simple graph: a Group with two Transforms as children,
        // each of which carries a single Geometry.
        
        // The scene group
        
        OSG::NodeRefPtr  scene = OSG::Node::create();
        OSG::GroupRefPtr g     = OSG::Group::create();
        
        scene->setCore(g);
        
        // The cylinder and its transformation
        OSG::NodeRefPtr     cyl    = OSG::Node::create();
        OSG::GeometryRefPtr cylgeo = OSG::makeCylinderGeo( 1.4f, .3f, 64, 
                                                           true, true, true );
        
        cyl->setCore(cylgeo);
    
        cyltrans = OSG::Transform::create();
    
        OSG::NodeRefPtr cyltransnode = OSG::Node::create();
        cyltransnode->setCore (cyltrans);
        cyltransnode->addChild(cyl     );
        
        // add it to the scene
        scene->addChild(cyltransnode);
        
        // The torus and its transformation
        OSG::NodeRefPtr     torus    = OSG::Node::create();
        OSG::GeometryRefPtr torusgeo = OSG::makeTorusGeo( .2f, 1, 32, 64 );
        
        torus->setCore(torusgeo);
            
        tortrans = OSG::Transform::create();
    
        OSG::NodeRefPtr tortransnode = OSG::Node::create();
        tortransnode->setCore (tortrans);
        tortransnode->addChild(torus   );
        
        // add it to the scene
        scene->addChild(tortransnode);
    
        // create the materials: Here, just using cgfx materials.
        OSG::CgFXMaterialRefPtr mat1 = OSG::CgFXMaterial::create();
        if(argc > 1)
        {
        	mat1->setEffectFile(argv[1]);
        }
        
    
        // assign the material to the geometry
        cylgeo->setMaterial(mat1);
        
        // assign the material to the geometry
        torusgeo->setMaterial(mat1);
    
        OSG::commitChanges();
    
        // create the SimpleSceneManager helper
        mgr = new OSG::SimpleSceneManager;
    
        // tell the manager what to manage
        mgr->setWindow(gwin );
        
    

        
        // file io
		OSG::FCFileType::FCPtrStore Containers;
		Containers.insert(scene);
		//Use an empty Ignore types vector
		OSG::FCFileType::FCTypeVector IgnoreTypes;
		//IgnoreTypes.push_back(Node::getClassType().getId());
	    
		//Write the Field Containers to a xml file
		OSG::FCFileHandler::the()->write(Containers,OSG::BoostPath("C:/Users/danielg/Desktop/test.xml"),IgnoreTypes);

        //Read FieldContainers from an XML file
        OSG::FCFileType::FCPtrStore NewContainers;
        NewContainers = OSG::FCFileHandler::the()->read(OSG::BoostPath("C://Users//danielg//Documents//VirtualCellData//trunk//Artwork//Models//Vehicles_and_Tools//Protein_Ship//Ship_Export_Test.dae"));

        //Write the read FieldContainers to an XML file
       // OSG::FCFileHandler::the()->write(NewContainers,OSG::BoostPath("C:/Users/danielg/Desktop/test2.xml"),IgnoreTypes);

		//NewContainers.clear();

		// NewContainers = OSG::FCFileHandler::the()->read(OSG::BoostPath("C:/Users/danielg/Desktop/test2.xml"));

		OSG::FCFileType::FCPtrStore::iterator itor = NewContainers.begin();
		OSG::FCFileType::FCPtrStore::iterator endIt = NewContainers.end();
		OSG::NodeRefPtr root;
		for(; itor != endIt; itor++)
		{
			OSG::Node *cur = OSG::dynamic_pointer_cast<OSG::Node>((*itor));
			if(cur != NULL)
			{
				if(cur->getParent() == NULL) 
				{
					root = cur; //mgr->setRoot(cur);
					break;
				}
			}
		}

		std::string filepath("C://Users//danielg//Desktop//test.osb");
		OSG::SceneFileHandler::the()->write(root,filepath.c_str());

		root = OSG::SceneFileHandler::the()->read(filepath.c_str());

		if(root != NULL)
		{
			mgr->setRoot(root);
		} else
		{
			std::cout << std::endl << "ERROR READING THE OSB FILE BACK IN~~~~!" << std::endl;
		}

		// show the whole scene
        mgr->showAll();
    }

    // GLUT main loop
    glutMainLoop();

    return 0;
}
Ejemplo n.º 5
0
// Initialize GLUT & OpenSG and set up the scene
int main(int argc, char **argv)
{
    // OSG init
    OSG::osgInit(argc,argv);

    // GLUT init
    int winid = setupGLUT(&argc, argv);

    // Args given?
    if(argc > 1)
    {
        if(sscanf(argv[1], "%u", &nlights) != 1)
        {
            FWARNING(("Number of lights '%s' not understood.\n", argv[1]));
            nlights = 3;
        }
    }
    
    // open a new scope, because the pointers below should go out of scope
    // before entering glutMainLoop.
    // Otherwise OpenSG will complain about objects being alive after shutdown.
    {
    
        // the connection between GLUT and OpenSG
        OSG::GLUTWindowRefPtr gwin = OSG::GLUTWindow::create();
        gwin->setGlutId(winid);
        gwin->init();
    
        /*
            A Light defines a source of light in the scene. Generally, two types
            of information are of interest: The position of the light source
            (geometry), and what elements of the scene are lit (semantics). 
    
            Using the position of the light in the graph for geometry allows
            moving the Light just like any other node, by putting it below a
            OSG::Transform Node and changing the transformation. This consistency
            also simplifies attaching Lights to moving parts in the scene: just
            put them below the same Transform and they will move with the object.
    
            The semantic interpretation also makes sense, it lets you restrict the
            influence area of the light to a subgraph of the scene. This can be
            used for efficiency, as every active light increases the amount of
            calculations necessary per vertex, even if the light doesn't influence
            the vertex, because it is too far away. It can also be used to
            overcome the restrictions on the number of lights. OpenSG currently
            only allows 8 concurrently active lights.
    
            It is also not difficult to imagine situations where both
            interpretations are necessary at the same time. Take for example a car
            driving through a night scene. You'd want to headlights to be fixed to
            the car and move together with it. But at the same time they should
            light the houses you're driving by, and not the mountains in the
            distance. 
    
            Thus there should be a way to do both at the same time. OpenSG solves
            this by splitting the two tasks to two Nodes. The Light's Node is for
            the sematntic part, it defines which object are lit by the Light. FOr
            the geometrc part the Light keeps a SFNodePtr to a different Node, the
            so called beacon. The local coordinate system of the beacon provides
            the reference coordinate system for the light's position.
    
    
            Thus the typical setup of an OpenSG scenegraph starts with a set of
            lights, which light the whole scene, followed by the actual geometry.
    
            Tip: Using the beacon of the camera (see \ref PageSystemWindowCamera)
            as the beacon of a light source creates a headlight.


            Every light is closely related to OpenGL's light specification. It has
            a diffuse, specular and ambient color. Additionally it can be switched
            on and off using the on field.
        */
    
    
        // Create the scene 
        
        OSG::NodeRefPtr  scene = OSG::Node::create();
        OSG::GroupRefPtr group = OSG::Group::create();
        scene->setCore(group);
    
        // create the scene to be lit
    
        // a simple torus is fine for now.
        // You can add more Geometry here if you want to.
        OSG::NodeRefPtr lit_scene = OSG::makeTorus(.5, 2, 32, 64);
    
        // helper node to keep the lights on top of each other
        OSG::NodeRefPtr lastnode = lit_scene;
    
        // create the light sources    
        OSG::Color3f colors[] = 
        {
            OSG::Color3f(1,0,0), OSG::Color3f(0,1,0), OSG::Color3f(0,0,1), 
            OSG::Color3f(1,1,0), OSG::Color3f(0,1,1), OSG::Color3f(1,0,1), 
            OSG::Color3f(1,1,1), OSG::Color3f(1,1,1)
        };
        if(nlights > 8)
        {
            FWARNING(("Currently only 8 lights supported\n"));
            nlights = 8;
        }
        
        // scale the lights to not overexpose everything. Just a little.
        OSG::Real32 scale = OSG::osgMax(1., 1.5 / nlights);
        
        for(OSG::UInt16 i = 0; i < nlights; ++i)
        {        
            // create the light source
            OSG::NodeRefPtr     light = OSG::Node::create();
            OSG::LightRefPtr    light_core;
            OSG::NodeRefPtr     geo_node;
            
            switch((i % 3) + 0)
            {
                /*
                    The PointLight has a position to define its location. In
                    addition, as it really is located in the scene, it has
                    attenuation parameters to change the light's intensity
                    depending on the distance to the light.
    
                    Point lights are more expesinve to compute than directional
                    lights, but not quite as expesive as spot lights. If you need
                    to see the localized effects of the light, a point light is a
                    good compromise between speed and quality.
                */
                case 0:
                {
                    OSG::PointLightRefPtr l = OSG::PointLight::create();
                    
                    l->setPosition             (0, 0, 0);
                    l->setConstantAttenuation  (1);
                    l->setLinearAttenuation    (0);
                    l->setQuadraticAttenuation (3);
                    
                    // a little sphere to show where the light is
                    geo_node = OSG::makeLatLongSphere(8, 8, 0.1f);
    
                    OSG::GeometryRefPtr       geo =
                        dynamic_cast<OSG::Geometry *>(geo_node->getCore());
                    OSG::SimpleMaterialRefPtr sm  = 
                        OSG::SimpleMaterial::create();
    
                    sm->setLit(false);
                    sm->setDiffuse(OSG::Color3f( colors[i][0], 
                                                 colors[i][1],
                                                 colors[i][2] ));
    
                    geo->setMaterial(sm);
    
                    light_core = l;
                }
                break;
                
                
                /*
                    The DirectionalLight just has a direction. 
    
                    To use it as a headlight use (0,0,-1) as a direction. it is
                    the computationally cheapest light source. Thus for the
                    fastest lit rendering, just a single directional light source.
                    The osg::SimpleSceneManager's headlight is a directional light
                    source.
    
                */
                case 1:
                {
                    OSG::DirectionalLightRefPtr l = 
                        OSG::DirectionalLight::create();
                    
                    l->setDirection(0, 0, 1);
                    
                    // a little cylinder to show where the light is
                    geo_node = OSG::makeCylinder(.1f, .03f, 8, true, true, true);
    
                    OSG::GeometryRefPtr       geo =
                        dynamic_cast<OSG::Geometry *>(geo_node->getCore());
                    OSG::SimpleMaterialRefPtr sm  = 
                        OSG::SimpleMaterial::create();
    
                    sm->setLit(false);
                    sm->setDiffuse(OSG::Color3f( colors[i][0], 
                                                 colors[i][1],
                                                 colors[i][2] ));
    
                    geo->setMaterial(sm);
    
                    light_core = l;
                }
                break;
                
                /*
                    The SpotLight adds a direction to the PointLight and a
                    spotCutOff angle to define the area that's lit. To define the
                    light intensity fallof within that area the spotExponent field
                    is used.
    
                    Spot lights are very expensive to compute, use them sparingly.
                */
                case 2:
                {
                    OSG::SpotLightRefPtr l = OSG::SpotLight::create();
                    
                    l->setPosition             (OSG::Pnt3f(0,  0, 0));
                    l->setDirection            (OSG::Vec3f(0, -1, 0));
                    l->setSpotExponent         (2);
                    l->setSpotCutOff           (OSG::osgDegree2Rad(45));
                    l->setConstantAttenuation  (1);
                    l->setLinearAttenuation    (0);
                    l->setQuadraticAttenuation (3);
                    
                    // a little cone to show where the light is
                    geo_node = OSG::makeCone(.2f, .2f, 8, true, true);
    
                    OSG::GeometryRefPtr       geo =
                        dynamic_cast<OSG::Geometry *>(geo_node->getCore());
                    OSG::SimpleMaterialRefPtr sm  = 
                        OSG::SimpleMaterial::create();
    
                    sm->setLit(false);
                    sm->setDiffuse(OSG::Color3f( colors[i][0], 
                                                 colors[i][1],
                                                 colors[i][2] ));
    
                    geo->setMaterial(sm);
    
                    light_core = l;
                }
                break;
            }
            
            // create the beacon and attach it to the scene
            OSG::NodeRefPtr         beacon      = OSG::Node::create();
            OSG::TransformRefPtr    beacon_core = OSG::Transform::create();
            
            lightBeacons[i] = beacon_core;
            
            beacon->setCore(beacon_core);
            beacon->addChild(geo_node);
        
            scene->addChild(beacon);
                
            light_core->setAmbient (colors[i][0] / scale,
                                    colors[i][1] / scale,
                                    colors[i][2] / scale,
                                    1);
            light_core->setDiffuse (colors[i][0] / scale,
                                    colors[i][1] / scale,
                                    colors[i][2] / scale,
                                    1);
            light_core->setSpecular(1 / scale,
                                    1 / scale,
                                    1 / scale,
                                    1);
            light_core->setBeacon  (beacon);
    
            light->setCore(light_core);
            light->addChild(lastnode);
            
            lights[i] = light_core;
            lastnode = light;
        }
    
        scene->addChild(lastnode);
    
        OSG::commitChanges();
    
        // create the SimpleSceneManager helper
        mgr = OSG::SimpleSceneManager::create();
    
        // tell the manager what to manage
        mgr->setWindow(gwin );
        mgr->setRoot  (scene);
        
        // switch the headlight off, we have enough lights as is
        mgr->setHeadlight(false);
    
        // show the whole scene
        mgr->showAll();
    }
    
    // GLUT main loop
    glutMainLoop();

    return 0;
}