/*********************************************************************
 *
 *         EZWGL, the EZ Widget and Graphics Library
 *
 *             Copyright (C) 1996, 1997  Maorong Zou
 *  
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **********************************************************************/
/*
 *  June 1996.  Beta Release.
 *  Sept 1996.  Release Version 1.0
 *  Dec 1996.  Release Version 1.1 Beta
 *  April 1997.  Release Version 1.2
 *  November 1997.  Release Version 1.3
 */
/*************************************************************
 *
 * Modeling Transformations 
 *
 */
#define _EZ_MATRIX_TRANS_C_
#include "EZ_Widget.h"
/***************************************************************
 *
 *  Functions implemented in this file
 */

void             EZ_Scale MY_ANSIARGS((float x, float y, float z));
void             EZ_Translate  MY_ANSIARGS((float x, float y, float z));
void             EZ_Rotate  MY_ANSIARGS((float angle, float x, float y, float z));

void             EZ_GenerateRotationMatrix MY_ANSIARGS((EZ_Matrix mtx, float angle, float x, float y, float z));

/**************************************************************
 *
 * scale.
 *  Unfortunately, scale is not orthogonal. It changes the length
 *  of the normal vector. If we alter the inverse transpose of the
 *  modelview matrix, then one has to normalize all the mormal vectors.
 *  We'll ignore this fact for now.
 */

void EZ_Scale(x, y, z)
     float x, y, z;
{
  if(EZ_InCompilingMode != 0)
    {
      EZ_Token *t = AllocateNTokens(4);
      t->i = TOKEN_SCALE;
      t[1].f = x; t[2].f = y;  t[3].f = z;
    }
  if(EZ_InExecutionMode != 0)
    {  
      EZ_MatrixStack *tmp = EZ_CurrentMStack;

      tmp->m[0][0] *= x;
      tmp->m[0][1] *= x;
      tmp->m[0][2] *= x;
      tmp->m[0][3] *= x;
      
      tmp->m[1][0] *= y;
      tmp->m[1][1] *= y;
      tmp->m[1][2] *= y;
      tmp->m[1][3] *= y;
      
      tmp->m[2][0] *= z;
      tmp->m[2][1] *= z;
      tmp->m[2][2] *= z;
      tmp->m[2][3] *= z;
      if(EZ_MatrixModeMM != EZ_TEXTURE)
	EZ_MatrixValid = 0;  
    }
}
/**************************************************************
 *
 *  Translate.
 *     Translation does not affect normal vectors.
 */
void EZ_Translate(x, y, z)
     float x, y, z;
{
  if(EZ_InCompilingMode != 0)
    {
      EZ_Token *t = AllocateNTokens(4);
      t->i = TOKEN_TRANSLATE;
      t[1].f = x; t[2].f = y;  t[3].f = z;
    }
  if(EZ_InExecutionMode != 0)
    {  
      EZ_MatrixStack *tmp = EZ_CurrentMStack;
  
      tmp->m[3][0] += (x *tmp->m[0][0]
		       + y *tmp->m[1][0]
		       + z *tmp->m[2][0]);

      tmp->m[3][1] += (x *tmp->m[0][1]
		       + y *tmp->m[1][1]
		       + z *tmp->m[2][1]);

      tmp->m[3][2] += (x *tmp->m[0][2]
		       + y *tmp->m[1][2]
		       + z *tmp->m[2][2]);
  
      tmp->m[3][3] += (x *tmp->m[0][3]
		       + y *tmp->m[1][3]
		       + z *tmp->m[2][3]);

      if(EZ_MatrixModeMM != EZ_TEXTURE)
	EZ_MatrixValid = 0;  
    }
}

/************************************************************
 *
 * rotate.  Rotate about (x,y,z) by angle degrees
 *
 *   Inverse transpose of a pure rotation is itself.
 */
#define Degree2Radian(a)     ((a)*0.0174532925199433)

void EZ_Rotate(angle, x,y,z)
     float angle,x,y,z;
{
  EZ_Matrix m;

  EZ_GenerateRotationMatrix(m,angle, x,y,z);
  EZ_MultMatrix(m);
}
/****************************************************************************
 *
 *  generate a rotation matrix about (x,y,z). Rotate angle degrees.
 *  Ref: Foley VanDam, P227.
 */
void EZ_GenerateRotationMatrix(m,angle, x,y,z)
     EZ_Matrix   m;
     float angle,x,y,z;
{
  float norma, norm; 

  norma = x*x + y*y + z*z;
  if(norma == 0.0)
    {
      EZ_IdentityMatrix(m);
      return;
    }
  else
    {
      float  rangle, sina, cosa;
      float  xx,xy,xz,yy, yz,zz, one_cosa;
      float  xyone_cosa, xzone_cosa, yzone_cosa;
      float  xsina, ysina, zsina;

      norm = 1.0/(float)sqrt((double)norma);
      x *= norm;
      y *= norm;
      z *= norm;
      rangle = Degree2Radian(angle);
      cosa = cos(rangle);
      one_cosa = 1.0 - cosa;
      sina = sin(rangle);
      xx = x * x; yy = y * y; zz = z * z;
      xy = x * y; xz = x * z; yz = y * z;
      xyone_cosa = xy * one_cosa;
      xzone_cosa = xz * one_cosa;
      yzone_cosa = yz * one_cosa;
      xsina = x * sina; ysina = y * sina; zsina = z * sina;
      
      m[0][0] = cosa + xx * one_cosa;
      m[0][1] = xyone_cosa + zsina;
      m[0][2] = xzone_cosa - ysina;
      m[0][3] = 0.0;

      m[1][0] = xyone_cosa - zsina;
      m[1][1] = cosa + yy * one_cosa;
      m[1][2] = yzone_cosa + xsina;
      m[1][3] = 0.0;

      m[2][0] = xzone_cosa + ysina;
      m[2][1] = yzone_cosa - xsina;
      m[2][2] = cosa + zz * one_cosa;
      m[2][3] = 0.0;

      m[3][0] = 0.0;
      m[3][1] = 0.0;
      m[3][2] = 0.0;
      m[3][3] = 1.0;
    }
}


/**********************************************************************/

#undef _EZ_MATRIX_TRANS_C_
