#define MODULE_ATM

#include "graf.h"

FLOAT ATM_ColorR, ATM_ColorG, ATM_ColorB;

FLOAT ATM_DistanceB,  ATM_DistanceE;
FLOAT ATM_DistFactor, ATM_DistAdd;

FLOAT ATM_exp,R[VERTEX_NCOMP];

void (*ATM_apply_function)( FLOAT * );

void atm_apply_linear( FLOAT *P )
{
    FLOAT t, distance;

    if ( ATM_DistanceE <= 0.0 ) return;

    R[VERTEX_COORD_X] = P[VERTEX_ORIG_COORD_X];
    R[VERTEX_COORD_Y] = P[VERTEX_ORIG_COORD_Y];
    R[VERTEX_COORD_Z] = P[VERTEX_ORIG_COORD_Z];
    trs_viewing_transform(1,(ZBF_VERTEX *)R);

    distance = ABS( R[VERTEX_COORD_Z] );

    if ( distance < ATM_DistanceB ) return;
    if ( distance > ATM_DistanceE ) distance = ATM_DistanceE;

    t =  ATM_DistFactor * distance + ATM_DistAdd;

    P[VERTEX_COLOR_R] = (1.0-t)*P[VERTEX_COLOR_R] + t*ATM_ColorR;
    P[VERTEX_COLOR_G] = (1.0-t)*P[VERTEX_COLOR_G] + t*ATM_ColorG;
    P[VERTEX_COLOR_B] = (1.0-t)*P[VERTEX_COLOR_B] + t*ATM_ColorB;
}

void atm_linear_fog( FLOAT distance_b, FLOAT distance_e, FLOAT *c )
{
    ATM_DistanceB = distance_b;
    ATM_DistanceE = distance_e;

    if ( ATM_DistanceE <= 0.0 )
    {
        ATM_apply_function = (void (*)())0;
        return;
    }

    ATM_DistFactor = 1.0 / (ATM_DistanceE - ATM_DistanceB);

    ATM_DistAdd = -ATM_DistanceB * ATM_DistFactor;

    ATM_ColorR = 255.0 * c[0];
    ATM_ColorG = 255.0 * c[1];
    ATM_ColorB = 255.0 * c[2];

    atm_set_function( atm_apply_linear );
}

void atm_apply_exp( FLOAT *P )
{
    FLOAT t, distance;

    R[VERTEX_COORD_X] = P[VERTEX_ORIG_COORD_X];
    R[VERTEX_COORD_Y] = P[VERTEX_ORIG_COORD_Y];
    R[VERTEX_COORD_Z] = P[VERTEX_ORIG_COORD_Z];
    trs_viewing_transform(1,(ZBF_VERTEX *)R);

    distance = ABS( R[VERTEX_COORD_Z] );

    t = 1.0 - exp( -ATM_exp * distance * distance );

    P[VERTEX_COLOR_R] = (1.0-t)*P[VERTEX_COLOR_R] + t*ATM_ColorR;
    P[VERTEX_COLOR_G] = (1.0-t)*P[VERTEX_COLOR_G] + t*ATM_ColorG;
    P[VERTEX_COLOR_B] = (1.0-t)*P[VERTEX_COLOR_B] + t*ATM_ColorB;
}

void atm_exp_fog( FLOAT factor, FLOAT *c )
{
    ATM_exp = 100.0 * factor;

    if ( ATM_exp == 0.0 )
    {
        ATM_apply_function = (void (*)())0;
        return;
    }

    ATM_ColorR = 255.0 * c[0];
    ATM_ColorG = 255.0 * c[1];
    ATM_ColorB = 255.0 * c[2];

    atm_set_function( atm_apply_exp );
}

void atm_set_function( void (*function)() )
{
    ATM_apply_function = function;

    if (  function != (void (*)())0 )
    {
        lmd_add_lmodel_interpolant( VERTEX_ORIG_COORD_Z );
    }
}

void atm_apply_atmosphere( FLOAT *P )
{
    if ( ATM_apply_function ) (*ATM_apply_function)( P );
}
