package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.text.TextField; public class elasticity extends Sprite { public var container:Sprite = new Sprite(); public var bd:BitmapData; // vector for drawing triangles public var v:Vector.>; public var uvtData:Vector.>; public var indices:Vector.>; // original position public var oldV:Vector.Vector.>; // target position for vertices after click and each drag public var newV:Vector.Vector.>; // coordinates for rendering e.g. when point going to final pos public var renderV:Vector.>; public var velocity:Vector.>; public var drawingSequenceIndex:int; public var drawingSequence:Vector.>; // pic width and height public var pw:Number; public var ph:Number; // the point where the mouse click on the image public var clickPoint:Point; public var oldMouse:Point; public var isDragging:Boolean; public var dir:Array; public var k:Number; public var k2:Number; public var k3:Number; public var friction:Number; [Embed(source = '../lib/chess.jpg')] public var pic:Class; public function elasticity():void { dir = new Array([1, 0], [0, 1], [ -1, 0], [0, -1]); // force factor for moving to the target position k = .75; // force factor from surrounding 4 connected vertices k2 = .296; // force factor from original position of a point k3 = .13; // friction = .68; bd = (new pic as Bitmap).bitmapData; pw = bd.width; ph = bd.height; clickPoint = new Point(pw/2,ph/2); initialize_v(); drawingSequenceIndex = 0; drawingSequence = new Vector.>(); drawingSequence.push(Vector.([0,1,3,2])); // moving up and left drawingSequence.push(Vector.([1,0,2,3])); // moving up and right drawingSequence.push(Vector.([3,2,0,1])); // moving down and left drawingSequence.push(Vector.([2,3,1,0])); // moving down and right v = new Vector.>(); reset_v(oldV); uvtData = new Vector.>(); reset_uvt(clickPoint); indices = new Vector.>(); indices.push(Vector.([0, 1, 3, 1, 2, 3])); indices.push(Vector.([0, 1, 2, 0, 2, 3])); indices.push(Vector.([0, 1, 3, 1, 2, 3])); indices.push(Vector.([0, 1, 2, 0, 2, 3])); isDragging = false; velocity = new Vector.>(); velocity.push(Vector.([new Point(0, 0),new Point(0, 0),new Point(0, 0)])); velocity.push(Vector.([new Point(0, 0),new Point(0, 0),new Point(0, 0)])); velocity.push(Vector.([new Point(0, 0),new Point(0, 0),new Point(0, 0)])); addChild(container); container.x = (stage.stageWidth-pw)/2; container.y = (stage.stageHeight-ph)/2; container.addEventListener(MouseEvent.MOUSE_DOWN, onClick); stage.addEventListener(MouseEvent.MOUSE_UP, onRelease); addEventListener(Event.ENTER_FRAME, onEnterFrame); // } public function onEnterFrame(e:Event):void { if (isDragging) { var currentMouse:Point = new Point(container.mouseX, container.mouseY); newV[1][1] = currentMouse; renderV[1][1] = currentMouse; determine_drawingSequence(currentMouse); oldMouse = new Point(container.mouseX, container.mouseY); } for (var y:int = 0; y < oldV.length; y++ ) { for (var x:int = 0; x < oldV[0].length; x++ ) { if (x == 1 && y == 1) { if (!isDragging) { elastic(y, x); } }else { elastic(y, x); } } } // Vector v will be drawn out by drawTriangles, so convert renderV into v // since renderV contains the actual coordinates to be drawn reset_v(renderV); container.graphics.clear(); for (var j:int = 0; j < 4; j++) { var i:int = drawingSequence[drawingSequenceIndex][j]; container.graphics.beginBitmapFill(bd); container.graphics.drawTriangles(v[i], indices[i], uvtData[i]); } } // elasticity of vertices public function elastic(y:int,x:int):void { var m:int; var n:int; var inc:Point; var inc2:Point; var acc:Point; acc = new Point(); inc = new Point(); inc2 = newV[y][x].subtract(oldV[y][x]); for (var i:int = 0; i < dir.length; i++ ) { if (y + dir[i][1] >= 0 && y + dir[i][1] < oldV.length && x + dir[i][0] >= 0 && x + dir[i][0] < oldV[0].length) { m = y + dir[i][1]; n = x + dir[i][0]; inc = inc.add(newV[m][n].subtract(oldV[m][n])); } } newV[y][x].x = oldV[y][x].x + k2 * inc.x - k3 * inc2.x; newV[y][x].y = oldV[y][x].y + k2 * inc.y - k3 * inc2.y; // acc.x = k * (newV[y][x].x - renderV[y][x].x); acc.y = k * (newV[y][x].y - renderV[y][x].y); // velocity[y][x] = velocity[y][x].add(acc); velocity[y][x].x *= friction; velocity[y][x].y *= friction; // renderV[y][x] = renderV[y][x].add(velocity[y][x]); } // Determine drawing sequence of quadrants by relative position of current mouse position // to the original click position, so that theie depths are in correct order public function determine_drawingSequence(newMouse:Point):void { if (newMouse.y <= clickPoint.y && newMouse.x <= clickPoint.x) { //Moving up and left drawingSequenceIndex = 0; }else if (newMouse.y <= clickPoint.y && newMouse.x >= clickPoint.x) { //Moving up and right drawingSequenceIndex = 1; }else if (newMouse.y >= clickPoint.y && newMouse.x <= clickPoint.x) { //Moving down and left drawingSequenceIndex = 2; }else if (newMouse.y >= clickPoint.y && newMouse.x >= clickPoint.x) { //Moving down and right drawingSequenceIndex = 3; } } public function onClick(e:Event):void { clickPoint = new Point(e.target.mouseX, e.target.mouseY); oldMouse = new Point(e.target.mouseX, e.target.mouseY); // update vertices after click on image update_v_data(); // update uvtData after click on image for correct mapping reset_uvt(clickPoint); isDragging = true; } public function onRelease(e:Event):void { isDragging = false; } // When the image is clicked, change the central and its 4 connected vertices public function update_v_data():void { oldV[0][1] = new Point(clickPoint.x,0); oldV[1][0] = new Point(0,clickPoint.y); oldV[1][1] = clickPoint; oldV[1][2] = new Point(pw,clickPoint.y); oldV[2][1] = new Point(clickPoint.x, ph); // newV[0][1] = new Point(clickPoint.x,0); newV[1][0] = new Point(0,clickPoint.y); newV[1][1] = clickPoint; newV[1][2] = new Point(pw,clickPoint.y); newV[2][1] = new Point(clickPoint.x, ph); // renderV[0][1] = new Point(clickPoint.x,0); renderV[1][0] = new Point(0,clickPoint.y); renderV[1][1] = clickPoint; renderV[1][2] = new Point(pw,clickPoint.y); renderV[2][1] = new Point(clickPoint.x, ph); } // update the vector for drawing the triangles // parameter = the set of vertices to be drawn public function reset_v(p:Vector.>):void { v = new Vector.>(); v.push(Vector.([p[0][0].x,p[0][0].y, p[0][1].x,p[0][1].y, p[1][1].x,p[1][1].y, p[1][0].x,p[1][0].y])); v.push(Vector.([p[0][1].x,p[0][1].y, p[0][2].x,p[0][2].y, p[1][2].x,p[1][2].y, p[1][1].x,p[1][1].y])); v.push(Vector.([p[1][1].x,p[1][1].y, p[1][2].x,p[1][2].y, p[2][2].x,p[2][2].y, p[2][1].x,p[2][1].y])); v.push(Vector.([p[1][0].x,p[1][0].y, p[1][1].x,p[1][1].y, p[2][1].x,p[2][1].y, p[2][0].x,p[2][0].y])); } // set the uvtData for the 4 quadrants public function reset_uvt(p:Point):void { var hr:Number = p.x / pw; var vr:Number = p.y / ph; uvtData = new Vector.>(); uvtData.push(Vector.([0,0,1, hr,0,1, hr,vr,1, 0,vr,1])); uvtData.push(Vector.([hr,0,1, 1,0,1, 1,vr,1, hr,vr,1])); uvtData.push(Vector.([hr,vr,1, 1,vr,1, 1,1,1, hr,1,1])); uvtData.push(Vector.([0,vr,1, hr,vr,1, hr,1,1, 0,1,1])); } public function initialize_v():void { // Vector.slice is not working yet in FP10 beta oldV = new Vector.>(); oldV.push(Vector.([new Point(0, 0),new Point(pw / 2, 0),new Point(pw, 0)])); oldV.push(Vector.([new Point(0, ph/2),clickPoint,new Point(pw, ph/2)])); oldV.push(Vector.([new Point(0, ph),new Point(pw / 2, ph),new Point(pw, ph)])); newV = new Vector.>(); newV.push(Vector.([new Point(0, 0),new Point(pw / 2, 0),new Point(pw, 0)])); newV.push(Vector.([new Point(0, ph/2),clickPoint,new Point(pw, ph/2)])); newV.push(Vector.([new Point(0, ph),new Point(pw / 2, ph),new Point(pw, ph)])); renderV = new Vector.>(); renderV.push(Vector.([new Point(0, 0),new Point(pw / 2, 0),new Point(pw, 0)])); renderV.push(Vector.([new Point(0, ph/2),clickPoint,new Point(pw, ph/2)])); renderV.push(Vector.([new Point(0, ph),new Point(pw / 2, ph),new Point(pw, ph)])); } } }