/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. * * osg/PrimitiveSetIndirect.cpp * Author: Julien Valentin 2016-2017 */ #include #include #include #include /// TODO: add base vertex feature to PrimitiveFunctor and PrimitiveIndexFunctor //#define PRIMFUNCTORBASEVERTEX 1 using namespace osg; //////////////////////////////////////////////////////////////////////////////////////////////////////// // // DrawElementsIndirect // template inline unsigned int getNumPrimitivesDI( const T&_this ) { unsigned int offset= _this.getFirstCommandToDraw(); IndirectCommandDrawElements *cmd=const_cast(_this.getIndirectCommandArray()); unsigned int total=0; switch(_this.getMode()) { case(PrimitiveSet::POINTS): return cmd->count(offset); case(PrimitiveSet::LINES): return cmd->count(offset)/2; case(PrimitiveSet::TRIANGLES): return cmd->count(offset)/3; case(PrimitiveSet::QUADS): return cmd->count(offset)/4; case(PrimitiveSet::LINE_STRIP): case(PrimitiveSet::LINE_LOOP): case(PrimitiveSet::TRIANGLE_STRIP): case(PrimitiveSet::TRIANGLE_FAN): case(PrimitiveSet::QUAD_STRIP): case(PrimitiveSet::PATCHES): case(PrimitiveSet::POLYGON): { return 1; } } return total; } unsigned int DrawElementsIndirectUInt::getNumPrimitives() const { return getNumPrimitivesDI(*this); } unsigned int DrawElementsIndirectUByte::getNumPrimitives() const { return getNumPrimitivesDI(*this); } unsigned int DrawElementsIndirectUShort::getNumPrimitives() const { return getNumPrimitivesDI(*this); } void DrawElementsIndirectUInt::draw(State& state, bool /*useVertexBufferObjects*/) const { GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); state.bindDrawIndirectBufferObject(dibo); GLenum mode = _mode; #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN; if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP; #endif GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID()); state.bindElementBufferObject(ebo); state.get()-> glDrawElementsIndirect(mode, GL_UNSIGNED_INT, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex()) //command array address +_firstCommand* _indirectCommandArray->getElementSize())// runtime offset computaion can be sizeof(*_indirectCommandArray->begin()) ); } DrawElementsIndirectUInt::~DrawElementsIndirectUInt() { releaseGLObjects(); } void DrawElementsIndirectUInt::offsetIndices(int offset) { for(iterator itr=begin(); itr!=end(); ++itr) { *itr += offset; } } #ifndef PRIMFUNCTORBASEVERTEX void DrawElementsIndirectUInt::accept(PrimitiveFunctor&) const {} void DrawElementsIndirectUInt::accept(PrimitiveIndexFunctor&) const {} #else void DrawElementsIndirectUInt::accept(PrimitiveFunctor& functor) const { // TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method if (!empty()) functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand), &(*this)[_indirectCommandArray->firstIndex(_firstCommand)], _indirectCommandArray->baseVertex(_firstCommand)); } void DrawElementsIndirectUInt::accept(PrimitiveIndexFunctor& functor) const { // TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method if (!empty()) functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand), &(*this)[_indirectCommandArray->firstIndex(_firstCommand)], _indirectCommandArray->baseVertex(_firstCommand)); } #endif void DrawElementsIndirectUByte::draw(State& state, bool /*useVertexBufferObjects*/) const { GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); state.bindDrawIndirectBufferObject(dibo); GLenum mode = _mode; #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN; if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP; #endif GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID()); state.bindElementBufferObject(ebo); state.get()-> glDrawElementsIndirect(mode, GL_UNSIGNED_BYTE, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())+_firstCommand* _indirectCommandArray->getElementSize())); } DrawElementsIndirectUByte::~DrawElementsIndirectUByte() { releaseGLObjects(); } void DrawElementsIndirectUByte::offsetIndices(int offset) { for(iterator itr=begin(); itr!=end(); ++itr) { *itr += offset; } } #ifndef PRIMFUNCTORBASEVERTEX void DrawElementsIndirectUByte::accept(PrimitiveFunctor&) const {} void DrawElementsIndirectUByte::accept(PrimitiveIndexFunctor&) const {} #else void DrawElementsIndirectUByte::accept(PrimitiveFunctor& functor) const { // TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method if (!empty()) functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand), &(*this)[_indirectCommandArray->firstIndex(_firstCommand)], _indirectCommandArray->baseVertex(_firstCommand)); } void DrawElementsIndirectUByte::accept(PrimitiveIndexFunctor& functor) const { // TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method if (!empty()) functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand), &(*this)[_indirectCommandArray->firstIndex(_firstCommand)], _indirectCommandArray->baseVertex(_firstCommand)); } #endif void DrawElementsIndirectUShort::draw(State& state, bool /*useVertexBufferObjects*/) const { GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); state.bindDrawIndirectBufferObject(dibo); GLenum mode = _mode; #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN; if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP; #endif GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID()); state.bindElementBufferObject(ebo); state.get()-> glDrawElementsIndirect(mode, GL_UNSIGNED_SHORT, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())+_firstCommand* _indirectCommandArray->getElementSize())); } DrawElementsIndirectUShort::~DrawElementsIndirectUShort() { releaseGLObjects(); } void DrawElementsIndirectUShort::offsetIndices(int offset) { for(iterator itr=begin(); itr!=end(); ++itr) { *itr += offset; } } #ifndef PRIMFUNCTORBASEVERTEX void DrawElementsIndirectUShort::accept(PrimitiveFunctor&) const {} void DrawElementsIndirectUShort::accept(PrimitiveIndexFunctor&) const {} #else void DrawElementsIndirectUShort::accept(PrimitiveFunctor& functor) const { // TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method if (!empty()) functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand), &(*this)[_indirectCommandArray->firstIndex(_firstCommand)], _indirectCommandArray->baseVertex(_firstCommand)); } void DrawElementsIndirectUShort::accept(PrimitiveIndexFunctor& functor) const { // TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method if (!empty()) functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand), &(*this)[_indirectCommandArray->firstIndex(_firstCommand)], _indirectCommandArray->baseVertex(_firstCommand)); } #endif //////////////////////////////////////////////////////////////////////////////////////////////////////// // // MultiDrawElementsIndirect // template inline unsigned int getNumPrimitivesMDI( const T&_this) { IndirectCommandDrawElements *_indirectCommandArray=const_cast(_this.getIndirectCommandArray()); unsigned int total=0; switch(_this.getMode()) { case(PrimitiveSet::POINTS): for(unsigned int i=0;i<_indirectCommandArray->getNumElements();++i) total+=_indirectCommandArray->count(i); break; case(PrimitiveSet::LINES): for(unsigned int i=0;i<_indirectCommandArray->getNumElements();++i) total+=_indirectCommandArray->count(i)/2; break; case(PrimitiveSet::TRIANGLES): for(unsigned int i=0;i<_indirectCommandArray->getNumElements();++i) total+=_indirectCommandArray->count(i)/3; break; case(PrimitiveSet::QUADS): for(unsigned int i=0;i<_indirectCommandArray->getNumElements();++i) total+=_indirectCommandArray->count(i)/4; break; case(PrimitiveSet::LINE_STRIP): case(PrimitiveSet::LINE_LOOP): case(PrimitiveSet::TRIANGLE_STRIP): case(PrimitiveSet::TRIANGLE_FAN): case(PrimitiveSet::QUAD_STRIP): case(PrimitiveSet::PATCHES): case(PrimitiveSet::POLYGON): { unsigned int primcount = _indirectCommandArray->getNumElements(); return primcount; } } return total; } unsigned int MultiDrawElementsIndirectUInt::getNumPrimitives() const { return getNumPrimitivesMDI(*this); } unsigned int MultiDrawElementsIndirectUByte::getNumPrimitives() const { return getNumPrimitivesMDI(*this); } unsigned int MultiDrawElementsIndirectUShort::getNumPrimitives() const { return getNumPrimitivesMDI(*this); } //////////////////////////////////////////////////////////////////////////////////////////////////////// // // MultiDrawElementsIndirectUByte // MultiDrawElementsIndirectUByte::~MultiDrawElementsIndirectUByte() { releaseGLObjects(); } void MultiDrawElementsIndirectUByte::draw(State& state, bool /*useVertexBufferObjects*/) const { GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); state.bindDrawIndirectBufferObject(dibo); GLenum mode = _mode; #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN; if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP; #endif GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID()); state.bindElementBufferObject(ebo); state.get()-> glMultiDrawElementsIndirect(mode, GL_UNSIGNED_BYTE, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())),_indirectCommandArray->getNumElements(), _stride); } #ifndef PRIMFUNCTORBASEVERTEX void MultiDrawElementsIndirectUByte::accept(PrimitiveFunctor&) const {} void MultiDrawElementsIndirectUByte::accept(PrimitiveIndexFunctor&) const {} #else void MultiDrawElementsIndirectUByte::accept(PrimitiveFunctor& functor) const { //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; if (!empty() ) for(unsigned int i = _firstCommand; icount(i), &(*this)[_indirectCommandArray->firstIndex(i)], _indirectCommandArray->baseVertex(i)); } void MultiDrawElementsIndirectUByte::accept(PrimitiveIndexFunctor& functor) const { //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; if (!empty() ) for(unsigned int i = _firstCommand; icount(i), &(*this)[_indirectCommandArray->firstIndex(i)], _indirectCommandArray->baseVertex(i)); } #endif //////////////////////////////////////////////////////////////////////////////////////////////////////// // // MultiDrawElementsIndirectUShort // MultiDrawElementsIndirectUShort::~MultiDrawElementsIndirectUShort() { releaseGLObjects(); } void MultiDrawElementsIndirectUShort::draw(State& state, bool /*useVertexBufferObjects*/) const { GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); state.bindDrawIndirectBufferObject(dibo); GLenum mode = _mode; #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN; if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP; #endif GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID()); state.bindElementBufferObject(ebo); state.get()-> glMultiDrawElementsIndirect(mode, GL_UNSIGNED_SHORT, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())), (_count>0) ?_count:_indirectCommandArray->getNumElements(),_stride); } #ifndef PRIMFUNCTORBASEVERTEX void MultiDrawElementsIndirectUShort::accept(PrimitiveFunctor&) const {} void MultiDrawElementsIndirectUShort::accept(PrimitiveIndexFunctor&) const {} #else void MultiDrawElementsIndirectUShort::accept(PrimitiveFunctor& functor) const { //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; if (!empty() ) for(unsigned int i = _firstCommand; icount(i), &(*this)[_indirectCommandArray->firstIndex(i)], _indirectCommandArray->baseVertex(i)); } void MultiDrawElementsIndirectUShort::accept(PrimitiveIndexFunctor& functor) const { //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method unsigned int maxindex = (_count>0) ?_firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; if (!empty() ) for(unsigned int i = _firstCommand; icount(i), &(*this)[_indirectCommandArray->firstIndex(i)], _indirectCommandArray->baseVertex(i)); } #endif //////////////////////////////////////////////////////////////////////////////////////////////////////// // // MultiDrawElementsIndirectUInt // MultiDrawElementsIndirectUInt::~MultiDrawElementsIndirectUInt() { releaseGLObjects(); } void MultiDrawElementsIndirectUInt::draw(State& state, bool /*useVertexBufferObjects*/) const { GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); state.bindDrawIndirectBufferObject(dibo); GLenum mode = _mode; #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN; if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP; #endif GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID()); state.bindElementBufferObject(ebo); state.get()-> glMultiDrawElementsIndirect(mode, GL_UNSIGNED_INT, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())), (_count>0) ? _count:_indirectCommandArray->getNumElements(), _stride); } #ifndef PRIMFUNCTORBASEVERTEX void MultiDrawElementsIndirectUInt::accept(PrimitiveFunctor&) const {} void MultiDrawElementsIndirectUInt::accept(PrimitiveIndexFunctor&) const {} #else void MultiDrawElementsIndirectUInt::accept(PrimitiveFunctor& functor) const { //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; if (!empty() ) for(unsigned int i = _firstCommand; icount(i), &(*this)[_indirectCommandArray->firstIndex(i)], _indirectCommandArray->baseVertex(i)); } void MultiDrawElementsIndirectUInt::accept(PrimitiveIndexFunctor& functor) const { //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method unsigned int maxindex = (_count>0) ?_firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; if (!empty() ) for(unsigned int i = _firstCommand; icount(i), &(*this)[_indirectCommandArray->firstIndex(i)], _indirectCommandArray->baseVertex(i)); } #endif //////////////////////////////////////////////////////////////////////////////////////////////////////// // // MultiDrawArrays // void DrawArraysIndirect::draw(osg::State& state, bool) const { GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); state.bindDrawIndirectBufferObject(dibo); GLExtensions* ext = state.get(); ext->glDrawArraysIndirect(_mode, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())+_firstCommand* _indirectCommandArray->getElementSize())); } void DrawArraysIndirect::accept(PrimitiveFunctor& functor) const { functor.drawArrays(_mode, _indirectCommandArray->first(_firstCommand), _indirectCommandArray->count(_firstCommand)); } void DrawArraysIndirect::accept(PrimitiveIndexFunctor& functor) const { functor.drawArrays(_mode, _indirectCommandArray->first(_firstCommand), _indirectCommandArray->count(_firstCommand)); } unsigned int DrawArraysIndirect::getNumIndices() const { return _indirectCommandArray->count(_firstCommand); } unsigned int DrawArraysIndirect::index(unsigned int pos) const { return _indirectCommandArray->first(_firstCommand)+ pos; } void DrawArraysIndirect::offsetIndices(int offset) { _indirectCommandArray->first(_firstCommand)+= offset; } unsigned int DrawArraysIndirect::getNumPrimitives() const { switch(_mode) { case(POINTS): return _indirectCommandArray->count(_firstCommand); case(LINES): return _indirectCommandArray->count(_firstCommand)/2; case(TRIANGLES): return _indirectCommandArray->count(_firstCommand)/3; case(QUADS): return _indirectCommandArray->count(_firstCommand)/4; case(LINE_STRIP): case(LINE_LOOP): case(TRIANGLE_STRIP): case(TRIANGLE_FAN): case(QUAD_STRIP): case(PATCHES): case(POLYGON): { return 1; } } return 0; } //////////////////////////////////////////////////////////////////////////////////////////////////////// // // MultiDrawArrays // void MultiDrawArraysIndirect::draw(osg::State& state, bool) const { GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); state.bindDrawIndirectBufferObject(dibo); GLExtensions* ext = state.get(); ext->glMultiDrawArraysIndirect(_mode, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())+_firstCommand*_indirectCommandArray->getElementSize()), (_count>0) ?_count:_indirectCommandArray->getNumElements(), _stride); } void MultiDrawArraysIndirect::accept(PrimitiveFunctor& functor) const { unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; for(unsigned int i = _firstCommand; ifirst(i), _indirectCommandArray->count(i)); } } void MultiDrawArraysIndirect::accept(PrimitiveIndexFunctor& functor) const { unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; for(unsigned int i = _firstCommand; ifirst(i), _indirectCommandArray->count(i)); } } unsigned int MultiDrawArraysIndirect::getNumIndices() const { unsigned int total=0; unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; for(unsigned int i = _firstCommand; icount(i); return total; } unsigned int MultiDrawArraysIndirect::index(unsigned int pos) const { unsigned int i = 0, maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; for(i=_firstCommand; icount(i); if (pos=maxindex) return 0; return _indirectCommandArray->first(maxindex-1) + pos; } void MultiDrawArraysIndirect::offsetIndices(int offset) { unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; for(unsigned int i = _firstCommand; ifirst(i) += offset; } unsigned int MultiDrawArraysIndirect::getNumPrimitives() const { unsigned int total=0;unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; switch(_mode) { case(POINTS): for(unsigned int i = _firstCommand; icount(i); break; case(LINES): for(unsigned int i = _firstCommand; icount(i)/2; break; case(TRIANGLES): for(unsigned int i = _firstCommand; icount(i)/3; break; case(QUADS): for(unsigned int i = _firstCommand; icount(i)/4; break; case(LINE_STRIP): case(LINE_LOOP): case(TRIANGLE_STRIP): case(TRIANGLE_FAN): case(QUAD_STRIP): case(PATCHES): case(POLYGON): { unsigned int primcount = _indirectCommandArray->getNumElements(); return primcount; } } return total; }