/*
* OpenGLDemoField.java
*
* Copyright � 1998-2011 Research In Motion Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Note: For the sake of simplicity, this sample application may not leverage
* resource bundles and resource strings. However, it is STRONGLY recommended
* that application developers make use of the localization features available
* within the BlackBerry development platform to ensure a seamless application
* experience across a variety of languages and geographies. For more information
* on localizing your application, please refer to the BlackBerry Java Development
* Environment Development Guide associated with this release.
*/
package com.rim.samples.device.opengl11demo;
import javax.microedition.khronos.opengles.GL;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
import net.rim.device.api.animation.AnimatedScalar;
import net.rim.device.api.animation.Animation;
import net.rim.device.api.animation.Animator;
import net.rim.device.api.opengles.GLField;
import net.rim.device.api.opengles.GLUtils;
import net.rim.device.api.system.Display;
import net.rim.device.api.system.EncodedImage;
/**
* A GLField subclass that renders a cube using OpenGL ES 1.1
*/
class OpenGLDemoField extends GLField {
private static final int TARGET_FRAMERATE = 60;
private Cube _cube;
private boolean _sizeChanged = true;
private Animator _animator;
private final AnimatedScalar _rotation = new AnimatedScalar(0.0f);
/**
* Creates a new OpenGLDemoField object
*/
OpenGLDemoField() {
super(GLField.VERSION_1_1);
setTargetFrameRate(TARGET_FRAMERATE);
initializeAnimation();
}
/**
* @see net.rim.device.api.opengles.GLField#initialize(GL)
*/
protected void initialize(final GL g) {
final GL11 gl = (GL11) g;
_cube = new Cube();
_cube.init(gl);
// Initialize OpenGL state and load all OpenGL resources
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glEnable(GL10.GL_CULL_FACE);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnable(GL10.GL_LIGHTING);
gl.glEnable(GL10.GL_LIGHT0);
// The default light is white with direction (0, 0 ,-1)
// Load texture
gl.glActiveTexture(GL10.GL_TEXTURE0);
final EncodedImage encodedImage =
EncodedImage.getEncodedImageResource("BlackBerry.png");
createTexture(gl, encodedImage, GL10.GL_RGB,
GL10.GL_UNSIGNED_SHORT_5_6_5);
checkError(gl);
}
/**
* Initializes the animations
*/
private void initializeAnimation() {
_animator = new Animator(0);
// Add an animation that will animate indefinitely from 0.0 to 360.0
// over 5 seconds.
final Animation animation =
_animator.addAnimationFromTo(_rotation,
AnimatedScalar.ANIMATION_PROPERTY_SCALAR, 0.0f, 360.0f,
Animation.EASINGCURVE_LINEAR, 5000L);
animation.setRepeatCount(Animation.REPEAT_COUNT_INDEFINITE);
_animator.begin(0L);
}
/**
* @see net.rim.device.api.opengles.GLField#render(GL)
*/
protected void render(final GL g) {
final GL11 gl = (GL11) g;
if (_sizeChanged) {
sizeChanged(gl, getWidth(), getHeight());
_sizeChanged = false;
}
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Transform the cube
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glTranslatef(0, 0, -3.5f);
gl.glRotatef(_rotation.getFloat(), 1.0f, 1.0f, 0.0f);
// Enable position, normal and texture coordinates
_cube.enableVertexAttrib();
_cube.enableTexcoordAttrib();
_cube.enableNormalAttrib();
// Draw the cube
_cube.render(gl);
checkError(gl);
}
/**
* @see net.rim.device.api.ui.Field#layout(int, int)
*/
protected void layout(final int width, final int height) {
// Use all available width and height up to the screen's size
setExtent(Math.min(width, Display.getWidth()), Math.min(height, Display
.getHeight()));
_sizeChanged = true;
}
/**
* @see net.rim.device.api.ui.Field#sizeChanged(GL11 , int, int)
*/
public void sizeChanged(final GL11 gl, final int width, final int height) {
// Update the viewport to reflect the new size
gl.glViewport(0, 0, width, height);
// Set up a perspective projection
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
// Note: The below convenience method can be replaced with an
// appropriate GL10#glFrustum call.
GLUtils.gluPerspective(gl, 45.0f, (float) width / (float) height,
0.15f, 100.0f);
}
/**
* @see net.rim.device.api.opengles.GLField#update()
*/
public void update() {
// Updates the animator at the same frequency as the GLField
_animator.update();
}
/**
* Creates and binds a new texture from the given EncodedImage
*
* @param gl
* The GL context.
* @param encodedImage
* EncodedImage containing the texture data to load
* @param format
* Format for the texture
* @param type
* Data type for the texture
* @return Texture name of the created texture
*/
private static int createTexture(final GL11 gl,
final EncodedImage encodedImage, final int format, final int type) {
final int[] textures = new int[1];
// Generate 1 texture
gl.glGenTextures(1, textures, 0);
final int texture = textures[0];
// Bind the newly generated texture
gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
// Turn on automatic mipmap generation
gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP,
GL10.GL_TRUE);
// Load the image data from the encodedImage into the texture
GLUtils.glTexImage2D(gl, GL10.GL_TEXTURE_2D, 0, format, type,
encodedImage, null);
// Turn on tri-linear filtering
gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
GL10.GL_LINEAR_MIPMAP_LINEAR);
gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_LINEAR);
gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
GL10.GL_REPEAT);
gl.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
GL10.GL_REPEAT);
return texture;
}
/**
* Throws a RuntimeException if a GL error was detected
*
* @param gl
* The GL context
* @throws RuntimeException
* If a GL error was detected
*/
private static void checkError(final GL11 gl) {
final int error = gl.glGetError();
if (error != 0) {
throw new RuntimeException("GL Error: " + error);
}
}
}