<commit_before>/**
 * Generate ACII art from image or video
 *
 * @module   Schwartz
 * @version  1.9.2
 *
 * @author   Zaytsev Alexandr
 *
 * @example
 *    // Exapmple with image
 *    var
 *        body    = document.getElementsByTagName('body')[0],
 *        outDiv  = document.createElement('div'),
 *        schwartz = new Schwartz({
 *            detail: 60
 *        });
 *    // end of vars
 *
 *    body.appendChild(outDiv);
 *    schwartz.generateFromImage('/path/to/img.jpg');
 *
 *
 *    // Example with video
 *    var
 *        body    = document.getElementsByTagName('body')[0],
 *        video   = document.getElementsByTagName('video')[0],
 *        outDiv  = document.createElement('div'),
 *
 *        schwartz = new Schwartz({
 *            inverse: true,
 *            detail: 60
 *        });
 *    // end of vars
 *
 *
 *    body.appendChild(outDiv);
 *    schwartz.generateFromVideo(video);
 */
!function( window, module ) {
    'use strict';

    var
        Schwartz = module();
        // end of vars

    // AMD
    if ( typeof define === 'function' && define.amd ) {
        define('Schwartz', [], function() {
            return Schwartz;
        });

    // YM Modules
    } else if ( typeof modules !== 'undefined' && typeof modules.define === 'function' ) {
        modules.define('Schwartz', [], function( provide ) {
            provide(Schwartz);
        });

    // Browser global
    } else {
        window.Schwartz = Schwartz;
    }
}( this, function() {
    'use strict';

    var
        Schwartz = (function() {
            var
                /**
                 * @const
                 */
                DEFAULT_DETAIL = 50,

                DEFAULT_INVERSE = false,

                /**
                 * After parse image callback
                 *
                 * @memberOf    module:Schwartz~Schwartz
                 * @callback    parseImageCallback
                 *
                 * @param       {Object[][]}  res       Art strings by line
                 * @param       {Number}      res.r     Red channel average
                 * @param       {Number}      res.g     Green channel average
                 * @param       {Number}      res.b     Blue channel average
                 * @param       {Number}      res.a     Alpha channel average
                 * @param       {Number}      res.c     Composite average
                 * @param       {Number}      res.sym   Symbol
                 */

                /**
                 * @memberOf     module:Schwartz~
                 *
                 * @constructs   Schwartz
                 *
                 * @param        {Object}               [options]
                 * @param        {Boolean}              [options.inverse=false]
                 * @param        {Number}               [options.detail=50]
                 * @param        {parseImageCallback}   [options.render]
                 */
                Schwartz = function Schwartz( options ) {
                    // enforces new
                    if ( !( this instanceof Schwartz ) ) {
                        return new Schwartz(options);
                    }

                    // constructor body
                    this.canvas        = document.createElement('canvas');
                    this.imgObj        = new Image();
                    this.c             = this.canvas.getContext('2d');

                    this.inverse       = options.inverse || DEFAULT_INVERSE;
                    this.callback      = options.render || false;

                    /**
                     * Default symbols
                     *
                     * @memberOf    module:Schwartz~Schwartz
                     * @member      loadImage
                     * @private
                     *
                     * @type        {Array}
                     */
                    this.charSet = [' ', '.', ',', ':', ';', '*', '|', '~', 'I', '1', '?', '7', '>', 'Y', 'F', '4', 'V', '#', '2', '9', '6', '8', '%', 'N', 'B', 'Q', 'M', '@', 'W'];

                    if ( options.detail ) {
                        this.setDetail(options.detail);
                    } else {
                        this.detail = DEFAULT_DETAIL;
                    }

                    this.charSet = ( this.inverse ) ? this.charSet : this.charSet.reverse();
                },

                /**
                 * ==============================
                 * ========PRIVATE METHODS=======
                 * ==============================
                 */

                /**
                 * Validate numbers
                 *
                 * @memberOf    module:Schwartz~Schwartz
                 * @method      isNumber
                 * @private
                 *
                 * @param       {*}         n
                 *
                 * @return      {Boolean}
                 */
                isNumber = function( n ) {
                    return !isNaN(parseFloat(n)) && isFinite(n);
                },

                /**
                 * After load image callback
                 *
                 * @memberOf    module:Schwartz~Schwartz
                 * @callback    loadImageCallback
                 *
                 * @param       {Object}    imageData
                 */

                /**
                 * @memberOf    module:Schwartz~Schwartz
                 * @method      loadImage
                 * @private
                 *
                 * @this        {Schwartz}
                 *
                 * @param       {String}                src
                 * @param       {loadImageCallback}     callback
                 */
                loadImage = function( src, callback ) {
                    var
                        self = this,

                        imageLoaded = function( ev ) {
                            var
                                imgW = self.imgObj.width,
                                imgH = self.imgObj.height,
                                img  = ev.target,
                                imageData;
                            // end of vars

                            self.canvas.width  = imgW;
                            self.canvas.height = imgH;

                            self.c.drawImage(img, 0, 0);
                            imageData = self.c.getImageData(0, 0, imgW, imgH);
                            callback.call(self, imageData);
                        };
                        // end of vars

                        this.imgObj.onload = imageLoaded;
                        this.imgObj.crossOrigin = 'use-credentials';
                        this.imgObj.src = src;
                },

                /**
                 * @memberOf    module:Schwartz~Schwartz
                 * @method      getSymbol
                 * @private
                 *
                 * @this        {Schwartz}
                 *
                 * @param       {Number}    val     Gray scale value
                 */
                getSymbol = function( val ) {
                    var
                        asciival;
                    // end of vars

                    // console.info(val);

                    if ( isNaN(val) ) {
                        asciival = this.charSet[this.charSet.length-1];
                    } else {
                        asciival = this.charSet[(this.charSet.length * val / 256 ) | 0];
                    }

                    return asciival;
                },

                /**
                 * @memberOf    module:Schwartz~Schwartz
                 * @method      getPixelGroupAvg
                 * @private
                 *
                 * @this        {Schwartz}
                 *
                 * @param       {Object}    options
                 * @param       {Object}    options.pixels              Canvas image data
                 * @param       {Number}    options.x                   Inital x position on the canvas
                 * @param       {Number}    options.y                   Inital y position on the canvas
                 * @param       {Number}    options.stepX
                 * @param       {Number}    options.stepY
                 *
                 * @return      {Object}    res
                 * @return      {Number}    res.r                       Red channel average
                 * @return      {Number}    res.g                       Green channel average
                 * @return      {Number}    res.b                       Blue channel average
                 * @return      {Number}    res.a                       Alpha channel average
                 * @return      {Number}    res.c                       Composite average
                 */
                getPixelGroupAvg = function( options ) {
                    var
                        imgPixels = options.pixels,
                        initX     = options.x,
                        initY     = options.y,
                        stepX     = options.stepX,
                        stepY     = options.stepY,

                        count     = 0,
                        sumR      = 0,
                        sumG      = 0,
                        sumB      = 0,
                        sumA      = 0,
                        sumC      = 0,

                        r, g, b, a, c,

                        x, y,
                        index;
                    // end of vars

                    for ( x = initX; x < initX + stepX; x++ ) {
                        for ( y = initY; y < initY + stepY; y++ ) {
                            index = (y * 4) * imgPixels.width + x * 4;

                            r = imgPixels.data[index];
                            g = imgPixels.data[index + 1];
                            b = imgPixels.data[index + 2];
                            a = imgPixels.data[index + 3];
                            c = (imgPixels.data[index] + imgPixels.data[index + 1] + imgPixels.data[index + 2]) / 3;

                            if ( !isNaN(r) && !isNaN(g) && !isNaN(b) && !isNaN(a) && !isNaN(c) ) {
                                sumR += r;
                                sumG += g;
                                sumB += b;
                                sumA += a;
                                sumC += c;
                                count++;
                            }
                        }
                    }

                    return {
                        r: (sumR/count) | 0,
                        g: (sumG/count) | 0,
                        b: (sumB/count) | 0,
                        a: (sumA/count) | 0,
                        c: (sumC/count) | 0
                    };
                },

                /**
                 * @memberOf    module:Schwartz~Schwartz
                 * @method      parseImage
                 * @private
                 *
                 * @this        {Schwartz}
                 *
                 * @param       {Object}    imageData   Canvas image data
                 */
                parseImage = function( imageData ) {
                    var
                        imgW = imageData.width,
                        imgH = imageData.height,
                        art  = [],

                        strChar, str, symbol,
                        p, x, y, avg;
                    //end of vars

                    this.dimX = Math.round((imgW * 100 / this.detail)/200);
                    this.dimY = Math.round((imgH * 100 / this.detail)/200);

                    this.dimX = ( this.dimX < 1) ? 1 : this.dimX;
                    this.dimY = ( this.dimY < 1) ? 1 : this.dimY;

                    for ( y = 0; y < imgH; ) {
                        str     = [];
                        strChar = '';

                        for ( x = 0; x < imgW; ) {
                            avg = getPixelGroupAvg({
                                pixels: imageData,
                                x: x,
                                y: y,
                                stepX: this.dimX,
                                stepY: this.dimY
                            });

                            symbol  = getSymbol.call(this, avg.c);
                            strChar += symbol;
                            avg.sym = symbol;

                            str.push(avg)

                            x += this.dimX;
                        }

                        art.push(str);

                        y += this.dimY;
                    }

                    if ( typeof this.callback !== 'undefined' && typeof this.callback === 'function' ) {
                        this.callback(art);
                    }
                },

                /**
                 * @memberOf    module:Schwartz~Schwartz
                 * @method      videoTimerCallback
                 * @private
                 *
                 * @this        {Schwartz}
                 */
                videoTimerCallback = function() {
                    var
                        videoWidth  = this.video.width,
                        videoHeight = this.video.height,
                        self        = this,
                        imageData;
                    // end of vars

                    if ( this.video.paused || this.video.ended ) {
                        return;
                    }

                    this.canvas.width  = videoWidth;
                    this.canvas.height = videoHeight;

                    this.c.drawImage(this.video, 0, 0, videoWidth, videoHeight);
                    imageData = this.c.getImageData(0, 0, videoWidth, videoHeight);
                    parseImage.call(this, imageData);

                    setTimeout(function () {
                        videoTimerCallback.call(self);
                    }, 0);
                };
            // end of vars

            /**
             * ==============================
             * ========PUBLIC METHODS========
             * ==============================
             */

            /**
             * @memberOf    module:Schwartz~Schwartz
             * @method      setDetail
             * @public
             *
             * @param       {Number}    n   Level of detail
             */
            Schwartz.prototype.setDetail = function( n ) {
                var
                    newDetail;
                // end of vars

                // validate number
                if ( isNumber(n) ) {
                    newDetail = parseInt(n, 10);

                    this.detail = ( newDetail < 1 ) ? 1 : ( newDetail > 100 ) ? 100 : newDetail;
                } else {
                    this.detail = DEFAULT_DETAIL;
                }

                return;
            };

            /**
             * @memberOf    module:Schwartz~Schwartz
             * @method      setCharSet
             * @public
             *
             * @param       {String}    str
             */
            Schwartz.prototype.setCharSet = function( str ) {
                var
                    // create local canvas
                    canvas = document.createElement('canvas'),
                    c      = canvas.getContext('2d'),
                    all    = [],

                    i, avg, imgPixels;
                // end of vars

                canvas.width  = 10;
                canvas.height = 20;
                c.fillStyle   = '#000';
                c.font        = '18px monospace';
                this.charSet  = [];

                for ( i = 0; i < str.length; i++ ) {
                    // reset canvas
                    canvas.width = canvas.width;

                    c.fillText(str[i], 0, 18);
                    imgPixels = c.getImageData(0, 0, canvas.width, canvas.height);

                    avg = getPixelGroupAvg({
                        pixels: imgPixels,
                        x: 0,
                        y: 0,
                        stepX: canvas.width,
                        stepY: canvas.height
                    });

                    all[avg.a] = str[i];
                }

                for ( i = 0; i < all.length; i++ ) {
                    if ( all[i] ) {
                        this.charSet.push(all[i]);
                    }
                }

                this.charSet = ( this.inverse ) ? this.charSet : this.charSet.reverse();
            };

            /**
             * @memberOf    module:Schwartz~Schwartz
             * @method      loadImg
             * @public
             *
             * @param       {String} src    Image source URI
             */
            Schwartz.prototype.generateFromImage = function( src ) {
                loadImage.call(this, src, parseImage);
            };

            /**
             * Inverse image
             *
             * @memberOf    module:Schwartz~Schwartz
             * @method      inverseImage
             * @public
             */
            Schwartz.prototype.inverseImage = function() {
                this.charSet.reverse();
            };

            /**
             * @memberOf    module:Schwartz~Schwartz
             * @method      loadImg
             * @public
             *
             * @param       {DOM Element}   video    Video DOM element
             */
            Schwartz.prototype.generateFromVideo = function( video ) {
                var
                    self = this;
                // end of vars

                this.video = video;

                video.addEventListener('play', function() {
                    videoTimerCallback.call(self);
                }, false);
            };

            return Schwartz;
        }());
    // end of vars

    return Schwartz;
});
<commit_msg>Bug fix with re-generate image in Chrome.<commit_after>/**
 * Generate ACII art from image or video
 *
 * @module   Schwartz
 * @version  1.9.3
 *
 * @author   Zaytsev Alexandr
 *
 * @example
 *    // Exapmple with image
 *    var
 *        body    = document.getElementsByTagName('body')[0],
 *        outDiv  = document.createElement('div'),
 *        schwartz = new Schwartz({
 *            detail: 60
 *        });
 *    // end of vars
 *
 *    body.appendChild(outDiv);
 *    schwartz.generateFromImage('/path/to/img.jpg');
 *
 *
 *    // Example with video
 *    var
 *        body    = document.getElementsByTagName('body')[0],
 *        video   = document.getElementsByTagName('video')[0],
 *        outDiv  = document.createElement('div'),
 *
 *        schwartz = new Schwartz({
 *            inverse: true,
 *            detail: 60
 *        });
 *    // end of vars
 *
 *
 *    body.appendChild(outDiv);
 *    schwartz.generateFromVideo(video);
 */
!function( window, module ) {
    'use strict';

    var
        Schwartz = module();
        // end of vars

    // AMD
    if ( typeof define === 'function' && define.amd ) {
        define('Schwartz', [], function() {
            return Schwartz;
        });

    // YM Modules
    } else if ( typeof modules !== 'undefined' && typeof modules.define === 'function' ) {
        modules.define('Schwartz', [], function( provide ) {
            provide(Schwartz);
        });

    // Browser global
    } else {
        window.Schwartz = Schwartz;
    }
}( this, function() {
    'use strict';

    var
        Schwartz = (function() {
            var
                /**
                 * @const
                 */
                DEFAULT_DETAIL = 50,

                DEFAULT_INVERSE = false,

                /**
                 * After parse image callback
                 *
                 * @memberOf    module:Schwartz~Schwartz
                 * @callback    parseImageCallback
                 *
                 * @param       {Object[][]}  res       Art strings by line
                 * @param       {Number}      res.r     Red channel average
                 * @param       {Number}      res.g     Green channel average
                 * @param       {Number}      res.b     Blue channel average
                 * @param       {Number}      res.a     Alpha channel average
                 * @param       {Number}      res.c     Composite average
                 * @param       {Number}      res.sym   Symbol
                 */

                /**
                 * @memberOf     module:Schwartz~
                 *
                 * @constructs   Schwartz
                 *
                 * @param        {Object}               [options]
                 * @param        {Boolean}              [options.inverse=false]
                 * @param        {Number}               [options.detail=50]
                 * @param        {parseImageCallback}   [options.render]
                 */
                Schwartz = function Schwartz( options ) {
                    // enforces new
                    if ( !( this instanceof Schwartz ) ) {
                        return new Schwartz(options);
                    }

                    // constructor body
                    this.canvas        = document.createElement('canvas');
                    this.imgObj        = new Image();
                    this.c             = this.canvas.getContext('2d');

                    this.inverse       = options.inverse || DEFAULT_INVERSE;
                    this.callback      = options.render || false;

                    /**
                     * Default symbols
                     *
                     * @memberOf    module:Schwartz~Schwartz
                     * @member      loadImage
                     * @private
                     *
                     * @type        {Array}
                     */
                    this.charSet = [' ', '.', ',', ':', ';', '*', '|', '~', 'I', '1', '?', '7', '>', 'Y', 'F', '4', 'V', '#', '2', '9', '6', '8', '%', 'N', 'B', 'Q', 'M', '@', 'W'];

                    if ( options.detail ) {
                        this.setDetail(options.detail);
                    } else {
                        this.detail = DEFAULT_DETAIL;
                    }

                    this.charSet = ( this.inverse ) ? this.charSet : this.charSet.reverse();
                },

                /**
                 * ==============================
                 * ========PRIVATE METHODS=======
                 * ==============================
                 */

                /**
                 * Validate numbers
                 *
                 * @memberOf    module:Schwartz~Schwartz
                 * @method      isNumber
                 * @private
                 *
                 * @param       {*}         n
                 *
                 * @return      {Boolean}
                 */
                isNumber = function( n ) {
                    return !isNaN(parseFloat(n)) && isFinite(n);
                },

                /**
                 * After load image callback
                 *
                 * @memberOf    module:Schwartz~Schwartz
                 * @callback    loadImageCallback
                 *
                 * @param       {Object}    imageData
                 */

                /**
                 * @memberOf    module:Schwartz~Schwartz
                 * @method      loadImage
                 * @private
                 *
                 * @this        {Schwartz}
                 *
                 * @param       {String}                src
                 * @param       {loadImageCallback}     callback
                 */
                loadImage = function( src, callback ) {
                    var
                        imgObj = new Image(),
                        self   = this,

                        imageLoaded = function( ev ) {
                            var
                                imgW = imgObj.width,
                                imgH = imgObj.height,
                                img  = ev.target,
                                imageData;
                            // end of vars

                            self.canvas.width  = imgW;
                            self.canvas.height = imgH;

                            self.c.drawImage(img, 0, 0);
                            imageData = self.c.getImageData(0, 0, imgW, imgH);
                            callback.call(self, imageData);
                        };
                        // end of vars

                        imgObj.onload      = imageLoaded;
                        imgObj.crossOrigin = 'use-credentials';
                        imgObj.src         = src;
                },

                /**
                 * @memberOf    module:Schwartz~Schwartz
                 * @method      getSymbol
                 * @private
                 *
                 * @this        {Schwartz}
                 *
                 * @param       {Number}    val     Gray scale value
                 */
                getSymbol = function( val ) {
                    var
                        asciival;
                    // end of vars

                    // console.info(val);

                    if ( isNaN(val) ) {
                        asciival = this.charSet[this.charSet.length-1];
                    } else {
                        asciival = this.charSet[(this.charSet.length * val / 256 ) | 0];
                    }

                    return asciival;
                },

                /**
                 * @memberOf    module:Schwartz~Schwartz
                 * @method      getPixelGroupAvg
                 * @private
                 *
                 * @this        {Schwartz}
                 *
                 * @param       {Object}    options
                 * @param       {Object}    options.pixels              Canvas image data
                 * @param       {Number}    options.x                   Inital x position on the canvas
                 * @param       {Number}    options.y                   Inital y position on the canvas
                 * @param       {Number}    options.stepX
                 * @param       {Number}    options.stepY
                 *
                 * @return      {Object}    res
                 * @return      {Number}    res.r                       Red channel average
                 * @return      {Number}    res.g                       Green channel average
                 * @return      {Number}    res.b                       Blue channel average
                 * @return      {Number}    res.a                       Alpha channel average
                 * @return      {Number}    res.c                       Composite average
                 */
                getPixelGroupAvg = function( options ) {
                    var
                        imgPixels = options.pixels,
                        initX     = options.x,
                        initY     = options.y,
                        stepX     = options.stepX,
                        stepY     = options.stepY,

                        count     = 0,
                        sumR      = 0,
                        sumG      = 0,
                        sumB      = 0,
                        sumA      = 0,
                        sumC      = 0,

                        r, g, b, a, c,

                        x, y,
                        index;
                    // end of vars

                    for ( x = initX; x < initX + stepX; x++ ) {
                        for ( y = initY; y < initY + stepY; y++ ) {
                            index = (y * 4) * imgPixels.width + x * 4;

                            r = imgPixels.data[index];
                            g = imgPixels.data[index + 1];
                            b = imgPixels.data[index + 2];
                            a = imgPixels.data[index + 3];
                            c = (imgPixels.data[index] + imgPixels.data[index + 1] + imgPixels.data[index + 2]) / 3;

                            if ( !isNaN(r) && !isNaN(g) && !isNaN(b) && !isNaN(a) && !isNaN(c) ) {
                                sumR += r;
                                sumG += g;
                                sumB += b;
                                sumA += a;
                                sumC += c;
                                count++;
                            }
                        }
                    }

                    return {
                        r: (sumR/count) | 0,
                        g: (sumG/count) | 0,
                        b: (sumB/count) | 0,
                        a: (sumA/count) | 0,
                        c: (sumC/count) | 0
                    };
                },

                /**
                 * @memberOf    module:Schwartz~Schwartz
                 * @method      parseImage
                 * @private
                 *
                 * @this        {Schwartz}
                 *
                 * @param       {Object}    imageData   Canvas image data
                 */
                parseImage = function( imageData ) {
                    var
                        imgW = imageData.width,
                        imgH = imageData.height,
                        art  = [],

                        strChar, str, symbol,
                        p, x, y, avg;
                    //end of vars

                    this.dimX = Math.round((imgW * 100 / this.detail)/200);
                    this.dimY = Math.round((imgH * 100 / this.detail)/200);

                    this.dimX = ( this.dimX < 1) ? 1 : this.dimX;
                    this.dimY = ( this.dimY < 1) ? 1 : this.dimY;

                    for ( y = 0; y < imgH; ) {
                        str     = [];
                        strChar = '';

                        for ( x = 0; x < imgW; ) {
                            avg = getPixelGroupAvg({
                                pixels: imageData,
                                x: x,
                                y: y,
                                stepX: this.dimX,
                                stepY: this.dimY
                            });

                            symbol  = getSymbol.call(this, avg.c);
                            strChar += symbol;
                            avg.sym = symbol;

                            str.push(avg)

                            x += this.dimX;
                        }

                        art.push(str);

                        y += this.dimY;
                    }

                    if ( typeof this.callback !== 'undefined' && typeof this.callback === 'function' ) {
                        this.callback(art);
                    }
                },

                /**
                 * @memberOf    module:Schwartz~Schwartz
                 * @method      videoTimerCallback
                 * @private
                 *
                 * @this        {Schwartz}
                 */
                videoTimerCallback = function() {
                    var
                        videoWidth  = this.video.width,
                        videoHeight = this.video.height,
                        self        = this,
                        imageData;
                    // end of vars

                    if ( this.video.paused || this.video.ended ) {
                        return;
                    }

                    this.canvas.width  = videoWidth;
                    this.canvas.height = videoHeight;

                    this.c.drawImage(this.video, 0, 0, videoWidth, videoHeight);
                    imageData = this.c.getImageData(0, 0, videoWidth, videoHeight);
                    parseImage.call(this, imageData);

                    setTimeout(function () {
                        videoTimerCallback.call(self);
                    }, 0);
                };
            // end of vars

            /**
             * ==============================
             * ========PUBLIC METHODS========
             * ==============================
             */

            /**
             * @memberOf    module:Schwartz~Schwartz
             * @method      setDetail
             * @public
             *
             * @param       {Number}    n   Level of detail
             */
            Schwartz.prototype.setDetail = function( n ) {
                var
                    newDetail;
                // end of vars

                // validate number
                if ( isNumber(n) ) {
                    newDetail = parseInt(n, 10);

                    this.detail = ( newDetail < 1 ) ? 1 : ( newDetail > 100 ) ? 100 : newDetail;
                } else {
                    this.detail = DEFAULT_DETAIL;
                }

                return;
            };

            /**
             * @memberOf    module:Schwartz~Schwartz
             * @method      setCharSet
             * @public
             *
             * @param       {String}    str
             */
            Schwartz.prototype.setCharSet = function( str ) {
                var
                    // create local canvas
                    canvas = document.createElement('canvas'),
                    c      = canvas.getContext('2d'),
                    all    = [],

                    i, avg, imgPixels;
                // end of vars

                canvas.width  = 10;
                canvas.height = 20;
                c.fillStyle   = '#000';
                c.font        = '18px monospace';
                this.charSet  = [];

                for ( i = 0; i < str.length; i++ ) {
                    // reset canvas
                    canvas.width = canvas.width;

                    c.fillText(str[i], 0, 18);
                    imgPixels = c.getImageData(0, 0, canvas.width, canvas.height);

                    avg = getPixelGroupAvg({
                        pixels: imgPixels,
                        x: 0,
                        y: 0,
                        stepX: canvas.width,
                        stepY: canvas.height
                    });

                    all[avg.a] = str[i];
                }

                for ( i = 0; i < all.length; i++ ) {
                    if ( all[i] ) {
                        this.charSet.push(all[i]);
                    }
                }

                this.charSet = ( this.inverse ) ? this.charSet : this.charSet.reverse();
            };

            /**
             * @memberOf    module:Schwartz~Schwartz
             * @method      loadImg
             * @public
             *
             * @param       {String} src    Image source URI
             */
            Schwartz.prototype.generateFromImage = function( src ) {
                loadImage.call(this, src, parseImage);
            };

            /**
             * Inverse image
             *
             * @memberOf    module:Schwartz~Schwartz
             * @method      inverseImage
             * @public
             */
            Schwartz.prototype.inverseImage = function() {
                this.charSet.reverse();
            };

            /**
             * @memberOf    module:Schwartz~Schwartz
             * @method      loadImg
             * @public
             *
             * @param       {DOM Element}   video    Video DOM element
             */
            Schwartz.prototype.generateFromVideo = function( video ) {
                var
                    self = this;
                // end of vars

                this.video = video;

                video.addEventListener('play', function() {
                    videoTimerCallback.call(self);
                }, false);
            };

            return Schwartz;
        }());
    // end of vars

    return Schwartz;
});
<|endoftext|>


<commit_before>var CONFIG_INDEXPAGE = "index.xhtml";
var CONFIG_PAGETITLE = "XML3D Motion - Interaction";

var CATEGORY_LIST = {
    unknown : { name : "???" },
    widgets: { name: "Widgets" },
    utils: { name: "Utilities" },
    misc : { name: "Misc" }
};

var EXAMPLE_LIST = [
    // --- Widgets ---
    {
        cat: "widgets",
        name: "TranslateBox",
        href: "tests/test_translatebox.xhtml",
        info: "A widget for translating objects using an interactive cube."
    },
    {
        cat: "widgets",
        name: "UniformScaler",
        href: "tests/test_uniformscaler.xhtml",
        info: "A widget for uniform scaling of objects by dragging small cubes at the corners of the object."
    },
    {
        cat: "widgets",
        name: "SingleAxisRotator",
        href: "tests/test_axisrotator.xhtml",
        info: "A widget for rotating an object around a single axis. It places interactive bars along the axis."
    },

    {
        cat: "widgets",
        name: "RingMenu",
        href: "tests/test_ringmenu.xhtml",
        info: "A widget for selecting objects placed on a ring."
    },
    {
        cat: "widgets",
        name: "TransformBox",
        href: "tests/test_transformbox.xhtml",
        info: "A widget to perform translation, rotation and scaling."
    },
    {
        cat: "widgets",
        name: "RotatorBox",
        href: "tests/test_rotatorbox.xhtml",
        info: "A widget for performing constrained rotation and translation."
    },

    // --- Miscellaneous ---
    {
        cat: "misc",
        name: "TrackBall",
        href: "tests/test_trackball.xhtml",
        info: "A test for the class underlying the .rotatable() plugin."
    },
    {
        cat: "misc",
        name: "Back to Motion Library",
        href: "../index.xhtml",
        info: "Back to the main page of the Motion Library examples."
    },
];

var CURRENT = null;
var CURRENT_CAT = null;

function initPage(){

    var url = window.location.href;
    for(var i in EXAMPLE_LIST){
        if(url.indexOf(EXAMPLE_LIST[i].href) != -1){
            CURRENT = EXAMPLE_LIST[i];
        }
    }
    if(CURRENT)
        CURRENT_CAT = CATEGORY_LIST[CURRENT.cat] || CATEGORY_LIST.unknown;

    window.LINK_PREFIX = "";
    if(CURRENT){
        var idx = 0
        while( (idx = CURRENT.href.indexOf("/", idx)) != -1){
            idx++; window.LINK_PREFIX += "../";
        }
    }

    if(window.PAGE_INDEX){
        buildIndex();
    }

    buildNavigation();

    var header = $('

'
                 + '' + CONFIG_PAGETITLE + '

'
    );
    $(document.body).prepend(header);
    var footer = $('

')
    $(document.body).append(footer);

    if(CURRENT_CAT)
        header.find("h2").text( CURRENT_CAT.name);
    else
        header.find("h2").hide();
    if(CURRENT)
        header.find("h3").text( CURRENT.name);
    else
        header.find("h3").hide();

}

function buildIndex(){
    var content = $("#content");
    var container = $('

');
    var list = buildTestList();
    container.append(list);
    content.append(container);
}

function buildNavigation(){
    var navi = $('

');
    navi.append($("
Navigation
"));

    function adjustNavi(){
        navi.height($(document.body).hasClass("navi_hidden") ? 43 : $(window).height() - 8);
    }

    navi.find("h4").click(function(){
        $(document.body).toggleClass("navi_hidden");
        adjustNavi();
    });
    $(window).bind('resize', adjustNavi);
    adjustNavi();

    var inner = $('

');
    navi.append(inner);
    var naviList = buildTestList();
    inner.append(naviList);

    naviList.prepend($('
Index
'));

    $(document.body).prepend(navi);
}

function buildTestList(){
    var naviList = $('

');

    for(var i in CATEGORY_LIST)
        CATEGORY_LIST[i].examples = [];

    for(var i in EXAMPLE_LIST){
        (CATEGORY_LIST[EXAMPLE_LIST[i].cat] || CATEGORY_LIST.unknown).examples.push(EXAMPLE_LIST[i]);
    }

    for(var catId in CATEGORY_LIST){
        var cat = CATEGORY_LIST[catId];
        if(cat.examples.length == 0)
            continue;
        var header = $('

' + cat.name + '

');
        var list = $('

');
        for(var i in cat.examples){
            var entry = cat.examples[i];
            list.append($('
' + entry.name + '' +
                ( entry.info || "" ) + '
'))

        }
        header.append(list);
        naviList.append(header);
    }

    return naviList;
}

$(function(){
    initPage();
});
<commit_msg>interaction-tests: added tests for behaviors<commit_after>var CONFIG_INDEXPAGE = "index.xhtml";
var CONFIG_PAGETITLE = "XML3D Motion - Interaction";

var CATEGORY_LIST = {
    unknown : { name : "???" },
    widgets: { name: "Widgets" },
    behaviors: { name: "Behaviors" },
    misc : { name: "Misc" }
};

var EXAMPLE_LIST = [
    // --- Widgets ---
    {
        cat: "widgets",
        name: "TranslateBox",
        href: "tests/test_translatebox.xhtml",
        info: "A widget for translating objects using an interactive cube."
    },
    {
        cat: "widgets",
        name: "UniformScaler",
        href: "tests/test_uniformscaler.xhtml",
        info: "A widget for uniform scaling of objects by dragging small cubes at the corners of the object."
    },
    {
        cat: "widgets",
        name: "SingleAxisRotator",
        href: "tests/test_axisrotator.xhtml",
        info: "A widget for rotating an object around a single axis. It places interactive bars along the axis."
    },

    {
        cat: "widgets",
        name: "RingMenu",
        href: "tests/test_ringmenu.xhtml",
        info: "A widget for selecting objects placed on a ring."
    },
    {
        cat: "widgets",
        name: "TransformBox",
        href: "tests/test_transformbox.xhtml",
        info: "A widget to perform translation, rotation and scaling."
    },
    {
        cat: "widgets",
        name: "RotatorBox",
        href: "tests/test_rotatorbox.xhtml",
        info: "A widget for performing constrained rotation and translation."
    },

    // --- Behaviors ---
    {
        cat: "behaviors",
        name: "Translatable",
        href: "tests/test_translatable.xhtml",
        info: "A behavior for translating a node inside a plane."
    },
    {
        cat: "behaviors",
        name: "Rotatable",
        href: "tests/test_rotatable.xhtml",
        info: "A behavior for rotating a node."
    },
    {
        cat: "behaviors",
        name: "Scalable",
        href: "tests/test_scalable.xhtml",
        info: "A behavior for rotating a node."
    },

    // --- Miscellaneous ---
    {
        cat: "misc",
        name: "TrackBall",
        href: "tests/test_trackball.xhtml",
        info: "A test for the class underlying the .rotatable() plugin."
    },
    {
        cat: "misc",
        name: "Back to Motion Library",
        href: "../index.xhtml",
        info: "Back to the main page of the Motion Library examples."
    },
];

var CURRENT = null;
var CURRENT_CAT = null;

function initPage(){

    var url = window.location.href;
    for(var i in EXAMPLE_LIST){
        if(url.indexOf(EXAMPLE_LIST[i].href) != -1){
            CURRENT = EXAMPLE_LIST[i];
        }
    }
    if(CURRENT)
        CURRENT_CAT = CATEGORY_LIST[CURRENT.cat] || CATEGORY_LIST.unknown;

    window.LINK_PREFIX = "";
    if(CURRENT){
        var idx = 0
        while( (idx = CURRENT.href.indexOf("/", idx)) != -1){
            idx++; window.LINK_PREFIX += "../";
        }
    }

    if(window.PAGE_INDEX){
        buildIndex();
    }

    buildNavigation();

    var header = $('

'
                 + '' + CONFIG_PAGETITLE + '

'
    );
    $(document.body).prepend(header);
    var footer = $('

')
    $(document.body).append(footer);

    if(CURRENT_CAT)
        header.find("h2").text( CURRENT_CAT.name);
    else
        header.find("h2").hide();
    if(CURRENT)
        header.find("h3").text( CURRENT.name);
    else
        header.find("h3").hide();

}

function buildIndex(){
    var content = $("#content");
    var container = $('

');
    var list = buildTestList();
    container.append(list);
    content.append(container);
}

function buildNavigation(){
    var navi = $('

');
    navi.append($("
Navigation
"));

    function adjustNavi(){
        navi.height($(document.body).hasClass("navi_hidden") ? 43 : $(window).height() - 8);
    }

    navi.find("h4").click(function(){
        $(document.body).toggleClass("navi_hidden");
        adjustNavi();
    });
    $(window).bind('resize', adjustNavi);
    adjustNavi();

    var inner = $('

');
    navi.append(inner);
    var naviList = buildTestList();
    inner.append(naviList);

    naviList.prepend($('
Index
'));

    $(document.body).prepend(navi);
}

function buildTestList(){
    var naviList = $('

');

    for(var i in CATEGORY_LIST)
        CATEGORY_LIST[i].examples = [];

    for(var i in EXAMPLE_LIST){
        (CATEGORY_LIST[EXAMPLE_LIST[i].cat] || CATEGORY_LIST.unknown).examples.push(EXAMPLE_LIST[i]);
    }

    for(var catId in CATEGORY_LIST){
        var cat = CATEGORY_LIST[catId];
        if(cat.examples.length == 0)
            continue;
        var header = $('

' + cat.name + '

');
        var list = $('

');
        for(var i in cat.examples){
            var entry = cat.examples[i];
            list.append($('
' + entry.name + '' +
                ( entry.info || "" ) + '
'))

        }
        header.append(list);
        naviList.append(header);
    }

    return naviList;
}

$(function(){
    initPage();
});
<|endoftext|>


<commit_before>/*jslint browser: true*/
/*global  $, console, PIXI, requestAnimFrame*/

// global variables
var canvas;
var renderer;
var stage;
var game;

// user input
var keysPressed = [];
var mouseDown = false;

// preloader
$(document).ready(
        function() {
            // load assets
            var loader = new PIXI.AssetLoader([
            	// images
                'img/pixi.js.png',

            	// sprites
                'img/sprites.json',

                // tileset
                'levels/tileset.json'
            ]);
            loader.addEventListener('onComplete', function(event) {
                // finished -> start game
                var time = 200;
                $('#loading').fadeOut(time, function() {
                    $('#game-canvas').fadeIn(time);
                    playBackgroundMusic();
                    setup();
                    initialize();
                });
            });

            // loading progress
            var loadCount = 0;
            loader.addEventListener('onProgress', function(event) {
                $('#loading p').html(
                        Math.round(100 * ++loadCount / loader.assetURLs.length)
                                + '%');
            });

            // start loading
            loader.load();
            $('#js-error').hide();
            $('#loading').show();
        });

function setup() {
    // setup renderer and stage
    canvas = $('#game-canvas');
    renderer = new PIXI.autoDetectRenderer(canvas.width(), canvas.height(),
            canvas[0]);

    // handle keyboard input
    document.onkeydown = function(event) {
        keysPressed.push(event.keyCode);
        return true;
    };
    document.onkeyup = function(event) {
        while (-1 < keysPressed.indexOf(event.keyCode)) {
            keysPressed.splice(keysPressed.indexOf(event.keyCode), 1);
        }
        return true;
    };

    // handle mouse input
    canvas[0].onmousedown = function() {
        mouseDown = true;
    };
    canvas[0].onmouseup = function() {
        mouseDown = false;
    };
}

/**
 * This function runs the game. It creates the renderer, the stage, the sprites
 * and so on.
 */
function initialize() {
    // game data
    game = {
    	level: [],
    	player: {
    		sprite: undefined,
    		position: undefined,
    		speed: 1,
    		movingDirection: undefined,
    		inputDirection: undefined
    	},
        speed: 1,
        sprites: []
    };

	// load player
    var playerFrames = [
    	'player.png',
    	'player_1l.png',
    	'player_2l.png',
    	'player_1l.png',
    	'player.png',
    	'player_1r.png',
    	'player_2r.png',
    	'player_1r.png'
    ];
    var playerTextures = [];
    for(var i = 0; i < playerFrames.length; i++) {
		playerTextures.push(PIXI.Texture.fromFrame(playerFrames[i]));
    }
    game.player.sprite = new PIXI.MovieClip(playerTextures);
    game.player.sprite.anchor.x = 0.5;
    game.player.sprite.anchor.y = 0.5;
    game.player.sprite.animationSpeed = 0;
    game.player.sprite.gotoAndPlay(0);
    game.sprites.push(game.player);

    // load level
    loadLevel('level1');
}

/**
 * This function is called in every tick of the game, usually 30 times per
 * second. All position updates and so on go here.
 */
function animate() {
	// read user input
	game.player.inputDirection = undefined;
	if(-1 < keysPressed.indexOf(38)) {
		game.player.inputDirection = 'north';
	}
	if(-1 < keysPressed.indexOf(39)) {
		game.player.inputDirection = 'east';
	}
	if(-1 < keysPressed.indexOf(40)) {
		game.player.inputDirection = 'south';
	}
	if(-1 < keysPressed.indexOf(37)) {
		game.player.inputDirection = 'west';
	}

    var tileset = game.level.tilesets[0];
    // update sprites
	$.each(game.sprites, function(i, agent) {
        // move
        var max;
        switch(agent.movingDirection) {
        	case 'west':
        		max = (tileset.tilewidth/2 + agent.sprite.position.x) % tileset.tilewidth;
        		if(agent.speed * game.speed < max) {
        			agent.sprite.position.x -= agent.speed * game.speed;
        		}
        		else {
        			agent.sprite.position.x -= max;
        			agent.movingDirection = undefined;
        			arriveOnTile(game.player.position.x, game.player.position.y);
        		}
        		break;

        	case 'east':
        		max = tileset.tilewidth - ((tileset.tilewidth/2 + agent.sprite.position.x) % tileset.tilewidth);
        		if(agent.speed * game.speed < max) {
        			agent.sprite.position.x += agent.speed * game.speed;
        		}
        		else {
        			agent.sprite.position.x += max;
        			agent.movingDirection = undefined;
        			arriveOnTile(game.player.position.x, game.player.position.y);
        		}
        		break;

        	case 'north':
        		max = (tileset.tileheight/2 + agent.sprite.position.y) % tileset.tileheight;
        		if(agent.speed * game.speed < max) {
        			agent.sprite.position.y -= agent.speed * game.speed;
        		}
        		else {
        			agent.sprite.position.y -= max;
        			agent.movingDirection = undefined;
        			arriveOnTile(game.player.position.x, game.player.position.y);
        		}
        		break;

        	case 'south':
        		max = tileset.tileheight - ((tileset.tileheight/2 + agent.sprite.position.y) % tileset.tileheight);
        		if(agent.speed * game.speed < max) {
        			agent.sprite.position.y += agent.speed * game.speed;
        		}
        		else {
        			agent.sprite.position.y += max;
        			agent.movingDirection = undefined;
        			arriveOnTile(game.player.position.x, game.player.position.y);
        		}
        		break;
		}

		// start moving
		if(agent.movingDirection === undefined) {
			switch(agent.inputDirection) {
				case 'west':
					if(agent.position.x > 0 && tileProperty('walkable', agent.position.x-1, agent.position.y) === '1') {
						agent.movingDirection = agent.inputDirection;
						agent.position.x--;
						agent.sprite.position.x -= Math.min(agent.speed * game.speed, tileset.tilewidth/2);
						agent.sprite.animationSpeed = 0.1 * agent.speed * game.speed;
					}
					else {
						if(!muted) {
							sound.bump.play();
						}
					}
					agent.sprite.rotation = -Math.PI/2;
					break;

				case 'east':
					if(agent.position.x < game.level.width-1 && tileProperty('walkable', agent.position.x+1, agent.position.y) === '1') {
						agent.movingDirection = agent.inputDirection;
						agent.position.x++;
						agent.sprite.position.x += Math.min(agent.speed * game.speed, tileset.tilewidth/2);
						agent.sprite.animationSpeed = 0.1 * agent.speed * game.speed;
					}
					else {
						if(!muted) {
							sound.bump.play();
						}
					}
					agent.sprite.rotation = Math.PI/2;
					break;

				case 'north':
					if(agent.position.y > 0 && tileProperty('walkable', agent.position.x, agent.position.y-1) === '1') {
						agent.movingDirection = agent.inputDirection;
						agent.position.y--;
						agent.sprite.position.y -= Math.min(agent.speed * game.speed, tileset.tileheight/2);
						agent.sprite.animationSpeed = 0.1 * agent.speed * game.speed;
					}
					else {
						if(!muted) {
							sound.bump.play();
						}
					}
					agent.sprite.rotation = 0;
					break;

				case 'south':
					if(agent.position.y < game.level.height-1 && tileProperty('walkable', agent.position.x, agent.position.y+1) === '1') {
						agent.movingDirection = agent.inputDirection;
						agent.position.y++;
						agent.sprite.position.y += Math.min(agent.speed * game.speed, tileset.tileheight/2);
						agent.sprite.animationSpeed = 0.1 * agent.speed * game.speed;
					}
					else {
						if(!muted) {
							sound.bump.play();
						}
					}
					agent.sprite.rotation = Math.PI;
					break;
			}
		}

		// still not moving
		if(agent.movingDirection === undefined) {
   			agent.sprite.animationSpeed = 0;
		    game.player.sprite.gotoAndPlay(0);
		}
	});
    // render
    renderer.render(stage);

    requestAnimFrame(animate);
}

// sound
var sound = {
    background: new Audio('audio/level1.wav'),
    bump: new Audio('audio/bump.wav'),
    pickup: new Audio('audio/pickup.wav')
};
var muted = true;

// @TODO load sound like sound.background = new Audio('audio/rich-vines.wav');

/**
 * This function initializes the background music and plays it if it is not
 * muted. Otherwise, the music is paused.
 */
function playBackgroundMusic() {
    // check for setup
    if (sound.background === undefined) {
        return;
    }

    // setup sound.background
    sound.background.loop = true;

    // play or pause
    if (muted) {
        sound.background.pause();
    }
    else {
        sound.background.play();
    }
}

/**
 * This function mutes the background music and stops the replay.
 */
function mute() {
    muted = true;
    $('#mute').html('Unmute').addClass('muted').removeClass('mute');
    playBackgroundMusic();
}

/**
 * This function unmutes the background music and restart the replay.
 */
function unmute() {
    muted = false;
    $('#mute').html('Mute').addClass('mute').removeClass('muted');
    playBackgroundMusic();
}

/**
 * This function toggles the background music and therefore mutes respectively
 * unmutes it.
 */
function toggleMute() {
    if (muted) {
        unmute();
    }
    else {
        mute();
    }
}

/**
 * This function computes the directory of the game's main html file. Prepend
 * this to paths to remove relative paths.
 *
 * @returns the main html file's directory
 */
function getBasePath() {
    var pathname = window.location.pathname;
    var directory;
    if (pathname.indexOf('/') === -1) {
        if (pathname.indexOf('.') === -1) {
            // directory at top level
            directory = pathname + '/';
        }
        else {
            // file at top level
            directory = '/';
        }
    }
    else {
        if (pathname.lastIndexOf('.') < pathname.lastIndexOf('/')) {
            // directory at nested level
            directory = pathname
                    + (pathname.lastIndexOf('/') === pathname.length - 1 ? ''
                            : '/');
        }
        else {
            // file at nested level
            directory = pathname.substring(0, pathname.lastIndexOf('/') + 1);
        }
    }
    return window.location.origin + directory;
}

/**
 * This function loads a level from a level file and displays it.
 * @param name is the level's name without file ending
 * @param callback is a function to be called when the level is loaded
 */
function loadLevel(name, callback) {
	$.ajax({
		url: 'levels/' + name  + '.json',
		dataType: 'json',
		success: function(level) {
			stage = new PIXI.Stage(0x260b01);
			game.level = level;
			$.each(level.layers, function(i, layer) {
				$.each(layer.data, function(i, tile) {
					if(tile !== 0) {
						// load sprite
						var texture = PIXI.Texture.fromFrame('tile_'+(tile < 10 ? '0' : '')+tile+'.png');
						var sprite = new PIXI.Sprite(texture);

						// find position
						var x = i % layer.width;
						var y = (i - x) / layer.width;

						// set position
						var tileset = level.tilesets[0];
						sprite.position.x = x * tileset.tilewidth;
						sprite.position.y = y * tileset.tileheight;

						// add sprite
						stage.addChild(sprite);

						// find start
						if(tileProperty('start', x, y) === '1') {
							game.player.position = {
								x: x,
								y: y
							};
							game.player.sprite.position = {
								x: (x + 0.5) * tileset.tilewidth,
								y: (y + 0.5) * tileset.tileheight
							};
							game.player.sprite.rotation = Math.PI/2;
						}
					}
				});
			});

			// add sprites
			$.each(game.sprites, function(i, sprite) {
				stage.addChild(sprite.sprite);
			});

			// callback
			if(callback !== undefined) {
				callback();
			}

		    // animate
		    requestAnimFrame(animate);
		}
	});
}

/**
 * This function finds properties of a tile at given coordinates.
 * @param prop is the name of the property to look for
 * @param x is the first coordinate
 * @param y is the second coordinate
 * @returns the value of the property
 */
function tileProperty(prop, x, y) {
	var layer = game.level.layers[0];
	var tile = layer.data[x + y*layer.width];
	var tileset = game.level.tilesets[0];
	if((tile-1) in tileset.tileproperties && prop in tileset.tileproperties[tile-1]) {
		return tileset.tileproperties[tile-1][prop];
	}
	else {
		return tileset.properties[prop];
	}
}

/**
 * This function is called on each tile the player steps on
 * @param x is the first coordinate of the new tile
 * @param y is the second coordinate of the new tile
 */
function arriveOnTile(x, y) {
	if(tileProperty('key', x, y) !== undefined) {
		if(!muted) {
			sound.pickup.play();
		}
	}
}<commit_msg>pickup keys<commit_after>/*jslint browser: true*/
/*global  $, console, PIXI, requestAnimFrame*/

// global variables
var canvas;
var renderer;
var stage;
var game;

// user input
var keysPressed = [];
var mouseDown = false;

// preloader
$(document).ready(
        function() {
            // load assets
            var loader = new PIXI.AssetLoader([
            	// images
                'img/pixi.js.png',

            	// sprites
                'img/sprites.json',

                // tileset
                'levels/tileset.json'
            ]);
            loader.addEventListener('onComplete', function(event) {
                // finished -> start game
                var time = 200;
                $('#loading').fadeOut(time, function() {
                    $('#game-canvas').fadeIn(time);
                    playBackgroundMusic();
                    setup();
                    initialize();
                });
            });

            // loading progress
            var loadCount = 0;
            loader.addEventListener('onProgress', function(event) {
                $('#loading p').html(
                        Math.round(100 * ++loadCount / loader.assetURLs.length)
                                + '%');
            });

            // start loading
            loader.load();
            $('#js-error').hide();
            $('#loading').show();
        });

function setup() {
    // setup renderer and stage
    canvas = $('#game-canvas');
    renderer = new PIXI.autoDetectRenderer(canvas.width(), canvas.height(),
            canvas[0]);

    // handle keyboard input
    document.onkeydown = function(event) {
        keysPressed.push(event.keyCode);
        return true;
    };
    document.onkeyup = function(event) {
        while (-1 < keysPressed.indexOf(event.keyCode)) {
            keysPressed.splice(keysPressed.indexOf(event.keyCode), 1);
        }
        return true;
    };

    // handle mouse input
    canvas[0].onmousedown = function() {
        mouseDown = true;
    };
    canvas[0].onmouseup = function() {
        mouseDown = false;
    };
}

/**
 * This function runs the game. It creates the renderer, the stage, the sprites
 * and so on.
 */
function initialize() {
    // game data
    game = {
    	level: [],
    	player: {
    		sprite: undefined,
    		position: undefined,
    		speed: 1,
    		movingDirection: undefined,
    		inputDirection: undefined
    	},
        speed: 1,
        sprites: []
    };

	// load player
    var playerFrames = [
    	'player.png',
    	'player_1l.png',
    	'player_2l.png',
    	'player_1l.png',
    	'player.png',
    	'player_1r.png',
    	'player_2r.png',
    	'player_1r.png'
    ];
    var playerTextures = [];
    for(var i = 0; i < playerFrames.length; i++) {
		playerTextures.push(PIXI.Texture.fromFrame(playerFrames[i]));
    }
    game.player.sprite = new PIXI.MovieClip(playerTextures);
    game.player.sprite.anchor.x = 0.5;
    game.player.sprite.anchor.y = 0.5;
    game.player.sprite.animationSpeed = 0;
    game.player.sprite.gotoAndPlay(0);
    game.sprites.push(game.player);

    // load level
    loadLevel('level1');
}

/**
 * This function is called in every tick of the game, usually 30 times per
 * second. All position updates and so on go here.
 */
function animate() {
	// read user input
	game.player.inputDirection = undefined;
	if(-1 < keysPressed.indexOf(38)) {
		game.player.inputDirection = 'north';
	}
	if(-1 < keysPressed.indexOf(39)) {
		game.player.inputDirection = 'east';
	}
	if(-1 < keysPressed.indexOf(40)) {
		game.player.inputDirection = 'south';
	}
	if(-1 < keysPressed.indexOf(37)) {
		game.player.inputDirection = 'west';
	}

    var tileset = game.level.tilesets[0];
    // update sprites
	$.each(game.sprites, function(i, agent) {
        // move
        var max;
        switch(agent.movingDirection) {
        	case 'west':
        		max = (tileset.tilewidth/2 + agent.sprite.position.x) % tileset.tilewidth;
        		if(agent.speed * game.speed < max) {
        			agent.sprite.position.x -= agent.speed * game.speed;
        		}
        		else {
        			agent.sprite.position.x -= max;
        			agent.movingDirection = undefined;
        			arriveOnTile(game.player.position.x, game.player.position.y);
        		}
        		break;

        	case 'east':
        		max = tileset.tilewidth - ((tileset.tilewidth/2 + agent.sprite.position.x) % tileset.tilewidth);
        		if(agent.speed * game.speed < max) {
        			agent.sprite.position.x += agent.speed * game.speed;
        		}
        		else {
        			agent.sprite.position.x += max;
        			agent.movingDirection = undefined;
        			arriveOnTile(game.player.position.x, game.player.position.y);
        		}
        		break;

        	case 'north':
        		max = (tileset.tileheight/2 + agent.sprite.position.y) % tileset.tileheight;
        		if(agent.speed * game.speed < max) {
        			agent.sprite.position.y -= agent.speed * game.speed;
        		}
        		else {
        			agent.sprite.position.y -= max;
        			agent.movingDirection = undefined;
        			arriveOnTile(game.player.position.x, game.player.position.y);
        		}
        		break;

        	case 'south':
        		max = tileset.tileheight - ((tileset.tileheight/2 + agent.sprite.position.y) % tileset.tileheight);
        		if(agent.speed * game.speed < max) {
        			agent.sprite.position.y += agent.speed * game.speed;
        		}
        		else {
        			agent.sprite.position.y += max;
        			agent.movingDirection = undefined;
        			arriveOnTile(game.player.position.x, game.player.position.y);
        		}
        		break;
		}

		// start moving
		if(agent.movingDirection === undefined) {
			switch(agent.inputDirection) {
				case 'west':
					if(agent.position.x > 0 && tileProperty('walkable', agent.position.x-1, agent.position.y) === '1') {
						agent.movingDirection = agent.inputDirection;
						agent.position.x--;
						agent.sprite.position.x -= Math.min(agent.speed * game.speed, tileset.tilewidth/2);
						agent.sprite.animationSpeed = 0.1 * agent.speed * game.speed;
					}
					else {
						if(!muted) {
							sound.bump.play();
						}
					}
					agent.sprite.rotation = -Math.PI/2;
					break;

				case 'east':
					if(agent.position.x < game.level.width-1 && tileProperty('walkable', agent.position.x+1, agent.position.y) === '1') {
						agent.movingDirection = agent.inputDirection;
						agent.position.x++;
						agent.sprite.position.x += Math.min(agent.speed * game.speed, tileset.tilewidth/2);
						agent.sprite.animationSpeed = 0.1 * agent.speed * game.speed;
					}
					else {
						if(!muted) {
							sound.bump.play();
						}
					}
					agent.sprite.rotation = Math.PI/2;
					break;

				case 'north':
					if(agent.position.y > 0 && tileProperty('walkable', agent.position.x, agent.position.y-1) === '1') {
						agent.movingDirection = agent.inputDirection;
						agent.position.y--;
						agent.sprite.position.y -= Math.min(agent.speed * game.speed, tileset.tileheight/2);
						agent.sprite.animationSpeed = 0.1 * agent.speed * game.speed;
					}
					else {
						if(!muted) {
							sound.bump.play();
						}
					}
					agent.sprite.rotation = 0;
					break;

				case 'south':
					if(agent.position.y < game.level.height-1 && tileProperty('walkable', agent.position.x, agent.position.y+1) === '1') {
						agent.movingDirection = agent.inputDirection;
						agent.position.y++;
						agent.sprite.position.y += Math.min(agent.speed * game.speed, tileset.tileheight/2);
						agent.sprite.animationSpeed = 0.1 * agent.speed * game.speed;
					}
					else {
						if(!muted) {
							sound.bump.play();
						}
					}
					agent.sprite.rotation = Math.PI;
					break;
			}
		}

		// still not moving
		if(agent.movingDirection === undefined) {
   			agent.sprite.animationSpeed = 0;
		    game.player.sprite.gotoAndPlay(0);
		}
	});
    // render
    renderer.render(stage);

    requestAnimFrame(animate);
}

// sound
var sound = {
    background: new Audio('audio/level1.wav'),
    bump: new Audio('audio/bump.wav'),
    pickup: new Audio('audio/pickup.wav')
};
var muted = true;

// @TODO load sound like sound.background = new Audio('audio/rich-vines.wav');

/**
 * This function initializes the background music and plays it if it is not
 * muted. Otherwise, the music is paused.
 */
function playBackgroundMusic() {
    // check for setup
    if (sound.background === undefined) {
        return;
    }

    // setup sound.background
    sound.background.loop = true;

    // play or pause
    if (muted) {
        sound.background.pause();
    }
    else {
        sound.background.play();
    }
}

/**
 * This function mutes the background music and stops the replay.
 */
function mute() {
    muted = true;
    $('#mute').html('Unmute').addClass('muted').removeClass('mute');
    playBackgroundMusic();
}

/**
 * This function unmutes the background music and restart the replay.
 */
function unmute() {
    muted = false;
    $('#mute').html('Mute').addClass('mute').removeClass('muted');
    playBackgroundMusic();
}

/**
 * This function toggles the background music and therefore mutes respectively
 * unmutes it.
 */
function toggleMute() {
    if (muted) {
        unmute();
    }
    else {
        mute();
    }
}

/**
 * This function computes the directory of the game's main html file. Prepend
 * this to paths to remove relative paths.
 *
 * @returns the main html file's directory
 */
function getBasePath() {
    var pathname = window.location.pathname;
    var directory;
    if (pathname.indexOf('/') === -1) {
        if (pathname.indexOf('.') === -1) {
            // directory at top level
            directory = pathname + '/';
        }
        else {
            // file at top level
            directory = '/';
        }
    }
    else {
        if (pathname.lastIndexOf('.') < pathname.lastIndexOf('/')) {
            // directory at nested level
            directory = pathname
                    + (pathname.lastIndexOf('/') === pathname.length - 1 ? ''
                            : '/');
        }
        else {
            // file at nested level
            directory = pathname.substring(0, pathname.lastIndexOf('/') + 1);
        }
    }
    return window.location.origin + directory;
}

/**
 * This function loads a level from a level file and displays it.
 * @param name is the level's name without file ending
 * @param callback is a function to be called when the level is loaded
 */
function loadLevel(name, callback) {
	$.ajax({
		url: 'levels/' + name  + '.json',
		dataType: 'json',
		success: function(level) {
			stage = new PIXI.Stage(0x260b01);
			game.level = level;
			game.level.sprites = [];
			$.each(level.layers, function(i, layer) {
				$.each(layer.data, function(i, tile) {
					if(tile !== 0) {
						// find position
						var x = i % layer.width;
						var y = (i - x) / layer.width;

						// add sprite
						setLevelTile(x, y, tile);

						// find start
						if(tileProperty('start', x, y) === '1') {
							game.player.position = {
								x: x,
								y: y
							};
							var tileset = game.level.tilesets[0];
							game.player.sprite.position = {
								x: (x + 0.5) * tileset.tilewidth,
								y: (y + 0.5) * tileset.tileheight
							};
							game.player.sprite.rotation = Math.PI/2;
						}
					}
				});
			});

			// add sprites
			$.each(game.sprites, function(i, sprite) {
				stage.addChild(sprite.sprite);
			});

			// callback
			if(callback !== undefined) {
				callback();
			}

		    // animate
		    requestAnimFrame(animate);
		}
	});
}

function setLevelTile(x, y, tile) {
	// create array
	if(game.level.sprites[x] === undefined) {
		game.level.sprites[x] = [];
	}

	// set level data
	game.level.layers[0].data[x + y*game.level.layers[0].width] = tile;

	// load sprite
	var texture = PIXI.Texture.fromFrame('tile_'+(tile < 10 ? '0' : '')+tile+'.png');
	var sprite = new PIXI.Sprite(texture);

	// set position
	var tileset = game.level.tilesets[0];
	sprite.position.x = x * tileset.tilewidth;
	sprite.position.y = y * tileset.tileheight;

	// add sprite
	// remove old sprite
	if(game.level.sprites[x][y] !== undefined) {
		stage.addChildAt(sprite, stage.children.indexOf(game.level.sprites[x][y]));
		stage.removeChild(game.level.sprites[x][y]);
		game.level.sprites[x][y] = sprite;
	}
	else {
		stage.addChild(sprite);
	}
	game.level.sprites[x][y] = sprite;
}

/**
 * This function finds properties of a tile at given coordinates.
 * @param prop is the name of the property to look for
 * @param x is the first coordinate
 * @param y is the second coordinate
 * @returns the value of the property
 */
function tileProperty(prop, x, y) {
	var layer = game.level.layers[0];
	var tile = layer.data[x + y*layer.width];
	var tileset = game.level.tilesets[0];
	if((tile-1) in tileset.tileproperties && prop in tileset.tileproperties[tile-1]) {
		return tileset.tileproperties[tile-1][prop];
	}
	else {
		return tileset.properties[prop];
	}
}

/**
 * This function is called on each tile the player steps on
 * @param x is the first coordinate of the new tile
 * @param y is the second coordinate of the new tile
 */
function arriveOnTile(x, y) {
	// pickup key
	if(tileProperty('key', x, y) !== undefined) {
		// play sound
		if(!muted) {
			sound.pickup.play();
		}

		// remove key from map
		setLevelTile(x, y, 1);
	}
}<|endoftext|>


<commit_before>/**
 * stack.js
 *
 * requirements:
 *	 tools.js
 *	 ui.js
 *	 slider.js
 */

/**
 */

/**
 * Stack is the core data viewer and interaction element.  It displays a list
 * of layers of an x,y-plane in an n-dimensional data set, tracks the
 * navigation/edit mode and organizes access to user interface elements such
 * as navigation sliders and buttons.  x, y dimensions are shown in the plane,
 * for all other dimensions, a slider is used.
 *
 * Layers can be images, text, SVG or arbitrary other overlays.
 *
 * A Stack is created with a given pixel resolution, pixel dimension, a
 * translation relative to the project and lists of planes to be excluded
 * (e.g. missing sections in serial section microscopy and missing frames in a
 * time series).  These properties limit the field of view and the slider
 * ranges.
 */
function Stack(
		project,					//!< {Project} reference to the parent project
		id,							//!< {Integer} the stack's id
		title,						//!< {String} the stack's title
		dimension,					//!< {Array} pixel dimensions [x, y, z, ...]
		resolution,					//!< {Array} physical resolution in units/pixel [x, y, z, ...]
		translation,				//!< @todo replace by an affine transform
		skip_planes,				//!< {Array} planes to be excluded from the stack's view [[z,t,...], [z,t,...], ...]
		trakem2_project				//!< {boolean} that states if a TrakEM2 project is available for this stack
)
{
	var n = dimension.length;

	/**
	 * update the scale bar (x-resolution) to a proper size
	 */
	var updateScaleBar = function()
	{
		var meter = self.scale / resolution[ 0 ];
		var width = 0;
		var text = "";
		for ( var i = 0; i < Stack.SCALE_BAR_SIZES.length; ++i )
		{
			text = Stack.SCALE_BAR_SIZES[ i ];
			width = Stack.SCALE_BAR_SIZES[ i ] * meter;
			if ( width > Math.min( 192, self.viewWidth / 5 ) )
				break;
		}
		var ui = 0;
		while ( text >= 1000 && ui < Stack.SCALE_BAR_UNITS.length - 1 )
		{
			text /= 1000;
			++ui;
		}
		scaleBar.style.width = width + "px";
		scaleBar.firstChild.firstChild.replaceChild(
			document.createTextNode( text + " " + Stack.SCALE_BAR_UNITS[ ui ] ),
			scaleBar.firstChild.firstChild.firstChild );
		return;
	}

	/**
	 * update all state informations and the screen content
	 */
	var update = function( now )
	{
		self.overview.redraw();
		updateScaleBar();

		//statusBar.replaceLast( "[" + ( Math.round( x * 10000 * resolution.x ) / 10000 ) + ", " + ( Math.round( y * 10000 * resolution.y ) / 10000 ) + "]" );

		if ( !transition.queued( redraw ) )
		{
			if ( now )
				transition.register( redraw );
			else
				redraw();
		}

		return
	}

	/**
	 * Get stack coordinates of the current view's top left corner.
	 * These values might be used as an offset to get the stack coordinates of a
	 * mouse event handled by the stack.
	 */
	this.screenPosition = function()
	{
		var width = self.viewWidth / self.scale;
		var height = self.viewHeight / self.scale;
		var l =
		{
			top : Math.floor( self.y - height / 2 ),
			left : Math.floor( self.x - width / 2 )
		};
		return l;
	}

	/**
	 * Get the project coordinates of the current view.
	 */
	this.projectCoordinates = function()
	{
		var l =
		{
			z : self.z * resolution.z + translation.z,
			s : self.s,
			scale : self.scale,
			y : self.y * resolution.y + translation.y,
			x : self.x * resolution.x + translation.x
		};
		return l;
	}

  /*
   * Get the top and left coordinates in physical project coordinates of
   * stack's window
   */
  this.getWorldTopLeft = function()
  {
    return {
      worldTop : ( ( self.y - self.viewHeight / self.scale / 2 ) ) * self.resolution.y + self.translation.y,
      worldLeft : ( ( self.x - self.viewWidth / self.scale / 2 ) ) * self.resolution.x + self.translation.x,
      scale : self.scale
    }
  }

	/**
	 * align and update the tiles to be ( x, y ) in the image center
	 */
	var redraw = function()
	{
		self.yc = Math.floor( self.y * self.scale - ( self.viewHeight / 2 ) );
		self.xc = Math.floor( self.x * self.scale - ( self.viewWidth / 2 ) );

		for ( var key in layers )
			layers[ key ].redraw();

		//----------------------------------------------------------------------
		/**
		 * This question is completely useless but without asking it, Firefox on
		 * Linux systems will not redraw the screen properly.  Took me ... to
		 * find this out.
		 */
		var a = view.offsetWidth;
		//----------------------------------------------------------------------

		self.old_z = self.z;
		self.old_y = self.y;
		self.old_x = self.x;
		self.old_s = self.s;
		self.old_scale = self.scale;
		self.old_yc = self.yc;
		self.old_xc = self.xc

		return 2;
	}

	/**
	 * get the view element
	 */
	this.getView = function()
	{
		return view;
	}

	/**
	 * move to project-coordinates
	 */
	this.moveTo = function( zp, yp, xp, sp )
	{
		if ( typeof sp == "number" )
		{
			self.s = Math.max( 0, Math.min( self.MAX_S, Math.round( sp ) ) );
			self.scale = 1 / Math.pow( 2, self.s );
		}

		self.x = Math.max( 0, Math.min( MAX_X, Math.round( ( xp - translation.x ) / resolution.x ) ) );
		self.y = Math.max( 0, Math.min( MAX_Y, Math.round( ( yp - translation.y ) / resolution.y ) ) );

		var z1;
		var z2;
		z1 = z2 = Math.round( ( zp - translation.z ) / resolution.z );
		while ( skip_planes[ z1 ] && skip_planes[ z2 ] )
		{
			z1 = Math.max( 0, z1 - 1 );
			z2 = Math.min( MAX_Z, z2 + 1 );
		}
		if ( !skip_planes[ z1 ] ) self.z = z1;
		else self.z = z2;
		self.z = Math.max( 0, Math.min( MAX_Z, self.z ) );

		update();

		return;
	}

	/**
	 * move to pixel coordinates
	 */
	this.moveToPixel = function( zp, yp, xp, sp )
	{
		self.s = Math.max( 0, Math.min( self.MAX_S, sp ) );

		self.scale = 1 / Math.pow( 2, self.s );

		project.moveTo(
			zp * resolution.z + translation.z,
			yp * resolution.y + translation.y,
			xp * resolution.x + translation.x );

		return true;
	}

	var resize = function()
	{
		self.viewWidth = stackWindow.getFrame().offsetWidth;
		self.viewHeight = stackWindow.getFrame().offsetHeight;

		for ( var key in layers ) {
      if( layers.hasOwnProperty( key )) {
        layers[ key ].resize( self.viewWidth, self.viewHeight );
      }
    }

		self.overview.redraw();

		return;
	}

	/**
	 * Get the stack window.
	 */
	this.getWindow = function() { return stackWindow; }

	/**
	 * Get the project.
	 */
	this.getProject = function(){ return project; }

	/**
	 * Get stack ID.
	 */
	this.getId = function(){ return id; }

	/**
	 * Add a layer.  Layers are associated by a unique key.
	 * If a layer with the passed key exists, then this layer will be replaced.
	 *
	 * @param key
	 * @param layer
	 */
	this.addLayer = function( key, layer )
	{
		if ( layers[ key ] )
			layers[ key ].unregister();
		layers[ key ] = layer;
		return;
	}

	/**
	 * Remove a layer specified by its key.  If no layer with this key exists,
	 * then nothing will happen.  The layer is returned;
	 *
	 */
	this.removeLayer = function( key )
	{
		var layer = layers[ key ];
		if ( typeof layer != "undefined" && layer )
		{
			layer.unregister();
			delete layers[ key ];
			return layer;
		}
		else
			return null;
	}

	/**
	 * Register a tool at this stack.  Unregisters the current tool and then
	 * makes the tool working.
	 */
	this.setTool = function( newTool )
	{
//		if ( typeof tool != "undefined" && tool )
//			tool.unregister();
		tool = newTool;
		if ( typeof tool != "undefined" && tool )
			tool.register( self );
	}

	// initialize
	var self = this;
	if ( !ui ) ui = new UI();

	self.id = id;

	self.resolution = resolution;
	self.translation = translation;
	self.dimension = dimension;

	var tool = null;
	var layers = {};

	var MAX_X = dimension.x - 1;   //!< the last possible x-coordinate
	var MAX_Y = dimension.y - 1;   //!< the last possible y-coordinate
	var MAX_Z = dimension.z - 1;   //!< the last possible z-coordinate

	//! estimate the zoom levels
	self.MAX_S = 0;
	var min_max = Math.min( MAX_X, MAX_Y );
	var min_size = 256;
	while ( min_max / Math.pow( 2, self.MAX_S ) / min_size > 4 )
		++self.MAX_S;

	//! all possible slices
	self.slices = new Array();
	for ( var i = 0; i < dimension.z; ++i )
	{
		if ( !skip_planes[ i ] )
			self.slices.push( i );
	}

	//-------------------------------------------------------------------------

	var transition = new Transition();

	// extract the borders of the viewer window from CSS rules
	var viewTop    = parseInt( getPropertyFromCssRules( 3, 0, "top" ) );
	var viewBottom = parseInt( getPropertyFromCssRules( 3, 0, "bottom" ) );
	var viewLeft   = parseInt( getPropertyFromCssRules( 3, 0, "left" ) );
	var viewRight  = parseInt( getPropertyFromCssRules( 3, 0, "right" ) );

	var stackWindow = new CMWWindow( title );
	var view = stackWindow.getFrame();

	var viewWidth = stackWindow.getFrame().offsetWidth;
	var viewHeight = stackWindow.getFrame().offsetHeight;

	stackWindow.addListener(
		function( callingWindow, signal )
		{
			//alert( signal );
			switch ( signal )
			{
			case CMWWindow.CLOSE:
				project.removeStack( id );
				break;
			case CMWWindow.RESIZE:
				resize();
				redraw();
				break;
			case CMWWindow.FOCUS:
				self.overview.getView().style.zIndex = "6";
				project.setFocusedStack( self );
				break;
			case CMWWindow.BLUR:
				self.overview.getView().style.zIndex = "5";
				if ( tool )
					tool.unregister();
				tool = null;
				window.onresize();
				break;
			}
			return true;
		} );

	self.overview = new Overview( self );
	view.appendChild( self.overview.getView() );

	var scaleBar = document.createElement( "div" );
	scaleBar.className = "sliceBenchmark";
	scaleBar.appendChild( document.createElement( "p" ) );
	scaleBar.firstChild.appendChild( document.createElement( "span" ) );
	scaleBar.firstChild.firstChild.appendChild( document.createTextNode( "test" ) );
	view.appendChild( scaleBar );

	// take care, that all values are within a proper range
    // Declare the x,y,z,s as coordinates in pixels
	self.z = 1;
	self.y = Math.floor( MAX_Y / 2 );
	self.x = Math.floor( MAX_X / 2 );
	self.s = self.MAX_S;

	self.old_z = -1;
	self.old_y = self.y;
	self.old_x = self.x;
	self.old_s = self.s;

	self.scale = 1 / Math.pow( 2, self.s );
	self.old_scale = self.scale;
}

//!< in nanometers
Stack.SCALE_BAR_SIZES = new Array(
			10,
			20,
			25,
			50,
			100,
			200,
			250,
			500,
			1000,
			2000,
			2500,
			5000,
			10000,
			20000,
			25000,
			50000,
			100000,
			200000,
			250000,
			500000,
			1000000,
			2000000,
			2500000,
			5000000,
			10000000,
			20000000,
			25000000,
			50000000,
			100000000,
			200000000,
			250000000,
			500000000,
			1000000000,
			2000000000,
			2500000000,
			5000000000,
			10000000000,
			20000000000,
			25000000000,
			50000000000,
			100000000000,
			200000000000,
			250000000000,
			500000000000 );
Stack.SCALE_BAR_UNITS = new Array(
			"nm",
			unescape( "%u03BCm" ),
			"mm",
			"m" );
<commit_msg>Added function Stack.getTool<commit_after>/**
 * stack.js
 *
 * requirements:
 *	 tools.js
 *	 ui.js
 *	 slider.js
 */

/**
 */

/**
 * Stack is the core data viewer and interaction element.  It displays a list
 * of layers of an x,y-plane in an n-dimensional data set, tracks the
 * navigation/edit mode and organizes access to user interface elements such
 * as navigation sliders and buttons.  x, y dimensions are shown in the plane,
 * for all other dimensions, a slider is used.
 *
 * Layers can be images, text, SVG or arbitrary other overlays.
 *
 * A Stack is created with a given pixel resolution, pixel dimension, a
 * translation relative to the project and lists of planes to be excluded
 * (e.g. missing sections in serial section microscopy and missing frames in a
 * time series).  These properties limit the field of view and the slider
 * ranges.
 */
function Stack(
		project,					//!< {Project} reference to the parent project
		id,							//!< {Integer} the stack's id
		title,						//!< {String} the stack's title
		dimension,					//!< {Array} pixel dimensions [x, y, z, ...]
		resolution,					//!< {Array} physical resolution in units/pixel [x, y, z, ...]
		translation,				//!< @todo replace by an affine transform
		skip_planes,				//!< {Array} planes to be excluded from the stack's view [[z,t,...], [z,t,...], ...]
		trakem2_project				//!< {boolean} that states if a TrakEM2 project is available for this stack
)
{
	var n = dimension.length;

	/**
	 * update the scale bar (x-resolution) to a proper size
	 */
	var updateScaleBar = function()
	{
		var meter = self.scale / resolution[ 0 ];
		var width = 0;
		var text = "";
		for ( var i = 0; i < Stack.SCALE_BAR_SIZES.length; ++i )
		{
			text = Stack.SCALE_BAR_SIZES[ i ];
			width = Stack.SCALE_BAR_SIZES[ i ] * meter;
			if ( width > Math.min( 192, self.viewWidth / 5 ) )
				break;
		}
		var ui = 0;
		while ( text >= 1000 && ui < Stack.SCALE_BAR_UNITS.length - 1 )
		{
			text /= 1000;
			++ui;
		}
		scaleBar.style.width = width + "px";
		scaleBar.firstChild.firstChild.replaceChild(
			document.createTextNode( text + " " + Stack.SCALE_BAR_UNITS[ ui ] ),
			scaleBar.firstChild.firstChild.firstChild );
		return;
	}

	/**
	 * update all state informations and the screen content
	 */
	var update = function( now )
	{
		self.overview.redraw();
		updateScaleBar();

		//statusBar.replaceLast( "[" + ( Math.round( x * 10000 * resolution.x ) / 10000 ) + ", " + ( Math.round( y * 10000 * resolution.y ) / 10000 ) + "]" );

		if ( !transition.queued( redraw ) )
		{
			if ( now )
				transition.register( redraw );
			else
				redraw();
		}

		return
	}

	/**
	 * Get stack coordinates of the current view's top left corner.
	 * These values might be used as an offset to get the stack coordinates of a
	 * mouse event handled by the stack.
	 */
	this.screenPosition = function()
	{
		var width = self.viewWidth / self.scale;
		var height = self.viewHeight / self.scale;
		var l =
		{
			top : Math.floor( self.y - height / 2 ),
			left : Math.floor( self.x - width / 2 )
		};
		return l;
	}

	/**
	 * Get the project coordinates of the current view.
	 */
	this.projectCoordinates = function()
	{
		var l =
		{
			z : self.z * resolution.z + translation.z,
			s : self.s,
			scale : self.scale,
			y : self.y * resolution.y + translation.y,
			x : self.x * resolution.x + translation.x
		};
		return l;
	}

  /*
   * Get the top and left coordinates in physical project coordinates of
   * stack's window
   */
  this.getWorldTopLeft = function()
  {
    return {
      worldTop : ( ( self.y - self.viewHeight / self.scale / 2 ) ) * self.resolution.y + self.translation.y,
      worldLeft : ( ( self.x - self.viewWidth / self.scale / 2 ) ) * self.resolution.x + self.translation.x,
      scale : self.scale
    }
  }

	/**
	 * align and update the tiles to be ( x, y ) in the image center
	 */
	var redraw = function()
	{
		self.yc = Math.floor( self.y * self.scale - ( self.viewHeight / 2 ) );
		self.xc = Math.floor( self.x * self.scale - ( self.viewWidth / 2 ) );

		for ( var key in layers )
			layers[ key ].redraw();

		//----------------------------------------------------------------------
		/**
		 * This question is completely useless but without asking it, Firefox on
		 * Linux systems will not redraw the screen properly.  Took me ... to
		 * find this out.
		 */
		var a = view.offsetWidth;
		//----------------------------------------------------------------------

		self.old_z = self.z;
		self.old_y = self.y;
		self.old_x = self.x;
		self.old_s = self.s;
		self.old_scale = self.scale;
		self.old_yc = self.yc;
		self.old_xc = self.xc

		return 2;
	}

	/**
	 * get the view element
	 */
	this.getView = function()
	{
		return view;
	}

	/**
	 * move to project-coordinates
	 */
	this.moveTo = function( zp, yp, xp, sp )
	{
		if ( typeof sp == "number" )
		{
			self.s = Math.max( 0, Math.min( self.MAX_S, Math.round( sp ) ) );
			self.scale = 1 / Math.pow( 2, self.s );
		}

		self.x = Math.max( 0, Math.min( MAX_X, Math.round( ( xp - translation.x ) / resolution.x ) ) );
		self.y = Math.max( 0, Math.min( MAX_Y, Math.round( ( yp - translation.y ) / resolution.y ) ) );

		var z1;
		var z2;
		z1 = z2 = Math.round( ( zp - translation.z ) / resolution.z );
		while ( skip_planes[ z1 ] && skip_planes[ z2 ] )
		{
			z1 = Math.max( 0, z1 - 1 );
			z2 = Math.min( MAX_Z, z2 + 1 );
		}
		if ( !skip_planes[ z1 ] ) self.z = z1;
		else self.z = z2;
		self.z = Math.max( 0, Math.min( MAX_Z, self.z ) );

		update();

		return;
	}

	/**
	 * move to pixel coordinates
	 */
	this.moveToPixel = function( zp, yp, xp, sp )
	{
		self.s = Math.max( 0, Math.min( self.MAX_S, sp ) );

		self.scale = 1 / Math.pow( 2, self.s );

		project.moveTo(
			zp * resolution.z + translation.z,
			yp * resolution.y + translation.y,
			xp * resolution.x + translation.x );

		return true;
	}

	var resize = function()
	{
		self.viewWidth = stackWindow.getFrame().offsetWidth;
		self.viewHeight = stackWindow.getFrame().offsetHeight;

		for ( var key in layers ) {
      if( layers.hasOwnProperty( key )) {
        layers[ key ].resize( self.viewWidth, self.viewHeight );
      }
    }

		self.overview.redraw();

		return;
	}

	/**
	 * Get the stack window.
	 */
	this.getWindow = function() { return stackWindow; }

	/**
	 * Get the project.
	 */
	this.getProject = function(){ return project; }

	/**
	 * Get stack ID.
	 */
	this.getId = function(){ return id; }

	/**
	 * Add a layer.  Layers are associated by a unique key.
	 * If a layer with the passed key exists, then this layer will be replaced.
	 *
	 * @param key
	 * @param layer
	 */
	this.addLayer = function( key, layer )
	{
		if ( layers[ key ] )
			layers[ key ].unregister();
		layers[ key ] = layer;
		return;
	}

	/**
	 * Remove a layer specified by its key.  If no layer with this key exists,
	 * then nothing will happen.  The layer is returned;
	 *
	 */
	this.removeLayer = function( key )
	{
		var layer = layers[ key ];
		if ( typeof layer != "undefined" && layer )
		{
			layer.unregister();
			delete layers[ key ];
			return layer;
		}
		else
			return null;
	}

	/**
	 * Register a tool at this stack.  Unregisters the current tool and then
	 * makes the tool working.
	 */
	this.setTool = function( newTool )
	{
//		if ( typeof tool != "undefined" && tool )
//			tool.unregister();
		tool = newTool;
		if ( typeof tool != "undefined" && tool )
			tool.register( self );
	}

	/** Return the current tool. */
	this.getTool = function()
	{
		return tool;
	}

	// initialize
	var self = this;
	if ( !ui ) ui = new UI();

	self.id = id;

	self.resolution = resolution;
	self.translation = translation;
	self.dimension = dimension;

	var tool = null;
	var layers = {};

	var MAX_X = dimension.x - 1;   //!< the last possible x-coordinate
	var MAX_Y = dimension.y - 1;   //!< the last possible y-coordinate
	var MAX_Z = dimension.z - 1;   //!< the last possible z-coordinate

	//! estimate the zoom levels
	self.MAX_S = 0;
	var min_max = Math.min( MAX_X, MAX_Y );
	var min_size = 256;
	while ( min_max / Math.pow( 2, self.MAX_S ) / min_size > 4 )
		++self.MAX_S;

	//! all possible slices
	self.slices = new Array();
	for ( var i = 0; i < dimension.z; ++i )
	{
		if ( !skip_planes[ i ] )
			self.slices.push( i );
	}

	//-------------------------------------------------------------------------

	var transition = new Transition();

	// extract the borders of the viewer window from CSS rules
	var viewTop    = parseInt( getPropertyFromCssRules( 3, 0, "top" ) );
	var viewBottom = parseInt( getPropertyFromCssRules( 3, 0, "bottom" ) );
	var viewLeft   = parseInt( getPropertyFromCssRules( 3, 0, "left" ) );
	var viewRight  = parseInt( getPropertyFromCssRules( 3, 0, "right" ) );

	var stackWindow = new CMWWindow( title );
	var view = stackWindow.getFrame();

	var viewWidth = stackWindow.getFrame().offsetWidth;
	var viewHeight = stackWindow.getFrame().offsetHeight;

	stackWindow.addListener(
		function( callingWindow, signal )
		{
			//alert( signal );
			switch ( signal )
			{
			case CMWWindow.CLOSE:
				project.removeStack( id );
				break;
			case CMWWindow.RESIZE:
				resize();
				redraw();
				break;
			case CMWWindow.FOCUS:
				self.overview.getView().style.zIndex = "6";
				project.setFocusedStack( self );
				break;
			case CMWWindow.BLUR:
				self.overview.getView().style.zIndex = "5";
				if ( tool )
					tool.unregister();
				tool = null;
				window.onresize();
				break;
			}
			return true;
		} );

	self.overview = new Overview( self );
	view.appendChild( self.overview.getView() );

	var scaleBar = document.createElement( "div" );
	scaleBar.className = "sliceBenchmark";
	scaleBar.appendChild( document.createElement( "p" ) );
	scaleBar.firstChild.appendChild( document.createElement( "span" ) );
	scaleBar.firstChild.firstChild.appendChild( document.createTextNode( "test" ) );
	view.appendChild( scaleBar );

	// take care, that all values are within a proper range
    // Declare the x,y,z,s as coordinates in pixels
	self.z = 1;
	self.y = Math.floor( MAX_Y / 2 );
	self.x = Math.floor( MAX_X / 2 );
	self.s = self.MAX_S;

	self.old_z = -1;
	self.old_y = self.y;
	self.old_x = self.x;
	self.old_s = self.s;

	self.scale = 1 / Math.pow( 2, self.s );
	self.old_scale = self.scale;
}

//!< in nanometers
Stack.SCALE_BAR_SIZES = new Array(
			10,
			20,
			25,
			50,
			100,
			200,
			250,
			500,
			1000,
			2000,
			2500,
			5000,
			10000,
			20000,
			25000,
			50000,
			100000,
			200000,
			250000,
			500000,
			1000000,
			2000000,
			2500000,
			5000000,
			10000000,
			20000000,
			25000000,
			50000000,
			100000000,
			200000000,
			250000000,
			500000000,
			1000000000,
			2000000000,
			2500000000,
			5000000000,
			10000000000,
			20000000000,
			25000000000,
			50000000000,
			100000000000,
			200000000000,
			250000000000,
			500000000000 );
Stack.SCALE_BAR_UNITS = new Array(
			"nm",
			unescape( "%u03BCm" ),
			"mm",
			"m" );
<|endoftext|>


<commit_before>module.exports = function (base){
  var base2 = base[2];

  var byte_255_str = 11111111;

  var code = "\n"
    + "for(var i = 0; i < 500000; i++)\n"
    + "  base2.js[10](byte_255_str);"
    ;

  console.log(code);

  var start = new Date().getTime();
  for(var i = 0; i < 500000; i++)
    base2.js[10](byte_255_str);
  console.log('\ntakes', new Date().getTime() - start + 'ms\n');

  var code = "\n"
    + "for(var i = 0; i < 500000; i++)\n"
    + "  base2.cpp[10](byte_255_str);"
    ;

  console.log(code);

  var start = new Date().getTime();
  for(var i = 0; i < 500000; i++)
    base2.cpp[10](byte_255_str);
  console.log('\ntakes', new Date().getTime() - start + 'ms\n');

}

/**

loop 50000
  base2.base10('11111111')

js: 0ms
cpp: 0ms

*/<commit_msg>Fixed dev code<commit_after>module.exports = function (base){
  var base2 = base[2];

  var byte_255_str = '11111111';

  var code = "\n"
    + "for(var i = 0; i < 500000; i++)\n"
    + "  base2.js[10](byte_255_str);"
    ;

  console.log(code);

  var start = new Date().getTime();
  for(var i = 0; i < 500000; i++)
    base2.js[10](byte_255_str);
  console.log('\ntakes', new Date().getTime() - start + 'ms\n');

  var code = "\n"
    + "for(var i = 0; i < 500000; i++)\n"
    + "  base2.cpp[10](byte_255_str);"
    ;

  console.log(code);

  var start = new Date().getTime();
  for(var i = 0; i < 500000; i++)
    base2.cpp[10](byte_255_str);
  console.log('\ntakes', new Date().getTime() - start + 'ms\n');

}

/**

loop 50000
  base2.base10('11111111')

js: 0ms
cpp: 0ms

*/<|endoftext|>


<commit_before>var http = require('http');
var server = require('./server.js');

var client = function (rushHost, rushPort, hostAndPort, timeout, resSize) {
    'use strict';

    var createServer = server.createServer(timeout, resSize, function () {
        var options = {};
        options.host = rushHost;
        options.port = rushPort;
        options.headers = {};
        options.headers['X-Relayer-Host'] = hostAndPort;
        //options.headers['X-relayer-persistence'] = 'BODY';
        options.method = 'POST';

        var req = http.request(options, function (res) {

            res.on('data', function (chunk) {
                var data = '';
                data += chunk;
                console.log(data);
            });
        });

        var body = { timeout:timeout, resSize:resSize};
        body = JSON.stringify(body);
        req.write(body);
        req.end();
    });
};

exports.client = client;<commit_msg>client and server refactored<commit_after>var http = require('http');
var server = require('./server.js');

var client = function (rushHost, rushPort, hostAndPort) {
    'use strict';

    var options = {};
    options.host = rushHost;
    options.port = rushPort;
    options.headers = {};
    options.headers['X-Relayer-Host'] = hostAndPort;
    //options.headers['X-relayer-persistence'] = 'BODY';
    options.method = 'POST';

    var req = http.request(options, function (res) {

        res.on('data', function (chunk) {
            var data = '';
            data += chunk;
            console.log(data);
        });
    });

    /*var body = { timeout:timeout, resSize:resSize};
    body = JSON.stringify(body);
    req.write(body);*/
    req.end();
};

exports.client = client;<|endoftext|>