00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "TGLFBO.h"
00013 #include <TMath.h>
00014 #include <TString.h>
00015 #include <TError.h>
00016
00017 #include <GL/glew.h>
00018
00019 #include <stdexcept>
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 ClassImp(TGLFBO);
00033
00034 Bool_t TGLFBO::fgRescaleToPow2 = kTRUE;
00035 Bool_t TGLFBO::fgMultiSampleNAWarned = kFALSE;
00036
00037 TGLFBO::TGLFBO() :
00038 fFrameBuffer (0),
00039 fColorTexture (0),
00040 fDepthBuffer (0),
00041 fMSFrameBuffer(0),
00042 fMSColorBuffer(0),
00043 fW (-1),
00044 fH (-1),
00045 fMSSamples (0),
00046 fMSCoverageSamples (0),
00047 fWScale (1),
00048 fHScale (1),
00049 fIsRescaled (kFALSE)
00050 {
00051
00052 }
00053
00054
00055 TGLFBO::~TGLFBO()
00056 {
00057
00058
00059 Release();
00060 }
00061
00062
00063 void TGLFBO::Init(int w, int h, int ms_samples)
00064 {
00065
00066
00067
00068 static const std::string eh("TGLFBO::Init ");
00069
00070
00071 if (!GLEW_EXT_framebuffer_object)
00072 {
00073 throw std::runtime_error(eh + "GL_EXT_framebuffer_object extension required for FBO.");
00074 }
00075
00076 fIsRescaled = kFALSE;
00077 if (fgRescaleToPow2)
00078 {
00079 Int_t nw = 1 << TMath::CeilNint(TMath::Log2(w));
00080 Int_t nh = 1 << TMath::CeilNint(TMath::Log2(h));
00081 if (nw != w || nh != h)
00082 {
00083 fWScale = ((Float_t)w) / nw;
00084 fHScale = ((Float_t)h) / nh;
00085 w = nw; h = nh;
00086 fIsRescaled = kTRUE;
00087 }
00088 }
00089
00090 if (ms_samples > 0 && ! GLEW_EXT_framebuffer_multisample)
00091 {
00092 if (!fgMultiSampleNAWarned)
00093 {
00094 Info(eh.c_str(), "GL implementation does not support multi-sampling for FBOs.");
00095 fgMultiSampleNAWarned = kTRUE;
00096 }
00097 ms_samples = 0;
00098 }
00099
00100 if (fFrameBuffer != 0)
00101 {
00102 if (fW == w && fH == h && fMSSamples == ms_samples)
00103 return;
00104 Release();
00105 }
00106
00107 Int_t maxSize;
00108 glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &maxSize);
00109 if (w > maxSize || h > maxSize)
00110 {
00111 throw std::runtime_error(eh + Form("maximum size supported by GL implementation is %d.", maxSize));
00112 }
00113
00114 fW = w; fH = h; fMSSamples = ms_samples;
00115
00116 if (fMSSamples > 0)
00117 {
00118 if (GLEW_NV_framebuffer_multisample_coverage)
00119 {
00120 GLint n_modes;
00121 glGetIntegerv(GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV, &n_modes);
00122 GLint *modes = new GLint[2*n_modes];
00123 glGetIntegerv(GL_MULTISAMPLE_COVERAGE_MODES_NV, modes);
00124
00125 for (int i = 0; i < n_modes; ++i)
00126 {
00127 if (modes[i*2+1] == fMSSamples && modes[i*2] > fMSCoverageSamples)
00128 fMSCoverageSamples = modes[i*2];
00129 }
00130
00131 delete [] modes;
00132 }
00133 Info(eh.c_str(), "InitMultiSample coverage_samples=%d, color_samples=%d.", fMSCoverageSamples, fMSSamples);
00134 InitMultiSample();
00135 }
00136 else
00137 {
00138 printf("TGLFBO::Init InitStandard ...\n");
00139 InitStandard();
00140 }
00141
00142 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
00143
00144 glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
00145 glBindTexture (GL_TEXTURE_2D, 0);
00146
00147 switch (status)
00148 {
00149 case GL_FRAMEBUFFER_COMPLETE_EXT:
00150 if (gDebug > 0)
00151 printf("%sConstructed TGLFBO ... all fine.\n", eh.c_str());
00152 break;
00153 case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
00154 Release();
00155 throw std::runtime_error(eh + "Constructed TGLFBO not supported, choose different formats.");
00156 break;
00157 default:
00158 Release();
00159 throw std::runtime_error(eh + "Constructed TGLFBO is not complete, unexpected error.");
00160 break;
00161 }
00162 }
00163
00164
00165 void TGLFBO::Release()
00166 {
00167
00168
00169 glDeleteFramebuffersEXT (1, &fFrameBuffer);
00170 glDeleteRenderbuffersEXT(1, &fDepthBuffer);
00171
00172 if (fMSFrameBuffer) glDeleteFramebuffersEXT (1, &fMSFrameBuffer);
00173 if (fMSColorBuffer) glDeleteRenderbuffersEXT(1, &fMSColorBuffer);
00174 if (fColorTexture) glDeleteTextures (1, &fColorTexture);
00175
00176 fW = fH = -1; fMSSamples = fMSCoverageSamples = 0;
00177 fFrameBuffer = fColorTexture = fDepthBuffer = fMSFrameBuffer = fMSColorBuffer = 0;
00178
00179 }
00180
00181
00182 void TGLFBO::Bind()
00183 {
00184
00185
00186 if (fMSSamples > 0) {
00187 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fMSFrameBuffer);
00188
00189
00190
00191
00192
00193 } else {
00194 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fFrameBuffer);
00195 }
00196 }
00197
00198
00199 void TGLFBO::Unbind()
00200 {
00201
00202
00203 if (fMSSamples > 0)
00204 {
00205 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fMSFrameBuffer);
00206 glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fFrameBuffer);
00207 glBlitFramebufferEXT(0, 0, fW, fH, 0, 0, fW, fH, GL_COLOR_BUFFER_BIT, GL_NEAREST);
00208 }
00209
00210 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
00211 }
00212
00213
00214 void TGLFBO::BindTexture()
00215 {
00216
00217
00218 glPushAttrib(GL_TEXTURE_BIT);
00219 glBindTexture(GL_TEXTURE_2D, fColorTexture);
00220 glEnable(GL_TEXTURE_2D);
00221
00222 if (fIsRescaled)
00223 {
00224 glMatrixMode(GL_TEXTURE);
00225 glPushMatrix();
00226 glScalef(fWScale, fHScale, 1);
00227 glMatrixMode(GL_MODELVIEW);
00228 }
00229 }
00230
00231
00232 void TGLFBO::UnbindTexture()
00233 {
00234
00235
00236 if (fIsRescaled)
00237 {
00238 glMatrixMode(GL_TEXTURE);
00239 glPopMatrix();
00240 glMatrixMode(GL_MODELVIEW);
00241 }
00242
00243 glPopAttrib();
00244 }
00245
00246
00247 void TGLFBO::SetAsReadBuffer()
00248 {
00249 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fFrameBuffer);
00250 }
00251
00252
00253
00254
00255 void TGLFBO::InitStandard()
00256 {
00257 glGenFramebuffersEXT(1, &fFrameBuffer);
00258 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fFrameBuffer);
00259
00260 fDepthBuffer = CreateAndAttachRenderBuffer(GL_DEPTH_COMPONENT24, GL_DEPTH_ATTACHMENT);
00261 fColorTexture = CreateAndAttachColorTexture();
00262 }
00263
00264
00265 void TGLFBO::InitMultiSample()
00266 {
00267 glGenFramebuffersEXT(1, &fMSFrameBuffer);
00268 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fMSFrameBuffer);
00269
00270 fMSColorBuffer = CreateAndAttachRenderBuffer(GL_RGBA8, GL_COLOR_ATTACHMENT0);
00271 fDepthBuffer = CreateAndAttachRenderBuffer(GL_DEPTH_COMPONENT24, GL_DEPTH_ATTACHMENT);
00272
00273
00274 glGenFramebuffersEXT(1, &fFrameBuffer);
00275 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fFrameBuffer);
00276
00277 fColorTexture = CreateAndAttachColorTexture();
00278 }
00279
00280
00281 UInt_t TGLFBO::CreateAndAttachRenderBuffer(Int_t format, Int_t type)
00282 {
00283 UInt_t id = 0;
00284
00285 glGenRenderbuffersEXT(1, &id);
00286 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, id);
00287
00288 if (fMSSamples > 0)
00289 {
00290 if (fMSCoverageSamples > 0)
00291 glRenderbufferStorageMultisampleCoverageNV(GL_RENDERBUFFER_EXT, fMSCoverageSamples, fMSSamples, format, fW, fH);
00292 else
00293 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, fMSSamples, format, fW, fH);
00294 }
00295 else
00296 {
00297 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, format, fW, fH);
00298 }
00299
00300 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, type, GL_RENDERBUFFER_EXT, id);
00301
00302 return id;
00303 }
00304
00305
00306 UInt_t TGLFBO::CreateAndAttachColorTexture()
00307 {
00308
00309
00310 UInt_t id = 0;
00311
00312 glGenTextures(1, &id);
00313
00314 glBindTexture(GL_TEXTURE_2D, id);
00315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00316 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00317 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00318 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00319 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, fW, fH, 0, GL_RGBA,
00320 GL_UNSIGNED_BYTE, NULL);
00321
00322 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
00323 GL_TEXTURE_2D, id, 0);
00324
00325 return id;
00326 }