#define MODULE_LGT

#include "graf.h"

extern int TRS_HeapPosition;
extern int ZBF_NX,ZBF_NY;
extern ZVALUE *ZBF_Z;

#define TRS_MAX_MATRIX_HEAP 32
#define TRS_VMatrix TRS_VMatrixHeap[TRS_HeapPosition]
extern TRS_MATRIX TRS_VMatrixHeap[TRS_MAX_MATRIX_HEAP];

FLOAT LGT_AmbientColor[MAX_SPECTRAL_SAMPLES] = { 0.2,0.2,0.2 };
int LGT_Shadows;

void lgt_shadows(int status)
{
    LGT_Shadows = status;
}

void lgt_ambient_level( FLOAT *col )
{
    int i;

    for( i=0; i<MAX_SPECTRAL_SAMPLES; i++ )
    {
        LGT_AmbientColor[i] = col[i];
    }
}

void lgt_get_matrix_light(int light)
{
    trs_matrix_mode(TRS_MATRIX_PROJECTION);
    trs_get_matrix(LGT_Lights[light].PMatrix);
    trs_matrix_mode(TRS_MATRIX_VIEWING);
    trs_get_matrix(LGT_Lights[light].VMatrix);
}

void lgt_get_matrix_object(int light)
{
    TRS_MATRIX matrix;
    double s,a[4][4];
    int i,j,k;

    trs_get_matrix(matrix);
    for( i=0; i<4; i++ )
    for( j=0; j<4; j++ ) a[i][j] = matrix[i][j];

    mtrinv((double *)a,4);

    for( i=0; i<4; i++ )
    for( j=0; j<4; j++ )
    {
        s = 0.0;
        for( k=0; k<4; k++ ) s += a[i][k]*LGT_Lights[light].VMatrix[k][j];
        matrix[i][j] = s;
    }

    for( i=0; i<4; i++ )
    for( j=0; j<4; j++ ) LGT_Lights[light].VMatrix[i][j] = matrix[i][j];
}

void lgt_free_shadow_map(int light)
{
    if ( LGT_Lights[light].shadow_map )
    {
        free(LGT_Lights[light].shadow_map);
    }

    LGT_Lights[light].SNX = 0;
    LGT_Lights[light].SNY = 0;
}

void lgt_get_shadow_map(int light)
{
    if ( LGT_Lights[light].shadow_map )
    {
        free(LGT_Lights[light].shadow_map);
    }

    LGT_Lights[light].shadow_map = (ZVALUE *)malloc(ZBF_NX*ZBF_NY*sizeof(ZVALUE));
    LGT_Lights[light].SNX = ZBF_NX;
    LGT_Lights[light].SNY = ZBF_NY;
    memcpy(LGT_Lights[light].shadow_map,ZBF_Z,ZBF_NX*ZBF_NY*sizeof(ZVALUE));
}

void lgt_define_light( int light,
    FLOAT pos_x, FLOAT pos_y, FLOAT pos_z, FLOAT pos_w,
    FLOAT dir_x, FLOAT dir_y, FLOAT dir_z,
    FLOAT ang_f, FLOAT ang_n, FLOAT *col  )
{
    FLOAT a,r,x,y,z,dx,dy,dz;

    if ( light<0 || light>=MAX_LIGHTS )
    {
        fprintf( stderr, "lgt_define_light: light index [%d] out of range.\n", light );
        return;
    }

    if ( pos_w != 0.0 )
    {
        pos_x /= pos_w;
        pos_y /= pos_w;
        pos_z /= pos_w;
    }

    x = pos_x*TRS_VMatrix[0][0] + pos_y*TRS_VMatrix[1][0] + 
        pos_z*TRS_VMatrix[2][0] +       TRS_VMatrix[3][0];

    y = pos_x*TRS_VMatrix[0][1] + pos_y*TRS_VMatrix[1][1] + 
        pos_z*TRS_VMatrix[2][1] +       TRS_VMatrix[3][1];

    z = pos_x*TRS_VMatrix[0][2] + pos_y*TRS_VMatrix[1][2] + 
        pos_z*TRS_VMatrix[2][2] +       TRS_VMatrix[3][2];

    if ( pos_w != 0.0 )
    {
        LGT_Lights[light].PositionX = x;
        LGT_Lights[light].PositionY = y;
        LGT_Lights[light].PositionZ = z;
        LGT_Lights[light].PositionW = 1.0;
    } else
    {
        r = sqrt( x*x+y*y+z*z );
        LGT_Lights[light].PositionX = x/r;
        LGT_Lights[light].PositionY = y/r;
        LGT_Lights[light].PositionZ = z/r;
        LGT_Lights[light].PositionW = 0.0;

        LGT_Lights[light].DirectionX = dir_x;
        LGT_Lights[light].DirectionY = dir_y;
        LGT_Lights[light].DirectionZ = dir_z;
    }

    if ( (LGT_Lights[light].FieldAngle = ang_f ) > 0.0 )
    {
        dx = dir_x*TRS_VMatrix[0][0] + dir_y*TRS_VMatrix[1][0] + 
             dir_z*TRS_VMatrix[2][0] +       TRS_VMatrix[3][0];

        dy = dir_x*TRS_VMatrix[0][1] + dir_y*TRS_VMatrix[1][1] + 
             dir_z*TRS_VMatrix[2][1] +       TRS_VMatrix[3][1];

        dz = dir_x*TRS_VMatrix[0][2] + dir_y*TRS_VMatrix[1][2] + 
             dir_z*TRS_VMatrix[2][2] +       TRS_VMatrix[3][2];

fprintf( stderr, "%g %g %g %g: %g %g %g\n", LGT_Lights[light].FieldAngle,dx,dy,dz,x,y,z);

        dx -= x; dy -= y; dz -= z;
        r = sqrt(dx*dx + dy*dy + dz*dz);

        LGT_Lights[light].DirectionX = dx / r;
        LGT_Lights[light].DirectionY = dy / r;
        LGT_Lights[light].DirectionZ = dz / r;

        LGT_Lights[light].FieldN = ang_n;
        a = LGT_Lights[light].FieldAngle*acos(0.0)/90.0;

        LGT_Lights[light].FieldAngle = cos(a);

fprintf( stderr, "%g %g %g %g\n", LGT_Lights[light].FieldAngle,dx/r,dy/r,dz/r);
    }

    LGT_Lights[light].Color[0] = col[0];
    LGT_Lights[light].Color[1] = col[1];
    LGT_Lights[light].Color[2] = col[2];
}

void lgt_light_onoff( int light, int onoff )
{
    if ( light >= MAX_LIGHTS )
    {
        fprintf( stderr, "lgt_light_onoff: light index [%d] out of range.\n", light );
        return;
    }

    LGT_Lights[light].LightInUse = onoff;
}
