1 /*
2     Copyright © 2020, Luna Nielsen
3     Distributed under the 2-Clause BSD License, see LICENSE file.
4     
5     Authors: Luna Nielsen
6 */
7 module engine.render.fbo;
8 import engine.render;
9 import engine.math;
10 import engine.core.window;
11 
12 /**
13     A framebuffer
14 */
15 class Framebuffer {
16 private:
17     Window window;
18 
19     vec2i size;
20     vec2i realsize;
21 
22     GLuint fbo;
23     GLuint color;
24     GLuint depth;
25 
26 package(engine):
27 
28     /**
29         Gets the texture ID associated with the fbo
30     */
31     GLuint getTexId() {
32         return color;
33     }
34 
35 public:
36 
37     /**
38         The constructor
39     */
40     this(Window window, vec2i size) {
41         this.window = window;
42         this.size = size;
43         this.realsize = size*2;
44         
45         // Bind FBO
46         glGenFramebuffers(1, &fbo);
47         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
48 
49         // Enable blending, etc.
50         glEnable(GL_BLEND);
51         glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
52         glEnable(GL_CULL_FACE);
53         glEnable(GL_DEPTH_TEST);
54         glDepthFunc(GL_LESS);
55 
56         // Generate texture
57         glGenTextures(1, &color);
58         glBindTexture(GL_TEXTURE_2D, color);
59         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, realsize.x, realsize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
60         
61         // Set up texture parameters
62         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
63         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
64 
65         // Generate depth buffer
66         glGenRenderbuffers(1, &depth);
67         glBindRenderbuffer(GL_RENDERBUFFER, depth);
68         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, realsize.x, realsize.y);
69 
70         // Configure framebuffer
71         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
72         glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, color, 0);
73     }
74 
75     /**
76         Bind the framebuffer
77     */
78     void bind() {
79         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
80         kmViewport(0, 0, realsize.x, realsize.y);
81         kmSetCameraTargetSize(size.x, size.y);
82     }
83 
84     /**
85         Unbind the framebuffer
86     */
87     void unbind() {
88         glBindFramebuffer(GL_FRAMEBUFFER, 0);
89         kmViewport(0, 0, window.width, window.height);
90     }
91 
92     /**
93         Renders the framebuffer to fit in the current viewport
94     */
95     void renderToFit() {
96         double widthScale = cast(double)kmViewportWidth / cast(double)realWidth;
97         double heightScale = cast(double)kmViewportHeight / cast(double)realHeight;
98         double scale = min(widthScale, heightScale);
99 
100         vec4 bounds = vec4(
101             0,
102             0,
103             realWidth*scale,
104             realHeight*scale
105         );
106 
107         if (widthScale > heightScale) bounds.x = (kmViewportWidth-bounds.z)/2;
108         else if (heightScale > widthScale) bounds.y = (kmViewportHeight-bounds.w)/2;
109 
110         GameBatch.draw(this, bounds);
111     }
112 
113     /**
114         Width of framebuffer
115     */
116     int width() {
117         return size.x;
118     }
119 
120     /**
121         Height of framebuffer
122     */
123     int height() {
124         return size.y;
125     }
126 
127     /**
128         Real width of framebuffer
129     */
130     int realWidth() {
131         return realsize.x;
132     }
133 
134     /**
135         Real height of framebuffer
136     */
137     int realHeight() {
138         return realsize.y;
139     }
140 }