Commit 5669c7e1 authored by Gaëtan Renaudeau's avatar Gaëtan Renaudeau

Merge pull request #56 from ProjectSeptemberInc/2.18.0

2.18.0-rc
parents d5c628c9 0c589f77
...@@ -74,7 +74,7 @@ android { ...@@ -74,7 +74,7 @@ android {
dependencies { dependencies {
compile fileTree(dir: "libs", include: ["*.jar"]) compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1" compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:0.17.+" compile "com.facebook.react:react-native:0.18.+"
compile project(':RNGL') compile project(':RNGL')
} }
...@@ -3,12 +3,14 @@ ...@@ -3,12 +3,14 @@
"version": "0.0.1", "version": "0.0.1",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "react-native start" "start": "node node_modules/react-native/local-cli/cli.js start"
}, },
"dependencies": { "dependencies": {
"gl-react": "^2.0.2", "fbjs": "^0.6.0",
"gl-react": "^2.1.0",
"gl-react-native": "file:../..", "gl-react-native": "file:../..",
"glsl-transitions": "^2015.11.8", "glsl-transitions": "^2015.11.8",
"react-native": "^0.17.0" "react": "^0.14.5",
"react-native": "0.18.0-rc"
} }
} }
require("gl-react/react-native");
const React = require("react-native"); const React = require("react-native");
const { const {
StyleSheet, StyleSheet,
......
...@@ -74,6 +74,6 @@ android { ...@@ -74,6 +74,6 @@ android {
dependencies { dependencies {
compile fileTree(dir: "libs", include: ["*.jar"]) compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1" compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:0.17.+" compile "com.facebook.react:react-native:0.18.+"
compile project(":RNGL") compile project(":RNGL")
} }
...@@ -3,13 +3,15 @@ ...@@ -3,13 +3,15 @@
"version": "0.0.1", "version": "0.0.1",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "react-native start" "start": "node node_modules/react-native/local-cli/cli.js start"
}, },
"dependencies": { "dependencies": {
"crypto": "0.0.3", "crypto": "0.0.3",
"gl-react": "^2.0.6", "fbjs": "^0.6.0",
"gl-react": "^2.1.0",
"gl-react-native": "file:../..", "gl-react-native": "file:../..",
"react-native": "^0.17.0", "react": "^0.14.5",
"react-native": "0.18.0-rc",
"seedrandom": "gre/seedrandom#released" "seedrandom": "gre/seedrandom#released"
} }
} }
import GL from "gl-react"; import GL from "gl-react";
const {React} = GL; import React from "react";
const {PropTypes} = React; const {PropTypes} = React;
const shaders = GL.Shaders.create({ const shaders = GL.Shaders.create({
......
require("gl-react/react-native");
const React = require("react-native"); const React = require("react-native");
const { const {
StyleSheet, StyleSheet,
......
...@@ -77,7 +77,7 @@ ...@@ -77,7 +77,7 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/fresco/0.8.1/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/fresco/0.8.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline-okhttp/0.8.1/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline-okhttp/0.8.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline/0.8.1/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline/0.8.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.react/react-native/0.17.1/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.react/react-native/0.18.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/org.webkit/android-jsc/r174650/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/org.webkit/android-jsc/r174650/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
...@@ -96,14 +96,14 @@ ...@@ -96,14 +96,14 @@
<orderEntry type="library" exported="" name="okio-1.6.0" level="project" /> <orderEntry type="library" exported="" name="okio-1.6.0" level="project" />
<orderEntry type="library" exported="" name="stetho-okhttp-1.2.0" level="project" /> <orderEntry type="library" exported="" name="stetho-okhttp-1.2.0" level="project" />
<orderEntry type="library" exported="" name="okhttp-2.5.0" level="project" /> <orderEntry type="library" exported="" name="okhttp-2.5.0" level="project" />
<orderEntry type="library" exported="" name="jsr305-3.0.0" level="project" />
<orderEntry type="library" exported="" name="stetho-1.2.0" level="project" /> <orderEntry type="library" exported="" name="stetho-1.2.0" level="project" />
<orderEntry type="library" exported="" name="jsr305-3.0.0" level="project" />
<orderEntry type="library" exported="" name="jackson-core-2.2.3" level="project" /> <orderEntry type="library" exported="" name="jackson-core-2.2.3" level="project" />
<orderEntry type="library" exported="" name="fbcore-0.8.1" level="project" /> <orderEntry type="library" exported="" name="fbcore-0.8.1" level="project" />
<orderEntry type="library" exported="" name="commons-cli-1.2" level="project" /> <orderEntry type="library" exported="" name="commons-cli-1.2" level="project" />
<orderEntry type="library" exported="" name="recyclerview-v7-23.0.1" level="project" /> <orderEntry type="library" exported="" name="recyclerview-v7-23.0.1" level="project" />
<orderEntry type="library" exported="" name="imagepipeline-0.8.1" level="project" /> <orderEntry type="library" exported="" name="imagepipeline-0.8.1" level="project" />
<orderEntry type="library" exported="" name="react-native-0.17.1" level="project" /> <orderEntry type="library" exported="" name="react-native-0.18.0" level="project" />
<orderEntry type="library" exported="" name="android-jsc-r174650" level="project" /> <orderEntry type="library" exported="" name="android-jsc-r174650" level="project" />
<orderEntry type="library" exported="" name="fresco-0.8.1" level="project" /> <orderEntry type="library" exported="" name="fresco-0.8.1" level="project" />
<orderEntry type="library" exported="" name="imagepipeline-okhttp-0.8.1" level="project" /> <orderEntry type="library" exported="" name="imagepipeline-okhttp-0.8.1" level="project" />
...@@ -112,6 +112,7 @@ ...@@ -112,6 +112,7 @@
<orderEntry type="library" exported="" name="drawee-0.8.1" level="project" /> <orderEntry type="library" exported="" name="drawee-0.8.1" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-23.0.1" level="project" /> <orderEntry type="library" exported="" name="appcompat-v7-23.0.1" level="project" />
<orderEntry type="library" exported="" name="support-annotations-23.0.1" level="project" /> <orderEntry type="library" exported="" name="support-annotations-23.0.1" level="project" />
<orderEntry type="module" module-name="react-native-fs" exported="" />
<orderEntry type="module" module-name="RNMaterialKit" exported="" /> <orderEntry type="module" module-name="RNMaterialKit" exported="" />
<orderEntry type="module" module-name="RNGL" exported="" /> <orderEntry type="module" module-name="RNGL" exported="" />
</component> </component>
......
...@@ -74,8 +74,10 @@ android { ...@@ -74,8 +74,10 @@ android {
dependencies { dependencies {
compile fileTree(dir: "libs", include: ["*.jar"]) compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1" compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:0.17.+" compile "com.facebook.react:react-native:0.18.+"
compile project(":RNMaterialKit") compile project(":RNMaterialKit")
compile project(":RNGL") compile project(":RNGL")
compile project(':react-native-fs')
} }
...@@ -11,6 +11,7 @@ import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; ...@@ -11,6 +11,7 @@ import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage; import com.facebook.react.shell.MainReactPackage;
import com.github.xinthink.rnmk.ReactMaterialKitPackage; import com.github.xinthink.rnmk.ReactMaterialKitPackage;
import com.projectseptember.RNGL.RNGLPackage; import com.projectseptember.RNGL.RNGLPackage;
import com.rnfs.RNFSPackage;
public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {
...@@ -28,6 +29,7 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand ...@@ -28,6 +29,7 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand
.setJSMainModuleName("index.android") .setJSMainModuleName("index.android")
.addPackage(new MainReactPackage()) .addPackage(new MainReactPackage())
.addPackage(new RNGLPackage()) .addPackage(new RNGLPackage())
.addPackage(new RNFSPackage())
.addPackage(new ReactMaterialKitPackage()) .addPackage(new ReactMaterialKitPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG) .setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED) .setInitialLifecycleState(LifecycleState.RESUMED)
......
...@@ -7,3 +7,6 @@ project(':RNMaterialKit').projectDir = file('../node_modules/react-native-materi ...@@ -7,3 +7,6 @@ project(':RNMaterialKit').projectDir = file('../node_modules/react-native-materi
include ':RNGL' include ':RNGL'
project(':RNGL').projectDir = file('../../../android') project(':RNGL').projectDir = file('../../../android')
include ':react-native-fs'
project(':react-native-fs').projectDir = new File(settingsDir, '../node_modules/react-native-fs/android')
\ No newline at end of file
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
34607B601C132B22009203B1 /* libRCTMaterialKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 34607B581C132B1C009203B1 /* libRCTMaterialKit.a */; }; 34607B601C132B22009203B1 /* libRCTMaterialKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 34607B581C132B1C009203B1 /* libRCTMaterialKit.a */; };
3461EB4B1C132AEC0003E4A2 /* libRNGL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3461EB4A1C132AD30003E4A2 /* libRNGL.a */; }; 3461EB4B1C132AEC0003E4A2 /* libRNGL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3461EB4A1C132AD30003E4A2 /* libRNGL.a */; };
34C9905A1C3530D6002F49FC /* libRNFS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 34C990581C3530CE002F49FC /* libRNFS.a */; };
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
...@@ -104,6 +105,13 @@ ...@@ -104,6 +105,13 @@
remoteGlobalIDString = 4107012F1ACB723B00C6AA39; remoteGlobalIDString = 4107012F1ACB723B00C6AA39;
remoteInfo = RNGL; remoteInfo = RNGL;
}; };
34C990571C3530CE002F49FC /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 34C990481C3530CE002F49FC /* RNFS.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = F12AFB9B1ADAF8F800E0535D;
remoteInfo = RNFS;
};
78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = { 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
...@@ -142,6 +150,7 @@ ...@@ -142,6 +150,7 @@
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; }; 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
34607B4F1C132B1C009203B1 /* RCTMaterialKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTMaterialKit.xcodeproj; path = "../node_modules/react-native-material-kit/iOS/RCTMaterialKit.xcodeproj"; sourceTree = "<group>"; }; 34607B4F1C132B1C009203B1 /* RCTMaterialKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTMaterialKit.xcodeproj; path = "../node_modules/react-native-material-kit/iOS/RCTMaterialKit.xcodeproj"; sourceTree = "<group>"; };
3461EB3B1C132AD30003E4A2 /* RNGL.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNGL.xcodeproj; path = "../node_modules/gl-react-native/ios/RNGL.xcodeproj"; sourceTree = "<group>"; }; 3461EB3B1C132AD30003E4A2 /* RNGL.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNGL.xcodeproj; path = "../node_modules/gl-react-native/ios/RNGL.xcodeproj"; sourceTree = "<group>"; };
34C990481C3530CE002F49FC /* RNFS.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNFS.xcodeproj; path = "../node_modules/react-native-fs/RNFS.xcodeproj"; sourceTree = "<group>"; };
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; }; 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
...@@ -158,6 +167,7 @@ ...@@ -158,6 +167,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
34C9905A1C3530D6002F49FC /* libRNFS.a in Frameworks */,
34607B601C132B22009203B1 /* libRCTMaterialKit.a in Frameworks */, 34607B601C132B22009203B1 /* libRCTMaterialKit.a in Frameworks */,
3461EB4B1C132AEC0003E4A2 /* libRNGL.a in Frameworks */, 3461EB4B1C132AEC0003E4A2 /* libRNGL.a in Frameworks */,
146834051AC3E58100842450 /* libReact.a in Frameworks */, 146834051AC3E58100842450 /* libReact.a in Frameworks */,
...@@ -287,6 +297,14 @@ ...@@ -287,6 +297,14 @@
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
34C990491C3530CE002F49FC /* Products */ = {
isa = PBXGroup;
children = (
34C990581C3530CE002F49FC /* libRNFS.a */,
);
name = Products;
sourceTree = "<group>";
};
78C398B11ACF4ADC00677621 /* Products */ = { 78C398B11ACF4ADC00677621 /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
...@@ -298,6 +316,7 @@ ...@@ -298,6 +316,7 @@
832341AE1AAA6A7D00B99B32 /* Libraries */ = { 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
34C990481C3530CE002F49FC /* RNFS.xcodeproj */,
34607B4F1C132B1C009203B1 /* RCTMaterialKit.xcodeproj */, 34607B4F1C132B1C009203B1 /* RCTMaterialKit.xcodeproj */,
3461EB3B1C132AD30003E4A2 /* RNGL.xcodeproj */, 3461EB3B1C132AD30003E4A2 /* RNGL.xcodeproj */,
146833FF1AC3E56700842450 /* React.xcodeproj */, 146833FF1AC3E56700842450 /* React.xcodeproj */,
...@@ -453,6 +472,10 @@ ...@@ -453,6 +472,10 @@
ProductGroup = 146834001AC3E56700842450 /* Products */; ProductGroup = 146834001AC3E56700842450 /* Products */;
ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */; ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
}, },
{
ProductGroup = 34C990491C3530CE002F49FC /* Products */;
ProjectRef = 34C990481C3530CE002F49FC /* RNFS.xcodeproj */;
},
{ {
ProductGroup = 3461EB3C1C132AD30003E4A2 /* Products */; ProductGroup = 3461EB3C1C132AD30003E4A2 /* Products */;
ProjectRef = 3461EB3B1C132AD30003E4A2 /* RNGL.xcodeproj */; ProjectRef = 3461EB3B1C132AD30003E4A2 /* RNGL.xcodeproj */;
...@@ -537,6 +560,13 @@ ...@@ -537,6 +560,13 @@
remoteRef = 3461EB491C132AD30003E4A2 /* PBXContainerItemProxy */; remoteRef = 3461EB491C132AD30003E4A2 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR; sourceTree = BUILT_PRODUCTS_DIR;
}; };
34C990581C3530CE002F49FC /* libRNFS.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRNFS.a;
remoteRef = 34C990571C3530CE002F49FC /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = { 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = {
isa = PBXReferenceProxy; isa = PBXReferenceProxy;
fileType = archive.ar; fileType = archive.ar;
......
...@@ -3,12 +3,15 @@ ...@@ -3,12 +3,15 @@
"version": "0.0.1", "version": "0.0.1",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "react-native start" "start": "node node_modules/react-native/local-cli/cli.js start"
}, },
"dependencies": { "dependencies": {
"fbjs": "^0.6.0",
"gl-react": "^2.1.0",
"gl-react-native": "file:../..", "gl-react-native": "file:../..",
"gl-react": "^2.0.8", "react": "^0.14.5",
"react-native": "^0.17.0", "react-native": "0.18.0-rc",
"react-native-material-kit": "^0.2.4" "react-native-fs": "^1.1.0",
"react-native-material-kit": "gre/react-native-material-kit#no-peerDependencies"
} }
} }
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const Blur1D = require("./Blur1D"); const Blur1D = require("./Blur1D");
module.exports = GL.createComponent(({ width, height, factor, children }) => module.exports = GL.createComponent(({ width, height, factor, children }) =>
......
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const shaders = GL.Shaders.create({ const shaders = GL.Shaders.create({
blur1D: { blur1D: {
......
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const shaders = GL.Shaders.create({ const shaders = GL.Shaders.create({
helloGL: { helloGL: {
......
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const shaders = GL.Shaders.create({ const shaders = GL.Shaders.create({
hueRotate: { hueRotate: {
......
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const shaders = GL.Shaders.create({ const shaders = GL.Shaders.create({
pieProgress: { pieProgress: {
......
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const shaders = GL.Shaders.create({ const shaders = GL.Shaders.create({
saturation: { saturation: {
......
require("gl-react/react-native");
const React = require("react-native"); const React = require("react-native");
const { const {
StyleSheet, StyleSheet,
...@@ -22,6 +20,8 @@ const { ...@@ -22,6 +20,8 @@ const {
MKButton, MKButton,
} = require("react-native-material-kit"); } = require("react-native-material-kit");
const RNFS = require("react-native-fs");
const HelloGL = require("./HelloGL"); const HelloGL = require("./HelloGL");
const Saturation = require("./Saturation"); const Saturation = require("./Saturation");
const HueRotate = require("./HueRotate"); const HueRotate = require("./HueRotate");
...@@ -82,7 +82,8 @@ class Simple extends Component { ...@@ -82,7 +82,8 @@ class Simple extends Component {
switch1: false, switch1: false,
switch2: false, switch2: false,
switch3: false, switch3: false,
captured: null captured: null,
captureConfig: null
}; };
this.onCapture1 = this.onCapture1.bind(this); this.onCapture1 = this.onCapture1.bind(this);
...@@ -97,9 +98,17 @@ class Simple extends Component { ...@@ -97,9 +98,17 @@ class Simple extends Component {
} }
onCapture1 () { onCapture1 () {
this.refs.helloGL.captureFrame().then(data64 => { const captureConfig = {
this.setState({ captured: data64 }); quality: Math.round((Math.random() * 100))/100,
}); type: Math.random() < 0.5 ? "jpg": "png",
format: Math.random() < 0.5 ? "base64" : "file"
};
if (captureConfig.format === "file") {
captureConfig.filePath = RNFS.DocumentDirectoryPath+"/hellogl_capture.png";
}
this.refs.helloGL
.captureFrame(captureConfig)
.then(captured => this.setState({ captured, captureConfig }));
} }
render () { render () {
...@@ -113,7 +122,8 @@ class Simple extends Component { ...@@ -113,7 +122,8 @@ class Simple extends Component {
switch1, switch1,
switch2, switch2,
switch3, switch3,
captured captured,
captureConfig
} = this.state; } = this.state;
return <View style={styles.container}> return <View style={styles.container}>
...@@ -128,9 +138,28 @@ class Simple extends Component { ...@@ -128,9 +138,28 @@ class Simple extends Component {
</Surface> </Surface>
<View style={{ paddingTop: 20, alignItems: "center", flexDirection: "row" }}> <View style={{ paddingTop: 20, alignItems: "center", flexDirection: "row" }}>
<Button onPress={this.onCapture1}>captureFrame()</Button> <Button onPress={this.onCapture1}>captureFrame()</Button>
{captured && <Image source={{ uri: captured }} style={{ marginLeft: 20, width: 51, height: 34 }} />} {captured &&
<Image source={{ uri: captured }}
style={{ marginLeft: 20, width: 51, height: 34 }}
/> }
</View> </View>
{captured && <Text style={{ marginTop: 10, fontSize: 10, fontFamily: "Cochin" }} numberOfLines={1}>{captured.slice(0, 100)}</Text>} {captureConfig &&
<View style={{ paddingTop: 20, alignItems: "center", flexDirection: "row", justifyContent: "space-between" }}>
<Text style={{ fontSize: 10 }}>
format={captureConfig.format}
</Text>
<Text style={{ fontSize: 10 }}>
type={captureConfig.type}
</Text>
<Text style={{ fontSize: 10 }}>
quality={captureConfig.quality+""}
</Text>
</View>
}
{captured &&
<Text numberOfLines={1} style={{ marginTop: 10, fontSize: 10, color: "#aaa" }}>
{captured.slice(0, 100)}
</Text> }
</Demo> </Demo>
<Demo id={2} title="2. Saturate an Image"> <Demo id={2} title="2. Saturate an Image">
......
...@@ -74,7 +74,7 @@ android { ...@@ -74,7 +74,7 @@ android {
dependencies { dependencies {
compile fileTree(dir: "libs", include: ["*.jar"]) compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1" compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:0.17.+" compile "com.facebook.react:react-native:0.18.+"
compile project(":RNGL") compile project(":RNGL")
} }
...@@ -3,11 +3,13 @@ ...@@ -3,11 +3,13 @@
"version": "0.0.1", "version": "0.0.1",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "react-native start" "start": "node node_modules/react-native/local-cli/cli.js start"
}, },
"dependencies": { "dependencies": {
"fbjs": "^0.6.0",
"gl-react": "^2.1.0",
"gl-react-native": "file:../..", "gl-react-native": "file:../..",
"gl-react": "^2.0.2", "react": "^0.14.5",
"react-native": "^0.17.0" "react-native": "0.18.0-rc"
} }
} }
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const shaders = GL.Shaders.create({ const shaders = GL.Shaders.create({
add: { add: {
......
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const { const {
PropTypes PropTypes
} = React; } = React;
......
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const { const {
PropTypes PropTypes
} = React; } = React;
......
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const shaders = GL.Shaders.create({ const shaders = GL.Shaders.create({
Copy: { Copy: {
......
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const shaders = GL.Shaders.create({ const shaders = GL.Shaders.create({
display2: { display2: {
......
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const shaders = GL.Shaders.create({ const shaders = GL.Shaders.create({
helloGL: { helloGL: {
......
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const shaders = GL.Shaders.create({ const shaders = GL.Shaders.create({
layer: { layer: {
......
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const shaders = GL.Shaders.create({ const shaders = GL.Shaders.create({
multiply: { multiply: {
......
const GL = require("gl-react"); const GL = require("gl-react");
const React = GL.React; const React = require("react");
const shaders = GL.Shaders.create({ const shaders = GL.Shaders.create({
TransparentNonPremultiplied: { TransparentNonPremultiplied: {
......
require("gl-react/react-native");
const React = require("react-native"); const React = require("react-native");
const { const {
Text, Text,
......
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":RNGL" external.linked.project.path="$MODULE_DIR$/../../android" external.root.project.path="$MODULE_DIR$/../AdvancedEffects/android" external.system.id="GRADLE" external.system.module.group="AdvancedEffects" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":RNGL" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
<afterSyncTasks>
<task>generateDebugAndroidTestSources</task>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
<option name="LIBRARY_PROJECT" value="true" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/../../android/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/../../android/build/intermediates/classes/androidTest/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$/../../android">
<sourceFolder url="file://$MODULE_DIR$/../../android/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/../../android/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/../../android/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/../../android/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/../../android/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/../../android/build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/../../android/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/../../android/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/../../android/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/../../android/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/../../android/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/../../android/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/debug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/../../android/src/androidTest/rs" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/../../android/build/intermediates/annotations" />
<excludeFolder url="file://$MODULE_DIR$/../../android/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/../../android/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/../../android/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/../../android/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/../../android/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/../../android/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/../../android/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/../../android/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/../../android/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/../../android/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/../../android/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="okhttp-ws-2.5.0" level="project" />
<orderEntry type="library" exported="" name="library-2.4.0" level="project" />
<orderEntry type="library" exported="" name="okio-1.6.0" level="project" />
<orderEntry type="library" exported="" name="stetho-okhttp-1.2.0" level="project" />
<orderEntry type="library" exported="" name="okhttp-2.5.0" level="project" />
<orderEntry type="library" exported="" name="stetho-1.2.0" level="project" />
<orderEntry type="library" exported="" name="jsr305-3.0.0" level="project" />
<orderEntry type="library" exported="" name="jackson-core-2.2.3" level="project" />
<orderEntry type="library" exported="" name="fbcore-0.8.1" level="project" />
<orderEntry type="library" exported="" name="commons-cli-1.2" level="project" />
<orderEntry type="library" exported="" name="recyclerview-v7-23.0.1" level="project" />
<orderEntry type="library" exported="" name="imagepipeline-0.8.1" level="project" />
<orderEntry type="library" exported="" name="react-native-0.17.1" level="project" />
<orderEntry type="library" exported="" name="android-jsc-r174650" level="project" />
<orderEntry type="library" exported="" name="fresco-0.8.1" level="project" />
<orderEntry type="library" exported="" name="imagepipeline-okhttp-0.8.1" level="project" />
<orderEntry type="library" exported="" name="bolts-android-1.1.4" level="project" />
<orderEntry type="library" exported="" name="support-v4-23.0.1" level="project" />
<orderEntry type="library" exported="" name="drawee-0.8.1" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-23.0.1" level="project" />
<orderEntry type="library" exported="" name="support-annotations-23.0.1" level="project" />
</component>
</module>
\ No newline at end of file
**[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) **[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)
# <img width="32" alt="icon" src="https://cloud.githubusercontent.com/assets/211411/9813786/eacfcc24-5888-11e5-8f9b-5a907a2cbb21.png"> gl-react-native ![](https://img.shields.io/badge/react--native-%200.17.x-05F561.svg) # <img width="32" alt="icon" src="https://cloud.githubusercontent.com/assets/211411/9813786/eacfcc24-5888-11e5-8f9b-5a907a2cbb21.png"> gl-react-native ![](https://img.shields.io/badge/react--native-%200.18.x-05F561.svg) ![](https://img.shields.io/badge/gl--react-%202.1.x-05F561.svg)
OpenGL bindings for React Native to implement complex effects over images and components, in the descriptive VDOM paradigm. OpenGL bindings for React Native to implement complex effects over images and components, in the descriptive VDOM paradigm.
......
...@@ -30,5 +30,5 @@ repositories { ...@@ -30,5 +30,5 @@ repositories {
} }
dependencies { dependencies {
compile 'com.facebook.react:react-native:0.17.+' compile 'com.facebook.react:react-native:0.18.+'
} }
package com.projectseptember.RNGL;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
public class CaptureConfig {
String format;
String type;
String filePath;
Double quality;
public CaptureConfig(String format, String type, String filePath, Double quality) {
this.format = format;
this.type = type;
this.filePath = filePath;
this.quality = quality;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CaptureConfig that = (CaptureConfig) o;
if (format != null ? !format.equals(that.format) : that.format != null) return false;
if (type != null ? !type.equals(that.type) : that.type != null) return false;
if (filePath != null ? !filePath.equals(that.filePath) : that.filePath != null)
return false;
return !(quality != null ? !quality.equals(that.quality) : that.quality != null);
}
@Override
public int hashCode() {
int result = format != null ? format.hashCode() : 0;
result = 31 * result + (type != null ? type.hashCode() : 0);
result = 31 * result + (filePath != null ? filePath.hashCode() : 0);
result = 31 * result + (quality != null ? quality.hashCode() : 0);
return result;
}
public static CaptureConfig fromMap (ReadableMap map) {
return new CaptureConfig(
map.getString("format"),
map.getString("type"),
map.getString("filePath"),
map.getDouble("quality")
);
}
public WritableMap toMap () {
WritableMap map = Arguments.createMap();
map.putString("format", format);
map.putString("type", type);
map.putString("filePath", filePath);
map.putDouble("quality", quality);
return map;
}
}
...@@ -27,6 +27,7 @@ import com.facebook.react.uimanager.ThemedReactContext; ...@@ -27,6 +27,7 @@ import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.events.RCTEventEmitter; import com.facebook.react.uimanager.events.RCTEventEmitter;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
...@@ -69,7 +70,11 @@ public class GLCanvas extends GLSurfaceView ...@@ -69,7 +70,11 @@ public class GLCanvas extends GLSurfaceView
private Map<Integer, GLFBO> fbos; private Map<Integer, GLFBO> fbos;
private ExecutorSupplier executorSupplier; private ExecutorSupplier executorSupplier;
private final Queue<Runnable> mRunOnDraw = new LinkedList<>(); private final Queue<Runnable> mRunOnDraw = new LinkedList<>();
private boolean captureFrameRequested = false;
private List<CaptureConfig> captureConfigs = new ArrayList<>();
private float pixelRatio;
private float displayDensity;
public GLCanvas(ThemedReactContext context, ExecutorSupplier executorSupplier) { public GLCanvas(ThemedReactContext context, ExecutorSupplier executorSupplier) {
super(context); super(context);
...@@ -78,6 +83,10 @@ public class GLCanvas extends GLSurfaceView ...@@ -78,6 +83,10 @@ public class GLCanvas extends GLSurfaceView
rnglContext = context.getNativeModule(RNGLContext.class); rnglContext = context.getNativeModule(RNGLContext.class);
setEGLContextClientVersion(2); setEGLContextClientVersion(2);
DisplayMetrics dm = reactContext.getResources().getDisplayMetrics();
displayDensity = dm.density;
pixelRatio = dm.density;
setEGLConfigChooser(8, 8, 8, 8, 16, 0); setEGLConfigChooser(8, 8, 8, 8, 16, 0);
getHolder().setFormat(PixelFormat.RGB_888); getHolder().setFormat(PixelFormat.RGB_888);
setZOrderOnTop(true); setZOrderOnTop(true);
...@@ -104,7 +113,7 @@ public class GLCanvas extends GLSurfaceView ...@@ -104,7 +113,7 @@ public class GLCanvas extends GLSurfaceView
if (!shaders.containsKey(id)) { if (!shaders.containsKey(id)) {
GLShaderData shaderData = rnglContext.getShader(id); GLShaderData shaderData = rnglContext.getShader(id);
if (shaderData == null) return null; if (shaderData == null) return null;
shaders.put(id, new GLShader(shaderData)); shaders.put(id, new GLShader(shaderData, id, rnglContext));
} }
return shaders.get(id); return shaders.get(id);
} }
...@@ -123,6 +132,12 @@ public class GLCanvas extends GLSurfaceView ...@@ -123,6 +132,12 @@ public class GLCanvas extends GLSurfaceView
@Override @Override
public void onSurfaceChanged(GL10 gl, int width, int height) {} public void onSurfaceChanged(GL10 gl, int width, int height) {}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
syncSize(w, h, pixelRatio);
}
@Override @Override
public void onDrawFrame(GL10 gl) { public void onDrawFrame(GL10 gl) {
runAll(mRunOnDraw); runAll(mRunOnDraw);
...@@ -156,16 +171,74 @@ public class GLCanvas extends GLSurfaceView ...@@ -156,16 +171,74 @@ public class GLCanvas extends GLSurfaceView
if (shouldRenderNow) { if (shouldRenderNow) {
this.render(); this.render();
deferredRendering = false; deferredRendering = false;
if (captureFrameRequested) { if (captureConfigs.size() > 0) {
captureFrameRequested = false; capture(); // FIXME: maybe we should schedule this?
}
}
}
private void capture () {
Bitmap capture = createSnapshot(); Bitmap capture = createSnapshot();
ReactContext reactContext = (ReactContext)getContext();
RCTEventEmitter eventEmitter = reactContext.getJSModule(RCTEventEmitter.class);
for (CaptureConfig config : captureConfigs) {
String result = null, error = null;
boolean isPng = config.type.equals("png");
boolean isJpeg = !isPng && (config.type.equals("jpg")||config.type.equals("jpeg"));
boolean isWebm = !isPng && !isJpeg && config.type.equals("webm");
boolean isBase64 = config.format.equals("base64");
boolean isFile = !isBase64 && config.format.equals("file");
Bitmap.CompressFormat compressFormat =
isPng ? Bitmap.CompressFormat.PNG :
isJpeg ? Bitmap.CompressFormat.JPEG :
isWebm ? Bitmap.CompressFormat.WEBP :
null;
int quality = (int)(100 * config.quality);
if (compressFormat == null) {
error = "Unsupported capture type '"+config.type+"'";
}
else if (isBase64) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
capture.compress(Bitmap.CompressFormat.PNG, 100, baos); capture.compress(compressFormat, quality, baos);
String frame = "data:image/png;base64,"+ String frame = "data:image/png;base64,"+
Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT); Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT);
dispatchOnCaptureFrame(frame); baos.close();
result = frame;
}
catch (Exception e) {
e.printStackTrace();
error = "Could not capture as base64: "+e.getMessage();
} }
} }
else if (isFile) {
try {
FileOutputStream fileOutputStream = new FileOutputStream(config.filePath);
capture.compress(compressFormat, quality, fileOutputStream);
fileOutputStream.close();
result = "file://"+config.filePath;
}
catch (Exception e) {
e.printStackTrace();
error = "Could not write file: "+e.getMessage();
}
}
else {
error = "Unsupported capture format '"+config.format+"'";
}
WritableMap response = Arguments.createMap();
response.putMap("config", config.toMap());
if (error != null) response.putString("error", error);
if (result != null) response.putString("result", result);
eventEmitter.receiveEvent(getId(), "captureFrame", response);
}
captureConfigs = new ArrayList<>();
} }
private boolean haveRemainingToPreload() { private boolean haveRemainingToPreload() {
...@@ -242,9 +315,14 @@ public class GLCanvas extends GLSurfaceView ...@@ -242,9 +315,14 @@ public class GLCanvas extends GLSurfaceView
execute(new Runnable() { execute(new Runnable() {
public void run() { public void run() {
// FIXME: maybe should set a flag so we don't do it twice?? // FIXME: maybe should set a flag so we don't do it twice??
try {
if (!syncData()) if (!syncData())
requestSyncData(); requestSyncData();
} }
catch (GLShaderCompilationFailed e) {
// This is ignored. It will be handled by RNGLContext.shaderFailedToCompile
}
}
}); });
} }
...@@ -525,8 +603,8 @@ public class GLCanvas extends GLSurfaceView ...@@ -525,8 +603,8 @@ public class GLCanvas extends GLSurfaceView
uniformsIntBuffer, uniformsIntBuffer,
uniformsFloatBuffer, uniformsFloatBuffer,
textures, textures,
data.width, (int)(data.width * data.pixelRatio),
data.height, (int)(data.height * data.pixelRatio),
data.fboId, data.fboId,
contextChildren, contextChildren,
children); children);
...@@ -598,11 +676,8 @@ public class GLCanvas extends GLSurfaceView ...@@ -598,11 +676,8 @@ public class GLCanvas extends GLSurfaceView
} }
private void recRender (GLRenderData renderData) { private void recRender (GLRenderData renderData) {
DisplayMetrics dm = reactContext.getResources().getDisplayMetrics(); int w = renderData.width;
int h = renderData.height;
int w = Float.valueOf(renderData.width.floatValue() * dm.density).intValue();
int h = Float.valueOf(renderData.height.floatValue() * dm.density).intValue();
for (GLRenderData child: renderData.contextChildren) for (GLRenderData child: renderData.contextChildren)
recRender(child); recRender(child);
...@@ -667,16 +742,6 @@ public class GLCanvas extends GLSurfaceView ...@@ -667,16 +742,6 @@ public class GLCanvas extends GLSurfaceView
} }
} }
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) { private void dispatchOnProgress (double progress, int loaded, int total) {
WritableMap event = Arguments.createMap(); WritableMap event = Arguments.createMap();
event.putDouble("progress", Double.isNaN(progress) ? 0.0 : progress); event.putDouble("progress", Double.isNaN(progress) ? 0.0 : progress);
...@@ -698,9 +763,14 @@ public class GLCanvas extends GLSurfaceView ...@@ -698,9 +763,14 @@ public class GLCanvas extends GLSurfaceView
event); event);
} }
public void requestCaptureFrame() { public void requestCaptureFrame (CaptureConfig config) {
captureFrameRequested = true;
this.requestRender(); this.requestRender();
for (CaptureConfig existing : captureConfigs) {
if (existing.equals(config)) {
return;
}
}
captureConfigs.add(config);
} }
private Bitmap createSnapshot () { private Bitmap createSnapshot () {
...@@ -751,4 +821,16 @@ public class GLCanvas extends GLSurfaceView ...@@ -751,4 +821,16 @@ public class GLCanvas extends GLSurfaceView
d.removeAll(b); d.removeAll(b);
return d; return d;
} }
public void setPixelRatio(float pixelRatio) {
this.pixelRatio = pixelRatio;
syncSize(this.getWidth(), this.getHeight(), pixelRatio);
}
private void syncSize (int w, int h, float pixelRatio) {
int width = (int) (w * pixelRatio / displayDensity);
int height = (int) (h * pixelRatio / displayDensity);
getHolder().setFixedSize(width, height);
}
} }
...@@ -27,6 +27,11 @@ public class GLCanvasManager extends SimpleViewManager<GLCanvas> { ...@@ -27,6 +27,11 @@ public class GLCanvasManager extends SimpleViewManager<GLCanvas> {
private ExecutorSupplier executorSupplier; private ExecutorSupplier executorSupplier;
@ReactProp(name="pixelRatio")
public void setPixelRatio (GLCanvas view, float pixelRatio) {
view.setPixelRatio(pixelRatio);
}
@ReactProp(name="nbContentTextures") @ReactProp(name="nbContentTextures")
public void setNbContentTextures (GLCanvas view, int nbContentTextures) { public void setNbContentTextures (GLCanvas view, int nbContentTextures) {
view.setNbContentTextures(nbContentTextures); view.setNbContentTextures(nbContentTextures);
...@@ -89,7 +94,7 @@ public class GLCanvasManager extends SimpleViewManager<GLCanvas> { ...@@ -89,7 +94,7 @@ public class GLCanvasManager extends SimpleViewManager<GLCanvas> {
Assertions.assertNotNull(args); Assertions.assertNotNull(args);
switch (commandType) { switch (commandType) {
case COMMAND_CAPTURE_FRAME: { case COMMAND_CAPTURE_FRAME: {
canvas.requestCaptureFrame(); canvas.requestCaptureFrame(CaptureConfig.fromMap(args.getMap(0)));
return; return;
} }
default: default:
......
...@@ -10,17 +10,19 @@ public class GLData { ...@@ -10,17 +10,19 @@ public class GLData {
final Integer shader; final Integer shader;
final ReadableMap uniforms; final ReadableMap uniforms;
final Integer width; final Double width;
final Integer height; final Double height;
final Double pixelRatio;
final Integer fboId; final Integer fboId;
final List<GLData> contextChildren; final List<GLData> contextChildren;
final List<GLData> children; final List<GLData> children;
public GLData(Integer shader, ReadableMap uniforms, Integer width, Integer height, Integer fboId, List<GLData> contextChildren, List<GLData> children) { public GLData(Integer shader, ReadableMap uniforms, Double width, Double height, Double pixelRatio, Integer fboId, List<GLData> contextChildren, List<GLData> children) {
this.shader = shader; this.shader = shader;
this.uniforms = uniforms; this.uniforms = uniforms;
this.width = width; this.width = width;
this.height = height; this.height = height;
this.pixelRatio = pixelRatio;
this.fboId = fboId; this.fboId = fboId;
this.contextChildren = contextChildren; this.contextChildren = contextChildren;
this.children = children; this.children = children;
...@@ -37,11 +39,12 @@ public class GLData { ...@@ -37,11 +39,12 @@ public class GLData {
public static GLData fromMap (ReadableMap map) { public static GLData fromMap (ReadableMap map) {
Integer shader = map.getInt("shader"); Integer shader = map.getInt("shader");
ReadableMap uniforms = map.getMap("uniforms"); ReadableMap uniforms = map.getMap("uniforms");
Integer width = (int) map.getDouble("width"); Double width = map.getDouble("width");
Integer height = (int) map.getDouble("height"); Double height = map.getDouble("height");
Double pixelRatio = map.getDouble("pixelRatio");
Integer fboId = map.getInt("fboId"); Integer fboId = map.getInt("fboId");
List<GLData> children = fromArray(map.getArray("children")); List<GLData> children = fromArray(map.getArray("children"));
List<GLData> contextChildren = fromArray(map.getArray("contextChildren")); List<GLData> contextChildren = fromArray(map.getArray("contextChildren"));
return new GLData(shader, uniforms, width, height, fboId, contextChildren, children); return new GLData(shader, uniforms, width, height, pixelRatio, fboId, contextChildren, children);
} }
} }
...@@ -21,29 +21,30 @@ public class GLShader { ...@@ -21,29 +21,30 @@ public class GLShader {
private int pointerLoc; // The "pointer" attribute is used to iterate over vertex private int pointerLoc; // The "pointer" attribute is used to iterate over vertex
private Map<String, Integer> uniformLocations; // The uniform locations cache private Map<String, Integer> uniformLocations; // The uniform locations cache
public GLShader(String name, String vert, String frag) { private Integer id;
this.name = name; private RNGLContext rnglContext;
this.vert = vert; private GLShaderCompilationFailed compilationFailed;
this.frag = frag;
}
public GLShader(GLShaderData data) { public GLShader(GLShaderData data, Integer id, RNGLContext rnglContext) {
this.name = data.name; this.name = data.name;
this.vert = data.vert; this.vert = data.vert;
this.frag = data.frag; this.frag = data.frag;
this.id = id;
this.rnglContext = rnglContext;
} }
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
super.finalize(); super.finalize();
if (buffer != null) { if (buffer != null) {
// TODO: need to check if this works properly
glDeleteProgram(program); glDeleteProgram(program);
glDeleteBuffers(1, buffer, 0); glDeleteBuffers(1, buffer, 0);
} }
} }
public void runtimeException (String msg) { public void runtimeException (String msg) {
throw new RuntimeException("Shader '"+name+"': "+msg); throw new GLShaderCompilationFailed(name, msg);
} }
public void bind () { public void bind () {
...@@ -64,7 +65,7 @@ public class GLShader { ...@@ -64,7 +65,7 @@ public class GLShader {
glGetProgramiv(program, GL_VALIDATE_STATUS, validSuccess, 0); glGetProgramiv(program, GL_VALIDATE_STATUS, validSuccess, 0);
if (validSuccess[0] == GL_FALSE) { if (validSuccess[0] == GL_FALSE) {
glGetProgramInfoLog(program); glGetProgramInfoLog(program);
runtimeException("Validation failed " + glGetProgramInfoLog(program)); runtimeException(glGetProgramInfoLog(program));
} }
} }
...@@ -133,7 +134,7 @@ public class GLShader { ...@@ -133,7 +134,7 @@ public class GLShader {
int compileSuccess[] = new int[1]; int compileSuccess[] = new int[1];
glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, compileSuccess, 0); glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, compileSuccess, 0);
if (compileSuccess[0] == GL_FALSE) { if (compileSuccess[0] == GL_FALSE) {
runtimeException("failed to compile: " + glGetShaderInfoLog(shaderHandle)); runtimeException(glGetShaderInfoLog(shaderHandle));
return -1; return -1;
} }
return shaderHandle; return shaderHandle;
...@@ -157,7 +158,7 @@ public class GLShader { ...@@ -157,7 +158,7 @@ public class GLShader {
this.uniformLocations = locations; this.uniformLocations = locations;
} }
private void makeProgram () { private void makeProgram () throws GLShaderCompilationFailed {
int vertex = compileShader(vert, GL_VERTEX_SHADER); int vertex = compileShader(vert, GL_VERTEX_SHADER);
if (vertex == -1) return; if (vertex == -1) return;
...@@ -172,7 +173,7 @@ public class GLShader { ...@@ -172,7 +173,7 @@ public class GLShader {
int[] linkSuccess = new int[1]; int[] linkSuccess = new int[1];
glGetProgramiv(program, GL_LINK_STATUS, linkSuccess, 0); glGetProgramiv(program, GL_LINK_STATUS, linkSuccess, 0);
if (linkSuccess[0] == GL_FALSE) { if (linkSuccess[0] == GL_FALSE) {
runtimeException("Linking failed "+glGetProgramInfoLog(program)); runtimeException(glGetProgramInfoLog(program));
} }
glUseProgram(program); glUseProgram(program);
...@@ -208,7 +209,18 @@ public class GLShader { ...@@ -208,7 +209,18 @@ public class GLShader {
} }
public boolean ensureCompile() { public boolean ensureCompile() {
if (!isReady()) makeProgram(); if (!isReady()) {
if (compilationFailed != null) throw compilationFailed;
try {
makeProgram();
rnglContext.shaderSucceedToCompile(id, uniformTypes);
}
catch (GLShaderCompilationFailed e) {
compilationFailed = e;
rnglContext.shaderFailedToCompile(id, e);
throw e;
}
}
return isReady(); return isReady();
} }
} }
package com.projectseptember.RNGL;
public class GLShaderCompilationFailed extends RuntimeException {
public final String shaderName;
public final String compileError;
public GLShaderCompilationFailed(String shaderName, String compileError) {
super("Shader '"+shaderName+"': "+compileError);
this.compileError = compileError;
this.shaderName = shaderName;
}
}
package com.projectseptember.RNGL; package com.projectseptember.RNGL;
import android.util.Log;
import static android.opengl.GLES20.*;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -20,6 +26,7 @@ public class RNGLContext extends ReactContextBaseJavaModule { ...@@ -20,6 +26,7 @@ public class RNGLContext extends ReactContextBaseJavaModule {
private Map<Integer, GLShaderData> shaders = new HashMap<>(); private Map<Integer, GLShaderData> shaders = new HashMap<>();
private Map<Integer, GLFBO> fbos = new HashMap<>(); private Map<Integer, GLFBO> fbos = new HashMap<>();
private Map<Integer, Callback> onCompileCallbacks = new HashMap<>();
public RNGLContext (ReactApplicationContext reactContext) { public RNGLContext (ReactApplicationContext reactContext) {
super(reactContext); super(reactContext);
...@@ -35,9 +42,67 @@ public class RNGLContext extends ReactContextBaseJavaModule { ...@@ -35,9 +42,67 @@ public class RNGLContext extends ReactContextBaseJavaModule {
} }
@ReactMethod @ReactMethod
public void addShader (final Integer id, final ReadableMap config) { public void addShader (final Integer id, final ReadableMap config, final Callback onCompile) {
final String frag = config.getString("frag"); final String frag = config.getString("frag");
final String name = config.getString("name"); final String name = config.getString("name");
shaders.put(id, new GLShaderData(name, STATIC_VERT, frag)); shaders.put(id, new GLShaderData(name, STATIC_VERT, frag));
if (onCompile != null) {
onCompileCallbacks.put(id, onCompile);
}
}
@ReactMethod
public void removeShader (final Integer id) {
GLShaderData shader = shaders.remove(id);
if (shader == null) {
throw new Error("removeShader("+id+"): shader does not exist");
}
}
public void shaderFailedToCompile(Integer id, GLShaderCompilationFailed e) {
Callback onCompile = onCompileCallbacks.get(id);
if (onCompile == null) {
Log.e("RNGLContext", e.getMessage());
}
else {
onCompile.invoke(e.compileError);
}
}
public void shaderSucceedToCompile(Integer id, Map<String, Integer> uniformTypes) {
Callback onCompile = onCompileCallbacks.get(id);
onCompileCallbacks.remove(id);
if (onCompile != null) {
WritableMap res = Arguments.createMap();
WritableMap uniforms = Arguments.createMap();
for (String key : uniformTypes.keySet()) {
uniforms.putString(key, glTypeString(uniformTypes.get(key)));
}
res.putMap("uniforms", uniforms);
onCompile.invoke(null, res);
}
}
static String glTypeString (int type) {
switch (type) {
case GL_FLOAT: return "float";
case GL_FLOAT_VEC2: return "vec2";
case GL_FLOAT_VEC3: return "vec3";
case GL_FLOAT_VEC4: return "vec4";
case GL_INT: return "int";
case GL_INT_VEC2: return "ivec2";
case GL_INT_VEC3: return "ivec3";
case GL_INT_VEC4: return "ivec4";
case GL_BOOL: return "bool";
case GL_BOOL_VEC2: return "bvec2";
case GL_BOOL_VEC3: return "bvec3";
case GL_BOOL_VEC4: return "bvec4";
case GL_FLOAT_MAT2: return "mat2";
case GL_FLOAT_MAT3: return "mat3";
case GL_FLOAT_MAT4: return "mat4";
case GL_SAMPLER_2D: return "sampler2D";
case GL_SAMPLER_CUBE: return "samplerCube";
}
return "";
} }
} }
#import <Foundation/Foundation.h>
@interface CaptureConfig: NSObject
@property (nonatomic, copy) NSString *format;
@property (nonatomic, copy) NSString *type;
@property (nonatomic, copy) NSString *filePath;
@property (nonatomic, copy) NSNumber *quality;
-(instancetype)initWithFormat: (NSString *)format
withType: (NSString *)type
withQuality: (NSNumber *)quality
withFilePath: (NSString *)filePath;
- (bool) isEqualToCaptureConfig: (CaptureConfig *)other;
- (NSDictionary *) dictionary;
@end
#import "CaptureConfig.h"
@implementation CaptureConfig
-(instancetype)initWithFormat: (NSString *)format
withType: (NSString *)type
withQuality: (NSNumber *)quality
withFilePath: (NSString *)filePath
{
if ((self = [super init])) {
self.format = format;
self.type = type;
self.quality = quality;
self.filePath = filePath;
}
return self;
}
- (bool) isEqualToCaptureConfig: (CaptureConfig *)other
{
return [self.format isEqualToString:other.format] &&
[self.type isEqualToString:other.type] &&
[self.quality isEqualToNumber:other.quality] &&
[self.filePath isEqualToString:other.filePath];
}
- (NSDictionary *) dictionary
{
return @{
@"format": self.format,
@"type": self.type,
@"quality": self.quality,
@"filePath": self.filePath
};
}
@end
#import <GLKit/GLKit.h> #import <GLKit/GLKit.h>
#import "GLData.h" #import "GLData.h"
#import "CaptureConfig.h"
#import "RCTComponent.h" #import "RCTComponent.h"
@interface GLCanvas: GLKView @interface GLCanvas: GLKView
...@@ -11,6 +12,7 @@ ...@@ -11,6 +12,7 @@
@property (nonatomic) BOOL visibleContent; @property (nonatomic) BOOL visibleContent;
@property (nonatomic) NSNumber *nbContentTextures; @property (nonatomic) NSNumber *nbContentTextures;
@property (nonatomic) NSNumber *renderId; @property (nonatomic) NSNumber *renderId;
@property (nonatomic) NSNumber *pixelRatio;
@property (nonatomic) NSArray *imagesToPreload; @property (nonatomic) NSArray *imagesToPreload;
@property (nonatomic, copy) RCTBubblingEventBlock onGLProgress; @property (nonatomic, copy) RCTBubblingEventBlock onGLProgress;
@property (nonatomic, copy) RCTBubblingEventBlock onGLLoad; @property (nonatomic, copy) RCTBubblingEventBlock onGLLoad;
...@@ -18,6 +20,6 @@ ...@@ -18,6 +20,6 @@
- (instancetype)initWithBridge:(RCTBridge *)bridge; - (instancetype)initWithBridge:(RCTBridge *)bridge;
- (void) requestCaptureFrame; - (void) requestCaptureFrame:(CaptureConfig *)config;
@end @end
...@@ -44,8 +44,6 @@ NSArray* diff (NSArray* a, NSArray* b) { ...@@ -44,8 +44,6 @@ NSArray* diff (NSArray* a, NSArray* b) {
GLRenderData *_renderData; GLRenderData *_renderData;
BOOL _captureFrameRequested;
NSArray *_contentData; NSArray *_contentData;
NSArray *_contentTextures; NSArray *_contentTextures;
NSDictionary *_images; // This caches the currently used images (imageSrc -> GLReactImage) NSDictionary *_images; // This caches the currently used images (imageSrc -> GLReactImage)
...@@ -63,6 +61,9 @@ NSArray* diff (NSArray* a, NSArray* b) { ...@@ -63,6 +61,9 @@ NSArray* diff (NSArray* a, NSArray* b) {
NSTimer *animationTimer; NSTimer *animationTimer;
BOOL _needSync; BOOL _needSync;
NSMutableArray *_captureConfigs;
BOOL _captureScheduled;
} }
- (instancetype)initWithBridge:(RCTBridge *)bridge - (instancetype)initWithBridge:(RCTBridge *)bridge
...@@ -71,23 +72,44 @@ NSArray* diff (NSArray* a, NSArray* b) { ...@@ -71,23 +72,44 @@ NSArray* diff (NSArray* a, NSArray* b) {
_bridge = bridge; _bridge = bridge;
_images = @{}; _images = @{};
_preloaded = [[NSMutableArray alloc] init]; _preloaded = [[NSMutableArray alloc] init];
_captureFrameRequested = false; _captureConfigs = [[NSMutableArray alloc] init];
_captureScheduled = false;
_dirtyOnLoad = true; _dirtyOnLoad = true;
_neverRendered = true; _neverRendered = true;
self.context = [bridge.rnglContext getContext]; self.context = [bridge.rnglContext getContext];
self.contentScaleFactor = RCTScreenScale();
} }
return self; return self;
} }
RCT_NOT_IMPLEMENTED(-init) RCT_NOT_IMPLEMENTED(-init)
- (void)dealloc
{
_bridge = nil;
_images = nil;
_preloaded = nil;
_captureConfigs = nil;
_contentData = nil;
_contentTextures = nil;
_data = nil;
_renderData = nil;
if (animationTimer) {
[animationTimer invalidate];
animationTimer = nil;
}
}
//// Props Setters //// Props Setters
- (void) requestCaptureFrame - (void) requestCaptureFrame: (CaptureConfig *)config
{ {
_captureFrameRequested = true;
[self setNeedsDisplay]; [self setNeedsDisplay];
for (CaptureConfig *existing in _captureConfigs) {
if ([existing isEqualToCaptureConfig:config]) {
return;
}
}
[_captureConfigs addObject:config];
} }
-(void)setImagesToPreload:(NSArray *)imagesToPreload -(void)setImagesToPreload:(NSArray *)imagesToPreload
...@@ -141,6 +163,12 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -141,6 +163,12 @@ RCT_NOT_IMPLEMENTED(-init)
} }
} }
- (void)setPixelRatio:(NSNumber *)pixelRatio
{
self.contentScaleFactor = [pixelRatio floatValue];
[self setNeedsDisplay];
}
- (void)setData:(GLData *)data - (void)setData:(GLData *)data
{ {
_data = data; _data = data;
...@@ -161,7 +189,7 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -161,7 +189,7 @@ RCT_NOT_IMPLEMENTED(-init)
[self setNeedsDisplay]; [self setNeedsDisplay];
} }
- (void)syncData - (bool)syncData:(NSError **)error
{ {
@autoreleasepool { @autoreleasepool {
...@@ -173,6 +201,7 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -173,6 +201,7 @@ RCT_NOT_IMPLEMENTED(-init)
weak_traverseTree = traverseTree = ^GLRenderData *(GLData *data) { weak_traverseTree = traverseTree = ^GLRenderData *(GLData *data) {
NSNumber *width = data.width; NSNumber *width = data.width;
NSNumber *height = data.height; NSNumber *height = data.height;
NSNumber *pixelRatio = data.pixelRatio;
int fboId = [data.fboId intValue]; int fboId = [data.fboId intValue];
NSMutableArray *contextChildren = [[NSMutableArray alloc] init]; NSMutableArray *contextChildren = [[NSMutableArray alloc] init];
...@@ -191,6 +220,7 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -191,6 +220,7 @@ RCT_NOT_IMPLEMENTED(-init)
GLShader *shader = [_bridge.rnglContext getShader:data.shader]; GLShader *shader = [_bridge.rnglContext getShader:data.shader];
if (shader == nil) return nil; if (shader == nil) return nil;
if (![shader ensureCompiles:error]) return nil;
NSDictionary *uniformTypes = [shader uniformTypes]; NSDictionary *uniformTypes = [shader uniformTypes];
NSMutableDictionary *uniforms = [[NSMutableDictionary alloc] init]; NSMutableDictionary *uniforms = [[NSMutableDictionary alloc] init];
...@@ -270,8 +300,8 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -270,8 +300,8 @@ RCT_NOT_IMPLEMENTED(-init)
initWithShader:shader initWithShader:shader
withUniforms:uniforms withUniforms:uniforms
withTextures:textures withTextures:textures
withWidth:width withWidth:(int)([width floatValue] * [pixelRatio floatValue])
withHeight:height withHeight:(int)([height floatValue] * [pixelRatio floatValue])
withFboId:fboId withFboId:fboId
withContextChildren:contextChildren withContextChildren:contextChildren
withChildren:children]; withChildren:children];
...@@ -279,16 +309,15 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -279,16 +309,15 @@ RCT_NOT_IMPLEMENTED(-init)
GLRenderData *res = traverseTree(_data); GLRenderData *res = traverseTree(_data);
if (res != nil) { if (res != nil) {
_needSync = false;
_renderData = traverseTree(_data); _renderData = traverseTree(_data);
_images = images; _images = images;
for (NSString *src in diff([prevImages allKeys], [images allKeys])) { for (NSString *src in diff([prevImages allKeys], [images allKeys])) {
[_preloaded removeObject:src]; [_preloaded removeObject:src];
} }
return true;
} }
else { else {
// the data is not ready, retry in one tick return false;
[self setNeedsDisplay];
} }
} }
} }
...@@ -305,7 +334,7 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -305,7 +334,7 @@ RCT_NOT_IMPLEMENTED(-init)
UIView *v = [view.subviews count] == 1 ? UIView *v = [view.subviews count] == 1 ?
view.subviews[0] : view.subviews[0] :
view; view;
imgData = [GLImageData genPixelsWithView:v]; imgData = [GLImageData genPixelsWithView:v withPixelRatio:self.contentScaleFactor];
} else { } else {
imgData = nil; imgData = nil;
} }
...@@ -360,7 +389,16 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -360,7 +389,16 @@ RCT_NOT_IMPLEMENTED(-init)
} }
if (_needSync) { if (_needSync) {
[self syncData]; NSError *error;
BOOL syncSuccessful = [self syncData:&error];
BOOL errorCanBeRecovered = error==nil || (error.code != GLLinkingFailure && error.code != GLCompileFailure);
if (!syncSuccessful && errorCanBeRecovered) {
// something failed but is recoverable, retry in one tick
[self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
}
else {
_needSync = false;
}
} }
if ([self haveRemainingToPreload]) { if ([self haveRemainingToPreload]) {
...@@ -375,21 +413,63 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -375,21 +413,63 @@ RCT_NOT_IMPLEMENTED(-init)
else { else {
_deferredRendering = false; _deferredRendering = false;
[self render]; [self render];
if (_captureFrameRequested) { if (!_captureScheduled && [_captureConfigs count] > 0) {
_captureFrameRequested = false; _captureScheduled = true;
[self performSelectorOnMainThread:@selector(capture) withObject:nil waitUntilDone:NO]; [self performSelectorOnMainThread:@selector(capture) withObject:nil waitUntilDone:NO];
} }
} }
} }
-(void)capture -(void) capture
{ {
_captureScheduled = false;
if (!self.onGLCaptureFrame) return;
UIImage *frameImage = [self snapshot]; UIImage *frameImage = [self snapshot];
NSData *frameData = UIImagePNGRepresentation(frameImage);
NSString *frame = for (CaptureConfig *config in _captureConfigs) {
[NSString stringWithFormat:@"data:image/png;base64,%@", id result;
[frameData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]]; id error;
if (self.onGLCaptureFrame) self.onGLCaptureFrame(@{ @"frame": frame });
BOOL isPng = [config.type isEqualToString:@"png"];
BOOL isJpeg = !isPng && ([config.type isEqualToString:@"jpeg"] || [config.type isEqualToString:@"jpg"]);
BOOL isBase64 = [config.format isEqualToString:@"base64"];
BOOL isFile = !isBase64 && [config.format isEqualToString:@"file"];
NSData *frameData =
isPng ? UIImagePNGRepresentation(frameImage) :
isJpeg ? UIImageJPEGRepresentation(frameImage, [config.quality floatValue]) :
nil;
if (!frameData) {
error = [NSString stringWithFormat:@"Unsupported capture type '%@'", config.type];
}
else if (isBase64) {
NSString *base64 = [frameData base64EncodedStringWithOptions: NSDataBase64Encoding64CharacterLineLength];
result = [NSString stringWithFormat:@"data:image/%@;base64,%@", config.type, base64];
}
else if (isFile) {
NSError *e;
if (![frameData writeToFile:config.filePath options:0 error:&e]) {
error = [NSString stringWithFormat:@"Could not write file: %@", e.localizedDescription];
}
else {
result = [NSString stringWithFormat:@"file://%@", config.filePath];
}
}
else {
error = [NSString stringWithFormat:@"Unsupported capture format '%@'", config.format];
}
NSMutableDictionary *response = [[NSMutableDictionary alloc] init];
response[@"config"] = [config dictionary];
if (error) response[@"error"] = error;
if (result) response[@"result"] = result;
self.onGLCaptureFrame(response);
}
_captureConfigs = [[NSMutableArray alloc] init];
} }
- (void)render - (void)render
...@@ -399,13 +479,12 @@ RCT_NOT_IMPLEMENTED(-init) ...@@ -399,13 +479,12 @@ RCT_NOT_IMPLEMENTED(-init)
RCT_PROFILE_BEGIN_EVENT(0, @"GLCanvas render", nil); RCT_PROFILE_BEGIN_EVENT(0, @"GLCanvas render", nil);
@autoreleasepool { @autoreleasepool {
CGFloat scale = RCTScreenScale();
void (^recDraw) (GLRenderData *renderData); void (^recDraw) (GLRenderData *renderData);
__block __weak void (^weak_recDraw) (GLRenderData *renderData); __block __weak void (^weak_recDraw) (GLRenderData *renderData);
weak_recDraw = recDraw = ^void(GLRenderData *renderData) { weak_recDraw = recDraw = ^void(GLRenderData *renderData) {
float w = [renderData.width floatValue] * scale; int w = renderData.width;
float h = [renderData.height floatValue] * scale; int h = renderData.height;
for (GLRenderData *child in renderData.contextChildren) for (GLRenderData *child in renderData.contextChildren)
weak_recDraw(child); weak_recDraw(child);
......
#import "GLCanvasManager.h" #import "GLCanvasManager.h"
#import "GLCanvas.h" #import "GLCanvas.h"
#import "RCTConvert+GLData.h" #import "RCTConvert+GLData.h"
#import "RCTConvert+CaptureConfig.h"
#import "RCTUIManager.h" #import "RCTUIManager.h"
#import "RCTLog.h" #import "RCTLog.h"
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
...@@ -17,17 +18,23 @@ RCT_EXPORT_MODULE(); ...@@ -17,17 +18,23 @@ RCT_EXPORT_MODULE();
return self; return self;
} }
- (dispatch_queue_t)methodQueue
{
return self.bridge.uiManager.methodQueue;
}
RCT_EXPORT_VIEW_PROPERTY(nbContentTextures, NSNumber); RCT_EXPORT_VIEW_PROPERTY(nbContentTextures, NSNumber);
RCT_EXPORT_VIEW_PROPERTY(opaque, BOOL); RCT_EXPORT_VIEW_PROPERTY(opaque, BOOL);
RCT_EXPORT_VIEW_PROPERTY(autoRedraw, BOOL); RCT_EXPORT_VIEW_PROPERTY(autoRedraw, BOOL);
RCT_EXPORT_VIEW_PROPERTY(data, GLData); RCT_EXPORT_VIEW_PROPERTY(data, GLData);
RCT_EXPORT_VIEW_PROPERTY(renderId, NSNumber); RCT_EXPORT_VIEW_PROPERTY(renderId, NSNumber);
RCT_EXPORT_VIEW_PROPERTY(pixelRatio, NSNumber);
RCT_EXPORT_VIEW_PROPERTY(imagesToPreload, NSArray); RCT_EXPORT_VIEW_PROPERTY(imagesToPreload, NSArray);
RCT_EXPORT_VIEW_PROPERTY(onGLLoad, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onGLLoad, RCTBubblingEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onGLProgress, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onGLProgress, RCTBubblingEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onGLCaptureFrame, RCTBubblingEventBlock); RCT_EXPORT_VIEW_PROPERTY(onGLCaptureFrame, RCTBubblingEventBlock);
RCT_EXPORT_METHOD(capture: (nonnull NSNumber *)reactTag) RCT_EXPORT_METHOD(capture: (nonnull NSNumber *)reactTag withConfig:(id)config)
{ {
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) { [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
UIView *view = viewRegistry[reactTag]; UIView *view = viewRegistry[reactTag];
...@@ -36,7 +43,7 @@ RCT_EXPORT_METHOD(capture: (nonnull NSNumber *)reactTag) ...@@ -36,7 +43,7 @@ RCT_EXPORT_METHOD(capture: (nonnull NSNumber *)reactTag)
} }
else { else {
GLCanvas *glCanvas = (GLCanvas *)view; GLCanvas *glCanvas = (GLCanvas *)view;
[glCanvas requestCaptureFrame]; [glCanvas requestCaptureFrame:[RCTConvert CaptureConfig:config]];
} }
}]; }];
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
@property (nonatomic) NSDictionary *uniforms; @property (nonatomic) NSDictionary *uniforms;
@property (nonatomic) NSNumber *width; @property (nonatomic) NSNumber *width;
@property (nonatomic) NSNumber *height; @property (nonatomic) NSNumber *height;
@property (nonatomic) NSNumber *pixelRatio;
@property (nonatomic) NSNumber *fboId; @property (nonatomic) NSNumber *fboId;
@property (nonatomic) NSArray *contextChildren; @property (nonatomic) NSArray *contextChildren;
@property (nonatomic) NSArray *children; @property (nonatomic) NSArray *children;
...@@ -16,6 +17,7 @@ ...@@ -16,6 +17,7 @@
withUniforms: (NSDictionary *)uniforms withUniforms: (NSDictionary *)uniforms
withWidth: (NSNumber *)width withWidth: (NSNumber *)width
withHeight: (NSNumber *)height withHeight: (NSNumber *)height
withPixelRatio: (NSNumber *)pixelRatio
withFboId: (NSNumber *)fboId withFboId: (NSNumber *)fboId
withContextChildren: (NSArray *)contextChildren withContextChildren: (NSArray *)contextChildren
withChildren: (NSArray *)children; withChildren: (NSArray *)children;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
withUniforms: (NSDictionary *)uniforms withUniforms: (NSDictionary *)uniforms
withWidth: (NSNumber *)width withWidth: (NSNumber *)width
withHeight: (NSNumber *)height withHeight: (NSNumber *)height
withPixelRatio: (NSNumber *)pixelRatio
withFboId: (NSNumber *)fboId withFboId: (NSNumber *)fboId
withContextChildren: (NSArray *)contextChildren withContextChildren: (NSArray *)contextChildren
withChildren: (NSArray *)children withChildren: (NSArray *)children
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
self.uniforms = uniforms; self.uniforms = uniforms;
self.width = width; self.width = width;
self.height = height; self.height = height;
self.pixelRatio = pixelRatio;
self.fboId = fboId; self.fboId = fboId;
self.contextChildren = contextChildren; self.contextChildren = contextChildren;
self.children = children; self.children = children;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
+ (GLImageData*) empty; + (GLImageData*) empty;
+ (GLImageData*) genPixelsWithImage: (UIImage *)image; + (GLImageData*) genPixelsWithImage: (UIImage *)image;
+ (GLImageData*) genPixelsWithView: (UIView *)view; + (GLImageData*) genPixelsWithView: (UIView *)view withPixelRatio:(float)pixelRatio;
- (instancetype)initWithData: (GLubyte *)data withWidth:(int)width withHeight:(int)height; - (instancetype)initWithData: (GLubyte *)data withWidth:(int)width withHeight:(int)height;
......
#import "GLImageData.h" #import "GLImageData.h"
#import "RCTUtils.h"
#import "RCTLog.h" #import "RCTLog.h"
// This structure aims to be used in an immutable way // This structure aims to be used in an immutable way
...@@ -55,16 +54,16 @@ GLImageData *EMPTY_PIXELS; ...@@ -55,16 +54,16 @@ GLImageData *EMPTY_PIXELS;
return [[GLImageData alloc] initWithData:data withWidth:width withHeight:height]; return [[GLImageData alloc] initWithData:data withWidth:width withHeight:height];
} }
+ (GLImageData *)genPixelsWithView: (UIView *)view + (GLImageData *)genPixelsWithView: (UIView *)view withPixelRatio:(float)pixelRatio
{ {
float width = RCTScreenScale() * view.bounds.size.width; float width = pixelRatio * view.bounds.size.width;
float height = RCTScreenScale() * view.bounds.size.height; float height = pixelRatio * view.bounds.size.height;
GLubyte *data = (GLubyte *)malloc(4 * width * height); GLubyte *data = (GLubyte *)malloc(4 * width * height);
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(data, width, height, 8, 4 * width, colourSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGContextRef ctx = CGBitmapContextCreate(data, width, height, 8, 4 * width, colourSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colourSpace); CGColorSpaceRelease(colourSpace);
CGContextClearRect(ctx, CGRectMake(0.0, 0.0, width, height)); CGContextClearRect(ctx, CGRectMake(0.0, 0.0, width, height));
CGContextScaleCTM(ctx, RCTScreenScale(), RCTScreenScale()); CGContextScaleCTM(ctx, pixelRatio, pixelRatio);
[view.layer renderInContext:ctx]; [view.layer renderInContext:ctx];
CGContextRelease(ctx); CGContextRelease(ctx);
return [[GLImageData alloc] initWithData:data withWidth:width withHeight:height]; return [[GLImageData alloc] initWithData:data withWidth:width withHeight:height];
......
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
@property (nonatomic) GLShader *shader; @property (nonatomic) GLShader *shader;
@property (nonatomic) NSDictionary *uniforms; @property (nonatomic) NSDictionary *uniforms;
@property (nonatomic) NSDictionary *textures; @property (nonatomic) NSDictionary *textures;
@property (nonatomic) NSNumber *width; @property (nonatomic) int width;
@property (nonatomic) NSNumber *height; @property (nonatomic) int height;
@property (nonatomic) int fboId; @property (nonatomic) int fboId;
@property (nonatomic) NSArray *contextChildren; @property (nonatomic) NSArray *contextChildren;
@property (nonatomic) NSArray *children; @property (nonatomic) NSArray *children;
...@@ -16,8 +16,8 @@ ...@@ -16,8 +16,8 @@
-(instancetype) initWithShader: (GLShader *)shader -(instancetype) initWithShader: (GLShader *)shader
withUniforms:(NSDictionary *)uniforms withUniforms:(NSDictionary *)uniforms
withTextures: (NSDictionary *)textures withTextures: (NSDictionary *)textures
withWidth: (NSNumber *)width withWidth: (int)width
withHeight: (NSNumber *)height withHeight: (int)height
withFboId: (int)fboId withFboId: (int)fboId
withContextChildren: (NSArray *)contextChildren withContextChildren: (NSArray *)contextChildren
withChildren: (NSArray *)children; withChildren: (NSArray *)children;
......
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
-(instancetype) initWithShader: (GLShader *)shader -(instancetype) initWithShader: (GLShader *)shader
withUniforms:(NSDictionary *)uniforms withUniforms:(NSDictionary *)uniforms
withTextures: (NSDictionary *)textures withTextures: (NSDictionary *)textures
withWidth: (NSNumber *)width withWidth: (int)width
withHeight: (NSNumber *)height withHeight: (int)height
withFboId: (int)fboId withFboId: (int)fboId
withContextChildren: (NSArray *)contextChildren withContextChildren: (NSArray *)contextChildren
withChildren: (NSArray *)children withChildren: (NSArray *)children
......
#import <GLKit/GLKit.h> #import <GLKit/GLKit.h>
#import "RCTBridgeModule.h" #import "RCTBridgeModule.h"
NS_ENUM(NSInteger) {
GLContextFailure = 87001,
GLLinkingFailure = 87002,
GLCompileFailure = 87003,
GLNotAProgram = 87004
};
@interface GLShader: NSObject @interface GLShader: NSObject
@property EAGLContext *context; @property EAGLContext *context;
...@@ -18,10 +25,7 @@ ...@@ -18,10 +25,7 @@
*/ */
- (void) bind; - (void) bind;
/** - (bool) ensureCompiles: (NSError**)error;
* Check the shader validity
*/
- (void) validate;
/** /**
* Set the value of an uniform * Set the value of an uniform
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#import "RCTConvert.h" #import "RCTConvert.h"
#import "GLShader.h" #import "GLShader.h"
GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shaderType) { GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shaderType, NSError **error) {
GLuint shaderHandle = glCreateShader(shaderType); GLuint shaderHandle = glCreateShader(shaderType);
...@@ -20,8 +20,10 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -20,8 +20,10 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
if (compileSuccess == GL_FALSE) { if (compileSuccess == GL_FALSE) {
GLchar messages[256]; GLchar messages[256];
glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]); glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages]; *error = [[NSError alloc]
RCTLogError(@"Shader '%@' failed to compile: %@", shaderName, messageString); initWithDomain:[NSString stringWithUTF8String:messages]
code:GLCompileFailure
userInfo:nil];
return -1; return -1;
} }
...@@ -41,6 +43,7 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -41,6 +43,7 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
GLint pointerLoc; // The "pointer" attribute is used to iterate over vertex GLint pointerLoc; // The "pointer" attribute is used to iterate over vertex
NSDictionary *_uniformTypes; // The types of the GLSL uniforms (N.B: array are not supported) NSDictionary *_uniformTypes; // The types of the GLSL uniforms (N.B: array are not supported)
NSDictionary *_uniformLocations; // The uniform locations cache NSDictionary *_uniformLocations; // The uniform locations cache
NSError *_error;
} }
- (instancetype)initWithContext: (EAGLContext*)context withName:(NSString *)name withVert:(NSString *)vert withFrag:(NSString *)frag - (instancetype)initWithContext: (EAGLContext*)context withName:(NSString *)name withVert:(NSString *)vert withFrag:(NSString *)frag
...@@ -51,7 +54,10 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -51,7 +54,10 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
_context = context; _context = context;
_vert = vert; _vert = vert;
_frag = frag; _frag = frag;
[self makeProgram]; NSError *error;
if (![self makeProgram:&error]) {
_error = error;
}
} }
return self; return self;
} }
...@@ -60,12 +66,21 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -60,12 +66,21 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
{ {
glDeleteProgram(program); glDeleteProgram(program);
glDeleteBuffers(1, &buffer); glDeleteBuffers(1, &buffer);
_name = nil;
_context = nil;
_vert = nil;
_frag = nil;
_uniformLocations = nil;
_uniformTypes = nil;
program = 0;
buffer = 0;
pointerLoc = 0;
} }
- (bool) ensureContext - (bool) ensureContext: (NSError **)error
{ {
if (![EAGLContext setCurrentContext:_context]) { if (!_context || ![EAGLContext setCurrentContext:_context]) {
RCTLogError(@"Shader '%@': Failed to set current OpenGL context", _name); *error = [[NSError alloc] initWithDomain:@"Failed to set current OpenGL context" code:GLContextFailure userInfo:nil];
return false; return false;
} }
return true; return true;
...@@ -73,11 +88,6 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -73,11 +88,6 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
- (void) bind - (void) bind
{ {
if (![self ensureContext]) return;
if ( glIsProgram(program) != GL_TRUE ){
RCTLogError(@"Shader '%@': not a program!", _name);
return;
}
glUseProgram(program); glUseProgram(program);
glBindBuffer(GL_ARRAY_BUFFER, buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer);
glEnableVertexAttribArray(pointerLoc); glEnableVertexAttribArray(pointerLoc);
...@@ -307,19 +317,6 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -307,19 +317,6 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
} }
} }
- (void) validate
{
glValidateProgram(program);
GLint validSuccess;
glGetProgramiv(program, GL_VALIDATE_STATUS, &validSuccess);
if (validSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
RCTLogError(@"Shader '%@': Validation failed %@", _name, messageString);
}
}
- (void) computeMeta - (void) computeMeta
{ {
NSMutableDictionary *uniforms = @{}.mutableCopy; NSMutableDictionary *uniforms = @{}.mutableCopy;
...@@ -342,15 +339,29 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -342,15 +339,29 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
_uniformLocations = locations; _uniformLocations = locations;
} }
- (void) makeProgram - (bool) ensureCompiles: (NSError **)error
{ {
if (![self ensureContext]) return; if (![self ensureContext:error]) {
return false;
}
if (!glIsProgram(program)) {
*error = [[NSError alloc] initWithDomain:@"not a program" code:GLNotAProgram userInfo:nil];
return false;
}
if (_error == nil) return true;
*error = _error;
return false;
}
- (bool) makeProgram: (NSError **)error
{
if (![self ensureContext:error]) return false;
GLuint vertex = compileShader(_name, _vert, GL_VERTEX_SHADER); GLuint vertex = compileShader(_name, _vert, GL_VERTEX_SHADER, error);
if (vertex == -1) return; if (vertex == -1) return false;
GLuint fragment = compileShader(_name, _frag, GL_FRAGMENT_SHADER); GLuint fragment = compileShader(_name, _frag, GL_FRAGMENT_SHADER, error);
if (fragment == -1) return; if (fragment == -1) return false;
program = glCreateProgram(); program = glCreateProgram();
glAttachShader(program, vertex); glAttachShader(program, vertex);
...@@ -362,9 +373,11 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -362,9 +373,11 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
if (linkSuccess == GL_FALSE) { if (linkSuccess == GL_FALSE) {
GLchar messages[256]; GLchar messages[256];
glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]); glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages]; *error = [[NSError alloc]
RCTLogError(@"Shader '%@': Linking failed %@", _name, messageString); initWithDomain:[NSString stringWithUTF8String:messages]
return; code:GLLinkingFailure
userInfo:nil];
return false;
} }
glUseProgram(program); glUseProgram(program);
...@@ -384,6 +397,8 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade ...@@ -384,6 +397,8 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
1.0, 1.0 1.0, 1.0
}; };
glBufferData(GL_ARRAY_BUFFER, sizeof(buf), buf, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(buf), buf, GL_STATIC_DRAW);
return true;
} }
......
#import "RCTConvert.h"
#import "CaptureConfig.h"
@interface RCTConvert (CaptureConfig)
+ (CaptureConfig *)CaptureConfig:(id)json;
@end
//
// RCTConvert+CaptureConfig.m
// RNGL
//
// Created by Gaetan Renaudeau on 30/12/15.
//
//
#import "RCTConvert+CaptureConfig.h"
@implementation RCTConvert (CaptureConfig)
+ (CaptureConfig *)CaptureConfig:(id)json
{
return [[CaptureConfig alloc]
initWithFormat:[RCTConvert NSString:json[@"format"]]
withType:[RCTConvert NSString:json[@"type"]]
withQuality:[RCTConvert NSNumber:json[@"quality"]]
withFilePath:[RCTConvert NSString:json[@"filePath"]]];
}
@end
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
NSDictionary *uniforms = [self NSDictionary:json[@"uniforms"]]; NSDictionary *uniforms = [self NSDictionary:json[@"uniforms"]];
NSNumber *width = [self NSNumber:json[@"width"]]; NSNumber *width = [self NSNumber:json[@"width"]];
NSNumber *height = [self NSNumber:json[@"height"]]; NSNumber *height = [self NSNumber:json[@"height"]];
NSNumber *pixelRatio = [self NSNumber:json[@"pixelRatio"]];
NSNumber *fboId = [self NSNumber:json[@"fboId"]]; NSNumber *fboId = [self NSNumber:json[@"fboId"]];
NSArray *contextChildrenJSON = [self NSArray: json[@"contextChildren"]]; NSArray *contextChildrenJSON = [self NSArray: json[@"contextChildren"]];
NSArray *childrenJSON = [self NSArray: json[@"children"]]; NSArray *childrenJSON = [self NSArray: json[@"children"]];
...@@ -30,6 +31,7 @@ ...@@ -30,6 +31,7 @@
withUniforms: uniforms withUniforms: uniforms
withWidth: width withWidth: width
withHeight: height withHeight: height
withPixelRatio: pixelRatio
withFboId: fboId withFboId: fboId
withContextChildren: contextChildren withContextChildren: contextChildren
withChildren: children]; withChildren: children];
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
346089D81BEFD0A500C90DB5 /* GLTexture.m in Sources */ = {isa = PBXBuildFile; fileRef = 346089CB1BEFD0A500C90DB5 /* GLTexture.m */; }; 346089D81BEFD0A500C90DB5 /* GLTexture.m in Sources */ = {isa = PBXBuildFile; fileRef = 346089CB1BEFD0A500C90DB5 /* GLTexture.m */; };
346089D91BEFD0A500C90DB5 /* RCTConvert+GLData.m in Sources */ = {isa = PBXBuildFile; fileRef = 346089CD1BEFD0A500C90DB5 /* RCTConvert+GLData.m */; }; 346089D91BEFD0A500C90DB5 /* RCTConvert+GLData.m in Sources */ = {isa = PBXBuildFile; fileRef = 346089CD1BEFD0A500C90DB5 /* RCTConvert+GLData.m */; };
346089DA1BEFD0A500C90DB5 /* RNGLContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 346089CF1BEFD0A500C90DB5 /* RNGLContext.m */; }; 346089DA1BEFD0A500C90DB5 /* RNGLContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 346089CF1BEFD0A500C90DB5 /* RNGLContext.m */; };
34C990421C34939C002F49FC /* RCTConvert+CaptureConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C990411C34939C002F49FC /* RCTConvert+CaptureConfig.m */; };
34C990471C349422002F49FC /* CaptureConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C990461C349422002F49FC /* CaptureConfig.m */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
...@@ -48,13 +50,17 @@ ...@@ -48,13 +50,17 @@
346089C61BEFD0A500C90DB5 /* GLRenderData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLRenderData.h; sourceTree = "<group>"; }; 346089C61BEFD0A500C90DB5 /* GLRenderData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLRenderData.h; sourceTree = "<group>"; };
346089C71BEFD0A500C90DB5 /* GLRenderData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLRenderData.m; sourceTree = "<group>"; }; 346089C71BEFD0A500C90DB5 /* GLRenderData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLRenderData.m; sourceTree = "<group>"; };
346089C81BEFD0A500C90DB5 /* GLShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLShader.h; sourceTree = "<group>"; }; 346089C81BEFD0A500C90DB5 /* GLShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLShader.h; sourceTree = "<group>"; };
346089C91BEFD0A500C90DB5 /* GLShader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GLShader.m; sourceTree = "<group>"; }; 346089C91BEFD0A500C90DB5 /* GLShader.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = GLShader.m; sourceTree = "<group>"; tabWidth = 2; };
346089CA1BEFD0A500C90DB5 /* GLTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLTexture.h; sourceTree = "<group>"; }; 346089CA1BEFD0A500C90DB5 /* GLTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLTexture.h; sourceTree = "<group>"; };
346089CB1BEFD0A500C90DB5 /* GLTexture.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = GLTexture.m; sourceTree = "<group>"; tabWidth = 2; }; 346089CB1BEFD0A500C90DB5 /* GLTexture.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = GLTexture.m; sourceTree = "<group>"; tabWidth = 2; };
346089CC1BEFD0A500C90DB5 /* RCTConvert+GLData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+GLData.h"; sourceTree = "<group>"; }; 346089CC1BEFD0A500C90DB5 /* RCTConvert+GLData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+GLData.h"; sourceTree = "<group>"; };
346089CD1BEFD0A500C90DB5 /* RCTConvert+GLData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+GLData.m"; sourceTree = "<group>"; }; 346089CD1BEFD0A500C90DB5 /* RCTConvert+GLData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+GLData.m"; sourceTree = "<group>"; };
346089CE1BEFD0A500C90DB5 /* RNGLContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNGLContext.h; sourceTree = "<group>"; }; 346089CE1BEFD0A500C90DB5 /* RNGLContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNGLContext.h; sourceTree = "<group>"; };
346089CF1BEFD0A500C90DB5 /* RNGLContext.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = RNGLContext.m; sourceTree = "<group>"; tabWidth = 2; }; 346089CF1BEFD0A500C90DB5 /* RNGLContext.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = RNGLContext.m; sourceTree = "<group>"; tabWidth = 2; };
34C990401C34939C002F49FC /* RCTConvert+CaptureConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+CaptureConfig.h"; sourceTree = "<group>"; };
34C990411C34939C002F49FC /* RCTConvert+CaptureConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+CaptureConfig.m"; sourceTree = "<group>"; tabWidth = 2; };
34C990451C34941C002F49FC /* CaptureConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CaptureConfig.h; sourceTree = "<group>"; };
34C990461C349422002F49FC /* CaptureConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = CaptureConfig.m; sourceTree = "<group>"; tabWidth = 2; };
4107012F1ACB723B00C6AA39 /* libRNGL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNGL.a; sourceTree = BUILT_PRODUCTS_DIR; }; 4107012F1ACB723B00C6AA39 /* libRNGL.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNGL.a; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */ /* End PBXFileReference section */
...@@ -92,6 +98,10 @@ ...@@ -92,6 +98,10 @@
346089CB1BEFD0A500C90DB5 /* GLTexture.m */, 346089CB1BEFD0A500C90DB5 /* GLTexture.m */,
346089CC1BEFD0A500C90DB5 /* RCTConvert+GLData.h */, 346089CC1BEFD0A500C90DB5 /* RCTConvert+GLData.h */,
346089CD1BEFD0A500C90DB5 /* RCTConvert+GLData.m */, 346089CD1BEFD0A500C90DB5 /* RCTConvert+GLData.m */,
34C990461C349422002F49FC /* CaptureConfig.m */,
34C990451C34941C002F49FC /* CaptureConfig.h */,
34C990401C34939C002F49FC /* RCTConvert+CaptureConfig.h */,
34C990411C34939C002F49FC /* RCTConvert+CaptureConfig.m */,
346089CE1BEFD0A500C90DB5 /* RNGLContext.h */, 346089CE1BEFD0A500C90DB5 /* RNGLContext.h */,
346089CF1BEFD0A500C90DB5 /* RNGLContext.m */, 346089CF1BEFD0A500C90DB5 /* RNGLContext.m */,
410701301ACB723B00C6AA39 /* Products */, 410701301ACB723B00C6AA39 /* Products */,
...@@ -161,10 +171,12 @@ ...@@ -161,10 +171,12 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
34C990421C34939C002F49FC /* RCTConvert+CaptureConfig.m in Sources */,
346089D31BEFD0A500C90DB5 /* GLFBO.m in Sources */, 346089D31BEFD0A500C90DB5 /* GLFBO.m in Sources */,
346089DA1BEFD0A500C90DB5 /* RNGLContext.m in Sources */, 346089DA1BEFD0A500C90DB5 /* RNGLContext.m in Sources */,
346089D21BEFD0A500C90DB5 /* GLData.m in Sources */, 346089D21BEFD0A500C90DB5 /* GLData.m in Sources */,
346089D91BEFD0A500C90DB5 /* RCTConvert+GLData.m in Sources */, 346089D91BEFD0A500C90DB5 /* RCTConvert+GLData.m in Sources */,
34C990471C349422002F49FC /* CaptureConfig.m in Sources */,
346089D51BEFD0A500C90DB5 /* GLImageData.m in Sources */, 346089D51BEFD0A500C90DB5 /* GLImageData.m in Sources */,
346089D41BEFD0A500C90DB5 /* GLImage.m in Sources */, 346089D41BEFD0A500C90DB5 /* GLImage.m in Sources */,
346089D61BEFD0A500C90DB5 /* GLRenderData.m in Sources */, 346089D61BEFD0A500C90DB5 /* GLRenderData.m in Sources */,
......
...@@ -45,9 +45,73 @@ RCT_EXPORT_MODULE() ...@@ -45,9 +45,73 @@ RCT_EXPORT_MODULE()
return _context; return _context;
} }
- (void)_addShader:(nonnull NSNumber *)id
withConfig:(NSDictionary *)config
withOnCompile:(RCTResponseSenderBlock)onCompile
{
NSString *frag = [RCTConvert NSString:config[@"frag"]];
NSString *name = [RCTConvert NSString:config[@"name"]];
if (!frag) {
RCTLogError(@"Shader '%@': missing frag field", name);
return;
}
GLShader *shader = [[GLShader alloc] initWithContext:_context withName:name withVert:fullViewportVert withFrag:frag];
NSError *error;
bool success = [shader ensureCompiles:&error];
if (onCompile) {
if (!success) {
onCompile(@[error.domain]);
}
else {
onCompile(@[[NSNull null],
@{
@"uniforms": shader.uniformTypes
}]);
}
}
else {
if (!success) {
RCTLogError(@"Shader '%@': %@", name, error.domain);
}
}
_shaders[id] = shader;
}
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));}"; 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(addShader:(nonnull NSNumber *)id withConfig:(NSDictionary *)config) { NSString* glTypeString (int type) {
switch (type) {
case GL_FLOAT: return @"float";
case GL_FLOAT_VEC2: return @"vec2";
case GL_FLOAT_VEC3: return @"vec3";
case GL_FLOAT_VEC4: return @"vec4";
case GL_INT: return @"int";
case GL_INT_VEC2: return @"ivec2";
case GL_INT_VEC3: return @"ivec3";
case GL_INT_VEC4: return @"ivec4";
case GL_BOOL: return @"bool";
case GL_BOOL_VEC2: return @"bvec2";
case GL_BOOL_VEC3: return @"bvec3";
case GL_BOOL_VEC4: return @"bvec4";
case GL_FLOAT_MAT2: return @"mat2";
case GL_FLOAT_MAT3: return @"mat3";
case GL_FLOAT_MAT4: return @"mat4";
case GL_SAMPLER_2D: return @"sampler2D";
case GL_SAMPLER_CUBE: return @"samplerCube";
}
return @"";
}
NSDictionary* glTypesString (NSDictionary *types) {
NSMutableDictionary *dict = types.mutableCopy;
for (NSString *key in [dict allKeys]) {
dict[key] = glTypeString([dict[key] intValue]);
}
return dict;
}
RCT_EXPORT_METHOD(addShader:(nonnull NSNumber *)id
withConfig:(NSDictionary *)config
withOnCompile:(RCTResponseSenderBlock)onCompile) {
NSString *frag = [RCTConvert NSString:config[@"frag"]]; NSString *frag = [RCTConvert NSString:config[@"frag"]];
NSString *name = [RCTConvert NSString:config[@"name"]]; NSString *name = [RCTConvert NSString:config[@"name"]];
if (!frag) { if (!frag) {
...@@ -55,9 +119,36 @@ RCT_EXPORT_METHOD(addShader:(nonnull NSNumber *)id withConfig:(NSDictionary *)co ...@@ -55,9 +119,36 @@ RCT_EXPORT_METHOD(addShader:(nonnull NSNumber *)id withConfig:(NSDictionary *)co
return; return;
} }
GLShader *shader = [[GLShader alloc] initWithContext:_context withName:name withVert:fullViewportVert withFrag:frag]; GLShader *shader = [[GLShader alloc] initWithContext:_context withName:name withVert:fullViewportVert withFrag:frag];
NSError *error;
bool success = [shader ensureCompiles:&error];
if (onCompile) {
if (!success) {
onCompile(@[error.domain]);
}
else {
onCompile(@[[NSNull null],
@{
@"uniforms": glTypesString(shader.uniformTypes)
}]);
}
}
else {
if (!success) {
RCTLogError(@"Shader '%@': %@", name, error.domain);
}
}
_shaders[id] = shader; _shaders[id] = shader;
} }
RCT_EXPORT_METHOD(removeShader:(nonnull NSNumber *)id) {
GLShader *shader = [_shaders objectForKey:id];
if (!shader) {
RCTLogError(@"removeShader(%@): shader does not exist", id);
return;
}
[_shaders removeObjectForKey:id];
}
@end @end
@implementation RCTBridge (RNGLContext) @implementation RCTBridge (RNGLContext)
......
{ {
"name": "gl-react-native", "name": "gl-react-native",
"version": "2.17.8", "version": "2.18.0-rc",
"description": "OpenGL bindings for react-native to implement complex effects over images and components, in the descriptive VDOM paradigm", "description": "OpenGL bindings for react-native to implement complex effects over images and components, in the descriptive VDOM paradigm",
"repository": { "repository": {
"type": "git", "type": "git",
...@@ -19,15 +19,10 @@ ...@@ -19,15 +19,10 @@
"author": "Project September <tech@projectseptember.com>", "author": "Project September <tech@projectseptember.com>",
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
"react-native": ">= 0.17.0 <0.18.0", "react-native": "0.18.0-rc",
"gl-react": ">= 2.0.3 <2.1.0" "gl-react": "^2.1.0"
}, },
"dependencies": { "dependencies": {
"invariant": "2.2.0" "invariant": "2.2.0"
},
"devDependencies": {
"babel-eslint": "^4.1.6",
"eslint": "^1.9.0",
"eslint-plugin-react": "^3.8.0"
} }
} }
...@@ -12,4 +12,4 @@ See README install instructions. ...@@ -12,4 +12,4 @@ See README install instructions.
React.NativeModules.UIManager.GLCanvas is %s`, GLCanvas); React.NativeModules.UIManager.GLCanvas is %s`, GLCanvas);
const {Commands} = GLCanvas; const {Commands} = GLCanvas;
module.exports = handle => UIManager.dispatchViewManagerCommand(handle, Commands.captureFrame, []); module.exports = (handle, config) => UIManager.dispatchViewManagerCommand(handle, Commands.captureFrame, [ config ]);
...@@ -10,4 +10,4 @@ See README install instructions. ...@@ -10,4 +10,4 @@ See README install instructions.
React.NativeModules.GLCanvasManager is %s`, GLCanvasManager); React.NativeModules.GLCanvasManager is %s`, GLCanvasManager);
module.exports = handle => GLCanvasManager.capture(handle); module.exports = (handle, config) => GLCanvasManager.capture(handle, config);
const invariant = require("invariant");
const React = require("react-native"); const React = require("react-native");
const { const {
Component, Component,
...@@ -6,6 +7,9 @@ const { ...@@ -6,6 +7,9 @@ const {
const captureFrame = require("./GLCanvas.captureFrame"); const captureFrame = require("./GLCanvas.captureFrame");
const serializeOption = config =>
config.format + ":" + config.type + ":" + config.quality;
const GLCanvasNative = requireNativeComponent("GLCanvas", GLCanvas, { const GLCanvasNative = requireNativeComponent("GLCanvas", GLCanvas, {
nativeOnly: { nativeOnly: {
onGLChange: true, onGLChange: true,
...@@ -25,21 +29,85 @@ function defer() { ...@@ -25,21 +29,85 @@ function defer() {
} }
class GLCanvas extends Component { class GLCanvas extends Component {
captureFrame (cb) {
const promise = ( componentWillMount () {
this._pendingCaptureFrame || // use pending capture OR create a new captureFrame pending this._pendingCaptureFrame = {};
(captureFrame(React.findNodeHandle(this.refs.native)), this._pendingCaptureFrame = defer()) }
).promise;
if (typeof cb === "function") { componentWillUnmount () {
console.warn("GLSurface: callback parameter of captureFrame is deprecated, use the returned promise instead"); // eslint-disable-line no-console Object.keys(this._pendingCaptureFrame).forEach(key =>
promise.then(cb); this._pendingCaptureFrame[key].reject(new Error("GLCanvas is unmounting")));
} this._pendingCaptureFrame = null;
return promise; }
}
onGLCaptureFrame = ({ nativeEvent: {frame} }) => { addPendingCaptureFrame (config) {
this._pendingCaptureFrame.resolve(frame); const key = serializeOption(config);
this._pendingCaptureFrame = undefined; return this._pendingCaptureFrame[key] || (
(captureFrame(React.findNodeHandle(this.refs.native), config),
this._pendingCaptureFrame[key] = defer())
);
}
captureFrame (configArg) {
let config;
if (configArg) {
invariant(typeof configArg==="object", "captureFrame takes an object option in parameter");
let nb = 0;
if ("format" in configArg) {
invariant(
typeof configArg.format === "string",
"captureFrame({format}): format must be a string (e.g: 'base64'), Got: '%s'",
configArg.format);
if (configArg.format === "file") invariant(
typeof configArg.filePath === "string" && configArg.filePath,
"captureFrame({filePath}): filePath must be defined when using 'file' format and be an non-empty string, Got: '%s'",
configArg.filePath);
nb ++;
}
if ("type" in configArg) {
invariant(
typeof configArg.type === "string",
"captureFrame({type}): type must be a string (e.g: 'png', 'jpg'), Got: '%s'",
configArg.type);
nb ++;
}
if ("quality" in configArg) {
invariant(
typeof configArg.quality === "number" &&
configArg.quality >= 0 &&
configArg.quality <= 1,
"captureFrame({quality}): quality must be a number between 0 and 1, Got: '%s'",
configArg.quality);
nb ++;
}
if ("filePath" in configArg) {
nb ++;
}
const keys = Object.keys(configArg);
invariant(keys.length === nb, "captureFrame(config): config must be an object with {format, type, quality, filePath}, found some invalid keys in '%s'", keys);
config = configArg;
}
return this.addPendingCaptureFrame({
format: "base64",
type: "png",
quality: 1,
filePath: "",
...config
}).promise;
}
onGLCaptureFrame = ({ nativeEvent: { error, result, config } }) => {
const key = serializeOption(config);
invariant(key in this._pendingCaptureFrame, "capture '%s' is not scheduled in this._pendingCaptureFrame", key);
if (error) {
this._pendingCaptureFrame[key].reject(error);
}
else {
this._pendingCaptureFrame[key].resolve(result);
}
delete this._pendingCaptureFrame[key];
}; };
render () { render () {
const { width, height, onLoad, onProgress, eventsThrough, ...restProps } = this.props; const { width, height, onLoad, onProgress, eventsThrough, ...restProps } = this.props;
return <GLCanvasNative return <GLCanvasNative
......
const {createShaders} = require("gl-react");
const { NativeModules: { RNGLContext } } = require("react-native");
module.exports = createShaders(function (id, shader) {
RNGLContext.addShader(id, shader);
});
...@@ -2,11 +2,13 @@ const invariant = require("invariant"); ...@@ -2,11 +2,13 @@ const invariant = require("invariant");
const {createSurface} = require("gl-react"); const {createSurface} = require("gl-react");
invariant(typeof createSurface === "function", "gl-react createSurface is not a function. Check your gl-react dependency"); invariant(typeof createSurface === "function", "gl-react createSurface is not a function. Check your gl-react dependency");
const React = require("react-native"); const React = require("react-native");
const GLCanvas = require("./GLCanvas");
const { const {
View, View,
PixelRatio
} = React; } = React;
const GLCanvas = require("./GLCanvas");
const getPixelRatio = props => props.scale || PixelRatio.get();
function renderVcontent (width, height, id, children, { visibleContent }) { function renderVcontent (width, height, id, children, { visibleContent }) {
const childrenStyle = { const childrenStyle = {
...@@ -40,4 +42,4 @@ function renderVcontainer ({ style, width, height, visibleContent, eventsThrough ...@@ -40,4 +42,4 @@ function renderVcontainer ({ style, width, height, visibleContent, eventsThrough
</View>; </View>;
} }
module.exports = createSurface(renderVcontainer, renderVcontent, renderVGL); module.exports = createSurface(renderVcontainer, renderVcontent, renderVGL, getPixelRatio);
...@@ -10,8 +10,8 @@ See README install instructions. ...@@ -10,8 +10,8 @@ See README install instructions.
React.NativeModules.RNGLContext is %s`, RNGLContext); React.NativeModules.RNGLContext is %s`, RNGLContext);
// Hook Shaders to RNGLContext // Hook Shaders to RNGLContext
Shaders.list().map(id => RNGLContext.addShader(id, Shaders.get(id))); Shaders.on("add", (id, shader, onCompile) => RNGLContext.addShader(id, shader, onCompile));
Shaders.on("add", (id, shader) => RNGLContext.addShader(id, shader)); Shaders.on("remove", id => RNGLContext.removeShader(id));
module.exports = { module.exports = {
Surface Surface
......
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