/**************************************************************************
  Copyright (C) 1992 Guy Moreillon
  All rights reserved.

  This software may be freely copied, modified, and redistributed
  provided that this copyright notice is preserved on all copies.

  You may not distribute this software, in whole or in part, as part of
  any commercial product without the express consent of the authors.

  There is no warranty or other guarantee of fitness of this software
  for any purpose.  It is provided solely "as is".
**************************************************************************/
/**************************************************************************

				RAD
		       (Interactive Radiosity)
		    	    Version 1.0
			       1992		    	    
		    	    
		  
		    	  Guy Moreillon
		    	  
**************************************************************************/

/**************************************************************************
  Fichier	: macros.h
  Description	: Fichier de definition des macros de base (include)
**************************************************************************/

#ifndef macros_h
#define macros_h

#include <stdio.h>
#include <math.h>

# define MAX(A, B) ((A) > (B) ? (A) : (B))
# define MIN(A, B) ((A) < (B) ? (A) : (B))

# define V_init(RES, X_VALUE, Y_VALUE, Z_VALUE)\
    {\
      RES[0] = X_VALUE;\
      RES[1] = Y_VALUE;\
      RES[2] = Z_VALUE;\
    }

# define V_null(RES)\
    {\
      V_init(RES, 0.0, 0.0, 0.0);\
    }


# define V_copy(RES, U)\
    {\
      RES[0] = U[0];\
      RES[1] = U[1];\
      RES[2] = U[2];\
    }

# define V_norm(U)\
    (fsqrt( U[0] * U[0] + \
            U[1] * U[1] + \
            U[2] * U[2]))


# define V_normalize(RES, U)\
    {\
      register float  norm;\
      norm = V_norm(U);\
      V_init(RES, U[0]/norm, \
                  U[1]/norm, \
                  U[2]/norm);\
    }


# define V_add(RES, LEFT, RIGHT)\
    {\
      RES[0] = LEFT[0] + RIGHT[0]; \
      RES[1] = LEFT[1] + RIGHT[1]; \
      RES[2] = LEFT[2] + RIGHT[2]; \
    }

# define V_add_self(RES, PLUS)\
    {\
      RES[0] += PLUS[0];\
      RES[1] += PLUS[1];\
      RES[2] += PLUS[2];\
    }

# define V_sub(RES, LEFT, RIGHT)\
    {\
      RES[0] = LEFT[0] - RIGHT[0]; \
      RES[1] = LEFT[1] - RIGHT[1]; \
      RES[2] = LEFT[2] - RIGHT[2]; \
    }


# define V_scale(RES, SCALAR, RIGHT)\
    {\
      RES[0] = (SCALAR) * RIGHT[0]; \
      RES[1] = (SCALAR) * RIGHT[1]; \
      RES[2] = (SCALAR) * RIGHT[2]; \
    }

# define V_mul(RES, RIGHT, LEFT)\
    {\
      RES[0] = RIGHT[0] * LEFT[0]; \
      RES[1] = RIGHT[1] * LEFT[1]; \
      RES[2] = RIGHT[2] * LEFT[2]; \
    }

# define V_div(RES, RIGHT, LEFT)\
    {\
      RES[0] = RIGHT[0]/LEFT[0];\
      RES[1] = RIGHT[1]/LEFT[1];\
      RES[2] = RIGHT[2]/LEFT[2];\
    }

# define V_dot(LEFT, RIGHT)\
    (LEFT[0] * RIGHT[0] + \
     LEFT[1] * RIGHT[1] + \
     LEFT[2] * RIGHT[2])


# define V_cross(RES, LEFT, RIGHT)\
    {\
      RES[0] = LEFT[1] * RIGHT[2] - \
                     LEFT[2] * RIGHT[1];  \
      RES[1] = LEFT[2] * RIGHT[0] - \
                     LEFT[0] * RIGHT[2];  \
      RES[2] = LEFT[0] * RIGHT[1] - \
                     LEFT[1] * RIGHT[0];  \
    }

# define V_add_mul(RES, LEFT, A, RIGHT)\
    {\
      RES[0] = LEFT[0] + (A) * RIGHT[0]; \
      RES[1] = LEFT[1] + (A) * RIGHT[1]; \
      RES[2] = LEFT[2] + (A) * RIGHT[2]; \
    }

# define V_interp(RES, A, LEFT, B, RIGHT)\
    {\
      RES[0] = (A) * LEFT[0] + (B) * RIGHT[0]; \
      RES[1] = (A) * LEFT[1] + (B) * RIGHT[1]; \
      RES[2] = (A) * LEFT[2] + (B) * RIGHT[2]; \
    }

# define V_abs(RES, V)\
    {\
      RES[0] = _ABS(V[0]);\
      RES[1] = _ABS(V[1]);\
      RES[2] = _ABS(V[2]);\
    }

# define V_dump(U)\
    {\
      printf("U = (%f, %f, %f)\n", U[0], \
                                   U[1], \
                                   U[2]);\
    }

# define V4D_dump(U)\
    {\
      printf("U = (%f, %f, %f, %f)\n", U[0], \
				       U[1], \
				       U[2], \
				       U[3]);\
    }

# define V_min(RES, P1, P2)\
    {\
      RES[0] = P1[0]<P2[0] ? P1[0] : P2[0];\
      RES[1] = P1[1]<P2[1] ? P1[1] : P2[1];\
      RES[2] = P1[2]<P2[2] ? P1[2] : P2[2];\
    }

# define V_max(RES, P1, P2)\
    {\
      RES[0] = P1[0]>P2[0] ? P1[0] : P2[0];\
      RES[1] = P1[1]>P2[1] ? P1[1] : P2[1];\
      RES[2] = P1[2]>P2[2] ? P1[2] : P2[2];\
    }

# define M_init(RES, XX, XY, XZ, YX, YY, YZ, ZX, ZY, ZZ)\
    {\
      RES[0][0] = XX; \
      RES[0][1] = XY; \
      RES[0][2] = XZ; \
     \
      RES[1][0] = YX; \
      RES[1][1] = YY; \
      RES[1][2] = YZ; \
     \
      RES[2][0] = ZX; \
      RES[2][1] = ZY; \
      RES[2][2] = ZZ; \
    }

# define M_copy(RES, SOURCE) \
    {\
      M_init(RES, SOURCE[0][0], \
                  SOURCE[0][1], \
                  SOURCE[0][2], \
                    \
                  SOURCE[1][0], \
                  SOURCE[1][1], \
                  SOURCE[1][2], \
                    \
                  SOURCE[2][0], \
                  SOURCE[2][1], \
                  SOURCE[2][2]);\
    }

# define M_indentity(RES) \
    {\
      M_init(RES, 1.0, 0.0, 0.0, \
                  0.0, 1.0, 0.0, \
                  0.0, 0.0, 1.0);\
    }

#define M4D_init(RES, XX, XY, XZ, XW, YX, YY, YZ, YW, ZX, ZY, ZZ, ZW, WX, WY, WZ, WW)\
    {\
      RES[0][0] = XX; \
      RES[0][1] = XY; \
      RES[0][2] = XZ; \
      RES[0][3] = XW; \
     \
      RES[1][0] = YX; \
      RES[1][1] = YY; \
      RES[1][2] = YZ; \
      RES[1][3] = YW; \
     \
      RES[2][0] = ZX; \
      RES[2][1] = ZY; \
      RES[2][2] = ZZ; \
      RES[2][3] = ZW; \
     \
      RES[3][0] = WX; \
      RES[3][1] = WY; \
      RES[3][2] = WZ; \
      RES[3][3] = WW; \
    }

# define M4D_identity(RES) \
    {\
      M4D_init(RES, 1.0, 0.0, 0.0, 0.0, \
                    0.0, 1.0, 0.0, 0.0, \
                    0.0, 0.0, 1.0, 0.0, \
                    0.0, 0.0, 0.0, 1.0);\
    }

# define M4D_copy(RES, SOURCE) \
    {\
      M4D_init(RES, SOURCE[0][0], \
                    SOURCE[0][1], \
                    SOURCE[0][2], \
                    SOURCE[0][3], \
                    \
                    SOURCE[1][0], \
                    SOURCE[1][1], \
                    SOURCE[1][2], \
                    SOURCE[1][3], \
                    \
                    SOURCE[2][0], \
                    SOURCE[2][1], \
                    SOURCE[2][2], \
                    SOURCE[2][3], \
                    \
                    SOURCE[3][0], \
                    SOURCE[3][1], \
                    SOURCE[3][2], \
                    SOURCE[3][3]);\
    }

# define M_dump(M) \
  {\
    V_dump(M[0]); \
    V_dump(M[1]); \
    V_dump(M[2]); \
  }

# define M4D_dump(M) \
  {\
    V4D_dump(M[0]); \
    V4D_dump(M[1]); \
    V4D_dump(M[2]); \
    V4D_dump(M[3]); \
  }

#define POLY_dump(POL) \
  {\
    printf("type = %d\n", POL.type); \
    V_dump(POL.vertex[0].point); \
    V_dump(POL.vertex[1].point); \
    V_dump(POL.vertex[2].point); \
    V_dump(POL.vertex[0].B); \
    V_dump(POL.vertex[1].B); \
    V_dump(POL.vertex[2].B); \
    V_dump(POL.vertex[0].dB); \
    V_dump(POL.vertex[1].dB); \
    V_dump(POL.vertex[2].dB); \
    V_dump(POL.tri.poly.normal); \
    V_dump(POL.tri.poly.sa); \
    V_dump(POL.tri.poly.sb); \
    printf("surface : %f\n", POL.tri.poly.surface); \
    printf("sons : %x\n", POL.tri.poly.sons); \
    printf("samples : %x\n", POL.tri.poly.samples); \
    printf("dad  : %x\n", POL.dad); \
  }


#define Bye_bye(S) { printf(S); exit(1);}

#define ExCp(EMISS, COLOR) (EMISS * (COLOR[0] + COLOR[1] + COLOR[2]))

#define SumV(V) (V[0] + V[1] + V[2])

#define min(A, B) (A<B)?A:B
#define max(A, B) (A>B)?A:B

#define I_add(RES, I, J) \
  {\
    RES.inf = I.inf + J.inf;\
    RES.sup = I.sup + J.sup;\
  }

#define I_cross(RES, I, J) \
  {\
    float  ii, is, si, ss;\
    ii = I.inf * J.inf;\
    is = I.inf * J.sup;\
    si = I.sup * J.inf;\
    ss = I.sup * J.sup;\
    RES.inf = min(ii, is);\
    RES.inf = min(RES.inf, si);\
    RES.inf = min(RES.inf, ss);\
    RES.sup = max(ii, is);\
    RES.sup = max(RES.sup, si);\
    RES.sup = max(RES.sup, ss);\
  }

#define I_eq(I, J) ((I.inf == J.inf) && (I.sup == J.sup))

#define I_min(RES, I, J) \
  {\
    RES.inf = min(I.inf, J.inf);\
    RES.sup = min(I.sup, J.sup);\
  }

#define I_max(RES, I, J) \
  {\
    RES.inf = max(I.inf, J.inf);\
    RES.sup = max(I.sup, J.sup);\
  }

#define I_add_scal(RES, I, L) \
  {\
    RES.inf = I.inf + (L);\
    RES.sup = I.sup + (L);\
  }

#define I_sub_scal(RES, I, L) \
  {\
    RES.inf = I.inf - (L);\
    RES.sup = I.sup - (L);\
  }

#define I_mul_scal(RES, L, I) \
  {\
    if ((L) >= 0.0)\
      {\
	RES.inf = (L)*I.inf;\
	RES.sup = (L)*I.sup;\
      }\
    else\
      {\
	RES.inf = (L)*I.sup;\
	RES.sup = (L)*I.inf;\
      };\
  }

#define Vox_sub_v(RES, VOX, V)\
  {\
    I_sub_scal(RES.x, VOX.x, V[0]);\
    I_sub_scal(RES.y, VOX.y, V[1]);\
    I_sub_scal(RES.z, VOX.z, V[2]);\
  }

#define Vox_dot_v(RES, VOX, V)\
  {\
    VOXEL dumvox;\
    I_mul_scal(dumvox.x, V[0], VOX.x);\
    I_mul_scal(dumvox.y, V[1], VOX.y);\
    I_mul_scal(dumvox.z, V[2], VOX.z);\
    I_add(RES, dumvox.x, dumvox.y);\
    I_add(RES, RES, dumvox.z);\
  }

#define V_cross_vox(RES, V, VOX)\
  {\
    VOXEL    dumvox;\
    INTERVAL dumi1, dumi2;\
    I_mul_scal(dumi1, V[1], VOX.z);\
    I_mul_scal(dumi2, -V[2], VOX.y);\
    I_add(dumvox.x, dumi1, dumi2);\
    I_mul_scal(dumi1, V[2], VOX.x);\
    I_mul_scal(dumi2, -V[0], VOX.z);\
    I_add(dumvox.x, dumi1, dumi2);\
    I_mul_scal(dumi1, V[0], VOX.y);\
    I_mul_scal(dumi2, -V[1], VOX.x);\
    I_add(dumvox.x, dumi1, dumi2);\
    RES = dumvox;\
  }

#endif
