diff --git a/.npmignore b/.npmignore index 5c5952bf978a6a6b6d130dd274b33623ec85c4f5..facea32a536d480581dddeadcf893c6b62ebf01d 100644 --- a/.npmignore +++ b/.npmignore @@ -1,4 +1,4 @@ -docs/ +imgs/ Examples/ # OSX diff --git a/README.md b/README.md index 7eaea4ac39c75527dc647e75017ddaed450eb771..a862c853c311498fe24a28e912ee5b592b88421c 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ OpenGL bindings for react-native to implement complex effects over images and co More technically, `gl-react-native` allows you to write a [fragment shader](https://www.opengl.org/wiki/Fragment_Shader) that covers a View. The shader can render: generated graphics/demos, effects on top of images, effects over any UI content... anything you can imagine! -**There's also a React version [`gl-react`](http://github.com/ProjectSeptemberInc/gl-react) with the same API.** +**`gl-react-native` is directly inspired from [`gl-react`](http://github.com/ProjectSeptemberInc/gl-react) and implement the same API (so you can write "universal" code).** -[![](docs/examples/simple.gif)](./Examples/Simple)[![](docs/examples/advancedeffects.gif)](./Examples/AdvancedEffects) +[![](imgs/simple.gif)](./Examples/Simple)[![](imgs/advancedeffects.gif)](./Examples/AdvancedEffects) ### HelloGL Gist @@ -25,7 +25,7 @@ void main () { } }); -class HelloGL extends React.Component { +class HelloGL extends GL.Component { render () { const { width, height } = this.props; return -``` - -`GL.Shaders.create` is inspired from ReactNative's `StyleSheet.create`: it creates an object with key-value and will returns an object with the same keys and where the values can be used in the Virtual DOM. - -The value of each Shader is an object with a `frag` field: the fragment GLSL code. - -## About Shaders - -There are two kinds of OpenGL Shaders: vertex and fragment shaders. -The vertex shader iterates over polygons and computes pixel positions, the fragment shaders iterates over pixels and computes a color. - -In current version of `gl-react-native`, the vertex shader is implemented for you -and you only have to implement the fragment shader. - -> This documentation assumes you know the basics of GLSL, the OpenGL Shading Language, if not, feel free to learn [shader-school](https://www.npmjs.com/package/shader-school), read the [specification](https://www.opengl.org/documentation/glsl/) or learn from the examples. - - diff --git a/docs/api/Target.md b/docs/api/Target.md deleted file mode 100644 index 5edde47124cb2529a84eb2dd84baca3503fbe683..0000000000000000000000000000000000000000 --- a/docs/api/Target.md +++ /dev/null @@ -1,26 +0,0 @@ -# GL.Target - -`GL.Target` allows to render a shader with any content (any React Native component rasterized as a uniform texture). - -> **N.B.** This feature is advanced and experimental. It current does not yet support subviews content refreshing (like Image load event,...). - -**Example:** - -```js -render () { - return - - - ...any React Native components - - - ; -} -``` - -## Props - -- **`uniform`** *(string)* **(required)**: The name of the shader texture uniform to use for rendering the content. diff --git a/docs/api/View.md b/docs/api/View.md deleted file mode 100644 index 99959191f5a71dcb435cd30db37967314869638d..0000000000000000000000000000000000000000 --- a/docs/api/View.md +++ /dev/null @@ -1,77 +0,0 @@ -# GL.View - -`GL.View` is a React Component that renders a given shader with uniforms (parameters to send to the shader). - -**Quick Examples:** - -Renders a "standalone" shader: - -```js -render () { - return ; -} -``` - -Renders a shader with uniform parameters: - -```js -render () { - return ; - /* - // in myEffect2: - uniform float floatValue; - uniform vec3 vec3Value; - */ -} -``` - -Renders a shader with an image (texture): - -```js -render () { - return ; - /* - // in myEffect3: - uniform sampler2D textureName; - */ -} -``` - - -## Props - -- **`shader`** *(id created by GL.Shaders.create)* **(required)**: The shader to use for rendering the `GL.View`. -- **`width`** and **`height`** *(Number)* **(required)**: the size of the view. -- **`uniforms`** *(object)*: an object that contains all uniform parameters to send to the shader. The key is the uniform name and the value is whatever value that makes sense for the uniform's type (see below). -- **`opaque`** *(bool)*: specify if the view should be opaque. By default, it is true, meaning that the GL View won't support texture opacity and alpha channel. -- **...any other props** get directly passed to the underlying view. - -## Uniform types - -Here is the correspondance of GLSL and JavaScript types. - -- `int`, `float`, `bool` : Number (e.g: `42`). -- `sampler2D` : either the image URL (String) OR an Object with an `uri` (`require("image!id")` is also supported), exactly like the `source` prop of `React.Image`. -- `vecN`,`ivecN`,`bvecN` where N is {2,3,4} : an array of N Number (e.g: `[1, 2, 3.5]` for a `vec3`) - -Complex struct types and uniform array **are not** currently supported. - -## Note on textures - -Images given to uniforms props are always loaded as they are. If you want resize/crop features, you can use an `React.Image` inside a `GL.Target`. diff --git a/docs/examples/1.md b/docs/examples/1.md deleted file mode 100644 index ae46957322d0e68b52482249d2aa939ec99007b6..0000000000000000000000000000000000000000 --- a/docs/examples/1.md +++ /dev/null @@ -1,52 +0,0 @@ -# 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 - -``` - -![](1.jpg) - -## 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 ; - } -} -``` - -A GL component is implemented in 2 parts: - -- first, you need to implement a fragment shader in GLSL (OpenGL Shading Language). -Give it to `GL.Shaders.create` and you have a backed object in return (like `StyleSheet.create`). -- second, you can render a `` and pass-in the shader you have defined previously. **Do not forget to give a width and height**. diff --git a/docs/examples/2.gif b/docs/examples/2.gif deleted file mode 100644 index 8685b526bddfd0fff3706e629a737a0f6134c3c6..0000000000000000000000000000000000000000 Binary files a/docs/examples/2.gif and /dev/null differ diff --git a/docs/examples/2.md b/docs/examples/2.md deleted file mode 100644 index ee90f622d788d6f35801015cca069198c5fba063..0000000000000000000000000000000000000000 --- a/docs/examples/2.md +++ /dev/null @@ -1,57 +0,0 @@ -# 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 - -``` - -![](2.gif) - - -## 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 ; - } -} -``` - -GL.View supports `uniforms` props that allow to send to the shader any parameters from the JavaScript world. - -In this example, we send the `factor` number (that come from props) and we also send the image. -The image have the same format as the `source` passed in an ``. diff --git a/docs/examples/3.gif b/docs/examples/3.gif deleted file mode 100644 index ebdf3f60680d4f45fdcc80c345cb365578db1036..0000000000000000000000000000000000000000 Binary files a/docs/examples/3.gif and /dev/null differ diff --git a/docs/examples/3.md b/docs/examples/3.md deleted file mode 100644 index 5d5cfbbcdeaa5a014e5fc71938494578aafb96f0..0000000000000000000000000000000000000000 --- a/docs/examples/3.md +++ /dev/null @@ -1,63 +0,0 @@ -# Hue Rotate on Text+Image - -`gl-react-native` not only allows 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} - -``` - -![](3.gif) - -## 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 deleted file mode 100644 index 76b7da1ed82e1fcf6010569b7578d6cb5fb7311c..0000000000000000000000000000000000000000 Binary files a/docs/examples/4.gif and /dev/null differ diff --git a/docs/examples/4.md b/docs/examples/4.md deleted file mode 100644 index 690cbd671f11754aed7306cd303dc190f22dd1d5..0000000000000000000000000000000000000000 --- a/docs/examples/4.md +++ /dev/null @@ -1,121 +0,0 @@ -# Progress Indicator - -This example shows a graphical component implemented in OpenGL that would not be easy to implement with raw RN components. - -```html - -``` - -![](4.gif) - -> N.B. the pie is transparent and the background is black with 50% opacity (the colors are passed by props). That would easily allow to put this view on top of an image to show an image upload progress. - -*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 deleted file mode 100644 index 39a35708e203f0ad953193319e2a4b55176f165a..0000000000000000000000000000000000000000 Binary files a/docs/examples/5.gif and /dev/null differ diff --git a/docs/examples/5.md b/docs/examples/5.md deleted file mode 100644 index 004c7cd2204acf86eee7e1ef9f2fd5117cbdbdcf..0000000000000000000000000000000000000000 --- a/docs/examples/5.md +++ /dev/null @@ -1,88 +0,0 @@ -# Touch Responsive - -This example shows a simple rendering that responds to touch events (one finger only). - -```html - -``` - -![](5.gif) - -## 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 deleted file mode 100644 index 55e46faf917ed3dfd253a0405f08001f64767d94..0000000000000000000000000000000000000000 Binary files a/docs/examples/6.gif and /dev/null differ diff --git a/docs/examples/6.md b/docs/examples/6.md deleted file mode 100644 index 688ccd73ef4fd71c3ce8961b7069003c3beff3b1..0000000000000000000000000000000000000000 --- a/docs/examples/6.md +++ /dev/null @@ -1,59 +0,0 @@ -# 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 - -``` - -![](6.gif) - -## 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.md b/docs/examples/advancedeffects.md deleted file mode 100644 index 2992eac90e0aaf2d9cbf20ec24a37acf87c79b62..0000000000000000000000000000000000000000 --- a/docs/examples/advancedeffects.md +++ /dev/null @@ -1,9 +0,0 @@ -# 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. - -![](advancedeffects.gif) diff --git a/docs/examples/simple.md b/docs/examples/simple.md deleted file mode 100644 index 3829d2e1b6e11fa299bd2f3e472fc83d8da5df38..0000000000000000000000000000000000000000 --- a/docs/examples/simple.md +++ /dev/null @@ -1,7 +0,0 @@ -# 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. - -![](simple.gif) diff --git a/docs/examples/advancedeffects.gif b/imgs/advancedeffects.gif similarity index 100% rename from docs/examples/advancedeffects.gif rename to imgs/advancedeffects.gif diff --git a/docs/examples/1.jpg b/imgs/hellogl.jpg similarity index 100% rename from docs/examples/1.jpg rename to imgs/hellogl.jpg diff --git a/docs/install-steps.png b/imgs/install-steps.png similarity index 100% rename from docs/install-steps.png rename to imgs/install-steps.png diff --git a/docs/examples/simple.gif b/imgs/simple.gif similarity index 100% rename from docs/examples/simple.gif rename to imgs/simple.gif diff --git a/package.json b/package.json index 78671fc55d584209bcd773eb63ef596ad3a42e8f..8b1802836b01c9ab0239dfad0b07b0faaaedb50a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "gl-react-native", "version": "0.0.1", - "description": "OpenGL bindings for react-native to implement complex effects over images and components, in VDOM descriptive paradigm", + "description": "OpenGL bindings for react-native to implement complex effects over images and components, in the descriptive VDOM paradigm", "main": "src/index.js", "repository": { "type": "git",