//-------- js/MorphsManager.js --------
// Generated by CoffeeScript 1.12.2
(function () {
    var MorphTarget, MorphsManager, RQ, VBO, console, cwaenv, document, log, setTimeout;
    cwaenv = this.getCWAEnv();
    console = this.console;
    document = this.document;
    setTimeout = this.setTimeout;
    log = console.log.bind(console);
    VBO = cwaenv.get("VBO");
    RQ = cwaenv.get("RotQuat");
    MorphTarget = cwaenv.get("MorphTarget");
    MorphsManager = (function () {
        function MorphsManager(mtags) {
            this.MORPH_TAGS = mtags;
            this.morphTargets = [];
            this.mtIndicesBy4CC = null;
            this.nVertices = -1;
            this.nVerticesNoDups = -1;
            this.morphOffsetBufs = [];
            this.morphNormBufs = [];
            this.posVBOs = null;
            this.normVBOs = null;
            this.zeroMorphBuf = null;
            this.multiMorphOffsetBuf = null;
            this.multiMorphNormBuf = null;
            this.vbosUsage = null;
            this.morphAlloc = null;
            this.morphAllocIsNew = null;
            this.iMulti = -1;
            this.multiMorphs = [];
            this.morphWeights = null;
            this.prevMorphAlloc = null;
            this.mmRanges = null;
            this.mmWeightedSegsList = null;
        }
        MorphsManager.fromJSON = function (jsnmtl, mtags) {
            var mm;
            mm = new MorphsManager(mtags);
            mm.setFromJSON(jsnmtl);
            return mm;
        };
        MorphsManager.fromBin = function (avdv, mtags) {
            var mm;
            mm = new MorphsManager(mtags);
            mm.setFromBin(avdv);
            return mm;
        };
        MorphsManager.prototype._lohi = function (lo, hi) {
            return [lo, hi];
        };
        MorphsManager.prototype._lohistr = function (lohi) {
            var hi, lo;
            lo = lohi[0], hi = lohi[1];
            return "[" + lo + ".." + hi + ")";
        };
        MorphsManager.prototype._lohi2str = function (lo, hi) {
            return this._lohistr(this._lohi(lo, hi));
        };
        MorphsManager.prototype._limits = function (rng) {
            var lo, sz;
            lo = rng.base;
            sz = rng.size;
            return this._lohi(lo, lo + sz);
        };
        MorphsManager.prototype._rngstr = function (rng) {
            return this._lohistr(this._limits(rng));
        };
        MorphsManager.prototype._jstr = function (j) {
            if (j === 0) {
                return "main";
            } else {
                return " dup";
            }
        };
        MorphsManager.prototype.setFromJSON = function (jsnmtl) {
            var NMT, json2mt, t;
            json2mt = MorphTarget.fromJSON;
            NMT = jsnmtl.length;
            this.morphTargets = (function () {
                var k, ref, results;
                results = [];
                for (t = k = 0, ref = NMT; 0 <= ref ? k < ref : k > ref; t = 0 <= ref ? ++k : --k) {
                    results.push(json2mt(jsnmtl[t]));
                }
                return results;
            })();
            return this.set4CCIndex();
        };
        MorphsManager.prototype.setFromBin = function (avdv) {
            var NMT, t;
            NMT = avdv.nextUint();
            this.morphTargets = (function () {
                var k, ref, results;
                results = [];
                for (t = k = 0, ref = NMT; 0 <= ref ? k < ref : k > ref; t = 0 <= ref ? ++k : --k) {
                    results.push(MorphTarget.fromBin(avdv));
                }
                return results;
            })();
            return this.set4CCIndex();
        };
        MorphsManager.prototype.set4CCIndex = function () {
            var k, len, m, mBy4cc, mtgt, ref;
            mBy4cc = [];
            ref = this.morphTargets;
            for (m = k = 0, len = ref.length; k < len; m = ++k) {
                mtgt = ref[m];
                mBy4cc[mtgt.getFourCCName()] = m;
            }
            return this.mtIndicesBy4CC = mBy4cc;
        };
        MorphsManager.prototype.enableMorphVBOs = function () {
            var i, k, len, ref, w;
            ref = this.morphWeights;
            for (i = k = 0, len = ref.length; k < len; i = ++k) {
                w = ref[i];
                if (!(w !== 0)) {
                    continue;
                }
                this.posVBOs[i].enableAttrib();
                this.normVBOs[i].enableAttrib();
            }
            return void 0;
        };
        MorphsManager.prototype.disableMorphVBOs = function () {
            var i, k, len, ref, w;
            ref = this.morphWeights;
            for (i = k = 0, len = ref.length; k < len; i = ++k) {
                w = ref[i];
                if (!(w !== 0)) {
                    continue;
                }
                this.posVBOs[i].disableAttrib();
                this.normVBOs[i].disableAttrib();
            }
            return void 0;
        };
        MorphsManager.prototype.getMorphWeights = function () {
            return this.morphWeights;
        };
        MorphsManager.prototype.createCPUVertexBuffers = function (nv) {
            var nV3;
            this.nVertices = nv;
            nV3 = nv * 3;
            this.zeroMorphBuf = new Float32Array(nV3);
            this.multiMorphOffsetBuf = new Float32Array(nV3);
            return this.multiMorphNormBuf = new Float32Array(nV3);
        };
        MorphsManager.prototype.createGLVBOs = function (gl, getAttrLoc) {
            var abcd, k, len, ref, setVBO;
            this.gl = gl;
            this.posVBOs = [];
            this.normVBOs = [];
            setVBO = (function (_this) {
                return function (vbos, id, buf) {
                    return vbos.push(VBO.makeDyn(gl, 3, buf, getAttrLoc(id)));
                };
            })(this);
            ref = this.MORPH_TAGS;
            for (k = 0, len = ref.length; k < len; k++) {
                abcd = ref[k];
                setVBO(this.posVBOs, "MorphPos" + abcd, this.zeroMorphBuf);
                setVBO(this.normVBOs, "MorphNorm" + abcd, this.zeroMorphBuf);
            }
            return void 0;
        };
        MorphsManager.prototype.makeVertexArrays = function (vDupIndices, globalHeadRot) {
            var NMT, NV, NV3, NVND, d, dupLists, i, k, l, len, len1, m, mtgt, n, ref, ref1, t, v;
            NV = this.nVertices;
            NV3 = 3 * NV;
            this.nVerticesNoDups = NVND = NV - vDupIndices.length;
            NMT = this.morphTargets.length;
            dupLists = (function () {
                var k, ref, results;
                results = [];
                for (i = k = 0, ref = NVND; 0 <= ref ? k < ref : k > ref; i = 0 <= ref ? ++k : --k) {
                    results.push([]);
                }
                return results;
            })();
            for (d = k = 0, len = vDupIndices.length; k < len; d = ++k) {
                v = vDupIndices[d];
                dupLists[v].push(NVND + d);
            }
            ref = this.morphTargets;
            for (m = l = 0, len1 = ref.length; l < len1; m = ++l) {
                mtgt = ref[m];
                mtgt.makeVertexArraySegments(NV, NVND, dupLists, globalHeadRot.xyzw);
            }
            this.morphAlloc = [];
            this.morphWeights = [];
            this.vbosUsage = [];
            for (t = n = 0, ref1 = this.MORPH_TAGS.length; 0 <= ref1 ? n < ref1 : n > ref1; t = 0 <= ref1 ? ++n : --n) {
                this.morphAlloc.push(-1);
                this.morphWeights.push(0);
                this.vbosUsage.push([{
                    base: -1,
                    size: 0
                }, {
                    base: -1,
                    size: 0
                }]);
            }
            return void 0;
        };
        MorphsManager.prototype.setGLDataForDraw = function (currentMorphs) {
            var activeMorphs, k, len, m, morph, t;
            this.prevMorphAlloc = this.morphAlloc;
            this.morphWeights = (function () {
                var k, ref, results;
                results = [];
                for (t = k = 0, ref = this.MORPH_TAGS.length; 0 <= ref ? k < ref : k > ref; t = 0 <= ref ? ++k : --k) {
                    results.push(0);
                }
                return results;
            }).call(this);
            activeMorphs = [];
            for (k = 0, len = currentMorphs.length; k < len; k++) {
                morph = currentMorphs[k];
                if (!((morph.getAmount()) !== 0)) {
                    continue;
                }
                m = this.mtIndicesBy4CC[morph.getName()];
                activeMorphs.push([m, morph.getAmount()]);
            }
            if (activeMorphs.length !== 0) {
                this.allocGLMorphSlots(activeMorphs);
                this.morphDataToGPU();
            }
            return void 0;
        };
        MorphsManager.prototype.allocGLMorphSlots = function (activeMorphs) {
            var NMT, a, aMph, aa, assignSlot, getFreeSlot, i, iMulti, k, l, len, multi, nUnalloc, nUsed, pm, ref, ref1, t, uLimit;
            NMT = this.MORPH_TAGS.length;
            this.morphAlloc = [];
            this.morphAllocIsNew = [];
            for (t = k = 0, ref = NMT; 0 <= ref ? k < ref : k > ref; t = 0 <= ref ? ++k : --k) {
                this.morphAlloc.push(-1);
                this.morphAllocIsNew.push(false);
            }
            nUsed = 0;
            nUnalloc = activeMorphs.length;
            uLimit = (activeMorphs.length <= NMT ? NMT : NMT - 1);
            assignSlot = (function (_this) {
                return function (i, aMph) {
                    _this.morphAlloc[i] = aMph[0];
                    _this.morphWeights[i] = aMph[1];
                    ++nUsed;
                    --nUnalloc;
                    return aMph[0] = -1;
                };
            })(this);
            ref1 = this.prevMorphAlloc;
            for (i = l = 0, len = ref1.length; l < len; i = ++l) {
                pm = ref1[i];
                if (!(0 <= pm && nUsed !== uLimit)) {
                    continue;
                }
                a = 0;
                aa = activeMorphs.length;
                while (a !== aa) {
                    if (activeMorphs[a][0] === pm) {
                        aa = a;
                    } else {
                        ++a;
                    }
                }
                if (a !== activeMorphs.length) {
                    assignSlot(i, activeMorphs[a]);
                }
            }
            getFreeSlot = (function (_this) {
                return function () {
                    i = 0;
                    while (0 <= _this.morphAlloc[i]) {
                        ++i;
                    }
                    return i;
                };
            })(this);
            multi = [];
            iMulti = -1;
            a = 0;
            while (nUnalloc !== 0) {
                if (nUsed !== uLimit) {
                    while (activeMorphs[a][0] < 0) {
                        ++a;
                    }
                    i = getFreeSlot();
                    this.morphAllocIsNew[i] = true;
                    assignSlot(i, activeMorphs[a]);
                    ++a;
                } else {
                    multi = (function () {
                        var len1, n, results;
                        results = [];
                        for (n = 0, len1 = activeMorphs.length; n < len1; n++) {
                            aMph = activeMorphs[n];
                            if (0 <= aMph[0]) {
                                results.push(aMph);
                            }
                        }
                        return results;
                    })();
                    iMulti = getFreeSlot();
                    this.morphWeights[iMulti] = 1;
                    ++nUsed;
                    nUnalloc -= multi.length;
                }
            }
            this.iMulti = iMulti;
            this.multiMorphs = multi;
            return void 0;
        };
        MorphsManager.prototype.dirtyRangesForVBOClean = function (usedrange, newrange) {
            var hi, k, len, limslist, lo, ref, results, uhi, ulo;
            ulo = usedrange.base;
            uhi = ulo + usedrange.size;
            lo = newrange.base;
            hi = lo + newrange.size;
            if (ulo < lo && hi < uhi) {
                limslist = [
                    [ulo, lo],
                    [hi, uhi]
                ];
            } else if (lo <= ulo && uhi <= hi) {
                limslist = [];
            } else {
                if (uhi <= hi) {
                    limslist = [
                        [ulo, (lo < uhi ? lo : uhi)]
                    ];
                }
                if (lo <= ulo) {
                    limslist = [
                        [(ulo < hi ? hi : ulo), uhi]
                    ];
                }
            }
            results = [];
            for (k = 0, len = limslist.length; k < len; k++) {
                ref = limslist[k], lo = ref[0], hi = ref[1];
                results.push({
                    base: lo,
                    size: hi - lo
                });
            }
            return results;
        };
        MorphsManager.prototype.cleanMorphVBOs = function (i, m, newsegs) {
            var cleanBuf, dhi, dlo, dr, drngs, j, k, l, len, len1, newrng, ref, usedrng, vbou_i;
            vbou_i = this.vbosUsage[i];
            ref = [0, 1];
            for (k = 0, len = ref.length; k < len; k++) {
                j = ref[k];
                usedrng = vbou_i[j];
                newrng = newsegs[j].range;
                if (usedrng.size === 0 || newrng.size === 0) {} else {
                    drngs = this.dirtyRangesForVBOClean(usedrng, newrng);
                    for (l = 0, len1 = drngs.length; l < len1; l++) {
                        dr = drngs[l];
                        dlo = dr.base;
                        dhi = dlo + dr.size;
                        cleanBuf = this.zeroMorphBuf.subarray(3 * dlo, 3 * dhi);
                        this.posVBOs[i].uploadPartialData(dlo, cleanBuf);
                        this.normVBOs[i].uploadPartialData(dlo, cleanBuf);
                    }
                }
                if (newrng.size !== 0) {
                    usedrng.base = newrng.base;
                    usedrng.size = newrng.size;
                }
            }
            return void 0;
        };
        MorphsManager.prototype.setMorphVBOs = function (i, mVtxSegs) {
            var bufs, j, k, len, mvsegs, ref, rng;
            ref = [0, 1];
            for (k = 0, len = ref.length; k < len; k++) {
                j = ref[k];
                mvsegs = mVtxSegs[j];
                rng = mvsegs.range;
                bufs = mvsegs.buffers;
                if (rng.size !== 0) {
                    this.posVBOs[i].uploadPartialData(rng.base, bufs.pos);
                    this.normVBOs[i].uploadPartialData(rng.base, bufs.norm);
                }
            }
            return void 0;
        };
        MorphsManager.prototype.generateMultiMorphsSegsDescs = function () {
            var NV, NVND, hi, j, k, l, len, len1, limits, lo, lohi, m, mmrng, mweight, ref, ref1, ref2, ref3, segs, segsj, shi, slo, srng, ssz, wSegs, wSegsList, wSegs_j, wSegsj;
            NV = this.nVertices;
            NVND = this.nVerticesNoDups;
            limits = [
                [NVND, 0],
                [NV, NVND]
            ];
            wSegsList = [];
            ref = this.multiMorphs;
            for (k = 0, len = ref.length; k < len; k++) {
                ref1 = ref[k], m = ref1[0], mweight = ref1[1];
                segs = this.morphTargets[m].getVertexSegments();
                wSegs = [];
                ref2 = [0, 1];
                for (l = 0, len1 = ref2.length; l < len1; l++) {
                    j = ref2[l];
                    segsj = segs[j];
                    srng = segsj.range;
                    slo = srng.base;
                    ssz = srng.size;
                    shi = slo + ssz;
                    ref3 = lohi = limits[j], lo = ref3[0], hi = ref3[1];
                    wSegs_j = null;
                    if (ssz !== 0) {
                        if (slo < lo) {
                            lohi[0] = slo;
                        }
                        if (hi < shi) {
                            lohi[1] = shi;
                        }
                        wSegsj = {
                            range: segsj.range,
                            buffers: segsj.buffers,
                            weight: mweight
                        };
                    }
                    wSegs.push(wSegsj);
                }
                wSegsList.push(wSegs);
            }
            mmrng = function (lohi) {
                lo = lohi[0], hi = lohi[1];
                if (hi <= lo) {
                    lo = hi = -1;
                }
                return {
                    base: lo,
                    size: hi - lo
                };
            };
            this.mmRanges = (function () {
                var len2, n, results;
                results = [];
                for (n = 0, len2 = limits.length; n < len2; n++) {
                    lohi = limits[n];
                    results.push(mmrng(lohi));
                }
                return results;
            })();
            this.mmWeightedSegsList = wSegsList;
            return void 0;
        };
        MorphsManager.prototype.generateMultiMorphsVBOs = function () {
            var hi, hi3, j, k, k3, l, len, len1, lo, lo3, mmNBuf, mmPBuf, n, nbseg, normbuf, o, pbseg, posbuf, ranges, ref, ref1, ref2, ref3, rng, slo, slo3, ssz, ssz3, wSegs, wSegsList, wSegsj, weight;
            ranges = this.mmRanges;
            wSegsList = this.mmWeightedSegsList;
            mmPBuf = this.multiMorphOffsetBuf;
            mmNBuf = this.multiMorphNormBuf;
            ref = [0, 1];
            for (k = 0, len = ref.length; k < len; k++) {
                j = ref[k];
                rng = ranges[j];
                lo = rng.base;
                hi = lo + rng.size;
                if (lo < hi) {
                    lo3 = 3 * lo;
                    hi3 = 3 * hi;
                    for (k3 = l = ref1 = lo3, ref2 = hi3; ref1 <= ref2 ? l < ref2 : l > ref2; k3 = ref1 <= ref2 ? ++l : --l) {
                        mmPBuf[k3] = 0;
                        mmNBuf[k3] = 0;
                    }
                    for (n = 0, len1 = wSegsList.length; n < len1; n++) {
                        wSegs = wSegsList[n];
                        if (!wSegs[j]) {
                            continue;
                        }
                        wSegsj = wSegs[j];
                        weight = wSegsj.weight;
                        rng = wSegsj.range;
                        slo = rng.base;
                        ssz = rng.size;
                        posbuf = wSegsj.buffers.pos;
                        normbuf = wSegsj.buffers.norm;
                        slo3 = 3 * slo;
                        ssz3 = 3 * ssz;
                        for (k3 = o = 0, ref3 = ssz3; 0 <= ref3 ? o < ref3 : o > ref3; k3 = 0 <= ref3 ? ++o : --o) {
                            mmPBuf[slo3 + k3] += weight * posbuf[k3];
                            mmNBuf[slo3 + k3] += weight * normbuf[k3];
                        }
                    }
                    pbseg = mmPBuf.subarray(lo3, hi3);
                    nbseg = mmNBuf.subarray(lo3, hi3);
                    this.posVBOs[this.iMulti].uploadPartialData(lo, pbseg);
                    this.normVBOs[this.iMulti].uploadPartialData(lo, nbseg);
                }
            }
            return void 0;
        };
        MorphsManager.prototype.morphDataToGPU = function () {
            var GL, GL_A_BUF, i, k, len, m, mmrng, mmvsegs, mvsegs, ref;
            GL = this.gl;
            GL_A_BUF = GL.ARRAY_BUFFER;
            ref = this.morphAlloc;
            for (i = k = 0, len = ref.length; k < len; i = ++k) {
                m = ref[i];
                if (!(0 <= m && this.morphAllocIsNew[i])) {
                    continue;
                }
                mvsegs = this.morphTargets[m].getVertexSegments();
                this.cleanMorphVBOs(i, m, mvsegs);
                this.setMorphVBOs(i, mvsegs);
            }
            if (0 <= this.iMulti) {
                this.generateMultiMorphsSegsDescs();
                mmvsegs = (function () {
                    var l, len1, ref1, results;
                    ref1 = this.mmRanges;
                    results = [];
                    for (l = 0, len1 = ref1.length; l < len1; l++) {
                        mmrng = ref1[l];
                        results.push({
                            range: mmrng
                        });
                    }
                    return results;
                }).call(this);
                this.cleanMorphVBOs(this.iMulti, -1, mmvsegs);
                this.generateMultiMorphsVBOs();
            }
            return void 0;
        };
        return MorphsManager;
    })();
    cwaenv.add(MorphsManager, "MorphsManager");
}).call(this);