/// matrix4f.cpp
///
/// (c) 2008-2018 by Carsten Busse <carsten.busse@googlemail.com>
///                  Bastian Spiegel <bs@tkscript.de> (additional coding)
///     - Distributed under terms of the Lesser GNU General Public License (LGPL).
///       See COPYING and <http://www.gnu.org/licenses/licenses.html#LGPL> for further information.
///
///

#include <math.h>

#include "tkmath_yac.h"
#include "tkmath.h"
#include "matrix.h"
#include "vector3f.h"
#include "vector4f.h"
#include "matrix4f.h"
#include "quaternionf.h"

#include "ying_Math.h"


const sU8 matrix4_element_order_table[2][4][4] =
   {
      // Row major
      {
         { 0,  1,  2,  3},
         { 4,  5,  6,  7},
         { 8,  9, 10, 11},
         {12, 13, 14, 15}
      },
      
      // Column major
      {
         { 0,  4,  8, 12},
         { 1,  5,  9, 13},
         { 2,  6, 10, 14},
         { 3,  7, 11, 15}
      }
   };



_Matrix4f::_Matrix4f(void) {
   _initIdentity();
}

_Matrix4f::~_Matrix4f() {
}

// Helper macros to access elements
#define TM4F(r,c)  floats[TM4(r,c)]
#define OM4F(r,c)  o->floats[OM4(r,c)]
#define M4F(a,r,c) (a)->floats[M4(a,r,c)]



// void _Matrix4f::_setColumnMajor(sSI _bEnabled) {
// }

// sSI _Matrix4f::_getColumnMajor(void) {
// }


sUI YAC_VCALL _Matrix4f::yacArrayGetNumElements(void) {
   return 16;
}

sUI YAC_VCALL _Matrix4f::yacArrayGetMaxElements(void) {
   return 16;
}

sUI YAC_VCALL _Matrix4f::yacArrayGetElementType(void) {
   return YAC_TYPE_FLOAT;
}

sUI YAC_VCALL _Matrix4f::yacArrayGetElementByteSize(void) {
   return sizeof(sF32);
}

void YAC_VCALL _Matrix4f::yacArraySet(YAC_ContextHandle _ctx, sUI _idx, YAC_Value *_val) {
   if(_idx < 16) 
   {
      sF32 v = 0.0f;
      switch (_val->type) 
      {
         case YAC_TYPE_VOID:
            v = 0.0f;
            break;

         case YAC_TYPE_INT:
            v = (sF32)_val->value.int_val;
            break;

         case YAC_TYPE_FLOAT:
            v = _val->value.float_val;
            break;

         case YAC_TYPE_OBJECT:
            if(YAC_VALID(_val->value.object_val)) 
            {
               if(!_val->value.object_val->yacScanF32(&v))
               {
                  v = 0.0f;
               }
            }
            break;

         default:
            Dyac_throw(TypeMismatch, "tkmath::Matrix4f::yacArraySet: Unknown Type!");
            v = 0.0f;
            break;
      }
      floats[_idx] = v;
   } 
   else 
   {
      /*not thread safe*/ static char buf[256];
      sprintf(buf, "tkmath::Matrix4f::yacArraySet: Index too high (%d>15)", _idx);
      Dyac_throw(WriteArrayOutOfBounds, buf);
   }
}

void YAC_VCALL _Matrix4f::yacArrayGet(YAC_ContextHandle _ctx, sUI _idx, YAC_Value *_val) {
   if(_idx < 16) 
   {
      _val->initFloat(floats[_idx]);
   } 
   else 
   {
      /*not thread safe*/ static char buf[256];
      sprintf(buf, "tkmath::Matrix4f::yacArrayGet Index too high (%d>15)", _idx);
      Dyac_throw(ReadArrayOutOfBounds, buf);
      _val->initFloat(0.0f);
   }
}

void *YAC_VCALL _Matrix4f::yacArrayGetPointer(void) {
   return (void*)floats;
}

sUI YAC_VCALL _Matrix4f::yacArrayGetWidth(void) {
   return 4;
}

sUI YAC_VCALL _Matrix4f::yacArrayGetHeight(void) {
   return 4;
}

sUI YAC_VCALL _Matrix4f::yacArrayGetStride(void) {
   return 4 * sizeof(sF32);
}

sSI YAC_VCALL _Matrix4f::yacTensorRank(void) {
   return YAC_TENSOR_RANK_MATRIX;
}

void YAC_VCALL _Matrix4f::yacSerialize(YAC_Object *_ofs, sUI _rtti) {
   YAC_BEG_SERIALIZE();
   YAC_SERIALIZE_I32(b_column_major);
   YAC_SERIALIZE_F32(floats[ 0]);
   YAC_SERIALIZE_F32(floats[ 1]);
   YAC_SERIALIZE_F32(floats[ 2]);
   YAC_SERIALIZE_F32(floats[ 3]);
   YAC_SERIALIZE_F32(floats[ 4]);
   YAC_SERIALIZE_F32(floats[ 5]);
   YAC_SERIALIZE_F32(floats[ 6]);
   YAC_SERIALIZE_F32(floats[ 7]);
   YAC_SERIALIZE_F32(floats[ 8]);
   YAC_SERIALIZE_F32(floats[ 9]);
   YAC_SERIALIZE_F32(floats[10]);
   YAC_SERIALIZE_F32(floats[11]);
   YAC_SERIALIZE_F32(floats[12]);
   YAC_SERIALIZE_F32(floats[13]);
   YAC_SERIALIZE_F32(floats[14]);
   YAC_SERIALIZE_F32(floats[15]);
}

sUI YAC_VCALL _Matrix4f::yacDeserialize(YAC_Object *_ifs, sUI _rtti) {
   sBool bCM;

   YAC_BEG_DESERIALIZE();

   // Deserialize column/row format, 1=column major, 0=row major
   bCM = YAC_DESERIALIZE_I32();

#ifdef USE_DYNAMIC_ORDER
   b_column_major = bCM;
   floats[ 0] = YAC_DESERIALIZE_F32();
   floats[ 1] = YAC_DESERIALIZE_F32();
   floats[ 2] = YAC_DESERIALIZE_F32();
   floats[ 3] = YAC_DESERIALIZE_F32();
   floats[ 4] = YAC_DESERIALIZE_F32();
   floats[ 5] = YAC_DESERIALIZE_F32();
   floats[ 6] = YAC_DESERIALIZE_F32();
   floats[ 7] = YAC_DESERIALIZE_F32();
   floats[ 8] = YAC_DESERIALIZE_F32();
   floats[ 9] = YAC_DESERIALIZE_F32();
   floats[10] = YAC_DESERIALIZE_F32();
   floats[11] = YAC_DESERIALIZE_F32();
   floats[12] = YAC_DESERIALIZE_F32();
   floats[13] = YAC_DESERIALIZE_F32();
   floats[14] = YAC_DESERIALIZE_F32();
   floats[15] = YAC_DESERIALIZE_F32();
#else
   if(bCM)
   {
      // Column major
      floats[ 0] = YAC_DESERIALIZE_F32();
      floats[ 1] = YAC_DESERIALIZE_F32();
      floats[ 2] = YAC_DESERIALIZE_F32();
      floats[ 3] = YAC_DESERIALIZE_F32();
      floats[ 4] = YAC_DESERIALIZE_F32();
      floats[ 5] = YAC_DESERIALIZE_F32();
      floats[ 6] = YAC_DESERIALIZE_F32();
      floats[ 7] = YAC_DESERIALIZE_F32();
      floats[ 8] = YAC_DESERIALIZE_F32();
      floats[ 9] = YAC_DESERIALIZE_F32();
      floats[10] = YAC_DESERIALIZE_F32();
      floats[11] = YAC_DESERIALIZE_F32();
      floats[12] = YAC_DESERIALIZE_F32();
      floats[13] = YAC_DESERIALIZE_F32();
      floats[14] = YAC_DESERIALIZE_F32();
      floats[15] = YAC_DESERIALIZE_F32();
   }
   else
   {
      // Convert row to column major
      floats[ 0] = YAC_DESERIALIZE_F32();
      floats[ 4] = YAC_DESERIALIZE_F32();
      floats[ 8] = YAC_DESERIALIZE_F32();
      floats[12] = YAC_DESERIALIZE_F32();
      floats[ 1] = YAC_DESERIALIZE_F32();
      floats[ 5] = YAC_DESERIALIZE_F32();
      floats[ 9] = YAC_DESERIALIZE_F32();
      floats[13] = YAC_DESERIALIZE_F32();
      floats[ 2] = YAC_DESERIALIZE_F32();
      floats[ 6] = YAC_DESERIALIZE_F32();
      floats[10] = YAC_DESERIALIZE_F32();
      floats[14] = YAC_DESERIALIZE_F32();
      floats[ 3] = YAC_DESERIALIZE_F32();
      floats[ 7] = YAC_DESERIALIZE_F32();
      floats[11] = YAC_DESERIALIZE_F32();
      floats[15] = YAC_DESERIALIZE_F32();
   }
#endif // USE_DYNAMIC_ORDER
   return 1;
}

void YAC_VCALL _Matrix4f::yacOperatorClamp(YAC_Object *_min, YAC_Object *_max) {
   if(YAC_CHK(_min,clid_Matrix4f) && YAC_CHK(_max,clid_Matrix4f)) 
   {
      _Matrix4f *min = (_Matrix4f*)_min;
      _Matrix4f *max = (_Matrix4f*)_max;

#define Dclamp(r,c)                      \
      if(TM4F(r,c) < M4F(min,r,c))       \
      {                                  \
         TM4F(r,c) = M4F(min,r,c);       \
      }                                  \
      else if(TM4F(r,c) > M4F(max,r,c))  \
      {                                  \
         TM4F(r,c) = M4F(max,r,c);       \
      }

      Dclamp(0,0) Dclamp(0,1) Dclamp(0,2) Dclamp(0,3)
      Dclamp(1,0) Dclamp(1,1) Dclamp(1,2) Dclamp(1,3)
      Dclamp(2,0) Dclamp(2,1) Dclamp(2,2) Dclamp(2,3)
      Dclamp(3,0) Dclamp(3,1) Dclamp(3,2) Dclamp(3,3)

#undef Dclamp
   }
   else 
   {
      Dyac_throw_def(InvalidPointer, "");
   }
}

void YAC_VCALL _Matrix4f::yacOperatorWrap(YAC_Object *_min, YAC_Object *_max) {
   if (YAC_CHK(_min,clid_Matrix4f)&&YAC_CHK(_max,clid_Matrix4f)) {
      _Matrix4f *min = (_Matrix4f*)_min;
      _Matrix4f *max = (_Matrix4f*)_max;

#define Dwrap(r,c)\
      if(TM4F(r,c) < M4F(min,r,c))                 \
      {                                            \
         TM4F(r,c) += M4F(max,r,c) - M4F(min,r,c); \
      }                                            \
      else if(TM4F(r,c) > M4F(max,r,c))            \
      {                                            \
         TM4F(r,c) -= M4F(max,r,c) - M4F(min,r,c); \
      }

      Dwrap(0,0) Dwrap(0,1) Dwrap(0,2) Dwrap(0,3)
      Dwrap(1,0) Dwrap(1,1) Dwrap(1,2) Dwrap(1,3)
      Dwrap(2,0) Dwrap(2,1) Dwrap(2,2) Dwrap(2,3)
      Dwrap(3,0) Dwrap(3,1) Dwrap(3,2) Dwrap(3,3)

#undef Dwrap
   } 
   else 
   {
      Dyac_throw_def(InvalidPointer, "");
   }
}

void YAC_VCALL _Matrix4f::yacOperator(sSI _cmd, YAC_Object *_o, YAC_Value *_r) {
   if(YAC_CHK(_o, clid_Matrix4f)) 
   {
      _Matrix4f *o = (_Matrix4f*)_o;
      switch (_cmd) 
      {
         case YAC_OP_CEQ:
            YAC_RETI( Dfltequal(TM4F(0,0), OM4F(0,0)) &&
                      Dfltequal(TM4F(1,0), OM4F(1,0)) &&
                      Dfltequal(TM4F(2,0), OM4F(2,0)) &&
                      Dfltequal(TM4F(3,0), OM4F(3,0)) &&
                      Dfltequal(TM4F(0,1), OM4F(0,1)) &&
                      Dfltequal(TM4F(1,1), OM4F(1,1)) &&
                      Dfltequal(TM4F(2,1), OM4F(2,1)) &&
                      Dfltequal(TM4F(3,1), OM4F(3,1)) &&
                      Dfltequal(TM4F(0,2), OM4F(0,2)) &&
                      Dfltequal(TM4F(1,2), OM4F(1,2)) &&
                      Dfltequal(TM4F(2,2), OM4F(2,2)) &&
                      Dfltequal(TM4F(3,2), OM4F(3,2)) &&
                      Dfltequal(TM4F(0,3), OM4F(0,3)) &&
                      Dfltequal(TM4F(1,3), OM4F(1,3)) &&
                      Dfltequal(TM4F(2,3), OM4F(2,3)) &&
                      Dfltequal(TM4F(3,3), OM4F(3,3)) 
                      );
            break;
            
         case YAC_OP_CNE:
            YAC_RETI( Dfltnotequal(TM4F(0,0), OM4F(0,0)) ||
                      Dfltnotequal(TM4F(1,0), OM4F(1,0)) ||
                      Dfltnotequal(TM4F(2,0), OM4F(2,0)) ||
                      Dfltnotequal(TM4F(3,0), OM4F(3,0)) ||
                      Dfltnotequal(TM4F(0,1), OM4F(0,1)) ||
                      Dfltnotequal(TM4F(1,1), OM4F(1,1)) ||
                      Dfltnotequal(TM4F(2,1), OM4F(2,1)) ||
                      Dfltnotequal(TM4F(3,1), OM4F(3,1)) ||
                      Dfltnotequal(TM4F(0,2), OM4F(0,2)) ||
                      Dfltnotequal(TM4F(1,2), OM4F(1,2)) ||
                      Dfltnotequal(TM4F(2,2), OM4F(2,2)) ||
                      Dfltnotequal(TM4F(3,2), OM4F(3,2)) ||
                      Dfltnotequal(TM4F(0,3), OM4F(0,3)) ||
                      Dfltnotequal(TM4F(1,3), OM4F(1,3)) ||
                      Dfltnotequal(TM4F(2,3), OM4F(2,3)) ||
                      Dfltnotequal(TM4F(3,3), OM4F(3,3)) 
                      );
            break;

         case YAC_OP_ASSIGN:
            TM4F(0,0) = OM4F(0,0);
            TM4F(1,0) = OM4F(1,0);
            TM4F(2,0) = OM4F(2,0);
            TM4F(3,0) = OM4F(3,0);
            TM4F(0,1) = OM4F(0,1);
            TM4F(1,1) = OM4F(1,1);
            TM4F(2,1) = OM4F(2,1);
            TM4F(3,1) = OM4F(3,1);
            TM4F(0,2) = OM4F(0,2);
            TM4F(1,2) = OM4F(1,2);
            TM4F(2,2) = OM4F(2,2);
            TM4F(3,2) = OM4F(3,2);
            TM4F(0,3) = OM4F(0,3);
            TM4F(1,3) = OM4F(1,3);
            TM4F(2,3) = OM4F(2,3);
            TM4F(3,3) = OM4F(3,3);
            break;

         case YAC_OP_ADD:
            _add_YAC_RSELF(_o);
            break;

         case YAC_OP_SUB:
            _sub_YAC_RSELF(_o);
            break;

         case YAC_OP_MUL:
            _mul_YAC_RSELF(_o);
            break;

         case YAC_OP_NEG:
            floats[ 0] = -floats[ 0];
            floats[ 1] = -floats[ 1];
            floats[ 2] = -floats[ 2];
            floats[ 3] = -floats[ 3];
            floats[ 4] = -floats[ 4];
            floats[ 5] = -floats[ 5];
            floats[ 6] = -floats[ 6];
            floats[ 7] = -floats[ 7];
            floats[ 8] = -floats[ 8];
            floats[ 9] = -floats[ 9];
            floats[10] = -floats[10];
            floats[11] = -floats[11];
            floats[12] = -floats[12];
            floats[13] = -floats[13];
            floats[14] = -floats[14];
            floats[15] = -floats[15];
            break;

         case YAC_OP_INIT:
            _initIdentity();
            break;

         default:
         {
            /*not thread safe*/ static char buf[256];
            sprintf(buf, "tkmath::Matrix4f::yacOperator: unsupported cmd %d!\n", _cmd);
            Dyac_throw_def(TkMathUnsupportedOperator, buf);
            return;
         }

      }
   } 
   else if(YAC_Is_FloatArray(_o))
   {
      // Assume that FloatArray uses same element order
      YAC_FloatArray *o=(YAC_FloatArray*)_o;
      switch (_cmd) 
      {
         case YAC_OP_ASSIGN:
            if (o->num_elements<16) 
            {
               sUI i;
               for(i=0; i<o->num_elements; i++) 
               {
                  floats[i] = o->elements[i];
               }
               for(; i<16; i++)
               {
                  floats[i] = 0.0f; // TODO: main diagonal should be 1.0f
               }
            } 
            else 
            {
               floats[ 0] = o->elements[ 0];
               floats[ 1] = o->elements[ 1];
               floats[ 2] = o->elements[ 2];
               floats[ 3] = o->elements[ 3];
               floats[ 4] = o->elements[ 4];
               floats[ 5] = o->elements[ 5];
               floats[ 6] = o->elements[ 6];
               floats[ 7] = o->elements[ 7];
               floats[ 8] = o->elements[ 8];
               floats[ 9] = o->elements[ 9];
               floats[10] = o->elements[10];
               floats[11] = o->elements[11];
               floats[12] = o->elements[12];
               floats[13] = o->elements[13];
               floats[14] = o->elements[14];
               floats[15] = o->elements[15];
            }
            break;

         default:
         {
            _Matrix4f t;
            t.class_ID = clid_Matrix4f;
            t._setColumnMajor(_getColumnMajor());
            t.assignFloatArray(o);
            yacOperator(_cmd, &t, _r);

            //Dyac_throw_def(TkMathUnsupportedOperator, "tkmath::Matrix4f::yacOperator Only Assign supported with FloatArray Type");
         }
         break;
      } // switch _cmd

   } // if FloatArray 
   else if(YAC_VALID(_o)) 
   {
      // Generic right hand side object
      sF32 val;
      if(_o->yacScanF32(&val)) 
      {
         yacOperatorF32(_cmd, val, _r);
      } 
      else
      {
         switch(_cmd) 
         {
            case YAC_OP_ASSIGN:
               assignGeneric(NULL, _o);
               break;

            default:
               /////Dyac_throw_def(TkMathUnsupportedOperator, "tkmath::Matrix4f::yacOperator: Only Assign supported with Generic Object Type");
               YAC_Object::yacOperator(_cmd,_o,_r);
               break;
         }
      }
   } 
   else 
   {
      switch(_cmd) 
      {
         case YAC_OP_NEG:
            floats[ 0] = -floats[ 0];
            floats[ 1] = -floats[ 1];
            floats[ 2] = -floats[ 2];
            floats[ 3] = -floats[ 3];
            floats[ 4] = -floats[ 4];
            floats[ 5] = -floats[ 5];
            floats[ 6] = -floats[ 6];
            floats[ 7] = -floats[ 7];
            floats[ 8] = -floats[ 8];
            floats[ 9] = -floats[ 9];
            floats[10] = -floats[10];
            floats[11] = -floats[11];
            floats[12] = -floats[12];
            floats[13] = -floats[13];
            floats[14] = -floats[14];
            floats[15] = -floats[15];
            break;

         case YAC_OP_INIT:
            _initIdentity();
            break;

         default:
            YAC_Object::yacOperator(_cmd,_o,_r);
            break;
      }
   }
}

void _Matrix4f::yacOperatorI(sSI _cmd, sSI val, YAC_Value *_r) {
   yacOperatorF32(_cmd, (sF32)val, _r);
}

void _Matrix4f::yacOperatorF32(sSI _cmd, sF32 val, YAC_Value *_r) {
   switch (_cmd) 
   {
      case YAC_OP_MUL:
         _mulf_YAC_RSELF(val);
         break;

      case YAC_OP_DIV:
         if(Dfltnonzero(val)) 
         {
            _mulf_YAC_RSELF(1.0f/val);
         } 
         else 
         {
            Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::yacOperatorF32: OP_DIV Cannot divide by zero");
         }
         break;

      default:
         char buf[256];
         sprintf(buf,"tkmath::Matrix4f::yacOperatorF32: Operator not supported %d",_cmd);
         Dyac_throw_def(TkMathUnsupportedOperator,buf);
         break;
   }
}

void _Matrix4f::assignFloats(sF32 *_fv, sUI _ne) {
   if(_ne != 16) 
   {
      Dyac_throw_def(WriteArrayOutOfBounds,"tkmath::Matrix4f: Array not of size 16");
   } 
   else 
   {
      // Copy elements
      sUI i;
      for(i=0; i<16; i++)
      {
         floats[i] = _fv[i];
      }
   }
}

void _Matrix4f::assignFloatArray(YAC_FloatArray *_fa) {
   assignFloats(_fa->elements, _fa->num_elements);
}

void _Matrix4f::assignGeneric(YAC_ContextHandle _ctx, YAC_Object *_o) {
   sUI ne = _o->yacArrayGetNumElements();
   sUI nH = _o->yacArrayGetHeight();
   sUI nW = _o->yacArrayGetWidth();

   if(nH <= 1) 
   {
      if(16 == nW) 
      { //exact number to fill the matrix - we con go on
         nH = 4;
         nW = 4;
      } 
      else 
      { //nah, throw an exception
         Dyac_throw_def(TkMathInvalidValue,"tkmath::Matrix4f: Array not of size 16");
      }
   }
   if(ne > 0)
   {
      sF32 *fv = (sF32*) _o->yacArrayGetPointer();

      if((NULL != fv) && (YAC_TYPE_FLOAT == _o->yacArrayGetElementType()))
      {
         // Copy fast, assume same element order
         sUI y, x;

         if(b_column_major)
         {
            sUI ySkip;
            if(nH > 4)
            {
               ySkip = nH - 4;
               nH = 4;
            }
            else
            {
               ySkip = 0;
            }
            if(nW > 4)
            {
               nW = 4;
            }

            sUI k = 0;
            sUI l = 0;
            for(x=0; x<nW; x++)
            {
               for(y=0; y<nH; y++)
               {
                  floats[k++] = fv[l++];
               }
               l += ySkip;
               for(; y<4; y++)
               {
                  floats[k++] = (x==y) ? 1.0f : 0.0f;
               }
            }
            for(; x<4; x++)
            {
               for(y=0; y<4; y++)
               {
                  floats[k++] = (x==y) ? 1.0f : 0.0f;
               }
            }
         }
         else
         {
            // Row major
            sUI xSkip;
            if(nH > 4)
            {
               nH = 4;
            }
            if(nW > 4)
            {
               xSkip = nW - 4;
               nW = 4;
            }
            else
            {
               xSkip = 0;
            }

            sUI k = 0;
            sUI l = 0;
            for(y=0; y<nH; y++)
            {
               for(x=0; x<nW; x++)
               {
                  floats[k++] = fv[l++];
               }
               l += xSkip;
               for(; x<4; x++)
               {
                  floats[k++] = (x==y) ? 1.0f : 0.0f;
               }
            }
            for(; y<4; y++)
            {
               for(x=0; x<4; x++)
               {
                  floats[k++] = (x==y) ? 1.0f : 0.0f;
               }
            }
         }
      }
      else
      {
         // Copy slow, typecast elements to float, assume same element order
         sUI y, x;

         if(b_column_major)
         {
            sUI ySkip;
            if(nH > 4)
            {
               ySkip = nH - 4;
               nH = 4;
            }
            else
            {
               ySkip = 0;
            }
            if(nW > 4)
            {
               nW = 4;
            }

            sUI k = 0;
            sUI l = 0;
            for(x=0; x<nW; x++)
            {
               for(y=0; y<nH; y++)
               {
                  YAC_Value v;
                  _o->yacArrayGet(_ctx, l++, &v);
                  v.typecast(YAC_TYPE_FLOAT);
                  floats[k++] = v.value.float_val;
               }
               l += ySkip;
               for(; y<4; y++)
               {
                  floats[k++] = (x==y) ? 1.0f : 0.0f;
               }
            }
            for(; x<4; x++)
            {
               for(y=0; y<4; y++)
               {
                  floats[k++] = (x==y) ? 1.0f : 0.0f;
               }
            }
         }
         else
         {
            // Row major
            sUI xSkip;
            if(nH > 4)
            {
               nH = 4;
            }
            if(nW > 4)
            {
               xSkip = nW - 4;
               nW = 4;
            }
            else
            {
               xSkip = 0;
            }

            sUI k = 0;
            sUI l = 0;
            for(y=0; y<nH; y++)
            {
               for(x=0; x<nW; x++)
               {
                  YAC_Value v;
                  _o->yacArrayGet(_ctx, l++, &v);
                  v.typecast(YAC_TYPE_FLOAT);
                  floats[k++] = v.value.float_val;
               }
               l += xSkip;
               for(; x<4; x++)
               {
                  floats[k++] = (x==y) ? 1.0f : 0.0f;
               }
            }
            for(; y<4; y++)
            {
               for(x=0; x<4; x++)
               {
                  floats[k++] = (x==y) ? 1.0f : 0.0f;
               }
            }
         }
      }
   }
   else
   {
      // Other array is empty or no array. Silently load identity
      _initIdentity();
   }
}

void _Matrix4f::_set(sSI _row, sSI _col, sF32 _v) {
   if((((sUI)_row) < 4) && (((sUI)_col) < 4))
   {
      TM4F(_row, _col) = _v;
   }
   else
   {
      /*not thread safe*/ static char buf[256];
      sprintf(buf, "tkmath::Matrix4f::setRC: Col/Row out of bounds! (row=%d, col=%d)\n", _row, _col);
      Dyac_throw_def(WriteArrayOutOfBounds, buf);
   }
}

sF32 _Matrix4f::_get(sSI _row, sSI _col) {
   if((((sUI)_row) < 4) && (((sUI)_col) < 4))
   {
      return TM4F(_row, _col);
   }
   else
   {
      /*not thread safe*/ static char buf[256];
      sprintf(buf, "tkmath::Matrix4f::getRC: Col/Row out of bounds! (row=%d, col=%d)\n", _row, _col);
      Dyac_throw_def(ReadArrayOutOfBounds, buf);
      return 0.0f;
   }
}

void _Matrix4f::_setA(sF32 x) {
   TM4F(0,0) = x;
}

void _Matrix4f::_setB(sF32 y) {
   TM4F(0,1) = y;
}

void _Matrix4f::_setC(sF32 x) {
   TM4F(0,2) = x;
}

void _Matrix4f::_setD(sF32 y) {
   TM4F(0,3) = y;
}

void _Matrix4f::_setE(sF32 y) {
   TM4F(1,0) = y;
}

void _Matrix4f::_setF(sF32 y) {
   TM4F(1,1) = y;
}

void _Matrix4f::_setG(sF32 y) {
   TM4F(1,2) = y;
}

void _Matrix4f::_setH(sF32 y) {
   TM4F(1,3) = y;
}


void _Matrix4f::_setI(sF32 y) {
   TM4F(2,0) = y;
}

void _Matrix4f::_setJ(sF32 y) {
   TM4F(2,1) = y;
}

void _Matrix4f::_setK(sF32 y) {
   TM4F(2,2) = y;
}

void _Matrix4f::_setL(sF32 y) {
   TM4F(2,3) = y;
}

void _Matrix4f::_setM(sF32 y) {
   TM4F(3,0) = y;
}

void _Matrix4f::_setN(sF32 y) {
   TM4F(3,1) = y;
}

void _Matrix4f::_setO(sF32 y) {
   TM4F(3,2) = y;
}

void _Matrix4f::_setP(sF32 y) {
   TM4F(3,3) = y;
}

sF32 _Matrix4f::_getA(void) {
   return TM4F(0,0);
}

sF32 _Matrix4f::_getB(void) {
   return TM4F(0,1);
}

sF32 _Matrix4f::_getC(void) {
   return TM4F(0,2);
}

sF32 _Matrix4f::_getD(void) {
   return TM4F(0,3);
}

sF32 _Matrix4f::_getE(void) {
   return TM4F(1,0);
}

sF32 _Matrix4f::_getF(void) {
   return TM4F(1,1);
}

sF32 _Matrix4f::_getG(void) {
   return TM4F(1,2);
}

sF32 _Matrix4f::_getH(void) {
   return TM4F(1,3);
}

sF32 _Matrix4f::_getI(void) {
   return TM4F(2,0);
}

sF32 _Matrix4f::_getJ(void) {
   return TM4F(2,1);
}

sF32 _Matrix4f::_getK(void) {
   return TM4F(2,2);
}

sF32 _Matrix4f::_getL(void) {
   return TM4F(2,3);
}

sF32 _Matrix4f::_getM(void) {
   return TM4F(3,0);
}

sF32 _Matrix4f::_getN(void) {
   return TM4F(3,1);
}

sF32 _Matrix4f::_getO(void) {
   return TM4F(3,2);
}

sF32 _Matrix4f::_getP(void) {
   return TM4F(3,3);
}

sBool YAC_VCALL _Matrix4f::yacToString(YAC_String *s) const {
   //
   // Generate string representation
   //
   s->yacArrayAlloc(1024,0,0,0);
   s->printf("((%g, %g, %g, %g), (%g, %g, %g, %g), (%g, %g, %g, %g), (%g, %g, %g, %g))",
             TM4F(0,0), TM4F(0,1), TM4F(0,2), TM4F(0,3),
             TM4F(1,0), TM4F(1,1), TM4F(1,2), TM4F(1,3),
             TM4F(2,0), TM4F(2,1), TM4F(2,2), TM4F(2,3),
             TM4F(3,0), TM4F(3,1), TM4F(3,2), TM4F(3,3)
             );
   s->fixLength();
   return 1;
}

void _Matrix4f::_getString(YAC_Value *_r) const {
   YAC_String *s = (YAC_String*) YAC_NEW_CORE_POOLED(YAC_CLID_STRING);
   yacToString(s);
   YAC_RETS(s,1);
}

void _Matrix4f::_add_YAC_RSELF(YAC_Object *_o) {
   //
   // Add two matrices
   //
   if(YAC_CHK(_o, clid_Matrix4f)) 
   {
      _Matrix4f *o = (_Matrix4f*)_o;
      TM4F(0,0) += OM4F(0,0);
      TM4F(0,1) += OM4F(0,1);
      TM4F(0,2) += OM4F(0,2);
      TM4F(0,3) += OM4F(0,3);
      TM4F(1,0) += OM4F(1,0);
      TM4F(1,1) += OM4F(1,1);
      TM4F(1,2) += OM4F(1,2);
      TM4F(1,3) += OM4F(1,3);
      TM4F(2,0) += OM4F(2,0);
      TM4F(2,1) += OM4F(2,1);
      TM4F(2,2) += OM4F(2,2);
      TM4F(2,3) += OM4F(2,3);
      TM4F(3,0) += OM4F(3,0);
      TM4F(3,1) += OM4F(3,1);
      TM4F(3,2) += OM4F(3,2);
      TM4F(3,3) += OM4F(3,3);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::add_SELF: Object not of type Matrix3f");
   }
}

void _Matrix4f::_add_YAC_RVAL(YAC_Object *_o, YAC_Value *_r) {
   if(YAC_CHK(_o, clid_Matrix4f)) 
   {
      _Matrix4f *o = (_Matrix4f*)_o;
      _Matrix4f *r = YAC_NEW_POOLED(Matrix4f);
      r->_setColumnMajor(_getColumnMajor());
      M4F(r,0,0) = TM4F(0,0) + OM4F(0,0);
      M4F(r,0,1) = TM4F(0,1) + OM4F(0,1);
      M4F(r,0,2) = TM4F(0,2) + OM4F(0,2);
      M4F(r,0,3) = TM4F(0,3) + OM4F(0,3);
      M4F(r,1,0) = TM4F(1,0) + OM4F(1,0);
      M4F(r,1,1) = TM4F(1,1) + OM4F(1,1);
      M4F(r,1,2) = TM4F(1,2) + OM4F(1,2);
      M4F(r,1,3) = TM4F(1,3) + OM4F(1,3);
      M4F(r,2,0) = TM4F(2,0) + OM4F(2,0);
      M4F(r,2,1) = TM4F(2,1) + OM4F(2,1);
      M4F(r,2,2) = TM4F(2,2) + OM4F(2,2);
      M4F(r,2,3) = TM4F(2,3) + OM4F(2,3);
      M4F(r,3,0) = TM4F(3,0) + OM4F(3,0);
      M4F(r,3,1) = TM4F(3,1) + OM4F(3,1);
      M4F(r,3,2) = TM4F(3,2) + OM4F(3,2);
      M4F(r,3,3) = TM4F(3,3) + OM4F(3,3);
      _r->initObject(r,1);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::add_VAL: Object not of type Matrix3f");
   }
}

void _Matrix4f::_add_YAC_RARG(YAC_Object *_o, YAC_Object *_r) {
   if(YAC_CHK(_o, clid_Matrix4f) && YAC_CHK(_r, clid_Matrix4f))
   {
      _Matrix4f *o = (_Matrix4f*)_o;
      _Matrix4f *r = (_Matrix4f*)_r;
      M4F(r,0,0) = TM4F(0,0) + OM4F(0,0);
      M4F(r,0,1) = TM4F(0,1) + OM4F(0,1);
      M4F(r,0,2) = TM4F(0,2) + OM4F(0,2);
      M4F(r,0,3) = TM4F(0,3) + OM4F(0,3);
      M4F(r,1,0) = TM4F(1,0) + OM4F(1,0);
      M4F(r,1,1) = TM4F(1,1) + OM4F(1,1);
      M4F(r,1,2) = TM4F(1,2) + OM4F(1,2);
      M4F(r,1,3) = TM4F(1,3) + OM4F(1,3);
      M4F(r,2,0) = TM4F(2,0) + OM4F(2,0);
      M4F(r,2,1) = TM4F(2,1) + OM4F(2,1);
      M4F(r,2,2) = TM4F(2,2) + OM4F(2,2);
      M4F(r,2,3) = TM4F(2,3) + OM4F(2,3);
      M4F(r,3,0) = TM4F(3,0) + OM4F(3,0);
      M4F(r,3,1) = TM4F(3,1) + OM4F(3,1);
      M4F(r,3,2) = TM4F(3,2) + OM4F(3,2);
      M4F(r,3,3) = TM4F(3,3) + OM4F(3,3);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::add_ARG: Object not of type Matrix3f");
   }
}

//sub two matrices
void _Matrix4f::_sub_YAC_RSELF(YAC_Object *_o) {
   if(YAC_CHK(_o, clid_Matrix4f)) 
   {
      _Matrix4f *o = (_Matrix4f*)_o;
      TM4F(0,0) -= OM4F(0,0);
      TM4F(0,1) -= OM4F(0,1);
      TM4F(0,2) -= OM4F(0,2);
      TM4F(0,3) -= OM4F(0,3);
      TM4F(1,0) -= OM4F(1,0);
      TM4F(1,1) -= OM4F(1,1);
      TM4F(1,2) -= OM4F(1,2);
      TM4F(1,3) -= OM4F(1,3);
      TM4F(2,0) -= OM4F(2,0);
      TM4F(2,1) -= OM4F(2,1);
      TM4F(2,2) -= OM4F(2,2);
      TM4F(2,3) -= OM4F(2,3);
      TM4F(3,0) -= OM4F(3,0);
      TM4F(3,1) -= OM4F(3,1);
      TM4F(3,2) -= OM4F(3,2);
      TM4F(3,3) -= OM4F(3,3);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::sub_SELF: Object not of type Matrix4f");
   }
}

void _Matrix4f::_sub_YAC_RVAL(YAC_Object *_o, YAC_Value *_r) {
   if(YAC_CHK(_o, clid_Matrix4f)) 
   {
      _Matrix4f *o = (_Matrix4f*)_o;
      _Matrix4f *r = YAC_NEW_POOLED(Matrix4f);
      r->_setColumnMajor(_getColumnMajor());
      M4F(r,0,0) = TM4F(0,0) - OM4F(0,0);
      M4F(r,0,1) = TM4F(0,1) - OM4F(0,1);
      M4F(r,0,2) = TM4F(0,2) - OM4F(0,2);
      M4F(r,0,3) = TM4F(0,3) - OM4F(0,3);
      M4F(r,1,0) = TM4F(1,0) - OM4F(1,0);
      M4F(r,1,1) = TM4F(1,1) - OM4F(1,1);
      M4F(r,1,2) = TM4F(1,2) - OM4F(1,2);
      M4F(r,1,3) = TM4F(1,3) - OM4F(1,3);
      M4F(r,2,0) = TM4F(2,0) - OM4F(2,0);
      M4F(r,2,1) = TM4F(2,1) - OM4F(2,1);
      M4F(r,2,2) = TM4F(2,2) - OM4F(2,2);
      M4F(r,2,3) = TM4F(2,3) - OM4F(2,3);
      M4F(r,3,0) = TM4F(3,0) - OM4F(3,0);
      M4F(r,3,1) = TM4F(3,1) - OM4F(3,1);
      M4F(r,3,2) = TM4F(3,2) - OM4F(3,2);
      M4F(r,3,3) = TM4F(3,3) - OM4F(3,3);
      _r->initObject(r,1);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::sub_VAL: Object not of type Matrix4f");
   }
}

void _Matrix4f::_sub_YAC_RARG(YAC_Object *_o, YAC_Object *_r) {
   if(YAC_CHK(_o, clid_Matrix4f) && YAC_CHK(_r, clid_Matrix4f))
   {
      _Matrix4f *o = (_Matrix4f*)_o;
      _Matrix4f *r = (_Matrix4f*)_r;
      M4F(r,0,0) = TM4F(0,0) - OM4F(0,0);
      M4F(r,0,1) = TM4F(0,1) - OM4F(0,1);
      M4F(r,0,2) = TM4F(0,2) - OM4F(0,2);
      M4F(r,0,3) = TM4F(0,3) - OM4F(0,3);
      M4F(r,1,0) = TM4F(1,0) - OM4F(1,0);
      M4F(r,1,1) = TM4F(1,1) - OM4F(1,1);
      M4F(r,1,2) = TM4F(1,2) - OM4F(1,2);
      M4F(r,1,3) = TM4F(1,3) - OM4F(1,3);
      M4F(r,2,0) = TM4F(2,0) - OM4F(2,0);
      M4F(r,2,1) = TM4F(2,1) - OM4F(2,1);
      M4F(r,2,2) = TM4F(2,2) - OM4F(2,2);
      M4F(r,2,3) = TM4F(2,3) - OM4F(2,3);
      M4F(r,3,0) = TM4F(3,0) - OM4F(3,0);
      M4F(r,3,1) = TM4F(3,1) - OM4F(3,1);
      M4F(r,3,2) = TM4F(3,2) - OM4F(3,2);
      M4F(r,3,3) = TM4F(3,3) - OM4F(3,3);
   }
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::sub_ARG: Object not of type Matrix4f");
   }
}

void _Matrix4f::_mulf_YAC_RSELF(sF32 s) {
   //
   // Multiply matrix by scalar value
   //
   sUI i;
   for(i=0; i<16; i++)
   {
      floats[i] *= s;
   }
}

void _Matrix4f::_mulf_YAC_RVAL(sF32 s, YAC_Value *_r) {
   _Matrix4f *r=YAC_NEW_POOLED(Matrix4f);
   r->_setColumnMajor(_getColumnMajor());
   M4F(r,0,0) = TM4F(0,0) * s;
   M4F(r,0,1) = TM4F(0,1) * s;
   M4F(r,0,2) = TM4F(0,2) * s;
   M4F(r,0,3) = TM4F(0,3) * s;
   M4F(r,1,0) = TM4F(1,0) * s;
   M4F(r,1,1) = TM4F(1,1) * s;
   M4F(r,1,2) = TM4F(1,2) * s;
   M4F(r,1,3) = TM4F(1,3) * s;
   M4F(r,2,0) = TM4F(2,0) * s;
   M4F(r,2,1) = TM4F(2,1) * s;
   M4F(r,2,2) = TM4F(2,2) * s;
   M4F(r,2,3) = TM4F(2,3) * s;
   M4F(r,3,0) = TM4F(3,0) * s;
   M4F(r,3,1) = TM4F(3,1) * s;
   M4F(r,3,2) = TM4F(3,2) * s;
   M4F(r,3,3) = TM4F(3,3) * s;
   _r->initObject(r, 1);
}

void _Matrix4f::_mulf_YAC_RARG(sF32 s, YAC_Object *_r) {
   if(YAC_CHK(_r, clid_Matrix4f)) 
   {
      _Matrix4f *r = (_Matrix4f*)_r;
      M4F(r,0,0) = TM4F(0,0) * s;
      M4F(r,0,1) = TM4F(0,1) * s;
      M4F(r,0,2) = TM4F(0,2) * s;
      M4F(r,0,3) = TM4F(0,3) * s;
      M4F(r,1,0) = TM4F(1,0) * s;
      M4F(r,1,1) = TM4F(1,1) * s;
      M4F(r,1,2) = TM4F(1,2) * s;
      M4F(r,1,3) = TM4F(1,3) * s;
      M4F(r,2,0) = TM4F(2,0) * s;
      M4F(r,2,1) = TM4F(2,1) * s;
      M4F(r,2,2) = TM4F(2,2) * s;
      M4F(r,2,3) = TM4F(2,3) * s;
      M4F(r,3,0) = TM4F(3,0) * s;
      M4F(r,3,1) = TM4F(3,1) * s;
      M4F(r,3,2) = TM4F(3,2) * s;
      M4F(r,3,3) = TM4F(3,3) * s;
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::mulf_ARG: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_mul_YAC_RSELF(YAC_Object *_o) {
   //
   // Multiply two matrices
   //
   if(YAC_CHK(_o, clid_Matrix4f)) 
   {
      _Matrix4f *o = (_Matrix4f*)_o;
      sF32 t[4][4];
      sUI y, x;

      for(y=0; y<4; y++)
      {
         for(x=0; x<4; x++)
         {
            // Calculate in row major order
            t[y][x] = 
               TM4F(y,0) * OM4F(0,x) + 
               TM4F(y,1) * OM4F(1,x) + 
               TM4F(y,2) * OM4F(2,x) +
               TM4F(y,3) * OM4F(3,x) ;
         }
      }
      // Convert/copy back to matrix element order
      for(y=0; y<4; y++)
      {
         for(x=0; x<4; x++)
         {
            TM4F(y,x) = t[y][x];
         }
      }
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::mul_SELF: Object not of type Matrix4f!\n");
   }
}

void _Matrix4f::_mul_YAC_RVAL(YAC_Object *_o, YAC_Value *_r) {
   if(YAC_CHK(_o, clid_Matrix4f)) 
   {
      _Matrix4f *o = (_Matrix4f*)_o;
      _Matrix4f *r = YAC_NEW_POOLED(Matrix4f);
      r->_setColumnMajor(_getColumnMajor());

      sUI y, x;
      for(y=0; y<4; y++)
      {
         for(x=0; x<4; x++)
         {
            M4F(r,y,x) = 
               TM4F(y,0) * OM4F(0,x) + 
               TM4F(y,1) * OM4F(1,x) + 
               TM4F(y,2) * OM4F(2,x) +
               TM4F(y,3) * OM4F(3,x) ;
         }
      }

      _r->initObject(r, 1);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::mul_VAL: Object not of type Matrix4f!\n");
   }
}

void _Matrix4f::_mul_YAC_RARG(YAC_Object *_o, YAC_Object *_r) {
   if(YAC_CHK(_o, clid_Matrix4f)) 
   {
      _Matrix4f *o = (_Matrix4f*)_o;
      _Matrix4f *r = (_Matrix4f*)_r;

      sUI y, x;
      for(y=0; y<4; y++)
      {
         for(x=0; x<4; x++)
         {
            M4F(r,y,x) = 
               TM4F(y,0) * OM4F(0,x) + 
               TM4F(y,1) * OM4F(1,x) + 
               TM4F(y,2) * OM4F(2,x) +
               TM4F(y,3) * OM4F(3,x) ;
         }
      }
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::mul_ARG: Object not of type Matrix4f!\n");
   }
}


void _Matrix4f::_mulv_YAC_RVAL(YAC_Object *_o, YAC_Value *_r) 
{
   //
   // Multiply matrix by (column-) vector and return new Vector4f
   //
   if(YAC_CHK(_o, clid_Vector4f)) 
   {
      _Vector4f *o = (_Vector4f*)_o;
      _Vector4f *r = YAC_NEW_POOLED(Vector4f);
      
      sUI y;
      for(y=0; y<4; y++)
      {
         r->floats[y] =
            TM4F(y,0) * o->floats[0] + 
            TM4F(y,1) * o->floats[1] + 
            TM4F(y,2) * o->floats[2] +
            TM4F(y,3) * o->floats[3] ;
      }
      _r->initObject(r, 1);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::mulv: Object not of type Vector4f");
   }
}


void _Matrix4f::_mulv_YAC_RARG(YAC_Object *_o, YAC_Object *_r) {
   if(YAC_CHK(_o, clid_Vector4f) && (YAC_CHK(_r, clid_Vector4f)))
   {
      _Vector4f *o = (_Vector4f*)_o;
      _Vector4f *r = (_Vector4f*)_r;

      sUI y;
      for(y=0; y<4; y++)
      {
         r->floats[y] =
               TM4F(y,0) * o->floats[0] + 
               TM4F(y,1) * o->floats[1] + 
               TM4F(y,2) * o->floats[2] +
               TM4F(y,3) * o->floats[3] ;
      }
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::mulv: Object not of type Vector4f");
   }
}

sF32 _Matrix4f::_getAbs(void) {
   //
   // Return "length" of matrix
   //
   return sqrtf(floats[ 0]*floats[ 0] + floats[ 1]*floats[ 1] + floats[ 2]*floats[ 2] + floats[ 3]*floats[ 3]+
                floats[ 4]*floats[ 4] + floats[ 5]*floats[ 5] + floats[ 6]*floats[ 6] + floats[ 7]*floats[ 7]+
                floats[ 8]*floats[ 8] + floats[ 9]*floats[ 9] + floats[10]*floats[10] + floats[11]*floats[11]+
                floats[12]*floats[12] + floats[13]*floats[13] + floats[14]*floats[14] + floats[15]*floats[15]
                );
}

sF32 _Matrix4f::_getAbsSqr(void) {
   //
   // Return squared "length" of matrix
   //
   return (floats[ 0]*floats[ 0] + floats[ 1]*floats[ 1] + floats[ 2]*floats[ 2] + floats[ 3]*floats[ 3]+
           floats[ 4]*floats[ 4] + floats[ 5]*floats[ 5] + floats[ 6]*floats[ 6] + floats[ 7]*floats[ 7]+
           floats[ 8]*floats[ 8] + floats[ 9]*floats[ 9] + floats[10]*floats[10] + floats[11]*floats[11]+
           floats[12]*floats[12] + floats[13]*floats[13] + floats[14]*floats[14] + floats[15]*floats[15]
           );
}

void _Matrix4f::_unit_YAC_RSELF(void) {
   //
   // Scale matrix to "length" 1
   //
   sF32 absval = _getAbs();
   if(Dfltnonzero(absval))
   {
      absval = 1.0f / absval;
      _mulf_YAC_RSELF(absval);
   }
   else 
   {
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::unit_SELF: Zero Matrix cannot be normalized!\n");
   }
}

void _Matrix4f::_unit_YAC_RVAL(YAC_Value *_r) {
   sF32 absval = _getAbs();
   if(Dfltnonzero(absval)) 
   {
      _Matrix4f *r = YAC_NEW_POOLED(Matrix4f);
      r->_setColumnMajor(_getColumnMajor());
      _mulf_YAC_RARG(absval, r);
      _r->initObject(r, 1);
   } 
   else 
   {
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::unit_VAL: Zero Matrix cannot be normalized!\n");
   }
}

void _Matrix4f::_unit_YAC_RARG(YAC_Object *_r) {
   sF32 absval = _getAbs();
   if(Dfltnonzero(absval)) 
   {
      _mulf_YAC_RARG(absval, _r);
   } 
   else 
   {
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::unit_ARG: Zero Matrix cannot be normalized!\n");
   }
}

void _Matrix4f::_unitScale_YAC_RSELF(sF32 s) {
   //
   // Scale matrix to "length" s
   //
   sF32 absval = _getAbs();
   if(Dfltnonzero(absval)) 
   {
      _mulf_YAC_RSELF(s / absval);
   } 
   else 
   {
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::unitScale_SELF: Zero Matrix cannot be normalized");
   }
}

void _Matrix4f::_unitScale_YAC_RVAL(sF32 s, YAC_Value *_r) {
   sF32 absval = _getAbs();
   if(Dfltnonzero(absval)) 
   {
      _Matrix4f *r = YAC_NEW_POOLED(Matrix4f);
      r->_setColumnMajor(_getColumnMajor());
      _mulf_YAC_RARG(s / absval, r);
      _r->initObject(r, 1);
   } 
   else 
   {
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::unitScale_VAL: Zero Matrix cannot be normalized");
   }
}

void _Matrix4f::_unitScale_YAC_RARG(sF32 s, YAC_Object *_r) {
   sF32 absval = _getAbs();
   if(Dfltnonzero(absval)) 
   {
      _mulf_YAC_RARG(s / absval, _r);
   } 
   else 
   {
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::unitScale_ARG: Zero Matrix cannot be normalized");
   }
}

sF32 _Matrix4f::_det(void) {
   //
   // Returns determinant of matrix
   //
   // Calculate determinant with leibniz' formula
   //
#define PDET(a,b,c,d) (TM4F(0,a) * TM4F(1,b) * TM4F(2,c) * TM4F(3, d))

   return (+PDET(0,1,2,3) - PDET(0,1,3,2) - PDET(0,2,1,3) + PDET(0,2,3,1) + PDET(0,3,1,2) - PDET(0,3,2,1)
           -PDET(1,0,2,3) + PDET(1,0,3,2) + PDET(1,2,0,3) - PDET(1,2,3,0) - PDET(1,3,0,2) + PDET(1,3,2,0)
           +PDET(2,0,1,3) - PDET(2,0,3,1) - PDET(2,1,0,3) + PDET(2,1,3,0) + PDET(2,3,0,1) - PDET(2,3,1,0)
           -PDET(3,0,1,2) + PDET(3,0,2,1) + PDET(3,1,0,2) - PDET(3,1,2,0) - PDET(3,2,0,1) + PDET(3,2,1,0)
           );
}


#ifdef INVERT_DET
void _Matrix4f::invertHelper(_Matrix4f *_t) {
   //inverts matrix if possible, determinant version
#define DET3(_a,_b,_c,_d,_e,_f,_g,_h,_i) ((_a*_e*_i)+(_b*_f*_g)+(_c*_d*_h)-(_c*_e*_g)-(_a*_f*_h)-(_b*_d*_i))
#define A TM4F(0,0)
#define B TM4F(0,1)
#define C TM4F(0,2)
#define D TM4F(0,3)
#define E TM4F(1,0)
#define F TM4F(1,1)
#define G TM4F(1,2)
#define H TM4F(1,3)
#define I TM4F(2,0)
#define J TM4F(2,1)
#define K TM4F(2,2)
#define L TM4F(2,3)
#define M TM4F(3,0)
#define N TM4F(3,1)
#define O TM4F(3,2)
#define P TM4F(3,3)
   sF32 detval = _det();
   if(Dfltnonzero(detval)) 
   {
      detval = 1.0f / detval;

      M4F(_t,0,0) =  DET3(F,G,H,J,K,L,N,O,P) * detval;
      M4F(_t,0,1) = -DET3(B,C,D,J,K,L,N,O,P) * detval;
      M4F(_t,0,2) =  DET3(B,C,D,F,G,H,N,O,P) * detval;
      M4F(_t,0,3) = -DET3(B,C,D,F,G,H,J,K,L) * detval;

      M4F(_t,1,0) = -DET3(E,G,H,I,K,L,M,O,P) * detval;
      M4F(_t,1,1) =  DET3(A,C,D,I,K,L,M,O,P) * detval;
      M4F(_t,1,2) = -DET3(A,C,D,E,G,H,M,O,P) * detval;
      M4F(_t,1,3) =  DET3(A,C,D,E,G,H,I,K,L) * detval;

      M4F(_t,2,0) =  DET3(E,F,H,I,J,L,M,N,P) * detval;
      M4F(_t,2,1) = -DET3(A,B,D,I,J,L,M,N,P) * detval;
      M4F(_t,2,2) =  DET3(A,B,D,E,F,H,M,N,P) * detval;
      M4F(_t,2,3) = -DET3(A,B,D,E,F,H,I,J,L) * detval;

      M4F(_t,3,0) = -DET3(E,F,G,I,J,K,M,N,O) * detval;
      M4F(_t,3,1) =  DET3(A,B,C,I,J,K,M,N,O) * detval;
      M4F(_t,3,2) = -DET3(A,B,C,E,F,G,M,N,O) * detval;
      M4F(_t,3,3) =  DET3(A,B,C,E,F,G,I,J,K) * detval;
   } 
   else 
   {
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::invert_SELF: Invalid Matrix (det==0)");
   }
#undef P
#undef O
#undef N
#undef M
#undef L
#undef K
#undef J
#undef I
#undef H
#undef G
#undef F
#undef E
#undef D
#undef C
#undef B
#undef A
#undef DET3
}

#else //INVERT_DET

//an alternative implementation of invert matrix
//this should theoretically be faster, as it uses less multiplications
//but in some compiler/os/architecture combinations the determinant version
//is faster
//
//maybe decide at compiletime?
void _Matrix4f::invertHelper(_Matrix4f *o) {
   sF32 m0,m1,m2,m3,s;
   sF32 rd0[8],rd1[8],rd2[8],rd3[8],*r0=rd0, *r1=rd1, *r2=rd2, *r3=rd3, *tmp;

   r0[0] = TM4F(0,0);
   r0[1] = TM4F(0,1);
   r0[2] = TM4F(0,2);
   r0[3] = TM4F(0,3);
   r0[4] = 1.0f;
   r0[5] = 0.0f;
   r0[6] = 0.0f;
   r0[7] = 0.0f;
   
   r1[0] = TM4F(1,0);
   r1[1] = TM4F(1,1);
   r1[2] = TM4F(1,2);
   r1[3] = TM4F(1,3);
   r1[5] = 1.0f;
   r1[4] = 0.0f;
   r1[6] = 0.0f;
   r1[7] = 0.0f;

   r2[0] = TM4F(2,0);
   r2[1] = TM4F(2,1);
   r2[2] = TM4F(2,2);
   r2[3] = TM4F(2,3);
   r2[6] = 1.0f;
   r2[4] = 0.0f;
   r2[5] = 0.0f;
   r2[7] = 0.0f;

   r3[0] = TM4F(3,0);
   r3[1] = TM4F(3,1);
   r3[2] = TM4F(3,2);
   r3[3] = TM4F(3,3);
   r3[7] = 1.0f;
   r3[4] = 0.0f;
   r3[5] = 0.0f;
   r3[6] = 0.0f;
   
   /* Choose myPivot, or die. */
   if (fabsf(r3[0])>fabsf(r2[0])) {tmp = r3;r3 = r2;r2 = tmp;};
   if (fabsf(r2[0])>fabsf(r1[0])) {tmp = r2;r2 = r1;r1 = tmp;};
   if (fabsf(r1[0])>fabsf(r0[0])) {tmp = r1;r1 = r0;r0 = tmp;};
   if (Dfltzero(r0[0])) 
   {
      //assert(!"could not invert matrix");
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::invert2: Invalid Matrix (det==0)");
   }
   /* Eliminate first variable. */
   m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0];
   s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s;
   s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s;
   s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s;
   s = r0[4];
   if (Dfltnonzero(s)) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; }
   s = r0[5];
   if (Dfltnonzero(s)) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; }
   s = r0[6];
   if (Dfltnonzero(s)) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; }
   s = r0[7];
   if (Dfltnonzero(s)) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; }
   
   /* Choose myPivot, or die. */
   if (fabsf(r3[1])>fabsf(r2[1])) {tmp = r3;r3 = r2;r2 = tmp;};
   if (fabsf(r2[1])>fabsf(r1[1])) {tmp = r2;r2 = r1;r1 = tmp;};
   if (Dfltzero(r1[1])) 
   {
      //assert(!"could not invert matrix");
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::invert2: Invalid Matrix (det==0)");
   }
   /* Eliminate second variable. */
   m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1];
   r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2];
   r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3];
   s = r1[4]; if (Dfltnonzero(s)) { r2[4] -= m2 * s; r3[4] -= m3 * s; }
   s = r1[5]; if (Dfltnonzero(s)) { r2[5] -= m2 * s; r3[5] -= m3 * s; }
   s = r1[6]; if (Dfltnonzero(s)) { r2[6] -= m2 * s; r3[6] -= m3 * s; }
   s = r1[7]; if (Dfltnonzero(s)) { r2[7] -= m2 * s; r3[7] -= m3 * s; }
   
   /* Choose myPivot, or die. */
   if (fabsf(r3[2])>fabsf(r2[2])) {tmp=r3;r3 = r2;r2 = tmp;};
   if (Dfltzero(r2[2])) 
   {
      // assert(!"could not invert matrix");
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::invert2: Invalid Matrix (det==0)");
   }
   /* Eliminate third variable. */
   m3 = r3[2]/r2[2];
   r3[3] -= m3 * r2[3];
   r3[4] -= m3 * r2[4];
   r3[5] -= m3 * r2[5];
   r3[6] -= m3 * r2[6];
   r3[7] -= m3 * r2[7];
   /* Last check. */
   if (Dfltzero(r3[3])) 
   {
      //assert(!"could not invert matrix");
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::invert2: Invalid Matrix (det==0)");
   }
   
   s = 1.0f/r3[3];              /* Now back substitute row 3. */
   r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s;
   
   m2 = r2[3];                 /* Now back substitute row 2. */
   s  = 1.0f/r2[2];
   r2[4] = s * (r2[4] - r3[4] * m2);
   r2[5] = s * (r2[5] - r3[5] * m2);
   r2[6] = s * (r2[6] - r3[6] * m2);
   r2[7] = s * (r2[7] - r3[7] * m2);
   m1 = r1[3];
   r1[4] -= r3[4] * m1;
   r1[5] -= r3[5] * m1;
   r1[6] -= r3[6] * m1;
   r1[7] -= r3[7] * m1;
   m0 = r0[3];
   r0[4] -= r3[4] * m0;
   r0[5] -= r3[5] * m0;
   r0[6] -= r3[6] * m0;
   r0[7] -= r3[7] * m0;
   
   m1 = r1[2];                 /* Now back substitute row 1. */
   s  = 1.0f/r1[1];
   r1[4] = s * (r1[4] - r2[4] * m1);
   r1[5] = s * (r1[5] - r2[5] * m1);
   r1[6] = s * (r1[6] - r2[6] * m1);
   r1[7] = s * (r1[7] - r2[7] * m1);
   m0 = r0[2];
   r0[4] -= r2[4] * m0;
   r0[5] -= r2[5] * m0;
   r0[6] -= r2[6] * m0;
   r0[7] -= r2[7] * m0;
   
   m0 = r0[1];                 /* Now back substitute row 0. */
   s  = 1.0f/r0[0];
   r0[4] = s * (r0[4] - r1[4] * m0);
   r0[5] = s * (r0[5] - r1[5] * m0);
   r0[6] = s * (r0[6] - r1[6] * m0);
   r0[7] = s * (r0[7] - r1[7] * m0);
   
   OM4F(0,0) = r0[4];  OM4F(0,1) = r0[5];
   OM4F(0,2) = r0[6];  OM4F(0,3) = r0[7];
   OM4F(1,0) = r1[4];  OM4F(1,1) = r1[5];
   OM4F(1,2) = r1[6];  OM4F(1,3) = r1[7];
   OM4F(2,0) = r2[4];  OM4F(2,1) = r2[5];
   OM4F(2,2) = r2[6];  OM4F(2,3) = r2[7];
   OM4F(3,0) = r3[4];  OM4F(3,1) = r3[5];
   OM4F(3,2) = r3[6];  OM4F(3,3) = r3[7];
   
}


#endif // INVERT_DET

void _Matrix4f::_invert_YAC_RSELF(void) {
   _Matrix4f t;
   t.class_ID = clid_Matrix4f;
   t._setColumnMajor(_getColumnMajor());

   invertHelper(&t);

   // Copy result
   for(sUI k=0; k<16; k++)
   {
      floats[k] = t.floats[k];
   }
}

void _Matrix4f::_invert_YAC_RVAL(YAC_Value *_r) {
   _Matrix4f *r = YAC_NEW_POOLED(Matrix4f);
   r->_setColumnMajor(_getColumnMajor());
   invertHelper(r);
   _r->initObject(r, 1);
}

void _Matrix4f::_invert_YAC_RARG(YAC_Object *_r) {
   if(YAC_CHK(_r, clid_Matrix4f)) 
   {
      sF32 detval = _det();
      if(Dfltnonzero(detval)) 
      {
         _Matrix4f *r = (_Matrix4f*)_r;

         invertHelper(r);
      } 
      else 
      {
         Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::invert_ARG: Invalid Matrix (det==0)");
      }
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::invert_ARG: Return object not of type Matrix4f");
   }
}

//transpose/mirrow matrix
void _Matrix4f::_transpose_YAC_RSELF(void) {
   sF32 a = floats[ 1];
   sF32 b = floats[ 2];
   sF32 c = floats[ 3];
   sF32 d = floats[ 6];
   sF32 e = floats[ 7];
   sF32 f = floats[11];
   floats[ 1] = floats[ 4];
   floats[ 2] = floats[ 8];
   floats[ 3] = floats[12];
   floats[ 6] = floats[ 9];
   floats[ 7] = floats[13];
   floats[11] = floats[14];
   floats[ 4] = a;
   floats[ 8] = b;
   floats[12] = c;
   floats[ 9] = d;
   floats[13] = e;
   floats[14] = f;
}

void _Matrix4f::_transpose_YAC_RVAL(YAC_Value *_r) {
   _Matrix4f *r = YAC_NEW_POOLED(Matrix4f);
   r->_setColumnMajor(_getColumnMajor());
   r->floats[ 0] = floats[ 0]; r->floats[ 1] = floats[4]; r->floats[ 2] = floats[ 8]; r->floats[ 3] = floats[12];
   r->floats[ 4] = floats[ 1]; r->floats[ 5] = floats[5]; r->floats[ 6] = floats[ 9]; r->floats[ 7] = floats[13];
   r->floats[ 8] = floats[ 2]; r->floats[ 9] = floats[6]; r->floats[10] = floats[10]; r->floats[11] = floats[14];
   r->floats[12] = floats[ 3]; r->floats[13] = floats[7]; r->floats[14] = floats[11]; r->floats[15] = floats[15];

   _r->initObject(r,1);
}

void _Matrix4f::_transpose_YAC_RARG(YAC_Object *_r) {
   if(YAC_CHK(_r, clid_Matrix4f))
   {
      _Matrix4f *r = (_Matrix4f*)_r;
      for(sUI y=0; y<4; y++)
      {
         for(sUI x=0; x<4; x++)
         {
            M4F(r,x,y) = TM4F(y,x);
         }
      }
   }
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix4f::transpose_ARG: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_setRow(sUI row, YAC_Object *_o) {
   _initRowV(row,_o);
}

void _Matrix4f::_getRow_YAC_RVAL(sUI row, YAC_Value *_r) {
   if(row < 4) 
   {
      _Vector4f *r = YAC_NEW_POOLED(Vector4f);
      r->_init(TM4F(row,0), TM4F(row,1), TM4F(row,2), TM4F(row,3));
      _r->initObject(r, 1);
   }
   else
   {
      /*not thread safe*/ static char buf[256];
      sprintf(buf, "tkmath::Matrix4f::getRow_VAL: Wrong Row Number! (%d>3)\n", row);
      Dyac_throw_def(WriteArrayOutOfBounds, buf);
   }
}

void _Matrix4f::_getRow_YAC_RARG(sUI row, YAC_Object *_r) {
   if(row < 4) 
   {
      if(YAC_CHK(_r, clid_Vector4f)) 
      {
         _Vector4f *r = (_Vector4f*)_r;
         r->_init(TM4F(row,0), TM4F(row,1), TM4F(row,2), TM4F(row,3));
      }
      else
      {
         Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::getRow_VAL: Return object not of type Vector4f");
      }
   }
   else
   {
      /*not thread safe*/ static char buf[256];
      sprintf(buf, "tkmath::Matrix4f::getRow_VAL: Wrong Row Number! (%d>3)\n", row);
      Dyac_throw_def(WriteArrayOutOfBounds, buf);
   }
}

void _Matrix4f::_setCol(sUI col, YAC_Object *_o) {
   _initColV(col,_o);
}

void _Matrix4f::_getCol_YAC_RVAL(sUI col, YAC_Value *_r) {
   if(col < 4) 
   {
      _Vector4f *r = YAC_NEW_POOLED(Vector4f);
      r->_init(TM4F(0,col), TM4F(1,col), TM4F(2,col), TM4F(3,col));
      _r->initObject(r, 1);
   }
   else
   {
      /*not thread safe*/ static char buf[256];
      sprintf(buf, "tkmath::Matrix4f::getCol_VAL: Wrong Row Number! (%d>3)\n", col);
      Dyac_throw_def(WriteArrayOutOfBounds, buf);
   }
}

void _Matrix4f::_getCol_YAC_RARG(sUI col, YAC_Object *_r) {
   if(col < 4) 
   {
      if(YAC_CHK(_r, clid_Vector4f)) 
      {
         _Vector4f *r = (_Vector4f*)_r;
         r->_init(TM4F(0,col), TM4F(1,col), TM4F(2,col), TM4F(3,col));
      }
      else
      {
         Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::getCol_ARG: Return object not of type Vector4f");
      }
   }
   else
   {
      /*not thread safe*/ static char buf[256];
      sprintf(buf, "tkmath::Matrix4f::getCol_ARG: Wrong Row Number! (%d>3)\n", col);
      Dyac_throw_def(WriteArrayOutOfBounds, buf);
   }
}

void _Matrix4f::_getQuaternionf_YAC_RVAL(YAC_Value *_r) {
   _Quaternionf *q = YAC_NEW_POOLED(Quaternionf);
   _getQuaternionf_YAC_RARG(q);
   _r->initObject(q, 1);
}

void _Matrix4f::_getQuaternionf_YAC_RARG(YAC_Object *_r) {
   if(YAC_CHK(_r, clid_Quaternionf)) 
   {
      _Quaternionf *q = (_Quaternionf*)_r;
      sF32 s0, s1, s2;
      sSI k0, k1, k2, k3;
      if((TM4F(0,0) + TM4F(1,1) + TM4F(2,2)) > 0.0f)
      {
         k0 = 0;
         k1 = 3;
         k2 = 2;
         k3 = 1;
         s0 = 1.0f;
         s1 = 1.0f;
         s2 = 1.0f;
      } 
      else if((TM4F(0,0) > TM4F(1,1)) && (TM4F(0,0) > TM4F(2,2)))
      {
         k0 = 1;
         k1 = 2;
         k2 = 3;
         k3 = 0;
         s0 =  1.0f;
         s1 = -1.0f;
         s2 = -1.0f;
      } 
      else if(TM4F(1,1) > TM4F(2,2))
      {
         k0 = 2;
         k1 = 1;
         k2 = 0;
         k3 = 3;
         s0 = -1.0f;
         s1 =  1.0f;
         s2 = -1.0f;
      } 
      else 
      {
         k0 = 3;
         k1 = 0;
         k2 = 1;
         k3 = 2;
         s0 = -1.0f;
         s1 = -1.0f;
         s2 =  1.0f;
      }
      sF32 t = s0 * TM4F(0,0) + s1 * TM4F(1,1) + s2 * TM4F(2,2) + 1.0f;
      sF32 s = 0.5f / sqrtf(t);
      //sF32 s = ReciprocalSqrt( t ) * 0.5f;
      q->floats[k0] = s * t;
      q->floats[k1] = ( TM4F(0,1) - s2 * TM4F(1,0) ) * s;
      q->floats[k2] = ( TM4F(2,0) - s1 * TM4F(0,2) ) * s;
      q->floats[k3] = ( TM4F(1,2) - s0 * TM4F(2,1) ) * s;
      //translational part of matrix - we omit it
      //q[4] = m[0 * 4 + 3];
      //q[5] = m[1 * 4 + 3];
      //q[6] = m[2 * 4 + 3];
      //q[7] = 0.0f;

//mist
/*      sF32 a,b,c,d,e,f,g,h,i;
      a=(floats[1]+floats[4])/4.0f;
      b=(floats[2]+floats[8])/4.0f;
      c=(floats[6]+floats[9])/4.0f;
      d=(floats[4]-floats[1])/4.0f;
      e=(floats[2]-floats[8])/4.0f;
      f=(floats[9]-floats[6])/4.0f;
      g=1.0f-floats[0];
      h=1.0f-floats[5];
      i=1.0f-floats[10];
      if (Dfltnonzero(g)&&Dfltnonzero(h)&&Dfltnonzero(i)) {
         q->floats[0]=sqrtf((f*f+e*e)/i);
	 q->floats[1]=sqrtf((a*a+b*b)/g);
	 q->floats[2]=sqrtf((a*a+c*c)/h);
	 q->floats[3]=sqrtf((b*b+c*c)/i);
      } else {
         Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix4f::Quaternionf Cannot determine Quaternion representation");
      }*/
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::getQuaternionf_ARG: Return object not of type Quaternionf");
   }
}

//initialisation methods
void _Matrix4f::_init(sF32 a, sF32 b, sF32 c, sF32 d, 
                      sF32 e, sF32 f, sF32 g, sF32 h, 
                      sF32 i, sF32 j, sF32 k, sF32 l, 
                      sF32 m, sF32 n, sF32 o, sF32 p) 
{
   TM4F(0,0) = a;
   TM4F(0,1) = b;
   TM4F(0,2) = c;
   TM4F(0,3) = d;
   TM4F(1,0) = e;
   TM4F(1,1) = f;
   TM4F(1,2) = g;
   TM4F(1,3) = h;
   TM4F(2,0) = i;
   TM4F(2,1) = j;
   TM4F(2,2) = k;
   TM4F(2,3) = l;
   TM4F(3,0) = m;
   TM4F(3,1) = n;
   TM4F(3,2) = o;
   TM4F(3,3) = p;
}

void _Matrix4f::_initRow(sUI row, sF32 p, sF32 q, sF32 r, sF32 s) {
   if(row < 4) 
   {
      TM4F(row, 0) = p;
      TM4F(row, 1) = q;
      TM4F(row, 2) = r;
      TM4F(row, 3) = s;
   } 
   else 
   {
      /*not thread safe*/ static char buf[256];
      sprintf(buf, "tkmath::Matrix3f::initRow: Wrong Row Number! (%d>3)", row);
      Dyac_throw_def(WriteArrayOutOfBounds, buf);
   }
}

void _Matrix4f::_initCol(sUI col, sF32 p, sF32 q, sF32 r, sF32 s) {
   if(col < 4) 
   {
      TM4F(0, col) = p;
      TM4F(1, col) = q;
      TM4F(2, col) = r;
      TM4F(3, col) = s;
   } 
   else 
   {
      /*not thread safe*/ static char buf[256];
      sprintf(buf, "tkmath::Matrix4f::initCol: Wrong Col Number! (%d>3)\n", col);
      Dyac_throw_def(WriteArrayOutOfBounds, buf);
   }
}

void _Matrix4f::_initRowV(sUI row, YAC_Object *_o) {
   if(YAC_VALID(_o)) 
   {
      _Vector4f t;
      t.class_ID = clid_Vector4f;
      t.assignGeneric(NULL, _o);

      if(row < 4) 
      {
         TM4F(row, 0) = t.floats[0];
         TM4F(row, 1) = t.floats[1];
         TM4F(row, 2) = t.floats[2];
         TM4F(row, 3) = t.floats[3];
      }
      else
      {
         /*not thread safe*/ static char buf[256];
         sprintf(buf, "tkmath::Matrix4f::initRowV: Wrong Row Number! (%d>3)\n", row);
         Dyac_throw_def(WriteArrayOutOfBounds, buf);
      }
   } 
   else 
   {
      Dyac_throw_def(TkMathInvalidValue,"tkmath::Matrix4f::initRowV: Invalid Object Value");
   }
}

void _Matrix4f::_initColV(sUI col, YAC_Object *_o) {
   if(YAC_VALID(_o)) 
   {
      _Vector4f t;
      t.class_ID = clid_Vector4f;
      t.assignGeneric(NULL,_o);

      if(col < 4) 
      {
         TM4F(0, col) = t.floats[0];
         TM4F(1, col) = t.floats[1];
         TM4F(2, col) = t.floats[2];
         TM4F(3, col) = t.floats[3];
      }
      else
      {
         /*not thread safe*/ static char buf[256];
         sprintf(buf, "tkmath::Matrix4f::initColV: Wrong Col Number! (%d>3)\n", col);
         Dyac_throw_def(WriteArrayOutOfBounds, buf);
      }
   } 
   else 
   {
      Dyac_throw_def(TkMathInvalidValue,"tkmath::Matrix4f::initColV: Invalid Object Value");
   }
}

void _Matrix4f::_initRotate(sF32 angle, YAC_Object *_dir) {
   if(YAC_BCHK(_dir, clid_Vector3f))
   {
      _Vector3f *v = (_Vector3f*) _dir;
      sF32 x = v->floats[0];
      sF32 y = v->floats[1];
      sF32 z = v->floats[2];
      sF32 s = (sF32) sin(angle);
      sF32 c = (sF32) cos(angle);
      TM4F(0, 0) = x*x*(1-c)+c;
      TM4F(0, 1) = x*y*(1-c)-z*s;
      TM4F(0, 2) = x*z*(1-c)+y*s;
      TM4F(0, 3) = 0;

      TM4F(1, 0) = y*x*(1-c)+z*s;
      TM4F(1, 1) = y*y*(1-c)+c;
      TM4F(1, 2) = y*z*(1-c)-x*s;
      TM4F(1, 3) = 0;

      TM4F(2, 0) = x*z*(1-c)-y*s;
      TM4F(2, 1) = y*z*(1-c)+x*s;
      TM4F(2, 2) = z*z*(1-c)+c;
      TM4F(2, 3) = 0;

      TM4F(3, 3) = 0;
      TM4F(3, 3) = 0;
      TM4F(3, 3) = 0;
      TM4F(3, 3) = 1;
   }
   else
   {
      Dyac_throw_def(NativeClassTypeMismatch, "direction vector is not a Vector4f object");
   }
}

void _Matrix4f::_initEulerXYX(sF32 a, sF32 b, sF32 c) {
   sF32 s1 = sinf(a), c1 = cosf(a);
   sF32 s2 = sinf(b), c2 = cosf(b);
   sF32 s3 = sinf(c), c3 = cosf(c);

   TM4F(0,0) = c2;
   TM4F(0,1) = s1*s2;
   TM4F(0,2) = c1*s2;
   TM4F(0,3) = 0.0f;

   TM4F(1,0) = s2*s3;
   TM4F(1,1) = c1*c3-c2*s1*s3;
   TM4F(1,2) = -c3*s1-c1*c2*s3;
   TM4F(1,3) = 0.0f;

   TM4F(2,0) = -c3*s2;
   TM4F(2,1) = c2*c3*s1+c1*s3;
   TM4F(2,2) = c1*c2*c3-s1*s3;
   TM4F(2,3) = 0.0f;

   TM4F(3,0) = 0.0f;
   TM4F(3,1) = 0.0f;
   TM4F(3,2) = 0.0f;
   TM4F(3,3) = 1.0f;
}

void _Matrix4f::_initEulerXZX(sF32 a, sF32 b, sF32 c) {
   sF32 s1 = sinf(a), c1 = cosf(a);
   sF32 s2 = sinf(b), c2 = cosf(b);
   sF32 s3 = sinf(c), c3 = cosf(c);

   TM4F(0,0) = c2;
   TM4F(0,1) = -c1*s2;
   TM4F(0,2) = s1*s2;
   TM4F(0,3) = 0.0f;

   TM4F(1,0) = c3*s2;
   TM4F(1,1) = c1*c2*c3-s1*s3;
   TM4F(1,2) = -c2*c3*s1-c1*s3;
   TM4F(1,3) = 0.0f;

   TM4F(2,0) = s2*s3;
   TM4F(2,1) = c3*s1+c1*c2*s3;
   TM4F(2,2) = c1*c3-c2*s1*s3;
   TM4F(2,3) = 0.0f;

   TM4F(3,0) = 0.0f;
   TM4F(3,1) = 0.0f;
   TM4F(3,2) = 0.0f;
   TM4F(3,3) = 1.0f;
}

void _Matrix4f::_initEulerYXY(sF32 a, sF32 b, sF32 c) {
   sF32 s1 = sinf(a), c1 = cosf(a);
   sF32 s2 = sinf(b), c2 = cosf(b);
   sF32 s3 = sinf(c), c3 = cosf(c);

   TM4F(0,0) = c1*c3-c2*s1*s3;
   TM4F(0,1) = s2*s3;
   TM4F(0,2) = c3*s1+c1*c2*s3;
   TM4F(0,3) = 0.0f;

   TM4F(1,0) = s1*s2;
   TM4F(1,1) = c2;
   TM4F(1,2) = -c1*s2;
   TM4F(1,3) = 0.0f;

   TM4F(2,0) = -c2*c3*s1-c1*s3;
   TM4F(2,1) = c3*s2;
   TM4F(2,2) = c1*c2*c3-s1*s3;
   TM4F(2,3) = 0.0f;

   TM4F(3,0) = 0.0f;
   TM4F(3,1) = 0.0f;
   TM4F(3,2) = 0.0f;
   TM4F(3,3) = 1.0f;
}

void _Matrix4f::_initEulerYZY(sF32 a, sF32 b, sF32 c) {
   sF32 s1 = sinf(a), c1 = cosf(a);
   sF32 s2 = sinf(b), c2 = cosf(b);
   sF32 s3 = sinf(c), c3 = cosf(c);

   TM4F(0,0) = c1*c2*c3-s1*s3;
   TM4F(0,1) = -c3*s2;
   TM4F(0,2) = c2*c3*s1+c1*s3;
   TM4F(0,3) = 0.0f;

   TM4F(1,0) = c1*s2;
   TM4F(1,1) = c2;
   TM4F(1,2) = s1*s2;
   TM4F(1,3) = 0.0f;

   TM4F(2,0) = -c3*s1-c1*c2*s3;
   TM4F(2,1) = s2*s3;
   TM4F(2,2) = c1*c3-c2*s1*s3;
   TM4F(2,3) = 0.0f;

   TM4F(3,0) = 0.0f;
   TM4F(3,1) = 0.0f;
   TM4F(3,2) = 0.0f;
   TM4F(3,3) = 1.0f;
}

void _Matrix4f::_initEulerZXZ(sF32 a, sF32 b, sF32 c) {
   sF32 s1 = sinf(a), c1 = cosf(a);
   sF32 s2 = sinf(b), c2 = cosf(b);
   sF32 s3 = sinf(c), c3 = cosf(c);

   TM4F(0,0) = c1*c3-c2*s1*s3;
   TM4F(0,1) = -c3*s1-c1*c2*s3;
   TM4F(0,2) = s2*s3;
   TM4F(0,3) = 0.0f;

   TM4F(1,0) = c2*c3*s1+c1*s3;
   TM4F(1,1) = c1*c2*c3-s1*s3;
   TM4F(1,2) = -c3*s2;
   TM4F(1,3) = 0.0f;

   TM4F(2,0) = s1*s2;
   TM4F(2,1) = c1*s2;
   TM4F(2,2) = c2;
   TM4F(2,3) = 0.0f;

   TM4F(3,0) = 0.0f;
   TM4F(3,1) = 0.0f;
   TM4F(3,2) = 0.0f;
   TM4F(3,3) = 1.0f;
}

void _Matrix4f::_initEulerZYZ(sF32 a, sF32 b, sF32 c) {
   sF32 s1 = sinf(a), c1 = cosf(a);
   sF32 s2 = sinf(b), c2 = cosf(b);
   sF32 s3 = sinf(c), c3 = cosf(c);

   TM4F(0,0) = c1*c2*c3-s1*s3;
   TM4F(0,1) = -c2*c3*s1-c1*s3;
   TM4F(0,2) = c3*s2;
   TM4F(0,3) = 0.0f;

   TM4F(1,0) = c3*s1+c1*c2*s3;
   TM4F(1,1) = c1*c3-c2*s1*s3;
   TM4F(1,2) = s2*s3;
   TM4F(1,3) = 0.0f;

   TM4F(2,0) = -c1*s2;
   TM4F(2,1) = s1*s2;
   TM4F(2,2) = c2;
   TM4F(2,3) = 0.0f;

   TM4F(3,0) = 0.0f;
   TM4F(3,1) = 0.0f;
   TM4F(3,2) = 0.0f;
   TM4F(3,3) = 1.0f;
}

void _Matrix4f::_initEulerXYZ(sF32 a, sF32 b, sF32 c) {
   sF32 s1 = sinf(a), c1 = cosf(a);
   sF32 s2 = sinf(b), c2 = cosf(b);
   sF32 s3 = sinf(c), c3 = cosf(c);

   TM4F(0,0) = c2*c3;
   TM4F(0,1) = c3*s1*s2-c1*s3;
   TM4F(0,2) = c1*c3*s2+s1*s3;
   TM4F(0,3) = 0.0f;

   TM4F(1,0) = c2*s3;
   TM4F(1,1) = c1*c3+s1*s2*s3;
   TM4F(1,2) = c1*s2*s3-c3*s1;
   TM4F(1,3) = 0.0f;

   TM4F(2,0) = -s2;
   TM4F(2,1) = c2*s1;
   TM4F(2,2) = c1*c2;
   TM4F(2,3) = 0.0f;

   TM4F(3,0) = 0.0f;
   TM4F(3,1) = 0.0f;
   TM4F(3,2) = 0.0f;
   TM4F(3,3) = 1.0f;
}

void _Matrix4f::_initEulerXZY(sF32 a, sF32 b, sF32 c) {
   sF32 s1 = sinf(a), c1 = cosf(a);
   sF32 s2 = sinf(b), c2 = cosf(b);
   sF32 s3 = sinf(c), c3 = cosf(c);

   TM4F(0,0) = c2*c3;
   TM4F(0,1) = s1*s3-c1*c3*s2;
   TM4F(0,2) = c3*s1*s2+c1*s3;
   TM4F(0,3) = 0.0f;

   TM4F(1,0) = s2;
   TM4F(1,1) = c1*c2;
   TM4F(1,2) = -c2*s1;
   TM4F(1,3) = 0.0f;

   TM4F(2,0) = -c2*s3;
   TM4F(2,1) = c3*s1+c1*s2*s3;
   TM4F(2,2) = c1*c3-s1*s2*s3;
   TM4F(2,3) = 0.0f;

   TM4F(3,0) = 0.0f;
   TM4F(3,1) = 0.0f;
   TM4F(3,2) = 0.0f;
   TM4F(3,3) = 1.0f;
}

void _Matrix4f::_initEulerYXZ(sF32 a, sF32 b, sF32 c) {
   sF32 s1 = sinf(a), c1 = cosf(a);
   sF32 s2 = sinf(b), c2 = cosf(b);
   sF32 s3 = sinf(c), c3 = cosf(c);

   TM4F(0,0) = c1*c3-s1*s2*s3;
   TM4F(0,1) = -c2*s3;
   TM4F(0,2) = c3*s1+c1*s2*s3;
   TM4F(0,3) = 0.0f;

   TM4F(1,0) = c3*s1*s2+c1*s3;
   TM4F(1,1) = c2*c3;
   TM4F(1,2) = s1*s3-c1*c3*s2;
   TM4F(1,3) = 0.0f;

   TM4F(2,0) = -c2*s1;
   TM4F(2,1) = s2;
   TM4F(2,2) = c1*c2;
   TM4F(2,3) = 0.0f;

   TM4F(3,0) = 0.0f;
   TM4F(3,1) = 0.0f;
   TM4F(3,2) = 0.0f;
   TM4F(3,3) = 1.0f;
}

void _Matrix4f::_initEulerYZX(sF32 a, sF32 b, sF32 c) {
   sF32 s1 = sinf(a), c1 = cosf(a);
   sF32 s2 = sinf(b), c2 = cosf(b);
   sF32 s3 = sinf(c), c3 = cosf(c);

   TM4F(0,0) = c1*c2;
   TM4F(0,1) = -s2;
   TM4F(0,2) = c2*s1;
   TM4F(0,3) = 0.0f;

   TM4F(1,0) = c1*c3*s2+s1*s3;
   TM4F(1,1) = c2*c3;
   TM4F(1,2) = c3*s1*s2-c1*s3;
   TM4F(1,3) = 0.0f;

   TM4F(2,0) = c1*s2*s3-c3*s1;
   TM4F(2,1) = c2*s3;
   TM4F(2,2) = c1*c3+s1*s2*s3;
   TM4F(2,3) = 0.0f;

   TM4F(3,0) = 0.0f;
   TM4F(3,1) = 0.0f;
   TM4F(3,2) = 0.0f;
   TM4F(3,3) = 1.0f;
}

void _Matrix4f::_initEulerZXY(sF32 a, sF32 b, sF32 c) {
   sF32 s1 = sinf(a), c1 = cosf(a);
   sF32 s2 = sinf(b), c2 = cosf(b);
   sF32 s3 = sinf(c), c3 = cosf(c);

   TM4F(0,0) = c1*c3+s1*s2*s3;
   TM4F(0,1) = c1*s2*s3-c3*s1;
   TM4F(0,2) = c2*s3;
   TM4F(0,3) = 0.0f;

   TM4F(1,0) = c2*s1;
   TM4F(1,1) = c1*c2;
   TM4F(1,2) = -s2;
   TM4F(1,3) = 0.0f;

   TM4F(2,0) = c3*s1*s2-c1*s3;
   TM4F(2,1) = c1*c3*s2+s1*s3;
   TM4F(2,2) = c2*c3;
   TM4F(2,3) = 0.0f;

   TM4F(3,0) = 0.0f;
   TM4F(3,1) = 0.0f;
   TM4F(3,2) = 0.0f;
   TM4F(3,3) = 1.0f;
}

void _Matrix4f::_initEulerZYX(sF32 a, sF32 b, sF32 c) {
   sF32 s1 = sinf(a), c1 = cosf(a);
   sF32 s2 = sinf(b), c2 = cosf(b);
   sF32 s3 = sinf(c), c3 = cosf(c);

   TM4F(0,0) = c1*c2;
   TM4F(0,1) = -c2*s1;
   TM4F(0,2) = s2;
   TM4F(0,3) = 0.0f;

   TM4F(1,0) = c3*s1+c1*s2*s3;
   TM4F(1,1) = c1*c3-s1*s2*s3;
   TM4F(1,2) = -c2*s3;
   TM4F(1,3) = 0.0f;

   TM4F(2,0) = s1*s3-c1*c3*s2;
   TM4F(2,1) = c3*s1*s2+c1*s3;
   TM4F(2,2) = c2*c3;
   TM4F(2,3) = 0.0f;

   TM4F(3,0) = 0.0f;
   TM4F(3,1) = 0.0f;
   TM4F(3,2) = 0.0f;
   TM4F(3,3) = 1.0f;
}

void _Matrix4f::_New(YAC_Object *_o, YAC_Value *_r) {
   if(YAC_VALID(_o))
   {
      _Matrix4f *r = YAC_NEW_POOLED(Matrix4f);
      r->_setColumnMajor(_getColumnMajor());
      r->assignGeneric(NULL, _o);
      _r->initObject(r, 1);
   } 
   else 
   {
      Dyac_throw_def(TkMathInvalidValue,"tkmath::Matrix4f::New: invalid Object");
   }
}

/*void _Matrix4f::_New(sF32 a, sF32 b, sF32 c, sF32 d, sF32 e, sF32 f, sF32 g, sF32 h, sF32 i, sF32 j, sF32 k, sF32 l, sF32 m, sF32 n, sF32 o, sF32 p, YAC_Value *_r) {
   _Matrix4f *r=YAC_NEW_POOLED(Matrix4f);
   r->_init(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p);
   _r->initObject(r,1);
}*/

/*void _matrix4f(sF32 a, sF32 b, sF32 c, sF32 d, sF32 e, sF32 f, sF32 g, sF32 h, sF32 i, sF32 j, sF32 k, sF32 l, sF32 m, sF32 n, sF32 o, sF32 p, YAC_Value *_r) {
   _Matrix4f *r=YAC_NEW_POOLED(Matrix4f);
   r->_init(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p);
   _r->initObject(r,1);
}*/

void YAC_CALL _matrix4f(YAC_Object *_o, YAC_Value *_r) {
   if(YAC_VALID(_o)) 
   {
      _Matrix4f *r=YAC_NEW_POOLED(Matrix4f);
      r->assignGeneric(NULL, _o);
      _r->initObject(r,1);
   } 
   else 
   {
      Dyac_throw_def(TkMathInvalidValue,"tkmath::matrix4f: invalid Object");
   }
}

//several generic matrices for usual cases

void _Matrix4f::_BuildPerspectiveMatrix4f_YAC_RVAL(sF32 fov, sF32 aspect, sF32 zNear, sF32 zFar, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   _BuildPerspectiveMatrix4f_YAC_RARG(fov, aspect, zNear, zFar, m);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildPerspectiveMatrix4f_YAC_RARG(sF32 fov, sF32 aspectRatio, sF32 zNear, sF32 zFar, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f)) 
   {
      sF32 sine, cotangent, deltaZ;
      sF32 radians = (fov * 0.5f) * ((sF32)sM_PI / 180.0f);
      _Matrix4f *m = (_Matrix4f*)_m;

      deltaZ = zFar - zNear;
      sine = sinf(radians);
      /* Should be non-zero to avoid division by zero. */
      //assert(deltaZ);
      //assert(sine);
      //assert(aspectRatio);
      cotangent = cosf(radians) / sine;

      m->_initCol(0,cotangent / aspectRatio,0,0,0);
      m->_initCol(1,0,cotangent,0,0);
      m->_initCol(2,0,0,-(zFar+zNear)/deltaZ,-2*zNear*zFar/deltaZ);
      m->_initCol(3,0,0,-1,0);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildPerspectiveMatrix4f Return object not of type Matrix4f");
   }
}

void _Matrix4f::_BuildLookAtMatrix4f_YAC_RVAL(YAC_Object *_eye, YAC_Object *_center, YAC_Object *_up, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   _BuildLookAtMatrix4f_YAC_RARG(_eye, _center, _up, m);
   _r->initObject(m,1);
}

void _Matrix4f::_BuildLookAtMatrix4f_YAC_RARG(YAC_Object *_eye, YAC_Object *_center, YAC_Object *_up, YAC_Object *_m) {
   if(
      YAC_CHK(_eye,    clid_Vector3f) && 
      YAC_CHK(_center, clid_Vector3f) &&
      YAC_CHK(_up,     clid_Vector3f)
      ) 
   {
      if(YAC_CHK(_m, clid_Matrix4f)) 
      {
         _Matrix4f *m      = (_Matrix4f*)_m;
         _Vector3f *eye    = (_Vector3f*)_eye;
         _Vector3f *center = (_Vector3f*)_center;
         _Vector3f *up     = (_Vector3f*)_up;
         YAC_NEW_STACK(Vector3f,x);
         YAC_NEW_STACK(Vector3f,y);
         YAC_NEW_STACK(Vector3f,z);
         YAC_NEW_STACK(Vector3f,neye);
         //z=eye-center
         eye->_sub_YAC_RARG(center,&z);
         //z.unit()
         z._unit_YAC_RSELF();
         //x=up x x
         up->_cross_YAC_RARG(&z,&x);
         //y=zxy
         z._cross_YAC_RARG(&x,&y);
         //x.unit()
         x._unit_YAC_RSELF();
         //y.unit()
         y._unit_YAC_RSELF();
         //neye=-eye
         eye->_mulf_YAC_RARG(-1.0f,&neye);
         
         m->_init(
            x.floats[0], x.floats[1], x.floats[2], x._dot(&neye),
            y.floats[0], y.floats[1], y.floats[2], y._dot(&neye),
            z.floats[0], z.floats[1], z.floats[2], z._dot(&neye),
            0,           0,           0,           1.0f         );
      } 
      else 
      {
         Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildLookAtMatrix4f: Return object not of type Matrix4f");
      }
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildLookAtMatrix4f: Objects not of type Vector3f"); 
   }
}

void _Matrix4f::_BuildRotateMatrix4f_YAC_RVAL(sF32 angle, YAC_Object *_dir, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   _BuildRotateMatrix4f_YAC_RARG(angle,_dir,m);
   _r->initObject(m,1);
}

void _Matrix4f::_BuildRotateMatrix4f_YAC_RARG(sF32 radians, YAC_Object *_dir, YAC_Object *_m) {
   if(YAC_CHK(_dir, clid_Vector3f)) 
   {
      if(YAC_CHK(_m, clid_Matrix4f)) 
      {
         //         sF32 radians;
         sF32 sine, cosine, ab, bc, ca, tx, ty, tz;
         _Vector3f *dir = (_Vector3f*)_dir;
         ////_Matrix4f *m   = (_Matrix4f*)_m;
         YAC_NEW_STACK(Vector3f, axis);
  
         dir->_unit_YAC_RARG(&axis);
  
         //         radians = angle * M_PI / 180.0;
         sine = sinf(radians);
         cosine = cosf(radians);
         ab = axis.floats[0] * axis.floats[1] * (1 - cosine);
         bc = axis.floats[1] * axis.floats[2] * (1 - cosine);
         ca = axis.floats[2] * axis.floats[0] * (1 - cosine);
         tx = axis.floats[0] * axis.floats[0];
         ty = axis.floats[1] * axis.floats[1];
         tz = axis.floats[2] * axis.floats[2];
         TM4F(0,0) = tx + cosine * (1 - tx);
         TM4F(0,1) = ab + axis.floats[2] * sine;
         TM4F(0,2) = ca - axis.floats[1] * sine;
         TM4F(0,3) = 0.0f;
         TM4F(1,0) = ab - axis.floats[2] * sine;
         TM4F(1,1) = ty + cosine * (1 - ty);
         TM4F(1,2) = bc + axis.floats[0] * sine;
         TM4F(1,3) = 0.0f;
         TM4F(2,0) = ca + axis.floats[1] * sine;
         TM4F(2,1) = bc - axis.floats[0] * sine;
         TM4F(2,2) = tz + cosine * (1 - tz);
         TM4F(2,3) = 0.0f;
         TM4F(3,0) = 0.0f;
         TM4F(3,1) = 0.0f;
         TM4F(3,2) = 0.0f;
         TM4F(3,3) = 1.0f;
      } 
      else 
      {
         Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildRotateMatrix4f: Return object not of type Matrix4f");
      }
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildRotateMatrix4f: Object not of type Vector3f");
   }
}

void _Matrix4f::_BuildTranslateMatrix4f_YAC_RVAL(YAC_Object *_move, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   _BuildTranslateMatrix4f_YAC_RARG(_move, m);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildTranslateMatrix4f_YAC_RARG(YAC_Object *_move, YAC_Object *_m) {
   if(YAC_CHK(_move, clid_Vector3f)) 
   {
      if(YAC_CHK(_m, clid_Matrix4f)) 
      {
         _Matrix4f *m    = (_Matrix4f*)_m;
         _Vector3f *move = (_Vector3f*)_move;
         m->_init(1, 0, 0, move->floats[0],
                  0, 1, 0, move->floats[1],
                  0, 0, 1, move->floats[2],
                  0, 0, 0, 1
                  );
      } 
      else 
      {
         Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildTranslateMatrix4f: Return object not of type Matrix4f");
      }
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildTranslateMatrix4f: Object not of type Vector3f");
   }
}

void _Matrix4f::_BuildScaleMatrix4f_YAC_RVAL(YAC_Object *_scale, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   _BuildScaleMatrix4f_YAC_RARG(_scale, m);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildScaleMatrix4f_YAC_RARG(YAC_Object *_scale, YAC_Object *_m) {
   if(YAC_CHK(_scale, clid_Vector3f)) 
   {
      if(YAC_CHK(_m, clid_Matrix4f)) 
      {
         _Matrix4f *m     = (_Matrix4f*)_m;
         _Vector3f *scale = (_Vector3f*)_scale;
         m->_init(scale->floats[0], 0,                0,                0,
                  0,                scale->floats[1], 0,                0,
                  0,                0,                scale->floats[2], 0,
                  0,                0,                0,                1
                  );
      } 
      else 
      {
         Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildScaleMatrix4f: Return object not of type Matrix4f");
      }
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildScaleMatrix4f: Object not of type Vector3f");
   }
}

void _Matrix4f::_BuildEulerXZX4f_YAC_RVAL(sF32 a, sF32 b, sF32 c, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   m->_initEulerXZX(a, b, c);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildEulerXZX4f_YAC_RARG(sF32 a, sF32 b, sF32 c, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f)) 
   {
      _Matrix4f *m = (_Matrix4f*)_m;
      m->_initEulerXZX(a, b, c);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildEulerXZX4f: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_BuildEulerXYX4f_YAC_RVAL(sF32 a, sF32 b, sF32 c, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   m->_initEulerXYX(a, b, c);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildEulerXYX4f_YAC_RARG(sF32 a, sF32 b, sF32 c, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f)) 
   {
      _Matrix4f *m = (_Matrix4f*)_m;
      m->_initEulerXYX(a, b, c);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildEulerXYX4f: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_BuildEulerYXY4f_YAC_RVAL(sF32 a, sF32 b, sF32 c, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   m->_initEulerYXY(a, b, c);
   _r->initObject(m,1);
}

void _Matrix4f::_BuildEulerYXY4f_YAC_RARG(sF32 a, sF32 b, sF32 c, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f)) 
   {
      _Matrix4f *m = (_Matrix4f*)_m;
      m->_initEulerYXY(a, b, c);
   }
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildEulerYXY4f: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_BuildEulerYZY4f_YAC_RVAL(sF32 a, sF32 b, sF32 c, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   m->_initEulerYZY(a, b, c);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildEulerYZY4f_YAC_RARG(sF32 a, sF32 b, sF32 c, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f)) 
   {
      _Matrix4f *m = (_Matrix4f*)_m;
      m->_initEulerYZY(a, b, c);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildEulerYZY4f: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_BuildEulerZYZ4f_YAC_RVAL(sF32 a, sF32 b, sF32 c, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   m->_initEulerZYZ(a, b, c);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildEulerZYZ4f_YAC_RARG(sF32 a, sF32 b, sF32 c, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f)) 
   {
      _Matrix4f *m = (_Matrix4f*)_m;
      m->_initEulerZYZ(a, b, c);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildEulerZYZ4f: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_BuildEulerZXZ4f_YAC_RVAL(sF32 a, sF32 b, sF32 c, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   m->_initEulerZXZ(a, b, c);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildEulerZXZ4f_YAC_RARG(sF32 a, sF32 b, sF32 c, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f)) 
   {
      _Matrix4f *m = (_Matrix4f*)_m;
      m->_initEulerZXZ(a, b, c);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildEulerZXZ4f: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_BuildEulerXZY4f_YAC_RVAL(sF32 a, sF32 b, sF32 c, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   m->_initEulerXZY(a, b, c);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildEulerXZY4f_YAC_RARG(sF32 a, sF32 b, sF32 c, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f)) 
   {
      _Matrix4f *m = (_Matrix4f*)_m;
      m->_initEulerXZY(a, b, c);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildEulerXZY4f: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_BuildEulerXYZ4f_YAC_RVAL(sF32 a, sF32 b, sF32 c, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   m->_initEulerXYZ(a, b, c);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildEulerXYZ4f_YAC_RARG(sF32 a, sF32 b, sF32 c, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f)) 
   {
      _Matrix4f *m = (_Matrix4f*)_m;
      m->_initEulerXYZ(a, b, c);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildEulerXYZ4f: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_BuildEulerYXZ4f_YAC_RVAL(sF32 a, sF32 b, sF32 c, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   m->_initEulerYXZ(a, b, c);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildEulerYXZ4f_YAC_RARG(sF32 a, sF32 b, sF32 c, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f)) 
   {
      _Matrix4f *m = (_Matrix4f*)_m;
      m->_initEulerYXZ(a, b, c);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildEulerYXZ4f: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_BuildEulerYZX4f_YAC_RVAL(sF32 a, sF32 b, sF32 c, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   m->_initEulerYZX(a, b, c);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildEulerYZX4f_YAC_RARG(sF32 a, sF32 b, sF32 c, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f)) 
   {
      _Matrix4f *m = (_Matrix4f*)_m;
      m->_initEulerYZX(a, b, c);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildEulerYZX4f: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_BuildEulerZYX4f_YAC_RVAL(sF32 a, sF32 b, sF32 c, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   m->_initEulerZYX(a, b, c);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildEulerZYX4f_YAC_RARG(sF32 a, sF32 b, sF32 c, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f))
   {
      _Matrix4f *m = (_Matrix4f*)_m;
      m->_initEulerZYX(a, b, c);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildEulerZYX4f: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_BuildEulerZXY4f_YAC_RVAL(sF32 a, sF32 b, sF32 c, YAC_Value *_r) {
   _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
   m->_setColumnMajor(_getColumnMajor());
   m->_initEulerZXY(a, b, c);
   _r->initObject(m, 1);
}

void _Matrix4f::_BuildEulerZXY4f_YAC_RARG(sF32 a, sF32 b, sF32 c, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f)) 
   {
      _Matrix4f *m = (_Matrix4f*)_m;
      m->_initEulerZXY(a, b, c);
   } 
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix4f::BuildEulerZXY4f: Return object not of type Matrix4f");
   }
}

void _Matrix4f::_initIdentity(void) {
   TM4F(0,0) = 1.0f;
   TM4F(1,0) = 0.0f;
   TM4F(2,0) = 0.0f;
   TM4F(3,0) = 0.0f;
   TM4F(0,1) = 0.0f;
   TM4F(1,1) = 1.0f;
   TM4F(2,1) = 0.0f;
   TM4F(3,1) = 0.0f;
   TM4F(0,2) = 0.0f;
   TM4F(1,2) = 0.0f;
   TM4F(2,2) = 1.0f;
   TM4F(3,2) = 0.0f;
   TM4F(0,3) = 0.0f;
   TM4F(1,3) = 0.0f;
   TM4F(2,3) = 0.0f;
   TM4F(3,3) = 1.0f;
}
