diff --git a/.eslintrc b/.eslintrc
index 4a515a314d3eae16996970b10e34ce502ed855dc..aa5082c1680143d31a168d78ba57481dc07a11d8 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,4 +1,5 @@
{
+ "parser": "babel-eslint",
"globals": {
"requestAnimationFrame": true
},
diff --git a/Examples/AdvancedEffects/android/app/app.iml b/Examples/AdvancedEffects/android/app/app.iml
index 7d9586ad5b466b26a5b508c84969714ecb4506c8..2cd6263fb978920319d5d99a6c685a4ebdea558d 100644
--- a/Examples/AdvancedEffects/android/app/app.iml
+++ b/Examples/AdvancedEffects/android/app/app.iml
@@ -78,7 +78,7 @@
-
+
@@ -97,15 +97,15 @@
-
+
+
-
diff --git a/Examples/AdvancedEffects/android/app/build.gradle b/Examples/AdvancedEffects/android/app/build.gradle
index 30541b8d1e312bad34c9c9ec79ff839c05d19cd6..56c9895c5e64c69c4f4d34fc506629e8102fe1d2 100644
--- a/Examples/AdvancedEffects/android/app/build.gradle
+++ b/Examples/AdvancedEffects/android/app/build.gradle
@@ -74,7 +74,7 @@ android {
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
- compile "com.facebook.react:react-native:0.16.+"
+ compile "com.facebook.react:react-native:0.17.+"
compile project(':RNGL')
}
diff --git a/Examples/AdvancedEffects/android/app/src/main/java/com/advancedeffects/MainActivity.java b/Examples/AdvancedEffects/android/app/src/main/java/com/advancedeffects/MainActivity.java
index 733e28752b1dda79e898b4d3ce5fafe708a0d085..6e9d0e3a45767321b3b44054fd9add23a91cde33 100644
--- a/Examples/AdvancedEffects/android/app/src/main/java/com/advancedeffects/MainActivity.java
+++ b/Examples/AdvancedEffects/android/app/src/main/java/com/advancedeffects/MainActivity.java
@@ -3,6 +3,7 @@ package com.advancedeffects;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
+import android.view.View;
import com.facebook.react.LifecycleState;
import com.facebook.react.ReactInstanceManager;
@@ -34,6 +35,8 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand
mReactRootView.startReactApplication(mReactInstanceManager, "AdvancedEffects", null);
setContentView(mReactRootView);
+
+ getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
}
@Override
diff --git a/Examples/AdvancedEffects/package.json b/Examples/AdvancedEffects/package.json
index 70137d00e4afd017bc5295ebb812a89fcc15d1db..d3b5ae1780f52d5186ca097c712a543096cef46a 100644
--- a/Examples/AdvancedEffects/package.json
+++ b/Examples/AdvancedEffects/package.json
@@ -9,6 +9,6 @@
"gl-react": "^2.0.2",
"gl-react-native": "file:../..",
"glsl-transitions": "^2015.11.8",
- "react-native": "^0.16.0"
+ "react-native": "^0.17.0"
}
}
diff --git a/Examples/AdvancedEffects/src/Banner.js b/Examples/AdvancedEffects/src/Banner.js
index e8bbe7f1ded31705072d32b459f567ed9af0d0fa..c9f5285f985750ea02c4e0c3a08e52ab28788567 100644
--- a/Examples/AdvancedEffects/src/Banner.js
+++ b/Examples/AdvancedEffects/src/Banner.js
@@ -27,7 +27,7 @@ void main( void ) {
class Banner extends React.Component {
render () {
const { width, height, time } = this.props;
- return
+ return console.log("Banner onLoad")}>
;
}
diff --git a/Examples/AdvancedEffects/src/Slideshow.js b/Examples/AdvancedEffects/src/Slideshow.js
index 20ca69c8773c1e50d3f1cf8121c3c0acd0cc2b64..fc1f232ff5c9d38f61204b91ede166d1800a3f50 100644
--- a/Examples/AdvancedEffects/src/Slideshow.js
+++ b/Examples/AdvancedEffects/src/Slideshow.js
@@ -34,7 +34,9 @@ class Slideshow extends React.Component {
const transitionUniforms = this._uniforms;
return
-
+ console.log("Slideshow onLoad")}
+ onProgress={e => console.log("Slideshow onProgress", e.nativeEvent)}>
true}
onMoveShouldSetResponder={() => true}
+ onLoad={() => console.log("Vignette onLoad")}
onResponderMove={this.onResponderMove}>
-
+
@@ -96,15 +96,15 @@
-
+
+
-
diff --git a/Examples/Simple/android/app/build.gradle b/Examples/Simple/android/app/build.gradle
index 4bcd0ed93be4d7004fe8f5fbcc5ef894ba47fc49..c24a17d0e0ec291322bb3dbe10d753c0010c5d0d 100644
--- a/Examples/Simple/android/app/build.gradle
+++ b/Examples/Simple/android/app/build.gradle
@@ -74,7 +74,7 @@ android {
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
- compile "com.facebook.react:react-native:0.16.+"
+ compile "com.facebook.react:react-native:0.17.+"
compile project(":RNMaterialKit")
compile project(":RNGL")
diff --git a/Examples/Simple/index.ios.js b/Examples/Simple/index.ios.js
index 18646c88d9deb06ff42bca1ed26c2d9787e653ca..d29231f7c169ea8e88d2cd99f9802dd11b45ab79 100644
--- a/Examples/Simple/index.ios.js
+++ b/Examples/Simple/index.ios.js
@@ -1,3 +1,4 @@
-const { AppRegistry } = require("react-native");
+const { AppRegistry, StatusBarIOS } = require("react-native");
const Simple = require("./src");
+StatusBarIOS.setHidden(true);
AppRegistry.registerComponent("Simple", () => Simple);
diff --git a/Examples/Simple/package.json b/Examples/Simple/package.json
index e42ff4e814fa8f7dae82b18788052295b36da06e..36c439e5b2572a1fd30cc4f75ada5c7f6aa48c82 100644
--- a/Examples/Simple/package.json
+++ b/Examples/Simple/package.json
@@ -8,7 +8,7 @@
"dependencies": {
"gl-react-native": "file:../..",
"gl-react": "^2.0.2",
- "react-native": "^0.16.0",
+ "react-native": "^0.17.0",
"react-native-material-kit": "^0.2.2"
}
}
diff --git a/Examples/Simple/src/OneFingerResponse.js b/Examples/Simple/src/OneFingerResponse.js
index 0841cec26ef8d4429821b0531dc23667fada6f3e..8cede1459d574ef0c227ac62a5753282cf35ac9a 100644
--- a/Examples/Simple/src/OneFingerResponse.js
+++ b/Examples/Simple/src/OneFingerResponse.js
@@ -2,6 +2,8 @@ const React = require("react-native");
const GL = require("gl-react");
const {Surface} = require("gl-react-native");
+const {PanResponder, UIManager} = React;
+
const shaders = GL.Shaders.create({
oneFingerResponse: {
frag: `
@@ -26,44 +28,57 @@ class OneFingerResponse extends React.Component {
super(props);
this.state = {
pressed: 0,
- position: [ 0, 0 ]
+ position: [ 0, 0 ],
+ surfaceBound: [ 0, 0, 1, 1 ] // x, y, w, h
};
- this.onTouchStart = this.onTouchStart.bind(this);
- this.onTouchEnd = this.onTouchEnd.bind(this);
- this.onTouchMove = this.onTouchMove.bind(this);
- }
- onTouchStart (evt) {
- this.setState({
- pressed: 1
- });
- this.onTouchMove(evt);
- }
- onTouchMove (evt) {
- const { width, height } = this.props;
- const { locationX, locationY } = evt.nativeEvent;
- this.setState({
- position: [
- Math.max(0, Math.min(locationX/width, 1)),
- Math.max(0, Math.min(1-locationY/height, 1))
- ]
- });
- }
- onTouchEnd () {
- this.setState({
- pressed: 0
+
+ this._panResponder = PanResponder.create({
+ onStartShouldSetPanResponder: (evt, gestureState) => true,
+ onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
+ onMoveShouldSetPanResponder: (evt, gestureState) => true,
+ onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
+
+ onPanResponderGrant: (evt, gestureState) =>
+ UIManager.measure(
+ React.findNodeHandle(this.refs.surface),
+ (a, b, w, h, x, y) =>
+ this.setState({
+ pressed: 1,
+ surfaceBound: [x,y,w,h],
+ position: [ gestureState.x0, gestureState.y0 ]
+ })),
+
+ onPanResponderMove: (evt, gestureState) =>
+ this.setState({
+ position: [ gestureState.x0 + gestureState.dx, gestureState.y0 + gestureState.dy ]
+ }),
+
+ onPanResponderTerminationRequest: (evt, gestureState) => true,
+
+ onPanResponderRelease: (evt, gestureState) =>
+ this.setState({
+ pressed: 0
+ }),
+
+ onPanResponderTerminate: (evt, gestureState) =>
+ this.setState({
+ pressed: 0
+ }),
+
+ onShouldBlockNativeResponder: (evt, gestureState) => true
});
+
}
render () {
const { width, height } = this.props;
- const { pressed, position } = this.state;
+ const { pressed, position:[x,y], surfaceBound: [sx,sy,sw,sh] } = this.state;
+ const position = [
+ (x - sx) / sw,
+ 1 - (y - sy) / sh
+ ];
return true}
- onMoveShouldSetResponderCapture={() => true}
- onResponderTerminationRequest={() => false}
- onResponderGrant={this.onTouchStart}
- onResponderMove={this.onTouchMove}
- onResponderRelease={this.onTouchEnd}
- onResponderTerminate={this.onTouchEnd}
+ ref="surface"
+ {...this._panResponder.panHandlers}
width={width}
height={height}>
{
+ this.refs.helloGL.captureFrame().then(data64 => {
this.setState({ captured: data64 });
});
}
@@ -108,21 +118,22 @@ class Simple extends Component {
return
- Welcome to GL React Native!
+ gl-react-native > Simple
this.setState({ current })} value={current}>
-
+
- {captured && }
+ {captured && }
+ {captured && {captured.slice(0, 100)}}
-
+
-
-
-
+
+
+
+
+
@@ -217,7 +231,7 @@ class Simple extends Component {
width={256}
height={160}
factor={factor/2}>
-
+
+ Note: This is highly experimental and not yet performant enough.
diff --git a/Examples/Tests/android/app/app.iml b/Examples/Tests/android/app/app.iml
index 521052c4c1f58bab757eb22487a6957c4f8de779..991e65671eb79f47663cdf3e4de5812a1430a0a6 100644
--- a/Examples/Tests/android/app/app.iml
+++ b/Examples/Tests/android/app/app.iml
@@ -77,7 +77,7 @@
-
+
@@ -96,15 +96,15 @@
-
+
+
-
diff --git a/Examples/Tests/android/app/build.gradle b/Examples/Tests/android/app/build.gradle
index 97b9dd81a075fc182c3c561f37dc57ec590044ba..bc93951aef3f45930b51658adb38e35bff52532a 100644
--- a/Examples/Tests/android/app/build.gradle
+++ b/Examples/Tests/android/app/build.gradle
@@ -74,7 +74,7 @@ android {
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
- compile "com.facebook.react:react-native:0.16.+"
+ compile "com.facebook.react:react-native:0.17.+"
compile project(":RNGL")
}
diff --git a/Examples/Tests/iOS/Tests.xcodeproj/project.pbxproj b/Examples/Tests/iOS/Tests.xcodeproj/project.pbxproj
index 021ccbc6e5c9b89700218c3367a7c59f14733454..97e8a0cb3d2ac0d0e641d0e1adabcdedb757b8fd 100644
--- a/Examples/Tests/iOS/Tests.xcodeproj/project.pbxproj
+++ b/Examples/Tests/iOS/Tests.xcodeproj/project.pbxproj
@@ -21,7 +21,7 @@
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
- 3461EB301C132AA90003E4A2 /* libRNGL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3461EB2F1C132A9F0003E4A2 /* libRNGL.a */; };
+ 34562A0D1C26B83E0079DC6F /* libRNGL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3461EB2F1C132A9F0003E4A2 /* libRNGL.a */; };
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
/* End PBXBuildFile section */
@@ -149,7 +149,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 3461EB301C132AA90003E4A2 /* libRNGL.a in Frameworks */,
+ 34562A0D1C26B83E0079DC6F /* libRNGL.a in Frameworks */,
146834051AC3E58100842450 /* libReact.a in Frameworks */,
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
diff --git a/Examples/Tests/package.json b/Examples/Tests/package.json
index da7ebdeb8d5d82757b30006efae9efb861cd2fb5..5e12bf40bc25bd3c5d4c6ac546ad36512812627f 100644
--- a/Examples/Tests/package.json
+++ b/Examples/Tests/package.json
@@ -8,6 +8,6 @@
"dependencies": {
"gl-react-native": "file:../..",
"gl-react": "^2.0.2",
- "react-native": "^0.16.0"
+ "react-native": "^0.17.0"
}
}
diff --git a/Examples/android/RNGL.iml b/Examples/android/RNGL.iml
new file mode 100644
index 0000000000000000000000000000000000000000..e3cb714fc579494723124b675e53b2f5c97483d9
--- /dev/null
+++ b/Examples/android/RNGL.iml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ generateDebugAndroidTestSources
+ generateDebugSources
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 296076a7d37084152490ed367ad6a8f02a236eae..7bf3accb7ec72174927817cb7edf47d87cee7888 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
**[Gitbook documentation](http://projectseptemberinc.gitbooks.io/gl-react/content/) / [Github](https://github.com/ProjectSeptemberInc/gl-react-native/) / [gl-react](https://github.com/ProjectSeptemberInc/gl-react/)** / [#gl-react on reactiflux](https://discordapp.com/channels/102860784329052160/106102146109325312)
-#
gl-react-native 
+#
gl-react-native 
OpenGL bindings for React Native to implement complex effects over images and components, in the descriptive VDOM paradigm.
@@ -14,14 +14,38 @@ OpenGL bindings for React Native to implement complex effects over images and co
## Installation
-a few steps are required to install `gl-react-native`:
-
-**Install the dependency to your React Native application:**
-
```
npm i --save gl-react-native
```
-**Configure your React Native Application:**
+### Configure your React Native Application
+
+**on iOS:**

+
+**on Android:**
+
+1. `android/settings.gradle`:: Add the following snippet
+ ```gradle
+ include ':RNGL'
+ project(':RNGL').projectDir = file('../node_modules/gl-react-native/android')
+ ```
+1. `android/app/build.gradle`: Add in dependencies block.
+ ```gradle
+ compile project(':RNGL')
+ ```
+1. in your `MainActivity` (or equivalent):
+ ```java
+ import com.projectseptember.RNGL.RNGLPackage;
+ ...
+
+ mReactInstanceManager = ReactInstanceManager.builder()
+ .setApplication(getApplication())
+ ...
+ .addPackage(new MainReactPackage())
+ .addPackage(new RNGLPackage())
+ ...
+ .build();
+
+ ```
diff --git a/android/RNGL.iml b/android/RNGL.iml
new file mode 100644
index 0000000000000000000000000000000000000000..0ee7994615f51180446a865a16fb4c90840aa6ef
--- /dev/null
+++ b/android/RNGL.iml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ generateDebugAndroidTestSources
+ generateDebugSources
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
index 43f1d0dbdd2faaf155ebf84fd690a1ff7fbfdde8..9c3c76cc7b63fd015b37b1f9bf4f7b5f7aaab3e7 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -30,5 +30,5 @@ repositories {
}
dependencies {
- compile 'com.facebook.react:react-native:0.16.+'
+ compile 'com.facebook.react:react-native:0.17.+'
}
diff --git a/android/src/main/java/com/projectseptember/RNGL/GLCanvas.java b/android/src/main/java/com/projectseptember/RNGL/GLCanvas.java
index a7e8d6c405698d451084cf678db72e59fe02ab39..d7a8919c9317bc34f2faa886f988dc1533ea4189 100644
--- a/android/src/main/java/com/projectseptember/RNGL/GLCanvas.java
+++ b/android/src/main/java/com/projectseptember/RNGL/GLCanvas.java
@@ -6,7 +6,9 @@ import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.net.Uri;
+import android.opengl.GLException;
import android.opengl.GLSurfaceView;
+import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
@@ -19,9 +21,12 @@ import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.uimanager.PointerEvents;
+import com.facebook.react.uimanager.ReactPointerEventsView;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.events.RCTEventEmitter;
+import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
@@ -37,7 +42,8 @@ import java.util.concurrent.Executor;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
-public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, Executor {
+public class GLCanvas extends GLSurfaceView
+ implements GLSurfaceView.Renderer, Executor, ReactPointerEventsView {
private ReactContext reactContext;
private RNGLContext rnglContext;
@@ -60,6 +66,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
private Map fbos;
private ExecutorSupplier executorSupplier;
private final Queue mRunOnDraw = new LinkedList<>();
+ private boolean captureFrameRequested = false;
public GLCanvas(ThemedReactContext context, ExecutorSupplier executorSupplier) {
super(context);
@@ -120,8 +127,6 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
if (contentTextures.size() != this.nbContentTextures)
resizeUniformContentTextures(nbContentTextures);
- syncEventsThrough(); // FIXME: need to do this here?
-
if (!preloadingDone) {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
@@ -144,6 +149,15 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
if (shouldRenderNow) {
this.render();
deferredRendering = false;
+ if (captureFrameRequested) {
+ captureFrameRequested = false;
+ Bitmap capture = createSnapshot();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ capture.compress(Bitmap.CompressFormat.PNG, 100, baos);
+ String frame = "data:image/png;base64,"+
+ Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
+ dispatchOnCaptureFrame(frame);
+ }
}
}
@@ -174,36 +188,6 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
this.setRenderMode(autoRedraw ? GLSurfaceView.RENDERMODE_CONTINUOUSLY : GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
- public void setEventsThrough(boolean eventsThrough) {
- syncEventsThrough();
- }
-
- public void setVisibleContent(boolean visibleContent) {
- syncEventsThrough();
- }
-
- public void setCaptureNextFrameId(int captureNextFrameId) {
- // FIXME move away from this pattern. just use a method, same to ObjC impl
- this.requestRender();
- }
-
- private boolean ensureCompiledShader (List data) {
- for (GLData d: data) {
- if (!ensureCompiledShader(d)) {
- return false;
- }
- }
- return true;
- }
-
- private boolean ensureCompiledShader (GLData data) {
- GLShader shader = getShader(data.shader);
- return shader != null &&
- shader.ensureCompile() &&
- ensureCompiledShader(data.children) &&
- ensureCompiledShader(data.contextChildren);
- }
-
public void setData (GLData data) {
this.data = data;
if (preloadingDone) syncContentBitmaps();
@@ -247,9 +231,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
public void requestSyncData () {
execute(new Runnable() {
public void run() {
- if (ensureCompiledShader(data))
- syncData();
- else
+ if (!syncData())
requestSyncData();
}
});
@@ -325,7 +307,6 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
private int countPreloaded () {
int nb = 0;
for (Uri toload: imagesToPreload) {
- Log.i("GLCanvas", "toload: "+toload.getPath()+" = "+preloaded.contains(toload));
if (preloaded.contains(toload)) {
nb++;
}
@@ -383,6 +364,7 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
Map prevImages = this.images;
GLShader shader = getShader(data.shader);
+ if (shader == null || !shader.ensureCompile()) return null;
Map uniformsInteger = new HashMap<>();
Map uniformsFloat = new HashMap<>();
Map uniformsIntBuffer = new HashMap<>();
@@ -392,11 +374,15 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
List children = new ArrayList<>();
for (GLData child: data.contextChildren) {
- contextChildren.add(recSyncData(child, images));
+ GLRenderData node = recSyncData(child, images);
+ if (node == null) return null;
+ contextChildren.add(node);
}
for (GLData child: data.children) {
- children.add(recSyncData(child, images));
+ GLRenderData node = recSyncData(child, images);
+ if (node == null) return null;
+ children.add(node);
}
Map uniformTypes = shader.getUniformTypes();
@@ -595,11 +581,14 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
}
}
- private void syncData () {
- if (data == null) return;
+ private boolean syncData () {
+ if (data == null) return true;
HashMap images = new HashMap<>();
- renderData = recSyncData(data, images);
+ GLRenderData node = recSyncData(data, images);
+ if (node == null) return false;
+ renderData = node;
this.images = images;
+ return true;
}
private void recRender (GLRenderData renderData) {
@@ -665,12 +654,16 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
}
- private void syncEventsThrough () {
- // TODO: figure out how to do this...
- // For some reason, the click through is half working
+ private void dispatchOnCaptureFrame (String frame) {
+ WritableMap event = Arguments.createMap();
+ event.putString("frame", frame);
+ ReactContext reactContext = (ReactContext)getContext();
+ reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
+ getId(),
+ "captureFrame",
+ event);
}
-
private void dispatchOnProgress (double progress, int loaded, int total) {
WritableMap event = Arguments.createMap();
event.putDouble("progress", progress);
@@ -691,4 +684,52 @@ public class GLCanvas extends GLSurfaceView implements GLSurfaceView.Renderer, E
"load",
event);
}
+
+ public void requestCaptureFrame() {
+ captureFrameRequested = true;
+ this.requestRender();
+ }
+
+ private Bitmap createSnapshot () {
+ return createSnapshot(0, 0, getWidth(), getHeight());
+ }
+
+ private Bitmap createSnapshot (int x, int y, int w, int h) {
+ int bitmapBuffer[] = new int[w * h];
+ int bitmapSource[] = new int[w * h];
+ IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer);
+ intBuffer.position(0);
+
+ try {
+ glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, intBuffer);
+ int offset1, offset2;
+ for (int i = 0; i < h; i++) {
+ offset1 = i * w;
+ offset2 = (h - i - 1) * w;
+ for (int j = 0; j < w; j++) {
+ int texturePixel = bitmapBuffer[offset1 + j];
+ int blue = (texturePixel >> 16) & 0xff;
+ int red = (texturePixel << 16) & 0x00ff0000;
+ int pixel = (texturePixel & 0xff00ff00) | red | blue;
+ bitmapSource[offset2 + j] = pixel;
+ }
+ }
+ } catch (GLException e) {
+ return null;
+ }
+
+ return Bitmap.createBitmap(bitmapSource, w, h, Bitmap.Config.ARGB_8888);
+ }
+
+ private PointerEvents mPointerEvents = PointerEvents.AUTO;
+
+ @Override
+ public PointerEvents getPointerEvents() {
+ return mPointerEvents;
+ }
+
+ void setPointerEvents(PointerEvents pointerEvents) {
+ mPointerEvents = pointerEvents;
+ }
+
}
diff --git a/android/src/main/java/com/projectseptember/RNGL/GLCanvasManager.java b/android/src/main/java/com/projectseptember/RNGL/GLCanvasManager.java
index 560d161a9203ea19d57544b8b1d1258257d20af3..36fc95fea762751cf32eee09974806ca07224292 100644
--- a/android/src/main/java/com/projectseptember/RNGL/GLCanvasManager.java
+++ b/android/src/main/java/com/projectseptember/RNGL/GLCanvasManager.java
@@ -6,13 +6,16 @@ import com.facebook.imagepipeline.core.DefaultExecutorSupplier;
import com.facebook.imagepipeline.core.ExecutorSupplier;
import com.facebook.imagepipeline.memory.PoolConfig;
import com.facebook.imagepipeline.memory.PoolFactory;
+import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.common.MapBuilder;
+import com.facebook.react.uimanager.PointerEvents;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ReactProp;
+import java.util.Locale;
import java.util.Map;
@@ -20,12 +23,15 @@ public class GLCanvasManager extends SimpleViewManager {
public static final String REACT_CLASS = "GLCanvas";
+ public static final int COMMAND_CAPTURE_FRAME = 1;
+
private ExecutorSupplier executorSupplier;
@ReactProp(name="nbContentTextures")
public void setNbContentTextures (GLCanvas view, int nbContentTextures) {
view.setNbContentTextures(nbContentTextures);
}
+
@ReactProp(name="renderId")
public void setRenderId (GLCanvas view, int renderId) {
view.setRenderId(renderId);
@@ -36,27 +42,20 @@ public class GLCanvasManager extends SimpleViewManager {
view.setOpaque(opaque);
}
- @ReactProp(name="autoRedraw")
+ @ReactProp(name = "autoRedraw")
public void setAutoRedraw (GLCanvas view, boolean autoRedraw) {
view.setAutoRedraw(autoRedraw);
}
- @ReactProp(name="eventsThrough")
- public void setEventsThrough (GLCanvas view, boolean eventsThrough) {
- view.setEventsThrough(eventsThrough);
- }
-
- @ReactProp(name="visibleContent")
- public void setVisibleContent (GLCanvas view, boolean visibleContent) {
- view.setVisibleContent(visibleContent);
- }
-
- @ReactProp(name="captureNextFrameId")
- public void setCaptureNextFrameId (GLCanvas view, int captureNextFrameId) {
- view.setCaptureNextFrameId(captureNextFrameId);
+ @ReactProp(name = "pointerEvents")
+ public void setPointerEvents(GLCanvas view, @Nullable String pointerEventsStr) {
+ if (pointerEventsStr != null) {
+ PointerEvents pointerEvents = PointerEvents.valueOf(pointerEventsStr.toUpperCase(Locale.US).replace("-", "_"));
+ view.setPointerEvents(pointerEvents);
+ }
}
- @ReactProp(name="data")
+ @ReactProp(name = "data")
public void setData (GLCanvas view, @Nullable ReadableMap data) {
view.setData(data == null ? null : GLData.fromMap(data));
}
@@ -81,13 +80,42 @@ public class GLCanvasManager extends SimpleViewManager {
return new GLCanvas(context, executorSupplier);
}
+ @Override
+ public void receiveCommand(
+ GLCanvas canvas,
+ int commandType,
+ @Nullable ReadableArray args) {
+ Assertions.assertNotNull(canvas);
+ Assertions.assertNotNull(args);
+ switch (commandType) {
+ case COMMAND_CAPTURE_FRAME: {
+ canvas.requestCaptureFrame();
+ return;
+ }
+ default:
+ throw new IllegalArgumentException(String.format(
+ "Unsupported command %d received by %s.",
+ commandType,
+ getClass().getSimpleName()));
+ }
+ }
+
@Override
public @Nullable Map getExportedCustomDirectEventTypeConstants() {
return MapBuilder.of(
+ "captureFrame",
+ MapBuilder.of("registrationName", "onGLCaptureFrame"),
"load",
- MapBuilder.of("registrationName", "onLoad"),
+ MapBuilder.of("registrationName", "onGLLoad"),
"progress",
- MapBuilder.of("registrationName", "onProgress")
+ MapBuilder.of("registrationName", "onGLProgress")
);
}
+
+ @Override
+ public Map getCommandsMap() {
+ return MapBuilder.of(
+ "captureFrame",
+ COMMAND_CAPTURE_FRAME);
+ }
}
diff --git a/ios/GLCanvas.h b/ios/GLCanvas.h
index 3ddd6728de4094418e1940926bed1cc508f921e5..4f04cdedf19f9201de7ded178c951825c969a010 100644
--- a/ios/GLCanvas.h
+++ b/ios/GLCanvas.h
@@ -1,5 +1,6 @@
#import
#import "GLData.h"
+#import "RCTComponent.h"
@interface GLCanvas: GLKView
@@ -11,12 +12,12 @@
@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;
+@property (nonatomic, copy) RCTBubblingEventBlock onGLProgress;
+@property (nonatomic, copy) RCTBubblingEventBlock onGLLoad;
+@property (nonatomic, copy) RCTBubblingEventBlock onGLCaptureFrame;
- (instancetype)initWithBridge:(RCTBridge *)bridge;
-- (void) capture:(RCTResponseSenderBlock)callback;
+- (void) requestCaptureFrame;
@end
diff --git a/ios/GLCanvas.m b/ios/GLCanvas.m
index ce52c30db02671f0120813b123ec6bb15ef3c407..3260fa8176f20cb7eee1129274f4e74f7f77502a 100644
--- a/ios/GLCanvas.m
+++ b/ios/GLCanvas.m
@@ -12,7 +12,6 @@
#import "GLRenderData.h"
#import "UIView+React.h"
-
NSString* srcResource (id res)
{
NSString *src;
@@ -33,9 +32,10 @@ NSString* srcResource (id res)
RCTBridge *_bridge;
GLRenderData *_renderData;
-
- NSMutableArray *_captureListeners;
+ BOOL _captureFrameRequested;
+
+ NSArray *_contentData;
NSArray *_contentTextures;
NSDictionary *_images; // This caches the currently used images (imageSrc -> GLReactImage)
@@ -49,8 +49,8 @@ NSString* srcResource (id res)
BOOL _preloadingDone;
NSTimer *animationTimer;
-
- BOOL _needSync;
+
+ BOOL _needSync;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
@@ -59,7 +59,7 @@ NSString* srcResource (id res)
_bridge = bridge;
_images = @{};
_preloaded = [[NSMutableArray alloc] init];
- _captureListeners = [[NSMutableArray alloc] init];
+ _captureFrameRequested = false;
_preloadingDone = false;
self.context = [bridge.rnglContext getContext];
self.contentScaleFactor = RCTScreenScale();
@@ -71,9 +71,9 @@ RCT_NOT_IMPLEMENTED(-init)
//// Props Setters
-- (void) capture:(RCTResponseSenderBlock)callback
+- (void) requestCaptureFrame
{
- [_captureListeners addObject:callback];
+ _captureFrameRequested = true;
[self setNeedsDisplay];
}
@@ -121,16 +121,12 @@ RCT_NOT_IMPLEMENTED(-init)
}
}
-- (void)setEventsThrough:(BOOL)eventsThrough
+- (void)setPointerEvents:(RCTPointerEvents)pointerEvents
{
- _eventsThrough = eventsThrough;
- [self syncEventsThrough];
-}
-
--(void)setVisibleContent:(BOOL)visibleContent
-{
- _visibleContent = visibleContent;
- [self syncEventsThrough];
+ self.userInteractionEnabled = (pointerEvents != RCTPointerEventsNone);
+ if (pointerEvents == RCTPointerEventsBoxNone) {
+ self.accessibilityViewIsModal = NO;
+ }
}
- (void)setData:(GLData *)data
@@ -141,22 +137,15 @@ RCT_NOT_IMPLEMENTED(-init)
- (void)setNbContentTextures:(NSNumber *)nbContentTextures
{
- [self resizeUniformContentTextures:[nbContentTextures intValue]];
_nbContentTextures = nbContentTextures;
}
//// Sync methods (called from props setters)
-- (void) syncEventsThrough
-{
- self.userInteractionEnabled = !(_eventsThrough);
- self.superview.userInteractionEnabled = !(_eventsThrough && !_visibleContent);
-}
-
- (void)requestSyncData
{
- _needSync = true;
- [self setNeedsDisplay];
+ _needSync = true;
+ [self setNeedsDisplay];
}
- (void)syncData
@@ -176,15 +165,20 @@ RCT_NOT_IMPLEMENTED(-init)
NSMutableArray *contextChildren = [[NSMutableArray alloc] init];
for (GLData *child in data.contextChildren) {
- [contextChildren addObject:weak_traverseTree(child)];
+ GLRenderData *node = weak_traverseTree(child);
+ if (node == nil) return nil;
+ [contextChildren addObject:node];
}
NSMutableArray *children = [[NSMutableArray alloc] init];
for (GLData *child in data.children) {
- [children addObject:weak_traverseTree(child)];
+ GLRenderData *node = weak_traverseTree(child);
+ if (node == nil) return nil;
+ [children addObject:node];
}
GLShader *shader = [_bridge.rnglContext getShader:data.shader];
+ if (shader == nil) return nil;
NSDictionary *uniformTypes = [shader uniformTypes];
NSMutableDictionary *uniforms = [[NSMutableDictionary alloc] init];
@@ -194,12 +188,12 @@ RCT_NOT_IMPLEMENTED(-init)
id value = [data.uniforms objectForKey:uniformName];
GLenum type = [uniformTypes[uniformName] intValue];
-
+
if (type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE) {
uniforms[uniformName] = [NSNumber numberWithInt:units++];
if ([value isEqual:[NSNull null]]) {
GLTexture *emptyTexture = [[GLTexture alloc] init];
- [emptyTexture setPixelsEmpty];
+ [emptyTexture setPixels:nil];
textures[uniformName] = emptyTexture;
}
else {
@@ -271,25 +265,40 @@ RCT_NOT_IMPLEMENTED(-init)
withChildren:children];
};
- _renderData = traverseTree(_data);
- _images = images;
+ GLRenderData *res = traverseTree(_data);
+ if (res != nil) {
+ _renderData = traverseTree(_data);
+ _images = images;
+ }
}
}
-- (void)syncContentTextures
+- (void)syncContentData
{
- int i = 0;
- for (GLTexture *texture in _contentTextures) {
- UIView* view = self.superview.subviews[i]; // We take siblings by index (closely related to the JS code)
+ NSMutableArray *contentData = [[NSMutableArray alloc] init];
+ int nb = [_nbContentTextures intValue];
+ for (int i = 0; i < nb; i++) {
+ UIView *view = self.superview.subviews[i]; // We take siblings by index (closely related to the JS code)
+ GLImageData *imgData = nil;
if (view) {
- if ([view.subviews count] == 1)
- [texture setPixelsWithView:view.subviews[0]];
- else
- [texture setPixelsWithView:view];
+ UIView *v = [view.subviews count] == 1 ?
+ view.subviews[0] :
+ view;
+ imgData = [GLImageData genPixelsWithView:v];
} else {
- [texture setPixelsEmpty];
+ imgData = nil;
}
- i ++;
+ contentData[i] = imgData;
+ }
+ _contentData = contentData;
+}
+
+
+- (void)syncContentTextures
+{
+ unsigned long max = MIN([_contentData count], [_contentTextures count]);
+ for (int i=0; i 0) {
- NSArray *listeners = _captureListeners;
- _captureListeners = [[NSMutableArray alloc] init];
-
+ if (_captureFrameRequested) {
+ _captureFrameRequested = false;
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]];
- for (int i = 0; i < nbCaptureListeners; i++) {
- RCTResponseSenderBlock listener = listeners[i];
- listener(@[[NSNull null], frame]);
- }
+ [frameData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]];
+ if (weakSelf.onGLCaptureFrame) weakSelf.onGLCaptureFrame(@{ @"frame": frame });
});
}
}
@@ -437,7 +441,6 @@ RCT_NOT_IMPLEMENTED(-init)
- (void)resizeUniformContentTextures:(int)n
{
- [EAGLContext setCurrentContext:self.context];
int length = (int) [_contentTextures count];
if (length == n) return;
if (n < length) {
@@ -454,25 +457,17 @@ RCT_NOT_IMPLEMENTED(-init)
- (void)dispatchOnLoad
{
- [_bridge.eventDispatcher sendInputEventWithName:@"load" body:@{ @"target": self.reactTag }];
+ if (self.onGLLoad) self.onGLLoad(@{});
}
- (void)dispatchOnProgress: (double)progress withLoaded:(int)loaded withTotal:(int)total
{
- NSDictionary *event =
+ if (self.onGLProgress) self.onGLProgress(
@{
- @"target": self.reactTag,
- @"progress": @(progress),
- @"loaded": @(loaded),
- @"total": @(total) };
- [_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];
+ @"progress": @(RCTZeroIfNaN(progress)),
+ @"loaded": @(RCTZeroIfNaN(loaded)),
+ @"total": @(RCTZeroIfNaN(total))
+ });
}
@end
diff --git a/ios/GLCanvasManager.m b/ios/GLCanvasManager.m
index ffa8abb37408dbbf288126611994a19c65657f1d..48c0212dcccc77b973e56263a1a8406c5694503f 100644
--- a/ios/GLCanvasManager.m
+++ b/ios/GLCanvasManager.m
@@ -20,26 +20,23 @@ RCT_EXPORT_MODULE();
RCT_EXPORT_VIEW_PROPERTY(nbContentTextures, NSNumber);
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(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);
+RCT_EXPORT_VIEW_PROPERTY(onGLLoad, RCTBubblingEventBlock);
+RCT_EXPORT_VIEW_PROPERTY(onGLProgress, RCTBubblingEventBlock);
+RCT_EXPORT_VIEW_PROPERTY(onGLCaptureFrame, RCTBubblingEventBlock);
-RCT_EXPORT_METHOD(capture: (nonnull NSNumber *)reactTag callback:(RCTResponseSenderBlock)callback)
+RCT_EXPORT_METHOD(capture: (nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) {
UIView *view = viewRegistry[reactTag];
if (![view isKindOfClass:[GLCanvas class]]) {
RCTLog(@"expecting UIView, got: %@", view);
- callback(@[@"view is not a GLCanvas"]);
}
else {
GLCanvas *glCanvas = (GLCanvas *)view;
- [glCanvas capture:callback];
+ [glCanvas requestCaptureFrame];
}
}];
}
diff --git a/ios/GLImage.m b/ios/GLImage.m
index 9e47648593dcd95695b71814c570c1770d8e1e92..d2715bc945ee9c2458b338052263a62eafd407f3 100644
--- a/ios/GLImage.m
+++ b/ios/GLImage.m
@@ -50,12 +50,12 @@ RCT_NOT_IMPLEMENTED(-init)
{
if (_image) {
if (!_data) {
- _data = genPixelsWithImage(_image);
+ _data = [GLImageData genPixelsWithImage:_image];
}
[_texture setPixels:_data];
}
else {
- [_texture setPixelsEmpty];
+ [_texture setPixels:nil];
}
return _texture;
}
diff --git a/ios/GLImageData.h b/ios/GLImageData.h
index 18d0f6f21bde956137f0964117cf3d7ddc6c1772..c2010f350abb18fc995d53dc2a50f3198f1ad32e 100644
--- a/ios/GLImageData.h
+++ b/ios/GLImageData.h
@@ -6,6 +6,11 @@
@property (nonatomic) int width;
@property (nonatomic) int height;
++ (GLImageData*) empty;
++ (GLImageData*) genPixelsWithImage: (UIImage *)image;
++ (GLImageData*) genPixelsWithView: (UIView *)view;
+
- (instancetype)initWithData: (GLubyte *)data withWidth:(int)width withHeight:(int)height;
@end
+
diff --git a/ios/GLImageData.m b/ios/GLImageData.m
index 1d5d1508605f88cdf8ae9c5462a4267459f9e27b..5ef0c814898a0129aba4d123a24a59ee077d86f6 100644
--- a/ios/GLImageData.m
+++ b/ios/GLImageData.m
@@ -1,7 +1,7 @@
#import "GLImageData.h"
-
-// TODO: rename to GLImageData
+#import "RCTUtils.h"
+#import "RCTLog.h"
// This structure aims to be used in an immutable way
@implementation GLImageData
@@ -11,6 +11,65 @@
int _height;
}
+GLImageData *EMPTY_PIXELS;
+
++ (GLImageData *)empty
+{
+ if (!EMPTY_PIXELS) {
+ int width = 2, height = 2;
+ 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;
+ }
+ EMPTY_PIXELS = [[GLImageData alloc] initWithData:data withWidth:width withHeight:height];
+ }
+ return EMPTY_PIXELS;
+}
+
++ (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
+{
+ float width = RCTScreenScale() * view.bounds.size.width;
+ float height = RCTScreenScale() * 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, CGRectMake(0.0, 0.0, width, height));
+ CGContextScaleCTM(ctx, RCTScreenScale(), RCTScreenScale());
+ [view.layer renderInContext:ctx];
+ CGContextRelease(ctx);
+ return [[GLImageData alloc] initWithData:data withWidth:width withHeight:height];
+}
+
- (instancetype)initWithData: (GLubyte *)data withWidth:(int)width withHeight:(int)height
{
self = [super init];
diff --git a/ios/GLTexture.h b/ios/GLTexture.h
index 7837b19e90c639f52c489f75458b708c8b18de9b..e47019df13c1f2593e60a9901e315a0a248f1bc2 100644
--- a/ios/GLTexture.h
+++ b/ios/GLTexture.h
@@ -2,8 +2,6 @@
#import "RCTBridge.h"
#import "GLImageData.h"
-GLImageData* genPixelsWithImage (UIImage *image);
-
@interface GLTexture: NSObject
@property EAGLContext *context;
@@ -16,9 +14,5 @@ GLImageData* genPixelsWithImage (UIImage *image);
- (void)setShapeWithWidth:(float)width withHeight:(float)height;
- (void)setPixels: (GLImageData *)data;
-- (void)setPixelsEmpty;
-- (void)setPixelsRandom: (int)width withHeight:(int)height;
-- (void)setPixelsWithImage: (UIImage *)image;
-- (void)setPixelsWithView: (UIView *)view;
@end
diff --git a/ios/GLTexture.m b/ios/GLTexture.m
index 8393520b55157480eb99cb4747d38919dbd8104b..865e4529be647fee4a141236958b44b8a30b445a 100644
--- a/ios/GLTexture.m
+++ b/ios/GLTexture.m
@@ -2,84 +2,14 @@
#import "RCTLog.h"
#import "RCTUtils.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)
-{
- float width = RCTScreenScale() * view.bounds.size.width;
- float height = RCTScreenScale() * 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, CGRectMake(0.0, 0.0, width, height));
- CGContextScaleCTM(ctx, RCTScreenScale(), RCTScreenScale());
- [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
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];
@@ -123,36 +53,12 @@ GLImageData *EMPTY_PIXELS;
- (void)setPixels: (GLImageData *)data
{
- if (data != dataCurrentlyUploaded) {
- dataCurrentlyUploaded = data;
+ GLImageData *d = data==nil ? [GLImageData empty] : data;
+ if (d != dataCurrentlyUploaded) {
+ dataCurrentlyUploaded = d;
[self bind];
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data.width, data.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.data);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, d.width, d.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, d.data);
}
}
-- (void)setPixelsEmpty
-{
- [self setPixels:EMPTY_PIXELS];
-}
-
-- (void)setPixelsRandom: (int)width withHeight:(int)height // for testing
-{
- GLImageData* data = genPixelsRandom(width, height);
- [self setPixels:data];
-}
-
-- (void)setPixelsWithImage: (UIImage *)image
-{
- GLImageData *data = genPixelsWithImage(image);
- if (!data) return;
- [self setPixels:data];
-}
-
-- (void)setPixelsWithView: (UIView *)view
-{
- GLImageData *data = genPixelsWithView(view);
- [self setPixels:data];
-}
-
-
@end
diff --git a/ios/RNGL.xcodeproj/project.pbxproj b/ios/RNGL.xcodeproj/project.pbxproj
index 4c89e0765ff1b3224714caba6d6617a6e2554ca4..e056536309818333ef49a03b15eb43dd9b82af05 100644
--- a/ios/RNGL.xcodeproj/project.pbxproj
+++ b/ios/RNGL.xcodeproj/project.pbxproj
@@ -44,17 +44,17 @@
346089C21BEFD0A500C90DB5 /* GLImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLImage.h; sourceTree = ""; };
346089C31BEFD0A500C90DB5 /* GLImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLImage.m; sourceTree = ""; };
346089C41BEFD0A500C90DB5 /* GLImageData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLImageData.h; sourceTree = ""; };
- 346089C51BEFD0A500C90DB5 /* GLImageData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLImageData.m; sourceTree = ""; };
+ 346089C51BEFD0A500C90DB5 /* GLImageData.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = GLImageData.m; sourceTree = ""; tabWidth = 2; };
346089C61BEFD0A500C90DB5 /* GLRenderData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLRenderData.h; sourceTree = ""; };
346089C71BEFD0A500C90DB5 /* GLRenderData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLRenderData.m; sourceTree = ""; };
346089C81BEFD0A500C90DB5 /* GLShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLShader.h; sourceTree = ""; };
346089C91BEFD0A500C90DB5 /* GLShader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLShader.m; sourceTree = ""; };
346089CA1BEFD0A500C90DB5 /* GLTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLTexture.h; sourceTree = ""; };
- 346089CB1BEFD0A500C90DB5 /* GLTexture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLTexture.m; sourceTree = ""; };
+ 346089CB1BEFD0A500C90DB5 /* GLTexture.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = GLTexture.m; sourceTree = ""; tabWidth = 2; };
346089CC1BEFD0A500C90DB5 /* RCTConvert+GLData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+GLData.h"; sourceTree = ""; };
346089CD1BEFD0A500C90DB5 /* RCTConvert+GLData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+GLData.m"; sourceTree = ""; };
346089CE1BEFD0A500C90DB5 /* RNGLContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNGLContext.h; sourceTree = ""; };
- 346089CF1BEFD0A500C90DB5 /* RNGLContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNGLContext.m; sourceTree = ""; };
+ 346089CF1BEFD0A500C90DB5 /* RNGLContext.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = RNGLContext.m; sourceTree = ""; tabWidth = 2; };
4107012F1ACB723B00C6AA39 /* libRNGL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNGL.a; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
diff --git a/ios/RNGLContext.m b/ios/RNGLContext.m
index 340124bd6a0189892b07556b08480b2315fb9f91..689bb50e5b53997b4e755e360697e2d5ca1c7716 100644
--- a/ios/RNGLContext.m
+++ b/ios/RNGLContext.m
@@ -64,7 +64,7 @@ RCT_EXPORT_METHOD(addShader:(nonnull NSNumber *)id withConfig:(NSDictionary *)co
- (RNGLContext *)rnglContext
{
- return self.modules[RCTBridgeModuleNameForClass([RNGLContext class])];
+ return [self moduleForClass:[RNGLContext class]];
}
@end
\ No newline at end of file
diff --git a/package.json b/package.json
index bb927c845facc1fb60daae5d66e144eca8db34be..8615e98e43b8a8e3478f49943f4734f7c51547d5 100644
--- a/package.json
+++ b/package.json
@@ -19,13 +19,14 @@
"author": "Project September ",
"license": "MIT",
"peerDependencies": {
- "react-native": ">= 0.16.0",
- "gl-react": ">= 2.0.2"
+ "react-native": ">= 0.17.0 <0.18.0",
+ "gl-react": ">= 2.0.3 <2.1.0"
},
"dependencies": {
"invariant": "2.2.0"
},
"devDependencies": {
+ "babel-eslint": "^4.1.6",
"eslint": "^1.9.0",
"eslint-plugin-react": "^3.8.0"
}
diff --git a/src/GLCanvas.captureFrame.android.js b/src/GLCanvas.captureFrame.android.js
new file mode 100644
index 0000000000000000000000000000000000000000..ceb938beba2c6e1c81e63891e1c628177c09af48
--- /dev/null
+++ b/src/GLCanvas.captureFrame.android.js
@@ -0,0 +1,15 @@
+const invariant = require("invariant");
+const React = require("react-native");
+const {
+ NativeModules: { UIManager }
+} = React;
+const {GLCanvas} = UIManager;
+invariant(GLCanvas,
+`gl-react-native: the native module is not available.
+Make sure you have properly configured it.
+See README install instructions.
+
+React.NativeModules.UIManager.GLCanvas is %s`, GLCanvas);
+const {Commands} = GLCanvas;
+
+module.exports = handle => UIManager.dispatchViewManagerCommand(handle, Commands.captureFrame, []);
diff --git a/src/GLCanvas.captureFrame.ios.js b/src/GLCanvas.captureFrame.ios.js
new file mode 100644
index 0000000000000000000000000000000000000000..24a716e17bf8feb7de298e610f8242c5ace886da
--- /dev/null
+++ b/src/GLCanvas.captureFrame.ios.js
@@ -0,0 +1,13 @@
+const invariant = require("invariant");
+const React = require("react-native");
+const {
+ NativeModules: { GLCanvasManager }
+} = React;
+invariant(GLCanvasManager,
+`gl-react-native: the native module is not available.
+Make sure you have properly configured it.
+See README install instructions.
+
+React.NativeModules.GLCanvasManager is %s`, GLCanvasManager);
+
+module.exports = handle => GLCanvasManager.capture(handle);
diff --git a/src/GLCanvas.js b/src/GLCanvas.js
index 6b5e3474bbdf8bf110f86f6d3ae3ed89f1457a0e..79d8dc7a14d417bb40f779769261b6b802b65615 100644
--- a/src/GLCanvas.js
+++ b/src/GLCanvas.js
@@ -1,30 +1,54 @@
const React = require("react-native");
-
const {
Component,
- requireNativeComponent,
- NativeModules: { GLCanvasManager }
+ requireNativeComponent
} = React;
-const GLCanvasNative = requireNativeComponent("GLCanvas", GLCanvas);
+const captureFrame = require("./GLCanvas.captureFrame");
-class GLCanvas extends Component {
- constructor (props) {
- super(props);
+const GLCanvasNative = requireNativeComponent("GLCanvas", GLCanvas, {
+ nativeOnly: {
+ onGLChange: true,
+ onGLProgress: true,
+ onGLCaptureFrame: true
}
+});
+
+function defer() {
+ const deferred = {};
+ const promise = new Promise(function(resolve, reject) {
+ deferred.resolve = resolve;
+ deferred.reject = reject;
+ });
+ deferred.promise = promise;
+ return deferred;
+}
+
+class GLCanvas extends Component {
captureFrame (cb) {
- GLCanvasManager.capture(
- React.findNodeHandle(this.refs.native),
- (error, frame) => {
- if (error) console.error(error); // eslint-disable-line no-console
- else cb(frame);
- });
+ const promise = (
+ this._pendingCaptureFrame || // use pending capture OR create a new captureFrame pending
+ (captureFrame(React.findNodeHandle(this.refs.native)), this._pendingCaptureFrame = defer())
+ ).promise;
+ if (typeof cb === "function") {
+ console.warn("GLSurface: callback parameter of captureFrame is deprecated, use the returned promise instead"); // eslint-disable-line no-console
+ promise.then(cb);
+ }
+ return promise;
+ }
+ onGLCaptureFrame = ({ nativeEvent: {frame} }) => {
+ this._pendingCaptureFrame.resolve(frame);
+ this._pendingCaptureFrame = undefined;
}
render () {
- const { width, height, ...restProps } = this.props;
+ const { width, height, onLoad, onProgress, eventsThrough, ...restProps } = this.props;
return ;
}
diff --git a/src/Surface.js b/src/Surface.js
index 2141b2c1822d98ae6fc934a4fa9ac45e18515721..ae0c8f8e8329b7c276503d321a4d907bb853f05d 100644
--- a/src/Surface.js
+++ b/src/Surface.js
@@ -1,4 +1,6 @@
+const invariant = require("invariant");
const {createSurface} = require("gl-react");
+invariant(typeof createSurface === "function", "gl-react createSurface is not a function. Check your gl-react dependency");
const React = require("react-native");
const GLCanvas = require("./GLCanvas");
@@ -13,7 +15,7 @@ function renderVcontent (width, height, id, children, { visibleContent }) {
left: 0,
width: width,
height: height,
- overflow: "hidden"
+ overflow: "hidden",
};
return {children};
}
@@ -22,15 +24,17 @@ function renderVGL (props) {
return ;
}
-function renderVcontainer ({ style, width, height }, contents, renderer) {
+function renderVcontainer ({ style, width, height, visibleContent, eventsThrough }, contents, renderer) {
const parentStyle = {
position: "relative",
...style,
width: width,
height: height,
- overflow: "hidden"
+ overflow: "hidden",
};
- return
+ return
{contents}
{renderer}
;
diff --git a/src/index.js b/src/index.js
index b4aa06d8073a6dfd65772d7b3a8031a956ffeba7..98ec5c7f1054b92d5353a5601b549794921a5ad0 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,6 +1,13 @@
+const invariant = require("invariant");
const { Shaders } = require("gl-react");
const Surface = require("./Surface");
const { NativeModules: { RNGLContext } } = require("react-native");
+invariant(RNGLContext,
+`gl-react-native: the native module is not available.
+Make sure you have properly configured it.
+See README install instructions.
+
+React.NativeModules.RNGLContext is %s`, RNGLContext);
// Hook Shaders to RNGLContext
Shaders.list().map(id => RNGLContext.addShader(id, Shaders.get(id)));