/* Do not edit, autogenerated by flexx.pyscript */

var _pyfunc_add = function (a, b) { // nargs: 2
    if (Array.isArray(a) && Array.isArray(b)) {
        return a.concat(b);
    } return a + b;
};
var _pyfunc_all = function (x) { // nargs: 1
    for (var i=0; i<x.length; i++) {
        if (!_pyfunc_truthy(x[i])){return false;}
    } return true;
};
var _pyfunc_contains = function contains (a, b) { // nargs: 2
    if (b == null) {
    } else if (Array.isArray(b)) {
        for (var i=0; i<b.length; i++) {if (_pyfunc_equals(a, b[i]))
                                           return true;}
        return false;
    } else if (b.constructor === Object) {
        for (var k in b) {if (a == k) return true;}
        return false;
    } else if (b.constructor == String) {
        return b.indexOf(a) >= 0;
    } var e = Error('Not a container: ' + b); e.name='TypeError'; throw e;
};
var _pyfunc_equals = function equals (a, b) { // nargs: 2
    if (a == null || b == null) {
    } else if (Array.isArray(a) && Array.isArray(b)) {
        var i = 0, iseq = a.length == b.length;
        while (iseq && i < a.length) {iseq = equals(a[i], b[i]); i+=1;}
        return iseq;
    } else if (a.constructor === Object && b.constructor === Object) {
        var akeys = Object.keys(a), bkeys = Object.keys(b);
        akeys.sort(); bkeys.sort();
        var i=0, k, iseq = equals(akeys, bkeys);
        while (iseq && i < akeys.length) {k=akeys[i]; iseq = equals(a[k], b[k]); i+=1;}
        return iseq;
    } return a == b;
};
var _pyfunc_instantiate = function (ob, args) { // nargs: 2
    if ((typeof ob === "undefined") ||
            (typeof window !== "undefined" && window === ob) ||
            (typeof global !== "undefined" && global === ob))
            {throw "Class constructor is called as a function.";}
    for (var name in ob) {
        if (Object[name] === undefined &&
            typeof ob[name] === 'function' && !ob[name].nobind) {
            ob[name] = ob[name].bind(ob);
        }
    }
    if (ob.__init__) {
        ob.__init__.apply(ob, args);
    }
};
var _pyfunc_mult = function (a, b) { // nargs: 2
    if ((typeof a === 'number') + (typeof b === 'number') === 1) {
        if (a.constructor === String) return _pymeth_repeat.call(a, b);
        if (b.constructor === String) return _pymeth_repeat.call(b, a);
        if (Array.isArray(b)) {var t=a; a=b; b=t;}
        if (Array.isArray(a)) {
            var res = []; for (var i=0; i<b; i++) res = res.concat(a);
            return res;
        }
    } return a * b;
};
var _pyfunc_range = function (start, end, step) {
var i, res = [];
    var val = start;
    var n = (end - start) / step;
    for (i=0; i<n; i++) {
        res.push(val);
        val += step;
    }
    return res;
};
var _pyfunc_truthy = function (v) {
    if (v === null || typeof v !== "object") {return v;}
    else if (v.length !== undefined) {return v.length ? v : false;}
    else if (v.byteLength !== undefined) {return v.byteLength ? v : false;}
    else if (v.constructor !== Object) {return true;}
    else {return Object.getOwnPropertyNames(v).length ? v : false;}
};
var _pymeth_append = function (x) { // nargs: 1
    if (!Array.isArray(this)) return this.append.apply(this, arguments);
    this.push(x);
};
var _pymeth_get = function (key, d) { // nargs: 1 2
    if (this.constructor !== Object) return this.get.apply(this, arguments);
    if (this[key] !== undefined) {return this[key];}
    else if (d !== undefined) {return d;}
    else {return null;}
};
var _pymeth_keys = function () { // nargs: 0
    if (typeof this['keys'] === 'function') return this.keys.apply(this, arguments);
    return Object.keys(this);
};
var _pymeth_lstrip = function (chars) { // nargs: 0 1
    if (this.constructor !== String) return this.lstrip.apply(this, arguments);
    chars = (chars === undefined) ? ' \t\r\n' : chars;
    for (var i=0; i<this.length; i++) {
        if (chars.indexOf(this[i]) < 0) return this.slice(i);
    } return '';
};
var _pymeth_remove = function (x) { // nargs: 1
    if (!Array.isArray(this)) return this.remove.apply(this, arguments);
    for (var i=0; i<this.length; i++) {
        if (_pyfunc_equals(this[i], x)) {this.splice(i, 1); return;}
    }
    var e = Error(x); e.name='ValueError'; throw e;
};
var _pymeth_repeat = function(count) { // nargs: 0
    if (this.repeat) return this.repeat(count);
    if (count < 1) return '';
    var result = '', pattern = this.valueOf();
    while (count > 1) {
        if (count & 1) result += pattern;
        count >>= 1, pattern += pattern;
    }
    return result + pattern;
};
var _pymeth_startswith = function (x) { // nargs: 1
    if (this.constructor !== String) return this.startswith.apply(this, arguments);
    return this.indexOf(x) == 0;
};
var Buffer, GlooObject, IndexBuffer, Program, Texture2D, Texture3DLike, VertexBuffer, __version__, check_error, console;
// PyScript module for gloo2.js - lightweight object oriented GL.

{ /* if this_is_js() */
console = window.console;
}
__version__ = "0.3";
check_error = function (gl, when) {
    var e, err, err_3, errors, msg, stub1_seq, stub2_itr;
    when = (when === undefined) ? "periodic check": when;
    // Check this from time to time to detect GL errors.
    //
    //     Parameters
    //     ----------
    //     when : str
    //         Shown in the exception to help the developer determine when
    //         this check was done.
    errors = [];
    while (true) {
        err = gl.getError();
        if ((_pyfunc_equals(err, gl.NO_ERROR) || (_pyfunc_truthy(errors) && _pyfunc_equals(err, errors[errors.length -1])))) {
            break;
        }
        _pymeth_append.call(errors, err);
    }
    if (errors.length) {
        msg = "";
        stub1_seq = errors;
        if ((typeof stub1_seq === "object") && (!Array.isArray(stub1_seq))) {
            stub1_seq = Object.keys(stub1_seq);
        }
        for (stub2_itr = 0; stub2_itr < stub1_seq.length; stub2_itr += 1) {
            e = stub1_seq[stub2_itr];
            msg=_pyfunc_add(msg, e)
        }
        err_3 = new Error('RuntimeError:' + ("OpenGL got errors (" + when + "): " + msg + "")); err_3.name = "RuntimeError"; throw err_3;
    }
    return null;
};

GlooObject = function () {
    // Abstract base class for all Gloo classes.
    _pyfunc_instantiate(this, arguments);
}
GlooObject.prototype._base_class = Object;
GlooObject.prototype._class_name = "GlooObject";

GlooObject.prototype.__init__ = function (gl) {
    // Init by passing the webgl context object.
    this._gl = gl;
    this.handle = null;
    this._create();
    if (!(this.handle !== null)) {throw "AssertionError: " + "this.handle !== null";}
    return null;
};

GlooObject.prototype._create = function () {
    var err_2;
    err_2 = new Error('NotImplementedError:' + ""); err_2.name = "NotImplementedError"; throw err_2;
    return null;
};


Program = function () {
    // The program is the central component to connect gloo objects and shaders.
    _pyfunc_instantiate(this, arguments);
}
Program.prototype = Object.create(GlooObject.prototype);
Program.prototype._base_class = GlooObject.prototype;
Program.prototype._class_name = "Program";

Program.prototype.UTYPEMAP = {"float": "uniform1fv", "vec2": "uniform2fv", "vec3": "uniform3fv", "vec4": "uniform4fv", "int": "uniform1iv", "ivec2": "uniform2iv", "ivec3": "uniform3iv", "ivec4": "uniform4iv", "bool": "uniform1iv", "bvec2": "uniform2iv", "bvec3": "uniform3iv", "bvec4": "uniform4iv", "mat2": "uniformMatrix2fv", "mat3": "uniformMatrix3fv", "mat4": "uniformMatrix4fv", "sampler1D": "uniform1i", "sampler2D": "uniform1i", "sampler3D": "uniform1i"};
Program.prototype.ATYPEMAP = {"float": "vertexAttrib1f", "vec2": "vertexAttrib2f", "vec3": "vertexAttrib3f", "vec4": "vertexAttrib4f"};
Program.prototype.ATYPEINFO = {"float": [1, 5126], "vec2": [2, 5126], "vec3": [3, 5126], "vec4": [4, 5126]};
Program.prototype._create = function () {
    this.handle = this._gl.createProgram();
    this.locations = {};
    this._unset_variables = [];
    this._validated = false;
    this._samplers = {};
    this._attributes = {};
    this._known_invalid = [];
    return null;
};

Program.prototype.delete = function () {
    // Delete the program.
    this._gl.deleteProgram(this.handle);
    return null;
};

Program.prototype.activate = function () {
    // Activate the program.
    this._gl.useProgram(this.handle);
    return null;
};

Program.prototype.deactivate = function () {
    // Disable the program.
    this._gl.useProgram(0);
    return null;
};

Program.prototype.set_shaders = function (vert, frag) {
    var code, err_3, err_4, errors, frag_handle, gl, handle, i, status, stub3_, tmp, type_, vert_handle;
    // Set GLSL code for the vertex and fragment shader.
    //
    // This function takes care of setting the shading code and
    // compiling+linking it into a working program object that is ready
    // to use.
    //
    // Parameters
    // ----------
    // vert : str
    //     GLSL code for the vertex shader.
    // frag : str
    //     GLSL code for the fragment shader.
    gl = this._gl;
    this._linked = false;
    vert_handle = gl.createShader(gl.VERTEX_SHADER);
    frag_handle = gl.createShader(gl.FRAGMENT_SHADER);
    tmp = [[vert, vert_handle, "vertex"], [frag, frag_handle, "fragment"]];
    for (i = 0; i < 2; i += 1) {
        stub3_ = tmp[i];
        code = stub3_[0];handle = stub3_[1];type_ = stub3_[2];
        gl.shaderSource(handle, code);
        gl.compileShader(handle);
        status = gl.getShaderParameter(handle, gl.COMPILE_STATUS);
        if ((!_pyfunc_truthy(status))) {
            errors = gl.getShaderInfoLog(handle);
            err_4 = new Error('RuntimeError:' + (_pyfunc_add((("errors in " + type_) + " shader:\n"), errors))); err_4.name = "RuntimeError"; throw err_4;
        }
    }
    gl.attachShader(this.handle, vert_handle);
    gl.attachShader(this.handle, frag_handle);
    gl.linkProgram(this.handle);
    if ((!_pyfunc_truthy(gl.getProgramParameter(this.handle, gl.LINK_STATUS)))) {
        err_3 = new Error('RuntimeError:' + ("Program link error:\n" + gl.getProgramInfoLog(this.handle))); err_3.name = "RuntimeError"; throw err_3;
    }
    this._unset_variables = this._get_active_attributes_and_uniforms();
    gl.detachShader(this.handle, vert_handle);
    gl.detachShader(this.handle, frag_handle);
    gl.deleteShader(vert_handle);
    gl.deleteShader(frag_handle);
    this._known_invalid = [];
    this._linked = true;
    return null;
};

Program.prototype._get_active_attributes_and_uniforms = function () {
    var attributes, ca, container, count, cu, getActive, getLocation, gl, i, info, j, m, name, regex, stub4_, stub5_seq, stub6_itr, uniforms, x;
    // Retrieve active attributes and uniforms to be able to check that
    // all uniforms/attributes are set by the user.
    gl = this._gl;
    this.locations = {};
    regex = new window.RegExp("(\\w+)\\s*(\\[(\\d+)\\])\\s*");
    cu = gl.getProgramParameter(this.handle, gl.ACTIVE_UNIFORMS);
    ca = gl.getProgramParameter(this.handle, gl.ACTIVE_ATTRIBUTES);
    attributes = [];
    uniforms = [];
    stub5_seq = [[attributes, ca, gl.getActiveAttrib, gl.getAttribLocation], [uniforms, cu, gl.getActiveUniform, gl.getUniformLocation]];
    if ((typeof stub5_seq === "object") && (!Array.isArray(stub5_seq))) {
        stub5_seq = Object.keys(stub5_seq);
    }
    for (stub6_itr = 0; stub6_itr < stub5_seq.length; stub6_itr += 1) {
        x = stub5_seq[stub6_itr];
        stub4_ = x;
        container = stub4_[0];count = stub4_[1];getActive = stub4_[2];getLocation = stub4_[3];
        for (i = 0; i < count; i += 1) {
            info = getActive.call(gl, this.handle, i);
            name = info.name;
            m = name.match(regex);
            if (_pyfunc_truthy(m)) {
                name = m[1];
                for (j = 0; j < info.size; j += 1) {
                    _pymeth_append.call(container, (["" + name + "[" + j + "]", info.type]));
                }
            } else {
                _pymeth_append.call(container, [name, info.type]);
            }
            this.locations[name] = getLocation.call(gl, this.handle, name);
        }
    }
    return _pyfunc_add(((function list_comprehenson () {var res = [];var v, iter0, i0;iter0 = attributes;if ((typeof iter0 === "object") && (!Array.isArray(iter0))) {iter0 = Object.keys(iter0);}for (i0=0; i0<iter0.length; i0++) {v = iter0[i0];{res.push(v[0]);}}return res;}).apply(this)), ((function list_comprehenson () {var res = [];var v, iter0, i0;iter0 = uniforms;if ((typeof iter0 === "object") && (!Array.isArray(iter0))) {iter0 = Object.keys(iter0);}for (i0=0; i0<iter0.length; i0++) {v = iter0[i0];{res.push(v[0]);}}return res;}).apply(this)));
};

Program.prototype.set_texture = function (name, value) {
    var err_3, handle, unit;
    // Set a texture sampler.
    //
    // A texture is a 2 dimensional grid of colors/intensities that
    // can be applied to a face (or used for other means by providing
    // a regular grid of data).
    //
    // Parameters
    // ----------
    // name : str
    //     The name by which the texture is known in the GLSL code.
    // value : Texture2D
    //     The gloo Texture2D object to bind.
    if ((!_pyfunc_truthy(this._linked))) {
        err_3 = new Error('RuntimeError:' + "Cannot set uniform when program has no code"); err_3.name = "RuntimeError"; throw err_3;
    }
    handle = _pymeth_get.call(this.locations, name, (-1));
    if (_pyfunc_truthy(handle < 0)) {
        if ((!_pyfunc_contains(name, this._known_invalid))) {
            _pymeth_append.call(this._known_invalid, name);
            console.log("Variable " + name + " is not an active texture");
        }
        return null;
    }
    if (_pyfunc_contains(name, this._unset_variables)) {
        _pymeth_remove.call(this._unset_variables, name);
    }
    this.activate();
    if (true) {
        unit = _pymeth_keys.call(this._samplers).length;
        if (_pyfunc_contains(name, this._samplers)) {
            unit = this._samplers[name][this._samplers[name].length -1];
        }
        this._samplers[name] = [value._target, value.handle, unit];
        this._gl.uniform1i(handle, unit);
    }
    return null;
};

Program.prototype.set_uniform = function (name, type_, value) {
    var a_type, count, err_3, funcname, handle, j, name_;
    // Set a uniform value.
    //
    // A uniform is a value that is global to both the vertex and
    // fragment shader.
    //
    // Parameters
    // ----------
    // name : str
    //     The name by which the uniform is known in the GLSL code.
    // type_ : str
    //     The type of the uniform, e.g. 'float', 'vec2', etc.
    // value : list of scalars
    //     The value for the uniform. Should be a list even for type float.
    if ((!_pyfunc_truthy(this._linked))) {
        err_3 = new Error('RuntimeError:' + "Cannot set uniform when program has no code"); err_3.name = "RuntimeError"; throw err_3;
    }
    handle = _pymeth_get.call(this.locations, name, (-1));
    if (_pyfunc_truthy(handle < 0)) {
        if ((!_pyfunc_contains(name, this._known_invalid))) {
            _pymeth_append.call(this._known_invalid, name);
            console.log("Variable " + name + " is not an active uniform");
        }
        return null;
    }
    if (_pyfunc_contains(name, this._unset_variables)) {
        _pymeth_remove.call(this._unset_variables, name);
    }
    count = 1;
    if ((!_pymeth_startswith.call(type_, "mat"))) {
        a_type = _pymeth_get.call({"int": "float", "bool": "float"}, type_, _pymeth_lstrip.call(type_, "ib"));
        count = Math.floor(value.length/(this.ATYPEINFO[a_type][0]));
    }
    if (_pyfunc_truthy(count > 1)) {
        for (j = 0; j < count; j += 1) {
            if ((_pyfunc_contains(("" + name + "[" + j + "]"), this._unset_variables))) {
                name_ = "" + name + "[" + j + "]";
                if (_pyfunc_contains(name_, this._unset_variables)) {
                    _pymeth_remove.call(this._unset_variables, name_);
                }
            }
        }
    }
    funcname = this.UTYPEMAP[type_];
    this.activate();
    if (_pymeth_startswith.call(type_, "mat")) {
        this._gl[funcname](handle, false, value);
    } else {
        this._gl[funcname](handle, value);
    }
    return null;
};

Program.prototype.set_attribute = function (name, type_, value, stride, offset) {
    var args, err_3, funcname, gtype, handle, is_vbo, size, stub7_;
    stride = (stride === undefined) ? 0: stride;
    offset = (offset === undefined) ? 0: offset;
    // Set an attribute value.
    //
    // An attribute represents per-vertex data and can only be used
    // in the vertex shader.
    //
    // Parameters
    // ----------
    // name : str
    //     The name by which the attribute is known in the GLSL code.
    // type_ : str
    //     The type of the attribute, e.g. 'float', 'vec2', etc.
    // value : VertexBuffer, array
    //     If value is a VertexBuffer, it is used (with stride and offset)
    //     for the vertex data. If value is an array, its used to set
    //     the value of all vertices (similar to a uniform).
    // stide : int, default 0
    //     The stride to "sample" the vertex data inside the buffer. Unless
    //     multiple vertex data are packed into a single buffer, this should
    //     be zero.
    // offset : int, default 0
    //     The offset to "sample" the vertex data inside the buffer. Unless
    //     multiple vertex data are packed into a single buffer, or only
    //     a part of the data must be used, this should probably be zero.
    if ((!_pyfunc_truthy(this._linked))) {
        err_3 = new Error('RuntimeError:' + "Cannot set attribute when program has no code"); err_3.name = "RuntimeError"; throw err_3;
    }
    is_vbo = value instanceof VertexBuffer;
    handle = _pymeth_get.call(this.locations, name, (-1));
    if (_pyfunc_truthy(handle < 0)) {
        if ((!_pyfunc_contains(name, this._known_invalid))) {
            _pymeth_append.call(this._known_invalid, name);
            if ((_pyfunc_truthy(is_vbo) && _pyfunc_truthy(offset > 0))) {
            } else {
                console.log("Variable " + name + " is not an active attribute");
            }
        }
        return null;
    }
    if (_pyfunc_contains(name, this._unset_variables)) {
        _pymeth_remove.call(this._unset_variables, name);
    }
    this.activate();
    if ((!_pyfunc_truthy(is_vbo))) {
        funcname = this.ATYPEMAP[type_];
        this._attributes[name] = [0, handle, funcname, value];
    } else {
        stub7_ = this.ATYPEINFO[type_];
        size = stub7_[0];gtype = stub7_[1];
        funcname = "vertexAttribPointer";
        args = [size, gtype, this._gl.FALSE, stride, offset];
        this._attributes[name] = [value.handle, handle, funcname, args];
    }
    return null;
};

Program.prototype._pre_draw = function () {
    var args, attr_handle, funcname, stub10_, stub11_seq, stub8_, stub9_seq, tex_handle, tex_target, unit, vbo_handle, x;
    // Prepare for drawing.
    this.activate();
    stub9_seq = this._samplers;
    for (x in stub9_seq) {
        if (!stub9_seq.hasOwnProperty(x)){ continue; }
        x = stub9_seq[x];
        stub8_ = x;
        tex_target = stub8_[0];tex_handle = stub8_[1];unit = stub8_[2];
        this._gl.activeTexture(_pyfunc_add(this._gl.TEXTURE0, unit));
        this._gl.bindTexture(tex_target, tex_handle);
    }
    stub11_seq = this._attributes;
    for (x in stub11_seq) {
        if (!stub11_seq.hasOwnProperty(x)){ continue; }
        x = stub11_seq[x];
        stub10_ = x;
        vbo_handle = stub10_[0];attr_handle = stub10_[1];funcname = stub10_[2];args = stub10_[3];
        if (_pyfunc_truthy(vbo_handle)) {
            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vbo_handle);
            this._gl.enableVertexAttribArray(attr_handle);
            this._gl[funcname].apply(this._gl, [].concat([attr_handle], args));
        } else {
            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null);
            this._gl.disableVertexAttribArray(attr_handle);
            this._gl[funcname].apply(this._gl, [].concat([attr_handle], args));
        }
    }
    if ((!_pyfunc_truthy(this._validated))) {
        this._validated = true;
        this._validate();
    }
    return null;
};

Program.prototype._validate = function () {
    var err_3;
    if (this._unset_variables.length) {
        console.log("Program has unset variables: " + this._unset_variables + "");
    }
    this._gl.validateProgram(this.handle);
    if ((!_pyfunc_truthy(this._gl.getProgramParameter(this.handle, this._gl.VALIDATE_STATUS)))) {
        console.log(this._gl.getProgramInfoLog(this.handle));
        err_3 = new Error('RuntimeError:' + "Program validation error"); err_3.name = "RuntimeError"; throw err_3;
    }
    return null;
};

Program.prototype.draw = function (mode, selection) {
    var count, err_3, first, gtype, stub12_;
    // Draw the current visualization defined by the program.
    //
    // Parameters
    // ----------
    // mode : GL enum
    //     Can be POINTS, LINES, LINE_LOOP, LINE_STRIP, LINE_FAN, TRIANGLES
    // selection : 2-element tuple or IndexBuffer
    //     The selection to draw, specified either as (first, count) or an
    //     IndexBuffer object.
    if ((!_pyfunc_truthy(this._linked))) {
        err_3 = new Error('RuntimeError:' + "Cannot draw program if code has not been set"); err_3.name = "RuntimeError"; throw err_3;
    }
    check_error(this._gl, "before draw");
    if (_pyfunc_truthy(selection instanceof IndexBuffer)) {
        this._pre_draw();
        selection.activate();
        count = selection._buffer_size / 2;
        gtype = this._gl.UNSIGNED_SHORT;
        this._gl.drawElements(mode, count, gtype, 0);
        selection.deactivate();
    } else {
        stub12_ = selection;
        first = stub12_[0];count = stub12_[1];
        if (_pyfunc_truthy(count)) {
            this._pre_draw();
            this._gl.drawArrays(mode, first, count);
        }
    }
    check_error(this._gl, "after draw");
    return null;
};


Buffer = function () {
    // Base buffer class for vertex data or index data.
    _pyfunc_instantiate(this, arguments);
}
Buffer.prototype = Object.create(GlooObject.prototype);
Buffer.prototype._base_class = GlooObject.prototype;
Buffer.prototype._class_name = "Buffer";

Buffer.prototype._target = null;
Buffer.prototype._usage = 35048;
Buffer.prototype._create = function () {
    this.handle = this._gl.createBuffer();
    this._buffer_size = 0;
    return null;
};

Buffer.prototype.delete = function () {
    // Delete the buffer.
    this._gl.deleteBuffer(this.handle);
    return null;
};

Buffer.prototype.activate = function () {
    // Activete the buffer.
    this._gl.bindBuffer(this._target, this.handle);
    return null;
};

Buffer.prototype.deactivate = function () {
    // Disable the buffer.
    this._gl.bindBuffer(this._target, null);
    return null;
};

Buffer.prototype.set_size = function (nbytes) {
    // Set the size of the buffer in bytes.
    //
    // Parameters
    // ----------
    // nbytes : int
    //     The number of bytes that the buffer needs to hold.
    if ((!_pyfunc_equals(nbytes, this._buffer_size))) {
        this.activate();
        this._gl.bufferData(this._target, nbytes, this._usage);
        this._buffer_size = nbytes;
    }
    return null;
};

Buffer.prototype.set_data = function (offset, data) {
    // Set the buffer data.
    //
    // Parameters
    // ----------
    // offset : int
    //     The offset in bytes for the new data.
    // data : typed array
    //     The data to upload.
    this.activate();
    this._gl.bufferSubData(this._target, offset, data);
    return null;
};


VertexBuffer = function () {
    // A buffer for vertex data.
    _pyfunc_instantiate(this, arguments);
}
VertexBuffer.prototype = Object.create(Buffer.prototype);
VertexBuffer.prototype._base_class = Buffer.prototype;
VertexBuffer.prototype._class_name = "VertexBuffer";

VertexBuffer.prototype._target = 34962;

IndexBuffer = function () {
    // A buffer for index data.
    _pyfunc_instantiate(this, arguments);
}
IndexBuffer.prototype = Object.create(Buffer.prototype);
IndexBuffer.prototype._base_class = Buffer.prototype;
IndexBuffer.prototype._class_name = "IndexBuffer";

IndexBuffer.prototype._target = 34963;

Texture2D = function () {
    // A 2 dimensional regular grid.
    _pyfunc_instantiate(this, arguments);
}
Texture2D.prototype = Object.create(GlooObject.prototype);
Texture2D.prototype._base_class = GlooObject.prototype;
Texture2D.prototype._class_name = "Texture2D";

Texture2D.prototype._target = 3553;
Texture2D.prototype._types = {"Int8Array": 5120, "Uint8Array": 5121, "Int16Array": 5122, "Uint16Array": 5123, "Int32Array": 5124, "Uint32Array": 5125, "Float32Array": 5126};
Texture2D.prototype._create = function () {
    this.handle = this._gl.createTexture();
    this._shape_format = null;
    return null;
};

Texture2D.prototype.delete = function () {
    // Delete the texture.
    this._gl.deleteTexture(this.handle);
    return null;
};

Texture2D.prototype.activate = function () {
    // Activate the texture.
    this._gl.bindTexture(this._target, this.handle);
    return null;
};

Texture2D.prototype.deactivate = function () {
    // Disable the texture.
    this._gl.bindTexture(this._target, 0);
    return null;
};

Texture2D.prototype._get_alignment = function (width) {
    var alignment, alignments, stub13_seq, stub14_itr;
    // Determines a textures byte alignment. If the width isn't a
    //         power of 2 we need to adjust the byte alignment of the image.
    //         The image height is unimportant.
    //
    //         www.opengl.org/wiki/Common_Mistakes#Texture_upload_and_pixel_reads
    alignments = [4, 8, 2, 1];
    stub13_seq = alignments;
    if ((typeof stub13_seq === "object") && (!Array.isArray(stub13_seq))) {
        stub13_seq = Object.keys(stub13_seq);
    }
    for (stub14_itr = 0; stub14_itr < stub13_seq.length; stub14_itr += 1) {
        alignment = stub13_seq[stub14_itr];
        if ((_pyfunc_equals((width % alignment), 0))) {
            return alignment;
        }
    }
    return null;
};

Texture2D.prototype.set_wrapping = function (wrap_s, wrap_t) {
    // Set the texture wrapping mode.
    //
    // Parameters
    // ----------
    // wrap_s : GL enum
    //     The mode to wrap the x dimension. Valid values are REPEAT
    //     CLAMP_TO_EDGE MIRRORED_REPEAT
    // wrap_t : GL enum
    //     The mode to wrap the y dimension. Same options as for wrap_s.
    this.activate();
    this._gl.texParameterf(this._target, this._gl.TEXTURE_WRAP_S, wrap_s);
    this._gl.texParameterf(this._target, this._gl.TEXTURE_WRAP_T, wrap_t);
    return null;
};

Texture2D.prototype.set_interpolation = function (min, mag) {
    // Set the texture interpolation mode
    //
    // Parameters
    // ----------
    // min : GL enum
    //     The interpolation mode when minifying (i.e. zoomed out). Valid
    //     values are LINEAR and NEAREST.
    // max : GL enum
    //     The interpolation mode when magnifying (i.e. zoomed in). Valid
    //     values are LINEAR, NEAREST, NEAREST_MIPMAP_NEAREST,
    //     LINEAR_MIPMAP_NEAREST, NEAREST_MIPMAP_LINEAR, LINEAR_MIPMAP_LINEAR.
    this.activate();
    this._gl.texParameterf(this._target, this._gl.TEXTURE_MIN_FILTER, min);
    this._gl.texParameterf(this._target, this._gl.TEXTURE_MAG_FILTER, mag);
    return null;
};

Texture2D.prototype.set_size = function (shape, format) {
    var height, stub15_, width;
    // Set the size of the 2D texture.
    //
    // Parameters
    // ----------
    // shape : tuple of ints
    //     The shape of the data to upload
    // format : GL enum
    //     The format of the texture data. Can be LUMINANCE, LUMINANCE_ALPHA,
    //     RGB, and RGBA.
    stub15_ = shape;
    height = stub15_[0];width = stub15_[1];
    if ((!_pyfunc_equals([height, width, format], this._shape_format))) {
        this._shape_format = [height, width, format];
        this.activate();
        this._gl.texImage2D(this._target, 0, format, width, height, 0, format, this._gl.UNSIGNED_BYTE, null);
    }
    this.u_shape = [height, width];
    return null;
};

Texture2D.prototype.set_data = function (offset, shape, data) {
    var _, alignment, err_3, format, gtype, height, stub16_, stub17_, width, x, y;
    // Set the 2D texture data.
    //
    // Parameters
    // ----------
    // offset : tuple of ints
    //     Offset in pixels for each dimension.
    // shape : tuple of ints
    //     The shape of the data to upload
    // data : typed array
    //     The actual pixel data. Can be of any type, but on the GPU the
    //     dat is stored in 8 bit precision.
    if (_pyfunc_equals(shape.length, 2)) {
        shape = [shape[0], shape[1], 1];
    }
    this.activate();
    format = this._shape_format[2];
    stub16_ = shape;
    height = stub16_[0];width = stub16_[1];_ = stub16_[2];
    stub17_ = offset;
    y = stub17_[0];x = stub17_[1];
    gtype = _pymeth_get.call(this._types, data.constructor.name, null);
    if ((gtype === null)) {
        err_3 = new Error('ValueError:' + ("Type " + data.constructor.name + " not allowed for texture")); err_3.name = "ValueError"; throw err_3;
    }
    alignment = this._get_alignment(_pyfunc_mult(shape[shape.length -2], shape[shape.length -1]));
    if ((!_pyfunc_equals(alignment, 4))) {
        this._gl.pixelStorei(this._gl.UNPACK_ALIGNMENT, alignment);
    }
    this._gl.texSubImage2D(this._target, 0, x, y, width, height, format, gtype, data);
    if ((!_pyfunc_equals(alignment, 4))) {
        this._gl.pixelStorei(this._gl.UNPACK_ALIGNMENT, 4);
    }
    return null;
};


Texture3DLike = function () {
    // A 2D texture with support to simulate a 3D texture.
    //
    // To use this class, use set_size() and set_data() as if it was a 3D
    // texture. Add the GLSL_SAMPLE_NEAREST or GLSL_SAMPLE_LINEAR to the
    // shader to add the sample3D() function that can be used instead of
    // texture2D(). This function needs ``shape`` and ``tiles`` arguments
    // which can be set via uniforms, using the ``u_shape`` and ``u_tiles``
    // attributes of this object.
    _pyfunc_instantiate(this, arguments);
}
Texture3DLike.prototype = Object.create(Texture2D.prototype);
Texture3DLike.prototype._base_class = Texture2D.prototype;
Texture3DLike.prototype._class_name = "Texture3DLike";

Texture3DLike.prototype.GLSL_SAMPLE_NEAREST = "\n        vec4 sample3D(sampler2D tex, vec3 texcoord, vec3 shape, vec2 tiles) {\n            shape.xyz = shape.zyx;  // silly row-major convention\n            float nrows = tiles.y, ncols = tiles.x;\n            // Don't let adjacent frames be interpolated into this one\n            texcoord.x = min(texcoord.x * shape.x, shape.x - 0.5);\n            texcoord.x = max(0.5, texcoord.x) / shape.x;\n            texcoord.y = min(texcoord.y * shape.y, shape.y - 0.5);\n            texcoord.y = max(0.5, texcoord.y) / shape.y;\n\n            float zindex = floor(texcoord.z * shape.z);\n\n            // Do a lookup in the 2D texture\n            float u = (mod(zindex, ncols) + texcoord.x) / ncols;\n            float v = (floor(zindex / ncols) + texcoord.y) / nrows;\n\n            return texture2D(tex, vec2(u,v));\n        }\n    ";
Texture3DLike.prototype.GLSL_SAMPLE_LINEAR = "\n        vec4 sample3D(sampler2D tex, vec3 texcoord, vec3 shape, vec2 tiles) {\n            shape.xyz = shape.zyx;  // silly row-major convention\n            float nrows = tiles.y, ncols = tiles.x;\n            // Don't let adjacent frames be interpolated into this one\n            texcoord.x = min(texcoord.x * shape.x, shape.x - 0.5);\n            texcoord.x = max(0.5, texcoord.x) / shape.x;\n            texcoord.y = min(texcoord.y * shape.y, shape.y - 0.5);\n            texcoord.y = max(0.5, texcoord.y) / shape.y;\n\n            float z = texcoord.z * shape.z;\n            float zindex1 = floor(z);\n            float u1 = (mod(zindex1, ncols) + texcoord.x) / ncols;\n            float v1 = (floor(zindex1 / ncols) + texcoord.y) / nrows;\n\n            float zindex2 = zindex1 + 1.0;\n            float u2 = (mod(zindex2, ncols) + texcoord.x) / ncols;\n            float v2 = (floor(zindex2 / ncols) + texcoord.y) / nrows;\n\n            vec4 s1 = texture2D(tex, vec2(u1, v1));\n            vec4 s2 = texture2D(tex, vec2(u2, v2));\n\n            return s1 * (zindex2 - z) + s2 * (z - zindex1);\n        }\n    ";
Texture3DLike.prototype._get_tile_info = function (shape) {
    var err_3, max_size, ncols, nrows;
    max_size = this._gl.getParameter(this._gl.MAX_TEXTURE_SIZE);
    nrows = Math.floor(max_size/shape[1]);
    nrows = Math.min(nrows, shape[0]);
    ncols = window.Math.ceil(shape[0] / nrows);
    if (_pyfunc_truthy(_pyfunc_mult(ncols, shape[2]) > max_size)) {
        err_3 = new Error('RuntimeError:' + ("Cannot fit 3D data with shape " + shape + " onto simulated 2D texture.")); err_3.name = "RuntimeError"; throw err_3;
    }
    return [nrows, ncols];
};

Texture3DLike.prototype.set_size = function (shape, format) {
    var ncols, nrows, sim_shape, stub18_;
    // Set the size of the 3D texture.
    //
    // Parameters
    // ----------
    // shape : tuple of ints
    //     The shape of the data to upload
    // format : GL enum
    //     The format of the texture data. Can be LUMINANCE, LUMINANCE_ALPHA,
    //     RGB, and RGBA.
    stub18_ = this._get_tile_info(shape);
    nrows = stub18_[0];ncols = stub18_[1];
    sim_shape = [_pyfunc_mult(shape[1], nrows), _pyfunc_mult(shape[2], ncols)];
    Texture3DLike.prototype._base_class.set_size.call(this, sim_shape, format);
    this.u_shape = [shape[0], shape[1], shape[2]];
    this.u_tiles = [ncols, nrows];
    return null;
};

Texture3DLike.prototype.set_data = function (offset, shape, data) {
    var Type, col, elements_per_tile, err_3, ncols, nrows, row, sim_shape, stub19_, stub20_, tile, z, zeros;
    // Set the 3D texture data.
    //
    // Parameters
    // ----------
    // offset : tuple of ints
    //     Offset in pixels for each dimension.
    // shape : tuple of ints
    //     The shape of the data to upload
    // data : typed array
    //     The actual pixel data. Can be of any type, but on the GPU the
    //     dat is stored in 8 bit precision.
    if (_pyfunc_equals(shape.length, 3)) {
        shape = [shape[0], shape[1], shape[2], 1];
    }
    if ((!(_pyfunc_all(((function list_comprehenson () {var res = [];var i, iter0, i0;iter0 = offset;if ((typeof iter0 === "object") && (!Array.isArray(iter0))) {iter0 = Object.keys(iter0);}for (i0=0; i0<iter0.length; i0++) {i = iter0[i0];{res.push(_pyfunc_equals(i, 0));}}return res;}).apply(this)))))) {
        err_3 = new Error('ValueError:' + "Texture3DLike does not support nonzero offset (for now)"); err_3.name = "ValueError"; throw err_3;
    }
    stub19_ = this._get_tile_info(shape);
    nrows = stub19_[0];ncols = stub19_[1];
    sim_shape = [_pyfunc_mult(shape[1], nrows), _pyfunc_mult(shape[2], ncols), shape[3]];
    if (_pyfunc_equals(ncols, 1)) {
        Texture3DLike.prototype._base_class.set_data.call(this, [0, 0], sim_shape, data);
    } else {
        Type = data.constructor;
        zeros = new Type(_pyfunc_mult(_pyfunc_mult(sim_shape[0], sim_shape[1]), sim_shape[2]));
        Texture3DLike.prototype._base_class.set_data.call(this, [0, 0], sim_shape, zeros);
        for (z = 0; z < shape[0]; z += 1) {
            stub20_ = [Math.floor(z/ncols), z % ncols];
            row = stub20_[0];col = stub20_[1];
            elements_per_tile = Math.floor(data.length/shape[0]);
            tile = data.slice(_pyfunc_mult(z, elements_per_tile),_pyfunc_mult((z + 1), elements_per_tile));
            Texture3DLike.prototype._base_class.set_data.call(this, [_pyfunc_mult(row, shape[1]), _pyfunc_mult(col, shape[2])], shape.slice(1), tile);
        }
    }
    return null;
};

module.exports = {
  "Buffer": Buffer,
  "GlooObject": GlooObject,
  "IndexBuffer": IndexBuffer,
  "Program": Program,
  "Texture2D": Texture2D,
  "Texture3DLike": Texture3DLike,
  "VertexBuffer": VertexBuffer,
  "check_error": check_error,
  "console": console
};
