/* * PanoramaGL library * Version 0.2 beta * Copyright (c) 2010 Javier Baez <[email protected]> * * 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.panoramagl; import android.opengl.GLU; import com.panoramagl.ios.structs.CGRect; import com.panoramagl.ios.structs.CGSize; import com.panoramagl.opengl.GLWrapper; import com.panoramagl.opengl.IGLWrapper; import com.panoramagl.opengl.matrix.MatrixTrackingGL; import com.panoramagl.transitions.PLITransition; import com.panoramagl.utils.PLLog; import com.panoramagl.utils.PLOpenGLSupport; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL11ExtensionPack; public class PLRenderer extends PLObjectBase implements PLIRenderer { /** * member variables */ private int[] mBackingWidth, mBackingHeight; private int[] mDefaultFramebuffer, mColorRenderbuffer; private PLIView mView; private PLIScene mScene; private boolean mIsRunning, mIsRendering; private CGRect mViewport, mTempViewport; private CGSize mSize, mTempSize; private boolean mContextSupportsFrameBufferObject; private PLRendererListener mListener; /** * init methods */ public PLRenderer(PLIView view, PLIScene scene) { super(); this.setInternalView(view); this.setInternalScene(scene); } @Override protected void initializeValues() { mBackingWidth = new int[1]; mBackingHeight = new int[1]; mDefaultFramebuffer = new int[1]; mColorRenderbuffer = new int[1]; mIsRunning = mIsRendering = false; mViewport = CGRect.CGRectMake(mTempViewport = CGRect.CGRectMake(0, 0, PLConstants.kViewportSize, PLConstants.kViewportSize)); mSize = CGSize.CGSizeMake(mTempSize = CGSize.CGSizeMake(0.0f, 0.0f)); mContextSupportsFrameBufferObject = false; } /** * property methods */ @Override public int getBackingWidth() { return mBackingWidth[0]; } @Override public int getBackingHeight() { return mBackingHeight[0]; } @Override public PLIView getInternalView() { return mView; } @Override public void setInternalView(PLIView view) { mView = view; } @Override public PLIScene getInternalScene() { return mScene; } @Override public void setInternalScene(PLIScene scene) { mScene = scene; } @Override public boolean isRunning() { return mIsRunning; } @Override public boolean isRendering() { return mIsRendering; } @Override public CGRect getViewport() { return mTempViewport.setValues(mViewport); } @Override public CGSize getSize() { return mTempSize.setValues(mSize); } protected boolean getContextSupportsFrameBufferObject() { return mContextSupportsFrameBufferObject; } @Override public PLRendererListener getInternalListener() { return mListener; } @Override public void setInternalListener(PLRendererListener listener) { mListener = listener; } /** * buffer methods */ protected void createFrameBuffer(GL11ExtensionPack gl11ep) { if (mContextSupportsFrameBufferObject) { gl11ep.glGenFramebuffersOES(1, mDefaultFramebuffer, 0); if (mDefaultFramebuffer[0] <= 0) PLLog.error("PLRenderer::createFrameBuffer", "Invalid framebuffer id returned!"); gl11ep.glGenRenderbuffersOES(1, mColorRenderbuffer, 0); if (mColorRenderbuffer[0] <= 0) PLLog.error("PLRenderer::createFrameBuffer", "Invalid renderbuffer id returned!"); gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, mDefaultFramebuffer[0]); gl11ep.glBindRenderbufferOES(GL11ExtensionPack.GL_RENDERBUFFER_OES, mColorRenderbuffer[0]); } } protected void destroyFramebuffer(GL11ExtensionPack gl11ep) { if (mContextSupportsFrameBufferObject) { if (mDefaultFramebuffer[0] != 0) { gl11ep.glDeleteFramebuffersOES(1, mDefaultFramebuffer, 0); mDefaultFramebuffer[0] = 0; } if (mColorRenderbuffer[0] != 0) { gl11ep.glDeleteRenderbuffersOES(1, mColorRenderbuffer, 0); mColorRenderbuffer[0] = 0; } } } /** * resize methods */ @Override public boolean resizeFromLayer() { return this.resizeFromLayer(null); } @Override public boolean resizeFromLayer(GL11ExtensionPack gl11ep) { if (mContextSupportsFrameBufferObject && gl11ep != null) { synchronized (this) { if (mBackingWidth[0] != mSize.width || mBackingHeight[0] != mSize.height) { boolean isRunning = mIsRunning; if (isRunning) mIsRunning = false; this.destroyFramebuffer(gl11ep); this.createFrameBuffer(gl11ep); gl11ep.glRenderbufferStorageOES(GL11ExtensionPack.GL_RENDERBUFFER_OES, GL11ExtensionPack.GL_RGBA8, mSize.width, mSize.height); gl11ep.glFramebufferRenderbufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, GL11ExtensionPack.GL_COLOR_ATTACHMENT0_OES, GL11ExtensionPack.GL_RENDERBUFFER_OES, mColorRenderbuffer[0]); gl11ep.glGetRenderbufferParameterivOES(GL11ExtensionPack.GL_RENDERBUFFER_OES, GL11ExtensionPack.GL_RENDERBUFFER_WIDTH_OES, mBackingWidth, 0); gl11ep.glGetRenderbufferParameterivOES(GL11ExtensionPack.GL_RENDERBUFFER_OES, GL11ExtensionPack.GL_RENDERBUFFER_HEIGHT_OES, mBackingHeight, 0); mViewport.x = -(mViewport.width / 2 - mSize.width / 2); mViewport.y = -(mViewport.height / 2 - mSize.height / 2); if (gl11ep.glCheckFramebufferStatusOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES) != GL11ExtensionPack.GL_FRAMEBUFFER_COMPLETE_OES) { PLLog.error("PLRenderer::resizeFromLayer", "Failed to make complete framebuffer object %x", gl11ep.glCheckFramebufferStatusOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES)); return false; } if (isRunning) mIsRunning = true; return true; } } } else { synchronized (this) { mViewport.x = -(mViewport.width / 2 - mSize.width / 2); mViewport.y = -(mViewport.height / 2 - mSize.height / 2); } } return false; } /** * render methods */ protected void renderScene(GL10 gl, PLIScene scene, PLICamera camera) { if (scene != null && camera != null) { gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); GLU.gluPerspective(gl, camera.getFov(), PLConstants.kPerspectiveAspect, PLConstants.kPerspectiveZNear, PLConstants.kPerspectiveZFar); gl.glMatrixMode(GL10.GL_MODELVIEW); scene.render(gl, this); } } @Override public void render(GL10 gl) { try { if (gl != null && mIsRunning) { mIsRendering = true; if (mContextSupportsFrameBufferObject) { GL11ExtensionPack gl11ep = (GL11ExtensionPack) gl; gl11ep.glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, mDefaultFramebuffer[0]); } gl.glViewport(mViewport.x, mViewport.y, mViewport.width, mViewport.height); gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); gl.glClearDepthf(1.0f); gl.glClear(GL10.GL_COLOR_BUFFER_BIT); gl.glClear(GL10.GL_DEPTH_BUFFER_BIT | GL10.GL_COLOR_BUFFER_BIT); gl.glEnable(GL10.GL_DEPTH_TEST); gl.glDepthFunc(GL10.GL_ALWAYS); gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); gl.glScalef(1.0f, 1.0f, PLConstants.kViewportScale); gl.glTranslatef(0.0f, 0.0f, 0.0f); gl.glRotatef(180.0f, 0.0f, 1.0f, 0.0f); if (mView != null && mView.isValidForTransition()) { PLITransition currentTransition = mView.getCurrentTransition(); if (currentTransition != null && currentTransition.isValid()) { this.renderScene(gl, currentTransition.getCurrentPanorama(), currentTransition.getCurrentPanoramaCamera()); this.renderScene(gl, currentTransition.getNewPanorama(), currentTransition.getNewPanoramaCamera()); } else this.renderScene(gl, mScene, mScene.getCamera()); } else this.renderScene(gl, mScene, mScene.getCamera()); if (mContextSupportsFrameBufferObject) { GL11ExtensionPack gl11ep = (GL11ExtensionPack) gl; gl11ep.glBindRenderbufferOES(GL11ExtensionPack.GL_RENDERBUFFER_OES, mColorRenderbuffer[0]); } mIsRendering = false; } } catch (Throwable e) { mIsRendering = false; PLLog.debug("PLRenderer::render", e); } } @Override public void renderNTimes(GL10 gl, int times) { for (int i = 0; i < times; i++) this.render(gl); } /** * control methods */ @Override public boolean start() { if (!mIsRunning) { synchronized (this) { mIsRunning = true; return true; } } return false; } @Override public boolean stop() { if (mIsRunning) { synchronized (this) { mIsRunning = false; return true; } } return false; } /** * PLIReleaseView methods */ @Override public void releaseView() { if (!mIsRunning) { mView = null; mScene = null; mListener = null; } } /** * dealloc methods */ @Override protected void finalize() throws Throwable { try { this.stop(); if (mContextSupportsFrameBufferObject) this.destroyFramebuffer((GL11ExtensionPack) mGLWrapper); } catch (Throwable e) { } mBackingWidth = mBackingHeight = null; mDefaultFramebuffer = mColorRenderbuffer = null; mView = null; mScene = null; mViewport = mTempViewport = null; mSize = mTempSize = null; mListener = null; mGLWrapper = null; super.finalize(); } // ============================ // Specific methods for Android // ============================ /** * android: member variables */ private boolean mIsGLContextCreated; private IGLWrapper mGLWrapper; /** * android: property methods */ protected boolean isGLContextCreated() { return mIsGLContextCreated; } protected IGLWrapper getGLWrapper() { return mGLWrapper; } @Override public GL10 getGLContext() { return mGLWrapper; } /** * android: GLSurfaceView.Renderer methods */ @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { try { mIsGLContextCreated = false; mGLWrapper = (PLOpenGLSupport.isHigherThanOpenGL1(gl) ? new GLWrapper(gl, mView.getGLSurfaceView()) : new MatrixTrackingGL(gl, mView.getGLSurfaceView())); //mContextSupportsFrameBufferObject = PLOpenGLSupport.checkIfContextSupportsFrameBufferObject(gl); this.start(); if (mListener != null) mListener.rendererCreated(this); } catch (Throwable e) { PLLog.error("PLRenderer::onSurfaceCreated", e); } } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { mSize.setValues(width, height); this.resizeFromLayer(mContextSupportsFrameBufferObject ? (GL11ExtensionPack) mGLWrapper : null); if (!mIsGLContextCreated) { if (mListener != null) mListener.rendererFirstChanged(mGLWrapper, this, width, height); mIsGLContextCreated = true; } if (mListener != null) mListener.rendererChanged(this, width, height); } @Override public void onDrawFrame(GL10 gl) { if (mIsGLContextCreated && mView != null) this.render(mGLWrapper); } }