1 module polyplex.core.render.gl.renderbuf;
2 import core = polyplex.core.render;
3 import polyplex.core.render.gl.gloo;
4 import polyplex.core.render.gl.gloo : RBO = Renderbuffer, FBO = Framebuffer;
5 import core.memory : GC;
6 
7 enum Attachment {
8     Color0=GL_COLOR_ATTACHMENT0,
9     Color1=GL_COLOR_ATTACHMENT1,
10     Color2=GL_COLOR_ATTACHMENT2,
11     Color3=GL_COLOR_ATTACHMENT3,
12     Color4=GL_COLOR_ATTACHMENT4,
13     Color5=GL_COLOR_ATTACHMENT5,
14     Color6=GL_COLOR_ATTACHMENT6,
15     Color7=GL_COLOR_ATTACHMENT7,
16     Color8=GL_COLOR_ATTACHMENT8,
17     Color9=GL_COLOR_ATTACHMENT9,
18     Color10=GL_COLOR_ATTACHMENT10,
19     Color11=GL_COLOR_ATTACHMENT11,
20     Color12=GL_COLOR_ATTACHMENT12,
21     Color13=GL_COLOR_ATTACHMENT13,
22     Color14=GL_COLOR_ATTACHMENT14,
23     Color15=GL_COLOR_ATTACHMENT15,
24     Depth=GL_DEPTH_ATTACHMENT
25 }
26 
27 public class Framebuffer {
28 private:
29     int             width;
30     int             height;
31     FBO             fbo;
32     RBO             rbo;
33     Texture[]       renderTextures;
34     GLenum[]        drawBufs;
35 
36     void bufferTexture() {
37         fbo.Bind();
38 
39         // Prepare textures.
40         foreach(to; renderTextures) {
41             if (to is null) continue;
42             to.Bind(TextureType.Tex2D);
43             to.Image2D(TextureType.Tex2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
44             to.SetParameter(TextureType.Tex2D, TextureParameter.MagFilter, GL.Nearest);
45             to.SetParameter(TextureType.Tex2D, TextureParameter.MinFilter, GL.Nearest);
46             to.Unbind();
47         }
48 
49         rbo.Bind(); 
50         rbo.Storage(GL_DEPTH_COMPONENT, width, height);
51         fbo.Renderbuffer(FramebufferType.Multi, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo.Id);
52 
53         // Attach textures.
54         foreach(i, to; renderTextures) {
55             to.Bind(TextureType.Tex2D);
56             fbo.Texture(GL_FRAMEBUFFER, drawBufs[i], to.Id, 0);
57             to.Unbind();
58         }
59         GL.DrawBuffers(cast(int)drawBufs.length, drawBufs.ptr);
60     }
61 
62     void updateTextureBuffer() {
63 
64     }
65 
66 public:
67     @property int Width() {
68         return width;
69     }
70 
71     @property int Height() {
72         return height;
73     }
74 
75     this(int width, int height, int colorAttachments = 1) {
76         this.width = width;
77         this.height = height;
78 
79         fbo = new FBO();
80         rbo = new RBO();
81 
82         // Add color attachment textures
83         foreach(i; 0..colorAttachments) {
84             drawBufs ~= GL_COLOR_ATTACHMENT0+cast(uint)i;
85             renderTextures ~= new Texture();
86         }
87 
88         // Setup framebuffer
89         bufferTexture();
90         fbo.Unbind();
91     }
92     ~this() {
93         destroy(fbo);
94         destroy(renderTextures);
95         destroy(rbo);
96     }
97 
98     Texture[] OutTextures() {
99         return renderTextures;
100     }
101 
102     /**
103         Resize destroys the current framebuffer and recreates it with the specified size.
104     */
105     void Resize(int width, int height) {
106         immutable(size_t) colorAttachments = renderTextures.length;
107         destroy(rbo);
108         destroy(fbo);
109         destroy(renderTextures);
110         destroy(drawBufs);
111         GC.collect();
112         
113 
114         this.width = width;
115         this.height = height;
116 
117         fbo = new FBO();
118         rbo = new RBO();
119 
120         // TODO: Optimize this.
121         renderTextures = new Texture[colorAttachments];
122         foreach(i; 0..colorAttachments) {
123             drawBufs ~= GL_COLOR_ATTACHMENT0+cast(uint)i;
124             renderTextures[i] = new Texture();
125         }
126 
127         // Setup framebuffer
128         bufferTexture();
129         fbo.Unbind();
130     }
131 
132     void Begin() {
133         fbo.Bind();
134         GL.Viewport(0, 0, width, height);
135     }
136 
137     void End() {
138         GL.BindFramebuffer(GL_FRAMEBUFFER, 0);
139         fbo.Unbind();
140     }
141 }