framework2
1236 строк · 39.5 Кб
1#include "ofFbo.h"
2#include "ofAppRunner.h"
3#include "ofUtils.h"
4#include "ofGraphics.h"
5#include "ofGLRenderer.h"
6#include "ofConstants.h"
7#include <unordered_map>
8
9#ifdef TARGET_OPENGLES
10#include <dlfcn.h>
11#endif
12#ifdef TARGET_ANDROID
13#include "ofxAndroidUtils.h"
14#endif
15
16using std::unordered_map;
17using std::vector;
18
19/*
20
21See
22http://www.gandogames.com/2010/07/tutorial-using-anti-aliasing-msaa-in-the-iphone/
23and
24http://stackoverflow.com/questions/3340189/how-do-you-activate-multisampling-in-opengl-es-on-the-iphone
25for multisampling on iphone
26
27*/
28
29#if defined(TARGET_OPENGLES) & !defined(TARGET_EMSCRIPTEN)
30bool ofFbo::bglFunctionsInitialized=false;
31
32typedef void (* glGenFramebuffersType) (GLsizei n, GLuint* framebuffers);
33glGenFramebuffersType glGenFramebuffersFunc;
34#define glGenFramebuffers glGenFramebuffersFunc
35
36typedef void (* glDeleteFramebuffersType) (GLsizei n, const GLuint* framebuffers);
37glDeleteFramebuffersType glDeleteFramebuffersFunc;
38#define glDeleteFramebuffers glDeleteFramebuffersFunc
39
40typedef void (* glDeleteRenderbuffersType) (GLsizei n, const GLuint* renderbuffers);
41glDeleteRenderbuffersType glDeleteRenderbuffersFunc;
42#define glDeleteRenderbuffers glDeleteRenderbuffersFunc
43
44typedef void (* glBindFramebufferType) (GLenum target, GLuint framebuffer);
45glBindFramebufferType glBindFramebufferFunc;
46#define glBindFramebuffer glBindFramebufferFunc
47
48typedef void (* glBindRenderbufferType) (GLenum target, GLuint renderbuffer);
49glBindRenderbufferType glBindRenderbufferFunc;
50#define glBindRenderbuffer glBindRenderbufferFunc
51
52typedef void (* glRenderbufferStorageType) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
53glRenderbufferStorageType glRenderbufferStorageFunc;
54#define glRenderbufferStorage glRenderbufferStorageFunc
55
56typedef void (* glFramebufferRenderbufferType) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
57glFramebufferRenderbufferType glFramebufferRenderbufferFunc;
58#define glFramebufferRenderbuffer glFramebufferRenderbufferFunc
59
60typedef void (* glRenderbufferStorageMultisampleType) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
61glRenderbufferStorageMultisampleType glRenderbufferStorageMultisampleFunc;
62#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleFunc
63
64typedef void (* glFramebufferTexture2DType) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
65glFramebufferTexture2DType glFramebufferTexture2DFunc;
66#define glFramebufferTexture2D glFramebufferTexture2DFunc
67
68typedef GLenum (* glCheckFramebufferStatusType) (GLenum target);
69glCheckFramebufferStatusType glCheckFramebufferStatusFunc;
70#define glCheckFramebufferStatus glCheckFramebufferStatusFunc
71#endif
72
73
74
75//-------------------------------------------------------------------------------------
76ofFboSettings::ofFboSettings(std::shared_ptr<ofBaseGLRenderer> renderer) {
77width = 0;
78height = 0;
79numColorbuffers = 1;
80useDepth = false;
81useStencil = false;
82depthStencilAsTexture = false;
83#ifndef TARGET_OPENGLES
84textureTarget = ofGetUsingArbTex() ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D;
85#else
86textureTarget = GL_TEXTURE_2D;
87#endif
88internalformat = GL_RGBA;
89depthStencilInternalFormat = GL_DEPTH_COMPONENT24;
90wrapModeHorizontal = GL_CLAMP_TO_EDGE;
91wrapModeVertical = GL_CLAMP_TO_EDGE;
92minFilter = GL_LINEAR;
93maxFilter = GL_LINEAR;
94numSamples = 0;
95this->renderer = renderer;
96}
97
98//--------------------------------------------------------------
99bool ofFboSettings::operator!=(const ofFboSettings & other){
100if(width != other.width){
101ofLogError() << "settings width differs from source";
102return true;
103}
104if(height != other.height){
105ofLogError() << "settings height differs from source";
106return true;
107}
108if(numColorbuffers != other.numColorbuffers){
109ofLogError() << "settings numColorbuffers differs from source";
110return true;
111}
112if(colorFormats != other.colorFormats){
113ofLogError() << "settings colorFormats differs from source";
114return true;
115}
116if(useDepth != other.useDepth){
117ofLogError() << "settings useDepth differs from source";
118return true;
119}
120if(useStencil != other.useStencil){
121ofLogError() << "settings useStencil differs from source";
122return true;
123}
124if(depthStencilAsTexture != other.depthStencilAsTexture){
125ofLogError() << "settings depthStencilAsTexture differs from source";
126return true;
127}
128if(textureTarget != other.textureTarget){
129ofLogError() << "settings textureTarget differs from source";
130return true;
131}
132if(internalformat != other.internalformat){
133ofLogError() << "settings internalformat differs from source";
134return true;
135}
136if(depthStencilInternalFormat != other.depthStencilInternalFormat){
137ofLogError() << "settings depthStencilInternalFormat differs from source";
138return true;
139}
140if(wrapModeHorizontal != other.wrapModeHorizontal){
141ofLogError() << "settings wrapModeHorizontal differs from source";
142return true;
143}
144if(wrapModeVertical != other.wrapModeVertical){
145ofLogError() << "settings wrapModeVertical differs from source";
146return true;
147}
148if(minFilter != other.minFilter){
149ofLogError() << "settings minFilter differs from source";
150return true;
151}
152if(maxFilter != other.maxFilter){
153ofLogError() << "settings maxFilter differs from source";
154return false;
155}
156if(numSamples != other.numSamples){
157ofLogError() << "settings numSamples differs from source";
158return true;
159}
160if(renderer.lock() != other.renderer.lock()){
161ofLogError() << "settings renderers are different";
162return true;
163}
164return false;
165}
166
167//--------------------------------------------------------------
168static unordered_map<GLuint,int> & getIdsFB(){
169static unordered_map<GLuint,int> * idsFB = new unordered_map<GLuint,int>;
170return *idsFB;
171}
172
173//--------------------------------------------------------------
174static void retainFB(GLuint id){
175if(id==0) return;
176if(getIdsFB().find(id)!=getIdsFB().end()){
177getIdsFB()[id]++;
178}else{
179getIdsFB()[id]=1;
180}
181}
182
183//--------------------------------------------------------------
184static void releaseFB(GLuint id){
185if(getIdsFB().find(id)!=getIdsFB().end()){
186getIdsFB()[id]--;
187if(getIdsFB()[id]==0){
188glDeleteFramebuffers(1, &id);
189}
190}else{
191ofLogWarning("ofFbo") << "releaseFB(): something's wrong here, releasing unknown frame buffer id " << id;
192glDeleteFramebuffers(1, &id);
193}
194}
195
196//--------------------------------------------------------------
197static unordered_map<GLuint,int> & getIdsRB(){
198static unordered_map<GLuint,int> * idsRB = new unordered_map<GLuint,int>;
199return *idsRB;
200}
201
202//--------------------------------------------------------------
203static void retainRB(GLuint id){
204if(id==0) return;
205if(getIdsRB().find(id)!=getIdsRB().end()){
206getIdsRB()[id]++;
207}else{
208getIdsRB()[id]=1;
209}
210}
211
212//--------------------------------------------------------------
213static void releaseRB(GLuint id){
214if(getIdsRB().find(id)!=getIdsRB().end()){
215getIdsRB()[id]--;
216if(getIdsRB()[id]==0){
217glDeleteRenderbuffers(1, &id);
218}
219}else{
220ofLogWarning("ofFbo") << "releaseRB(): something's wrong here, releasing unknown render buffer id " << id;
221glDeleteRenderbuffers(1, &id);
222}
223}
224
225//-------------------------------------------------------------------------------------
226int ofFbo::_maxColorAttachments = -1;
227int ofFbo::_maxDrawBuffers = -1;
228int ofFbo::_maxSamples = -1;
229
230
231//--------------------------------------------------------------
232ofFbo::ofFbo():
233fbo(0),
234fboTextures(0),
235depthBuffer(0),
236stencilBuffer(0),
237dirty(false),
238defaultTextureIndex(0),
239bIsAllocated(false)
240{
241#if defined(TARGET_OPENGLES) & !defined(TARGET_EMSCRIPTEN)
242if(!bglFunctionsInitialized){
243if(ofIsGLProgrammableRenderer()){
244glGenFramebuffers = (glGenFramebuffersType)dlsym(RTLD_DEFAULT, "glGenFramebuffers");
245glDeleteFramebuffers = (glDeleteFramebuffersType)dlsym(RTLD_DEFAULT, "glDeleteFramebuffers");
246glDeleteRenderbuffers = (glDeleteRenderbuffersType)dlsym(RTLD_DEFAULT, "glDeleteRenderbuffers");
247glBindFramebuffer = (glBindFramebufferType)dlsym(RTLD_DEFAULT, "glBindFramebuffer");
248glBindRenderbuffer = (glBindRenderbufferType)dlsym(RTLD_DEFAULT, "glBindRenderbuffer");
249glRenderbufferStorage = (glRenderbufferStorageType)dlsym(RTLD_DEFAULT, "glRenderbufferStorage");
250glFramebufferRenderbuffer = (glFramebufferRenderbufferType)dlsym(RTLD_DEFAULT, "glFramebufferRenderbuffer");
251glRenderbufferStorageMultisample = (glRenderbufferStorageMultisampleType)dlsym(RTLD_DEFAULT, "glRenderbufferStorageMultisample");
252glFramebufferTexture2D = (glFramebufferTexture2DType)dlsym(RTLD_DEFAULT, "glFramebufferTexture2D");
253glCheckFramebufferStatus = (glCheckFramebufferStatusType)dlsym(RTLD_DEFAULT, "glCheckFramebufferStatus");
254}else{
255glGenFramebuffers = (glGenFramebuffersType)dlsym(RTLD_DEFAULT, "glGenFramebuffersOES");
256glDeleteFramebuffers = (glDeleteFramebuffersType)dlsym(RTLD_DEFAULT, "glDeleteFramebuffersOES");
257glDeleteRenderbuffers = (glDeleteRenderbuffersType)dlsym(RTLD_DEFAULT, "glDeleteRenderbuffersOES");
258glBindFramebuffer = (glBindFramebufferType)dlsym(RTLD_DEFAULT, "glBindFramebufferOES");
259glBindRenderbuffer = (glBindRenderbufferType)dlsym(RTLD_DEFAULT, "glBindRenderbufferOES");
260glRenderbufferStorage = (glRenderbufferStorageType)dlsym(RTLD_DEFAULT, "glRenderbufferStorageOES");
261glFramebufferRenderbuffer = (glFramebufferRenderbufferType)dlsym(RTLD_DEFAULT, "glFramebufferRenderbufferOES");
262glRenderbufferStorageMultisample = (glRenderbufferStorageMultisampleType)dlsym(RTLD_DEFAULT, "glRenderbufferStorageMultisampleOES");
263glFramebufferTexture2D = (glFramebufferTexture2DType)dlsym(RTLD_DEFAULT, "glFramebufferTexture2DOES");
264glCheckFramebufferStatus = (glCheckFramebufferStatusType)dlsym(RTLD_DEFAULT, "glCheckFramebufferStatusOES");
265}
266}
267#endif
268}
269
270//--------------------------------------------------------------
271ofFbo::ofFbo(const ofFbo & mom){
272settings = mom.settings;
273bIsAllocated = mom.bIsAllocated;
274
275fbo = mom.fbo;
276retainFB(fbo);
277fboTextures = mom.fboTextures;
278if(settings.numSamples){
279retainFB(fboTextures);
280}
281if(mom.settings.depthStencilAsTexture){
282depthBufferTex = mom.depthBufferTex;
283}else{
284depthBuffer = mom.depthBuffer;
285retainRB(depthBuffer);
286}
287stencilBuffer = mom.stencilBuffer;
288retainRB(stencilBuffer);
289
290colorBuffers = mom.colorBuffers;
291for(int i=0;i<(int)colorBuffers.size();i++){
292retainRB(colorBuffers[i]);
293}
294textures = mom.textures;
295dirty = mom.dirty;
296defaultTextureIndex = mom.defaultTextureIndex;
297activeDrawBuffers = mom.activeDrawBuffers;
298if(fbo!=0){
299#ifdef TARGET_ANDROID
300ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo);
301#endif
302}
303}
304
305//--------------------------------------------------------------
306ofFbo & ofFbo::operator=(const ofFbo & mom){
307if(&mom==this) return *this;
308clear();
309settings = mom.settings;
310bIsAllocated = mom.bIsAllocated;
311
312fbo = mom.fbo;
313retainFB(fbo);
314fboTextures = mom.fboTextures;
315if(settings.numSamples){
316retainFB(fboTextures);
317}
318if(mom.settings.depthStencilAsTexture){
319depthBufferTex = mom.depthBufferTex;
320}else{
321depthBuffer = mom.depthBuffer;
322retainRB(depthBuffer);
323}
324stencilBuffer = mom.stencilBuffer;
325retainRB(stencilBuffer);
326
327colorBuffers = mom.colorBuffers;
328for(int i=0;i<(int)colorBuffers.size();i++){
329retainRB(colorBuffers[i]);
330}
331textures = mom.textures;
332dirty = mom.dirty;
333defaultTextureIndex = mom.defaultTextureIndex;
334activeDrawBuffers = mom.activeDrawBuffers;
335if(fbo!=0){
336#ifdef TARGET_ANDROID
337ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo);
338#endif
339}
340return *this;
341}
342
343ofFbo::ofFbo(ofFbo && mom)
344:settings(std::move(mom.settings))
345,fbo(mom.fbo)
346,fboTextures(mom.fboTextures)
347,depthBuffer(mom.depthBuffer)
348,stencilBuffer(mom.stencilBuffer)
349,colorBuffers(std::move(mom.colorBuffers))
350,textures(std::move(mom.textures))
351,depthBufferTex(std::move(mom.depthBufferTex))
352,activeDrawBuffers(std::move(mom.activeDrawBuffers))
353,dirty(std::move(mom.dirty))
354,defaultTextureIndex(std::move(mom.defaultTextureIndex))
355,bIsAllocated(std::move(mom.bIsAllocated)){
356if(fbo!=0){
357#ifdef TARGET_ANDROID
358ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo);
359#endif
360}
361mom.fbo = 0;
362mom.depthBuffer = 0;
363mom.fboTextures = 0;
364mom.stencilBuffer = 0;
365}
366
367ofFbo & ofFbo::operator=(ofFbo && mom){
368if(&mom==this) return *this;
369clear();
370settings = std::move(mom.settings);
371bIsAllocated = std::move(mom.bIsAllocated);
372
373fbo = mom.fbo;
374fboTextures = mom.fboTextures;
375if(mom.settings.depthStencilAsTexture){
376depthBufferTex = std::move(mom.depthBufferTex);
377}else{
378depthBuffer = mom.depthBuffer;
379}
380stencilBuffer = std::move(mom.stencilBuffer);
381
382colorBuffers = std::move(mom.colorBuffers);
383textures = std::move(mom.textures);
384dirty = std::move(mom.dirty);
385defaultTextureIndex = std::move(mom.defaultTextureIndex);
386
387if(fbo!=0){
388#ifdef TARGET_ANDROID
389ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo);
390#endif
391}
392mom.fbo = 0;
393mom.depthBuffer = 0;
394mom.fboTextures = 0;
395mom.stencilBuffer = 0;
396return *this;
397}
398
399//--------------------------------------------------------------
400ofFbo::~ofFbo(){
401clear();
402}
403
404//--------------------------------------------------------------
405int ofFbo::maxColorAttachments() {
406if(_maxColorAttachments<0) checkGLSupport();
407return _maxColorAttachments;
408}
409
410//--------------------------------------------------------------
411int ofFbo::maxDrawBuffers() {
412if(_maxDrawBuffers<0) checkGLSupport();
413return _maxDrawBuffers;
414}
415
416//--------------------------------------------------------------
417int ofFbo::maxSamples() {
418if(_maxSamples<0) checkGLSupport();
419return _maxSamples;
420}
421
422
423//--------------------------------------------------------------
424void ofFbo::clear() {
425if(fbo){
426releaseFB(fbo);
427fbo=0;
428}
429if(depthBuffer){
430releaseRB(depthBuffer);
431depthBuffer = 0;
432}
433if(depthBufferTex.isAllocated()){
434depthBufferTex.clear();
435}
436if(stencilBuffer){
437releaseRB(stencilBuffer);
438stencilBuffer = 0;
439}
440if(settings.numSamples && fboTextures){
441releaseFB(fboTextures);
442fboTextures = 0;
443}
444textures.clear();
445for (int i=0; i < (int)colorBuffers.size(); i++) {
446releaseRB(colorBuffers[i]);
447}
448colorBuffers.clear();
449activeDrawBuffers.clear();
450bIsAllocated = false;
451#ifdef TARGET_ANDROID
452ofRemoveListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo);
453#endif
454}
455
456
457#ifndef TARGET_OPENGLES
458//--------------------------------------------------------------
459void ofFbo::clearColorBuffer(const ofFloatColor & color){
460glClearBufferfv(GL_COLOR, 0, &color.r);
461}
462
463//--------------------------------------------------------------
464void ofFbo::clearColorBuffer(size_t buffer_idx, const ofFloatColor & color){
465glClearBufferfv(GL_COLOR, buffer_idx, &color.r);
466}
467
468//--------------------------------------------------------------
469void ofFbo::clearDepthBuffer(float value){
470glClearBufferfv(GL_DEPTH, 0, &value);
471}
472
473//--------------------------------------------------------------
474void ofFbo::clearStencilBuffer(int value){
475glClearBufferiv(GL_STENCIL, 0, &value);
476}
477
478//--------------------------------------------------------------
479void ofFbo::clearDepthStencilBuffer(float depth, int stencil){
480glClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil);
481}
482#endif
483
484//--------------------------------------------------------------
485void ofFbo::destroy() {
486clear();
487}
488
489//--------------------------------------------------------------
490bool ofFbo::checkGLSupport() {
491#ifndef TARGET_OPENGLES
492
493if (!ofIsGLProgrammableRenderer()){
494if(ofGLCheckExtension("GL_EXT_framebuffer_object")){
495ofLogVerbose("ofFbo") << "GL frame buffer object supported";
496}else{
497ofLogError("ofFbo") << "GL frame buffer object not supported by this graphics card";
498return false;
499}
500}
501
502glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &_maxColorAttachments);
503glGetIntegerv(GL_MAX_DRAW_BUFFERS, &_maxDrawBuffers);
504glGetIntegerv(GL_MAX_SAMPLES, &_maxSamples);
505
506ofLogVerbose("ofFbo") << "checkGLSupport(): "
507<< "maxColorAttachments: " << _maxColorAttachments << ", "
508<< "maxDrawBuffers: " << _maxDrawBuffers << ", "
509<< "maxSamples: " << _maxSamples;
510#else
511
512if(ofIsGLProgrammableRenderer() || ofGLCheckExtension("GL_OES_framebuffer_object")){
513ofLogVerbose("ofFbo") << "GL frame buffer object supported";
514}else{
515ofLogError("ofFbo") << "GL frame buffer object not supported by this graphics card";
516return false;
517}
518#endif
519
520return true;
521}
522
523
524//--------------------------------------------------------------
525void ofFbo::allocate(int width, int height, int internalformat, int numSamples) {
526
527settings.width = width;
528settings.height = height;
529settings.internalformat = internalformat;
530settings.numSamples = numSamples;
531
532#ifdef TARGET_OPENGLES
533settings.useDepth = false;
534settings.useStencil = false;
535//we do this as the fbo and the settings object it contains could be created before the user had the chance to disable or enable arb rect.
536settings.textureTarget = GL_TEXTURE_2D;
537#else
538settings.useDepth = true;
539settings.useStencil = true;
540//we do this as the fbo and the settings object it contains could be created before the user had the chance to disable or enable arb rect.
541settings.textureTarget = ofGetUsingArbTex() ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D;
542#endif
543
544allocate(settings);
545}
546
547//--------------------------------------------------------------
548void ofFbo::allocate(ofFboSettings _settings) {
549if(!checkGLSupport()) return;
550
551clear();
552auto renderer = _settings.renderer.lock();
553if(renderer){
554settings.renderer = renderer;
555}else{
556settings.renderer = ofGetGLRenderer();
557}
558
559// check that passed values are correct
560if(_settings.width <= 0 || _settings.height <= 0){
561ofLogError("ofFbo") << "width and height have to be more than 0";
562}
563if(_settings.numSamples > maxSamples() && maxSamples() > -1) {
564ofLogWarning("ofFbo") << "allocate(): clamping numSamples " << _settings.numSamples << " to maxSamples " << maxSamples() << " for frame buffer object" << fbo;
565_settings.numSamples = maxSamples();
566}
567
568if(_settings.depthStencilAsTexture && _settings.numSamples){
569ofLogWarning("ofFbo") << "allocate(): multisampling not supported with depthStencilAsTexture, setting 0 samples for frame buffer object " << fbo;
570_settings.numSamples = 0;
571}
572
573//currently depth only works if stencil is enabled.
574// http://forum.openframeworks.cc/index.php/topic,6837.0.html
575#ifdef TARGET_OPENGLES
576if(_settings.useDepth){
577_settings.useStencil = true;
578}
579if( _settings.depthStencilAsTexture ){
580_settings.depthStencilAsTexture = false;
581ofLogWarning("ofFbo") << "allocate(): depthStencilAsTexture is not available for iOS";
582}
583#endif
584
585GLenum depthAttachment = GL_DEPTH_ATTACHMENT;
586
587if( _settings.useDepth && _settings.useStencil ){
588_settings.depthStencilInternalFormat = GL_DEPTH_STENCIL;
589#ifdef TARGET_OPENGLES
590depthAttachment = GL_DEPTH_ATTACHMENT;
591#else
592depthAttachment = GL_DEPTH_STENCIL_ATTACHMENT;
593#endif
594}else if(_settings.useDepth){
595depthAttachment = GL_DEPTH_ATTACHMENT;
596}else if(_settings.useStencil){
597depthAttachment = GL_STENCIL_ATTACHMENT;
598_settings.depthStencilInternalFormat = GL_STENCIL_INDEX;
599}
600
601// set needed values for allocation on instance settings
602// the rest will be set by the corresponding methods during allocation
603settings.width = _settings.width;
604settings.height = _settings.height;
605settings.numSamples = _settings.numSamples;
606
607// create main fbo
608// this is the main one we bind for drawing into
609// all the renderbuffers are attached to this (whether MSAA is enabled or not)
610glGenFramebuffers(1, &fbo);
611retainFB(fbo);
612
613GLint previousFboId = 0;
614
615// note that we are using a glGetInteger method here, which may stall the pipeline.
616// in the allocate() method, this is not that tragic since this will not be called
617// within the draw() loop. Here, we need not optimise for performance, but for
618// simplicity and readability .
619
620glGetIntegerv(GL_FRAMEBUFFER_BINDING, &previousFboId);
621glBindFramebuffer(GL_FRAMEBUFFER, fbo);
622
623//- USE REGULAR RENDER BUFFER
624if(!_settings.depthStencilAsTexture){
625if(_settings.useDepth && _settings.useStencil){
626stencilBuffer = depthBuffer = createAndAttachRenderbuffer(_settings.depthStencilInternalFormat, depthAttachment);
627retainRB(stencilBuffer);
628retainRB(depthBuffer);
629}else if(_settings.useDepth){
630depthBuffer = createAndAttachRenderbuffer(_settings.depthStencilInternalFormat, depthAttachment);
631retainRB(depthBuffer);
632}else if(_settings.useStencil){
633stencilBuffer = createAndAttachRenderbuffer(_settings.depthStencilInternalFormat, depthAttachment);
634retainRB(stencilBuffer);
635}
636//- INSTEAD USE TEXTURE
637}else{
638if(_settings.useDepth || _settings.useStencil){
639createAndAttachDepthStencilTexture(_settings.textureTarget,_settings.depthStencilInternalFormat,depthAttachment);
640#ifdef TARGET_OPENGLES
641// if there's depth and stencil the texture should be attached as
642// depth and stencil attachments
643// http://www.khronos.org/registry/gles/extensions/OES/OES_packed_depth_stencil.txt
644if(_settings.useDepth && _settings.useStencil){
645glFramebufferTexture2D(GL_FRAMEBUFFER,
646GL_STENCIL_ATTACHMENT,
647GL_TEXTURE_2D, depthBufferTex.texData.textureID, 0);
648}
649#endif
650}
651}
652
653settings.useDepth = _settings.useDepth;
654settings.useStencil = _settings.useStencil;
655settings.depthStencilInternalFormat = _settings.depthStencilInternalFormat;
656settings.depthStencilAsTexture = _settings.depthStencilAsTexture;
657settings.textureTarget = _settings.textureTarget;
658settings.wrapModeHorizontal = _settings.wrapModeHorizontal;
659settings.wrapModeVertical = _settings.wrapModeVertical;
660settings.maxFilter = _settings.maxFilter;
661settings.minFilter = _settings.minFilter;
662
663// if we want MSAA, create a new fbo for textures
664#ifndef TARGET_OPENGLES
665if(_settings.numSamples){
666glGenFramebuffers(1, &fboTextures);
667retainFB(fboTextures);
668}else{
669fboTextures = fbo;
670}
671#else
672fboTextures = fbo;
673if(_settings.numSamples){
674ofLogWarning("ofFbo") << "allocate(): multisampling not supported in OpenGL ES";
675}
676#endif
677
678// now create all textures and color buffers
679if(_settings.colorFormats.size() > 0) {
680for(int i=0; i<(int)_settings.colorFormats.size(); i++) createAndAttachTexture(_settings.colorFormats[i], i);
681} else if(_settings.numColorbuffers > 0) {
682for(int i=0; i<_settings.numColorbuffers; i++) createAndAttachTexture(_settings.internalformat, i);
683_settings.colorFormats = settings.colorFormats;
684} else {
685#ifndef TARGET_OPENGLES
686glDrawBuffer(GL_NONE);
687#else
688ofLogWarning("ofFbo") << "allocate(): no color buffers specified for frame buffer object " << fbo;
689#endif
690}
691settings.internalformat = _settings.internalformat;
692
693dirty.resize(_settings.colorFormats.size(), true); // we start with all color buffers dirty.
694
695// if textures are attached to a different fbo (e.g. if using MSAA) check it's status
696if(fbo != fboTextures) {
697glBindFramebuffer(GL_FRAMEBUFFER, fboTextures);
698}
699
700// check everything is ok with this fbo
701bIsAllocated = checkStatus();
702
703// restore previous framebuffer id
704glBindFramebuffer(GL_FRAMEBUFFER, previousFboId);
705
706/* UNCOMMENT OUTSIDE OF DOING RELEASES
707
708// this should never happen
709if(settings != _settings) ofLogWarning("ofFbo") << "allocation not complete, passed settings not equal to created ones, this is an internal OF bug";
710
711*/
712#ifdef TARGET_ANDROID
713ofAddListener(ofxAndroidEvents().reloadGL,this,&ofFbo::reloadFbo);
714#endif
715}
716
717//--------------------------------------------------------------
718void ofFbo::reloadFbo(){
719if(bIsAllocated){
720allocate(settings);
721}
722}
723
724//--------------------------------------------------------------
725bool ofFbo::isAllocated() const {
726return bIsAllocated;
727}
728
729//----------------------------------------------------------
730GLuint ofFbo::createAndAttachRenderbuffer(GLenum internalFormat, GLenum attachmentPoint) {
731GLuint buffer;
732glGenRenderbuffers(1, &buffer);
733glBindRenderbuffer(GL_RENDERBUFFER, buffer);
734#ifndef TARGET_OPENGLES
735if (settings.numSamples==0) {
736glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, settings.width, settings.height);
737} else {
738glRenderbufferStorageMultisample(GL_RENDERBUFFER, settings.numSamples, internalFormat, settings.width, settings.height);
739}
740#else
741if(ofGLSupportsNPOTTextures()){
742glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, settings.width, settings.height);
743}else{
744glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, ofNextPow2(settings.width), ofNextPow2(settings.height));
745}
746#endif
747glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachmentPoint, GL_RENDERBUFFER, buffer);
748return buffer;
749}
750
751//----------------------------------------------------------
752void ofFbo::createAndAttachTexture(GLenum internalFormat, GLenum attachmentPoint) {
753
754ofTextureData texData;
755
756texData.textureTarget = settings.textureTarget;
757texData.width = settings.width;
758texData.height = settings.height;
759texData.glInternalFormat = internalFormat;
760texData.bFlipTexture = false;
761texData.wrapModeHorizontal = settings.wrapModeHorizontal;
762texData.wrapModeVertical = settings.wrapModeVertical;
763texData.magFilter = settings.maxFilter;
764texData.minFilter = settings.minFilter;
765
766ofTexture tex;
767tex.allocate(texData);
768
769attachTexture(tex, internalFormat, attachmentPoint);
770dirty.push_back(true);
771activeDrawBuffers.push_back(GL_COLOR_ATTACHMENT0 + attachmentPoint);
772}
773
774//----------------------------------------------------------
775void ofFbo::attachTexture(ofTexture & tex, GLenum internalFormat, GLenum attachmentPoint) {
776// bind fbo for textures (if using MSAA this is the newly created fbo, otherwise its the same fbo as before)
777GLint temp;
778glGetIntegerv(GL_FRAMEBUFFER_BINDING, &temp);
779glBindFramebuffer(GL_FRAMEBUFFER, fboTextures);
780
781glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachmentPoint, tex.texData.textureTarget, tex.texData.textureID, 0);
782if(attachmentPoint >= textures.size()) {
783textures.resize(attachmentPoint+1);
784}
785textures[attachmentPoint] = tex;
786
787settings.colorFormats.resize(attachmentPoint + 1);
788settings.colorFormats[attachmentPoint] = internalFormat;
789settings.numColorbuffers = settings.colorFormats.size();
790
791// if MSAA, bind main fbo and attach renderbuffer
792if(settings.numSamples) {
793glBindFramebuffer(GL_FRAMEBUFFER, fbo);
794
795GLuint colorBuffer = createAndAttachRenderbuffer(internalFormat, GL_COLOR_ATTACHMENT0 + attachmentPoint);
796colorBuffers.push_back(colorBuffer);
797retainRB(colorBuffer);
798}
799glBindFramebuffer(GL_FRAMEBUFFER, temp);
800
801}
802
803//----------------------------------------------------------
804void ofFbo::createAndAttachDepthStencilTexture(GLenum target, GLint internalformat, GLenum attachment, GLenum transferFormat, GLenum transferType){
805
806
807// allocate depthBufferTex as depth buffer;
808depthBufferTex.texData.glInternalFormat = internalformat;
809depthBufferTex.texData.textureTarget = target;
810depthBufferTex.texData.bFlipTexture = false;
811depthBufferTex.texData.width = settings.width;
812depthBufferTex.texData.height = settings.height;
813
814depthBufferTex.allocate(depthBufferTex.texData,transferFormat,transferType);
815
816glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, target, depthBufferTex.texData.textureID, 0);
817}
818
819//----------------------------------------------------------
820void ofFbo::createAndAttachDepthStencilTexture(GLenum target, GLint internalformat, GLenum attachment){
821
822// allocate depthBufferTex as depth buffer;
823depthBufferTex.texData.glInternalFormat = internalformat;
824depthBufferTex.texData.textureTarget = target;
825depthBufferTex.texData.bFlipTexture = false;
826depthBufferTex.texData.width = settings.width;
827depthBufferTex.texData.height = settings.height;
828
829depthBufferTex.allocate(depthBufferTex.texData);
830
831glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, target, depthBufferTex.texData.textureID, 0);
832}
833
834//----------------------------------------------------------
835void ofFbo::begin(bool setupScreen) const{
836auto renderer = settings.renderer.lock();
837if(renderer){
838if(setupScreen){
839renderer->begin(*this, OF_FBOMODE_PERSPECTIVE | OF_FBOMODE_MATRIXFLIP);
840}else{
841renderer->begin(*this, OF_FBOMODE_NODEFAULTS);
842}
843}
844}
845
846
847void ofFbo::begin(ofFboMode mode) const{
848auto renderer = settings.renderer.lock();
849if(renderer){
850renderer->begin(*this, mode);
851}
852}
853
854
855//----------------------------------------------------------
856/*void ofFbo::begin() const {
857auto renderer = settings.renderer.lock();
858if (renderer) {
859renderer->begin(*this, true);
860}
861}
862
863//----------------------------------------------------------
864void ofFbo::beginNoPerspective() const {
865auto renderer = settings.renderer.lock();
866if (renderer) {
867renderer->begin(*this, false);
868}
869}
870
871//----------------------------------------------------------
872void ofFbo::beginNoMatrixFlip() const {
873auto renderer = settings.renderer.lock();
874if (renderer) {
875renderer->beginNoMatrixFlip(*this);
876}
877}
878
879//----------------------------------------------------------
880void ofFbo::beginNoMatrixFlipNoPerspective() const {
881auto renderer = settings.renderer.lock();
882if (renderer) {
883renderer->beginNoMatrixFlipNoPerspective(*this);
884}
885}*/
886
887//----------------------------------------------------------
888void ofFbo::end() const{
889auto renderer = settings.renderer.lock();
890if(renderer){
891renderer->end(*this);
892}
893}
894
895//----------------------------------------------------------
896void ofFbo::bind() const{
897auto renderer = settings.renderer.lock();
898if(renderer){
899renderer->bind(*this);
900}
901}
902
903//----------------------------------------------------------
904void ofFbo::unbind() const{
905auto renderer = settings.renderer.lock();
906if(renderer){
907renderer->unbind(*this);
908}
909}
910
911//----------------------------------------------------------
912void ofFbo::flagDirty() const{
913if (fbo != fboTextures){
914// ---------| if fbo != fboTextures, we are dealing with an MSAA enabled FBO.
915//
916// All currently active draw buffers need to be flagged dirty
917//
918// If a draw buffer has been activated and then de-activated, it has been
919// flagged dirty at activation, so we can be sure all buffers which have
920// been rendered to are flagged dirty.
921//
922int numBuffersToFlag = std::min(dirty.size(), activeDrawBuffers.size());
923for(int i=0; i < numBuffersToFlag; i++){
924dirty[i] = true;
925}
926}
927}
928
929//----------------------------------------------------------
930int ofFbo::getNumTextures() const {
931return textures.size();
932}
933
934//----------------------------------------------------------
935void ofFbo::setActiveDrawBuffer(int i){
936if(!bIsAllocated) return;
937#ifndef TARGET_OPENGLES
938vector<int> activebuffers(1, i);
939setActiveDrawBuffers(activebuffers);
940#endif
941}
942
943//----------------------------------------------------------
944void ofFbo::setActiveDrawBuffers(const vector<int>& ids){
945if(!bIsAllocated) return;
946#ifndef TARGET_OPENGLES
947int numBuffers = activeDrawBuffers.size();
948activeDrawBuffers.clear();
949activeDrawBuffers.resize(numBuffers, GL_NONE); // we initialise the vector with GL_NONE, so a buffer will not be written to unless activated.
950for(int i=0; i < (int)ids.size(); i++){
951int id = ids[i];
952if (id < getNumTextures()){
953GLenum e = GL_COLOR_ATTACHMENT0 + id;
954activeDrawBuffers[id] = e; // activate requested buffers
955dirty[id] = true; // dirty activated draw buffers.
956}else{
957ofLogWarning("ofFbo") << "setActiveDrawBuffers(): fbo " << fbo << " couldn't set texture " << i << ", only " << getNumTextures() << "allocated";
958}
959}
960glDrawBuffers(activeDrawBuffers.size(),&activeDrawBuffers[0]);
961#endif
962}
963
964//----------------------------------------------------------
965void ofFbo::activateAllDrawBuffers(){
966if(!bIsAllocated) return;
967#ifndef TARGET_OPENGLES
968vector<int> activeBuffers(getNumTextures(),0);
969for(int i=0; i < getNumTextures(); i++){
970activeBuffers[i] = i;
971}
972setActiveDrawBuffers(activeBuffers);
973#endif
974}
975
976//----------------------------------------------------------
977void ofFbo::setDefaultTextureIndex(int defaultTexture)
978{
979defaultTextureIndex = defaultTexture;
980}
981
982//----------------------------------------------------------
983int ofFbo::getDefaultTextureIndex() const
984{
985return defaultTextureIndex;
986}
987
988//----------------------------------------------------------
989ofTexture& ofFbo::getTextureReference(){
990return getTexture();
991}
992
993//----------------------------------------------------------
994ofTexture& ofFbo::getTextureReference(int attachmentPoint) {
995return getTexture(attachmentPoint);
996}
997
998//----------------------------------------------------------
999const ofTexture& ofFbo::getTextureReference() const{
1000return getTexture();
1001}
1002
1003//----------------------------------------------------------
1004const ofTexture& ofFbo::getTextureReference(int attachmentPoint) const{
1005return getTexture(attachmentPoint);
1006}
1007
1008//----------------------------------------------------------
1009ofTexture& ofFbo::getTexture(){
1010return getTexture(defaultTextureIndex);
1011}
1012
1013//----------------------------------------------------------
1014ofTexture& ofFbo::getTexture(int attachmentPoint) {
1015updateTexture(attachmentPoint);
1016
1017return textures[attachmentPoint];
1018}
1019
1020//----------------------------------------------------------
1021const ofTexture& ofFbo::getTexture() const{
1022return getTexture(defaultTextureIndex);
1023}
1024
1025//----------------------------------------------------------
1026const ofTexture& ofFbo::getTexture(int attachmentPoint) const{
1027ofFbo * mutThis = const_cast<ofFbo*>(this);
1028mutThis->updateTexture(attachmentPoint);
1029
1030return textures[attachmentPoint];
1031}
1032
1033//----------------------------------------------------------
1034void ofFbo::setAnchorPercent(float xPct, float yPct){
1035getTexture().setAnchorPercent(xPct, yPct);
1036}
1037
1038//----------------------------------------------------------
1039void ofFbo::setAnchorPoint(float x, float y){
1040getTexture().setAnchorPoint(x, y);
1041}
1042
1043//----------------------------------------------------------
1044void ofFbo::resetAnchor(){
1045getTexture().resetAnchor();
1046}
1047
1048//----------------------------------------------------------
1049void ofFbo::readToPixels(ofPixels & pixels, int attachmentPoint) const{
1050if(!bIsAllocated) return;
1051#ifndef TARGET_OPENGLES
1052getTexture(attachmentPoint).readToPixels(pixels);
1053#else
1054pixels.allocate(settings.width,settings.height,ofGetImageTypeFromGLType(settings.internalformat));
1055bind();
1056int format = ofGetGLFormatFromInternal(settings.internalformat);
1057glReadPixels(0,0,settings.width, settings.height, format, GL_UNSIGNED_BYTE, pixels.getData());
1058unbind();
1059#endif
1060}
1061
1062//----------------------------------------------------------
1063void ofFbo::readToPixels(ofShortPixels & pixels, int attachmentPoint) const{
1064if(!bIsAllocated) return;
1065#ifndef TARGET_OPENGLES
1066getTexture(attachmentPoint).readToPixels(pixels);
1067#else
1068pixels.allocate(settings.width,settings.height,ofGetImageTypeFromGLType(settings.internalformat));
1069bind();
1070int format = ofGetGLFormatFromInternal(settings.internalformat);
1071glReadPixels(0,0,settings.width, settings.height, format, GL_UNSIGNED_SHORT, pixels.getData());
1072unbind();
1073#endif
1074}
1075
1076//----------------------------------------------------------
1077void ofFbo::readToPixels(ofFloatPixels & pixels, int attachmentPoint) const{
1078if(!bIsAllocated) return;
1079#ifndef TARGET_OPENGLES
1080getTexture(attachmentPoint).readToPixels(pixels);
1081#else
1082pixels.allocate(settings.width,settings.height,ofGetImageTypeFromGLType(settings.internalformat));
1083bind();
1084int format = ofGetGLFormatFromInternal(settings.internalformat);
1085glReadPixels(0,0,settings.width, settings.height, format, GL_FLOAT, pixels.getData());
1086unbind();
1087#endif
1088}
1089
1090#ifndef TARGET_OPENGLES
1091//----------------------------------------------------------
1092void ofFbo::copyTo(ofBufferObject & buffer) const{
1093if(!bIsAllocated) return;
1094bind();
1095buffer.bind(GL_PIXEL_PACK_BUFFER);
1096glReadPixels(0, 0, settings.width, settings.height, ofGetGLFormatFromInternal(settings.internalformat), ofGetGLTypeFromInternal(settings.internalformat), NULL);
1097buffer.unbind(GL_PIXEL_PACK_BUFFER);
1098unbind();
1099}
1100#endif
1101
1102//----------------------------------------------------------
1103void ofFbo::updateTexture(int attachmentPoint) {
1104if(!bIsAllocated) return;
1105#ifndef TARGET_OPENGLES
1106if(fbo != fboTextures && dirty[attachmentPoint]) {
1107
1108// if fbo != fboTextures, we are dealing with an MSAA enabled FBO.
1109// and we need to blit one fbo into another to see get the texture
1110// content
1111
1112if (!ofIsGLProgrammableRenderer()){
1113// save current drawbuffer
1114glPushAttrib(GL_COLOR_BUFFER_BIT);
1115}
1116
1117auto renderer = settings.renderer.lock();
1118if(renderer){
1119GLint readBuffer;
1120glGetIntegerv(GL_READ_BUFFER, &readBuffer);
1121
1122renderer->bindForBlitting(*this,*this,attachmentPoint);
1123glBlitFramebuffer(0, 0, settings.width, settings.height, 0, 0, settings.width, settings.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
1124renderer->unbind(*this);
1125
1126glReadBuffer(readBuffer);
1127}
1128
1129if(!ofIsGLProgrammableRenderer()){
1130// restore current drawbuffer
1131glPopAttrib();
1132}
1133dirty[attachmentPoint] = false;
1134}
1135#endif
1136}
1137
1138//----------------------------------------------------------
1139void ofFbo::draw(float x, float y) const{
1140draw(x, y, settings.width, settings.height);
1141}
1142
1143//----------------------------------------------------------
1144void ofFbo::draw(float x, float y, float width, float height) const{
1145if(!bIsAllocated || settings.numColorbuffers==0) return;
1146getTexture().draw(x, y, width, height);
1147}
1148
1149//----------------------------------------------------------
1150GLuint ofFbo::getFbo() const {
1151return fbo;
1152}
1153
1154//----------------------------------------------------------
1155GLuint ofFbo::getId() const {
1156return fbo;
1157}
1158
1159//----------------------------------------------------------
1160GLuint ofFbo::getIdDrawBuffer() const{
1161return fboTextures;
1162}
1163
1164//----------------------------------------------------------
1165float ofFbo::getWidth() const {
1166return settings.width;
1167}
1168
1169
1170//----------------------------------------------------------
1171float ofFbo::getHeight() const {
1172return settings.height;
1173}
1174
1175
1176//----------------------------------------------------------
1177bool ofFbo::checkStatus() const {
1178GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
1179switch(status) {
1180case GL_FRAMEBUFFER_COMPLETE:
1181ofLogVerbose("ofFbo") << "FRAMEBUFFER_COMPLETE - OK";
1182return true;
1183case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
1184ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
1185break;
1186case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
1187ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
1188break;
1189case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
1190ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
1191break;
1192#ifndef TARGET_PROGRAMMABLE_GL
1193case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:
1194ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_FORMATS";
1195break;
1196#endif
1197case GL_FRAMEBUFFER_UNSUPPORTED:
1198ofLogError("ofFbo") << "FRAMEBUFFER_UNSUPPORTED";
1199break;
1200#ifndef TARGET_OPENGLES
1201case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
1202ofLogWarning("ofFbo") << "FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER";
1203break;
1204case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
1205ofLogError("ofFbo") << "FRAMEBUFFER_INCOMPLETE_READ_BUFFER";
1206break;
1207case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
1208ofLogError("ofFbo") << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE";
1209break;
1210#endif
1211default:
1212ofLogError("ofFbo") << "UNKNOWN ERROR " << status;
1213break;
1214
1215}
1216
1217return false;
1218}
1219
1220//----------------------------------------------------------
1221ofTexture & ofFbo::getDepthTexture(){
1222if(!settings.depthStencilAsTexture){
1223ofLogError("ofFbo") << "getDepthTexture(): frame buffer object " << fbo << " not allocated with depthStencilAsTexture";
1224}
1225return depthBufferTex;
1226}
1227
1228//----------------------------------------------------------
1229const ofTexture & ofFbo::getDepthTexture() const{
1230if(!settings.depthStencilAsTexture){
1231ofLogError("ofFbo") << "getDepthTexture(): frame buffer object " << fbo << " not allocated with depthStencilAsTexture";
1232}
1233return depthBufferTex;
1234}
1235
1236//#endif
1237