1

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();
    }

}
genpfault
  • 51,148
  • 11
  • 85
  • 139
Samuel Liz
  • 49
  • 8
  • Ready, the code @andon-m-coleman – Samuel Liz Jan 18 '14 at 13:25
  • You keep adding more code, but not the right code. I need to see where you create your render context, probably using [`GLSurfaceView`](http://developer.android.com/reference/android/opengl/GLSurfaceView.html). The important thing to note is this: *"By default `GLSurfaceView` will create a `PixelFormat.RGB_888` format surface. If a translucent surface is required, call `getHolder().setFormat(PixelFormat.TRANSLUCENT)`."* – Andon M. Coleman Jan 18 '14 at 13:29
  • Ready @andon-m-coleman – Samuel Liz Jan 18 '14 at 13:42

1 Answers1

0

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);

}
Community
  • 1
  • 1
Andon M. Coleman
  • 42,359
  • 2
  • 81
  • 106
  • Try that, but nothing now returns 255. I'm drawing a semi-transparent image, should detect – Samuel Liz Jan 18 '14 at 02:52
  • Well, that is good. It should be returning **255** for anything opaque (fixed-point framebuffers do not store negative values). I will bet good money that your pixel format is **RGB_565** (default on Android). That format does not store an alpha channel anywhere, you will need to use **RGBA_8888**. – Andon M. Coleman Jan 18 '14 at 02:57
  • I add the format RGBA_8888 to bitmapand add: GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA); GLES20.glEnable(GLES20.GL_BLEND); Stayed the same :( – Samuel Liz Jan 18 '14 at 03:29
  • Please update your question to show the code where you setup your EGL render context. – Andon M. Coleman Jan 18 '14 at 03:43
  • @SamuelLiz: See my updated answer, it should solve your problem. Depending on what you are actually trying to do, you *may not need* the `view.SetZOrderOnTop (...)` and `setFormat (PixelFormat.RGBA_8888)` lines. – Andon M. Coleman Jan 18 '14 at 13:55
  • I want to detect if a pixel is transparent in texture drawn I add the following line to the creation of the SurfaceView and nothing. getHolder().setFormat(PixelFormat.RGBA_8888) – Samuel Liz Jan 18 '14 at 14:00
  • That is not enough, see the code I just added to my answer. You need to call `setEGLConfigChooser (...)` to setup the proper framebuffer. – Andon M. Coleman Jan 18 '14 at 14:01
  • 1
    Yes, add this line and now it works Thanks a million – Samuel Liz Jan 18 '14 at 14:05