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 {
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
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')
}
......@@ -3,12 +3,14 @@
"version": "0.0.1",
"private": true,
"scripts": {
"start": "react-native start"
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"gl-react": "^2.0.2",
"fbjs": "^0.6.0",
"gl-react": "^2.1.0",
"gl-react-native": "file:../..",
"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 {
StyleSheet,
......
......@@ -74,6 +74,6 @@ android {
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
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")
}
......@@ -3,13 +3,15 @@
"version": "0.0.1",
"private": true,
"scripts": {
"start": "react-native start"
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"crypto": "0.0.3",
"gl-react": "^2.0.6",
"fbjs": "^0.6.0",
"gl-react": "^2.1.0",
"gl-react-native": "file:../..",
"react-native": "^0.17.0",
"react": "^0.14.5",
"react-native": "0.18.0-rc",
"seedrandom": "gre/seedrandom#released"
}
}
import GL from "gl-react";
const {React} = GL;
import React from "react";
const {PropTypes} = React;
const shaders = GL.Shaders.create({
......
require("gl-react/react-native");
const React = require("react-native");
const {
StyleSheet,
......
......@@ -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/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.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/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
......@@ -96,14 +96,14 @@
<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="jsr305-3.0.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="react-native-0.18.0" 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" />
......@@ -112,6 +112,7 @@
<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" />
<orderEntry type="module" module-name="react-native-fs" exported="" />
<orderEntry type="module" module-name="RNMaterialKit" exported="" />
<orderEntry type="module" module-name="RNGL" exported="" />
</component>
......
......@@ -74,8 +74,10 @@ android {
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
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(":RNGL")
compile project(':react-native-fs')
}
......@@ -11,6 +11,7 @@ import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;
import com.github.xinthink.rnmk.ReactMaterialKitPackage;
import com.projectseptember.RNGL.RNGLPackage;
import com.rnfs.RNFSPackage;
public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler {
......@@ -28,6 +29,7 @@ public class MainActivity extends Activity implements DefaultHardwareBackBtnHand
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
.addPackage(new RNGLPackage())
.addPackage(new RNFSPackage())
.addPackage(new ReactMaterialKitPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
......
......@@ -7,3 +7,6 @@ project(':RNMaterialKit').projectDir = file('../node_modules/react-native-materi
include ':RNGL'
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 @@
146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
34607B601C132B22009203B1 /* libRCTMaterialKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 34607B581C132B1C009203B1 /* libRCTMaterialKit.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 */; };
/* End PBXBuildFile section */
......@@ -104,6 +105,13 @@
remoteGlobalIDString = 4107012F1ACB723B00C6AA39;
remoteInfo = RNGL;
};
34C990571C3530CE002F49FC /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 34C990481C3530CE002F49FC /* RNFS.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = F12AFB9B1ADAF8F800E0535D;
remoteInfo = RNFS;
};
78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
......@@ -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>"; };
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>"; };
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>"; };
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 */
......@@ -158,6 +167,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
34C9905A1C3530D6002F49FC /* libRNFS.a in Frameworks */,
34607B601C132B22009203B1 /* libRCTMaterialKit.a in Frameworks */,
3461EB4B1C132AEC0003E4A2 /* libRNGL.a in Frameworks */,
146834051AC3E58100842450 /* libReact.a in Frameworks */,
......@@ -287,6 +297,14 @@
name = Products;
sourceTree = "<group>";
};
34C990491C3530CE002F49FC /* Products */ = {
isa = PBXGroup;
children = (
34C990581C3530CE002F49FC /* libRNFS.a */,
);
name = Products;
sourceTree = "<group>";
};
78C398B11ACF4ADC00677621 /* Products */ = {
isa = PBXGroup;
children = (
......@@ -298,6 +316,7 @@
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup;
children = (
34C990481C3530CE002F49FC /* RNFS.xcodeproj */,
34607B4F1C132B1C009203B1 /* RCTMaterialKit.xcodeproj */,
3461EB3B1C132AD30003E4A2 /* RNGL.xcodeproj */,
146833FF1AC3E56700842450 /* React.xcodeproj */,
......@@ -453,6 +472,10 @@
ProductGroup = 146834001AC3E56700842450 /* Products */;
ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
},
{
ProductGroup = 34C990491C3530CE002F49FC /* Products */;
ProjectRef = 34C990481C3530CE002F49FC /* RNFS.xcodeproj */;
},
{
ProductGroup = 3461EB3C1C132AD30003E4A2 /* Products */;
ProjectRef = 3461EB3B1C132AD30003E4A2 /* RNGL.xcodeproj */;
......@@ -537,6 +560,13 @@
remoteRef = 3461EB491C132AD30003E4A2 /* PBXContainerItemProxy */;
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 */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
......
......@@ -3,12 +3,15 @@
"version": "0.0.1",
"private": true,
"scripts": {
"start": "react-native start"
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"fbjs": "^0.6.0",
"gl-react": "^2.1.0",
"gl-react-native": "file:../..",
"gl-react": "^2.0.8",
"react-native": "^0.17.0",
"react-native-material-kit": "^0.2.4"
"react": "^0.14.5",
"react-native": "0.18.0-rc",
"react-native-fs": "^1.1.0",
"react-native-material-kit": "gre/react-native-material-kit#no-peerDependencies"
}
}
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const Blur1D = require("./Blur1D");
module.exports = GL.createComponent(({ width, height, factor, children }) =>
......
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const shaders = GL.Shaders.create({
blur1D: {
......
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const shaders = GL.Shaders.create({
helloGL: {
......
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const shaders = GL.Shaders.create({
hueRotate: {
......
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const shaders = GL.Shaders.create({
pieProgress: {
......
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const shaders = GL.Shaders.create({
saturation: {
......
require("gl-react/react-native");
const React = require("react-native");
const {
StyleSheet,
......@@ -22,6 +20,8 @@ const {
MKButton,
} = require("react-native-material-kit");
const RNFS = require("react-native-fs");
const HelloGL = require("./HelloGL");
const Saturation = require("./Saturation");
const HueRotate = require("./HueRotate");
......@@ -82,7 +82,8 @@ class Simple extends Component {
switch1: false,
switch2: false,
switch3: false,
captured: null
captured: null,
captureConfig: null
};
this.onCapture1 = this.onCapture1.bind(this);
......@@ -97,9 +98,17 @@ class Simple extends Component {
}
onCapture1 () {
this.refs.helloGL.captureFrame().then(data64 => {
this.setState({ captured: data64 });
});
const captureConfig = {
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 () {
......@@ -113,7 +122,8 @@ class Simple extends Component {
switch1,
switch2,
switch3,
captured
captured,
captureConfig
} = this.state;
return <View style={styles.container}>
......@@ -128,9 +138,28 @@ class Simple extends Component {
</Surface>
<View style={{ paddingTop: 20, alignItems: "center", flexDirection: "row" }}>
<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>
{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 id={2} title="2. Saturate an Image">
......
......@@ -74,7 +74,7 @@ android {
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:0.17.+"
compile "com.facebook.react:react-native:0.18.+"
compile project(":RNGL")
}
......@@ -3,11 +3,13 @@
"version": "0.0.1",
"private": true,
"scripts": {
"start": "react-native start"
"start": "node node_modules/react-native/local-cli/cli.js start"
},
"dependencies": {
"fbjs": "^0.6.0",
"gl-react": "^2.1.0",
"gl-react-native": "file:../..",
"gl-react": "^2.0.2",
"react-native": "^0.17.0"
"react": "^0.14.5",
"react-native": "0.18.0-rc"
}
}
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const shaders = GL.Shaders.create({
add: {
......
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const {
PropTypes
} = React;
......
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const {
PropTypes
} = React;
......
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const shaders = GL.Shaders.create({
Copy: {
......
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const shaders = GL.Shaders.create({
display2: {
......
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const shaders = GL.Shaders.create({
helloGL: {
......
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const shaders = GL.Shaders.create({
layer: {
......
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const shaders = GL.Shaders.create({
multiply: {
......
const GL = require("gl-react");
const React = GL.React;
const React = require("react");
const shaders = GL.Shaders.create({
TransparentNonPremultiplied: {
......
require("gl-react/react-native");
const React = require("react-native");
const {
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)
# <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.
......
......@@ -30,5 +30,5 @@ repositories {
}
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;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
......@@ -69,7 +70,11 @@ public class GLCanvas extends GLSurfaceView
private Map<Integer, GLFBO> fbos;
private ExecutorSupplier executorSupplier;
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) {
super(context);
......@@ -78,6 +83,10 @@ public class GLCanvas extends GLSurfaceView
rnglContext = context.getNativeModule(RNGLContext.class);
setEGLContextClientVersion(2);
DisplayMetrics dm = reactContext.getResources().getDisplayMetrics();
displayDensity = dm.density;
pixelRatio = dm.density;
setEGLConfigChooser(8, 8, 8, 8, 16, 0);
getHolder().setFormat(PixelFormat.RGB_888);
setZOrderOnTop(true);
......@@ -104,7 +113,7 @@ public class GLCanvas extends GLSurfaceView
if (!shaders.containsKey(id)) {
GLShaderData shaderData = rnglContext.getShader(id);
if (shaderData == null) return null;
shaders.put(id, new GLShader(shaderData));
shaders.put(id, new GLShader(shaderData, id, rnglContext));
}
return shaders.get(id);
}
......@@ -123,6 +132,12 @@ public class GLCanvas extends GLSurfaceView
@Override
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
public void onDrawFrame(GL10 gl) {
runAll(mRunOnDraw);
......@@ -156,16 +171,74 @@ public class GLCanvas extends GLSurfaceView
if (shouldRenderNow) {
this.render();
deferredRendering = false;
if (captureFrameRequested) {
captureFrameRequested = false;
if (captureConfigs.size() > 0) {
capture(); // FIXME: maybe we should schedule this?
}
}
}
private void capture () {
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();
capture.compress(Bitmap.CompressFormat.PNG, 100, baos);
capture.compress(compressFormat, quality, baos);
String frame = "data:image/png;base64,"+
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() {
......@@ -242,9 +315,14 @@ public class GLCanvas extends GLSurfaceView
execute(new Runnable() {
public void run() {
// FIXME: maybe should set a flag so we don't do it twice??
try {
if (!syncData())
requestSyncData();
}
catch (GLShaderCompilationFailed e) {
// This is ignored. It will be handled by RNGLContext.shaderFailedToCompile
}
}
});
}
......@@ -525,8 +603,8 @@ public class GLCanvas extends GLSurfaceView
uniformsIntBuffer,
uniformsFloatBuffer,
textures,
data.width,
data.height,
(int)(data.width * data.pixelRatio),
(int)(data.height * data.pixelRatio),
data.fboId,
contextChildren,
children);
......@@ -598,11 +676,8 @@ public class GLCanvas extends GLSurfaceView
}
private void recRender (GLRenderData renderData) {
DisplayMetrics dm = reactContext.getResources().getDisplayMetrics();
int w = Float.valueOf(renderData.width.floatValue() * dm.density).intValue();
int h = Float.valueOf(renderData.height.floatValue() * dm.density).intValue();
int w = renderData.width;
int h = renderData.height;
for (GLRenderData child: renderData.contextChildren)
recRender(child);
......@@ -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) {
WritableMap event = Arguments.createMap();
event.putDouble("progress", Double.isNaN(progress) ? 0.0 : progress);
......@@ -698,9 +763,14 @@ public class GLCanvas extends GLSurfaceView
event);
}
public void requestCaptureFrame() {
captureFrameRequested = true;
public void requestCaptureFrame (CaptureConfig config) {
this.requestRender();
for (CaptureConfig existing : captureConfigs) {
if (existing.equals(config)) {
return;
}
}
captureConfigs.add(config);
}
private Bitmap createSnapshot () {
......@@ -751,4 +821,16 @@ public class GLCanvas extends GLSurfaceView
d.removeAll(b);
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> {
private ExecutorSupplier executorSupplier;
@ReactProp(name="pixelRatio")
public void setPixelRatio (GLCanvas view, float pixelRatio) {
view.setPixelRatio(pixelRatio);
}
@ReactProp(name="nbContentTextures")
public void setNbContentTextures (GLCanvas view, int nbContentTextures) {
view.setNbContentTextures(nbContentTextures);
......@@ -89,7 +94,7 @@ public class GLCanvasManager extends SimpleViewManager<GLCanvas> {
Assertions.assertNotNull(args);
switch (commandType) {
case COMMAND_CAPTURE_FRAME: {
canvas.requestCaptureFrame();
canvas.requestCaptureFrame(CaptureConfig.fromMap(args.getMap(0)));
return;
}
default:
......
......@@ -10,17 +10,19 @@ public class GLData {
final Integer shader;
final ReadableMap uniforms;
final Integer width;
final Integer height;
final Double width;
final Double height;
final Double pixelRatio;
final Integer fboId;
final List<GLData> contextChildren;
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.uniforms = uniforms;
this.width = width;
this.height = height;
this.pixelRatio = pixelRatio;
this.fboId = fboId;
this.contextChildren = contextChildren;
this.children = children;
......@@ -37,11 +39,12 @@ public class GLData {
public static GLData fromMap (ReadableMap map) {
Integer shader = map.getInt("shader");
ReadableMap uniforms = map.getMap("uniforms");
Integer width = (int) map.getDouble("width");
Integer height = (int) map.getDouble("height");
Double width = map.getDouble("width");
Double height = map.getDouble("height");
Double pixelRatio = map.getDouble("pixelRatio");
Integer fboId = map.getInt("fboId");
List<GLData> children = fromArray(map.getArray("children"));
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 {
private int pointerLoc; // The "pointer" attribute is used to iterate over vertex
private Map<String, Integer> uniformLocations; // The uniform locations cache
public GLShader(String name, String vert, String frag) {
this.name = name;
this.vert = vert;
this.frag = frag;
}
private Integer id;
private RNGLContext rnglContext;
private GLShaderCompilationFailed compilationFailed;
public GLShader(GLShaderData data) {
public GLShader(GLShaderData data, Integer id, RNGLContext rnglContext) {
this.name = data.name;
this.vert = data.vert;
this.frag = data.frag;
this.id = id;
this.rnglContext = rnglContext;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
if (buffer != null) {
// TODO: need to check if this works properly
glDeleteProgram(program);
glDeleteBuffers(1, buffer, 0);
}
}
public void runtimeException (String msg) {
throw new RuntimeException("Shader '"+name+"': "+msg);
throw new GLShaderCompilationFailed(name, msg);
}
public void bind () {
......@@ -64,7 +65,7 @@ public class GLShader {
glGetProgramiv(program, GL_VALIDATE_STATUS, validSuccess, 0);
if (validSuccess[0] == GL_FALSE) {
glGetProgramInfoLog(program);
runtimeException("Validation failed " + glGetProgramInfoLog(program));
runtimeException(glGetProgramInfoLog(program));
}
}
......@@ -133,7 +134,7 @@ public class GLShader {
int compileSuccess[] = new int[1];
glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, compileSuccess, 0);
if (compileSuccess[0] == GL_FALSE) {
runtimeException("failed to compile: " + glGetShaderInfoLog(shaderHandle));
runtimeException(glGetShaderInfoLog(shaderHandle));
return -1;
}
return shaderHandle;
......@@ -157,7 +158,7 @@ public class GLShader {
this.uniformLocations = locations;
}
private void makeProgram () {
private void makeProgram () throws GLShaderCompilationFailed {
int vertex = compileShader(vert, GL_VERTEX_SHADER);
if (vertex == -1) return;
......@@ -172,7 +173,7 @@ public class GLShader {
int[] linkSuccess = new int[1];
glGetProgramiv(program, GL_LINK_STATUS, linkSuccess, 0);
if (linkSuccess[0] == GL_FALSE) {
runtimeException("Linking failed "+glGetProgramInfoLog(program));
runtimeException(glGetProgramInfoLog(program));
}
glUseProgram(program);
......@@ -208,7 +209,18 @@ public class GLShader {
}
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();
}
}
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;
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.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import java.util.HashMap;
import java.util.Map;
......@@ -20,6 +26,7 @@ public class RNGLContext extends ReactContextBaseJavaModule {
private Map<Integer, GLShaderData> shaders = new HashMap<>();
private Map<Integer, GLFBO> fbos = new HashMap<>();
private Map<Integer, Callback> onCompileCallbacks = new HashMap<>();
public RNGLContext (ReactApplicationContext reactContext) {
super(reactContext);
......@@ -35,9 +42,67 @@ public class RNGLContext extends ReactContextBaseJavaModule {
}
@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 name = config.getString("name");
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 "GLData.h"
#import "CaptureConfig.h"
#import "RCTComponent.h"
@interface GLCanvas: GLKView
......@@ -11,6 +12,7 @@
@property (nonatomic) BOOL visibleContent;
@property (nonatomic) NSNumber *nbContentTextures;
@property (nonatomic) NSNumber *renderId;
@property (nonatomic) NSNumber *pixelRatio;
@property (nonatomic) NSArray *imagesToPreload;
@property (nonatomic, copy) RCTBubblingEventBlock onGLProgress;
@property (nonatomic, copy) RCTBubblingEventBlock onGLLoad;
......@@ -18,6 +20,6 @@
- (instancetype)initWithBridge:(RCTBridge *)bridge;
- (void) requestCaptureFrame;
- (void) requestCaptureFrame:(CaptureConfig *)config;
@end
......@@ -44,8 +44,6 @@ NSArray* diff (NSArray* a, NSArray* b) {
GLRenderData *_renderData;
BOOL _captureFrameRequested;
NSArray *_contentData;
NSArray *_contentTextures;
NSDictionary *_images; // This caches the currently used images (imageSrc -> GLReactImage)
......@@ -63,6 +61,9 @@ NSArray* diff (NSArray* a, NSArray* b) {
NSTimer *animationTimer;
BOOL _needSync;
NSMutableArray *_captureConfigs;
BOOL _captureScheduled;
}
- (instancetype)initWithBridge:(RCTBridge *)bridge
......@@ -71,23 +72,44 @@ NSArray* diff (NSArray* a, NSArray* b) {
_bridge = bridge;
_images = @{};
_preloaded = [[NSMutableArray alloc] init];
_captureFrameRequested = false;
_captureConfigs = [[NSMutableArray alloc] init];
_captureScheduled = false;
_dirtyOnLoad = true;
_neverRendered = true;
self.context = [bridge.rnglContext getContext];
self.contentScaleFactor = RCTScreenScale();
}
return self;
}
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
- (void) requestCaptureFrame
- (void) requestCaptureFrame: (CaptureConfig *)config
{
_captureFrameRequested = true;
[self setNeedsDisplay];
for (CaptureConfig *existing in _captureConfigs) {
if ([existing isEqualToCaptureConfig:config]) {
return;
}
}
[_captureConfigs addObject:config];
}
-(void)setImagesToPreload:(NSArray *)imagesToPreload
......@@ -141,6 +163,12 @@ RCT_NOT_IMPLEMENTED(-init)
}
}
- (void)setPixelRatio:(NSNumber *)pixelRatio
{
self.contentScaleFactor = [pixelRatio floatValue];
[self setNeedsDisplay];
}
- (void)setData:(GLData *)data
{
_data = data;
......@@ -161,7 +189,7 @@ RCT_NOT_IMPLEMENTED(-init)
[self setNeedsDisplay];
}
- (void)syncData
- (bool)syncData:(NSError **)error
{
@autoreleasepool {
......@@ -173,6 +201,7 @@ RCT_NOT_IMPLEMENTED(-init)
weak_traverseTree = traverseTree = ^GLRenderData *(GLData *data) {
NSNumber *width = data.width;
NSNumber *height = data.height;
NSNumber *pixelRatio = data.pixelRatio;
int fboId = [data.fboId intValue];
NSMutableArray *contextChildren = [[NSMutableArray alloc] init];
......@@ -191,6 +220,7 @@ RCT_NOT_IMPLEMENTED(-init)
GLShader *shader = [_bridge.rnglContext getShader:data.shader];
if (shader == nil) return nil;
if (![shader ensureCompiles:error]) return nil;
NSDictionary *uniformTypes = [shader uniformTypes];
NSMutableDictionary *uniforms = [[NSMutableDictionary alloc] init];
......@@ -270,8 +300,8 @@ RCT_NOT_IMPLEMENTED(-init)
initWithShader:shader
withUniforms:uniforms
withTextures:textures
withWidth:width
withHeight:height
withWidth:(int)([width floatValue] * [pixelRatio floatValue])
withHeight:(int)([height floatValue] * [pixelRatio floatValue])
withFboId:fboId
withContextChildren:contextChildren
withChildren:children];
......@@ -279,16 +309,15 @@ RCT_NOT_IMPLEMENTED(-init)
GLRenderData *res = traverseTree(_data);
if (res != nil) {
_needSync = false;
_renderData = traverseTree(_data);
_images = images;
for (NSString *src in diff([prevImages allKeys], [images allKeys])) {
[_preloaded removeObject:src];
}
return true;
}
else {
// the data is not ready, retry in one tick
[self setNeedsDisplay];
return false;
}
}
}
......@@ -305,7 +334,7 @@ RCT_NOT_IMPLEMENTED(-init)
UIView *v = [view.subviews count] == 1 ?
view.subviews[0] :
view;
imgData = [GLImageData genPixelsWithView:v];
imgData = [GLImageData genPixelsWithView:v withPixelRatio:self.contentScaleFactor];
} else {
imgData = nil;
}
......@@ -360,7 +389,16 @@ RCT_NOT_IMPLEMENTED(-init)
}
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]) {
......@@ -375,21 +413,63 @@ RCT_NOT_IMPLEMENTED(-init)
else {
_deferredRendering = false;
[self render];
if (_captureFrameRequested) {
_captureFrameRequested = false;
if (!_captureScheduled && [_captureConfigs count] > 0) {
_captureScheduled = true;
[self performSelectorOnMainThread:@selector(capture) withObject:nil waitUntilDone:NO];
}
}
}
-(void)capture
-(void) capture
{
_captureScheduled = false;
if (!self.onGLCaptureFrame) return;
UIImage *frameImage = [self snapshot];
NSData *frameData = UIImagePNGRepresentation(frameImage);
NSString *frame =
[NSString stringWithFormat:@"data:image/png;base64,%@",
[frameData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]];
if (self.onGLCaptureFrame) self.onGLCaptureFrame(@{ @"frame": frame });
for (CaptureConfig *config in _captureConfigs) {
id result;
id error;
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
......@@ -399,13 +479,12 @@ RCT_NOT_IMPLEMENTED(-init)
RCT_PROFILE_BEGIN_EVENT(0, @"GLCanvas render", nil);
@autoreleasepool {
CGFloat scale = RCTScreenScale();
void (^recDraw) (GLRenderData *renderData);
__block __weak void (^weak_recDraw) (GLRenderData *renderData);
weak_recDraw = recDraw = ^void(GLRenderData *renderData) {
float w = [renderData.width floatValue] * scale;
float h = [renderData.height floatValue] * scale;
int w = renderData.width;
int h = renderData.height;
for (GLRenderData *child in renderData.contextChildren)
weak_recDraw(child);
......
#import "GLCanvasManager.h"
#import "GLCanvas.h"
#import "RCTConvert+GLData.h"
#import "RCTConvert+CaptureConfig.h"
#import "RCTUIManager.h"
#import "RCTLog.h"
#import <UIKit/UIKit.h>
......@@ -17,17 +18,23 @@ RCT_EXPORT_MODULE();
return self;
}
- (dispatch_queue_t)methodQueue
{
return self.bridge.uiManager.methodQueue;
}
RCT_EXPORT_VIEW_PROPERTY(nbContentTextures, NSNumber);
RCT_EXPORT_VIEW_PROPERTY(opaque, BOOL);
RCT_EXPORT_VIEW_PROPERTY(autoRedraw, BOOL);
RCT_EXPORT_VIEW_PROPERTY(data, GLData);
RCT_EXPORT_VIEW_PROPERTY(renderId, NSNumber);
RCT_EXPORT_VIEW_PROPERTY(pixelRatio, NSNumber);
RCT_EXPORT_VIEW_PROPERTY(imagesToPreload, NSArray);
RCT_EXPORT_VIEW_PROPERTY(onGLLoad, RCTBubblingEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onGLProgress, RCTBubblingEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onGLCaptureFrame, RCTBubblingEventBlock);
RCT_EXPORT_METHOD(capture: (nonnull NSNumber *)reactTag)
RCT_EXPORT_METHOD(capture: (nonnull NSNumber *)reactTag withConfig:(id)config)
{
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
UIView *view = viewRegistry[reactTag];
......@@ -36,7 +43,7 @@ RCT_EXPORT_METHOD(capture: (nonnull NSNumber *)reactTag)
}
else {
GLCanvas *glCanvas = (GLCanvas *)view;
[glCanvas requestCaptureFrame];
[glCanvas requestCaptureFrame:[RCTConvert CaptureConfig:config]];
}
}];
}
......
......@@ -8,6 +8,7 @@
@property (nonatomic) NSDictionary *uniforms;
@property (nonatomic) NSNumber *width;
@property (nonatomic) NSNumber *height;
@property (nonatomic) NSNumber *pixelRatio;
@property (nonatomic) NSNumber *fboId;
@property (nonatomic) NSArray *contextChildren;
@property (nonatomic) NSArray *children;
......@@ -16,6 +17,7 @@
withUniforms: (NSDictionary *)uniforms
withWidth: (NSNumber *)width
withHeight: (NSNumber *)height
withPixelRatio: (NSNumber *)pixelRatio
withFboId: (NSNumber *)fboId
withContextChildren: (NSArray *)contextChildren
withChildren: (NSArray *)children;
......
......@@ -6,6 +6,7 @@
withUniforms: (NSDictionary *)uniforms
withWidth: (NSNumber *)width
withHeight: (NSNumber *)height
withPixelRatio: (NSNumber *)pixelRatio
withFboId: (NSNumber *)fboId
withContextChildren: (NSArray *)contextChildren
withChildren: (NSArray *)children
......@@ -15,6 +16,7 @@
self.uniforms = uniforms;
self.width = width;
self.height = height;
self.pixelRatio = pixelRatio;
self.fboId = fboId;
self.contextChildren = contextChildren;
self.children = children;
......
......@@ -8,7 +8,7 @@
+ (GLImageData*) empty;
+ (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;
......
#import "GLImageData.h"
#import "RCTUtils.h"
#import "RCTLog.h"
// This structure aims to be used in an immutable way
......@@ -55,16 +54,16 @@ GLImageData *EMPTY_PIXELS;
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 height = RCTScreenScale() * view.bounds.size.height;
float width = pixelRatio * view.bounds.size.width;
float height = pixelRatio * view.bounds.size.height;
GLubyte *data = (GLubyte *)malloc(4 * width * height);
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(data, width, height, 8, 4 * width, colourSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colourSpace);
CGContextClearRect(ctx, CGRectMake(0.0, 0.0, width, height));
CGContextScaleCTM(ctx, RCTScreenScale(), RCTScreenScale());
CGContextScaleCTM(ctx, pixelRatio, pixelRatio);
[view.layer renderInContext:ctx];
CGContextRelease(ctx);
return [[GLImageData alloc] initWithData:data withWidth:width withHeight:height];
......
......@@ -7,8 +7,8 @@
@property (nonatomic) GLShader *shader;
@property (nonatomic) NSDictionary *uniforms;
@property (nonatomic) NSDictionary *textures;
@property (nonatomic) NSNumber *width;
@property (nonatomic) NSNumber *height;
@property (nonatomic) int width;
@property (nonatomic) int height;
@property (nonatomic) int fboId;
@property (nonatomic) NSArray *contextChildren;
@property (nonatomic) NSArray *children;
......@@ -16,8 +16,8 @@
-(instancetype) initWithShader: (GLShader *)shader
withUniforms:(NSDictionary *)uniforms
withTextures: (NSDictionary *)textures
withWidth: (NSNumber *)width
withHeight: (NSNumber *)height
withWidth: (int)width
withHeight: (int)height
withFboId: (int)fboId
withContextChildren: (NSArray *)contextChildren
withChildren: (NSArray *)children;
......
......@@ -6,8 +6,8 @@
-(instancetype) initWithShader: (GLShader *)shader
withUniforms:(NSDictionary *)uniforms
withTextures: (NSDictionary *)textures
withWidth: (NSNumber *)width
withHeight: (NSNumber *)height
withWidth: (int)width
withHeight: (int)height
withFboId: (int)fboId
withContextChildren: (NSArray *)contextChildren
withChildren: (NSArray *)children
......
#import <GLKit/GLKit.h>
#import "RCTBridgeModule.h"
NS_ENUM(NSInteger) {
GLContextFailure = 87001,
GLLinkingFailure = 87002,
GLCompileFailure = 87003,
GLNotAProgram = 87004
};
@interface GLShader: NSObject
@property EAGLContext *context;
......@@ -18,10 +25,7 @@
*/
- (void) bind;
/**
* Check the shader validity
*/
- (void) validate;
- (bool) ensureCompiles: (NSError**)error;
/**
* Set the value of an uniform
......
......@@ -5,7 +5,7 @@
#import "RCTConvert.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);
......@@ -20,8 +20,10 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
RCTLogError(@"Shader '%@' failed to compile: %@", shaderName, messageString);
*error = [[NSError alloc]
initWithDomain:[NSString stringWithUTF8String:messages]
code:GLCompileFailure
userInfo:nil];
return -1;
}
......@@ -41,6 +43,7 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
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 *_uniformLocations; // The uniform locations cache
NSError *_error;
}
- (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
_context = context;
_vert = vert;
_frag = frag;
[self makeProgram];
NSError *error;
if (![self makeProgram:&error]) {
_error = error;
}
}
return self;
}
......@@ -60,12 +66,21 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
{
glDeleteProgram(program);
glDeleteBuffers(1, &buffer);
_name = nil;
_context = nil;
_vert = nil;
_frag = nil;
_uniformLocations = nil;
_uniformTypes = nil;
program = 0;
buffer = 0;
pointerLoc = 0;
}
- (bool) ensureContext
- (bool) ensureContext: (NSError **)error
{
if (![EAGLContext setCurrentContext:_context]) {
RCTLogError(@"Shader '%@': Failed to set current OpenGL context", _name);
if (!_context || ![EAGLContext setCurrentContext:_context]) {
*error = [[NSError alloc] initWithDomain:@"Failed to set current OpenGL context" code:GLContextFailure userInfo:nil];
return false;
}
return true;
......@@ -73,11 +88,6 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
- (void) bind
{
if (![self ensureContext]) return;
if ( glIsProgram(program) != GL_TRUE ){
RCTLogError(@"Shader '%@': not a program!", _name);
return;
}
glUseProgram(program);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glEnableVertexAttribArray(pointerLoc);
......@@ -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
{
NSMutableDictionary *uniforms = @{}.mutableCopy;
......@@ -342,15 +339,29 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
_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);
if (vertex == -1) return;
GLuint vertex = compileShader(_name, _vert, GL_VERTEX_SHADER, error);
if (vertex == -1) return false;
GLuint fragment = compileShader(_name, _frag, GL_FRAGMENT_SHADER);
if (fragment == -1) return;
GLuint fragment = compileShader(_name, _frag, GL_FRAGMENT_SHADER, error);
if (fragment == -1) return false;
program = glCreateProgram();
glAttachShader(program, vertex);
......@@ -362,9 +373,11 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
if (linkSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
RCTLogError(@"Shader '%@': Linking failed %@", _name, messageString);
return;
*error = [[NSError alloc]
initWithDomain:[NSString stringWithUTF8String:messages]
code:GLLinkingFailure
userInfo:nil];
return false;
}
glUseProgram(program);
......@@ -384,6 +397,8 @@ GLuint compileShader (NSString* shaderName, NSString* shaderString, GLenum shade
1.0, 1.0
};
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 @@
NSDictionary *uniforms = [self NSDictionary:json[@"uniforms"]];
NSNumber *width = [self NSNumber:json[@"width"]];
NSNumber *height = [self NSNumber:json[@"height"]];
NSNumber *pixelRatio = [self NSNumber:json[@"pixelRatio"]];
NSNumber *fboId = [self NSNumber:json[@"fboId"]];
NSArray *contextChildrenJSON = [self NSArray: json[@"contextChildren"]];
NSArray *childrenJSON = [self NSArray: json[@"children"]];
......@@ -30,6 +31,7 @@
withUniforms: uniforms
withWidth: width
withHeight: height
withPixelRatio: pixelRatio
withFboId: fboId
withContextChildren: contextChildren
withChildren: children];
......
......@@ -18,6 +18,8 @@
346089D81BEFD0A500C90DB5 /* GLTexture.m in Sources */ = {isa = PBXBuildFile; fileRef = 346089CB1BEFD0A500C90DB5 /* GLTexture.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 */; };
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 */
/* Begin PBXCopyFilesBuildPhase section */
......@@ -48,13 +50,17 @@
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>"; };
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>"; };
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>"; };
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>"; };
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; };
/* End PBXFileReference section */
......@@ -92,6 +98,10 @@
346089CB1BEFD0A500C90DB5 /* GLTexture.m */,
346089CC1BEFD0A500C90DB5 /* RCTConvert+GLData.h */,
346089CD1BEFD0A500C90DB5 /* RCTConvert+GLData.m */,
34C990461C349422002F49FC /* CaptureConfig.m */,
34C990451C34941C002F49FC /* CaptureConfig.h */,
34C990401C34939C002F49FC /* RCTConvert+CaptureConfig.h */,
34C990411C34939C002F49FC /* RCTConvert+CaptureConfig.m */,
346089CE1BEFD0A500C90DB5 /* RNGLContext.h */,
346089CF1BEFD0A500C90DB5 /* RNGLContext.m */,
410701301ACB723B00C6AA39 /* Products */,
......@@ -161,10 +171,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
34C990421C34939C002F49FC /* RCTConvert+CaptureConfig.m in Sources */,
346089D31BEFD0A500C90DB5 /* GLFBO.m in Sources */,
346089DA1BEFD0A500C90DB5 /* RNGLContext.m in Sources */,
346089D21BEFD0A500C90DB5 /* GLData.m in Sources */,
346089D91BEFD0A500C90DB5 /* RCTConvert+GLData.m in Sources */,
34C990471C349422002F49FC /* CaptureConfig.m in Sources */,
346089D51BEFD0A500C90DB5 /* GLImageData.m in Sources */,
346089D41BEFD0A500C90DB5 /* GLImage.m in Sources */,
346089D61BEFD0A500C90DB5 /* GLRenderData.m in Sources */,
......
......@@ -45,9 +45,73 @@ RCT_EXPORT_MODULE()
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));}";
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 *name = [RCTConvert NSString:config[@"name"]];
if (!frag) {
......@@ -55,9 +119,36 @@ RCT_EXPORT_METHOD(addShader:(nonnull NSNumber *)id withConfig:(NSDictionary *)co
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": glTypesString(shader.uniformTypes)
}]);
}
}
else {
if (!success) {
RCTLogError(@"Shader '%@': %@", name, error.domain);
}
}
_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
@implementation RCTBridge (RNGLContext)
......
{
"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",
"repository": {
"type": "git",
......@@ -19,15 +19,10 @@
"author": "Project September <tech@projectseptember.com>",
"license": "MIT",
"peerDependencies": {
"react-native": ">= 0.17.0 <0.18.0",
"gl-react": ">= 2.0.3 <2.1.0"
"react-native": "0.18.0-rc",
"gl-react": "^2.1.0"
},
"dependencies": {
"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.
React.NativeModules.UIManager.GLCanvas is %s`, 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.
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 {
Component,
......@@ -6,6 +7,9 @@ const {
const captureFrame = require("./GLCanvas.captureFrame");
const serializeOption = config =>
config.format + ":" + config.type + ":" + config.quality;
const GLCanvasNative = requireNativeComponent("GLCanvas", GLCanvas, {
nativeOnly: {
onGLChange: true,
......@@ -25,21 +29,85 @@ function defer() {
}
class GLCanvas extends Component {
captureFrame (cb) {
const promise = (
this._pendingCaptureFrame || // use pending capture OR create a new captureFrame pending
(captureFrame(React.findNodeHandle(this.refs.native)), this._pendingCaptureFrame = defer())
).promise;
if (typeof cb === "function") {
console.warn("GLSurface: callback parameter of captureFrame is deprecated, use the returned promise instead"); // eslint-disable-line no-console
promise.then(cb);
}
return promise;
}
onGLCaptureFrame = ({ nativeEvent: {frame} }) => {
this._pendingCaptureFrame.resolve(frame);
this._pendingCaptureFrame = undefined;
componentWillMount () {
this._pendingCaptureFrame = {};
}
componentWillUnmount () {
Object.keys(this._pendingCaptureFrame).forEach(key =>
this._pendingCaptureFrame[key].reject(new Error("GLCanvas is unmounting")));
this._pendingCaptureFrame = null;
}
addPendingCaptureFrame (config) {
const key = serializeOption(config);
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 () {
const { width, height, onLoad, onProgress, eventsThrough, ...restProps } = this.props;
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");
const {createSurface} = require("gl-react");
invariant(typeof createSurface === "function", "gl-react createSurface is not a function. Check your gl-react dependency");
const React = require("react-native");
const GLCanvas = require("./GLCanvas");
const {
View,
PixelRatio
} = React;
const GLCanvas = require("./GLCanvas");
const getPixelRatio = props => props.scale || PixelRatio.get();
function renderVcontent (width, height, id, children, { visibleContent }) {
const childrenStyle = {
......@@ -40,4 +42,4 @@ function renderVcontainer ({ style, width, height, visibleContent, eventsThrough
</View>;
}
module.exports = createSurface(renderVcontainer, renderVcontent, renderVGL);
module.exports = createSurface(renderVcontainer, renderVcontent, renderVGL, getPixelRatio);
......@@ -10,8 +10,8 @@ See README install instructions.
React.NativeModules.RNGLContext is %s`, RNGLContext);
// Hook Shaders to RNGLContext
Shaders.list().map(id => RNGLContext.addShader(id, Shaders.get(id)));
Shaders.on("add", (id, shader) => RNGLContext.addShader(id, shader));
Shaders.on("add", (id, shader, onCompile) => RNGLContext.addShader(id, shader, onCompile));
Shaders.on("remove", id => RNGLContext.removeShader(id));
module.exports = {
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