Esempio n. 1
0
    void Actor::doAttach(
        Actor* actor,
        const Ogre::String& slot, 
        const Ogre::String& childSlot, 
        const Ogre::Vector3& offsetPosition,
        const Ogre::Quaternion& offsetOrientation ) 
    {
        Ogre::Vector3 offsetPositionMod = offsetPosition;
        Ogre::Quaternion offsetOrientationMod = offsetOrientation;

        if( actor == NULL )
            Throw(NullPointerException, 
            "Aktor "+mName+": Der anzufügende Aktor darf nicht NULL sein." );
        if( actor->mParent != NULL )
            Throw(NullPointerException, 
            "Aktor "+mName+": Der Aktor ist bereits an einen anderen Aktor angefügt." );

        // Verschiebung durch den Child-Slot berechnen
        // Ist es ein nicht Standard-Slot && Kontrolliert der Aktor ein Objekt && Ist dieses ein Mesh
        if( childSlot.compare(DEFAULT_SLOT_NAME) != 0 &&
            actor->getControlledObject() != NULL && 
            actor->getControlledObject()->isMeshObject() )
        {
            Entity* ent = dynamic_cast<MeshObject*>(actor->getControlledObject())->getEntity();

            // Braucht ein Skelett
            if( !ent->hasSkeleton() )
                Throw(IllegalArgumentException, 
                "Aktor "+mName+": Das kontrollierte MeshObject des ChildAktor hat kein Skeleton." );

            // Der Slot muss existieren
            try
            {
                Bone* bone = ent->getSkeleton()->getBone( childSlot );

                Vector3 vec = bone->_getDerivedPosition();
                Quaternion quat = bone->_getDerivedOrientation();

                // Durch den Bone ExtraOffset hinzufügen
                offsetOrientationMod = offsetOrientation *  quat;
                offsetPositionMod = ( offsetOrientationMod * (-vec) ) + offsetPosition;
            }
            catch (Ogre::Exception) {
                Throw(IllegalArgumentException, 
                    "Aktor "+mName+": Der geforderte Slot '"+childSlot+"' am ChildAktor existiert nicht." );
            }
        }

        // Das wirkliche Anfügen
        // Ist es ein nicht Standard-Slot && Kontrolliert der Aktor ein Objekt && Ist dieses ein Mesh
        if( slot.compare(DEFAULT_SLOT_NAME) != 0 && 
            getControlledObject() != NULL && 
            getControlledObject()->isMeshObject() )
        {
            if( actor->getControlledObject() == NULL )
                Throw(IllegalArgumentException, 
                "Aktor "+mName+": Der zu befestigende Aktor darf bei SLOTs nicht leer sein." );

            MovableObject* movObj = actor->getControlledObject()->getMovableObject();
            Entity* ent = dynamic_cast<MeshObject*>(getControlledObject())->getEntity();

            // Braucht ein Skelett
            if( !ent->hasSkeleton() )
                Throw(IllegalArgumentException, 
                "Aktor "+mName+": Das kontrollierte MeshObject hat kein Skeleton." );

            // Der Slot muss existieren
            try
            {
                ent->getSkeleton()->getBone( slot );
            }
            catch (Ogre::Exception) {
                Throw(IllegalArgumentException, 
                    "Aktor "+mName+": Der geforderte Slot '"+slot+"' existiert nicht." );
            }

            // Am Bone befestigen
            ent->attachObjectToBone( slot, movObj, offsetOrientationMod, offsetPositionMod );
            // Der Aktor wurde an einem Bone befestigt
            actor->mBone = ent->getSkeleton()->getBone( slot );

            return;
        }
        // Wenn hier kein MeshObjekt dran ist, trotzdem irgendwie zusammenfügen
        else
        {
            actor->placeIntoNode( mSceneNode,  offsetPositionMod, offsetOrientationMod );

            // Der Aktor wurde nicht an einem Bone befestigt
            actor->mBone = 0;
            return;      
        }
    }         
Esempio n. 2
0
void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bounds, Transformation original, std::vector<std::string> boneSequence)
{
    assert(shape != NULL);

    bool saveTheShape = inTheSkeletonTree;
    // Interpret flags
    bool hidden    = (flags & 0x01) != 0; // Not displayed
    bool collide   = (flags & 0x02) != 0; // Use mesh for collision
    bool bbcollide = (flags & 0x04) != 0; // Use bounding box for collision

    // Bounding box collision isn't implemented, always use mesh for now.
    if (bbcollide)
    {
        collide = true;
        bbcollide = false;
    }

    // If the object was marked "NCO" earlier, it shouldn't collide with
    // anything.
    if (flags & 0x800)
    {
        collide = false;
        bbcollide = false;
    }

    if (!collide && !bbcollide && hidden)
        // This mesh apparently isn't being used for anything, so don't
        // bother setting it up.
        return;

    // Material name for this submesh, if any
    String material;

    // Skip the entire material phase for hidden nodes
    if (!hidden)
    {
        // These are set below if present
        NiTexturingProperty *t = NULL;
        NiMaterialProperty *m = NULL;
        NiAlphaProperty *a = NULL;

        // Scan the property list for material information
        PropertyList &list = shape->props;
        int n = list.length();
        for (int i=0; i<n; i++)
        {
            // Entries may be empty
            if (!list.has(i)) continue;

            Property *pr = &list[i];

            if (pr->recType == RC_NiTexturingProperty)
                t = (NiTexturingProperty*)pr;
            else if (pr->recType == RC_NiMaterialProperty)
                m = (NiMaterialProperty*)pr;
            else if (pr->recType == RC_NiAlphaProperty)
                a = (NiAlphaProperty*)pr;
        }

        // Texture
        String texName;
        if (t && t->textures[0].inUse)
        {
            NiSourceTexture *st = t->textures[0].texture.getPtr();
            if (st->external)
            {
                SString tname = st->filename;

                /* findRealTexture checks if the file actually
                   exists. If it doesn't, and the name ends in .tga, it
                   will try replacing the extension with .dds instead
                   and search for that. Bethesda at some at some point
                   converted all their BSA textures from tga to dds for
                   increased load speed, but all texture file name
                   references were kept as .tga.

                   The function replaces the name in place (that's why
                   we cast away the const modifier), but this is no
                   problem since all the nif data is stored in a local
                   throwaway buffer.
                 */
                texName = "textures\\" + tname.toString();
                findRealTexture(texName);
            }
            else warn("Found internal texture, ignoring.");
        }

        // Alpha modifiers
        int alphaFlags = -1;
        ubyte alphaTest = 0;
        if (a)
        {
            alphaFlags = a->flags;
            alphaTest  = a->data->threshold;
        }

        // Material
        if (m || !texName.empty())
        {
            // If we're here, then this mesh has a material. Thus we
            // need to calculate a snappy material name. It should
            // contain the mesh name (mesh->getName()) but also has to
            // be unique. One mesh may use many materials.
            material = getUniqueName(mesh->getName());

            if (m)
            {
                // Use NiMaterialProperty data to create the data
                const S_MaterialProperty *d = m->data;

                std::multimap<std::string,std::string>::iterator itr = MaterialMap.find(texName);
                std::multimap<std::string,std::string>::iterator lastElement;
                lastElement = MaterialMap.upper_bound(texName);
                if (itr != MaterialMap.end())
                {
                    for ( ; itr != lastElement; ++itr)
                    {
                        //std::cout << "OK!";
                        //MaterialPtr mat = MaterialManager::getSingleton().getByName(itr->second,recourceGroup);
                        material = itr->second;
                        //if( mat->getA
                    }
                }
                else
                {
                    //std::cout << "new";
                    createMaterial(material, d->ambient, d->diffuse, d->specular, d->emissive,
                                    d->glossiness, d->alpha, alphaFlags, alphaTest, texName);
                    MaterialMap.insert(std::make_pair(texName,material));
                }
            }
            else
            {
                // We only have a texture name. Create a default
                // material for it.
                Vector zero, one;
                for (int i=0; i<3;i++)
                {
                    zero.array[i] = 0.0;
                    one.array[i] = 1.0;
                }

                createMaterial(material, one, one, zero, zero, 0.0, 1.0,
                               alphaFlags, alphaTest, texName);
            }
        }
    } // End of material block, if(!hidden) ...

    /* Do in-place transformation of all the vertices and normals. This
       is pretty messy stuff, but we need it to make the sub-meshes
       appear in the correct place. Neither Ogre nor Bullet support
       nested levels of sub-meshes with transformations applied to each
       level.
    */
    NiTriShapeData *data = shape->data.getPtr();
    int numVerts = data->vertices.length / 3;

    float *ptr = (float*)data->vertices.ptr;
    float *optr = ptr;

    std::list<VertexBoneAssignment> vertexBoneAssignments;

    Nif::NiTriShapeCopy copy = shape->clone();
   
	if(!shape->controller.empty())
	{
		Nif::Controller* cont = shape->controller.getPtr();
		if(cont->recType == RC_NiGeomMorpherController)
		{
			Nif::NiGeomMorpherController* morph = dynamic_cast<Nif::NiGeomMorpherController*> (cont);
			copy.morph = morph->data.get();
			copy.morph.setStartTime(morph->timeStart);
			copy.morph.setStopTime(morph->timeStop);
            saveTheShape = true;
		}

	}
    //use niskindata for the position of vertices.
    if (!shape->skin.empty())
    {



        // vector that stores if the position of a vertex is absolute
        std::vector<bool> vertexPosAbsolut(numVerts,false);
		std::vector<Ogre::Vector3> vertexPosOriginal(numVerts, Ogre::Vector3::ZERO);
		std::vector<Ogre::Vector3> vertexNormalOriginal(numVerts, Ogre::Vector3::ZERO);

        float *ptrNormals = (float*)data->normals.ptr;
        //the bone from skin->bones[boneIndex] is linked to skin->data->bones[boneIndex]
        //the first one contains a link to the bone, the second vertex transformation
        //relative to the bone
        int boneIndex = 0;
        Bone *bonePtr;
        Vector3 vecPos;
        Quaternion vecRot;

        std::vector<NiSkinData::BoneInfo> boneList = shape->skin->data->bones;

        /*
        Iterate through the boneList which contains what vertices are linked to
        the bone (it->weights array) and at what position (it->trafo)
        That position is added to every vertex.
        */
        for (std::vector<NiSkinData::BoneInfo>::iterator it = boneList.begin();
                it != boneList.end(); it++)
        {
            if(mSkel.isNull())
            {
                std::cout << "No skeleton for :" << shape->skin->bones[boneIndex].name.toString() << std::endl;
                break;
            }
            //get the bone from bones array of skindata
			if(!mSkel->hasBone(shape->skin->bones[boneIndex].name.toString()))
				std::cout << "We don't have this bone";
            bonePtr = mSkel->getBone(shape->skin->bones[boneIndex].name.toString());

            // final_vector = old_vector + old_rotation*new_vector*old_scale


			Nif::NiSkinData::BoneInfoCopy boneinfocopy;
			boneinfocopy.trafo.rotation = convertRotation(it->trafo->rotation);
			boneinfocopy.trafo.trans = convertVector3(it->trafo->trans);
			boneinfocopy.bonename = shape->skin->bones[boneIndex].name.toString();
            boneinfocopy.bonehandle = bonePtr->getHandle();
            copy.boneinfo.push_back(boneinfocopy);
            for (unsigned int i=0; i<it->weights.length; i++)
            {
				 vecPos = bonePtr->_getDerivedPosition() +
                bonePtr->_getDerivedOrientation() * convertVector3(it->trafo->trans);

            vecRot = bonePtr->_getDerivedOrientation() * convertRotation(it->trafo->rotation);
                unsigned int verIndex = (it->weights.ptr + i)->vertex;
				//boneinfo.weights.push_back(*(it->weights.ptr + i));
                Nif::NiSkinData::IndividualWeight ind;
                ind.weight = (it->weights.ptr + i)->weight;
                ind.boneinfocopyindex = copy.boneinfo.size() - 1;
                if(copy.vertsToWeights.find(verIndex) == copy.vertsToWeights.end())
                {
                    std::vector<Nif::NiSkinData::IndividualWeight> blank;
                    blank.push_back(ind);
                    copy.vertsToWeights[verIndex] = blank;
                }
                else
                {
                    copy.vertsToWeights[verIndex].push_back(ind);
                }

                //Check if the vertex is relativ, FIXME: Is there a better solution?
                if (vertexPosAbsolut[verIndex] == false)
                {
                    //apply transformation to the vertices
                    Vector3 absVertPos = vecPos + vecRot * Vector3(ptr + verIndex *3);
					absVertPos = absVertPos * (it->weights.ptr + i)->weight;
					vertexPosOriginal[verIndex] = Vector3(ptr + verIndex *3);

					mBoundingBox.merge(absVertPos);
                    //convert it back to float *
                    for (int j=0; j<3; j++)
                        (ptr + verIndex*3)[j] = absVertPos[j];

                    //apply rotation to the normals (not every vertex has a normal)
                    //FIXME: I guessed that vertex[i] = normal[i], is that true?
                    if (verIndex < data->normals.length)
                    {
                        Vector3 absNormalsPos = vecRot * Vector3(ptrNormals + verIndex *3);
						absNormalsPos = absNormalsPos * (it->weights.ptr + i)->weight;
						vertexNormalOriginal[verIndex] = Vector3(ptrNormals + verIndex *3);

                        for (int j=0; j<3; j++)
                            (ptrNormals + verIndex*3)[j] = absNormalsPos[j];
                    }

                    vertexPosAbsolut[verIndex] = true;
                }
				else
				{
					Vector3 absVertPos = vecPos + vecRot * vertexPosOriginal[verIndex];
					absVertPos = absVertPos * (it->weights.ptr + i)->weight;
					Vector3 old = Vector3(ptr + verIndex *3);
					absVertPos = absVertPos + old;

					mBoundingBox.merge(absVertPos);
                    //convert it back to float *
                    for (int j=0; j<3; j++)
                        (ptr + verIndex*3)[j] = absVertPos[j];

                    //apply rotation to the normals (not every vertex has a normal)
                    //FIXME: I guessed that vertex[i] = normal[i], is that true?
                    if (verIndex < data->normals.length)
                    {
                        Vector3 absNormalsPos = vecRot * vertexNormalOriginal[verIndex];
						absNormalsPos = absNormalsPos * (it->weights.ptr + i)->weight;
						Vector3 oldNormal = Vector3(ptrNormals + verIndex *3);
						absNormalsPos = absNormalsPos + oldNormal;

                        for (int j=0; j<3; j++)
                            (ptrNormals + verIndex*3)[j] = absNormalsPos[j];
                    }
				}


                VertexBoneAssignment vba;
                vba.boneIndex = bonePtr->getHandle();
                vba.vertexIndex = verIndex;
                vba.weight = (it->weights.ptr + i)->weight;


                vertexBoneAssignments.push_back(vba);
            }


            boneIndex++;
        }


    }
    else
    {

			copy.boneSequence = boneSequence;
        // Rotate, scale and translate all the vertices,
        const Matrix &rot = shape->trafo->rotation;
        const Vector &pos = shape->trafo->pos;
        float scale = shape->trafo->scale;

		copy.trafo.trans = convertVector3(original.pos);
		copy.trafo.rotation = convertRotation(original.rotation);
		copy.trafo.scale = original.scale;
		//We don't use velocity for anything yet, so it does not need to be saved

		// Computes C = B + AxC*scale
        for (int i=0; i<numVerts; i++)
        {
            vectorMulAdd(rot, pos, ptr, scale);
			Ogre::Vector3 absVertPos = Ogre::Vector3(*(ptr + 3 * i), *(ptr + 3 * i + 1), *(ptr + 3 * i + 2));
			mBoundingBox.merge(absVertPos);
            ptr += 3;
        }

        // Remember to rotate all the vertex normals as well
        if (data->normals.length)
        {
            ptr = (float*)data->normals.ptr;
            for (int i=0; i<numVerts; i++)
            {
                vectorMul(rot, ptr);
                ptr += 3;
            }
        }
		if(!mSkel.isNull() ){
			int boneIndex;
			
				boneIndex = mSkel->getNumBones() - 1;
			for(int i = 0; i < numVerts; i++){
		 VertexBoneAssignment vba;
                vba.boneIndex = boneIndex;
                vba.vertexIndex = i;
                vba.weight = 1;
				 vertexBoneAssignments.push_back(vba);
			}
		}
    }

    if (!hidden)
    {
        // Add this vertex set to the bounding box
        bounds.add(optr, numVerts);
        if(saveTheShape)
            shapes.push_back(copy);

        // Create the submesh
        createOgreSubMesh(shape, material, vertexBoneAssignments);
    }
}