/*
* 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 lit cube with material properties.
*
* @author Claus Hoefele
*/
public class LightingMaterialsSample 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, // 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
};
/** 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;
/** The cube"s appearance. */
private Appearance _cubeAppearance;
/** Light for the scene. */
private Light _light;
/** Graphics singleton used for rendering. */
private Graphics3D _graphics3d;
/** Light mode ambient (0). */
private static final int LIGHT_AMBIENT = 0;
/** Light mode directional (1). */
private static final int LIGHT_DIRECTIONAL = 1;
/** Light mode omni (2). */
private static final int LIGHT_OMNI = 2;
/** Light mode spot (3). */
private static final int LIGHT_SPOT = 3;
/** Current light mode. */
private int _lightMode;
/** Color target default (0). */
private static final int COLOR_DEFAULT = 0;
/** Color target ambient (1). */
private static final int COLOR_AMBIENT = 1;
/** Color target diffuse (2). */
private static final int COLOR_DIFFUSE = 2;
/** Color target emissive (3). */
private static final int COLOR_EMISSIVE = 3;
/** Color target specular (4). */
private static final int COLOR_SPECULAR = 4;
/** Current color target. */
private int _colorTarget;
/**
* 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 vertexNormals =
new VertexArray(VERTEX_NORMALS.length/3, 3, 1);
vertexNormals.set(0, VERTEX_NORMALS.length/3, VERTEX_NORMALS);
_cubeVertexData.setNormals(vertexNormals);
// Create the triangles that define the cube; the indices point to
// vertices in VERTEX_POSITIONS.
_cubeTriangles = new TriangleStripArray(TRIANGLE_INDICES,
TRIANGLE_LENGTHS);
// 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);
// Rotate the cube so we can see 3 sides.
_cubeTransform = new Transform();
_cubeTransform.postRotate(45.0f, 1.0f, 0.0f, 0.0f);
_cubeTransform.postRotate(45.0f, 0.0f, 1.0f, 0.0f);
// Create appearance and the material.
_cubeAppearance = new Appearance();
_colorTarget = COLOR_DEFAULT;
setMaterial(_cubeAppearance, _colorTarget);
// Create light.
_light = new Light();
_lightMode = LIGHT_OMNI;
setLightMode(_light, _lightMode);
Transform lightTransform = new Transform();
lightTransform.postTranslate(0.0f, 0.0f, 3.0f);
_graphics3d.resetLights();
_graphics3d.addLight(_light, lightTransform);
}
/**
* Sets the light mode.
*
* @param light light to be modified.
* @param mode light mode.
*/
protected void setLightMode(Light light, int mode)
{
switch (mode)
{
case LIGHT_AMBIENT:
light.setMode(Light.AMBIENT);
light.setIntensity(2.0f);
break;
case LIGHT_DIRECTIONAL:
light.setMode(Light.DIRECTIONAL);
light.setIntensity(1.0f);
break;
case LIGHT_OMNI:
light.setMode(Light.OMNI);
light.setIntensity(2.0f);
break;
case LIGHT_SPOT:
light.setMode(Light.SPOT);
light.setSpotAngle(20.0f);
light.setIntensity(2.0f);
break;
// no default
}
}
/**
* Sets the material according to the given target.
*
* @param appearance appearance to be modified.
* @param colorTarget target color.
*/
protected void setMaterial(Appearance appearance, int colorTarget)
{
Material material = new Material();
switch (colorTarget)
{
case COLOR_DEFAULT:
break;
case COLOR_AMBIENT:
material.setColor(Material.AMBIENT, 0x00FF0000);
break;
case COLOR_DIFFUSE:
material.setColor(Material.DIFFUSE, 0x00FF0000);
break;
case COLOR_EMISSIVE:
material.setColor(Material.EMISSIVE, 0x00FF0000);
break;
case COLOR_SPECULAR:
material.setColor(Material.SPECULAR, 0x00FF0000);
material.setShininess(2);
break;
// no default
}
appearance.setMaterial(material);
}
/**
* 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,
_cubeAppearance, _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(LEFT)) + "/" +
getKeyName(getKeyCode(RIGHT)) + ": Rotate y ", 0, height, 0);
// Lower half menu.
height = getHeight() - fontHeight;
switch (_light.getMode())
{
case Light.AMBIENT:
graphics.drawString(getKeyName(getKeyCode(GAME_B)) +
": Light: ambient", 0, height, 0);
break;
case Light.DIRECTIONAL:
graphics.drawString(getKeyName(getKeyCode(GAME_B)) +
": Light: directional", 0, height, 0);
break;
case Light.OMNI:
graphics.drawString(getKeyName(getKeyCode(GAME_B)) +
": Light: omni", 0, height, 0);
break;
case Light.SPOT:
graphics.drawString(getKeyName(getKeyCode(GAME_B)) +
": Light: spot", 0, height, 0);
break;
// no default
}
height -= fontHeight;
switch (_colorTarget)
{
case COLOR_AMBIENT:
graphics.drawString(getKeyName(getKeyCode(GAME_A)) +
": Color: ambient", 0, height, 0);
break;
case COLOR_DEFAULT:
graphics.drawString(getKeyName(getKeyCode(GAME_A)) +
": Color: default", 0, height, 0);
break;
case COLOR_DIFFUSE:
graphics.drawString(getKeyName(getKeyCode(GAME_A)) +
": Color: diffuse", 0, height, 0);
break;
case COLOR_EMISSIVE:
graphics.drawString(getKeyName(getKeyCode(GAME_A)) +
": Color: emissive", 0, height, 0);
break;
case COLOR_SPECULAR:
graphics.drawString(getKeyName(getKeyCode(GAME_A)) +
": Color: specular", 0, height, 0);
break;
// no default
}
}
/**
* Handles key presses.
*
* @param keyCode key code.
*/
protected void keyPressed(int keyCode)
{
switch (getGameAction(keyCode))
{
case LEFT:
_cubeTransform.postRotate(-10.0f, 0.0f, 1.0f, 0.0f);
break;
case RIGHT:
_cubeTransform.postRotate(10.0f, 0.0f, 1.0f, 0.0f);
break;
case FIRE:
init();
break;
case GAME_A:
_colorTarget++;
_colorTarget %= 5;
setMaterial(_cubeAppearance, _colorTarget);
break;
case GAME_B:
_lightMode++;
_lightMode %= 4;
setLightMode(_light, _lightMode);
break;
// no default
}
repaint();
}
/**
* 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 "Lighting and Materials";
}
}
|