8 static void attach_depth_texture(Texture *tex);
10 #define MAX_STACK_SIZE 16
11 static RTStackItem rstack[MAX_STACK_SIZE];
14 void set_render_target(RenderTarget *rt)
17 if(!rstack[rtop].rt) {
18 glGetIntegerv(GL_VIEWPORT, rstack[rtop].saved_vp);
23 int *vp = rstack[rtop].saved_vp;
24 glViewport(vp[0], vp[1], vp[2], vp[3]);
25 glBindFramebuffer(GL_FRAMEBUFFER, 0);
31 RenderTarget *current_render_target()
33 return rstack[rtop].rt;
36 bool push_render_target(RenderTarget *rt)
39 error_log("push_render_target(0) is invalid\n");
42 if(rtop >= MAX_STACK_SIZE - 1) {
43 warning_log("push_render_target: overflow\n");
46 int *vp = rstack[rtop + 1].saved_vp;
47 RenderTarget *prev = current_render_target();
51 vp[2] = prev->get_width();
52 vp[3] = prev->get_height();
54 memcpy(vp, rstack[rtop].saved_vp, 4 * sizeof(int));
56 rstack[++rtop].rt = rt;
60 bool pop_render_target()
63 error_log("pop_render_target: undeflow\n");
67 int *vp = rstack[rtop].saved_vp;
68 glViewport(vp[0], vp[1], vp[2], vp[3]);
70 if(rstack[--rtop].rt) {
71 rstack[rtop].rt->bind();
73 glBindFramebuffer(GL_FRAMEBUFFER, 0);
78 RenderTarget::RenderTarget()
82 width = height = tex_width = tex_height = 0;
86 for(int i=0; i<4; i++) {
88 own_texture[i] = true;
92 RenderTarget::~RenderTarget()
97 bool RenderTarget::create(int xsz, int ysz, unsigned int fmt, unsigned int flags)
99 return create_mrt(xsz, ysz, 1, fmt, flags);
102 bool RenderTarget::create_mrt(int xsz, int ysz, int num, unsigned int fmt, unsigned int flags)
104 glGenFramebuffers(1, &fbo);
105 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
109 tex_width = next_pow2(xsz);
110 tex_height = next_pow2(ysz);
113 texmat.scaling((float)width / (float)tex_width, (float)height / (float)tex_height, 1);
115 if(flags & RT_COLOR) {
116 for(int i=0; i<num; i++) {
117 tex[i] = new Texture;
118 tex[i]->create(tex_width, tex_height, TEX_2D, fmt);
119 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D,
120 tex[i]->get_id(), 0);
121 own_texture[i] = true;
124 // in case set_texture was called before create
125 for(int i=0; i<num; i++) {
127 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D,
128 tex[i]->get_id(), 0);
133 if(flags & (RT_DEPTH | RT_STENCIL)) {
134 unsigned int fmt, attachment;
136 glGenRenderbuffers(1, &rbdepth);
137 glBindRenderbuffer(GL_RENDERBUFFER, rbdepth);
139 switch(flags & (RT_DEPTH | RT_STENCIL)) {
141 fmt = GL_DEPTH_COMPONENT24;
142 attachment = GL_DEPTH_ATTACHMENT;
146 fmt = GL_STENCIL_INDEX8;
147 attachment = GL_STENCIL_ATTACHMENT;
150 case RT_DEPTH | RT_STENCIL:
151 fmt = GL_DEPTH24_STENCIL8;
152 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
156 glRenderbufferStorage(GL_RENDERBUFFER, fmt, width, height);
157 glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, rbdepth);
160 attach_depth_texture(depth);
163 glBindFramebuffer(GL_FRAMEBUFFER, 0);
167 void RenderTarget::destroy()
169 for(int i=0; i<4; i++) {
170 if(tex[i] && own_texture[i]) {
176 glDeleteRenderbuffers(1, &rbdepth);
180 glDeleteFramebuffers(1, &fbo);
185 int RenderTarget::get_width() const
190 int RenderTarget::get_height() const
195 void RenderTarget::set_texture(Texture *tex, int idx)
197 if(this->tex[idx] && own_texture[idx]) {
198 delete this->tex[idx];
200 this->tex[idx] = tex;
201 own_texture[idx] = false;
204 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
205 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + idx, GL_TEXTURE_2D,
207 glBindFramebuffer(GL_FRAMEBUFFER, 0);
211 void RenderTarget::set_depth_texture(Texture *tex)
216 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
217 attach_depth_texture(tex);
218 glBindFramebuffer(GL_FRAMEBUFFER, 0);
222 Texture *RenderTarget::texture(int idx) const
227 Texture *RenderTarget::depth_texture() const
232 void RenderTarget::set_auto_viewport(bool enable)
237 bool RenderTarget::auto_viewport() const
242 void RenderTarget::bind() const
244 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
247 glViewport(0, 0, width, height);
251 const Mat4 &RenderTarget::texture_matrix() const
256 static void attach_depth_texture(Texture *tex)
258 unsigned int fmt = tex->get_format();
259 unsigned int attachment = 0;
262 case GL_DEPTH_COMPONENT:
263 case GL_DEPTH_COMPONENT16:
264 case GL_DEPTH_COMPONENT24:
265 case GL_DEPTH_COMPONENT32:
266 attachment = GL_DEPTH_ATTACHMENT;
269 case GL_STENCIL_INDEX:
270 case GL_STENCIL_INDEX1:
271 case GL_STENCIL_INDEX4:
272 case GL_STENCIL_INDEX8:
273 attachment = GL_STENCIL_ATTACHMENT;
276 case GL_DEPTH_STENCIL:
277 case GL_DEPTH24_STENCIL8:
278 case GL_DEPTH32F_STENCIL8:
279 case GL_UNSIGNED_INT_24_8:
280 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
284 error_log("failed to attach depth/stencil texture: unexpected texture format: %x\n", fmt);
288 glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, tex->get_id(), 0);