Commit a44e1721 authored by Gaëtan Renaudeau's avatar Gaëtan Renaudeau

Implement multi-pass feature

parent aeca4572
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -6,7 +6,7 @@
"start": "node_modules/react-native/packager/packager.sh"
},
"dependencies": {
"gl-react-native": "../..",
"gl-react-native": "file:../..",
"glsl-transitions": "^2015.8.17",
"react-native": "^0.9.0"
}
......
const React = require("react-native");
const GL = require("gl-react-native");
const Blur1D = require("./Blur1D");
class Blur extends GL.Component {
render () {
const { width, height, factor, children } = this.props;
return <Blur1D width={width} height={height} direction={[ factor, 0 ]}>
<Blur1D width={width} height={height} direction={[ 0, factor ]}>
{children}
</Blur1D>
</Blur1D>;
}
}
module.exports = Blur;
......@@ -2,12 +2,12 @@ const React = require("react-native");
const GL = require("gl-react-native");
const shaders = GL.Shaders.create({
blurX: {
blur1D: {
frag: `
precision highp float;
varying vec2 uv;
uniform sampler2D image;
uniform float factor;
uniform sampler2D t;
uniform vec2 direction;
uniform vec2 resolution;
// from https://github.com/Jam3/glsl-fast-gaussian-blur
......@@ -27,26 +27,26 @@ vec4 blur13(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
}
void main () {
gl_FragColor = blur13(image, uv, resolution, vec2(factor, 0.0));
gl_FragColor = blur13(t, uv, resolution, direction);
}
`
}
});
class BlurX extends React.Component {
class Blur1D extends GL.Component {
render () {
const { width, height, factor, children } = this.props;
const { width, height, direction, children } = this.props;
return <GL.View
shader={shaders.blurX}
shader={shaders.blur1D}
width={width}
height={height}
uniforms={{
factor,
direction,
resolution: [ width, height ]
}}>
<GL.Target uniform="image">{children}</GL.Target>
<GL.Target uniform="t">{children}</GL.Target>
</GL.View>;
}
}
module.exports = BlurX;
module.exports = Blur1D;
This diff is collapsed.
......@@ -16,6 +16,7 @@ const HueRotate = require("./HueRotate");
const PieProgress = require("./PieProgress");
const OneFingerResponse = require("./OneFingerResponse");
const AnimatedHelloGL = require("./AnimatedHelloGL");
const Blur = require("./Blur");
class Simple extends React.Component {
constructor (props) {
......@@ -23,7 +24,8 @@ class Simple extends React.Component {
this.state = {
saturationFactor: 1,
hue: 0,
progress: 0.2,
progress: 0,
factor: 0,
text: "and I will return leading the pack"
};
}
......@@ -34,7 +36,8 @@ class Simple extends React.Component {
saturationFactor,
hue,
text,
progress
progress,
factor
} = this.state;
return <ScrollView style={styles.container}>
......@@ -111,6 +114,16 @@ class Simple extends React.Component {
/>
</View>
<Text style={styles.demoTitle}>7. Blur (2-pass)</Text>
<View style={styles.demo}>
<Blur width={256} height={180} factor={factor}>
http://i.imgur.com/3On9QEu.jpg
</Blur>
<SliderIOS
maximumValue={2}
onValueChange={factor => this.setState({ factor })} />
</View>
</View>
</ScrollView>;
}
......
This diff is collapsed.
#import <GLKit/GLKit.h>
#import "GLData.h"
@interface GLCanvas: GLKView
@property (nonatomic) GLData *data;
@property (nonatomic) BOOL opaque;
@property (nonatomic) NSNumber *nbTargets;
- (instancetype)initWithBridge:(RCTBridge *)bridge
withContext:(EAGLContext*)context;
@end
#import "RCTBridge.h"
#import "RCTUtils.h"
#import "RCTConvert.h"
#import "RCTLog.h"
#import "GLCanvas.h"
#import "GLShader.h"
#import "GLShadersRegistry.h"
#import "GLTexture.h"
#import "GLImage.h"
#import "GLRenderData.h"
// For reference, see implementation of gl-shader's GLCanvas
@implementation GLCanvas
{
RCTBridge *_bridge; // bridge is required to instanciate GLReactImage
GLRenderData *_renderData;
NSArray *_targetTextures;
NSDictionary *_images; // This caches the currently used images (imageSrc -> GLReactImage)
BOOL _opaque; // opaque prop (if false, the GLCanvas will become transparent)
BOOL _deferredRendering; // This flag indicates a render has been deferred to the next frame (when using GL.Target)
GLint defaultFBO;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
withContext:(EAGLContext*)context
{
if ((self = [super init])) {
_bridge = bridge;
_images = @{};
self.context = context;
}
return self;
}
RCT_NOT_IMPLEMENTED(-init)
- (void)setOpaque:(BOOL)opaque
{
_opaque = opaque;
[self setNeedsDisplay];
}
NSString* srcResource (id res)
{
NSString *src;
if ([res isKindOfClass:[NSString class]]) {
src = [RCTConvert NSString:res];
} else {
BOOL isStatic = [RCTConvert BOOL:res[@"isStatic"]];
src = [RCTConvert NSString:res[@"path"]];
if (!src || isStatic) src = [RCTConvert NSString:res[@"uri"]];
}
return src;
}
- (void)setData:(GLData *)data
{
_data = data;
[self requestSyncData];
}
- (void)requestSyncData
{
[self syncData];
}
- (void)syncData
{
[EAGLContext setCurrentContext:self.context];
@autoreleasepool {
NSDictionary *prevImages = _images;
NSMutableDictionary *images = [[NSMutableDictionary alloc] init];
GLRenderData * (^traverseTree) (GLData *data, int frameIndex);
__block __weak GLRenderData * (^weak_traverseTree)(GLData *data, int frameIndex);
weak_traverseTree = traverseTree = ^GLRenderData *(GLData *data, int frameIndex) {
NSNumber *width = data.width;
NSNumber *height = data.height;
// Traverse children and compute GLRenderData
NSMutableArray *children = [[NSMutableArray alloc] init];
NSMutableDictionary *fbosMapping = [[NSMutableDictionary alloc] init];
int fboId = 0;
int i = 0;
for (GLData *child in data.children) {
if (fboId == frameIndex) fboId ++;
fbosMapping[[NSNumber numberWithInt:i]] = [NSNumber numberWithInt:fboId];
[children addObject:traverseTree(child, fboId)];
fboId ++;
i ++;
}
GLShader *shader = [GLShadersRegistry getShader:data.shader];
NSDictionary *uniformTypes = [shader uniformTypes];
NSMutableDictionary *uniforms = [[NSMutableDictionary alloc] init];
NSMutableDictionary *textures = [[NSMutableDictionary alloc] init];
int units = 0;
for (NSString *uniformName in data.uniforms) {
id value = [data.uniforms objectForKey:uniformName];
GLenum type = [uniformTypes[uniformName] intValue];
if (value && (type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE)) {
uniforms[uniformName] = [NSNumber numberWithInt:units++];
NSString *type = [RCTConvert NSString:value[@"type"]];
if ([type isEqualToString:@"target"]) {
int id = [[RCTConvert NSNumber:value[@"id"]] intValue];
if (id >= [_targetTextures count]) {
[self resizeTargets:id+1];
}
textures[uniformName] = _targetTextures[id];
}
else if ([type isEqualToString:@"framebuffer"]) {
NSNumber *id = fbosMapping[[RCTConvert NSNumber:value[@"id"]]];
GLFBO *fbo = [GLShadersRegistry getFBO:id];
textures[uniformName] = fbo.color[0];
}
else if ([type isEqualToString:@"image"]) {
NSObject *val = value[@"value"];
NSString *src = srcResource(val);
if (!src) {
RCTLogError(@"invalid uniform '%@' texture value '%@'", uniformName, value);
}
GLImage *image = images[src];
if (image == nil) {
image = prevImages[src];
if (image != nil)
images[src] = image;
}
if (image == nil) {
image = [[GLImage alloc] initWithBridge:_bridge withOnLoad:^{
[self requestSyncData];
}];
image.src = src;
images[src] = image;
}
textures[uniformName] = [image getTexture];
}
else {
RCTLogError(@"invalid uniform '%@' value of type '%@'", uniformName, type);
}
}
else {
uniforms[uniformName] = value;
}
}
int maxTextureUnits;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
if (units > maxTextureUnits) {
RCTLogError(@"Maximum number of texture reach. got %i >= max %i", units, maxTextureUnits);
}
for (NSString *uniformName in shader.uniformTypes) {
if (uniforms[uniformName] == nil) {
RCTLogError(@"All defined uniforms must be provided. Missing '%@'", uniformName);
}
}
return [[GLRenderData alloc] initWithShader:shader withUniforms:uniforms withTextures:textures withWidth:width withHeight:height withFrameIndex:frameIndex withChildren:children];
};
_renderData = traverseTree(_data, -1);
_images = images;
[self setNeedsDisplay];
}
}
- (void)setNbTargets:(NSNumber *)nbTargets
{
[self resizeTargets:[nbTargets intValue]];
}
- (void)resizeTargets:(int)n
{
[EAGLContext setCurrentContext:self.context];
int length = (int) [_targetTextures count];
if (length == n) return;
if (n < length) {
_targetTextures = [_targetTextures subarrayWithRange:NSMakeRange(0, n)];
}
else {
NSMutableArray *targetTextures = [[NSMutableArray alloc] initWithArray:_targetTextures];
for (int i = (int) [_targetTextures count]; i < n; i++) {
[targetTextures addObject:[[GLTexture alloc] init]];
}
_targetTextures = targetTextures;
}
}
- (void)syncTargetTextures
{
int i = 0;
for (GLTexture *texture in _targetTextures) {
UIView* view = self.superview.subviews[i]; // We take siblings by index (closely related to the JS code)
if (view) {
[texture setPixelsWithView:view];
} else {
[texture setPixelsEmpty];
}
i ++;
}
}
- (void)drawRect:(CGRect)rect
{
BOOL needsDeferredRendering = _nbTargets > 0;
if (needsDeferredRendering && !_deferredRendering) {
dispatch_async(dispatch_get_main_queue(), ^{
_deferredRendering = true;
[self setNeedsDisplay];
});
}
else {
[self render:rect];
_deferredRendering = false;
}
}
- (void)render:(CGRect)rect
{
if (!_renderData) return;
self.layer.opaque = _opaque;
CGFloat scale = RCTScreenScale();
@autoreleasepool {
void (^recDraw) (GLRenderData *renderData);
__block __weak void (^weak_recDraw) (GLRenderData *renderData);
weak_recDraw = recDraw = ^void(GLRenderData *renderData) {
float w = [renderData.width floatValue] * scale;
float h = [renderData.height floatValue] * scale;
for (GLRenderData *child in renderData.children)
recDraw(child);
if (renderData.frameIndex == -1) {
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
glViewport(0, 0, w, h);
}
else {
GLFBO *fbo = [GLShadersRegistry getFBO:[NSNumber numberWithInt:renderData.frameIndex]];
[fbo setShapeWithWidth:w withHeight:h];
[fbo bind];
}
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0, 0.0, 0.0, 0.0);
[renderData.shader bind];
for (NSString *uniformName in renderData.textures) {
GLTexture *texture = renderData.textures[uniformName];
int unit = [((NSNumber *)renderData.uniforms[uniformName]) intValue];
[texture bind:unit];
}
for (NSString *uniformName in renderData.uniforms) {
[renderData.shader setUniform:uniformName withValue:renderData.uniforms[uniformName]];
}
glDrawArrays(GL_TRIANGLES, 0, 6);
};
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO);
[self syncTargetTextures];
recDraw(_renderData);
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
}
}
@end
\ No newline at end of file
#import "RCTViewManager.h"
@interface GLViewManager : RCTViewManager
@interface GLCanvasManager : RCTViewManager
@end
#import "GLViewManager.h"
#import "GLView.h"
#import "GLCanvasManager.h"
#import "GLCanvas.h"
#import "RCTConvert+GLData.h"
#import "RCTLog.h"
#import <UIKit/UIKit.h>
@implementation GLViewManager
#import "GLShadersRegistry.h"
@implementation GLCanvasManager
RCT_EXPORT_MODULE();
......@@ -15,16 +18,14 @@ RCT_EXPORT_MODULE();
return self;
}
RCT_EXPORT_VIEW_PROPERTY(uniforms, NSDictionary);
RCT_EXPORT_VIEW_PROPERTY(shader, NSNumber);
RCT_EXPORT_VIEW_PROPERTY(targetUniforms, NSArray);
RCT_EXPORT_VIEW_PROPERTY(nbTargets, NSNumber);
RCT_EXPORT_VIEW_PROPERTY(opaque, BOOL);
RCT_EXPORT_VIEW_PROPERTY(targetIncrement, NSNumber);
RCT_EXPORT_VIEW_PROPERTY(data, GLData);
- (UIView *)view
{
GLView * v;
v = [[GLView alloc] initWithBridge:self.bridge];
GLCanvas * v;
v = [[GLCanvas alloc] initWithBridge:self.bridge withContext:[GLShadersRegistry getContext]];
return v;
}
......
#import <Foundation/Foundation.h>
@interface GLData: NSObject
@property (nonatomic) NSNumber *shader;
@property (nonatomic) NSDictionary *uniforms;
@property (nonatomic) NSNumber *width;
@property (nonatomic) NSNumber *height;
@property (nonatomic) NSArray *children;
-(instancetype)initWithShader: (NSNumber *)shader
withUniforms: (NSDictionary *)uniforms
withWidth: (NSNumber *)width
withHeight: (NSNumber *)height
withChildren: (NSArray *)children;
@end
#import "GLData.h"
@implementation GLData
-(instancetype)initWithShader: (NSNumber *)shader
withUniforms: (NSDictionary *)uniforms
withWidth: (NSNumber *)width
withHeight: (NSNumber *)height
withChildren: (NSArray *)children
{
if ((self = [super init])) {
self.shader = shader;
self.uniforms = uniforms;
self.width = width;
self.height = height;
self.children = children;
}
return self;
}
@end
#import <GLKit/GLKit.h>
@interface GLFBO: NSObject
@property (nonatomic) EAGLContext *context;
// This contains the framebuffer GLTexture instances
@property (nonatomic) NSArray *color;
- (instancetype)init;
- (void)bind;
- (void)setShapeWithWidth:(float)width withHeight:(float)height;
@end
#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);
glBindRenderbuffer(GL_FRAMEBUFFER, _rbo);
glBindTexture(GL_FRAMEBUFFER, _tex);
}
@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;
}
GLuint initRenderBuffer (float width, float height, GLuint component, GLuint attachment)
{
GLuint handle;
glGenRenderbuffers(1, &handle);
glBindRenderbuffer(GL_RENDERBUFFER, handle);
glRenderbufferStorage(GL_RENDERBUFFER, component, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, handle);
return handle;
}
@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);
if( _width < 0 || _width > maxFBOSize ||
_height < 0 || _height > maxFBOSize) {
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
#import "RCTBridge.h"
#import "ImageData.h"
#import "GLTexture.h"
@interface GLReactImage: NSObject
@interface GLImage: NSObject
@property (nonatomic, copy) NSString *src;
@property (nonatomic) UIImage *image;
......@@ -10,6 +10,6 @@
- (instancetype)initWithBridge:(RCTBridge *)bridge withOnLoad:(void (^)(void))onload NS_DESIGNATED_INITIALIZER;
- (ImageData *) getImageData;
- (GLTexture *) getTexture;
@end
#import "GLReactImage.h"
#import "GLUtils.h"
#import "ImageData.h"
#import "GLImage.h"
#import "GLImageData.h"
#import "RCTBridge.h"
#import "RCTImageLoader.h"
#import "RCTLog.h"
#import "GLTexture.h"
@implementation GLReactImage
@implementation GLImage
{
RCTBridge *_bridge; // React's bridge allow to access the imageLoader
UIImage *_image; // The currently loaded image (nil if no image fully loaded yet)
ImageData *_data; // Cache of the _data related to this image (computed by getImageData)
GLImageData *_data; // Cache of the data related to this image (computed by getImageData)
GLTexture *_texture; // Cache of the texture
void (^_onload)(void); // called everytime an image loads
RCTImageLoaderCancellationBlock _loading; // the current loading cancellation function
}
......@@ -23,6 +23,7 @@
_onload = onload;
_image = nil;
_loading = nil;
_texture = [[GLTexture alloc] init];
}
return self;
}
......@@ -34,6 +35,7 @@
_onload = nil;
_loading = nil;
_bridge = nil;
_texture = nil;
}
RCT_NOT_IMPLEMENTED(-init)
......@@ -44,17 +46,23 @@ RCT_NOT_IMPLEMENTED(-init)
_data = nil;
}
- (ImageData *) getImageData
- (GLTexture *) getTexture
{
if (!_data) {
_data = genPixelsWithImage(_image);
if (_image) {
if (!_data) {
_data = genPixelsWithImage(_image);
}
[_texture setPixels:_data];
}
else {
[_texture setPixelsEmpty];
}
return _data;
return _texture;
}
- (void)setSrc:(NSString *)src
{
if (![src isEqual:_src]) {
if (![src isEqualToString:_src]) {
_src = [src copy];
[self reloadImage];
}
......
#import <GLKit/GLKit.h>
@interface ImageData: NSObject
@interface GLImageData: NSObject
@property (nonatomic) GLubyte *data;
@property (nonatomic) int width;
......
#import "ImageData.h"
#import "GLImageData.h"
// TODO: rename to GLImageData
// This structure aims to be used in an immutable way
@implementation ImageData
@implementation GLImageData
{
GLubyte *_data;
int _width;
......
#import "GLShader.h"
@interface GLRenderData : NSObject
@property (nonatomic) GLShader *shader;
@property (nonatomic) NSDictionary *uniforms;
@property (nonatomic) NSDictionary *textures;
@property (nonatomic) NSNumber *width;
@property (nonatomic) NSNumber *height;
@property (nonatomic) int frameIndex;
@property (nonatomic) NSArray *children;
-(instancetype) initWithShader: (GLShader *)shader
withUniforms:(NSDictionary *)uniforms
withTextures: (NSDictionary *)textures
withWidth: (NSNumber *)width
withHeight: (NSNumber *)height
withFrameIndex: (int)frameIndex
withChildren: (NSArray *)children;
@end
#include "GLRenderData.h"
@implementation GLRenderData
-(instancetype) initWithShader: (GLShader *)shader
withUniforms:(NSDictionary *)uniforms
withTextures: (NSDictionary *)textures
withWidth: (NSNumber *)width
withHeight: (NSNumber *)height
withFrameIndex: (int)frameIndex
withChildren: (NSArray *)children
{
if ((self = [super init])) {
self.shader = shader;
self.uniforms = uniforms;
self.textures = textures;
self.width = width;
self.height = height;
self.frameIndex = frameIndex;
self.children = children;
}
return self;
}
@end
\ No newline at end of file
......@@ -3,9 +3,31 @@
#import "RCTBridgeModule.h"
#import "RCTLog.h"
#import "RCTConvert.h"
#import "GLUtils.h"
#import "GLShader.h"
GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shaderType) {
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]);
NSString *messageString = [NSString stringWithUTF8String:messages];
RCTLogError(@"Shader '%@' failed to compile: %@", shaderName, messageString);
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)
......
#import <UIKit/UIKit.h>
#import "RCTBridgeModule.h"
#import "GLShader.h"
#import "GLFBO.h"
@interface GLShadersRegistry : NSObject <RCTBridgeModule>
......@@ -8,7 +9,11 @@
/**
* Get the global shader for a given id.
*/
+ (GLShader*) getShader: (NSNumber *)ctxid;
+ (GLShader*) getShader: (NSNumber *)id;
+ (GLFBO*) getFBO: (NSNumber *)id;
+ (EAGLContext *) getContext;
@property NSMutableDictionary *shaders;
@end
......@@ -5,22 +5,36 @@
#import "RCTLog.h"
#import "GLShadersRegistry.h"
// FIXME: current context and fbos live here... this should be global somewhere else.
@implementation GLShadersRegistry
{
NSMutableDictionary *_shaders;
EAGLContext *_context;
NSMutableDictionary *_fbos;
}
GLShadersRegistry *GLShadersRegistry_instance; // FIXME is that the proper way to do singleton?
RCT_EXPORT_MODULE();
+ (GLShader*) getShader: (NSNumber *)ctxid
+ (GLShader*) getShader: (NSNumber *)id
{
return [GLShadersRegistry_instance shaders][ctxid];
return [GLShadersRegistry_instance getShader:id];
}
+ (GLFBO *) getFBO: (NSNumber *)id
{
return [GLShadersRegistry_instance getFBO:id];
}
+ (EAGLContext *) getContext
{
return [GLShadersRegistry_instance getContext];
}
// methods
- (instancetype)init
{
self = [super init];
......@@ -30,15 +44,37 @@ RCT_EXPORT_MODULE();
RCTLogError(@"Failed to initialize OpenGLES 2.0 context");
}
_shaders = @{}.mutableCopy;
_fbos = @{}.mutableCopy;
GLShadersRegistry_instance = self;
}
return self;
}
- (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;
}
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));}";
RCT_EXPORT_METHOD(register:(nonnull NSNumber *)id withConfig:(NSDictionary *)config withName:(NSString *)name) {
RCT_EXPORT_METHOD(register:(nonnull NSNumber *)id withConfig:(NSDictionary *)config) {
NSString *frag = [RCTConvert NSString:config[@"frag"]];
NSString *name = [RCTConvert NSString:config[@"name"]];
if (!frag) {
RCTLogError(@"Shader '%@': missing frag field", name);
return;
......
#import <GLKit/GLKit.h>
#import "RCTBridge.h"
#import "ImageData.h"
#import "GLImageData.h"
GLImageData* genPixelsWithImage (UIImage *image);
@interface GLTexture: NSObject
@property EAGLContext *context;
@property GLuint handle;
- (instancetype)init;
- (int)bind: (int)unit;
- (void)bind;
- (void)setShapeWithWidth:(float)width withHeight:(float)height;
- (void)setPixels: (ImageData *)data;
- (void)setPixels: (GLImageData *)data;
- (void)setPixelsEmpty;
- (void)setPixelsRandom: (int)width withHeight:(int)height;
- (void)setPixelsWithImage: (UIImage *)image;
......
#import "GLTexture.h"
#import "GLUtils.h"
#import "RCTLog.h"
GLImageData* genPixelsEmpty (int width, int height)
{
GLubyte* data = (GLubyte *) malloc(width*height*4*sizeof(GLubyte));
for (int i = 0; i < width * height * 4; i+=4) {
data[i] = data[i+1] = data[i+2] = 0;
data[i+3] = 0;
}
return [[GLImageData alloc] initWithData:data withWidth:width withHeight:height];
}
GLImageData* genPixelsRandom (int width, int height)
{
GLubyte* data = (GLubyte *) malloc(width*height*4*sizeof(GLubyte));
for (int i = 0; i < width * height * 4; i+=4) {
data[i] = rand() % 255;
data[i+1] = rand() % 255;
data[i+2] = rand() % 255;
data[i+3] = 255;
}
return [[GLImageData alloc] initWithData:data withWidth:width withHeight:height];
}
GLImageData* genPixelsWithImage (UIImage *image)
{
int width = image.size.width;
int height = image.size.height;
if (width == 0 || height == 0) {
RCTLogError(@"The image must be loaded in setPixelsWithImage call");
return nil;
}
GLubyte* data = malloc(width * height * 4);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(data, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
if (ctx == NULL) {
RCTLogError(@"unable to create the bitmap context");
CGColorSpaceRelease(colorSpace);
free(data);
return nil;
}
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, height);
CGContextConcatCTM(ctx, flipVertical);
CGRect rect = CGRectMake(0.0, 0.0, width, height);
CGContextClearRect(ctx, rect);
CGContextDrawImage(ctx, rect, image.CGImage);
CGColorSpaceRelease(colorSpace);
CGContextRelease(ctx);
return [[GLImageData alloc] initWithData:data withWidth:width withHeight:height];
}
GLImageData* genPixelsWithView (UIView *view)
{
int width = view.bounds.size.width;
int height = view.bounds.size.height;
GLubyte *data = (GLubyte *)malloc(4 * width * height);
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(data, width, height, 8, 4 * width, colourSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colourSpace);
CGContextClearRect(ctx, view.bounds);
[view.layer renderInContext:ctx];
CGContextRelease(ctx);
return [[GLImageData alloc] initWithData:data withWidth:width withHeight:height];
}
@implementation GLTexture
{
GLuint handle; // The identifier of the gl texture
ImageData* dataCurrentlyUploaded; // The last set data (cache)
GLuint _handle; // The identifier of the gl texture
GLImageData* dataCurrentlyUploaded; // The last set data (cache)
}
GLImageData *EMPTY_PIXELS;
- (instancetype)init
{
if (!EMPTY_PIXELS) {
EMPTY_PIXELS = genPixelsEmpty(2, 2);
}
self = [super init];
if (self) {
[self makeTexture];
......@@ -19,67 +87,68 @@
- (void)dealloc
{
glDeleteTextures(1, &handle);
glDeleteTextures(1, &_handle);
dataCurrentlyUploaded = nil;
}
- (void) makeTexture
{
glGenTextures(1, &handle);
glBindTexture(GL_TEXTURE_2D, handle);
glGenTextures(1, &_handle);
glBindTexture(GL_TEXTURE_2D, _handle);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
- (bool) ensureContext
{
if (![EAGLContext setCurrentContext:_context]) {
RCTLogError(@"Failed to set current OpenGL context");
return false;
}
return true;
}
- (int)bind: (int)unit
{
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, handle);
glBindTexture(GL_TEXTURE_2D, _handle);
return unit;
}
- (void)setPixels: (ImageData *)data
- (void)bind
{
glBindTexture(GL_TEXTURE_2D, _handle);
}
- (void)setShapeWithWidth:(float)width withHeight:(float)height
{
[self bind];
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
}
- (void)setPixels: (GLImageData *)data
{
if (data != dataCurrentlyUploaded) {
dataCurrentlyUploaded = data;
glBindTexture(GL_TEXTURE_2D, handle);
[self bind];
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data.width, data.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.data);
}
}
- (void)setPixelsEmpty
{
ImageData* data = genPixelsEmpty(2, 2);
[self setPixels:data];
[self setPixels:EMPTY_PIXELS];
}
- (void)setPixelsRandom: (int)width withHeight:(int)height // for testing
{
ImageData* data = genPixelsRandom(width, height);
GLImageData* data = genPixelsRandom(width, height);
[self setPixels:data];
}
- (void)setPixelsWithImage: (UIImage *)image
{
ImageData *data = genPixelsWithImage(image);
GLImageData *data = genPixelsWithImage(image);
if (!data) return;
[self setPixels:data];
}
- (void)setPixelsWithView: (UIView *)view
{
ImageData *data = genPixelsWithView(view);
GLImageData *data = genPixelsWithView(view);
[self setPixels:data];
}
......
#import <GLKit/GLKit.h>
#import "ImageData.h"
GLuint compileShader (NSString *shaderName, NSString *shaderString, GLenum shaderType);
ImageData* genPixelsEmpty (int width, int height);
ImageData* genPixelsRandom (int width, int height);
ImageData* genPixelsWithImage (UIImage *image);
ImageData* genPixelsWithView (UIView *view);
\ No newline at end of file
#import "GLUtils.h"
#import "RCTLog.h"
GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shaderType) {
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]);
NSString *messageString = [NSString stringWithUTF8String:messages];
RCTLogError(@"Shader '%@' failed to compile: %@", shaderName, messageString);
return -1;
}
return shaderHandle;
}
ImageData* genPixelsEmpty (int width, int height)
{
GLubyte* data = (GLubyte *) malloc(width*height*4*sizeof(GLubyte));
for (int i = 0; i < width * height * 4; i+=4) {
data[i] = data[i+1] = data[i+2] = 0;
data[i+3] = 0;
}
return [[ImageData alloc] initWithData:data withWidth:width withHeight:height];
}
ImageData* genPixelsRandom (int width, int height)
{
GLubyte* data = (GLubyte *) malloc(width*height*4*sizeof(GLubyte));
for (int i = 0; i < width * height * 4; i+=4) {
data[i] = rand() % 255;
data[i+1] = rand() % 255;
data[i+2] = rand() % 255;
data[i+3] = 255;
}
return [[ImageData alloc] initWithData:data withWidth:width withHeight:height];
}
ImageData* genPixelsWithImage (UIImage *image)
{
int width = image.size.width;
int height = image.size.height;
if (width == 0 || height == 0) {
RCTLogError(@"The image must be loaded in setPixelsWithImage call");
return nil;
}
GLubyte* data = malloc(width * height * 4);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(data, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
if (ctx == NULL) {
RCTLogError(@"unable to create the bitmap context");
CGColorSpaceRelease(colorSpace);
free(data);
return nil;
}
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, height);
CGContextConcatCTM(ctx, flipVertical);
CGRect rect = CGRectMake(0.0, 0.0, width, height);
CGContextClearRect(ctx, rect);
CGContextDrawImage(ctx, rect, image.CGImage);
CGColorSpaceRelease(colorSpace);
CGContextRelease(ctx);
return [[ImageData alloc] initWithData:data withWidth:width withHeight:height];
}
ImageData* genPixelsWithView (UIView *view)
{
int width = view.bounds.size.width;
int height = view.bounds.size.height;
GLubyte *data = (GLubyte *)malloc(4 * width * height);
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(data, width, height, 8, 4 * width, colourSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colourSpace);
CGContextClearRect(ctx, view.bounds);
[view.layer renderInContext:ctx];
CGContextRelease(ctx);
return [[ImageData alloc] initWithData:data withWidth:width withHeight:height];
}
\ No newline at end of file
#import <GLKit/GLKit.h>
@interface GLView : GLKView
@property (nonatomic) NSNumber *shader;
@property (nonatomic) NSDictionary *uniforms;
@property (nonatomic) NSArray *targetUniforms;
@property (nonatomic) BOOL opaque;
@property (nonatomic) NSNumber *targetIncrement;
- (instancetype)initWithBridge:(RCTBridge *)bridge;
@end
#import "RCTBridge.h"
#import "RCTUtils.h"
#import "RCTConvert.h"
#import "RCTLog.h"
#import "GLView.h"
#import "GLUtils.h"
#import "GLShader.h"
#import "GLShadersRegistry.h"
#import "GLTexture.h"
#import "GLReactImage.h"
@implementation GLView
{
RCTBridge *_bridge; // bridge is required to instanciate GLReactImage
GLShader *glShader; // The current GLShader used by the view
NSDictionary *_uniforms; // The current uniforms bound to the shader (name -> value)
NSArray *_targetUniforms; // When using GL.Target, this defines the uniform names to render into
NSDictionary *_textures; // This allocate the sampler2D uniforms of the shaders (name -> glTexture)
NSDictionary *_textureUnits; // This stores the image unit for a given sampler2D uniform (name -> int)
NSDictionary *_images; // This caches the currently used images (imageSrc -> GLReactImage)
BOOL _opaque; // opaque prop (if false, the GLView will become transparent)
BOOL _deferredRendering; // This flag indicates a render has been deferred to the next frame (when using GL.Target)
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
{
if ((self = [super init])) {
_bridge = bridge;
_images = @{};
}
return self;
}
RCT_NOT_IMPLEMENTED(-init)
- (void)setShader:(NSNumber *)ctxid
{
glShader = [GLShadersRegistry getShader:ctxid];
if (!glShader) {
return; // the shader might not have been uploaded yet from the JS (invalid ctxid are checked on JS side to avoid concurrency issues)
}
[glShader bind];
// Cache the textures
NSMutableDictionary *textures = @{}.mutableCopy;
NSMutableDictionary *textureUnits = @{}.mutableCopy;
int unit = 0;
NSDictionary *uniformTypes = [glShader uniformTypes];
for (NSString *uniformName in [uniformTypes allKeys]) {
GLenum type = [uniformTypes[uniformName] intValue];
if (type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE) {
textures[uniformName] = [[GLTexture alloc] init];
textureUnits[uniformName] = [NSNumber numberWithInt: unit ++];
}
}
int maxTextureUnits;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
if (unit > maxTextureUnits) {
RCTLogError(@"Maximum number of texture reach. got %i >= max %i", unit, maxTextureUnits);
}
_textures = textures;
_textureUnits = textureUnits;
[self setContext:glShader.context]; // use the shader's context (currently it is the same for all shaders)
[self setUniforms:_uniforms]; // Ensure uniforms are not set before
[self setNeedsDisplay];
}
NSString* srcResource (id res)
{
NSString *src;
if ([res isKindOfClass:[NSString class]]) {
src = [RCTConvert NSString:res];
} else {
BOOL isStatic = [RCTConvert BOOL:res[@"isStatic"]];
src = [RCTConvert NSString:res[@"path"]];
if (!src || isStatic) src = [RCTConvert NSString:res[@"uri"]];
}
return src;
}
- (void)setUniforms:(NSDictionary *)uniforms
{
/// Diff logic on texture uniforms to manage the _images cache.
NSMutableSet *currentResources = [[NSMutableSet alloc] init];
NSMutableDictionary *images = _images.mutableCopy;
for (NSString *name in [_uniforms allKeys]) {
id uniformValue = _uniforms[name];
GLTexture *texture = _textures[name];
if (texture) {
// Texture uniform
NSString *src = srcResource(uniformValue);
if (!src) {
RCTLogError(@"resource is not valid.");
return;
}
GLReactImage *image = _images[src];
if (!image) {
image = [[GLReactImage alloc] initWithBridge:_bridge withOnLoad:^{
[self setNeedsDisplay];
}];
images[src] = image;
}
image.src = src;
[currentResources addObject:src];
}
}
// remove old resources (that are not anymore used in new uniforms)
NSMutableSet *toDelete = [NSMutableSet setWithArray:[images allKeys]];
[toDelete minusSet:currentResources];
for (NSString *src in toDelete) {
GLReactImage *image = images[src];
image.src = nil;
}
[images removeObjectsForKeys:[toDelete allObjects]];
// Finally set the new state and request a rendering.
_images = images;
_uniforms = uniforms;
[self setNeedsDisplay];
}
- (void)setTargetIncrement:(NSNumber *)targetIncrement
{
[self setNeedsDisplay];
}
- (void)setTargetUniforms:(NSArray *)targetUniforms
{
_targetUniforms = targetUniforms;
[self setNeedsDisplay];
}
- (void)setOpaque:(BOOL)opaque
{
_opaque = opaque;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
BOOL needsDeferredRendering = _targetUniforms != nil;
if (needsDeferredRendering && !_deferredRendering) {
dispatch_async(dispatch_get_main_queue(), ^{
_deferredRendering = true;
[self setNeedsDisplay];
});
}
else {
[self render:rect];
_deferredRendering = false;
}
}
- (void)render:(CGRect)rect
{
if (!glShader) {
return;
}
self.layer.opaque = _opaque;
[glShader bind];
// Setting uniforms
for (NSString *name in [_uniforms allKeys]) {
id uniformValue = _uniforms[name];
GLTexture *texture = _textures[name];
if (texture) {
// Texture uniform
int unit = [_textureUnits[name] intValue];
GLReactImage *image = _images[srcResource(uniformValue)];
NSNumber *value = [NSNumber numberWithInt: [texture bind:unit]];
if (image.image) {
[texture setPixels:[image getImageData]];
} else {
[texture setPixelsEmpty];
}
[glShader setUniform:name withValue:value];
} else {
// Simple uniform
[glShader setUniform:name withValue:uniformValue];
}
}
// Handling <GL.Target /> children rasterisation
if (_targetUniforms) {
int i = 0;
for (NSString *uniformName in _targetUniforms) {
GLTexture *texture = _textures[uniformName];
if (!texture) {
RCTLogError(@"There is no sampler uniform called '%@' in your shader", uniformName);
return;
}
UIView* view = self.superview.subviews[i]; // We take siblings by index (closely related to the JS code)
int unit = [_textureUnits[uniformName] intValue];
NSNumber *value = [NSNumber numberWithInt: [texture bind:unit]];
if (view) {
[texture setPixelsWithView:view];
} else {
[texture setPixelsEmpty];
}
[glShader setUniform:uniformName withValue:value];
i ++;
}
}
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0, 0.0, 0.0, 0.0);
CGFloat scale = RCTScreenScale();
glViewport(0, 0, scale * self.frame.size.width, scale * self.frame.size.height);
glScissor(scale * rect.origin.x, scale * rect.origin.y, scale * rect.size.width, scale * rect.size.height);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
@end
\ No newline at end of file
#import "RCTConvert.h"
#import "GLData.h"
@interface RCTConvert (GLData)
+ (GLData *)GLData:(id)json;
@end
#import "RCTConvert+GLData.h"
@implementation RCTConvert (GLData)
+ (GLData *)GLData:(id)json
{
json = [self NSDictionary:json];
NSNumber *shader = [self NSNumber:json[@"shader"]];
NSDictionary *uniforms = [self NSDictionary:json[@"uniforms"]];
NSNumber *width = [self NSNumber:json[@"width"]];
NSNumber *height = [self NSNumber:json[@"height"]];
NSArray *childrenJSON = [self NSArray: json[@"children"]];
NSMutableArray *children = [NSMutableArray array];
for (NSObject *childJSON in childrenJSON) {
GLData *child = [self GLData:childJSON];
[children addObject:child];
}
return [[GLData alloc] initWithShader: shader
withUniforms: uniforms
withWidth: width
withHeight: height
withChildren: children];
}
@end
const invariant = require("invariant");
const React = require("react-native");
const {
NativeModules: { GLShadersRegistry },
requireNativeComponent,
Component,
PropTypes,
View,
} = React;
let _uid = 1;
const Shaders = {
create: function (obj) {
invariant(typeof obj === "object", "config must be an object");
const result = {};
for (let key in obj) {
const shader = obj[key];
invariant(typeof shader === "object" && typeof shader.frag === "string",
"invalid shader given to Shaders.create(). A valid shader is a { frag: String }");
const id = _uid ++;
GLShadersRegistry.register(id, shader, key);
result[key] = id;
}
return result;
},
exists: function (id) {
return typeof id === "number" && id >= 1 && id < _uid;
}
};
class Target extends Component {
render () {
invariant(
false,
"GL.Target elements are for GL.View configuration only and should not be rendered"
);
}
}
Target.displayName = "GL.Target";
Target.propTypes = {
children: PropTypes.any.isRequired,
uniform: PropTypes.string.isRequired
};
const GLViewNative = requireNativeComponent("GLView", GLView);
class GLView extends Component {
constructor (props, context) {
super(props, context);
this._targetIncrement = 0; // This is a current workaround to force the refresh of targets
}
setNativeProps (props) {
this.refs.native.setNativeProps(props);
}
render() {
const props = this.props;
const { style, width, height, children, shader } = props;
invariant(Shaders.exists(shader), "Shader #%s does not exists", shader);
const nativeStyle = {
width: width,
height: height,
...style
};
if (children) {
const parentStyle = {
position: "relative",
width: width,
height: height,
overflow: "hidden"
};
const childrenStyle = {
position: "absolute",
top: 0,
left: 0,
width: width,
height: height
};
const targetUniforms = [];
const targets = React.Children.map(children, child => {
invariant(child.type === Target, "GL.View can only contains children of type GL.Target. Got '%s'", child.type && child.type.displayName || child);
const uniform = child.props.uniform;
targetUniforms.push(uniform);
return <View style={[ childrenStyle, child.props.style ]}>{child.props.children}</View>;
});
return <View style={parentStyle}>
{targets}
<GLViewNative
ref="native"
{...props}
style={nativeStyle}
children={undefined}
targetUniforms={targetUniforms}
targetIncrement={this._targetIncrement++} />
</View>;
}
else {
return <GLViewNative ref="native" {...props} style={nativeStyle} />;
}
}
}
GLView.displayName = "GL.View";
GLView.propTypes = {
shader: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
uniforms: PropTypes.object,
opaque: PropTypes.bool
};
GLView.defaultProps = {
opaque: true
};
module.exports = {
View: GLView,
Target,
Shaders
};
......@@ -2,7 +2,7 @@
"name": "gl-react-native",
"version": "0.0.1",
"description": "OpenGL bindings for react-native to implement complex effects over images and components, in VDOM descriptive paradigm",
"main": "index.js",
"main": "src/index.js",
"repository": {
"type": "git",
"url": "github.com:ProjectSeptemberInc/gl-react-native.git"
......@@ -18,10 +18,11 @@
},
"dependencies": {
"invariant": "^2.1.0",
"react-native": "^0.9.0"
"react-native": "^0.9.0",
"gl-react-core": "git+ssh://git@github.com:ProjectSeptemberInc/gl-react-core.git"
},
"devDependencies": {
"eslint": "^1.1.0",
"eslint": "^1.2.1",
"eslint-plugin-react": "^3.2.3"
}
}
const React = require("react-native");
const {createComponent} = require("gl-react-core");
module.exports = createComponent(React);
const {createShaders} = require("gl-react-core");
const { NativeModules: { GLShadersRegistry } } = require("react-native");
module.exports = createShaders(function (id, shader) {
GLShadersRegistry.register(id, shader);
});
const {createTarget} = require("gl-react-core");
const React = require("react-native");
module.exports = createTarget(React);
const {createView} = require("gl-react-core");
const React = require("react-native");
const Shaders = require("./Shaders");
const Target = require("./Target");
const Component = require("./Component");
const {
requireNativeComponent,
View,
} = React;
const GLCanvas = requireNativeComponent("GLCanvas", null);
const renderVtarget = function (style, width, height, id, children) {
const childrenStyle = {
position: "absolute",
top: 0,
left: 0,
width: width,
height: height,
overflow: "hidden"
};
return <View style={[ childrenStyle, style ]}>{children}</View>;
};
const renderVGL = function (props, width, height, data, nbTargets) {
return <GLCanvas
ref="native"
{...props}
style={{ ...props.style, width, height }}
data={data}
nbTargets={nbTargets}
/>;
};
const renderVcontainer = function (style, width, height, targets, renderer) {
if (targets) {
const parentStyle = {
...style,
position: "relative",
width: width,
height: height,
overflow: "hidden"
};
return <View style={parentStyle}>
{targets}
{renderer}
</View>;
}
else {
return renderer;
}
};
const GLView = createView(React, Shaders, Target, Component, renderVcontainer, renderVtarget, renderVGL);
GLView.prototype.setNativeProps = function (props) {
this.refs.native.setNativeProps(props);
};
module.exports = GLView;
const Shaders = require("./Shaders");
const View = require("./View");
const Target = require("./Target");
const Component = require("./Component");
module.exports = {
Shaders,
View,
Target,
Component
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment