index.js 2.76 KB
Newer Older
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
const invariant = require("invariant");
const React = require("react-native");
const {
  NativeModules: { GLShadersRegistry },
  requireNativeComponent,
  Component,
  PropTypes,
  View,
} = React;

let _uid = 1;

const Shaders = {
  create: function (obj) {
    invariant(typeof obj === "object", "config must be an object");
    const result = {};
    for (let key in obj) {
      // TODO : validate first
      const id = _uid ++;
      GLShadersRegistry.register(id, obj[key]);
      result[key] = id;
    }
    return result;
  },
  exists: function (id) {
    return typeof id === "number" && id >= 1 && id < _uid;
  }
};

class Target extends Component {
  render () {
    invariant(
      false,
      "GL.Target elements are for GL.View configuration only and should not be rendered"
    );
  }
}
Target.displayName = "GL.Target";
Target.propTypes = {
  children: PropTypes.any.isRequired,
  uniform: PropTypes.string.isRequired
};

const GLViewNative = requireNativeComponent("GLView", GLView);
class GLView extends Component {
  setNativeProps (props) {
    this.refs.native.setNativeProps(props);
  }

  render() {
    const props = this.props;
    const { style, width, height, children, shader } = props;

    invariant(Shaders.exists(shader), "Shader #%s does not exists", shader);

    const nativeStyle = {
      width: width,
      height: height,
      ...style
    };

    if (children) {
      const parentStyle = {
        position: "relative",
        width: nativeStyle.width,
        height: nativeStyle.height,
        overflow: "hidden"
      };
      const childrenStyle = {
        position: "absolute",
        top: 0,
        left: 0,
        width: nativeStyle.width,
        height: nativeStyle.height
      };

      const targetUniforms = [];
      const targets = React.Children.map(children, child => {
        invariant(child.type === Target, "GL.View can only contains children of type GL.Target. Got '%s'", child.type && child.type.displayName || child);
        const uniform = child.props.uniform;
        targetUniforms.push(uniform);
        return <View style={[ childrenStyle, child.props.style ]}>{child.props.children}</View>;
      });
      return <View style={parentStyle}>
        {targets}
        <GLViewNative ref="native" {...props} style={nativeStyle} children={undefined} targetUniforms={targetUniforms} />
      </View>;
    }
    else {
      return <GLViewNative ref="native" {...props} style={nativeStyle} />;
    }
  }
}
GLView.displayName = "GL.View";
GLView.propTypes = {
  shader: PropTypes.number.isRequired,
  width: PropTypes.number,
  height: PropTypes.number,
  uniforms: PropTypes.object,
  childrenUniform: PropTypes.string,
  opaque: PropTypes.bool
};
GLView.defaultProps = {
  opaque: true
};

module.exports = {
  View: GLView,
  Target,
  Shaders
};