GLFBO.java 3.91 KB
Newer Older
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
1 2 3 4
package com.projectseptember.RNGL;

import java.util.ArrayList;
import java.util.List;
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
5
import java.util.concurrent.Executor;
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
6 7 8

import static android.opengl.GLES20.*;

Gaëtan Renaudeau's avatar
wip  
Gaëtan Renaudeau committed
9
public class GLFBO {
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
10 11 12 13
    public final List<GLTexture> color = new ArrayList<>();
    private int handle;
    private int width = 0;
    private int height = 0;
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
    private Executor glExecutor;

    /**
     * GLFBO constructor as well as all methods must be called in GL Thread
     * @param glExecutor is only required for finalize()
     */
    public GLFBO (Executor glExecutor) {
        this.glExecutor = glExecutor;
        FBOState state = new FBOState();

        int[] handleArr = new int[1];
        glGenFramebuffers(1, handleArr, 0);
        handle = handleArr[0];

        int numColors = 1;

        glBindFramebuffer(GL_FRAMEBUFFER, handle);

        for(int i=0; i<numColors; ++i) {
            color.add(initTexture(width, height, GL_COLOR_ATTACHMENT0 + i));
        }
        state.restore();
    }
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
37

Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
38 39
    private GLTexture initTexture (int width, int height, int attachment) {
        GLTexture texture = new GLTexture(glExecutor);
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
40 41
        texture.bind();
        texture.setShape(width, height);
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
42
        glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture.getHandle(), 0);
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
43 44 45 46 47 48
        return texture;
    }

    class FBOState {

        private int fbo;
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
49 50
        private int rbo;
        private int tex;
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
51 52

        public FBOState() {
Gaëtan Renaudeau's avatar
wip  
Gaëtan Renaudeau committed
53
            int[] fbo = new int[1];
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
54 55
            int[] rbo = new int[1];
            int[] tex = new int[1];
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
56
            glGetIntegerv(GL_FRAMEBUFFER_BINDING, fbo, 0);
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
57 58
            glGetIntegerv(GL_RENDERBUFFER_BINDING, rbo, 0);
            glGetIntegerv(GL_TEXTURE_BINDING_2D, tex, 0);
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
59
            this.fbo = fbo[0];
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
60 61
            this.rbo = rbo[0];
            this.tex = tex[0];
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
62 63 64 65
        }

        private void restore() {
            glBindFramebuffer(GL_FRAMEBUFFER, fbo);
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
66 67
            glBindRenderbuffer(GL_RENDERBUFFER, rbo);
            glBindTexture(GL_TEXTURE_2D, tex);
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
68 69 70 71 72 73
        }
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
74 75 76 77 78 79 80
        glExecutor.execute(new Runnable() {
            @Override
            public void run() {
                int[] handleArr = new int[]{handle};
                glDeleteFramebuffers(1, handleArr, 0);
            }
        });
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
81 82 83 84 85 86 87 88
    }


    void checkStatus () {
        int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        if(status != GL_FRAMEBUFFER_COMPLETE) {
            switch (status) {
                case GL_FRAMEBUFFER_UNSUPPORTED:
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
89
                    throw new RuntimeException("Framebuffer unsupported");
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
90
                case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
91
                    throw new RuntimeException("Framebuffer incomplete attachment");
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
92
                case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
93
                    throw new RuntimeException("Framebuffer incomplete dimensions");
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
94
                case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
95
                    throw new RuntimeException("Framebuffer incomplete missing attachment");
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
96
                default:
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
97
                    throw new RuntimeException("Failed to create framebuffer: " + status);
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111
            }
        }
    }

    public void bind () {
        glBindFramebuffer(GL_FRAMEBUFFER, handle);
        glViewport(0, 0, width, height);
    }

    public void setShape(int w, int h) {
        if (w == width && h == height) return;
        int[] maxFBOSize = new int[1];
        glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, maxFBOSize, 0);
        if( w < 0 || w > maxFBOSize[0] || h < 0 || h > maxFBOSize[0]) {
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
112
            throw new IllegalArgumentException("Can't resize framebuffer. Invalid dimensions");
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
113 114 115 116
        }
        width = w;
        height = h;

Gaëtan Renaudeau's avatar
wip  
Gaëtan Renaudeau committed
117
        FBOState state = new FBOState();
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
118 119 120 121 122 123 124 125

        for (GLTexture clr: color) {
            clr.setShape(w, h);
        }

        glBindFramebuffer(GL_FRAMEBUFFER, handle);
        checkStatus();

Gaëtan Renaudeau's avatar
wip  
Gaëtan Renaudeau committed
126
        state.restore();
Gaëtan Renaudeau's avatar
WIP  
Gaëtan Renaudeau committed
127 128
    }
}