/// matrix2f.cpp
///
/// (c) 2008 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 "vector2f.h"
#include "matrix2f.h"

#include "ying_Math.h"

_Matrix2f::_Matrix2f(void) {
   floats[0]=floats[1]=floats[2]=floats[3]=0.0f;
}

_Matrix2f::~_Matrix2f() {
}

sUI YAC_VCALL _Matrix2f::yacArrayGetNumElements(void) {
   return 4;
}

sUI YAC_VCALL _Matrix2f::yacArrayGetMaxElements(void) {
   return 4;
}

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

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

void YAC_VCALL _Matrix2f::yacArraySet(YAC_ContextHandle _ctx, sUI _idx, YAC_Value *_val) {
   if (_idx<4) {
      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::Matrix2f::yacArraySet Unknown Type!");
            v=0.0f;
            break;
      }
      floats[_idx]=v;
   }
   else 
   {
      static char buf[256];
      sprintf(buf, "tkmath::Matrix2f::yacArraySet Index too high (%d>3)", _idx);
      Dyac_throw(WriteArrayOutOfBounds, buf);
   }
}

void YAC_VCALL _Matrix2f::yacArrayGet(YAC_ContextHandle _ctx, sUI _idx, YAC_Value *_val) {
   if (_idx<4) 
   {
      _val->initFloat(floats[_idx]);
   } 
   else 
   {
      static char buf[256];
      sprintf(buf, "tkmath::Matrix2f::yacArrayGet Index too high (%d>3)", _idx);
      Dyac_throw(ReadArrayOutOfBounds, buf);
      _val->initFloat(0.0f);
   }
}

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

sUI YAC_VCALL _Matrix2f::yacArrayGetWidth(void) {
   return 2;
}

sUI YAC_VCALL _Matrix2f::yacArrayGetHeight(void) {
   return 2;
}

sUI YAC_VCALL _Matrix2f::yacArrayGetStride(void) {
   return 2*sizeof(sF32);
}

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

void YAC_VCALL _Matrix2f::yacSerialize(YAC_Object *_ofs, sUI _rtti) {
   YAC_BEG_SERIALIZE();
   YAC_SERIALIZE_F32(floats[0]);
   YAC_SERIALIZE_F32(floats[1]);
   YAC_SERIALIZE_F32(floats[2]);
   YAC_SERIALIZE_F32(floats[3]);
}

sUI YAC_VCALL _Matrix2f::yacDeserialize(YAC_Object *_ifs, sUI _rtti) {
   YAC_BEG_DESERIALIZE();
   floats[0]=YAC_DESERIALIZE_F32();
   floats[1]=YAC_DESERIALIZE_F32();
   floats[2]=YAC_DESERIALIZE_F32();
   floats[3]=YAC_DESERIALIZE_F32();
   return 1;
}

void YAC_VCALL _Matrix2f::yacOperatorClamp(YAC_Object *_min, YAC_Object *_max) {
   if (YAC_CHK(_min,clid_Matrix2f)&&YAC_CHK(_max,clid_Matrix2f)) {
      _Matrix2f *min=(_Matrix2f*)_min;
      _Matrix2f *max=(_Matrix2f*)_max;
      if (floats[0]<min->floats[0]) floats[0]=min->floats[0];
      else if (floats[0]>max->floats[0]) floats[0]=max->floats[0];
      if (floats[1]<min->floats[1]) floats[1]=min->floats[1];
      else if (floats[1]>max->floats[1]) floats[1]=max->floats[1];
      if (floats[2]<min->floats[2]) floats[2]=min->floats[2];
      else if (floats[2]>max->floats[2]) floats[2]=max->floats[2];
      if (floats[3]<min->floats[3]) floats[3]=min->floats[3];
      else if (floats[3]>max->floats[3]) floats[3]=max->floats[3];
   } else Dyac_throw_def(InvalidPointer, "");
}

void YAC_VCALL _Matrix2f::yacOperatorWrap(YAC_Object *_min, YAC_Object *_max) {
   if (YAC_CHK(_min,clid_Matrix2f)&&YAC_CHK(_max,clid_Matrix2f)) {
      _Matrix2f *min=(_Matrix2f*)_min;
      _Matrix2f *max=(_Matrix2f*)_max;
      if (floats[0]<min->floats[0]) floats[0]+=(max->floats[0]-min->floats[0]);
      else if (floats[0]>max->floats[0]) floats[0]-=(max->floats[0]-min->floats[0]);
      if (floats[1]<min->floats[1]) floats[1]+=(max->floats[1]-min->floats[1]);
      else if (floats[1]>max->floats[1]) floats[1]-=(max->floats[1]-min->floats[1]);
      if (floats[2]<min->floats[2]) floats[2]+=(max->floats[2]-min->floats[2]);
      else if (floats[2]>max->floats[2]) floats[2]-=(max->floats[2]-min->floats[2]);
      if (floats[3]<min->floats[3]) floats[3]+=(max->floats[3]-min->floats[3]);
      else if (floats[3]>max->floats[3]) floats[3]-=(max->floats[3]-min->floats[3]);
   } else Dyac_throw_def(InvalidPointer, "");
}

void YAC_VCALL _Matrix2f::yacOperator(sSI _cmd,YAC_Object *_o, YAC_Value *_r) {
   if (YAC_CHK(_o,clid_Matrix2f)) {
      _Matrix2f *o=(_Matrix2f*)_o;
      switch (_cmd) {
         case YAC_OP_CEQ:
            YAC_RETI( Dfltequal(floats[0], o->floats[0]) && 
                      Dfltequal(floats[1], o->floats[1]) && 
                      Dfltequal(floats[2], o->floats[2]) &&
                      Dfltequal(floats[3], o->floats[3]) );
            break;
         case YAC_OP_CNE:
            YAC_RETI( Dfltnotequal(floats[0], o->floats[0]) || 
                      Dfltnotequal(floats[1], o->floats[1]) ||
                      Dfltnotequal(floats[2], o->floats[2]) ||
                      Dfltnotequal(floats[3], o->floats[3]) );
            break;
         case YAC_OP_ASSIGN:
            floats[0]=o->floats[0];
            floats[1]=o->floats[1];
            floats[2]=o->floats[2];
            floats[3]=o->floats[3];
            break;
         case YAC_OP_ADD:
            {
               //_Matrix2f *r = YAC_NEW_POOLED(Matrix2f);
               //*r=*this;
               //r->_add(_o);
               //_r->initObject(r,1);
               _add_YAC_RSELF(_o);
            }
            break;
         case YAC_OP_SUB:
            {
               //_Matrix2f *r = YAC_NEW_POOLED(Matrix2f);
               //*r=*this;
               //r->_sub(_o);
               //_r->initObject(r,1);
               _sub_YAC_RSELF(_o);
            }
            break;
         case YAC_OP_MUL:
            {
               //_Matrix2f *r = YAC_NEW_POOLED(Matrix2f);
               //*r=*this;
               //r->_mul(_o);
               //_r->initObject(r,1);
               _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];
            break;
         case YAC_OP_INIT:
            floats[0]=0.0f;
            floats[1]=0.0f;
            floats[2]=0.0f;
            floats[3]=0.0f;
            break;
         default:
         {
            static char buf[256];
            sprintf(buf, "tkmath::Matrix2f::yacOperator: unsupported cmd %d!\n", _cmd);
            Dyac_throw_def(TkMathUnsupportedOperator, buf);
            return;
         }
      }
   } else if (YAC_Is_FloatArray(_o)) {
      YAC_FloatArray *o=(YAC_FloatArray*)_o;
      switch (_cmd) {
         case YAC_OP_ASSIGN:
            if (o->num_elements<4) {
               sUI i;
               for (i=0;i<o->num_elements;i++) floats[i]=o->elements[i];
               for (;i<4;i++) floats[i]=0.0f;
            } else {
               floats[0]=o->elements[0];
               floats[1]=o->elements[1];
               floats[2]=o->elements[2];
               floats[3]=o->elements[3];
            }
            break;
         default:
	    _Matrix2f t;
	    t.class_ID=clid_Matrix2f;
	    t.assignFloatArray(o);
	    yacOperator(_cmd, &t, _r);
            //Dyac_throw_def(TkMathUnsupportedOperator, "tkmath::Matrix2f::yacOperator Only Assign supported with FloatArray Type");
            break;
      }
   } else if (YAC_VALID(_o)) {
      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::Matrix2f::yacOperator Only Assign supported with Generic Object Type");
	    break;
      }
   } else {
      switch (_cmd) {
         case YAC_OP_NEG:
	    floats[0]=-floats[0];
	    floats[1]=-floats[1];
	    floats[2]=-floats[2];
	    floats[3]=-floats[3];
	    break;
	 default:
            YAC_Object::yacOperator(_cmd,_o,_r);
      }
   }
}

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

void _Matrix2f::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::Matrix2f::yacOperatorF32 OP_DIV Cannot divide by zero");
         }
         break;
      default:
         char buf[256];
         sprintf(buf,"tkmath::Matrix2f::yacOperatorF32 Operator not supported %d",_cmd);
         Dyac_throw_def(TkMathUnsupportedOperator,buf);
   }
}


void _Matrix2f::assignFloats(sF32 *_fv, sUI _ne) {
   if(_ne != 4) {
      Dyac_throw_def(WriteArrayOutOfBounds,"tkmath::Matrix2f Array not of size 4");
   } else {
      // Copy two elements
      floats[0] = _fv[0];
      floats[1] = _fv[1];
      floats[2] = _fv[2];
      floats[3] = _fv[3];
   }
}

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

void _Matrix2f::assignGeneric(YAC_ContextHandle _ctx, YAC_Object *_o) {
   sUI ne = _o->yacArrayGetNumElements();
   sUI nH = _o->yacArrayGetHeight();
   sUI nW = _o->yacArrayGetWidth();
   if (nH==0) {
      if (nW==4) { //exact number to fill the matrix - we can go on
         nH=2;
	 nW=2;
      } else { //nah, throw an exception
         Dyac_throw_def(TkMathInvalidValue,"tkmath::Matrix2f Array not of size 4");
      }
   }
   if(ne > 0)
   {
      if(YAC_TYPE_FLOAT == _o->yacArrayGetElementType())
      {
         sF32 *fv = (sF32*) _o->yacArrayGetPointer();
         if(NULL != fv)
         {
            // Copy fast
	    sUI i,j;
	    for (i=0;(i<2)&&(i<nH);i++) {
	       for (j=0;(j<2)&&(j<nW);j++) {
	          floats[(i*2)+j]=fv[(i*nW)+j];
	       }
	       for (;j<2;j++) {
	          if (i!=j) floats[(i*2)+j]=0.0f;
		  else floats[(i*2)+j]=1.0f;
	       }
	    }
	    for (;(i<2);i++) {
	       for (j=0;j<2;j++) {
	          if (i!=j) floats[(i*2)+j]=0.0f;
		  else floats[(i*2)+j]=1.0f;
	       }
	    }

            return;
         }
         else
         {
            // Retrieve individual float elements and assign
            YAC_Value v;
	    sUI i,j;
	    for (i=0;(i<2)&&(i<nH);i++) {
	       for (j=0;(j<2)&&(j<nW);j++) {
	          _o->yacArrayGet(_ctx, (i*nW)+j, &v);
	          floats[(i*2)+j]=v.value.float_val;
	       }
	       for (;j<2;j++) {
	          if (i!=j) floats[(i*2)+j]=0.0f;
		  else floats[(i*2)+j]=1.0f;
	       }
	    }
	    for (;(i<2);i++) {
	       for (j=0;j<2;j++) {
	          if (i!=j) floats[(i*2)+j]=0.0f;
		  else floats[(i*2)+j]=1.0f;
	       }
	    }
         }
      }
      else
      {
         // Retrieve individual elements, typecast to float and assign
         YAC_Value v;
         sUI i,j;
         for (i=0;(i<2)&&(i<nH);i++) {
            for (j=0;(j<2)&&(j<nW);j++) {
               _o->yacArrayGet(_ctx, (i*nW)+j, &v);
	       v.typecast(YAC_TYPE_FLOAT);
               floats[(i*2)+j]=v.value.float_val;
	       v.unset();
            }
            for (;j<2;j++) {
               if (i!=j) floats[(i*2)+j]=0.0f;
	       else floats[(i*2)+j]=1.0f;
            }
         }
         for (;(i<2);i++) {
            for (j=0;j<2;j++) {
               if (i!=j) floats[(i*2)+j]=0.0f;
	       else floats[(i*2)+j]=1.0f;
            }
         }
      }
   }
   else
   {
      // Other array is empty or no array. Silently assign 0.0f
      floats[0]=floats[1]=floats[2]=floats[3]=0.0f;
   }
}


//direct element access
void _Matrix2f::_setA(sF32 x) {
   floats[0]=x;
}

void _Matrix2f::_setB(sF32 y) {
   floats[1]=y;
}

void _Matrix2f::_setC(sF32 x) {
   floats[2]=x;
}

void _Matrix2f::_setD(sF32 y) {
   floats[3]=y;
}

sF32 _Matrix2f::_getA(void) {
   return floats[0];
}

sF32 _Matrix2f::_getB(void) {
   return floats[1];
}

sF32 _Matrix2f::_getC(void) {
   return floats[2];
}

sF32 _Matrix2f::_getD(void) {
   return floats[3];
}

//generate string representation
sBool YAC_VCALL _Matrix2f::yacToString(YAC_String *s) const {
   s->yacArrayAlloc(1024,0,0,0);
   s->printf("((%g, %g), (%g, %g))",floats[0],floats[1],floats[2],floats[3]);
   s->fixLength();
   return 1;
}

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

//add two matrices
void _Matrix2f::_add_YAC_RSELF(YAC_Object *_o) {
   if (YAC_CHK(_o,clid_Matrix2f)) {
      _Matrix2f *o=(_Matrix2f*)_o;
      floats[0]+=o->floats[0];
      floats[1]+=o->floats[1];
      floats[2]+=o->floats[2];
      floats[3]+=o->floats[3];
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::add_SELF Object not of type Matrix2f");
   }
}

void _Matrix2f::_add_YAC_RVAL(YAC_Object *_o, YAC_Value *_r) {
   if (YAC_CHK(_o,clid_Matrix2f)) {
      _Matrix2f *o=(_Matrix2f*)_o;
      _Matrix2f *r=YAC_NEW_POOLED(Matrix2f);
      r->floats[0] = floats[0] + o->floats[0];
      r->floats[1] = floats[1] + o->floats[1];
      r->floats[2] = floats[2] + o->floats[2];
      r->floats[3] = floats[3] + o->floats[3];
      _r->initObject(r,1);
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::add_VAL Object not of type Matrix2f");
   }
}

void _Matrix2f::_add_YAC_RARG(YAC_Object *_o, YAC_Object *_r) {
   if (YAC_CHK(_o,clid_Matrix2f)&&YAC_CHK(_r, clid_Matrix2f)) {
      _Matrix2f *o=(_Matrix2f*)_o;
      _Matrix2f *r=(_Matrix2f*)_r;
      r->floats[0] = floats[0] + o->floats[0];
      r->floats[1] = floats[1] + o->floats[1];
      r->floats[2] = floats[2] + o->floats[2];
      r->floats[3] = floats[3] + o->floats[3];
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::add_ARG Object not of type Matrix2f");
   }
}

//sub two matrices
void _Matrix2f::_sub_YAC_RSELF(YAC_Object *_o) {
   if (YAC_CHK(_o,clid_Matrix2f)) {
      _Matrix2f *o=(_Matrix2f*)_o;
      floats[0]-=o->floats[0];
      floats[1]-=o->floats[1];
      floats[2]-=o->floats[2];
      floats[3]-=o->floats[3];
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::sub_SELF Object not of type Matrix2f");
   }
}

void _Matrix2f::_sub_YAC_RVAL(YAC_Object *_o, YAC_Value *_r) {
   if (YAC_CHK(_o,clid_Matrix2f)) {
      _Matrix2f *o=(_Matrix2f*)_o;
      _Matrix2f *r=YAC_NEW_POOLED(Matrix2f);
      r->floats[0] = floats[0] - o->floats[0];
      r->floats[1] = floats[1] - o->floats[1];
      r->floats[2] = floats[2] - o->floats[2];
      r->floats[3] = floats[3] - o->floats[3];
      _r->initObject(r,1);
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::sub_VAL Object not of type Matrix2f");
   }
}

void _Matrix2f::_sub_YAC_RARG(YAC_Object *_o, YAC_Object *_r) {
   if (YAC_CHK(_o,clid_Matrix2f)&&YAC_CHK(_r,clid_Matrix2f)) {
      _Matrix2f *o=(_Matrix2f*)_o;
      _Matrix2f *r=(_Matrix2f*)_r;
      r->floats[0] = floats[0] - o->floats[0];
      r->floats[1] = floats[1] - o->floats[1];
      r->floats[2] = floats[2] - o->floats[2];
      r->floats[3] = floats[3] - o->floats[3];
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::sub_ARG Object not of type Matrix2f");
   }
}

//multiply matrix with scalar value
void _Matrix2f::_mulf_YAC_RSELF(sF32 s) {
   floats[0]*=s;
   floats[1]*=s;
   floats[2]*=s;
   floats[3]*=s;
}

void _Matrix2f::_mulf_YAC_RVAL(sF32 s, YAC_Value *_r) {
   _Matrix2f *r=YAC_NEW_POOLED(Matrix2f);
   r->floats[0] = floats[0] * s;
   r->floats[1] = floats[1] * s;
   r->floats[2] = floats[2] * s;
   r->floats[3] = floats[3] * s;
   _r->initObject(r,1);
}

void _Matrix2f::_mulf_YAC_RARG(sF32 s, YAC_Object *_r) {
   if (YAC_CHK(_r, clid_Matrix2f)) {
      _Matrix2f *r=(_Matrix2f*)_r;
      r->floats[0] = floats[0] * s;
      r->floats[1] = floats[1] * s;
      r->floats[2] = floats[2] * s;
      r->floats[3] = floats[3] * s;
   } else {
     Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::mulf_ARG Return object not of type Matrix2f");
   }
}

//multiply two matrices
void _Matrix2f::_mul_YAC_RSELF(YAC_Object *_o) {
   if (YAC_CHK(_o,clid_Matrix2f)) {
      _Matrix2f *o=(_Matrix2f*)_o;
      sF32 a,b,c,d;
      a=floats[0]*o->floats[0]+floats[1]*o->floats[2];
      b=floats[0]*o->floats[1]+floats[1]*o->floats[3];
      c=floats[2]*o->floats[0]+floats[3]*o->floats[2];
      d=floats[2]*o->floats[1]+floats[3]*o->floats[3];
      floats[0]=a;
      floats[1]=b;
      floats[2]=c;
      floats[3]=d;
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::mul_SELF Object not of type Matrix2f!\n");
   }
}

void _Matrix2f::_mul_YAC_RVAL(YAC_Object *_o, YAC_Value *_r) {
   if (YAC_CHK(_o,clid_Matrix2f)) {
      _Matrix2f *o=(_Matrix2f*)_o;
      _Matrix2f *r = YAC_NEW_POOLED(Matrix2f);
      r->floats[0]=floats[0]*o->floats[0]+floats[1]*o->floats[2];
      r->floats[1]=floats[0]*o->floats[1]+floats[1]*o->floats[3];
      r->floats[2]=floats[2]*o->floats[0]+floats[3]*o->floats[2];
      r->floats[3]=floats[2]*o->floats[1]+floats[3]*o->floats[3];
      _r->initObject(r,1);
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::mul_VAL Object not of type Matrix2f!\n");
   }
}

void _Matrix2f::_mul_YAC_RARG(YAC_Object *_o, YAC_Object *_r) {
   if (YAC_CHK(_o,clid_Matrix2f)&&YAC_CHK(_r,clid_Matrix2f)) {
      _Matrix2f *o=(_Matrix2f*)_o;
      _Matrix2f *r=(_Matrix2f*)_r;
      r->floats[0]=floats[0]*o->floats[0]+floats[1]*o->floats[2];
      r->floats[1]=floats[0]*o->floats[1]+floats[1]*o->floats[3];
      r->floats[2]=floats[2]*o->floats[0]+floats[3]*o->floats[2];
      r->floats[3]=floats[2]*o->floats[1]+floats[3]*o->floats[3];
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::mul_ARG Object not of type Matrix2f!\n");
   }
}

//multiply matrix with vector
void _Matrix2f::_mulv_YAC_RVAL(YAC_Object *_o, YAC_Value *_r) {
   if (YAC_CHK(_o,clid_Vector2f)) {
      _Vector2f *o=(_Vector2f*)_o;
      _Vector2f *r = YAC_NEW_POOLED(Vector2f);
      r->floats[0]=floats[0]*o->floats[0]+floats[1]*o->floats[1];
      r->floats[1]=floats[2]*o->floats[0]+floats[3]*o->floats[1];
      _r->initObject(r,1);
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::mulv Object not of type Vector2f");
   }
}

void _Matrix2f::_mulv_YAC_RARG(YAC_Object *_o, YAC_Object *_r) {
   if (YAC_CHK(_o,clid_Vector2f)&&(YAC_CHK(_r,clid_Vector2f))) {
      _Vector2f *o=(_Vector2f*)_o;
      _Vector2f *r = (_Vector2f*)_r;
      r->floats[0]=floats[0]*o->floats[0]+floats[1]*o->floats[1];
      r->floats[1]=floats[2]*o->floats[0]+floats[3]*o->floats[1];
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::mulv Object not of type Vector2f");
   }
}

//return "length" of matrix
sF32 _Matrix2f::_getAbs(void) {
   return sqrtf(floats[0]*floats[0]+floats[1]*floats[1]+floats[2]*floats[2]+floats[3]*floats[3]);
}

//return squared "length" of matrix
sF32 _Matrix2f::_getAbsSqr(void) {
   return (floats[0]*floats[0]+floats[1]*floats[1]+floats[2]*floats[2]+floats[3]*floats[3]);
}

//unify matrix to "length" 1
void _Matrix2f::_unit_YAC_RSELF(void) {
   sF32 absval=_getAbs();
   if (Dfltnonzero(absval)) {
      absval=1.0f/absval;
      floats[0]*=absval;
      floats[1]*=absval;
      floats[2]*=absval;
      floats[3]*=absval;
   } else {
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix2f::unit_SELF Zero Matrix cannot be normalized!\n");
   }
}

void _Matrix2f::_unit_YAC_RVAL(YAC_Value *_r) {
   sF32 absval=_getAbs();
   if (Dfltnonzero(absval)) {
      _Matrix2f *r=YAC_NEW_POOLED(Matrix2f);
      absval=1.0f/absval;
      r->floats[0] = floats[0] * absval;
      r->floats[1] = floats[1] * absval;
      r->floats[2] = floats[2] * absval;
      r->floats[3] = floats[3] * absval;
      _r->initObject(r,1);
   } else {
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix2f::unit_VAL Zero Matrix cannot be normalized!\n");
   }
}

void _Matrix2f::_unit_YAC_RARG(YAC_Object *_r) {
   if (YAC_CHK(_r, clid_Matrix2f)) {
      sF32 absval=_getAbs();
      if (Dfltnonzero(absval)) {
         _Matrix2f *r=(_Matrix2f*)_r;
	 absval=1.0f/absval;
         r->floats[0] = floats[0] * absval;
         r->floats[1] = floats[1] * absval;
         r->floats[2] = floats[2] * absval;
         r->floats[3] = floats[3] * absval;
      } else {
         Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix2f::unit_ARG Zero Matrix cannot be normalized!\n");
      }
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::unit_ARG Return object not of type Matrix2f");
   }
}

//scale matrix to "length" s
void _Matrix2f::_unitScale_YAC_RSELF(sF32 s) {
   sF32 absval=_getAbs();
   if (Dfltnonzero(absval)) {
      absval=s/absval;
      floats[0]*=absval;
      floats[1]*=absval;
      floats[2]*=absval;
      floats[3]*=absval;
   } else {
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix2f::unitScale_SELF Zero Matrix cannot be normalized");
   }
}

void _Matrix2f::_unitScale_YAC_RVAL(sF32 s, YAC_Value *_r) {
   sF32 absval=_getAbs();
   if (Dfltnonzero(absval)) {
      _Matrix2f *r=YAC_NEW_POOLED(Matrix2f);
      absval=s/absval;
      r->floats[0] = floats[0] * absval;
      r->floats[1] = floats[1] * absval;
      r->floats[2] = floats[2] * absval;
      r->floats[3] = floats[3] * absval;
      _r->initObject(r,1);
   } else {
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix2f::unitScale_VAL Zero Matrix cannot be normalized");
   }
}

void _Matrix2f::_unitScale_YAC_RARG(sF32 s, YAC_Object *_r) {
   if (YAC_CHK(_r, clid_Matrix2f)) {
      sF32 absval=_getAbs();
      if (Dfltnonzero(absval)) {
         _Matrix2f *r=(_Matrix2f*)_r;
         absval=s/absval;
         r->floats[0] = floats[0] * absval;
         r->floats[1] = floats[1] * absval;
         r->floats[2] = floats[2] * absval;
         r->floats[3] = floats[3] * absval;
      } else {
         Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix2f::unitScale_SELF Zero Matrix cannot be normalized");
      }
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::unitScale_SELF Return object not of type Matrix2f");
   }
}

//return determinant of matrix
sF32 _Matrix2f::_det(void) {
   return (floats[0]*floats[3]-floats[1]*floats[2]);
}

//invert matrix
void _Matrix2f::_invert_YAC_RSELF(void) {
   sF32 detval=_det();
   if (Dfltnonzero(detval)) {
      sF32 a,b,c,d;
      a=floats[3]/detval;
      b=-floats[1]/detval;
      c=-floats[2]/detval;
      d=floats[0]/detval;
      floats[0]=a;
      floats[1]=b;
      floats[2]=c;
      floats[3]=d;
   } else {
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix2f::invert_SELF Invalid Matrix (det==0)");
   }
}

void _Matrix2f::_invert_YAC_RVAL(YAC_Value *_r) {
   sF32 detval=_det();
   if (Dfltnonzero(detval)) {
      _Matrix2f *r=YAC_NEW_POOLED(Matrix2f);
      r->floats[0] =  floats[3] / detval;
      r->floats[1] = -floats[1] / detval;
      r->floats[2] = -floats[2] / detval;
      r->floats[3] =  floats[0] / detval;
      _r->initObject(r,1);
   } else {
      Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix2f::invert_VAL Invalid Matrix (det==0)");
   }
}

void _Matrix2f::_invert_YAC_RARG(YAC_Object *_r) {
   if (YAC_CHK(_r, clid_Matrix2f)) {
      sF32 detval=_det();
      if (Dfltnonzero(detval)) {
         _Matrix2f *r=(_Matrix2f*)_r;
         r->floats[0] =  floats[3] / detval;
         r->floats[1] = -floats[1] / detval;
         r->floats[2] = -floats[2] / detval;
         r->floats[3] =  floats[0] / detval;
      } else {
         Dyac_throw_def(TkMathDivisionByZero, "tkmath::Matrix2f::invert_ARG Invalid Matrix (det==0)");
      }
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::invert_ARG Return object not of type Matrix2f");
   }
}

//transpose/mirrow matrix
void _Matrix2f::_transpose_YAC_RSELF(void) {
   sF32 a;
   a=floats[2];
   floats[2]=floats[1];
   floats[1]=a;
}

void _Matrix2f::_transpose_YAC_RVAL(YAC_Value *_r) {
   _Matrix2f *r=YAC_NEW_POOLED(Matrix2f);
   r->floats[0]=floats[0]; r->floats[1]=floats[2];
   r->floats[2]=floats[1]; r->floats[3]=floats[3];
   _r->initObject(r,1);
}

void _Matrix2f::_transpose_YAC_RARG(YAC_Object *_r) {
   if (YAC_CHK(_r, clid_Matrix2f)) {
      _Matrix2f *r=(_Matrix2f*)_r;
      r->floats[0]=floats[0]; r->floats[1]=floats[2];
      r->floats[2]=floats[1]; r->floats[3]=floats[3];
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Matrix2f::transpose_ARG Return object not of type Matrix2f");
   }
}

//initialisation methods
void _Matrix2f::_init(sF32 a, sF32 b, sF32 c, sF32 d) {
   floats[0]=a;
   floats[1]=b;
   floats[2]=c;
   floats[3]=d;
}

void _Matrix2f::_initRow(sUI row, sF32 x, sF32 y) {
   if (row<2) {
      floats[row*2]=x;
      floats[row*2+1]=y;
   } else {
      static char buf[256];
      sprintf(buf, "tkmath::Matrix2f::initRow Wrong Row Number! (%d>1)", row);
      Dyac_throw_def(WriteArrayOutOfBounds, buf);
   }
}

void _Matrix2f::_initCol(sUI col, sF32 x, sF32 y) {
   if (col<2) {
      floats[col]=x;
      floats[col+2]=y;
   } else {
      static char buf[256];
      sprintf(buf, "tkmath::Matrix2f::initCol Wrong Col Number! (%d>1)\n", col);
      Dyac_throw_def(WriteArrayOutOfBounds, buf);
   }
}

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

void _Matrix2f::_getRow_YAC_RVAL(sUI row, YAC_Value *_r) {
   if (row>1) {
         static char buf[256];
         sprintf(buf, "tkmath::Matrix2f::getRow_VAL Wrong Row Number! (%d>1)\n", row);
         Dyac_throw_def(WriteArrayOutOfBounds, buf);
   }
   _Vector2f *r=YAC_NEW_POOLED(Vector2f);
   r->_init(floats[(row*2)+0],floats[(row*2)+1]);
   _r->initObject(r,1);
}

void _Matrix2f::_getRow_YAC_RARG(sUI row, YAC_Object *_r) {
   if (row>1) {
         static char buf[256];
         sprintf(buf, "tkmath::Matrix2f::getRow_ARG Wrong Row Number! (%d>1)\n", row);
         Dyac_throw_def(WriteArrayOutOfBounds, buf);
   }
   if (!YAC_CHK(_r,clid_Vector2f)) {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix2f::getRow_ARG Return object not of type Vector2f");
   }
   _Vector2f *r=(_Vector2f*)_r;
   r->_init(floats[(row*2)+0],floats[(row*2)+1]);
}

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

void _Matrix2f::_getCol_YAC_RVAL(sUI col, YAC_Value *_r) {
   if (col>1) {
         static char buf[256];
         sprintf(buf, "tkmath::Matrix2f::getCol_VAL Wrong Row Number! (%d>1)\n", col);
         Dyac_throw_def(WriteArrayOutOfBounds, buf);
   }
   _Vector2f *r=YAC_NEW_POOLED(Vector2f);
   r->_init(floats[0+col],floats[2+col]);
   _r->initObject(r,1);
}

void _Matrix2f::_getCol_YAC_RARG(sUI col, YAC_Object *_r) {
   if (col>1) {
         static char buf[256];
         sprintf(buf, "tkmath::Matrix2f::getCol_ARG Wrong Row Number! (%d>1)\n", col);
         Dyac_throw_def(WriteArrayOutOfBounds, buf);
   }
   if (!YAC_CHK(_r,clid_Vector2f)) {
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Matrix2f::getCol_ARG Return object not of type Vector2f");
   }
   _Vector2f *r=(_Vector2f*)_r;
   r->_init(floats[0+col],floats[2+col]);
}

void _Matrix2f::_initRowV(sUI row, YAC_Object *_o) {
   if (YAC_VALID(_o)) {
      _Vector2f t;
      t.class_ID=clid_Vector2f;
      t.assignGeneric(NULL,_o);
      if (row>1) {
         static char buf[256];
         sprintf(buf, "tkmath::Matrix2f::initRowV Wrong Row Number! (%d>1)\n", row);
         Dyac_throw_def(WriteArrayOutOfBounds, buf);
      }
      floats[(row*2)+0]=t.floats[0];
      floats[(row*2)+1]=t.floats[1];
   } else {
      Dyac_throw_def(TkMathInvalidValue,"tkmath::Matrix2f::initRowV: Invalid Object Value");
   }

}

void _Matrix2f::_initColV(sUI col, YAC_Object *_o) {
   if (YAC_VALID(_o)) {
      _Vector2f t;
      t.class_ID=clid_Vector2f;
      t.assignGeneric(NULL,_o);
      if (col>1) {
         static char buf[256];
         sprintf(buf, "tkmath::Matrix2f::initColV Wrong Col Number! (%d>1)\n", col);
         Dyac_throw_def(WriteArrayOutOfBounds, buf);
      }
      floats[0+col]=t.floats[0];
      floats[2+col]=t.floats[1];
   } else {
      Dyac_throw_def(TkMathInvalidValue,"tkmath::Matrix2f::initColV: Invalid Object Value");
   }
}

void _Matrix2f::_initIdentity(void) {
   floats[ 0] = 1.0f;
   floats[ 1] = 0.0f;

   floats[ 2] = 0.0f;
   floats[ 3] = 1.0f;
}

void _Matrix2f::_New(sF32 a, sF32 b, sF32 c, sF32 d, YAC_Value *_r) {
   _Matrix2f *r=YAC_NEW_POOLED(Matrix2f);
   r->_init(a,b,c,d);
   _r->initObject(r,1);
}

void YAC_CALL _matrix2f(sF32 a, sF32 b, sF32 c, sF32 d, YAC_Value *_r) {
   _Matrix2f *r=YAC_NEW_POOLED(Matrix2f);
   r->_init(a,b,c,d);
   _r->initObject(r,1);
}
