Package com.rim.samples.device.opengl20demo

Source Code of com.rim.samples.device.opengl20demo.OpenGLDemoField

/*
* 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.opengl20demo;

import java.io.IOException;
import java.io.InputStream;

import javax.microedition.khronos.opengles.GL;

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.io.IOUtilities;
import net.rim.device.api.math.Matrix4f;
import net.rim.device.api.math.Vector3f;
import net.rim.device.api.opengles.GL20;
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 2.0
*/
class OpenGLDemoField extends GLField {
    private static final int TARGET_FRAMERATE = 60;

    // Shader filenames
    private static final String VERTEX_SHADER = "/shaders/TextureLight.vsh";
    private static final String FRAGMENT_SHADER = "/shaders/TextureLight.fsh";

    private Cube _cube;

    private boolean _sizeChanged = true;

    // Matrix for transforming the cube
    private final Matrix4f _matrix = new Matrix4f();

    // Projection matrix
    private final Matrix4f _projection = new Matrix4f();

    // Axis to rotate the cube around
    private final Vector3f _rotationAxis = new Vector3f(1.0f, 1.0f, 0.0f);

    // Shader program
    private int _program;

    // Vertex attribute locations
    private int _positionLoc;
    private int _texCoordLoc;
    private int _normalLoc;

    // Uniform locations
    private int _matrixLoc;
    private int _lightDirectionLoc;
    private int _lightAmbientLoc;
    private int _lightDiffuseLoc;
    private int _textureLoc;

    private Animator _animator;
    private final AnimatedScalar _rotation = new AnimatedScalar(0.0f);

    /**
     * Creates a new OpenGLDemoField object
     */
    OpenGLDemoField() {
        super(GLField.VERSION_2_0);

        setTargetFrameRate(TARGET_FRAMERATE);
        initializeAnimation();
    }

    /**
     * @see net.rim.device.api.opengles.GLField#initialize(GL)
     */
    protected void initialize(final GL g) {
        final GL20 gl = (GL20) g;

        // Create geometry for drawing a cube
        _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(GL20.GL_DEPTH_TEST);
        gl.glEnable(GL20.GL_CULL_FACE);

        // Load the shaders
        _program =
                createShaderProgram(gl, getSource(VERTEX_SHADER),
                        getSource(FRAGMENT_SHADER));
        gl.glUseProgram(_program);

        // Get attribute locations
        _positionLoc = gl.glGetAttribLocation(_program, "position");
        _texCoordLoc = gl.glGetAttribLocation(_program, "texCoord");
        _normalLoc = gl.glGetAttribLocation(_program, "normal");

        // Get uniform locations
        _matrixLoc = gl.glGetUniformLocation(_program, "matrix");
        _lightDirectionLoc =
                gl.glGetUniformLocation(_program, "lightDirection");
        _lightAmbientLoc = gl.glGetUniformLocation(_program, "lightAmbient");
        _lightDiffuseLoc = gl.glGetUniformLocation(_program, "lightDiffuse");
        _textureLoc = gl.glGetUniformLocation(_program, "texture");

        // Set uniform values
        gl.glUniform1i(_textureLoc, 0);

        // Light direction (normalized)
        gl.glUniform3f(_lightDirectionLoc, 0.0f, 0.0f, -1.0f);

        // Ambient light color
        gl.glUniform3f(_lightAmbientLoc, 0.2f, 0.2f, 0.2f);

        // Diffuse light color
        gl.glUniform3f(_lightDiffuseLoc, 1.0f, 1.0f, 1.0f);

        // Load texture
        gl.glActiveTexture(GL20.GL_TEXTURE0);
        final EncodedImage encodedImage =
                EncodedImage.getEncodedImageResource("BlackBerry.png");
        createTexture(gl, encodedImage, GL20.GL_RGB,
                GL20.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 2.0*PI over 5 seconds.
        final float r = (float) (Math.PI * 2.0);
        final Animation animation =
                _animator.addAnimationFromTo(_rotation,
                        AnimatedScalar.ANIMATION_PROPERTY_SCALAR, 0.0f, r,
                        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 GL20 gl = (GL20) g;

        if (_sizeChanged) {
            sizeChanged(gl, getWidth(), getHeight());
            _sizeChanged = false;
        }

        gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

        gl.glUseProgram(_program);

        // Transform the cube
        _matrix.setIdentity();
        _matrix.translate(0.0f, 0.0f, -3.5f);
        _matrix.rotate(_rotationAxis, _rotation.getFloat());

        // There are no matrix modes in GL20.
        // Multiply the model-view matrix with the projection
        // matrix and pass it to the shader program.
        Matrix4f.multiply(_projection, _matrix, _matrix);
        gl.glUniformMatrix4fv(_matrixLoc, 1, false, _matrix.getArray(), 0);

        // Set the attribute location of the position, normal and texture
        // coordinates
        _cube.enableVertexAttrib(_positionLoc);
        _cube.enableTexcoordAttrib(_texCoordLoc);
        _cube.enableNormalAttrib(_normalLoc);

        // 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;
    }

    /**
     * Called when the size of the drawable area changes
     *
     * @param gl
     *            The GL context
     * @param width
     *            The new width
     * @param height
     *            The new height
     */
    public void sizeChanged(final GL20 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
        Matrix4f.createPerspective(45.0f, (float) width / (float) height,
                0.15f, 100.0f, _projection);
    }

    /**
     * @see net.rim.device.api.opengles.GLField#update()
     */
    public void update() {
        // Updates the animator at the same frequency as the GLField
        _animator.update();
    }

    /**
     * Creates a shader program from the given vertex shader and fragment shader
     * source
     *
     * @param gl
     *            The GL context
     * @param vertexShaderSource
     *            The vertex shader source code
     * @param fragmentShaderSource
     *            The fragment shader source code
     * @return The program object id
     * @throws RuntimeException
     *             If there was an error compiling or linking the shaders
     */
    private static int createShaderProgram(final GL20 gl,
            final String vertexShaderSource, final String fragmentShaderSource) {
        final String[] infolog = new String[2];

        // Load and compile shaders
        final int vertexShader =
                GLUtils.glLoadShader(gl, GL20.GL_VERTEX_SHADER,
                        vertexShaderSource, infolog, 0);
        final int fragmentShader =
                GLUtils.glLoadShader(gl, GL20.GL_FRAGMENT_SHADER,
                        fragmentShaderSource, infolog, 1);

        // Check for shader compile errors
        if (vertexShader == 0) {
            throw new RuntimeException("Vertex shader compile error. \n"
                    + infolog[0]);
        }
        if (fragmentShader == 0) {
            throw new RuntimeException("Fragment shader compile error. \n"
                    + infolog[1]);
        }

        // Create the program object
        final int program = gl.glCreateProgram();
        if (program == 0) {
            throw new RuntimeException("Error creating shader program.");
        }

        // Attach the shader
        gl.glAttachShader(program, vertexShader);
        gl.glAttachShader(program, fragmentShader);

        // Link the program
        gl.glLinkProgram(program);

        // Check the link status
        final int[] linked = new int[1];
        gl.glGetProgramiv(program, GL20.GL_LINK_STATUS, linked, 0);
        if (linked[0] == GL20.GL_FALSE) {
            // Get the error string before deleting the program
            final String log = gl.glGetProgramInfoLog(program);
            gl.glDeleteProgram(program);
            throw new RuntimeException("Program link error. " + log);
        }

        // Delete the shader objects now that the program is linked
        gl.glDeleteShader(vertexShader);
        gl.glDeleteShader(fragmentShader);

        return program;
    }

    /**
     * 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 GL20 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(GL20.GL_TEXTURE_2D, texture);

        // Load the image data from the encodedImage into the texture
        GLUtils.glTexImage2D(gl, GL20.GL_TEXTURE_2D, 0, format, type,
                encodedImage, null);

        // Turn on automatic mipmap generation
        gl.glGenerateMipmap(GL20.GL_TEXTURE_2D);

        // Turn on tri-linear filtering
        gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MIN_FILTER,
                GL20.GL_LINEAR_MIPMAP_LINEAR);
        gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAG_FILTER,
                GL20.GL_LINEAR);
        gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_S,
                GL20.GL_REPEAT);
        gl.glTexParameteri(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_WRAP_T,
                GL20.GL_REPEAT);

        return texture;
    }

    /**
     * Returns the text from the given file in the given module
     *
     * @param filename
     *            The name of the file
     * @return The text in the file as a String or a blank String if there was
     *         an error
     */
    private String getSource(final String filename) {
        try {
            return readTextFromFile(filename);
        } catch (final IOException e) {
            return "";
        }
    }

    /**
     * Returns the text from the given file in the given module
     *
     * @param filename
     *            The name of the file
     * @return The text in the file as a String
     * @throws IOException
     *             If there was an error
     */
    private String readTextFromFile(final String filename) throws IOException {
        if (filename == null) {
            return "";
        }

        final InputStream stream = getClass().getResourceAsStream(filename);

        final byte[] bytes = IOUtilities.streamToBytes(stream);
        final String text = new String(bytes);

        stream.close();

        return text;
    }

    /**
     * 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 GL20 gl) {
        final int error = gl.glGetError();

        if (error != 0) {
            throw new RuntimeException("GL Error: " + error);
        }
    }
}
TOP

Related Classes of com.rim.samples.device.opengl20demo.OpenGLDemoField

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.