createComponent

GL.createComponent is a function used to create a GL Component.

A "GL Component" a React Component that always either renders a GL.Node or another GL Component.

GL.createComponent(props => glView) takes a render function (takes props object in parameter and returns a GL.Node or GL Component) and returns a GL Component.

const MyEffect = GL.createComponent(
  (props) => <GL.Node .../>
);

GL.createComponent enable effects composition: The fact that a component is a GL component technically tells the gl-react algorithm to "unfold" the render() looking for a GL.Node to merge with. If your component is not a GL Component, it will be treated as a content to rasterized and the effect composition won't work.

staticFields

GL.createComponent(props => glView, staticFields)

To facilitate the usage of GL.createComponent there is also an optional second parameter which is the React Component static fields. We recommend you to always provide displayName for gl-react debug purpose.

module.exports = GL.createComponent(renderGLViewFunction, { displayName: "MyEffect" });

width, height and pixelRatio props

The props function parameter is the union of the inherited {width, height, pixelRatio} with user defined props. That way, width, height and pixelRatio are always available in the props object as an opportunity to pass them in shader as an uniform (for instance you want to apply a effect that depends on the buffer size).

If you define a component MyEffect, an user can either define its value with props (e.g. <MyEffect width={42} height={42} pixelRatio={1}>) or just don't define them, in this second case, they will be inherited from parent component (or Surface).

Composing effects

Effects component can be implemented as follow:

const shaders = GL.Shaders.create({
  myEffect: {
    frag: `
precision highp float;
varying vec2 uv;
uniform sampler2D tex;
uniform float someParam;

void main() {
  vec4 textureColor = texture(tex, uv);
  vec4 c = ... // do something with textureColor and someParam
  gl_FragColor = c;
}
    `
  }
});

const MyEffect = GL.createComponent(
  ({ children, someParam }) =>
  <GL.Node shader={shaders.myEffect} uniforms={{ someParam }}>
    <GL.Uniform name="tex">{children}</GL.Uniform>
  </GL.Node>
);

Once you have defined effect components that inject children (let's say Blur and Negative), you can compose them together.

Example:

<Blur factor={1.2} width={200} height={150}>
  <Negative>
    http://i.imgur.com/qM9BHCy.jpg
  </Negative>
</Blur>

and define another generic component out of it:

const BlurNegative = GL.createComponent(
  ({ width, height, blur, children }) =>
    <Blur factor={blur} width={width} height={height}>
      <Negative>
        {children}
      </Negative>
    </Blur>
);

and use it:

<BlurNegative factor={1.2} width={200} height={150}>
  http://i.imgur.com/qM9BHCy.jpg
</BlurNegative>

More generic implementation

Here is a more recommended way to make your effects components even more generic and reusable (also more concise in code):

const MyEffect = GL.createComponent(
  ({ children: tex, someParam }) =>
    <GL.Node
      shader={shaders.myEffect}
      uniforms={{ someParam, tex }}
    />
);

{ tex } can be anything: an image URL, another stack of effects, a content (like a View, a Text,...). That way you don't have to worry about your component capabilities.

Implementation notes

Effects composition are made efficient using OpenGL Framebuffers: the rendering is made in the same pipeline.

gl-react contains the core logic (shared across both gl-react-dom and gl-react-native) that convert the Virtual DOM Tree into data, an object tree that represent the rendering pipeline.

Respective implementation will then uses that data tree and render it in OpenGL (for gl-react-native) or in WebGL (for gl-react-dom, using stack.gl libs).