/// vector4f.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 "matrix.h"
#include "vector3f.h"
#include "vector4f.h"
#include "matrix4f.h"

#include "ying_Math.h"

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

_Vector4f::~_Vector4f() {
}

sUI _Vector4f::yacArrayGetNumElements(void) {
   return 4;
}

sUI _Vector4f::yacArrayGetMaxElements(void) {
   return 4;
}

sUI _Vector4f::yacArrayGetElementType(void) {
   return YAC_TYPE_FLOAT;
}

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

void YAC_VCALL _Vector4f::yacArraySet(YAC_ContextHandle _ctx, sUI _idx, YAC_Value *_val) {
   if(_idx < 4) 
   {
      sF32 v;
      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;
               }
            } 
            else 
            {
               // Silently cast <null> to 0.0f
               v = 0.0f;
            }
            break;
         default:
            // Should never ever happen!
            Dyac_throw(TypeMismatch, "tkmath::Vector3f::yacArraySet: unknown type");
            v = 0.0f;
            break;
      }
      floats[_idx] = v;
   }
   else 
   {
      static char buf[256];
      sprintf(buf, "tkmath::Vector4f::yacArraySet Index too high (%d>3)", _idx);
      Dyac_throw(WriteArrayOutOfBounds, buf);
   }
}

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

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

sSI YAC_VCALL _Vector4f::yacTensorRank(void) {
   return YAC_TENSOR_RANK_VECTOR;
}

void YAC_VCALL _Vector4f::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 _Vector4f::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 _Vector4f::yacOperatorAssign(YAC_Object *_o) {
   if(YAC_CHK(_o, clid_Vector4f)) 
   {
      _Vector4f *o = (_Vector4f*) _o;
      floats[0] = o->floats[0];
      floats[1] = o->floats[1];
      floats[2] = o->floats[2];
      floats[3] = o->floats[3];
   }
   if(YAC_CHK(_o, clid_Vector3f)) 
   {
      _Vector3f *o = (_Vector3f*) _o;
      floats[0] = o->floats[0];
      floats[1] = o->floats[1];
      floats[2] = o->floats[2];
      floats[3] = 1;
   }
   else 
   {
      YAC_Value r;
      yacOperator(YAC_OP_ASSIGN, _o, &r);
      r.unset();
   }
}

void YAC_VCALL _Vector4f::yacOperatorClamp(YAC_Object *_min, YAC_Object *_max) {
   if(YAC_CHK(_min, clid_Vector4f))
   {
      if(YAC_CHK(_max, clid_Vector4f))
      {
         _Vector4f *min=(_Vector4f*)_min;
         _Vector4f *max=(_Vector4f*)_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, "tkmath::Vector4f::yacOperatorClamp: invalid _max object.");
      }
   } 
   else 
   {
      Dyac_throw_def(InvalidPointer, "tkmath::Vector4f::yacOperatorClamp: invalid _min object.");
   }
}

void YAC_VCALL _Vector4f::yacOperatorWrap(YAC_Object *_min, YAC_Object *_max) {
   if(YAC_CHK(_min, clid_Vector4f))
   {
      if(YAC_CHK(_max, clid_Vector4f))
      {
         _Vector4f *min=(_Vector4f*)_min;
         _Vector4f *max=(_Vector4f*)_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, "tkmath::Vector4f::yacOperatorWrap: invalid _max object.");
      }
   } 
   else 
   {
      Dyac_throw_def(InvalidPointer, "tkmath::Vector4f::yacOperatorWrap: invalid _min object.");
   }
}

void YAC_VCALL _Vector4f::yacOperator(sSI _cmd,YAC_Object *_o, YAC_Value *_r) {
   if(YAC_CHK(_o, clid_Vector4f)) 
   {
      _Vector4f *o = (_Vector4f*) _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:
            _add_YAC_RSELF(_o);
            break;
         case YAC_OP_SUB:
            _sub_YAC_RSELF(_o);
            break;
//         case YAC_OP_MUL:
//            _mul(_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] = 1.0f;
            break;
         default:
         {
            // Should never ever happen !
            static char buf[256];
            sprintf(buf, "tkmath::Vector4f::yacOperator unsupported cmd %d", _cmd);
            Dyac_throw_def(TkMathUnsupportedOperator, buf);
         }
         return;
      }
   } 
   else if(YAC_VALID(_o))
   {
      sF32 val;
      if (_o->yacScanF32(&val)) {
         yacOperatorF32(_cmd, val, _r);
      } else
      // Check whether the object is derived from FloatArray
      if(YAC_Is_FloatArray(_o)) 
      {
         YAC_FloatArray *o = (YAC_FloatArray*) _o;
         switch(_cmd) 
         {
            case YAC_OP_ASSIGN:
               assignFloatArray(o);
               break;

            default:
            {
               // Create temporary Vector3f object on stack
               _Vector4f t;
               t.class_ID = clid_Vector4f;
               t.assignFloatArray(o);

               // Recursively call yacOperator again
               yacOperator(_cmd, &t, _r);
            }
            break;
         }
      }
      else 
      {
         // Handle generic float container object
         switch(_cmd)
         {
            case YAC_OP_ASSIGN:
               assignGeneric(NULL, _o);
               break;

            default:
            {
/*               _Vector4f t;
               t.class_ID = clid_Vector4f;
               t.assignGeneric(NULL, _o);*/

               // Recursively call yacOperator again
               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];
	    break;
	 default:
      // Call generic yacOperator, e.g. for <null> comparisons
            YAC_Object::yacOperator(_cmd, _o, _r);
      }
   }
}

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

void _Vector4f::yacOperatorF32(sSI _cmd, sF32 val, YAC_Value *_r) {
   switch (_cmd) {
      case YAC_OP_MUL:
         _mulf_YAC_RSELF(val);
         break;
      case YAC_OP_DIV:
         if (Dfltnotequal(val, 0)) {
            _mulf_YAC_RSELF(1.0f/val);
         } else {
            Dyac_throw_def(TkMathDivisionByZero, "tkmath::Vector4f::yacOperatorF32 OP_DIV Cannot divide by zero");
         }
         break;
      default:
         char buf[256];
         sprintf(buf,"tkmath::Vector4f::yacOperatorF32 Operator not supported %d",_cmd);
         Dyac_throw_def(TkMathUnsupportedOperator,buf);
   }
}

void _Vector4f::assignFloats(sF32 *_fv, sUI _ne) {
   if(_ne <= 4)
   {
      // Copy as much elements from array as possible but never more than 4
      sUI i;
      for(i=0; i<_ne; i++)
      {
         floats[i] = _fv[i];
      }
      // Fill the rest with 0.0f
      for(; i<4; i++)
      {
         floats[i] = 0.0f;
      }
   }
   else
   {
      // Copy four elements
      floats[0] = _fv[0];
      floats[1] = _fv[1];
      floats[2] = _fv[2];
      floats[3] = _fv[3];
   }
}

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

void _Vector4f::assignGeneric(YAC_ContextHandle _ctx, YAC_Object *_o) {
   sUI ne = _o->yacArrayGetNumElements();
   if(ne > 0)
   {
      if(YAC_TYPE_FLOAT == _o->yacArrayGetElementType())
      {
         sF32 *fv = (sF32*) _o->yacArrayGetPointer();
         if(NULL != fv)
         {
            // Copy fast
            assignFloats(fv, ne);
            return;
         }
         else
         {
            // Retrieve individual float elements and assign
            YAC_Value v;
            sUI i;
            for(i=0; (i<4) && (i<ne); i++)
            {
               _o->yacArrayGet(_ctx, i, &v);
               floats[i] = v.value.float_val;
            }
            // Fill the rest with 0.0f
            for(; i<4; i++)
            {
               floats[i] = 0.0f;
            }
         }
      }
      else
      {
         // Retrieve individual elements, typecast to float and assign
         YAC_Value v;
         sUI i;
         for(i=0; (i<4) && (i<ne); i++)
         {
            _o->yacArrayGet(_ctx, i, &v);
            v.typecast(YAC_TYPE_FLOAT);
            floats[i] = v.value.float_val;
            v.unset();
         }
         // Fill the rest with 0.0f
         for(; i<4; i++)
         {
            floats[i] = 0.0f;
         }
      }
   }
   else
   {
      // Other array is empty or no array. Silently assign 0.0f
      floats[0] = floats[1] = floats[2] = floats[3] = 0.0f;
   }
}

//direct access methods
void _Vector4f::_setX(sF32 x) {
   floats[0] = x;
}

void _Vector4f::_setY(sF32 y) {
   floats[1] = y;
}

void _Vector4f::_setZ(sF32 z) {
   floats[2] = z;
}

void _Vector4f::_setW(sF32 w) {
   floats[3] = w;
}

sF32 _Vector4f::_getX(void) {
   return floats[0];
}

sF32 _Vector4f::_getY(void) {
   return floats[1];
}

sF32 _Vector4f::_getZ(void) {
   return floats[2];
}

sF32 _Vector4f::_getW(void) {
   return floats[3];
}

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

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

void _Vector4f::_add_YAC_RSELF(YAC_Object *_o) {
   if(YAC_CHK(_o, clid_Vector4f))
   {
      _Vector4f *o = (_Vector4f*) _o;
      floats[0] += o->floats[0];
      floats[1] += o->floats[1];
      floats[2] += o->floats[2];
      floats[3] += o->floats[3];
   } 
   else if(YAC_CHK(_o, clid_Vector3f))
   {
      _Vector3f *o = (_Vector3f*) _o;
      floats[0] += o->floats[0];
      floats[1] += o->floats[1];
      floats[2] += o->floats[2];
   } 
   else 
   {
/*      // Add generic Object
      YAC_Value r;
      yacOperator(YAC_OP_ADD, _o, &r);*/
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Vector4f::add_SELF Invalid Vector4f Object");
   }
}

void _Vector4f::_add_YAC_RVAL(YAC_Object *_o, YAC_Value *_r) {
   if(YAC_CHK(_o, clid_Vector4f))
   {
      _Vector4f *o = (_Vector4f*) _o;
      _Vector4f *r = YAC_NEW_POOLED(Vector4f);
      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 if(YAC_CHK(_o, clid_Vector3f))
   {
      _Vector3f *o = (_Vector3f*) _o;
      _Vector4f *r = YAC_NEW_POOLED(Vector4f);
      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];
      _r->initObject(r,1);
   } 
   else 
   {
/*      // Add generic Object
      YAC_Value r;
      yacOperator(YAC_OP_ADD, _o, &r);*/
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Vector4f::add_VAL Invalid Vector4f Object");
   }
}

void _Vector4f::_add_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;
      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 if(YAC_CHK(_o, clid_Vector3f)&&YAC_CHK(_r, clid_Vector4f))
   {
      _Vector3f *o = (_Vector3f*) _o;
      _Vector4f *r = (_Vector4f*) _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];
   } 
   else 
   {
/*      // Add generic Object
      YAC_Value r;
      yacOperator(YAC_OP_ADD, _o, &r);*/
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Vector4f::add_ARG Invalid Vector4f Object");
   }
}

void _Vector4f::_sub_YAC_RSELF(YAC_Object *_o) {
   if(YAC_CHK(_o, clid_Vector4f)) 
   {
      _Vector4f *o = (_Vector4f*) _o;
      floats[0] -= o->floats[0];
      floats[1] -= o->floats[1];
      floats[2] -= o->floats[2];
      floats[3] -= o->floats[3];
   } 
   else if(YAC_CHK(_o, clid_Vector3f)) 
   {
      _Vector3f *o = (_Vector3f*) _o;
      floats[0] -= o->floats[0];
      floats[1] -= o->floats[1];
      floats[2] -= o->floats[2];
   } 
   else 
   {
/*      // Subtract generic Object
      YAC_Value r;
      yacOperator(YAC_OP_SUB, _o, &r);*/
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Vector4f::sub_SELF Invalid Vector4f Object");
   }
}

void _Vector4f::_sub_YAC_RVAL(YAC_Object *_o, YAC_Value *_r) {
   if(YAC_CHK(_o, clid_Vector4f)) 
   {
      _Vector4f *o = (_Vector4f*) _o;
      _Vector4f *r = YAC_NEW_POOLED(Vector4f);
      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 if(YAC_CHK(_o, clid_Vector3f)) 
   {
      _Vector3f *o = (_Vector3f*) _o;
      _Vector4f *r = YAC_NEW_POOLED(Vector4f);
      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];
      _r->initObject(r,1);
   } 
   else 
   {
/*      // Subtract generic Object
      YAC_Value r;
      yacOperator(YAC_OP_SUB, _o, &r);*/
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Vector4f::sub_VAL Invalid Vector4f Object");
   }
}

void _Vector4f::_sub_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;
      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 if(YAC_CHK(_o, clid_Vector3f)&&YAC_CHK(_r, clid_Vector4f)) 
   {
      _Vector3f *o = (_Vector3f*) _o;
      _Vector4f *r = (_Vector4f*) _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];
   } 
   else 
   {
/*      // Subtract generic Object
      YAC_Value r;
      yacOperator(YAC_OP_SUB, _o, &r);*/
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Vector4f::sub_ARG Invalid Vector4f Object");
   }
}

sF32 _Vector4f::_dot(YAC_Object *_o) {
   if(YAC_CHK(_o,clid_Vector4f)) 
   {
      _Vector4f *o=(_Vector4f*)_o;
      return (floats[0]*o->floats[0] + floats[1]*o->floats[1] + floats[2]*o->floats[2] + floats[3]*o->floats[3]);
   }
   else 
   {
/*      // Dot product with generic Object
      _Vector4f t;
      t.assignGeneric(NULL, _o);
      return (floats[0]*t.floats[0] + floats[1]*t.floats[1] + floats[2]*t.floats[2] + floats[3]*t.floats[3]);*/
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Vector4f::dot: invalid Vector4f Object");
   }
   return 0.0f;
}

//return the tensor product of two vectors
void _Vector4f::_tensor_YAC_RVAL(YAC_Object *_o, YAC_Value *_r) {
   if(YAC_CHK(_o, clid_Vector4f))
   {
      _Vector4f t;
      _Matrix4f *m = YAC_NEW_POOLED(Matrix4f);
      _Vector4f *o=(_Vector4f*)_o;

      m->floats[0]=floats[0]*o->floats[0];
      m->floats[1]=floats[0]*o->floats[1];
      m->floats[2]=floats[0]*o->floats[2];
      m->floats[3]=floats[0]*o->floats[3];
      m->floats[4]=floats[1]*o->floats[0];
      m->floats[5]=floats[1]*o->floats[1];
      m->floats[6]=floats[1]*o->floats[2];
      m->floats[7]=floats[1]*o->floats[3];
      m->floats[8]=floats[2]*o->floats[0];
      m->floats[9]=floats[2]*o->floats[1];
      m->floats[10]=floats[2]*o->floats[2];
      m->floats[11]=floats[2]*o->floats[3];
      m->floats[12]=floats[3]*o->floats[0];
      m->floats[13]=floats[3]*o->floats[1];
      m->floats[14]=floats[3]*o->floats[2];
      m->floats[15]=floats[3]*o->floats[3];
      _r->initObject(m,1);
   }
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Vector4f::tensor: invalid Vector4f object");
   }
}

void _Vector4f::_tensor_YAC_RARG(YAC_Object *_o, YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f))
   {
      _Vector4f t;
      _Matrix4f *m = (_Matrix4f*) _m;
      _Vector4f *o;
      if(YAC_CHK(_o, clid_Vector4f)) 
      {
         o = (_Vector4f*) _o;
      m->floats[0]=floats[0]*o->floats[0];
      m->floats[1]=floats[0]*o->floats[1];
      m->floats[2]=floats[0]*o->floats[2];
      m->floats[3]=floats[0]*o->floats[3];
      m->floats[4]=floats[1]*o->floats[0];
      m->floats[5]=floats[1]*o->floats[1];
      m->floats[6]=floats[1]*o->floats[2];
      m->floats[7]=floats[1]*o->floats[3];
      m->floats[8]=floats[2]*o->floats[0];
      m->floats[9]=floats[2]*o->floats[1];
      m->floats[10]=floats[2]*o->floats[2];
      m->floats[11]=floats[2]*o->floats[3];
      m->floats[12]=floats[3]*o->floats[0];
      m->floats[13]=floats[3]*o->floats[1];
      m->floats[14]=floats[3]*o->floats[2];
      m->floats[15]=floats[3]*o->floats[3];
      }
      else
      {
/*         t.assignGeneric(NULL, _o);
         o = &t;*/
	 Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Vector4f::tensor_: invalid Vector4f Object");
      }
   }
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Vector4f::tensor_: invalid Matrix4f object");
   }
}

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

void _Vector4f::_mulf_YAC_RVAL(sF32 s, YAC_Value *_r) {
   _Vector4f *r = YAC_NEW_POOLED(Vector4f);
   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 _Vector4f::_mulf_YAC_RARG(sF32 s, YAC_Object *_r) {
   if (YAC_CHK(_r, clid_Vector4f)) {
      _Vector4f *r = (_Vector4f*)_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::Vector4f::mulf_ARG Return object not of type Vector4f");
   }
}

//multiply each individual element
void _Vector4f::_mul_YAC_RSELF(YAC_Object *_o) {
   if(YAC_CHK(_o, clid_Vector4f)) 
   {
      _Vector4f *o = (_Vector4f*) _o;

      floats[0] *= o->floats[0];
      floats[1] *= o->floats[1];
      floats[2] *= o->floats[2];
      floats[3] *= o->floats[3];
   } 
   else 
   {
/*      // Multiply by generic Object
      YAC_Value r;
      yacOperator(YAC_OP_MUL, _o, &r);*/
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Vector4f::mul_SELF invalid Vector4f object");
   }
}

void _Vector4f::_mul_YAC_RVAL(YAC_Object *_o, YAC_Value *_r) {
   if(YAC_CHK(_o, clid_Vector4f)) 
   {
      _Vector4f *o = (_Vector4f*) _o;
      _Vector4f *r = YAC_NEW_POOLED(Vector4f);

      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 
   {
/*      // Multiply by generic Object
      YAC_Value r;
      yacOperator(YAC_OP_MUL, _o, &r);*/
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Vector4f::mul_VAL invalid Vector4f object");
   }
}

void _Vector4f::_mul_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;

      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 
   {
/*      // Multiply by generic Object
      YAC_Value r;
      yacOperator(YAC_OP_MUL, _o, &r);*/
      Dyac_throw_def(NativeClassTypeMismatch,"tkmath::Vector4f::mul_ARG invalid Vector4f object");
   }
}

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

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

//scale vector to length 1
void _Vector4f::_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::Vector4f::unit_SELF Zero Vector cannot be normalized");
   }
}

void _Vector4f::_unit_YAC_RVAL(YAC_Value *_r) {
   sF32 absval = _getAbs();
   if(Dfltnonzero(absval)) 
   {
      _Vector4f *r=YAC_NEW_POOLED(Vector4f);
      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::Vector4f::unit_VAL Zero Vector cannot be normalized");
   }
}

void _Vector4f::_unit_YAC_RARG(YAC_Object *_r) {
   if (YAC_CHK(_r, clid_Vector4f)) {
      sF32 absval = _getAbs();
      if(Dfltnonzero(absval)) 
      {
         _Vector4f *r=(_Vector4f*)_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::Vector4f::unit_ARG Zero Vector cannot be normalized");
      }
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Vector4f::unit_ARG Return object not of type Vector4f");
   }
}

//scale vector to length s
void _Vector4f::_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::Vector4f::unitScale_SELF Zero Vector cannot be normalized");
   }
}

void _Vector4f::_unitScale_YAC_RVAL(sF32 s, YAC_Value *_r) {
   sF32 absval=_getAbs();
   if (Dfltnonzero(absval))
   {
      _Vector4f *r = YAC_NEW_POOLED(Vector4f);
      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::Vector4f::unitScale_VAL Zero Vector cannot be normalized");
   }
}

void _Vector4f::_unitScale_YAC_RARG(sF32 s, YAC_Object *_r) {
   if (YAC_CHK(_r, clid_Vector4f)) {
      sF32 absval=_getAbs();
      if (Dfltnonzero(absval))
      {
         _Vector4f *r=(_Vector4f*)_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::Vector4f::unitScale_SELF Zero Vector cannot be normalized");
      }
   } else {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Vector4f::unitScale_ARG Return object not of type Vector4f");
   }
}

//initialisation methods
void _Vector4f::_init(sF32 p, sF32 q, sF32 r, sF32 s) {
   floats[0] = p;
   floats[1] = q;
   floats[2] = r;
   floats[3] = s;
}

void _Vector4f::_initScalef(YAC_Object *_o, sF32 _s) {
   if(YAC_CHK(_o, clid_Vector4f))
   {
      _Vector4f *o = (_Vector4f*) _o;

      floats[0] = o->floats[0] * _s;
      floats[1] = o->floats[1] * _s;
      floats[2] = o->floats[2] * _s;
      floats[3] = o->floats[3] * _s;
   }
   else
   {
      Dyac_throw_def(InvalidPointer, "tkmath::Vector4f::initScalef: invalid object parameter");
   }
}

void _Vector4f::_rotate(YAC_Object *_m) {
   if(YAC_CHK(_m, clid_Matrix4f))
   {
      _Matrix4f *m = (_Matrix4f*) _m;
      _Vector4f t; t.class_ID = clid_Vector4f;
      t.yacOperatorAssign(this);
      m->_mulv_YAC_RARG(&t, this);
   }
   else 
   {
      Dyac_throw_def(NativeClassTypeMismatch, "tkmath::Vector4f::rotate: arg #1 is not a valid Matrix4f object");
   }
}

void _Vector4f::_New(sF32 p, sF32 q, sF32 r, sF32 s, YAC_Value *_r) {
   _Vector4f *res=YAC_NEW_POOLED(Vector4f);
   res->_init(p,q,r,s);
   _r->initObject(res,1);
}

void YAC_CALL _vector4f(sF32 p, sF32 q, sF32 r, sF32 s,YAC_Value *_r) {
   _Vector4f *res=YAC_NEW_POOLED(Vector4f);
   res->_init(p,q,r,s);
   _r->initObject(res,1);
}
