/*
 * Stonage: a puzzle game
 * Copyright (C) 2001 Luc Saillard <luc@saillard.org>
 *
 * Routine to manage screen (fade, copy, ... )
 * 
 * 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 "stonage.h"

#include <SDL/SDL.h>
#if defined(HAVE_SDL_SDL_IMAGE_H)
#include <SDL/SDL_image.h>
#endif
#include <stdlib.h>

#include "image.h"

static void Screen_Fade_Warp(SDL_Surface *current, SDL_Surface *after, int effect);
static void Screen_Fade_Box(SDL_Surface *current, SDL_Surface *after, int effect);

/* If this flag is true, do not animate transition background */
int noanimation=0;

/**
 *
 * Realize a fade between the current screen to give after some animation
 * the new screen.
 * Content from after is copied to current
 *
 */
void
Screen_Fade(SDL_Surface *current, SDL_Surface *after)
{
  SDL_Event   events;
  int effect;

  /* Flush the event queue */
  while (SDL_PollEvent(&events))
    ;

  if (noanimation)
   {
     SDL_BlitSurface(after, NULL, current, NULL);
     SDL_Flip(current);
     return;
   }
  
  /* IMPORTANT: When we add a new effect, we need to modify this number */
  effect = RANDOM()%7;
  switch(effect)
   {
    case 0:
    case 1:
      Screen_Fade_Warp(current,after,effect);
      break;
    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
      Screen_Fade_Box(current,after,effect-2);
      break;
   }
}

static char *file_warp[]=
{
  "images/warp1.png",
  "images/warp2.png",
};


static void
Screen_Fade_Warp(SDL_Surface *current, SDL_Surface *after, int file_warp_to_use)
{
  SDL_Surface *warp;
  SDL_Event   events;
  int time=1000;
  int start_time, current_time, time_elapsed;
  int level;
  int i;
  unsigned char *pwarp;

  /* Load the warp screen data */
  warp = Image_Load(file_warp[file_warp_to_use],0);
  if (warp==NULL)
    return;

  /* Scale the warp screen to after, current size */
#if ENABLE_DEBUG
  if (warp->w != after->w || warp->h != after->h)
   {
     SDL_Surface *w2;

     w2 = SDL_CreateRGBSurface(SDL_SWSURFACE, after->w, after->h,8,0,0,0,0);
     fprintf(stderr,"Scale the warp screen to after, current size Not implemented ");
   }
#endif

  /* Current and after must have the same pixel format */
#if ENABLE_DEBUG
  if (after->format->BytesPerPixel != current->format->BytesPerPixel)
   {
     fprintf(stderr,"Please correct your source code.Screen_Fade need to surface with the same pixel format.");
     after = SDL_DisplayFormat(after);
   }
#endif

  start_time=SDL_GetTicks();
  do
   {
     current_time=SDL_GetTicks();
     time_elapsed = current_time-start_time;

     level = 255 * time_elapsed / time;
     pwarp = (unsigned char *)warp->pixels;

     SDL_LockSurface(current);

     switch (after->format->BytesPerPixel)
      {
       case 1:
	  {
	    uint8 *p1 = after->pixels;
	    uint8 *p2 = current->pixels;
	    for (i=0 ;i < (after->w * after->h) ; i++, p1++, p2++, pwarp++)
	     {
	       if (*pwarp < level )
		 *p2 = *p1;
	     }
	    break;
	  }
       case 2:
	  {
	    uint16 *p1 = after->pixels;
	    uint16 *p2 = current->pixels;
	    for (i=0 ;i < (after->w * after->h) ; i++, p1++, p2++, pwarp++)
	     {
	       if (*pwarp < level )
		 *p2 = *p1;
	     }
	    break;
	  }
       case 3:
	  {
	    unsigned char *p1 = after->pixels;
	    unsigned char *p2 = current->pixels;
	    for (i=0 ;i < (after->w * after->h) ; i++, pwarp++)
	     {
	       if (*pwarp < level )
		{
		  *p2++ = *p1++;
		  *p2++ = *p1++;
		  *p2++ = *p1++;
		}
	       else
		{
		  p1+=3;
		  p2+=3;
		}
	     }
	    break;
	  }
       case 4:
	  {
	    uint32 *p1 = after->pixels;
	    uint32 *p2 = current->pixels;
	    for (i=0 ;i < (after->w * after->h) ; i++, p1++, p2++, pwarp++)
	     {
	       if (*pwarp < level )
		 *p2 = *p1;
	     }
	    break;
	  }
       default:
	 fprintf(stderr,_("Depth of this screen isn't supported\n"));
	 break;
      }
     SDL_UnlockSurface(current);
     SDL_Flip(current);

     /* If the user close the window, or press a key get out from this fading */
     SDL_PumpEvents();
     if (SDL_PeepEvents(&events,1,SDL_PEEKEVENT,SDL_QUIT|SDL_KEYUP|SDL_MOUSEBUTTONUP)==1)
       break;

   } while (time_elapsed < time && level<256);

  /* Draw entire after screen */
  SDL_BlitSurface(after, NULL, current, NULL);
  SDL_Flip(current);

  SDL_FreeSurface(warp);

  while (SDL_PollEvent(&events))
    ;
}



static void
Screen_Fade_Box(SDL_Surface *current, SDL_Surface *after, int effect_to_use)
{
  int step=0;
  int x,y;

  int box_height, box_width, box_height_step;
  int box_y;
  int speed;
  SDL_Rect box_rect;
  SDL_Event   events;
  int start_time, current_time;

  switch(effect_to_use)
   {
    case 0:
      box_width=64;
      box_height=16;
      speed=25;
      break;
    case 1:
      box_width=after->w;
      box_height=16;
      speed=25;
      break;
    case 2:
      box_width=32;
      box_height=48;
      speed=15;
      break;
    case 3:
      box_width=after->w/2;
      box_height=32;
      speed=15;
      break;
    default:
      box_width=32;
      box_height=32;
      speed=15;
      break;
   }

  box_height_step=1;
  start_time=SDL_GetTicks();
  while (step<2) 
   {
     box_y=0;
     if (step==0)
      {
	for (y=0;y<after->h;y++)
	 {
	   for (x=0;x<after->w;x+=box_width*2)
	    {
	      box_rect.x=x;
	      box_rect.y=box_y;
	      box_rect.w=box_width;
	      box_rect.h=box_height_step;
	      SDL_BlitSurface(after,&box_rect,current,&box_rect);
	    }
	   box_y+=box_height;
	 }
      }
     else
      {
	for (y=0;y<after->h;y++)
	 {
	   for (x=box_width;x<after->w;x+=box_width*2)
	    {
	      box_rect.x=x;
	      box_rect.y=box_y;
	      if (x+box_width>after->w)
		box_rect.w=after->w;
	      else
		box_rect.w=x+box_width;
	      box_rect.h=box_height_step;
	      SDL_BlitSurface(after,&box_rect,current,&box_rect);
	    }
	   box_y+=box_height;
	 }
      }
     SDL_Flip(current);
     
     current_time=SDL_GetTicks();
     if (current_time - start_time > speed)
      {
	start_time=SDL_GetTicks();
	box_height_step++;
	if (box_height_step>box_height)
	 {
	   step++;
	   box_height_step=1;
	 }
      }

     SDL_PumpEvents();
     if (SDL_PeepEvents(&events,1,SDL_PEEKEVENT,SDL_QUIT|SDL_KEYUP|SDL_MOUSEBUTTONUP)==1)
	break;
   }

  /* Draw entire after screen */
  SDL_BlitSurface(after, NULL, current, NULL);
  SDL_Flip(current);

  while (SDL_PollEvent(&events))
    ;
}

