stuckless
stuckless

Reputation: 6545

How to make the LibGDX GLSurfaceView transparent so that we can see the Android ImageView behind it?

The basic premise is that I have 2 Android Views... A background view that fills the screen (ImageView in this case), and a LibGDX GLSurfaceView that is in the foreground, and is the LibGDX application. I want to punch a hole in the LibGDX GLSurfaceView, so that I can see the background ImageView show through. ie, the LibGDX part is behaving like an overlay. Sadly I cannot get this to work at all. I've stripped away all the code to leave just the bare necessities that hopefully demonstrate what I'm trying to do.

In the full application, it is an Android application where the background View is a Video, and the foreground, being rendered by LibGdx is a set of video controls, that needs to be overlaid on the video.

public class MiniClientGDXTestActivity extends AndroidApplication implements ApplicationListener {
    @Bind(R.id.surface)
    FrameLayout uiFrameHolder;

    Stage stage;
    Batch batch;
    Camera camera;
    Viewport viewport;
    ShapeRenderer shapeRenderer;


    private View miniClientView;

    public MiniClientGDXTestActivity() {
    }

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

        hideSystemUI(this);

        setContentView(R.layout.miniclientgltest_layout);
        ButterKnife.bind(this);

        AndroidApplicationConfiguration cfg = new AndroidApplicationConfiguration();
        //cfg.useGL20 = false;
        // we need to change the default pixel format - since it does not include an alpha channel
        // we need the alpha channel so the camera preview will be seen behind the GL scene
        cfg.r = 8;
        cfg.g = 8;
        cfg.b = 8;
        cfg.a = 8;

        miniClientView = initializeForView(this, cfg);

        if (graphics.getView() instanceof SurfaceView) {
            SurfaceView glView = (SurfaceView) graphics.getView();
            glView.setBackgroundColor(android.graphics.Color.TRANSPARENT);
            // force alpha channel - I'm not sure we need this as the GL surface is already using alpha channel
            glView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        }

        uiFrameHolder.addView(miniClientView);
    }

    @Override
    public void create() {
        camera = new OrthographicCamera();
        viewport = new StretchViewport(1920, 1080, camera);
        stage = new Stage(viewport);
        batch = stage.getBatch();
        shapeRenderer = new ShapeRenderer();

        Gdx.graphics.setContinuousRendering(false);
        Gdx.graphics.requestRendering();
    }

    @Override
    public void resize(int width, int height) {
        stage.getViewport().setWorldSize(1920, 1080);
        stage.getViewport().update(width, height, true);
        Gdx.graphics.requestRendering();
    }

    @Override
    public void render() {
        Gdx.gl20.glClearColor(0, 0, 0, 0);
        Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

        // draw whatever we have on the stage
        stage.draw();

        // draw red rectangle
        drawRect(10, 10, 1000, 1000);

        // draw a blue box
        fillRect(50, 50, 800, 800);

        // punch a hole in the surface (ie, clear an area) so that we can see the view that is
        // behind this view
        clearRect(200, 200, 1600, 600);
    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void dispose() {

    }

    public void drawRect(final int x, final int y, final int width, final int height) {
        shapeRenderer.setProjectionMatrix(camera.combined);
        shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
        shapeRenderer.rect(x, y, width, height, Color.RED, Color.RED, Color.RED, Color.RED);
        shapeRenderer.end();
    }

    public void fillRect(final int x, final int y, final int width, final int height) {
        shapeRenderer.setProjectionMatrix(camera.combined);
        shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
        shapeRenderer.rect(x, y, width, height, Color.BLUE, Color.BLUE, Color.BLUE, Color.BLUE);
        shapeRenderer.end();
    }

    public void clearRect(final int x, final int y, final int width, final int height) {
//                Gdx.gl.glEnable(GL20.GL_BLEND);
//                Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);


        shapeRenderer.setProjectionMatrix(camera.combined);
        shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
        shapeRenderer.setColor(Color.CLEAR);
        shapeRenderer.rect(x, y, width, height);
        shapeRenderer.end();

//                Gdx.gl.glDisable(GL20.GL_BLEND);
    }

}

And here's the XML layout

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:keepScreenOn="true">

    <FrameLayout
        android:visibility="visible"
        android:id="@+id/surface"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">

        <!-- to see if we can see this -->
        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="match_parent" android:scaleType="fitXY" android:src="@drawable/background"/>

        <!-- gdx gets added here -->
    </FrameLayout>


</FrameLayout>

Upvotes: 4

Views: 1147

Answers (1)

stuckless
stuckless

Reputation: 6545

It would appear that calling setZOrderOnTop with using PixelFormat.RGBA_8888 did the trick.

    if (graphics.getView() instanceof SurfaceView) {
        GLSurfaceView glView = (GLSurfaceView) graphics.getView();
        glView.setZOrderOnTop(true);
        glView.getHolder().setFormat(PixelFormat.RGBA_8888);
    }

now when the clearRect method is called it will punch a hole in the GLSurfaceView to see the Android view that is below.

Upvotes: 4

Related Questions