CameraAnimator.java
/*
* Copyright © 2012 Nokia Corporation. All rights reserved.
* Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation.
* Oracle and Java are trademarks or registered trademarks of Oracle and/or its
* affiliates. Other product and company names mentioned herein may be trademarks
* or trade names of their respective owners.
* See LICENSE.TXT for license information.
*/
package com.nokia.example.amaze.ui;
import javax.microedition.m3g.Camera;
import javax.microedition.m3g.Transform;
import javax.microedition.m3g.World;
/**
* Class for pause and transition camera animations.
*/
public class CameraAnimator {
// Constants
private static final float NUM_OF_TRANSITION_STEPS = 30;
private static final float MIN_TRANSITION_STEP = 0.01f;
private static final float PAUSE_ANIMATION_ROTATION_SPEED = 0.2f;
// Animation types
public static final int PAUSE_ANIMATION = 0;
public static final int TRANSITION_ANIMATION_TO_POV = 1;
public static final int TRANSITION_ANIMATION_TO_TOP = 2;
public static final int LEVEL_RESET_ANIMATION_STEP = 3;
// Members
private Listener _listener = null;
private World _world = null;
private Camera _camera = null;
private Transform _currentTransform = null;
private Transform _targetTransform = null;
private float[] _currentMatrix = null;
private float[] _targetMatrix = null;
private float[] _transitionMatrix = null;
private float[] _currentOrientation = null;
private float[] _targetOrientation = null;
private int _animationType = -1;
private int _stepCount = 0;
private boolean _running = false;
/**
* Constructor.
* @param listener The listener which is the maze canvas.
*/
public CameraAnimator(Listener listener, World world, Camera camera) {
if (listener == null || world == null || camera == null) {
throw new IllegalArgumentException("None of the arguments can be null!");
}
_listener = listener;
_world = world;
_camera = camera;
}
/**
* Starts the animation of the given type.
* @param type The animation type.
* @param targetTransform The target transform. Can be null.
*/
public void startAnimation(int type, Transform targetTransform, float[] targetOrientation) {
System.out.println("CameraAnimator::startAnimation(): " + type);
if (_running) {
releaseResources();
_running = false;
}
_animationType = type;
_stepCount = 0;
if (targetTransform != null) {
_targetTransform = targetTransform;
_targetMatrix = new float[16];
_targetTransform.get(_targetMatrix);
}
_currentTransform = new Transform();
Camera activeCamera = _world.getActiveCamera();
if (activeCamera == null) {
// No active camera set, do set it now
System.out.println("CameraAnimator::startAnimation(): No active camera set.");
_world.setActiveCamera(_camera);
_camera.getTransform(_currentTransform); }
else {
activeCamera.getTransform(_currentTransform);
if (_camera != activeCamera) {
System.out.println("CameraAnimator::startAnimation(): Switching the camera.");
_camera.setTransform(_currentTransform);
_world.setActiveCamera(_camera);
}
}
if (targetOrientation != null) {
_targetOrientation = targetOrientation;
_currentOrientation = new float[4];
_camera.getOrientation(_currentOrientation);
}
if (targetTransform != null) {
_currentMatrix = new float[16];
_currentTransform.get(_currentMatrix);
_transitionMatrix = calculateTransitionMatrix(_currentMatrix,
_targetMatrix);
}
_running = true;
}
/**
* For convenience.
* @param type
* @param targetCamera
*/
public void startAnimation(int type, Camera targetCamera) {
if (targetCamera == null) {
return;
}
Transform transform = new Transform();
targetCamera.getTransform(transform);
float[] orientation = new float[4];
targetCamera.getOrientation(orientation);
startAnimation(type, transform, orientation);
}
/**
* For convenience.
* @param type
*/
public void startAnimation(int type) {
startAnimation(type, null, null);
}
/**
* Stops the animation.
*/
public void stopAnimation() {
System.out.println("CameraAnimator::stopAnimation()");
releaseResources();
_running = false;
_listener.onAnimationFinished(_animationType);
}
/**
* @return True if the animator running, false otherwise.
*/
public final boolean running() {
return _running;
}
/**
* @return The type of the current animation.
*/
public final int animationType() {
return _animationType;
}
/**
*
*/
public void update() {
if (_targetTransform != null) {
if (!takeTransitionStepTowardsTarget()) {
System.out.println("CameraAnimator::update(): No more transition steps required.");
if (_animationType == TRANSITION_ANIMATION_TO_POV
|| _animationType == TRANSITION_ANIMATION_TO_TOP)
{
// We're done here
_running = false;
stopAnimation();
}
else {
releaseResources();
}
}
if (_currentTransform != null) {
_camera.setTransform(_currentTransform);
}
if (_targetOrientation != null) {
_camera.setOrientation(_currentOrientation[0],
_currentOrientation[1],
_currentOrientation[2],
_currentOrientation[3]);
}
}
else if (_animationType == PAUSE_ANIMATION) {
_camera.postRotate(PAUSE_ANIMATION_ROTATION_SPEED, 0f, 1f, 0f);
}
else if (_animationType == LEVEL_RESET_ANIMATION_STEP) {
_camera.translate(0f, 12.0f, 12.0f);
_stepCount++;
if (_stepCount > 60) {
stopAnimation();
}
}
else {
stopAnimation();
}
}
/**
* Prints the matrix of the given transform. For debugging purposes.
* @param transform The transform to print.
*/
public static final void printTransform(Transform transform) {
if (transform == null) {
return;
}
final float[] matrix = new float[16];
transform.get(matrix);
for (int i = 0; i < 16; ++i) {
if ((i + 1) % 4 == 0) {
System.out.println(matrix[i]);
}
else {
System.out.print(matrix[i] + "\t");
}
}
}
/**
* Prints the values of the properties of the given camera.
* @param camera The camera of which values to print.
*/
public static final void printCameraValues(Camera camera) {
if (camera != null) {
Transform transform = new Transform();
camera.getTransform(transform);
printTransform(transform);
// Print orientation
final float[] orientation = new float[4];
camera.getOrientation(orientation);
System.out.print("Orientation: [");
System.out.println(orientation[0] + ", "
+ orientation[1] + ", "
+ orientation[2] + ", "
+ orientation[3] + "]");
}
}
/**
*
* @param current
* @param target
* @param diff
* @return
*/
private final float newValue(float current, float target, float diff) {
if (diff < 0) {
diff = Math.abs(diff);
}
if (Math.abs(current - target) < diff) {
return target;
}
if (target > current) {
return current + diff;
}
return current - diff;
}
/**
* Takes a step towards the target camera transition.
* @return True if the matrix was modified, false otherwise.
*/
private boolean takeTransitionStepTowardsTarget() {
final int matrixLength = _currentMatrix.length;
final int maxChangesCount = (_targetOrientation == null)
? matrixLength : _transitionMatrix.length;
int noChangesCount = 0;
for (int i = 0; i < matrixLength; ++i) {
if (_currentMatrix[i] == _targetMatrix[i]) {
noChangesCount++;
continue;
}
_currentMatrix[i] = newValue(_currentMatrix[i],
_targetMatrix[i], _transitionMatrix[i]);
}
if (_targetOrientation != null) {
for (int i = 0; i < 4; ++i) {
if (_currentOrientation[i] == _targetOrientation[i]) {
noChangesCount++;
continue;
}
_currentOrientation[i] =
newValue(_currentOrientation[i],
_targetOrientation[i],
_transitionMatrix[i + matrixLength]);
}
}
_currentTransform.set(_currentMatrix);
/*System.out.println("CameraAnimator::takeTransitionStepTowardsTarget(): "
+ noChangesCount + "/" + maxChangesCount);*/
return (noChangesCount != maxChangesCount);
}
/**
*
* @param from
* @param to
* @return
*/
private float[] calculateTransitionMatrix(float[] from, float[] to) {
if (from == null || to == null || from.length != to.length){
return null;
}
final int length = from.length;
float[] transitionMatrix = new float[length + 4];
for (int i = 0; i < length; ++i) {
if (to[i] == from[i]) {
continue;
}
transitionMatrix[i] = (to[i] - from[i]) / NUM_OF_TRANSITION_STEPS;
/*System.out.println("(" + to[i] + " - " + from[i] + ") / "
+ NUM_OF_TRANSITION_STEPS + " = " + transitionMatrix[i]);*/
if (transitionMatrix[i] == 0) {
transitionMatrix[i] = MIN_TRANSITION_STEP;
}
}
if (_targetOrientation != null) {
// Calculate the transition steps for the orientation
for (int i = 0; i < 4; ++i) {
transitionMatrix[i + length] =
(_targetOrientation[i] - _currentOrientation[i])
/ NUM_OF_TRANSITION_STEPS;
if (transitionMatrix[i + length] == 0) {
transitionMatrix[i + length] = MIN_TRANSITION_STEP;
}
}
}
return transitionMatrix;
}
/**
* Releases resources.
*/
private void releaseResources() {
_currentTransform = null;
_targetTransform = null;
_targetMatrix = null;
_currentMatrix = null;
_currentOrientation = null;
_targetOrientation = null;
_transitionMatrix = null;
}
/**
* Listener interface for events of this class.
*/
public interface Listener {
/**
* Called when an animation is finished.
* @param animationType The type of the animation which was finished.
*/
void onAnimationFinished(int animationType);
}
}