0

I have implemented a color picking method and it also works; sometimes. The problem is when I call my method in the onSurfaceChanged method, it does read back the correct pixels. But when I call my method in the onTouchevent of the GLSurfaceView, it reads back only zeros. In my method I create a framebuffer object and attach two renderbuffer objects to it. My renderer is set to RENDERMODE_WHEN_DIRTY and glGetError() returns 0. Where exactly is the problem? I'm not sure whether it is my method, or if I simply cannot do this in an onTouchevent. Here is the sourcecode of my picking method in my renderer:

public int pick(int x, int y) {
    int result = -2;

    int[]  view = new int[4];
    GLES20.glGetIntegerv(GLES20.GL_VIEWPORT, view, 0);

    y = view[3] - y;

    int[] fbo = new int[1];
    GLES20.glGenFramebuffers(1, fbo, 0);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo[0]);

    int[] rbo = new int[2];
    GLES20.glGenRenderbuffers(2, rbo, 0);

    GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, rbo[0]);
    GLES20.glRenderbufferStorage(
            GLES20.GL_RENDERBUFFER, 
            GLES20.GL_RGBA4, view[2], view[3]);

    GLES20.glFramebufferRenderbuffer(
            GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, 
            GLES20.GL_RENDERBUFFER, rbo[0]);

    GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, rbo[1]);
    GLES20.glRenderbufferStorage(
            GLES20.GL_RENDERBUFFER, 
            GLES20.GL_DEPTH_COMPONENT16, 
            view[2], view[3]);

    GLES20.glFramebufferRenderbuffer(
            GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, 
            GLES20.GL_RENDERBUFFER, rbo[1]);

    int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
    if (status == GLES20.GL_FRAMEBUFFER_COMPLETE) {
        result = -1;
        GLES20.glClear(
                GLES20.GL_COLOR_BUFFER_BIT | 
                GLES20.GL_DEPTH_BUFFER_BIT);

        for (int i = 0; i < mObjects.size(); i++)
            mObjects.get(i).render(mProgram, mMatrixMVP, true);

        ByteBuffer pixels = ByteBuffer.allocate(view[2] * view[3] * 4);
        pixels.order(ByteOrder.nativeOrder());

        GLES20.glReadPixels( // I read every pixel just for debugging
                0, 0, view[2], view[3], GLES20.GL_RGBA, 
                GLES20.GL_UNSIGNED_BYTE, pixels);

        int e = GLES20.glGetError(); // always returns 0
        byte[] tmp = pixels.array(); // only zeros when called in onTouch

        for (int i = 0; i < mObjects.size(); i++)
            if ((Math.abs(r - mObjects.get(i).CODE_R) < 8) &&
                (Math.abs(g - mObjects.get(i).CODE_G) < 8) &&
                (Math.abs(b - mObjects.get(i).CODE_B) < 8)) {

                result = i;
                break;
            }
    } 

    GLES20.glDeleteRenderbuffers(2, rbo, 0);
    GLES20.glDeleteFramebuffers(1, fbo, 0);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

    return result;
}

And since it might be relevent, here is my onDrawFrame method:

@Override
public void onDrawFrame(GL10 gl) {
    GLES20.glClear(
            GLES20.GL_COLOR_BUFFER_BIT | 
            GLES20.GL_DEPTH_BUFFER_BIT);

    for (int i = 0; i < mObjects.size(); i++)
        mObjects.get(i).render(mProgram, mMatrixMVP, false);
}

I have read that the onDrawFrame Method runs in a seperate thread, but I don't think that this is the problem, since I am in RENDERMODE_WHEN_DIRTY...

2 Answers2

0

Why dont you check this library. I think it is quite good, you could use it instead of create a new color picker.

https://github.com/LarsWerkman/HoloColorPicker

jpardogo
  • 5,636
  • 2
  • 23
  • 27
  • Well, I am still trying to learn OpenGL. Therefore I first want to know how something works and create a basic model myself. When I look at this library, there are still very many things I have never heard of. So this would be something like an overkill for me ^^ –  Jun 20 '13 at 10:14
  • Good stuff, I think you are doing good trying to create it for yourself. Anyway you can always check this library code in case you need something of it. ;) – jpardogo Jun 20 '13 at 10:25
0

Even if you use RENDERMODE_WHEN_DIRTY your renderer runs on a different thread, it just doesn't render untill you call requestRender(). You can try to use the queueEvent()-method to run the code on your render thread instead and see if that helps. You could also change your pick()-method so that it internally uses a Runnable and the queueEvent-method (or a Handler). You would of course also need to use some kind of callback to be able to "return" a result.

Jave
  • 31,598
  • 14
  • 77
  • 90