diff --git a/Examples/Simple/Button.js b/Examples/Simple/Button.js
new file mode 100644
index 0000000000000000000000000000000000000000..1cf8b932ec697aba7598fd7f9409aae5393e18c9
--- /dev/null
+++ b/Examples/Simple/Button.js
@@ -0,0 +1,42 @@
+const React = require("react-native");
+
+const {
+ StyleSheet,
+ Component,
+ View,
+ Text,
+ TouchableOpacity
+} = React;
+
+const styles = StyleSheet.create({
+ root: {
+ backgroundColor: "#ddd",
+ borderRadius: 4,
+ borderColor: "#ccc",
+ borderWidth: 1,
+ borderStyle: "solid",
+ width: 150,
+ padding: 10
+ },
+ text: {
+ color: "#333"
+ }
+});
+
+class Button extends Component {
+ render () {
+ const { children, width, ...rest } = this.props;
+ return (
+
+
+ {children}
+
+
+ );
+ }
+}
+
+Button.propTypes = {
+};
+
+module.exports = Button;
diff --git a/Examples/Simple/index.ios.js b/Examples/Simple/index.ios.js
index 7b2453a52fbeaff7ba75d1d59c3b9c2900d6e23f..84f844920e190d131f246200c7be351030a6d8b7 100644
--- a/Examples/Simple/index.ios.js
+++ b/Examples/Simple/index.ios.js
@@ -20,6 +20,7 @@ const PieProgress = require("./PieProgress");
const OneFingerResponse = require("./OneFingerResponse");
const AnimatedHelloGL = require("./AnimatedHelloGL");
const Blur = require("./Blur");
+const Button = require("./Button");
class Simple extends React.Component {
constructor (props) {
@@ -33,7 +34,15 @@ class Simple extends React.Component {
switch1: false,
switch2: false,
switch3: false,
+ captured: null
};
+ this.onCapture1 = this.onCapture1.bind(this);
+ }
+
+ onCapture1 () {
+ this.refs.helloGL.captureFrame(data64 => {
+ this.setState({ captured: data64 });
+ });
}
render () {
@@ -46,6 +55,7 @@ class Simple extends React.Component {
switch1,
switch2,
switch3,
+ captured
} = this.state;
return
@@ -56,7 +66,11 @@ class Simple extends React.Component {
1. Hello GL
-
+
+
+
+ {captured && }
+
2. Saturate an Image
diff --git a/RNGL/GLCanvas.h b/RNGL/GLCanvas.h
index a4ffb0038b17577a0cfcaaf690a67d2dbea5d278..835fe5a3eb018aa1b0a311e3e703f972a809de82 100644
--- a/RNGL/GLCanvas.h
+++ b/RNGL/GLCanvas.h
@@ -7,12 +7,14 @@
@property (nonatomic) BOOL opaque;
@property (nonatomic) BOOL autoRedraw;
@property (nonatomic) BOOL eventsThrough;
+@property (nonatomic) int captureNextFrameId;
@property (nonatomic) BOOL visibleContent;
@property (nonatomic) NSNumber *nbContentTextures;
@property (nonatomic) NSNumber *renderId;
@property (nonatomic) NSArray *imagesToPreload;
@property (nonatomic, assign) BOOL onProgress;
@property (nonatomic, assign) BOOL onLoad;
+@property (nonatomic, assign) BOOL onChange;
- (instancetype)initWithBridge:(RCTBridge *)bridge
withContext:(EAGLContext *)context;
diff --git a/RNGL/GLCanvas.m b/RNGL/GLCanvas.m
index 26161ded38fb7185cd2f959d3b0d3a141bfaba06..fa7720be73d1020cda51977516531c2e79ab8caa 100644
--- a/RNGL/GLCanvas.m
+++ b/RNGL/GLCanvas.m
@@ -47,6 +47,8 @@ NSString* srcResource (id res)
BOOL _preloadingDone;
NSTimer *animationTimer;
+
+ int _lastCaptureId;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
@@ -57,6 +59,7 @@ NSString* srcResource (id res)
_images = @{};
_preloaded = [[NSMutableArray alloc] init];
_preloadingDone = false;
+ _lastCaptureId = 0;
self.context = context;
self.contentScaleFactor = RCTScreenScale();
}
@@ -135,6 +138,12 @@ RCT_NOT_IMPLEMENTED(-init)
_nbContentTextures = nbContentTextures;
}
+- (void)setCaptureNextFrameId:(int)captureNextFrameId
+{
+ _captureNextFrameId = captureNextFrameId;
+ [self setNeedsDisplay];
+}
+
//// Sync methods (called from props setters)
- (void) syncEventsThrough
@@ -290,6 +299,7 @@ RCT_NOT_IMPLEMENTED(-init)
{
self.layer.opaque = _opaque;
[self syncEventsThrough];
+ __weak GLCanvas *weakSelf = self;
if (!_preloadingDone) {
glClearColor(0.0, 0.0, 0.0, 0.0);
@@ -299,13 +309,27 @@ RCT_NOT_IMPLEMENTED(-init)
BOOL needsDeferredRendering = _nbContentTextures > 0 && !_autoRedraw;
if (needsDeferredRendering && !_deferredRendering) {
dispatch_async(dispatch_get_main_queue(), ^{
+ if (!weakSelf) return;
_deferredRendering = true;
- [self setNeedsDisplay];
+ [weakSelf setNeedsDisplay];
});
}
else {
[self render];
_deferredRendering = false;
+ if (_captureNextFrameId > _lastCaptureId) {
+ _lastCaptureId ++;
+ int id = _lastCaptureId;
+ dispatch_async(dispatch_get_main_queue(), ^{ // snapshot not allowed in render tick. defer it.
+ if (!weakSelf) return;
+ UIImage *frameImage = [weakSelf snapshot];
+ NSData *frameData = UIImagePNGRepresentation(frameImage);
+ NSString *frame =
+ [NSString stringWithFormat:@"data:image/png;base64,%@",
+ [frameData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]];
+ [weakSelf dispatchOnCapture:frame withId:id];
+ });
+ }
}
}
@@ -433,4 +457,11 @@ RCT_NOT_IMPLEMENTED(-init)
[_bridge.eventDispatcher sendInputEventWithName:@"progress" body:event];
}
+- (void)dispatchOnCapture: (NSString *)frame withId:(int)id
+{
+ NSDictionary *event = @{ @"target": self.reactTag, @"frame": frame, @"id":@(id) };
+ // FIXME: using onChange is a hack before we use the new system to directly call callbacks. we will replace with: self.onCaptureNextFrame(...)
+ [_bridge.eventDispatcher sendInputEventWithName:@"change" body:event];
+}
+
@end
diff --git a/RNGL/GLCanvasManager.m b/RNGL/GLCanvasManager.m
index 4c598f61f6638da626013999d2ca1eac9e736419..7e8cdb3bcc04530e4bc06d2a46011810a8da0eae 100644
--- a/RNGL/GLCanvasManager.m
+++ b/RNGL/GLCanvasManager.m
@@ -23,11 +23,13 @@ RCT_EXPORT_VIEW_PROPERTY(opaque, BOOL);
RCT_EXPORT_VIEW_PROPERTY(autoRedraw, BOOL);
RCT_EXPORT_VIEW_PROPERTY(eventsThrough, BOOL);
RCT_EXPORT_VIEW_PROPERTY(visibleContent, BOOL);
+RCT_EXPORT_VIEW_PROPERTY(captureNextFrameId, int);
RCT_EXPORT_VIEW_PROPERTY(data, GLData);
RCT_EXPORT_VIEW_PROPERTY(renderId, NSNumber);
RCT_EXPORT_VIEW_PROPERTY(imagesToPreload, NSArray);
RCT_EXPORT_VIEW_PROPERTY(onLoad, BOOL);
RCT_EXPORT_VIEW_PROPERTY(onProgress, BOOL);
+RCT_EXPORT_VIEW_PROPERTY(onChange, BOOL);
- (UIView *)view
{
diff --git a/src/GLCanvas.js b/src/GLCanvas.js
new file mode 100644
index 0000000000000000000000000000000000000000..2cb43e77d599c82878070e5e951e452785e0398b
--- /dev/null
+++ b/src/GLCanvas.js
@@ -0,0 +1,58 @@
+const React = require("react-native");
+
+const {
+ Component,
+ requireNativeComponent
+} = React;
+
+const GLCanvasNative = requireNativeComponent("GLCanvas", GLCanvas);
+
+class GLCanvas extends Component {
+ constructor (props) {
+ super(props);
+ this.state = {
+ captureNextFrameId: 0 // the current id to send to the ObjC part.
+ };
+ this._captureId = 1; // track the current id to use for captures. it get incremented when the frame is obtained.
+ this._captureListeners = { [this._captureId]: [] }; // callbacks by capture id
+
+ this._needsCapture = false;
+ this.handleCapture = this.handleCapture.bind(this);
+ this.onCaptureFrame = this.onCaptureFrame.bind(this);
+ }
+ captureFrame (cb) {
+ this._captureListeners[this._captureId].push(cb);
+ this.requestCapture();
+ }
+ onCaptureFrame ({ nativeEvent: {frame, id} }) {
+ if (id in this._captureListeners) {
+ this._captureListeners[id].forEach(listener => listener(frame));
+ delete this._captureListeners[id];
+ }
+ this._captureId ++;
+ this._captureListeners[this._captureId] = [];
+ }
+ requestCapture () {
+ if (this._needsCapture) return;
+ this._needsCapture = true;
+ requestAnimationFrame(this.handleCapture);
+ }
+ handleCapture () {
+ if (!this._needsCapture) return;
+ this._needsCapture = false;
+ this.setState({ captureNextFrameId: this._captureId });
+ }
+ render () {
+ const { width, height, ...restProps } = this.props;
+ const { captureNextFrameId } = this.state;
+ return ;
+ }
+}
+
+module.exports = GLCanvas;
diff --git a/src/View.js b/src/View.js
index d04365bad4bd67150b7b07958364ff213caccf38..975ed9c68bf2b418d4952671f641473733cf18d9 100644
--- a/src/View.js
+++ b/src/View.js
@@ -2,14 +2,12 @@ const {createView} = require("gl-react-core");
const React = require("react-native");
const Shaders = require("./Shaders");
const Uniform = require("./Uniform");
+const GLCanvas = require("./GLCanvas");
const {
- requireNativeComponent,
View,
} = React;
-const GLCanvas = requireNativeComponent("GLCanvas", null);
-
const renderVcontent = function (width, height, id, children, { visibleContent }) {
const childrenStyle = {
position: "absolute",
@@ -23,12 +21,7 @@ const renderVcontent = function (width, height, id, children, { visibleContent }
};
const renderVGL = function (props) {
- const { width, height, ...restProps } = props;
- return ;
+ return ;
};
const renderVcontainer = function ({ style, width, height }, contents, renderer) {