/*
* Sample code for M3G article on IBM developerWorks.
* http://www.ibm.com/developerworks/
*/
package m3gsamples2;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
/**
* Uses a scene graph tree to structure a hierarchy of 3D objects.
*
* @author Claus Hoefele
*/
public class SceneGraphSample extends Canvas implements Sample, Runnable
{
/** The cube's vertex positions (x, y, z). */
private static final byte[] VERTEX_POSITIONS = {
-1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, // front
1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, // back
1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, // right
-1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, // left
-1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, // top
-1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1 // bottom
};
/** The cube's normals. */
private static final byte[] VERTEX_NORMALS = {
0, 0, 127, 0, 0, 127, 0, 0, 127, 0, 0, 127, // front
0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, // back
127, 0, 0, 127, 0, 0, 127, 0, 0, 127, 0, 0, // right
-128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, 0, // left
0, 127, 0, 0, 127, 0, 0, 127, 0, 0, 127, 0, // top
0, -128, 0, 0, -128, 0, 0, -128, 0, 0, -128, 0, // bottom
};
/** Indices that define how to connect the vertices to build
* triangles. */
private static final int[] TRIANGLE_INDICES = {
0, 1, 2, 3, // front
4, 5, 6, 7, // back
8, 9, 10, 11, // right
12, 13, 14, 15, // left
16, 17, 18, 19, // top
20, 21, 22, 23 // bottom
};
/** Lengths of triangle strips in TRIANGLE_INDICES. */
private static int[] TRIANGLE_LENGTHS = {
4, 4, 4, 4, 4, 4
};
/** User ID for all meshes (1).*/
private static final int USER_ID_ALL_MESHES = 1;
/** User ID for blue meshes (2).*/
private static final int USER_ID_BLUE_MESHES = 2;
/** User ID for red meshes (3).*/
private static final int USER_ID_RED_MESHES = 3;
/** Number of frames used for one direction of the animation.*/
private static int COUNTER_MAX = 20;
/** Frame counter. */
private int _counter = COUNTER_MAX/2;
/** Scaling factor per frame.*/
private float _scale = 0.02f;
/** Object that represents the 3D world. */
private World _world;
/** Flag for stopping the Thread.*/
private boolean _isRunning;
/** Graphics singleton used for rendering. */
private Graphics3D _graphics3d;
/**
* When the sample is shown, it's initialized and the animation
* thread started.
*/
public void showNotify()
{
init();
Thread thread = new Thread(this);
_isRunning = true;
thread.start();
}
/**
* Stops the animation thread.
*/
public void hideNotify()
{
_isRunning = false;
}
/**
* Initializes the sample.
*/
protected void init()
{
// Get the singleton for 3D rendering and a World.
_graphics3d = Graphics3D.getInstance();
_world = new World();
// Create a camera with perspective projection.
Camera camera = new Camera();
float aspect = (float) getWidth() / (float) getHeight();
camera.setPerspective(30.0f, aspect, 1.0f, 1000.0f);
camera.setTranslation(0.0f, 0.0f, 10.0f);
_world.addChild(camera);
_world.setActiveCamera(camera);
// Create lights.
Light light = new Light();
light.setMode(Light.OMNI);
light.setTranslation(0.0f, 0.0f, 3.0f);
_world.addChild(light);
// Create two sets of vertex data: one for blue meshes and one for red
// meshes.
VertexBuffer blueCubeVertexData = new VertexBuffer();
blueCubeVertexData.setDefaultColor(0x000000FF); // blue
VertexBuffer redCubeVertexData = new VertexBuffer();
redCubeVertexData.setDefaultColor(0x00FF0000); // red
VertexArray vertexPositions =
new VertexArray(VERTEX_POSITIONS.length/3, 3, 1);
vertexPositions.set(0, VERTEX_POSITIONS.length/3, VERTEX_POSITIONS);
blueCubeVertexData.setPositions(vertexPositions, 1.0f, null);
redCubeVertexData.setPositions(vertexPositions, 1.0f, null);
VertexArray vertexNormals =
new VertexArray(VERTEX_NORMALS.length/3, 3, 1);
vertexNormals.set(0, VERTEX_NORMALS.length/3, VERTEX_NORMALS);
blueCubeVertexData.setNormals(vertexNormals);
redCubeVertexData.setNormals(vertexNormals);
// Create the triangles that define the cube; the indices point to
// vertices in VERTEX_POSITIONS.
TriangleStripArray cubeTriangles = new TriangleStripArray(
TRIANGLE_INDICES, TRIANGLE_LENGTHS);
// Create material.
Material material = new Material();
material.setVertexColorTrackingEnable(true);
Appearance appearance = new Appearance();
appearance.setMaterial(material);
// Create groups to organize the cubes.
Group allMeshes = new Group();
allMeshes.setUserID(USER_ID_ALL_MESHES);
_world.addChild(allMeshes);
Group blueMeshes = new Group();
blueMeshes.setUserID(USER_ID_BLUE_MESHES);
allMeshes.addChild(blueMeshes);
Group redMeshes = new Group();
redMeshes.setUserID(USER_ID_RED_MESHES);
allMeshes.addChild(redMeshes);
// Create eight cubes in a circle.
for (int i=0; i<8; i++)
{
Mesh cubeMesh = null;
if ((i%2) == 0)
{
cubeMesh = new Mesh(blueCubeVertexData, cubeTriangles, appearance);
blueMeshes.addChild(cubeMesh);
}
else
{
cubeMesh = new Mesh(redCubeVertexData, cubeTriangles, appearance);
redMeshes.addChild(cubeMesh);
}
cubeMesh.setTranslation(1.5f * (float) Math.cos(i*Math.PI/4), 1.5f * (float) Math.sin(i*Math.PI/4), 0.0f);
cubeMesh.setScale(0.4f, 0.4f, 0.4f);
}
}
/**
* Drives the animation.
*/
public void run()
{
while(_isRunning)
{
// Rotate all meshes.
Group allMeshes = (Group) _world.find(USER_ID_ALL_MESHES);
allMeshes.postRotate(2, 0.0f, 0.0f, 1.0f);
_counter++;
if ((_counter%COUNTER_MAX) == 0)
{
_scale *= -1;
}
// Scale blue meshes.
Group blueMeshes = (Group) _world.find(USER_ID_BLUE_MESHES);
blueMeshes.scale(1 + _scale, 1 + _scale, 1 + _scale);
// Scale red meshes.
Group redMeshes = (Group) _world.find(USER_ID_RED_MESHES);
redMeshes.scale(1 - _scale, 1 - _scale, 1 - _scale);
repaint();
try
{
Thread.sleep(50);
}
catch (Exception e){}
}
}
/**
* Renders the sample on the screen.
*
* @param graphics the graphics object to draw on.
*/
protected void paint(Graphics graphics)
{
_graphics3d.bindTarget(graphics);
_graphics3d.render(_world);
_graphics3d.releaseTarget();
}
/**
* Returns the <code>Displayable</code> used to display this sample.
*
* @return display
*/
public Displayable getDisplayable()
{
return this;
}
/**
* Returns the display name of this sample.
*
* @return name
*/
public String getName()
{
return "Scene Graph";
}
}
|