Futher work on TextureAtlasBuilder/Visitor, now functioning enough to deploy on real models.
This commit is contained in:
parent
1055bd013d
commit
19f3d975dd
@ -722,14 +722,18 @@ class OSGUTIL_EXPORT Optimizer
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void addStateSet(osg::StateSet* stateset);
|
bool pushStateSet(osg::StateSet* stateset);
|
||||||
|
void popStateSet();
|
||||||
|
|
||||||
typedef std::set<osg::StateSet*> StateSets;
|
typedef std::set<osg::Drawable*> Drawables;
|
||||||
|
typedef std::map<osg::StateSet*, Drawables> StateSetMap;
|
||||||
typedef std::set<osg::Texture2D*> Textures;
|
typedef std::set<osg::Texture2D*> Textures;
|
||||||
|
typedef std::vector<osg::StateSet*> StateSetStack;
|
||||||
|
|
||||||
TextureAtlasBuilder _builder;
|
TextureAtlasBuilder _builder;
|
||||||
|
|
||||||
StateSets _statesets;
|
StateSetMap _statesetMap;
|
||||||
|
StateSetStack _statesetStack;
|
||||||
Textures _textures;
|
Textures _textures;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -2975,8 +2975,8 @@ void Optimizer::FlattenBillboardVisitor::process()
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Optimizer::TextureAtlasBuilder::TextureAtlasBuilder():
|
Optimizer::TextureAtlasBuilder::TextureAtlasBuilder():
|
||||||
_maximumAtlasWidth(512),
|
_maximumAtlasWidth(2048),
|
||||||
_maximumAtlasHeight(512),
|
_maximumAtlasHeight(2048),
|
||||||
_margin(8)
|
_margin(8)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -3024,7 +3024,7 @@ void Optimizer::TextureAtlasBuilder::buildAtlas()
|
|||||||
aitr != _atlasList.end() && !addedSourceToAtlas;
|
aitr != _atlasList.end() && !addedSourceToAtlas;
|
||||||
++aitr)
|
++aitr)
|
||||||
{
|
{
|
||||||
osg::notify(osg::NOTICE)<<"checking source "<<source->_image->getFileName()<<" to see it it'll fit in atlas "<<aitr->get()<<std::endl;
|
osg::notify(osg::INFO)<<"checking source "<<source->_image->getFileName()<<" to see it it'll fit in atlas "<<aitr->get()<<std::endl;
|
||||||
if ((*aitr)->doesSourceFit(source))
|
if ((*aitr)->doesSourceFit(source))
|
||||||
{
|
{
|
||||||
addedSourceToAtlas = true;
|
addedSourceToAtlas = true;
|
||||||
@ -3032,13 +3032,13 @@ void Optimizer::TextureAtlasBuilder::buildAtlas()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
osg::notify(osg::NOTICE)<<"source "<<source->_image->getFileName()<<" does not fit in atlas "<<aitr->get()<<std::endl;
|
osg::notify(osg::INFO)<<"source "<<source->_image->getFileName()<<" does not fit in atlas "<<aitr->get()<<std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!addedSourceToAtlas)
|
if (!addedSourceToAtlas)
|
||||||
{
|
{
|
||||||
osg::notify(osg::NOTICE)<<"creating new Atlas for "<<source->_image->getFileName()<<std::endl;
|
osg::notify(osg::INFO)<<"creating new Atlas for "<<source->_image->getFileName()<<std::endl;
|
||||||
|
|
||||||
osg::ref_ptr<Atlas> atlas = new Atlas(_maximumAtlasWidth,_maximumAtlasHeight,_margin);
|
osg::ref_ptr<Atlas> atlas = new Atlas(_maximumAtlasWidth,_maximumAtlasHeight,_margin);
|
||||||
_atlasList.push_back(atlas.get());
|
_atlasList.push_back(atlas.get());
|
||||||
@ -3173,10 +3173,27 @@ bool Optimizer::TextureAtlasBuilder::Source::suitableForAtlas(unsigned int maxim
|
|||||||
if (_image->s()+margin*2 > maximumAtlasWidth) return false;
|
if (_image->s()+margin*2 > maximumAtlasWidth) return false;
|
||||||
if (_image->t()+margin*2 > maximumAtlasHeight) return false;
|
if (_image->t()+margin*2 > maximumAtlasHeight) return false;
|
||||||
|
|
||||||
// FIXME need to handle compressed textures...
|
switch(_image->getPixelFormat())
|
||||||
|
{
|
||||||
|
case(GL_COMPRESSED_ALPHA_ARB):
|
||||||
|
case(GL_COMPRESSED_INTENSITY_ARB):
|
||||||
|
case(GL_COMPRESSED_LUMINANCE_ALPHA_ARB):
|
||||||
|
case(GL_COMPRESSED_LUMINANCE_ARB):
|
||||||
|
case(GL_COMPRESSED_RGBA_ARB):
|
||||||
|
case(GL_COMPRESSED_RGB_ARB):
|
||||||
|
case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):
|
||||||
|
case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):
|
||||||
|
case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
|
||||||
|
case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
|
||||||
|
// can't handle compressed textures inside an atlas
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (_texture.valid())
|
if (_texture.valid())
|
||||||
{
|
{
|
||||||
|
|
||||||
if (_texture->getWrap(osg::Texture2D::WRAP_S)==osg::Texture2D::REPEAT ||
|
if (_texture->getWrap(osg::Texture2D::WRAP_S)==osg::Texture2D::REPEAT ||
|
||||||
_texture->getWrap(osg::Texture2D::WRAP_S)==osg::Texture2D::MIRROR)
|
_texture->getWrap(osg::Texture2D::WRAP_S)==osg::Texture2D::MIRROR)
|
||||||
{
|
{
|
||||||
@ -3197,6 +3214,7 @@ bool Optimizer::TextureAtlasBuilder::Source::suitableForAtlas(unsigned int maxim
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3323,16 +3341,17 @@ bool Optimizer::TextureAtlasBuilder::Atlas::doesSourceFit(Source* source)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((_y + sourceImage->t() + 2*_margin) > _maximumAtlasWidth)
|
if ((_y + sourceImage->t() + 2*_margin) > _maximumAtlasHeight)
|
||||||
{
|
{
|
||||||
// image doesn't have up space in height axis.
|
// image doesn't have up space in height axis.
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// does the source fit in the current row?
|
// does the source fit in the current row?
|
||||||
if ((_x + sourceImage->s() + 2*_margin) <= _maximumAtlasWidth)
|
if ((_x + sourceImage->s() + 2*_margin) <= _maximumAtlasWidth)
|
||||||
{
|
{
|
||||||
// yes it fits :-)
|
// yes it fits :-)
|
||||||
osg::notify(osg::NOTICE)<<"Fits in current row"<<std::endl;
|
osg::notify(osg::INFO)<<"Fits in current row"<<std::endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3340,7 +3359,7 @@ bool Optimizer::TextureAtlasBuilder::Atlas::doesSourceFit(Source* source)
|
|||||||
if ((_height + sourceImage->t() + 2*_margin) <= _maximumAtlasHeight)
|
if ((_height + sourceImage->t() + 2*_margin) <= _maximumAtlasHeight)
|
||||||
{
|
{
|
||||||
// yes it fits :-)
|
// yes it fits :-)
|
||||||
osg::notify(osg::NOTICE)<<"Fits in next row"<<std::endl;
|
osg::notify(osg::INFO)<<"Fits in next row"<<std::endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3353,7 +3372,7 @@ bool Optimizer::TextureAtlasBuilder::Atlas::addSource(Source* source)
|
|||||||
// double check source is compatible
|
// double check source is compatible
|
||||||
if (!doesSourceFit(source))
|
if (!doesSourceFit(source))
|
||||||
{
|
{
|
||||||
osg::notify(osg::NOTICE)<<"source "<<source->_image->getFileName()<<" does not fit in atlas "<<this<<std::endl;
|
osg::notify(osg::INFO)<<"source "<<source->_image->getFileName()<<" does not fit in atlas "<<this<<std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3397,7 +3416,7 @@ bool Optimizer::TextureAtlasBuilder::Atlas::addSource(Source* source)
|
|||||||
// yes it fits, so add the source to the atlas's list of sources it contains
|
// yes it fits, so add the source to the atlas's list of sources it contains
|
||||||
_sourceList.push_back(source);
|
_sourceList.push_back(source);
|
||||||
|
|
||||||
osg::notify(osg::NOTICE)<<"current row insertion, source "<<source->_image->getFileName()<<" "<<_x<<","<<_y<<" fits in row of atlas "<<this<<std::endl;
|
osg::notify(osg::INFO)<<"current row insertion, source "<<source->_image->getFileName()<<" "<<_x<<","<<_y<<" fits in row of atlas "<<this<<std::endl;
|
||||||
|
|
||||||
// set up the source so it knows where it is in the atlas
|
// set up the source so it knows where it is in the atlas
|
||||||
source->_x = _x + _margin;
|
source->_x = _x + _margin;
|
||||||
@ -3425,7 +3444,7 @@ bool Optimizer::TextureAtlasBuilder::Atlas::addSource(Source* source)
|
|||||||
// yes it fits, so add the source to the atlas' list of sources it contains
|
// yes it fits, so add the source to the atlas' list of sources it contains
|
||||||
_sourceList.push_back(source);
|
_sourceList.push_back(source);
|
||||||
|
|
||||||
osg::notify(osg::NOTICE)<<"next row insertion, source "<<source->_image->getFileName()<<" "<<_x<<","<<_y<<" fits in row of atlas "<<this<<std::endl;
|
osg::notify(osg::INFO)<<"next row insertion, source "<<source->_image->getFileName()<<" "<<_x<<","<<_y<<" fits in row of atlas "<<this<<std::endl;
|
||||||
|
|
||||||
// set up the source so it knows where it is in the atlas
|
// set up the source so it knows where it is in the atlas
|
||||||
source->_x = _x + _margin;
|
source->_x = _x + _margin;
|
||||||
@ -3439,12 +3458,12 @@ bool Optimizer::TextureAtlasBuilder::Atlas::addSource(Source* source)
|
|||||||
|
|
||||||
_height = _y + sourceImage->t() + 2*_margin;
|
_height = _y + sourceImage->t() + 2*_margin;
|
||||||
|
|
||||||
osg::notify(osg::NOTICE)<<"source "<<source->_image->getFileName()<<" "<<_x<<","<<_y<<" fits in row of atlas "<<this<<std::endl;
|
osg::notify(osg::INFO)<<"source "<<source->_image->getFileName()<<" "<<_x<<","<<_y<<" fits in row of atlas "<<this<<std::endl;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::notify(osg::NOTICE)<<"source "<<source->_image->getFileName()<<" does not fit in atlas "<<this<<std::endl;
|
osg::notify(osg::INFO)<<"source "<<source->_image->getFileName()<<" does not fit in atlas "<<this<<std::endl;
|
||||||
|
|
||||||
// shouldn't get here, unless doesSourceFit isn't working...
|
// shouldn't get here, unless doesSourceFit isn't working...
|
||||||
return false;
|
return false;
|
||||||
@ -3458,10 +3477,10 @@ void Optimizer::TextureAtlasBuilder::Atlas::clampToNearestPowerOfTwoSize()
|
|||||||
unsigned int h = 1;
|
unsigned int h = 1;
|
||||||
while (h<_height) h *= 2;
|
while (h<_height) h *= 2;
|
||||||
|
|
||||||
osg::notify(osg::NOTICE)<<"Clamping "<<_width<<", "<<_height<<" to "<<w<<","<<h<<std::endl;
|
osg::notify(osg::INFO)<<"Clamping "<<_width<<", "<<_height<<" to "<<w<<","<<h<<std::endl;
|
||||||
|
|
||||||
_width = w;
|
_width = w;
|
||||||
_height = w;
|
_height = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -3470,12 +3489,19 @@ void Optimizer::TextureAtlasBuilder::Atlas::clampToNearestPowerOfTwoSize()
|
|||||||
|
|
||||||
void Optimizer::TextureAtlasBuilder::Atlas::copySources()
|
void Optimizer::TextureAtlasBuilder::Atlas::copySources()
|
||||||
{
|
{
|
||||||
|
osg::notify(osg::INFO)<<"Allocated to "<<_width<<","<<_height<<std::endl;
|
||||||
_image->allocateImage(_width,_height,1,
|
_image->allocateImage(_width,_height,1,
|
||||||
_image->getPixelFormat(),_image->getDataType(),
|
_image->getPixelFormat(),_image->getDataType(),
|
||||||
_image->getPacking());
|
_image->getPacking());
|
||||||
|
|
||||||
|
{
|
||||||
|
// clear memory
|
||||||
|
unsigned int size = _image->getTotalSizeInBytes();
|
||||||
|
unsigned char* str = _image->data();
|
||||||
|
for(unsigned int i=0; i<size; ++i) *(str++) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
osg::notify(osg::NOTICE)<<"Atlas::copySources() "<<std::endl;
|
osg::notify(osg::INFO)<<"Atlas::copySources() "<<std::endl;
|
||||||
for(SourceList::iterator itr = _sourceList.begin();
|
for(SourceList::iterator itr = _sourceList.begin();
|
||||||
itr !=_sourceList.end();
|
itr !=_sourceList.end();
|
||||||
++itr)
|
++itr)
|
||||||
@ -3485,7 +3511,8 @@ void Optimizer::TextureAtlasBuilder::Atlas::copySources()
|
|||||||
|
|
||||||
if (atlas)
|
if (atlas)
|
||||||
{
|
{
|
||||||
osg::notify(osg::NOTICE)<<"Copying image "<<source->_image->getFileName()<<" to "<<source->_x<<" ,"<<source->_y<<std::endl;
|
osg::notify(osg::INFO)<<"Copying image "<<source->_image->getFileName()<<" to "<<source->_x<<" ,"<<source->_y<<std::endl;
|
||||||
|
osg::notify(osg::INFO)<<" image size "<<source->_image->s()<<","<<source->_image->t()<<std::endl;
|
||||||
|
|
||||||
const osg::Image* sourceImage = source->_image.get();
|
const osg::Image* sourceImage = source->_image.get();
|
||||||
osg::Image* atlasImage = atlas->_image.get();
|
osg::Image* atlasImage = atlas->_image.get();
|
||||||
@ -3513,21 +3540,28 @@ void Optimizer::TextureAtlasBuilder::Atlas::copySources()
|
|||||||
|
|
||||||
void Optimizer::TextureAtlasVisitor::reset()
|
void Optimizer::TextureAtlasVisitor::reset()
|
||||||
{
|
{
|
||||||
_statesets.clear();
|
_statesetMap.clear();
|
||||||
|
_statesetStack.clear();
|
||||||
_textures.clear();
|
_textures.clear();
|
||||||
_builder.reset();
|
_builder.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Optimizer::TextureAtlasVisitor::addStateSet(osg::StateSet* stateset)
|
bool Optimizer::TextureAtlasVisitor::pushStateSet(osg::StateSet* stateset)
|
||||||
{
|
{
|
||||||
osg::StateSet::TextureAttributeList& tal = stateset->getTextureAttributeList();
|
osg::StateSet::TextureAttributeList& tal = stateset->getTextureAttributeList();
|
||||||
|
|
||||||
// if no textures ignore
|
// if no textures ignore
|
||||||
if (tal.empty()) return;
|
if (tal.empty()) return false;
|
||||||
|
|
||||||
|
bool pushStateState = false;
|
||||||
|
|
||||||
// if already in stateset list ignore
|
// if already in stateset list ignore
|
||||||
if (_statesets.count(stateset)>0) return;
|
if (_statesetMap.count(stateset)>0)
|
||||||
|
{
|
||||||
|
pushStateState = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
bool containsTexture2D = false;
|
bool containsTexture2D = false;
|
||||||
for(unsigned int unit=0; unit<tal.size(); ++unit)
|
for(unsigned int unit=0; unit<tal.size(); ++unit)
|
||||||
{
|
{
|
||||||
@ -3541,13 +3575,28 @@ void Optimizer::TextureAtlasVisitor::addStateSet(osg::StateSet* stateset)
|
|||||||
|
|
||||||
if (containsTexture2D)
|
if (containsTexture2D)
|
||||||
{
|
{
|
||||||
_statesets.insert(stateset);
|
_statesetMap[stateset];
|
||||||
|
pushStateState = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pushStateState)
|
||||||
|
{
|
||||||
|
_statesetStack.push_back(stateset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return pushStateState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Optimizer::TextureAtlasVisitor::popStateSet()
|
||||||
|
{
|
||||||
|
_statesetStack.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Optimizer::TextureAtlasVisitor::apply(osg::Node& node)
|
void Optimizer::TextureAtlasVisitor::apply(osg::Node& node)
|
||||||
{
|
{
|
||||||
|
bool pushedStateState = false;
|
||||||
|
|
||||||
osg::StateSet* ss = node.getStateSet();
|
osg::StateSet* ss = node.getStateSet();
|
||||||
if (ss && ss->getDataVariance()==osg::Object::STATIC)
|
if (ss && ss->getDataVariance()==osg::Object::STATIC)
|
||||||
@ -3555,11 +3604,13 @@ void Optimizer::TextureAtlasVisitor::apply(osg::Node& node)
|
|||||||
if (isOperationPermissibleForObject(&node) &&
|
if (isOperationPermissibleForObject(&node) &&
|
||||||
isOperationPermissibleForObject(ss))
|
isOperationPermissibleForObject(ss))
|
||||||
{
|
{
|
||||||
addStateSet(ss);
|
pushedStateState = pushStateSet(ss);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
traverse(node);
|
traverse(node);
|
||||||
|
|
||||||
|
if (pushedStateState) popStateSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Optimizer::TextureAtlasVisitor::apply(osg::Geode& geode)
|
void Optimizer::TextureAtlasVisitor::apply(osg::Geode& geode)
|
||||||
@ -3569,37 +3620,140 @@ void Optimizer::TextureAtlasVisitor::apply(osg::Geode& geode)
|
|||||||
osg::StateSet* ss = geode.getStateSet();
|
osg::StateSet* ss = geode.getStateSet();
|
||||||
|
|
||||||
|
|
||||||
|
bool pushedGeodeStateState = false;
|
||||||
|
|
||||||
if (ss && ss->getDataVariance()==osg::Object::STATIC)
|
if (ss && ss->getDataVariance()==osg::Object::STATIC)
|
||||||
{
|
{
|
||||||
if (isOperationPermissibleForObject(ss))
|
if (isOperationPermissibleForObject(ss))
|
||||||
{
|
{
|
||||||
addStateSet(ss);
|
pushedGeodeStateState = pushStateSet(ss);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(unsigned int i=0;i<geode.getNumDrawables();++i)
|
for(unsigned int i=0;i<geode.getNumDrawables();++i)
|
||||||
{
|
{
|
||||||
|
|
||||||
osg::Drawable* drawable = geode.getDrawable(i);
|
osg::Drawable* drawable = geode.getDrawable(i);
|
||||||
if (drawable)
|
if (drawable)
|
||||||
{
|
{
|
||||||
|
bool pushedDrawableStateState = false;
|
||||||
|
|
||||||
ss = drawable->getStateSet();
|
ss = drawable->getStateSet();
|
||||||
if (ss && ss->getDataVariance()==osg::Object::STATIC)
|
if (ss && ss->getDataVariance()==osg::Object::STATIC)
|
||||||
{
|
{
|
||||||
if (isOperationPermissibleForObject(drawable) &&
|
if (isOperationPermissibleForObject(drawable) &&
|
||||||
isOperationPermissibleForObject(ss))
|
isOperationPermissibleForObject(ss))
|
||||||
{
|
{
|
||||||
addStateSet(ss);
|
pushedDrawableStateState = pushStateSet(ss);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_statesetStack.empty())
|
||||||
|
{
|
||||||
|
for(StateSetStack::iterator ssitr = _statesetStack.begin();
|
||||||
|
ssitr != _statesetStack.end();
|
||||||
|
++ssitr)
|
||||||
|
{
|
||||||
|
_statesetMap[*ssitr].insert(drawable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pushedDrawableStateState) popStateSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pushedGeodeStateState) popStateSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Optimizer::TextureAtlasVisitor::optimize()
|
void Optimizer::TextureAtlasVisitor::optimize()
|
||||||
{
|
{
|
||||||
osg::notify(osg::INFO) << "Num of StateSet="<<_statesets.size()<< std::endl;
|
|
||||||
|
|
||||||
_builder.reset();
|
_builder.reset();
|
||||||
|
|
||||||
|
if (_textures.size()<2)
|
||||||
|
{
|
||||||
|
// nothing to optimize
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Textures alreadyCheckedForRepeat;
|
||||||
|
|
||||||
|
StateSetMap::iterator sitr;
|
||||||
|
for(sitr = _statesetMap.begin();
|
||||||
|
sitr != _statesetMap.end();
|
||||||
|
++sitr)
|
||||||
|
{
|
||||||
|
osg::StateSet* stateset = sitr->first;
|
||||||
|
Drawables& drawables = sitr->second;
|
||||||
|
|
||||||
|
osg::StateSet::TextureAttributeList& tal = stateset->getTextureAttributeList();
|
||||||
|
for(unsigned int unit=0; unit<tal.size(); ++unit)
|
||||||
|
{
|
||||||
|
osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(stateset->getTextureAttribute(unit,osg::StateAttribute::TEXTURE));
|
||||||
|
if (texture && alreadyCheckedForRepeat.count(texture)==0)
|
||||||
|
{
|
||||||
|
alreadyCheckedForRepeat.insert(texture);
|
||||||
|
|
||||||
|
bool s_repeat = texture->getWrap(osg::Texture2D::WRAP_S)==osg::Texture2D::REPEAT ||
|
||||||
|
texture->getWrap(osg::Texture2D::WRAP_S)==osg::Texture2D::MIRROR;
|
||||||
|
|
||||||
|
bool t_repeat = texture->getWrap(osg::Texture2D::WRAP_T)==osg::Texture2D::REPEAT ||
|
||||||
|
texture->getWrap(osg::Texture2D::WRAP_T)==osg::Texture2D::MIRROR;
|
||||||
|
|
||||||
|
if (s_repeat || t_repeat)
|
||||||
|
{
|
||||||
|
bool s_outOfRange = false;
|
||||||
|
bool t_outOfRange = false;
|
||||||
|
|
||||||
|
float s_min = -0.001;
|
||||||
|
float s_max = 1.001;
|
||||||
|
|
||||||
|
float t_min = -0.001;
|
||||||
|
float t_max = 1.001;
|
||||||
|
|
||||||
|
for(Drawables::iterator ditr = drawables.begin();
|
||||||
|
ditr != drawables.end();
|
||||||
|
++ditr)
|
||||||
|
{
|
||||||
|
osg::Geometry* geom = (*ditr)->asGeometry();
|
||||||
|
osg::Vec2Array* texcoords = geom ? dynamic_cast<osg::Vec2Array*>(geom->getTexCoordArray(unit)) : 0;
|
||||||
|
if (texcoords)
|
||||||
|
{
|
||||||
|
for(osg::Vec2Array::iterator titr = texcoords->begin();
|
||||||
|
titr != texcoords->end() && !s_outOfRange && !t_outOfRange;
|
||||||
|
++titr)
|
||||||
|
{
|
||||||
|
osg::Vec2 tc = *titr;
|
||||||
|
if (tc[0]<s_min) { s_min = tc[0]; s_outOfRange = true; }
|
||||||
|
if (tc[0]>s_max) { s_max = tc[0]; s_outOfRange = true; }
|
||||||
|
|
||||||
|
if (tc[1]<t_min) { t_min = tc[1]; s_outOfRange = true; }
|
||||||
|
if (tc[1]>t_max) { t_max = tc[1]; s_outOfRange = true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if no texcoords then texgen must be being used, therefore must assume that texture is truely repeating
|
||||||
|
s_outOfRange = true;
|
||||||
|
t_outOfRange = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool s_canChangeToClamp = s_repeat && !s_outOfRange;
|
||||||
|
bool t_canChangeToClamp = t_repeat && !t_outOfRange;
|
||||||
|
if ((!s_repeat || s_canChangeToClamp) &&
|
||||||
|
(!t_repeat || t_canChangeToClamp))
|
||||||
|
{
|
||||||
|
// safe to convert into CLAMP wrap mode.
|
||||||
|
osg::notify(osg::INFO)<<"Changing wrap mode to CLAMP"<<std::endl;
|
||||||
|
if (s_canChangeToClamp) texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture::CLAMP);
|
||||||
|
if (t_canChangeToClamp) texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture::CLAMP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// add the textures as sources for the TextureAtlasBuilder
|
// add the textures as sources for the TextureAtlasBuilder
|
||||||
for(Textures::iterator titr = _textures.begin();
|
for(Textures::iterator titr = _textures.begin();
|
||||||
titr != _textures.end();
|
titr != _textures.end();
|
||||||
@ -3611,12 +3765,13 @@ void Optimizer::TextureAtlasVisitor::optimize()
|
|||||||
// build the atlas'
|
// build the atlas'
|
||||||
_builder.buildAtlas();
|
_builder.buildAtlas();
|
||||||
|
|
||||||
|
|
||||||
// remap the textures in the StateSet's
|
// remap the textures in the StateSet's
|
||||||
for(StateSets::iterator sitr = _statesets.begin();
|
for(sitr = _statesetMap.begin();
|
||||||
sitr != _statesets.end();
|
sitr != _statesetMap.end();
|
||||||
++sitr)
|
++sitr)
|
||||||
{
|
{
|
||||||
osg::StateSet* stateset = *sitr;
|
osg::StateSet* stateset = sitr->first;
|
||||||
osg::StateSet::TextureAttributeList& tal = stateset->getTextureAttributeList();
|
osg::StateSet::TextureAttributeList& tal = stateset->getTextureAttributeList();
|
||||||
for(unsigned int unit=0; unit<tal.size(); ++unit)
|
for(unsigned int unit=0; unit<tal.size(); ++unit)
|
||||||
{
|
{
|
||||||
@ -3627,7 +3782,54 @@ void Optimizer::TextureAtlasVisitor::optimize()
|
|||||||
if (newTexture && newTexture!=texture)
|
if (newTexture && newTexture!=texture)
|
||||||
{
|
{
|
||||||
stateset->setTextureAttribute(unit, newTexture);
|
stateset->setTextureAttribute(unit, newTexture);
|
||||||
stateset->setTextureAttribute(unit, new osg::TexMat(_builder.getTextureMatrix(texture)));
|
|
||||||
|
Drawables& drawables = sitr->second;
|
||||||
|
|
||||||
|
osg::Matrix matrix = _builder.getTextureMatrix(texture);
|
||||||
|
|
||||||
|
// first check to see if all drawables are ok for applying texturematrix to.
|
||||||
|
bool canTexMatBeFlattenedToAllDrawables = true;
|
||||||
|
for(Drawables::iterator ditr = drawables.begin();
|
||||||
|
ditr != drawables.end();
|
||||||
|
++ditr)
|
||||||
|
{
|
||||||
|
osg::Geometry* geom = (*ditr)->asGeometry();
|
||||||
|
osg::Vec2Array* texcoords = geom ? dynamic_cast<osg::Vec2Array*>(geom->getTexCoordArray(unit)) : 0;
|
||||||
|
|
||||||
|
if (!texcoords) canTexMatBeFlattenedToAllDrawables = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canTexMatBeFlattenedToAllDrawables)
|
||||||
|
{
|
||||||
|
// osg::notify(osg::NOTICE)<<"All drawables can be flattened "<<drawables.size()<<std::endl;
|
||||||
|
for(Drawables::iterator ditr = drawables.begin();
|
||||||
|
ditr != drawables.end();
|
||||||
|
++ditr)
|
||||||
|
{
|
||||||
|
osg::Geometry* geom = (*ditr)->asGeometry();
|
||||||
|
osg::Vec2Array* texcoords = geom ? dynamic_cast<osg::Vec2Array*>(geom->getTexCoordArray(unit)) : 0;
|
||||||
|
if (texcoords)
|
||||||
|
{
|
||||||
|
for(osg::Vec2Array::iterator titr = texcoords->begin();
|
||||||
|
titr != texcoords->end();
|
||||||
|
++titr)
|
||||||
|
{
|
||||||
|
osg::Vec2 tc = *titr;
|
||||||
|
(*titr).set(tc[0]*matrix(0,0) + tc[1]*matrix(1,0) + matrix(3,0),
|
||||||
|
tc[0]*matrix(0,1) + tc[1]*matrix(1,1) + matrix(3,1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
osg::notify(osg::NOTICE)<<"Error, Optimizer::TextureAtlasVisitor::optimize() shouldn't ever get here..."<<std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// osg::notify(osg::NOTICE)<<"Applying TexMat "<<drawables.size()<<std::endl;
|
||||||
|
stateset->setTextureAttribute(unit, new osg::TexMat(matrix));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user