be5f709bdb
creating subclasses of osg::Array that referenced data stored an application's internal data structures. I took a stab at implementing that and ran into a couple of downcasts in Geometry.cpp. Enclosed is my take at fixing those along with a simple example of how to do this."
247 lines
9.2 KiB
C++
247 lines
9.2 KiB
C++
/* OpenSceneGraph example, osgsharedarray.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <osg/Array>
|
|
#include <osg/Geode>
|
|
#include <osg/Geometry>
|
|
#include <osgViewer/Viewer>
|
|
|
|
/** This class is an example of how to create your own subclass of osg::Array. This
|
|
* is useful if your application has data in its own form of storage and you don't
|
|
* want to make another copy into one of the predefined osg::Array classes.
|
|
*
|
|
* @note This is not really intended to be a useful subclass of osg::Array. It
|
|
* doesn't do anything smart about memory management. It is simply intended as
|
|
* an example you can follow to create your own subclasses of osg::Array for
|
|
* your application's storage requirements.
|
|
*/
|
|
class MyArray : public osg::Array {
|
|
public:
|
|
/** Default ctor. Creates an empty array. */
|
|
MyArray() :
|
|
osg::Array(osg::Array::Vec3ArrayType,3,GL_FLOAT),
|
|
_numElements(0),
|
|
_ptr(NULL) {
|
|
}
|
|
|
|
/** "Normal" ctor.
|
|
*
|
|
* @param no The number of elements in the array.
|
|
* @param ptr Pointer to the data. This class just keeps that
|
|
* pointer. It doesn't manage the memory.
|
|
*/
|
|
MyArray(unsigned int no, osg::Vec3* ptr) :
|
|
osg::Array(osg::Array::Vec3ArrayType,3,GL_FLOAT),
|
|
_numElements(no),
|
|
_ptr(ptr) {
|
|
}
|
|
|
|
/** Copy ctor. */
|
|
MyArray(const MyArray& other, const osg::CopyOp& copyop) :
|
|
osg::Array(osg::Array::Vec3ArrayType,3,GL_FLOAT),
|
|
_numElements(other._numElements),
|
|
_ptr(other._ptr) {
|
|
}
|
|
|
|
/** What type of object would clone return? */
|
|
virtual Object* cloneType() const {
|
|
return new MyArray();
|
|
}
|
|
|
|
/** Create a copy of the object. */
|
|
virtual osg::Object* clone(const osg::CopyOp& copyop) const {
|
|
return new MyArray(*this,copyop);
|
|
}
|
|
|
|
/** Accept method for ArrayVisitors.
|
|
*
|
|
* @note This will end up in ArrayVisitor::apply(osg::Array&).
|
|
*/
|
|
virtual void accept(osg::ArrayVisitor& av) {
|
|
av.apply(*this);
|
|
}
|
|
|
|
/** Const accept method for ArrayVisitors.
|
|
*
|
|
* @note This will end up in ConstArrayVisitor::apply(const osg::Array&).
|
|
*/
|
|
virtual void accept(osg::ConstArrayVisitor& cav) const {
|
|
cav.apply(*this);
|
|
}
|
|
|
|
/** Accept method for ValueVisitors. */
|
|
virtual void accept(unsigned int index, osg::ValueVisitor& vv) {
|
|
vv.apply(_ptr[index]);
|
|
}
|
|
|
|
/** Const accept method for ValueVisitors. */
|
|
virtual void accept(unsigned int index, osg::ConstValueVisitor& cvv) const {
|
|
cvv.apply(_ptr[index]);
|
|
}
|
|
|
|
/** Compare method.
|
|
* Return -1 if lhs element is less than rhs element, 0 if equal,
|
|
* 1 if lhs element is greater than rhs element.
|
|
*/
|
|
virtual int compare(unsigned int lhs,unsigned int rhs) const {
|
|
const osg::Vec3& elem_lhs = _ptr[lhs];
|
|
const osg::Vec3& elem_rhs = _ptr[rhs];
|
|
if (elem_lhs<elem_rhs) return -1;
|
|
if (elem_rhs<elem_lhs) return 1;
|
|
return 0;
|
|
}
|
|
|
|
/** Returns a pointer to the first element of the array. */
|
|
virtual const GLvoid* getDataPointer() const {
|
|
return _ptr;
|
|
}
|
|
|
|
/** Returns the number of elements in the array. */
|
|
virtual unsigned int getNumElements() const {
|
|
return _numElements;
|
|
}
|
|
|
|
/** Returns the number of bytes of storage required to hold
|
|
* all of the elements of the array.
|
|
*/
|
|
virtual unsigned int getTotalDataSize() const {
|
|
return _numElements * sizeof(osg::Vec3);
|
|
}
|
|
|
|
private:
|
|
unsigned int _numElements;
|
|
osg::Vec3* _ptr;
|
|
};
|
|
|
|
/** The data values for the example. Simply defines a cube with
|
|
* per-face colors and normals.
|
|
*/
|
|
namespace {
|
|
|
|
static const osg::Vec3 myVertices[] = { osg::Vec3(-1.,-1.,-1.),
|
|
osg::Vec3( 1.,-1.,-1.),
|
|
osg::Vec3(-1., 1.,-1.),
|
|
osg::Vec3( 1., 1.,-1.),
|
|
osg::Vec3(-1.,-1., 1.),
|
|
osg::Vec3( 1.,-1., 1.),
|
|
osg::Vec3(-1., 1., 1.),
|
|
osg::Vec3( 1., 1., 1.)
|
|
};
|
|
|
|
static const osg::Vec3 myNormals[] = { osg::Vec3( 0., 0., 1.),
|
|
osg::Vec3( 1., 0., 0.),
|
|
osg::Vec3( 0., 0.,-1.),
|
|
osg::Vec3(-1., 0., 0.),
|
|
osg::Vec3( 0., 1., 0.),
|
|
osg::Vec3( 0.,-1., 0.)
|
|
};
|
|
|
|
static const osg::Vec4 myColors[] = { osg::Vec4( 1., 0., 0., 1.),
|
|
osg::Vec4( 0., 1., 0., 1.),
|
|
osg::Vec4( 1., 1., 0., 1.),
|
|
osg::Vec4( 0., 0., 1., 1.),
|
|
osg::Vec4( 1., 0., 1., 1.),
|
|
osg::Vec4( 0., 1., 1., 1.)
|
|
};
|
|
|
|
static const unsigned short myIndices[] = { 4, 5, 7, 6,
|
|
5, 1, 3, 7,
|
|
1, 0, 2, 3,
|
|
0, 4, 6, 2,
|
|
6, 7, 3, 2,
|
|
0, 1, 5, 4
|
|
};
|
|
}
|
|
|
|
/** Create a Geode that describes a cube using our own
|
|
* subclass of osg::Array for the vertices. It uses
|
|
* the "regular" array classes for all of the other
|
|
* arrays.
|
|
*
|
|
* Creating your own Array class isn't really very
|
|
* useful for a tiny amount of data like this. You
|
|
* could just go ahead and copy the data into one of
|
|
* the "regular" Array classes like this does for
|
|
* normals and colors. The point of creating your
|
|
* own subclass of Array is for use with datasets
|
|
* that are much larger than anything you could
|
|
* create a simple example from. In that case, you
|
|
* might not want to create a copy of the data in
|
|
* one of the Array classes that comes with OSG, but
|
|
* instead reuse the copy your application already
|
|
* has and wrap it up in a subclass of osg::Array
|
|
* that presents the right interface for use with
|
|
* OpenSceneGraph.
|
|
*
|
|
* Note that I'm only using the shared array for the
|
|
* vertices. You could do something similar for any
|
|
* of the Geometry node's data arrays.
|
|
*/
|
|
osg::Geode* createGeometry()
|
|
{
|
|
osg::Geode* geode = new osg::Geode();
|
|
|
|
// create Geometry
|
|
osg::ref_ptr<osg::Geometry> geom(new osg::Geometry());
|
|
|
|
// add vertices using MyArray class
|
|
unsigned int numVertices = sizeof(myVertices)/sizeof(myVertices[0]);
|
|
geom->setVertexArray(new MyArray(numVertices,const_cast<osg::Vec3*>(&myVertices[0])));
|
|
|
|
// add normals
|
|
unsigned int numNormals = sizeof(myNormals)/sizeof(myNormals[0]);
|
|
geom->setNormalArray(new osg::Vec3Array(numNormals,const_cast<osg::Vec3*>(&myNormals[0])));
|
|
geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
|
|
|
|
// add colors
|
|
unsigned int numColors = sizeof(myColors)/sizeof(myColors[0]);
|
|
osg::Vec4Array* normal_array = new osg::Vec4Array(numColors,const_cast<osg::Vec4*>(&myColors[0]));
|
|
geom->setColorArray(normal_array);
|
|
geom->setColorBinding(osg::Geometry::BIND_PER_PRIMITIVE);
|
|
|
|
// add PrimitiveSet
|
|
unsigned int numIndices = sizeof(myIndices)/sizeof(myIndices[0]);
|
|
geom->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::QUADS,
|
|
numIndices,
|
|
const_cast<unsigned short *>(myIndices)));
|
|
|
|
// Changing these flags will tickle different cases in
|
|
// Geometry::drawImplementation. They should all work fine
|
|
// with the shared array. Setting VertexIndices will hit
|
|
// some other cases.
|
|
geom->setUseVertexBufferObjects(false);
|
|
geom->setUseDisplayList(false);
|
|
geom->setFastPathHint(false);
|
|
|
|
geode->addDrawable( geom.get() );
|
|
|
|
return geode;
|
|
}
|
|
|
|
int main(int , char **)
|
|
{
|
|
// construct the viewer.
|
|
osgViewer::Viewer viewer;
|
|
|
|
// add model to viewer.
|
|
viewer.setSceneData( createGeometry() );
|
|
|
|
// create the windows and run the threads.
|
|
return viewer.run();
|
|
}
|