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, unsigned int flags)
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");
48 if(!(flags & RT_NO_VPORT)) {
49 int *vp = rstack[rtop + 1].saved_vp;
50 glGetIntegerv(GL_VIEWPORT, vp);
52 rstack[++rtop].rt = rt;
54 if(!(flags & RT_NO_BIND)) {
60 bool pop_render_target(unsigned int flags)
63 error_log("pop_render_target: underflow\n");
67 if(!(flags & RT_NO_VPORT)) {
68 int *vp = rstack[rtop].saved_vp;
69 glViewport(vp[0], vp[1], vp[2], vp[3]);
74 if(!(flags & RT_NO_BIND)) {
76 rstack[rtop].rt->bind(RT_NO_VPORT);
78 glBindFramebuffer(GL_FRAMEBUFFER, 0);
84 RenderTarget::RenderTarget()
89 width = height = tex_width = tex_height = 0;
94 for(int i=0; i<4; i++) {
96 own_texture[i] = true;
101 RenderTarget::~RenderTarget()
106 bool RenderTarget::create(int xsz, int ysz, unsigned int fmt, unsigned int flags)
108 return create_mrt(xsz, ysz, 1, fmt, flags);
111 bool RenderTarget::create_mrt(int xsz, int ysz, int num, unsigned int fmt, unsigned int flags)
113 glGenFramebuffers(1, &fbo);
114 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
119 tex_width = next_pow2(xsz);
120 tex_height = next_pow2(ysz);
123 texmat.scaling((float)width / (float)tex_width, (float)height / (float)tex_height, 1);
125 if(flags & RT_COLOR) {
126 for(int i=0; i<num; i++) {
127 tex[i] = new Texture;
128 tex[i]->create(tex_width, tex_height, TEX_2D, fmt);
129 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D,
130 tex[i]->get_id(), 0);
131 glBindTexture(GL_TEXTURE_2D, 0);
132 own_texture[i] = true;
135 // in case set_texture was called before create
136 for(int i=0; i<num; i++) {
138 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D,
139 tex[i]->get_id(), 0);
144 if(flags & (RT_DEPTH | RT_STENCIL)) {
145 unsigned int attachment;
147 glGenRenderbuffers(1, &rbdepth);
148 glBindRenderbuffer(GL_RENDERBUFFER, rbdepth);
150 switch(flags & (RT_DEPTH | RT_STENCIL)) {
152 rbdepth_fmt = GL_DEPTH_COMPONENT24;
153 attachment = GL_DEPTH_ATTACHMENT;
157 rbdepth_fmt = GL_STENCIL_INDEX8;
158 attachment = GL_STENCIL_ATTACHMENT;
161 case RT_DEPTH | RT_STENCIL:
162 rbdepth_fmt = GL_DEPTH24_STENCIL8;
163 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
167 glRenderbufferStorage(GL_RENDERBUFFER, rbdepth_fmt, width, height);
168 glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, rbdepth);
169 glBindRenderbuffer(GL_RENDERBUFFER, 0);
172 attach_depth_texture(depth);
175 glBindFramebuffer(GL_FRAMEBUFFER, 0);
179 bool RenderTarget::create_wrap_fbo(unsigned int fbo, int xsz, int ysz)
184 width = tex_width = xsz;
185 height = tex_height = ysz;
188 texmat = Mat4::identity;
193 void RenderTarget::destroy()
195 for(int i=0; i<4; i++) {
196 if(tex[i] && own_texture[i]) {
202 glDeleteRenderbuffers(1, &rbdepth);
206 glDeleteFramebuffers(1, &fbo);
211 bool RenderTarget::resize(int xsz, int ysz)
213 if(!own_fbo) return false; /* TODO */
215 int new_tx = next_pow2(xsz);
216 int new_ty = next_pow2(ysz);
218 if(new_tx != tex_width || new_ty != tex_height) {
222 for(int i=0; i<4; i++) {
224 tex[i]->create(new_tx, new_ty, TEX_2D, tex[i]->get_format());
229 depth->create(new_tx, new_ty, TEX_2D, depth->get_format());
234 glBindRenderbuffer(GL_RENDERBUFFER, rbdepth);
235 glRenderbufferStorage(GL_RENDERBUFFER, rbdepth_fmt, xsz, ysz);
243 int RenderTarget::get_width() const
248 int RenderTarget::get_height() const
253 void RenderTarget::set_texture(Texture *tex, int idx)
255 if(this->tex[idx] && own_texture[idx]) {
256 delete this->tex[idx];
258 this->tex[idx] = tex;
259 own_texture[idx] = false;
262 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
263 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + idx, GL_TEXTURE_2D,
265 glBindFramebuffer(GL_FRAMEBUFFER, 0);
269 void RenderTarget::set_depth_texture(Texture *tex)
274 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
275 attach_depth_texture(tex);
276 glBindFramebuffer(GL_FRAMEBUFFER, 0);
280 Texture *RenderTarget::texture(int idx) const
285 Texture *RenderTarget::depth_texture() const
290 void RenderTarget::set_auto_viewport(bool enable)
295 bool RenderTarget::auto_viewport() const
300 void RenderTarget::bind(unsigned int flags) const
302 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
304 if(auto_vport && !(flags & RT_NO_VPORT)) {
305 glViewport(0, 0, width, height);
309 const Mat4 &RenderTarget::texture_matrix() const
314 static void attach_depth_texture(Texture *tex)
316 unsigned int fmt = tex->get_format();
317 unsigned int attachment = 0;
320 case GL_DEPTH_COMPONENT:
321 case GL_DEPTH_COMPONENT16:
322 case GL_DEPTH_COMPONENT24:
323 case GL_DEPTH_COMPONENT32:
324 attachment = GL_DEPTH_ATTACHMENT;
327 case GL_STENCIL_INDEX:
328 case GL_STENCIL_INDEX1:
329 case GL_STENCIL_INDEX4:
330 case GL_STENCIL_INDEX8:
331 attachment = GL_STENCIL_ATTACHMENT;
334 case GL_DEPTH_STENCIL:
335 case GL_DEPTH24_STENCIL8:
336 case GL_DEPTH32F_STENCIL8:
337 case GL_UNSIGNED_INT_24_8:
338 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
342 error_log("failed to attach depth/stencil texture: unexpected texture format: %x\n", fmt);
346 glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex->get_id(), 0);