Skip to content

Android.opengl.GLSurfaceView

Methods

requestRender()
화면을 다시 렌더링할 필요가 생길 경우 호출하면 된다.

GLSurfaceView.Renderer

랜더링을 담당한다.

onSurfaceCreated(GL10 gl, EGLConfig config)
Surface가 생성될 경우 발생되는 이벤트.
onSurfaceChanged(GL10 gl, int w, int h)
Surface가 변경될 경우 발생되는 이벤트.
onDrawFrame(GL10 gl)
화면을 그려줄 경우 발생되는 이벤트.

Capture screen of GLSurfaceView to bitmap

GLSurfaceView를 캡쳐하여, Bitmap에 복사하는 방법은 아래와 같다. 단, onDrawFrame()에서 적용해야하므로 동기화 및 병목현상에 주의해야한다.

private Bitmap createBitmapFromGLSurface(int x, int y, int w, int h, GL10 gl)
        throws OutOfMemoryError {
    int bitmapBuffer[] = new int[w * h];
    int bitmapSource[] = new int[w * h];
    IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer);
    intBuffer.position(0);

    try {
        gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, intBuffer);
        int offset1, offset2;
        for (int i = 0; i < h; i++) {
            offset1 = i * w;
            offset2 = (h - i - 1) * w;
            for (int j = 0; j < w; j++) {
                int texturePixel = bitmapBuffer[offset1 + j];
                int blue = (texturePixel >> 16) & 0xff;
                int red = (texturePixel << 16) & 0x00ff0000;
                int pixel = (texturePixel & 0xff00ff00) | red | blue;
                bitmapSource[offset2 + j] = pixel;
            }
        }
    } catch (GLException e) {
        return null;
    }

    return Bitmap.createBitmap(bitmapSource, w, h, Bitmap.Config.ARGB_8888);
}

GLSurfaceView 배경 투명하게 적용하는 방법

setEGLConfigChooser(8, 8, 8, 8, 16, 0);
getHolder().setFormat(PixelFormat.TRANSLUCENT);

Example

JniCanvasTest.java:

package com.example;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;

public class JniCanvasTest extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MapView(getApplicationContext()));
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}

MapView.java:

package com.example;

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

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.view.MotionEvent;
public class MapView extends GLSurfaceView implements Renderer {
    public MapView(Context context) {
        super(context);

        this.setRenderer(this);
        this.requestFocus();
        this.setRenderMode(RENDERMODE_WHEN_DIRTY);
        this.setFocusableInTouchMode(true);

//      try {
//          Thread.sleep(3000);
//      } catch (InterruptedException e) {
//          e.printStackTrace();
//      }
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // nativeCreated();
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        // nativeChanged(width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        // nativeUpdate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        requestRender();
        return super.onTouchEvent(event);
    }
}

Troubleshooting

IllegalStateException: setRenderer has already been called for this instance

setRenderer()를 호출하는 순서가 틀릴 경우 이러한 에러가 나타날 수 있다. 따라서 올바르게 수정한다면 아래의 예제와 비슷해진다.

setEGLContextClientVersion(2);
setRenderer(this);

// 화면갱신요청이 있을 때 까지 대기.
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

// 화면을 지속적으로 갱신.
// setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
requestRender();

See also

Favorite site

References


  1. Introducing_glsurfaceview.pdf 

  2. Glsurfaceview_analysis_1.pdf 

  3. Glsurfaceview_analysis_2.pdf