Sanjiban Bairagya
Sanjiban Bairagya

Reputation: 744

GLSurfaceView's setRenderer function cannot be called more than once

I have a GLSurfaceView on which I am putting an image and applying the GRAYSCALE effect, as follows:

final GLSurfaceView glView = (GLSurfaceView) findViewById(R.id.glSurfaceImg);
glView.setEGLContextClientVersion(2);
glView.setRenderer(new EffectsRenderer(this, bitmap_resized, EffectFactory.EFFECT_GRAYSCALE));
glView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

Above code is working fine, that is, the image is showing properly, with the correct filter as well. But I have a button as well, clicking on which, I want the filter effect on the image to change from EFFECT_GRAYSCALE to EFFECT_GRAIN for which I am running the following code:

myButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        glView.setRenderer(new EffectsRenderer(ImageFiltersActivity.this, bitmap_resized, EffectFactory.EFFECT_GRAIN));
    }
});

But the above code is not working. When I click on the button, I get the following error: java.lang.IllegalStateException: setRenderer has already been called for this instance.

What do I do now as a turnaround to this problem, in order to achieve my goal of applying a different filter on the image on clicking on my button?

My EffectsRenderer class goes as follows (in case it is required for reference):

public class EffectsRenderer implements GLSurfaceView.Renderer {
    private Bitmap photo;
    private int photoWidth, photoHeight;
    private int textures[] = new int[2];
    private Square square;

    private String filter;
    private EffectContext effectContext;
    private Effect effect;

    public EffectsRenderer(Context context, Bitmap bitmap, String filter){
        super();
        photo = bitmap;
        this.filter = filter;
        photoWidth = photo.getWidth();
        photoHeight = photo.getHeight();
    }

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

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0,0,width, height);
        GLES20.glClearColor(0,0,0,1);
        generateSquare();
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        if(effectContext==null) {
            effectContext = EffectContext.createWithCurrentGlContext();
        }
        if(effect!=null){
            effect.release();
        }
        applyFilter();
        square.draw(textures[1]);
    }

    private void generateSquare(){
        GLES20.glGenTextures(2, textures, 0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);

        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, photo, 0);
        square = new Square();
    }

    private void applyFilter(){
        EffectFactory factory = effectContext.getFactory();
        effect = factory.createEffect(filter);
        effect.apply(textures[0], photoWidth, photoHeight, textures[1]);
    }
}

Upvotes: 0

Views: 938

Answers (1)

fadden
fadden

Reputation: 52313

You aren't allowed to call setRenderer() more than once, as noted in the documentation.

Instead, use a single Renderer instance, and have it switch behavior. Modify your onDrawFrame() to detect that the requested filter has changed, and react appropriately.

Upvotes: 1

Related Questions