Commit 80459af3 authored by Gaëtan Renaudeau's avatar Gaëtan Renaudeau

move docs to gl-react repo

parent 1f788771
docs/
imgs/
Examples/
# OSX
......
......@@ -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.View
......@@ -37,16 +37,7 @@ class HelloGL extends React.Component {
}
```
![](docs/examples/1.jpg)
## Focus
- **Virtual DOM and immutable** paradigm: OpenGL is a low level imperative and mutable API. This library takes the best of it and exposes it in an immutable, descriptive way.
- **Performance**
- **Developer experience**: the application doesn't crash on bugs - it uses React Native error message to display GLSL errors, with Live Reload support to make experimenting with effects easy.
- **Uniform bindings**: bindings from JavaScript objects to OpenGL GLSL language types (bool, int, float, vec2, vec3, vec4, mat2, mat3, mat4, sampler2D...)
- **Support for images** as a texture uniform.
- **Support for UIView rasterisation** as a texture uniform.
![](imgs/hellogl.jpg)
## Installation
......@@ -60,7 +51,7 @@ npm i --save gl-react-native
**Configure your React Native Application:**
![](docs/install-steps.png)
![](imgs/install-steps.png)
## Influence / Credits
......@@ -71,4 +62,4 @@ npm i --save gl-react-native
## Documentation
[**Gitbook**](http://projectseptemberinc.gitbooks.io/gl-react-native/content/)
[**Gitbook**](http://projectseptemberinc.gitbooks.io/gl-react/content/)
{
"structure": {
"summary": "docs/README.md"
}
}
# Summary
* [The API](api/README.md)
* [GL.Shaders.create](api/Shaders.create.md)
* [GL.View](api/View.md)
* [GL.Target](api/Target.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)
# The API
```js
var GL = require("gl-react-native");
```
## [GL.Shaders.create](Shaders.create.md)
`GL.Shaders.create(spec)` allows to create shaders that can be used later in GL.View component.
## [GL.View](View.md)
`GL.View` is a React Component that renders a given shader with uniforms (parameters to send to the shader).
## [GL.Target](Target.md)
*(advanced)* `GL.Target` allows to render a shader with any content (any React Native component rasterized as a uniform texture).
# GL.Shaders.create
`GL.Shaders.create(spec)` allows to create shaders that can be used later in *GL.View* component.
**Example usage:**
```js
var shaders = GL.Shaders.create({
myEffect: {
frag: `
void main () {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // red
}
`
},
...
})
// Use it later:
<GL.View shader={shaders.myEffect} ... />
```
`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.
# 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 <GL.View
shader={shaders.myEffect3}
width={200}
height={100}>
<GL.Target uniform="textureName">
...any React Native components
</GL.Target>
</GL.View>;
}
```
## Props
- **`uniform`** *(string)* **(required)**: The name of the shader texture uniform to use for rendering the content.
# 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 <GL.View
shader={shaders.myEffect}
width={200}
height={100} />;
}
```
Renders a shader with uniform parameters:
```js
render () {
return <GL.View
shader={shaders.myEffect2}
width={200}
height={100}
uniforms={{
floatValue: 0.5,
vec3Value: [ 1, 0.5, 0.5 ]
}} />;
/*
// in myEffect2:
uniform float floatValue;
uniform vec3 vec3Value;
*/
}
```
Renders a shader with an image (texture):
```js
render () {
return <GL.View
shader={shaders.myEffect3}
width={200}
height={100}
uniforms={{
textureName: {{ uri: "...url" }} // RN convention
}} />;
/*
// 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`.
# 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
<HelloGL width={256} height={171} />
```
![](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 <GL.View
shader={shaders.helloGL}
width={width}
height={height}
/>;
}
}
```
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 `<GL.View>` and pass-in the shader you have defined previously. **Do not forget to give a width and height**.
# 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
<Saturation
width={256}
height={171}
factor={saturationFactor}
image={{ uri: "http://i.imgur.com/iPKTONG.jpg" }}
/>
```
![](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
shader={shaders.saturation}
width={width}
height={height}
uniforms={{ factor, image }}
/>;
}
}
```
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 `<Image/>`.
# 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
<HueRotate
width={256}
height={180}
hue={hue}>
<Image style={{ width: 256, height: 244 }} source={{ uri: "http://i.imgur.com/qVxHrkY.jpg" }}/>
<Text style={styles.demoText1}>Throw me to the wolves</Text>
<Text style={styles.demoText2}>{text}</Text>
</HueRotate>
```
![](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 <GL.View
shader={shaders.hueRotate}
width={width}
height={height}
uniforms={{ hue }}>
<GL.Target uniform="tex">{children}</GL.Target>
</GL.View>;
}
}
```
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.
# Progress Indicator
This example shows a graphical component implemented in OpenGL that would not be easy to implement with raw RN components.
```html
<PieProgress width={256} height={180} progress={progress} />
```
![](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
<PieProgress
width={256}
height={180}
progress={progress}
colorInside={[0,0,0,0]}
colorOutside={[0,0,0,0.5]}
radius={0.4}
/>
```
## 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 <GL.View
width={width}
height={height}
shader={shaders.pieProgress}
opaque={false}
uniforms={{
dim: [ width, height ],
progress,
colorInside,
colorOutside,
radius
}}
/>;
}
}
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
```
# Touch Responsive
This example shows a simple rendering that responds to touch events (one finger only).
```html
<OneFingerResponse width={256} height={180} />
```
![](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 <GL.View
onStartShouldSetResponderCapture={() => 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.
# 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
<AnimatedHelloGL width={256} height={180} />
```
![](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 <GL.View
shader={shaders.helloGL}
width={width}
height={height}
uniforms={{ value }}
/>;
}
}
```
# 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)
# 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)
{
"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",
......
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