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);
};
var I = _mat4i();
var Temp = _mat4i();
function makeOldAnimator(obj, nodes, anims, lastAnim) {
    var pI = new WebGLFloatArray([0.0, 0.0, 0.0,0.0]);
    var rI = new WebGLFloatArray([0.0, 1.0, 0.0, 0.0, 0.0]);
    var pt = new WebGLFloatArray([0.0, 0.0, 0.0, 0.0]);
    var rt = new WebGLFloatArray([0.0, 1.0, 0.0, 0.0, 0.0]);
    var mx = Temp;//_mat4i;//new WebGLFloatArray(16);
    return function (animNumber, time, stat, cache) {
        var a = anims[animNumber];
        if (a.length)
            time = time % a.length;
        else
            time = 0;
        var akl = a.keys.length;
        for (var i = 0; i < akl; i += 1) {
            var anim = (a.keys)[i];
            var p = anim.position;
            var r = anim.rotation;
            var parent3568 = (obj.nodes)[anim.index].parent;
            var getKeyP = function (keys, time,dd) {
                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 lerppInto(k, ki, dt,dd);
                    };
                };
                return k;
            };
            var getKeyR = function (keys, time,d) {
                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 lerprInto(k, ki, dt,d);
                    };
                };
                return k;
            };
            animsT++;
            if (p) {
                if (p.length == 1) {
                    animsP1++;
                    p = p[0];
                } else {
                    p = getKeyP(p, time,pt);
                };
            } else {
                animsPi++;
                p = pI;
            };
            if (r) {
                if (r.length == 1) {
                    animsR1++;
                    r = r[0];
                } else {
                    r = getKeyR(r, time,rt);
                };
                _translationxquatInto(p[1], p[2], p[3], r[1], r[2], r[3], r[4], mx);
            } else {
                animsRi++;
                //r = rI;
                mx[ 0] = 1.0;
                mx[ 1] = 0.0;
                mx[ 2] = 0.0;
                //mx[ 3] = 0.0;
                mx[ 4] = 0.0;
                mx[ 5] = 1.0;
                mx[ 6] = 0.0;
                //mx[ 7] = 0.0;
                mx[ 8] = 0.0;
                mx[ 9] = 0.0;
                mx[10] = 1.0;
                //mx[11] = 0.0;
                mx[12] = p[1];
                mx[13] = p[2];
                mx[14] = p[3];
                //mx[15] = 1.0;
            };
            if (parent3568 == 0) animsXi++;
            //var pm = parent3568 > 0 ? (obj.animNodes)[parent3568] : I;
            //_matx3(pm, mx, (obj.animNodes)[anim.index]);

            if (parent3568 > 0)
                _matx3((obj.animNodes)[parent3568], mx,
                       (obj.animNodes)[anim.index]);
            else
                _mcopy(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] = I;
    };
    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] = _mat4i(); //new WebGLFloatArray([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
    };
    for (var i = 0; i < obj.anims.length; ++i) {
        //for (var j =0; j < (obj.anims[i]).length; ++j) {
        var a = obj.anims[i];
            //if (a) {
                var akl = a.keys.length;
                for (var l = 0; l < akl; l += 1) {
                    var anim = (a.keys)[l];
                    var p = anim.position;
                    var r = anim.rotation;
                    if (p) {
                        for (var k = 0; k < p.length; k++) {
                            p[k] = new WebGLFloatArray(p[k]);
                        }
                    }
                    if (r) {
                        for (var k = 0; k < r.length; k++) {
                            r[k] = new WebGLFloatArray(r[k]);
                        }
                    }
                }
                // }
                //    }
    }
    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, true);
        };
        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 WebGLFloatArray(16);
            var temp2 = new WebGLFloatArray(16 * (bones.length + 1));
            for (var i = 0; i < temp2.length; i += 1) {
                temp2[i] = 11111.0;
            };
            for (var i = 0; i < 16; i += 1) {
                temp2[i] = 0.0;
            };
            temp2[0] = 1.0;
            temp2[5] = 1.0;
            temp2[10] = 1.0;
            temp2[15] = 1.0;


            //var tempx = new Array(16 * bones.length);
            //for (var i = 0; i < tempx.length; i += 1) {
            //    tempx[i] = 1.0;
            //};
            //for (var i = 0; i < 16; i += 1) {
            //    tempx[i] = 0.0;
            //};
            //tempx[0] = 1.0;
            //tempx[5] = 1.0;
            //tempx[11] = 1.0;
            //tempx[15] = 1.0;

            //var s = "";
            //for (var i = 0; i < tempx.length; i += 1) {
            //    s += temp2[i] + ",";
            //}
            //logger("len2="+temp2.length+" lenx="+tempx.length);
            //logger("temp2="+s);
            //logger("tempx="+tempx);
            //var once = true;
            logger("@@@@@len="+temp2.length+"("+(temp2.length/16)+") ?="+bones.length);
            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);
                    //_matx3Ofs(I,I, temp2, (i + 1) * 16);
                    //    _matx3Ofs(b, ofs.elements, tempx, (i + 1) * 16);
                    //for (var j = 0; j<16;j++) {
                    //    if ((j==0)||(j==5)||(j==10)||(j==15))
                    //        temp2[(i+1)*16+j] = 1.0;
                    //    else
                    //        temp2[(i+1)*16+j] = 0.0;
                    //}
                };
                //var bad = null;
                //for (var i = 0; i < tempx.length; i += 1) {
                //    if (tempx[i] != temp2[i]) bad=true;
                //}
                //if (bad && once) {
                //    s = "";
                //    for (var i = 0; i < tempx.length; i += 1) {
                //        s += temp2[i] + ",";
                //    }
                //    alert("len2="+temp2.length+",lenx="+tempx.length+"tempx="+tempx+" temp2="+s); once = null;
                //}
                gl.uniformMatrix4fv(uniform, null, 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);
    };
};