/*
* Sample code for M3G article on IBM developerWorks.
* http://www.ibm.com/developerworks/
*/
package m3gsamples1;
import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;
/**
* Sample displaying a cube that can be transformed.
*
* @author Claus Hoefele
*/
public class TransformationsSample extends Canvas implements Sample
{
/** 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,
-1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1
};
/** The cube"s vertex colors (R, G, B). */
private static final byte[] VERTEX_COLORS = {
0, 0, (byte) 128, 0, 0, (byte) 255,
0, (byte) 255, 0, 0, (byte) 255, (byte) 255,
(byte) 255, 0, 0, (byte) 255, 0, (byte) 255,
(byte) 255, (byte) 255, 0, (byte) 255, (byte) 255, (byte) 255
};
/** Indices that define how to connect the vertices to build
* triangles. */
private static int[] TRIANGLE_INDICES = {
0, 1, 2, 3, 7, 1, 5, 4, 7, 6, 2, 4, 0, 1
};
/** The cube"s vertex data. */
private VertexBuffer _cubeVertexData;
/** The cube"s triangles defined as triangle strips. */
private TriangleStripArray _cubeTriangles;
/** The cube"s transformation. */
private Transform _cubeTransform;
/** Transform using x-axis. */
private static final int TRANSFORMATION_X_AXIS = 0;
/** Transform using y-axis. */
private static final int TRANSFORMATION_Y_AXIS = 1;
/** Transform using z-axis. */
private static final int TRANSFORMATION_Z_AXIS = 2;
/** Rotate. */
private static final int TRANSFORMATION_ROTATE = 0;
/** Translate. */
private static final int TRANSFORMATION_TRANSLATE = 1;
/** Scale. */
private static final int TRANSFORMATION_SCALE = 2;
/** Current transformation. */
private int _transformation = TRANSFORMATION_ROTATE;
/** Graphics singleton used for rendering. */
private Graphics3D _graphics3d;
/**
* Called when this sample is displayed.
*/
public void showNotify()
{
init();
}
/**
* Initializes the sample.
*/
protected void init()
{
// Get the singleton for 3D rendering.
_graphics3d = Graphics3D.getInstance();
// Create vertex data.
_cubeVertexData = new VertexBuffer();
VertexArray vertexPositions =
new VertexArray(VERTEX_POSITIONS.length/3, 3, 1);
vertexPositions.set(0, VERTEX_POSITIONS.length/3, VERTEX_POSITIONS);
_cubeVertexData.setPositions(vertexPositions, 1.0f, null);
VertexArray vertexColors =
new VertexArray(VERTEX_COLORS.length/3, 3, 1);
vertexColors.set(0, VERTEX_COLORS.length/3, VERTEX_COLORS);
_cubeVertexData.setColors(vertexColors);
// Create the triangles that define the cube; the indices point to
// vertices in VERTEX_POSITIONS.
_cubeTriangles = new TriangleStripArray(TRIANGLE_INDICES,
new int[] {TRIANGLE_INDICES.length});
// 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);
Transform cameraTransform = new Transform();
cameraTransform.postTranslate(0.0f, 0.0f, 10.0f);
_graphics3d.setCamera(camera, cameraTransform);
// Reset the cube"s transformations.
_cubeTransform = new Transform();
_transformation = TRANSFORMATION_ROTATE;
}
/**
* Renders the sample on the screen.
*
* @param graphics the graphics object to draw on.
*/
protected void paint(Graphics graphics)
{
_graphics3d.bindTarget(graphics);
_graphics3d.clear(null);
_graphics3d.render(_cubeVertexData, _cubeTriangles,
new Appearance(), _cubeTransform);
_graphics3d.releaseTarget();
drawMenu(graphics);
}
/**
* Draws a menu on the screen.
*
* @param graphics graphics context.
*/
protected void drawMenu(Graphics graphics)
{
graphics.setColor(0xFFFFFFFF);
int fontHeight = graphics.getFont().getHeight();
// Upper half menu.
int height = 0;
graphics.drawString(getKeyName(getKeyCode(FIRE)) + ": Reset", 0,
height, 0);
height += fontHeight;
graphics.drawString(
getKeyName(getKeyCode(UP)) + "/" +
getKeyName(getKeyCode(DOWN)) + ": x " +
getKeyName(getKeyCode(LEFT)) + "/" +
getKeyName(getKeyCode(RIGHT)) + ": y " +
getKeyName(getKeyCode(GAME_A)) + "/" +
getKeyName(getKeyCode(GAME_B)) + ": z ", 0, height, 0);
// Lower half menu.
height = getHeight() - fontHeight;
if (_transformation == TRANSFORMATION_ROTATE)
{
graphics.drawString(getKeyName(getKeyCode(GAME_C)) +
": Transformation: rotate", 0, height, 0);
}
else if (_transformation == TRANSFORMATION_TRANSLATE)
{
graphics.drawString(getKeyName(getKeyCode(GAME_C)) +
": Transformation: translate", 0, height, 0);
}
else if (_transformation == TRANSFORMATION_SCALE)
{
graphics.drawString(getKeyName(getKeyCode(GAME_C)) +
": Transformation: scale", 0, height, 0);
}
}
/**
* Handles key presses.
*
* @param keyCode key code.
*/
protected void keyPressed(int keyCode)
{
switch (getGameAction(keyCode))
{
case UP:
transform(_transformation, TRANSFORMATION_X_AXIS, false);
break;
case DOWN:
transform(_transformation, TRANSFORMATION_X_AXIS, true);
break;
case LEFT:
transform(_transformation, TRANSFORMATION_Y_AXIS, false);
break;
case RIGHT:
transform(_transformation, TRANSFORMATION_Y_AXIS, true);
break;
case GAME_A:
transform(_transformation, TRANSFORMATION_Z_AXIS, false);
break;
case GAME_B:
transform(_transformation, TRANSFORMATION_Z_AXIS, true);
break;
case FIRE:
init();
break;
case GAME_C:
_transformation++;
_transformation %= 3;
break;
// no default
}
repaint();
}
/**
* Transforms the cube with the given parameters.
*
* @param transformation transformation (rotate, translate, scale)
* @param axis axis of translation (x, y, z)
* @param positiveDirection true for increase, false for decreasing
* value.
*/
protected void transform(int transformation, int axis,
boolean positiveDirection)
{
if (transformation == TRANSFORMATION_ROTATE)
{
float amount = 10.0f * (positiveDirection ? 1 : -1);
switch (axis)
{
case TRANSFORMATION_X_AXIS:
_cubeTransform.postRotate(amount, 1.0f, 0.0f, 0.0f);
break;
case TRANSFORMATION_Y_AXIS:
_cubeTransform.postRotate(amount, 0.0f, 1.0f, 0.0f);
break;
case TRANSFORMATION_Z_AXIS:
_cubeTransform.postRotate(amount, 0.0f, 0.0f, 1.0f);
break;
// no default
}
}
else if (transformation == TRANSFORMATION_SCALE)
{
float amount = positiveDirection ? 1.2f : 0.8f;
switch (axis)
{
case TRANSFORMATION_X_AXIS:
_cubeTransform.postScale(amount, 1.0f, 1.0f);
break;
case TRANSFORMATION_Y_AXIS:
_cubeTransform.postScale(1.0f, amount, 1.0f);
break;
case TRANSFORMATION_Z_AXIS:
_cubeTransform.postScale(1.0f, 1.0f, amount);
break;
// no default
}
}
else if (transformation == TRANSFORMATION_TRANSLATE)
{
float amount = 0.2f * (positiveDirection ? 1 : -1);
switch (axis)
{
case TRANSFORMATION_X_AXIS:
_cubeTransform.postTranslate(amount, 0.0f, 0.0f);
break;
case TRANSFORMATION_Y_AXIS:
_cubeTransform.postTranslate(0.0f, amount, 0.0f);
break;
case TRANSFORMATION_Z_AXIS:
_cubeTransform.postTranslate(0.0f, 0.0f, amount);
break;
// no default
}
}
}
/**
* Handles key repeat events for phones that support them. Redirects
* all key input to <code>keyPressed()</code>.
*
* @param keyCode key code.
*/
protected void keyRepeated(int keyCode)
{
keyPressed(keyCode);
}
/**
* 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 "Transformations";
}
}
|