Switch between different views using keys 1 - 3

Cloth / Fabric Simulation

Here is the interesting part of the computation:

                        
function Fabric( canvas, settings )
{
    var _canvas = canvas;
    var _width = canvas.width;
    var _height = canvas.height;

    var _mousePos = new Point( 0, 0 );

    var _entities = [];
    var _constraints = [];

    function init()
    {
        _entities = [];
        _constraints = [];

        var origin = _settings.origin;
        var width = _settings.clothWidth;
        var height = _settings.clothHeight;
        var segments = _settings.segments;
        var e = _settings.strength;

        var xStride = width / segments;
        var yStride = height / segments;

        var cols = segments + 1;

        for( var y = 0; y <= segments; ++y )
        {
            for( var x = 0; x <= segments; ++x )
            {
                var px = origin.x + x * xStride;
                var py = origin.y + y * yStride;

                _entities.push( new Entity( px, py ) );

                var i = y * cols + x;

                if( x > 0 )
                {
                    _constraints.push( new DistanceConstraint( _entities[ i ], _entities[ i - 1 ], e ) );
                }

                if( y > 0 )
                {
                    _constraints.push( new DistanceConstraint( _entities[ i ], _entities[ ( y - 1 ) * cols + x ], e ) );
                }

                if( y == 0 && x % 5 == 0 )
                {
                    _constraints.push( new EdgeConstraint( _entities[ i ] ) );
                }
            }
        }
    }

    this.step = function()
    {
        for( var i = 0, n = _entities.length; i < n; ++i )
        {
            var p = _entities[ i ];

            var vx = ( p.x - p.lastX ) * _settings.elasticity;
            var vy = ( p.y - p.lastY ) * _settings.elasticity;

            p.lastX = p.x;
            p.lastY = p.y;

            p.x += vx;
            p.y += vy;

            p.x += _settings.gravity.x;
            p.y += _settings.gravity.y;
        }

        for( var j = 0; j < 20; ++j )
        {
            for( var k = 0; k < _constraints.length; ++k )
            {
                _constraints[ k ].step();
            }
        }
    };
}

function DistanceConstraint( entityA, entityB, strength )
{
    this.a = entityA;
    this.b = entityB;
    this.strength = strength;

    var dx = entityA.x - entityB.x;
    var dy = entityA.y - entityB.y;

    this.distance = Math.sqrt( dx * dx + dy * dy );

    this.step = function()
    {
        var nx = this.a.x - this.b.x;
        var ny = this.a.y - this.b.y;

        var m = ( nx * nx + ny * ny );

        var s = ( ( this.distance * this.distance - m ) / m ) * this.strength;

        nx *= s;
        ny *= s;

        this.a.x += nx;
        this.a.y += ny;

        this.b.x -= nx;
        this.b.y -= ny;
    };
}

function EdgeConstraint( entity )
{
    this.a = entity;
    this.x = entity.x;
    this.y = entity.y;

    this.step = function()
    {
        this.a.x = this.x;
        this.a.y = this.y;
    };
}