flash on 2014-10-29

by mutantleg
followup to: http://wonderfl.net/c/ur0E
now with quaternions and fancy math
♥0 | Line 216 | Modified 2014-10-29 09:02:41 | MIT License
play

ActionScript3 source code

/**
 * Copyright mutantleg ( http://wonderfl.net/user/mutantleg )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/6HYm
 */

package {
    import flash.utils.Dictionary;
    import flash.events.Event;
    import flash.display.Sprite;
    public class FlashTest extends Sprite {
        public function FlashTest() {
            
          myChar = new xChar();  
          dictBone = new Dictionary();


          var a:xBone;          
          
          //second thought..  adding new bones will need some rethinking
          
          //0
          a = addBone(myChar);  dictBone["root"] = a;
       
           //1   
              a = addBone(myChar); a.pos.x=32; a.pos.y=32; dictBone["leg1a"] = a; 
              a.parent = 0; a.depth = 1;
             //2     
              a = addBone(myChar); a.pos.x=0; a.pos.y=32; dictBone["leg2a"] = a; 
              a.parent = 1; a.depth = 2;    
             //3     
              a = addBone(myChar); a.pos.x=0; a.pos.y=32; dictBone["leg3a"] = a; 
              a.parent = 2; a.depth = 3;                  
             //4     
              a = addBone(myChar); a.pos.x=0; a.pos.z=-24; dictBone["leg4a"] = a; 
              a.parent = 3; a.depth = 4;                  
              
          //5
          a = addBone(myChar); a.pos.x=-32; a.pos.y=32; dictBone["leg1b"] = a; 
          a.parent = 0; a.depth = 1;
          //6        
          a = addBone(myChar); a.pos.x=0; a.pos.y=32; dictBone["leg2b"] = a; 
          a.parent = 5; a.depth = 2;
          //7        
          a = addBone(myChar); a.pos.x=0; a.pos.y=32; dictBone["leg3b"] = a; 
          a.parent = 6; a.depth = 3;
          //8     
          a = addBone(myChar); a.pos.x=0; a.pos.z=-24; dictBone["leg4b"] = a; 
          a.parent = 7; a.depth = 4;                  
      
          myChar.update();
          
          
          
            
          stage.addEventListener(Event.ENTER_FRAME, onEnter);  
        }//ctor
        
        public var dictBone:Dictionary;
        
        public var myChar:xChar;
         
        public function addBone(ch:xChar):xBone
        {
          var a:xBone; a = new xBone();
          a.id = ch.vecBone.length;
          ch.vecBone.push(a);
          return a;   
        } //addbone

        public var gt:int = 0;        
        
        public function onEnter(e:Event):void
        {
          graphics.clear();  
          graphics.lineStyle(2, 0);
            
          var sx:Number;          var sy:Number;
          sx = 230;        sy = 230;   
            
          var a:xBone; var p:xBone;
          var vec:Vector.<xBone>;
          var num:int; var i:int;
             
          var ang:Number;
          var xang:Number;
          ang = gt * 0.05;
          xang = Math.sin(ang) * Math.cos(ang);

          a = dictBone["root"];
          a.ori.reset();   //a.ori.rotAxis(-xang, 2);
          a.pos.y = Math.sin(Math.abs(xang)*-2)*64;
          
          //still needs tweaks
          //when it goes down it should do this
          //but im too tired
          //     **    **\    \      ***   |
          // |****/   |****    \       ****|
          // |        |         \/
          
          a = dictBone["leg1a"];
          a.ori.reset();   a.ori.rotAxis(xang*3,0);
          a.pos.z = xang*32;
          a = dictBone["leg2a"];
          a.ori.reset();   a.ori.rotAxis(xang+1,0);

          a = dictBone["leg1b"];
          a.ori.reset();   a.ori.rotAxis(-xang*3,0);
          a.pos.z = -xang*32;
          a = dictBone["leg2b"];
          a.ori.reset();   a.ori.rotAxis(-xang+1,0);
          

          myChar.ori.reset();
          myChar.ori.rotAxis(0.9, 0);
          //myChar.ori.rotAxis(0.4, 2);            
         // myChar.ori.rotAxis(1.5, 1);
          
          myChar.ori.rotAxis(gt*0.02, 1);
       
          myChar.update();
     
          vec = myChar.vecBone;
          num = vec.length;
          
          
          a = vec[0];
          
          graphics.lineStyle();
          graphics.beginFill(0, 0.2);
          //graphics.drawCircle(myChar.pos.x+sx, myChar.pos.y+sy+64,32);
          graphics.drawEllipse(myChar.pos.x+sx-32,myChar.pos.y+sy+80-16,64,32);
          graphics.endFill();
          
          graphics.lineStyle(4,0);
          for (i = 0; i < num; i++)
          {
             a = vec[i];
             graphics.drawCircle(a.wpos.x+sx,a.wpos.y+sy, 8); 
             if (a.depth <= 0) { continue; }
             p = vec[a.parent];
             graphics.moveTo(p.wpos.x+sx, p.wpos.y+sy);
             graphics.lineTo(a.wpos.x+sx, a.wpos.y+sy);
          }//nexti
          
          a = vec[0];
          graphics.beginFill(0xFF, 0.5);
             graphics.drawCircle(a.wpos.x+sx,a.wpos.y+sy, 32);           
          graphics.endFill();  
            
            
            gt += 1;
        }//onenter
        
    }//classend
}

import flash.geom.Matrix3D;

internal class xChar
{
  public var pos:xVec = new xVec();
  public var ori:xQuat = new xQuat();
  public var scale:xVec = new xVec(1, 1, 1);
  public var baseMat:Vector.<Number> = new Vector.<Number>(16, false);
  public var vecBone:Vector.<xBone> = new Vector.<xBone>(0, false);

  public var tempMat:Vector.<Number> = Vector.<Number>([1, 0, 0, 0,   0, 1, 0, 0,    0, 0, 1, 0,    0, 0, 0, 1]);

 public function update():void
  {
      var i:int;      var num:int;      var a:xBone;      var p:xBone;
      var rx:Number;      var ry:Number;      var rz:Number;
      var vec:Vector.<xBone>;      var mat:Vector.<Number>;     
      var pmat:Vector.<Number>;   var pori:xQuat;
  
      mat = baseMat;
      ori.setVec(mat);
      mat[12] = pos.x;        mat[13] = pos.y;        mat[14] = pos.z;

      mat[0] *= scale.x;    mat[1] *= scale.x;       mat[2] *= scale.x;        
      mat[4] *= scale.y;    mat[5] *= scale.y;       mat[6] *= scale.y;
      mat[8] *= scale.z;    mat[9] *= scale.z;       mat[10] *=scale.z;

      vec = vecBone;   num = vec.length;
      
      //bone vector is expected to be sorted by depth at this point
      for (i = 0; i < num; i++)
      {
        a = vec[i];
        
        if (a.depth <= 0)  {  pmat = baseMat;   pori = ori;  } //no parent bone: use root as parent
        else  {  p = vec[a.parent];   pmat = p.transMat;  pori = p.wori;  }
        
         mat = tempMat;           a.ori.setVec(mat);
         mat[12] = a.pos.x;            mat[13] = a.pos.y;            mat[14] = a.pos.z;
      
         mat[0] *= a.scale.x;          mat[1] *= a.scale.x;          mat[2] *= a.scale.x;  
         mat[4] *= a.scale.y;          mat[5] *= a.scale.y;          mat[6] *= a.scale.y;    
         mat[8] *= a.scale.z;          mat[9] *= a.scale.z;          mat[10] *= a.scale.z;

         multMatrix(pmat, tempMat,  a.transMat);

        //ori and position for attachments (world transform)
          a.wori.copyQuat(pori);
          a.wori.mul(a.ori);
          a.wori.normalise();
          a.wpos.setValue(a.transMat[12], a.transMat[13], a.transMat[14]);

      }//nexti
  }//update

    //only works of 4x4 matrices (16 Number)
    public function multMatrix(a:Vector.<Number>, b:Vector.<Number>, r:Vector.<Number>):void
    {
        var i:int;
        for (i = 0; i < 16; i += 4)
        {
            r[i] =     a[0] * b[i] + a[4] * b[i + 1] + a[8] * b[i + 2] + a[12] * b[i + 3];
            r[i + 1] = a[1] * b[i] + a[5] * b[i + 1] + a[9] * b[i + 2] + a[13] * b[i + 3];
            r[i + 2] = a[2] * b[i] + a[6] * b[i + 1] + a[10] * b[i + 2] + a[14] * b[i + 3];
            r[i + 3] = a[3] * b[i] + a[7] * b[i + 1] + a[11] * b[i + 2] + a[15] * b[i + 3];
        }//nexti
    }//multmatrix
        
}//xchar


internal class xBone
{
  public var pos:xVec = new xVec();    public var ori:xQuat = new xQuat();    //local pos
  public var wpos:xVec = new xVec();    public var wori:xQuat = new xQuat();  //world pos    
  public var scale:xVec = new xVec(1,1,1); //scale
  public var transMat:Vector.<Number> = new Vector.<Number>(16, false);
  public var parent:int = 0;
  public var id:int = 0;
  public var depth:int = 0;
  public var spec:int = 0;
}//xbone


internal class xVec
{
  public var x:Number = 0;  public var y:Number = 0;  public var z:Number = 0;
  public function xVec(ax:Number=0,ay:Number=0,az:Number=0)
  { x = ax; y = ay; z = az; }
  public function setValue(ax:Number=0,ay:Number=0,az:Number=0):void
  { x = ax; y = ay; z = az; }
}//xvec


internal class xQuat
{
 public var x:Number = 0;        public var y:Number = 0;    
 public var z:Number = 0;        public var w:Number = 1;

  public function reset():void {    x = 0;  y = 0;  z = 0;  w = 1;}
  public function copyQuat(a:xQuat):void { x=a.x; y=a.y; z=a.z; w=a.w; }
    
  public function normalise():void
    {
        var mag:Number;        mag = (x * x) + (y * y) + (z * z) + (w * w);
            if (mag == 1.0) return; //already normal
            if (mag == 0) { x = 0;  y = 0;  z = 0;  w = 1; return; }
        mag = 1.0 / Math.sqrt(mag);
        x *= mag;            y *= mag;            z *= mag;            w *= mag;
    }//norm
  
  public function mul(a:xQuat):void
    {
        var tx:Number;            var ty:Number;            var tz:Number;            var tw:Number;
        tx =    (w * a.x + x * a.w + y * a.z - z * a.y);            ty =    (w * a.y + y * a.w + z * a.x - x * a.z);
        tz =    (w * a.z + z * a.w + x * a.y - y * a.x);            tw =    (w * a.w - x * a.x - y * a.y - z * a.z);
        x = tx;            y = ty;            z = tz;            w = tw;
    }//mul
    

    //0 x  1 y  2 z
    public function rotAxis(ang:Number, xyz:int=0):void
    {
        ang *= 0.5;
        var ax:Number; var ay:Number; var az:Number; var aw:Number;
        var tx:Number; var ty:Number; var tz:Number; var tw:Number;
        ax = xyz==0? Math.sin(ang):0;            ay  = xyz==1? Math.sin(ang):0;        az = xyz==2? Math.sin(ang):0;            aw = Math.cos(ang);
        tx =    (w * ax + x * aw + y * az - z * ay);            ty =    (w * ay + y * aw + z * ax - x * az);
        tz =    (w * az + z * aw + x * ay - y * ax);            tw =    (w * aw - x * ax - y * ay - z * az);
        x = tx;            y = ty;            z = tz;            w = tw;     
        normalise();        
    }//rotaxis
    
    public function nlerp(q1:xQuat, q2:xQuat, t:Number):void
    {
      var dot:Number;    var b:Number;    var rx:Number;     var ry:Number;     var rz:Number;     var rw:Number; 
      dot = q1.w*q2.w + q1.x*q2.x + q1.y*q2.y + q1.z * q2.z;
      b = 1.0 - t;  if (dot < 0) { t = -t;}
      w = b * q1.w + t * q2.w;      x = b * q1.x + t * q2.x;      y = b * q1.y + t * q2.y;      z = b * q1.z + t * q2.z;
    }//nlerp
    
    public function setVec(vec:Vector.<Number>):void
    {
        var xx:Number      = x * x;            var xy:Number      = x * y;            var xz:Number      = x * z;            var xw:Number      = x * w;
        var yy:Number      = y * y;            var yz:Number      = y * z;          var yw:Number      = y * w;
        var zz:Number      = z * z;            var zw:Number      = z * w;
        vec[3]  = vec[7] = vec[11] = vec[12] = vec[13] = vec[14] = 0.0;            vec[15] = 1.0;
        vec[0]  = 1.0 - 2.0 * ( yy + zz );            vec[4]  =     2.0 * ( xy - zw );            vec[8]  =     2.0 * ( xz + yw );
        vec[1]  =  2.0 * ( xy + zw ) ;                vec[5]  = 1.0 - 2.0 * ( xx + zz ) ;      vec[9]  =  2.0 * ( yz - xw ) ;
        vec[2]  =     2.0 * ( xz - yw );              vec[6]  =     2.0 * ( yz + xw );            vec[10] = 1.0 - 2.0 * ( xx + yy );        
    }//setvec

    public static var tempVec:Vector.<Number> = new Vector.<Number>(16, false);
    public function setMatrix(m:Matrix3D):void  { setVec(tempVec); m.rawData = tempVec;  }

}//xquat