public void ApplyVelocity()
        {

            {
                var current = this.body;
                //var v = this.AngularVelocity * 10;
                //current.SetAngularVelocity(v);

                current.ApplyAngularImpulse(
                   this.AngularVelocity * AngularVelocityMultiplier
                   * this.CurrentInput.forcex
                   * ApplyVelocityElapse.ElapsedMilliseconds
                   * 1.0
                   * (1 - (this.body.GetLinearVelocity().Length() / this.speed).Min(0.9) * 0.5)
               );


                var vx = Math.Cos(current.GetAngle()) * this.LinearVelocityY * this.speed * this.CurrentInput.forcey
                        + Math.Cos(current.GetAngle() + Math.PI / 2) * this.LinearVelocityX * this.speed;
                var vy = Math.Sin(current.GetAngle()) * this.LinearVelocityY * this.speed * this.CurrentInput.forcey
                        + Math.Sin(current.GetAngle() + Math.PI / 2) * this.LinearVelocityX * this.speed;





                this.visual.currentvisual.alpha = 1.0;

                #region RemoteGameReference
                if (RemoteGameReference != null)
                    if (vx == 0)
                        if (vy == 0)
                        //if (v == 0)
                        {
                            // not moving anymore in network mode
                            // far enough to be out of sync?

                            //if (karmabody.GetAngularVelocity() == 0)
                            if (karmabody.GetLinearVelocity().Length() == 0)
                                if (this.KarmaInput0.All(k => k.value == 0))
                                {




                                    var gap = new __vec2(
                                        (float)this.karmabody.GetPosition().x - (float)this.body.GetPosition().x,
                                        (float)this.karmabody.GetPosition().y - (float)this.body.GetPosition().y
                                    );

                                    // tolerate lesser distance?

                                    var CloseEnough = gap.GetLength() < 1.2;
                                    var TooFar = gap.GetLength() > 5;

                                    if (CloseEnough)
                                    {
                                        ApplyVelocityMoveToLocation = false;
                                    }

                                    if (TooFar || ApplyVelocityMoveToLocation)
                                    {
                                        //this.body.SetPositionAndAngle(
                                        //    new b2Vec2(
                                        //        this.karmabody.GetPosition().x,
                                        //        this.karmabody.GetPosition().y
                                        //    ),
                                        //    this.karmabody.GetAngle()
                                        //);

                                        // show we are in the wrong place!
                                        this.visual.currentvisual.alpha = 0.3;


                                        // look at where we should be instead
                                        this.body.SetAngle(
                                            gap.GetRotation()
                                        );

                                        // and walk there!
                                        vx = Math.Cos(current.GetAngle()) * 0.5 * this.speed
                                           + Math.Cos(current.GetAngle() + Math.PI / 2) * 0 * this.speed;
                                        vy = Math.Sin(current.GetAngle()) * 0.5 * this.speed
                                               + Math.Sin(current.GetAngle() + Math.PI / 2) * 0 * this.speed;

                                        ApplyVelocityMoveToLocation = true;
                                    }
                                    else
                                    {
                                        var da0 = this.karmabody.GetAngle() - this.body.GetAngle();
                                        var da360 = (this.karmabody.GetAngle() + 360.DegreesToRadians()) - this.body.GetAngle();

                                        if (da0 < da360)
                                        {
                                            this.body.SetAngle(
                                                   this.body.GetAngle() + da0 * 0.2
                                            );
                                        }
                                        else
                                        {
                                            this.body.SetAngle(
                                                   this.body.GetAngle() + da360 * 0.2
                                            );
                                        }

                                        if (CloseEnough)
                                        {

                                        }
                                        else
                                        {
                                            this.body.SetPosition(
                                                new b2Vec2(
                                                    this.body.GetPosition().x + gap.x * 0.3,
                                                    this.body.GetPosition().y + gap.y * 0.3
                                                )
                                            );
                                        }
                                    }
                                }

                        }
                #endregion


                current.SetLinearVelocity(
                    new b2Vec2(
                     vx, vy


                    )
                );
            }


            // what about our karma body?
            if (this.KarmaInput0.Count > 0)
            {
                var _karma__keyDown = this.KarmaInput0.Peek();

                var _karma_velocity = new Velocity();


                ExtractVelocityFromInput(_karma__keyDown, _karma_velocity);

                var current = this.karmabody;
                //var v = _karma_velocity.AngularVelocity * 10;
                //current.SetAngularVelocity(v);

                this.karmabody.ApplyAngularImpulse(
                    _karma_velocity.AngularVelocity
                    * ApplyVelocityElapse.ElapsedMilliseconds
                    * 0.5
                    * (1 - (this.karmabody.GetLinearVelocity().Length() / this.speed).Min(0.9) * 0.25)
                );


                var vx = Math.Cos(current.GetAngle()) * _karma_velocity.LinearVelocityY * this.speed
                                   + Math.Cos(current.GetAngle() + Math.PI / 2) * _karma_velocity.LinearVelocityX * this.speed;
                var vy = Math.Sin(current.GetAngle()) * _karma_velocity.LinearVelocityY * this.speed
                        + Math.Sin(current.GetAngle() + Math.PI / 2) * _karma_velocity.LinearVelocityX * this.speed;

                current.SetLinearVelocity(
                    new b2Vec2(
                     vx, vy
                    )
                );

                if (_karma__keyDown.fixup)
                {
                    var fixupmultiplier = 0.90;
                    // like a magnet
                    current.SetPositionAndAngle(
                        new b2Vec2(
                            _karma__keyDown.x + (current.GetPosition().x - _karma__keyDown.x) * fixupmultiplier,
                            _karma__keyDown.y + (current.GetPosition().y - _karma__keyDown.y) * fixupmultiplier
                        ),
                        // meab me in scotty
                            _karma__keyDown.angle + (current.GetAngle() - _karma__keyDown.angle) * fixupmultiplier

                    );
                }
            }


            this.damagebody.SetPositionAndAngle(
               new b2Vec2(this.body.GetPosition().x, this.body.GetPosition().y), this.body.GetAngle()
             );

            ApplyVelocityElapse.Restart();
        }
        public StarlingGameSpriteWithPhysics()
        {
            sessionid = random.Next();


            //b2Body ground_current = null;
            //b2Body air_current = null;




            #region ground_b2world
            // first frame  ... set up our physccs
            // zombies!!
            ground_b2world = new b2World(new b2Vec2(0, 0), false);
            ground_b2world.SetContactListener(
               new XContactListener()
            );

            var ground_b2debugDraw = new b2DebugDraw();

            ground_dd = new ScriptCoreLib.ActionScript.flash.display.Sprite();
            ground_dd.transform.colorTransform = new ColorTransform(0.0, 0, 1.0);





            ground_b2debugDraw.SetSprite(ground_dd);
            // textures are 512 pixels, while our svgs are 400px
            // so how big is a meter in our game world? :)
            ground_b2debugDraw.SetDrawScale(16);
            ground_b2debugDraw.SetFillAlpha(0.1);
            ground_b2debugDraw.SetLineThickness(1.0);
            ground_b2debugDraw.SetFlags(b2DebugDraw.e_shapeBit);

            ground_b2world.SetDebugDraw(ground_b2debugDraw);





            #endregion


            #region groundkarma_b2world
            // first frame  ... set up our physccs
            // zombies!!
            groundkarma_b2world = new b2World(new b2Vec2(0, 0), false);

            var groundkarma_b2debugDraw = new b2DebugDraw();

            groundkarma_dd = new ScriptCoreLib.ActionScript.flash.display.Sprite();
            groundkarma_dd.transform.colorTransform = new ColorTransform(0.0, 1.0, 0.0);





            groundkarma_b2debugDraw.SetSprite(groundkarma_dd);
            // textures are 512 pixels, while our svgs are 400px
            // so how big is a meter in our game world? :)
            groundkarma_b2debugDraw.SetDrawScale(16);
            groundkarma_b2debugDraw.SetFillAlpha(0.1);
            groundkarma_b2debugDraw.SetLineThickness(1.0);
            groundkarma_b2debugDraw.SetFlags(b2DebugDraw.e_shapeBit);

            groundkarma_b2world.SetDebugDraw(groundkarma_b2debugDraw);





            #endregion

            #region air_b2world
            // first frame  ... set up our physccs
            // zombies!!
            air_b2world = new b2World(new b2Vec2(0, 0), false);

            var air_b2debugDraw = new b2DebugDraw();

            air_dd = new ScriptCoreLib.ActionScript.flash.display.Sprite();

            // make it red!
            air_dd.transform.colorTransform = new ColorTransform(1.0, 0, 0);
            // make it slave
            air_dd.alpha = 0.3;





            air_b2debugDraw.SetSprite(air_dd);
            // textures are 512 pixels, while our svgs are 400px
            // so how big is a meter in our game world? :)
            air_b2debugDraw.SetDrawScale(16);
            air_b2debugDraw.SetFillAlpha(0.1);
            air_b2debugDraw.SetLineThickness(1.0);
            air_b2debugDraw.SetFlags(b2DebugDraw.e_shapeBit);

            air_b2world.SetDebugDraw(air_b2debugDraw);








            #endregion

            #region damage_b2world
            // first frame  ... set up our physccs
            // zombies!!
            damage_b2world = new b2World(new b2Vec2(0, 0), false);
            damage_b2world.SetContactListener(
               new XContactListener { DiscardSmallImpulse = false }
            );

            var damage_b2debugDraw = new b2DebugDraw();

            damage_dd = new ScriptCoreLib.ActionScript.flash.display.Sprite();

            // make it red!
            //air_dd.transform.colorTransform = new ColorTransform(1.0, 0, 0);
            // make it slave
            damage_dd.alpha = 0.3;





            damage_b2debugDraw.SetSprite(air_dd);
            // textures are 512 pixels, while our svgs are 400px
            // so how big is a meter in our game world? :)
            damage_b2debugDraw.SetDrawScale(16);
            damage_b2debugDraw.SetFillAlpha(0.1);
            damage_b2debugDraw.SetLineThickness(1.0);
            damage_b2debugDraw.SetFlags(b2DebugDraw.e_shapeBit);

            damage_b2world.SetDebugDraw(damage_b2debugDraw);








            #endregion

            #region smoke_b2world
            // first frame  ... set up our physccs
            // zombies!!
            smoke_b2world = new b2World(new b2Vec2(0, 0), false);

            var smoke_b2debugDraw = new b2DebugDraw();

            smoke_dd = new ScriptCoreLib.ActionScript.flash.display.Sprite();

            // make it red!
            //air_dd.transform.colorTransform = new ColorTransform(1.0, 0, 0);
            // make it slave
            smoke_dd.alpha = 0.3;





            smoke_b2debugDraw.SetSprite(air_dd);
            // textures are 512 pixels, while our svgs are 400px
            // so how big is a meter in our game world? :)
            smoke_b2debugDraw.SetDrawScale(16);
            smoke_b2debugDraw.SetFillAlpha(0.1);
            smoke_b2debugDraw.SetLineThickness(1.0);
            smoke_b2debugDraw.SetFlags(b2DebugDraw.e_shapeBit);

            smoke_b2world.SetDebugDraw(smoke_b2debugDraw);








            #endregion



            //#region obstacles
            //{
            //    var bodyDef = new b2BodyDef();

            //    bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody;

            //    // stop moving if legs stop walking!
            //    bodyDef.linearDamping = 10.0;
            //    bodyDef.angularDamping = 0.3;
            //    //bodyDef.angle = 1.57079633;
            //    bodyDef.fixedRotation = true;

            //    var body = air_b2world.CreateBody(bodyDef);
            //    body.SetPosition(new b2Vec2(10, 10));

            //    var fixDef = new Box2D.Dynamics.b2FixtureDef();
            //    fixDef.density = 0.1;
            //    fixDef.friction = 0.01;
            //    fixDef.restitution = 0;


            //    fixDef.shape = new Box2D.Collision.Shapes.b2CircleShape(4);


            //    var fix = body.CreateFixture(fixDef);

            //    body.SetPosition(
            //        new b2Vec2(-8, 0)
            //    );
            //}

            //{
            //    var bodyDef = new b2BodyDef();

            //    bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody;

            //    // stop moving if legs stop walking!
            //    bodyDef.linearDamping = 10.0;
            //    bodyDef.angularDamping = 0.3;
            //    //bodyDef.angle = 1.57079633;
            //    bodyDef.fixedRotation = true;

            //    var body = ground_b2world.CreateBody(bodyDef);
            //    body.SetPosition(new b2Vec2(10, 10));

            //    var fixDef = new Box2D.Dynamics.b2FixtureDef();
            //    fixDef.density = 0.1;
            //    fixDef.friction = 0.01;
            //    fixDef.restitution = 0;


            //    fixDef.shape = new Box2D.Collision.Shapes.b2CircleShape(4);


            //    var fix = body.CreateFixture(fixDef);


            //    body.SetPosition(
            //        new b2Vec2(8, -8)
            //    );
            //}

            //{
            //    var bodyDef = new b2BodyDef();

            //    bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody;

            //    // stop moving if legs stop walking!
            //    bodyDef.linearDamping = 10.0;
            //    bodyDef.angularDamping = 0.3;
            //    //bodyDef.angle = 1.57079633;
            //    bodyDef.fixedRotation = true;

            //    var body = groundkarma_b2world.CreateBody(bodyDef);
            //    body.SetPosition(new b2Vec2(10, 10));

            //    var fixDef = new Box2D.Dynamics.b2FixtureDef();
            //    fixDef.density = 0.1;
            //    fixDef.friction = 0.01;
            //    fixDef.restitution = 0;


            //    fixDef.shape = new Box2D.Collision.Shapes.b2CircleShape(4);


            //    var fix = body.CreateFixture(fixDef);


            //    body.SetPosition(
            //        new b2Vec2(8, 8)
            //    );
            //}
            //#endregion


            physicstime.Start();

            this.onbeforefirstframe += (stage, s) =>
            {
                if (!disablephysicsdiagnostics)
                {
                    s.nativeOverlay.addChild(ground_dd);
                    s.nativeOverlay.addChild(groundkarma_dd);
                    s.nativeOverlay.addChild(air_dd);
                    s.nativeOverlay.addChild(damage_dd);
                }
                // 1000 / 15
                var syncframeinterval = 1000 / 15;
                var syncframesince = 0L;
                var syncframeextra = 0L;


                // NaN ?
                syncframeid = 0;
                syncframetime = 0;


                var prevvelocity = 0.0;
                onframe +=
                    delegate
                    {
                        // drop frames
                        //if (frameid % 2 == 0)
                        //    return;

                        var physicstime_elapsed = physicstime.ElapsedMilliseconds + syncframeextra;
                        syncframeextra = 0;

                        // physicstime_elapsed needs to be split!

                        var physicstime_elapsed_PRE = physicstime_elapsed;




                        physicstime.Restart();

                        // add up the time we are spending
                        syncframesince += physicstime_elapsed;

                        #region raise_onsyncframe
                        var raise_onsyncframe = false;
                        // time for sync frame yet?
                        if (syncframesince >= syncframeinterval)
                        {
                            // time for syncframe!
                            raise_onsyncframe = true;

                            // does it actually help us? disabled for now
                            var dx = syncframesince - syncframeinterval;
                            syncframesince = 0;

                            // Error: raise_onsyncframe: { physicstime_elapsed_PRE = 275, dx = 75, physicstime_elapsed_POST = 0 }

                            physicstime_elapsed_PRE -= dx;
                            syncframeextra += dx;


                            // dropping frames?
                            //syncframeextra = Math.Min(syncframeextra, syncframeinterval);
                        }
                        #endregion


                        var iterations = 10;

                        syncframetime += physicstime_elapsed_PRE;

                        #region PRE Step

                        //update physics world
                        ground_b2world.Step(physicstime_elapsed_PRE / 1000.0, iterations, iterations);
                        groundkarma_b2world.Step(physicstime_elapsed_PRE / 1000.0, iterations, iterations);
                        air_b2world.Step(physicstime_elapsed_PRE / 1000.0, iterations, iterations);
                        damage_b2world.Step(physicstime_elapsed_PRE / 1000.0, iterations, iterations);
                        smoke_b2world.Step(physicstime_elapsed_PRE / 1000.0, iterations, iterations);
                        #endregion

                        ground_b2world.ClearForces();
                        groundkarma_b2world.ClearForces();
                        air_b2world.ClearForces();
                        damage_b2world.ClearForces();
                        smoke_b2world.ClearForces();


                        #region DrawDebugData ClearForces
                        if (!disablephysicsdiagnostics)
                        {

                            ground_b2world.DrawDebugData();
                            groundkarma_b2world.DrawDebugData();
                            air_b2world.DrawDebugData();
                            damage_b2world.DrawDebugData();
                            smoke_b2world.DrawDebugData();
                        }
                        #endregion

                        // syncframe
                        if (raise_onsyncframe)
                        {
                            syncframeid++;
                            this.onsyncframe(stage, s);

                            foreach (var item in units)
                            {
                                item.FeedKarma();
                            }
                        }


                        #region air_dd vs ground_dd
                        if (current != null)
                            if (current.body.GetWorld() == air_b2world)
                            {
                                air_dd.alpha = 0.6;
                                ground_dd.alpha = 0.1;
                            }
                            else
                            {
                                air_dd.alpha = 0.1;
                                ground_dd.alpha = 0.6;
                            }
                        #endregion

                        #region DisableDefaultContentDransformation
                        DisableDefaultContentDransformation = true;
                        {
                            var cm = new Matrix();

                            var any_movement = 0.0;

                            if (current != null)
                            {
                                cm.translate(
                                    -(current.body.GetPosition().x * 16),
                                    -(current.body.GetPosition().y * 16)
                                );



                                cm.rotate(-current.body.GetAngle() - Math.PI / 2 + current.CameraRotation);


                                if (current.body.GetType() == Box2D.Dynamics.b2Body.b2_dynamicBody)
                                {
                                    any_movement = (
                                        current.body.GetLinearVelocity().Length() +
                                        Math.Abs(current.body.GetAngularVelocity())
                                        )

                                    / 15.0;
                                }
                                else
                                {
                                    // force movement mode in a building
                                    any_movement = 1.0;
                                }

                            }


                            //cm.rotate(-current.GetAngle());








                            move_zoom +=
                               (any_movement - 0.5) *
                                 physicstime_elapsed * 0.004;
                            move_zoom = move_zoom.Max(0.0).Min(1.0);

                            var xinternalscale = internalscale;

                            if (disable_movezoom_and_altitude_for_scale)
                            {
                                // nop
                            }
                            else
                            {
                                xinternalscale +=
                                    +0.20 * (1.0 - current.Altitude)
                                    + ((1.0 - move_zoom) * 0.04);
                            }

                            var diagonal = new __vec2
                            {
                                x = stage.stageWidth,
                                y = stage.stageHeight
                            };

                            //stagescale = xinternalscale * (stage.stageWidth) / (800.0);
                            stagescale = xinternalscale * (diagonal.GetLength()) / (1000.0);


                            cm.scale(stagescale, stagescale);


                            cm.translate(
                                (stage.stageWidth * 0.5),
                                (stage.stageHeight * internal_center_y)
                            );


                            Content.transformationMatrix = cm;

                            ground_dd.transform.matrix = cm;
                            groundkarma_dd.transform.matrix = cm;
                            air_dd.transform.matrix = cm;
                            damage_dd.transform.matrix = cm;
                        }
                        #endregion



                        foreach (var item in units)
                        {
                            item.ShowPositionAndAngle();

                            #region driverseat
                            if (item.driverseat != null)
                                if (item.driverseat.driver != null)
                                {
                                    var driver = item.driverseat.driver;

                                    driver.SetPositionAndAngle(


                                            item.body.GetPosition().x + Math.Cos(item.body.GetAngle() - Math.PI * 0.5 - item.CameraRotation) * 2.2,
                                            item.body.GetPosition().y + Math.Sin(item.body.GetAngle() - Math.PI * 0.5 - item.CameraRotation) * 2.2
                                        ,
                                        item.body.GetAngle() - item.CameraRotation
                                    );

                                    driver.ShowPositionAndAngle();
                                }
                            #endregion

                            item.ApplyVelocity();
                        }





                    };
            };


        }
        public void ApplyVelocity()
        {
            if (this.visual.Altitude != 0)
                if (AutomaticTouchdown)
                    if (this.driverseat.driver == null)
                    {
                        this.VerticalVelocity = -0.4;

                        // reset

                        this.AngularVelocity = 0;
                        this.LinearVelocityX = 0;
                        this.LinearVelocityY = 0;
                    }

            var dx = Context.gametime.ElapsedMilliseconds - ApplyVelocityElapsed;
            ApplyVelocityElapsed = Context.gametime.ElapsedMilliseconds;


            {
                var current = this.body;
                //var v = this.AngularVelocity * 10;
                //current.SetAngularVelocity(v);



                current.ApplyAngularImpulse(
                    this.AngularVelocity
                     * this.CurrentInput.forcex
                    * 0.4
                    * (1 - (this.body.GetLinearVelocity().Length() / this.speed).Min(0.9) * 0.5)
                );


                var vx = Math.Cos(current.GetAngle()) * this.LinearVelocityY * this.speed * this.CurrentInput.forcey
                        + Math.Cos(current.GetAngle() + Math.PI / 2) * this.LinearVelocityX * this.speed * this.CurrentInput.forcex;
                var vy = Math.Sin(current.GetAngle()) * this.LinearVelocityY * this.speed * this.CurrentInput.forcey
                        + Math.Sin(current.GetAngle() + Math.PI / 2) * this.LinearVelocityX * this.speed * this.CurrentInput.forcex;




                #region RemoteGameReference
                if (RemoteGameReference != null)
                    if (vx == 0)
                        if (vy == 0)
                        //if (v == 0)
                        {
                            // not moving anymore in network mode
                            // far enough to be out of sync?

                            //if (karmabody.GetAngularVelocity() == 0)
                            if (body.GetLinearVelocity().Length() == 0)
                                if (this.KarmaInput0.All(k => k.value == 0))
                                {




                                    var gap = new __vec2(
                                        (float)this.groundkarma_body.GetPosition().x - (float)this.body.GetPosition().x,
                                        (float)this.groundkarma_body.GetPosition().y - (float)this.body.GetPosition().y
                                    );

                                    // tolerate lesser distance?

                                    var da0 = this.groundkarma_body.GetAngle() - this.body.GetAngle();
                                    var da360 = (this.groundkarma_body.GetAngle() + 360.DegreesToRadians()) - this.body.GetAngle();

                                    if (da0 < da360)
                                    {
                                        this.body.SetAngle(
                                               this.body.GetAngle() + da0 * 0.2
                                        );
                                    }
                                    else
                                    {
                                        this.body.SetAngle(
                                               this.body.GetAngle() + da360 * 0.2
                                        );
                                    }


                                    this.body.SetPosition(
                                        new b2Vec2(
                                            this.body.GetPosition().x + gap.x * 0.1,
                                            this.body.GetPosition().y + gap.y * 0.1
                                        )
                                    );
                                }

                        }
                #endregion







                this.body.SetLinearVelocity(
                    new b2Vec2(
                     vx, vy


                    )
                );

                // attempt to course correct if near 90 degree angles!

                //if (this.AngularVelocity == 0)
                //{
                //    var fixupmultiplier = 0.90;

                //    var fixai = (current.GetAngle().RadiansToDegrees() / 4.0);

                //    if (AngularVelocitySign > 0)
                //        fixai = Math.Ceiling(fixai);
                //    else
                //        fixai = Math.Floor(fixai);

                //    var fixaf = (fixai * 16).DegreesToRadians();


                //    // like a magnet
                //    current.SetAngle(
                //        // meab me in scotty
                //            fixaf + (current.GetAngle() - fixaf) * fixupmultiplier

                //    );
                //}
                //else
                //{
                //    AngularVelocitySign = Math.Sign(this.AngularVelocity);
                //}
            }


            this.visual.Altitude =
                (this.visual.Altitude + 0.005 * dx * this.VerticalVelocity).Max(0).Min(1);


            // what about our karma body?
            if (this.KarmaInput0.Count > 0)
            {
                var _karma__keyDown = this.KarmaInput0.Peek();

                var _karma_velocity = new Velocity();


                ExtractVelocityFromInput(_karma__keyDown, _karma_velocity);

                var current = this.groundkarma_body;
                //var v = _karma_velocity.AngularVelocity * 10;
                //current.SetAngularVelocity(v);


                current.ApplyAngularImpulse(
                    this.AngularVelocity * 0.6 * (1 - (current.GetLinearVelocity().Length() / this.speed).Min(0.9) * 0.5)
                );


                var vx = Math.Cos(current.GetAngle()) * _karma_velocity.LinearVelocityY * this.speed
                                   + Math.Cos(current.GetAngle() + Math.PI / 2) * _karma_velocity.LinearVelocityX * this.speed;
                var vy = Math.Sin(current.GetAngle()) * _karma_velocity.LinearVelocityY * this.speed
                        + Math.Sin(current.GetAngle() + Math.PI / 2) * _karma_velocity.LinearVelocityX * this.speed;

                current.SetActive(
                    _karma__keyDown.BodyIsActive
                );

                current.SetLinearVelocity(
                    new b2Vec2(
                     vx, vy
                    )
                );

                if (_karma__keyDown.fixup)
                {
                    var fixupmultiplier = 0.90;

                    // like a magnet
                    current.SetPositionAndAngle(
                        new b2Vec2(
                            _karma__keyDown.x + (current.GetPosition().x - _karma__keyDown.x) * fixupmultiplier,
                            _karma__keyDown.y + (current.GetPosition().y - _karma__keyDown.y) * fixupmultiplier
                        ),
                        // meab me in scotty
                            _karma__keyDown.angle + (current.GetAngle() - _karma__keyDown.angle) * fixupmultiplier

                    );
                }
            }
        }
        public PhysicalBunker(StarlingGameSpriteWithBunkerTextures textures, StarlingGameSpriteWithPhysics Context, bool IsShop = false)
        {
            var textures_bunker = textures;

            this.CurrentInput = new KeySample();

            this.driverseat = new DriverSeat();

            this.textures = textures;
            this.Context = Context;


            for (int i = 0; i < 7; i++)
            {
                this.KarmaInput0.Enqueue(
                    new KeySample()
                );
            }

            visualshadow = new Image(
               textures.bunker2_shadow()
           ).AttachTo(Context.Content_layer2_shadows);

            visual = new Sprite().AttachTo(Context.Content_layer3_buildings);


            visual_body = new Image(
               textures.bunker2()
           ).AttachTo(visual);

            visual_shopoverlay = new Image(
                 textures.bunker2_shopoverlay()
             ).AttachTo(visual);

            visual_shopoverlay_arrow = new Image(
                 textures.bunker2_shopoverlay_arrow()
             ).AttachTo(visual);


            if (IsShop)
            {

                #region hud_arrow
                var hud_arrow = new Image(
                      textures_bunker.bunker2_shopoverlay_arrow()
                  ).AttachTo(Context);


                StarlingGameSpriteWithPhysics.onframe +=
                    (ScriptCoreLib.ActionScript.flash.display.Stage stage, Starling starling) =>
                    {
                        var gap = new __vec2(
                             (float)(this.body.GetPosition().x - Context.current.body.GetPosition().x),
                             (float)(this.body.GetPosition().y - Context.current.body.GetPosition().y)
                         );

                        var distance = gap.GetLength();

                        if (distance < 40)
                        {
                            visual_shopoverlay_arrow.visible = true;
                            hud_arrow.visible = false;
                            return;
                        }


                        //if (distance < 50)
                        //{
                        //    visual_shopoverlay_arrow.visible = false;
                        //    hud_arrow.visible = false;
                        //    return;
                        //}

                        visual_shopoverlay_arrow.visible = false;
                        hud_arrow.visible = true;

                        var cm = new Matrix();

                        // 
                        var yy = 8 * Math.Sin(this.Context.gametime.ElapsedMilliseconds * 0.002);



                        cm.translate(-128, -128 - 64 + yy);


                        cm.scale(Context.stagescale, Context.stagescale);


                        cm.rotate(gap.GetRotation() - Context.current.body.GetAngle() + Context.current.CameraRotation);

                        cm.translate(
                            (stage.stageWidth * 0.5),
                            (stage.stageHeight * Context.internal_center_y)
                        );


                        hud_arrow.transformationMatrix = cm;
                    };
                #endregion

            }

            this.IsShop = IsShop;

            #region damage_b2world
            {
                //initialize body
                var bdef = new b2BodyDef();
                bdef.angle = 0;
                bdef.fixedRotation = true;
                this.damagebody = Context.damage_b2world.CreateBody(bdef);

                //initialize shape
                var fixdef = new b2FixtureDef();

                var shape = new b2PolygonShape();
                fixdef.shape = shape;

                shape.SetAsBox(4.5, 4.5);

                fixdef.restitution = 0.4; //positively bouncy!



                var fix = this.damagebody.CreateFixture(fixdef);

                var fix_data = new Action<double>(
                     force =>
                     {
                         if (force < 1)
                             return;

                         Context.oncollision(this, force);
                     }
                );

                fix.SetUserData(fix_data);
            }
            #endregion


            #region ground_b2world
            {
                //initialize body
                var bdef = new b2BodyDef();
                bdef.angle = 0;
                bdef.fixedRotation = true;
                this.body = Context.ground_b2world.CreateBody(bdef);

                //initialize shape
                var fixdef = new b2FixtureDef();

                var shape = new b2PolygonShape();
                fixdef.shape = shape;

                shape.SetAsBox(4.5, 4.5);

                fixdef.restitution = 0.4; //positively bouncy!



                var fix = this.body.CreateFixture(fixdef);

                var fix_data = new Action<double>(
                     force =>
                     {
                         if (force < 1)
                             return;

                         Context.oncollision(this, force);
                     }
                );

                fix.SetUserData(fix_data);
            }
            #endregion

            {
                //initialize body
                var bdef = new b2BodyDef();
                bdef.angle = 0;
                bdef.fixedRotation = true;
                this.karmabody = Context.groundkarma_b2world.CreateBody(bdef);

                //initialize shape
                var fixdef = new b2FixtureDef();

                var shape = new b2PolygonShape();
                fixdef.shape = shape;


                shape.SetAsBox(4.5, 4.5);
                fixdef.restitution = 0.4; //positively bouncy!



                this.karmabody.CreateFixture(fixdef);
            }
            Context.internalunits.Add(this);
        }
        public void ApplyVelocity()
        {
            // this is now

            {
                var current = this.body;
                //var v = velocity.AngularVelocity * 10;         current.SetAngularVelocity(v);


                current.ApplyAngularImpulse(
                    velocity.AngularVelocity
                      * this.CurrentInput.forcex
                    * ApplyVelocityElapse.ElapsedMilliseconds
                    * 0.01
                    * (1 - (this.body.GetLinearVelocity().Length() / this.speed).Min(0.9) * 0.5)
                );



                var vx = Math.Cos(current.GetAngle()) * velocity.LinearVelocityY * this.speed * this.CurrentInput.forcey
                    + Math.Cos(current.GetAngle() + Math.PI / 2) * velocity.LinearVelocityX * this.speed;
                var vy = Math.Sin(current.GetAngle()) * velocity.LinearVelocityY * this.speed * this.CurrentInput.forcey
                        + Math.Sin(current.GetAngle() + Math.PI / 2) * velocity.LinearVelocityX * this.speed;


                this.visual.currentvisual.alpha = 1.0;

                #region RemoteGameReference
                if (RemoteGameReference != null)
                    if (vx == 0)
                        if (vy == 0)
                            //if (v == 0)
                            {
                                // not moving anymore in network mode
                                // far enough to be out of sync?

                                if (karmabody.GetLinearVelocity().Length() == 0)
                                    if (this.KarmaInput0.All(k => k.value == 0))
                                    {

                                        this.body.SetAngle(
                                             karmabody.GetAngle()
                                         );


                                        var gap = new __vec2(
                                            (float)this.karmabody.GetPosition().x - (float)this.body.GetPosition().x,
                                            (float)this.karmabody.GetPosition().y - (float)this.body.GetPosition().y
                                        );

                                        // tolerate lesser distance?
                                        if (gap.GetLength() > 0.5)
                                        {
                                            //this.body.SetPositionAndAngle(
                                            //    new b2Vec2(
                                            //        this.karmabody.GetPosition().x,
                                            //        this.karmabody.GetPosition().y
                                            //    ),
                                            //    this.karmabody.GetAngle()
                                            //);

                                            // show we are in the wrong place!
                                            this.visual.currentvisual.alpha = 0.3;


                                            // look at where we should be instead
                                            this.body.SetAngle(
                                                gap.GetRotation()
                                            );

                                            // and walk there!
                                            vx = Math.Cos(current.GetAngle()) * 0.5 * this.speed
                                               + Math.Cos(current.GetAngle() + Math.PI / 2) * 0 * this.speed;
                                            vy = Math.Sin(current.GetAngle()) * 0.5 * this.speed
                                                   + Math.Sin(current.GetAngle() + Math.PI / 2) * 0 * this.speed;
                                        }
                                    }

                            }
                #endregion

       
                current.SetLinearVelocity(
                    new b2Vec2(
                     vx, vy
                    )
                );

            }

            // what about our karma body?
            if (this.KarmaInput0.Count > 0)
            {
                var _karma__keyDown = this.KarmaInput0.Peek();

                var _karma_velocity = new Velocity();


                ExtractVelocityFromInput(_karma__keyDown, _karma_velocity);

                var current = this.karmabody;
                //var v = _karma_velocity.AngularVelocity * 10;
                //current.SetAngularVelocity(v);

                current.ApplyAngularImpulse(
                    _karma_velocity.AngularVelocity
                    * ApplyVelocityElapse.ElapsedMilliseconds
                   * 0.01
                    * (1 - (current.GetLinearVelocity().Length() / this.speed).Min(0.9) * 0.5)
                );


                var vx = Math.Cos(current.GetAngle()) * _karma_velocity.LinearVelocityY * this.speed
                                   + Math.Cos(current.GetAngle() + Math.PI / 2) * _karma_velocity.LinearVelocityX * this.speed;
                var vy = Math.Sin(current.GetAngle()) * _karma_velocity.LinearVelocityY * this.speed
                        + Math.Sin(current.GetAngle() + Math.PI / 2) * _karma_velocity.LinearVelocityX * this.speed;


                current.SetActive(
                     _karma__keyDown.BodyIsActive
                 );

                current.SetLinearVelocity(
                    new b2Vec2(
                     vx, vy
                    )
                );

                if (_karma__keyDown.fixup)
                {
                    var fixupmultiplier = 0.90;

                    current.SetAngle(
                        // meab me in scotty,
                         _karma__keyDown.angle + (current.GetAngle() - _karma__keyDown.angle) * fixupmultiplier

                    );



                    var gap = new __vec2(
                        (float)this.karmabody.GetPosition().x - (float)_karma__keyDown.x,
                        (float)this.karmabody.GetPosition().y - (float)_karma__keyDown.y
                    );

                    if (gap.GetLength() > 0.1)
                    {
                        current.SetLinearVelocity(
                             new b2Vec2(
                              vx - gap.x * 2.0,
                              vy - gap.y * 2.0
                             )
                         );
                    }
                }
            }
            ApplyVelocityElapse.Restart();
        }
        public void ApplyVelocity()
        {
            unit4_physics.update(Context.gametime.ElapsedMilliseconds - xgt);


            #region RemoteGameReference
            if (RemoteGameReference != null)
            {
                //this.visual0.currentvisual.alpha = 0.5;

                // not moving anymore in network mode
                // far enough to be out of sync?

                if (karmaunit4_physics.body.GetLinearVelocity().Length() < 0.5)
                    if (this.KarmaInput0.All(k => k.value == 0))
                    {
                        var gap = new __vec2(
                            (float)this.karmaunit4_physics.body.GetPosition().x - (float)this.body.GetPosition().x,
                            (float)this.karmaunit4_physics.body.GetPosition().y - (float)this.body.GetPosition().y
                        );

                        this.body.SetAngle(
                               this.body.GetAngle() + (this.karmaunit4_physics.body.GetAngle() - this.body.GetAngle()) * 0.2
                        );

                        // tolerate lesser distance?
                        //if (gap.GetLength() > 3)
                        {

                            // too much out of sync!
                            var TooMuchOutOfSyncOrOutOfView = gap.GetLength() > 10;
                            if (TooMuchOutOfSyncOrOutOfView)
                            {
                                this.body.SetPositionAndAngle(
                                    new b2Vec2(
                                        this.karmaunit4_physics.body.GetPosition().x,
                                        this.karmaunit4_physics.body.GetPosition().y
                                    ),
                                    this.karmaunit4_physics.body.GetAngle()
                                );
                            }
                            else
                            {
                                this.body.SetPosition(
                                    new b2Vec2(
                                        this.body.GetPosition().x + gap.x * 0.2,
                                        this.body.GetPosition().y + gap.y * 0.2
                                    )
                                );
                            }


                            // look at where we should be instead


                        }
                    }

            }
            #endregion



            // what about our karma body?
            if (this.KarmaInput0.Count > 0)
            {
                var _karma__keyDown = this.KarmaInput0.Peek();
                ExtractVelocityFromInput(_karma__keyDown, karmaunit4_physics);


                karmaunit4_physics.update(Context.gametime.ElapsedMilliseconds - xgt);



                if (_karma__keyDown.fixup)
                {
                    var fixupmultiplier = 0.95;

                    // like a magnet
                    karmaunit4_physics.body.SetPositionAndAngle(
                        new b2Vec2(
                            _karma__keyDown.x + (karmaunit4_physics.body.GetPosition().x - _karma__keyDown.x) * fixupmultiplier,
                            _karma__keyDown.y + (karmaunit4_physics.body.GetPosition().y - _karma__keyDown.y) * fixupmultiplier
                        ),
                        // meab me in scotty,
                            _karma__keyDown.angle + (karmaunit4_physics.body.GetAngle() - _karma__keyDown.angle) * fixupmultiplier

                    );
                }


            }

            xgt = Context.gametime.ElapsedMilliseconds;
        }
        public SpiralSurface(ISurface v)
        {
            v.onsurface +=
               gl =>
               {
                   //var __gl = (ScriptCoreLib.Android.__WebGLRenderingContext)(object)gl;

                   //Log.wtf("AndroidGLSpiralActivity", "onsurface");

                   var buffer = gl.createBuffer();

                   gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

                   gl.bufferData(gl.ARRAY_BUFFER,
                    new Float32Array(
                            -1.0f, -1.0f, 1.0f,
                            -1.0f, -1.0f, 1.0f,
                            1.0f, -1.0f, 1.0f,
                            1.0f, -1.0f, 1.0f
                    ), gl.STATIC_DRAW);


                   // Create Program



                   #region createProgram

                   var program = gl.createProgram(
                       new SpiralVertexShader(),
                       new SpiralFragmentShader()
                   );



                   gl.linkProgram(program);
                   gl.useProgram(program);



                   #endregion

                   var parameters_time = 0L;
                   var parameters_screenWidth = 0;
                   var parameters_screenHeight = 0;
                   var parameters_aspectX = 0.0f;
                   var parameters_aspectY = 1.0f;

                   #region onresize
                   v.onresize +=
                       (width, height) =>
                       {
                           //Log.wtf("AndroidGLSpiralActivity", "onresize");

                           parameters_screenWidth = width;
                           parameters_screenHeight = height;

                           parameters_aspectX = (float)width / (float)height;
                           parameters_aspectY = 1.0f;

                           gl.viewport(0, 0, width, height);
                       };
                   #endregion


                   #region onframe
                   var framecount = 0;
                   v.onframe +=
                       delegate
                       {
                           var time = parameters_time / 1000f;

                           //if (framecount == 0)
                           //    Log.wtf("AndroidGLSpiralActivity", "onframe " + ((object)time).ToString());

                           parameters_time += 100;

                           gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

                           // Load program into GPU


                           // Get var locations

                           var vertex_position = gl.getAttribLocation(program, "position");

                           // Set values to program variables

                           dynamic program_uniforms = new ShaderProgramUniforms
                           {
                               gl = gl,
                               program = program
                           };

                           var resolution = new __vec2 { x = parameters_screenWidth, y = parameters_screenHeight };
                           var aspect = new __vec2 { x = parameters_aspectX, y = parameters_aspectY };

                           program_uniforms.time = time;
                           program_uniforms.resolution = resolution;
                           program_uniforms.aspect = aspect;

                           // Render geometry

                           gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
                           //opengl.glVertexAttribPointer(vertex_position, 2, (int)gl.FLOAT, false, 0, 0);
                           gl.vertexAttribPointer((uint)vertex_position, 2, gl.FLOAT, false, 0, 0);
                           gl.enableVertexAttribArray((uint)vertex_position);
                           gl.drawArrays(gl.TRIANGLES, 0, 6);
                           gl.disableVertexAttribArray((uint)vertex_position);

                           framecount++;
                       };
                   #endregion

                   //Log.wtf("AndroidGLSpiralActivity", "onsurface done");

               };
        }
        protected override void onCreate(Bundle savedInstanceState)
        {
            base.onCreate(savedInstanceState);
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

            //this.ToFullscreen();

            var v = new RenderingContextView(this);

            v.onsurface +=
                gl =>
                {
                    //var __gl = (ScriptCoreLib.Android.__WebGLRenderingContext)(object)gl;



                    Log.wtf("AndroidGLDisturbActivity", "onsurface");

                    // Create Vertex buffer (2 triangles)

                    var buffer = gl.createBuffer();
                    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
                    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f), gl.STATIC_DRAW);



                    // Create Program


                    #region createProgram

                    var program = gl.createProgram(
                        new DisturbVertexShader(),
                        new DisturbFragmentShader()
                    );



                    gl.linkProgram(program);
                    gl.useProgram(program);



                    #endregion

                    var uniforms = program.Uniforms(gl);

                    #region loadTexture
                    Func<android.graphics.Bitmap, ScriptCoreLib.JavaScript.WebGL.WebGLTexture> loadTexture = (image) =>
                    {
                        var texture_ = gl.createTexture();

                        gl.enable(gl.TEXTURE_2D);
                        gl.bindTexture(gl.TEXTURE_2D, texture_);

                        //public void texImage2D(uint target, int level, uint internalformat, uint format, uint type, IHTMLCanvas canvas);
                        //public void texImage2D(uint target, int level, uint internalformat, uint format, uint type, IHTMLVideo video);
                        //public void texImage2D(uint target, int level, uint internalformat, uint format, uint type, ImageData pixels);
                        //public void texImage2D(uint target, int level, uint internalformat, int width, int height, int border, uint format, uint type, ArrayBufferView pixels);

                        //public void texImage2D(uint target, int level, uint internalformat, uint format, uint type, IHTMLImage image);
                        //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

                        //GLUtils.texImage2D(
                        //    /*target*/ (int)gl.TEXTURE_2D,
                        //    /*level*/ 0,
                        //    /*internalformat*/(int)gl.RGBA,
                        //    image,
                        //    /*type*/  (int)gl.UNSIGNED_BYTE,
                        //    0
                        //);

                        GLUtils.texImage2D((int)gl.TEXTURE_2D, 0, image, 0);

                        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, (int)gl.LINEAR);
                        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, (int)gl.LINEAR_MIPMAP_LINEAR);
                        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, (int)gl.REPEAT);
                        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, (int)gl.REPEAT);
                        gl.generateMipmap(gl.TEXTURE_2D);


                        // Recycle the bitmap, since its data has been loaded into OpenGL.
                        image.recycle();


                        return texture_;
                    };
                    #endregion

                    #region openFileFromAssets
                    Func<string, InputStream> openFileFromAssets = (string spath) =>
                    {
                        InputStream value = null;
                        try
                        {
                            value = this.getResources().getAssets().open(spath);
                        }
                        catch
                        {

                        }
                        return value;

                    };
                    #endregion

                    var texture__ = android.graphics.BitmapFactory.decodeStream(
                        openFileFromAssets("assets/AndroidGLDisturbActivity/disturb.jpg")
                    );
                    var texture = loadTexture(
                        texture__
                    );

                    var vertexPositionLocation = default(long);
                    var textureLocation = default(WebGLUniformLocation);

                    var parameters_time = 0L;
                    var parameters_screenWidth = 0;
                    var parameters_screenHeight = 0;
                    var parameters_aspectX = 0.0f;
                    var parameters_aspectY = 1.0f;

                    #region onresize
                    v.onresize +=
                        (width, height) =>
                        {
                            Log.wtf("AndroidGLDisturbActivity", "onresize");

                            parameters_screenWidth = width;
                            parameters_screenHeight = height;

                            gl.viewport(0, 0, width, height);
                        };
                    #endregion


                    #region onframe
                    var framecount = 0;
                    v.onframe +=
                        delegate
                        {
                            var time = parameters_time / 1000f;

                            if (framecount == 0)
                                Log.wtf("AndroidGLDisturbActivity", "onframe " + ((object)time).ToString());

                            parameters_time += 100;

                            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

                            // Load program into GPU


                            // Get var locations

                            vertexPositionLocation = gl.getAttribLocation(program, "position");
                            textureLocation = gl.getUniformLocation(program, "texture");

                            // Set values to program variables


                            var resolution = new __vec2 { x = parameters_screenWidth, y = parameters_screenHeight };

                            uniforms.time = time;
                            uniforms.resolution = resolution;

                            //gl.uniform1f(gl.getUniformLocation(program, "time"), time);
                            //gl.uniform2f(gl.getUniformLocation(program, "resolution"), parameters_screenWidth, parameters_screenHeight);

                            gl.uniform1i(textureLocation, 0);
                            gl.activeTexture(gl.TEXTURE0);
                            gl.bindTexture(gl.TEXTURE_2D, texture);

                            // Render geometry

                            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
                            gl.vertexAttribPointer((uint)vertexPositionLocation, 2, gl.FLOAT, false, 0, 0);
                            gl.enableVertexAttribArray((uint)vertexPositionLocation);
                            gl.drawArrays(gl.TRIANGLES, 0, 6);
                            gl.disableVertexAttribArray((uint)vertexPositionLocation);




                            framecount++;
                        };
                    #endregion

                    Log.wtf("AndroidGLDisturbActivity", "onsurface done");

                };


            this.setContentView(v);

            //this.TryHideActionbar(v);

            this.ShowToast("http://my.jsc-solutions.net");
        }
        /// <summary>
        /// This is a javascript application.
        /// </summary>
        /// <param name="page">HTML document rendered by the web server which can now be enhanced.</param>
        public Application(IDefault page = null)
        {
            // view-source:http://mrdoob.com/lab/javascript/webgl/glsl/04/

            var time = new Stopwatch();
            time.Start();

            var parameters_screenWidth = 0;
            var parameters_screenHeight = 0;

            var gl = new WebGLRenderingContext();
            var canvas = gl.canvas.AttachToDocument();


            #region IsDisposed
            var IsDisposed = false;

            Dispose = delegate
            {
                if (IsDisposed)
                    return;

                IsDisposed = true;

                canvas.Orphanize();
            };
            #endregion

            // Create Vertex buffer (2 triangles)

            var buffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f), gl.STATIC_DRAW);

            // Create Program


            var program = gl.createProgram(
                new DisturbVertexShader(),
                new DisturbFragmentShader()
            );

            gl.linkProgram(program);
            gl.useProgram(program);


            #region loadTexture
            Action<IHTMLImage, WebGLTexture> loadTexture =
                async (image, texture_) =>
                {
                    await image;


                    gl.enable(gl.TEXTURE_2D);
                    gl.bindTexture(gl.TEXTURE_2D, texture_);
                    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, (int)gl.LINEAR);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, (int)gl.LINEAR_MIPMAP_LINEAR);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, (int)gl.REPEAT);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, (int)gl.REPEAT);
                    gl.generateMipmap(gl.TEXTURE_2D);
                    gl.bindTexture(gl.TEXTURE_2D, null);

                };
            #endregion


            var texture = gl.createTexture();

            loadTexture(new HTML.Images.FromAssets.disturb(), texture);


            var vertexPositionLocation = default(long);
            var textureLocation = default(WebGLUniformLocation);

            #region resize
            Action resize = delegate
            {
                canvas.style.SetLocation(0, 0);

                canvas.width = Native.window.Width;
                canvas.height = Native.window.Height;

                parameters_screenWidth = canvas.width;
                parameters_screenHeight = canvas.height;

                gl.viewport(0, 0, canvas.width, canvas.height);
            };

            Native.window.onresize +=
                delegate
                {
                    if (IsDisposed)
                        return;

                    resize();
                };

            resize();
            #endregion




            Native.window.onframe +=
                delegate
                {
                    if (IsDisposed)
                        return;

                    if (program == null) return;


                    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

                    // Load program into GPU


                    // Get var locations

                    vertexPositionLocation = gl.getAttribLocation(program, "position");
                    textureLocation = gl.getUniformLocation(program, "texture");

                    // Set values to program variables

                    var program_uniforms = program.Uniforms(gl);


                    var resolution = new __vec2 { x = parameters_screenWidth, y = parameters_screenHeight };


                    program_uniforms.time = time.ElapsedMilliseconds / 1000f;

                    // could the uniform accept anonymous type and infer vec2 based on x and y?
                    program_uniforms.resolution = resolution;

                    //gl.uniform1f(gl.getUniformLocation(program, "time"), parameters_time / 1000);
                    //gl.uniform2f(gl.getUniformLocation(program, "resolution"), parameters_screenWidth, parameters_screenHeight);

                    gl.uniform1i(textureLocation, 0);
                    gl.activeTexture(gl.TEXTURE0);
                    gl.bindTexture(gl.TEXTURE_2D, texture);

                    // Render geometry

                    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
                    gl.vertexAttribPointer((uint)vertexPositionLocation, 2, gl.FLOAT, false, 0, 0);
                    gl.enableVertexAttribArray((uint)vertexPositionLocation);
                    gl.drawArrays(gl.TRIANGLES, 0, 6);
                    gl.disableVertexAttribArray((uint)vertexPositionLocation);


                };


            #region requestFullscreen
            Native.document.body.ondblclick +=
                delegate
                {
                    if (IsDisposed)
                        return;

                    // http://tutorialzine.com/2012/02/enhance-your-website-fullscreen-api/

                    Native.document.body.requestFullscreen();


                };
            #endregion



        }
 public static void uniform2f(this gl gl, WebGLUniformLocation location, __vec2 xy)
 {
     gl.uniform2f(location, xy.x, xy.y);
 }