5d18f0ee11
and GLuint to get round compile issues under MacOSX.
721 lines
26 KiB
Plaintext
721 lines
26 KiB
Plaintext
//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield
|
|
//Distributed under the terms of the GNU Library General Public License (LGPL)
|
|
//as published by the Free Software Foundation.
|
|
|
|
#ifndef OSG_DRAWABLE
|
|
#define OSG_DRAWABLE 1
|
|
|
|
#include <osg/BoundingBox>
|
|
#include <osg/State>
|
|
#include <osg/Types>
|
|
#include <osg/Vec2>
|
|
#include <osg/NodeVisitor>
|
|
|
|
#include <vector>
|
|
#include <map>
|
|
#include <set>
|
|
|
|
namespace osg {
|
|
|
|
class Statistics;
|
|
class Vec2;
|
|
class Vec3;
|
|
class Vec4;
|
|
class Node;
|
|
|
|
// this is define to alter the way display lists are compiled inside the
|
|
// the draw method, it has been found that the NVidia drivers fail completely
|
|
// to optimize COMPILE_AND_EXECUTE in fact make it go slower than for no display
|
|
// lists, but optimize a seperate COMPILE very well?! Define it as default
|
|
// the use of a sperate COMPILE, then glCallList rather than use COMPILE_AND_EXECUTE.
|
|
|
|
#define USE_SEPERATE_COMPILE_AND_EXECUTE
|
|
|
|
/** Pure virtual base class for drawable Geometry. Contains no drawing primitives
|
|
directly, these are provided by subclasses such as osg::Geometry. State attributes
|
|
for a Drawable are maintained in StateSet which the Drawable maintains
|
|
a referenced counted pointer to. Both Drawable's and StateSet's can
|
|
be shared for optimal memory usage and graphics performance.
|
|
|
|
Subclasses should provide an instance of getStats(Statistics *st) if the subclass
|
|
contains drawing primitives. This member function should add the primitives it
|
|
draws into the Statistics class; for example add the number of quads, triangles etc
|
|
created. For an example see Geometry.cpp:
|
|
getStats(osgUtil::Statistics *stat).
|
|
Failure to implement this routine will only result in the stats displayed for
|
|
your drawable being wrong.
|
|
Another example is in the InfinitePlane class- this draws a normal geoset AND
|
|
its own special set of quads, so this case of getPrims calls:
|
|
the normal geoset stats gs->getStats(..), and then adds the number of quads
|
|
rendered directly (it is rendered in a display list, but we do know how many
|
|
quads are in the display list).
|
|
*/
|
|
class SG_EXPORT Drawable : public Object
|
|
{
|
|
public:
|
|
|
|
Drawable();
|
|
|
|
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
|
|
Drawable(const Drawable& drawable,const CopyOp& copyop=CopyOp::SHALLOW_COPY);
|
|
|
|
virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const Drawable*>(obj)!=NULL; }
|
|
virtual const char* libraryName() const { return "osg"; }
|
|
virtual const char* className() const { return "Drawable"; }
|
|
|
|
|
|
/** A vector of osg::Node pointers which is used to store the parent(s) of drawable.*/
|
|
typedef std::vector<Node*> ParentList;
|
|
|
|
/** Get the parent list of drawable. */
|
|
inline const ParentList& getParents() const { return _parents; }
|
|
|
|
/** Get the a copy of parent list of node. A copy is returned to
|
|
* prevent modification of the parent list.*/
|
|
inline ParentList getParents() { return _parents; }
|
|
|
|
/** Get a single parent of Drawable.
|
|
* @param i index of the parent to get.
|
|
* @return the parent i.
|
|
*/
|
|
inline Node* getParent(const unsigned int i) { return _parents[i]; }
|
|
/** Get a single const parent of Drawable.
|
|
* @param i index of the parent to get.
|
|
* @return the parent i.
|
|
*/
|
|
inline const Node* getParent(const unsigned int i) const { return _parents[i]; }
|
|
|
|
/**
|
|
* Get the number of parents of node.
|
|
* @return the number of parents of this node.
|
|
*/
|
|
inline const unsigned int getNumParents() const { return _parents.size(); }
|
|
|
|
|
|
|
|
/** Set the StateSet attached to the Drawable.
|
|
Previously attached StateSet are automatically unreferenced on
|
|
assignment of a new drawstate.*/
|
|
inline void setStateSet(StateSet *state) { _dstate = state; }
|
|
|
|
/** Get the attached StateSet.*/
|
|
inline StateSet* getStateSet() { return _dstate.get();}
|
|
|
|
/** Get the attached const StateSet.*/
|
|
inline const StateSet* getStateSet() const { return _dstate.get();}
|
|
|
|
|
|
/** Set the drawable to it can or cannot be used in conjunction with OpenGL
|
|
* display lists. With set to true, calls to Drawable::setUseDisplayList,
|
|
* whereas when set to false, no display lists can be created and calls
|
|
* to setUseDisplayList are ignored, and a warning is produced. The later
|
|
* is typically used to guard against the switching on of display lists
|
|
* on objects with dynamic internal data such as continuous Level of Detail
|
|
* algorithms.*/
|
|
void setSupportsDisplayList(const bool flag);
|
|
|
|
/** Get whether display lists are supported for this drawable instance.*/
|
|
inline const bool getSupportsDisplayList() const { return _supportsDisplayList; }
|
|
|
|
|
|
/** When set to true, force the draw method to use OpenGL Display List for rendering.
|
|
If false rendering directly. If the display list has not been already
|
|
compile the next call to draw will automatically create the display list.*/
|
|
void setUseDisplayList(const bool flag);
|
|
|
|
/** Return whether OpenGL display lists are being used for rendering.*/
|
|
inline const bool getUseDisplayList() const { return _useDisplayList; }
|
|
|
|
/** Force a recompile on next draw() of any OpenGL display list associated with this geoset.*/
|
|
void dirtyDisplayList();
|
|
|
|
|
|
/** Dirty the bounding box, forcing a computeBound() on the next call
|
|
* to getBound(). Should be called in the internal geometry of the Drawable
|
|
* is modified.*/
|
|
void dirtyBound();
|
|
|
|
/** get bounding box of geoset.
|
|
* Note, now made virtual to make it possible to implement user-drawn
|
|
* objects albeit so what crudely, to be improved later.
|
|
*/
|
|
inline const BoundingBox& getBound() const
|
|
{
|
|
if( !_bbox_computed)
|
|
computeBound();
|
|
return _bbox;
|
|
}
|
|
|
|
/** draw OpenGL primitives.
|
|
* If the drawable has _useDisplayList set to true then use an OpenGL display
|
|
* list, automatically compiling one if required.
|
|
* Otherwise call drawImmediateMode().
|
|
* Note, draw method should *not* be overridden in subclasses as it
|
|
* manages the optional display list.
|
|
*/
|
|
inline void draw(State& state);
|
|
|
|
/** Immediately compile this drawable into an OpenGL Display List.
|
|
Note I, operation is ignored if _useDisplayList to false.
|
|
Note II, compile is not intended to be overridden in subclasses.*/
|
|
void compile(State& state);
|
|
|
|
|
|
struct AppCallback : public osg::Referenced
|
|
{
|
|
/** do customized app code.*/
|
|
virtual void app(osg::NodeVisitor *visitor, osg::Drawable* drawable) = 0;
|
|
};
|
|
|
|
/** Set the AppCallback which allows users to attach customize the undating of an object during the app traversal.*/
|
|
void setAppCallback(AppCallback* ac);
|
|
|
|
/** Get the non const AppCallback.*/
|
|
AppCallback* getAppCallback() { return _appCallback.get(); }
|
|
|
|
/** Get the const AppCallback.*/
|
|
const AppCallback* getAppCallback() const { return _appCallback.get(); }
|
|
|
|
|
|
struct CullCallback : public osg::Referenced
|
|
{
|
|
/** do customized cull code.*/
|
|
virtual bool cull(osg::NodeVisitor *visitor, osg::Drawable* drawable, osg::State *state=NULL) const = 0;
|
|
};
|
|
|
|
/** Set the CullCallback which allows users to attach customize the culling of Drawable during the cull traversal.*/
|
|
void setCullCallback(CullCallback* cc) { _cullCallback=cc; }
|
|
|
|
/** Get the non const CullCallback.*/
|
|
CullCallback* getCullCallback() { return _cullCallback.get(); }
|
|
|
|
/** Get the const CullCallback.*/
|
|
const CullCallback* getCullCallback() const { return _cullCallback.get(); }
|
|
|
|
|
|
/** Callback attached to an Drawable which allows the users to customize the drawing of an exist Drawable object.
|
|
* The draw callback is implement as a replacement to the Drawable's own drawImmediateMode() method, if the
|
|
* the user intends to decorate the exist draw code then simple call the drawable->drawImmediateMode() from
|
|
* with the callbacks drawImmediateMode() method. This allows the users to do both pre and post callbacks
|
|
* without fuss and can even diable the inner draw in required.*/
|
|
struct DrawCallback : public osg::Referenced
|
|
{
|
|
/** do customized draw code.*/
|
|
virtual void drawImmediateMode(State& state,osg::Drawable* drawable) const = 0;
|
|
};
|
|
|
|
/** Set the DrawCallback which allows users to attach customize the drawing of existing Drawable object.*/
|
|
void setDrawCallback(DrawCallback* dc) { _drawCallback=dc; dirtyDisplayList(); }
|
|
|
|
/** Get the non const DrawCallback.*/
|
|
DrawCallback* getDrawCallback() { return _drawCallback.get(); }
|
|
|
|
/** Get the const DrawCallback.*/
|
|
const DrawCallback* getDrawCallback() const { return _drawCallback.get(); }
|
|
|
|
|
|
/** draw directly ignoring an OpenGL display list which could be attached.
|
|
* This is the internal draw method which does the drawing itself,
|
|
* and is the method to override when deriving from Drawable.
|
|
*/
|
|
virtual void drawImmediateMode(State& state) = 0;
|
|
|
|
|
|
|
|
/** use deleteDisplayList instead of glDeleteList to allow
|
|
* OpenGL display list to cached until they can be deleted
|
|
* by the OpenGL context in which they were created, specified
|
|
* by contextID.*/
|
|
static void deleteDisplayList(uint contextID,uint globj);
|
|
|
|
/** flush all the cached display list which need to be deleted
|
|
* in the OpenGL context related to contextID.*/
|
|
static void flushDeletedDisplayLists(uint contextID);
|
|
|
|
|
|
/** Collect Stistics count from Drawable.*/
|
|
virtual bool getStats(Statistics&) { return false; }
|
|
|
|
|
|
typedef uint AttributeBitMask;
|
|
|
|
enum AttributeBitMaskValues
|
|
{
|
|
COORDS = 0x1,
|
|
NORMALS = 0x2,
|
|
COLORS = 0x4,
|
|
TEXTURE_COORDS = 0x8,
|
|
TEXTURE_COORDS_0 = TEXTURE_COORDS,
|
|
TEXTURE_COORDS_1 = 0x10,
|
|
TEXTURE_COORDS_2 = 0x20,
|
|
TEXTURE_COORDS_3 = 0x40
|
|
};
|
|
|
|
class AttributeFunctor
|
|
{
|
|
public:
|
|
|
|
AttributeFunctor(AttributeBitMask abm):_abm(abm) {}
|
|
virtual ~AttributeFunctor() {}
|
|
|
|
void setAttributeBitMask(AttributeBitMask abm) { _abm=abm; }
|
|
AttributeBitMask getAttributeBitMask() const { return _abm; }
|
|
|
|
virtual bool apply(AttributeBitMask,Vec2*,Vec2*) { return false; }
|
|
virtual bool apply(AttributeBitMask,Vec3*,Vec3*) { return false; }
|
|
virtual bool apply(AttributeBitMask,Vec4*,Vec4*) { return false; }
|
|
|
|
protected:
|
|
|
|
AttributeBitMask _abm;
|
|
};
|
|
|
|
/** return the attributes supported by applyAttrbuteOperation() as an AttributeBitMask.*/
|
|
virtual AttributeBitMask suppportsAttributeOperation() const { return (AttributeBitMask)0; }
|
|
|
|
/** return the attributes successully applied in applyAttributeUpdate.*/
|
|
virtual AttributeBitMask applyAttributeOperation(AttributeFunctor&) { return 0; }
|
|
|
|
|
|
class PrimitiveFunctor
|
|
{
|
|
public:
|
|
|
|
virtual void setVertexArray(unsigned int count,Vec3* vertices) = 0;
|
|
|
|
virtual void drawArrays(GLenum mode,GLint first,GLsizei count) = 0;
|
|
virtual void drawElements(GLenum mode,GLsizei count,GLubyte* indices) = 0;
|
|
virtual void drawElements(GLenum mode,GLsizei count,GLushort* indices) = 0;
|
|
virtual void drawElements(GLenum mode,GLsizei count,GLuint* indices) = 0;
|
|
|
|
virtual void begin(GLenum mode) = 0;
|
|
virtual void vertex(const Vec3& vert) = 0;
|
|
virtual void vertex(float x,float y,float z) = 0;
|
|
virtual void end() = 0;
|
|
|
|
};
|
|
|
|
/** apply the internal geometry as basic primitives to a PrimitiveFunctor.*/
|
|
virtual void applyPrimitiveOperation(PrimitiveFunctor&) {}
|
|
|
|
|
|
protected:
|
|
|
|
Drawable& operator = (const Drawable&) { return *this;}
|
|
|
|
virtual ~Drawable();
|
|
|
|
/** compute the bounding box of the drawable. Method must be
|
|
implemented by subclasses.*/
|
|
virtual const bool computeBound() const = 0;
|
|
|
|
void addParent(osg::Node* node);
|
|
void removeParent(osg::Node* node);
|
|
|
|
ParentList _parents;
|
|
friend class Node;
|
|
friend class Geode;
|
|
|
|
ref_ptr<StateSet> _dstate;
|
|
|
|
bool _supportsDisplayList;
|
|
bool _useDisplayList;
|
|
|
|
typedef std::vector<uint> GLObjectList;
|
|
mutable GLObjectList _globjList;
|
|
|
|
mutable BoundingBox _bbox;
|
|
mutable bool _bbox_computed;
|
|
|
|
ref_ptr<AppCallback> _appCallback;
|
|
ref_ptr<DrawCallback> _drawCallback;
|
|
ref_ptr<CullCallback> _cullCallback;
|
|
|
|
// static cache of deleted display lists which can only
|
|
// by completely deleted once the appropriate OpenGL context
|
|
// is set.
|
|
typedef std::map<uint,std::set<uint> > DeletedDisplayListCache;
|
|
static DeletedDisplayListCache s_deletedDisplayListCache;
|
|
|
|
};
|
|
|
|
inline void Drawable::draw(State& state)
|
|
{
|
|
if (_useDisplayList)
|
|
{
|
|
|
|
// get the contextID (user defined ID of 0 upwards) for the
|
|
// current OpenGL context.
|
|
uint contextID = state.getContextID();
|
|
|
|
// fill in array if required.
|
|
while (_globjList.size()<=contextID) _globjList.push_back(0);
|
|
|
|
// get the globj for the current contextID.
|
|
uint& globj = _globjList[contextID];
|
|
|
|
// call the globj if already set otherwise compile and execute.
|
|
if( globj != 0 )
|
|
{
|
|
glCallList( globj );
|
|
}
|
|
else if (_useDisplayList)
|
|
{
|
|
#ifdef USE_SEPERATE_COMPILE_AND_EXECUTE
|
|
globj = glGenLists( 1 );
|
|
glNewList( globj, GL_COMPILE );
|
|
if (_drawCallback.valid())
|
|
_drawCallback->drawImmediateMode(state,this);
|
|
else
|
|
drawImmediateMode(state);
|
|
glEndList();
|
|
|
|
glCallList( globj);
|
|
#else
|
|
globj = glGenLists( 1 );
|
|
glNewList( globj, GL_COMPILE_AND_EXECUTE );
|
|
if (_drawCallback.valid())
|
|
_drawCallback->drawImmediateMode(state,this);
|
|
else
|
|
drawImmediateMode(state);
|
|
glEndList();
|
|
#endif
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// draw object as nature intended..
|
|
if (_drawCallback.valid())
|
|
_drawCallback->drawImmediateMode(state,this);
|
|
else
|
|
drawImmediateMode(state);
|
|
}
|
|
};
|
|
|
|
template<class T>
|
|
class TriangleFunctor : public Drawable::PrimitiveFunctor, public T
|
|
{
|
|
public:
|
|
|
|
TriangleFunctor()
|
|
{
|
|
_vertexArraySize=0;
|
|
_vertexArrayPtr=0;
|
|
_modeCache=0;
|
|
}
|
|
|
|
virtual ~TriangleFunctor() {}
|
|
|
|
virtual void setVertexArray(unsigned int count,Vec3* vertices)
|
|
{
|
|
_vertexArraySize = count;
|
|
_vertexArrayPtr = vertices;
|
|
}
|
|
|
|
virtual void drawArrays(GLenum mode,GLint first,GLsizei count)
|
|
{
|
|
if (_vertexArrayPtr==0 && count==0) return;
|
|
|
|
switch(mode)
|
|
{
|
|
case(GL_TRIANGLES):
|
|
{
|
|
Vec3* vlast = &_vertexArrayPtr[first+count];
|
|
for(Vec3* vptr=&_vertexArrayPtr[first];vptr<vlast;vptr+=3)
|
|
operator()(*(vptr),*(vptr+1),*(vptr+2));
|
|
break;
|
|
}
|
|
case(GL_TRIANGLE_STRIP):
|
|
{
|
|
Vec3* vptr = &_vertexArrayPtr[first];
|
|
for(GLsizei i=2;i<count;++i,++vptr)
|
|
{
|
|
if ((i%2)) operator()(*(vptr),*(vptr+2),*(vptr+1));
|
|
else operator()(*(vptr),*(vptr+1),*(vptr+2));
|
|
}
|
|
break;
|
|
}
|
|
case(GL_QUADS):
|
|
{
|
|
Vec3* vptr = &_vertexArrayPtr[first];
|
|
for(GLsizei i=3;i<count;i+=4,vptr+=4)
|
|
{
|
|
operator()(*(vptr),*(vptr+1),*(vptr+2));
|
|
operator()(*(vptr),*(vptr+2),*(vptr+3));
|
|
}
|
|
break;
|
|
}
|
|
case(GL_QUAD_STRIP):
|
|
{
|
|
Vec3* vptr = &_vertexArrayPtr[first];
|
|
for(GLsizei i=3;i<count;i+=2,vptr+=2)
|
|
{
|
|
operator()(*(vptr),*(vptr+1),*(vptr+2));
|
|
operator()(*(vptr+1),*(vptr+3),*(vptr+2));
|
|
}
|
|
break;
|
|
}
|
|
case(GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN
|
|
case(GL_TRIANGLE_FAN):
|
|
{
|
|
Vec3* vfirst = &_vertexArrayPtr[first];
|
|
Vec3* vptr = vfirst+1;
|
|
for(GLsizei i=2;i<count;++i,++vptr)
|
|
{
|
|
operator()(*(vfirst),*(vptr),*(vptr+1));
|
|
}
|
|
break;
|
|
}
|
|
case(GL_POINTS):
|
|
case(GL_LINES):
|
|
case(GL_LINE_STRIP):
|
|
case(GL_LINE_LOOP):
|
|
default:
|
|
// can't be converted into to triangles.
|
|
break;
|
|
}
|
|
}
|
|
|
|
virtual void drawElements(GLenum mode,GLsizei count,GLubyte* indices)
|
|
{
|
|
if (indices==0 || count==0) return;
|
|
|
|
typedef GLubyte* IndexPointer;
|
|
|
|
switch(mode)
|
|
{
|
|
case(GL_TRIANGLES):
|
|
{
|
|
IndexPointer ilast = &indices[count];
|
|
for(IndexPointer iptr=indices;iptr<ilast;iptr+=3)
|
|
operator()(_vertexArrayPtr[*iptr],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)]);
|
|
break;
|
|
}
|
|
case(GL_TRIANGLE_STRIP):
|
|
{
|
|
IndexPointer iptr = indices;
|
|
for(GLsizei i=2;i<count;++i,++iptr)
|
|
{
|
|
if ((i%2)) operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+2)],_vertexArrayPtr[*(iptr+1)]);
|
|
else operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)]);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_QUADS):
|
|
{
|
|
IndexPointer iptr = indices;
|
|
for(GLsizei i=3;i<count;i+=4,iptr+=4)
|
|
{
|
|
operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)]);
|
|
operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+2)],_vertexArrayPtr[*(iptr+3)]);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_QUAD_STRIP):
|
|
{
|
|
IndexPointer iptr = indices;
|
|
for(GLsizei i=3;i<count;i+=2,iptr+=2)
|
|
{
|
|
operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)]);
|
|
operator()(_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+3)],_vertexArrayPtr[*(iptr+2)]);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN
|
|
case(GL_TRIANGLE_FAN):
|
|
{
|
|
IndexPointer iptr = indices;
|
|
Vec3& vfirst = _vertexArrayPtr[*iptr];
|
|
++iptr;
|
|
for(GLsizei i=2;i<count;++i,++iptr)
|
|
{
|
|
operator()(vfirst,_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)]);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_POINTS):
|
|
case(GL_LINES):
|
|
case(GL_LINE_STRIP):
|
|
case(GL_LINE_LOOP):
|
|
default:
|
|
// can't be converted into to triangles.
|
|
break;
|
|
}
|
|
}
|
|
|
|
virtual void drawElements(GLenum mode,GLsizei count,GLushort* indices)
|
|
{
|
|
if (indices==0 || count==0) return;
|
|
|
|
typedef GLushort* IndexPointer;
|
|
|
|
switch(mode)
|
|
{
|
|
case(GL_TRIANGLES):
|
|
{
|
|
IndexPointer ilast = &indices[count];
|
|
for(IndexPointer iptr=indices;iptr<ilast;iptr+=3)
|
|
{
|
|
operator()(_vertexArrayPtr[*iptr],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)]);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_TRIANGLE_STRIP):
|
|
{
|
|
IndexPointer iptr = indices;
|
|
for(GLsizei i=2;i<count;++i,++iptr)
|
|
{
|
|
if ((i%2)) operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+2)],_vertexArrayPtr[*(iptr+1)]);
|
|
else operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)]);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_QUADS):
|
|
{
|
|
IndexPointer iptr = indices;
|
|
for(GLsizei i=3;i<count;i+=4,iptr+=4)
|
|
{
|
|
operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)]);
|
|
operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+2)],_vertexArrayPtr[*(iptr+3)]);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_QUAD_STRIP):
|
|
{
|
|
IndexPointer iptr = indices;
|
|
for(GLsizei i=3;i<count;i+=2,iptr+=2)
|
|
{
|
|
operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)]);
|
|
operator()(_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+3)],_vertexArrayPtr[*(iptr+2)]);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN
|
|
case(GL_TRIANGLE_FAN):
|
|
{
|
|
IndexPointer iptr = indices;
|
|
Vec3& vfirst = _vertexArrayPtr[*iptr];
|
|
++iptr;
|
|
for(GLsizei i=2;i<count;++i,++iptr)
|
|
{
|
|
operator()(vfirst,_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)]);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_POINTS):
|
|
case(GL_LINES):
|
|
case(GL_LINE_STRIP):
|
|
case(GL_LINE_LOOP):
|
|
default:
|
|
// can't be converted into to triangles.
|
|
break;
|
|
}
|
|
}
|
|
|
|
virtual void drawElements(GLenum mode,GLsizei count,GLuint* indices)
|
|
{
|
|
if (indices==0 || count==0) return;
|
|
|
|
typedef GLuint* IndexPointer;
|
|
|
|
switch(mode)
|
|
{
|
|
case(GL_TRIANGLES):
|
|
{
|
|
IndexPointer ilast = &indices[count];
|
|
for(IndexPointer iptr=indices;iptr<ilast;iptr+=3)
|
|
operator()(_vertexArrayPtr[*iptr],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)]);
|
|
break;
|
|
}
|
|
case(GL_TRIANGLE_STRIP):
|
|
{
|
|
IndexPointer iptr = indices;
|
|
for(GLsizei i=2;i<count;++i,++iptr)
|
|
{
|
|
if ((i%2)) operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+2)],_vertexArrayPtr[*(iptr+1)]);
|
|
else operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)]);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_QUADS):
|
|
{
|
|
IndexPointer iptr = indices;
|
|
for(GLsizei i=3;i<count;i+=4,iptr+=4)
|
|
{
|
|
operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)]);
|
|
operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+2)],_vertexArrayPtr[*(iptr+3)]);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_QUAD_STRIP):
|
|
{
|
|
IndexPointer iptr = indices;
|
|
for(GLsizei i=3;i<count;i+=2,iptr+=2)
|
|
{
|
|
operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)]);
|
|
operator()(_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+3)],_vertexArrayPtr[*(iptr+2)]);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN
|
|
case(GL_TRIANGLE_FAN):
|
|
{
|
|
IndexPointer iptr = indices;
|
|
Vec3& vfirst = _vertexArrayPtr[*iptr];
|
|
++iptr;
|
|
for(GLsizei i=2;i<count;++i,++iptr)
|
|
{
|
|
operator()(vfirst,_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)]);
|
|
}
|
|
break;
|
|
}
|
|
case(GL_POINTS):
|
|
case(GL_LINES):
|
|
case(GL_LINE_STRIP):
|
|
case(GL_LINE_LOOP):
|
|
default:
|
|
// can't be converted into to triangles.
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/** begin(..),vertex(..) & end() are convinience methods for adapting
|
|
* non vertex array primitives to vertex array based primitives.
|
|
* this is done to simplify the implementation of primtive functor
|
|
* subclasses - users only need override drawArray and drawElements.*/
|
|
inline void begin(GLenum mode)
|
|
{
|
|
_modeCache = mode;
|
|
_vertexCache.clear();
|
|
}
|
|
|
|
inline void vertex(const Vec3& vert) { _vertexCache.push_back(vert); }
|
|
inline void vertex(float x,float y,float z) { _vertexCache.push_back(osg::Vec3(x,y,z)); }
|
|
inline void end()
|
|
{
|
|
if (!_vertexCache.empty())
|
|
{
|
|
setVertexArray(_vertexCache.size(),&_vertexCache.front());
|
|
drawArrays(_modeCache,0,_vertexCache.size());
|
|
}
|
|
}
|
|
|
|
protected:
|
|
|
|
|
|
unsigned int _vertexArraySize;
|
|
Vec3* _vertexArrayPtr;
|
|
|
|
GLenum _modeCache;
|
|
std::vector<Vec3> _vertexCache;
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
#endif
|