Android OpenGL ES(五):GLSurfaceView

2023-10-29

分类: Android OpenGL ES基础 2012-02-27 16:56  3365人阅读  评论(0)  收藏  举报

Android OpenGL ES 相关的包主要定义在

  • javax.microedition.khronos.opengles    GL 绘图指令
  • javax.microedition.khronos.egl               EGL 管理Display, surface等
  • android.opengl    Android GL辅助类,连接OpenGL 与Android View,Activity
  • javax.nio Buffer类

其中GLSurfaceView 为android.opengl  包中核心类:

  • 起到连接OpenGL ES与Android 的View层次结构之间的桥梁作用。
  • 使得Open GL ES库适应于Anndroid系统的Activity生命周期。
  • 使得选择合适的Frame buffer像素格式变得容易。
  • 创建和管理单独绘图线程以达到平滑动画效果。
  • 提供了方便使用的调试工具来跟踪OpenGL ES函数调用以帮助检查错误。

使用过Java ME ,JSR 239 开发过OpenGL ES可以看到 Android 包javax.microedition.khronos.egl ,javax.microedition.khronos.opengles 和JSR239 基本一致,因此理论上不使用android.opengl 包中的类也可以开发Android上OpenGL ES应用,但此时就需要自己使用EGL来管理Display,Context, Surfaces 的创建,释放,捆绑。

使用EGL 实现GLSurfaceView一个可能的实现如下:

[java]  view plain copy
  1. class GLSurfaceView extends SurfaceView  
  2.  implements SurfaceHolder.Callback, Runnable {  
  3.  public GLSurfaceView(Context context) {  
  4.  super(context);  
  5.  mHolder = getHolder();  
  6.  mHolder.addCallback(this);  
  7.  mHolder.setType(SurfaceHolder.SURFACE_TYPE_GPU);  
  8.  }  
  9.    
  10.  public void setRenderer(Renderer renderer) {  
  11.  mRenderer = renderer;  
  12.  }  
  13.    
  14.  public void surfaceCreated(SurfaceHolder holder) {  
  15.  }  
  16.    
  17.  public void surfaceDestroyed(SurfaceHolder holder) {  
  18.  running = false;  
  19.  try {  
  20.  thread.join();  
  21.  } catch (InterruptedException e) {  
  22.  }  
  23.  thread = null;  
  24.  }  
  25.    
  26.  public void surfaceChanged(SurfaceHolder holder,  
  27.  int format, int w, int h) {  
  28.  synchronized(this){  
  29.  mWidth = w;  
  30.  mHeight = h;  
  31.  thread = new Thread(this);  
  32.  thread.start();  
  33.  }  
  34.  }  
  35.    
  36.  public interface Renderer {  
  37.  void EGLCreate(SurfaceHolder holder);  
  38.  void EGLDestroy();  
  39.  int Initialize(int width, int height);  
  40.  void DrawScene(int width, int height);  
  41.  }  
  42.    
  43.  public void run() {  
  44.  synchronized(this) {  
  45.  mRenderer.EGLCreate(mHolder);  
  46.  mRenderer.Initialize(mWidth, mHeight);  
  47.    
  48.  running=true;  
  49.  while (running) {  
  50.  mRenderer.DrawScene(mWidth, mHeight);  
  51.  }  
  52.    
  53.  mRenderer.EGLDestroy();  
  54.  }  
  55.  }  
  56.    
  57.  private SurfaceHolder mHolder;  
  58.  private Thread thread;  
  59.  private boolean running;  
  60.  private Renderer mRenderer;  
  61.  private int mWidth;  
  62.  private int mHeight;  
  63.    
  64. }  
  65.    
  66. class GLRenderer implements GLSurfaceView.Renderer {  
  67.  public GLRenderer() {  
  68.  }  
  69.    
  70.  public int Initialize(int width, int height){  
  71.  gl.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);  
  72.    
  73.  return 1;  
  74.  }  
  75.    
  76.  public void DrawScene(int width, int height){  
  77.  gl.glClear(GL10.GL_COLOR_BUFFER_BIT);  
  78.    
  79.  egl.eglSwapBuffers(eglDisplay, eglSurface);  
  80.  }  
  81.    
  82.  public void EGLCreate(SurfaceHolder holder){  
  83.  int[] num_config = new int[1];  
  84.  EGLConfig[] configs = new EGLConfig[1];  
  85.  int[] configSpec = {  
  86.  EGL10.EGL_RED_SIZE,            8,  
  87.  EGL10.EGL_GREEN_SIZE,        8,  
  88.  EGL10.EGL_BLUE_SIZE,        8,  
  89.    
  90.  EGL10.EGL_SURFACE_TYPE,     EGL10.EGL_WINDOW_BIT,  
  91.  EGL10.EGL_NONE  
  92.  };  
  93.    
  94.  this.egl = (EGL10) EGLContext.getEGL();  
  95.    
  96.  eglDisplay = this.egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);  
  97.  this.egl.eglInitialize(eglDisplay, null);  
  98.    
  99.  this.egl.eglChooseConfig(eglDisplay, configSpec,  
  100.  configs, 1, num_config);  
  101.    
  102.  eglConfig = configs[0];  
  103.  eglContext = this.egl.eglCreateContext(eglDisplay, eglConfig,  
  104.  EGL10.EGL_NO_CONTEXT, null);  
  105.    
  106.  eglSurface = this.egl.eglCreateWindowSurface(eglDisplay,  
  107.  eglConfig, holder, null);  
  108.    
  109.  this.egl.eglMakeCurrent(eglDisplay, eglSurface,  
  110.  eglSurface, eglContext);  
  111.    
  112.  gl = (GL10)eglContext.getGL();  
  113.  }  
  114.    
  115.  public void EGLDestroy(){  
  116.  if (eglSurface != null) {  
  117.  egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE,  
  118.  EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);  
  119.  egl.eglDestroySurface(eglDisplay, eglSurface);  
  120.  eglSurface = null;  
  121.  }  
  122.  if (eglContext != null) {  
  123.  egl.eglDestroyContext(eglDisplay, eglContext);  
  124.  eglContext = null;  
  125.  }  
  126.  if (eglDisplay != null) {  
  127.  egl.eglTerminate(eglDisplay);  
  128.  eglDisplay = null;  
  129.  }  
  130.  }  
  131.    
  132.  private EGL10 egl;  
  133.  private GL10 gl;  
  134.  private EGLDisplay eglDisplay;  
  135.  private EGLConfig  eglConfig;  
  136.  private EGLContext eglContext;  
  137.  private EGLSurface eglSurface;  
  138. }  

可以看到需要派生SurfaceView ,并手工创建,销毁Display,Context ,工作繁琐。

使用GLSurfaceView 内部提供了上面类似的实现,对于大部分应用只需调用一个方法来设置OpenGLView用到的GLSurfaceView.Renderer.

[java]  view plain copy
  1. public void  setRenderer(GLSurfaceView.Renderer renderer)  

GLSurfaceView.Renderer定义了一个统一图形绘制的接口,它定义了如下三个接口函数:

[java]  view plain copy
  1. // Called when the surface is created or recreated.  
  2. public void onSurfaceCreated(GL10 gl, EGLConfig config)  
  3. // Called to draw the current frame.  
  4. public void onDrawFrame(GL10 gl)  
  5. // Called when the surface changed size.  
  6. public void onSurfaceChanged(GL10 gl, int width, int height)  

  • onSurfaceCreated : 在这个方法中主要用来设置一些绘制时不常变化的参数,比如:背景色,是否打开 z-buffer等。
  • onDrawFrame: 定义实际的绘图操作。
  • onSurfaceChanged: 如果设备支持屏幕横向和纵向切换,这个方法将发生在横向<->纵向互换时。此时可以重新设置绘制的纵横比率。

如果有需要,也可以通过函数来修改GLSurfaceView一些缺省设置:

  • setDebugFlags(int) 设置Debug标志。
  • setEGLConfigChooser (boolean) 选择一个Config接近16bitRGB颜色模式,可以打开或关闭深度(Depth)Buffer ,缺省为RGB_565 并打开至少有16bit 的 depth Buffer.
  • setEGLConfigChooser(EGLConfigChooser)  选择自定义EGLConfigChooser。
  • setEGLConfigChooser(int, int, int, int, int, int) 指定red ,green, blue, alpha, depth ,stencil 支持的位数,缺省为RGB_565 ,16 bit depth buffer.

GLSurfaceView 缺省创建为RGB_565 颜色格式的Surface ,如果需要支持透明度,可以调用getHolder().setFormat(PixelFormat.TRANSLUCENT).

GLSurfaceView 的渲染模式有两种,一种是连续不断的更新屏幕,另一种为on-demand ,只有在调用requestRender()  在更新屏幕。 缺省为RENDERMODE_CONTINUOUSLY 持续刷新屏幕。

GLSurfaceView是我认为Android源码体系中一个非常值得研究和学习的源代码,当你完全看懂GLSurfaceView的大部分代码和代码结构设计对你在以后的编码过程中设计自己的功能模块时有很好的借鉴作用。

如下代码是完全按照系统的GLSurfaceView的代码结构设计的动态GL壁纸Engine,能够非常方便的实现OpenGL方式的动态壁纸:

[java]  view plain copy
  1. public class GLWallpaperService extends WallpaperService {  
  2.     private static final String TAG = "GLWallpaperService";  
  3.   
  4.     @Override  
  5.     public Engine onCreateEngine() {  
  6.         return new GLEngine();  
  7.     }  
  8.   
  9.     public class GLEngine extends Engine {  
  10.         public final static int RENDERMODE_WHEN_DIRTY = 0;  
  11.         public final static int RENDERMODE_CONTINUOUSLY = 1;  
  12.   
  13.         private GLThread mGLThread;  
  14.         private EGLConfigChooser mEGLConfigChooser;  
  15.         private EGLContextFactory mEGLContextFactory;  
  16.         private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;  
  17.         private GLWrapper mGLWrapper;  
  18.         private int mDebugFlags;  
  19.   
  20.         public GLEngine() {  
  21.             super();  
  22.         }  
  23.   
  24.         @Override  
  25.         public void onVisibilityChanged(boolean visible) {  
  26.             if (visible) {  
  27.                 onResume();  
  28.             } else {  
  29.                 onPause();  
  30.             }  
  31.             super.onVisibilityChanged(visible);  
  32.         }  
  33.   
  34.         @Override  
  35.         public void onCreate(SurfaceHolder surfaceHolder) {  
  36.             super.onCreate(surfaceHolder);  
  37.             // Log.d(TAG, "GLEngine.onCreate()");  
  38.         }  
  39.   
  40.         @Override  
  41.         public void onDestroy() {  
  42.             super.onDestroy();  
  43.             // Log.d(TAG, "GLEngine.onDestroy()");  
  44.             mGLThread.requestExitAndWait();  
  45.         }  
  46.   
  47.         @Override  
  48.         public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {  
  49.             // Log.d(TAG, "onSurfaceChanged()");  
  50.             mGLThread.onWindowResize(width, height);  
  51.             super.onSurfaceChanged(holder, format, width, height);  
  52.         }  
  53.   
  54.         @Override  
  55.         public void onSurfaceCreated(SurfaceHolder holder) {  
  56.             Log.d(TAG, "onSurfaceCreated()");  
  57.             mGLThread.surfaceCreated(holder);  
  58.             super.onSurfaceCreated(holder);  
  59.         }  
  60.   
  61.         @Override  
  62.         public void onSurfaceDestroyed(SurfaceHolder holder) {  
  63.             Log.d(TAG, "onSurfaceDestroyed()");  
  64.             mGLThread.surfaceDestroyed();  
  65.             super.onSurfaceDestroyed(holder);  
  66.         }  
  67.   
  68.         /** 
  69.          * An EGL helper class. 
  70.          */  
  71.         public void setGLWrapper(GLWrapper glWrapper) {  
  72.             mGLWrapper = glWrapper;  
  73.         }  
  74.   
  75.         public void setDebugFlags(int debugFlags) {  
  76.             mDebugFlags = debugFlags;  
  77.         }  
  78.   
  79.         public int getDebugFlags() {  
  80.             return mDebugFlags;  
  81.         }  
  82.   
  83.         public void setRenderer(Renderer renderer) {  
  84.             checkRenderThreadState();  
  85.             if (mEGLConfigChooser == null) {  
  86.                 mEGLConfigChooser = new SimpleEGLConfigChooser(true);  
  87.             }  
  88.             if (mEGLContextFactory == null) {  
  89.                 mEGLContextFactory = new DefaultContextFactory();  
  90.             }  
  91.             if (mEGLWindowSurfaceFactory == null) {  
  92.                 mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();  
  93.             }  
  94.             mGLThread = new GLThread(renderer, mEGLConfigChooser, mEGLContextFactory, mEGLWindowSurfaceFactory, mGLWrapper);  
  95.             mGLThread.start();  
  96.         }  
  97.   
  98.         public void setEGLContextFactory(EGLContextFactory factory) {  
  99.             checkRenderThreadState();  
  100.             mEGLContextFactory = factory;  
  101.         }  
  102.   
  103.         public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) {  
  104.             checkRenderThreadState();  
  105.             mEGLWindowSurfaceFactory = factory;  
  106.         }  
  107.   
  108.         public void setEGLConfigChooser(EGLConfigChooser configChooser) {  
  109.             checkRenderThreadState();  
  110.             mEGLConfigChooser = configChooser;  
  111.         }  
  112.   
  113.         public void setEGLConfigChooser(boolean needDepth) {  
  114.             setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));  
  115.         }  
  116.   
  117.         public void setEGLConfigChooser(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize,  
  118.                 int stencilSize) {  
  119.             setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize, blueSize, alphaSize, depthSize,  
  120.                     stencilSize));  
  121.         }  
  122.   
  123.         public void setRenderMode(int renderMode) {  
  124.             mGLThread.setRenderMode(renderMode);  
  125.         }  
  126.   
  127.         public int getRenderMode() {  
  128.             return mGLThread.getRenderMode();  
  129.         }  
  130.   
  131.         public void requestRender() {  
  132.             mGLThread.requestRender();  
  133.         }  
  134.   
  135.         public void onPause() {  
  136.             mGLThread.onPause();  
  137.         }  
  138.   
  139.         public void onResume() {  
  140.             mGLThread.onResume();  
  141.         }  
  142.   
  143.         public void queueEvent(Runnable r) {  
  144.             mGLThread.queueEvent(r);  
  145.         }  
  146.   
  147.         private void checkRenderThreadState() {  
  148.             if (mGLThread != null) {  
  149.                 throw new IllegalStateException("setRenderer has already been called for this instance.");  
  150.             }  
  151.         }  
  152.     }  
  153.   
  154.     public interface Renderer {  
  155.   
  156.         public void onSurfaceCreated(GL10 gl, EGLConfig config);  
  157.   
  158.         public void onSurfaceChanged(GL10 gl, int width, int height);  
  159.   
  160.         public void onDrawFrame(GL10 gl);  
  161.     }  
  162. }  
  163.   
  164. class LogWriter extends Writer {  
  165.     private StringBuilder mBuilder = new StringBuilder();  
  166.   
  167.     @Override  
  168.     public void close() {  
  169.         flushBuilder();  
  170.     }  
  171.   
  172.     @Override  
  173.     public void flush() {  
  174.         flushBuilder();  
  175.     }  
  176.   
  177.     @Override  
  178.     public void write(char[] buf, int offset, int count) {  
  179.         for (int i = 0; i < count; i++) {  
  180.             char c = buf[offset + i];  
  181.             if (c == '\n') {  
  182.                 flushBuilder();  
  183.             } else {  
  184.                 mBuilder.append(c);  
  185.             }  
  186.         }  
  187.     }  
  188.   
  189.     private void flushBuilder() {  
  190.         if (mBuilder.length() > 0) {  
  191.             Log.v("GLSurfaceView", mBuilder.toString());  
  192.             mBuilder.delete(0, mBuilder.length());  
  193.         }  
  194.     }  
  195. }  
  196.   
  197. // ----------------------------------------------------------------------  
  198.   
  199. /** 
  200.  * An interface for customizing the eglCreateContext and eglDestroyContext calls. 
  201.  * 
  202.  
  203.  * This interface must be implemented by clients wishing to call 
  204.  * {@link GLWallpaperService#setEGLContextFactory(EGLContextFactory)} 
  205.  */  
  206. interface EGLContextFactory {  
  207.     EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig);  
  208.   
  209.     void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);  
  210. }  
  211.   
  212. class DefaultContextFactory implements EGLContextFactory {  
  213.   
  214.     public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {  
  215.         return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, null);  
  216.     }  
  217.   
  218.     public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {  
  219.         egl.eglDestroyContext(display, context);  
  220.     }  
  221. }  
  222.   
  223. /** 
  224.  * An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls. 
  225.  * 
  226.  
  227.  * This interface must be implemented by clients wishing to call 
  228.  * {@link GLWallpaperService#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)} 
  229.  */  
  230. interface EGLWindowSurfaceFactory {  
  231.     EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config, Object nativeWindow);  
  232.   
  233.     void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);  
  234. }  
  235.   
  236. class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {  
  237.   
  238.     public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay  
  239.             display, EGLConfig config, Object nativeWindow) {  
  240.         // this is a bit of a hack to work around Droid init problems - if you don't have this, it'll get hung up on orientation changes  
  241.         EGLSurface eglSurface = null;  
  242.         while (eglSurface == null) {  
  243.             try {  
  244.                 eglSurface = egl.eglCreateWindowSurface(display,  
  245.                         config, nativeWindow, null);  
  246.             } catch (Throwable t) {  
  247.             } finally {  
  248.                 if (eglSurface == null) {  
  249.                     try {  
  250.                         Thread.sleep(10);  
  251.                     } catch (InterruptedException t) {  
  252.                     }  
  253.                 }  
  254.             }  
  255.         }  
  256.         return eglSurface;  
  257.     }  
  258.   
  259.     public void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface) {  
  260.         egl.eglDestroySurface(display, surface);  
  261.     }  
  262. }  
  263.   
  264. interface GLWrapper {  
  265.     /** 
  266.      * Wraps a gl interface in another gl interface. 
  267.      * 
  268.      * @param gl 
  269.      * a GL interface that is to be wrapped. 
  270.      * @return either the input argument or another GL object that wraps the input argument. 
  271.      */  
  272.     GL wrap(GL gl);  
  273. }  
  274.   
  275. class EglHelper {  
  276.   
  277.     private EGL10 mEgl;  
  278.     private EGLDisplay mEglDisplay;  
  279.     private EGLSurface mEglSurface;  
  280.     private EGLContext mEglContext;  
  281.     EGLConfig mEglConfig;  
  282.   
  283.     private EGLConfigChooser mEGLConfigChooser;  
  284.     private EGLContextFactory mEGLContextFactory;  
  285.     private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;  
  286.     private GLWrapper mGLWrapper;  
  287.   
  288.     public EglHelper(EGLConfigChooser chooser, EGLContextFactory contextFactory,  
  289.             EGLWindowSurfaceFactory surfaceFactory, GLWrapper wrapper) {  
  290.         this.mEGLConfigChooser = chooser;  
  291.         this.mEGLContextFactory = contextFactory;  
  292.         this.mEGLWindowSurfaceFactory = surfaceFactory;  
  293.         this.mGLWrapper = wrapper;  
  294.     }  
  295.   
  296.     /** 
  297.      * Initialize EGL for a given configuration spec. 
  298.      * 
  299.      * @param configSpec 
  300.      */  
  301.     public void start() {  
  302.         // Log.d("EglHelper" + instanceId, "start()");  
  303.         if (mEgl == null) {  
  304.             // Log.d("EglHelper" + instanceId, "getting new EGL");  
  305.             /* 
  306.              * Get an EGL instance 
  307.              */  
  308.             mEgl = (EGL10) EGLContext.getEGL();  
  309.         } else {  
  310.             // Log.d("EglHelper" + instanceId, "reusing EGL");  
  311.         }  
  312.   
  313.         if (mEglDisplay == null) {  
  314.             // Log.d("EglHelper" + instanceId, "getting new display");  
  315.             /* 
  316.              * Get to the default display. 
  317.              */  
  318.             mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);  
  319.         } else {  
  320.             // Log.d("EglHelper" + instanceId, "reusing display");  
  321.         }  
  322.   
  323.         if (mEglConfig == null) {  
  324.             // Log.d("EglHelper" + instanceId, "getting new config");  
  325.             /* 
  326.              * We can now initialize EGL for that display 
  327.              */  
  328.             int[] version = new int[2];  
  329.             mEgl.eglInitialize(mEglDisplay, version);  
  330.             mEglConfig = mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);  
  331.         } else {  
  332.             // Log.d("EglHelper" + instanceId, "reusing config");  
  333.         }  
  334.   
  335.         if (mEglContext == null) {  
  336.             // Log.d("EglHelper" + instanceId, "creating new context");  
  337.             /* 
  338.              * Create an OpenGL ES context. This must be done only once, an OpenGL context is a somewhat heavy object. 
  339.              */  
  340.             mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);  
  341.             if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {  
  342.                 throw new RuntimeException("createContext failed");  
  343.             }  
  344.         } else {  
  345.             // Log.d("EglHelper" + instanceId, "reusing context");  
  346.         }  
  347.   
  348.         mEglSurface = null;  
  349.     }  
  350.   
  351.     /* 
  352.      * React to the creation of a new surface by creating and returning an OpenGL interface that renders to that 
  353.      * surface. 
  354.      */  
  355.     public GL createSurface(SurfaceHolder holder) {  
  356.         /* 
  357.          * The window size has changed, so we need to create a new surface. 
  358.          */  
  359.         if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {  
  360.   
  361.             /* 
  362.              * Unbind and destroy the old EGL surface, if there is one. 
  363.              */  
  364.             mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);  
  365.             mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);  
  366.         }  
  367.   
  368.         /* 
  369.          * Create an EGL surface we can render into. 
  370.          */  
  371.         mEglSurface = mEGLWindowSurfaceFactory.createWindowSurface(mEgl, mEglDisplay, mEglConfig, holder);  
  372.   
  373.         if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {  
  374.             throw new RuntimeException("createWindowSurface failed");  
  375.         }  
  376.   
  377.         /* 
  378.          * Before we can issue GL commands, we need to make sure the context is current and bound to a surface. 
  379.          */  
  380.         if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {  
  381.             throw new RuntimeException("eglMakeCurrent failed.");  
  382.         }  
  383.   
  384.         GL gl = mEglContext.getGL();  
  385.         if (mGLWrapper != null) {  
  386.             gl = mGLWrapper.wrap(gl);  
  387.         }  
  388.   
  389.         /* 
  390.          * if ((mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS))!= 0) { int configFlags = 0; Writer log = 
  391.          * null; if ((mDebugFlags & DEBUG_CHECK_GL_ERROR) != 0) { configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR; } 
  392.          * if ((mDebugFlags & DEBUG_LOG_GL_CALLS) != 0) { log = new LogWriter(); } gl = GLDebugHelper.wrap(gl, 
  393.          * configFlags, log); } 
  394.          */  
  395.         return gl;  
  396.     }  
  397.   
  398.     /** 
  399.      * Display the current render surface. 
  400.      * 
  401.      * @return false if the context has been lost. 
  402.      */  
  403.     public boolean swap() {  
  404.         mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);  
  405.   
  406.         /* 
  407.          * Always check for EGL_CONTEXT_LOST, which means the context and all associated data were lost (For instance 
  408.          * because the device went to sleep). We need to sleep until we get a new surface. 
  409.          */  
  410.         return mEgl.eglGetError() != EGL11.EGL_CONTEXT_LOST;  
  411.     }  
  412.   
  413.     public void destroySurface() {  
  414.         if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {  
  415.             mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);  
  416.             mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);  
  417.             mEglSurface = null;  
  418.         }  
  419.     }  
  420.   
  421.     public void finish() {  
  422.         if (mEglContext != null) {  
  423.             mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);  
  424.             mEglContext = null;  
  425.         }  
  426.         if (mEglDisplay != null) {  
  427.             mEgl.eglTerminate(mEglDisplay);  
  428.             mEglDisplay = null;  
  429.         }  
  430.     }  
  431. }  
  432.   
  433. class GLThread extends Thread {  
  434.     private final static boolean LOG_THREADS = false;  
  435.     public final static int DEBUG_CHECK_GL_ERROR = 1;  
  436.     public final static int DEBUG_LOG_GL_CALLS = 2;  
  437.   
  438.     private final GLThreadManager sGLThreadManager = new GLThreadManager();  
  439.     private GLThread mEglOwner;  
  440.   
  441.     private EGLConfigChooser mEGLConfigChooser;  
  442.     private EGLContextFactory mEGLContextFactory;  
  443.     private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;  
  444.     private GLWrapper mGLWrapper;  
  445.   
  446.     public SurfaceHolder mHolder;  
  447.     private boolean mSizeChanged = true;  
  448.   
  449.     // Once the thread is started, all accesses to the following member  
  450.     // variables are protected by the sGLThreadManager monitor  
  451.     public boolean mDone;  
  452.     private boolean mPaused;  
  453.     private boolean mHasSurface;  
  454.     private boolean mWaitingForSurface;  
  455.     private boolean mHaveEgl;  
  456.     private int mWidth;  
  457.     private int mHeight;  
  458.     private int mRenderMode;  
  459.     private boolean mRequestRender;  
  460.     private boolean mEventsWaiting;  
  461.     // End of member variables protected by the sGLThreadManager monitor.  
  462.   
  463.     private GLWallpaperService.Renderer mRenderer;  
  464.     private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>();  
  465.     private EglHelper mEglHelper;  
  466.   
  467.     GLThread(GLWallpaperService.Renderer renderer, EGLConfigChooser chooser, EGLContextFactory contextFactory,  
  468.             EGLWindowSurfaceFactory surfaceFactory, GLWrapper wrapper) {  
  469.         super();  
  470.         mDone = false;  
  471.         mWidth = 0;  
  472.         mHeight = 0;  
  473.         mRequestRender = true;  
  474.         mRenderMode = GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY;  
  475.         mRenderer = renderer;  
  476.         this.mEGLConfigChooser = chooser;  
  477.         this.mEGLContextFactory = contextFactory;  
  478.         this.mEGLWindowSurfaceFactory = surfaceFactory;  
  479.         this.mGLWrapper = wrapper;  
  480.     }  
  481.   
  482.     @Override  
  483.     public void run() {  
  484.         setName("GLThread " + getId());  
  485.         if (LOG_THREADS) {  
  486.             Log.i("GLThread""starting tid=" + getId());  
  487.         }  
  488.   
  489.         try {  
  490.             guardedRun();  
  491.         } catch (InterruptedException e) {  
  492.             // fall thru and exit normally  
  493.         } finally {  
  494.             sGLThreadManager.threadExiting(this);  
  495.         }  
  496.     }  
  497.   
  498.     /* 
  499.      * This private method should only be called inside a synchronized(sGLThreadManager) block. 
  500.      */  
  501.     private void stopEglLocked() {  
  502.         if (mHaveEgl) {  
  503.             mHaveEgl = false;  
  504.             mEglHelper.destroySurface();  
  505.             sGLThreadManager.releaseEglSurface(this);  
  506.         }  
  507.     }  
  508.   
  509.     private void guardedRun() throws InterruptedException {  
  510.         mEglHelper = new EglHelper(mEGLConfigChooser, mEGLContextFactory, mEGLWindowSurfaceFactory, mGLWrapper);  
  511.         try {  
  512.             GL10 gl = null;  
  513.             boolean tellRendererSurfaceCreated = true;  
  514.             boolean tellRendererSurfaceChanged = true;  
  515.   
  516.             /* 
  517.              * This is our main activity thread's loop, we go until asked to quit. 
  518.              */  
  519.             while (!isDone()) {  
  520.                 /* 
  521.                  * Update the asynchronous state (window size) 
  522.                  */  
  523.                 int w = 0;  
  524.                 int h = 0;  
  525.                 boolean changed = false;  
  526.                 boolean needStart = false;  
  527.                 boolean eventsWaiting = false;  
  528.   
  529.                 synchronized (sGLThreadManager) {  
  530.                     while (true) {  
  531.                         // Manage acquiring and releasing the SurfaceView  
  532.                         // surface and the EGL surface.  
  533.                         if (mPaused) {  
  534.                             stopEglLocked();  
  535.                         }  
  536.                         if (!mHasSurface) {  
  537.                             if (!mWaitingForSurface) {  
  538.                                 stopEglLocked();  
  539.                                 mWaitingForSurface = true;  
  540.                                 sGLThreadManager.notifyAll();  
  541.                             }  
  542.                         } else {  
  543.                             if (!mHaveEgl) {  
  544.                                 if (sGLThreadManager.tryAcquireEglSurface(this)) {  
  545.                                     mHaveEgl = true;  
  546.                                     mEglHelper.start();  
  547.                                     mRequestRender = true;  
  548.                                     needStart = true;  
  549.                                 }  
  550.                             }  
  551.                         }  
  552.   
  553.                         // Check if we need to wait. If not, update any state  
  554.                         // that needs to be updated, copy any state that  
  555.                         // needs to be copied, and use "break" to exit the  
  556.                         // wait loop.  
  557.   
  558.                         if (mDone) {  
  559.                             return;  
  560.                         }  
  561.   
  562.                         if (mEventsWaiting) {  
  563.                             eventsWaiting = true;  
  564.                             mEventsWaiting = false;  
  565.                             break;  
  566.                         }  
  567.   
  568.                         if ((!mPaused) && mHasSurface && mHaveEgl && (mWidth > 0) && (mHeight > 0)  
  569.                                 && (mRequestRender || (mRenderMode == GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY))) {  
  570.                             changed = mSizeChanged;  
  571.                             w = mWidth;  
  572.                             h = mHeight;  
  573.                             mSizeChanged = false;  
  574.                             mRequestRender = false;  
  575.                             if (mHasSurface && mWaitingForSurface) {  
  576.                                 changed = true;  
  577.                                 mWaitingForSurface = false;  
  578.                                 sGLThreadManager.notifyAll();  
  579.                             }  
  580.                             break;  
  581.                         }  
  582.   
  583.                         // By design, this is the only place where we wait().  
  584.   
  585.                         if (LOG_THREADS) {  
  586.                             Log.i("GLThread""waiting tid=" + getId());  
  587.                         }  
  588.                         sGLThreadManager.wait();  
  589.                     }  
  590.                 } // end of synchronized(sGLThreadManager)  
  591.   
  592.                 /* 
  593.                  * Handle queued events 
  594.                  */  
  595.                 if (eventsWaiting) {  
  596.                     Runnable r;  
  597.                     while ((r = getEvent()) != null) {  
  598.                         r.run();  
  599.                         if (isDone()) {  
  600.                             return;  
  601.                         }  
  602.                     }  
  603.                     // Go back and see if we need to wait to render.  
  604.                     continue;  
  605.                 }  
  606.   
  607.                 if (needStart) {  
  608.                     tellRendererSurfaceCreated = true;  
  609.                     changed = true;  
  610.                 }  
  611.                 if (changed) {  
  612.                     gl = (GL10) mEglHelper.createSurface(mHolder);  
  613.                     tellRendererSurfaceChanged = true;  
  614.                 }  
  615.                 if (tellRendererSurfaceCreated) {  
  616.                     mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);  
  617.                     tellRendererSurfaceCreated = false;  
  618.                 }  
  619.                 if (tellRendererSurfaceChanged) {  
  620.                     mRenderer.onSurfaceChanged(gl, w, h);  
  621.                     tellRendererSurfaceChanged = false;  
  622.                 }  
  623.                 if ((w > 0) && (h > 0)) {  
  624.                     /* draw a frame here */  
  625.                     mRenderer.onDrawFrame(gl);  
  626.   
  627.                     /* 
  628.                      * Once we're done with GL, we need to call swapBuffers() to instruct the system to display the 
  629.                      * rendered frame 
  630.                      */  
  631.                     mEglHelper.swap();  
  632.                     Thread.sleep(10);  
  633.                 }  
  634.             }  
  635.         } finally {  
  636.             /* 
  637.              * clean-up everything... 
  638.              */  
  639.             synchronized (sGLThreadManager) {  
  640.                 stopEglLocked();  
  641.                 mEglHelper.finish();  
  642.             }  
  643.         }  
  644.     }  
  645.   
  646.     private boolean isDone() {  
  647.         synchronized (sGLThreadManager) {  
  648.             return mDone;  
  649.         }  
  650.     }  
  651.   
  652.     public void setRenderMode(int renderMode) {  
  653.         if (!((GLWallpaperService.GLEngine.RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY))) {  
  654.             throw new IllegalArgumentException("renderMode");  
  655.         }  
  656.         synchronized (sGLThreadManager) {  
  657.             mRenderMode = renderMode;  
  658.             if (renderMode == GLWallpaperService.GLEngine.RENDERMODE_CONTINUOUSLY) {  
  659.                 sGLThreadManager.notifyAll();  
  660.             }  
  661.         }  
  662.     }  
  663.   
  664.     public int getRenderMode() {  
  665.         synchronized (sGLThreadManager) {  
  666.             return mRenderMode;  
  667.         }  
  668.     }  
  669.   
  670.     public void requestRender() {  
  671.         synchronized (sGLThreadManager) {  
  672.             mRequestRender = true;  
  673.             sGLThreadManager.notifyAll();  
  674.         }  
  675.     }  
  676.   
  677.     public void surfaceCreated(SurfaceHolder holder) {  
  678.         mHolder = holder;  
  679.         synchronized (sGLThreadManager) {  
  680.             if (LOG_THREADS) {  
  681.                 Log.i("GLThread""surfaceCreated tid=" + getId());  
  682.             }  
  683.             mHasSurface = true;  
  684.             sGLThreadManager.notifyAll();  
  685.         }  
  686.     }  
  687.   
  688.     public void surfaceDestroyed() {  
  689.         synchronized (sGLThreadManager) {  
  690.             if (LOG_THREADS) {  
  691.                 Log.i("GLThread""surfaceDestroyed tid=" + getId());  
  692.             }  
  693.             mHasSurface = false;  
  694.             sGLThreadManager.notifyAll();  
  695.             while (!mWaitingForSurface && isAlive() && !mDone) {  
  696.                 try {  
  697.                     sGLThreadManager.wait();  
  698.                 } catch (InterruptedException e) {  
  699.                     Thread.currentThread().interrupt();  
  700.                 }  
  701.             }  
  702.         }  
  703.     }  
  704.   
  705.     public void onPause() {  
  706.         synchronized (sGLThreadManager) {  
  707.             mPaused = true;  
  708.             sGLThreadManager.notifyAll();  
  709.         }  
  710.     }  
  711.   
  712.     public void onResume() {  
  713.         synchronized (sGLThreadManager) {  
  714.             mPaused = false;  
  715.             mRequestRender = true;  
  716.             sGLThreadManager.notifyAll();  
  717.         }  
  718.     }  
  719.   
  720.     public void onWindowResize(int w, int h) {  
  721.         synchronized (sGLThreadManager) {  
  722.             mWidth = w;  
  723.             mHeight = h;  
  724.             mSizeChanged = true;  
  725.             sGLThreadManager.notifyAll();  
  726.         }  
  727.     }  
  728.   
  729.     public void requestExitAndWait() {  
  730.         // don't call this from GLThread thread or it is a guaranteed  
  731.         // deadlock!  
  732.         synchronized (sGLThreadManager) {  
  733.             mDone = true;  
  734.             sGLThreadManager.notifyAll();  
  735.         }  
  736.         try {  
  737.             join();  
  738.         } catch (InterruptedException ex) {  
  739.             Thread.currentThread().interrupt();  
  740.         }  
  741.     }  
  742.   
  743.     /** 
  744.      * Queue an "event" to be run on the GL rendering thread. 
  745.      * 
  746.      * @param r 
  747.      * the runnable to be run on the GL rendering thread. 
  748.      */  
  749.     public void queueEvent(Runnable r) {  
  750.         synchronized (this) {  
  751.             mEventQueue.add(r);  
  752.             synchronized (sGLThreadManager) {  
  753.                 mEventsWaiting = true;  
  754.                 sGLThreadManager.notifyAll();  
  755.             }  
  756.         }  
  757.     }  
  758.   
  759.     private Runnable getEvent() {  
  760.         synchronized (this) {  
  761.             if (mEventQueue.size() > 0) {  
  762.                 return mEventQueue.remove(0);  
  763.             }  
  764.   
  765.         }  
  766.         return null;  
  767.     }  
  768.   
  769.     private class GLThreadManager {  
  770.   
  771.         public synchronized void threadExiting(GLThread thread) {  
  772.             if (LOG_THREADS) {  
  773.                 Log.i("GLThread""exiting tid=" + thread.getId());  
  774.             }  
  775.             thread.mDone = true;  
  776.             if (mEglOwner == thread) {  
  777.                 mEglOwner = null;  
  778.             }  
  779.             notifyAll();  
  780.         }  
  781.   
  782.         /* 
  783.          * Tries once to acquire the right to use an EGL surface. Does not block. 
  784.          * 
  785.          * @return true if the right to use an EGL surface was acquired. 
  786.          */  
  787.         public synchronized boolean tryAcquireEglSurface(GLThread thread) {  
  788.             if (mEglOwner == thread || mEglOwner == null) {  
  789.                 mEglOwner = thread;  
  790.                 notifyAll();  
  791.                 return true;  
  792.             }  
  793.             return false;  
  794.         }  
  795.   
  796.         public synchronized void releaseEglSurface(GLThread thread) {  
  797.             if (mEglOwner == thread) {  
  798.                 mEglOwner = null;  
  799.             }  
  800.             notifyAll();  
  801.         }  
  802.     }  
  803. }  
  804.   
  805. interface EGLConfigChooser {  
  806.     EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);  
  807. }  
  808.   
  809. abstract class BaseConfigChooser implements EGLConfigChooser {  
  810.     public BaseConfigChooser(int[] configSpec) {  
  811.         mConfigSpec = configSpec;  
  812.     }  
  813.   
  814.     public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {  
  815.         int[] num_config = new int[1];  
  816.         egl.eglChooseConfig(display, mConfigSpec, null0, num_config);  
  817.   
  818.         int numConfigs = num_config[0];  
  819.   
  820.         if (numConfigs <= 0) {  
  821.             throw new IllegalArgumentException("No configs match configSpec");  
  822.         }  
  823.   
  824.         EGLConfig[] configs = new EGLConfig[numConfigs];  
  825.         egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, num_config);  
  826.         EGLConfig config = chooseConfig(egl, display, configs);  
  827.         if (config == null) {  
  828.             throw new IllegalArgumentException("No config chosen");  
  829.         }  
  830.         return config;  
  831.     }  
  832.   
  833.     abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs);  
  834.   
  835.     protected int[] mConfigSpec;  
  836.     public static class ComponentSizeChooser extends BaseConfigChooser {  
  837.         public ComponentSizeChooser(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize,  
  838.                 int stencilSize) {  
  839.             super(new int[] { EGL10.EGL_RED_SIZE, redSize, EGL10.EGL_GREEN_SIZE, greenSize, EGL10.EGL_BLUE_SIZE,  
  840.                     blueSize, EGL10.EGL_ALPHA_SIZE, alphaSize, EGL10.EGL_DEPTH_SIZE, depthSize, EGL10.EGL_STENCIL_SIZE,  
  841.                     stencilSize, EGL10.EGL_NONE });  
  842.             mValue = new int[1];  
  843.             mRedSize = redSize;  
  844.             mGreenSize = greenSize;  
  845.             mBlueSize = blueSize;  
  846.             mAlphaSize = alphaSize;  
  847.             mDepthSize = depthSize;  
  848.             mStencilSize = stencilSize;  
  849.         }  
  850.   
  851.         @Override  
  852.         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {  
  853.             EGLConfig closestConfig = null;  
  854.             int closestDistance = 1000;  
  855.             for (EGLConfig config : configs) {  
  856.                 int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);  
  857.                 int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);  
  858.                 if (d >= mDepthSize && s >= mStencilSize) {  
  859.                     int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);  
  860.                     int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);  
  861.                     int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);  
  862.                     int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);  
  863.                     int distance = Math.abs(r - mRedSize) + Math.abs(g - mGreenSize) + Math.abs(b - mBlueSize)  
  864.                     + Math.abs(a - mAlphaSize);  
  865.                     if (distance < closestDistance) {  
  866.                         closestDistance = distance;  
  867.                         closestConfig = config;  
  868.                     }  
  869.                 }  
  870.             }  
  871.             return closestConfig;  
  872.         }  
  873.   
  874.         private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue) {  
  875.   
  876.             if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {  
  877.                 return mValue[0];  
  878.             }  
  879.             return defaultValue;  
  880.         }  
  881.   
  882.         private int[] mValue;  
  883.         // Subclasses can adjust these values:  
  884.         protected int mRedSize;  
  885.         protected int mGreenSize;  
  886.         protected int mBlueSize;  
  887.         protected int mAlphaSize;  
  888.         protected int mDepthSize;  
  889.         protected int mStencilSize;  
  890.     }  
  891.   
  892.     /** 
  893.      * This class will choose a supported surface as close to RGB565 as possible, with or without a depth buffer. 
  894.      * 
  895.      */  
  896.     public static class SimpleEGLConfigChooser extends ComponentSizeChooser {  
  897.         public SimpleEGLConfigChooser(boolean withDepthBuffer) {  
  898.             super(4440, withDepthBuffer ? 16 : 00);  
  899.             // Adjust target values. This way we'll accept a 4444 or  
  900.             // 555 buffer if there's no 565 buffer available.  
  901.             mRedSize = 5;  
  902.             mGreenSize = 6;  
  903.             mBlueSize = 5;  
  904.         }  
  905.     }  
  906. }  


更多 0
主题推荐
opengl es android stringbuilder asynchronous arraylist
猜你在找
OpenGL——glTexCoord2f()和glTexImage2D()函数的使用注意点
从零开始学习OpenGL ES之一 – 基本概念
《高效学习OpenGL》 之 缓冲区及其用途 glDrawBuffer(),glReadBuffer(),glColorMask(),glClearBuffer()
【STL】标准库中vector的操作
PreferenceManager过滤
定制dialog的方式
多线程编程 基础篇 (四)
Android NDK编译之undefined reference to 'JNI_CreateJavaVM'
chromium for android 硬件渲染流程总结
iOS6应用中第三方类库不支持armv7s的问题
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android OpenGL ES(五):GLSurfaceView 的相关文章

  • Unity笔记:修改代码执行的默认打开方式

    使用 External Tools 偏好设置可设置用于编写脚本 处理图像和进行源代码控制的外部应用程序 External Script Editor 选择 Unity 应使用哪个应用程序来打开脚本文件 Unity 会自动将正确的参数传递给内
  • Unity 导出XCode工程运行报错: ‘UnityFramework/UnityFramework.h‘ file not found

    简介 近期项目升级到2019 4 10f1版本 在用自动化打包的时候 遇到了一些问题 其中一个是 在导出XCode工程之后 运行工程的时候 编译报错 UnityFramework UnityFramework h file not foun
  • Unity 音频卡顿 静帧 等待等问题的解决方案

    是否遇到过在Unity中加载音频文件卡顿 也就是画面卡住 的现象 特别是加载外部音频文件时 虽然时间很短 但这终归不是什么好现象 尤其是打游戏的话 影响很大 但是一些有牌面的Boss也不能不配音乐 当然也可以通过其它方式解决 比如特定条件统
  • Unity使用Newtonsoft报错的解决方案

    文章目录 Unity 使用 Newtonsoft 报错的解决方案 问题描述 解决方法 方法一 使用 Unity 的 Package Manager 自动导入 方法二 访问 GitHub 下载 unitypackage 文件手动导入 Unit
  • 浅解cocos2d-x中的CCSprite绘制原理

    cocos2d x版本为2 0 4 此画图调用的是opengl es 2 0版本 支持三角形画图 故必须有一个顶点数组 此定义定义在CCSprite h中 ccV3F C4B T2F Quad m sQuad 而这个顶点数组的定义为 4 c
  • Openframework在VS2010中的配置

    Openframework在VS2010中的配置 首先去官网下载Openframework 下载后最好解压到C盘根目录下 不然会出现各种问题 我也不知道怎么解决 随便打开其中的例程 然后右击该工程 选择属性 如下图 接着在C C 常规选项里
  • Unity3D Engine Architecture

    原文 http www umingo de doku php id paper mechs and tanks section03 Architecture To better understand the game s software
  • Unity使用spine动画

    Unity使用spine动画 在 Unity 中 常常使用 Spine 来制作一些动画 引擎本身并不能直接播放 Spine 动画 需要额外导入一个 RunTime 插件库才能支持 官网插件导入 当然 也可以到 Spine 官网关于 Unit
  • visual studio:是否统一换行符 提示弹窗是否显示

    工具 选项 环境 文档 加载时检查一致的行尾
  • unity的LOD组件

    本文转载自http blog csdn net huutu article details 52106468 LOD是Level Of Detais 的简称 多细节层次 在游戏场景中 根据摄像机与模型的距离 来决定显示哪一个模型 一般距离近
  • Unity打包WebGL的优化常用操作?

    1 贴图部分优化 如果贴图格式时2048 在不影响画面效果的情况下 改成1024或者5 12 还可以缩小包体 2 压缩和解压缩问题 WebGL打包的时候分三种压缩情况 gzip 比Brotli文件打 但打包快 http和https都支持 B
  • Mecanim Any State

    Any State表示任意状态 任意状态是 一个一直存在的特殊状态 他的存在是为了保证你在无意转移至某个你当前正处于的特殊状态而准备的 为你的状态机中的每个状态设置相同的对外转移是一个快捷的方式 假如有Walk Run Fly Die这四个
  • Unity3D的四种坐标系

    1 World Space 世界坐标 我们在场景中添加物体 如 Cube 他们都是以世界坐标显示在场景中的 transform position可以获得该位置坐标 2 Screen Space 屏幕坐标 以像素来定义的 以屏幕的左下角为 0
  • jni 调用以自定义 java 接口作为参数的 java 方法

    我正在cocos2d x平台上开发一个插件项目 我想编写一些c 包装器接口来通过调用java方法JNI from jar软件开发工具包 我知道如何使用 JNI 调用静态 java 方法 但我对 java 函数中的接口参数感到困惑 我有一个处
  • Android.mk - 构建目录中的所有源文件

    我正在使用 Android NDK 构建我的 cocos2dx 项目 在 Android mk 中 有一个 LOCAL SRC FILES 的定义 其中列出了每个 cpp 文件 每当我添加新的源文件时 我也需要将它添加到那里 它看起来像这样
  • 暂停时快速高斯模糊[关闭]

    Closed 这个问题需要调试细节 目前不接受答案 In cocos2d x我需要实现快速高斯模糊 它应该是这样的 我刚刚在 App Store 上发现了一些游戏 已经统一完成了这样的模糊 所以 这很好fadeIn fadeOut当用户暂停
  • Cocos2dx Android 构建错误:“arm-linux-androideabi-g++:没有这样的文件或目录”

    我下载了最新的cocos2dx 3 10 和NDK r11 我执行的时候出现以下错误cocos compile p android android studio Error AndroidDev android ndk r11 toolch
  • Cocos 2d-x 中带有贝塞尔曲线的圆角矩形

    是否可以使用 DrawNode 对象绘制一个圆角矩形 我认为使用贝塞尔曲线是可能的 但我做了一些尝试 但我认为我无法处理它 查看 API 我只发现这两个函数 绘制四边形贝塞尔曲线 const Vec2 origin const Vec2 c
  • Cocos2d-x:可以使用HTML(UIWebView)吗?

    我正在尝试cocos2d x现在我可以为 Android 构建 Javascript 示例并在浏览器中运行它们 现在我想创建自己的游戏 但由于有 HTML 背景 我宁愿使用 HTML 标签和 CSS 也不愿使用 Javascript 来设置
  • [cocos2d-x]当我尝试在 Windows 10 中运行“python android-build.py -p 19 cpp-tests”时出现错误

    当我尝试运行命令时python android build p cpp tests 我收到如图所示的错误 在此之前 我收到了另一条关于 Android SDK Tools 版本兼容性的错误消息 所以 我只是将 sdk 版本从 26 0 0

随机推荐

  • 欧拉函数模板

    欧拉函数 n varphi n n 表示 1 n
  • libvirt 报错

    执行virsh命令出现 下面的错误 error failed to connect to the hypervisor error no valid connection error Failed to connect socket to
  • Nginx 学习笔记01

    Nginx 学习笔记01 概念 Nginx是lgor Sysoev为俄罗斯访问量第二的rambler ru站点设计开发的 从2004年发布至今 凭借开源的力量 已经接近成熟与完善 Nginx功能丰富 可作为HTTP服务器 也可作为反向代理服
  • 打不到VarAsType的解决办法

    在uses单元加入Variants VarType function from Variants unit in Delphi 7 In Delphi 5 VarType function is declared in Systems un
  • 【Verilog基础】7.计数器

    4位计数器 module count4 out reset clk output 3 0 out input reset clk reg 3 0 out always posedge clk begin if reset out lt 0
  • SQL之子查询

    1 案例 案例1 OrderItems表示订单商品表 含有字段订单号 order num 订单价格 item price Orders表代表订单信息表 含有顾客id cust id和订单号 order num OrderItems表 ord
  • matlab 获取向量长度,matlab 获取矩阵和向量长度 length 和 size

    matlab 获取矩阵和向量长度 length 和 size 觉得有用的话 欢迎一起讨论相互学习 概论 size 获取数组的行数和列数 length 数组长度 即行数或列数中的较大值 numel 元素总数 size s size A 当只有
  • 浅谈智能还书车

    智能还书车是一种新型的智能化设备 配备触摸显示屏或简单操作的人机交流界面 图形界面 通过协议或其他网络及专用接口与图书馆自动化系统数据相连接 由读者自行对图书进行快速归还 读者把图书放到书车上 系统自动对图书进行归还操作 无须读者再做其他操
  • postgresql查询锁表pid,SQL、开始时间、执行SQL的ip地址

    SELECT distinct pg stat get backend pid S backendid AS pid pg stat get backend activity start S backendid AS start time
  • Spring Boot 框架介绍和使用

    本文参考自Spring Boot文档 Spring Boot 简介 Spring框架功能很强大 但是就算是一个很简单的项目 我们也要配置很多东西 因此就有了Spring Boot框架 它的作用很简单 就是帮我们自动配置 Spring Boo
  • SpringBoot整合MyBatisPlus显示隐藏打印sql语句日志

    显示 configuration log impl org apache ibatis logging stdout StdOutImpl 不显示 configuration log impl org apache ibatis loggi
  • QueryWrapper多表联查分页、IPage分页(解决IPage+ QueryWrapper 多表联查、条件搜素、模糊匹配的分页问题)

    QueryWrapper多表联查分页 IPage分页 解决IPage QueryWrapper 多表联查 条件搜素 模糊匹配的分页问题 实体类 controller service Impl 重写的mapper xml 最终sql Quer
  • 在shopify中如何使用JavaScript结合开发文档实现不加入购物车直接进入订单支付环节呢?

    今天有一个shopify修改的需求 在shopify中如何使用JavaScript结合开发文档实现不加入购物车直接进入订单支付环节 通过查看开发文档和尝试 发现可以实现 获取到商品信息 然后通过 cart create js接口提交订单 然
  • Matlab学习笔记 奇异值、奇异矩阵、svd函数

    奇异值 奇异值分解法是线性代数中一种重要的矩阵分解法 在信号处理 统计学等领域有重要应用 定义 设A为m n阶矩阵 A 表示A的转置矩阵 A A的n个特征值的非负平方根叫作A的奇异值 记为 i A 如果把A A的特征值记为 i A A 则
  • 前端学习资料汇总

    前端工具 can i see http caniuse com 一个查看css及html5在各个浏览器及手机端的支持情况 前端视野 平时可以多看看的网站了解下最新资讯 前端观察站 腾讯的前端技术 挺有含金量 html5 中国 http ww
  • C++模板实现队列

    我准备练习一下模板的知识 然后自己实现vector类 在这之前 先用模板实现一个队列来热身吧 队列的底层是链表 主要是熟悉一下模板的写法 另外 就是模板的定义和实现都要写在一个文件中 export关键字可以避免这样 还没用过 所以倒数第二行
  • cv2.threshold() 进行简单的图像分割,构建Mask

    cv2 thresholding构建Mask 1 T threshImage cv2 threshold src thresh maxval type 2 效果图 3 构建Mask 4 源码 4 1 自制渐变色原始图 4 2 磁盘已存在图片
  • CSAPP(第三版)第二章答案

    2 30 补码发生溢出返回0 否则返回1 int tadd ok int x int y int sum x y if x gt 0 y gt 0 sum lt 0 x lt 0 y lt 0 sum gt 0 return 0 else
  • 图像质量评价Code和Dataset

    图像质量评价Code和Dataset Research on Image Quality Assessment Lin Zhang School of Software Engineering Tongji University Lei Z
  • Android OpenGL ES(五):GLSurfaceView

    Android OpenGL ES 五 GLSurfaceView 分类 Android OpenGL ES基础 2012 02 27 16 56 3365人阅读 评论 0 收藏 举报 android null thread interfa