333 lines
8.0 KiB
C++
333 lines
8.0 KiB
C++
/* -*-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.
|
|
*/
|
|
#if defined(_MSC_VER)
|
|
#pragma warning( disable : 4786 )
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <float.h>
|
|
|
|
#include <osg/Geometry>
|
|
#include <osg/Texture2D>
|
|
#include <osg/TexEnv>
|
|
#include <osg/AlphaFunc>
|
|
#include <osg/Notify>
|
|
|
|
#include <osgSim/ImpostorSprite>
|
|
|
|
using namespace osg;
|
|
using namespace osgSim;
|
|
|
|
ImpostorSprite::ImpostorSprite():
|
|
_parent(0),
|
|
_ism(0),
|
|
_previous(0),
|
|
_next(0),
|
|
_lastFrameUsed(osg::UNINITIALIZED_FRAME_NUMBER),
|
|
_texture(0),
|
|
_s(0),
|
|
_t(0)
|
|
{
|
|
// don't use display list since we will be updating the geometry.
|
|
setUseDisplayList(false);
|
|
_color.set(1.0f, 1.0f, 1.0f, 1.0f );
|
|
}
|
|
|
|
ImpostorSprite::ImpostorSprite(const ImpostorSprite&):
|
|
osg::Drawable(),
|
|
_parent(0),
|
|
_ism(0),
|
|
_previous(0),
|
|
_next(0),
|
|
_lastFrameUsed(osg::UNINITIALIZED_FRAME_NUMBER),
|
|
_texture(0),
|
|
_s(0),
|
|
_t(0)
|
|
{
|
|
setUseDisplayList(false);
|
|
_color.set(1.0f, 1.0f, 1.0f, 1.0f );
|
|
}
|
|
|
|
ImpostorSprite::~ImpostorSprite()
|
|
{
|
|
if (_ism)
|
|
{
|
|
_ism->remove(this);
|
|
}
|
|
}
|
|
|
|
float ImpostorSprite::calcPixelError(const osg::Matrix& MVPW) const
|
|
{
|
|
// find the maximum screen space pixel error between the control coords and the quad coners.
|
|
float max_error_sqrd = 0.0f;
|
|
|
|
for(int i=0;i<4;++i)
|
|
{
|
|
|
|
osg::Vec3 projected_coord = _coords[i]*MVPW;
|
|
osg::Vec3 projected_control = _controlcoords[i]*MVPW;
|
|
|
|
float dx = (projected_coord.x()-projected_control.x());
|
|
float dy = (projected_coord.y()-projected_control.y());
|
|
|
|
float error_sqrd = dx*dx+dy*dy;
|
|
|
|
if (error_sqrd > max_error_sqrd) max_error_sqrd = error_sqrd;
|
|
|
|
}
|
|
|
|
return sqrtf(max_error_sqrd);
|
|
}
|
|
void ImpostorSprite::drawImplementation(osg::RenderInfo& renderInfo) const
|
|
{
|
|
osg::GLBeginEndAdapter& gl = (renderInfo.getState()->getGLBeginEndAdapter());
|
|
|
|
// when the tex env is set to REPLACE, and the
|
|
// texture is set up correctly the color has no effect.
|
|
gl.Color4fv( _color.ptr() );
|
|
|
|
gl.Begin( GL_QUADS );
|
|
|
|
gl.TexCoord2fv( (GLfloat *)&_texcoords[0] );
|
|
gl.Vertex3fv( (GLfloat *)&_coords[0] );
|
|
|
|
gl.TexCoord2fv( (GLfloat *)&_texcoords[1] );
|
|
gl.Vertex3fv( (GLfloat *)&_coords[1] );
|
|
|
|
gl.TexCoord2fv( (GLfloat *)&_texcoords[2] );
|
|
gl.Vertex3fv( (GLfloat *)&_coords[2] );
|
|
|
|
gl.TexCoord2fv( (GLfloat *)&_texcoords[3] );
|
|
gl.Vertex3fv( (GLfloat *)&_coords[3] );
|
|
|
|
gl.End();
|
|
}
|
|
|
|
osg::BoundingBox ImpostorSprite::computeBoundingBox() const
|
|
{
|
|
osg::BoundingBox bbox;
|
|
bbox.expandBy(_coords[0]);
|
|
bbox.expandBy(_coords[1]);
|
|
bbox.expandBy(_coords[2]);
|
|
bbox.expandBy(_coords[3]);
|
|
|
|
if (!bbox.valid())
|
|
{
|
|
OSG_WARN << "******* ImpostorSprite::computeBound() problem"<<std::endl;
|
|
}
|
|
|
|
return bbox;
|
|
}
|
|
|
|
void ImpostorSprite::setTexture(osg::Texture2D* tex,int s,int t)
|
|
{
|
|
_texture = tex;
|
|
_s = s;
|
|
_t = t;
|
|
}
|
|
|
|
|
|
void ImpostorSprite::accept(AttributeFunctor& af)
|
|
{
|
|
af.apply(VERTICES,4,_coords);
|
|
af.apply(TEXTURE_COORDS_0,4,_texcoords);
|
|
}
|
|
|
|
void ImpostorSprite::accept(ConstAttributeFunctor& af) const
|
|
{
|
|
af.apply(VERTICES,4,_coords);
|
|
af.apply(TEXTURE_COORDS_0,4,_texcoords);
|
|
}
|
|
|
|
void ImpostorSprite::accept(osg::PrimitiveFunctor& functor) const
|
|
{
|
|
functor.setVertexArray(4,_coords);
|
|
functor.drawArrays( GL_QUADS, 0, 4);
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Helper class for managing the reuse of ImpostorSprite resources.
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
ImpostorSpriteManager::ImpostorSpriteManager():
|
|
_first(NULL),
|
|
_last(NULL)
|
|
{
|
|
_texenv = new osg::TexEnv;
|
|
_texenv->setMode(osg::TexEnv::REPLACE);
|
|
|
|
_alphafunc = new osg::AlphaFunc;
|
|
_alphafunc->setFunction( osg::AlphaFunc::GREATER, 0.000f );
|
|
|
|
_reuseStateSetIndex = 0;
|
|
}
|
|
|
|
|
|
ImpostorSpriteManager::~ImpostorSpriteManager()
|
|
{
|
|
while (_first)
|
|
{
|
|
ImpostorSprite* next = _first->_next;
|
|
_first->_ism = NULL;
|
|
_first->_previous = NULL;
|
|
_first->_next = NULL;
|
|
_first = next;
|
|
}
|
|
|
|
}
|
|
|
|
void ImpostorSpriteManager::push_back(ImpostorSprite* is)
|
|
{
|
|
if (is==NULL || is==_last) return;
|
|
|
|
// remove entry for exisiting position in linked list
|
|
// if it is already inserted.
|
|
if (is->_previous)
|
|
{
|
|
(is->_previous)->_next = is->_next;
|
|
}
|
|
|
|
if (is->_next)
|
|
{
|
|
(is->_next)->_previous = is->_previous;
|
|
}
|
|
|
|
if (_first==is) _first = is->_next;
|
|
|
|
if (empty())
|
|
{
|
|
_first = is;
|
|
_last = is;
|
|
is->_ism = this;
|
|
is->_previous = NULL;
|
|
is->_next = NULL;
|
|
}
|
|
else
|
|
{
|
|
|
|
// now add the element into the list.
|
|
ImpostorSprite* previous_last = _last;
|
|
previous_last->_next = is;
|
|
_last = is;
|
|
_last->_ism = this;
|
|
_last->_previous = previous_last;
|
|
_last->_next = NULL;
|
|
}
|
|
}
|
|
|
|
void ImpostorSpriteManager::remove(ImpostorSprite* is)
|
|
{
|
|
if (is==NULL) return;
|
|
|
|
// remove entry for exisiting position in linked list
|
|
// if it is already inserted.
|
|
if (is->_previous)
|
|
{
|
|
(is->_previous)->_next = is->_next;
|
|
}
|
|
|
|
if (is->_next)
|
|
{
|
|
(is->_next)->_previous = is->_previous;
|
|
}
|
|
|
|
if (_first==is) _first = is->_next;
|
|
if (_last==is) _last = is->_previous;
|
|
}
|
|
|
|
ImpostorSprite* ImpostorSpriteManager::createOrReuseImpostorSprite(int s,int t,unsigned int frameNumber)
|
|
{
|
|
if (!empty())
|
|
{
|
|
|
|
// search for a valid impostor to reuse.
|
|
ImpostorSprite* curr = _first;
|
|
while (curr)
|
|
{
|
|
if (curr->getLastFrameUsed()<=frameNumber &&
|
|
curr->s()==s &&
|
|
curr->t()==t)
|
|
{
|
|
push_back(curr);
|
|
return curr;
|
|
}
|
|
else
|
|
{
|
|
curr = curr->_next;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// creating new impostor sprite.
|
|
|
|
|
|
osg::StateSet* stateset = new osg::StateSet;
|
|
|
|
stateset->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
|
|
stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
|
|
stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
|
|
|
|
stateset->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
|
|
|
|
stateset->setAttributeAndModes( _alphafunc.get(), osg::StateAttribute::ON );
|
|
|
|
osg::Texture2D* texture = new osg::Texture2D;
|
|
texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
|
|
texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
|
|
|
|
stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
|
|
stateset->setTextureAttribute(0,_texenv.get());
|
|
|
|
/*
|
|
TexEnv* texenv = new TexEnv;
|
|
texenv->setMode(TexEnv::REPLACE);
|
|
stateset->setAttribute(texenv);
|
|
|
|
AlphaFunc* alphafunc = new osg::AlphaFunc;
|
|
alphafunc->setFunction( osg::AlphaFunc::GREATER, 0.000f );
|
|
stateset->setAttributeAndModes( alphafunc, osg::StateAttribute::ON );
|
|
*/
|
|
|
|
|
|
// stateset->setMode( GL_ALPHA_TEST, osg::StateAttribute::OFF );
|
|
|
|
ImpostorSprite* is = new ImpostorSprite;
|
|
is->setStateSet(stateset);
|
|
is->setTexture(texture,s,t);
|
|
|
|
push_back(is);
|
|
|
|
return is;
|
|
|
|
}
|
|
|
|
osg::StateSet* ImpostorSpriteManager::createOrReuseStateSet()
|
|
{
|
|
if (_reuseStateSetIndex<_stateSetList.size())
|
|
{
|
|
return _stateSetList[_reuseStateSetIndex++].get();
|
|
}
|
|
_stateSetList.push_back(new osg::StateSet);
|
|
_reuseStateSetIndex=_stateSetList.size();
|
|
return _stateSetList.back().get();
|
|
}
|
|
|
|
void ImpostorSpriteManager::reset()
|
|
{
|
|
_reuseStateSetIndex = 0;
|
|
}
|