/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001  Ludvig Strigeus
 *
 * 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.
 *
 * $Header: /cvsroot/scummvm/scummvm/sdl.cpp,v 1.18 2001/11/09 19:08:47 strigeus Exp $
 *
 */

//#define NEED_SDL_HEADERS

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <graphics/displayinfo.h>
#include <graphics/gfx.h>
#include <libraries/asl.h>

#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>

#include <proto/lowlevel.h>
#include <clib/exec_protos.h>
#include <clib/timer_protos.h>
#include <proto/asl.h>
#include <time.h>

#include "stdafx.h"
#include "scumm.h"
#include "gui.h"
#include "sdl.h"        // Include SDL Types...
#include "prefs.h"      // Screenmode Prefs protos
#include "grabscreen.h" // Grabscreen proto
#include "timer.h"
#include <SDL.h>
#include <SDL_timer.h>
#include <SDL_audio.h>

#if defined(USE_IMUSE)
#undef USE_IMUSE
#include "sound.h"
#endif

//#define SCALEUP_2x2

#define ENTER 0x44
#define ESC   0x45
#define PAUSE 0x19
#define RIGHT 0x4E
#define LEFT  0x4F

Scumm scumm;
ScummDebugger debugger;
Gui gui;

#if defined(USE_IMUSE)
SoundEngine sound;
#endif

//static SDL_Surface *screen;
UWORD *BLANKPointer;
static char *screen;
static struct Screen *scr;
static struct Window *win;
struct timerequest *T;

void SDL_Delay2 (Uint32 ms)
{

	if(ms<50)
	{
		clock_t to_wait=clock();

#ifndef __SASC
		ms*=(CLOCKS_PER_SEC/130);
#endif
		to_wait+=ms;

		while(clock()<to_wait);
	}
	else
	{
		Delay(ms/30);
	}
}

void FreeAGAResources(void) {
    printf("Freeing resources...\n");
    SDL_PauseAudio(1);
    Delay(10); // To avoid crashes when some data cannot be found
    SDL_Quit();
    if (T) DeleteTimer(T);
    if (BLANKPointer) FreeVec(BLANKPointer);
    if (screen) free(screen);
    if (win) CloseWindow(win);
    if (scr) CloseScreen(scr);
    }

void AllocAGAResources(void) {
    struct ScreenModeRequester *ScreenRequest;
    uint32 ModeID;
    int a;

    ModeID=readmodeid();   // Tries to read ModeID from file 'ScummAGA.Prefs'

    if (!ModeID)

    if (ScreenRequest=(struct ScreenModeRequester *)AllocAslRequestTags(
                                 ASL_ScreenModeRequest,
                                 ASLSM_TitleText, (ULONG) "Pick 320x200 Screenmode ",
                                 ASLSM_PositiveText, (ULONG) "Ok",
                                 ASLSM_NegativeText, (ULONG) "Cancel",
                                 //ASLSM_InitialInfoOpened, TRUE,
                                 ASLSM_MinWidth, 320,
                                 ASLSM_MinHeight, 200,
                                 ASLSM_MinDepth, 8,
                                 ASLSM_MaxDepth, 8,
                                 TAG_DONE))
	{
    if (!AslRequestTags(ScreenRequest,    ASLSM_TitleText, (ULONG) "Pick 8Bit 320x200 Screenmode ",
                                 ASLSM_PositiveText, (ULONG) "Ok",
                                 ASLSM_NegativeText, (ULONG) "Cancel",
                                 ASLSM_MinWidth, 320,
                                 ASLSM_MinHeight, 200,
                                 ASLSM_MinDepth, 8,
                                 ASLSM_MaxDepth, 8,
                                 TAG_DONE))
        {
        printf("Error: Invalid ScreenMode\n");
        exit(-1);
        } else {
            ModeID=ScreenRequest->sm_DisplayID;
            if (storemodeid(ModeID)) printf("New ModeID saved to 'ScummAGA.Prefs'\n");
                else printf("Warning: Cannot write ModeID to file 'ScummAGA.Prefs'\n");
       }
    }


    printf("Allocating Chunky Buffer...\n");
    screen=(char *)malloc(64000);

    printf("Opening Screen...\n");
    scr = OpenScreenTags(NULL, SA_Depth,8,
                             SA_DisplayID,ModeID, //593920,
                             SA_Type,CUSTOMSCREEN,
                             TAG_END);
  if (scr)
  {
        win = OpenWindowTags(NULL,
                             WA_Flags, WFLG_BORDERLESS|WFLG_ACTIVATE|WFLG_RMBTRAP|WFLG_REPORTMOUSE,
                             WA_IDCMP, IDCMP_RAWKEY|IDCMP_VANILLAKEY|IDCMP_MOUSEMOVE|IDCMP_MOUSEBUTTONS|IDCMP_ACTIVEWINDOW|IDCMP_INACTIVEWINDOW,
                             WA_CustomScreen, (int)scr,
                             //WA_Width,640,
                             //WA_Height,400,
                             TAG_END);
  if (win)
  {
    // Small Tip to Remove Intuition mouse pointer
    if (BLANKPointer=(UWORD *)AllocVec(100,MEMF_CHIP|MEMF_CLEAR))
    {
       if(T=CreateTimer(UNIT_VBLANK))
       {

       SetPointer(win,BLANKPointer,0,0,0,0);
       SetMouseQueue(win, 5);
       ReportMouse(true, win);
       
       SetRGB32(&scr->ViewPort,0,0x00000000,0x00000000,0x00000000);
       /*SetRGB32(&scr->ViewPort,1,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF);
       SetAPen(win->RPort,1);
       WritePixel(win->RPort,319,199);
       */
       }
    }

  }
} else exit(1);


}

void updatePalette(Scumm *s) {

    ULONG colorsAGA[770];

    int first = s->_palDirtyMin;
	int num = s->_palDirtyMax - first + 1;
	int i,j,k;
	byte *data = s->_currentPalette;

	data += first*3;
    j=1+(first*3);k=256;
	for (i=0; i<num; i++,data+=3) {
        colorsAGA[j] = (data[0]<<2)<<24;
		colorsAGA[j+1] = (data[1]<<2)<<24;
		colorsAGA[j+2] = (data[2]<<2)<<24;
		//colors[i].unused = 0;
        if (first!=0)
        {
        SetRGB32(&scr->ViewPort,first+i,colorsAGA[j],colorsAGA[j+1],colorsAGA[j+2]);
        }
        j+=3;
    }
    // Terminator: NEEDED
    //if (first!=0) {
        colorsAGA[0]=num<<16;
        colorsAGA[((num*3)+1)]=0x00000000;
    // Conversion de la palette 8Bits en palette 32Bits pour LoadRGB32()
    if (first==0)
        LoadRGB32(&scr->ViewPort,colorsAGA);

	s->_palDirtyMax = -1;
	s->_palDirtyMin = 0x3E8;
}

/* void updatePalette(Scumm *s) {
	SDL_Color colors[256];
	int first = s->_palDirtyMin;
	int num = s->_palDirtyMax - first + 1;
	int i;
	byte *data = s->_currentPalette;

	data += first*3;
	for (i=0; i<num; i++,data+= 3) {
		colors[i].r = data[0]<<2;
		colors[i].g = data[1]<<2;
		colors[i].b = data[2]<<2;
		colors[i].unused = 0;
	}
	
	SDL_SetColors(screen, colors, first, num);
	
	s->_palDirtyMax = -1;
	s->_palDirtyMin = 0x3E8;
}
*/

int mapKey(int key, byte mod) {
	/*
    if (key>=SDLK_F1 && key<=SDLK_F9) {
		return key - SDLK_F1 + 315;
	} else if (key>='a' && key<='z' && mod&KMOD_SHIFT) {
		key&=~0x20;
	} else if (key>=SDLK_NUMLOCK && key<=SDLK_EURO)
		return 0;
	return key;
    */
    return 0;
}

/*int mapKey(int key, byte mod) {
	if (key>=SDLK_F1 && key<=SDLK_F9) {
		return key - SDLK_F1 + 315;
	} else if (key>='a' && key<='z' && mod&KMOD_SHIFT) {
		key&=~0x20;
	} else if (key>=SDLK_NUMLOCK && key<=SDLK_EURO)
		return 0;
	return key;
}
*/

void waitForTimer(Scumm *s)
{
	//SDL_Event event;
	byte dontPause = true;
	
    WORD mx, my;
    int key;
    struct IntuiMessage *msg;

    do
    {
       //s->_rightBtnPressed |= 0;
       //s->_leftBtnPressed |= 0;
       while (msg = (struct IntuiMessage *)GetMsg(win->UserPort))
       {
           mx = msg->MouseX;
           my = msg->MouseY;
           ReplyMsg((struct Message *)msg);
           //printf("Switch\n");
           switch (msg->Class)
           {
             case IDCMP_VANILLAKEY:

              s->_keyPressed=msg->Code;
              switch(msg->Code)
              {
                case '+':
                    s->_defaultTalkDelay+=30;
                break;
                case '-':
                    s->_defaultTalkDelay-=30;
                    if (s->_defaultTalkDelay<=0) s->_defaultTalkDelay=0;
                break;
              }
              if (msg->Code == 'F')
                 {
                  if (msg->Qualifier&IEQUALIFIER_RSHIFT)
                     printf("FAST\n");
                     s->_fastMode ^= 1;
                 }
               if (msg->Code == 'G')
                 {
                  if (msg->Qualifier&IEQUALIFIER_RSHIFT)
                     printf("SLOW\n");
                     s->_fastMode = false;
                 }
              if ((msg->Code > '0') && (msg->Code <= '9'))
                { s->_saveLoadSlot = msg->Code - '0';
              if (msg->Qualifier&IEQUALIFIER_RSHIFT)
                 {

                        sprintf(s->_saveLoadName, "Quicksave %d", s->_saveLoadSlot);
						//printf("ShiftDROIT+Chiffre => %s\n",s->_saveLoadName);
                        s->_saveLoadFlag = 1;    }
                    else if (msg->Qualifier&=IEQUALIFIER_LSHIFT)
						s->_saveLoadFlag = 2;
					s->_saveLoadCompatible = false;


             }
             break;

             case IDCMP_RAWKEY:
                  // F1 - F9 Pressed
                  key=msg->Code;
                  if ((key >= 0x50) && (key <= 0x58))
                  {
                    switch (key)
                    {
                    	case 0x50:
                            grabscreen();
                        break;

                        case 0x54:
                            s->_keyPressed=0;
                            printf("Warning: F5 may produce an error with some games (ex. Monkey) \n");
                            key+=202;
                            s->_keyPressed=(key-282+315);
                        break;
                    }
                  }
                  else s->_keyPressed=0;


             break;

             case IDCMP_MOUSEMOVE:
                int newx,newy;
                newx=mx;newy=my;
                //printf("MouseMove: mx=%d, my=%d, s->mouse.x=%d, s->mouse.y=%d\n",mx,my,s->mouse.x,s->mouse.y);
                if (newx != s->mouse.x || newy != s->mouse.y)
                 {
					s->mouse.x = newx;
					s->mouse.y = newy;
					s->drawMouse();
					updateScreen(s);
				  }
			 break;

             case IDCMP_ACTIVEWINDOW:
                //printf("Active\n");
                //active=TRUE;
             break;

             case IDCMP_INACTIVEWINDOW:
                //active=FALSE;
                //printf("Inactive\n");
             break;

             case IDCMP_MOUSEBUTTONS:
                if (msg->Code==MENUUP)
                {

                    s->_rightBtnPressed |= 1;
                 }
                 else if (msg->Code==SELECTUP)
					{
                    s->_leftBtnPressed |= 1;}
             break;
           }
       }
		if (!(s->_fastMode&2))
	    AGA_Delay(dontPause ? 25 : 300);
        //SDL_Delay2(dontPause ? 49: 500);
        //Delay(1);
     } while (!dontPause);
}

/*void waitForTimer(Scumm *s) {
	SDL_Event event;
	byte dontPause = true;

	do {
		while (SDL_PollEvent(&event)) {
			switch(event.type) {
			case SDL_KEYDOWN:
				s->_keyPressed = mapKey(event.key.keysym.sym, event.key.keysym.mod);
				if (event.key.keysym.sym >= '0' && event.key.keysym.sym<='9')
                    {
					de 0 à 9: + shift: on sauve...
                    s->_saveLoadSlot = event.key.keysym.sym - '0';
					if (event.key.keysym.mod&KMOD_SHIFT) {
						sprintf(s->_saveLoadName, "Quicksave %d", s->_saveLoadSlot);
						s->_saveLoadFlag = 1;
                        de 0 à 9 + ctrl: on charge/sauve
					} else if (event.key.keysym.mod&KMOD_CTRL)
						s->_saveLoadFlag = 2;
					s->_saveLoadCompatible = false;
				}
                z+ctrl: on quitte
				if (event.key.keysym.sym=='z' && event.key.keysym.mod&KMOD_CTRL) {
					exit(1);
				}
                f+ctrl: fastmode
				if (event.key.keysym.sym=='f' && event.key.keysym.mod&KMOD_CTRL) {
					s->_fastMode ^= 1;
				}
                g+ctrl:fastmode
				if (event.key.keysym.sym=='g' && event.key.keysym.mod&KMOD_CTRL) {
					s->_fastMode ^= 2;
				}
                d+ctrl:debgguer
				if (event.key.keysym.sym=='d' && event.key.keysym.mod&KMOD_CTRL) {
					debugger.attach(s);
				}
                s+ctrl: resource
				if (event.key.keysym.sym=='s' && event.key.keysym.mod&KMOD_CTRL) {
					s->resourceStats();
				}

				break;
			case SDL_MOUSEMOTION: {
				int newx,newy;
#if !defined(SCALEUP_2x2)
				newx = event.motion.x;
				newy = event.motion.y;
#else
				newx = event.motion.x>>1;
				newy = event.motion.y>>1;
#endif
				if (newx != s->mouse.x || newy != s->mouse.y) {
					s->mouse.x = newx;
					s->mouse.y = newy;
					s->drawMouse();
					updateScreen(s);
				}
				break;
				}
			case SDL_MOUSEBUTTONDOWN:
				if (event.button.button==SDL_BUTTON_LEFT)
					s->_leftBtnPressed |= 1;
				else if (event.button.button==SDL_BUTTON_RIGHT)
					s->_rightBtnPressed |= 1;
				break;
#if 0
			case SDL_ACTIVEEVENT:
				if (event.active.state & SDL_APPINPUTFOCUS) {
					dontPause = event.active.gain;
				}
				break;
#endif
			case SDL_QUIT:
				exit(1);
				break;
			}
		}

		if (!(s->_fastMode&2))
			SDL_Delay(dontPause ? 10 : 100);
	} while (!dontPause);

}
*/

#define MAX_DIRTY_RECTS 40
SDL_Rect dirtyRects[MAX_DIRTY_RECTS];
int numDirtyRects;
bool fullRedraw;

int old_mouse_x, old_mouse_y;
int old_mouse_h, old_mouse_w;
bool has_mouse,hide_mouse;

#define BAK_WIDTH 40
#define BAK_HEIGHT 24
byte old_backup[BAK_WIDTH*BAK_HEIGHT*2];


void addDirtyRect(int x, int y, int w, int h) {
	SDL_Rect *r;
	if (numDirtyRects==MAX_DIRTY_RECTS)
		fullRedraw = true;
	else if (!fullRedraw) {
		r = &dirtyRects[numDirtyRects++];
#if defined(SCALEUP_2x2)
		r->x = x*2;
		r->y = y*2;
		r->w = w*2;
		r->h = h*2;
#else
		r->x = x;
		r->y = y;
		r->w = w;
		r->h = h;
#endif
	}
}

void addDirtyRectClipped(int x, int y, int w, int h) {
	if (x<0) { w += x; x=0; }
	if (y<0) { h += y; y=0; }
	if (w >= 320-x) w = 320-x;
	if (h >= 200-y) h = 200-y;
	if (w>0 && h>0)
		addDirtyRect(x,y,w,h);
}

/* Copy part of bitmap */
// AGA version...
void blitToScreen(Scumm *s, byte *src,int x, int y, int w, int h) {
	byte *dst;
	int i;

	hide_mouse = true;
	if (has_mouse) {
		s->drawMouse();
	}

	//if (SDL_LockSurface(screen)==-1)
	//	  error("SDL_LockSurface failed: %s.\n", SDL_GetError());

#if !defined(SCALEUP_2x2)
	// Addresse du pixel en dst
    dst = (byte*)screen + y*320 + x;
	addDirtyRect(x,y,w,h);
	do {
		memcpy(dst, src, w);
		dst += 320;
		src += 320;
	} while (--h);
    // AJOUT
    //WriteChunkyPixels(win->RPort,x,y,x+w,y+h,(UBYTE *)screen+y*320+x,320);
#else
	dst = (byte*)screen + y*640*2 + x*2;
	addDirtyRect(x,y,w,h);		
	do {
		i=0;
		do {
			dst[i*2] = dst[i*2+1] = src[i];
		} while (++i!=w);
		memcpy(dst+640, dst, w*2);
		dst += 640*2;
		src += 320;
	} while (--h);

#endif

	//SDL_UnlockSurface(screen);
}
/*
void blitToScreen(Scumm *s, byte *src,int x, int y, int w, int h) {
	byte *dst;
	int i;

	hide_mouse = true;
	if (has_mouse) {
		s->drawMouse();
	}

	if (SDL_LockSurface(screen)==-1)
		error("SDL_LockSurface failed: %s.\n", SDL_GetError());

#if !defined(SCALEUP_2x2)
	// Addresse du pixel en dst
    dst = (byte*)screen->pixels + y*320 + x;
	addDirtyRect(x,y,w,h);
	do {
		memcpy(dst, src, w);
		dst += 320;
		src += 320;
	} while (--h);
    // AGA WriteChunkyPixels(win->RPort,x,y,x+w,y+h,320);
#else
	dst = (byte*)screen->pixels + y*640*2 + x*2;
	addDirtyRect(x,y,w,h);
	do {
		i=0;
		do {
			dst[i*2] = dst[i*2+1] = src[i];
		} while (++i!=w);
		memcpy(dst+640, dst, w*2);
		dst += 640*2;
		src += 320;
	} while (--h);

#endif

	SDL_UnlockSurface(screen);
}
*/

void updateScreen(Scumm *s) {
    int k;
	if (s->_fastMode&2)
		return;

	if (hide_mouse) {
		hide_mouse = false;
		s->drawMouse();
	}
	
	if(s->_palDirtyMax != -1) {
		updatePalette(s);
	}
	if (fullRedraw) {
		//SDL_UpdateRect(screen, 0,0,0,0);
        WriteChunkyPixels(win->RPort,0,0,319,199,(UBYTE *)screen,320);
#if defined(SHOW_AREA)
		debug(2,"update area 100 %%");
#endif
	} else if (numDirtyRects) {
#if defined(SHOW_AREA)
		int area = 0,i;
		for (i=0; i<numDirtyRects; i++)
			area += (dirtyRects[i].w * dirtyRects[i].h);
		debug(2,"update area %f %%", (float)area/640);
#endif

		// SDL_UpdateRects(screen, numDirtyRects, dirtyRects);
        for (k=0; k<numDirtyRects; k++)
            WriteChunkyPixels(win->RPort,dirtyRects[k].x,dirtyRects[k].y,dirtyRects[k].x+dirtyRects[k].w,dirtyRects[k].y+dirtyRects[k].h,(UBYTE *)screen+(dirtyRects[k].y*320)+(dirtyRects[k].x),320);

	}

	numDirtyRects = 0;
}

/*void updateScreen(Scumm *s) {

	if (s->_fastMode&2)
		return;

	if (hide_mouse) {
		hide_mouse = false;
		s->drawMouse();
	}

	if(s->_palDirtyMax != -1) {
		updatePalette(s);
	}
	if (fullRedraw) {
		SDL_UpdateRect(screen, 0,0,0,0);
#if defined(SHOW_AREA)
		debug(2,"update area 100 %%");
#endif
	} else if (numDirtyRects) {
#if defined(SHOW_AREA)
		int area = 0,i;
		for (i=0; i<numDirtyRects; i++)
			area += (dirtyRects[i].w * dirtyRects[i].h);
		debug(2,"update area %f %%", (float)area/640);
#endif

		SDL_UpdateRects(screen, numDirtyRects, dirtyRects);
	}

	numDirtyRects = 0;
}
*/
void drawMouse(Scumm *s, int xdraw, int ydraw, int w, int h, byte *buf, bool visible) {
	//printf("drawMouse(1)\n");
    int x,y;
	byte *dst,*bak;
	byte color;

	if (hide_mouse)
		visible = false;

	//if (SDL_LockSurface(screen)==-1)
	//	  error("SDL_LockSurface failed: %s.\n", SDL_GetError());

#if defined(SCALEUP_2x2)

	if (has_mouse) {
		dst = (byte*)screen + old_mouse_y*640*2 + old_mouse_x*2;
		bak = old_backup;

		for (y=0; y<old_mouse_h; y++,bak+=BAK_WIDTH*2,dst+=640*2) {
			if ( (uint)(old_mouse_y + y) < 200) {
				for (x=0; x<old_mouse_w; x++) {
					if ((uint)(old_mouse_x + x) < 320) {
						dst[x*2+640] = dst[x*2] = bak[x*2];
						dst[x*2+640+1] = dst[x*2+1] = bak[x*2+1];
					}
				}
			}
		}
	}

	if (visible) {
		dst = (byte*)screen + ydraw*640*2 + xdraw*2;
		bak = old_backup;

		for (y=0; y<h; y++,dst+=640*2,bak+=BAK_WIDTH*2,buf+=w) {
			if ((uint)(ydraw+y)<200) {
				for (x=0; x<w; x++) {
					if ((uint)(xdraw+x)<320) {
						bak[x*2] = dst[x*2];
						bak[x*2+1] = dst[x*2+1];
						if ((color=buf[x])!=0xFF) {
							dst[x*2] = color;
							dst[x*2+1] = color;
							dst[x*2+640] = color;
							dst[x*2+1+640] = color;
						}
					}
				}
			}
		}
	}
#else
	if (has_mouse) {
		dst = (byte*)screen + old_mouse_y*320 + old_mouse_x;
		bak = old_backup;

		for (y=0; y<h; y++,bak+=BAK_WIDTH,dst+=320) {
			if ( (uint)(old_mouse_y + y) < 200) {
				for (x=0; x<w; x++) {
					if ((uint)(old_mouse_x + x) < 320) {
						dst[x] = bak[x];
					}
				}
			}
		}
	}
	if (visible) {
		dst = (byte*)screen + ydraw*320 + xdraw;
		bak = old_backup;

		for (y=0; y<h; y++,dst+=320,bak+=BAK_WIDTH,buf+=w) {
			if ((uint)(ydraw+y)<200) {
				for (x=0; x<w; x++) {
					if ((uint)(xdraw+x)<320) {
						bak[x] = dst[x];
						if ((color=buf[x])!=0xFF) {
							dst[x] = color;
						}
					}
				}
			}
		}
	}


#endif	

	//SDL_UnlockSurface(screen);

	if (has_mouse) {
		has_mouse = false;
		addDirtyRectClipped(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h);
	}

	if (visible) {
		has_mouse = true;
		addDirtyRectClipped(xdraw, ydraw, w, h);
		old_mouse_x = xdraw;
		old_mouse_y = ydraw;
		old_mouse_w = w;
		old_mouse_h = h;
	}
}

/*void drawMouse(Scumm *s, int xdraw, int ydraw, int w, int h, byte *buf, bool visible) {
	int x,y;
	byte *dst,*bak;
	byte color;
                           m
	if (hide_mouse)
		visible = false;

	if (SDL_LockSurface(screen)==-1)
		error("SDL_LockSurface failed: %s.\n", SDL_GetError());

#if defined(SCALEUP_2x2)

	if (has_mouse) {
		dst = (byte*)screen->pixels + old_mouse_y*640*2 + old_mouse_x*2;
		bak = old_backup;

		for (y=0; y<old_mouse_h; y++,bak+=BAK_WIDTH*2,dst+=640*2) {
			if ( (uint)(old_mouse_y + y) < 200) {
				for (x=0; x<old_mouse_w; x++) {
					if ((uint)(old_mouse_x + x) < 320) {
						dst[x*2+640] = dst[x*2] = bak[x*2];
						dst[x*2+640+1] = dst[x*2+1] = bak[x*2+1];
					}
				}
			}
		}
	}

	if (visible) {
		dst = (byte*)screen->pixels + ydraw*640*2 + xdraw*2;
		bak = old_backup;

		for (y=0; y<h; y++,dst+=640*2,bak+=BAK_WIDTH*2,buf+=w) {
			if ((uint)(ydraw+y)<200) {
				for (x=0; x<w; x++) {
					if ((uint)(xdraw+x)<320) {
						bak[x*2] = dst[x*2];
						bak[x*2+1] = dst[x*2+1];
						if ((color=buf[x])!=0xFF) {
							dst[x*2] = color;
							dst[x*2+1] = color;
							dst[x*2+640] = color;
							dst[x*2+1+640] = color;
						}
					}
				}
			}
		}
	}
#else
	if (has_mouse) {
		dst = (byte*)screen->pixels + old_mouse_y*320 + old_mouse_x;
		bak = old_backup;

		for (y=0; y<h; y++,bak+=BAK_WIDTH,dst+=320) {
			if ( (uint)(old_mouse_y + y) < 200) {
				for (x=0; x<w; x++) {
					if ((uint)(old_mouse_x + x) < 320) {
						dst[x] = bak[x];
					}
				}
			}
		}
	}
	if (visible) {
		dst = (byte*)screen->pixels + ydraw*320 + xdraw;
		bak = old_backup;

		for (y=0; y<h; y++,dst+=320,bak+=BAK_WIDTH,buf+=w) {
			if ((uint)(ydraw+y)<200) {
				for (x=0; x<w; x++) {
					if ((uint)(xdraw+x)<320) {
						bak[x] = dst[x];
						if ((color=buf[x])!=0xFF) {
							dst[x] = color;
						}
					}
				}
			}
		}
	}


#endif

	SDL_UnlockSurface(screen);

	if (has_mouse) {
		has_mouse = false;
		addDirtyRectClipped(old_mouse_x, old_mouse_y, old_mouse_w, old_mouse_h);
	}

	if (visible) {
		has_mouse = true;
		addDirtyRectClipped(xdraw, ydraw, w, h);
		old_mouse_x = xdraw;
		old_mouse_y = ydraw;
		old_mouse_w = w;
		old_mouse_h = h;
	}
}*/

void drawMouse(Scumm *s, int xdraw, int ydraw, int color, byte *mask, bool visible) {

    int x,y;
	uint32 bits;
	byte *dst,*bak;

	if (hide_mouse)
		visible = false;

	//if (SDL_LockSurface(screen)==-1)
	//	  error("SDL_LockSurface failed: %s.\n", SDL_GetError());

#if defined(SCALEUP_2x2)

	if (has_mouse) {
		dst = (byte*)screen + old_mouse_y*640*2 + old_mouse_x*2;
		bak = old_backup;

		for (y=0; y<16; y++,bak+=48,dst+=640*2) {
			if ( (uint)(old_mouse_y + y) < 200) {
				for (x=0; x<24; x++) {
					if ((uint)(old_mouse_x + x) < 320) {
						dst[x*2+640] = dst[x*2] = bak[x*2];
						dst[x*2+640+1] = dst[x*2+1] = bak[x*2+1];
					}
				}
			}
		}
	}

	if (visible) {
		dst = (byte*)screen + ydraw*640*2 + xdraw*2;
		bak = old_backup;

		for (y=0; y<16; y++,dst+=640*2,bak+=48) {
			bits = mask[3] | (mask[2]<<8) | (mask[1]<<16);
			mask += 4;
			if ((uint)(ydraw+y)<200) {
				for (x=0; x<24; x++,bits<<=1) {
					if ((uint)(xdraw+x)<320) {
						bak[x*2] = dst[x*2];
						bak[x*2+1] = dst[x*2+1];
						if (bits&(1<<23)) {
							dst[x*2] = color;
							dst[x*2+1] = color;
							dst[x*2+640] = color;
							dst[x*2+1+640] = color;
						}
					}
				}
			}
		}
	}
#else
	if (has_mouse) {
		dst = (byte*)screen + old_mouse_y*320 + old_mouse_x;
		bak = old_backup;

		for (y=0; y<16; y++,bak+=24,dst+=320) {
			if ( (uint)(old_mouse_y + y) < 200) {
				for (x=0; x<24; x++) {
					if ((uint)(old_mouse_x + x) < 320) {
						dst[x] = bak[x];
					}
				}
			}
		}
	}
	if (visible) {
		dst = (byte*)screen + ydraw*320 + xdraw;
		bak = old_backup;

		for (y=0; y<16; y++,dst+=320,bak+=24) {
			bits = mask[3] | (mask[2]<<8) | (mask[1]<<16);
			mask += 4;
			if ((uint)(ydraw+y)<200) {
				for (x=0; x<24; x++,bits<<=1) {
					if ((uint)(xdraw+x)<320) {
						bak[x] = dst[x];
						if (bits&(1<<23)) {
							dst[x] = color;
						}
					}
				}
			}
		}
	}


#endif	

	//SDL_UnlockSurface(screen);

	if (has_mouse) {
		has_mouse = false;
		addDirtyRectClipped(old_mouse_x, old_mouse_y, 24, 16);
	}

	if (visible) {
		has_mouse = true;
		addDirtyRectClipped(xdraw, ydraw, 24, 16);
		old_mouse_x = xdraw;
		old_mouse_y = ydraw;
	}

}

/*void drawMouse(Scumm *s, int xdraw, int ydraw, int color, byte *mask, bool visible) {
	int x,y;
	uint32 bits;
	byte *dst,*bak;

	if (hide_mouse)
		visible = false;

	if (SDL_LockSurface(screen)==-1)
		error("SDL_LockSurface failed: %s.\n", SDL_GetError());

#if defined(SCALEUP_2x2)

	if (has_mouse) {
		dst = (byte*)screen->pixels + old_mouse_y*640*2 + old_mouse_x*2;
		bak = old_backup;

		for (y=0; y<16; y++,bak+=48,dst+=640*2) {
			if ( (uint)(old_mouse_y + y) < 200) {
				for (x=0; x<24; x++) {
					if ((uint)(old_mouse_x + x) < 320) {
						dst[x*2+640] = dst[x*2] = bak[x*2];
						dst[x*2+640+1] = dst[x*2+1] = bak[x*2+1];
					}
				}
			}
		}
	}

	if (visible) {
		dst = (byte*)screen->pixels + ydraw*640*2 + xdraw*2;
		bak = old_backup;

		for (y=0; y<16; y++,dst+=640*2,bak+=48) {
			bits = mask[3] | (mask[2]<<8) | (mask[1]<<16);
			mask += 4;
			if ((uint)(ydraw+y)<200) {
				for (x=0; x<24; x++,bits<<=1) {
					if ((uint)(xdraw+x)<320) {
						bak[x*2] = dst[x*2];
						bak[x*2+1] = dst[x*2+1];
						if (bits&(1<<23)) {
							dst[x*2] = color;
							dst[x*2+1] = color;
							dst[x*2+640] = color;
							dst[x*2+1+640] = color;
						}
					}
				}
			}
		}
	}
#else
	if (has_mouse) {
		dst = (byte*)screen->pixels + old_mouse_y*320 + old_mouse_x;
		bak = old_backup;

		for (y=0; y<16; y++,bak+=24,dst+=320) {
			if ( (uint)(old_mouse_y + y) < 200) {
				for (x=0; x<24; x++) {
					if ((uint)(old_mouse_x + x) < 320) {
						dst[x] = bak[x];
					}
				}
			}
		}
	}
	if (visible) {
		dst = (byte*)screen->pixels + ydraw*320 + xdraw;
		bak = old_backup;

		for (y=0; y<16; y++,dst+=320,bak+=24) {
			bits = mask[3] | (mask[2]<<8) | (mask[1]<<16);
			mask += 4;
			if ((uint)(ydraw+y)<200) {
				for (x=0; x<24; x++,bits<<=1) {
					if ((uint)(xdraw+x)<320) {
						bak[x] = dst[x];
						if (bits&(1<<23)) {
							dst[x] = color;
						}
					}
				}
			}
		}
	}


#endif

	SDL_UnlockSurface(screen);

	if (has_mouse) {
		has_mouse = false;
		addDirtyRectClipped(old_mouse_x, old_mouse_y, 24, 16);
	}

	if (visible) {
		has_mouse = true;
		addDirtyRectClipped(xdraw, ydraw, 24, 16);
		old_mouse_x = xdraw;
		old_mouse_y = ydraw;
	}

}*/

#define SAMPLES_PER_SEC 22050
#define BUFFER_SIZE (8192)
#define BITS_PER_SAMPLE 16

struct MixerChannel {
	void *_sfx_sound;
	uint32 _sfx_pos;
	uint32 _sfx_size;
	uint32 _sfx_fp_speed;
	uint32 _sfx_fp_pos;

	void mix(int16 *data, uint32 len);
	void clear();
};

#define NUM_MIXER 4

static MixerChannel mixer_channel[NUM_MIXER];

/*
MixerChannel *find_channel() {
	printf("find_channel()\n");

    int i;
	MixerChannel *mc = mixer_channel;
	for(i=0; i<NUM_MIXER; i++,mc++) {
		if (!mc->_sfx_sound)
			return mc;
	}

	return NULL;
}*/

MixerChannel *find_channel() {
	int i;
	MixerChannel *mc;
    if (scumm.sound)
        {
    mc = mixer_channel;
	for(i=0; i<NUM_MIXER; i++,mc++) {
		if (!mc->_sfx_sound)
			return mc;
	}
    }
	return NULL;
}

/*
bool isSfxFinished() {
    printf("isSfxFinished()\n");

	int i;
	for(i=0; i<NUM_MIXER; i++)
		if (mixer_channel[i]._sfx_sound)
			return false;

    return true;
}   */

bool isSfxFinished() {
	int i;
	if (scumm.sound)
        {
    for(i=0; i<NUM_MIXER; i++)
		if (mixer_channel[i]._sfx_sound)
			return false;
	  }
    return true;
}
/*
void playSfxSound(void *sound, uint32 size, uint rate) {
printf("playSfxSound()\n");

    MixerChannel *mc = find_channel();

	if (!mc) {
		warning("No mixer channel available");
		return;
	}

	mc->_sfx_sound = sound;
	mc->_sfx_pos = 0;
	mc->_sfx_fp_speed = (1<<16) * rate / 22050;
	mc->_sfx_fp_pos = 0;

	while (size&0xFFFF0000) size>>=1, rate>>=1;
	mc->_sfx_size = size * 22050 / rate;

}*/

void playSfxSound(void *sound, uint32 size, uint rate) {
	MixerChannel *mc;
    if (scumm.sound)
    {
    mc = find_channel();

	if (!mc) {
		warning("No mixer channel available");
		return;
	 }

	mc->_sfx_sound = sound;
	mc->_sfx_pos = 0;
	mc->_sfx_fp_speed = (1<<16) * rate / 22050;
	mc->_sfx_fp_pos = 0;

	while (size&0xFFFF0000) size>>=1, rate>>=1;
	mc->_sfx_size = size * 22050 / rate;
   }
}

/*
void MixerChannel::mix(int16 *data, uint32 len) {
	printf("MixerChannel::mix()\n");
    int8 *s;
	int i;
	uint32 fp_pos, fp_speed;

	if (!_sfx_sound)
		return;
	if (len > _sfx_size)
		len = _sfx_size;
	_sfx_size -= len;

	s = (int8*)_sfx_sound + _sfx_pos;
	fp_pos = _sfx_fp_pos;
	fp_speed = _sfx_fp_speed;

	do {
		fp_pos += fp_speed;
		*data++ += (*s<<6);
		s += fp_pos >> 16;
		fp_pos &= 0x0000FFFF;
	} while (--len);

	_sfx_pos = s - (int8*)_sfx_sound;
	_sfx_fp_speed = fp_speed;
	_sfx_fp_pos = fp_pos;

	if (!_sfx_size)
		clear();

}*/

void MixerChannel::mix(int16 *data, uint32 len) {
	int8 *s;
	int i;
	uint32 fp_pos, fp_speed;

 if (scumm.sound)
  {
	if (!_sfx_sound)
		return;
	if (len > _sfx_size)
		len = _sfx_size;
	_sfx_size -= len;

	s = (int8*)_sfx_sound + _sfx_pos;
	fp_pos = _sfx_fp_pos;
	fp_speed = _sfx_fp_speed;

	do {
		fp_pos += fp_speed;
		*data++ += (*s<<6);
		s += fp_pos >> 16;
		fp_pos &= 0x0000FFFF;
	} while (--len);

	_sfx_pos = s - (int8*)_sfx_sound;
	_sfx_fp_speed = fp_speed;
	_sfx_fp_pos = fp_pos;

	if (!_sfx_size)
		clear();
     }
}

/*void MixerChannel::clear() {
printf("MixerChannel::clear()\n");
    free(_sfx_sound);
	_sfx_sound = NULL;

}*/

void MixerChannel::clear() {
	if (scumm.sound)
      {
    free(_sfx_sound);
	_sfx_sound = NULL;
      }
}

/*void fill_sound(void *userdata, Uint8 *stream, int len) {
printf("fill_sound()\n");
    int i;

#if defined(USE_IMUSE)
	sound.generate_samples((int16*)stream, len>>1);
#else
	memset(stream, 0, len);
#endif
	
	for(i=NUM_MIXER-1; i>=0;i--) {
		mixer_channel[i].mix((int16*)stream, len>>1);
	}

}*/

void fill_sound(void *userdata, Uint8 *stream, int len)
{
   int i;
   if (scumm.sound)
    {

#if defined(USE_IMUSE)
	sound.generate_samples((int16*)stream, len>>1);
#else
	memset(stream, 0, len);
#endif

	for(i=NUM_MIXER-1; i>=0;i--)
    {
		mixer_channel[i].mix((int16*)stream, len>>1);
	}
  }
}

void initGraphics(Scumm *s, bool fullScreen)
{

    SDL_AudioSpec desired;

    printf("ScummAGA v0.38 (based on ScummVM 0.3 alpha)\n");

    if (scumm.sound)
        {
        if (SDL_Init(SDL_INIT_AUDIO)==-1)
            {
		error("Could not initialize SDL: %s.\n", SDL_GetError());
	    exit(1);
	        }
        }

    // Alloc Intuition Screen/Window and Chunky Buffer
    AllocAGAResources();

	/* Clean up on exit */
 	atexit(FreeAGAResources);
    //if (scumm.sound) atexit(SDL_Quit);

	char buf[512], *gameName;

	sprintf(buf, "ScummVM - %s", gameName = s->getGameName());
	free(gameName);

    if (scumm.sound)
    {
	desired.freq = SAMPLES_PER_SEC;
	desired.format = AUDIO_S16SYS;
	desired.channels = 1;
	desired.samples = 2048;
	desired.callback = fill_sound;
	SDL_OpenAudio(&desired, NULL);
	SDL_PauseAudio(0);
    }

	/*SDL_WM_SetCaption(buf,buf);
	SDL_ShowCursor(SDL_DISABLE);
    */

/*#if !defined(SCALEUP_2x2)
	screen = SDL_SetVideoMode(320, 200, 8, fullScreen ? (SDL_SWSURFACE | SDL_FULLSCREEN) : SDL_SWSURFACE);
#else
	screen = SDL_SetVideoMode(640, 400, 8, fullScreen ? (SDL_SWSURFACE | SDL_FULLSCREEN) : SDL_SWSURFACE);
#endif
*/
	printf("%d %d, %d %d, %d %d %d, %d %d %d %d %d\n",
		sizeof(int8), sizeof(uint8),
		sizeof(int16), sizeof(uint16),
		sizeof(int32), sizeof(uint32),
		sizeof(void*),
		sizeof(Box), sizeof(MouseCursor),sizeof(CodeHeader),
		sizeof(ImageHeader),
		sizeof(Scumm)
	);
   //Delay(200);
}

/*void initGraphics(Scumm *s, bool fullScreen) {
	SDL_AudioSpec desired;

	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)==-1) {
		error("Could not initialize SDL: %s.\n", SDL_GetError());
	    exit(1);
	}

 	atexit(SDL_Quit);

	char buf[512], *gameName;
	
	sprintf(buf, "ScummVM - %s", gameName = s->getGameName());
	free(gameName);

	desired.freq = SAMPLES_PER_SEC;
	desired.format = AUDIO_S16SYS;
	desired.channels = 1;
	desired.samples = 2048;
	desired.callback = fill_sound;
	SDL_OpenAudio(&desired, NULL);
	SDL_PauseAudio(0);


	SDL_WM_SetCaption(buf,buf);
	SDL_ShowCursor(SDL_DISABLE);

#if !defined(SCALEUP_2x2)
	screen = SDL_SetVideoMode(320, 200, 8, fullScreen ? (SDL_SWSURFACE | SDL_FULLSCREEN) : SDL_SWSURFACE);
#else
	screen = SDL_SetVideoMode(640, 400, 8, fullScreen ? (SDL_SWSURFACE | SDL_FULLSCREEN) : SDL_SWSURFACE);
#endif

	printf("%d %d, %d %d, %d %d %d, %d %d %d %d %d\n", 
		sizeof(int8), sizeof(uint8),
		sizeof(int16), sizeof(uint16),
		sizeof(int32), sizeof(uint32),
		sizeof(void*),
		sizeof(Box), sizeof(MouseCursor),sizeof(CodeHeader),
		sizeof(ImageHeader),
		sizeof(Scumm)
	);
}
*/
#undef main

int main(int argc, char* argv[]) {
	int delta,tmp;
    ULONG keypressed;


if (scumm.sound) {
#if defined(USE_IMUSE)
	sound.initialize(NULL);
	scumm._soundDriver = &sound;
#endif
  }
    // FASTMODE !!
    //scumm._fastMode=true;

	scumm._gui = &gui;
	scumm.scummMain(argc, argv);

	gui.init(&scumm);

	delta = 0;
	do {
		updateScreen(&scumm);

		if (gui._active) {
			gui.loop();
			tmp = 5;
		} else {
			tmp = delta = scumm.scummLoop(delta);
			tmp += tmp>>1;
			
			if (scumm._fastMode)
				tmp=1;
		}
		
		while(tmp>0) {
			waitForTimer(&scumm);
			tmp--;
		}

        keypressed=GetKey();

	} while(keypressed!=0x59); // While(1);

    
    //SDL_Quit();
    // FreeAGAResources();
    /*
    tt=GetKey();
    switch (tt)
    {
       case ESC:
        printf("Esc pressed...\n");
        break;
    }
    */
    //if (scumm.sound) SDL_Quit();
    printf("Normal Exit\n");
	return 0;
}
