]> git.mxchange.org Git - simgear.git/blob - simgear/scene/tgdb/pt_lights.cxx
Modified Files:
[simgear.git] / simgear / scene / tgdb / pt_lights.cxx
1 // pt_lights.cxx -- build a 'directional' light on the fly
2 //
3 // Written by Curtis Olson, started March 2002.
4 //
5 // Copyright (C) 2002  Curtis L. Olson  - http://www.flightgear.org/~curt
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23 #ifdef HAVE_CONFIG_H
24 #  include <simgear_config.h>
25 #endif
26
27 #include "pt_lights.hxx"
28
29 #include <osg/Array>
30 #include <osg/Geometry>
31 #include <osg/CullFace>
32 #include <osg/Geode>
33 #include <osg/MatrixTransform>
34 #include <osg/NodeCallback>
35 #include <osg/NodeVisitor>
36 #include <osg/Texture2D>
37 #include <osg/AlphaFunc>
38 #include <osg/BlendFunc>
39 #include <osg/TexEnv>
40 #include <osg/Sequence>
41 #include <osg/PolygonMode>
42 #include <osg/Fog>
43 #include <osg/FragmentProgram>
44 #include <osg/VertexProgram>
45 #include <osg/Point>
46 #include <osg/PointSprite>
47 #include <osg/Material>
48 #include <osg/Group>
49 #include <osg/StateSet>
50
51 #include <osgUtil/CullVisitor>
52
53 #include <simgear/math/sg_random.h>
54 #include <simgear/debug/logstream.hxx>
55 #include <simgear/threads/SGThread.hxx>
56 #include <simgear/threads/SGGuard.hxx>
57 #include <simgear/scene/util/SGEnlargeBoundingBox.hxx>
58
59 #include "SGVasiDrawable.hxx"
60
61 static void
62 setPointSpriteImage(unsigned char* data, unsigned log2resolution,
63                     unsigned charsPerPixel)
64 {
65   int env_tex_res = (1 << log2resolution);
66   for (int i = 0; i < env_tex_res; ++i) {
67     for (int j = 0; j < env_tex_res; ++j) {
68       int xi = 2*i + 1 - env_tex_res;
69       int yi = 2*j + 1 - env_tex_res;
70       if (xi < 0)
71         xi = -xi;
72       if (yi < 0)
73         yi = -yi;
74       
75       xi -= 1;
76       yi -= 1;
77       
78       if (xi < 0)
79         xi = 0;
80       if (yi < 0)
81         yi = 0;
82       
83       float x = 1.5*xi/(float)(env_tex_res);
84       float y = 1.5*yi/(float)(env_tex_res);
85       //       float x = 2*xi/(float)(env_tex_res);
86       //       float y = 2*yi/(float)(env_tex_res);
87       float dist = sqrt(x*x + y*y);
88       float bright = SGMiscf::clip(255*(1-dist), 0, 255);
89       for (unsigned l = 0; l < charsPerPixel; ++l)
90         data[charsPerPixel*(i*env_tex_res + j) + l] = (unsigned char)bright;
91     }
92   }
93 }
94
95 static osg::Image*
96 getPointSpriteImage(int logResolution)
97 {
98   osg::Image* image = new osg::Image;
99   
100   osg::Image::MipmapDataType mipmapOffsets;
101   unsigned off = 0;
102   for (int i = logResolution; 0 <= i; --i) {
103     unsigned res = 1 << i;
104     off += res*res;
105     mipmapOffsets.push_back(off);
106   }
107   
108   int env_tex_res = (1 << logResolution);
109   
110   unsigned char* imageData = new unsigned char[off];
111   image->setImage(env_tex_res, env_tex_res, 1,
112                   GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, imageData,
113                   osg::Image::USE_NEW_DELETE);
114   image->setMipmapLevels(mipmapOffsets);
115   
116   for (int k = logResolution; 0 <= k; --k) {
117     setPointSpriteImage(image->getMipmapData(logResolution - k), k, 1);
118   }
119   
120   return image;
121 }
122
123 static osg::Texture2D*
124 gen_standard_light_sprite(void)
125 {
126   // double checked locking ...
127   static osg::ref_ptr<osg::Texture2D> texture;
128   if (texture.valid())
129     return texture.get();
130   
131   static SGMutex mutex;
132   SGGuard<SGMutex> guard(mutex);
133   if (texture.valid())
134     return texture.get();
135   
136   texture = new osg::Texture2D;
137   texture->setImage(getPointSpriteImage(6));
138   texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);
139   texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);
140   
141   return texture.get();
142 }
143
144 SGPointSpriteLightCullCallback::SGPointSpriteLightCullCallback(const osg::Vec3& da,
145                                                                float sz) :
146   _pointSpriteStateSet(new osg::StateSet),
147   _distanceAttenuationStateSet(new osg::StateSet)
148 {
149   osg::PointSprite* pointSprite = new osg::PointSprite;
150   _pointSpriteStateSet->setTextureAttributeAndModes(0, pointSprite,
151                                                     osg::StateAttribute::ON);
152   osg::Texture2D* texture = gen_standard_light_sprite();
153   _pointSpriteStateSet->setTextureAttribute(0, texture);
154   _pointSpriteStateSet->setTextureMode(0, GL_TEXTURE_2D,
155                                        osg::StateAttribute::ON);
156   osg::TexEnv* texEnv = new osg::TexEnv;
157   texEnv->setMode(osg::TexEnv::MODULATE);
158   _pointSpriteStateSet->setTextureAttribute(0, texEnv);
159   
160   osg::Point* point = new osg::Point;
161   point->setFadeThresholdSize(1);
162   point->setMinSize(1);
163   point->setMaxSize(sz);
164   point->setSize(sz);
165   point->setDistanceAttenuation(da);
166   _distanceAttenuationStateSet->setAttributeAndModes(point);
167 }
168
169 // FIXME make state sets static
170 SGPointSpriteLightCullCallback::SGPointSpriteLightCullCallback(osg::Point* point) :
171   _pointSpriteStateSet(new osg::StateSet),
172   _distanceAttenuationStateSet(new osg::StateSet)
173 {
174   osg::PointSprite* pointSprite = new osg::PointSprite;
175   _pointSpriteStateSet->setTextureAttributeAndModes(0, pointSprite,
176                                                     osg::StateAttribute::ON);
177   osg::Texture2D* texture = gen_standard_light_sprite();
178   _pointSpriteStateSet->setTextureAttribute(0, texture);
179   _pointSpriteStateSet->setTextureMode(0, GL_TEXTURE_2D,
180                                        osg::StateAttribute::ON);
181   osg::TexEnv* texEnv = new osg::TexEnv;
182   texEnv->setMode(osg::TexEnv::MODULATE);
183   _pointSpriteStateSet->setTextureAttribute(0, texEnv);
184   
185   _distanceAttenuationStateSet->setAttributeAndModes(point);
186 }
187
188 void
189 SGPointSpriteLightCullCallback::operator()(osg::Node* node,
190                                            osg::NodeVisitor* nv)
191 {
192   assert(dynamic_cast<osgUtil::CullVisitor*>(nv));
193   osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
194   
195   // Test for point sprites and point parameters availibility
196   unsigned contextId = cv->getRenderInfo().getContextID();
197   SGSceneFeatures* features = SGSceneFeatures::instance();
198   bool usePointSprite = features->getEnablePointSpriteLights(contextId);
199   bool usePointParameters = features->getEnableDistanceAttenuationLights(contextId);
200   
201   if (usePointSprite)
202     cv->pushStateSet(_pointSpriteStateSet.get());
203   
204   if (usePointParameters)
205     cv->pushStateSet(_distanceAttenuationStateSet.get());
206   
207   traverse(node, nv);
208   
209   if (usePointParameters)
210     cv->popStateSet();
211   
212   if (usePointSprite)
213     cv->popStateSet();
214 }
215
216 osg::Node*
217 SGLightFactory::getLight(const SGLightBin::Light& light)
218 {
219   osg::Vec3Array* vertices = new osg::Vec3Array;
220   osg::Vec4Array* colors = new osg::Vec4Array;
221
222   vertices->push_back(light.position.osg());
223   colors->push_back(light.color.osg());
224   
225   osg::Geometry* geometry = new osg::Geometry;
226   geometry->setVertexArray(vertices);
227   geometry->setNormalBinding(osg::Geometry::BIND_OFF);
228   geometry->setColorArray(colors);
229   geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
230
231   // Enlarge the bounding box to avoid such light nodes being victim to
232   // small feature culling.
233   geometry->setComputeBoundingBoxCallback(new SGEnlargeBoundingBox(1));
234   
235   osg::DrawArrays* drawArrays;
236   drawArrays = new osg::DrawArrays(osg::PrimitiveSet::POINTS,
237                                    0, vertices->size());
238   geometry->addPrimitiveSet(drawArrays);
239   
240   osg::StateSet* stateSet = geometry->getOrCreateStateSet();
241   stateSet->setRenderBinDetails(9, "DepthSortedBin");
242   stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
243   
244   osg::BlendFunc* blendFunc = new osg::BlendFunc;
245   stateSet->setAttribute(blendFunc);
246   stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
247   
248   osg::AlphaFunc* alphaFunc;
249   alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01);
250   stateSet->setAttribute(alphaFunc);
251   stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
252   
253   osg::Geode* geode = new osg::Geode;
254   geode->addDrawable(geometry);
255
256   return geode;
257 }
258
259 osg::Node*
260 SGLightFactory::getLight(const SGDirectionalLightBin::Light& light)
261 {
262   osg::Vec3Array* vertices = new osg::Vec3Array;
263   osg::Vec4Array* colors = new osg::Vec4Array;
264
265   SGVec4f visibleColor(light.color);
266   SGVec4f invisibleColor(visibleColor[0], visibleColor[1],
267                          visibleColor[2], 0);
268   SGVec3f normal = normalize(light.normal);
269   SGVec3f perp1 = perpendicular(normal);
270   SGVec3f perp2 = cross(normal, perp1);
271   SGVec3f position = light.position;
272   vertices->push_back(position.osg());
273   vertices->push_back((position + perp1).osg());
274   vertices->push_back((position + perp2).osg());
275   colors->push_back(visibleColor.osg());
276   colors->push_back(invisibleColor.osg());
277   colors->push_back(invisibleColor.osg());
278   
279   osg::Geometry* geometry = new osg::Geometry;
280   geometry->setVertexArray(vertices);
281   geometry->setNormalBinding(osg::Geometry::BIND_OFF);
282   geometry->setColorArray(colors);
283   geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
284   // Enlarge the bounding box to avoid such light nodes being victim to
285   // small feature culling.
286   geometry->setComputeBoundingBoxCallback(new SGEnlargeBoundingBox(1));
287   
288   osg::DrawArrays* drawArrays;
289   drawArrays = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,
290                                    0, vertices->size());
291   geometry->addPrimitiveSet(drawArrays);
292   
293   osg::StateSet* stateSet = geometry->getOrCreateStateSet();
294   stateSet->setRenderBinDetails(9, "DepthSortedBin");
295
296   osg::Material* material = new osg::Material;
297   material->setColorMode(osg::Material::OFF);
298   stateSet->setAttribute(material);
299
300   osg::CullFace* cullFace = new osg::CullFace;
301   cullFace->setMode(osg::CullFace::BACK);
302   stateSet->setAttribute(cullFace, osg::StateAttribute::ON);
303   stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
304   
305   osg::PolygonMode* polygonMode = new osg::PolygonMode;
306   polygonMode->setMode(osg::PolygonMode::FRONT, osg::PolygonMode::POINT);
307   stateSet->setAttribute(polygonMode);
308
309   stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
310   
311   osg::BlendFunc* blendFunc = new osg::BlendFunc;
312   stateSet->setAttribute(blendFunc);
313   stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
314   
315   osg::AlphaFunc* alphaFunc;
316   alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01);
317   stateSet->setAttribute(alphaFunc);
318   stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
319   
320   osg::Geode* geode = new osg::Geode;
321   geode->addDrawable(geometry);
322
323   return geode;
324 }
325
326 osg::Drawable*
327 SGLightFactory::getLights(const SGLightBin& lights, unsigned inc, float alphaOff)
328 {
329   if (lights.getNumLights() <= 0)
330     return 0;
331   
332   osg::Vec3Array* vertices = new osg::Vec3Array;
333   osg::Vec4Array* colors = new osg::Vec4Array;
334
335   for (unsigned i = 0; i < lights.getNumLights(); i += inc) {
336     vertices->push_back(lights.getLight(i).position.osg());
337     SGVec4f color = lights.getLight(i).color;
338     color[3] = SGMiscf::max(0, SGMiscf::min(1, color[3] + alphaOff));
339     colors->push_back(color.osg());
340   }
341   
342   osg::Geometry* geometry = new osg::Geometry;
343   
344   geometry->setVertexArray(vertices);
345   geometry->setNormalBinding(osg::Geometry::BIND_OFF);
346   geometry->setColorArray(colors);
347   geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
348   
349   osg::DrawArrays* drawArrays;
350   drawArrays = new osg::DrawArrays(osg::PrimitiveSet::POINTS,
351                                    0, vertices->size());
352   geometry->addPrimitiveSet(drawArrays);
353   
354   osg::StateSet* stateSet = geometry->getOrCreateStateSet();
355   stateSet->setRenderBinDetails(9, "DepthSortedBin");
356
357   stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
358   
359   osg::BlendFunc* blendFunc = new osg::BlendFunc;
360   stateSet->setAttribute(blendFunc);
361   stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
362   
363   osg::AlphaFunc* alphaFunc;
364   alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01);
365   stateSet->setAttribute(alphaFunc);
366   stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
367   
368   return geometry;
369 }
370
371
372 osg::Drawable*
373 SGLightFactory::getLights(const SGDirectionalLightBin& lights)
374 {
375   if (lights.getNumLights() <= 0)
376     return 0;
377   
378   osg::Vec3Array* vertices = new osg::Vec3Array;
379   osg::Vec4Array* colors = new osg::Vec4Array;
380
381   for (unsigned i = 0; i < lights.getNumLights(); ++i) {
382     SGVec4f visibleColor(lights.getLight(i).color);
383     SGVec4f invisibleColor(visibleColor[0], visibleColor[1],
384                            visibleColor[2], 0);
385     SGVec3f normal = normalize(lights.getLight(i).normal);
386     SGVec3f perp1 = perpendicular(normal);
387     SGVec3f perp2 = cross(normal, perp1);
388     SGVec3f position = lights.getLight(i).position;
389     vertices->push_back(position.osg());
390     vertices->push_back((position + perp1).osg());
391     vertices->push_back((position + perp2).osg());
392     colors->push_back(visibleColor.osg());
393     colors->push_back(invisibleColor.osg());
394     colors->push_back(invisibleColor.osg());
395   }
396   
397   osg::Geometry* geometry = new osg::Geometry;
398   
399   geometry->setVertexArray(vertices);
400   geometry->setNormalBinding(osg::Geometry::BIND_OFF);
401   geometry->setColorArray(colors);
402   geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
403   
404   osg::DrawArrays* drawArrays;
405   drawArrays = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,
406                                    0, vertices->size());
407   geometry->addPrimitiveSet(drawArrays);
408   
409   osg::StateSet* stateSet = geometry->getOrCreateStateSet();
410   stateSet->setRenderBinDetails(9, "DepthSortedBin");
411
412   osg::Material* material = new osg::Material;
413   material->setColorMode(osg::Material::OFF);
414   stateSet->setAttribute(material);
415
416   osg::CullFace* cullFace = new osg::CullFace;
417   cullFace->setMode(osg::CullFace::BACK);
418   stateSet->setAttribute(cullFace, osg::StateAttribute::ON);
419   stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
420   
421   osg::PolygonMode* polygonMode = new osg::PolygonMode;
422   polygonMode->setMode(osg::PolygonMode::FRONT, osg::PolygonMode::POINT);
423   stateSet->setAttribute(polygonMode);
424
425   stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
426   
427   osg::BlendFunc* blendFunc = new osg::BlendFunc;
428   stateSet->setAttribute(blendFunc);
429   stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
430   
431   osg::AlphaFunc* alphaFunc;
432   alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01);
433   stateSet->setAttribute(alphaFunc);
434   stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
435   
436   return geometry;
437 }
438
439 static SGVasiDrawable*
440 buildVasi(const SGDirectionalLightBin& lights, const SGVec3f& up,
441        const SGVec4f& red, const SGVec4f& white)
442 {
443   unsigned count = lights.getNumLights();
444   if ( count == 4 ) {
445     SGVasiDrawable* drawable = new SGVasiDrawable(red, white);
446
447     // PAPI configuration
448     // papi D
449     drawable->addLight(lights.getLight(0).position,
450                        lights.getLight(0).normal, up, 3.5);
451     // papi C
452     drawable->addLight(lights.getLight(1).position,
453                        lights.getLight(1).normal, up, 3.167);
454     // papi B
455     drawable->addLight(lights.getLight(2).position,
456                        lights.getLight(2).normal, up, 2.833);
457     // papi A
458     drawable->addLight(lights.getLight(3).position,
459                        lights.getLight(3).normal, up, 2.5);
460     return drawable;
461   }
462   else if (count == 12) {
463     SGVasiDrawable* drawable = new SGVasiDrawable(red, white);
464     
465     // probably vasi, first 6 are downwind bar (2.5 deg)
466     for (unsigned i = 0; i < 6; ++i)
467       drawable->addLight(lights.getLight(i).position,
468                          lights.getLight(i).normal, up, 2.5);
469     // last 6 are upwind bar (3.0 deg)
470     for (unsigned i = 6; i < 12; ++i)
471       drawable->addLight(lights.getLight(i).position,
472                          lights.getLight(i).normal, up, 3.0);
473     
474     return drawable;
475   } else {
476     // fail safe
477     SG_LOG(SG_TERRAIN, SG_ALERT,
478            "unknown vasi/papi configuration, count = " << count);
479     return 0;
480   }
481 }
482
483 osg::Drawable*
484 SGLightFactory::getVasi(const SGVec3f& up, const SGDirectionalLightBin& lights,
485                         const SGVec4f& red, const SGVec4f& white)
486 {
487   SGVasiDrawable* drawable = buildVasi(lights, up, red, white);
488   if (!drawable)
489     return 0;
490
491   osg::StateSet* stateSet = drawable->getOrCreateStateSet();
492   stateSet->setRenderBinDetails(9, "DepthSortedBin");
493   stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
494
495   osg::BlendFunc* blendFunc = new osg::BlendFunc;
496   stateSet->setAttribute(blendFunc);
497   stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
498   
499   osg::AlphaFunc* alphaFunc;
500   alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01);
501   stateSet->setAttribute(alphaFunc);
502   stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
503
504   return drawable;
505 }
506
507 osg::Node*
508 SGLightFactory::getSequenced(const SGDirectionalLightBin& lights)
509 {
510   if (lights.getNumLights() <= 0)
511     return 0;
512
513   // generate a repeatable random seed
514   sg_srandom(unsigned(lights.getLight(0).position[0]));
515   float flashTime = 2e-2 + 5e-3*sg_random();
516   osg::Sequence* sequence = new osg::Sequence;
517   sequence->setDefaultTime(flashTime);
518
519   for (int i = lights.getNumLights() - 1; 0 <= i; --i)
520     sequence->addChild(getLight(lights.getLight(i)), flashTime);
521   sequence->addChild(new osg::Group, 1 + 1e-1*sg_random());
522   sequence->setInterval(osg::Sequence::LOOP, 0, -1);
523   sequence->setDuration(1.0f, -1);
524   sequence->setMode(osg::Sequence::START);
525   sequence->setSync(true);
526
527   osg::StateSet* stateSet = sequence->getOrCreateStateSet();
528   stateSet->setRenderBinDetails(9, "DepthSortedBin");
529   stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
530
531   osg::BlendFunc* blendFunc = new osg::BlendFunc;
532   stateSet->setAttribute(blendFunc);
533   stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
534   
535   osg::AlphaFunc* alphaFunc;
536   alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01);
537   stateSet->setAttribute(alphaFunc);
538   stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
539
540   osg::Point* point = new osg::Point;
541   point->setMinSize(6);
542   point->setMaxSize(10);
543   point->setSize(10);
544   point->setDistanceAttenuation(osg::Vec3(1.0, 0.0001, 0.00000001));
545   sequence->setCullCallback(new SGPointSpriteLightCullCallback(point));
546
547   return sequence;
548 }
549
550 osg::Node*
551 SGLightFactory::getOdal(const SGLightBin& lights)
552 {
553   if (lights.getNumLights() < 2)
554     return 0;
555
556   // generate a repeatable random seed
557   sg_srandom(unsigned(lights.getLight(0).position[0]));
558   float flashTime = 2e-2 + 5e-3*sg_random();
559   osg::Sequence* sequence = new osg::Sequence;
560   sequence->setDefaultTime(flashTime);
561
562   // centerline lights
563   for (int i = lights.getNumLights() - 1; 2 <= i; --i)
564     sequence->addChild(getLight(lights.getLight(i)), flashTime);
565
566   // runway end lights
567   osg::Group* group = new osg::Group;
568   for (unsigned i = 0; i < 2; ++i)
569     group->addChild(getLight(lights.getLight(i)));
570   sequence->addChild(group, flashTime);
571
572   // add an extra empty group for a break
573   sequence->addChild(new osg::Group, 9 + 1e-1*sg_random());
574   sequence->setInterval(osg::Sequence::LOOP, 0, -1);
575   sequence->setDuration(1.0f, -1);
576   sequence->setMode(osg::Sequence::START);
577   sequence->setSync(true);
578
579   osg::StateSet* stateSet = sequence->getOrCreateStateSet();
580   stateSet->setRenderBinDetails(9, "DepthSortedBin");
581   stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
582
583   osg::BlendFunc* blendFunc = new osg::BlendFunc;
584   stateSet->setAttribute(blendFunc);
585   stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
586   
587   osg::AlphaFunc* alphaFunc;
588   alphaFunc = new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01);
589   stateSet->setAttribute(alphaFunc);
590   stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
591
592   osg::Point* point = new osg::Point;
593   point->setMinSize(6);
594   point->setMaxSize(10);
595   point->setSize(10);
596   point->setDistanceAttenuation(osg::Vec3(1.0, 0.0001, 0.00000001));
597   sequence->setCullCallback(new SGPointSpriteLightCullCallback(point));
598
599   return sequence;
600 }