예제 #1
0
파일: skeleton.cpp 프로젝트: rainChu/openmw
void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent)
{
    Ogre::Bone *bone;
    if(!skel->hasBone(node->name))
        bone = skel->createBone(node->name);
    else
        bone = skel->createBone();
    if(parent) parent->addChild(bone);
    mNifToOgreHandleMap[node->recIndex] = bone->getHandle();

    bone->setOrientation(node->trafo.rotation);
    bone->setPosition(node->trafo.pos);
    bone->setScale(Ogre::Vector3(node->trafo.scale));
    bone->setBindingPose();

    if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */
         node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */
         node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */
         node->recType == Nif::RC_NiBSAnimationNode || /* Handled in the object loader */
         node->recType == Nif::RC_NiBillboardNode || /* Handled in the object loader */
         node->recType == Nif::RC_NiBSParticleNode ||
         node->recType == Nif::RC_NiCamera ||
         node->recType == Nif::RC_NiAutoNormalParticles ||
         node->recType == Nif::RC_NiRotatingParticles
         ))
        warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName());

    Nif::ControllerPtr ctrl = node->controller;
    while(!ctrl.empty())
    {
        if(!(ctrl->recType == Nif::RC_NiParticleSystemController ||
             ctrl->recType == Nif::RC_NiVisController ||
             ctrl->recType == Nif::RC_NiUVController ||
             ctrl->recType == Nif::RC_NiKeyframeController ||
             ctrl->recType == Nif::RC_NiGeomMorpherController
             ))
            warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName());
        ctrl = ctrl->next;
    }

    const Nif::NiNode *ninode = dynamic_cast<const Nif::NiNode*>(node);
    if(ninode)
    {
        const Nif::NodeList &children = ninode->children;
        for(size_t i = 0;i < children.length();i++)
        {
            if(!children[i].empty())
                buildBones(skel, children[i].getPtr(), bone);
        }
    }
}
예제 #2
0
Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata,
                                            const Ogre::String &name, const Ogre::String &group,
                                            const Nif::NiTexturingProperty *texprop,
                                            const Nif::NiMaterialProperty *matprop,
                                            const Nif::NiAlphaProperty *alphaprop,
                                            const Nif::NiVertexColorProperty *vertprop,
                                            const Nif::NiZBufferProperty *zprop,
                                            const Nif::NiSpecularProperty *specprop,
                                            const Nif::NiWireframeProperty *wireprop,
                                            const Nif::NiStencilProperty *stencilprop,
                                            bool &needTangents, bool particleMaterial)
{
    Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton();
    Ogre::MaterialPtr material = matMgr.getByName(name);
    if(!material.isNull())
        return name;

    Ogre::Vector3 ambient(1.0f);
    Ogre::Vector3 diffuse(1.0f);
    Ogre::Vector3 specular(0.0f);
    Ogre::Vector3 emissive(0.0f);
    float glossiness = 0.0f;
    float alpha = 1.0f;
    int alphaFlags = 0;
    int alphaTest = 0;
    int vertMode = 2;
    //int lightMode = 1;
    int depthFlags = 3;
    // Default should be 1, but Bloodmoon's models are broken
    int specFlags = 0;
    int wireFlags = 0;
    int drawMode = 1;
    Ogre::String texName[7];

    bool vertexColour = (shapedata->colors.size() != 0);

    // Texture
    if(texprop)
    {
        for(int i = 0;i < 7;i++)
        {
            if(!texprop->textures[i].inUse)
                continue;
            if(texprop->textures[i].texture.empty())
            {
                warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name);
                continue;
            }

            const Nif::NiSourceTexture *st = texprop->textures[i].texture.getPtr();
            if(st->external)
                texName[i] = Misc::ResourceHelpers::correctTexturePath(st->filename);
            else
                warn("Found internal texture, ignoring.");
        }

        Nif::ControllerPtr ctrls = texprop->controller;
        while(!ctrls.empty())
        {
            if (ctrls->recType != Nif::RC_NiFlipController) // Handled in ogrenifloader
                warn("Unhandled texture controller "+ctrls->recName+" in "+name);
            ctrls = ctrls->next;
        }
    }

    // Alpha modifiers
    if(alphaprop)
    {
        alphaFlags = alphaprop->flags;
        alphaTest = alphaprop->data.threshold;

        Nif::ControllerPtr ctrls = alphaprop->controller;
        while(!ctrls.empty())
        {
            warn("Unhandled alpha controller "+ctrls->recName+" in "+name);
            ctrls = ctrls->next;
        }
    }

    // Vertex color handling
    if(vertprop)
    {
        vertMode = vertprop->data.vertmode;
        // FIXME: Handle lightmode?
        //lightMode = vertprop->data.lightmode;

        Nif::ControllerPtr ctrls = vertprop->controller;
        while(!ctrls.empty())
        {
            warn("Unhandled vertex color controller "+ctrls->recName+" in "+name);
            ctrls = ctrls->next;
        }
    }

    if(zprop)
    {
        depthFlags = zprop->flags;
        // Depth function???

        Nif::ControllerPtr ctrls = zprop->controller;
        while(!ctrls.empty())
        {
            warn("Unhandled depth controller "+ctrls->recName+" in "+name);
            ctrls = ctrls->next;
        }
    }

    if(specprop)
    {
        specFlags = specprop->flags;

        Nif::ControllerPtr ctrls = specprop->controller;
        while(!ctrls.empty())
        {
            warn("Unhandled specular controller "+ctrls->recName+" in "+name);
            ctrls = ctrls->next;
        }
    }

    if(wireprop)
    {
        wireFlags = wireprop->flags;

        Nif::ControllerPtr ctrls = wireprop->controller;
        while(!ctrls.empty())
        {
            warn("Unhandled wireframe controller "+ctrls->recName+" in "+name);
            ctrls = ctrls->next;
        }
    }

    if(stencilprop)
    {
        drawMode = stencilprop->data.drawMode;
        if (stencilprop->data.enabled)
            warn("Unhandled stencil test in "+name);

        Nif::ControllerPtr ctrls = stencilprop->controller;
        while(!ctrls.empty())
        {
            warn("Unhandled stencil controller "+ctrls->recName+" in "+name);
            ctrls = ctrls->next;
        }
    }

    // Material
    if(matprop)
    {
        ambient = matprop->data.ambient;
        diffuse = matprop->data.diffuse;
        specular = matprop->data.specular;
        emissive = matprop->data.emissive;
        glossiness = matprop->data.glossiness;
        alpha = matprop->data.alpha;

        Nif::ControllerPtr ctrls = matprop->controller;
        while(!ctrls.empty())
        {
            if (ctrls->recType != Nif::RC_NiAlphaController && ctrls->recType != Nif::RC_NiMaterialColorController)
                warn("Unhandled material controller "+ctrls->recName+" in "+name);
            ctrls = ctrls->next;
        }
    }

    if (particleMaterial)
    {
        alpha = 1.f; // Apparently ignored, might be overridden by particle vertex colors?
    }

    {
        // Generate a hash out of all properties that can affect the material.
        size_t h = 0;
        boost::hash_combine(h, ambient.x);
        boost::hash_combine(h, ambient.y);
        boost::hash_combine(h, ambient.z);
        boost::hash_combine(h, diffuse.x);
        boost::hash_combine(h, diffuse.y);
        boost::hash_combine(h, diffuse.z);
        boost::hash_combine(h, alpha);
        boost::hash_combine(h, specular.x);
        boost::hash_combine(h, specular.y);
        boost::hash_combine(h, specular.z);
        boost::hash_combine(h, glossiness);
        boost::hash_combine(h, emissive.x);
        boost::hash_combine(h, emissive.y);
        boost::hash_combine(h, emissive.z);
        for(int i = 0;i < 7;i++)
        {
            if(!texName[i].empty())
            {
                boost::hash_combine(h, texName[i]);
                boost::hash_combine(h, texprop->textures[i].clamp);
                boost::hash_combine(h, texprop->textures[i].uvSet);
            }
        }
        boost::hash_combine(h, drawMode);
        boost::hash_combine(h, vertexColour);
        boost::hash_combine(h, alphaFlags);
        boost::hash_combine(h, alphaTest);
        boost::hash_combine(h, vertMode);
        boost::hash_combine(h, depthFlags);
        boost::hash_combine(h, specFlags);
        boost::hash_combine(h, wireFlags);

        std::map<size_t,std::string>::iterator itr = sMaterialMap.find(h);
        if (itr != sMaterialMap.end())
        {
            // a suitable material exists already - use it
            sh::MaterialInstance* instance = sh::Factory::getInstance().getMaterialInstance(itr->second);
            needTangents = !sh::retrieveValue<sh::StringValue>(instance->getProperty("normalMap"), instance).get().empty();
            return itr->second;
        }
        // not found, create a new one
        sMaterialMap.insert(std::make_pair(h, name));
    }

    // No existing material like this. Create a new one.
    sh::MaterialInstance *instance = sh::Factory::getInstance().createMaterialInstance(name, "openmw_objects_base");
    if(vertMode == 0 || !vertexColour)
    {
        instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1)));
        instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha)));
        instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1)));
        instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("0")));
    }
    else if(vertMode == 1)
    {
        instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1)));
        instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha)));
        instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour")));
        instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("1")));
    }
    else if(vertMode == 2)
    {
        instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour")));
        instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour")));
        instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1)));
        instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("2")));
    }
    else
        std::cerr<< "Unhandled vertex mode: "<<vertMode <<std::endl;

    if(specFlags)
    {
        instance->setProperty("specular", sh::makeProperty(
            new sh::Vector4(specular.x, specular.y, specular.z, glossiness)));
    }

    if(wireFlags)
    {
        instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe")));
    }

    if (drawMode == 1)
        instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("clockwise")));
    else if (drawMode == 2)
        instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("anticlockwise")));
    else if (drawMode == 3)
        instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("none")));

    instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture]));
    instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture]));
    instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture]));
    instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture]));
    instance->setProperty("darkMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DarkTexture]));
    if (!texName[Nif::NiTexturingProperty::BaseTexture].empty())
    {
        instance->setProperty("use_diffuse_map", sh::makeProperty(new sh::BooleanValue(true)));
        setTextureProperties(instance, "diffuseMap", texprop->textures[Nif::NiTexturingProperty::BaseTexture]);
    }
    if (!texName[Nif::NiTexturingProperty::GlowTexture].empty())
    {
        instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true)));
        setTextureProperties(instance, "emissiveMap", texprop->textures[Nif::NiTexturingProperty::GlowTexture]);
    }
    if (!texName[Nif::NiTexturingProperty::DetailTexture].empty())
    {
        instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true)));
        setTextureProperties(instance, "detailMap", texprop->textures[Nif::NiTexturingProperty::DetailTexture]);
    }
    if (!texName[Nif::NiTexturingProperty::DarkTexture].empty())
    {
        instance->setProperty("use_dark_map", sh::makeProperty(new sh::BooleanValue(true)));
        setTextureProperties(instance, "darkMap", texprop->textures[Nif::NiTexturingProperty::DarkTexture]);
    }

    bool useParallax = !texName[Nif::NiTexturingProperty::BumpTexture].empty()
            && texName[Nif::NiTexturingProperty::BumpTexture].find("_nh.") != std::string::npos;
    instance->setProperty("use_parallax", sh::makeProperty(new sh::BooleanValue(useParallax)));

    for(int i = 0;i < 7;i++)
    {
        if(i == Nif::NiTexturingProperty::BaseTexture ||
           i == Nif::NiTexturingProperty::DetailTexture ||
           i == Nif::NiTexturingProperty::DarkTexture ||
           i == Nif::NiTexturingProperty::BumpTexture ||
           i == Nif::NiTexturingProperty::GlowTexture)
            continue;
        if(!texName[i].empty())
            warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i) + " in " + name);
    }

    if (vertexColour)
        instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true)));

    // Override alpha flags based on our override list (transparency-overrides.cfg)
    if ((alphaFlags&1) && !texName[0].empty())
    {
        NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]);
        if (result.first)
        {
            alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */
            alphaTest = result.second;
            depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on
        }
    }

    // Add transparency if NiAlphaProperty was present
    if((alphaFlags&1))
    {
        std::string blend_mode;
        blend_mode += getBlendFactor((alphaFlags>>1)&0xf);
        blend_mode += " ";
        blend_mode += getBlendFactor((alphaFlags>>5)&0xf);
        instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode)));
    }