Search in sources :

Example 1 with Animation

use of net.drewke.tdme.engine.model.Animation in project tdme by andreasdr.

the class DAEReader method readNode.

/**
	 * Reads a DAE visual scene group node
	 * @param authoring tool
	 * @param path name
	 * @param model
	 * @param parent group
	 * @param xml node
	 * @param xml root
	 * @param frames per seconds
	 * @throws Exception
	 * @return group
	 */
private static Group readNode(AuthoringTool authoringTool, String pathName, Model model, Group parentGroup, Element xmlRoot, Element xmlNode, float fps) throws Exception {
    String xmlNodeId = xmlNode.getAttribute("id");
    String xmlNodeName = xmlNode.getAttribute("name");
    if (xmlNodeId.length() == 0)
        xmlNodeId = xmlNodeName;
    StringTokenizer t = null;
    // default node matrix
    Matrix4x4 transformationsMatrix = null;
    // set up local transformations matrix
    List<Element> xmlMatrixElements = getChildrenByTagName(xmlNode, "matrix");
    if (xmlMatrixElements.size() == 1) {
        String xmlMatrix = getChildrenByTagName(xmlNode, "matrix").get(0).getTextContent();
        t = new StringTokenizer(xmlMatrix, " \n\r");
        // 
        transformationsMatrix = new Matrix4x4(Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken())).transpose();
    }
    // tdme model definitions
    Group group = new Group(model, parentGroup, xmlNodeId, xmlNodeName);
    //
    if (transformationsMatrix != null) {
        group.getTransformationsMatrix().multiply(transformationsMatrix);
    }
    // parse animations
    List<Element> xmlAnimationsLibrary = getChildrenByTagName(xmlRoot, "library_animations");
    if (xmlAnimationsLibrary.isEmpty() == false) {
        List<Element> xmlAnimations = getChildrenByTagName(xmlAnimationsLibrary.get(0), "animation");
        for (Element xmlAnimation : xmlAnimations) {
            // older DAE has animation/animation xml nodes
            List<Element> _xmlAnimation = getChildrenByTagName(xmlAnimation, "animation");
            if (_xmlAnimation.isEmpty() == false) {
                xmlAnimation = _xmlAnimation.get(0);
            }
            // find sampler source
            String xmlSamplerSource = null;
            Element xmlChannel = getChildrenByTagName(xmlAnimation, "channel").get(0);
            if (xmlChannel.getAttribute("target").startsWith(xmlNodeId + "/")) {
                xmlSamplerSource = xmlChannel.getAttribute("source").substring(1);
            }
            // check for sampler source
            if (xmlSamplerSource == null) {
                continue;
            }
            // parse animation output matrices
            String xmlSamplerOutputSource = null;
            String xmlSamplerInputSource = null;
            Element xmlSampler = getChildrenByTagName(xmlAnimation, "sampler").get(0);
            for (Element xmlSamplerInput : getChildrenByTagName(xmlSampler, "input")) {
                if (xmlSamplerInput.getAttribute("semantic").equals("OUTPUT")) {
                    xmlSamplerOutputSource = xmlSamplerInput.getAttribute("source").substring(1);
                } else if (xmlSamplerInput.getAttribute("semantic").equals("INPUT")) {
                    xmlSamplerInputSource = xmlSamplerInput.getAttribute("source").substring(1);
                }
            }
            // check for sampler source
            if (xmlSamplerOutputSource == null) {
                throw new ModelFileIOException("Could not find xml sampler output source for animation for " + xmlNodeId);
            }
            // load animation input matrices
            // TODO: check accessor "time"
            float[] keyFrameTimes = null;
            for (Element xmlAnimationSource : getChildrenByTagName(xmlAnimation, "source")) {
                if (xmlAnimationSource.getAttribute("id").equals(xmlSamplerInputSource)) {
                    Element xmlFloatArray = getChildrenByTagName(xmlAnimationSource, "float_array").get(0);
                    int frames = Integer.parseInt(xmlFloatArray.getAttribute("count"));
                    String valueString = xmlFloatArray.getTextContent();
                    int keyFrameIdx = 0;
                    keyFrameTimes = new float[frames];
                    t = new StringTokenizer(valueString, " \n\r");
                    while (t.hasMoreTokens()) {
                        keyFrameTimes[keyFrameIdx++] = Float.parseFloat(t.nextToken());
                    }
                }
            }
            // load animation output matrices
            // TODO: check accessor "transform"
            Matrix4x4[] keyFrameMatrices = null;
            for (Element xmlAnimationSource : getChildrenByTagName(xmlAnimation, "source")) {
                if (xmlAnimationSource.getAttribute("id").equals(xmlSamplerOutputSource)) {
                    Element xmlFloatArray = getChildrenByTagName(xmlAnimationSource, "float_array").get(0);
                    int keyFrames = Integer.parseInt(xmlFloatArray.getAttribute("count")) / 16;
                    // some models have animations without frames
                    if (keyFrames > 0) {
                        String valueString = xmlFloatArray.getTextContent();
                        t = new StringTokenizer(valueString, " \n\r");
                        // parse key frame
                        int keyFrameIdx = 0;
                        keyFrameMatrices = new Matrix4x4[keyFrames];
                        while (t.hasMoreTokens()) {
                            // set animation transformation matrix at frame
                            keyFrameMatrices[keyFrameIdx] = new Matrix4x4(Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken()), Float.parseFloat(t.nextToken())).transpose();
                            keyFrameIdx++;
                        }
                    }
                }
            }
            // create linear animation by key frame times and key frames
            if (keyFrameTimes != null && keyFrameMatrices != null) {
                int frames = (int) Math.ceil(keyFrameTimes[keyFrameTimes.length - 1] * fps);
                // create default animation
                ModelHelper.createDefaultAnimation(model, frames);
                //
                Animation animation = group.createAnimation(frames);
                Matrix4x4[] transformationsMatrices = animation.getTransformationsMatrices();
                Matrix4x4 tansformationsMatrixLast = keyFrameMatrices[0];
                int keyFrameIdx = 0;
                int frameIdx = 0;
                float timeStampLast = 0.0f;
                for (float keyFrameTime : keyFrameTimes) {
                    Matrix4x4 transformationsMatrixCurrent = keyFrameMatrices[(keyFrameIdx) % keyFrameMatrices.length];
                    float timeStamp;
                    for (timeStamp = timeStampLast; timeStamp < keyFrameTime; timeStamp += 1.0f / fps) {
                        if (frameIdx >= frames) {
                            System.out.println("Warning: skipping frame: " + frameIdx);
                            frameIdx++;
                            continue;
                        }
                        Matrix4x4.interpolateLinear(tansformationsMatrixLast, transformationsMatrixCurrent, (timeStamp - timeStampLast) / (keyFrameTime - timeStampLast), transformationsMatrices[frameIdx]);
                        frameIdx++;
                    }
                    timeStampLast = timeStamp;
                    tansformationsMatrixLast = transformationsMatrixCurrent;
                    keyFrameIdx++;
                }
            }
        }
    }
    // parse sub groups
    for (Element _xmlNode : getChildrenByTagName(xmlNode, "node")) {
        Group _group = readVisualSceneNode(authoringTool, pathName, model, group, xmlRoot, _xmlNode, fps);
        if (_group != null) {
            group.getSubGroups().put(_group.getId(), _group);
            model.getGroups().put(_group.getId(), _group);
        }
    }
    // check for geometry data
    String xmlInstanceGeometryId = null;
    List<Element> xmlInstanceGeometryElements = getChildrenByTagName(xmlNode, "instance_geometry");
    if (xmlInstanceGeometryElements.isEmpty() == false) {
        Element xmlInstanceGeometryElement = xmlInstanceGeometryElements.get(0);
        // fetch instance geometry url
        xmlInstanceGeometryId = xmlInstanceGeometryElement.getAttribute("url").substring(1);
        // determine bound materials
        HashMap<String, String> materialSymbols = new HashMap<String, String>();
        for (Element xmlBindMaterial : getChildrenByTagName(xmlInstanceGeometryElement, "bind_material")) for (Element xmlTechniqueCommon : getChildrenByTagName(xmlBindMaterial, "technique_common")) for (Element xmlInstanceMaterial : getChildrenByTagName(xmlTechniqueCommon, "instance_material")) {
            materialSymbols.put(xmlInstanceMaterial.getAttribute("symbol"), xmlInstanceMaterial.getAttribute("target"));
        }
        // parse geometry
        readGeometry(authoringTool, pathName, model, group, xmlRoot, xmlInstanceGeometryId, materialSymbols);
        //
        return group;
    }
    // otherwise check for "instance_node"
    String xmlInstanceNodeId = null;
    for (Element xmlInstanceNodeElement : getChildrenByTagName(xmlNode, "instance_node")) {
        xmlInstanceNodeId = xmlInstanceNodeElement.getAttribute("url").substring(1);
    }
    // do we have a instance node id?
    if (xmlInstanceNodeId != null) {
        for (Element xmlLibraryNodes : getChildrenByTagName(xmlRoot, "library_nodes")) for (Element xmlLibraryNode : getChildrenByTagName(xmlLibraryNodes, "node")) if (xmlLibraryNode.getAttribute("id").equals(xmlInstanceNodeId)) {
            // parse sub groups
            for (Element _xmlNode : getChildrenByTagName(xmlLibraryNode, "node")) {
                Group _group = readVisualSceneNode(authoringTool, pathName, model, parentGroup, xmlRoot, _xmlNode, fps);
                if (_group != null) {
                    group.getSubGroups().put(_group.getId(), _group);
                    model.getGroups().put(_group.getId(), _group);
                }
            }
            // parse geometry 
            for (Element xmlInstanceGeometry : getChildrenByTagName(xmlLibraryNode, "instance_geometry")) {
                String xmlGeometryId = xmlInstanceGeometry.getAttribute("url").substring(1);
                // parse material symbols
                HashMap<String, String> materialSymbols = new HashMap<String, String>();
                for (Element xmlBindMaterial : getChildrenByTagName(xmlInstanceGeometry, "bind_material")) for (Element xmlTechniqueCommon : getChildrenByTagName(xmlBindMaterial, "technique_common")) for (Element xmlInstanceMaterial : getChildrenByTagName(xmlTechniqueCommon, "instance_material")) {
                    materialSymbols.put(xmlInstanceMaterial.getAttribute("symbol"), xmlInstanceMaterial.getAttribute("target"));
                }
                // parse geometry
                readGeometry(authoringTool, pathName, model, group, xmlRoot, xmlGeometryId, materialSymbols);
            }
        }
    }
    //
    return group;
}
Also used : Group(net.drewke.tdme.engine.model.Group) HashMap(net.drewke.tdme.utils.HashMap) Element(org.w3c.dom.Element) Matrix4x4(net.drewke.tdme.math.Matrix4x4) Joint(net.drewke.tdme.engine.model.Joint) StringTokenizer(java.util.StringTokenizer) Animation(net.drewke.tdme.engine.model.Animation)

Example 2 with Animation

use of net.drewke.tdme.engine.model.Animation in project tdme by andreasdr.

the class Object3DBase method computeTransformationsMatrices.

/**
	 * Calculates all groups transformation matrices
	 * @param groups
	 * @param parent transformations matrix
	 * @param animation state
	 * @param depth
	 */
protected void computeTransformationsMatrices(HashMap<String, Group> groups, Matrix4x4 parentTransformationsMatrix, AnimationState animationState, int depth) {
    // iterate through groups
    for (Group group : groups.getValuesIterator()) {
        // check for overlay animation
        AnimationState overlayAnimation = overlayAnimationsByJointId.get(group.getId());
        if (overlayAnimation != null)
            animationState = overlayAnimation;
        // group transformation matrix
        Matrix4x4 transformationsMatrix = null;
        // compute animation matrix if animation setups exist
        Animation animation = group.getAnimation();
        if (animation != null && animationState.finished == false) {
            Matrix4x4[] animationMatrices = animation.getTransformationsMatrices();
            int frames = animationState.setup.getFrames();
            float fps = model.getFPS();
            // determine current and last matrix
            float frameAtLast = (animationState.lastAtTime / 1000f) * fps;
            float frameAtCurrent = (animationState.currentAtTime / 1000f) * fps;
            // check if looping is disabled
            if (animationState.setup.isLoop() == false && frameAtCurrent >= frames) {
                // set frame at current to last frame
                frameAtLast = frames - 1;
                frameAtCurrent = frames - 1;
                animationState.finished = true;
            }
            //
            int matrixAtLast = ((int) frameAtLast % frames);
            int matrixAtCurrent = ((int) frameAtCurrent % frames);
            animationState.time = frames <= 1 ? 0.0f : (float) matrixAtCurrent / (float) (frames - 1);
            // compute animation transformations matrix
            float t = frameAtCurrent - (float) Math.floor(frameAtLast);
            if (t < 1f) {
                if (matrixAtLast == matrixAtCurrent) {
                    matrixAtCurrent = ((matrixAtCurrent + 1) % frames);
                }
                transformationsMatrix = Matrix4x4.interpolateLinear(animationMatrices[matrixAtLast + animationState.setup.getStartFrame()], animationMatrices[matrixAtCurrent + animationState.setup.getStartFrame()], t, tmpMatrix1);
            } else {
                transformationsMatrix = tmpMatrix1.set(animationMatrices[matrixAtCurrent + animationState.setup.getStartFrame()]);
            }
        }
        // do we have no animation matrix?
        if (transformationsMatrix == null) {
            // no animation matrix, set up local transformation matrix up as group matrix
            transformationsMatrix = tmpMatrix1.set(group.getTransformationsMatrix());
        }
        // apply parent transformation matrix 
        if (parentTransformationsMatrix != null) {
            transformationsMatrix.multiply(parentTransformationsMatrix);
        }
        // put and associate transformation matrices with group
        transformationsMatrices.get(group.getId()).set(transformationsMatrix);
        // calculate for sub groups
        HashMap<String, Group> subGroups = group.getSubGroups();
        if (subGroups.size() > 0) {
            // put to matrices stack
            transformationsMatricesStack[depth].set(transformationsMatrix);
            // compute sub groups transformations
            computeTransformationsMatrices(subGroups, transformationsMatricesStack[depth], animationState, depth + 1);
        }
    }
}
Also used : Group(net.drewke.tdme.engine.model.Group) Animation(net.drewke.tdme.engine.model.Animation) Matrix4x4(net.drewke.tdme.math.Matrix4x4)

Aggregations

Animation (net.drewke.tdme.engine.model.Animation)2 Group (net.drewke.tdme.engine.model.Group)2 Matrix4x4 (net.drewke.tdme.math.Matrix4x4)2 StringTokenizer (java.util.StringTokenizer)1 Joint (net.drewke.tdme.engine.model.Joint)1 HashMap (net.drewke.tdme.utils.HashMap)1 Element (org.w3c.dom.Element)1