@@ -20,6 +20,7 @@ ELSE(ANDROID)
|
||||
|
||||
IF(DYNAMIC_OPENSCENEGRAPH)
|
||||
|
||||
ADD_SUBDIRECTORY(osgsimpleMDI)
|
||||
ADD_SUBDIRECTORY(osg2cpp)
|
||||
ADD_SUBDIRECTORY(osganalysis)
|
||||
ADD_SUBDIRECTORY(osganimate)
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
SET(TARGET_SRC
|
||||
ShapeToGeometry.cpp
|
||||
DrawIndirectPrimitiveSet.cpp
|
||||
AggregateGeometryVisitor.cpp
|
||||
osggpucull.cpp
|
||||
)
|
||||
|
||||
SET(TARGET_H
|
||||
ShapeToGeometry.h
|
||||
DrawIndirectPrimitiveSet.h
|
||||
AggregateGeometryVisitor.h
|
||||
GpuCullShaders.h
|
||||
)
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2014 Robert Osfield
|
||||
* Copyright (C) 2014 Pawel Ksiezopolski
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include "DrawIndirectPrimitiveSet.h"
|
||||
#include <osg/State>
|
||||
#include <osg/buffered_value>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/GLExtensions>
|
||||
#include <osg/Drawable>
|
||||
|
||||
void DrawArraysIndirect::draw(osg::State& state, bool /*useVertexBufferObjects*/) const
|
||||
{
|
||||
// if you want to see how many primitives were rendered - uncomment code below, but
|
||||
// be warned : it is a serious performance killer ( because of GPU->CPU roundtrip )
|
||||
|
||||
// osg::Drawable::Extensions *dext = osg::Drawable::getExtensions( state.getContextID(),true );
|
||||
// int* tab = (int*)dext->glMapBuffer(GL_DRAW_INDIRECT_BUFFER,GL_READ_ONLY);
|
||||
// int val = _indirect/sizeof(int);
|
||||
// OSG_WARN<<"DrawArraysIndirect ("<<val<<"): "<< tab[val] << " " << tab[val+1] << " " << tab[val+2] << " " << tab[val+3] << std::endl;
|
||||
// dext->glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER);
|
||||
|
||||
state.get<osg::GLExtensions>()->glDrawArraysIndirect( _mode, reinterpret_cast<const void*>(_indirect) );
|
||||
|
||||
}
|
||||
|
||||
void MultiDrawArraysIndirect::draw(osg::State& state, bool /*useVertexBufferObjects*/) const
|
||||
{
|
||||
// DrawIndirectGLExtensions *ext = DrawIndirectGLExtensions::getExtensions( state.getContextID(),true );
|
||||
state.get<osg::GLExtensions>()->glMultiDrawArraysIndirect( _mode, reinterpret_cast<const void*>(_indirect), _drawcount, _stride );
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2014 Robert Osfield
|
||||
* Copyright (C) 2014 Pawel Ksiezopolski
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OSG_DRAWINDIRECTPRIMITIVESET
|
||||
#define OSG_DRAWINDIRECTPRIMITIVESET 1
|
||||
|
||||
#include <osg/PrimitiveSet>
|
||||
#include <osg/BufferObject>
|
||||
#include <osg/TextureBuffer>
|
||||
|
||||
|
||||
class DrawArraysIndirect : public osg::DrawArrays
|
||||
{
|
||||
public:
|
||||
DrawArraysIndirect(GLenum mode=0, unsigned int indirect=0)
|
||||
: osg::DrawArrays(mode), _indirect(indirect)
|
||||
{
|
||||
}
|
||||
virtual osg::Object* cloneType() const { return new DrawArraysIndirect(); }
|
||||
virtual osg::Object* clone(const osg::CopyOp& /*copyop*/) const { return NULL; }
|
||||
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const DrawArraysIndirect*>(obj)!=NULL; }
|
||||
virtual const char* libraryName() const { return "osg"; }
|
||||
virtual const char* className() const { return "DrawArraysIndirect"; }
|
||||
|
||||
virtual void draw(osg::State& state, bool useVertexBufferObjects) const;
|
||||
protected:
|
||||
unsigned int _indirect;
|
||||
};
|
||||
|
||||
class MultiDrawArraysIndirect : public osg::DrawArrays
|
||||
{
|
||||
public:
|
||||
MultiDrawArraysIndirect(GLenum mode=0, unsigned int indirect=0, GLsizei drawcount=0, GLsizei stride=0)
|
||||
: osg::DrawArrays(mode), _indirect(indirect), _drawcount(drawcount), _stride(stride)
|
||||
{
|
||||
}
|
||||
virtual osg::Object* cloneType() const { return new MultiDrawArraysIndirect(); }
|
||||
virtual osg::Object* clone(const osg::CopyOp& /*copyop*/) const { return NULL; }
|
||||
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const MultiDrawArraysIndirect*>(obj)!=NULL; }
|
||||
virtual const char* libraryName() const { return "osg"; }
|
||||
virtual const char* className() const { return "MultiDrawArraysIndirect"; }
|
||||
|
||||
virtual void draw(osg::State& state, bool useVertexBufferObjects) const;
|
||||
protected:
|
||||
unsigned int _indirect;
|
||||
GLsizei _drawcount;
|
||||
GLsizei _stride;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -36,14 +36,12 @@
|
||||
#include <osgViewer/Viewer>
|
||||
#include <osgViewer/ViewerEventHandlers>
|
||||
#include <osg/BufferTemplate>
|
||||
#include <osg/PrimitiveSetIndirect>
|
||||
#include "ShapeToGeometry.h"
|
||||
#include "AggregateGeometryVisitor.h"
|
||||
#include "DrawIndirectPrimitiveSet.h"
|
||||
#include "GpuCullShaders.h"
|
||||
|
||||
#ifndef GL_RASTERIZER_DISCARD
|
||||
#define GL_RASTERIZER_DISCARD 0x8C89
|
||||
#endif
|
||||
|
||||
// each instance type may have max 8 LODs ( if you change
|
||||
// this value, don't forget to change it in vertex shaders accordingly )
|
||||
@@ -178,21 +176,19 @@ struct IndirectTarget
|
||||
IndirectTarget()
|
||||
: maxTargetQuantity(0)
|
||||
{
|
||||
indirectCommands = new osg::BufferTemplate< std::vector<DrawArraysIndirectCommand> >;
|
||||
indirectCommands = new osg::DrawArraysIndirectCommandArray ;
|
||||
}
|
||||
IndirectTarget( AggregateGeometryVisitor* agv, osg::Program* program )
|
||||
: geometryAggregator(agv), drawProgram(program), maxTargetQuantity(0)
|
||||
{
|
||||
indirectCommands = new osg::BufferTemplate< std::vector<DrawArraysIndirectCommand> >;
|
||||
indirectCommands = new osg::DrawArraysIndirectCommandArray;
|
||||
}
|
||||
void endRegister(unsigned int index, unsigned int rowsPerInstance, GLenum pixelFormat, GLenum type, GLint internalFormat, bool useMultiDrawArraysIndirect )
|
||||
{
|
||||
// osg::Image* indirectCommandImage = new osg::Image;
|
||||
//indirectCommandImage->setImage( indirectCommands->getTotalDataSize()/sizeof(unsigned int), 1, 1, GL_R32I, GL_RED, GL_UNSIGNED_INT, (unsigned char*)indirectCommands->getDataPointer(), osg::Image::NO_DELETE );
|
||||
|
||||
osg::VertexBufferObject * indirectCommandImagebuffer=new osg::VertexBufferObject();
|
||||
indirectCommandImagebuffer->setUsage(GL_DYNAMIC_DRAW);
|
||||
indirectCommands->setBufferObject(indirectCommandImagebuffer);
|
||||
osg::DrawIndirectBufferObject * indirectCommandbuffer=new osg::DrawIndirectBufferObject();
|
||||
indirectCommandbuffer->setUsage(GL_DYNAMIC_DRAW);
|
||||
indirectCommands->setBufferObject(indirectCommandbuffer);
|
||||
|
||||
indirectCommandTextureBuffer = new osg::TextureBuffer(indirectCommands);
|
||||
indirectCommandTextureBuffer->setInternalFormat( GL_R32I );
|
||||
@@ -205,26 +201,28 @@ struct IndirectTarget
|
||||
{
|
||||
std::vector<DrawArraysIndirect*> newPrimitiveSets;
|
||||
|
||||
for(unsigned int j=0;j<indirectCommands->getData().size(); ++j)
|
||||
newPrimitiveSets.push_back( new DrawArraysIndirect( GL_TRIANGLES, j*sizeof( DrawArraysIndirectCommand ) ) );
|
||||
for(unsigned int j=0;j<indirectCommands->size(); ++j)
|
||||
newPrimitiveSets.push_back( new DrawArraysIndirect( GL_TRIANGLES, j*sizeof( osg::DrawArraysIndirectCommand ), indirectCommands ) );
|
||||
|
||||
geometryAggregator->getAggregatedGeometry()->removePrimitiveSet(0,geometryAggregator->getAggregatedGeometry()->getNumPrimitiveSets() );
|
||||
|
||||
for(unsigned int j=0;j<indirectCommands->getData().size(); ++j)
|
||||
for(unsigned int j=0;j<indirectCommands->size(); ++j)
|
||||
geometryAggregator->getAggregatedGeometry()->addPrimitiveSet( newPrimitiveSets[j] );
|
||||
|
||||
|
||||
/*DrawIndirectBufferBinding should be deprecated
|
||||
///attach a DrawIndirect buffer binding to the stateset for non builtin primset DrawArraysIndirect
|
||||
osg::ref_ptr<osg::DrawIndirectBufferBinding> bb=new osg::DrawIndirectBufferBinding();
|
||||
bb->setBufferObject(indirectCommandbuffer );
|
||||
geometryAggregator->getAggregatedGeometry()->getOrCreateStateSet()->setAttribute(bb );*/
|
||||
}
|
||||
else // use glMultiDrawArraysIndirect()
|
||||
{
|
||||
osg::MultiDrawArraysIndirect * mdi=new osg::MultiDrawArraysIndirect(GL_TRIANGLES);
|
||||
mdi->setIndirectCommandArray(indirectCommands);
|
||||
geometryAggregator->getAggregatedGeometry()->removePrimitiveSet(0,geometryAggregator->getAggregatedGeometry()->getNumPrimitiveSets() );
|
||||
geometryAggregator->getAggregatedGeometry()->addPrimitiveSet( new MultiDrawArraysIndirect( GL_TRIANGLES, 0, indirectCommands->getData().size(), 0 ) );
|
||||
geometryAggregator->getAggregatedGeometry()->addPrimitiveSet(mdi );
|
||||
|
||||
}
|
||||
|
||||
///attach a DrawIndirect buffer binding to the stateset
|
||||
osg::ref_ptr<osg::DrawIndirectBufferBinding> bb=new osg::DrawIndirectBufferBinding(indirectCommands);
|
||||
|
||||
geometryAggregator->getAggregatedGeometry()->getOrCreateStateSet()->setAttributeAndModes(bb );
|
||||
geometryAggregator->getAggregatedGeometry()->setUseDisplayList(false);
|
||||
geometryAggregator->getAggregatedGeometry()->setUseVertexBufferObjects(true);
|
||||
|
||||
@@ -268,7 +266,7 @@ struct IndirectTarget
|
||||
stateset->setAttributeAndModes( drawProgram.get(), osg::StateAttribute::ON );
|
||||
}
|
||||
|
||||
osg::ref_ptr< osg::BufferTemplate< std::vector<DrawArraysIndirectCommand> > > indirectCommands;
|
||||
osg::ref_ptr< osg::DrawArraysIndirectCommandArray > indirectCommands;
|
||||
osg::ref_ptr<osg::TextureBuffer> indirectCommandTextureBuffer;
|
||||
osg::ref_ptr< AggregateGeometryVisitor > geometryAggregator;
|
||||
osg::ref_ptr<osg::Program> drawProgram;
|
||||
@@ -318,7 +316,7 @@ struct GPUCullData
|
||||
// AggregateGeometryVisitor creates single osg::Geometry from all objects used by specific indirect target
|
||||
AggregateGeometryVisitor::AddObjectResult aoResult = target->second.geometryAggregator->addObject( node , typeID, lodNumber );
|
||||
// Information about first vertex and a number of vertices is stored for later primitiveset creation
|
||||
target->second.indirectCommands->getData().push_back( DrawArraysIndirectCommand( aoResult.first, aoResult.count ) );
|
||||
target->second.indirectCommands->push_back( osg::DrawArraysIndirectCommand( aoResult.count,1,aoResult.first ) );
|
||||
|
||||
osg::ComputeBoundsVisitor cbv;
|
||||
node->accept(cbv);
|
||||
@@ -360,10 +358,10 @@ struct GPUCullData
|
||||
std::map<unsigned int, IndirectTarget>::iterator it,eit;
|
||||
for(it=targets.begin(), eit=targets.end(); it!=eit; ++it)
|
||||
{
|
||||
for(unsigned j=0; j<it->second.indirectCommands->getData().size(); ++j)
|
||||
for(unsigned j=0; j<it->second.indirectCommands->size(); ++j)
|
||||
{
|
||||
DrawArraysIndirectCommand& iComm = it->second.indirectCommands->getData().at(j);
|
||||
OSG_INFO<<"("<<iComm.first<<" "<<iComm.primCount<<" "<<iComm.count<<") ";
|
||||
osg::DrawArraysIndirectCommand& iComm = it->second.indirectCommands->at(j);
|
||||
OSG_INFO<<"("<<iComm.first<<" "<<iComm.instanceCount<<" "<<iComm.count<<") ";
|
||||
}
|
||||
unsigned int sizeInBytes = (unsigned int ) it->second.maxTargetQuantity * sizeof(osg::Vec4);
|
||||
OSG_INFO<<" => Maximum elements in target : "<< it->second.maxTargetQuantity <<" ( "<< sizeInBytes <<" bytes, " << sizeInBytes/1024<< " kB )" << std::endl;
|
||||
@@ -727,9 +725,9 @@ struct ResetTexturesCallback : public osg::StateSet::Callback
|
||||
osg::TextureBuffer* tex = dynamic_cast<osg::TextureBuffer*>( stateset->getTextureAttribute(*it,osg::StateAttribute::TEXTURE) );
|
||||
if(tex==NULL)
|
||||
continue;
|
||||
osg::BufferData* img = const_cast<osg::BufferData*>(tex->getBufferData());
|
||||
if(img!=NULL)
|
||||
img->dirty();
|
||||
osg::BufferData* drawcmds = tex->getBufferData();
|
||||
if(drawcmds!=NULL)
|
||||
drawcmds->dirty();
|
||||
}
|
||||
for(it=texUnitsDirtyParams.begin(), eit=texUnitsDirtyParams.end(); it!=eit; ++it)
|
||||
{
|
||||
|
||||
7
examples/osgsimpleMDI/CMakeLists.txt
Normal file
7
examples/osgsimpleMDI/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
#this file is automatically generated
|
||||
|
||||
|
||||
SET(TARGET_SRC osgsimpleMDI.cpp )
|
||||
|
||||
#### end var setup ###
|
||||
SETUP_EXAMPLE(osgsimpleMDI)
|
||||
141
examples/osgsimpleMDI/osgsimpleMDI.cpp
Normal file
141
examples/osgsimpleMDI/osgsimpleMDI.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/* OpenSceneGraph example, osgtransformfeedback
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* file: examples/osgsimpleMDI/osgsimpleMDI.cpp
|
||||
* author: Julien Valentin 2017-08-01
|
||||
* copyright: (C) 2013
|
||||
* license: OpenSceneGraph Public License (OSGPL)
|
||||
*
|
||||
* A simple example of mdi with basevertex
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <osg/GL2Extensions>
|
||||
#include <osg/Notify>
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Point>
|
||||
#include <osg/Vec3>
|
||||
#include <osg/Vec4>
|
||||
#include <osg/Program>
|
||||
#include <osg/Shader>
|
||||
#include <osg/BlendFunc>
|
||||
|
||||
#include <iostream>
|
||||
#include <osgViewer/Viewer>
|
||||
#include <osgViewer/ViewerEventHandlers>
|
||||
|
||||
#include <osg/PrimitiveSetIndirect>
|
||||
#include <osg/BufferIndexBinding>
|
||||
|
||||
|
||||
|
||||
int main( int argc, char**argv )
|
||||
{
|
||||
|
||||
osg::ArgumentParser arguments(&argc,argv);
|
||||
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates Multi Indirect Draw with basevertex");
|
||||
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] ");
|
||||
arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information");
|
||||
arguments.getApplicationUsage()->addCommandLineOption("--numX","square count on X");
|
||||
arguments.getApplicationUsage()->addCommandLineOption("--numY","square count on Y");
|
||||
arguments.getApplicationUsage()->addCommandLineOption("--classic","disable MDI and use classic DrawElements");
|
||||
|
||||
if (arguments.read("-h") || arguments.read("--help"))
|
||||
{
|
||||
arguments.getApplicationUsage()->write(std::cout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int MAXX=200;
|
||||
int MAXY=200;
|
||||
arguments.read("--numX",MAXX);
|
||||
arguments.read("--numY",MAXY);
|
||||
|
||||
bool MDIenable=true;
|
||||
if(arguments.read("--classic"))
|
||||
{ MDIenable=false;
|
||||
OSG_WARN<<"disabling MDI"<<std::endl;
|
||||
}
|
||||
|
||||
osg::Geode* root( new osg::Geode );
|
||||
|
||||
osg::ref_ptr<osg::ElementBufferObject> ebo=new osg::ElementBufferObject;
|
||||
|
||||
///create empty mdi
|
||||
osg::MultiDrawElementsIndirectUShort* mdi=new osg::MultiDrawElementsIndirectUShort(osg::PrimitiveSet::TRIANGLE_STRIP);
|
||||
osg::DefaultIndirectCommandDrawElements* mdicommands= new osg::DefaultIndirectCommandDrawElements();
|
||||
mdi->setIndirectCommandArray(mdicommands);
|
||||
|
||||
osg::ref_ptr<osg::Geometry> geom=new osg::Geometry();
|
||||
geom->setUseVertexBufferObjects(true);
|
||||
osg::BoundingBox bb;
|
||||
bb.set(0,0,0,MAXX,0,MAXY);
|
||||
//set bounds by hand cause of the lack of support of basevertex in PrimitiveFunctors
|
||||
geom->setInitialBound(bb);
|
||||
|
||||
osg::Vec3 myCoords[] =
|
||||
{
|
||||
osg::Vec3(0,0.0f,0.7f),
|
||||
osg::Vec3(0,0.0f,0),
|
||||
osg::Vec3(0.7,0.0f,0),
|
||||
osg::Vec3(0.7f,0.0f,0.7f)
|
||||
};
|
||||
|
||||
unsigned short myIndices[] = { 0, 1, 3, 2 };
|
||||
unsigned int myIndicesUI[] = { 0, 1, 3, 2 };
|
||||
|
||||
osg::Vec3Array * verts=new osg::Vec3Array();
|
||||
|
||||
|
||||
for(int j =0 ; j<MAXY; ++j) {
|
||||
for(int i =0 ; i<MAXX; ++i) {
|
||||
|
||||
///create indirect command
|
||||
osg::DrawElementsIndirectCommand cmd;
|
||||
cmd.count=4;
|
||||
cmd.instanceCount=1;
|
||||
cmd.firstIndex=verts->size();
|
||||
cmd.baseVertex=verts->size();
|
||||
mdicommands->push_back(cmd);
|
||||
|
||||
for(int z=0; z<4; z++) {
|
||||
verts->push_back(osg::Vec3(i,0,j)+myCoords[z]);
|
||||
mdi->addElement(myIndices[z]);
|
||||
}
|
||||
}
|
||||
}
|
||||
geom->setVertexArray(verts);
|
||||
if(MDIenable) {
|
||||
geom->addPrimitiveSet(mdi);
|
||||
|
||||
} else
|
||||
for(int i=0; i<MAXY*MAXX; ++i) {
|
||||
osg::DrawElementsUInt *dre=new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP,4,myIndicesUI) ;
|
||||
dre->setElementBufferObject(ebo);
|
||||
geom->addPrimitiveSet(dre);
|
||||
for(int z=0; z<4; z++)myIndicesUI[z]+=4;
|
||||
}
|
||||
root->addChild(geom);
|
||||
osgViewer::Viewer viewer;
|
||||
viewer.addEventHandler(new osgViewer::StatsHandler);
|
||||
viewer.setSceneData( root );
|
||||
return viewer.run();
|
||||
}
|
||||
@@ -213,30 +213,6 @@ class OSG_EXPORT ShaderStorageBufferBinding : public BufferIndexBinding
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class OSG_EXPORT DrawIndirectBufferBinding : public BufferIndexBinding
|
||||
{
|
||||
public:
|
||||
DrawIndirectBufferBinding();
|
||||
/** Create a binding for a draw indirect buffer target.
|
||||
* @param bd associated buffer data
|
||||
*/
|
||||
DrawIndirectBufferBinding( BufferData* bd);
|
||||
DrawIndirectBufferBinding(const DrawIndirectBufferBinding& rhs, const CopyOp& copyop=CopyOp::SHALLOW_COPY);
|
||||
META_StateAttribute(osg, DrawIndirectBufferBinding, INDIRECTDRAWBUFFERBINDING);
|
||||
|
||||
virtual void apply(State& state) const;
|
||||
|
||||
virtual int compare(const StateAttribute& bb) const
|
||||
{
|
||||
COMPARE_StateAttribute_Types(DrawIndirectBufferBinding, bb)
|
||||
COMPARE_StateAttribute_Parameter(_target)
|
||||
COMPARE_StateAttribute_Parameter(_bufferData)
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace osg
|
||||
|
||||
#endif
|
||||
|
||||
@@ -635,6 +635,28 @@ class OSG_EXPORT ElementBufferObject : public BufferObject
|
||||
virtual ~ElementBufferObject();
|
||||
};
|
||||
|
||||
class OSG_EXPORT DrawIndirectBufferObject : public BufferObject
|
||||
{
|
||||
public:
|
||||
|
||||
DrawIndirectBufferObject();
|
||||
|
||||
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
|
||||
DrawIndirectBufferObject(const DrawIndirectBufferObject& vbo,const CopyOp& copyop=CopyOp::SHALLOW_COPY);
|
||||
|
||||
META_Object(osg,DrawIndirectBufferObject);
|
||||
|
||||
unsigned int addArray(osg::Array* array);
|
||||
void removeArray(osg::Array* array);
|
||||
|
||||
void setArray(unsigned int i, Array* array);
|
||||
Array* getArray(unsigned int i);
|
||||
const Array* getArray(unsigned int i) const;
|
||||
|
||||
protected:
|
||||
virtual ~DrawIndirectBufferObject();
|
||||
};
|
||||
|
||||
class Image;
|
||||
class OSG_EXPORT PixelBufferObject : public BufferObject
|
||||
{
|
||||
|
||||
@@ -435,6 +435,8 @@ typedef char GLchar;
|
||||
#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D
|
||||
#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E
|
||||
#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F
|
||||
#define GL_DRAW_INDIRECT_BUFFER 0x8F3F
|
||||
#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43
|
||||
#endif
|
||||
|
||||
// ARB_shader_atomic_counters
|
||||
@@ -556,14 +558,14 @@ typedef char GLchar;
|
||||
#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
|
||||
#endif
|
||||
|
||||
#define GL_INT64_ARB 0x140E
|
||||
#define GL_UNSIGNED_INT64_ARB 0x140F
|
||||
#define GL_INT64_VEC2_ARB 0x8FE9
|
||||
#define GL_INT64_VEC3_ARB 0x8FEA
|
||||
#define GL_INT64_VEC4_ARB 0x8FEB
|
||||
#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5
|
||||
#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6
|
||||
#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7
|
||||
#define GL_INT64_ARB 0x140E
|
||||
#define GL_UNSIGNED_INT64_ARB 0x140F
|
||||
#define GL_INT64_VEC2_ARB 0x8FE9
|
||||
#define GL_INT64_VEC3_ARB 0x8FEA
|
||||
#define GL_INT64_VEC4_ARB 0x8FEB
|
||||
#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5
|
||||
#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6
|
||||
#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7
|
||||
/* ------------------------------ GL_KHR_debug ----------------------------- */
|
||||
#ifndef GL_KHR_debug
|
||||
#define GL_KHR_debug 1
|
||||
|
||||
@@ -133,7 +133,15 @@ class OSG_EXPORT PrimitiveSet : public BufferData
|
||||
DrawElementsUBytePrimitiveType,
|
||||
DrawElementsUShortPrimitiveType,
|
||||
DrawElementsUIntPrimitiveType,
|
||||
MultiDrawArraysPrimitiveType
|
||||
MultiDrawArraysPrimitiveType,
|
||||
DrawArraysIndirectPrimitiveType,
|
||||
DrawElementsUByteIndirectPrimitiveType,
|
||||
DrawElementsUShortIndirectPrimitiveType,
|
||||
DrawElementsUIntIndirectPrimitiveType,
|
||||
MultiDrawArraysIndirectPrimitiveType,
|
||||
MultiDrawElementsUByteIndirectPrimitiveType,
|
||||
MultiDrawElementsUShortIndirectPrimitiveType,
|
||||
MultiDrawElementsUIntIndirectPrimitiveType
|
||||
};
|
||||
|
||||
enum Mode
|
||||
|
||||
671
include/osg/PrimitiveSetIndirect
Normal file
671
include/osg/PrimitiveSetIndirect
Normal file
@@ -0,0 +1,671 @@
|
||||
/* -*-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
|
||||
* Author: Julien Valentin 2016-2017
|
||||
*/
|
||||
|
||||
#ifndef OSG_INDIRECTPRIMITIVESET
|
||||
#define OSG_INDIRECTPRIMITIVESET 1
|
||||
|
||||
#include <osg/PrimitiveSet>
|
||||
|
||||
|
||||
namespace osg {
|
||||
|
||||
///common interface for IndirectCommandDrawArrayss
|
||||
class OSG_EXPORT IndirectCommandDrawArrays: public BufferData
|
||||
{
|
||||
public:
|
||||
IndirectCommandDrawArrays() : BufferData() { setBufferObject(new DrawIndirectBufferObject()); }
|
||||
|
||||
IndirectCommandDrawArrays(const IndirectCommandDrawArrays& copy,const CopyOp& copyop/*=CopyOp::SHALLOW_COPY*/) :
|
||||
BufferData(copy, copyop) {}
|
||||
|
||||
virtual unsigned int getTotalDataSize() const { return getNumElements()*getElementSize(); }
|
||||
|
||||
virtual unsigned int & count(const unsigned int&index)=0;
|
||||
virtual unsigned int & instanceCount(const unsigned int&index)=0;
|
||||
virtual unsigned int & first(const unsigned int&index)=0;
|
||||
virtual unsigned int & baseInstance(const unsigned int&index)=0;
|
||||
|
||||
virtual unsigned int getElementSize() const = 0;
|
||||
virtual unsigned int getNumElements() const = 0;
|
||||
virtual void reserveElements(const unsigned int) = 0;
|
||||
virtual void resizeElements(const unsigned int) = 0;
|
||||
};
|
||||
|
||||
class OSG_EXPORT IndirectCommandDrawElements: public BufferData
|
||||
{
|
||||
public:
|
||||
IndirectCommandDrawElements() : BufferData() { setBufferObject(new DrawIndirectBufferObject()); }
|
||||
|
||||
IndirectCommandDrawElements(const IndirectCommandDrawElements& copy,const CopyOp& copyop/*=CopyOp::SHALLOW_COPY*/)
|
||||
: BufferData(copy, copyop) {}
|
||||
|
||||
virtual unsigned int getTotalDataSize() const { return getNumElements()*getElementSize(); }
|
||||
|
||||
virtual unsigned int & count(const unsigned int&index)=0;
|
||||
virtual unsigned int & instanceCount(const unsigned int&index)=0;
|
||||
virtual unsigned int & firstIndex(const unsigned int&index)=0;
|
||||
virtual unsigned int & baseVertex(const unsigned int&index)=0;
|
||||
virtual unsigned int & baseInstance(const unsigned int&index)=0;
|
||||
|
||||
virtual unsigned int getElementSize()const = 0;
|
||||
virtual unsigned int getNumElements() const = 0;
|
||||
virtual void reserveElements(const unsigned int) = 0;
|
||||
virtual void resizeElements(const unsigned int) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// DrawArraysCommand
|
||||
struct DrawArraysIndirectCommand
|
||||
{
|
||||
DrawArraysIndirectCommand(unsigned int pcount = 0, unsigned int pinstanceCount = 0, unsigned int pfirst = 0, unsigned int pbaseInstance = 0) :
|
||||
count(pcount), instanceCount(pinstanceCount), first(pfirst), baseInstance(pbaseInstance) {}
|
||||
|
||||
unsigned int count;
|
||||
unsigned int instanceCount;
|
||||
unsigned int first;
|
||||
unsigned int baseInstance;
|
||||
};
|
||||
|
||||
/// default implementation of IndirectCommandDrawArrays
|
||||
/// DefaultIndirectCommandDrawArrays to be hosted on GPU
|
||||
class OSG_EXPORT DefaultIndirectCommandDrawArrays: public IndirectCommandDrawArrays, public MixinVector<DrawArraysIndirectCommand>
|
||||
{
|
||||
public:
|
||||
META_Object(osg,DefaultIndirectCommandDrawArrays)
|
||||
|
||||
DefaultIndirectCommandDrawArrays() : IndirectCommandDrawArrays(), MixinVector<DrawArraysIndirectCommand>() {}
|
||||
DefaultIndirectCommandDrawArrays(const DefaultIndirectCommandDrawArrays& copy,const CopyOp& copyop/*=CopyOp::SHALLOW_COPY*/) :
|
||||
IndirectCommandDrawArrays(copy, copyop),MixinVector<DrawArraysIndirectCommand>() {}
|
||||
|
||||
virtual const GLvoid* getDataPointer() const { return empty()?0:&front(); }
|
||||
virtual unsigned int getElementSize()const { return 16u; };
|
||||
virtual unsigned int getNumElements() const { return static_cast<unsigned int>(size()); }
|
||||
virtual void reserveElements(const unsigned int n) {reserve(n);}
|
||||
virtual void resizeElements(const unsigned int n) {resize(n);}
|
||||
|
||||
virtual unsigned int & count(const unsigned int&index) { return at(index).count; }
|
||||
virtual unsigned int & instanceCount(const unsigned int&index) { return at(index).instanceCount; }
|
||||
virtual unsigned int & first(const unsigned int&index) { return at(index).first; }
|
||||
virtual unsigned int & baseInstance(const unsigned int&index) { return at(index).baseInstance; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// default implementation of IndirectCommandDrawElements
|
||||
/// DrawElementsCommand
|
||||
struct DrawElementsIndirectCommand
|
||||
{
|
||||
DrawElementsIndirectCommand(unsigned int pcount = 0, unsigned int pinstanceCount = 0, unsigned int pfirstIndex = 0, unsigned int pbaseVertex = 0, unsigned int pbaseInstance = 0) :
|
||||
count(pcount), instanceCount(pinstanceCount), firstIndex(pfirstIndex), baseVertex(pbaseVertex), baseInstance(pbaseInstance) {}
|
||||
|
||||
unsigned int count;
|
||||
unsigned int instanceCount;
|
||||
unsigned int firstIndex;
|
||||
unsigned int baseVertex;
|
||||
unsigned int baseInstance;
|
||||
};
|
||||
|
||||
/// vector of DrawElementsCommand to be hosted on GPU
|
||||
class OSG_EXPORT DefaultIndirectCommandDrawElements: public IndirectCommandDrawElements, public MixinVector<DrawElementsIndirectCommand>
|
||||
{
|
||||
public:
|
||||
META_Object(osg,DefaultIndirectCommandDrawElements)
|
||||
|
||||
DefaultIndirectCommandDrawElements() : IndirectCommandDrawElements(), MixinVector<DrawElementsIndirectCommand>() {}
|
||||
|
||||
DefaultIndirectCommandDrawElements(const DefaultIndirectCommandDrawElements& copy,const CopyOp& copyop/*=CopyOp::SHALLOW_COPY*/) :
|
||||
IndirectCommandDrawElements(copy, copyop), MixinVector<DrawElementsIndirectCommand>() {}
|
||||
|
||||
virtual const GLvoid* getDataPointer() const { return empty()?0:&front(); }
|
||||
virtual unsigned int getNumElements() const { return static_cast<unsigned int>(size()); }
|
||||
virtual unsigned int getElementSize()const { return 20u; };
|
||||
virtual void reserveElements(const unsigned int n) {reserve(n);}
|
||||
virtual void resizeElements(const unsigned int n) {resize(n);}
|
||||
|
||||
virtual unsigned int & count(const unsigned int&index) { return at(index).count; }
|
||||
virtual unsigned int & instanceCount(const unsigned int&index) { return at(index).instanceCount; }
|
||||
virtual unsigned int & firstIndex(const unsigned int&index) { return at(index).firstIndex; }
|
||||
virtual unsigned int & baseVertex(const unsigned int&index) { return at(index).baseVertex; }
|
||||
virtual unsigned int & baseInstance(const unsigned int&index) { return at(index).baseInstance; }
|
||||
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief The DrawElementsIndirect base PrimitiveSet
|
||||
///
|
||||
class OSG_EXPORT DrawElementsIndirect : public DrawElements
|
||||
{
|
||||
public:
|
||||
|
||||
DrawElementsIndirect(Type primType=PrimitiveType, GLenum mode = 0,unsigned int firstCommand = 0, GLsizei stride = 0) :
|
||||
DrawElements(primType,mode, 0),_firstCommand(firstCommand),_stride(stride) { setIndirectCommandArray(new DefaultIndirectCommandDrawElements()); }
|
||||
|
||||
DrawElementsIndirect(const DrawElementsIndirect& rhs,const CopyOp& copyop=CopyOp::SHALLOW_COPY) :
|
||||
DrawElements(rhs,copyop),_firstCommand(rhs._firstCommand), _stride(rhs._stride) { _indirectCommandArray=(DefaultIndirectCommandDrawElements*)copyop(rhs._indirectCommandArray.get()); }
|
||||
|
||||
/// set command array of this indirect primitive set
|
||||
inline void setIndirectCommandArray(IndirectCommandDrawElements*idc)
|
||||
{
|
||||
_indirectCommandArray = idc;
|
||||
//ensure bo of idc is of the correct type
|
||||
if(!dynamic_cast<DrawIndirectBufferObject* >(_indirectCommandArray->getBufferObject()))
|
||||
_indirectCommandArray->setBufferObject(new DrawIndirectBufferObject());
|
||||
}
|
||||
|
||||
/// get command array of this indirect primitive set
|
||||
inline IndirectCommandDrawElements* getIndirectCommandArray() { return _indirectCommandArray; }
|
||||
inline const IndirectCommandDrawElements* getIndirectCommandArray() const { return _indirectCommandArray; }
|
||||
|
||||
///Further methods are for advanced DI when you plan to use your own IndirectCommandElement (stride)
|
||||
///or if you want to draw a particular command index of the IndirectCommandElement(FirstCommandToDraw)
|
||||
|
||||
/// set offset of the first command to draw in the IndirectCommandDrawArrays
|
||||
inline void setFirstCommandToDraw( unsigned int i) { _firstCommand = i; }
|
||||
|
||||
/// get offset of the first command in the IndirectCommandDrawArrays
|
||||
inline unsigned int getFirstCommandToDraw() const { return _firstCommand; }
|
||||
|
||||
/// stride (to set if you use custom CommandArray)
|
||||
inline void setStride( GLsizei i) { _stride=i; }
|
||||
|
||||
/// stride (to set if you use custom CommandArray)
|
||||
inline GLsizei getStride() const { return _stride; }
|
||||
|
||||
virtual unsigned int getNumPrimitives() const=0;
|
||||
|
||||
protected:
|
||||
virtual ~DrawElementsIndirect() {}
|
||||
|
||||
unsigned int _firstCommand;
|
||||
GLsizei _stride;
|
||||
ref_ptr<IndirectCommandDrawElements> _indirectCommandArray;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief The DrawElementsIndirectUByte PrimitiveSet
|
||||
///
|
||||
class OSG_EXPORT DrawElementsIndirectUByte : public DrawElementsIndirect, public VectorGLubyte
|
||||
{
|
||||
public:
|
||||
|
||||
typedef VectorGLubyte vector_type;
|
||||
|
||||
DrawElementsIndirectUByte(GLenum mode = 0/*,unsigned int firstCommand = 0, GLsizei stride = 0*/) :
|
||||
DrawElementsIndirect(DrawElementsUByteIndirectPrimitiveType,mode) {}
|
||||
|
||||
DrawElementsIndirectUByte(const DrawElementsIndirectUByte& array, const CopyOp& copyop=CopyOp::SHALLOW_COPY) :
|
||||
DrawElementsIndirect(array,copyop),
|
||||
vector_type(array) {}
|
||||
|
||||
/**
|
||||
* \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used.
|
||||
* \param no Number of intended elements. This will be the size of the underlying vector.
|
||||
* \param ptr Pointer to a GLubyte to copy index data from.
|
||||
*/
|
||||
DrawElementsIndirectUByte(GLenum mode, unsigned int no, const GLubyte* ptr) :
|
||||
DrawElementsIndirect(DrawElementsUByteIndirectPrimitiveType,mode),
|
||||
vector_type(ptr,ptr+no) {}
|
||||
|
||||
/**
|
||||
* \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used.
|
||||
* \param no Number of intended elements. This will be the size of the underlying vector.
|
||||
*/
|
||||
DrawElementsIndirectUByte(GLenum mode, unsigned int no) :
|
||||
DrawElementsIndirect(DrawElementsUByteIndirectPrimitiveType,mode),
|
||||
vector_type(no) {}
|
||||
|
||||
virtual Object* cloneType() const { return new DrawElementsIndirectUByte(); }
|
||||
virtual Object* clone(const CopyOp& copyop) const { return new DrawElementsIndirectUByte(*this,copyop); }
|
||||
virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const DrawElementsIndirectUByte*>(obj)!=NULL; }
|
||||
virtual const char* libraryName() const { return "osg"; }
|
||||
virtual const char* className() const { return "DrawElementsIndirectUByte"; }
|
||||
|
||||
virtual const GLvoid* getDataPointer() const { return empty()?0:&front(); }
|
||||
virtual unsigned int getTotalDataSize() const { return static_cast<unsigned int>(size()); }
|
||||
virtual bool supportsBufferObject() const { return false; }
|
||||
|
||||
virtual void draw(State& state, bool useVertexBufferObjects) const;
|
||||
|
||||
virtual void accept(PrimitiveFunctor& functor) const;
|
||||
virtual void accept(PrimitiveIndexFunctor& functor) const;
|
||||
|
||||
virtual unsigned int getNumIndices() const { return static_cast<unsigned int>(size()); }
|
||||
virtual unsigned int index(unsigned int pos) const { return (*this)[pos]; }
|
||||
virtual void offsetIndices(int offset);
|
||||
|
||||
virtual GLenum getDataType() { return GL_UNSIGNED_BYTE; }
|
||||
|
||||
virtual void resizeElements(unsigned int numIndices) { resize(numIndices); }
|
||||
virtual void reserveElements(unsigned int numIndices) { reserve(numIndices); }
|
||||
|
||||
virtual void setElement(unsigned int i, unsigned int v) { (*this)[i] = v; }
|
||||
virtual unsigned int getElement(unsigned int i) { return (*this)[i]; }
|
||||
|
||||
virtual void addElement(unsigned int v) { push_back(GLubyte(v)); }
|
||||
virtual unsigned int getNumPrimitives() const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~DrawElementsIndirectUByte();
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief The DrawElementsIndirectUShort PrimitiveSet
|
||||
///
|
||||
class OSG_EXPORT DrawElementsIndirectUShort : public DrawElementsIndirect, public VectorGLushort
|
||||
{
|
||||
public:
|
||||
|
||||
typedef VectorGLushort vector_type;
|
||||
|
||||
DrawElementsIndirectUShort(GLenum mode = 0/*,unsigned int firstCommand = 0, GLsizei stride = 0*/) :
|
||||
DrawElementsIndirect(DrawElementsUShortIndirectPrimitiveType,mode) {}
|
||||
|
||||
DrawElementsIndirectUShort(const DrawElementsIndirectUShort& array,const CopyOp& copyop=CopyOp::SHALLOW_COPY) :
|
||||
DrawElementsIndirect(array,copyop),
|
||||
vector_type(array) {}
|
||||
|
||||
/**
|
||||
* \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used.
|
||||
* \param no Number of intended elements. This will be the size of the underlying vector.
|
||||
* \param ptr Pointer to a GLushort to copy index data from.
|
||||
*/
|
||||
DrawElementsIndirectUShort(GLenum mode, unsigned int no, const GLushort* ptr) :
|
||||
DrawElementsIndirect(DrawElementsUShortIndirectPrimitiveType,mode),
|
||||
vector_type(ptr,ptr+no) {}
|
||||
|
||||
/**
|
||||
* \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used.
|
||||
* \param no Number of intended elements. This will be the size of the underlying vector.
|
||||
*/
|
||||
DrawElementsIndirectUShort(GLenum mode, unsigned int no) :
|
||||
DrawElementsIndirect(DrawElementsUShortIndirectPrimitiveType,mode),
|
||||
vector_type(no) {}
|
||||
|
||||
template <class InputIterator>
|
||||
DrawElementsIndirectUShort(GLenum mode, InputIterator first,InputIterator last) :
|
||||
DrawElementsIndirect(DrawElementsUShortIndirectPrimitiveType,mode),
|
||||
vector_type(first,last) {}
|
||||
|
||||
virtual Object* cloneType() const { return new DrawElementsIndirectUShort(); }
|
||||
virtual Object* clone(const CopyOp& copyop) const { return new DrawElementsIndirectUShort(*this,copyop); }
|
||||
virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const DrawElementsIndirectUShort*>(obj)!=NULL; }
|
||||
virtual const char* libraryName() const { return "osg"; }
|
||||
virtual const char* className() const { return "DrawElementsIndirectUShort"; }
|
||||
|
||||
virtual const GLvoid* getDataPointer() const { return empty()?0:&front(); }
|
||||
virtual unsigned int getTotalDataSize() const { return 2u*static_cast<unsigned int>(size()); }
|
||||
virtual bool supportsBufferObject() const { return false; }
|
||||
|
||||
virtual void draw(State& state, bool useVertexBufferObjects) const;
|
||||
|
||||
virtual void accept(PrimitiveFunctor& functor) const;
|
||||
virtual void accept(PrimitiveIndexFunctor& functor) const;
|
||||
|
||||
virtual unsigned int getNumIndices() const { return static_cast<unsigned int>(size()); }
|
||||
virtual unsigned int index(unsigned int pos) const { return (*this)[pos]; }
|
||||
virtual void offsetIndices(int offset);
|
||||
|
||||
virtual GLenum getDataType() { return GL_UNSIGNED_SHORT; }
|
||||
virtual void resizeElements(unsigned int numIndices) { resize(numIndices); }
|
||||
virtual void reserveElements(unsigned int numIndices) { reserve(numIndices); }
|
||||
|
||||
virtual void setElement(unsigned int i, unsigned int v) { (*this)[i] = v; }
|
||||
virtual unsigned int getElement(unsigned int i) { return (*this)[i]; }
|
||||
|
||||
virtual void addElement(unsigned int v) { push_back(GLushort(v)); }
|
||||
virtual unsigned int getNumPrimitives() const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~DrawElementsIndirectUShort();
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief The DrawElementsIndirectUInt PrimitiveSet
|
||||
///
|
||||
class OSG_EXPORT DrawElementsIndirectUInt : public DrawElementsIndirect, public VectorGLuint
|
||||
{
|
||||
public:
|
||||
|
||||
typedef VectorGLuint vector_type;
|
||||
|
||||
DrawElementsIndirectUInt(GLenum mode = 0/*,unsigned int firstCommand = 0, GLsizei stride = 0*/) :
|
||||
DrawElementsIndirect(DrawElementsUIntIndirectPrimitiveType,mode) {}
|
||||
|
||||
DrawElementsIndirectUInt(const DrawElementsIndirectUInt& array,const CopyOp& copyop=CopyOp::SHALLOW_COPY) :
|
||||
DrawElementsIndirect(array,copyop),
|
||||
vector_type(array) {}
|
||||
|
||||
/**
|
||||
* \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used.
|
||||
* \param no Number of intended elements. This will be the size of the underlying vector.
|
||||
* \param ptr Pointer to a GLunsigned int to copy index data from.
|
||||
*/
|
||||
DrawElementsIndirectUInt(GLenum mode, unsigned int no, const GLuint* ptr) :
|
||||
DrawElementsIndirect(DrawElementsUIntIndirectPrimitiveType,mode),
|
||||
vector_type(ptr,ptr+no) {}
|
||||
|
||||
/**
|
||||
* \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used.
|
||||
* \param no Number of intended elements. This will be the size of the underlying vector.
|
||||
*/
|
||||
DrawElementsIndirectUInt(GLenum mode, unsigned int no) :
|
||||
DrawElementsIndirect(DrawElementsUIntIndirectPrimitiveType,mode),
|
||||
vector_type(no) {}
|
||||
|
||||
template <class InputIterator>
|
||||
DrawElementsIndirectUInt(GLenum mode, InputIterator first,InputIterator last) :
|
||||
DrawElementsIndirect(DrawElementsUIntIndirectPrimitiveType,mode),
|
||||
vector_type(first,last) {}
|
||||
|
||||
virtual Object* cloneType() const { return new DrawElementsIndirectUInt(); }
|
||||
virtual Object* clone(const CopyOp& copyop) const { return new DrawElementsIndirectUInt(*this,copyop); }
|
||||
virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const DrawElementsIndirectUInt*>(obj)!=NULL; }
|
||||
virtual const char* libraryName() const { return "osg"; }
|
||||
virtual const char* className() const { return "DrawElementsIndirectUInt"; }
|
||||
|
||||
virtual const GLvoid* getDataPointer() const { return empty()?0:&front(); }
|
||||
virtual unsigned int getTotalDataSize() const { return 4u*static_cast<unsigned int>(size()); }
|
||||
virtual bool supportsBufferObject() const { return false; }
|
||||
|
||||
virtual void draw(State& state, bool useVertexBufferObjects) const;
|
||||
|
||||
virtual void accept(PrimitiveFunctor& functor) const;
|
||||
virtual void accept(PrimitiveIndexFunctor& functor) const;
|
||||
|
||||
virtual unsigned int getNumIndices() const { return static_cast<unsigned int>(size()); }
|
||||
virtual unsigned int index(unsigned int pos) const { return (*this)[pos]; }
|
||||
virtual void offsetIndices(int offset);
|
||||
|
||||
virtual GLenum getDataType() { return GL_UNSIGNED_INT; }
|
||||
virtual void resizeElements(unsigned int numIndices) { resize(numIndices); }
|
||||
virtual void reserveElements(unsigned int numIndices) { reserve(numIndices); }
|
||||
virtual void setElement(unsigned int i, unsigned int v) { (*this)[i] = v; }
|
||||
virtual unsigned int getElement(unsigned int i) { return (*this)[i]; }
|
||||
virtual void addElement(unsigned int v) { push_back(GLuint(v)); }
|
||||
|
||||
virtual unsigned int getNumPrimitives() const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~DrawElementsIndirectUInt();
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief The MultiDrawElementsIndirect PrimitiveSets
|
||||
///
|
||||
class OSG_EXPORT MultiDrawElementsIndirectUShort : public DrawElementsIndirectUShort
|
||||
{
|
||||
public:
|
||||
MultiDrawElementsIndirectUShort(GLenum mode = 0/*,unsigned int firstCommand = 0, GLsizei stride = 0*/) :
|
||||
DrawElementsIndirectUShort(mode),_count(0) { _primitiveType=(Type(MultiDrawElementsUShortIndirectPrimitiveType)); }
|
||||
|
||||
MultiDrawElementsIndirectUShort(const MultiDrawElementsIndirectUShort& mdi,const CopyOp& copyop=CopyOp::SHALLOW_COPY) :
|
||||
DrawElementsIndirectUShort(mdi,copyop),_count(mdi._count) {}
|
||||
/**
|
||||
* \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used.
|
||||
* \param no Number of intended elements. This will be the size of the underlying vector.
|
||||
* \param ptr Pointer to a GLunsigned int to copy index data from.
|
||||
*/
|
||||
MultiDrawElementsIndirectUShort(GLenum mode, unsigned int no, const GLushort* ptr) :
|
||||
DrawElementsIndirectUShort(mode,no,ptr)
|
||||
{_primitiveType=(Type(MultiDrawElementsUShortIndirectPrimitiveType));}
|
||||
|
||||
/**
|
||||
* \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used.
|
||||
* \param no Number of intended elements. This will be the size of the underlying vector.
|
||||
*/
|
||||
MultiDrawElementsIndirectUShort(GLenum mode, unsigned int no) :
|
||||
DrawElementsIndirectUShort(mode,no)
|
||||
{_primitiveType=(Type(MultiDrawElementsUShortIndirectPrimitiveType));}
|
||||
|
||||
template <class InputIterator>
|
||||
MultiDrawElementsIndirectUShort(GLenum mode, InputIterator first,InputIterator last) :
|
||||
DrawElementsIndirectUShort(mode,first,last)
|
||||
{_primitiveType=(Type(MultiDrawElementsUShortIndirectPrimitiveType));}
|
||||
|
||||
virtual osg::Object* cloneType() const { return new MultiDrawElementsIndirectUShort(); }
|
||||
virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new MultiDrawElementsIndirectUShort(*this,copyop); }
|
||||
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const MultiDrawElementsIndirectUShort*>(obj)!=NULL; }
|
||||
virtual const char* className() const { return "MultiDrawElementsIndirectUShort"; }
|
||||
|
||||
virtual void draw(State& state, bool useVertexBufferObjects) const;
|
||||
virtual void accept(PrimitiveFunctor& functor) const;
|
||||
virtual void accept(PrimitiveIndexFunctor& functor) const;
|
||||
virtual unsigned int getNumPrimitives() const;
|
||||
|
||||
///if you want to draw a subset of the IndirectCommandElement(FirstCommandToDraw,NumCommandsToDraw)
|
||||
|
||||
/// count of Indirect Command to execute
|
||||
inline void setNumCommandsToDraw( unsigned int i) { _count=i; }
|
||||
/// count of Indirect Command to execute
|
||||
inline unsigned int getNumCommandsToDraw()const { return _count; }
|
||||
|
||||
protected:
|
||||
unsigned int _count;
|
||||
virtual ~MultiDrawElementsIndirectUShort();
|
||||
};
|
||||
|
||||
class OSG_EXPORT MultiDrawElementsIndirectUByte : public DrawElementsIndirectUByte
|
||||
{
|
||||
public:
|
||||
MultiDrawElementsIndirectUByte(GLenum mode = 0) :
|
||||
DrawElementsIndirectUByte(mode),_count(0) { _primitiveType=(Type(MultiDrawElementsUByteIndirectPrimitiveType)); }
|
||||
|
||||
MultiDrawElementsIndirectUByte(const MultiDrawElementsIndirectUByte& mdi,const CopyOp& copyop=CopyOp::SHALLOW_COPY) :
|
||||
DrawElementsIndirectUByte(mdi,copyop),_count(mdi._count) {}
|
||||
/**
|
||||
* \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used.
|
||||
* \param no Number of intended elements. This will be the size of the underlying vector.
|
||||
* \param ptr Pointer to a GLunsigned int to copy index data from.
|
||||
*/
|
||||
MultiDrawElementsIndirectUByte(GLenum mode, unsigned int no, const GLubyte* ptr) :
|
||||
DrawElementsIndirectUByte(mode,no,ptr)
|
||||
{_primitiveType=(Type(MultiDrawElementsUByteIndirectPrimitiveType));}
|
||||
|
||||
/**
|
||||
* \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used.
|
||||
* \param no Number of intended elements. This will be the size of the underlying vector.
|
||||
*/
|
||||
MultiDrawElementsIndirectUByte(GLenum mode, unsigned int no) :
|
||||
DrawElementsIndirectUByte(mode,no)
|
||||
{_primitiveType=(Type(MultiDrawElementsUByteIndirectPrimitiveType));}
|
||||
|
||||
template <class InputIterator>
|
||||
MultiDrawElementsIndirectUByte(GLenum mode, InputIterator first,InputIterator last) :
|
||||
DrawElementsIndirectUByte(mode,first,last)
|
||||
{_primitiveType=(Type(MultiDrawElementsUByteIndirectPrimitiveType));}
|
||||
|
||||
virtual osg::Object* cloneType() const { return new MultiDrawElementsIndirectUByte(); }
|
||||
virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new MultiDrawElementsIndirectUByte(*this,copyop); }
|
||||
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const MultiDrawElementsIndirectUByte*>(obj)!=NULL; }
|
||||
virtual const char* className() const { return "MultiDrawElementsIndirectUByte"; }
|
||||
|
||||
virtual void draw(State& state, bool useVertexBufferObjects) const;
|
||||
virtual void accept(PrimitiveFunctor& functor) const;
|
||||
virtual void accept(PrimitiveIndexFunctor& functor) const;
|
||||
virtual unsigned int getNumPrimitives() const;
|
||||
|
||||
/// count of Indirect Command to execute
|
||||
inline void setNumCommandsToDraw( unsigned int i) { _count=i; }
|
||||
/// count of Indirect Command to execute
|
||||
inline unsigned int getNumCommandsToDraw()const { return _count; }
|
||||
|
||||
protected:
|
||||
unsigned int _count;
|
||||
virtual ~MultiDrawElementsIndirectUByte();
|
||||
};
|
||||
|
||||
class OSG_EXPORT MultiDrawElementsIndirectUInt : public DrawElementsIndirectUInt
|
||||
{
|
||||
public:
|
||||
MultiDrawElementsIndirectUInt(GLenum mode = 0) :
|
||||
DrawElementsIndirectUInt(mode),_count(0) { _primitiveType=(Type(MultiDrawElementsUIntIndirectPrimitiveType)); }
|
||||
|
||||
MultiDrawElementsIndirectUInt(const MultiDrawElementsIndirectUInt& mdi,const CopyOp& copyop=CopyOp::SHALLOW_COPY) :
|
||||
DrawElementsIndirectUInt(mdi,copyop),_count(mdi._count) {}
|
||||
/**
|
||||
* \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used.
|
||||
* \param no Number of intended elements. This will be the size of the underlying vector.
|
||||
* \param ptr Pointer to a GLunsigned int to copy index data from.
|
||||
*/
|
||||
MultiDrawElementsIndirectUInt(GLenum mode, unsigned int no, const GLuint* ptr) :
|
||||
DrawElementsIndirectUInt(mode,no,ptr)
|
||||
{_primitiveType=(Type(MultiDrawElementsUIntIndirectPrimitiveType));}
|
||||
|
||||
/**
|
||||
* \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used.
|
||||
* \param no Number of intended elements. This will be the size of the underlying vector.
|
||||
*/
|
||||
MultiDrawElementsIndirectUInt(GLenum mode, unsigned int no) :
|
||||
DrawElementsIndirectUInt(mode,no)
|
||||
{_primitiveType=(Type(MultiDrawElementsUIntIndirectPrimitiveType));}
|
||||
|
||||
template <class InputIterator>
|
||||
MultiDrawElementsIndirectUInt(GLenum mode, InputIterator first,InputIterator last) :
|
||||
DrawElementsIndirectUInt(mode,first,last)
|
||||
{_primitiveType=(Type(MultiDrawElementsUIntIndirectPrimitiveType));}
|
||||
|
||||
virtual osg::Object* cloneType() const { return new MultiDrawElementsIndirectUInt(); }
|
||||
virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new MultiDrawElementsIndirectUInt(*this,copyop); }
|
||||
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const MultiDrawElementsIndirectUInt*>(obj)!=NULL; }
|
||||
virtual const char* className() const { return "MultiDrawElementsIndirectUInt"; }
|
||||
|
||||
virtual void draw(State& state, bool useVertexBufferObjects) const;
|
||||
virtual void accept(PrimitiveFunctor& functor) const;
|
||||
virtual void accept(PrimitiveIndexFunctor& functor) const;
|
||||
virtual unsigned int getNumPrimitives() const;
|
||||
|
||||
/// count of Indirect Command to execute
|
||||
inline void setNumCommandsToDraw( unsigned int i) { _count=i; }
|
||||
/// count of Indirect Command to execute
|
||||
inline unsigned int getNumCommandsToDraw()const { return _count; }
|
||||
|
||||
protected:
|
||||
unsigned int _count;
|
||||
virtual ~MultiDrawElementsIndirectUInt();
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief The MultiDrawArraysIndirect PrimitiveSet
|
||||
///
|
||||
class OSG_EXPORT DrawArraysIndirect : public osg::PrimitiveSet
|
||||
{
|
||||
public:
|
||||
|
||||
DrawArraysIndirect(GLenum mode=0, unsigned int firstcommand = 0, GLsizei stride = 0) :
|
||||
osg::PrimitiveSet(Type(DrawArraysIndirectPrimitiveType), mode),
|
||||
_firstCommand(firstcommand), _stride(stride) { setIndirectCommandArray(new DefaultIndirectCommandDrawArrays); }
|
||||
|
||||
DrawArraysIndirect(const DrawArraysIndirect& dal,const CopyOp& copyop=CopyOp::SHALLOW_COPY) :
|
||||
osg::PrimitiveSet(dal,copyop),
|
||||
_firstCommand(dal._firstCommand),
|
||||
_stride(dal._stride),
|
||||
_indirectCommandArray((DefaultIndirectCommandDrawArrays*)copyop( dal._indirectCommandArray.get())) {}
|
||||
|
||||
virtual osg::Object* cloneType() const { return new DrawArraysIndirect(); }
|
||||
virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new DrawArraysIndirect(*this,copyop); }
|
||||
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const DrawArraysIndirect*>(obj)!=NULL; }
|
||||
virtual const char* libraryName() const { return "osg"; }
|
||||
virtual const char* className() const { return "DrawArraysIndirect"; }
|
||||
|
||||
virtual void draw(State& state, bool useVertexBufferObjects) const;
|
||||
|
||||
virtual void accept(PrimitiveFunctor& functor) const;
|
||||
virtual void accept(PrimitiveIndexFunctor& functor) const;
|
||||
|
||||
virtual unsigned int getNumIndices() const;
|
||||
virtual unsigned int index(unsigned int pos) const;
|
||||
virtual void offsetIndices(int offset);
|
||||
|
||||
virtual unsigned int getNumPrimitives() const;
|
||||
|
||||
/// stride (to set if you use custom CommandArray)
|
||||
inline void setStride( GLsizei i) { _stride=i; }
|
||||
|
||||
/// stride (to set if you use custom CommandArray)
|
||||
inline GLsizei getStride()const { return _stride; }
|
||||
|
||||
/// set offset of the first command in the IndirectCommandDrawArrays
|
||||
inline void setFirstCommandToDraw( unsigned int i) { _firstCommand=i; }
|
||||
|
||||
/// get offset of the first command in the IndirectCommandDrawArrays
|
||||
inline unsigned int getFirstCommandToDraw() const { return _firstCommand; }
|
||||
|
||||
inline void setIndirectCommandArray(IndirectCommandDrawArrays*idc)
|
||||
{
|
||||
_indirectCommandArray = idc;
|
||||
//ensure bo of idc is of the correct type
|
||||
if(!dynamic_cast<DrawIndirectBufferObject* >(_indirectCommandArray->getBufferObject()))
|
||||
_indirectCommandArray->setBufferObject(new DrawIndirectBufferObject());
|
||||
}
|
||||
inline const IndirectCommandDrawArrays* getIndirectCommandArray() const { return _indirectCommandArray; }
|
||||
inline IndirectCommandDrawArrays* getIndirectCommandArray() { return _indirectCommandArray; }
|
||||
|
||||
protected:
|
||||
|
||||
unsigned int _firstCommand;
|
||||
GLsizei _stride;
|
||||
ref_ptr<IndirectCommandDrawArrays> _indirectCommandArray;
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \brief The MultiDrawArraysIndirect PrimitiveSet
|
||||
///
|
||||
class OSG_EXPORT MultiDrawArraysIndirect : public DrawArraysIndirect
|
||||
{
|
||||
public:
|
||||
|
||||
MultiDrawArraysIndirect(GLenum mode=0, unsigned int firstcommand = 0, unsigned int count = 0, GLsizei stride = 0) :
|
||||
osg::DrawArraysIndirect(mode, firstcommand, stride), _count(count) { _primitiveType=Type(MultiDrawArraysIndirectPrimitiveType); }
|
||||
|
||||
MultiDrawArraysIndirect(const MultiDrawArraysIndirect& dal,const CopyOp& copyop=CopyOp::SHALLOW_COPY) :
|
||||
osg::DrawArraysIndirect(dal,copyop), _count(dal._count) {}
|
||||
|
||||
virtual osg::Object* cloneType() const { return new MultiDrawArraysIndirect(); }
|
||||
virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new MultiDrawArraysIndirect(*this,copyop); }
|
||||
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const MultiDrawArraysIndirect*>(obj)!=NULL; }
|
||||
virtual const char* className() const { return "MultiDrawArraysIndirect"; }
|
||||
|
||||
virtual void draw(State& state, bool useVertexBufferObjects) const;
|
||||
|
||||
virtual void accept(PrimitiveFunctor& functor) const;
|
||||
virtual void accept(PrimitiveIndexFunctor& functor) const;
|
||||
|
||||
virtual unsigned int getNumIndices() const;
|
||||
virtual unsigned int index(unsigned int pos) const;
|
||||
virtual void offsetIndices(int offset);
|
||||
|
||||
virtual unsigned int getNumPrimitives() const;
|
||||
|
||||
/// count of Indirect Command to execute
|
||||
inline void setNumCommandsToDraw( unsigned int i) { _count=i; }
|
||||
/// count of Indirect Command to execute
|
||||
inline unsigned int getNumCommandsToDraw()const { return _count; }
|
||||
|
||||
protected:
|
||||
unsigned int _count;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -591,6 +591,27 @@ class OSG_EXPORT State : public Referenced
|
||||
}
|
||||
|
||||
|
||||
inline void bindDrawIndirectBufferObject(osg::GLBufferObject* ibo)
|
||||
{
|
||||
if (ibo->isDirty())
|
||||
{
|
||||
ibo->compileBuffer();
|
||||
_currentDIBO = ibo;
|
||||
}
|
||||
else if (ibo != _currentDIBO)
|
||||
{
|
||||
ibo->bindBuffer();
|
||||
_currentDIBO = ibo;
|
||||
}
|
||||
}
|
||||
|
||||
inline void unbindDrawIndirectBufferObject()
|
||||
{
|
||||
if (!_currentDIBO) return;
|
||||
_glBindBuffer(GL_DRAW_INDIRECT_BUFFER,0);
|
||||
_currentDIBO = 0;
|
||||
}
|
||||
|
||||
void setCurrentVertexArrayObject(GLuint vao) { _currentVAO = vao; }
|
||||
GLuint getCurrentVertexArrayObject() const { return _currentVAO; }
|
||||
|
||||
@@ -1259,6 +1280,7 @@ class OSG_EXPORT State : public Referenced
|
||||
unsigned int _currentActiveTextureUnit;
|
||||
unsigned int _currentClientActiveTextureUnit;
|
||||
GLBufferObject* _currentPBO;
|
||||
GLBufferObject* _currentDIBO;
|
||||
GLuint _currentVAO;
|
||||
|
||||
|
||||
|
||||
@@ -174,34 +174,4 @@ ShaderStorageBufferBinding::ShaderStorageBufferBinding(const ShaderStorageBuffer
|
||||
}
|
||||
|
||||
|
||||
DrawIndirectBufferBinding::DrawIndirectBufferBinding( )
|
||||
: BufferIndexBinding(GL_DRAW_INDIRECT_BUFFER, 0)
|
||||
{
|
||||
}
|
||||
void DrawIndirectBufferBinding::apply(State& state) const
|
||||
{
|
||||
if (_bufferData.valid())
|
||||
{
|
||||
BufferObject * bo = _bufferData->getBufferObject();
|
||||
GLBufferObject* glObject
|
||||
= bo->getOrCreateGLBufferObject(state.getContextID());
|
||||
if (!glObject->_extensions->isUniformBufferObjectSupported)
|
||||
return;
|
||||
if (glObject->isDirty()) glObject->compileBuffer();
|
||||
glObject->_extensions->glBindBuffer (_target, glObject->getGLObjectID());
|
||||
}
|
||||
}
|
||||
DrawIndirectBufferBinding::DrawIndirectBufferBinding( BufferData* bo)
|
||||
: BufferIndexBinding(GL_DRAW_INDIRECT_BUFFER, 0, bo, 0, 0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DrawIndirectBufferBinding::DrawIndirectBufferBinding(const DrawIndirectBufferBinding& rhs,
|
||||
const CopyOp& copyop)
|
||||
: BufferIndexBinding(rhs, copyop)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
} // namespace osg
|
||||
|
||||
@@ -1358,6 +1358,50 @@ const DrawElements* ElementBufferObject::getDrawElements(unsigned int i) const
|
||||
return dynamic_cast<const DrawElements*>(getBufferData(i));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DrawIndirectBufferObject
|
||||
//
|
||||
DrawIndirectBufferObject::DrawIndirectBufferObject()
|
||||
{
|
||||
setTarget(GL_DRAW_INDIRECT_BUFFER);
|
||||
setUsage(GL_STATIC_DRAW_ARB);
|
||||
// setUsage(GL_STREAM_DRAW_ARB);
|
||||
}
|
||||
|
||||
DrawIndirectBufferObject::DrawIndirectBufferObject(const DrawIndirectBufferObject& vbo,const CopyOp& copyop):
|
||||
BufferObject(vbo,copyop)
|
||||
{
|
||||
}
|
||||
|
||||
DrawIndirectBufferObject::~DrawIndirectBufferObject()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int DrawIndirectBufferObject::addArray(osg::Array* array)
|
||||
{
|
||||
return addBufferData(array);
|
||||
}
|
||||
|
||||
void DrawIndirectBufferObject::removeArray(osg::Array* array)
|
||||
{
|
||||
removeBufferData(array);
|
||||
}
|
||||
|
||||
void DrawIndirectBufferObject::setArray(unsigned int i, Array* array)
|
||||
{
|
||||
setBufferData(i,array);
|
||||
}
|
||||
|
||||
Array* DrawIndirectBufferObject::getArray(unsigned int i)
|
||||
{
|
||||
return dynamic_cast<osg::Array*>(getBufferData(i));
|
||||
}
|
||||
|
||||
const Array* DrawIndirectBufferObject::getArray(unsigned int i) const
|
||||
{
|
||||
return dynamic_cast<const osg::Array*>(getBufferData(i));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
@@ -136,6 +136,7 @@ SET(TARGET_H
|
||||
${HEADER_PATH}/Polytope
|
||||
${HEADER_PATH}/PositionAttitudeTransform
|
||||
${HEADER_PATH}/PrimitiveSet
|
||||
${HEADER_PATH}/PrimitiveSetIndirect
|
||||
${HEADER_PATH}/PrimitiveRestartIndex
|
||||
${HEADER_PATH}/Program
|
||||
${HEADER_PATH}/Projection
|
||||
@@ -342,6 +343,7 @@ SET(TARGET_SRC
|
||||
Polytope.cpp
|
||||
PositionAttitudeTransform.cpp
|
||||
PrimitiveSet.cpp
|
||||
PrimitiveSetIndirect.cpp
|
||||
PrimitiveRestartIndex.cpp
|
||||
Program.cpp
|
||||
Projection.cpp
|
||||
|
||||
618
src/osg/PrimitiveSetIndirect.cpp
Normal file
618
src/osg/PrimitiveSetIndirect.cpp
Normal file
@@ -0,0 +1,618 @@
|
||||
/* -*-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 <osg/PrimitiveSetIndirect>
|
||||
#include <osg/BufferObject>
|
||||
#include <osg/State>
|
||||
#include <osg/Notify>
|
||||
#include <assert.h>
|
||||
|
||||
/// TODO: add base vertex feature to PrimitiveFunctor and PrimitiveIndexFunctor
|
||||
//#define PRIMFUNCTORBASEVERTEX 1
|
||||
|
||||
using namespace osg;
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DrawElementsIndirect
|
||||
//
|
||||
template<class T>
|
||||
inline unsigned int getNumPrimitivesDI( const T&_this )
|
||||
{
|
||||
unsigned int offset= _this.getFirstCommandToDraw();
|
||||
IndirectCommandDrawElements *cmd=const_cast<IndirectCommandDrawElements *>(_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<DrawElementsIndirectUInt>(*this); }
|
||||
unsigned int DrawElementsIndirectUByte::getNumPrimitives() const { return getNumPrimitivesDI<DrawElementsIndirectUByte>(*this); }
|
||||
unsigned int DrawElementsIndirectUShort::getNumPrimitives() const { return getNumPrimitivesDI<DrawElementsIndirectUShort>(*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());
|
||||
|
||||
assert (useVertexBufferObjects && ebo);
|
||||
|
||||
state.bindElementBufferObject(ebo);
|
||||
|
||||
state.get<GLExtensions>()-> glDrawElementsIndirect(mode, GL_UNSIGNED_INT,
|
||||
(const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex()) //command array adress
|
||||
+_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;
|
||||
}
|
||||
}
|
||||
void DrawElementsIndirectUInt::accept(PrimitiveFunctor& functor) const
|
||||
{
|
||||
#ifdef PRIMFUNCTORBASEVERTEX
|
||||
// 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 DrawElementsIndirectUInt::accept(PrimitiveIndexFunctor& functor) const
|
||||
{
|
||||
#ifdef PRIMFUNCTORBASEVERTEX
|
||||
// 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());
|
||||
|
||||
assert (useVertexBufferObjects && ebo);
|
||||
|
||||
state.bindElementBufferObject(ebo);
|
||||
|
||||
state.get<GLExtensions>()-> 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;
|
||||
}
|
||||
}
|
||||
void DrawElementsIndirectUByte::accept(PrimitiveFunctor& functor) const
|
||||
{
|
||||
#ifdef PRIMFUNCTORBASEVERTEX
|
||||
// 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::accept(PrimitiveIndexFunctor& functor) const
|
||||
{
|
||||
#ifdef PRIMFUNCTORBASEVERTEX
|
||||
// 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());
|
||||
|
||||
assert (useVertexBufferObjects && ebo);
|
||||
|
||||
state.bindElementBufferObject(ebo);
|
||||
|
||||
state.get<GLExtensions>()-> 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;
|
||||
}
|
||||
}
|
||||
void DrawElementsIndirectUShort::accept(PrimitiveFunctor& functor) const
|
||||
{
|
||||
#ifdef PRIMFUNCTORBASEVERTEX
|
||||
// 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::accept(PrimitiveIndexFunctor& functor) const
|
||||
{
|
||||
#ifdef PRIMFUNCTORBASEVERTEX
|
||||
// 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<class T> inline
|
||||
unsigned int getNumPrimitivesMDI( const T&_this)
|
||||
{
|
||||
IndirectCommandDrawElements *_indirectCommandArray=const_cast<IndirectCommandDrawElements *>(_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<MultiDrawElementsIndirectUInt>(*this); }
|
||||
unsigned int MultiDrawElementsIndirectUByte::getNumPrimitives() const { return getNumPrimitivesMDI<MultiDrawElementsIndirectUByte>(*this); }
|
||||
unsigned int MultiDrawElementsIndirectUShort::getNumPrimitives() const { return getNumPrimitivesMDI<MultiDrawElementsIndirectUShort>(*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());
|
||||
|
||||
assert (useVertexBufferObjects && ebo);
|
||||
|
||||
state.bindElementBufferObject(ebo);
|
||||
|
||||
state.get<GLExtensions>()-> glMultiDrawElementsIndirect(mode, GL_UNSIGNED_BYTE,
|
||||
(const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())),_indirectCommandArray->getNumElements(), _stride);
|
||||
}
|
||||
|
||||
void MultiDrawElementsIndirectUByte::accept(PrimitiveFunctor& functor) const
|
||||
{
|
||||
#ifdef PRIMFUNCTORBASEVERTEX
|
||||
//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; i<maxindex; ++i)
|
||||
functor.drawElements(_mode,_indirectCommandArray->count(i),
|
||||
&(*this)[_indirectCommandArray->firstIndex(i)],
|
||||
_indirectCommandArray->baseVertex(i));
|
||||
#endif
|
||||
}
|
||||
|
||||
void MultiDrawElementsIndirectUByte::accept(PrimitiveIndexFunctor& functor) const
|
||||
{
|
||||
#ifdef PRIMFUNCTORBASEVERTEX
|
||||
//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; i<maxindex; ++i)
|
||||
functor.drawElements(_mode,_indirectCommandArray->count(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());
|
||||
|
||||
assert (useVertexBufferObjects && ebo);
|
||||
|
||||
state.bindElementBufferObject(ebo);
|
||||
|
||||
state.get<GLExtensions>()-> glMultiDrawElementsIndirect(mode, GL_UNSIGNED_SHORT, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())),
|
||||
(_count>0) ?_count:_indirectCommandArray->getNumElements(),_stride);
|
||||
}
|
||||
|
||||
void MultiDrawElementsIndirectUShort::accept(PrimitiveFunctor& functor) const
|
||||
{
|
||||
#ifdef PRIMFUNCTORBASEVERTEX
|
||||
//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; i<maxindex; ++i)
|
||||
functor.drawElements(_mode,_indirectCommandArray->count(i),
|
||||
&(*this)[_indirectCommandArray->firstIndex(i)],
|
||||
_indirectCommandArray->baseVertex(i));
|
||||
#endif
|
||||
}
|
||||
|
||||
void MultiDrawElementsIndirectUShort::accept(PrimitiveIndexFunctor& functor) const
|
||||
{
|
||||
#ifdef PRIMFUNCTORBASEVERTEX
|
||||
//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; i<maxindex; ++i)
|
||||
functor.drawElements(_mode,_indirectCommandArray->count(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());
|
||||
|
||||
assert (useVertexBufferObjects && ebo);
|
||||
|
||||
state.bindElementBufferObject(ebo);
|
||||
|
||||
state.get<GLExtensions>()-> glMultiDrawElementsIndirect(mode, GL_UNSIGNED_INT, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())),
|
||||
(_count>0) ? _count:_indirectCommandArray->getNumElements(), _stride);
|
||||
}
|
||||
|
||||
void MultiDrawElementsIndirectUInt::accept(PrimitiveFunctor& functor) const
|
||||
{
|
||||
#ifdef PRIMFUNCTORBASEVERTEX
|
||||
//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; i<maxindex; ++i)
|
||||
functor.drawElements(_mode,_indirectCommandArray->count(i),
|
||||
&(*this)[_indirectCommandArray->firstIndex(i)],
|
||||
_indirectCommandArray->baseVertex(i));
|
||||
#endif
|
||||
}
|
||||
|
||||
void MultiDrawElementsIndirectUInt::accept(PrimitiveIndexFunctor& functor) const
|
||||
{
|
||||
#ifdef PRIMFUNCTORBASEVERTEX
|
||||
//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; i<maxindex; ++i)
|
||||
functor.drawElements(_mode,_indirectCommandArray->count(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<GLExtensions>();
|
||||
|
||||
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<GLExtensions>();
|
||||
|
||||
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; i<maxindex; ++i)
|
||||
{
|
||||
functor.drawArrays(_mode, _indirectCommandArray->first(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; i<maxindex; ++i)
|
||||
{
|
||||
functor.drawArrays(_mode, _indirectCommandArray->first(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; i<maxindex; ++i)
|
||||
total+= _indirectCommandArray->count(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; i<maxindex;++i)
|
||||
{
|
||||
unsigned int count = _indirectCommandArray->count(i);
|
||||
if (pos<count) break;
|
||||
pos -= count;
|
||||
}
|
||||
if (i>=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; i<maxindex; ++i)
|
||||
_indirectCommandArray->first(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; i<maxindex; ++i)
|
||||
total+=_indirectCommandArray->count(i);
|
||||
break;
|
||||
case(LINES):
|
||||
for(unsigned int i = _firstCommand; i<maxindex; ++i)
|
||||
total+=_indirectCommandArray->count(i)/2;
|
||||
break;
|
||||
case(TRIANGLES):
|
||||
for(unsigned int i = _firstCommand; i<maxindex; ++i)
|
||||
total+=_indirectCommandArray->count(i)/3;
|
||||
break;
|
||||
case(QUADS):
|
||||
for(unsigned int i = _firstCommand; i<maxindex; ++i)
|
||||
total+=_indirectCommandArray->count(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;
|
||||
}
|
||||
@@ -89,6 +89,7 @@ State::State():
|
||||
_currentClientActiveTextureUnit=0;
|
||||
|
||||
_currentPBO = 0;
|
||||
_currentDIBO = 0;
|
||||
_currentVAO = 0;
|
||||
|
||||
_isSecondaryColorSupported = false;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <osg/PrimitiveSetIndirect>
|
||||
#include <osgUtil/DrawElementTypeSimplifier>
|
||||
|
||||
#include <osg/Geode>
|
||||
@@ -61,6 +62,44 @@ void DrawElementTypeSimplifier::simplify(osg::Geometry & geometry) const
|
||||
|
||||
break;
|
||||
}
|
||||
case osg::PrimitiveSet::DrawElementsUShortIndirectPrimitiveType:
|
||||
{
|
||||
osg::DrawElementsIndirectUShort & de = *static_cast<osg::DrawElementsIndirectUShort*>(it->get());
|
||||
|
||||
max = getMax<osg::DrawElementsIndirectUShort>(de);
|
||||
if (max < 255) *it = copy<osg::DrawElementsIndirectUShort, osg::DrawElementsIndirectUByte>(de);
|
||||
|
||||
break;
|
||||
}
|
||||
case osg::PrimitiveSet::DrawElementsUIntIndirectPrimitiveType:
|
||||
{
|
||||
osg::DrawElementsIndirectUInt & de = *static_cast<osg::DrawElementsIndirectUInt*>(it->get());
|
||||
|
||||
max = getMax<osg::DrawElementsIndirectUInt>(de);
|
||||
if (max < 256) *it = copy<osg::DrawElementsIndirectUInt, osg::DrawElementsIndirectUByte>(de);
|
||||
else if (max < 65536) *it = copy<osg::DrawElementsIndirectUInt, osg::DrawElementsIndirectUShort>(de);
|
||||
|
||||
break;
|
||||
}
|
||||
case osg::PrimitiveSet::MultiDrawElementsUShortIndirectPrimitiveType:
|
||||
{
|
||||
osg::MultiDrawElementsIndirectUShort & de = *static_cast<osg::MultiDrawElementsIndirectUShort*>(it->get());
|
||||
|
||||
max = getMax<osg::MultiDrawElementsIndirectUShort>(de);
|
||||
if (max < 255) *it = copy<osg::MultiDrawElementsIndirectUShort, osg::MultiDrawElementsIndirectUByte>(de);
|
||||
|
||||
break;
|
||||
}
|
||||
case osg::PrimitiveSet::MultiDrawElementsUIntIndirectPrimitiveType:
|
||||
{
|
||||
osg::MultiDrawElementsIndirectUInt & de = *static_cast<osg::MultiDrawElementsIndirectUInt*>(it->get());
|
||||
|
||||
max = getMax<osg::MultiDrawElementsIndirectUInt>(de);
|
||||
if (max < 256) *it = copy<osg::MultiDrawElementsIndirectUInt, osg::MultiDrawElementsIndirectUByte>(de);
|
||||
else if (max < 65536) *it = copy<osg::MultiDrawElementsIndirectUInt, osg::MultiDrawElementsIndirectUShort>(de);
|
||||
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
188
src/osgWrappers/serializers/osg/PrimitiveSetIndirect.cpp
Normal file
188
src/osgWrappers/serializers/osg/PrimitiveSetIndirect.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
#include <osg/PrimitiveSetIndirect>
|
||||
#include <osg/ValueObject>
|
||||
#include <osgDB/ObjectWrapper>
|
||||
#include <osgDB/InputStream>
|
||||
#include <osgDB/OutputStream>
|
||||
|
||||
namespace DACommandsArrays {
|
||||
REGISTER_OBJECT_WRAPPER( IndirectCommandDrawArrays,
|
||||
0,
|
||||
osg::IndirectCommandDrawArrays,
|
||||
"osg::Object osg::BufferData osg::IndirectCommandDrawArrays" )
|
||||
{
|
||||
{
|
||||
UPDATE_TO_VERSION_SCOPED( 147 )
|
||||
ADDED_ASSOCIATE("osg::BufferData")
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace DECommandsArrays {
|
||||
REGISTER_OBJECT_WRAPPER( IndirectCommandDrawElements,
|
||||
0,
|
||||
osg::IndirectCommandDrawElements,
|
||||
"osg::Object osg::BufferData osg::IndirectCommandDrawElements" )
|
||||
{
|
||||
{
|
||||
UPDATE_TO_VERSION_SCOPED( 147 )
|
||||
ADDED_ASSOCIATE("osg::BufferData")
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace DefaultDACommandsArrays {
|
||||
|
||||
|
||||
static bool checkDACommands( const osg::DefaultIndirectCommandDrawArrays& node )
|
||||
{
|
||||
return node.size()>0;
|
||||
}
|
||||
|
||||
static bool readDACommands( osgDB::InputStream& is, osg::DefaultIndirectCommandDrawArrays& node )
|
||||
{
|
||||
unsigned int elmt, size = 0; is >> size >> is.BEGIN_BRACKET;
|
||||
node.resize(size);
|
||||
for ( unsigned int i=0; i<size; ++i )
|
||||
{
|
||||
is >>elmt; node.count(i) = elmt;
|
||||
is >>elmt; node.instanceCount(i) = elmt;
|
||||
is >>elmt; node.first(i) = elmt;
|
||||
is >>elmt; node.baseInstance(i) = elmt;
|
||||
}
|
||||
is >> is.END_BRACKET;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool writeDACommands( osgDB::OutputStream& os, const osg::DefaultIndirectCommandDrawArrays& node )
|
||||
{
|
||||
unsigned int size = node.getNumElements();
|
||||
osg::DefaultIndirectCommandDrawArrays& nonconstnode =const_cast<osg::DefaultIndirectCommandDrawArrays&>(node);
|
||||
os << size << os.BEGIN_BRACKET << std::endl;
|
||||
for ( unsigned int i=0; i<size; ++i )
|
||||
{
|
||||
os << nonconstnode.count(i);
|
||||
os << nonconstnode.instanceCount(i);
|
||||
os << nonconstnode.first(i);
|
||||
os << nonconstnode.baseInstance(i);
|
||||
}
|
||||
os << os.END_BRACKET << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
REGISTER_OBJECT_WRAPPER( osgDefaultIndirectCommandDrawArrays,
|
||||
new osg::DefaultIndirectCommandDrawArrays,
|
||||
osg::DefaultIndirectCommandDrawArrays,
|
||||
"osg::Object osg::BufferData osg::IndirectCommandDrawArrays osg::DefaultIndirectCommandDrawArrays" )
|
||||
{
|
||||
ADD_USER_SERIALIZER(DACommands);
|
||||
}
|
||||
}
|
||||
namespace DefaultDECommandsArrays {
|
||||
|
||||
static bool checkDECommands( const osg::DefaultIndirectCommandDrawElements& node )
|
||||
{
|
||||
return node.size()>0;
|
||||
}
|
||||
|
||||
static bool readDECommands( osgDB::InputStream& is, osg::DefaultIndirectCommandDrawElements& node )
|
||||
{
|
||||
unsigned int elmt, size = 0; is >> size >> is.BEGIN_BRACKET;
|
||||
node.resize(size);
|
||||
for ( unsigned int i=0; i<size; ++i )
|
||||
{
|
||||
is >>elmt; node.count(i) = elmt;
|
||||
is >>elmt; node.instanceCount(i) = elmt;
|
||||
is >>elmt; node.firstIndex(i) = elmt;
|
||||
is >>elmt; node.baseVertex(i) = elmt;
|
||||
is >>elmt; node.baseInstance(i) = elmt;
|
||||
}
|
||||
is >> is.END_BRACKET;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool writeDECommands( osgDB::OutputStream& os, const osg::DefaultIndirectCommandDrawElements& node )
|
||||
{
|
||||
unsigned int size = node.getNumElements();
|
||||
osg::DefaultIndirectCommandDrawElements& nonconstnode =const_cast<osg::DefaultIndirectCommandDrawElements&>(node);
|
||||
os << size << os.BEGIN_BRACKET << std::endl;
|
||||
for ( unsigned int i=0; i<size; ++i )
|
||||
{
|
||||
os << nonconstnode.count(i);
|
||||
os << nonconstnode.instanceCount(i);
|
||||
os << nonconstnode.firstIndex(i);
|
||||
os << nonconstnode.baseVertex(i);
|
||||
os << nonconstnode.baseInstance(i);
|
||||
}
|
||||
os << os.END_BRACKET << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
REGISTER_OBJECT_WRAPPER( osgDefaultIndirectCommandDrawElements,
|
||||
new osg::DefaultIndirectCommandDrawElements,
|
||||
osg::DefaultIndirectCommandDrawElements,
|
||||
"osg::Object osg::BufferData osg::IndirectCommandDrawElements osg::DefaultIndirectCommandDrawElements" )
|
||||
{
|
||||
{
|
||||
UPDATE_TO_VERSION_SCOPED( 147 )
|
||||
ADDED_ASSOCIATE("osg::BufferData")
|
||||
}
|
||||
ADD_USER_SERIALIZER(DECommands);
|
||||
}
|
||||
}
|
||||
namespace DrawArraysIndirectWrapper {
|
||||
|
||||
REGISTER_OBJECT_WRAPPER( DrawArraysIndirect,
|
||||
new osg::DrawArraysIndirect,
|
||||
osg::DrawArraysIndirect,
|
||||
"osg::Object osg::BufferData osg::PrimitiveSet osg::DrawArraysIndirect" )
|
||||
{
|
||||
ADD_OBJECT_SERIALIZER( IndirectCommandArray, osg::IndirectCommandDrawArrays ,new osg::DefaultIndirectCommandDrawArrays());
|
||||
ADD_UINT_SERIALIZER( FirstCommandToDraw, 0);
|
||||
ADD_INT_SERIALIZER( Stride, 0);
|
||||
}
|
||||
|
||||
}
|
||||
namespace MultiDrawArraysIndirectWrapper {
|
||||
|
||||
REGISTER_OBJECT_WRAPPER( MultiDrawArraysIndirect,
|
||||
new osg::MultiDrawArraysIndirect,
|
||||
osg::MultiDrawArraysIndirect,
|
||||
"osg::Object osg::BufferData osg::PrimitiveSet osg::DrawArraysIndirect osg::MultiDrawArraysIndirect" )
|
||||
{
|
||||
ADD_UINT_SERIALIZER( NumCommandsToDraw, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace DrawElementsIndirectWrapper {
|
||||
|
||||
REGISTER_OBJECT_WRAPPER( DrawElementsIndirect,
|
||||
0,
|
||||
osg::DrawElementsIndirect,
|
||||
"osg::Object osg::BufferData osg::PrimitiveSet osg::DrawElementsIndirect" )
|
||||
{
|
||||
ADD_OBJECT_SERIALIZER( IndirectCommandArray, osg::IndirectCommandDrawElements, new osg::DefaultIndirectCommandDrawElements());
|
||||
ADD_UINT_SERIALIZER( FirstCommandToDraw, 0);
|
||||
ADD_INT_SERIALIZER( Stride, 0);
|
||||
}
|
||||
|
||||
}
|
||||
#define INDIRECTDRAW_ELEMENTS_WRAPPER( DRAWELEMENTS, ELEMENTTYPE ) \
|
||||
namespace Wrapper##DRAWELEMENTS { \
|
||||
REGISTER_OBJECT_WRAPPER( DRAWELEMENTS, new osg::DRAWELEMENTS, osg::DRAWELEMENTS, "osg::Object osg::BufferData osg::PrimitiveSet osg::DrawElementsIndirect osg::"#DRAWELEMENTS) \
|
||||
{ \
|
||||
ADD_ISAVECTOR_SERIALIZER( vector, osgDB::BaseSerializer::ELEMENTTYPE, 4 ); \
|
||||
} \
|
||||
}\
|
||||
namespace WrapperMulti##DRAWELEMENTS { \
|
||||
REGISTER_OBJECT_WRAPPER( Multi##DRAWELEMENTS, new osg::Multi##DRAWELEMENTS, osg::Multi##DRAWELEMENTS, "osg::Object osg::BufferData osg::PrimitiveSet osg::DrawElementsIndirect osg::"#DRAWELEMENTS" osg::Multi"#DRAWELEMENTS) \
|
||||
{ \
|
||||
ADD_UINT_SERIALIZER( NumCommandsToDraw, 0);\
|
||||
} \
|
||||
}\
|
||||
|
||||
|
||||
INDIRECTDRAW_ELEMENTS_WRAPPER( DrawElementsIndirectUByte, RW_UCHAR )
|
||||
INDIRECTDRAW_ELEMENTS_WRAPPER( DrawElementsIndirectUShort, RW_USHORT )
|
||||
INDIRECTDRAW_ELEMENTS_WRAPPER( DrawElementsIndirectUInt, RW_UINT )
|
||||
|
||||
|
||||
Reference in New Issue
Block a user