RNGLContext.m 4.2 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 35 36 37 38 39 40 41 42 43 44 45 46 47

#import "RNGLContext.h"
#import "RCTConvert.h"
#import "RCTLog.h"


@implementation RNGLContext
{
  NSMutableDictionary *_shaders;
  EAGLContext *_context;
  NSMutableDictionary *_fbos;
}

@synthesize bridge = _bridge;

RCT_EXPORT_MODULE()

- (void)setBridge:(RCTBridge *)bridge
{
  _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
  if (!_context) {
    RCTLogError(@"Failed to initialize OpenGLES 2.0 context");
  }
  _shaders = @{}.mutableCopy;
  _fbos = @{}.mutableCopy;
}

- (GLShader *) getShader: (NSNumber *)id
{
  return _shaders[id];
}

- (GLFBO *) getFBO: (NSNumber *)id
{
  GLFBO *fbo = _fbos[id];
  if (!fbo) {
    fbo = [[GLFBO alloc] init];
    _fbos[id] = fbo;
  }
  return fbo;
}

- (EAGLContext *) getContext
{
  return _context;
}

48 49 50 51
- (void)_addShader:(nonnull NSNumber *)id
withConfig:(NSDictionary *)config
withOnCompile:(RCTResponseSenderBlock)onCompile
{
52
  NSString *vert = [RCTConvert NSString:config[@"vert"]];
53 54
  NSString *frag = [RCTConvert NSString:config[@"frag"]];
  NSString *name = [RCTConvert NSString:config[@"name"]];
55 56 57
  if (!vert) {
    vert = fullViewportVert;
  }
58 59 60 61
  if (!frag) {
    RCTLogError(@"Shader '%@': missing frag field", name);
    return;
  }
62
  GLShader *shader = [[GLShader alloc] initWithContext:_context withName:name withVert:vert withFrag:frag];
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
  NSError *error;
  bool success = [shader ensureCompiles:&error];
  if (onCompile) {
    if (!success) {
      onCompile(@[error.domain]);
    }
    else {
      onCompile(@[[NSNull null],
                  @{
                    @"uniforms": shader.uniformTypes
                    }]);
    }
  }
  else {
    if (!success) {
      RCTLogError(@"Shader '%@': %@", name, error.domain);
    }
  }
  _shaders[id] = shader;
}

84 85
static NSString* fullViewportVert = @"attribute vec2 position;varying vec2 uv;void main() {gl_Position = vec4(position,0.0,1.0);uv = vec2(0.5, 0.5) * (position+vec2(1.0, 1.0));}";

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
NSString* glTypeString (int type) {
  switch (type) {
    case GL_FLOAT: return @"float";
    case GL_FLOAT_VEC2: return @"vec2";
    case GL_FLOAT_VEC3: return @"vec3";
    case GL_FLOAT_VEC4: return @"vec4";
    case GL_INT: return @"int";
    case GL_INT_VEC2: return @"ivec2";
    case GL_INT_VEC3: return @"ivec3";
    case GL_INT_VEC4: return @"ivec4";
    case GL_BOOL: return @"bool";
    case GL_BOOL_VEC2: return @"bvec2";
    case GL_BOOL_VEC3: return @"bvec3";
    case GL_BOOL_VEC4: return @"bvec4";
    case GL_FLOAT_MAT2: return @"mat2";
    case GL_FLOAT_MAT3: return @"mat3";
    case GL_FLOAT_MAT4: return @"mat4";
    case GL_SAMPLER_2D: return @"sampler2D";
    case GL_SAMPLER_CUBE: return @"samplerCube";
  }
  return @"";
}
NSDictionary* glTypesString (NSDictionary *types) {
  NSMutableDictionary *dict = types.mutableCopy;
  for (NSString *key in [dict allKeys]) {
    dict[key] = glTypeString([dict[key] intValue]);
  }
  return dict;
}

RCT_EXPORT_METHOD(addShader:(nonnull NSNumber *)id
                  withConfig:(NSDictionary *)config
                  withOnCompile:(RCTResponseSenderBlock)onCompile) {
119
  NSString *vert = [RCTConvert NSString:config[@"vert"]];
120 121
  NSString *frag = [RCTConvert NSString:config[@"frag"]];
  NSString *name = [RCTConvert NSString:config[@"name"]];
122 123 124
  if (!vert) {
    vert = fullViewportVert;
  }
125 126 127 128
  if (!frag) {
    RCTLogError(@"Shader '%@': missing frag field", name);
    return;
  }
129
  GLShader *shader = [[GLShader alloc] initWithContext:_context withName:name withVert:vert withFrag:frag];
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
  NSError *error;
  bool success = [shader ensureCompiles:&error];
  if (onCompile) {
    if (!success) {
      onCompile(@[error.domain]);
    }
    else {
      onCompile(@[[NSNull null],
                  @{
                    @"uniforms": glTypesString(shader.uniformTypes)
                    }]);
    }
  }
  else {
    if (!success) {
      RCTLogError(@"Shader '%@': %@", name, error.domain);
    }
  }
148 149 150
  _shaders[id] = shader;
}

151 152 153 154 155 156 157 158 159
RCT_EXPORT_METHOD(removeShader:(nonnull NSNumber *)id) {
  GLShader *shader = [_shaders objectForKey:id];
  if (!shader) {
    RCTLogError(@"removeShader(%@): shader does not exist", id);
    return;
  }
  [_shaders removeObjectForKey:id];
}

160 161 162 163 164 165
@end

@implementation RCTBridge (RNGLContext)

- (RNGLContext *)rnglContext
{
166
  return [self moduleForClass:[RNGLContext class]];
167 168
}

169
@end