GLFBO.m 3.13 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
#import "GLFBO.h"
#import "GLTexture.h"
#import "RCTLog.h"

@interface FBOState: NSObject

@property (nonatomic) GLint fbo;
@property (nonatomic) GLint rbo;
@property (nonatomic) GLint tex;

- (instancetype)initFromContext;
- (void)restore;

@end

@implementation FBOState

- (instancetype)initFromContext
{
  if ((self = [super init])) {
    GLint fbo, rbo, tex;
    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
    glGetIntegerv(GL_RENDERBUFFER_BINDING, &rbo);
    glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex);
    self.fbo = fbo;
    self.rbo = rbo;
    self.tex = tex;
  }
  return self;
}

- (void)restore
{
  glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
35 36
  glBindRenderbuffer(GL_RENDERBUFFER, _rbo);
  glBindTexture(GL_TEXTURE_2D, _tex);
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
}

@end

GLTexture *initTexture (float width, float height, GLuint attachment)
{
  GLTexture *texture = [[GLTexture alloc] init];
  [texture bind];
  [texture setShapeWithWidth:width withHeight:height];
  glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture.handle, 0);
  return texture;
}

@implementation GLFBO
{
  GLuint _handle;
  float _width;
  float _height;
  NSArray *_color;
}

-(void)dealloc
{
  glDeleteFramebuffers(1, &_handle);
}

-(instancetype)init
{
  if ((self = [super init])) {
    _color = [[NSArray alloc] init];
    FBOState *state = [[FBOState alloc] initFromContext];
    
    glGenFramebuffers(1, &_handle);
    
    int numColors = 1;
    
    glBindFramebuffer(GL_FRAMEBUFFER, _handle);
    
    NSMutableArray *color = [[NSMutableArray alloc] init];
    for(int i=0; i<numColors; ++i) {
      color[i] = initTexture(_width, _height, GL_COLOR_ATTACHMENT0 + i);
    }
    _color = color;
    
    [state restore];
  }
  return self;
}

- (void)checkStatus
{
  GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
  if(status != GL_FRAMEBUFFER_COMPLETE) {
    switch (status) {
      case GL_FRAMEBUFFER_UNSUPPORTED:
        RCTLogError(@"Framebuffer unsupported");
        break;
      case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
        RCTLogError(@"Framebuffer incomplete attachment");
        break;
      case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
        RCTLogError(@"Framebuffer incomplete dimensions");
        break;
      case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
        RCTLogError(@"Framebuffer incomplete missing attachment");
        break;
      default:
        RCTLogError(@"Failed to create framebuffer: %i", status);
    }
  }
}

- (void)bind
{
  glBindFramebuffer(GL_FRAMEBUFFER, _handle);
  glViewport(0, 0, _width, _height);
}

- (void)setShapeWithWidth:(float)width withHeight:(float)height
{
  if (width == _width && height == _height) return;
  GLint maxFBOSize;
  glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxFBOSize);
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
120 121
  if( width < 0 || width > maxFBOSize ||
      height < 0 || height > maxFBOSize) {
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    RCTLogError(@"Can't resize framebuffer. Invalid dimensions");
    return;
  }
  _width = width;
  _height = height;
  
  FBOState *state = [[FBOState alloc] initFromContext];
  
  for (GLTexture *clr in _color) {
    [clr setShapeWithWidth:width withHeight:height];
  }
  
  glBindFramebuffer(GL_FRAMEBUFFER, _handle);
  [self checkStatus];
  
  [state restore];
}

@end