OpenSceneGraph/include/osg/GeoSet
Robert Osfield 1e4a0cadf5 Changed the naming and calling convention of the new Drawable::AttributeFunctor
and have updated GeoSet to use mutable values for the _numverts etc, allowing
osg::GeoSet::computeNumVerts() to be a const operation. osg::GeoSet::getNumVerts
is now a const once more, so avoiding compilation problems.  Also chaned the new
osgconv orientation code to use a Drawable::AttributeFunctor so it can work on
other Drawables other than just GeoSets.
2001-10-13 11:16:10 +00:00

652 lines
25 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_GEOSET
#define OSG_GEOSET 1
#include <osg/Vec2>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Drawable>
namespace osg {
/** Encapsulates OpenGL drawing primitives, geometry and
optional binding of normal, color and texture coordinates. Used
for representing the visible objects in the scene. State attributes
for a GeoSet are maintained in StateSet which the GeoSet maintains
a referenced counted pointer to. Both GeoSet's and StateSet's can
be shared for optimal memory usage and graphics performance.
*/
class SG_EXPORT GeoSet : public Drawable
{
public:
enum PrimitiveType {
NO_TYPE,
POINTS,
LINES,
LINE_STRIP,
FLAT_LINE_STRIP,
LINE_LOOP,
TRIANGLES,
TRIANGLE_STRIP,
FLAT_TRIANGLE_STRIP,
TRIANGLE_FAN,
FLAT_TRIANGLE_FAN,
QUADS,
QUAD_STRIP,
POLYGON
};
enum BindingType {
BIND_OFF,
BIND_OVERALL,
BIND_PERPRIM,
BIND_PERVERTEX,
BIND_DEFAULT
};
enum InterleaveArrayType {
IA_OFF,
IA_V2F,
IA_V3F,
IA_C4UB_V2F,
IA_C4UB_V3F,
IA_C3F_V3F,
IA_N3F_V3F,
IA_C4F_N3F_V3F,
IA_T2F_V3F,
IA_T4F_V4F,
IA_T2F_C4UB_V3F,
IA_T2F_C3F_V3F,
IA_T2F_N3F_V3F,
IA_T2F_C4F_N3F_V3F,
IA_T4F_C4F_N3F_V4F
};
struct IndexPointer
{
mutable uint _size;
bool _is_ushort;
union
{
ushort* _ushort;
uint* _uint;
} _ptr;
IndexPointer() { _size=0;_is_ushort=true;_ptr._ushort = (ushort*)0; }
inline const bool operator == (const IndexPointer& ip) const
{
return _size == ip._size &&
_is_ushort == ip._is_ushort &&
_ptr._ushort == ip._ptr._ushort;
}
inline const bool valid() const
{
return _ptr._ushort != (ushort*)0;
}
inline const bool null() const
{
return _ptr._ushort == (ushort*)0;
}
inline void setToNull()
{
_size = 0;
_is_ushort = true;
_ptr._ushort = (ushort*)0;
}
inline void set(uint size,ushort* data)
{
_size = size;
_is_ushort = true;
_ptr._ushort = data;
}
void set(const uint size,uint* data)
{
_size = size;
_is_ushort = false;
_ptr._uint = data;
}
inline const uint maxIndex() const
{
uint max = 0;
if (_is_ushort)
{
for(uint ai = 0; ai < _size; ai++ )
if( _ptr._ushort[ai] > max ) max = _ptr._ushort[ai];
}
else
{
for(uint ai = 0; ai < _size; ai++ )
if( _ptr._uint[ai] > max ) max = _ptr._uint[ai];
}
return max;
}
inline const uint operator [] (const uint pos) const
{
if (_is_ushort) return _ptr._ushort[pos];
else return _ptr._uint[pos];
}
};
GeoSet();
virtual Object* clone() const { return new GeoSet(); }
virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const GeoSet*>(obj)!=NULL; }
virtual const char* className() const { return "GeoSet"; }
// data access methods.
inline void setNumPrims( const int n ) { _numprims = n; }
inline const int getNumPrims() const { return _numprims; }
void setPrimType( const PrimitiveType type );
inline const PrimitiveType getPrimType() const { return _primtype; }
inline void setPrimLengths( int *lens ) { _primLengths = lens; }
inline int *getPrimLengths() { return _primLengths; }
inline const int *getPrimLengths() const { return _primLengths; }
void computeNumVerts() const;
/** get the number of coords required by the defined primitives. */
// inline const int getNumCoords() const
inline const int getNumCoords() const
{ if( _numcoords == 0 ) computeNumVerts(); return _numcoords; }
/** get a pointer to Vec3 coord array. */
inline Vec3* getCoords() { return _coords; }
/** get a const pointer to Vec3 coord array. */
inline const Vec3* getCoords() const { return _coords; }
/** get the number of indices required by the defined primitives. */
inline const int getNumCoordIndices() const { return _cindex._size; }
/** get the coord index array. */
inline IndexPointer& getCoordIndices() { return _cindex; }
/** get the const coord index array. */
inline const IndexPointer& getCoordIndices() const { return _cindex; }
/** set the coords (i.e the geometry) of the geoset.*/
void setCoords( Vec3 *cp );
/** set the coords (i.e the geometry) and ushort indices of the geoset.
To reduce memory footprint and bandwidth for small datasets it is
recommended the ushort indices are used instead of unit indices.*/
void setCoords( Vec3 *cp, ushort *ci );
/** set the coords (i.e the geometry) and uint indices of the geoset.
Unless your data set exceeds 65536 indices prefer ushort indices
over uint indices, only use this unit indices version if necessary.*/
void setCoords( Vec3 *cp, uint *ci );
/** set the coords (i.e the geometry) and indices of the geoset.*/
void setCoords( Vec3 *cp, IndexPointer& ip );
/** get the number of normals required by the defined primitives and normals binding.*/
inline const int getNumNormals() const { return _numnormals; }
/** get a pointer to Vec3 normal array. */
inline Vec3* getNormals() { return _normals; }
/** get a const pointer to Vec3 normal array. */
inline const Vec3* getNormals() const { return _normals; }
/** get the number of normal indices required by the defined primitives and normals binding.*/
inline int getNumNormalIndices() const { return _nindex._size; }
/** get the normal index array. */
inline IndexPointer& getNormalIndices() { return _nindex; }
/** get the const normal index array. */
inline const IndexPointer& getNormalIndices() const { return _nindex; }
/** set the normals of the geoset.*/
void setNormals( Vec3 *np );
/** set the normals and normal indices of the geoset.*/
void setNormals( Vec3 *np, ushort *ni );
/** set the normals and normal indices of the geoset.*/
void setNormals( Vec3 *np, uint *ni );
/** set the normals and normal indices of the geoset.*/
void setNormals( Vec3 *np, IndexPointer& ip );
/** set the normals binding to the vertices/primitives/overall.*/
void setNormalBinding( const BindingType binding );
inline const BindingType getNormalBinding() const { return _normal_binding; }
/** get the number of colors required by the defined primitives and color binding.*/
inline const int getNumColors() const { return _numcolors; }
/** get a pointer to Vec4 color array. */
inline Vec4* getColors() { return _colors; }
/** get a pointer to Vec4 color array. */
inline const Vec4* getColors() const { return _colors; }
/** get the number of colors indices required by the defined primitives and color binding.*/
inline int getNumColorIndices() const { return _colindex._size; }
/** get the color index array. */
inline IndexPointer& getColorIndices() { return _colindex; }
/** get the const color index array. */
inline const IndexPointer& getColorIndices() const { return _colindex; }
/** set the colors of the geoset.*/
void setColors( Vec4 *cp );
/** set the colors and color indices of the geoset.*/
void setColors( Vec4 *cp, ushort *li );
/** set the colors and color indices of the geoset.*/
void setColors( Vec4 *cp, uint *li );
/** set the colors and color indices of the geoset.*/
void setColors( Vec4 *cp, IndexPointer& ip );
/** set the color binding to the vertices/primitives/overall.*/
void setColorBinding( BindingType binding );
inline BindingType getColorBinding() const { return _color_binding; }
/** get the number of texture coords required by the defined primitives and textures binding.*/
inline const int getNumTextureCoords() const { return _numtcoords; }
/** get a pointer to Vec4 color array. */
inline Vec2* getTextureCoords() { return _tcoords; }
/** get a pointer to Vec4 color array. */
inline const Vec2* getTextureCoords() const { return _tcoords; }
/** get the number of texture coord indices required by the defined primitives and texture binding.*/
inline const int getNumTextureIndices() const { return _tindex._size; }
/** get the texture index array. */
inline IndexPointer& getTextureIndices() { return _tindex; }
/** get the texture index array. */
inline const IndexPointer& getTextureIndices() const { return _tindex; }
/** set the texture coords of the geoset.*/
void setTextureCoords( Vec2 *tc );
/** set the texture coords and texture coord indices of the geoset.*/
void setTextureCoords( Vec2 *tc, ushort *ti );
/** set the texture coords and texture coord indices of the geoset.*/
void setTextureCoords( Vec2 *tc, uint *ti );
/** set the texture coords and texture indices of the geoset.*/
void setTextureCoords( Vec2 *tc, IndexPointer& ip );
/** set the texture coord binding to the vertices/primitives/overall.*/
void setTextureBinding( const BindingType binding );
inline const BindingType getTextureBinding() const { return _texture_binding; }
/** get the number of texture coords required by the defined primitives and textures binding.*/
inline const int getNumInterleavedCoords() const { return _numcoords; }
/** get a pointer to interleaved float array. */
inline void* getInterleavedArray() { return _iarray; }
/** get a const pointer to interleaved float array. */
inline const void* getInterleavedArray() const { return _iarray; }
/** get the number of texture coord indices required by the defined primitives and texture binding.*/
inline const int getNumInterleavedIndices() const { return _iaindex._size; }
/** get the texture index array. */
inline IndexPointer& getInterleavedIndices() { return _iaindex; }
/** get the interleaved index array. */
inline const IndexPointer& getInterleavedIndices() const { return _iaindex; }
/** get the interleaved array storage format. */
inline const InterleaveArrayType getInterleavedFromat() const { return _iaformat; }
/** set the interleaved arrays of the geoset.*/
void setInterleavedArray( const InterleaveArrayType format, float *ia );
void setInterleavedArray( const InterleaveArrayType format, float *ia, ushort *iai );
void setInterleavedArray( const InterleaveArrayType format, float *ia, uint *iai );
void setInterleavedArray( const InterleaveArrayType format, float *ia, IndexPointer& iai );
/** draw geoset 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 GeoSet for user-drawn objects.
*/
virtual void drawImmediateMode(State& state);
const bool check() const;
/** return the attributes supported by applyAttrbuteUpdate() as an AttributeBitMask.*/
virtual AttributeBitMask suppportsAttributeOperation() const;
/** return the attributes successully applied in applyAttributeUpdate.*/
virtual AttributeBitMask applyAttributeOperation(AttributeFunctor& auf);
protected:
GeoSet(const GeoSet&):Drawable() {}
GeoSet& operator = (const GeoSet&) { return *this;}
virtual ~GeoSet();
virtual const bool computeBound() const;
int _numprims;
PrimitiveType _primtype;
int _needprimlen;
unsigned int _oglprimtype;
int *_primLengths;
mutable unsigned char _primlength;
unsigned char _flat_shaded_skip;
mutable int _numcoords;
Vec3 *_coords;
IndexPointer _cindex;
BindingType _normal_binding;
mutable int _numnormals;
Vec3 *_normals;
IndexPointer _nindex;
BindingType _color_binding;
mutable int _numcolors;
Vec4 *_colors;
IndexPointer _colindex;
BindingType _texture_binding;
mutable int _numtcoords;
Vec2 *_tcoords;
IndexPointer _tindex;
void *_iarray;
IndexPointer _iaindex;
InterleaveArrayType _iaformat;
unsigned int _ogliaformat;
int _fast_path;
void set_fast_path( void );
void draw_fast_path( void );
void draw_alternate_path( void );
};
/** Template function for iterating through a GeoSet operating on triangles
with templated functor. Function automatically decomposes quads and polygons
into sub triangles which are passed onto functor.*/
template<class T>
void for_each_triangle(GeoSet& gset,T& op)
{
switch(gset.getPrimType())
{
case(GeoSet::TRIANGLE_STRIP):
case(GeoSet::FLAT_TRIANGLE_STRIP):
{
if (gset.getCoordIndices().valid())
{
if (gset.getCoordIndices()._is_ushort)
{
ushort* iptr = gset.getCoordIndices()._ptr._ushort;
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
const int primLength = gset.getPrimLengths()[i];
ushort* iend = iptr+primLength;
for(int j = 2; j < primLength; j++ )
{
if( !(j%2) )
op(vptr[*(iptr)],vptr[*(iptr+1)],vptr[*(iptr+2)]);
else
op(vptr[*(iptr)],vptr[*(iptr+2)],vptr[*(iptr+1)]);
++iptr;
}
iptr=iend;
}
}
else
{
uint* iptr = gset.getCoordIndices()._ptr._uint;
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
const int primLength = gset.getPrimLengths()[i];
uint* iend = iptr+primLength;
for(int j = 2; j < primLength; j++ )
{
if( !(j%2) )
op(vptr[*(iptr)],vptr[*(iptr+1)],vptr[*(iptr+2)]);
else
op(vptr[*(iptr)],vptr[*(iptr+2)],vptr[*(iptr+1)]);
++iptr;
}
iptr=iend;
}
}
}
else
{
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
const int primLength = gset.getPrimLengths()[i];
Vec3* vend = vptr+primLength;
for(int j = 2; j < primLength; j++ )
{
if( !(j%2) )
op(*(vptr),*(vptr+1),*(vptr+2));
else
op(*(vptr),*(vptr+2),*(vptr+1));
++vptr;
}
vptr=vend;
}
}
}
break;
case(GeoSet::TRIANGLES):
{
if (gset.getCoordIndices().valid())
{
if (gset.getCoordIndices()._is_ushort)
{
ushort* iptr = gset.getCoordIndices()._ptr._ushort;
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
op(vptr[*(iptr)],vptr[*(iptr+1)],vptr[*(iptr+2)]);
iptr+=3;
}
}
else
{
uint* iptr = gset.getCoordIndices()._ptr._uint;
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
op(vptr[*(iptr)],vptr[*(iptr+1)],vptr[*(iptr+2)]);
iptr+=3;
}
}
}
else
{
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
op(*(vptr),*(vptr+1),*(vptr+2));
vptr+=3;
}
}
}
break;
case(GeoSet::QUAD_STRIP):
{
if (gset.getCoordIndices().valid())
{
if (gset.getCoordIndices()._is_ushort)
{
ushort* iptr = gset.getCoordIndices()._ptr._ushort;
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
const int primLength = gset.getPrimLengths()[i];
ushort* iend = iptr+primLength;
for(int j = 3; j < primLength; j+=2 )
{
op(vptr[*(iptr)],vptr[*(iptr+1)],vptr[*(iptr+2)]);
op(vptr[*(iptr)],vptr[*(iptr+3)],vptr[*(iptr+2)]);
iptr+=2;
}
iptr=iend;
}
}
else
{
uint* iptr = gset.getCoordIndices()._ptr._uint;
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
const int primLength = gset.getPrimLengths()[i];
uint* iend = iptr+primLength;
for(int j = 3; j < primLength; j+=2 )
{
op(vptr[*(iptr)],vptr[*(iptr+1)],vptr[*(iptr+2)]);
op(vptr[*(iptr)],vptr[*(iptr+3)],vptr[*(iptr+2)]);
iptr+=2;
}
iptr=iend;
}
}
}
else
{
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
const int primLength = gset.getPrimLengths()[i];
Vec3* vend = vptr+primLength;
for(int j = 3; j < primLength; j+=2 )
{
op(*(vptr),*(vptr+1),*(vptr+2));
op(*(vptr),*(vptr+3),*(vptr+2));
vptr+=2;
}
vptr=vend;
}
}
}
break;
case(GeoSet::QUADS):
{
if (gset.getCoordIndices().valid())
{
if (gset.getCoordIndices()._is_ushort)
{
ushort* iptr = gset.getCoordIndices()._ptr._ushort;
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
op(vptr[*(iptr)],vptr[*(iptr+1)],vptr[*(iptr+2)]);
op(vptr[*(iptr)],vptr[*(iptr+3)],vptr[*(iptr+2)]);
iptr+=4;
}
}
else
{
uint* iptr = gset.getCoordIndices()._ptr._uint;
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
op(vptr[*(iptr)],vptr[*(iptr+1)],vptr[*(iptr+2)]);
op(vptr[*(iptr)],vptr[*(iptr+3)],vptr[*(iptr+2)]);
iptr+=4;
}
}
}
else
{
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
op(*(vptr),*(vptr+1),*(vptr+2));
op(*(vptr),*(vptr+3),*(vptr+2));
vptr+=4;
}
}
}
break;
case(GeoSet::TRIANGLE_FAN):
case(GeoSet::POLYGON):
{
if (gset.getCoordIndices().valid())
{
if (gset.getCoordIndices()._is_ushort)
{
ushort* iptr = gset.getCoordIndices()._ptr._ushort;
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
const int primLength = gset.getPrimLengths()[i];
if (primLength>0)
{
const Vec3& start = vptr[*(iptr)];
ushort* iend = iptr+primLength;
++iptr;
for(int j = 2; j < primLength; ++j )
{
op(start,vptr[*(iptr)],vptr[*(iptr+1)]);
++iptr;
}
iptr=iend;
}
}
}
else
{
uint* iptr = gset.getCoordIndices()._ptr._uint;
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
const int primLength = gset.getPrimLengths()[i];
if (primLength>0)
{
const Vec3& start = vptr[*(iptr)];
uint* iend = iptr+primLength;
++iptr;
for(int j = 2; j < primLength; ++j )
{
op(start,vptr[*(iptr)],vptr[*(iptr+1)]);
++iptr;
}
iptr=iend;
}
}
}
}
else
{
Vec3* vptr = gset.getCoords();
const int numPrim = gset.getNumPrims();
for(int i=0; i<numPrim; ++i )
{
const int primLength = gset.getPrimLengths()[i];
if (primLength>0)
{
const Vec3& start = *vptr;
Vec3* vend = vptr+primLength;
++vptr;
for(int j = 2; j < primLength; ++j)
{
op(start,*(vptr),*(vptr+1));
++vptr;
}
vptr = vend;
}
}
}
}
break;
default:
break;
}
};
};
#endif