createTexture(size, data, texture, nearest) {
    const gl = this.gl_;
    texture = texture || gl.createTexture();
    const filter = nearest ? gl.NEAREST : gl.LINEAR;

    gl.bindTexture(gl.TEXTURE_2D, texture);

    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

    const level = 0;
    const internalFormat = gl.RGBA;
    const border = 0;
    const format = gl.RGBA;
    const type = gl.UNSIGNED_BYTE;

    if (data instanceof Uint8Array) {
      gl.texImage2D(
        gl.TEXTURE_2D,
        level,
        internalFormat,
        size[0],
        size[1],
        border,
        format,
        type,
        data,
      );
    } else if (data) {
      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, format, type, data);
    } else {
      gl.texImage2D(
        gl.TEXTURE_2D,
        level,
        internalFormat,
        size[0],
        size[1],
        border,
        format,
        type,
        null,
      );
    }
    return texture;
  }
Will create or reuse a given webgl texture and apply the given size. If no image data
specified, the texture will be empty, otherwise image data will be used and the `size`
parameter will be ignored.  If a Uint8Array is provided for data, a size must also be provided.
Note: wrap parameters are set to clamp to edge, min filter is set to linear.
@param {Array<number>} size Expected size of the texture
@param {ImageData|HTMLImageElement|HTMLCanvasElement|Uint8Array|null} data Image data/object to bind to the texture
@param {WebGLTexture} [texture] Existing texture to reuse
@param {boolean} [nearest] Use gl.NEAREST for min/mag filter.
@return {WebGLTexture} The generated texture