Question

In the renderer of OpenGL I try the following code:

ByteBuffer buf = ByteBuffer.allocate(1 * 1 * 4);

GLES20.glReadPixels(60, 100, 1, 1, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);


float red = buf.get()/255.0f;

float green = buf.get()/255.0f;

float blue = buf.get()/255.0f;

float alpha = buf.get();

EngineX.show("red: " + red + " green: " + green + " blue: " + blue + " alpha: " + alpha);

The alpha value always returns -1.0.

//Implementation of Class SurfaceView //I do not do anything special with this implementation

public class GLSurfaceViewX extends GLSurfaceView
{
    BaseActivity activity;

    public GLSurfaceViewX(Context context)
    {
        super(context);
        activity = (BaseActivity) context;
            getHolder().setFormat(PixelFormat.RGBA_8888);
    }
}

//This is the activity //Here the view of drawing is created

public abstract class BaseActivity extends Activity
{
    private EngineX engine;
     GLSurfaceViewX view;

    @Override
    protected void onCreate(final Bundle pSavedInstanceState)
    {
        super.onCreate(pSavedInstanceState);

        if (!isOGLES20Compatible())
        {
            view = null;
            showErrorDialogBox();
            return;
        }
        engine = new EngineX(this);

        view = new GLSurfaceViewX(this);

        view.setEGLContextClientVersion(2);

        view.setRenderer(engine);

        // Render the view only when there is a change in the drawing data
        view.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);

        setContentView(view);

    }

    @Override
    protected void onResume()
    {
        EngineX.show("BaseActivity: onResume");
        super.onResume();
        if (view != null)
        {
            view.onResume();
        }

    }

    @Override
    protected void onPause()
    {
        EngineX.show("BaseActivity: onPause");

        super.onPause();
        if (view != null)
        {
            view.onPause();
        }
    }

    @Override
    protected void onDestroy()
    {
        if (engine != null)
        {
            engine.closeGame();
        }

        super.onDestroy();
    }

    /* This method verify that your Phone is compatible with OGLES 2.x */
    private boolean isOGLES20Compatible()
    {
        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        ConfigurationInfo info = am.getDeviceConfigurationInfo();
        return (info.reqGlEsVersion >= 0x20000);
    }

    /* show an error message */
    private void showErrorDialogBox()
    {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage("Sorry! OpenGL ES 2.0 not supported on device.").setCancelable(false)
                .setPositiveButton("OK", new DialogInterface.OnClickListener()
                {
                    public void onClick(DialogInterface dialog, int id)
                    {
                        dialog.cancel();
                        finish();
                    }
                });
        AlertDialog alert = builder.create();
        alert.show();
    }

}
Was it helpful?

Solution

Well, first you have to realize that Java is incapable of representing the number 255 using a byte. It has no unsigned byte type. A full-bright color component will come back 0xFF, which in Java (two's complement) is -1.

So, how do you fix this? I would consider the following:

float red   = (buf.get () & 0xFF) / 255.0f;
float green = (buf.get () & 0xFF) / 255.0f;
float blue  = (buf.get () & 0xFF) / 255.0f;
float alpha = (buf.get () & 0xFF);

This works because the signed byte is promoted to an integer to perform the bitwise AND. The resulting integer is still signed, but what happens here is that the sign-bit is not included in the value you AND'd (0x000000FF), so the number loses its sign and is thus able to properly represent values > 127.

  • NOTE: I am not sure why you are not dividing alpha by 255.0f like the rest of the values; they are all 8-bit.

Also keep in mind that not all pixel formats actually have a place in the framebuffer to store alpha values. Destination alpha is not required for many things, you can do alpha blending using only the alpha value generated by what you are currently drawing (source alpha). If you are using a format like RGB_565, RGB_888 or OPAQUE, then reading the alpha channel back will always give you a constant value.


Update:

In order for your framebuffer to store an alpha channel, you should modify the following function:

@Override
protected void onCreate(final Bundle pSavedInstanceState)
{
    super.onCreate(pSavedInstanceState);

    if (!isOGLES20Compatible())
    {
        view = null;
        showErrorDialogBox();
        return;
    }
    engine = new EngineX(this);

    view = new GLSurfaceViewX(this);

    view.setEGLContextClientVersion(2);
    

    //
    // Default is usually RGB565 or RGB8 (no Alpha) -- you need RGBA8
    //
    view.setEGLConfigChooser (8, 8, 8, 8, 16, 0);

    //
    // If you want the actual SURFACE to be translucent, then you also need this
    //
    view.setZOrderOnTop         (true);
    view.getHolder ().setFormat (PixelFormat.RGBA_8888);


    view.setRenderer(engine);

    // Render the view only when there is a change in the drawing data
    view.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);

    setContentView(view);

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top