9 static void attach_depth_texture(Texture *tex);
11 #define MAX_STACK_SIZE 16
12 static RTStackItem rstack[MAX_STACK_SIZE];
15 void set_render_target(RenderTarget *rt)
18 if(!rstack[rtop].rt) {
19 glGetIntegerv(GL_VIEWPORT, rstack[rtop].saved_vp);
24 int *vp = rstack[rtop].saved_vp;
25 glViewport(vp[0], vp[1], vp[2], vp[3]);
26 glBindFramebuffer(GL_FRAMEBUFFER, 0);
32 RenderTarget *current_render_target()
34 return rstack[rtop].rt;
37 bool push_render_target(RenderTarget *rt)
40 error_log("push_render_target(0) is invalid\n");
43 if(rtop >= MAX_STACK_SIZE - 1) {
44 warning_log("push_render_target: overflow\n");
47 int *vp = rstack[rtop + 1].saved_vp;
48 RenderTarget *prev = current_render_target();
52 vp[2] = prev->get_width();
53 vp[3] = prev->get_height();
55 glGetIntegerv(GL_VIEWPORT, vp);
57 rstack[++rtop].rt = rt;
63 bool pop_render_target()
66 error_log("pop_render_target: undeflow\n");
70 int *vp = rstack[rtop].saved_vp;
71 glViewport(vp[0], vp[1], vp[2], vp[3]);
73 if(rstack[--rtop].rt) {
74 rstack[rtop].rt->bind();
76 glBindFramebuffer(GL_FRAMEBUFFER, 0);
81 RenderTarget::RenderTarget()
86 width = height = tex_width = tex_height = 0;
90 for(int i=0; i<4; i++) {
92 own_texture[i] = true;
97 RenderTarget::~RenderTarget()
102 bool RenderTarget::create(int xsz, int ysz, unsigned int fmt, unsigned int flags)
104 return create_mrt(xsz, ysz, 1, fmt, flags);
107 bool RenderTarget::create_mrt(int xsz, int ysz, int num, unsigned int fmt, unsigned int flags)
109 glGenFramebuffers(1, &fbo);
110 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
114 tex_width = next_pow2(xsz);
115 tex_height = next_pow2(ysz);
118 texmat.scaling((float)width / (float)tex_width, (float)height / (float)tex_height, 1);
120 if(flags & RT_COLOR) {
121 for(int i=0; i<num; i++) {
122 tex[i] = new Texture;
123 tex[i]->create(tex_width, tex_height, TEX_2D, fmt);
124 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D,
125 tex[i]->get_id(), 0);
126 glBindTexture(GL_TEXTURE_2D, 0);
127 own_texture[i] = true;
130 // in case set_texture was called before create
131 for(int i=0; i<num; i++) {
133 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D,
134 tex[i]->get_id(), 0);
139 if(flags & (RT_DEPTH | RT_STENCIL)) {
140 unsigned int attachment;
142 glGenRenderbuffers(1, &rbdepth);
143 glBindRenderbuffer(GL_RENDERBUFFER, rbdepth);
145 switch(flags & (RT_DEPTH | RT_STENCIL)) {
147 rbdepth_fmt = GL_DEPTH_COMPONENT24;
148 attachment = GL_DEPTH_ATTACHMENT;
152 rbdepth_fmt = GL_STENCIL_INDEX8;
153 attachment = GL_STENCIL_ATTACHMENT;
156 case RT_DEPTH | RT_STENCIL:
157 rbdepth_fmt = GL_DEPTH24_STENCIL8;
158 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
162 glRenderbufferStorage(GL_RENDERBUFFER, rbdepth_fmt, width, height);
163 glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, rbdepth);
164 glBindRenderbuffer(GL_RENDERBUFFER, 0);
167 attach_depth_texture(depth);
170 glBindFramebuffer(GL_FRAMEBUFFER, 0);
174 void RenderTarget::destroy()
176 for(int i=0; i<4; i++) {
177 if(tex[i] && own_texture[i]) {
183 glDeleteRenderbuffers(1, &rbdepth);
187 glDeleteFramebuffers(1, &fbo);
192 bool RenderTarget::resize(int xsz, int ysz)
194 int new_tx = next_pow2(xsz);
195 int new_ty = next_pow2(ysz);
197 if(new_tx != tex_width || new_ty != tex_height) {
201 for(int i=0; i<4; i++) {
203 tex[i]->create(new_tx, new_ty, TEX_2D, tex[i]->get_format());
208 depth->create(new_tx, new_ty, TEX_2D, depth->get_format());
213 glBindRenderbuffer(GL_RENDERBUFFER, rbdepth);
214 glRenderbufferStorage(GL_RENDERBUFFER, rbdepth_fmt, xsz, ysz);
222 int RenderTarget::get_width() const
227 int RenderTarget::get_height() const
232 void RenderTarget::set_texture(Texture *tex, int idx)
234 if(this->tex[idx] && own_texture[idx]) {
235 delete this->tex[idx];
237 this->tex[idx] = tex;
238 own_texture[idx] = false;
241 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
242 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + idx, GL_TEXTURE_2D,
244 glBindFramebuffer(GL_FRAMEBUFFER, 0);
248 void RenderTarget::set_depth_texture(Texture *tex)
253 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
254 attach_depth_texture(tex);
255 glBindFramebuffer(GL_FRAMEBUFFER, 0);
259 Texture *RenderTarget::texture(int idx) const
264 Texture *RenderTarget::depth_texture() const
269 void RenderTarget::set_auto_viewport(bool enable)
274 bool RenderTarget::auto_viewport() const
279 void RenderTarget::bind() const
281 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
284 glViewport(0, 0, width, height);
288 const Mat4 &RenderTarget::texture_matrix() const
293 static void attach_depth_texture(Texture *tex)
295 unsigned int fmt = tex->get_format();
296 unsigned int attachment = 0;
299 case GL_DEPTH_COMPONENT:
300 case GL_DEPTH_COMPONENT16:
301 case GL_DEPTH_COMPONENT24:
302 case GL_DEPTH_COMPONENT32:
303 attachment = GL_DEPTH_ATTACHMENT;
306 case GL_STENCIL_INDEX:
307 case GL_STENCIL_INDEX1:
308 case GL_STENCIL_INDEX4:
309 case GL_STENCIL_INDEX8:
310 attachment = GL_STENCIL_ATTACHMENT;
313 case GL_DEPTH_STENCIL:
314 case GL_DEPTH24_STENCIL8:
315 case GL_DEPTH32F_STENCIL8:
316 case GL_UNSIGNED_INT_24_8:
317 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
321 error_log("failed to attach depth/stencil texture: unexpected texture format: %x\n", fmt);
325 glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex->get_id(), 0);