function loadModel(url, callback, logger) {
    var x = new XMLHttpRequest();
    x.open("GET", url, true);
    x.overrideMimeType("application/json");
    x.send(null);
    if (logger) {
        logger("sent request for " + url);
    };
    x.onreadystatechange = function () {
        if (x.readyState == 4) {
            if (x.responseText) {
                if (logger) {
                    logger("loaded " + url);
                };
                callback(parseModel(x.responseText, logger));
            };
        };
    };
};
function parseModel(dae, logger) {
    var obj = JSON.parse(dae);
    if (logger) {
        logger("parsed json -> " + obj);
    };
    for (var m = null, _js_arrvar3559 = obj.materials, _js_idx3558 = 0; _js_idx3558 < _js_arrvar3559.length; _js_idx3558 += 1) {
        m = _js_arrvar3559[_js_idx3558];
        var id3560 = m.id;
        var textures3561 = m.textures;
        if (logger) {
            var a = "material " + id3560 + ":";
            for (var i = null, _js_arrvar3563 = textures3561, _js_idx3562 = 0; _js_idx3562 < _js_arrvar3563.length; _js_idx3562 += 1) {
                i = _js_arrvar3563[_js_idx3562];
                a += " [image " + i + " " + i.channel + "]";
            };
            logger(a);
        };
    };
    var foo = "";
    for (var m = null, _js_arrvar3565 = obj.materials, _js_idx3564 = 0; _js_idx3564 < _js_arrvar3565.length; _js_idx3564 += 1) {
        m = _js_arrvar3565[_js_idx3564];
        for (var i = null, _js_arrvar3567 = m.textures, _js_idx3566 = 0; _js_idx3566 < _js_arrvar3567.length; _js_idx3566 += 1) {
            i = _js_arrvar3567[_js_idx3566];
        };
    };
    logger(foo);
    return obj;
};
function lerpp(a, b, d) {
    var d2 = 1.0 - d;
    return [a[0], d2 * a[1] + d * b[1], d2 * a[2] + d * b[2], d2 * a[3] + d * b[3]];
};
function lerpr(a, b, d) {
    var d2 = 1.0 - d;
    var w = d2 * a[1] + d * b[1];
    var x = d2 * a[2] + d * b[2];
    var y = d2 * a[3] + d * b[3];
    var z = d2 * a[4] + d * b[4];
    var l = Math.sqrt(w * w + x * x + y * y + z * z);
    return [a[0], w / l, x / l, y / l, z / l];
};
function lerppInto(a, b, d, dest) {
    var d2 = 1.0 - d;
    dest[0] = a[0];
    dest[1] = d2 * a[1] + d * b[1];
    dest[2] = d2 * a[2] + d * b[2];
    dest[3] = d2 * a[3] + d * b[3];
    return dest;
};
function lerprInto(a, b, d, dest) {
    var d2 = 1.0 - d;
    var w = d2 * a[1] + d * b[1];
    var x = d2 * a[2] + d * b[2];
    var y = d2 * a[3] + d * b[3];
    var z = d2 * a[4] + d * b[4];
    var l = Math.sqrt(w * w + x * x + y * y + z * z);
    dest[0] = a[0];
    dest[1] = w / l;
    dest[2] = x / l;
    dest[3] = y / l;
    dest[4] = z / l;
    return dest;
};
function fmod(x, y) {
    return x - y * Math.floor(x / y);
};
function makeOldAnimator(obj, nodes, anims, lastAnim) {
    return function (animNumber, time, stat, cache) {
        var a = anims[animNumber];
        var mx = new Array(16);
        var pI = [0.0, 0.0, 0.0];
        var rI = [0.0, 1.0, 0.0, 0.0, 0.0];
        time = time % a.length;
        for (var i = 0; i < a.keys.length; i += 1) {
            var anim = (a.keys)[i];
            var p = anim.position;
            var r = anim.rotation;
            var parent3568 = (obj.nodes)[anim.index].parent;
            var getKey3569 = function (keys, lerp, time) {
                var k = keys[0];
                for (var ii = 0; ii < keys.length; ii += 1) {
                    var ki = keys[ii];
                    if (ki[0] < time) {
                        k = ki;
                    } else {
                        var dt = (time - k[0]) / (ki[0] - k[0]);
                        return lerp(k, ki, dt);
                    };
                };
                return k;
            };
            if (p) {
                if (p.length == 1) {
                    p = p[0];
                } else {
                    p = getKey3569(p, lerpp, time);
                };
            } else {
                p = pI;
            };
            if (r) {
                if (r.length == 1) {
                    r = r[0];
                } else {
                    r = getKey3569(r, lerpr, time);
                };
            } else {
                r = rI;
            };
            _translationxquatInto(p[1], p[2], p[3], r[1], r[2], r[3], r[4], mx);
            var pm = parent3568 > 0 ? (obj.animNodes)[parent3568] : [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
            _matx3(pm, mx, (obj.animNodes)[anim.index]);
        };
    };
};
function makeAnimInfo(obj) {
    var nodes3570 = obj.nodes;
    var anims3571 = obj.anims;
    var state = { "obj" : obj, "anim-nodes" : new Array() };
    for (var i = 0; i < obj.nodes.length; i += 1) {
        (state["anim-nodes"])[i] = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
    };
    return state;
};
function vboFromModel(gl, obj, program, logger) {
    for (var m = null, _js_arrvar3573 = obj.materials, _js_idx3572 = 0; _js_idx3572 < _js_arrvar3573.length; _js_idx3572 += 1) {
        m = _js_arrvar3573[_js_idx3572];
        for (var i = null, _js_arrvar3577 = m.textures, _js_idx3576 = 0; _js_idx3576 < _js_arrvar3577.length; _js_idx3576 += 1) {
            i = _js_arrvar3577[_js_idx3576];
            var tex = gl.createTexture();
            tex.image = new Image();
            tex.id = m.id;
            tex.image.validate = "always";
            tex.image.onload = (function (tex) {
                return function () {
                    if (logger) {
                        logger("loaded tex" + tex.id);
                    };
                    gl.enable(gl.TEXTURE_2D);
                    gl.bindTexture(gl.TEXTURE_2D, tex);
                    gl.texImage2D(gl.TEXTURE_2D, 0, tex.image);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
                    gl.generateMipmap(gl.TEXTURE_2D);
                };
            })(tex);
            tex.image.onerror = (function (i, tex) {
                return function () {
                    if (logger) {
                        logger("tex errored" + tex.id);
                    };
                };
            })(i, tex);
            tex.image.src = "data/" + i.source;
            i.glTex = tex;
        };
    };
    logger("set animator for object" + " anims = " + obj.anims + " nodes = " + obj.nodes);
    obj.animNodes = new Array(obj.nodes.length);
    for (var i = 0; i < obj.nodes.length; i += 1) {
        (obj.animNodes)[i] = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
    };
    obj.animate = makeOldAnimator(obj, obj.nodes, obj.anims, -1, 1, null);
    for (var m = null, _js_arrvar3575 = obj.meshes, _js_idx3574 = 0; _js_idx3574 < _js_arrvar3575.length; _js_idx3574 += 1) {
        m = _js_arrvar3575[_js_idx3574];
        var indices = gl.createBuffer();
        var vertices = new Array();
        var textureList = new Array();
        if (logger) {
            logger("create vbo for mesh " + m.id);
        };
        var ofs = m["bone-offsets"];
        for (var i = 0; i < ofs.length; i += 1) {
            ofs[i] = matFromArray(ofs[i]);
        };
        if (logger) {
            logger("create vbo for mesh " + m.id);
        };
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indices);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(m.indices), gl.STATIC_DRAW);
        var makevbo3578 = function (i, data, size, type, normalize, stride, offset) {
            if (data) {
                vertices[i] = { "buffer" : gl.createBuffer(), "size" : size, "type" : type ? type : gl["FLOAT"], "normalize" : normalize ? normalize : false, "stride" : stride ? stride : 0, "offset" : offset ? offset : 0 };
                gl.bindBuffer(gl.ARRAY_BUFFER, vertices[i].buffer);
                gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
            };
        };
        makevbo3578(0, new WebGLFloatArray(m.positions), 3);
        if (m.normals) {
            makevbo3578(1, new WebGLFloatArray(m.normals), 3);
        };
        if (m.tangents) {
            makevbo3578(2, new WebGLFloatArray(m.tangents), 3);
        };
        if (m.bitangents) {
            makevbo3578(3, new WebGLFloatArray(m.bitangents), 3);
        };
        if (m["uv-0"]) {
            makevbo3578(4, new WebGLFloatArray(m["uv-0"]), 2);
        };
        if (m["bone-weights"]) {
            logger("bone weight");
            makevbo3578(5, new WebGLUnsignedByteArray(m["bone-weights"]), 4, gl.UNSIGNED_BYTE, true);
        };
        if (m["bone-indices"]) {
            makevbo3578(6, new WebGLUnsignedByteArray(m["bone-indices"]), 4, gl.UNSIGNED_BYTE, null);
        };
        var mat = m.material;
        for (var mm = null, _js_arrvar3580 = obj.materials, _js_idx3579 = 0; _js_idx3579 < _js_arrvar3580.length; _js_idx3579 += 1) {
            mm = _js_arrvar3580[_js_idx3579];
            if (mm.id == mat) {
                if (logger) {
                    logger("got material match for mesh");
                };
                for (var i = null, _js_arrvar3582 = mm.textures, _js_idx3581 = 0; _js_idx3581 < _js_arrvar3582.length; _js_idx3581 += 1) {
                    i = _js_arrvar3582[_js_idx3581];
                    textureList.push({ "uniform" : gl.getUniformLocation(program, i.channel + "Texture"), "texture" : i.glTex });
                    if (logger) {
                        logger("push object onto list ...");
                        logger("->" + textureList);
                    };
                };
            };
        };
        logger("texture list = " + textureList + "|");
        logger("set bone uploader for mesh");
        m.uploadBones = (function (obj, bones, offsets) {
            var temp = new Array(16);
            var temp2 = new Array(16 * bones.length);
            for (var i = 0; i < temp2.length; i += 1) {
                temp2[i] = 1111111111;
            };
            for (var i = 0; i < 16; i += 1) {
                temp2[i] = 0;
            };
            temp2[0] = 1;
            temp2[5] = 1;
            temp2[11] = 1;
            temp2[15] = 1;
            return function (gl, uniform, animNodes, stat) {
                for (var i = 0; i < bones.length; i += 1) {
                    var b = animNodes[bones[i]];
                    var ofs = offsets[i];
                    _matx3Ofs(b, ofs.elements, temp2, (i + 1) * 16);
                };
                gl.uniformMatrix4fv(uniform, null, new WebGLFloatArray(temp2));
            };
        })(obj, m.bones, m["bone-offsets"]);
        logger("setting up binder closures");
        logger("set binder for mesh");
        for (var i = 0; i < vertices.length; i += 1) {
            var v = vertices[i];
            if (v) {
                v.bindFun = (function (gl, i, buffer, size, type, normalize, stride, offset) {
                    return function () {
                        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
                        gl.vertexAttribPointer(i, size, type, normalize, stride, offset);
                        gl.enableVertexAttribArray(i);
                    };
                })(gl, i, v.buffer, v.size, v.type, v.normalize, v.stride, v.offset);
            };
        };
        logger("verts length = " + vertices.length);
        m.bind = (function (gl, ci, cv, textures) {
            return function (gl, stat) {
                var x = 0;
                for (var _i = 0; _i < textures.length; _i += 1) {
                    var i = textures[_i];
                    gl.activeTexture(x + gl.TEXTURE0);
                    gl.enable(gl.TEXTURE_2D);
                    gl.bindTexture(gl.TEXTURE_2D, i.texture);
                    gl.uniform1i(i.uniform, x);
                    ++x;
                };
                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ci);
                for (var i = 0; i < cv.length; i += 1) {
                    var v = cv[i];
                    if (v) {
                        gl.bindBuffer(gl.ARRAY_BUFFER, v.buffer);
                        gl.vertexAttribPointer(i, v.size, v.type, v.normalize, v.stride, v.offset);
                        gl.enableVertexAttribArray(i);
                    };
                };
            };
        })(gl, indices, vertices, textureList);
    };
};