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

#define AEPS 1.0e-4
#define CEPS 1.0e-7

#undef  TRUE
#define TRUE  1

#undef  FALSE 
#define FALSE 0

#undef  MAX
#define MAX(x,y)  ((x)>(y)?(x):(y))

#undef  MIN
#define MIN(x,y)  ((x)<(y)?(x):(y))

#undef  ABS
#define ABS(x)  ((x)>0?(x):(-(x)))

#define normalize( x, y, z )     \
    r = sqrt( x*x + y*y + z*z ); \
    if ( r != 0.0 ) {            \
        x /= r; y /= r; z /= r;  \
        }

typedef unsigned char CVALUE;
typedef float FLOAT;
typedef float ZVALUE;

typedef FLOAT TRS_MATRIX[4][4];

#define MAX_SPECTRAL_SAMPLES 3
#define MAX_TEXTURE_COORDS   3

typedef
struct {
    FLOAT r;
    FLOAT g;
    FLOAT b;
    FLOAT a;
} RGBA;

typedef
struct {
    FLOAT Ambient[MAX_SPECTRAL_SAMPLES];
    FLOAT Diffuse[MAX_SPECTRAL_SAMPLES];
    FLOAT Specular[MAX_SPECTRAL_SAMPLES];
    FLOAT SpecularExp;
    FLOAT Alpha;
} ZBF_MATERIAL;


#define VERTEX_COORD_X      0
#define VERTEX_COORD_Y      1
#define VERTEX_COORD_Z      2
#define VERTEX_COORD_W      3

#define VERTEX_TEXTURE      4
#define VERTEX_TEXTURE_U    4
#define VERTEX_TEXTURE_V    5
#define VERTEX_TEXTURE_W    6

#define VERTEX_COLOR_I      (VERTEX_TEXTURE+MAX_TEXTURE_COORDS)

#define VERTEX_COLOR_R      (VERTEX_COLOR_I+1)
#define VERTEX_COLOR_G      (VERTEX_COLOR_I+2)
#define VERTEX_COLOR_B      (VERTEX_COLOR_I+3)
#define VERTEX_COLOR_A      (VERTEX_COLOR_I+4)

#define VERTEX_NORMAL_X     (VERTEX_COLOR_I+5)
#define VERTEX_NORMAL_Y     (VERTEX_COLOR_I+6)
#define VERTEX_NORMAL_Z     (VERTEX_COLOR_I+7)

#define VERTEX_ORIG_COORD_X (VERTEX_COLOR_I+8)
#define VERTEX_ORIG_COORD_Y (VERTEX_COLOR_I+9)
#define VERTEX_ORIG_COORD_Z (VERTEX_COLOR_I+10)

#define VERTEX_MATERIAL_AMBIENT      (VERTEX_COLOR_I+11)
#define VERTEX_MATERIAL_DIFFUSE      (VERTEX_MATERIAL_AMBIENT+MAX_SPECTRAL_SAMPLES)
#define VERTEX_MATERIAL_SPECULAR     (VERTEX_MATERIAL_DIFFUSE+MAX_SPECTRAL_SAMPLES)
#define VERTEX_MATERIAL_SPECULAR_EXP (VERTEX_MATERIAL_SPECULAR+MAX_SPECTRAL_SAMPLES)
#define VERTEX_MATERIAL_ALPHA        (VERTEX_MATERIAL_SPECULAR_EXP+1)

#define VERTEX_NCOMP (VERTEX_MATERIAL_ALPHA+1)

typedef
struct {
    FLOAT CoordX;
    FLOAT CoordY;
    FLOAT CoordZ;
    FLOAT CoordW;

    FLOAT Texture[MAX_TEXTURE_COORDS];

    FLOAT ColorI;

    FLOAT ColorR;
    FLOAT ColorG;
    FLOAT ColorB;
    FLOAT ColorA;

    FLOAT NormalX;
    FLOAT NormalY;
    FLOAT NormalZ;

    FLOAT OrigCoordX;
    FLOAT OrigCoordY;
    FLOAT OrigCoordZ;

    ZBF_MATERIAL Material;
} ZBF_VERTEX;

#define LMD_LMODEL_CMAP        0
#define LMD_LMODEL_NOLIGHTS    1
#define LMD_LMODEL_CONSTANT    2
#define LMD_LMODEL_GOURAUD     3
#define LMD_LMODEL_PHONG       4
#define LMD_LMODEL_SHADOW_PASS 5
#define LMD_LMODEL_USER        6

#define NUMBER_OF_LMODELS      7

#ifdef MODULE_LMD

int LMD_Interpolate[NUMBER_OF_LMODELS][VERTEX_NCOMP] = {
    { VERTEX_COORD_X, VERTEX_COORD_Y, VERTEX_COORD_Z, VERTEX_COORD_W, VERTEX_COLOR_I },

    { VERTEX_COORD_X, VERTEX_COORD_Y, VERTEX_COORD_Z, VERTEX_COORD_W,
      VERTEX_COLOR_R, VERTEX_COLOR_G, VERTEX_COLOR_B },

    { VERTEX_COORD_X, VERTEX_COORD_Y, VERTEX_COORD_Z, VERTEX_COORD_W },

    { VERTEX_COORD_X, VERTEX_COORD_Y, VERTEX_COORD_Z, VERTEX_COORD_W,
      VERTEX_COLOR_R, VERTEX_COLOR_G, VERTEX_COLOR_B },
  
    { VERTEX_COORD_X, VERTEX_COORD_Y, VERTEX_COORD_Z, VERTEX_COORD_W,
      VERTEX_NORMAL_X,VERTEX_NORMAL_Y,VERTEX_NORMAL_Z,
      VERTEX_ORIG_COORD_X, VERTEX_ORIG_COORD_Y, VERTEX_ORIG_COORD_Z },

    { VERTEX_COORD_X, VERTEX_COORD_Y, VERTEX_COORD_Z, VERTEX_COORD_W }
  };

int LMD_NtoInterpolate[NUMBER_OF_LMODELS] = { 5, 7, 4, 7, 10, 4 };

int LMD_Lmodel = LMD_LMODEL_CMAP;

#else

extern int LMD_Interpolate[NUMBER_OF_LMODELS][VERTEX_NCOMP];
extern int LMD_NtoInterpolate[NUMBER_OF_LMODELS];

extern int LMD_Lmodel;

#endif

#define MAX_LIGHTS 32 

typedef struct
{
    FLOAT PositionX;
    FLOAT PositionY;
    FLOAT PositionZ;
    FLOAT PositionW;

    FLOAT DirectionX;
    FLOAT DirectionY;
    FLOAT DirectionZ;

    FLOAT FieldN;
    FLOAT FieldAngle;

    FLOAT Color[MAX_SPECTRAL_SAMPLES];

    int LightInUse;

    TRS_MATRIX VMatrix,PMatrix;

    int SNX,SNY;
    ZVALUE *shadow_map;
} LIGHT;

#define LGT_LIGHT_OFF 0
#define LGT_LIGHT_ON  1

#ifdef MODULE_LGT

LIGHT LGT_Lights[MAX_LIGHTS];

#else

extern LIGHT LGT_Lights[MAX_LIGHTS];

#endif

#define USR_MAX_VERTICES 256

#define ZBF_RGBA 1
#define ZBF_CMAP 2

#define TRS_MATRIX_PROJECTION 0
#define TRS_MATRIX_VIEWING    1
#define TRS_MATRIX_GLOBAL     2

#define LMD_COLOR_COLOR    0
#define LMD_COLOR_AMBIENT_AND_DIFFUSE 1
#define LMD_COLOR_AMBIENT  2
#define LMD_COLOR_DIFFUSE  3

int zbf_open( int, int );
void zbf_close( void );
void zbf_set_user_function(void (*)(FLOAT *, int), void (*)(FLOAT *, int));
void zbf_clear( void );
void zbf_zclear( void );
void zbf_draw_polygon( int, ZBF_VERTEX * );
void zbf_draw_triangle( FLOAT V[3][VERTEX_NCOMP] );
void zbf_draw_triangle_y( FLOAT V[3][VERTEX_NCOMP] );
void zbf_draw_triangle_x( FLOAT, FLOAT *, FLOAT * );
void zbf_draw_polyline( int, ZBF_VERTEX * );
void zbf_draw_line( FLOAT *, FLOAT * );

void lgt_define_light( int, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT,
                            FLOAT, FLOAT, FLOAT, FLOAT, FLOAT * );
void lgt_light_onoff( int, int );

void lmd_set_lmodel( int );
void lmd_evaluate_lmodel( FLOAT * );
void lmd_add_lmodel_interpolant( int );
void lmd_set_lmodel_interpolants( int, int * );

void trs_view_from( FLOAT, FLOAT, FLOAT, FLOAT );
void trs_init_transformations( );
void trs_translate( FLOAT, FLOAT, FLOAT );
void trs_scale( FLOAT, FLOAT, FLOAT );
void trs_rotate( FLOAT, int );
void trs_get_matrix( TRS_MATRIX );
void trs_load_matrix( TRS_MATRIX );
void trs_matrix_mode( int );
void trs_pop_matrix( void );
void trs_push_matrix( void );
void trs_perspective( FLOAT, FLOAT, FLOAT, FLOAT );
void trs_ortho( FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT );
void trs_polarview( FLOAT, FLOAT, FLOAT, FLOAT );
void trs_lookat( FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT, FLOAT );
void trs_viewing_transform( int, ZBF_VERTEX * );
void trs_normal_transform( int, ZBF_VERTEX * );
void trs_projection_transform( int, ZBF_VERTEX * );
void trs_scale_transform( int, ZBF_VERTEX * );
void trs_viewport( int, int, int, int );

int clp_clip_polygon( int, ZBF_VERTEX *  );

void txr_texture_lookup( FLOAT *, int );
void txr_set_function( void (*)( FLOAT *, int ) );
void txr_load_texture( int, int, CVALUE *, CVALUE *, CVALUE * );

FLOAT *usr_pack3f( FLOAT, FLOAT, FLOAT );
void usr_bgnpolygon( void );
void usr_vertex( FLOAT * );
void usr_normal( FLOAT * );
void usr_texture( FLOAT * );
void usr_color( FLOAT * );
void usr_color4( FLOAT * );
void usr_color_index( FLOAT );
void usr_endpolygon( void );
void usr_material_alpha( FLOAT );
void usr_material_ambient( FLOAT * );
void usr_material_diffuse( FLOAT * );
void usr_material_specular( FLOAT *, FLOAT );
void usr_map_color( int, FLOAT, FLOAT, FLOAT );
void usr_map_color4( int, FLOAT, FLOAT, FLOAT,FLOAT );

void atm_linear_fog( FLOAT, FLOAT, FLOAT * );
void atm_exp_fog( FLOAT, FLOAT * );
void atm_apply_atmosphere( FLOAT * );
void atm_set_function( void (*)( FLOAT * ) );

void utl_sphere_quality(int);
void utl_sphere(FLOAT,FLOAT,FLOAT,FLOAT);
void utl_cylinder(FLOAT,FLOAT,FLOAT,FLOAT,FLOAT,FLOAT,FLOAT,FLOAT,FLOAT);
void utl_cone(FLOAT,FLOAT,FLOAT,FLOAT,FLOAT,FLOAT,FLOAT,FLOAT,FLOAT,FLOAT);
