1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-19 22:23:51 +00:00

Make better use of the available texture units (Bug #2702)

Nvidia drivers only support a maximum of 4 fixed function texture units. To resolve this problem, bind texture units in order instead of binding to the NiTexturingProperty::TextureType unit.
This commit is contained in:
scrawl 2015-06-17 20:32:10 +02:00
parent 3ebfb4e0d9
commit 81a4a6da6b

View file

@ -344,7 +344,7 @@ namespace NifOsg
osg::ref_ptr<TextKeyMapHolder> textkeys (new TextKeyMapHolder); osg::ref_ptr<TextKeyMapHolder> textkeys (new TextKeyMapHolder);
osg::ref_ptr<osg::Node> created = handleNode(nifNode, NULL, textureManager, std::map<int, int>(), 0, 0, false, &textkeys->mTextKeys); osg::ref_ptr<osg::Node> created = handleNode(nifNode, NULL, textureManager, std::vector<int>(), 0, 0, false, &textkeys->mTextKeys);
if (nif->getUseSkinning()) if (nif->getUseSkinning())
{ {
@ -357,7 +357,7 @@ namespace NifOsg
return created; return created;
} }
void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map<int, int>& boundTextures, int animflags) void applyNodeProperties(const Nif::Node *nifNode, osg::Node *applyTo, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::vector<int>& boundTextures, int animflags)
{ {
const Nif::PropertyList& props = nifNode->props; const Nif::PropertyList& props = nifNode->props;
for (size_t i = 0; i <props.length();++i) for (size_t i = 0; i <props.length();++i)
@ -412,7 +412,7 @@ namespace NifOsg
} }
osg::ref_ptr<osg::Node> handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager, osg::ref_ptr<osg::Node> handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::TextureManager* textureManager,
std::map<int, int> boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) std::vector<int> boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL)
{ {
osg::ref_ptr<osg::Group> node = new osg::MatrixTransform(nifNode->trafo.toMatrix()); osg::ref_ptr<osg::Group> node = new osg::MatrixTransform(nifNode->trafo.toMatrix());
@ -558,7 +558,7 @@ namespace NifOsg
return node; return node;
} }
void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map<int, int> &boundTextures, int animflags) void handleMeshControllers(const Nif::Node *nifNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int> &boundTextures, int animflags)
{ {
for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next)
{ {
@ -568,8 +568,8 @@ namespace NifOsg
{ {
const Nif::NiUVController *uvctrl = static_cast<const Nif::NiUVController*>(ctrl.getPtr()); const Nif::NiUVController *uvctrl = static_cast<const Nif::NiUVController*>(ctrl.getPtr());
std::set<int> texUnits; std::set<int> texUnits;
for (std::map<int, int>::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) for (unsigned int i=0; i<boundTextures.size(); ++i)
texUnits.insert(it->first); texUnits.insert(i);
osg::ref_ptr<UVController> ctrl = new UVController(uvctrl->data.getPtr(), texUnits); osg::ref_ptr<UVController> ctrl = new UVController(uvctrl->data.getPtr(), texUnits);
setupController(uvctrl, ctrl, animflags); setupController(uvctrl, ctrl, animflags);
@ -888,7 +888,7 @@ namespace NifOsg
} }
} }
void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map<int, int>& boundTextures, int animflags) void triShapeToGeometry(const Nif::NiTriShape *triShape, osg::Geometry *geometry, osg::Node* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
{ {
const Nif::NiTriShapeData* data = triShape->data.getPtr(); const Nif::NiTriShapeData* data = triShape->data.getPtr();
@ -898,10 +898,10 @@ namespace NifOsg
geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), &data->normals[0]), osg::Array::BIND_PER_VERTEX); geometry->setNormalArray(new osg::Vec3Array(data->normals.size(), &data->normals[0]), osg::Array::BIND_PER_VERTEX);
} }
for (std::map<int, int>::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it) int textureStage = 0;
for (std::vector<int>::const_iterator it = boundTextures.begin(); it != boundTextures.end(); ++it,++textureStage)
{ {
int textureStage = it->first; int uvSet = *it;
int uvSet = it->second;
if (uvSet >= (int)data->uvlist.size()) if (uvSet >= (int)data->uvlist.size())
{ {
// Occurred in "ascendedsleeper.nif", but only for hidden Shadow nodes, apparently // Occurred in "ascendedsleeper.nif", but only for hidden Shadow nodes, apparently
@ -928,7 +928,7 @@ namespace NifOsg
applyMaterialProperties(parentNode, materialProps, composite, !data->colors.empty(), animflags); applyMaterialProperties(parentNode, materialProps, composite, !data->colors.empty(), animflags);
} }
void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::map<int, int>& boundTextures, int animflags) void handleTriShape(const Nif::NiTriShape* triShape, osg::Group* parentNode, SceneUtil::CompositeStateSetUpdater* composite, const std::vector<int>& boundTextures, int animflags)
{ {
osg::ref_ptr<osg::Geometry> geometry; osg::ref_ptr<osg::Geometry> geometry;
if(!triShape->controller.empty()) if(!triShape->controller.empty())
@ -1027,7 +1027,7 @@ namespace NifOsg
} }
void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, void handleSkinnedTriShape(const Nif::NiTriShape *triShape, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite,
const std::map<int, int>& boundTextures, int animflags) const std::vector<int>& boundTextures, int animflags)
{ {
osg::ref_ptr<osg::Geode> geode (new osg::Geode); osg::ref_ptr<osg::Geode> geode (new osg::Geode);
@ -1152,7 +1152,7 @@ namespace NifOsg
} }
void handleProperty(const Nif::Property *property, void handleProperty(const Nif::Property *property,
osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::map<int, int>& boundTextures, int animflags) osg::Node *node, SceneUtil::CompositeStateSetUpdater* composite, Resource::TextureManager* textureManager, std::vector<int>& boundTextures, int animflags)
{ {
switch (property->recType) switch (property->recType)
{ {
@ -1254,6 +1254,15 @@ namespace NifOsg
{ {
const Nif::NiTexturingProperty* texprop = static_cast<const Nif::NiTexturingProperty*>(property); const Nif::NiTexturingProperty* texprop = static_cast<const Nif::NiTexturingProperty*>(property);
osg::StateSet* stateset = node->getOrCreateStateSet(); osg::StateSet* stateset = node->getOrCreateStateSet();
if (boundTextures.size())
{
// overriding a parent NiTexturingProperty, so remove what was previously bound
for (unsigned int i=0; i<boundTextures.size(); ++i)
stateset->setTextureMode(i, GL_TEXTURE_2D, osg::StateAttribute::OFF);
boundTextures.clear();
}
for (int i=0; i<Nif::NiTexturingProperty::NumTextures; ++i) for (int i=0; i<Nif::NiTexturingProperty::NumTextures; ++i)
{ {
if (texprop->textures[i].inUse) if (texprop->textures[i].inUse)
@ -1290,19 +1299,21 @@ namespace NifOsg
wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP,
wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP); wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP);
stateset->setTextureAttributeAndModes(i, texture2d, osg::StateAttribute::ON); int texUnit = boundTextures.size();
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
if (i == Nif::NiTexturingProperty::GlowTexture) if (i == Nif::NiTexturingProperty::GlowTexture)
{ {
osg::TexEnv* texEnv = new osg::TexEnv; osg::TexEnv* texEnv = new osg::TexEnv;
texEnv->setMode(osg::TexEnv::ADD); texEnv->setMode(osg::TexEnv::ADD);
stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON);
} }
else if (i == Nif::NiTexturingProperty::DarkTexture) else if (i == Nif::NiTexturingProperty::DarkTexture)
{ {
osg::TexEnv* texEnv = new osg::TexEnv; osg::TexEnv* texEnv = new osg::TexEnv;
texEnv->setMode(osg::TexEnv::MODULATE); texEnv->setMode(osg::TexEnv::MODULATE);
stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON);
} }
else if (i == Nif::NiTexturingProperty::DetailTexture) else if (i == Nif::NiTexturingProperty::DetailTexture)
{ {
@ -1318,15 +1329,10 @@ namespace NifOsg
texEnv->setOperand1_RGB(GL_SRC_COLOR); texEnv->setOperand1_RGB(GL_SRC_COLOR);
texEnv->setSource0_RGB(GL_PREVIOUS_ARB); texEnv->setSource0_RGB(GL_PREVIOUS_ARB);
texEnv->setSource1_RGB(GL_TEXTURE); texEnv->setSource1_RGB(GL_TEXTURE);
stateset->setTextureAttributeAndModes(i, texEnv, osg::StateAttribute::ON); stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON);
} }
boundTextures[i] = tex.uvSet; boundTextures.push_back(tex.uvSet);
}
else if (boundTextures.find(i) != boundTextures.end())
{
stateset->setTextureAttributeAndModes(i, new osg::Texture2D, osg::StateAttribute::OFF);
boundTextures.erase(i);
} }
handleTextureControllers(texprop, composite, textureManager, stateset, animflags); handleTextureControllers(texprop, composite, textureManager, stateset, animflags);
} }