2001-09-20 05:19:47 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <float.h>
|
|
|
|
|
|
|
|
#include <osg/Drawable>
|
|
|
|
#include <osg/State>
|
|
|
|
#include <osg/Notify>
|
2002-02-09 06:55:21 +08:00
|
|
|
#include <osg/Node>
|
|
|
|
|
|
|
|
#include <algorithm>
|
2001-09-20 05:19:47 +08:00
|
|
|
|
|
|
|
using namespace osg;
|
|
|
|
|
|
|
|
Drawable::DeletedDisplayListCache Drawable::s_deletedDisplayListCache;
|
|
|
|
|
|
|
|
Drawable::Drawable()
|
|
|
|
{
|
2002-02-28 08:11:31 +08:00
|
|
|
_globjList.resize(DisplaySettings::instance()->getMaxNumberOfGraphicsContexts(),0);
|
|
|
|
|
2001-09-20 05:19:47 +08:00
|
|
|
_bbox_computed = false;
|
|
|
|
|
|
|
|
// Note, if your are defining a subclass from drawable which is
|
|
|
|
// dynamically updated then you should set both the following to
|
|
|
|
// to false in your constructor. This will prevent any display
|
|
|
|
// lists from being automatically created and safeguard the
|
|
|
|
// dynamic updating of data.
|
|
|
|
_supportsDisplayList = true;
|
|
|
|
_useDisplayList = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2002-02-07 09:07:11 +08:00
|
|
|
Drawable::Drawable(const Drawable& drawable,const CopyOp& copyop):
|
|
|
|
Object(drawable,copyop),
|
2002-02-09 06:55:21 +08:00
|
|
|
_parents(), // leave empty as parentList is managed by Geode
|
2002-09-02 20:31:35 +08:00
|
|
|
_stateset(copyop(drawable._stateset.get())),
|
2002-10-30 21:27:15 +08:00
|
|
|
_bbox(drawable._bbox),
|
|
|
|
_bbox_computed(drawable._bbox_computed),
|
|
|
|
_shape(copyop(drawable._shape.get())),
|
2002-02-07 09:07:11 +08:00
|
|
|
_supportsDisplayList(drawable._supportsDisplayList),
|
|
|
|
_useDisplayList(drawable._useDisplayList),
|
|
|
|
_globjList(drawable._globjList),
|
2002-03-14 06:44:22 +08:00
|
|
|
_drawCallback(drawable._drawCallback),
|
|
|
|
_cullCallback(drawable._cullCallback)
|
2002-02-07 09:07:11 +08:00
|
|
|
{}
|
2001-09-20 05:19:47 +08:00
|
|
|
|
|
|
|
Drawable::~Drawable()
|
|
|
|
{
|
|
|
|
dirtyDisplayList();
|
|
|
|
}
|
|
|
|
|
2002-02-09 06:55:21 +08:00
|
|
|
void Drawable::addParent(osg::Node* node)
|
|
|
|
{
|
|
|
|
_parents.push_back(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Drawable::removeParent(osg::Node* node)
|
|
|
|
{
|
|
|
|
ParentList::iterator pitr = std::find(_parents.begin(),_parents.end(),node);
|
|
|
|
if (pitr!=_parents.end()) _parents.erase(pitr);
|
|
|
|
}
|
|
|
|
|
2002-09-02 20:31:35 +08:00
|
|
|
osg::StateSet* Drawable::getOrCreateStateSet()
|
|
|
|
{
|
|
|
|
if (!_stateset) _stateset = osgNew StateSet;
|
|
|
|
return _stateset.get();
|
|
|
|
}
|
|
|
|
|
2002-02-09 06:55:21 +08:00
|
|
|
void Drawable::dirtyBound()
|
|
|
|
{
|
|
|
|
if (_bbox_computed)
|
|
|
|
{
|
|
|
|
_bbox_computed = false;
|
|
|
|
|
|
|
|
// dirty parent bounding sphere's to ensure that all are valid.
|
|
|
|
for(ParentList::iterator itr=_parents.begin();
|
|
|
|
itr!=_parents.end();
|
|
|
|
++itr)
|
|
|
|
{
|
|
|
|
(*itr)->dirtyBound();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2001-09-20 05:19:47 +08:00
|
|
|
|
|
|
|
void Drawable::compile(State& state)
|
|
|
|
{
|
|
|
|
if (!_useDisplayList) return;
|
|
|
|
|
|
|
|
// 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 comple and execute.
|
|
|
|
if( globj != 0 )
|
|
|
|
{
|
|
|
|
glDeleteLists( globj, 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-09-02 20:31:35 +08:00
|
|
|
if (_stateset.valid())
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
2002-09-02 20:31:35 +08:00
|
|
|
_stateset->compile(state);
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
globj = glGenLists( 1 );
|
|
|
|
glNewList( globj, GL_COMPILE );
|
2002-05-29 07:43:22 +08:00
|
|
|
|
|
|
|
if (_drawCallback.valid())
|
|
|
|
_drawCallback->drawImmediateMode(state,this);
|
|
|
|
else
|
|
|
|
drawImmediateMode(state);
|
|
|
|
|
2001-09-20 05:19:47 +08:00
|
|
|
glEndList();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2002-09-02 20:31:35 +08:00
|
|
|
void Drawable::setSupportsDisplayList(bool flag)
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
|
|
|
// if value unchanged simply return.
|
|
|
|
if (_supportsDisplayList==flag) return;
|
|
|
|
|
|
|
|
// if previously set to true then need to check about display lists.
|
|
|
|
if (_supportsDisplayList)
|
|
|
|
{
|
|
|
|
if (_useDisplayList)
|
|
|
|
{
|
|
|
|
// used to support display lists and display lists switched
|
|
|
|
// on so now delete them and turn useDisplayList off.
|
|
|
|
dirtyDisplayList();
|
|
|
|
_useDisplayList = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// set with new value.
|
|
|
|
_supportsDisplayList=flag;
|
|
|
|
}
|
|
|
|
|
2002-09-02 20:31:35 +08:00
|
|
|
void Drawable::setUseDisplayList(bool flag)
|
2001-09-20 05:19:47 +08:00
|
|
|
{
|
|
|
|
// if value unchanged simply return.
|
|
|
|
if (_useDisplayList==flag) return;
|
|
|
|
|
|
|
|
// if was previously set to true, remove display list.
|
|
|
|
if (_useDisplayList)
|
|
|
|
{
|
|
|
|
dirtyDisplayList();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_supportsDisplayList)
|
|
|
|
{
|
|
|
|
|
|
|
|
// set with new value.
|
|
|
|
_useDisplayList = flag;
|
|
|
|
|
|
|
|
}
|
|
|
|
else // does not support display lists.
|
|
|
|
{
|
|
|
|
if (flag)
|
|
|
|
{
|
2001-12-15 07:18:28 +08:00
|
|
|
notify(WARN)<<"Warning: attempt to setUseDisplayList(true) on a drawable with does not support display lists."<<std::endl;
|
2001-09-20 05:19:47 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// set with new value.
|
|
|
|
_useDisplayList = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Drawable::dirtyDisplayList()
|
|
|
|
{
|
|
|
|
for(uint i=0;i<_globjList.size();++i)
|
|
|
|
{
|
|
|
|
if (_globjList[i] != 0)
|
|
|
|
{
|
|
|
|
Drawable::deleteDisplayList(i,_globjList[i]);
|
|
|
|
_globjList[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Drawable::deleteDisplayList(uint contextID,uint globj)
|
|
|
|
{
|
|
|
|
if (globj!=0)
|
|
|
|
{
|
|
|
|
// insert the globj into the cache for the appropriate context.
|
|
|
|
s_deletedDisplayListCache[contextID].insert(globj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** flush all the cached display list which need to be deleted
|
|
|
|
* in the OpenGL context related to contextID.*/
|
|
|
|
void Drawable::flushDeletedDisplayLists(uint contextID)
|
|
|
|
{
|
|
|
|
DeletedDisplayListCache::iterator citr = s_deletedDisplayListCache.find(contextID);
|
|
|
|
if (citr!=s_deletedDisplayListCache.end())
|
|
|
|
{
|
|
|
|
std::set<uint>& displayListSet = citr->second;
|
|
|
|
for(std::set<uint>::iterator gitr=displayListSet.begin();
|
|
|
|
gitr!=displayListSet.end();
|
|
|
|
++gitr)
|
|
|
|
{
|
|
|
|
glDeleteLists(*gitr,1);
|
|
|
|
}
|
|
|
|
|
|
|
|
s_deletedDisplayListCache.erase(citr);
|
|
|
|
}
|
|
|
|
}
|
2002-07-10 23:35:47 +08:00
|
|
|
|
|
|
|
void Drawable::setAppCallback(AppCallback* ac)
|
|
|
|
{
|
|
|
|
if (_appCallback==ac) return;
|
|
|
|
|
|
|
|
int delta = 0;
|
|
|
|
if (_appCallback.valid()) --delta;
|
|
|
|
if (ac) ++delta;
|
2002-07-11 04:30:57 +08:00
|
|
|
|
|
|
|
_appCallback = ac;
|
2002-07-10 23:35:47 +08:00
|
|
|
|
|
|
|
if (delta!=0)
|
|
|
|
{
|
|
|
|
for(ParentList::iterator itr=_parents.begin();
|
|
|
|
itr!=_parents.end();
|
|
|
|
++itr)
|
|
|
|
{
|
|
|
|
(*itr)->setNumChildrenRequiringAppTraversal((*itr)->getNumChildrenRequiringAppTraversal()+delta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-07-19 06:35:54 +08:00
|
|
|
|
|
|
|
struct ComputeBound : public Drawable::PrimitiveFunctor
|
|
|
|
{
|
|
|
|
ComputeBound():_vertices(0) {}
|
|
|
|
|
2002-11-06 18:24:33 +08:00
|
|
|
virtual void setVertexArray(unsigned int,const Vec3* vertices) { _vertices = vertices; }
|
2002-07-19 06:35:54 +08:00
|
|
|
|
|
|
|
virtual void drawArrays(GLenum,GLint first,GLsizei count)
|
|
|
|
{
|
|
|
|
if (_vertices)
|
|
|
|
{
|
2002-11-06 18:24:33 +08:00
|
|
|
const osg::Vec3* vert = _vertices+first;
|
2002-07-19 06:35:54 +08:00
|
|
|
for(;count>0;--count,++vert)
|
|
|
|
{
|
|
|
|
_bb.expandBy(*vert);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-11-06 18:24:33 +08:00
|
|
|
virtual void drawElements(GLenum,GLsizei count,const GLubyte* indices)
|
2002-07-19 06:35:54 +08:00
|
|
|
{
|
|
|
|
if (_vertices)
|
|
|
|
{
|
|
|
|
for(;count>0;--count,++indices)
|
|
|
|
{
|
|
|
|
_bb.expandBy(_vertices[*indices]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-11-06 18:24:33 +08:00
|
|
|
virtual void drawElements(GLenum,GLsizei count,const GLushort* indices)
|
2002-07-19 06:35:54 +08:00
|
|
|
{
|
|
|
|
if (_vertices)
|
|
|
|
{
|
|
|
|
for(;count>0;--count,++indices)
|
|
|
|
{
|
|
|
|
_bb.expandBy(_vertices[*indices]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-11-06 18:24:33 +08:00
|
|
|
virtual void drawElements(GLenum,GLsizei count,const GLuint* indices)
|
2002-07-19 06:35:54 +08:00
|
|
|
{
|
|
|
|
if (_vertices)
|
|
|
|
{
|
|
|
|
for(;count>0;--count,++indices)
|
|
|
|
{
|
|
|
|
_bb.expandBy(_vertices[*indices]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void begin(GLenum) {}
|
|
|
|
virtual void vertex(const Vec3& vert) { _bb.expandBy(vert); }
|
|
|
|
virtual void vertex(float x,float y,float z) { _bb.expandBy(x,y,z); }
|
|
|
|
virtual void end() {}
|
|
|
|
|
2002-11-06 18:24:33 +08:00
|
|
|
const Vec3* _vertices;
|
2002-07-19 06:35:54 +08:00
|
|
|
BoundingBox _bb;
|
|
|
|
};
|
|
|
|
|
2002-09-02 20:31:35 +08:00
|
|
|
bool Drawable::computeBound() const
|
2002-07-19 06:35:54 +08:00
|
|
|
{
|
|
|
|
ComputeBound cb;
|
|
|
|
|
|
|
|
Drawable* non_const_this = const_cast<Drawable*>(this);
|
|
|
|
non_const_this->accept(cb);
|
|
|
|
|
|
|
|
_bbox = cb._bb;
|
|
|
|
_bbox_computed = true;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|