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;
}
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);
}
}
}
Aggregations