1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12  *
13  * osg/PrimitiveSetIndirect.cpp
14  * Author: Julien Valentin 2016-2017
15 */
16 
17 #include <osg/PrimitiveSetIndirect>
18 #include <osg/BufferObject>
19 #include <osg/State>
20 #include <osg/Notify>
21 
22 ///  TODO: add base vertex feature to PrimitiveFunctor and PrimitiveIndexFunctor
23 //#define PRIMFUNCTORBASEVERTEX 1
24 
25 using namespace osg;
26 ////////////////////////////////////////////////////////////////////////////////////////////////////////
27 //
28 // DrawElementsIndirect
29 //
30 template<class T>
getNumPrimitivesDI(const T & _this)31 inline unsigned int getNumPrimitivesDI( const T&_this )
32 {
33     unsigned int offset= _this.getFirstCommandToDraw();
34     IndirectCommandDrawElements *cmd=const_cast<IndirectCommandDrawElements *>(_this.getIndirectCommandArray());
35     unsigned int total=0;
36     switch(_this.getMode())
37     {
38         case(PrimitiveSet::POINTS):
39             return cmd->count(offset);
40         case(PrimitiveSet::LINES):
41             return cmd->count(offset)/2;
42         case(PrimitiveSet::TRIANGLES):
43             return cmd->count(offset)/3;
44         case(PrimitiveSet::QUADS):
45             return cmd->count(offset)/4;
46         case(PrimitiveSet::LINE_STRIP):
47         case(PrimitiveSet::LINE_LOOP):
48         case(PrimitiveSet::TRIANGLE_STRIP):
49         case(PrimitiveSet::TRIANGLE_FAN):
50         case(PrimitiveSet::QUAD_STRIP):
51         case(PrimitiveSet::PATCHES):
52         case(PrimitiveSet::POLYGON):
53         {
54             return 1;
55         }
56     }
57     return total;
58 }
59 
getNumPrimitives() const60 unsigned int DrawElementsIndirectUInt::getNumPrimitives() const { return getNumPrimitivesDI<DrawElementsIndirectUInt>(*this); }
getNumPrimitives() const61 unsigned int DrawElementsIndirectUByte::getNumPrimitives() const { return getNumPrimitivesDI<DrawElementsIndirectUByte>(*this); }
getNumPrimitives() const62 unsigned int DrawElementsIndirectUShort::getNumPrimitives() const { return getNumPrimitivesDI<DrawElementsIndirectUShort>(*this); }
63 
draw(State & state,bool) const64 void DrawElementsIndirectUInt::draw(State& state, bool /*useVertexBufferObjects*/) const
65 {
66     GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() );
67     state.bindDrawIndirectBufferObject(dibo);
68 
69     GLenum mode = _mode;
70 #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
71     if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN;
72     if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP;
73 #endif
74 
75     GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID());
76 
77     state.bindElementBufferObject(ebo);
78 
79     state.get<GLExtensions>()-> glDrawElementsIndirect(mode, GL_UNSIGNED_INT,
80         (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex()) //command array address
81         +_firstCommand* _indirectCommandArray->getElementSize())// runtime offset computaion can be sizeof(*_indirectCommandArray->begin())
82     );
83 }
84 
~DrawElementsIndirectUInt()85 DrawElementsIndirectUInt::~DrawElementsIndirectUInt()
86 {
87     releaseGLObjects();
88 }
89 
offsetIndices(int offset)90 void DrawElementsIndirectUInt::offsetIndices(int offset)
91 {
92     for(iterator itr=begin();
93             itr!=end();
94             ++itr)
95     {
96         *itr += offset;
97     }
98 }
99 
100 #ifndef PRIMFUNCTORBASEVERTEX
accept(PrimitiveFunctor &) const101 void DrawElementsIndirectUInt::accept(PrimitiveFunctor&) const {}
accept(PrimitiveIndexFunctor &) const102 void DrawElementsIndirectUInt::accept(PrimitiveIndexFunctor&) const {}
103 #else
accept(PrimitiveFunctor & functor) const104 void DrawElementsIndirectUInt::accept(PrimitiveFunctor& functor) const
105 {
106    //  TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method
107    if (!empty())
108         functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand),
109                              &(*this)[_indirectCommandArray->firstIndex(_firstCommand)],
110                              _indirectCommandArray->baseVertex(_firstCommand));
111 }
112 
accept(PrimitiveIndexFunctor & functor) const113 void DrawElementsIndirectUInt::accept(PrimitiveIndexFunctor& functor) const
114 {
115    //  TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method
116    if (!empty())
117         functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand),
118                              &(*this)[_indirectCommandArray->firstIndex(_firstCommand)],
119                              _indirectCommandArray->baseVertex(_firstCommand));
120 }
121 #endif
122 
draw(State & state,bool) const123 void DrawElementsIndirectUByte::draw(State& state, bool /*useVertexBufferObjects*/) const
124 {
125     GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() );
126     state.bindDrawIndirectBufferObject(dibo);
127 
128     GLenum mode = _mode;
129 #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
130     if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN;
131     if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP;
132 #endif
133 
134     GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID());
135 
136     state.bindElementBufferObject(ebo);
137 
138     state.get<GLExtensions>()-> glDrawElementsIndirect(mode, GL_UNSIGNED_BYTE,
139                                                       (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())+_firstCommand* _indirectCommandArray->getElementSize()));
140 }
141 
~DrawElementsIndirectUByte()142 DrawElementsIndirectUByte::~DrawElementsIndirectUByte()
143 {
144     releaseGLObjects();
145 }
146 
offsetIndices(int offset)147 void DrawElementsIndirectUByte::offsetIndices(int offset)
148 {
149     for(iterator itr=begin();
150             itr!=end();
151             ++itr)
152     {
153         *itr += offset;
154     }
155 }
156 
157 #ifndef PRIMFUNCTORBASEVERTEX
accept(PrimitiveFunctor &) const158 void DrawElementsIndirectUByte::accept(PrimitiveFunctor&) const {}
accept(PrimitiveIndexFunctor &) const159 void DrawElementsIndirectUByte::accept(PrimitiveIndexFunctor&) const {}
160 #else
accept(PrimitiveFunctor & functor) const161 void DrawElementsIndirectUByte::accept(PrimitiveFunctor& functor) const
162 {
163    //  TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method
164    if (!empty())
165         functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand),
166                              &(*this)[_indirectCommandArray->firstIndex(_firstCommand)],
167                              _indirectCommandArray->baseVertex(_firstCommand));
168 }
169 
accept(PrimitiveIndexFunctor & functor) const170 void DrawElementsIndirectUByte::accept(PrimitiveIndexFunctor& functor) const
171 {
172    //  TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method
173    if (!empty())
174         functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand),
175                       &(*this)[_indirectCommandArray->firstIndex(_firstCommand)],
176                       _indirectCommandArray->baseVertex(_firstCommand));
177 }
178 #endif
179 
draw(State & state,bool) const180 void DrawElementsIndirectUShort::draw(State& state, bool /*useVertexBufferObjects*/) const
181 {
182     GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() );
183     state.bindDrawIndirectBufferObject(dibo);
184 
185     GLenum mode = _mode;
186 #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
187     if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN;
188     if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP;
189 #endif
190 
191     GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID());
192 
193     state.bindElementBufferObject(ebo);
194 
195     state.get<GLExtensions>()-> glDrawElementsIndirect(mode, GL_UNSIGNED_SHORT,
196                                                        (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())+_firstCommand* _indirectCommandArray->getElementSize()));
197 }
198 
~DrawElementsIndirectUShort()199 DrawElementsIndirectUShort::~DrawElementsIndirectUShort()
200 {
201     releaseGLObjects();
202 }
203 
offsetIndices(int offset)204 void DrawElementsIndirectUShort::offsetIndices(int offset)
205 {
206     for(iterator itr=begin();
207             itr!=end();
208             ++itr)
209     {
210         *itr += offset;
211     }
212 }
213 
214 #ifndef PRIMFUNCTORBASEVERTEX
accept(PrimitiveFunctor &) const215 void DrawElementsIndirectUShort::accept(PrimitiveFunctor&) const {}
accept(PrimitiveIndexFunctor &) const216 void DrawElementsIndirectUShort::accept(PrimitiveIndexFunctor&) const {}
217 #else
accept(PrimitiveFunctor & functor) const218 void DrawElementsIndirectUShort::accept(PrimitiveFunctor& functor) const
219 {
220    //  TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method
221    if (!empty())
222         functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand),
223                              &(*this)[_indirectCommandArray->firstIndex(_firstCommand)],
224                              _indirectCommandArray->baseVertex(_firstCommand));
225 }
226 
accept(PrimitiveIndexFunctor & functor) const227 void DrawElementsIndirectUShort::accept(PrimitiveIndexFunctor& functor) const
228 {
229    //  TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method
230    if (!empty())
231         functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand),
232                              &(*this)[_indirectCommandArray->firstIndex(_firstCommand)],
233                              _indirectCommandArray->baseVertex(_firstCommand));
234 }
235 #endif
236 
237 ////////////////////////////////////////////////////////////////////////////////////////////////////////
238 //
239 // MultiDrawElementsIndirect
240 //
241 template<class T>   inline
getNumPrimitivesMDI(const T & _this)242 unsigned int getNumPrimitivesMDI( const T&_this)
243 {
244     IndirectCommandDrawElements *_indirectCommandArray=const_cast<IndirectCommandDrawElements *>(_this.getIndirectCommandArray());
245     unsigned int total=0;
246     switch(_this.getMode())
247     {
248         case(PrimitiveSet::POINTS):
249             for(unsigned int i=0;i<_indirectCommandArray->getNumElements();++i)
250                 total+=_indirectCommandArray->count(i);
251             break;
252         case(PrimitiveSet::LINES):
253             for(unsigned int i=0;i<_indirectCommandArray->getNumElements();++i)
254             total+=_indirectCommandArray->count(i)/2;
255             break;
256         case(PrimitiveSet::TRIANGLES):
257             for(unsigned int i=0;i<_indirectCommandArray->getNumElements();++i)
258             total+=_indirectCommandArray->count(i)/3;
259             break;
260         case(PrimitiveSet::QUADS):
261             for(unsigned int i=0;i<_indirectCommandArray->getNumElements();++i)
262             total+=_indirectCommandArray->count(i)/4;
263             break;
264         case(PrimitiveSet::LINE_STRIP):
265         case(PrimitiveSet::LINE_LOOP):
266         case(PrimitiveSet::TRIANGLE_STRIP):
267         case(PrimitiveSet::TRIANGLE_FAN):
268         case(PrimitiveSet::QUAD_STRIP):
269         case(PrimitiveSet::PATCHES):
270         case(PrimitiveSet::POLYGON):
271         {
272             unsigned int primcount = _indirectCommandArray->getNumElements();
273             return primcount;
274         }
275     }
276     return total;
277 }
278 
getNumPrimitives() const279 unsigned int MultiDrawElementsIndirectUInt::getNumPrimitives() const { return getNumPrimitivesMDI<MultiDrawElementsIndirectUInt>(*this); }
getNumPrimitives() const280 unsigned int MultiDrawElementsIndirectUByte::getNumPrimitives() const { return getNumPrimitivesMDI<MultiDrawElementsIndirectUByte>(*this); }
getNumPrimitives() const281 unsigned int MultiDrawElementsIndirectUShort::getNumPrimitives() const { return getNumPrimitivesMDI<MultiDrawElementsIndirectUShort>(*this); }
282 
283 ////////////////////////////////////////////////////////////////////////////////////////////////////////
284 //
285 // MultiDrawElementsIndirectUByte
286 //
~MultiDrawElementsIndirectUByte()287 MultiDrawElementsIndirectUByte::~MultiDrawElementsIndirectUByte()
288 {
289     releaseGLObjects();
290 }
291 
draw(State & state,bool) const292 void MultiDrawElementsIndirectUByte::draw(State& state, bool /*useVertexBufferObjects*/) const
293 {
294     GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() );
295 
296     state.bindDrawIndirectBufferObject(dibo);
297     GLenum mode = _mode;
298 #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
299     if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN;
300     if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP;
301 #endif
302 
303     GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID());
304 
305     state.bindElementBufferObject(ebo);
306 
307     state.get<GLExtensions>()-> glMultiDrawElementsIndirect(mode, GL_UNSIGNED_BYTE,
308                                                             (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())),_indirectCommandArray->getNumElements(), _stride);
309 }
310 
311 #ifndef PRIMFUNCTORBASEVERTEX
accept(PrimitiveFunctor &) const312 void MultiDrawElementsIndirectUByte::accept(PrimitiveFunctor&) const {}
accept(PrimitiveIndexFunctor &) const313 void MultiDrawElementsIndirectUByte::accept(PrimitiveIndexFunctor&) const {}
314 #else
accept(PrimitiveFunctor & functor) const315 void MultiDrawElementsIndirectUByte::accept(PrimitiveFunctor& functor) const
316 {
317   //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method
318        unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand;
319        if (!empty() )
320             for(unsigned int i = _firstCommand; i<maxindex; ++i)
321                     functor.drawElements(_mode,_indirectCommandArray->count(i),
322                                          &(*this)[_indirectCommandArray->firstIndex(i)],
323                                          _indirectCommandArray->baseVertex(i));
324 }
325 
accept(PrimitiveIndexFunctor & functor) const326 void MultiDrawElementsIndirectUByte::accept(PrimitiveIndexFunctor& functor) const
327 {
328   //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method
329        unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand;
330        if (!empty() )
331             for(unsigned int i = _firstCommand; i<maxindex; ++i)
332                     functor.drawElements(_mode,_indirectCommandArray->count(i),
333                                          &(*this)[_indirectCommandArray->firstIndex(i)],
334                                          _indirectCommandArray->baseVertex(i));
335 }
336 #endif
337 
338 
339 
340 
341 ////////////////////////////////////////////////////////////////////////////////////////////////////////
342 //
343 // MultiDrawElementsIndirectUShort
344 //
~MultiDrawElementsIndirectUShort()345 MultiDrawElementsIndirectUShort::~MultiDrawElementsIndirectUShort()
346 {
347     releaseGLObjects();
348 }
349 
draw(State & state,bool) const350 void MultiDrawElementsIndirectUShort::draw(State& state, bool /*useVertexBufferObjects*/) const
351 {   GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() );
352     state.bindDrawIndirectBufferObject(dibo);
353 
354     GLenum mode = _mode;
355 #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
356     if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN;
357     if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP;
358 #endif
359 
360     GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID());
361 
362     state.bindElementBufferObject(ebo);
363 
364     state.get<GLExtensions>()-> glMultiDrawElementsIndirect(mode, GL_UNSIGNED_SHORT, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())),
365                                                             (_count>0) ?_count:_indirectCommandArray->getNumElements(),_stride);
366 }
367 
368 #ifndef PRIMFUNCTORBASEVERTEX
accept(PrimitiveFunctor &) const369 void MultiDrawElementsIndirectUShort::accept(PrimitiveFunctor&) const {}
accept(PrimitiveIndexFunctor &) const370 void MultiDrawElementsIndirectUShort::accept(PrimitiveIndexFunctor&) const {}
371 #else
accept(PrimitiveFunctor & functor) const372 void MultiDrawElementsIndirectUShort::accept(PrimitiveFunctor& functor) const
373 {
374   //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method
375        unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand;
376        if (!empty() )
377             for(unsigned int i = _firstCommand; i<maxindex; ++i)
378                     functor.drawElements(_mode,_indirectCommandArray->count(i),
379                                          &(*this)[_indirectCommandArray->firstIndex(i)],
380                                          _indirectCommandArray->baseVertex(i));
381 }
382 
accept(PrimitiveIndexFunctor & functor) const383 void MultiDrawElementsIndirectUShort::accept(PrimitiveIndexFunctor& functor) const
384 {
385   //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method
386        unsigned int maxindex = (_count>0) ?_firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand;
387        if (!empty() )
388             for(unsigned int i = _firstCommand; i<maxindex; ++i)
389                     functor.drawElements(_mode,_indirectCommandArray->count(i),
390                                          &(*this)[_indirectCommandArray->firstIndex(i)],
391                                          _indirectCommandArray->baseVertex(i));
392 }
393 #endif
394 
395 ////////////////////////////////////////////////////////////////////////////////////////////////////////
396 //
397 // MultiDrawElementsIndirectUInt
398 //
~MultiDrawElementsIndirectUInt()399 MultiDrawElementsIndirectUInt::~MultiDrawElementsIndirectUInt()
400 {
401     releaseGLObjects();
402 }
403 
draw(State & state,bool) const404 void MultiDrawElementsIndirectUInt::draw(State& state, bool /*useVertexBufferObjects*/) const
405 {
406     GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() );
407     state.bindDrawIndirectBufferObject(dibo);
408     GLenum mode = _mode;
409 #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE)
410     if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN;
411     if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP;
412 #endif
413 
414     GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID());
415 
416     state.bindElementBufferObject(ebo);
417 
418     state.get<GLExtensions>()-> glMultiDrawElementsIndirect(mode, GL_UNSIGNED_INT, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())),
419                                                             (_count>0) ? _count:_indirectCommandArray->getNumElements(), _stride);
420 }
421 
422 #ifndef PRIMFUNCTORBASEVERTEX
accept(PrimitiveFunctor &) const423 void MultiDrawElementsIndirectUInt::accept(PrimitiveFunctor&) const {}
accept(PrimitiveIndexFunctor &) const424 void MultiDrawElementsIndirectUInt::accept(PrimitiveIndexFunctor&) const {}
425 #else
accept(PrimitiveFunctor & functor) const426 void MultiDrawElementsIndirectUInt::accept(PrimitiveFunctor& functor) const
427 {
428   //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method
429        unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand;
430        if (!empty() )
431             for(unsigned int i = _firstCommand; i<maxindex; ++i)
432                     functor.drawElements(_mode,_indirectCommandArray->count(i),
433                                          &(*this)[_indirectCommandArray->firstIndex(i)],
434                                          _indirectCommandArray->baseVertex(i));
435 }
436 
accept(PrimitiveIndexFunctor & functor) const437 void MultiDrawElementsIndirectUInt::accept(PrimitiveIndexFunctor& functor) const
438 {
439   //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method
440        unsigned int maxindex = (_count>0) ?_firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand;
441        if (!empty() )
442             for(unsigned int i = _firstCommand; i<maxindex; ++i)
443                     functor.drawElements(_mode,_indirectCommandArray->count(i),
444                         &(*this)[_indirectCommandArray->firstIndex(i)],
445                         _indirectCommandArray->baseVertex(i));
446 }
447 #endif
448 
449 
450 ////////////////////////////////////////////////////////////////////////////////////////////////////////
451 //
452 // MultiDrawArrays
453 //
draw(osg::State & state,bool) const454 void DrawArraysIndirect::draw(osg::State& state, bool) const
455 {
456     GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() );
457     state.bindDrawIndirectBufferObject(dibo);
458 
459     GLExtensions* ext = state.get<GLExtensions>();
460 
461     ext->glDrawArraysIndirect(_mode,  (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())+_firstCommand* _indirectCommandArray->getElementSize()));
462 }
463 
accept(PrimitiveFunctor & functor) const464 void DrawArraysIndirect::accept(PrimitiveFunctor& functor) const
465 {
466     functor.drawArrays(_mode, _indirectCommandArray->first(_firstCommand), _indirectCommandArray->count(_firstCommand));
467 }
468 
accept(PrimitiveIndexFunctor & functor) const469 void DrawArraysIndirect::accept(PrimitiveIndexFunctor& functor) const
470 {
471     functor.drawArrays(_mode, _indirectCommandArray->first(_firstCommand), _indirectCommandArray->count(_firstCommand));
472 }
473 
getNumIndices() const474 unsigned int DrawArraysIndirect::getNumIndices() const
475 {
476     return _indirectCommandArray->count(_firstCommand);
477 }
478 
index(unsigned int pos) const479 unsigned int DrawArraysIndirect::index(unsigned int pos) const
480 {
481  return _indirectCommandArray->first(_firstCommand)+ pos;
482 }
483 
offsetIndices(int offset)484 void DrawArraysIndirect::offsetIndices(int offset)
485 {
486     _indirectCommandArray->first(_firstCommand)+= offset;
487 }
488 
getNumPrimitives() const489 unsigned int DrawArraysIndirect::getNumPrimitives() const
490 {
491     switch(_mode)
492     {
493         case(POINTS):
494             return _indirectCommandArray->count(_firstCommand);
495         case(LINES):
496             return _indirectCommandArray->count(_firstCommand)/2;
497         case(TRIANGLES):
498             return _indirectCommandArray->count(_firstCommand)/3;
499         case(QUADS):
500             return _indirectCommandArray->count(_firstCommand)/4;
501         case(LINE_STRIP):
502         case(LINE_LOOP):
503         case(TRIANGLE_STRIP):
504         case(TRIANGLE_FAN):
505         case(QUAD_STRIP):
506         case(PATCHES):
507         case(POLYGON):
508         {
509             return 1;
510         }
511     }
512     return 0;
513 }
514 
515 ////////////////////////////////////////////////////////////////////////////////////////////////////////
516 //
517 // MultiDrawArrays
518 //
draw(osg::State & state,bool) const519 void MultiDrawArraysIndirect::draw(osg::State& state, bool) const
520 {
521     GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() );
522     state.bindDrawIndirectBufferObject(dibo);
523 
524     GLExtensions* ext = state.get<GLExtensions>();
525 
526     ext->glMultiDrawArraysIndirect(_mode,  (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())+_firstCommand*_indirectCommandArray->getElementSize()),
527     (_count>0) ?_count:_indirectCommandArray->getNumElements(), _stride);
528 
529 }
530 
accept(PrimitiveFunctor & functor) const531 void MultiDrawArraysIndirect::accept(PrimitiveFunctor& functor) const
532 {
533     unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand;
534     for(unsigned int i = _firstCommand; i<maxindex; ++i)
535     {
536         functor.drawArrays(_mode, _indirectCommandArray->first(i), _indirectCommandArray->count(i));
537     }
538 }
539 
accept(PrimitiveIndexFunctor & functor) const540 void MultiDrawArraysIndirect::accept(PrimitiveIndexFunctor& functor) const
541 {
542     unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand;
543     for(unsigned int i = _firstCommand; i<maxindex; ++i)
544     {
545         functor.drawArrays(_mode, _indirectCommandArray->first(i), _indirectCommandArray->count(i));
546     }
547 }
548 
getNumIndices() const549 unsigned int MultiDrawArraysIndirect::getNumIndices() const
550 {
551     unsigned int total=0;
552     unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand;
553     for(unsigned int i = _firstCommand; i<maxindex; ++i)
554         total+= _indirectCommandArray->count(i);
555 
556     return total;
557 }
558 
index(unsigned int pos) const559 unsigned int MultiDrawArraysIndirect::index(unsigned int pos) const
560 {
561     unsigned int i = 0, maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand;
562     for(i=_firstCommand; i<maxindex;++i)
563       {
564         unsigned int count = _indirectCommandArray->count(i);
565         if (pos<count) break;
566         pos -= count;
567     }
568     if (i>=maxindex) return 0;
569     return _indirectCommandArray->first(maxindex-1) + pos;
570 
571 }
572 
offsetIndices(int offset)573 void MultiDrawArraysIndirect::offsetIndices(int offset)
574 {
575     unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand;
576     for(unsigned int i = _firstCommand; i<maxindex; ++i)
577         _indirectCommandArray->first(i) += offset;
578 }
579 
getNumPrimitives() const580 unsigned int MultiDrawArraysIndirect::getNumPrimitives() const
581 {
582     unsigned int total=0;unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand;
583 
584     switch(_mode)
585     {
586         case(POINTS):
587             for(unsigned int i = _firstCommand; i<maxindex; ++i)
588                 total+=_indirectCommandArray->count(i);
589             break;
590         case(LINES):
591             for(unsigned int i = _firstCommand; i<maxindex; ++i)
592             total+=_indirectCommandArray->count(i)/2;
593             break;
594         case(TRIANGLES):
595             for(unsigned int i = _firstCommand; i<maxindex; ++i)
596             total+=_indirectCommandArray->count(i)/3;
597             break;
598         case(QUADS):
599             for(unsigned int i = _firstCommand; i<maxindex; ++i)
600             total+=_indirectCommandArray->count(i)/4;
601             break;
602         case(LINE_STRIP):
603         case(LINE_LOOP):
604         case(TRIANGLE_STRIP):
605         case(TRIANGLE_FAN):
606         case(QUAD_STRIP):
607         case(PATCHES):
608         case(POLYGON):
609         {
610             unsigned int primcount = _indirectCommandArray->getNumElements();
611             return primcount;
612         }
613     }
614     return total;
615 }
616