goat3dgfx

annotate src/rtarg.cc @ 31:3ba80928b530

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