diff --git a/.npmignore b/.npmignore
index c39012e9e737a6c38a42deb0c22ca3cafd1f232e..5c5952bf978a6a6b6d130dd274b33623ec85c4f5 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,3 +1,6 @@
+docs/
+Examples/
+
# OSX
#
.DS_Store
diff --git a/Examples/AdvancedEffects/src/TransitionGenerator.js b/Examples/AdvancedEffects/src/TransitionGenerator.js
index ae9e17a118ba91b1e3d4da9751191ae0ba6962c0..587002289c3f97eca563bfc6c0f6e81fff4a72c2 100644
--- a/Examples/AdvancedEffects/src/TransitionGenerator.js
+++ b/Examples/AdvancedEffects/src/TransitionGenerator.js
@@ -4,19 +4,37 @@ GlslTransitions.forEach(function (t) {
byName[t.name] = t;
});
const transitions = [
+ [ "directionalwipe", function () {
+ const angle = Math.random() * 2 * Math.PI;
+ return {
+ direction: [ Math.cos(angle), Math.sin(angle) ]
+ };
+ } ],
[ "cube", function () {
return { persp: 0.9 - Math.random()*Math.random(), unzoom: Math.random()*Math.random() };
} ],
+ [ "randomsquares", function () {
+ const size = Math.round(4 + 20 * Math.random());
+ return {
+ size: [ size, size ],
+ smoothness: Math.random()
+ };
+ } ],
"undulating burn out",
[ "CrossZoom", function () {
return { strength: 0.5 * Math.random() };
} ],
+ "swap",
+ [ "wind", function () {
+ return { size: 0.1+0.2 * Math.random() };
+ } ],
"glitch displace",
[ "Mosaic", function () {
let dx = Math.round(Math.random() * 6 - 3), dy = Math.round(Math.random() * 6 - 3);
if (dx===0 && dy===0) dy = -1;
return { endx: dx, endy: dy };
} ],
+ "Dreamy",
[ "DoomScreenTransition", function () {
return {
barWidth: Math.round(6 + 20 * Math.random()),
@@ -25,21 +43,23 @@ const transitions = [
frequency: Math.random()
};
} ],
- [ "colourDistance", function () {
- return { interpolationPower: 6 * Math.random() };
- } ],
- "swap",
[ "doorway", function () {
return { perspective: Math.random() * Math.random(), depth: 1 + 10 * Math.random() * Math.random() };
} ],
"Star Wipe",
"pinwheel",
- "SimpleFlip",
"TilesScanline",
- "Dreamy",
+ [ "flyeye", function () {
+ return {
+ size: Math.random() * Math.random(),
+ zoom: 200 * Math.random() * Math.random(),
+ colorSeparation: 0.8 * Math.random() * Math.random()
+ };
+ } ],
"Swirl",
"burn",
"Radial",
+ "SimpleFlip",
[ "ripple", function () {
return {
amplitude: 200 * Math.random(),
@@ -47,40 +67,13 @@ const transitions = [
};
} ],
"morph",
- ["ButterflyWaveScrawler", function () {
- return {
- amplitude: Math.random(),
- waves: 50 * Math.random() * Math.random(),
- colorSeparation: 0.8 * Math.random() * Math.random()
- };
- } ],
[ "flash", function () {
return { flashIntensity: 4 * Math.random() };
} ],
- [ "randomsquares", function () {
- const size = Math.round(4 + 20 * Math.random());
- return {
- size: [ size, size ],
- smoothness: Math.random()
- };
- } ],
- [ "flyeye", function () {
- return {
- size: Math.random() * Math.random(),
- zoom: 200 * Math.random() * Math.random(),
- colorSeparation: 0.8 * Math.random() * Math.random()
- };
- } ],
"squeeze",
- [ "directionalwipe", function () {
- const angle = Math.random() * 2 * Math.PI;
- return {
- direction: [ Math.cos(angle), Math.sin(angle) ]
- };
- } ],
"circleopen",
- [ "wind", function () {
- return { size: 0.1+0.2 * Math.random() };
+ [ "colourDistance", function () {
+ return { interpolationPower: 6 * Math.random() };
} ]
].map(function (obj) {
let name, genUniforms;
@@ -104,8 +97,11 @@ const transitions = [
};
});
+let _i = 0;
+
function random () {
- const i = Math.floor(Math.random() * transitions.length);
+ const i = _i;
+ _i = _i+1 >= transitions.length ? 0 : _i+1;
const t = transitions[i];
const uniforms = t.genUniforms && t.genUniforms() || {};
return {
diff --git a/Examples/Simple/HueRotate.js b/Examples/Simple/HueRotate.js
index 268f751616df76267595de71b4901cef34fa5d42..d822a42858985ae38bc3d5d16c41f8af32c70955 100644
--- a/Examples/Simple/HueRotate.js
+++ b/Examples/Simple/HueRotate.js
@@ -31,9 +31,7 @@ class HueRotate extends React.Component {
shader={shaders.hueRotate}
width={width}
height={height}
- uniforms={{
- hue
- }}>
+ uniforms={{ hue }}>
{children}
;
}
diff --git a/Examples/Simple/OneFingerResponse.js b/Examples/Simple/OneFingerResponse.js
index 43bd608bd567d8f22ed9b214b772d07fa4980bbe..3f360311eb32d49ecad9850baaaecc65cfc300ce 100644
--- a/Examples/Simple/OneFingerResponse.js
+++ b/Examples/Simple/OneFingerResponse.js
@@ -2,7 +2,7 @@ const React = require("react-native");
const GL = require("gl-react-native");
const shaders = GL.Shaders.create({
- pieProgress: {
+ oneFingerResponse: {
frag: `
precision mediump float;
varying vec2 uv;
@@ -20,7 +20,7 @@ void main () {
}
});
-class PieProgress extends React.Component {
+class OneFingerResponse extends React.Component {
constructor (props) {
super(props);
this.state = {
@@ -65,10 +65,10 @@ class PieProgress extends React.Component {
onResponderTerminate={this.onTouchEnd}
width={width}
height={height}
- shader={shaders.pieProgress}
+ shader={shaders.oneFingerResponse}
uniforms={{ pressed, position }}
/>;
}
}
-module.exports = PieProgress;
+module.exports = OneFingerResponse;
diff --git a/Examples/Simple/README.md b/Examples/Simple/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..c22e2fb15de946bf41651bda8d1611c4792f2321
--- /dev/null
+++ b/Examples/Simple/README.md
@@ -0,0 +1,18 @@
+
+
+## Run the example
+
+```
+npm install
+```
+
+Then open AdvancedEffects.xcodeproj with XCode and run the application.
+
+## Developing with the example
+
+```
+npm install react-native
+npm install ../.. # everytime the lib code changes
+```
+
+(also make sure a `npm install` has been called on the root directory of gl-react-native).
diff --git a/docs/README.md b/docs/README.md
index 120fda936fca2c2eeb25a46033cdd3eaf61447ba..05ba01c8049209a346adec2f2e947ce5e06a1df3 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -4,10 +4,11 @@
* [GL.Shaders.create](api/Shaders.create.md)
* [GL.View](api/View.md)
* [GL.Target](api/Target.md)
-* Examples
- * [Hello World](examples/1.md)
- * [Effects over Image](examples/2.md)
- * [Effects over anything](examples/3.md)
- * [Animation](examples/4.md)
- * [Touch responsive](examples/5.md)
- * [Upload Indicator](examples/6.md)
+* [Simple Examples](examples/simple.md)
+ * [Hello GL](examples/1.md)
+ * [Saturate an Image](examples/2.md)
+ * [Hue Rotate on Text+Image](examples/3.md)
+ * [Progress Indicator](examples/4.md)
+ * [Touch Responsive](examples/5.md)
+ * [Animation](examples/6.md)
+* [Advanced Effects Examples](examples/advancedeffects.md)
diff --git a/docs/examples/1.jpg b/docs/examples/1.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..2e6329794c9280231f5675204cd95dcfb6823f63
Binary files /dev/null and b/docs/examples/1.jpg differ
diff --git a/docs/examples/1.md b/docs/examples/1.md
index 8b137891791fe96927ad78e64b0aad7bded08bdc..1fdd588d3797836b71e940efc07d132d784b2884 100644
--- a/docs/examples/1.md
+++ b/docs/examples/1.md
@@ -1 +1,46 @@
+# Hello GL
+This minimal example shows the classical "Hello World" of OpenGL 2D drawing, showing a nice 2D gradient where:
+
+- The RED component increases with the X position of the pixel.
+- The GREEN component increases with the Y position of the pixel.
+
+> N.B. a GLSL fragment uses a ["functional rendering"](http://greweb.me/2013/11/functional-rendering/)
+paradigm, which means you have to implement a `Position => Color` function.
+
+
+
+```html
+
+```
+
+## Implementation
+
+```js
+const React = require("react-native");
+const GL = require("gl-react-native");
+
+const shaders = GL.Shaders.create({
+ helloGL: {
+ frag: `
+precision highp float;
+varying vec2 uv; // This variable vary in all pixel position (normalized from vec2(0.0,0.0) to vec2(1.0,1.0))
+
+void main () { // This function is called FOR EACH PIXEL
+ gl_FragColor = vec4(uv.x, uv.y, 0.5, 1.0); // red vary over X, green vary over Y, blue is 50%, alpha is 100%.
+}
+ `
+ }
+});
+
+class HelloGL extends React.Component {
+ render () {
+ const { width, height } = this.props;
+ return ;
+ }
+}
+```
diff --git a/docs/examples/2.gif b/docs/examples/2.gif
new file mode 100644
index 0000000000000000000000000000000000000000..8685b526bddfd0fff3706e629a737a0f6134c3c6
Binary files /dev/null and b/docs/examples/2.gif differ
diff --git a/docs/examples/2.md b/docs/examples/2.md
new file mode 100644
index 0000000000000000000000000000000000000000..8ffdc265a9b663129ffd531e67a00b5b754f5773
--- /dev/null
+++ b/docs/examples/2.md
@@ -0,0 +1,51 @@
+# Saturate an Image
+
+Effects on images like *saturation, contrast, brightness, inverse, hue,...* are very easy to implement in GLSL. Here is the example of **Saturation**.
+
+
+
+```html
+
+```
+
+## Implementation
+
+```js
+const React = require("react-native");
+const GL = require("gl-react-native");
+
+const shaders = GL.Shaders.create({
+ saturation: {
+ frag: `
+precision highp float;
+varying vec2 uv;
+uniform sampler2D image;
+uniform float factor;
+
+void main () {
+ vec4 c = texture2D(image, uv);
+ // Algorithm from Chapter 16 of OpenGL Shading Language
+ const vec3 W = vec3(0.2125, 0.7154, 0.0721);
+ gl_FragColor = vec4(mix(vec3(dot(c.rgb, W)), c.rgb, factor), c.a);
+}
+ `
+ }
+});
+
+class Saturation extends React.Component {
+ render () {
+ const { width, height, factor, image } = this.props;
+ return ;
+ }
+}
+```
diff --git a/docs/examples/3.gif b/docs/examples/3.gif
new file mode 100644
index 0000000000000000000000000000000000000000..ebdf3f60680d4f45fdcc80c345cb365578db1036
Binary files /dev/null and b/docs/examples/3.gif differ
diff --git a/docs/examples/3.md b/docs/examples/3.md
new file mode 100644
index 0000000000000000000000000000000000000000..d2f1716df16fd4cff460fa9369dd4accc1108dd5
--- /dev/null
+++ b/docs/examples/3.md
@@ -0,0 +1,63 @@
+# Hue Rotate on Text+Image
+
+`gl-react-native` not only allow to add effects on top of images but also on top of any content. This example shows the Hue rotation effect on top of texts and image.
+
+
+
+```html
+
+
+ Throw me to the wolves
+ {text}
+
+```
+
+## Implementation
+
+```js
+const React = require("react-native");
+const GL = require("gl-react-native");
+
+const shaders = GL.Shaders.create({
+ hueRotate: {
+ frag: `
+precision highp float;
+varying vec2 uv;
+uniform sampler2D tex;
+uniform float hue;
+
+const mat3 rgb2yiq = mat3(0.299, 0.587, 0.114, 0.595716, -0.274453, -0.321263, 0.211456, -0.522591, 0.311135);
+const mat3 yiq2rgb = mat3(1.0, 0.9563, 0.6210, 1.0, -0.2721, -0.6474, 1.0, -1.1070, 1.7046);
+
+void main() {
+ vec3 yColor = rgb2yiq * texture2D(tex, uv).rgb;
+ float originalHue = atan(yColor.b, yColor.g);
+ float finalHue = originalHue + hue;
+ float chroma = sqrt(yColor.b*yColor.b+yColor.g*yColor.g);
+ vec3 yFinalColor = vec3(yColor.r, chroma * cos(finalHue), chroma * sin(finalHue));
+ gl_FragColor = vec4(yiq2rgb*yFinalColor, 1.0);
+}
+ `
+ }
+});
+
+class HueRotate extends React.Component {
+ render () {
+ const { width, height, hue, children } = this.props;
+ return
+ {children}
+ ;
+ }
+}
+```
+
+The `GL.Target` describes which texture uniform is used for the rasterization of its children content.
+
+Note how powerful it is to compose React Components that way.
diff --git a/docs/examples/4.gif b/docs/examples/4.gif
new file mode 100644
index 0000000000000000000000000000000000000000..76b7da1ed82e1fcf6010569b7578d6cb5fb7311c
Binary files /dev/null and b/docs/examples/4.gif differ
diff --git a/docs/examples/4.md b/docs/examples/4.md
new file mode 100644
index 0000000000000000000000000000000000000000..54c7679c41d992faf5e27c4984ae4497b1991982
--- /dev/null
+++ b/docs/examples/4.md
@@ -0,0 +1,125 @@
+# Progress Indicator
+
+This example show a graphical composant implemented in OpenGL that would not be easy to implement with raw RN components.
+
+> N.B. the pie is transparent and the background is black with 50% opacity. That would easily allow to put this view on top of an image to show an image upload progress.
+
+
+
+```html
+
+```
+
+*explicit props:*
+
+```html
+
+```
+
+## Implementation
+
+```js
+const React = require("react-native");
+const GL = require("gl-react-native");
+
+const shaders = GL.Shaders.create({
+ pieProgress: {
+ frag: `
+precision mediump float;
+varying vec2 uv;
+
+uniform vec4 colorInside, colorOutside;
+uniform float radius;
+uniform float progress;
+uniform vec2 dim;
+
+const vec2 center = vec2(0.5);
+const float PI = acos(-1.0);
+
+void main () {
+ vec2 norm = dim / min(dim.x, dim.y);
+ vec2 p = uv * norm - (norm-1.0)/2.0;
+ vec2 delta = p - center;
+ float inside =
+ step(length(delta), radius) *
+ step((PI + atan(delta.y, -delta.x)) / (2.0 * PI), progress);
+ gl_FragColor = mix(
+ colorOutside,
+ colorInside,
+ inside
+ );
+}
+ `
+ }
+});
+
+class PieProgress extends React.Component {
+ render () {
+ const {
+ width,
+ height,
+ progress,
+ colorInside,
+ colorOutside,
+ radius
+ } = this.props;
+ return ;
+ }
+}
+PieProgress.defaultProps = {
+ colorInside: [0, 0, 0, 0],
+ colorOutside: [0, 0, 0, 0.5],
+ radius: 0.4
+};
+```
+
+Note the usage of complex uniform types.
+
+
+The JavaScript uniform:
+```js
+dim: [ width, height ]
+```
+
+is mapped to GLSL uniform:
+```glsl
+uniform vec2 dim;
+```
+
+where dim.x == width and dim.y == height.
+
+
+Same mapping happens for the colors: `[1, 0.5, 0.2, 1]` mapped to a `vec4` will spread into {r,g,b,a}.
+
+> Complex types in GLSL have "dynamic" properties:
+vecN `v` can simultaneously be used using:
+
+>```
+v[0] v[1] v[2] v[3] // array notation
+v.r v.g v.b v.a // color notation
+v.x v.y v.z v.w // position notation
+v.s v.t v.u v.v // coord notation
+```
diff --git a/docs/examples/5.gif b/docs/examples/5.gif
new file mode 100644
index 0000000000000000000000000000000000000000..39a35708e203f0ad953193319e2a4b55176f165a
Binary files /dev/null and b/docs/examples/5.gif differ
diff --git a/docs/examples/5.md b/docs/examples/5.md
new file mode 100644
index 0000000000000000000000000000000000000000..b687f90ce753c8699811f3194f4d0f611f387022
--- /dev/null
+++ b/docs/examples/5.md
@@ -0,0 +1,91 @@
+# Touch Responsive
+
+This example shows a simple rendering that responds to touch events (one finger only).
+
+
+
+```html
+
+```
+
+## Implementation
+
+```js
+const React = require("react-native");
+const GL = require("gl-react-native");
+
+const shaders = GL.Shaders.create({
+ oneFingerResponse: {
+ frag: `
+precision mediump float;
+varying vec2 uv;
+
+uniform float pressed;
+uniform vec2 position;
+
+void main () {
+ float dist = pow(1.0 - distance(position, uv), 4.0);
+ float edgeDistX = pow(1.0 - distance(position.x, uv.x), 24.0);
+ float edgeDistY = pow(1.0 - distance(position.y, uv.y), 24.0);
+ gl_FragColor = pressed * vec4(0.8 * dist + edgeDistX, 0.7 * dist + edgeDistY, 0.6 * dist, 1.0);
+}
+ `
+ }
+});
+
+class OneFingerResponse extends React.Component {
+ constructor (props) {
+ super(props);
+ this.state = {
+ pressed: 0,
+ position: [ 0, 0 ]
+ };
+ this.onTouchStart = this.onTouchStart.bind(this);
+ this.onTouchEnd = this.onTouchEnd.bind(this);
+ this.onTouchMove = this.onTouchMove.bind(this);
+ }
+ onTouchStart (evt) {
+ this.setState({
+ pressed: 1
+ });
+ this.onTouchMove(evt);
+ }
+ onTouchMove (evt) {
+ const { width, height } = this.props;
+ const { locationX, locationY } = evt.nativeEvent;
+ this.setState({
+ position: [
+ Math.max(0, Math.min(locationX/width, 1)),
+ Math.max(0, Math.min(1-locationY/height, 1))
+ ]
+ });
+ }
+ onTouchEnd () {
+ this.setState({
+ pressed: 0
+ });
+ }
+ render () {
+ const { width, height } = this.props;
+ const { pressed, position } = this.state;
+ return true}
+ onMoveShouldSetResponderCapture={() => true}
+ onResponderTerminationRequest={() => false}
+ onResponderGrant={this.onTouchStart}
+ onResponderMove={this.onTouchMove}
+ onResponderRelease={this.onTouchEnd}
+ onResponderTerminate={this.onTouchEnd}
+ width={width}
+ height={height}
+ shader={shaders.oneFingerResponse}
+ uniforms={{ pressed, position }}
+ />;
+ }
+}
+```
+
+The GLSL code shown here is a bit more advanced, we recommend you to take a look at the [GLSL specification](https://www.opengl.org/documentation/glsl/) to learn what the primitive function are doing.
diff --git a/docs/examples/6.gif b/docs/examples/6.gif
new file mode 100644
index 0000000000000000000000000000000000000000..55e46faf917ed3dfd253a0405f08001f64767d94
Binary files /dev/null and b/docs/examples/6.gif differ
diff --git a/docs/examples/6.md b/docs/examples/6.md
new file mode 100644
index 0000000000000000000000000000000000000000..1dd13020edbfe54b3ab56a6666a2a3fa66e155cc
--- /dev/null
+++ b/docs/examples/6.md
@@ -0,0 +1,59 @@
+# Animation
+
+Any value can be programmatically animated in a render loop. This example extends the simple [Hello GL](1.md) to add a `value` uniform that is passed in blue color component. `value` is animated over time.
+
+
+
+```html
+
+```
+
+## Implementation
+
+```js
+const React = require("react-native");
+const GL = require("gl-react-native");
+
+const shaders = GL.Shaders.create({
+ helloGL: {
+ frag: `
+precision highp float;
+varying vec2 uv;
+
+uniform float value;
+
+void main () {
+ gl_FragColor = vec4(uv.x, uv.y, value, 1.0);
+}
+ `
+ }
+});
+
+class HelloGL extends React.Component {
+ constructor (props) {
+ super(props);
+ this.state = {
+ value: 0
+ };
+ }
+ componentDidMount () {
+ const loop = time => {
+ requestAnimationFrame(loop);
+ this.setState({
+ value: (1 + Math.cos(time / 1000)) / 2 // cycle between 0 and 1
+ });
+ };
+ requestAnimationFrame(loop);
+ }
+ render () {
+ const { width, height } = this.props;
+ const { value } = this.state;
+ return ;
+ }
+}
+```
diff --git a/docs/examples/advancedeffects.gif b/docs/examples/advancedeffects.gif
new file mode 100644
index 0000000000000000000000000000000000000000..ce9d74c7d8be1ac0b045fe5db4d0aad882fdc187
Binary files /dev/null and b/docs/examples/advancedeffects.gif differ
diff --git a/docs/examples/advancedeffects.md b/docs/examples/advancedeffects.md
new file mode 100644
index 0000000000000000000000000000000000000000..2992eac90e0aaf2d9cbf20ec24a37acf87c79b62
--- /dev/null
+++ b/docs/examples/advancedeffects.md
@@ -0,0 +1,9 @@
+# AdvancedEffects examples
+
+*AdvancedEffects* is a React Native application that shows more advanced `gl-react-native` samples.
+
+It performs non trivial animated effects that still runs at 60 FPS on a iPhone.
+
+It is available in [`Examples/AdvancedEffects`](https://github.com/ProjectSeptemberInc/gl-react-native/tree/master/Examples/AdvancedEffects) folder.
+
+
diff --git a/docs/examples/simple.gif b/docs/examples/simple.gif
new file mode 100644
index 0000000000000000000000000000000000000000..cbb9c67eb6ee8af9e06d832286d36aea0c544ab1
Binary files /dev/null and b/docs/examples/simple.gif differ
diff --git a/docs/examples/simple.md b/docs/examples/simple.md
new file mode 100644
index 0000000000000000000000000000000000000000..3829d2e1b6e11fa299bd2f3e472fc83d8da5df38
--- /dev/null
+++ b/docs/examples/simple.md
@@ -0,0 +1,7 @@
+# Simple examples
+
+*Simple* is a React Native application that shows minimal `gl-react-native` samples.
+
+It is available in [`Examples/Simple`](https://github.com/ProjectSeptemberInc/gl-react-native/tree/master/Examples/Simple) folder.
+
+