/***********************************************************************/
/*                                                                     */
/* Project      : GRAV                                                 */
/* Current Rel. : 3.1                                                  */
/* Creator      : Michael Knigge                                       */
/* Creation Date: 03/13/95                                             */
/* Description  : some effects (fade in/out etc.)                      */
/*                                                                     */
/* Functions    : grav_fade_out()                                      */
/*                grav_fade_in()                                       */
/*                grav_rotate_palette()                                */
/*                grav_invert()                                        */
/*                grav_invert_24bit()                                  */
/*                grav_mirror_image()                                  */
/*                grav_flip_image()                                    */
/*                grav_to_grey()                                       */
/*                grav_scale()                                         */
/*                                                                     */
/***********************************************************************/

#include <stdio.h>
#include <malloc.h>
#include <ncurses.h>
#include "standard.h"
#include "defines.h"
#include "gbm.h"
#include "gbmmir.h"
#include "gbmscale.h"
#include "effects.h"

int grav_fade_out(GBM *gbm, GBMRGB gbmrgb[])
{
   int    local;
   int    done;
   GBMRGB work_rgb[0x100];
   
   if (gbm->bpp > 8)
      return(FALSE);
   
   /*
    * first store the current palette in work_rgb...
    */
   for (local=0; local<256; local++)
   {
      work_rgb[local].r = gbmrgb[local].r / 4;
      work_rgb[local].g = gbmrgb[local].g / 4;
      work_rgb[local].b = gbmrgb[local].b / 4;
   }

   do
   {
      done = TRUE;
      
      for (local=0; local<256; local++)
      {
         if (work_rgb[local].r != 0)
         {
            work_rgb[local].r--;
            done = FALSE;
         }
         
         if (work_rgb[local].g != 0)
         {
            work_rgb[local].g--;
            done = FALSE;
         }

         if (work_rgb[local].b != 0)
         {
            work_rgb[local].b--;
            done = FALSE;
         }

         vga_setpalette(local,
                        work_rgb[local].r,
                        work_rgb[local].g,
                        work_rgb[local].b);      
      }
   }
   while(done != TRUE);

   return(TRUE);
}

int grav_fade_in(GBM *gbm, GBMRGB gbmrgb[])
{
   int    local;
   int    done;
   GBMRGB work_rgb[0x100];

   if (gbm->bpp > 8)
      return(FALSE);

   /*
    * first initialize the work-palette...
    */
   for (local=0; local<256; local++)
   {
      work_rgb[local].r = 0;
      work_rgb[local].g = 0;
      work_rgb[local].b = 0;
   }
   
   /*
    * now do the fade-in....
    */
   do
   {
      done = TRUE;
      
      for (local=0; local<256; local++)
      {
         if (work_rgb[local].r != gbmrgb[local].r / 4)
         {
            work_rgb[local].r++;
            done = FALSE;
         }
         
         if (work_rgb[local].g != gbmrgb[local].g / 4)
         {
            work_rgb[local].g++;
            done = FALSE;
         }

         if (work_rgb[local].b != gbmrgb[local].b / 4)
         {
            work_rgb[local].b++;
            done = FALSE;
         }

         vga_setpalette(local,
                        work_rgb[local].r,
                        work_rgb[local].g,
                        work_rgb[local].b);
      }
   }
   while(done != TRUE);

   return(TRUE);
}

int grav_rotate_palette(GBM *gbm, GBMRGB gbmrgb[], int colors)
{
   int local;
   GBMRGB tmp_rgb;

   
   if (gbm->bpp > 8)
      return(FALSE);

   colors--;

   /*
    * save the first entry
    */
   tmp_rgb.r = gbmrgb[0].r;
   tmp_rgb.g = gbmrgb[0].g;   
   tmp_rgb.b = gbmrgb[0].b;      


   for(local=0; local<colors; local++)
   {
      gbmrgb[local].r = gbmrgb[local+1].r;
      gbmrgb[local].g = gbmrgb[local+1].g;
      gbmrgb[local].b = gbmrgb[local+1].b;
   }
   
   gbmrgb[colors].r = tmp_rgb.r;
   gbmrgb[colors].g = tmp_rgb.g;
   gbmrgb[colors].b = tmp_rgb.b;

   return(TRUE);
}


int grav_invert(char *bitmap, GBM *gbm, GBMRGB gbmrgb[])
{
   int local;
   
    
   if (gbm->bpp == 24)
      return(grav_invert_24bit(bitmap, gbm, gbmrgb));
      
   for (local=0; local<256; local++)
   {
      gbmrgb[local].r = 255 - gbmrgb[local].r;
      gbmrgb[local].g = 255 - gbmrgb[local].g;
      gbmrgb[local].b = 255 - gbmrgb[local].b;
   }

   return(TRUE);
}

int grav_invert_24bit(char *bitmap, GBM *gbm, GBMRGB gbmrgb[])
{
   int local;
   int max;
   int width;
   
   unsigned char *work_bitmap;

   
   width       = grav_get_bitmap_width(gbm);
   work_bitmap = bitmap;
   max         = gbm->h * width;


   for (local=0; local<max; local++)
   {
      work_bitmap[0] = 255 - work_bitmap[0];
      work_bitmap++;
   }
   
   return(TRUE);
}


int grav_mirror_image(GBM *gbm, char *bitmap)
{
   if ( gbm_ref_vert(gbm, bitmap))
      return(GRAV_ERROR_MIRROR);
   else
      return(GRAV_NO_ERROR);
}                           


int grav_flip_image(GBM *gbm, char *bitmap)
{
   if ( gbm_ref_horz(gbm, bitmap))
      return(GRAV_ERROR_FLIP);
   else
      return(GRAV_NO_ERROR);
}                           


char *grav_to_grey(char *bitmap, GBM *gbm, GBMRGB gbmrgb[])
{
   int  col;
   int  line;
   int  index;
   int  width;

   unsigned char *work_bitmap;

   unsigned short red;
   unsigned short green;
   unsigned short blue;
   unsigned char  new_value;
   unsigned int   local;


   /*
    * get bitmap-width and store bitmap-pointer in work_bitmap
    */
    
   width       = grav_get_bitmap_width(gbm);
   work_bitmap = bitmap;

   /*
    * do the work....
    */
    
   for (line=0; line<gbm->h; line++)
   {
      local = 0;
      
      for (col=0; col<gbm->w; col++)
      {
         if (gbm->bpp == 8)
         {
            index = work_bitmap[col];
            red   = gbmrgb[index].r / 4;
            green = gbmrgb[index].g / 4;
            blue  = gbmrgb[index].b / 4;
         }
         else
         {
            red   = work_bitmap[local];
            blue  = work_bitmap[local+1];
            green = work_bitmap[local+2];
         }
         
         /*
          * calculate the new value...
          */

         new_value = ((red * 77) + (green * 15) + (blue * 28)) >> 8;
         
         if (gbm->bpp == 8)
         {
            work_bitmap[col] = new_value;
         }
         else
         {
            work_bitmap[local]   = new_value;
            work_bitmap[local+1] = new_value;
            work_bitmap[local+2] = new_value;
            local                = local + 3;
         }
      }
      work_bitmap = work_bitmap + width;
   }

   /*
    * store the new palette for 8bit pictures...
    */
    
   if (gbm->bpp == 8)
   {
      for(local=0; local<0x100; local++)
      {
         gbmrgb[local].r = local * 4;
         gbmrgb[local].g = local * 4;
         gbmrgb[local].b = local * 4;
      }
   }

   return(bitmap);
}

char *grav_scale(int *error_id, char *bitmap, GBM *gbm, int width, int height)
{
   long new_bitmap_size;
   char *new_bitmap;

  /*
   * calculate size of new bitmap...
   */
   new_bitmap_size = height * (((width * gbm->bpp + 31) / 32) * 4);

   /*
    * request memory for new bitmap
    */
   if ((new_bitmap = malloc((int) new_bitmap_size)) == NULL)
   {
      *error_id = GRAV_ERROR_ALLOC;
      return(NULL);
   }  
   
   /*
    * initialize the bitmap
    */
   memset(new_bitmap, 0, new_bitmap_size);

   if (gbm_simple_scale(bitmap, gbm->w, gbm->h, new_bitmap, width, height, gbm->bpp) != GBM_ERR_OK)
   {
      *error_id = GRAV_ERROR_SCALE;
      return(NULL);
   }

   gbm->w    = width;
   gbm->h    = height;
   *error_id = GRAV_NO_ERROR;
   
   return(new_bitmap);
}
