/*
    ChemCon - molecular mechanics and molecular graphics
    Copyright (C) 1998-2002  Alexei Nikitin

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "Light_model.h"

#include <math.h>

int pow_tab[ 256 ] [ 50 ];

struct pow_tab_init
{
    pow_tab_init()
    {
        for( int i = 0;  i <= 255; i++ )
            for( int j = 1;  j < 50;  j++ )
            pow_tab[ i ] [ j ] = ( int )( 255 * pow( i / 255.0, j ) );
    }

}
pow_tab_init;

/*
void  Light_model::
//I( int *r, int *g, int *b, Material *sp, double cos_theta, double D )
I( int *r, int *g, int *b, Material *sp, int cos_theta, double D )
  {
    //double  R, G, B;
    int  R, G, B;

    if( D < 0.0 )    { D = 0.0;  cos_theta = 1.0; }
//    double  mirror         = sp->Ks;// * pow( cos_theta, sp->n );
//    int  mirror         = sp->Ks * pow( cos_theta/256.0, sp->n );
    int  mirror         = (sp->Ks * pow_tab[ cos_theta ][ sp->n ])>>8;
    //double  Il_cos_theta  = ( 1.0 - Ia )* sp->Kd * cos_theta;
    int  Il_cos_theta  = (( 255 - Ia )* sp->Kd * cos_theta)>>8;

    switch( N )
      {
        case 0 :
          {
// N0
//
//  Il = 1 - Ia
//                                                n
//  I = Ia* Ka + Il * ( Kd * cos theta  + Ks * cos theta  )
//

//            R = sp->R*( Ia*diffused_source.R + Il_cos_theta ) + mirror;
//            G = sp->G*( Ia*diffused_source.G + Il_cos_theta ) + mirror;
//            B = sp->B*( Ia*diffused_source.B + Il_cos_theta ) + mirror;
//            R = sp->R*( Ia*sp->Ka*diffused_source.R + Il_cos_theta ) + mirror;
//            G = sp->G*( Ia*sp->Ka*diffused_source.G + Il_cos_theta ) + mirror;
//            B = sp->B*( Ia*sp->Ka*diffused_source.B + Il_cos_theta ) + mirror;

            int IaKa = (Ia*sp->Ka)>>8;
            *r = ((sp->R*( ((IaKa*diffused_source.R)) + (Il_cos_theta) ))>>16) + mirror;
            *r = ( *r > 255 ) ? 255 : *r;
            //if( *r > 255 )  *r = 255;
            *g = ((sp->G*( ((IaKa*diffused_source.G)) + (Il_cos_theta) ))>>16) + mirror;
            *g = ( *g > 255 ) ? 255 : *g;
            //if( *g > 255 )  *g = 255;
            *b = ((sp->B*( ((IaKa*diffused_source.B)) + (Il_cos_theta) ))>>16) + mirror;
            *b = ( *b > 255 ) ? 255 : *b;
            //if( *b > 255 )  *b = 255;
            return;
          }

        case 1 :
          {
// N1
//
//  Il = 1 - Ia
//
//         K
//  k = -------
//       D + K
//                                                    n
//  I = k*( Ia* Ka + Il * ( Kd * cos theta  + Ks * cos theta  ))
//
            double k = K/(D + K);
            *r = k*(sp->R*( Ia*sp->Ka*diffused_source.R + Il_cos_theta ) + mirror);
            *g = k*(sp->G*( Ia*sp->Ka*diffused_source.G + Il_cos_theta ) + mirror);
            *b = k*(sp->B*( Ia*sp->Ka*diffused_source.B + Il_cos_theta ) + mirror);
            break;
          }
        case 2 :
          {
// N2
//
//  Il = 1 - Ia
//
//          (K*(SQRT(2)+1))^2
//  k = --------------------------
//       ( D  + K*(SQRT(2)+1) )^2
//                                                    n
//  I = k*( Ia* Ka + Il * ( Kd * cos theta  + Ks * cos theta  ))
//
            double k = K * ( 1.414213562373 + 1 );
            k = k*k/((D+k)*(D+k));
            R = k*(sp->R*( Ia*sp->Ka*diffused_source.R + Il_cos_theta ) + mirror);
            G = k*(sp->G*( Ia*sp->Ka*diffused_source.G + Il_cos_theta ) + mirror);
            B = k*(sp->B*( Ia*sp->Ka*diffused_source.B + Il_cos_theta ) + mirror);
            break;
          }
        case 3 :
          {
// N3
//
//  Il = 1 - Ia
//
//         K
//  k = -------
//       D + K
//                                                    n
//  I = Ia* Ka + k * Il * ( Kd * cos theta  + Ks * cos theta  )
//
            double k = K/(D + K);
            R = sp->R*( Ia*sp->Ka*diffused_source.R + k*Il_cos_theta ) + k*mirror;
            G = sp->G*( Ia*sp->Ka*diffused_source.G + k*Il_cos_theta ) + k*mirror;
            B = sp->B*( Ia*sp->Ka*diffused_source.B + k*Il_cos_theta ) + k*mirror;
            break;
          }
        case 4 :
          {
// N4
//
//  Il = 1 - Ia
//
//          (K*(SQRT(2)+1))^2
//  k = --------------------------
//       ( D  + K*(SQRT(2)+1) )^2
//                                                    n
//  I = k*( Ia* Ka + Il * ( Kd * cos theta  + Ks * cos theta  ))
//
            double k = K * ( 1.414213562373 + 1 );
            k = k*k/((D+k)*(D+k));
            R = sp->R*( Ia*sp->Ka*diffused_source.R + k*Il_cos_theta ) + k*mirror;
            G = sp->G*( Ia*sp->Ka*diffused_source.G + k*Il_cos_theta ) + k*mirror;
            B = sp->B*( Ia*sp->Ka*diffused_source.B + k*Il_cos_theta ) + k*mirror;
            break;
          }
      }

//    *r = int(R * 255.0);    if( *r > 255 )  *r = 255;
//    *g = int(G * 255.0);    if( *g > 255 )  *g = 255;
//    *b = int(B * 255.0);    if( *b > 255 )  *b = 255;
    //if( *r > 255 )  *r = 255;
    //if( *g > 255 )  *g = 255;
    //if( *b > 255 )  *b = 255;
  }
//*/
/*
void  Light_model_for_selected::
I( int *r, int *g, int *b, Material *sp, double cos_theta, double D )
  {
    double  R=0.0, G=0.0, B=0.0;

    double  w = Selected_atom.film_width;
    double  r = Selected_atom.radius;
    double  Nz = r*cos_theta;
    double  d = sqrt( Nz*Nz + ( r + w )*( r + w ) - r*r ) - Nz;

    double  tmp = d*Selected_atom.K_transparency/sqrt( w*( 2*r + w ) );
    double  KtR = sp->film_R*tmp;
    double  KtG = sp->film_G*tmp;
    double  KtB = sp->film_B*tmp;

    TColor color = Base_LM.I( sp, cos_theta, D );

    R = GetRValue( color )/255.0 +
        KtR*( ( 1.0 - Ia )*sp->film_R + Ia*diffused_source.R*sp->film_R );
    G = GetGValue( color )/255.0 +
        KtG*( ( 1.0 - Ia )*sp->film_G + Ia*diffused_source.G*sp->film_G );
    B = GetBValue( color )/255.0 +
        KtB*( ( 1.0 - Ia )*sp->film_B + Ia*diffused_source.B*sp->film_B );

    *r = R * 255.0;    if( *r > 255 )  *r = 255;
    *g = G * 255.0;    if( *g > 255 )  *g = 255;
    *b = B * 255.0;    if( *b > 255 )  *b = 255;
  }
*/

//--------------------------------------------------------------

Light_model::Light_model()
   //  : N( 0 ), K( 1.0 ), Ia( 0.3 ), /*Il( 0 ),*/ Ib( 0 )
//fix   : K_( 1 ), Ia_( 128 ), /*Il( 0 ),*/ Ib_( 0 )
   : K_( 200 ), Ia_( 128 ), /*Il( 0 ),*/ Ib_( 0 )
   {
       //    diffused_source.R = 1;  diffused_source.G = 1;  diffused_source.B = 1;
       diffused_source_.R_ = 255;
       diffused_source_.G_ = 255;
       diffused_source_.B_ = 255;
       bg_.R_              = 0;
       bg_.G_              = 0;
       bg_.B_              =  0;
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1

/*
extern  int pow_tab[ 256 ][ 50 ];

void  Light_model::
I( int *r, int *g, int *b, Material *m, int cos_theta, int D )
  {
    int mirror, Il_cos_theta, k, IaKa;
    // *r=0; *g=255; *b=0;  return;

    if( D < 0 )        { D = 0;  cos_theta = 255; }
    mirror         = (m->Ks * pow_tab[ cos_theta ][ m->n ])>>8;
    Il_cos_theta  = (( 255 - Ia )* m->Kd * cos_theta)>>8;
// N1
//
//  Il = 1 - Ia
//
//         K
//  k = -------
//       D + K
//                                                    n
//  I = k*( Ia* Ka + Il * ( Kd * cos theta  + Ks * cos theta  ))
//
    k = (255*K)/(D + K);

//    IaKa = (Ia*m->Ka)>>8;
//    *r = (int)(k*((m->R*( IaKa*diffused_source.R + Il_cos_theta )>>16) + mirror))>>8;
//    *g = (int)(k*((m->G*( IaKa*diffused_source.G + Il_cos_theta )>>16) + mirror))>>8;
//    *b = (int)(k*((m->B*( IaKa*diffused_source.B + Il_cos_theta )>>16) + mirror))>>8;
//    *r = ( *r > 255 ) ? 255 : *r;
//    *g = ( *g > 255 ) ? 255 : *g;
//    *b = ( *b > 255 ) ? 255 : *b;

//*/
/*__asm
{
//94:           int IaKa = (Ia*sp->Ka)>>8;
mov         edx,dword ptr [this]
mov         eax,dword ptr [m]
mov         ecx,dword ptr [edx+8]
imul        ecx,dword ptr [eax]
sar         ecx,8
mov         dword ptr [IaKa],ecx
//95:       *r = (int)(k*((sp->R*( IaKa*diffused_source.R + Il_cos_theta )>>16) + mirror))>>8;
mov         edx,dword ptr [this]
mov         eax,dword ptr [IaKa]
imul        eax,dword ptr [edx+10h]
add         eax,dword ptr [Il_cos_theta]
mov         ecx,dword ptr [m]
mov         edx,dword ptr [ecx+10h]
imul        edx,eax
sar         edx,10h
add         edx,dword ptr [mirror]
mov         eax,dword ptr [k]
imul        eax,edx
sar         eax,8
mov         ecx,dword ptr [r]
mov         dword ptr [ecx],eax
//96:       *g = (int)(k*((sp->G*( IaKa*diffused_source.G + Il_cos_theta )>>16) + mirror))>>8;
mov         edx,dword ptr [this]
mov         eax,dword ptr [IaKa]
imul        eax,dword ptr [edx+14h]
add         eax,dword ptr [Il_cos_theta]
mov         ecx,dword ptr [m]

//mov         edx,dword ptr [ecx+14h]
//imul        edx,eax
//sar         edx,10h
//add         edx,dword ptr [mirror]

mov         ecx,dword ptr [ecx+14h]
imul        ecx,eax
sar         ecx,10h
add         ecx,dword ptr [mirror]

mov         eax,dword ptr [k]
//imul        eax,edx
imul        eax,ecx
sar         eax,8
mov         ecx,dword ptr [g]
mov         dword ptr [ecx],eax
//97:       *b = (int)(k*((sp->B*( IaKa*diffused_source.B + Il_cos_theta )>>16) + mirror))>>8;
//mov         edx,dword ptr [this]
//*/
/*mov         eax,dword ptr [IaKa]
imul        eax,dword ptr [edx+18h]
add         eax,dword ptr [Il_cos_theta]
mov         ecx,dword ptr [m]
mov         ecx,dword ptr [ecx+18h]
imul        ecx,eax
sar         ecx,10h
add         ecx,dword ptr [mirror]
mov         eax,dword ptr [k]
imul        eax,ecx
sar         eax,8
mov         ecx,dword ptr [b]
mov         dword ptr [ecx],eax
*/

/*/ / 98 :           * r = ( * r > 255 ) ? 255 : * r;
mov         edx, dword ptr [ r ]
cmp         dword ptr [ edx ], 0FF h
jle         L2
mov         dword ptr [ ebp - 18 h ], 0FF h
jmp         L22
mov         eax, dword ptr [ r ]
mov         ecx, dword ptr [ eax ]
mov         dword ptr [ ebp - 18 h ], ecx
L22 :
mov         edx, dword ptr [ r ]
mov         eax, dword ptr [ ebp - 18 h ]
mov         dword ptr [ edx ], eax
L2 :
   //99:           *g = ( *g > 255 ) ? 255 : *g;
   mov         ecx, dword ptr [ g ]
   cmp         dword ptr [ ecx ], 0FF h
   jle         L3
   mov         dword ptr [ ebp - 1 Ch ], 0FF h
   jmp         L33
   mov         edx, dword ptr [ g ]
   mov         eax, dword ptr [ edx ]
   mov         dword ptr [ ebp - 1 Ch ], eax
   L33 :
   mov         ecx, dword ptr [ g ]
   mov         edx, dword ptr [ ebp - 1 Ch ]
   mov         dword ptr [ ecx ], edx
   L3 :
   //100:          *b = ( *b > 255 ) ? 255 : *b;
   mov         eax, dword ptr [ b ]
   cmp         dword ptr [ eax ], 0FF h
   jle         L4
   mov         dword ptr [ ebp - 20 h ], 0FF h
   jmp         L44
   mov         ecx, dword ptr [ b ]
   mov         edx, dword ptr [ ecx ]
   mov         dword ptr [ ebp - 20 h ], edx
   L44 :
   mov         eax, dword ptr [ b ]
   mov         ecx, dword ptr [ ebp - 20 h ]
   mov         dword ptr [ eax ], ecx
   L4 :        */
/*}
    *r = ( *r > 255 ) ? 255 : *r;
    *g = ( *g > 255 ) ? 255 : *g;
    *b = ( *b > 255 ) ? 255 : *b;
  }
*/

