Please note that as of October 24, 2014, the Nokia Developer Wiki will no longer be accepting user contributions, including new entries, edits and comments, as we begin transitioning to our new home, in the Windows Phone Development Wiki. We plan to move over the majority of the existing entries. Thanks for all your past and future contributions.

Using M3G Animation in Java ME

From Wiki
Jump to: navigation, search



This code example shows how to use Mobile 3D Graphics API for animation with KeyframeSequence, AnimationTrack, and AnimationController classes.

First, define what kind of animation to use (see animationInitialization(Light light, Mesh mesh) method). Then create a KeyframeSequence object which consist of some keyframes with appropriate values, and create AnimationTrack object with animation type defining.

Then create a AnimationController object, tune it, and add AnimationTrack objects to the 3D entity (like Light, Mesh, and others).

Later in paint() method the animate function is called for each 3D entity and the scene is rendered.

Animation is added to an already existing snippet Using M3G to draw in Java ME. So here only those new declarations, handlers, methods, and changes are shown which should be performed over a simple drawing snippet.


Source file:

import javax.microedition.m3g.AnimationController;
import javax.microedition.m3g.AnimationTrack;
import javax.microedition.m3g.KeyframeSequence;

public class AnimationMIDlet extends MIDlet {
* Reference to MIDlet instance for using it inside Canvas3D

static AnimationMIDlet instance;
* The Canvas3D constructor.

public AnimationMIDlet() {
AnimationMIDlet.instance = this;
* From MIDlet.
* Called when MIDlet is started.
* Sets object from canvas3d variable as current displayable.
* Schedules a MyTimerTask timer task.

public void startApp() {
Display.getDisplay(this).setCurrent(new Canvas3D());
* Inner class for handling the canvas.

class Canvas3D extends Canvas implements Runnable,CommandListener{
* absolute counter of animation in world units

int iApplicationTime;
* Mesh object that represents a cube

Mesh iAnimatedMesh;
public Canvas3D() {
Thread thread = new Thread(this);
* Initialize self.

void initialize() {
// get the singleton Graphics3D instance
iG3D = Graphics3D.getInstance();
iBackground = backgroundInitialization("/background.png");
//Material is an Appearance component encapsulating material
//attributes for lighting computations.
Material material = materialInitialization(0xFFFFFFFF,
0xFFFFFFFF, 100.0f);
iCamera = cameraInitialization(70.0f);
iLight = lightInitialization(0xFFFFFFFF, Light.SPOT);
try {
//creating of cube object as Mesh
iAnimatedMesh = сubeMeshInitialization(material);
animationInitialization(iLight, iAnimatedMesh);
}catch(Exception e) {
//TODO: write handler code
iApplicationTime = 0;
public void run(){
int dt =0;
long loopStartTime =System.currentTimeMillis();
running = true;
dt = (int)(System.currentTimeMillis()-loopStartTime);
loopStartTime = System.currentTimeMillis();
//incrementing world time
iApplicationTime = iApplicationTime + dt;
try {
Thread.sleep(20 - (System.currentTimeMillis() - loopStartTime));
} catch (Exception e) {
// TODO: handle exception
* From Canvas.
* Rendering the scene

protected void paint(Graphics g) {
//incrementing world time
iApplicationTime = iApplicationTime + 50;
// Bind the Graphics of this Canvas to Graphics3D.
//We enable depth buffer, dithering and true color rendering(if it
//supported of course)
iG3D.bindTarget(g, true, Graphics3D.DITHER | Graphics3D.TRUE_COLOR);
// clear the color and depth buffers
// set up the camera in the desired position
Transform transform = new Transform();
transform.postTranslate(0.0f, 0.0f, 35.0f);
iG3D.setCamera(iCamera, transform);
//calcuulating parameters for animation according to
//current world time
// update Light object
iG3D.addLight(iLight, transform);
//calcuulating parameters for animation according to
//current world time
// In immediate mode, node transforms are ignored, so we get
// our animated transformation into a local transform object
// update our transform (this will give us a rotating cube)
iG3D.render(iAnimatedMesh, transform);
* From CommandListener.
* @param command
* @param displayable

public void commandAction(Command command, Displayable displayable) {
if (command == exitCommand) {
// exit the MIDlet
running = false;
* @param light is the Light object for color animation
* @param mesh is the Mesh object for rotation animation

private void animationInitialization(Light light, Mesh mesh) {
//Sequence of keyframes for rotation of cube
//creating color KeyframeSequence object
//with 5 keyframes with 3 components in each
//and setting the intepolation type
KeyframeSequence colorKeyframes = new KeyframeSequence(5, 3,
//then setting the duration of color animation
//this animation will play only once without repeat
//setting index, timestamp, and components values for 5 keyframes
colorKeyframes.setKeyframe(0, 0, new float[]{1.0f, 1.0f, 1.0f});
colorKeyframes.setKeyframe(1, 1000, new float[]{1.0f, 0.0f, 0.0f});
colorKeyframes.setKeyframe(2, 2000, new float[]{0.0f, 1.0f, 0.0f});
colorKeyframes.setKeyframe(3, 3000, new float[]{0.0f, 0.0f, 1.0f});
colorKeyframes.setKeyframe(4, 4000, new float[]{1.0f, 1.0f, 1.0f});
//Associates a KeyframeSequence with an AnimationController and sets
//the type of animation. In this case it's color animation.
//creating AnimationTrack object for color animation
AnimationTrack colorAnimationTrack =
new AnimationTrack(colorKeyframes, AnimationTrack.COLOR);
//Sequence of keyframes for color transition for light
//creating color KeyframeSequence object
//with 2 keyframes and 4 components in each
//and setting the intepolation type to SLERP
//that specifies spherical linear interpolation of quaternions
KeyframeSequence rotationKeyframes =
new KeyframeSequence(2, 4, KeyframeSequence.SLERP);
//this animation will be repeating while animation inside active
//getRotationQuaternion() method converts vector and angle
//values to quaternion
rotationKeyframes.setKeyframe(0, 0,
getRotationQuaternion(0.0f, new float[] {0.0f, 1.0f, 0.0f}));
rotationKeyframes.setKeyframe(1, 4000,
getRotationQuaternion(359.0f, new float[] {0.0f, 1.0f, 0.0f}));
//AnimationTrack associates a KeyframeSequence with an
//AnimationController and sets the type of animation.
//In this case it's orientation animation.
//creating AnimationTrack object for orientation animation
AnimationTrack rotationAnimationTrack =
new AnimationTrack(rotationKeyframes,
//creating AnimationController which
//controls the position, speed and weight of an animation sequence
AnimationController animator = new AnimationController();
//set controller for animation tracks
//set active time interval for controller
//8000 is not necessarily in milliseconds, it's abstract world
animator.setActiveInterval(0, 8000);
//set speed to half of normal
//animator.setSpeed(0.5f, 0);
//Sets a new playback position, relative to world time
//0 - desired playback position in sequence time units
//4000 - the world time at which the
//sequence time must be equal to 0
animator.setPosition(0, 4000);
//adding animation tracks to our objects that we
//wanting to animate
* Calculates the quaternion for a rotation of
* angle degrees about the vector.
* @param angle - is an angle of rotation round of vector
* @param vector - 3D vector of rotation
* @return quaternion of rotation

private float[] getRotationQuaternion(float angle, float[] vector) {
float[] quaternion = new float[4];
double angleRadians = Math.toRadians(angle)/2.0;
//i component
quaternion[0] = vector[0] * (float)Math.sin(angleRadians);
//j component
quaternion[1] = vector[1] * (float)Math.sin(angleRadians);
//k component
quaternion[2] = vector[2] * (float)Math.sin(angleRadians);
//w scalar component
quaternion[3] = (float)Math.cos(angleRadians);
return quaternion;


As result we have a MIDlet which draws a rotated cube mesh and an animated color of light source.

See also

Supplementary material

You can download this MIDlet, source code and resources from here: Simple

Article Metadata
Code ExampleTested with
Devices(s): Nokia 6131, Nokia 7373, Nokia N81, Nokia N82, Nokia C3-01, Nokia Asha 306, Nokia E7-00
Created: IlGolub (28 Nov 2008)
Last edited: lpvalente (16 Nov 2013)
This page was last modified on 16 November 2013, at 18:19.
122 page views in the last 30 days.