#include "3du.h"
#pragma hdrstop

// =======================================================================
// Работа с памятью ======================================================
// =======================================================================

#ifdef          ASM_PRAGMAS
DECLSPEC        memFill(void *blk, int value, int length)
{
  MEMFILL(blk,value,length);
}

DECLSPEC        memZero(void *blk, int length)
{
  MEMZERO(blk,length);
}

DECLSPEC        memCopy(void *dst, void *src, int length)
{
  MEMCOPY(dst,src,length);
}

DECLSPEC_INT    memIdent(void *blk1, void *blk2, int length)
{
  return MEMIDENT(blk1,blk2,length);
}
#endif          // ASM_PRAGMAS

// =======================================================================
// Векторные операции ====================================================
// =======================================================================
DECLSPEC  vtSet(vector_t *pv,u3dval x,u3dval y,u3dval z)
{
  pv->x=x;
  pv->x=y;
  pv->x=z;
}

DECLSPEC  vthSet(hvector_t *phv,u3dval x,u3dval y,u3dval z,u3dval w)
{
  phv->x=x;
  phv->x=y;
  phv->x=z;
  phv->w=w;
}

DECLSPEC vtZero(vector_t *pv)
{
  VTZERO(*pv);
}

DECLSPEC vthZero(hvector_t *pv)
{
  VTHZERO(*pv);
}

DECLSPEC vtCopy(vector_t *pdst,vector_t *psrc)
{
  VTCOPY(*pdst,*psrc);
}

DECLSPEC vthCopy(hvector_t *pdst,hvector_t *psrc)
{
  VTHCOPY(*pdst,*psrc);
}

DECLSPEC vtAdd(vector_t *pdst,vector_t *pv1,vector_t *pv2)
{
  VTADD(*pdst,*pv1,*pv2);
}

DECLSPEC vthAdd(hvector_t *pdst,hvector_t *pv1,hvector_t *pv2)
{
  VTHADD(*pdst,*pv1,*pv2);
}

DECLSPEC vtSub(vector_t *pdst,vector_t *pv1,vector_t *pv2)
{
  VTSUB(*pdst,*pv1,*pv2);
}

DECLSPEC vthSub(hvector_t *pdst,hvector_t *pv1,hvector_t *pv2)
{
  VTHSUB(*pdst,*pv1,*pv2);
}

DECLSPEC vtNegate(vector_t *dst, vector_t *src)
{
  VTNEGATE(*dst,*src);
}

DECLSPEC vthNegate(hvector_t *dst, hvector_t *src)
{
  VTHNEGATE(*dst,*src);
}

DECLSPEC vtMul(vector_t *pdst,vector_t *pv,u3dval ml)
{
  VTMUL(*pdst,*pv,ml);
}

DECLSPEC vthMul(hvector_t *pdst,hvector_t *pv,u3dval ml)
{
  VTHMUL(*pdst,*pv,ml);
}

DECLSPEC vtDot(vector_t *pv1,vector_t *pv2,u3dval *pres)
{
  *pres=VTDOT(*pv1,*pv2);
}

DECLSPEC vthDot(hvector_t *pv1,hvector_t *pv2,u3dval *pres)
{
  *pres=VTHDOT(*pv1,*pv2);
}

DECLSPEC vtAbs(vector_t *pv,u3dval *pres)
{
  *pres=VTABS(*pv);
}

DECLSPEC vtNormalize(vector_t *pv)
{
  u3dval a=VTABS((*pv));
  if(a==0.0) return;
  pv->x/=a;
  pv->y/=a;
  pv->z/=a;
}

DECLSPEC vthNormalize(hvector_t *pv)
{
  u3dval a=VTABS((*pv));  // не VTHABS !
  if(a==0.0) return;
  pv->x/=a;
  pv->y/=a;
  pv->z/=a;
  pv->w=U3DVAL(1);
}

DECLSPEC vtHomogenize(hvector_t *pv)
{
  if(pv->w!=0.0)
  {
    VTHHOMOGENIZE((*pv));
  }
  else
  {
    pv->x=U3DVAL(0);
    pv->y=U3DVAL(0);
    pv->z=U3DVAL(0);
    pv->w=U3DVAL(1);
  }
}

DECLSPEC vtCross(vector_t *pdst,vector_t *pv1,vector_t *pv2)
{
  VTCROSS(*pdst,*pv1,*pv2);
}

DECLSPEC vtMin(vector_t *pvec,u3dval *pres, int *pind)
{
  int i,ind;
  u3dval res;
  ind=0;
  res=VTIND(*pvec,0);
  for(i=1;i<3;i++)
    if(res>VTIND(*pvec,i))
    {
      res=VTIND(*pvec,i);
      ind=i;
    }
  *pres=res;
  *pind=ind;
}

DECLSPEC vtMax(vector_t *pvec, u3dval *pres, int *pind)
{
  int i,ind;
  u3dval res;
  res=VTIND(*pvec,0);
  ind=0;
  for(i=1;i<3;i++)
    if(res<VTIND(*pvec,i))
    {
      res=VTIND(*pvec,i);
      ind=i;
    }
  *pres=res;
  *pind=ind;
}

DECLSPEC_INT vtIsZero(vector_t *pvec)
{
  return VTISZERO(*pvec);
}

DECLSPEC_INT vthIsZero(hvector_t *pvec)
{
  return VTHISZERO(*pvec);
}

DECLSPEC_INT vtIsEqual(vector_t *pv1,vector_t *pv2)
{
  vector_t v;
  VTSUB(v,*pv1,*pv2);
  return VTISZERO(v);
}

DECLSPEC_INT vthIsEqual(hvector_t *pv1,hvector_t *pv2)
{
  hvector_t v;
  VTHSUB(v,*pv1,*pv2);
  return VTHISZERO(v);
}

DECLSPEC vtScaleBy(vector_t *pdst,vector_t *pv1,vector_t *pv2)
{
  VTSCALEBY(*pdst,*pv1,*pv2);
}

DECLSPEC vthScaleBy(hvector_t *pdst,hvector_t *pv1,hvector_t *pv2)
{
  VTHSCALEBY(*pdst,*pv1,*pv2);
}

DECLSPEC vtZoomIF(vector_t *zoom,vector_t *initial,vector_t *final)
{
  VTZOOMIF(*zoom,*initial,*final);
}

DECLSPEC vthZoomIF(hvector_t *zoom,hvector_t *initial,hvector_t *final)
{
  VTHZOOMIF(*zoom,*initial,*final);
}

DECLSPEC vtRadToDeg(vector_t *dst,vector_t *src)
{
  VTRADTODEG(*dst,*src);
}

DECLSPEC vtDegToRad(vector_t *dst,vector_t *src)
{
  VTDEGTORAD(*dst,*src);
}

// Был Хейтсман. Теперь я. Вроде работает лучше. Только бы не сломалось.
// P.S. Интересно, Хейтсман сам писал этот участок, или это из QuakeII ?
DECLSPEC vtProjectOnPlane(vector_t *dst,vector_t *p,vector_t *n)
{
  VTCOPY(*dst,*n);
  VTMUL(*dst,*dst,VTDOT(*n,*p));
  VTSUB(*dst,*p,*dst);
}

DECLSPEC vtPerpendicular(vector_t *dst,vector_t *src)
{
  u3dval ax, ay;
  vector_t tempvec={0,0,0};
  ax=fabs(src->x);
  ay=fabs(src->y);
  if(ax<ay)
  {
    if(ax<fabs(src->z))
      tempvec.x=1;
    else
      tempvec.z=1;
  }
  else
  {
    if(ay<fabs(src->z))
      tempvec.y=1;
    else
      tempvec.z=1;
  }
  vtProjectOnPlane(dst,&tempvec,src);
  VTNORMALIZE(*dst);
}

DECLSPEC vtRotateAroundVector(vector_t *dst,vector_t *dir,vector_t *point,
                              u3dval radians)
{
  int i;
  static vector_t vr,vu,vf;
  static matrix_t m,im,zrot,tmpmat,rot;
  // Создаем новый базис
  VTCOPY(vf,*dir);
  VTNORMALIZE(vf);
  vtPerpendicular(&vr,&vf);
  VTCROSS(vu,vr,vf);
  // Создаем матрицы перехода
  MTVECTOCOLS(m,vr,vu,vf);
  MTTRANSPOSE(im,m);
  // Создаем матрицу поворота вокруг третьего орта
  mtZRotation(zrot,radians);
  // Выполняем преобразования
  MTMUL(tmpmat,m,zrot);
  MTMUL(rot,tmpmat,im);
  MTVECMUL(*dst,rot,*point);
}

// =======================================================================
// Матричные операции ====================================================
// =======================================================================
DECLSPEC  mtZero(matrix_t mat)
{
  MTZERO(mat);
}

DECLSPEC  mthZero(hmatrix_t mat)
{
  MTHZERO(mat);
}

DECLSPEC  mttZero(transform_t mat)
{
  MTTZERO(mat);
}

DECLSPEC  mtCopy(matrix_t dst,matrix_t src)
{
  MTCOPY(dst,src);
}

DECLSPEC  mthCopy(hmatrix_t dst,hmatrix_t src)
{
  MTHCOPY(dst,src);
}

DECLSPEC  mttCopy(transform_t dst,transform_t src)
{
  MTHCOPY(dst,src);
}

//        Установка в единицу
DECLSPEC  mtIdentity(matrix_t mat)
{
  MTIDENTITY(mat);
}

DECLSPEC  mthIdentity(hmatrix_t mat)
{
  MTHIDENTITY(mat);
}

DECLSPEC  mttIdentity(transform_t mat)
{
  MTTIDENTITY(mat);
}

DECLSPEC  mtSetLU(u3dval *dst,matrix_t src)
{
  MTSETLU(dst,src);
}

DECLSPEC  mtGetLU(matrix_t dst,u3dval *src)
{
  MTGETLU(dst,src);
}

DECLSPEC  mtVectorows(matrix_t mat,vector_t *r1,vector_t *r2,vector_t *r3)
{
  MTVECTOROWS(mat,*r1,*r2,*r3);
}

DECLSPEC  mtVectorowsv(matrix_t mat,vector_t *r123)
{
  MTVECTOROWS(mat,r123[0],r123[1],r123[2]);
}

DECLSPEC  mthVectorows(hmatrix_t mat,hvector_t *r1,hvector_t *r2,
                       hvector_t *r3)
{
  MTHVECTOROWS(mat,*r1,*r2,*r3);
}

DECLSPEC  mthVectorowsv(hmatrix_t mat,hvector_t *r123)
{
  MTHVECTOROWS(mat,r123[0],r123[1],r123[2]);
}

DECLSPEC  mtVectocols(matrix_t mat,vector_t *c1,vector_t *c2,vector_t *c3)
{
  MTVECTOCOLS(mat,*c1,*c2,*c3);
}

DECLSPEC  mtVectocolsv(matrix_t mat,vector_t *c123)
{
  MTVECTOCOLS(mat,c123[0],c123[1],c123[2]);
}

DECLSPEC  mthVectocols(hmatrix_t mat,hvector_t *c1,hvector_t *c2,
                       hvector_t *c3)
{
  MTHVECTOCOLS(mat,*c1,*c2,*c3);
}

DECLSPEC  mthVectocolsv(hmatrix_t mat,hvector_t *c123)
{
  MTHVECTOCOLS(mat,c123[0],c123[1],c123[2]);
}

DECLSPEC  mtTranspose(matrix_t dst,matrix_t src)
{
  MTTRANSPOSE(dst,src);
}

DECLSPEC  mthTranspose(hmatrix_t dst,hmatrix_t src)
{
  MTHTRANSPOSE(dst,src);
}

DECLSPEC  mtSelftranspose(matrix_t mat)
{
  MTSELFTRANSPOSE(mat);
}

DECLSPEC  mthSelftranspose(hmatrix_t mat)
{
  MTHSELFTRANSPOSE(mat);
}

DECLSPEC  mtVecmul(vector_t *dst,matrix_t mat,vector_t *v)
{
  MTVECMUL(*dst,mat,*v);
}

DECLSPEC  mthVecmul(hvector_t *dst,hmatrix_t mat,hvector_t *v)
{
  MTHVECMUL(*dst,mat,*v);
}

DECLSPEC  mthVectransform(vector_t *dst,transform_t mat,vector_t *v)
{
  MTHVECTRANSFORM(*dst,mat,*v);
}

DECLSPEC  mtMul(matrix_t dst,matrix_t m1,matrix_t m2)
{
  MTMUL(dst,m1,m2);
}

DECLSPEC  mthMul(hmatrix_t dst,hmatrix_t m1,hmatrix_t m2)
{
  MTHMUL(dst,m1,m2);
}

DECLSPEC  mthMulTransforms(transform_t dst,transform_t m1,transform_t m2)
{
  MTHMULTRANSFORMS(dst,m1,m2);
}

DECLSPEC  mthConcatTransform(transform_t dst,transform_t tr)
{
  MTHCONCATTRANSFORM(dst,tr);
}

DECLSPEC mtXRotation(matrix_t mat,u3dval around_x)
{
  mat[0] = (u3dval)1;
  mat[1] = (u3dval)0;
  mat[2] = (u3dval)0;

  mat[3] = (u3dval)0;
  mat[4] = U3DVAL(cos(around_x));
  mat[5] = U3DVAL(sin(around_x));

  mat[6] = (u3dval)0;
  mat[7] = -mat[5];   // -sin
  mat[8] = mat[4];    // cos
}

DECLSPEC mtYRotation(matrix_t mat,u3dval around_y)
{
  mat[0] = U3DVAL(cos(around_y));
  mat[1] = (u3dval)0;
  mat[2] = U3DVAL(sin(around_y));
  mat[3] = (u3dval)0;
  mat[4] = (u3dval)1;
  mat[5] = (u3dval)0;

  mat[6] = -mat[2];
  mat[7] = 0;
  mat[8] = mat[0];
}

DECLSPEC mtZRotation(matrix_t mat,u3dval around_z)
{
  mat[0] = U3DVAL(cos(around_z));
  mat[1] = U3DVAL(sin(around_z));
  mat[2] = (u3dval)0;

  mat[3] = -mat[1];
  mat[4] = mat[0];
  mat[5] = (u3dval)0;

  mat[6] = (u3dval)0;
  mat[7] = (u3dval)0;
  mat[8] = (u3dval)1;
}

// =======================================================================
//        Действия с цветами
// =======================================================================
DECLSPEC  rgbByteToU3D(rgb_t *rgb, bytergb_t *brgb)
{
  RGBBYTETOU3D(*rgb,*brgb);  
}

DECLSPEC  rgbaByteToU3D(rgba_t *rgba, bytergba_t *brgba)
{
  RGBABYTETOU3D(*rgba,*brgba);
}

DECLSPEC  rgbU3DToByte(bytergb_t *brgb, rgb_t *rgb)
{
  RGBU3DTOBYTE(*brgb,*rgb);
}

DECLSPEC  rgbaU3DToByte(bytergba_t *brgba, rgba_t *rgba)
{
  RGBAU3DTOBYTE(*brgba,*rgba);
}

// =======================================================================
// Наложение карты окружения. (Intel, 1995)
// =======================================================================

DECLSPEC  texEnvironMap(transform_t mat,vector_t *normal, texcoord_t *uv)
{
	vector_t R;
	u3dval a, length;
	MTVECMUL(R,mat,*normal);
//	if (R.z < 0.0f) R.z = 0.00001f;
	length = VTABS(R);
	if(length>U3D_ZERO_EPSILON) 
	{
	  length = U3DVAL(1.0) / length;
		VTMUL(R,R,length);
	}
	a = U3DVAL(2.0) * R.z;
	VTMUL(R,R,a);             // reflected R = 2N(N.E) -E;  E = eye
	R.z -= U3DVAL(1.0);
	length = VTABS(R);
	if(length>U3D_ZERO_EPSILON) 
	{
	  length=U3DVAL(1.0)/length;
		VTMUL(R,R,length);
	}
	a=(float)sqrt(U3DVAL(1.0)-R.y*R.y);
	uv->u = (float)atan2(R.x,-R.z)/(M_2PI);
	if(uv->u<U3DVAL(0.0)) 
	  uv->u+=U3DVAL(1.0);
	uv->v=U3DVAL(1.0)-(float)atan2(a,R.y)/M_PI;
}
