• An OpenGL ES renderer based on the GLSurfaceView rendering framework.


       
    /*
     * Copyright (C) 2008 The Android Open Source Project
     *
     * 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.
     */

    import java.io.IOException;
    import java.io.InputStream;
    import java.util.concurrent.Semaphore;

    import javax.microedition.khronos.egl.EGL10;
    import javax.microedition.khronos.egl.EGL11;
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.egl.EGLContext;
    import javax.microedition.khronos.egl.EGLDisplay;
    import javax.microedition.khronos.egl.EGLSurface;
    import javax.microedition.khronos.opengles.GL;
    import javax.microedition.khronos.opengles.GL10;
    import javax.microedition.khronos.opengles.GL11;
    import javax.microedition.khronos.opengles.GL11Ext;

    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.opengl.GLUtils;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;

    /**
     * An OpenGL ES renderer based on the GLSurfaceView rendering framework. This
     * class is responsible for drawing a list of renderables to the screen every
     * frame. It also manages loading of textures and (when VBOs are used) the
     * allocation of vertex buffer objects.
     */
    public class SimpleGLRenderer implements GLSurfaceView.Renderer {
      // Specifies the format our textures should be converted to upon load.
      private static BitmapFactory.Options sBitmapOptions = new BitmapFactory.Options();
      // An array of things to draw every frame.
      private GLSprite[] mSprites;
      // Pre-allocated arrays to use at runtime so that allocation during the
      // test can be avoided.
      private int[] mTextureNameWorkspace;
      private int[] mCropWorkspace;
      // A reference to the application context.
      private Context mContext;

      // Determines the use of vertex arrays.

      // Determines the use of vertex buffer objects.

      public SimpleGLRenderer(Context context) {
        // Pre-allocate and store these objects so we can use them at runtime
        // without allocating memory mid-frame.
        mTextureNameWorkspace = new int[1];
        mCropWorkspace = new int[4];

        // Set our bitmaps to 16-bit, 565 format.
        sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;

        mContext = context;
      }

      public int[] getConfigSpec() {
        // We don't need a depth buffer, and don't care about our
        // color depth.
        int[] configSpec = EGL10.EGL_DEPTH_SIZE, 0, EGL10.EGL_NONE };
        return configSpec;
      }

      public void setSprites(GLSprite[] sprites) {
        mSprites = sprites;
      }

      /**
       * Changes the vertex mode used for drawing.
       
       @param useVerts
       *            Specifies whether to use a vertex array. If false, the
       *            DrawTexture extension is used.
       @param useHardwareBuffers
       *            Specifies whether to store vertex arrays in main memory or on
       *            the graphics card. Ignored if useVerts is false.
       */

      /** Draws the sprites. */
      public void drawFrame(GL10 gl) {
        if (mSprites != null) {

          gl.glMatrixMode(GL10.GL_MODELVIEW);

          for (int x = 0; x < mSprites.length; x++) {
            mSprites[x].draw(gl);
          }

        }
      }

      /* Called when the size of the window changes. */
      public void sizeChanged(GL10 gl, int width, int height) {
        gl.glViewport(00, width, height);

        /*
         * Set our projection matrix. This doesn't have to be done each time we
         * draw, but usually a new projection needs to be set when the viewport
         * is resized.
         */
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glOrthof(0.0f, width, 0.0f, height, 0.0f1.0f);

        gl.glShadeModel(GL10.GL_FLAT);
        gl.glEnable(GL10.GL_BLEND);
        gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
        gl.glColor4x(0x100000x100000x100000x10000);
        gl.glEnable(GL10.GL_TEXTURE_2D);
      }

      /**
       * Called whenever the surface is created. This happens at startup, and may
       * be called again at runtime if the device context is lost (the screen goes
       * to sleep, etc). This function must fill the contents of vram with texture
       * data and (when using VBOs) hardware vertex arrays.
       */
      public void surfaceCreated(GL10 gl) {
        /*
         * Some one-time OpenGL initialization can be made here probably based
         * on features of this particular context
         */
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);

        gl.glClearColor(0.5f0.5f0.5f1);
        gl.glShadeModel(GL10.GL_FLAT);
        gl.glDisable(GL10.GL_DEPTH_TEST);
        gl.glEnable(GL10.GL_TEXTURE_2D);
        /*
         * By default, OpenGL enables features that improve quality but reduce
         * performance. One might want to tweak that especially on software
         * renderer.
         */
        gl.glDisable(GL10.GL_DITHER);
        gl.glDisable(GL10.GL_LIGHTING);

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

        if (mSprites != null) {

          // If we are using hardware buffers and the screen lost context
          // then the buffer indexes that we recorded previously are now
          // invalid. Forget them here and recreate them below.

          // Load our texture and set its texture name on all sprites.

          // To keep this sample simple we will assume that sprites that share
          // the same texture are grouped together in our sprite list. A real
          // app would probably have another level of texture management,
          // like a texture hash.

          int lastLoadedResource = -1;
          int lastTextureId = -1;

          for (int x = 0; x < mSprites.length; x++) {
            int resource = mSprites[x].getResourceId();
            if (resource != lastLoadedResource) {
              lastTextureId = loadBitmap(mContext, gl, resource);
              lastLoadedResource = resource;
            }
            mSprites[x].setTextureName(lastTextureId);
            // mSprites[x].getGrid().generateHardwareBuffers(gl);

          }
        }
      }

      /**
       * Called when the rendering thread shuts down. This is a good place to
       * release OpenGL ES resources.
       
       @param gl
       */
      public void shutdown(GL10 gl) {
        if (mSprites != null) {

          int lastFreedResource = -1;
          int[] textureToDelete = new int[1];

          for (int x = 0; x < mSprites.length; x++) {
            int resource = mSprites[x].getResourceId();
            if (resource != lastFreedResource) {
              textureToDelete[0= mSprites[x].getTextureName();
              gl.glDeleteTextures(1, textureToDelete, 0);
              mSprites[x].setTextureName(0);
            }
          }
        }
      }

      /**
       * Loads a bitmap into OpenGL and sets up the common parameters for 2D
       * texture maps.
       */
      protected int loadBitmap(Context context, GL10 gl, int resourceId) {
        int textureName = -1;
        if (context != null && gl != null) {
          gl.glGenTextures(1, mTextureNameWorkspace, 0);

          textureName = mTextureNameWorkspace[0];
          gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);

          gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
              GL10.GL_NEAREST);
          gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
              GL10.GL_LINEAR);

          gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
              GL10.GL_CLAMP_TO_EDGE);
          gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
              GL10.GL_CLAMP_TO_EDGE);

          gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
              GL10.GL_REPLACE);

          InputStream is = context.getResources().openRawResource(resourceId);
          Bitmap bitmap;
          try {
            bitmap = BitmapFactory.decodeStream(is, null, sBitmapOptions);
          finally {
            try {
              is.close();
            catch (IOException e) {
              // Ignore.
            }
          }

          GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

          mCropWorkspace[00;
          mCropWorkspace[1= bitmap.getHeight();
          mCropWorkspace[2= bitmap.getWidth();
          mCropWorkspace[3= -bitmap.getHeight();

          bitmap.recycle();

          ((GL11gl).glTexParameteriv(GL10.GL_TEXTURE_2D,
              GL11Ext.GL_TEXTURE_CROP_RECT_OES, mCropWorkspace, 0);

          int error = gl.glGetError();
          if (error != GL10.GL_NO_ERROR) {
            Log.e("SpriteMethodTest""Texture Load GLError: " + error);
          }

        }

        return textureName;
      }

    }

    /**
     * Base class defining the core set of information necessary to render (and move
     * an object on the screen. This is an abstract type and must be derived to add
     * methods to actually draw (see CanvasSprite and GLSprite).
     */
    abstract class Renderable {
      // Position.
      public float x;
      public float y;
      public float z;

      // Velocity.
      public float velocityX;
      public float velocityY;
      public float velocityZ;

      // Size.
      public float width;
      public float height;
    }

    /**
     * This is the OpenGL ES version of a sprite. It is more complicated than the
     * CanvasSprite class because it can be used in more than one way. This class
     * can draw using a grid of verts, a grid of verts stored in VBO objects, or
     * using the DrawTexture extension.
     */
    class GLSprite extends Renderable {
      // The OpenGL ES texture handle to draw.
      private int mTextureName;
      // The id of the original resource that mTextureName is based on.
      private int mResourceId;

      // If drawing with verts or VBO verts, the grid object defining those verts.

      public GLSprite(int resourceId) {
        super();
        mResourceId = resourceId;
      }

      public void setTextureName(int name) {
        mTextureName = name;
      }

      public int getTextureName() {
        return mTextureName;
      }

      public void setResourceId(int id) {
        mResourceId = id;
      }

      public int getResourceId() {
        return mResourceId;
      }

      public void draw(GL10 gl) {
        gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureName);

        // Draw using the DrawTexture extension.
        ((GL11Extgl).glDrawTexfOES(x, y, z, width, height);

      }
    }

    /**
     * An implementation of SurfaceView that uses the dedicated surface for
     * displaying an OpenGL animation. This allows the animation to run in a
     * separate thread, without requiring that it be driven by the update mechanism
     * of the view hierarchy.
     
     * The application-specific rendering code is delegated to a GLView.Renderer
     * instance.
     */
    class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
      public GLSurfaceView(Context context) {
        super(context);
        init();
      }

      public GLSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
      }

      private void init() {
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
      }

      public SurfaceHolder getSurfaceHolder() {
        return mHolder;
      }

      public void setGLWrapper(GLWrapper glWrapper) {
        mGLWrapper = glWrapper;
      }

      public void setRenderer(Renderer renderer) {
        mGLThread = new GLThread(renderer);
        mGLThread.start();
      }

      public void surfaceCreated(SurfaceHolder holder) {
        mGLThread.surfaceCreated();
      }

      public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return
        mGLThread.surfaceDestroyed();
      }

      public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // Surface size or format has changed. This should not happen in this
        // example.
        mGLThread.onWindowResize(w, h);
      }

      /**
       * Inform the view that the activity is paused.
       */
      public void onPause() {
        mGLThread.onPause();
      }

      /**
       * Inform the view that the activity is resumed.
       */
      public void onResume() {
        mGLThread.onResume();
      }

      /**
       * Inform the view that the window focus has changed.
       */
      @Override
      public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        mGLThread.onWindowFocusChanged(hasFocus);
      }

      /**
       * Set an "event" to be run on the GL rendering thread.
       
       @param r
       *            the runnable to be run on the GL rendering thread.
       */
      public void setEvent(Runnable r) {
        mGLThread.setEvent(r);
      }

      @Override
      protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mGLThread.requestExitAndWait();
      }

      // ----------------------------------------------------------------------

      public interface GLWrapper {
        GL wrap(GL gl);
      }

      // ----------------------------------------------------------------------

      /**
       * A generic renderer interface.
       */
      public interface Renderer {
        /**
         @return the EGL configuration specification desired by the renderer.
         */
        int[] getConfigSpec();

        /**
         * Surface created. Called when the surface is created. Called when the
         * application starts, and whenever the GPU is reinitialized. This will
         * typically happen when the device awakes after going to sleep. Set
         * your textures here.
         */
        void surfaceCreated(GL10 gl);

        /**
         * Called when the rendering thread is about to shut down. This is a
         * good place to release OpenGL ES resources (textures, buffers, etc).
         
         @param gl
         */
        void shutdown(GL10 gl);

        /**
         * Surface changed size. Called after the surface is created and
         * whenever the OpenGL ES surface size changes. Set your viewport here.
         
         @param gl
         @param width
         @param height
         */
        void sizeChanged(GL10 gl, int width, int height);

        /**
         * Draw the current frame.
         
         @param gl
         */
        void drawFrame(GL10 gl);
      }

      /**
       * An EGL helper class.
       */

      private class EglHelper {
        public EglHelper() {

        }

        /**
         * Initialize EGL for a given configuration spec.
         
         @param configSpec
         */
        public void start(int[] configSpec) {
          /*
           * Get an EGL instance
           */
          mEgl = (EGL10EGLContext.getEGL();

          /*
           * Get to the default display.
           */
          mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

          /*
           * We can now initialize EGL for that display
           */
          int[] version = new int[2];
          mEgl.eglInitialize(mEglDisplay, version);

          EGLConfig[] configs = new EGLConfig[1];
          int[] num_config = new int[1];
          mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1,
              num_config);
          mEglConfig = configs[0];

          /*
           * Create an OpenGL ES context. This must be done only once, an
           * OpenGL context is a somewhat heavy object.
           */
          mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig,
              EGL10.EGL_NO_CONTEXT, null);

          mEglSurface = null;
        }

        /*
         * Create and return an OpenGL surface
         */
        public GL createSurface(SurfaceHolder holder) {
          /*
           * The window size has changed, so we need to create a new surface.
           */
          if (mEglSurface != null) {

            /*
             * Unbind and destroy the old EGL surface, if there is one.
             */
            mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
                EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
            mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
          }

          /*
           * Create an EGL surface we can render into.
           */
          mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig,
              holder, null);

          /*
           * Before we can issue GL commands, we need to make sure the context
           * is current and bound to a surface.
           */
          mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
              mEglContext);

          GL gl = mEglContext.getGL();
          if (mGLWrapper != null) {
            gl = mGLWrapper.wrap(gl);
          }
          return gl;
        }

        /**
         * Display the current render surface.
         
         @return false if the context has been lost.
         */
        public boolean swap() {
          mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);

          /*
           * Always check for EGL_CONTEXT_LOST, which means the context and
           * all associated data were lost (For instance because the device
           * went to sleep). We need to sleep until we get a new surface.
           */
          return mEgl.eglGetError() != EGL11.EGL_CONTEXT_LOST;
        }

        public void finish() {
          if (mEglSurface != null) {
            mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
                EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
            mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
            mEglSurface = null;
          }
          if (mEglContext != null) {
            mEgl.eglDestroyContext(mEglDisplay, mEglContext);
            mEglContext = null;
          }
          if (mEglDisplay != null) {
            mEgl.eglTerminate(mEglDisplay);
            mEglDisplay = null;
          }
        }

        EGL10 mEgl;
        EGLDisplay mEglDisplay;
        EGLSurface mEglSurface;
        EGLConfig mEglConfig;
        EGLContext mEglContext;
      }

      /**
       * A generic GL Thread. Takes care of initializing EGL and GL. Delegates to
       * a Renderer instance to do the actual drawing.
       
       */

      class GLThread extends Thread {
        GLThread(Renderer renderer) {
          super();
          mDone = false;
          mWidth = 0;
          mHeight = 0;
          mRenderer = renderer;
          setName("GLThread");
        }

        @Override
        public void run() {
          /*
           * When the android framework launches a second instance of an
           * activity, the new instance's onCreate() method may be called
           * before the first instance returns from onDestroy().
           
           * This semaphore ensures that only one instance at a time accesses
           * EGL.
           */
          try {
            try {
              sEglSemaphore.acquire();
            catch (InterruptedException e) {
              return;
            }
            guardedRun();
          catch (InterruptedException e) {
            // fall thru and exit normally
          finally {
            sEglSemaphore.release();
          }
        }

        private void guardedRun() throws InterruptedException {
          mEglHelper = new EglHelper();
          /*
           * Specify a configuration for our opengl session and grab the first
           * configuration that matches is
           */
          int[] configSpec = mRenderer.getConfigSpec();
          mEglHelper.start(configSpec);

          GL10 gl = null;
          boolean tellRendererSurfaceCreated = true;
          boolean tellRendererSurfaceChanged = true;

          /*
           * This is our main activity thread's loop, we go until asked to
           * quit.
           */
          while (!mDone) {

            /*
             * Update the asynchronous state (window size)
             */
            int w, h;
            boolean changed;
            boolean needStart = false;
            synchronized (this) {
              if (mEvent != null) {

                mEvent.run();

              }
              if (mPaused) {
                mEglHelper.finish();
                needStart = true;
              }
              if (needToWait()) {
                while (needToWait()) {
                  wait();
                }
              }
              if (mDone) {
                break;
              }
              changed = mSizeChanged;
              w = mWidth;
              h = mHeight;
              mSizeChanged = false;
            }
            if (needStart) {
              mEglHelper.start(configSpec);
              tellRendererSurfaceCreated = true;
              changed = true;
            }
            if (changed) {
              gl = (GL10mEglHelper.createSurface(mHolder);
              tellRendererSurfaceChanged = true;
            }
            if (tellRendererSurfaceCreated) {
              mRenderer.surfaceCreated(gl);
              tellRendererSurfaceCreated = false;
            }
            if (tellRendererSurfaceChanged) {
              mRenderer.sizeChanged(gl, w, h);
              tellRendererSurfaceChanged = false;
            }
            if ((w > 0&& (h > 0)) {

              /* draw a frame here */
              mRenderer.drawFrame(gl);

              /*
               * Once we're done with GL, we need to call swapBuffers() to
               * instruct the system to display the rendered frame
               */

              mEglHelper.swap();

            }

          }

          /*
           * clean-up everything...
           */
          if (gl != null) {
            mRenderer.shutdown(gl);
          }

          mEglHelper.finish();
        }

        private boolean needToWait() {
          return (mPaused || (!mHasFocus|| (!mHasSurface|| mContextLost)
              && (!mDone);
        }

        public void surfaceCreated() {
          synchronized (this) {
            mHasSurface = true;
            mContextLost = false;
            notify();
          }
        }

        public void surfaceDestroyed() {
          synchronized (this) {
            mHasSurface = false;
            notify();
          }
        }

        public void onPause() {
          synchronized (this) {
            mPaused = true;
          }
        }

        public void onResume() {
          synchronized (this) {
            mPaused = false;
            notify();
          }
        }

        public void onWindowFocusChanged(boolean hasFocus) {
          synchronized (this) {
            mHasFocus = hasFocus;
            if (mHasFocus == true) {
              notify();
            }
          }
        }

        public void onWindowResize(int w, int h) {
          synchronized (this) {
            mWidth = w;
            mHeight = h;
            mSizeChanged = true;
          }
        }

        public void requestExitAndWait() {
          // don't call this from GLThread thread or it is a guaranteed
          // deadlock!
          synchronized (this) {
            mDone = true;
            notify();
          }
          try {
            join();
          catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
          }
        }

        /**
         * Queue an "event" to be run on the GL rendering thread.
         
         @param r
         *            the runnable to be run on the GL rendering thread.
         */
        public void setEvent(Runnable r) {
          synchronized (this) {
            mEvent = r;
          }
        }

        public void clearEvent() {
          synchronized (this) {
            mEvent = null;
          }
        }

        private boolean mDone;
        private boolean mPaused;
        private boolean mHasFocus;
        private boolean mHasSurface;
        private boolean mContextLost;
        private int mWidth;
        private int mHeight;
        private Renderer mRenderer;
        private Runnable mEvent;
        private EglHelper mEglHelper;
      }

      private static final Semaphore sEglSemaphore = new Semaphore(1);
      private boolean mSizeChanged = true;

      private SurfaceHolder mHolder;
      private GLThread mGLThread;
      private GLWrapper mGLWrapper;
    }

       
  • 相关阅读:
    Windows系统中监控文件复制操作的几种方式
    右击菜单一键优化(增加新建office2003、新建reg和bat,删除新建公文包、新建wps、新建rar)
    美颜我迪!
    为什么我们不要 .NET 程序员
    访问局域网电脑提示“指定的网络名不存在”的解决办法
    WIN7X64SP1极限精简版by双心
    一键精简Windows不常用的字体.cmd
    dll文件32位64位检测工具以及Windows文件夹SysWow64的坑【转发】
    Win7精简成功后的总结
    dependency walker检查dll依赖关系目录设置的问题
  • 原文地址:https://www.cnblogs.com/weinyzhou/p/2750066.html
Copyright © 2020-2023  润新知