1 /* -*-c++-*- */
2 /* osgEarth - Geospatial SDK for OpenSceneGraph
3  * Copyright 2019 Pelican Mapping
4  * http://osgearth.org
5  *
6  * osgEarth is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>
18  */
19 #include <osgEarth/LineDrawable>
20 #include <osgEarth/Shaders>
21 #include <osgEarth/Registry>
22 #include <osgEarth/Capabilities>
23 #include <osgEarth/LineFunctor>
24 #include <osgEarth/GLUtils>
25 #include <osgEarth/CullingUtils>
26 
27 #include <osg/LineStipple>
28 #include <osg/LineWidth>
29 #include <osgUtil/Optimizer>
30 
31 #include <osgDB/ObjectWrapper>
32 
33 
34 #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) || defined(OSG_GLES3_AVAILABLE)
35 #define OE_GLES_AVAILABLE
36 #endif
37 
38 using namespace osgEarth;
39 
40 
41 // References:
42 // https://mattdesl.svbtle.com/drawing-lines-is-hard
43 // https://github.com/mattdesl/webgl-lines
44 
45 
46 #define LC "[LineGroup] "
47 
48 // Comment this out to test the non-GLSL path
49 #define USE_GPU
50 
51 namespace osgEarth { namespace Serializers { namespace LineGroup
52 {
53     REGISTER_OBJECT_WRAPPER(
54         LineGroup,
55         new osgEarth::LineGroup,
56         osgEarth::LineGroup,
57         "osg::Object osg::Node osg::Group osg::Geode osgEarth::LineGroup")
58     {
59         // no properties
60     }
61 } } }
62 
LineGroup()63 LineGroup::LineGroup()
64 {
65     //nop
66 }
67 
LineGroup(const LineGroup & rhs,const osg::CopyOp & copy)68 LineGroup::LineGroup(const LineGroup& rhs, const osg::CopyOp& copy) :
69 osg::Geode(rhs, copy)
70 {
71     //nop
72 }
73 
~LineGroup()74 LineGroup::~LineGroup()
75 {
76     //nop
77 }
78 
79 namespace
80 {
81     struct ImportLinesOperator
82     {
83         osg::Vec3Array* _verts;
84         osg::Vec4Array* _colors;
85         LineGroup* _group;
86         LineDrawable* _drawable;
87 
setGeometry__anona61a04170111::ImportLinesOperator88         virtual void setGeometry(osg::Geometry* geom)
89         {
90             _verts = dynamic_cast<osg::Vec3Array*>(geom->getVertexArray());
91             _colors = dynamic_cast<osg::Vec4Array*>(geom->getColorArray());
92         }
93 
line__anona61a04170111::ImportLinesOperator94         void line(unsigned i1, unsigned i2)
95         {
96             if (_verts)
97             {
98                 _drawable->pushVertex((*_verts)[i1]);
99                 _drawable->pushVertex((*_verts)[i2]);
100                 if (_colors && _colors->size() == _verts->size())
101                 {
102                     _drawable->setColor(_drawable->getNumVerts()-2, (*_colors)[_colors->size()-2]);
103                     _drawable->setColor(_drawable->getNumVerts()-1, (*_colors)[_colors->size()-1]);
104                 }
105             }
106         }
107     };
108 
109     typedef LineIndexFunctor<ImportLinesOperator> ImportLinesFunctorBase;
110 
111     struct ImportLinesFunctor : public ImportLinesFunctorBase
112     {
113         osg::LineWidth* _width;
114         osg::LineStipple* _stipple;
115 
ImportLinesFunctor__anona61a04170111::ImportLinesFunctor116         ImportLinesFunctor(osg::Geometry* input, LineGroup* group, osg::LineWidth* width, osg::LineStipple* stipple)
117         {
118             setGeometry(input);
119             _group = group;
120             _drawable = 0L;
121             _width = width;
122             _stipple = stipple;
123         }
124 
emit__anona61a04170111::ImportLinesFunctor125         void emit()
126         {
127             if (_colors && _colors->getBinding() == osg::Array::BIND_OVERALL && _colors->size() > 0)
128             {
129                 _drawable->setColor((*_colors)[0]);
130             }
131 
132             _drawable->dirty();
133 
134             if (_width)
135             {
136                 _drawable->setLineWidth(_width->getWidth());
137             }
138 
139             if (_stipple)
140             {
141                 _drawable->setStipplePattern(_stipple->getPattern());
142                 _drawable->setStippleFactor(_stipple->getFactor());
143             }
144 
145             _group->addChild(_drawable);
146         }
147 
drawArrays__anona61a04170111::ImportLinesFunctor148         virtual void drawArrays(GLenum mode,GLint first,GLsizei count)
149         {
150             if (mode == GL_LINES || mode == GL_LINE_STRIP || mode == GL_LINE_LOOP)
151             {
152                 _drawable = new LineDrawable(GL_LINES);
153                 ImportLinesFunctorBase::drawArrays(mode, first, count);
154                 emit();
155             }
156         }
157 
drawElements__anona61a04170111::ImportLinesFunctor158         virtual void drawElements(GLenum mode,GLsizei count,const GLubyte* indices)
159         {
160             if (mode == GL_LINES || mode == GL_LINE_STRIP || mode == GL_LINE_LOOP)
161             {
162                 _drawable = new LineDrawable(GL_LINES);
163                 ImportLinesFunctorBase::drawElements(mode, count, indices);
164                 emit();
165             }
166         }
167 
drawElements__anona61a04170111::ImportLinesFunctor168         virtual void drawElements(GLenum mode,GLsizei count,const GLushort* indices)
169         {
170             if (mode == GL_LINES || mode == GL_LINE_STRIP || mode == GL_LINE_LOOP)
171             {
172                 _drawable = new LineDrawable(GL_LINES);
173                 ImportLinesFunctorBase::drawElements(mode, count, indices);
174                 emit();
175             }
176         }
177 
drawElements__anona61a04170111::ImportLinesFunctor178         virtual void drawElements(GLenum mode,GLsizei count,const GLuint* indices)
179         {
180             if (mode == GL_LINES || mode == GL_LINE_STRIP || mode == GL_LINE_LOOP)
181             {
182                 _drawable = new LineDrawable(GL_LINES);
183                 ImportLinesFunctorBase::drawElements(mode, count, indices);
184                 emit();
185             }
186         }
187     };
188 
189 
190 
191     struct ImportLinesVisitor : public osg::NodeVisitor
192     {
193         LineGroup* _group;
194         bool _removePrimSets;
195         typedef std::pair<osg::Node*, osg::LineWidth*> Width;
196         typedef std::pair<osg::Node*, osg::LineStipple*> Stipple;
197         std::stack<Width> _width;
198         std::stack<Stipple> _stipple;
199 
ImportLinesVisitor__anona61a04170111::ImportLinesVisitor200         ImportLinesVisitor(LineGroup* group, bool removePrimSets) : _group(group), _removePrimSets(removePrimSets)
201         {
202             setTraversalMode(TRAVERSE_ALL_CHILDREN);
203             setNodeMaskOverride(~0);
204         }
205 
apply__anona61a04170111::ImportLinesVisitor206         void apply(osg::Node& node)
207         {
208             pushState(node);
209             traverse(node);
210             popState(node);
211         }
212 
apply__anona61a04170111::ImportLinesVisitor213         void apply(osg::Drawable& drawable)
214         {
215             pushState(drawable);
216             osg::Geometry* geom = drawable.asGeometry();
217             if (geom)
218             {
219                 ImportLinesFunctor import(
220                     geom,
221                     _group,
222                     _width.empty() ? 0L : _width.top().second,
223                     _stipple.empty() ? 0L : _stipple.top().second);
224 
225                 drawable.accept(import);
226 
227                 if (_removePrimSets)
228                 {
229                     for (int i = 0; i < (int)geom->getNumPrimitiveSets(); ++i)
230                     {
231                         GLenum mode = geom->getPrimitiveSet(i)->getMode();
232                         if (mode == GL_LINES || mode == GL_LINE_STRIP || mode == GL_LINE_LOOP)
233                         {
234                             geom->removePrimitiveSet(i--);
235                         }
236                     }
237                 }
238             }
239             popState(drawable);
240         }
241 
pushState__anona61a04170111::ImportLinesVisitor242         void pushState(osg::Node& node)
243         {
244             osg::StateSet* ss = node.getStateSet();
245             if (ss)
246             {
247                 osg::LineWidth* width = dynamic_cast<osg::LineWidth*>(ss->getAttribute(osg::StateAttribute::LINEWIDTH));
248                 if (width)
249                 {
250                     _width.push(std::make_pair(&node, width));
251                 }
252                 osg::LineStipple* stipple = dynamic_cast<osg::LineStipple*>(ss->getAttribute(osg::StateAttribute::LINESTIPPLE));
253                 if (stipple)
254                 {
255                     _stipple.push(std::make_pair(&node, stipple));
256                 }
257             }
258         }
259 
popState__anona61a04170111::ImportLinesVisitor260         void popState(osg::Node& node)
261         {
262             if (!_width.empty() && _width.top().first == &node)
263                 _width.pop();
264             if (!_stipple.empty() && _stipple.top().first == &node)
265                 _stipple.pop();
266         }
267     };
268 }
269 
270 void
import(osg::Node * node,bool removePrimitiveSets)271 LineGroup::import(osg::Node* node, bool removePrimitiveSets)
272 {
273     if (node)
274     {
275         ImportLinesVisitor visitor(this, removePrimitiveSets);
276         node->accept(visitor);
277     }
278 }
279 
280 void
optimize()281 LineGroup::optimize()
282 {
283     // Optimize state sharing so the MergeGeometryVisitor can work better.
284     // Without this step, the #defines used for width and stippling will
285     // hold up the merge.
286     osg::ref_ptr<StateSetCache> cache = new StateSetCache();
287     cache->optimize(this);
288 
289     // Merge all non-dynamic drawables to reduce the total number of
290     // OpenGL calls.
291     osgUtil::Optimizer::MergeGeometryVisitor mg;
292     mg.setTargetMaximumNumberOfVertices(65536);
293     accept(mg);
294 }
295 
296 LineDrawable*
getLineDrawable(unsigned i)297 LineGroup::getLineDrawable(unsigned i)
298 {
299     return i < getNumChildren() ? dynamic_cast<LineDrawable*>(getChild(i)) : 0L;
300 }
301 
302 //...................................................................
303 
304 #undef  LC
305 #define LC "[LineDrawable] "
306 
307 
308 namespace osgEarth { namespace Serializers { namespace LineDrawable
309 {
310     REGISTER_OBJECT_WRAPPER(
311         LineDrawable,
312         new osgEarth::LineDrawable,
313         osgEarth::LineDrawable,
314         "osg::Object osg::Node osg::Drawable osg::Geometry osgEarth::LineDrawable")
315     {
316         ADD_UINT_SERIALIZER( Mode, GL_LINE_STRIP );
317         ADD_INT_SERIALIZER( StippleFactor, 1 );
318         ADD_USHORT_SERIALIZER( StipplePattern, 0xFFFF );
319         ADD_VEC4_SERIALIZER( Color, osg::Vec4(1,1,1,1) );
320         ADD_FLOAT_SERIALIZER( LineWidth, 1.0f );
321         ADD_UINT_SERIALIZER( First, 0u );
322         ADD_UINT_SERIALIZER( Count, 0u );
323     }
324 } } }
325 
326 // static attribute binding locations. Changable by the user.
327 int LineDrawable::PreviousVertexAttrLocation = 9;
328 int LineDrawable::NextVertexAttrLocation = 10;
329 
LineDrawable()330 LineDrawable::LineDrawable() :
331 osg::Geometry(),
332 _mode(GL_LINE_STRIP),
333 _gpu(false),
334 _factor(1),
335 _pattern(0xFFFF),
336 _color(1, 1, 1, 1),
337 _width(1.0f),
338 _smooth(false),
339 _first(0u),
340 _count(0u),
341 _current(NULL),
342 _previous(NULL),
343 _next(NULL),
344 _colors(NULL)
345 {
346 #ifdef USE_GPU
347     _gpu = Registry::capabilities().supportsGLSL();
348     setupShaders();
349 #endif
350 }
351 
LineDrawable(GLenum mode)352 LineDrawable::LineDrawable(GLenum mode) :
353 osg::Geometry(),
354 _mode(mode),
355 _gpu(false),
356 _factor(1),
357 _pattern(0xFFFF),
358 _color(1,1,1,1),
359 _width(1.0f),
360 _smooth(false),
361 _first(0u),
362 _count(0u),
363 _current(NULL),
364 _previous(NULL),
365 _next(NULL),
366 _colors(NULL)
367 {
368 #ifdef USE_GPU
369     _gpu =
370         Registry::capabilities().supportsGLSL() &&
371         (_mode == GL_LINES || _mode == GL_LINE_STRIP || _mode == GL_LINE_LOOP);
372 
373     setupShaders();
374 #endif
375 }
376 
LineDrawable(const LineDrawable & rhs,const osg::CopyOp & copy)377 LineDrawable::LineDrawable(const LineDrawable& rhs, const osg::CopyOp& copy) :
378 osg::Geometry(rhs, copy),
379 _mode(rhs._mode),
380 _gpu(rhs._gpu),
381 _color(rhs._color),
382 _factor(rhs._factor),
383 _pattern(rhs._pattern),
384 _width(rhs._width),
385 _smooth(rhs._smooth),
386 _first(rhs._first),
387 _count(rhs._count),
388 _current(NULL),
389 _previous(NULL),
390 _next(NULL),
391 _colors(NULL)
392 {
393     _current = static_cast<osg::Vec3Array*>(getVertexArray());
394 
395     if (_gpu)
396     {
397         _previous = static_cast<osg::Vec3Array*>(getVertexAttribArray(PreviousVertexAttrLocation));
398         _next = static_cast<osg::Vec3Array*>(getVertexAttribArray(NextVertexAttrLocation));
399     }
400 
401     setupShaders();
402 }
403 
~LineDrawable()404 LineDrawable::~LineDrawable()
405 {
406     //nop
407 }
408 
409 void
initialize()410 LineDrawable::initialize()
411 {
412     // Already initialized?
413     if (_current)
414         return;
415 
416     // See if the arrays already exist:
417     _current = static_cast<osg::Vec3Array*>(getVertexArray());
418     if (_gpu)
419     {
420         _previous = static_cast<osg::Vec3Array*>(getVertexAttribArray(PreviousVertexAttrLocation));
421         _next = static_cast<osg::Vec3Array*>(getVertexAttribArray(NextVertexAttrLocation));
422     }
423 
424     setUseVertexBufferObjects(_supportsVertexBufferObjects);
425     setUseDisplayList(false);
426 
427     if (!_current)
428     {
429         _current = new osg::Vec3Array();
430         _current->setBinding(osg::Array::BIND_PER_VERTEX);
431         setVertexArray(_current);
432 
433         _colors = new osg::Vec4Array();
434         _colors->setBinding(osg::Array::BIND_PER_VERTEX);
435         setColorArray(_colors);
436 
437         if (_gpu)
438         {
439             _previous = new osg::Vec3Array();
440             _previous->setBinding(osg::Array::BIND_PER_VERTEX);
441             _previous->setNormalize(false);
442             setVertexAttribArray(PreviousVertexAttrLocation, _previous);
443 
444             _next = new osg::Vec3Array();
445             _next->setBinding(osg::Array::BIND_PER_VERTEX);
446             _next->setNormalize(false);
447             setVertexAttribArray(NextVertexAttrLocation, _next);
448         }
449     }
450 }
451 
452 void
setMode(GLenum mode)453 LineDrawable::setMode(GLenum mode)
454 {
455     if (_mode != mode)
456     {
457         _mode = mode;
458     }
459 }
460 
461 void
setLineWidth(float value)462 LineDrawable::setLineWidth(float value)
463 {
464     if (_width != value)
465     {
466         _width = value;
467         GLUtils::setLineWidth(getOrCreateStateSet(), value, 1);
468     }
469 }
470 
471 void
setLineWidth(osg::StateSet * stateSet,float value,int overrideFlags)472 LineDrawable::setLineWidth(osg::StateSet* stateSet, float value, int overrideFlags)
473 {
474     GLUtils::setLineWidth(stateSet, value, overrideFlags);
475 }
476 
477 void
setStipplePattern(GLushort pattern)478 LineDrawable::setStipplePattern(GLushort pattern)
479 {
480     //if (_pattern != pattern)
481     {
482         _pattern = pattern;
483         GLUtils::setLineStipple(getOrCreateStateSet(), _factor, _pattern, 1);
484     }
485 }
486 
487 void
setStippleFactor(GLint factor)488 LineDrawable::setStippleFactor(GLint factor)
489 {
490     if (_factor != factor)
491     {
492         _factor = factor;
493         GLUtils::setLineStipple(getOrCreateStateSet(), _factor, _pattern, 1);
494     }
495 }
496 
497 void
setLineSmooth(bool value)498 LineDrawable::setLineSmooth(bool value)
499 {
500     if (_smooth != value)
501     {
502         _smooth = value;
503         GLUtils::setLineSmooth(getOrCreateStateSet(), _smooth? 1 : 0);
504     }
505 }
506 
507 void
setColor(const osg::Vec4 & color)508 LineDrawable::setColor(const osg::Vec4& color)
509 {
510     if (_color != color)
511     {
512         initialize();
513 
514         _color = color;
515         if (_colors && !_colors->empty())
516         {
517             _colors->assign(_colors->size(), _color);
518             _colors->dirty();
519         }
520     }
521 }
522 
523 void
setColor(unsigned vi,const osg::Vec4 & color)524 LineDrawable::setColor(unsigned vi, const osg::Vec4& color)
525 {
526     if (_gpu)
527     {
528         if (_mode == GL_LINE_STRIP || _mode == GL_LINE_LOOP)
529         {
530             if (vi == 0)
531             {
532                 for (unsigned i=0; i<2; ++i)
533                     (*_colors)[i] = color;
534                 for (unsigned i=_colors->size()-2; i<_colors->size(); ++i)
535                     (*_colors)[i] = color;
536             }
537             else
538                 for (unsigned i=vi*4-2; i<vi*4+2; ++i)
539                     (*_colors)[i] = color;
540         }
541         else
542         {
543             (*_colors)[vi*2u] = color;
544             (*_colors)[vi*2u+1] = color;
545         }
546     }
547     else
548     {
549         (*_colors)[vi] = color;
550     }
551     _colors->dirty();
552 }
553 
554 void
setFirst(unsigned value)555 LineDrawable::setFirst(unsigned value)
556 {
557     _first = value;
558     updateFirstCount();
559 }
560 
561 unsigned
getFirst() const562 LineDrawable::getFirst() const
563 {
564     return _first;
565 }
566 
567 void
setCount(unsigned value)568 LineDrawable::setCount(unsigned value)
569 {
570     _count = value;
571     updateFirstCount();
572 }
573 
574 unsigned
getCount() const575 LineDrawable::getCount() const
576 {
577     return _count;
578 }
579 
580 void
updateFirstCount()581 LineDrawable::updateFirstCount()
582 {
583     if (_gpu)
584     {
585         osg::StateSet* ss = getOrCreateStateSet();
586         ss->setDataVariance(ss->DYNAMIC);
587 
588         osg::Uniform* u = ss->getUniform("oe_LineDrawable_limits");
589         if (!u)
590         {
591             u = new osg::Uniform(osg::Uniform::FLOAT_VEC2, "oe_LineDrawable_limits");
592             ss->addUniform(u, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
593         }
594 
595         if (_mode == GL_LINE_STRIP)
596         {
597             u->set(osg::Vec2(4u*_first + 2u, 4u*(_first+_count-1u)+1u));
598         }
599         else if (_mode == GL_LINES)
600         {
601             u->set(osg::Vec2(2u * _first, _count > 1u ? 2u * (_first + _count) - 1u : 0u));
602         }
603     }
604     else
605     {
606         if (getNumPrimitiveSets() > 0)
607         {
608             osg::DrawArrays* da = dynamic_cast<osg::DrawArrays*>(getPrimitiveSet(0));
609             if (da)
610             {
611                 da->setFirst(_first);
612                 da->dirty();
613             }
614         }
615     }
616 }
617 
618 void
pushVertex(const osg::Vec3 & vert)619 LineDrawable::pushVertex(const osg::Vec3& vert)
620 {
621     initialize();
622 
623     if (_gpu)
624     {
625         if (_mode == GL_LINE_STRIP)
626         {
627             bool first = _current->empty();
628 
629             _previous->push_back(first ? vert : _current->back());
630             _previous->push_back(first ? vert : _current->back());
631             _previous->push_back(first ? vert : _current->back());
632             _previous->push_back(first ? vert : _current->back());
633 
634             if (!first)
635             {
636                 *(_next->end() - 4) = vert;
637                 *(_next->end() - 3) = vert;
638                 *(_next->end() - 2) = vert;
639                 *(_next->end() - 1) = vert;
640             }
641 
642             _current->push_back(vert);
643             _current->push_back(vert);
644             _current->push_back(vert);
645             _current->push_back(vert);
646 
647             _next->push_back(vert);
648             _next->push_back(vert);
649             _next->push_back(vert);
650             _next->push_back(vert);
651 
652             _colors->push_back(_color);
653             _colors->push_back(_color);
654             _colors->push_back(_color);
655             _colors->push_back(_color);
656         }
657 
658         else if (_mode == GL_LINE_LOOP)
659         {
660             bool first = _current->empty();
661 
662             _previous->push_back(first ? vert : _current->back());
663             _previous->push_back(first ? vert : _current->back());
664             _previous->push_back(first ? vert : _current->back());
665             _previous->push_back(first ? vert : _current->back());
666 
667             if (!first)
668             {
669                 *(_next->end() - 4) = vert;
670                 *(_next->end() - 3) = vert;
671                 *(_next->end() - 2) = vert;
672                 *(_next->end() - 1) = vert;
673 
674                 (*_previous)[0] = vert;
675                 (*_previous)[1] = vert;
676                 (*_previous)[2] = vert;
677                 (*_previous)[3] = vert;
678             }
679 
680             _current->push_back(vert);
681             _current->push_back(vert);
682             _current->push_back(vert);
683             _current->push_back(vert);
684 
685             _next->push_back(_current->front());
686             _next->push_back(_current->front());
687             _next->push_back(_current->front());
688             _next->push_back(_current->front());
689 
690             _colors->push_back(_color);
691             _colors->push_back(_color);
692             _colors->push_back(_color);
693             _colors->push_back(_color);
694         }
695 
696         else if (_mode == GL_LINES)
697         {
698             bool first = ((_current->size() / 2) & 0x01) == 0;
699 
700             if (first)
701             {
702                 _previous->push_back(vert);
703                 _previous->push_back(vert);
704 
705                 _next->push_back(vert);
706                 _next->push_back(vert);
707             }
708             else
709             {
710                 _previous->push_back(_current->back());
711                 _previous->push_back(_current->back());
712 
713                 *(_next->end() - 2) = vert;
714                 *(_next->end() - 1) = vert;
715 
716                 _next->push_back(vert);
717                 _next->push_back(vert);
718             }
719 
720             _current->push_back(vert);
721             _current->push_back(vert);
722 
723             _colors->push_back(_color);
724             _colors->push_back(_color);
725         }
726 
727         _previous->dirty();
728         _next->dirty();
729     }
730 
731     else
732     {
733         _current->push_back(vert);
734         _colors->push_back(_color);
735     }
736 
737     _current->dirty();
738     _colors->dirty();
739 }
740 
741 void
setVertex(unsigned vi,const osg::Vec3 & vert)742 LineDrawable::setVertex(unsigned vi, const osg::Vec3& vert)
743 {
744     initialize();
745 
746     // if we've already called dirty() that means we are editing a completed
747     // drawable and therefore need dynamic variance.
748     if (getNumPrimitiveSets() > 0u && getDataVariance() != DYNAMIC)
749     {
750         setDataVariance(DYNAMIC);
751     }
752 
753     unsigned size = _current->size();
754     unsigned numVerts = getNumVerts();
755 
756     // "vi" = virtual index, "ri" = real index.
757 
758     if (vi < numVerts)
759     {
760         if (_gpu)
761         {
762             if (_mode == GL_LINE_STRIP)
763             {
764                 unsigned ri = vi*4u;
765                 unsigned rnum = 4u; // number of real verts to set
766 
767                 // update the main verts:
768                 for (unsigned n = ri; n < ri+rnum; ++n)
769                 {
770                     (*_current)[n] = vert;
771                 }
772                 _current->dirty();
773 
774                 // update next/previous verts:
775                 if (numVerts == 1u)
776                 {
777                     for(unsigned i=0; i<4; ++i)
778                     {
779                         (*_next)[i] = (*_previous)[i] = vert;
780                     }
781                     _next->dirty();
782                     _previous->dirty();
783                 }
784                 else
785                 {
786                     if (vi > 0u)
787                     {
788                         unsigned rni = ri-4u;
789                         for (unsigned n = 0; n < rnum; ++n)
790                         {
791                             (*_next)[rni + n] = vert;
792                         }
793                         _next->dirty();
794                     }
795                     else // if vi == 0
796                     {
797                         for (unsigned n = 0; n < rnum; ++n)
798                         {
799                             (*_previous)[n] = vert;
800                         }
801                         _previous->dirty();
802                     }
803 
804                     if (vi < numVerts-1)
805                     {
806                         unsigned rpi = ri+4u;
807                         for (unsigned n = 0; n < rnum; ++n)
808                         {
809                             (*_previous)[rpi + n] = vert;
810                         }
811                         _previous->dirty();
812                     }
813                     else // if (vi == numVerts-1)
814                     {
815                         for (unsigned n = 0; n < rnum; ++n)
816                         {
817                             (*_next)[ri+n] = vert;
818                         }
819                         _next->dirty();
820                     }
821                 }
822             }
823 
824             else if (_mode == GL_LINE_LOOP)
825             {
826                 unsigned ri = vi*4u; // starting real index
827                 unsigned rnum = 4u; // number of real verts to set
828 
829                 // update the main verts:
830                 for (unsigned n = ri; n < ri+rnum; ++n)
831                 {
832                     (*_current)[n] = vert;
833                 }
834                 _current->dirty();
835 
836                 // update next/previous verts:
837                 if (numVerts == 1u)
838                 {
839                     for(unsigned i=0; i<4; ++i)
840                     {
841                         (*_next)[i] = (*_previous)[i] = vert;
842                     }
843                 }
844                 else
845                 {
846                     unsigned rni = vi==0u? numVerts-4u : ri-4u;
847                     unsigned rpi = vi==numVerts-1u ? 0u : ri+4u;
848 
849                     for(unsigned n=0; n<rnum; ++n)
850                     {
851                         (*_next)[rni+n] = vert;
852                         (*_previous)[rpi+n] = vert;
853                     }
854                 }
855 
856                 _next->dirty();
857                 _previous->dirty();
858             }
859 
860             else if (_mode == GL_LINES)
861             {
862                 unsigned ri = vi * 2u;
863 
864                 (*_current)[ri] = vert;
865                 (*_current)[ri + 1] = vert;
866                 _current->dirty();
867 
868                 bool first = (vi & 0x01) == 0;
869                 if (first)
870                 {
871                     (*_previous)[ri] = vert;
872                     (*_previous)[ri+1] = vert;
873                     (*_previous)[ri+2] = vert;
874                     (*_previous)[ri+3] = vert;
875                     _previous->dirty();
876                 }
877                 else
878                 {
879                     (*_next)[ri+1] = vert;
880                     (*_next)[ri] = vert;
881                     (*_next)[ri-1] = vert;
882                     (*_next)[ri-2] = vert;
883                     _next->dirty();
884                 }
885             }
886         }
887 
888         else
889         {
890             (*_current)[vi] = vert;
891             _current->dirty();
892         }
893 
894         dirtyBound();
895     }
896 }
897 
898 const osg::Vec3&
getVertex(unsigned index) const899 LineDrawable::getVertex(unsigned index) const
900 {
901     return (*_current)[getRealIndex(index)];
902 }
903 
904 unsigned
getRealIndex(unsigned index) const905 LineDrawable::getRealIndex(unsigned index) const
906 {
907     if (_gpu)
908         return (_mode == GL_LINE_STRIP || _mode == GL_LINE_LOOP) ? index*4u : index*2u;
909     else
910         return index;
911 }
912 
913 void
importVertexArray(const osg::Vec3Array * verts)914 LineDrawable::importVertexArray(const osg::Vec3Array* verts)
915 {
916     initialize();
917 
918     _current->clear();
919     _colors->clear();
920     if (verts && verts->size() > 0)
921     {
922         if (_gpu)
923         {
924             _previous->clear();
925             _next->clear();
926         }
927 
928         reserve(verts->size());
929 
930         for (osg::Vec3Array::const_iterator i = verts->begin(); i != verts->end(); ++i)
931         {
932             pushVertex(*i);
933         }
934     }
935 
936     dirty();
937 }
938 
939 void
allocate(unsigned numVerts)940 LineDrawable::allocate(unsigned numVerts)
941 {
942     initialize();
943 
944     unsigned num = getNumVerts();
945     if (numVerts >= num)
946     {
947         for (unsigned i = num; i < numVerts; ++i)
948         {
949             pushVertex(osg::Vec3(0,0,0));
950         }
951     }
952     else
953     {
954         clear();
955         for (unsigned i = 0; i < numVerts; ++i)
956         {
957             pushVertex(osg::Vec3(0,0,0));
958         }
959     }
960 
961     dirty();
962 }
963 
964 // Calculates the "virtual" number of vertices in this drawable.
965 // The actual number of vertices depends on the GL mode.
966 unsigned
getNumVerts() const967 LineDrawable::getNumVerts() const
968 {
969     if (!_current || _current->empty())
970         return 0u;
971 
972     if (_gpu)
973     {
974         if (_mode == GL_LINE_STRIP || _mode == GL_LINE_LOOP)
975             return _current->size()/4; //_current->size() == 2 ? 1 : (_current->size()+2)/4;
976         else
977             return _current->size()/2;
978     }
979     else
980     {
981         return _current->size();
982     }
983 }
984 
985 unsigned
actualVertsPerVirtualVert(unsigned index) const986 LineDrawable::actualVertsPerVirtualVert(unsigned index) const
987 {
988     if (_gpu)
989         if (_mode == GL_LINE_STRIP || _mode == GL_LINE_LOOP)
990             return 4u; //index == 0u? 2u : 4u;
991         else
992             return 2u;
993     else
994         return 1u;
995 }
996 
997 unsigned
numVirtualVerts(const osg::Array * a) const998 LineDrawable::numVirtualVerts(const osg::Array* a) const
999 {
1000     unsigned n = a->getNumElements();
1001     if (n == 0u)
1002         return 0u;
1003 
1004     if (_gpu)
1005         if (_mode == GL_LINE_STRIP || _mode == GL_LINE_LOOP)
1006             return n/4u; //n == 2u ? 1u : (n+2u)/4u;
1007         else
1008             return n/2u;
1009     else
1010         return n;
1011 }
1012 
1013 void
reserve(unsigned size)1014 LineDrawable::reserve(unsigned size)
1015 {
1016     initialize();
1017 
1018     unsigned actualSize = size;
1019     if (_gpu)
1020     {
1021         actualSize = (_mode == GL_LINE_STRIP || _mode == GL_LINE_LOOP) ? size*4u : size*2u;
1022     }
1023 
1024     if (actualSize > _current->size())
1025     {
1026         ArrayList arrays;
1027         getArrayList(arrays);
1028         for (ArrayList::iterator i = arrays.begin(); i != arrays.end(); ++i)
1029             i->get()->reserveArray(actualSize);
1030     }
1031 }
1032 
1033 void
clear()1034 LineDrawable::clear()
1035 {
1036     initialize();
1037 
1038     unsigned n = getNumVerts();
1039     if (n > 0u)
1040     {
1041         ArrayList arrays;
1042         getArrayList(arrays);
1043         for (ArrayList::iterator i = arrays.begin(); i != arrays.end(); ++i)
1044         {
1045             i->get()->resizeArray(0);
1046         }
1047         reserve(n);
1048     }
1049 }
1050 
1051 namespace
1052 {
makeDE(unsigned size)1053     osg::DrawElements* makeDE(unsigned size)
1054     {
1055         osg::DrawElements* de =
1056 #ifndef OE_GLES_AVAILABLE
1057             size > 0xFFFF ? (osg::DrawElements*)new osg::DrawElementsUInt(GL_TRIANGLES) :
1058 #endif
1059             size > 0xFF ?   (osg::DrawElements*)new osg::DrawElementsUShort(GL_TRIANGLES) :
1060                             (osg::DrawElements*)new osg::DrawElementsUByte(GL_TRIANGLES);
1061         de->reserveElements(size);
1062         return de;
1063     }
1064 }
1065 
1066 void
dirty()1067 LineDrawable::dirty()
1068 {
1069     initialize();
1070 
1071     dirtyBound();
1072 
1073     _current->dirty();
1074 
1075     if (_gpu)
1076     {
1077         _previous->dirty();
1078         _next->dirty();
1079     }
1080 
1081     // rebuild primitive sets.
1082     if (getNumPrimitiveSets() > 0)
1083     {
1084         removePrimitiveSet(0, 1);
1085     }
1086 
1087     if (_gpu && _current->size() >= 4)
1088     {
1089         // IMPORTANT!
1090         // Don't change the order of the elements! Because of the way
1091         // GPU line stippling works, it is critical that the provoking vertex
1092         // be at the beginning of each line segment. In this case we are using
1093         // GL_TRIANGLES and thus the provoking vertex (PV) is the FINAL vert
1094         // in each triangle.
1095 
1096         if (_mode == GL_LINE_STRIP)
1097         {
1098             unsigned numEls = (getNumVerts()-1)*6;
1099             osg::DrawElements* els = makeDE(numEls);
1100 
1101             for (int e = 2; e < _current->size() - 2; e += 4)
1102             {
1103                 els->addElement(e+3);
1104                 els->addElement(e+1);
1105                 els->addElement(e+0); // PV
1106                 els->addElement(e+2);
1107                 els->addElement(e+3);
1108                 els->addElement(e+0); // PV
1109             }
1110 
1111             addPrimitiveSet(els);
1112         }
1113 
1114         else if (_mode == GL_LINE_LOOP)
1115         {
1116             unsigned numEls = getNumVerts()*6;
1117             osg::DrawElements* els = makeDE(numEls);
1118 
1119             int e;
1120             for (e = 2; e < _current->size() - 2; e += 4)
1121             {
1122                 els->addElement(e+3);
1123                 els->addElement(e+1);
1124                 els->addElement(e+0); // PV
1125                 els->addElement(e+2);
1126                 els->addElement(e+3);
1127                 els->addElement(e+0); // PV
1128             }
1129 
1130             els->addElement(1);
1131             els->addElement(e+1);
1132             els->addElement(e+0); // PV
1133             els->addElement(0);
1134             els->addElement(1);
1135             els->addElement(e+0); // PV
1136 
1137             addPrimitiveSet(els);
1138         }
1139 
1140         else if (_mode == GL_LINES)
1141         {
1142             // if there are an odd number of verts, ignore the last one.
1143             unsigned numVerts = getNumVerts();
1144             if (numVerts & 0x01) --numVerts;
1145 
1146             if (numVerts > 0u)
1147             {
1148                 unsigned numEls = (numVerts/2)*6;
1149                 osg::DrawElements* els = makeDE(numEls);
1150 
1151                 for(unsigned e=0; e<numVerts*2u; e += 4)
1152                 {
1153                 //for (int e = 0; e < _current->size(); e += 4)
1154                     els->addElement(e+3);
1155                     els->addElement(e+1);
1156                     els->addElement(e+0); // PV
1157                     els->addElement(e+2);
1158                     els->addElement(e+3);
1159                     els->addElement(e+0); // PV
1160                 }
1161 
1162                 addPrimitiveSet(els);
1163             }
1164         }
1165     }
1166 
1167     else
1168     {
1169         ArrayList arrays;
1170         getArrayList(arrays);
1171         for (unsigned i = 0; i<arrays.size(); ++i)
1172             arrays[i]->dirty();
1173 
1174         addPrimitiveSet(new osg::DrawArrays(_mode, _first, _count > 0u? _count : _current->size()));
1175     }
1176 }
1177 
1178 osg::observer_ptr<osg::StateSet> LineDrawable::s_gpuStateSet;
1179 
1180 void
setupShaders()1181 LineDrawable::setupShaders()
1182 {
1183     // Create the singleton state set for the line shader. This stateset will be
1184     // shared by all LineDrawable instances so OSG will sort them together.
1185     if (_gpu && !_gpuStateSet.valid())
1186     {
1187         if (s_gpuStateSet.lock(_gpuStateSet) == false)
1188         {
1189             // serialize access and double-check:
1190             static Threading::Mutex s_mutex;
1191             Threading::ScopedMutexLock lock(s_mutex);
1192 
1193             if (s_gpuStateSet.lock(_gpuStateSet) == false)
1194             {
1195                 s_gpuStateSet = _gpuStateSet = new osg::StateSet();
1196 
1197                 VirtualProgram* vp = VirtualProgram::getOrCreate(s_gpuStateSet.get());
1198                 vp->setName("osgEarth::LineDrawable");
1199                 Shaders shaders;
1200                 shaders.load(vp, shaders.LineDrawable);
1201                 vp->addBindAttribLocation("oe_LineDrawable_prev", LineDrawable::PreviousVertexAttrLocation);
1202                 vp->addBindAttribLocation("oe_LineDrawable_next", LineDrawable::NextVertexAttrLocation);
1203                 s_gpuStateSet->getOrCreateUniform("oe_LineDrawable_limits", osg::Uniform::FLOAT_VEC2)->set(osg::Vec2f(-1, -1));
1204                 s_gpuStateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED);
1205             }
1206         }
1207     }
1208 }
1209 
1210 void
accept(osg::NodeVisitor & nv)1211 LineDrawable::accept(osg::NodeVisitor& nv)
1212 {
1213     if (nv.validNodeMask(*this))
1214     {
1215         // Only push the shader if necessary.
1216         // The reason for this approach is go we can inject the singleton
1217         // LineDrawable shader yet still allow the user to customize
1218         // the node's StateSet.
1219         bool shade =
1220             _gpu &&
1221             nv.getVisitorType() == nv.CULL_VISITOR &&
1222             _gpuStateSet.valid();
1223 
1224         osgUtil::CullVisitor* cv = shade? Culling::asCullVisitor(nv) : 0L;
1225 
1226         nv.pushOntoNodePath(this);
1227 
1228         if (cv)
1229             cv->pushStateSet(_gpuStateSet.get());
1230 
1231         nv.apply(*this);
1232 
1233         if (cv)
1234             cv->popStateSet();
1235 
1236         nv.popFromNodePath();
1237     }
1238 }
1239 
1240 
1241 void
resizeGLObjectBuffers(unsigned maxSize)1242 LineDrawable::resizeGLObjectBuffers(unsigned maxSize)
1243 {
1244     osg::Geometry::resizeGLObjectBuffers(maxSize);
1245     if (_gpuStateSet.valid())
1246         _gpuStateSet->resizeGLObjectBuffers(maxSize);
1247 }
1248 
1249 void
releaseGLObjects(osg::State * state) const1250 LineDrawable::releaseGLObjects(osg::State* state) const
1251 {
1252     osg::Geometry::releaseGLObjects(state);
1253     if (_gpuStateSet.valid())
1254         _gpuStateSet->releaseGLObjects(state);
1255 }
1256