diff --git a/components/nif/effect.cpp b/components/nif/effect.cpp index 79cd10431..7947e301d 100644 --- a/components/nif/effect.cpp +++ b/components/nif/effect.cpp @@ -19,14 +19,20 @@ void NiTextureEffect::read(NIFStream *nif) { NiDynamicEffect::read(nif); - /* - 3 x Vector4 = [1,0,0,0] - int = 2 - int = 0 or 3 - int = 2 - int = 2 - */ - nif->skip(16*4); + // Model Projection Matrix + nif->skip(3 * 3 * sizeof(float)); + + // Model Projection Transform + nif->skip(3 * sizeof(float)); + + // Texture Filtering + nif->skip(4); + + clamp = nif->getUInt(); + + textureType = (TextureType)nif->getUInt(); + + coordGenType = (CoordGenType)nif->getUInt(); texture.read(nif); diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index 02647e444..015809a68 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -70,6 +70,26 @@ struct NiSpotLight : public NiPointLight struct NiTextureEffect : NiDynamicEffect { 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 post(NIFFile *nif); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 975d6d6e0..53a0cdc19 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -6,6 +6,7 @@ #include #include #include +#include // resource #include @@ -36,6 +37,7 @@ #include #include +#include #include #include #include @@ -439,6 +441,81 @@ namespace NifOsg return lod; } + osg::ref_ptr handleSourceTexture(const Nif::NiSourceTexture* st, Resource::ImageManager* imageManager) + { + if (!st) + return NULL; + + osg::ref_ptr 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(nifNode); + if (textureEffect->textureType != Nif::NiTextureEffect::Environment_Map) + { + std::cerr << "Unhandled NiTextureEffect type " << textureEffect->textureType << std::endl; + return; + } + + osg::ref_ptr 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 texture2d (new osg::Texture2D(handleSourceTexture(textureEffect->texture.getPtr(), imageManager))); + texture2d->setName("envMap"); + unsigned int clamp = static_cast(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 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 handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::ImageManager* imageManager, std::vector boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL) { @@ -582,13 +659,18 @@ namespace NifOsg const Nif::NiNode *ninode = dynamic_cast(nifNode); 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; for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - { handleNode(children[i].getPtr(), node, imageManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode); - } } } @@ -707,8 +789,7 @@ namespace NifOsg wrapT = inherit->getWrap(osg::Texture2D::WRAP_T); } - std::string filename = Misc::ResourceHelpers::correctTexturePath(st->filename, imageManager->getVFS()); - osg::ref_ptr texture (new osg::Texture2D(imageManager->getImage(filename))); + osg::ref_ptr texture (new osg::Texture2D(handleSourceTexture(st.getPtr(), imageManager))); texture->setWrap(osg::Texture::WRAP_S, wrapS); texture->setWrap(osg::Texture::WRAP_T, wrapT); 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; continue; } - osg::ref_ptr image; const Nif::NiSourceTexture *st = tex.texture.getPtr(); - 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); - } + osg::ref_ptr image = handleSourceTexture(st, imageManager); unsigned int clamp = static_cast(tex.clamp); int wrapT = (clamp) & 0x1;