goat3dgfx
diff src/rtarg.cc @ 0:1873dfd13f2d
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 14 Nov 2013 05:27:09 +0200 |
parents | |
children | 7d6b667821cf |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/rtarg.cc Thu Nov 14 05:27:09 2013 +0200 1.3 @@ -0,0 +1,259 @@ 1.4 +#include <stack> 1.5 +#include "rtarg.h" 1.6 +#include "texture.h" 1.7 +#include "logger.h" 1.8 + 1.9 +RenderTarget::RenderTarget() 1.10 +{ 1.11 + width = height = 0; 1.12 + fbo = 0; 1.13 + rbuf_zstencil = 0; 1.14 + color_tex = 0; 1.15 + tex_face = 0; 1.16 + tex_targ = 0; 1.17 +} 1.18 + 1.19 +RenderTarget::~RenderTarget() 1.20 +{ 1.21 + cleanup(); 1.22 +} 1.23 + 1.24 +bool RenderTarget::create(unsigned int fmt) 1.25 +{ 1.26 + int vp[4]; 1.27 + glGetIntegerv(GL_VIEWPORT, vp); 1.28 + 1.29 + return create(vp[2] - vp[0], vp[3] - vp[1], fmt); 1.30 +} 1.31 + 1.32 +bool RenderTarget::create(int width, int height, unsigned int fmt) 1.33 +{ 1.34 + debug_log("RenderTarget::create(%d, %d)\n", width, height); 1.35 + cleanup(); 1.36 + 1.37 + tex_targ = GL_TEXTURE_2D; 1.38 + this->width = width; 1.39 + this->height = height; 1.40 + int tex_width = next_pow2(width); 1.41 + int tex_height = next_pow2(height); 1.42 + 1.43 + CHECKGLERR; 1.44 + color_tex = new Texture2D; 1.45 + color_tex->create(tex_width, tex_height, fmt); 1.46 + CHECKGLERR; 1.47 + tex_face = 0; 1.48 + 1.49 + glGenFramebuffers(1, &fbo); 1.50 + glBindFramebuffer(GL_FRAMEBUFFER, fbo); 1.51 + 1.52 + glBindTexture(GL_TEXTURE_2D, color_tex->get_id()); 1.53 + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_tex->get_id(), 0); 1.54 + glBindTexture(GL_TEXTURE_2D, 0); 1.55 + 1.56 + glGenRenderbuffers(1, &rbuf_zstencil); 1.57 + glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zstencil); 1.58 + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, tex_width, tex_height); 1.59 + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil); 1.60 + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil); 1.61 + 1.62 + glBindFramebuffer(GL_FRAMEBUFFER, 0); 1.63 + CHECKGLERR; 1.64 + return true; 1.65 +} 1.66 + 1.67 +bool RenderTarget::create(Texture *tex, int face) 1.68 +{ 1.69 + debug_log("RenderTarget::create(tex{%d, %d}, face:%d)\n", tex->get_size(0), 1.70 + tex->get_size(1), face); 1.71 + 1.72 + tex_targ = GL_TEXTURE_2D; 1.73 + if(dynamic_cast<TextureCube*>(tex)) { 1.74 + if(face >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) { 1.75 + tex_targ = face; 1.76 + } else if(face >= 0 && face < 6) { 1.77 + tex_targ = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; 1.78 + } else { 1.79 + error_log("invalid face (%d) passed to RenderTarget::create(TextureCube*, int)\n", face); 1.80 + return false; 1.81 + } 1.82 + } 1.83 + 1.84 + cleanup(); 1.85 + 1.86 + width = tex->get_size(0); 1.87 + height = tex->get_size(1); 1.88 + 1.89 + color_tex = tex; 1.90 + 1.91 + glGenFramebuffers(1, &fbo); 1.92 + glBindFramebuffer(GL_FRAMEBUFFER, fbo); 1.93 + 1.94 + glBindTexture(tex_targ, color_tex->get_id()); 1.95 + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_targ, color_tex->get_id(), 0); 1.96 + glBindTexture(tex_targ, 0); 1.97 + 1.98 + glGenRenderbuffers(1, &rbuf_zstencil); 1.99 + glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zstencil); 1.100 + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); 1.101 + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil); 1.102 + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbuf_zstencil); 1.103 + 1.104 + glBindFramebuffer(GL_FRAMEBUFFER, 0); 1.105 + CHECKGLERR; 1.106 + return true; 1.107 +} 1.108 + 1.109 +void RenderTarget::cleanup() 1.110 +{ 1.111 + delete color_tex; 1.112 + color_tex = 0; 1.113 + 1.114 + if(fbo) { 1.115 + glDeleteFramebuffers(1, &fbo); 1.116 + } 1.117 + if(rbuf_zstencil) { 1.118 + glDeleteRenderbuffers(1, &rbuf_zstencil); 1.119 + } 1.120 + 1.121 + fbo = rbuf_zstencil = 0; 1.122 + width = height = 0; 1.123 + tex_face = 0; 1.124 + tex_targ = 0; 1.125 +} 1.126 + 1.127 +bool RenderTarget::resize(int width, int height) 1.128 +{ 1.129 + this->width = width; 1.130 + this->height = height; 1.131 + int tex_width = next_pow2(width); 1.132 + int tex_height = next_pow2(height); 1.133 + 1.134 + debug_log("resizing render target (fbo %u): %dx%d [%dx%d]\n", fbo, width, height, tex_width, tex_height); 1.135 + 1.136 + glBindFramebuffer(GL_FRAMEBUFFER, fbo); 1.137 + 1.138 + color_tex->create(tex_width, tex_height, color_tex->get_format()); 1.139 + color_tex->bind(); 1.140 + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex_targ, color_tex->get_id(), 0); 1.141 + glBindTexture(tex_targ, 0); 1.142 + 1.143 + glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zstencil); 1.144 + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, tex_width, tex_height); 1.145 + 1.146 + glBindFramebuffer(GL_FRAMEBUFFER, 0); 1.147 + return true; 1.148 +} 1.149 + 1.150 +int RenderTarget::get_width() const 1.151 +{ 1.152 + return width; 1.153 +} 1.154 + 1.155 +int RenderTarget::get_height() const 1.156 +{ 1.157 + return height; 1.158 +} 1.159 + 1.160 +Texture *RenderTarget::get_texture() const 1.161 +{ 1.162 + return color_tex; 1.163 +} 1.164 + 1.165 +Matrix4x4 RenderTarget::get_texture_matrix() const 1.166 +{ 1.167 + float sx = (float)width / (float)color_tex->get_size(0); 1.168 + float sy = (float)height / (float)color_tex->get_size(1); 1.169 + 1.170 + // counting on RVO to optimize this away 1.171 + return Matrix4x4(sx, 0, 0, 0, 1.172 + 0, sy, 0, 0, 1.173 + 0, 0, 1, 0, 1.174 + 0, 0, 0, 1); 1.175 +} 1.176 + 1.177 + 1.178 +static const char *fbstname[] = { 1.179 + "GL_FRAMEBUFFER_COMPLETE", 1.180 + "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT", 1.181 + "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT", 1.182 + "no such fbo error", 1.183 + "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS", 1.184 + "GL_FRAMEBUFFER_INCOMPLETE_FORMATS", 1.185 + "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER", 1.186 + "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER", 1.187 + "GL_FRAMEBUFFER_UNSUPPORTED" 1.188 +}; 1.189 + 1.190 +bool RenderTarget::check() const 1.191 +{ 1.192 + bool res = true; 1.193 + 1.194 +#ifndef GL_ES_VERSION_2_0 1.195 + int prev_fb = 0; 1.196 + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &prev_fb); 1.197 +#endif 1.198 + 1.199 + glBindFramebuffer(GL_FRAMEBUFFER, fbo); 1.200 + 1.201 + int status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 1.202 + if(status != GL_FRAMEBUFFER_COMPLETE) { 1.203 + error_log("RenderTarget::check: incomplete FBO %u: %s\n", fbo, 1.204 + fbstname[status - GL_FRAMEBUFFER_COMPLETE]); 1.205 + res = false; 1.206 + goto end; 1.207 + } 1.208 + 1.209 +end: 1.210 +#ifndef GL_ES_VERSION_2_0 1.211 + glBindFramebuffer(GL_FRAMEBUFFER, prev_fb); 1.212 +#endif 1.213 + return res; 1.214 +} 1.215 + 1.216 +void RenderTarget::bind() const 1.217 +{ 1.218 + glBindFramebuffer(GL_FRAMEBUFFER, fbo); 1.219 + 1.220 + glViewport(0, 0, width, height); 1.221 +} 1.222 + 1.223 +struct Viewport { int vp[4]; }; 1.224 +static std::stack<Viewport> vpstack; 1.225 + 1.226 +void set_render_target(const RenderTarget *rtarg) 1.227 +{ 1.228 + Viewport vp; 1.229 + 1.230 + if(rtarg) { 1.231 + glGetIntegerv(GL_VIEWPORT, vp.vp); 1.232 + vpstack.push(vp); 1.233 + 1.234 + rtarg->bind(); 1.235 + } else { 1.236 +#ifdef GL_ES_VERSION_2_0 1.237 + extern unsigned int default_fbo; 1.238 + glBindFramebuffer(GL_FRAMEBUFFER, default_fbo); 1.239 +#else 1.240 + glBindFramebuffer(GL_FRAMEBUFFER, 0); 1.241 +#endif 1.242 + 1.243 + if(vpstack.empty()) { 1.244 + return; 1.245 + } 1.246 + vp = vpstack.top(); 1.247 + vpstack.pop(); 1.248 + glViewport(vp.vp[0], vp.vp[1], vp.vp[2], vp.vp[3]); 1.249 + } 1.250 +} 1.251 + 1.252 +int next_pow2(int x) 1.253 +{ 1.254 + x--; 1.255 + x = (x >> 1) | x; 1.256 + x = (x >> 2) | x; 1.257 + x = (x >> 4) | x; 1.258 + x = (x >> 8) | x; 1.259 + x = (x >> 16) | x; 1.260 + return x + 1; 1.261 +} 1.262 +