JMU
3D Graphics in J2ME
An Introduction


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Overview
Immediate Mode - Rendering Engine
Immediate Mode - Important Classes
Immediate Mode - Important Classes (cont.)
Immediate Mode - An Example

The Rendering Process

j2meexamples/src/java3d/CubeCanvas.java
        package java3d;

import javax.microedition.lcdui.*;
import javax.microedition.m3g.*;

import drivers.*;

/**
 * A simple example of immediate mode rendering using the
 * Mobile 3D Graphics API for J2ME
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class CubeCanvas extends Canvas implements AnimatorObserver
{
    private Appearance      appearance;
    private Background      background;
    private float           angle;
    private Graphics3D      g3;
    private IndexBuffer     indexBuffer;
    private Transform       rotation;
    private VertexBuffer    cube;

    
    // The vertices for the cube using a triangle strip that is organized
    // as follows:
    //
    //                1         0
    //                 o-------o 
    //                 | \     |
    //                 |   \   |
    //                 |     \ |
    //                 o-------o
    //                3         2
    //
    private static short[] vertices = {
            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,   // Left
            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,   // Top
            1,-1, 1,  -1,-1, 1,   1,-1,-1,  -1,-1,-1    // Bottom
    };
    private static int[] stripLengths = { 4, 4, 4, 4, 4, 4 };


    
    // The normals
    private static byte[] normals = {  
            0, 0, 1,    0, 0, 1,    0, 0, 1,    0, 0, 1, // Front
            0, 0,-1,    0, 0,-1,    0, 0,-1,    0, 0,-1, // Back
           -1, 0, 0,   -1, 0, 0,   -1, 0, 0,   -1, 0, 0, // Left
            1, 0, 0,    1, 0, 0,    1, 0, 0,    1, 0, 0, // Right
            0, 1, 0,    0, 1, 0,    0, 1, 0,    0, 1, 0, // Top
            0,-1, 0,    0,-1, 0,    0,-1, 0,    0,-1, 0  // Bottom
    };
    
    
    /**
     * Default Constructor
     */
    public CubeCanvas() 
    {
        // Add the Exit command to the menu
        addCommand(new Command("Exit", Command.EXIT, 1));

        // Initalize the rendering engine
        init();
        
        // Initialize the cube
        createCube();
    }

    /**
     * Handle a "tick" from the Animator
     */
    public void animate()
    {
        repaint();
    }
    
    /**
     * Create a cube
     */
    private void createCube()
    {
        Material           material;
        VertexArray        normalArray, vertexArray;
        
        
        // Create a VertexArray for the vertices
        vertexArray = new VertexArray(vertices.length/3, 3, 2);
        vertexArray.set(0, vertices.length/3, vertices);

        // Create a VertexArray for the normals
        normalArray = new VertexArray(normals.length/3, 3, 1);
        normalArray.set(0, normals.length/3, normals);
       
        // Create the VertexBuffer for the cube
        cube = new VertexBuffer();
        cube.setPositions(vertexArray, 1.0f, null);
        cube.setNormals(normalArray);

        // Create the IndexBuffer for the cube
        indexBuffer = new TriangleStripArray( 0, stripLengths );

        // Create the Material for the cube
        material = new Material();
        material.setColor(Material.DIFFUSE,  0xC2A14D);    // JMU Gold
        material.setColor(Material.SPECULAR, 0xFFFFFFFF);  // White
        material.setShininess(100.0f);
         
        // Create the Appearance for the cube
        appearance = new Appearance();
        appearance.setMaterial(material);
    }

    
    /**
     * Initialize the rendering engine
     */
     private void init()
     {
        Camera          camera;
        float           aspect;
        Light           light;
        Transform       cameraTranslation;
        
        angle = 0.0f;
        
        // Create the Background
        background = new Background();
        background.setColor(0x450084); // JMU Purple    

        // Create the rotational transform
        rotation   = new Transform();
        

        // get the singleton Graphics3D instance
        g3 = Graphics3D.getInstance();

        // Create the Camera
        aspect = (float)getWidth()/ (float)getHeight();
        camera = new Camera();
        camera.setPerspective(60.0f,     // Field of View (Vertical)
                              aspect,    // Aspect Ratio
                              1.0f,      // Near Clipping Plane
                              1000.0f ); // Far Clipping Plane

        // Move the camera
        cameraTranslation = new Transform();
        cameraTranslation.postTranslate(0.0f, 0.0f, 3.0f);
        g3.setCamera(camera, cameraTranslation);        


        // Create a light at the camera position
        g3.resetLights();
        light = new Light();
        light.setColor(0xFFFFFF);
        light.setIntensity(1.0f);
        g3.addLight(light, cameraTranslation);
     }
    
    
    /**
     * Render this component
     *
     * @param g   The underlying rendering engine
     */
    protected void paint(Graphics g) 
    {
        // Bind the Graphics object to the Graphics3D object
        g3.bindTarget(g, true, Graphics3D.DITHER |Graphics3D.TRUE_COLOR);

        // Clear the pixel and depth buffers
        g3.clear(background);

        // Rotate the cube
        angle += 1.0f;
        rotation.setIdentity();
        rotation.postRotate(angle,
                            1.0f, 0.0f, 0.0f);  // Rotate around the x-axis

        // Render the cube
        g3.render(cube, indexBuffer, appearance, rotation);

        // Flush the rendering engine
        g3.releaseTarget();
    }
    
    
}
        
Immediate Mode - An Example (cont.)

The MIDlet

j2meexamples/src/drivers/CubeDriver.java
        package drivers;

import java.util.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

import java3d.*;

/**
 * A simple example of immediate mode rendering using the
 * Mobile 3D Graphics API for J2ME
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class CubeDriver extends MIDlet implements CommandListener
{
    Animator       animator;
    CubeCanvas     canvas;
    Timer          timer;

    /**
     * Default Constructor
     */
    public CubeDriver() 
    {
        // Construct the Displayable
        canvas = new CubeCanvas();
        canvas.setCommandListener(this);
        
        // Construct the Timer
        timer = new Timer();
        
        // Construct the Timer "callback"
        animator = new Animator(canvas);
    }

    
    /**
     * Handle commandAction events
     * (required by CommandListener)
     *
     * @param c   The Command
     * @param d   The Displayable that generated the event
     */
    public void commandAction(Command c, Displayable d) 
    {
        if (c.getCommandType() == Command.EXIT) 
        {
            destroyApp(true);
        }
    }    

    /**
     * Destroy this MIDlet
     */
    public void destroyApp(boolean unconditional) 
    {
    }
    
    
    /**
     * Entry point
     */
    public void startApp() 
    {
        Display.getDisplay(this).setCurrent(canvas);
        timer.schedule(animator, 0, 40 );
    }

    /**
     * Pause this MIDlet
     */
    public void pauseApp() 
    {
    }

    
}        
Retained Mode