Implement support for sphere map NiTextureEffects (Fixes #1827)

move
scrawl 9 years ago
parent 01497ac8db
commit 5f4ace1bc2

@ -19,14 +19,20 @@ void NiTextureEffect::read(NIFStream *nif)
{ {
NiDynamicEffect::read(nif); NiDynamicEffect::read(nif);
/* // Model Projection Matrix
3 x Vector4 = [1,0,0,0] nif->skip(3 * 3 * sizeof(float));
int = 2
int = 0 or 3 // Model Projection Transform
int = 2 nif->skip(3 * sizeof(float));
int = 2
*/ // Texture Filtering
nif->skip(16*4); nif->skip(4);
clamp = nif->getUInt();
textureType = (TextureType)nif->getUInt();
coordGenType = (CoordGenType)nif->getUInt();
texture.read(nif); texture.read(nif);

@ -70,6 +70,26 @@ struct NiSpotLight : public NiPointLight
struct NiTextureEffect : NiDynamicEffect struct NiTextureEffect : NiDynamicEffect
{ {
NiSourceTexturePtr texture; NiSourceTexturePtr texture;
unsigned int clamp;
enum TextureType
{
Projected_Light = 0,
Projected_Shadow = 1,
Environment_Map = 2,
Fog_Map = 3
};
TextureType textureType;
enum CoordGenType
{
World_Parallel = 0,
World_Perspective,
Sphere_Map,
Specular_Cube_Map,
Diffuse_Cube_Map
};
CoordGenType coordGenType;
void read(NIFStream *nif); void read(NIFStream *nif);
void post(NIFFile *nif); void post(NIFFile *nif);

@ -6,6 +6,7 @@
#include <osg/Geometry> #include <osg/Geometry>
#include <osg/Array> #include <osg/Array>
#include <osg/LOD> #include <osg/LOD>
#include <osg/TexGen>
// resource // resource
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
@ -36,6 +37,7 @@
#include <osg/TexEnvCombine> #include <osg/TexEnvCombine>
#include <components/nif/node.hpp> #include <components/nif/node.hpp>
#include <components/nif/effect.hpp>
#include <components/sceneutil/util.hpp> #include <components/sceneutil/util.hpp>
#include <components/sceneutil/skeleton.hpp> #include <components/sceneutil/skeleton.hpp>
#include <components/sceneutil/riggeometry.hpp> #include <components/sceneutil/riggeometry.hpp>
@ -439,6 +441,81 @@ namespace NifOsg
return lod; return lod;
} }
osg::ref_ptr<osg::Image> handleSourceTexture(const Nif::NiSourceTexture* st, Resource::ImageManager* imageManager)
{
if (!st)
return NULL;
osg::ref_ptr<osg::Image> image;
if (!st->external && !st->data.empty())
{
image = handleInternalTexture(st->data.getPtr());
}
else
{
std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, imageManager->getVFS());
image = imageManager->getImage(filename);
}
return image;
}
void handleEffect(const Nif::Node* nifNode, osg::Node* node, Resource::ImageManager* imageManager)
{
if (nifNode->recType != Nif::RC_NiTextureEffect)
{
std::cerr << "Unhandled effect " << nifNode->recName << " in " << mFilename << std::endl;
return;
}
const Nif::NiTextureEffect* textureEffect = static_cast<const Nif::NiTextureEffect*>(nifNode);
if (textureEffect->textureType != Nif::NiTextureEffect::Environment_Map)
{
std::cerr << "Unhandled NiTextureEffect type " << textureEffect->textureType << std::endl;
return;
}
osg::ref_ptr<osg::TexGen> texGen (new osg::TexGen);
switch (textureEffect->coordGenType)
{
case Nif::NiTextureEffect::World_Parallel:
texGen->setMode(osg::TexGen::OBJECT_LINEAR);
break;
case Nif::NiTextureEffect::World_Perspective:
texGen->setMode(osg::TexGen::EYE_LINEAR);
break;
case Nif::NiTextureEffect::Sphere_Map:
texGen->setMode(osg::TexGen::SPHERE_MAP);
break;
default:
std::cerr << "Unhandled NiTextureEffect coordGenType " << textureEffect->coordGenType << std::endl;
return;
}
osg::ref_ptr<osg::Texture2D> texture2d (new osg::Texture2D(handleSourceTexture(textureEffect->texture.getPtr(), imageManager)));
texture2d->setName("envMap");
unsigned int clamp = static_cast<unsigned int>(textureEffect->clamp);
int wrapT = (clamp) & 0x1;
int wrapS = (clamp >> 1) & 0x1;
texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP);
texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP);
osg::ref_ptr<osg::TexEnvCombine> texEnv = new osg::TexEnvCombine;
texEnv->setCombine_Alpha(osg::TexEnvCombine::REPLACE);
texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS);
texEnv->setCombine_RGB(osg::TexEnvCombine::ADD);
texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS);
texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE);
int texUnit = 3; // FIXME
osg::StateSet* stateset = node->getOrCreateStateSet();
stateset->setTextureAttributeAndModes(texUnit, texture2d, osg::StateAttribute::ON);
stateset->setTextureAttributeAndModes(texUnit, texGen, osg::StateAttribute::ON);
stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON);
stateset->addUniform(new osg::Uniform("envMapColor", osg::Vec4f(1,1,1,1)));
}
osg::ref_ptr<osg::Node> handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::ImageManager* imageManager, osg::ref_ptr<osg::Node> handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::ImageManager* imageManager,
std::vector<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)
{ {
@ -582,15 +659,20 @@ namespace NifOsg
const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(nifNode); const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(nifNode);
if(ninode) if(ninode)
{ {
const Nif::NodeList &effects = ninode->effects;
for (size_t i = 0; i < effects.length(); ++i)
{
if (!effects[i].empty())
handleEffect(effects[i].getPtr(), node, imageManager);
}
const Nif::NodeList &children = ninode->children; const Nif::NodeList &children = ninode->children;
for(size_t i = 0;i < children.length();++i) for(size_t i = 0;i < children.length();++i)
{ {
if(!children[i].empty()) if(!children[i].empty())
{
handleNode(children[i].getPtr(), node, imageManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); handleNode(children[i].getPtr(), node, imageManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode);
} }
} }
}
return node; return node;
} }
@ -707,8 +789,7 @@ namespace NifOsg
wrapT = inherit->getWrap(osg::Texture2D::WRAP_T); wrapT = inherit->getWrap(osg::Texture2D::WRAP_T);
} }
std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, imageManager->getVFS()); osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D(handleSourceTexture(st.getPtr(), imageManager)));
osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D(imageManager->getImage(filename)));
texture->setWrap(osg::Texture::WRAP_S, wrapS); texture->setWrap(osg::Texture::WRAP_S, wrapS);
texture->setWrap(osg::Texture::WRAP_T, wrapT); texture->setWrap(osg::Texture::WRAP_T, wrapT);
textures.push_back(texture); textures.push_back(texture);
@ -1318,17 +1399,8 @@ namespace NifOsg
std::cerr << "Warning: texture layer " << i << " is in use but empty in " << mFilename << std::endl; std::cerr << "Warning: texture layer " << i << " is in use but empty in " << mFilename << std::endl;
continue; continue;
} }
osg::ref_ptr<osg::Image> image;
const Nif::NiSourceTexture *st = tex.texture.getPtr(); const Nif::NiSourceTexture *st = tex.texture.getPtr();
if (!st->external && !st->data.empty()) osg::ref_ptr<osg::Image> image = handleSourceTexture(st, imageManager);
{
image = handleInternalTexture(st->data.getPtr());
}
else
{
std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, imageManager->getVFS());
image = imageManager->getImage(filename);
}
unsigned int clamp = static_cast<unsigned int>(tex.clamp); unsigned int clamp = static_cast<unsigned int>(tex.clamp);
int wrapT = (clamp) & 0x1; int wrapT = (clamp) & 0x1;

Loading…
Cancel
Save