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