/**********************************************************************
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) 
***********************************************************************/

//#define JPEG_INTERNALS
//TODO clean up memory management 
//convert types and memory and file stuff to I4
#include "loaders/load.hh"
#include "loaders/jpg_load.hh"
#include "time/profile.hh"
#include "memory/malloc.hh"
#include "palette/pal.hh"
#include "status/status.hh"

i4_profile_class pf_jpg_scanline_decode("jpg_scanline_decode");
i4_profile_class pf_jpg_decode("jpg_decode");

  
w16 jpg_r_and; w8 jpg_r_shift; //r and g shifts are to the left
w16 jpg_g_and; w8 jpg_g_shift; 
w16 jpg_b_and; w8 jpg_b_shift; //b shift is to the right

void setup_pix_format(const i4_pixel_format *fmt)
{  
  jpg_b_shift = 8-fmt->blue_bits;  
  jpg_b_and   = fmt->blue_mask;

  jpg_g_shift = fmt->blue_bits - (8-fmt->green_bits);
  jpg_g_and   = fmt->green_mask;

  jpg_r_shift = fmt->green_bits + fmt->blue_bits - (8-fmt->red_bits);
  jpg_r_and   = fmt->red_mask;
}

static inline void pack_colorbgr(w16 *dest, w8 *src, sw32 num_pixels)
{   
  while (num_pixels)
  {  
    //shifts must go first, ands last  
    *dest = ((src[0] << jpg_r_shift) & jpg_r_and) |
            ((src[1] << jpg_g_shift) & jpg_g_and) |
            ((src[2] >> jpg_b_shift) & jpg_b_and);
    
    dest++;
    src += 3;

    num_pixels--;
  }  
}

i4_bool i4_jpg_loader_class::convert_to_raw16(i4_file_class *src_fp,
                                              FILE *dst_fp,
                                              i4_status_class *status,
                                              const i4_pal *pal,
                                              sw32 expected_width,
                                              sw32 expected_height)
{
  djpeg_dest_ptr dest_mgr = NULL;
  JDIMENSION num_scanlines;
  int i,x;

  //setup this conversion stuff
  setup_pix_format(&pal->source);
  
  /* Initialize the JPEG decompression object with default error handling. */
  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_decompress(&cinfo);
  /* Add some application-specific error messages (from cderror.h) */
  jerr.addon_message_table = cdjpeg_message_table;
  jerr.first_addon_message = JMSG_FIRSTADDONCODE;
  jerr.last_addon_message = JMSG_LASTADDONCODE;
  /* Insert custom COM marker processor. */
  jpeg_set_marker_processor(&cinfo, JPEG_COM, COM_handler);
  /* Specify data source for decompression */
  jpeg_stdio_src(&cinfo, src_fp);

  /* Read file header, set default decompression parameters */
  (void) jpeg_read_header(&cinfo, TRUE);

  dest_mgr = jinit_write_targa(&cinfo);

  /* Start decompressor */
  (void) jpeg_start_decompress(&cinfo);
  
  w16 *data = (w16 *)i4_malloc(cinfo.image_width*2, "jpeg 16-bit buffer");  

  w32 scn=0;
  /* Process data */
  while (cinfo.output_scanline < cinfo.output_height)
  {
    pf_jpg_scanline_decode.start();
    num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,dest_mgr->buffer_height);
    pf_jpg_scanline_decode.stop();

    for(i=0;iupdate(i/(float)num_scanlines);

      pack_colorbgr(data,dest_mgr->buffer[i],cinfo.image_width);
      fwrite(data,cinfo.image_width*2,1,dst_fp);
      /*
      for(x=0;xbuffer[i])+(x*3)))));
      }
      
      scn += cinfo.image_width;
      */
    }
  }

  /* Finish decompression and release memory.
   * I must do it in this order because output module has allocated memory
   * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
   */
  i4_free(data);

  (void) jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);
  
  return i4_T;
}

i4_bool i4_jpg_loader_class::special_load16(i4_file_class *src_fp,
                                            w16 *dst_tex,
                                            sw32 base_width,
                                            const i4_pal *pal)
{
  pf_jpg_decode.start();

  djpeg_dest_ptr dest_mgr = NULL;
  JDIMENSION num_scanlines;
  int i,x;

  //setup this conversion stuff
  setup_pix_format(&pal->source);  
  
  /* Initialize the JPEG decompression object with default error handling. */
  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_decompress(&cinfo);
  /* Add some application-specific error messages (from cderror.h) */
  jerr.addon_message_table = cdjpeg_message_table;
  jerr.first_addon_message = JMSG_FIRSTADDONCODE;
  jerr.last_addon_message = JMSG_LASTADDONCODE;
  /* Insert custom COM marker processor. */
  jpeg_set_marker_processor(&cinfo, JPEG_COM, COM_handler);
  /* Specify data source for decompression */
  jpeg_stdio_src(&cinfo, src_fp);

  /* Read file header, set default decompression parameters */
  (void) jpeg_read_header(&cinfo, TRUE);

  dest_mgr = jinit_write_targa(&cinfo);

  /* Start decompressor */
  (void) jpeg_start_decompress(&cinfo);  

  w16 *data = dst_tex;

  w32 scn=0;
  /* Process data */
  while (cinfo.output_scanline < cinfo.output_height)
  {
    pf_jpg_scanline_decode.start();
    num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,dest_mgr->buffer_height);
    pf_jpg_scanline_decode.stop();

    for(i=0;ibuffer[i],cinfo.image_width);            
    }
  }

  /* Finish decompression and release memory.
   * I must do it in this order because output module has allocated memory
   * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
   */  

  (void) jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);

  pf_jpg_decode.stop();  
  return i4_T;
}

i4_bool i4_jpg_loader_class::special_load24(i4_file_class *src_fp,
                                            w8   *dst_tex,
                                            sw32 *dst_width,
                                            sw32 *dst_height)
{                                           
  pf_jpg_decode.start();

  djpeg_dest_ptr dest_mgr = NULL;
  JDIMENSION num_scanlines;
  int i,x;  
  
  /* Initialize the JPEG decompression object with default error handling. */
  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_decompress(&cinfo);
  /* Add some application-specific error messages (from cderror.h) */
  jerr.addon_message_table = cdjpeg_message_table;
  jerr.first_addon_message = JMSG_FIRSTADDONCODE;
  jerr.last_addon_message = JMSG_LASTADDONCODE;
  /* Insert custom COM marker processor. */
  jpeg_set_marker_processor(&cinfo, JPEG_COM, COM_handler);
  /* Specify data source for decompression */
  jpeg_stdio_src(&cinfo, src_fp);

  /* Read file header, set default decompression parameters */
  (void) jpeg_read_header(&cinfo, TRUE);

  dest_mgr = jinit_write_targa(&cinfo);

  /* Start decompressor */
  (void) jpeg_start_decompress(&cinfo);  

  w8 *data = dst_tex;
  sw32 data_add = cinfo.image_width*3;

  *dst_width  = cinfo.image_width;
  *dst_height = cinfo.image_height;
  
  /* Process data */
  while (cinfo.output_scanline < cinfo.output_height)
  {
    pf_jpg_scanline_decode.start();
    num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,dest_mgr->buffer_height);
    pf_jpg_scanline_decode.stop();

    for(i=0; ibuffer[i],cinfo.image_width*3);                  
      data += data_add;
    }
  }

  /* Finish decompression and release memory.
   * I must do it in this order because output module has allocated memory
   * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
   */  

  (void) jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);

  pf_jpg_decode.stop();  
  
  return i4_T;
}


i4_image_class *i4_jpg_loader_class::load(i4_file_class *fp,
                             i4_status_class *status)
{
  djpeg_dest_ptr dest_mgr = NULL;
  JDIMENSION num_scanlines;
  int i,x;
    
  // Initialize the JPEG decompression object with default error handling.
  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_decompress(&cinfo);
  // Add some application-specific error messages (from cderror.h)
  jerr.addon_message_table = cdjpeg_message_table;
  jerr.first_addon_message = JMSG_FIRSTADDONCODE;
  jerr.last_addon_message = JMSG_LASTADDONCODE;
  // Insert custom COM marker processor.
  jpeg_set_marker_processor(&cinfo, JPEG_COM, COM_handler);
   
  /* Specify data source for decompression */
  jpeg_stdio_src(&cinfo, fp);

  /* Read file header, set default decompression parameters */
  (void) jpeg_read_header(&cinfo, TRUE);

  dest_mgr = jinit_write_targa(&cinfo);

  /* Start decompressor */
  (void) jpeg_start_decompress(&cinfo);


  w32 *data=(w32 *)i4_malloc(cinfo.image_width*cinfo.image_height*4,"jpeg image");
  w32 scn=0;
  /* Process data */
  while (cinfo.output_scanline < cinfo.output_height) {
    num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
                                        dest_mgr->buffer_height);
    for(i=0;iupdate(i/(float)num_scanlines);



      for(x=0;xbuffer[i])+(x*3)))));
      }
      scn+=cinfo.image_width;
    }
  }

  /* Finish decompression and release memory.
   * I must do it in this order because output module has allocated memory
   * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
   */
  (void) jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);


  i4_pixel_format fmt;
  fmt.default_format();

  fmt.alpha_mask=0;           // no alpha in jpegs?
  fmt.calc_shift();


  const i4_pal *pal=i4_pal_man.register_pal(&fmt);

  i4_image_class *im=i4_create_image(
    cinfo.image_width,
    cinfo.image_height,               // width & height
    pal,                            // palette (should be 32 bit by default)
    data,
    cinfo.image_width*4);                           // bytes per line

  im->dont_free_data=i4_F;
      
  return im;
}


class i4_jpg_loader_class i4_jpg_loader_instance;