Exemplo n.º 1
0
/*!
  \internal
  \fn void SelectedItem::paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget)
  Overrides the superclass method. Handles the static display of the SelectedItem, object
  movement and animation. Calls drawBackground(...) and draw(...).
*/
void SelectedItem::paint(QPainter *painter,const QStyleOptionGraphicsItem *,QWidget *)
{
    if ( !currentItem ) {
        qWarning("SelectedItem::paint(...): No current item.");
        return;
    }

    if (!Qtopia::mousePreferred() || active)
        drawBackground(painter);

    if ( animationState() == Animating ) {
        // During animation, we get multiple calls to paint(...). In each, we paint the next
        // frame of the movie.
        if ( movie ) {
            QPixmap moviePixmap = movie->currentPixmap();
            draw(painter,moviePixmap,
                    static_cast<int>(rect().x()),static_cast<int>(rect().y()));
        } else {
            // We'll try to do a coded animation using the GridItem's Animator object.
            // This call to paint(...) will have been invoked via a signal from playTimeLine
            // which ultimatey triggers playStep(...), which saves the point at which the
            // animation has run to (animationStage) - drawAnimated(...) will make use of
            // animationStage.
            drawAnimated(painter);
        }
    } else {
        // Not currently animating, but we may be sliding across from one item to its
        // neighbour.
        if ( destItem ) {
            // Yes, moving across -- we're going to draw selected images for both the
            // source item and the destination item, but we're going to use this item as
            // the clipping region. First, set up the clipping region.
            painter->setClipRect(rect());

            // During moveStep(...), we calculated new positions for the two items when they
            // are drawn as SelectedItems. This calculation takes into account the magnified
            // area between the two pixmaps.
            draw(painter,currentItem->selectedPic(),currentX,currentY);
            draw(painter,destItem->selectedPic(),destX,destY);
        } else {
            // We're not sliding, we're just drawing 'item' as the selected item.
            if (!Qtopia::mousePreferred() || active)
                draw(painter,currentItem->selectedPic(),static_cast<int>(rect().x()),static_cast<int>(rect().y()));
        }
    }
}
Exemplo n.º 2
0
/*!
  \internal
  Returns true if the item is currently animating or about to animate.
*/
bool SelectedItem::isAnimating() const
{
    AnimationState state = animationState();
    return ( state == Animating || state == AnimationPending );
}
Exemplo n.º 3
0
void SkinnedMesh::Load(const string& filename, const VertexAttributesMap_t& vertexAttributes, bool counterClockWise) {
    Mesh::Load(filename, vertexAttributes, counterClockWise);

    // Delete last model's skeleton if present
    if (skeleton_ != nullptr) {
        ModelManager::GetInstance()->RemoveSkeletonReferenceFromCache(filename_);
    }

    // Check cache first
    if (ModelManager::GetInstance()->CheckIfSkeletonLoaded(filename)) {
        skeleton_ = ModelManager::GetInstance()->LoadSkeletonFromCache(filename);
        return;
    }

    // Reload the scene - we need it to query information about the bones
    const aiScene* scene = nullptr;
    if (importer_ == nullptr) {
        importer_ = new Assimp::Importer;

        scene = importer_->ReadFile(filename, aiProcess_LimitBoneWeights);

        if (scene == nullptr) {
            Logger::GetInstance()->Error("Couldn't load mesh " + filename);
            delete importer_;
            importer_ = nullptr;
            return;
        }
    } else {
        scene = importer_->GetScene();
    }

    if (!scene->HasAnimations()) {
        Logger::GetInstance()->Warning("Skinned mesh " + filename + " has no animations");
        return;
    }

    // Because there are several sub meshes, we want to remember the bone is from which mesh
    set<string> necessaryBones;
    map<string, vector<pair<const aiBone*, size_t>>> bones;
    map<string, size_t> boneNameToIndex;
    size_t cumulativeNumVertices = 0; 
    queue<const aiNode*> nodes;
    nodes.push(scene->mRootNode);

    ///////////////////////////////////////////////////////////////////////////////////
    // Load the bones from the mesh
    while (!nodes.empty()) {
        const aiNode* node = nodes.front();
        nodes.pop();

        for (size_t i = 0; i < node->mNumMeshes; i++) {
            const aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
            size_t numVertices = mesh->mNumVertices;

            // Get the surface to set the bones and weights for GPU skinned meshes
            SurfaceTriangles_t* surface = surfaces_[node->mMeshes[i]];

            // Retrieve for each bones the offset matrix and the vertex with their weight that are attached to it
            if (mesh->HasBones()) {
                if (meshType_ == MESH_TYPE_STATIC) {
                    surface->numBones = surface->numVertices;
                    surface->numWeights = surface->numVertices;

                    surface->bones = new Vector4[surface->numBones];
                    surface->weights = new Vector4[surface->numWeights];

                    // We intialize all weights to 0
                    for (size_t j = 0; j < surface->numBones; j++) {
                        Vector4& contribuingWeight = surface->weights[j];
                        contribuingWeight.w = 0.0f;
                    }
                }

                for (size_t j = 0; j < mesh->mNumBones; j++) {
                    const aiBone* bone = mesh->mBones[j];

                    // Only do this for a static mesh, because it will be skinned on the GPU
                    if (meshType_ == MESH_TYPE_STATIC) {
                        // Map the bone index that we'll give to the vertex to its name
                        size_t boneIndex = 0;
                        map<string, size_t>::iterator it = boneNameToIndex.find(bone->mName.data);
                        if (it != boneNameToIndex.end()) {
                            boneIndex = it->second;
                        } else {
                            boneIndex = boneNameToIndex.size();
                            boneNameToIndex[bone->mName.data] = boneIndex;

                        }

                        for (size_t k = 0; k < bone->mNumWeights; k++) {
                            const aiVertexWeight& weight = bone->mWeights[k];
                            Vector4& contribuingBone = surface->bones[weight.mVertexId];
                            Vector4& contribuingWeights = surface->weights[weight.mVertexId];

                            if (contribuingWeights.x == 0.0f) {
                                contribuingBone.x = (float)boneIndex;
                                contribuingWeights.x = weight.mWeight;
                            } else if (contribuingWeights.y == 0.0f) {
                                contribuingBone.y = (float)boneIndex;
                                contribuingWeights.y = weight.mWeight;
                            } else if (contribuingWeights.z == 0.0f) {
                                contribuingBone.z = (float)boneIndex;
                                contribuingWeights.z = weight.mWeight;
                            } else {
                                contribuingBone.w = (float)boneIndex;
                                contribuingWeights.w = weight.mWeight;
                            }
                        }
                    }

                    if (bones.find(bone->mName.data) == bones.end()) {
                        bones[bone->mName.data] = vector<pair<const aiBone*, size_t>>();
                    }

                    bones[bone->mName.data].push_back( pair<const aiBone*, size_t>(bone, cumulativeNumVertices) );
                    necessaryBones.insert(bone->mName.data);

                    // Also, there might be some bones in the hierarchy that have no vertices attached to them
                    // They might still be useful because they connect other bones, so we have to add them to the
                    // skeleton.
                    queue<const aiNode*> nodeHierarchy;
                    nodeHierarchy.push(scene->mRootNode);

                    while (!nodeHierarchy.empty()) {
                        const aiNode* currentNode = nodeHierarchy.front();
                        nodeHierarchy.pop();

                        if (currentNode->mName == bone->mName) {
                            const aiNode* parentNode = currentNode->mParent;

                            while (parentNode != nullptr || (parentNode != nullptr && parentNode->mName == node->mName) ||
                                   (node->mParent != nullptr && parentNode != nullptr && parentNode->mName == node->mParent->mName))
                            {
                                necessaryBones.insert(parentNode->mName.data);
                                parentNode = parentNode->mParent;
                            }

                            break;
                        } else {
                            for (size_t k = 0; k < currentNode->mNumChildren; k++) {
                                nodeHierarchy.push(currentNode->mChildren[k]);
                            }
                        }
                    }
                }
            }

            cumulativeNumVertices += numVertices;
        }

        for (size_t i = 0; i < node->mNumChildren; i++) {
            nodes.push(node->mChildren[i]);
        }
    }

    ///////////////////////////////////////////////////////////////////////////////////
    // Build the skeleton
    skeleton_ = new Skeleton;
    aiMatrix4x4 globalTransform = scene->mRootNode->mTransformation;
    Matrix4x4 globalInverseTransform(globalTransform.a1, globalTransform.a2, globalTransform.a3, globalTransform.a4,
                                     globalTransform.b1, globalTransform.b2, globalTransform.b3, globalTransform.b4,
                                     globalTransform.c1, globalTransform.c2, globalTransform.c3, globalTransform.c4,
                                     globalTransform.d1, globalTransform.d2, globalTransform.d3, globalTransform.d4);
    globalInverseTransform.Inverse();
    skeleton_->SetGlobalInverseTransform(globalInverseTransform);

    nodes.push(scene->mRootNode);

    while (!nodes.empty()) {
        const aiNode* node = nodes.front();
        nodes.pop();

        set<string>::iterator s_it = necessaryBones.find(node->mName.data);
        if (s_it != necessaryBones.end()) {
            const aiNode* parent = node->mParent;

            if (parent == nullptr) {
                skeleton_->CreateBone(*s_it, Matrix4x4::IDENTITY);
            } else {
                // Build the bone hierarchy
                Bone_t* parentBone = skeleton_->FindBoneByName(parent->mName.data);
                if (parentBone == nullptr) {
                    parentBone = skeleton_->CreateBone(parent->mName.data, Matrix4x4::IDENTITY);
                }

                map<string, vector<pair<const aiBone*, size_t>>>::iterator it = bones.find(node->mName.data);
                if (it == bones.end()) {
                    aiMatrix4x4 offset = node->mTransformation;
                    Matrix4x4 offsetMatrix(offset.a1, offset.a2, offset.a3, offset.a4,
                                           offset.b1, offset.b2, offset.b3, offset.b4,
                                           offset.c1, offset.c2, offset.c3, offset.c4,
                                           offset.d1, offset.d2, offset.d3, offset.d4);

                    Bone_t* bone = skeleton_->CreateBone(*s_it, offsetMatrix);
                    parentBone->linkedBones.push_back(bone);
                } else {
                    aiMatrix4x4 offset = it->second[0].first->mOffsetMatrix;
                    Matrix4x4 offsetMatrix(offset.a1, offset.a2, offset.a3, offset.a4,
                                           offset.b1, offset.b2, offset.b3, offset.b4,
                                           offset.c1, offset.c2, offset.c3, offset.c4,
                                           offset.d1, offset.d2, offset.d3, offset.d4);

                    Bone_t* bone = skeleton_->CreateBone(it->first, offsetMatrix);
                    parentBone->linkedBones.push_back(bone);

                    // Only do this for a dynamic mesh, because it will be skinned on the GPU
                    if (meshType_ == MESH_TYPE_DYNAMIC) {
                        for (size_t i = 0; i < it->second.size(); i++) {
                            const aiVertexWeight* weights = it->second[i].first->mWeights;
                            size_t baseIndex = it->second[i].second;

                            for (size_t j = 0; j < it->second[i].first->mNumWeights; j++) {
                                bone->vertexWeight[baseIndex + weights[j].mVertexId] = weights[j].mWeight;
                            }
                        }
                    } else {
                        // Map the bone to the index given to the vertices
                        boneToIndex_[bone] = boneNameToIndex[node->mName.data];
                    }
                }
            }
        }

        for (size_t i = 0; i < node->mNumChildren; i++) {
            nodes.push(node->mChildren[i]);
        }
    }

    ///////////////////////////////////////////////////////////////////////////////////
    // Load the animations
    for (size_t i = 0; i < scene->mNumAnimations; i++) {
        aiAnimation* animation = scene->mAnimations[i];
        AnimationState animationState(animation->mDuration, animation->mTicksPerSecond);
        
        // Get the keys for all bones
        for (size_t j = 0; j < animation->mNumChannels; j++) {
            const aiNodeAnim* nodeAnim = animation->mChannels[j];

            vector<pair<double, Vector3>> positionKeys, scaleKeys;
            vector<pair<double, Quaternion>> rotationKeys;

            // Get all the key frames
            for (size_t k = 0; k < nodeAnim->mNumPositionKeys; k++) {
                const aiVectorKey& positionKey = nodeAnim->mPositionKeys[k];
                const aiVector3D& position = positionKey.mValue;
                positionKeys.push_back(pair<double, Vector3>( positionKey.mTime, Vector3(position.x, position.y, position.z) ));
            }

            for (size_t k = 0; k < nodeAnim->mNumRotationKeys; k++) {
                const aiQuatKey& rotationKey = nodeAnim->mRotationKeys[k];
                const aiQuaternion& rotation = rotationKey.mValue;
                rotationKeys.push_back(pair<double, Quaternion>( rotationKey.mTime, Quaternion(rotation.w, rotation.x, rotation.y, rotation.z) ));
            }

            for (size_t k = 0; k < nodeAnim->mNumScalingKeys; k++) {
                const aiVectorKey& scalingKey = nodeAnim->mScalingKeys[k];
                const aiVector3D& scale = scalingKey.mValue;
                scaleKeys.push_back(pair<double, Vector3>( scalingKey.mTime, Vector3(scale.x, scale.y, scale.z) ));
            }

            animationState.SetPositionKeysForBone(nodeAnim->mNodeName.data, positionKeys);
            animationState.SetRotationKeysForBone(nodeAnim->mNodeName.data, rotationKeys);
            animationState.SetScaleKeysForBone(nodeAnim->mNodeName.data, scaleKeys);
        }

        skeleton_->AddAnimationState(animation->mName.data, animationState);
    }

    // Cache the skeleton for future loads
    ModelManager::GetInstance()->CacheSkeleton(filename, skeleton_);

    Logger::GetInstance()->Info("Successfully loaded animations from file " + filename);
}