goat3dgfx

view src/rtarg.cc @ 34:3eb6c8f89fe1

merge
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 02 Mar 2014 17:41:10 +0200
parents dc5918c62a64
children
line source
1 #include <stack>
2 #include "rtarg.h"
3 #include "texture.h"
4 #include "logger.h"
6 using namespace goatgfx;
8 RenderTarget::RenderTarget()
9 {
10 width = height = 0;
11 fbo = 0;
12 rbuf_zstencil = 0;
13 color_tex = 0;
14 tex_face = 0;
15 tex_targ = 0;
16 }
18 RenderTarget::~RenderTarget()
19 {
20 cleanup();
21 }
23 bool RenderTarget::create(unsigned int fmt)
24 {
25 int vp[4];
26 glGetIntegerv(GL_VIEWPORT, vp);
28 return create(vp[2] - vp[0], vp[3] - vp[1], fmt);
29 }
31 bool RenderTarget::create(int width, int height, unsigned int fmt)
32 {
33 debug_log("RenderTarget::create(%d, %d)\n", width, height);
34 cleanup();
36 tex_targ = GL_TEXTURE_2D;
37 this->width = width;
38 this->height = height;
39 int tex_width = next_pow2(width);
40 int tex_height = next_pow2(height);
42 CHECKGLERR;
43 color_tex = new Texture;
44 color_tex->create(tex_width, tex_height, TEX_2D, fmt);
45 CHECKGLERR;
46 tex_face = 0;
48 glGenFramebuffers(1, &fbo);
49 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
51 glBindTexture(GL_TEXTURE_2D, color_tex->get_id());
52 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_tex->get_id(), 0);
53 glBindTexture(GL_TEXTURE_2D, 0);
55 glGenRenderbuffers(1, &rbuf_zstencil);
56 glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zstencil);
57 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, tex_width, tex_height);
58 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil);
59 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil);
61 glBindFramebuffer(GL_FRAMEBUFFER, 0);
62 CHECKGLERR;
63 return true;
64 }
66 bool RenderTarget::create(Texture *tex, int face)
67 {
68 debug_log("RenderTarget::create(tex{%d, %d}, face:%d)\n", tex->get_size(0),
69 tex->get_size(1), face);
71 tex_targ = GL_TEXTURE_2D;
72 if(tex->get_type() == TEX_CUBE) {
73 if(face >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) {
74 tex_targ = face;
75 } else if(face >= 0 && face < 6) {
76 tex_targ = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
77 } else {
78 error_log("invalid face (%d) passed to RenderTarget::create(TextureCube*, int)\n", face);
79 return false;
80 }
81 }
83 cleanup();
85 width = tex->get_size(0);
86 height = tex->get_size(1);
88 color_tex = tex;
90 glGenFramebuffers(1, &fbo);
91 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
93 glBindTexture(tex_targ, color_tex->get_id());
94 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_targ, color_tex->get_id(), 0);
95 glBindTexture(tex_targ, 0);
97 glGenRenderbuffers(1, &rbuf_zstencil);
98 glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zstencil);
99 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
100 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil);
101 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil);
103 glBindFramebuffer(GL_FRAMEBUFFER, 0);
104 CHECKGLERR;
105 return true;
106 }
108 void RenderTarget::cleanup()
109 {
110 delete color_tex;
111 color_tex = 0;
113 if(fbo) {
114 glDeleteFramebuffers(1, &fbo);
115 }
116 if(rbuf_zstencil) {
117 glDeleteRenderbuffers(1, &rbuf_zstencil);
118 }
120 fbo = rbuf_zstencil = 0;
121 width = height = 0;
122 tex_face = 0;
123 tex_targ = 0;
124 }
126 bool RenderTarget::resize(int width, int height)
127 {
128 this->width = width;
129 this->height = height;
130 int tex_width = next_pow2(width);
131 int tex_height = next_pow2(height);
133 debug_log("resizing render target (fbo %u): %dx%d [%dx%d]\n", fbo, width, height, tex_width, tex_height);
135 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
137 color_tex->create(tex_width, tex_height, TEX_2D, color_tex->get_format());
138 color_tex->bind();
139 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_targ, color_tex->get_id(), 0);
140 glBindTexture(tex_targ, 0);
142 glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zstencil);
143 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, tex_width, tex_height);
145 glBindFramebuffer(GL_FRAMEBUFFER, 0);
146 return true;
147 }
149 int RenderTarget::get_width() const
150 {
151 return width;
152 }
154 int RenderTarget::get_height() const
155 {
156 return height;
157 }
159 Texture *RenderTarget::get_texture() const
160 {
161 return color_tex;
162 }
164 Matrix4x4 RenderTarget::get_texture_matrix() const
165 {
166 float sx = (float)width / (float)color_tex->get_size(0);
167 float sy = (float)height / (float)color_tex->get_size(1);
169 // counting on RVO to optimize this away
170 return Matrix4x4(sx, 0, 0, 0,
171 0, sy, 0, 0,
172 0, 0, 1, 0,
173 0, 0, 0, 1);
174 }
177 static const char *fbstname[] = {
178 "GL_FRAMEBUFFER_COMPLETE",
179 "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
180 "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT",
181 "no such fbo error",
182 "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS",
183 "GL_FRAMEBUFFER_INCOMPLETE_FORMATS",
184 "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER",
185 "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER",
186 "GL_FRAMEBUFFER_UNSUPPORTED"
187 };
189 bool RenderTarget::check() const
190 {
191 bool res = true;
193 #ifndef GL_ES_VERSION_2_0
194 int prev_fb = 0;
195 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &prev_fb);
196 #endif
198 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
200 int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
201 if(status != GL_FRAMEBUFFER_COMPLETE) {
202 error_log("RenderTarget::check: incomplete FBO %u: %s\n", fbo,
203 fbstname[status - GL_FRAMEBUFFER_COMPLETE]);
204 res = false;
205 goto end;
206 }
208 end:
209 #ifndef GL_ES_VERSION_2_0
210 glBindFramebuffer(GL_FRAMEBUFFER, prev_fb);
211 #endif
212 return res;
213 }
215 void RenderTarget::bind() const
216 {
217 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
219 glViewport(0, 0, width, height);
220 }
222 struct Viewport { int vp[4]; };
223 static std::stack<Viewport> vpstack;
225 namespace goatgfx {
227 void set_render_target(const RenderTarget *rtarg)
228 {
229 Viewport vp;
231 if(rtarg) {
232 glGetIntegerv(GL_VIEWPORT, vp.vp);
233 vpstack.push(vp);
235 rtarg->bind();
236 } else {
237 #ifdef GL_ES_VERSION_2_0
238 extern unsigned int default_fbo;
239 glBindFramebuffer(GL_FRAMEBUFFER, default_fbo);
240 #else
241 glBindFramebuffer(GL_FRAMEBUFFER, 0);
242 #endif
244 if(vpstack.empty()) {
245 return;
246 }
247 vp = vpstack.top();
248 vpstack.pop();
249 glViewport(vp.vp[0], vp.vp[1], vp.vp[2], vp.vp[3]);
250 }
251 }
253 int next_pow2(int x)
254 {
255 x--;
256 x = (x >> 1) | x;
257 x = (x >> 2) | x;
258 x = (x >> 4) | x;
259 x = (x >> 8) | x;
260 x = (x >> 16) | x;
261 return x + 1;
262 }
264 } // namespace goatgfx