#import #import #import #import #import "GLShader.h" GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shaderType, NSError **error) { GLuint shaderHandle = glCreateShader(shaderType); const char * shaderStringUTF8 = [shaderString UTF8String]; int shaderStringLength = (int) [shaderString length]; glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength); glCompileShader(shaderHandle); GLint compileSuccess; glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess); if (compileSuccess == GL_FALSE) { GLchar messages[256]; glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]); *error = [[NSError alloc] initWithDomain:[NSString stringWithUTF8String:messages] code:GLCompileFailure userInfo:nil]; return -1; } return shaderHandle; } /** * a GLShader represents the atomic component of GL React Native. * It currently statically holds a program that renders 2 static triangles over the full viewport (2D) */ @implementation GLShader { EAGLContext *_context; // Context related to this shader GLuint program; // Program of the shader GLuint buffer; // the buffer currently contains 2 static triangles covering the surface GLint pointerLoc; // The "pointer" attribute is used to iterate over vertex NSDictionary *_uniformTypes; // The types of the GLSL uniforms NSDictionary *_uniformSizes; // The size of the uniform variable NSDictionary *_uniformLocations; // The uniform locations cache NSArray *__uniformNames; // The uniforms names NSError *_error; } - (instancetype)initWithContext: (EAGLContext*)context withName:(NSString *)name withVert:(NSString *)vert withFrag:(NSString *)frag { self = [super init]; if (self) { _name = name; _context = context; _vert = vert; _frag = frag; NSError *error; if (![self makeProgram:&error]) { _error = error; } } return self; } - (void)dealloc { glDeleteProgram(program); glDeleteBuffers(1, &buffer); _name = nil; _context = nil; _vert = nil; _frag = nil; _uniformLocations = nil; _uniformTypes = nil; program = 0; buffer = 0; pointerLoc = 0; } - (bool) ensureContext: (NSError **)error { if (!_context || ![EAGLContext setCurrentContext:_context]) { *error = [[NSError alloc] initWithDomain:@"Failed to set current OpenGL context" code:GLContextFailure userInfo:nil]; return false; } return true; } - (void) bind { glUseProgram(program); glBindBuffer(GL_ARRAY_BUFFER, buffer); glEnableVertexAttribArray(pointerLoc); glVertexAttribPointer(pointerLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); } - (void) setUniform: (NSString *)name withValue:(id)value { GLint size = [_uniformSizes[name] intValue]; GLenum type = [_uniformTypes[name] intValue]; if (size != 1) { NSArray *v = [RCTConvert NSArray:value]; if (!v || [v count]!=size) { RCTLogError(@"Shader '%@': uniform '%@' should be an array of %i elements", _name, name, size); return; } for (int i=0; i