/******************************************************************************/
/*                                                                            */
/*  IMAGE24 - All basic routines for the Image24 class                        */
/*                                                                            */
/*  In version 1 this is not used.                                            */
/*                                                                            */
/******************************************************************************/

#define STRICT
#include <windows.h>
#include <commctrl.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include "const.h"
#include "classes.h"
#include "funcdefs.h"
#include "blocks.rh"
#include "extern.h"

/*
--------------------------------------------------------------------------------

   Default constructor and destructor

--------------------------------------------------------------------------------
*/

Image24::Image24 ()
{
   if (nr < 0)     // If constructor's malloc failed
      return ;     // There is nothing more to do
   img = NULL ;
}

Image24::~Image24 ()
{
   if (nr < 0)     // If constructor's malloc failed
      return ;     // There is nothing more to do
   if (img != NULL)
      free ( img ) ;
   if (dib_image != NULL)
      delete dib_image ;
}


/*
--------------------------------------------------------------------------------

   Usual constructor

--------------------------------------------------------------------------------
*/

Image24::Image24 ( VortexParams *params )
      : Image ( "Vortex (24-bit)" )
{
   int irow, icol, rdiff, cdiff, dist ;
   unsigned char *rowptr ;

   if (nr < 0)     // If constructor's malloc failed
      return ;     // There is nothing more to do

   nr = params->nrows ;
   nc = params->ncols ;
   nbytes = 3 ;

   img = (unsigned char *) malloc ( 3 * nr * nc ) ;

   if (img == NULL) {
      nr = nc = -1 ;   // Flag failure
      return ;
      }


   begin_wait_message ( "Creating blocks image" , 0 ) ;
   for (irow=0 ; irow<nr ; irow++) {
      rowptr = img + irow * 3 * nc ;    // Row in computed image
      for (icol=0 ; icol<nc ; icol++) {
         rand = (irow + icol) % 256 ;
         rowptr[3*icol] = (unsigned char) rand ;
         rowptr[3*icol+1] = (unsigned char) rand ;
         rowptr[3*icol+2] = (unsigned char) rand ;
         }
      }

   dib_image = new DIBimage ( nr , nc , 3 , img ) ;
   end_wait_message () ;

   if (dib_image == NULL) {
      audit ( "insufficient_memory to create DIB image" ) ;
      nr = nc = -1 ;   // Flag failure
      free ( img ) ;
      img = NULL ;  // Not necessary, but cheap insurance
      return ;
      }
}


/*
--------------------------------------------------------------------------------

   Write BMP file

--------------------------------------------------------------------------------
*/

int Image24::write_bmp ( char *filename )
{
   int i, row_bytes, head_size, img_size, top, left, nrows, ncols ;
   unsigned char *pixels ;
   FILE *fp ;
   BITMAPINFO *bmi ;
   BITMAPINFOHEADER *bmih ;
   BITMAPFILEHEADER bmifh ;

/*
   get the location and dimensions of the full screen image to write
*/

   top = left = 0 ;
   nrows = nr ;
   ncols = nc ;

/*
   Allocate memory
   Each scan line must start on a LONG boundary.
   So we allocate enough memory for any padding necessary at the end of each.
*/

   head_size = sizeof(BITMAPINFOHEADER) ;

   bmi = (BITMAPINFO *) malloc ( head_size ) ;

   row_bytes = (3 * ncols + sizeof(LONG) - 1) / sizeof(LONG) * sizeof(LONG) ;

   img_size = nrows * row_bytes ;
   pixels = (unsigned char *) malloc ( img_size ) ;

   if ((bmi == NULL)  ||  (pixels == NULL)) {
      MessageBox ( hwndFrame , "ERROR: Cannot write image to BMP file" ,
                     "Insufficient memory" , MB_ICONEXCLAMATION | MB_OK) ;
      if (bmi != NULL)
         free ( bmi ) ;
      if (pixels != NULL)
         free ( pixels ) ;
      return 1 ;
      }

/*
   Fill in BITMAPINFOHEADER
*/

   bmih = (BITMAPINFOHEADER *) bmi ;

   memset ( bmih , 0 , sizeof(BITMAPINFOHEADER) ) ;

   bmih->biSize = sizeof(BITMAPINFOHEADER) ;
   bmih->biWidth = ncols ;
   bmih->biHeight = nrows ;  // Positive makes it bottom-to-top
   bmih->biPlanes = 1 ;
   bmih->biBitCount = (char) 24 ;
   bmih->biCompression = BI_RGB ;
   bmih->biSizeImage = 0 ;  // OK for BI_RGB
   bmih->biXPelsPerMeter = 0 ;
   bmih->biYPelsPerMeter = 0 ;
   bmih->biClrUsed = 0 ;
   bmih->biClrImportant = 0 ;  // Uses full RGB table

/*
   Copy the image, recalling that each row is padded (if necessary) to LONG
*/

   begin_wait_message ( "Writing image" , 0 ) ;
   memset ( pixels , 0 , img_size ) ;

   for (i=0 ; i<nrows ; i++)
      memcpy ( pixels + (nrows - i - 1) * row_bytes ,
               img + (i + top) * 3 * nc + left , 3 * ncols ) ;

/*
   Fill in the BITMAPFILEHEADER
*/

   bmifh.bfType = 0x4d42 ;   // "BM" reversed
   bmifh.bfSize = sizeof(BITMAPFILEHEADER) + head_size + img_size ;
   bmifh.bfReserved1 = 0 ;
   bmifh.bfReserved2 = 0 ;
   bmifh.bfOffBits = sizeof(BITMAPFILEHEADER) + head_size ;

/*
   Write the file
*/

   if (fopen_s ( &fp , filename , "wb" )) {
      MessageBox ( hwndFrame , "ERROR: Cannot write image to BMP file" ,
                  "Cannot open file for writing" ,MB_ICONEXCLAMATION | MB_OK) ;
      free ( bmi ) ;
      free ( pixels ) ;
      end_wait_message () ;
      return 1 ;
      }

   fwrite ( &bmifh , sizeof(BITMAPFILEHEADER) , 1 , fp ) ;
   if (! ferror ( fp ))
      fwrite ( bmi , head_size , 1 , fp ) ;
   if (! ferror ( fp ))
      fwrite ( pixels , img_size , 1 , fp ) ;

   free ( bmi ) ;
   free ( pixels ) ;
   end_wait_message () ;

   if (ferror ( fp )) {
      MessageBox ( hwndFrame , "ERROR: Cannot write image to BMP file" ,
                  "Cannot write file" ,MB_ICONEXCLAMATION | MB_OK) ;
      fclose ( fp ) ;
      return 1 ;
      }

   fclose ( fp ) ;
   return 0 ;
}

/*
--------------------------------------------------------------------------------

   Draw

--------------------------------------------------------------------------------
*/

int Image24::draw ( HWND hwnd , int printing )
{
   dib_image->draw ( hwnd , printing ) ;
   return 0 ;
}
