com.adobe.plugins.FastCanvasRenderer.java Source code

Java tutorial

Introduction

Here is the source code for com.adobe.plugins.FastCanvasRenderer.java

Source

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

package com.adobe.plugins;

import java.io.IOException;
import java.io.InputStream;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import org.json.JSONArray;

import android.app.Activity;
//import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES10;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import android.util.Log;

public class FastCanvasRenderer implements GLSurfaceView.Renderer {
    // ==========================================================================
    public FastCanvasRenderer(FastCanvasView view) {
        super();
        mView = view;
        // Frame limiter
        //startTime = System.currentTimeMillis();
    }

    // ==========================================================================
    private String mRenderCommands;
    private LinkedList<FastCanvasMessage> mLocalQueue = new LinkedList<FastCanvasMessage>();
    private List<FastCanvasTexture> mTextures = new ArrayList<FastCanvasTexture>();
    private List<FastCanvasMessage> mCaptureQueue = new ArrayList<FastCanvasMessage>();
    private FastCanvasView mView;

    // Frame limiter
    //private long startTime;

    // ==========================================================================
    private void flushQueue() {
        synchronized (this) {
            if (!FastCanvas.copyMessageQueue(mLocalQueue)) {
                // Tear down. if any to be done.
                return;
            }
        }

        mRenderCommands = "";
        FastCanvasMessage m;

        while (mLocalQueue.size() > 0) {
            m = mLocalQueue.remove();
            if (m.type == FastCanvasMessage.Type.LOAD) {
                Activity theActivity = FastCanvas.getActivity();
                if (theActivity != null) {
                    // If we are re-using a texture ID, unload the old texture
                    for (int i = 0; i < mTextures.size(); i++) {
                        if (mTextures.get(i).id == m.textureID) {
                            unloadTexture(m.textureID);
                            break;
                        }
                    }

                    // Load and track the texture
                    String path = "www/" + m.url;
                    boolean success = false;
                    FastCanvasTextureDimension dim = new FastCanvasTextureDimension();

                    // See the following for why PNG files with premultiplied alpha and GLUtils don't get along
                    // http://stackoverflow.com/questions/3921685/issues-with-glutils-teximage2d-and-alpha-in-textures
                    if (path.toLowerCase(Locale.US).endsWith(".png")) {
                        success = FastCanvasJNI.addPngTexture(theActivity.getAssets(), path, m.textureID, dim);
                        if (success == false) {
                            Log.i("CANVAS",
                                    "CanvasRenderer loadTexture failed to load PNG in native code, falling back to GLUtils.");
                        }
                    }

                    if (success == false) {
                        try {
                            InputStream instream = theActivity.getAssets().open(path);
                            final Bitmap bmp = BitmapFactory.decodeStream(instream);
                            loadTexture(bmp, m.textureID);
                            dim.width = bmp.getWidth();
                            dim.height = bmp.getHeight();
                            success = true;
                        } catch (IOException e) {
                            Log.i("CANVAS", "CanvasRenderer loadTexture error=", e);
                            m.callbackContext.error(e.getMessage());
                        }
                    }

                    if (success == true) {
                        FastCanvasTexture t = new FastCanvasTexture(m.url, m.textureID);
                        mTextures.add(t);

                        JSONArray args = new JSONArray();
                        args.put(dim.width);
                        args.put(dim.height);
                        m.callbackContext.success(args);
                    }
                }
            } else if (m.type == FastCanvasMessage.Type.UNLOAD) {
                // Stop tracking the texture
                for (int i = 0; i < mTextures.size(); i++) {
                    if (mTextures.get(i).id == m.textureID) {
                        mTextures.remove(i);
                        break;
                    }
                }
                unloadTexture(m.textureID);
            } else if (m.type == FastCanvasMessage.Type.RELOAD) {
                Activity theActivity = FastCanvas.getActivity();
                if (theActivity != null) {
                    // Reload the texture
                    String path = "www/" + m.url;
                    boolean success = false;

                    if (path.toLowerCase(Locale.US).endsWith(".png")) {
                        success = FastCanvasJNI.addPngTexture(theActivity.getAssets(), path, m.textureID, null);
                    }

                    if (success == false) {
                        try {
                            InputStream instream = theActivity.getAssets().open(path);
                            final Bitmap bmp = BitmapFactory.decodeStream(instream);
                            loadTexture(bmp, m.textureID);
                        } catch (IOException e) {
                            Log.i("CANVAS", "CanvasRenderer reloadTexture error=", e);
                        }
                    }
                }
            } else if (m.type == FastCanvasMessage.Type.RENDER) {
                mRenderCommands = m.drawCommands;
                while (!mCaptureQueue.isEmpty()) {
                    FastCanvasMessage captureMessage = mCaptureQueue.get(0);
                    FastCanvasJNI.captureGLLayer(captureMessage.callbackContext.getCallbackId(), captureMessage.x,
                            captureMessage.y, captureMessage.width, captureMessage.height, captureMessage.url);
                    mCaptureQueue.remove(0);
                }
            } else if (m.type == FastCanvasMessage.Type.SET_ORTHO) {
                Log.i("CANVAS", "CanvasRenderer setOrtho width=" + m.width + ", height=" + m.height);
                FastCanvasJNI.setOrtho(m.width, m.height);
            } else if (m.type == FastCanvasMessage.Type.CAPTURE) {
                Log.i("CANVAS", "CanvasRenderer capture");
                mCaptureQueue.add(m);
            } else if (m.type == FastCanvasMessage.Type.SET_BACKGROUND) {
                Log.i("CANVAS", "CanvasRenderer setBackground color=" + m.drawCommands);
                // Some validation of the background color string is
                // done in JS, but the format of m.drawCommands cannot
                // be fully validated so we're going to give this a shot
                // and simply fail silently if an error occurs in parsing
                try {
                    int red = Integer.valueOf(m.drawCommands.substring(0, 2), 16);
                    int green = Integer.valueOf(m.drawCommands.substring(2, 4), 16);
                    int blue = Integer.valueOf(m.drawCommands.substring(4, 6), 16);
                    FastCanvasJNI.setBackgroundColor(red, green, blue);
                } catch (Exception e) {
                    Log.e("CANVAS", "Parsing background color: \"" + m.drawCommands + "\"", e);
                }
            }
        }
    }

    // ==========================================================================
    private void checkError() {
        int error = GLES10.glGetError();
        if (error != GLES10.GL_NO_ERROR) {
            Log.i("CANVAS", "CanvasRenderer glError=" + error);
        }
        assert error == GLES10.GL_NO_ERROR;
    }

    private boolean mDebugTextureChecked = false;

    private void debugTexture() {
        if (!mDebugTextureChecked) {/* Not for PGBuild
                                    synchronized( this ) {
                                    Activity theActivity = FastCanvas.getActivity();
                                    if ( theActivity != null ) { 
                                    try {
                                        
                                    // grabbing debug font image from the library
                                    // project's resource folder rather than the
                                    // main projects assets directory
                                    Log.i("CANVAS", "Loading debug texture" );
                                    Resources res = FastCanvas.getActivity().getResources();
                                    InputStream instream = res.openRawResource(R.drawable.debugfont);
                                    Bitmap tmp = BitmapFactory.decodeStream(instream);
                                        
                                    Bitmap bmp = Bitmap.createBitmap(tmp.getWidth(), tmp.getHeight(), Bitmap.Config.ARGB_8888);
                                    android.graphics.Canvas c = new android.graphics.Canvas();
                                    c.setBitmap(bmp);
                                    android.graphics.Paint p = new android.graphics.Paint();
                                    p.setFilterBitmap(true);
                                    c.drawBitmap(tmp, 0, 0, p);
                                    tmp.recycle();
                                    loadTexture(bmp, -1);
                                    bmp.recycle();
                                    } catch(Exception e) {
                                    Log.i("CANVAS", "Debug texture unavailable to load: " + e.getMessage());
                                    }
                                    }
                                    }*/
            mDebugTextureChecked = true;
        }
    }

    // ==========================================================================
    public void onDrawFrame(GL10 gl) {
        if (!mView.isPaused) {
            /*
            // Frame limiter.
            try {
               long endTime = System.currentTimeMillis();
                long dt = endTime - startTime;
                if (dt < 33)
             Thread.sleep(33 - dt);
                startTime = System.currentTimeMillis();
            } catch ( Exception e ) {
            }
            */

            flushQueue();
            debugTexture();

            FastCanvasJNI.render(mRenderCommands);
            checkError();
        }
    }

    // ==========================================================================
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        Log.i("CANVAS", "CanvasRenderer onSurfaceCreated. config:" + config.toString() + " gl:" + gl.toString());

        IntBuffer ib = IntBuffer.allocate(100);
        ib.position(0);
        GLES10.glGetIntegerv(GLES10.GL_RED_BITS, ib);
        int red = ib.get(0);
        GLES10.glGetIntegerv(GLES10.GL_GREEN_BITS, ib);
        int green = ib.get(0);
        GLES10.glGetIntegerv(GLES10.GL_BLUE_BITS, ib);
        int blue = ib.get(0);
        GLES10.glGetIntegerv(GLES10.GL_STENCIL_BITS, ib);
        int stencil = ib.get(0);
        GLES10.glGetIntegerv(GLES10.GL_DEPTH_BITS, ib);
        int depth = ib.get(0);

        Log.i("CANVAS", "CanvasRenderer R=" + red + " G=" + green + " B=" + blue + " DEPETH=" + depth + " STENCIL="
                + stencil);
    }

    // ==========================================================================
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        Log.i("CANVAS",
                "CanvasRenderer onSurfaceChanged. width:" + width + " height:" + height + " gl:" + gl.toString());

        FastCanvasJNI.surfaceChanged(width, height);
    }

    // ==========================================================================
    // Not an override - this is a way for the view to tell the renderer when the context has been destroyed
    public void onSurfaceDestroyed() {
        Log.i("CANVAS", "CanvasRenderer onSurfaceDestroyed");

        mDebugTextureChecked = false;
    }

    // ==========================================================================
    public void loadTexture(Bitmap bmp, int id) {
        if (bmp == null) {
            Log.i("CANVAS", "CanvasRenderer Aborting loadtexture " + id);
            return;
        }

        int[] glID = new int[1];
        GLES10.glGenTextures(1, glID, 0);
        GLES10.glBindTexture(GLES10.GL_TEXTURE_2D, glID[0]);
        GLES10.glTexParameterf(GLES10.GL_TEXTURE_2D, GLES10.GL_TEXTURE_MIN_FILTER, GLES10.GL_LINEAR);
        GLES10.glTexParameterf(GLES10.GL_TEXTURE_2D, GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_LINEAR);

        int width = bmp.getWidth();
        int height = bmp.getHeight();
        int p2Width = 2;
        while (p2Width < width) {
            p2Width *= 2;
        }

        int p2Height = 2;
        while (p2Height < height) {
            p2Height *= 2;
        }

        if (width == p2Width && height == p2Height) {
            GLUtils.texImage2D(GLES10.GL_TEXTURE_2D, 0, bmp, 0);
        } else {
            Log.i("Canvas", "Canvas::AddTexture scaling texture " + id + " to power of 2");
            GLES10.glTexImage2D(GLES10.GL_TEXTURE_2D, 0, GLES10.GL_RGBA, p2Width, p2Height, 0, GLES10.GL_RGBA,
                    GLES10.GL_UNSIGNED_BYTE, null);
            GLUtils.texSubImage2D(GLES10.GL_TEXTURE_2D, 0, 0, 0, bmp);
            width = p2Width;
            height = p2Height;
        }

        checkError();

        FastCanvasJNI.addTexture(id, glID[0], width, height);
        Log.i("CANVAS", "CanvasRenderer Leaving loadtexture " + id);
    }

    // ==========================================================================
    public void unloadTexture(int id) {
        FastCanvasJNI.removeTexture(id);
        Log.i("CANVAS", "CanvasRenderer unloadtexture");
        checkError();
    }

    // ==========================================================================
    public void reloadTextures() {
        Log.i("CANVAS", "CanvasRenderer reloadtextures");
        Iterator<FastCanvasTexture> ti = mTextures.iterator();
        while (ti.hasNext()) {
            FastCanvasTexture t = ti.next();
            FastCanvasMessage m = new FastCanvasMessage(FastCanvasMessage.Type.RELOAD);
            m.url = t.url;
            m.textureID = t.id;
            Log.i("CANVAS", "CanvasRenderer queueing reload texture " + m.textureID + ", " + m.url);
            mLocalQueue.add(m);
        }
    }
}