/**********************************************************************
This file is part of Crack dot Com's free source code release of Golgotha.
for information about compiling & licensing issues visit this URL
 If that doesn't help, contact Jonathan Clark at 
  golgotha_source@usa.net (Subject should have "GOLG" in it) 
***********************************************************************/

#include "mip_average.hh"
#include "palette/pal.hh"
#include "mip.hh"
#include 

void setup_pixel_formats(i4_pixel_format ®_fmt,
                         i4_pixel_format &chroma_fmt,
                         i4_pixel_format &alpha_fmt,
                         w32 chroma_color)
{
  //regular format setup
  mip_b_shift = 8-reg_fmt.blue_bits;  
  mip_b_and   = reg_fmt.blue_mask;

  mip_g_shift = reg_fmt.blue_bits - (8-reg_fmt.green_bits);
  mip_g_and   = reg_fmt.green_mask;

  mip_r_shift = reg_fmt.green_bits + reg_fmt.blue_bits - (8-reg_fmt.red_bits);
  mip_r_and   = reg_fmt.red_mask;

  //chroma format setup
  mip_c_b_shift = 8-chroma_fmt.blue_bits;  
  mip_c_b_and   = chroma_fmt.blue_mask;

  mip_c_g_shift = chroma_fmt.blue_bits - (8-chroma_fmt.green_bits);
  mip_c_g_and   = chroma_fmt.green_mask;

  mip_c_r_shift = chroma_fmt.green_bits + chroma_fmt.blue_bits - (8-chroma_fmt.red_bits);
  mip_c_r_and   = chroma_fmt.red_mask;

  mip_c_a_shift = chroma_fmt.green_bits + chroma_fmt.blue_bits + chroma_fmt.red_bits - (8-chroma_fmt.alpha_bits);
  mip_c_a_and   = chroma_fmt.alpha_mask;

  //alpha format setup
  mip_a_b_shift = 8-alpha_fmt.blue_bits;  
  mip_a_b_and   = alpha_fmt.blue_mask;

  mip_a_g_shift = alpha_fmt.blue_bits - (8-alpha_fmt.green_bits);
  mip_a_g_and   = alpha_fmt.green_mask;

  mip_a_r_shift = alpha_fmt.green_bits + alpha_fmt.blue_bits - (8-alpha_fmt.red_bits);
  mip_a_r_and   = alpha_fmt.red_mask;
       
  mip_a_a_shift = alpha_fmt.green_bits + alpha_fmt.blue_bits + alpha_fmt.red_bits - (8-alpha_fmt.alpha_bits);
  mip_a_a_and   = alpha_fmt.alpha_mask;

  //chroma key color setup
  mip_chroma_red   = (chroma_color & 0xFF0000) >> 16;
  mip_chroma_green = (chroma_color & 0x00FF00) >> 8;
  mip_chroma_blue  = (chroma_color & 0x0000FF);
}


void r1_dos_paths(char *src)
{
  while (*src)
  {
    if (*src=='/')
      *src='\\';
    
    src++;
  }
}

void r1_unix_paths(char *src)
{  
  while (*src)
  {
    if (*src=='\\')
      *src='/';
    
    src++;
  }   
}

char *r1_remove_paths(char *src)
{
  char *ret = src;

  while (*src)
  {
    if (*src=='/')
      ret=src+1;

    src++;    
  }

  return ret;
}

void r1_remove_extention(char *src)
{
  while (*src)
  {
    if (*src=='.')
    {
      *src=0;
      return;
    }
    src++;
  }
}

void concatenate_path(char *src, char *path)
{
  char temp[256];

  char *last_path = r1_remove_paths(src);
  strcpy(temp,last_path);

  *last_path=0;

  strcat(src,path);
  strcat(src,temp);
}

void chroma_process(w8 *&p, float &r, float &g, float &b, sw8 &num_regular, sw8 &num_chroma)
{
  if (p[0]==mip_chroma_red && p[1]==mip_chroma_green && p[2]==mip_chroma_blue)
  {    
    //IS the chroma color. dont average
    num_chroma++;
  }
  else
  {
    //not the chroma color. average as a regular pixel
    r += (float)(p[0]);
    g += (float)(p[1]);
    b += (float)(p[2]);
    
    num_regular++;
  }
}

void average_4x4_chroma(w16 *&dst, w8 *dst_24, w8 *&p0, w8 *p1, w8 *p2, w8 *p3)
{
  sw8 num_chroma  = 0;
  sw8 num_regular = 0;

  float r=0;
  float g=0;
  float b=0;

  chroma_process(p0,r,g,b,num_regular,num_chroma);
  chroma_process(p1,r,g,b,num_regular,num_chroma);
  chroma_process(p2,r,g,b,num_regular,num_chroma);
  chroma_process(p3,r,g,b,num_regular,num_chroma);

  //return the chroma color
  if (num_chroma > num_regular)
  {
    //alpha component and rgb component of 16-bit pixel should be entirely 0'd
    dst_24[0] = mip_chroma_red;
    dst_24[1] = mip_chroma_green;
    dst_24[2] = mip_chroma_blue;

    *dst  = 0;
    
    return;
  }

  float ooreg = 1.f / num_regular;
  
  r *= ooreg; if (r<0) r=0; if (r>255) r = 255;
  g *= ooreg; if (g<0) g=0; if (g>255) g = 255;
  b *= ooreg; if (b<0) b=0; if (b>255) b = 255;

  dst_24[0] = (w8)r;
  dst_24[1] = (w8)g;
  dst_24[2] = (w8)b;

  *dst = (( (w16)dst_24[0] << mip_c_r_shift) & mip_c_r_and) |
         (( (w16)dst_24[1] << mip_c_g_shift) & mip_c_g_and) |
         (( (w16)dst_24[2] >> mip_c_b_shift) & mip_c_b_and) |          
         (( 0xFFFFFFFF << mip_c_a_shift) & mip_c_a_and);  
}

void average_4x4_chroma(w8 *dst_24, w8 *&p0, w8 *p1, w8 *p2, w8 *p3)
{
  sw8 num_chroma  = 0;
  sw8 num_regular = 0;

  float r=0;
  float g=0;
  float b=0;

  chroma_process(p0,r,g,b,num_regular,num_chroma);
  chroma_process(p1,r,g,b,num_regular,num_chroma);
  chroma_process(p2,r,g,b,num_regular,num_chroma);
  chroma_process(p3,r,g,b,num_regular,num_chroma);

  //return the chroma color
  if (num_chroma > num_regular)
  {
    //alpha component and rgb component of 16-bit pixel should be entirely 0'd
    dst_24[0] = mip_chroma_red;
    dst_24[1] = mip_chroma_green;
    dst_24[2] = mip_chroma_blue;
    return;
  }

  float ooreg = 1.f / num_regular;
  
  r *= ooreg; if (r<0) r=0; if (r>255) r = 255;
  g *= ooreg; if (g<0) g=0; if (g>255) g = 255;
  b *= ooreg; if (b<0) b=0; if (b>255) b = 255;

  dst_24[0] = (w8)r;
  dst_24[1] = (w8)g;
  dst_24[2] = (w8)b;
}

void average_4x4_alpha(w8 *dst_24, w8 *&p0, w8 *p1, w8 *p2, w8 *p3)
{
  sw32 ia,ir,ig,ib;
  
  ia = p0[0];
  ir = p0[1];
  ig = p0[2];
  ib = p0[3];
  
  ia += (p1[0]);
  ir += (p1[1]);
  ig += (p1[2]);
  ib += (p1[3]);
  
  ia += (p2[0]);
  ir += (p2[1]);
  ig += (p2[2]);
  ib += (p2[3]);
  
  ia += (p3[0]);
  ir += (p3[1]);  
  ig += (p3[2]);
  ib += (p3[3]);

  ia = ia >> 2;
  ir = ir >> 2;
  ig = ig >> 2;
  ib = ib >> 2;
  
  dst_24[0] = (w8)ia;
  dst_24[1] = (w8)ir;
  dst_24[2] = (w8)ig;
  dst_24[3] = (w8)ib;
}

void average_4x4_alpha(w16 *dst, w8 *dst_24, w8 *&p0, w8 *p1, w8 *p2, w8 *p3)
{
  sw32 ia,ir,ig,ib;
  
  ia = p0[0];
  ir = p0[1];
  ig = p0[2];
  ib = p0[3];
  
  ia += (p1[0]);
  ir += (p1[1]);
  ig += (p1[2]);
  ib += (p1[3]);
  
  ia += (p2[0]);
  ir += (p2[1]);
  ig += (p2[2]);
  ib += (p2[3]);
  
  ia += (p3[0]);
  ir += (p3[1]);  
  ig += (p3[2]);
  ib += (p3[3]);

  ia = ia >> 2;
  ir = ir >> 2;
  ig = ig >> 2;
  ib = ib >> 2;
  
  dst_24[0] = (w8)ia;
  dst_24[1] = (w8)ir;
  dst_24[2] = (w8)ig;
  dst_24[3] = (w8)ib;

  *dst = (( (w16)dst_24[1] << mip_a_r_shift) & mip_a_r_and) |
         (( (w16)dst_24[2] << mip_a_g_shift) & mip_a_g_and) |
         (( (w16)dst_24[3] >> mip_a_b_shift) & mip_a_b_and) |          
         (( (w16)dst_24[0] << mip_a_a_shift) & mip_a_a_and);
}


void average_4x4_normal(w16 *dst, w8 *dst_24, w8 *p0, w32 bpl)
{  
#ifndef WIN32
  
  sw32 ir,ig,ib;
  
  ir = p0[0];
  ig = p0[1];
  ib = p0[2];
  
  ir += (p0[0+3]);
  ig += (p0[1+3]);
  ib += (p0[2+3]);
  
  ir += (p0[0+bpl]);
  ig += (p0[1+bpl]);
  ib += (p0[2+bpl]);
  
  ir += (p0[0+bpl+3]);
  ig += (p0[1+bpl+3]);
  ib += (p0[2+bpl+3]);

  ir = ir >> 2;
  ig = ig >> 2;
  ib = ib >> 2;

  dst_24[0] = (w8)ir;
  dst_24[1] = (w8)ig;
  dst_24[2] = (w8)ib;

  *dst = (( (w16)p0[0] << mip_r_shift) & mip_r_and) |
         (( (w16)p0[1] << mip_g_shift) & mip_g_and) |
         (( (w16)p0[2] >> mip_b_shift) & mip_b_and);
#else
  _asm
  {
  mov esi,p0
  mov edi,dst
  
  mov ecx,bpl

  mov eax,0 //red
  mov ebx,0 //green
  mov edx,0 //blue

  mov al,byte ptr [esi]  
  add al,byte ptr [esi+3]
  adc ah,0
  add al,byte ptr [esi+ecx]
  adc ah,0
  add al,byte ptr [esi+ecx+3]
  adc ah,0

  mov bl,byte ptr [esi+1]  
  add bl,byte ptr [esi+4]
  adc bh,0
  add bl,byte ptr [esi+ecx+1]
  adc bh,0
  add bl,byte ptr [esi+ecx+4]
  adc bh,0

  mov dl,byte ptr [esi+2]
  add dl,byte ptr [esi+5]
  adc dh,0
  add dl,byte ptr [esi+ecx+2]
  adc dh,0
  add dl,byte ptr [esi+ecx+5]
  adc dh,0
      
  shr eax,2
  shr ebx,2
  shr edx,2

  mov esi,dst_24

  mov byte ptr [esi],al
  mov byte ptr [esi+1],bl
  mov byte ptr [esi+2],dl
  
  mov cl,mip_r_shift
  shl eax,cl
  and eax,mip_r_and

  mov cl,mip_g_shift
  shl ebx,cl
  and ebx,mip_g_and

  mov cl,mip_b_shift
  shr edx,cl
  and edx,mip_b_and

  or  eax,ebx
  or  eax,edx

  mov word ptr [edi],ax
  }
#endif
} 

void average_4x4_normal(w8 *dst_24, w8 *p0, w32 bpl)
{  
#ifndef WIN32
  sw32 ir,ig,ib;
  
  ir = (p0[0]);
  ig = (p0[1]);
  ib = (p0[2]);
  
  ir += (p0[0+3]);
  ig += (p0[1+3]);
  ib += (p0[2+3]);
  
  ir += (p0[0+bpl]);
  ig += (p0[1+bpl]);
  ib += (p0[2+bpl]);
  
  ir += (p0[0+bpl+3]);
  ig += (p0[1+bpl+3]);
  ib += (p0[2+bpl+3]);  

  ir = ir >> 2; if (ir<0) ir = 0; else if (ir>255) ir = 255;
  ig = ig >> 2; if (ig<0) ig = 0; else if (ig>255) ig = 255;
  ib = ib >> 2; if (ib<0) ib = 0; else if (ib>255) ib = 255;
  
  dst_24[0] = (w8)ir;
  dst_24[1] = (w8)ig;
  dst_24[2] = (w8)ib;  
#else  
  _asm
  {
  mov esi,p0
  mov edx,bpl
  mov edi,dst_24

  mov eax,0 //red
  mov ebx,0 //green
  mov ecx,0 //blue

  mov al,byte ptr [esi]  
  add al,byte ptr [esi+3]
  adc ah,0
  add al,byte ptr [esi+edx]
  adc ah,0
  add al,byte ptr [esi+edx+3]
  adc ah,0

  mov bl,byte ptr [esi+1]  
  add bl,byte ptr [esi+4]
  adc bh,0
  add bl,byte ptr [esi+edx+1]
  adc bh,0
  add bl,byte ptr [esi+edx+4]
  adc bh,0

  mov cl,byte ptr [esi+2]
  add cl,byte ptr [esi+5]
  adc ch,0
  add cl,byte ptr [esi+edx+2]
  adc ch,0
  add cl,byte ptr [esi+edx+5]
  adc ch,0
      
  shr eax,2
  shr ebx,2
  shr ecx,2
  
  mov byte ptr [edi],al
  mov byte ptr [edi+1],bl
  mov byte ptr [edi+2],cl
  }
#endif
} 


void mip_24_to_16(w8 *mip24, w16 *mip16, sw32 &width, sw32 &height, sw32 &base_width, w8 &flags)
{
  pf_mip_24_to_16.start();

  sw32 i,j,total_pixels;
  
  w8  *src = mip24;
  w16 *dst = mip16;
    
  sw32 base_bpl = base_width*3;
  sw32 src_add  = (base_width - width)*3;
  
  if (flags & R1_MIP_IS_ALPHATEXTURE)
  {
    base_bpl = base_width*4;
    src_add  = (base_width - width)*4;
  }  

  if (flags & R1_MIP_IS_TRANSPARENT)
  {
    for (j=0;j