/* 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/windows.cpp,v 1.24 2001/12/28 15:26:28 strigeus Exp $
 */

/*
   (Very ugly) DirectX additions by Gregory Montoir (cyx@frenchkiss.net)
   The scrolling window seems not correct (bounds are out of the screen)... i'll see...
   2002.02.12
 */

#include <windows.h>
#include <windowsx.h>

#include "stdafx.h"
#include <assert.h>

#include "scumm.h"
#include "sound.h"
#include "gui.h"

#if !defined(ALLOW_GDI)
#error The GDI driver is not as complete as the SDL driver. You need to define ALLOW_GDI to use this driver.
#endif

#define SRC_WIDTH 320
#define SRC_HEIGHT 200
#define SRC_PITCH (320)

#define DEST_WIDTH 320
#define DEST_HEIGHT 200

#define USE_DIRECTX 1
#define USE_DRAWDIB 0
#define USE_GDI 0

#if USE_DIRECTX
#include <ddraw.h>
#endif

#define SAMPLES_PER_SEC 22050
#define BUFFER_SIZE (8192)
#define BITS_PER_SAMPLE 16

//static bool shutdown;


#if USE_GDI
typedef struct DIB {
	HBITMAP hSect;
	byte *buf;
	RGBQUAD *pal;
	bool new_pal;
} DIB;
#endif

class WndMan {
	HMODULE hInst;
	HWND hWnd;


	bool terminated;	

#if USE_DIRECTX
	LPDIRECTDRAW lpdd;
	LPDIRECTDRAWSURFACE lpddsPrimary;
	LPDIRECTDRAWSURFACE lpddsSecondary;
#endif

#if USE_GDI
public:
	DIB dib;
private:
#endif

public:
	byte *_vgabuf;

	Scumm *_scumm;

	HANDLE _event;
	DWORD _threadId;
	HWAVEOUT _handle;
	WAVEHDR _hdr[2];

public:
	void init();

	bool handleMessage();
	void run();
	void setPalette(byte *ctab, int first, int num);
	void writeToScreen();

	void prepare_header(WAVEHDR *wh, int i);
	void sound_init();
	static DWORD _stdcall sound_thread(WndMan *wm);

#if USE_GDI
	bool allocateDIB(int w, int h);
#endif

#if USE_DIRECTX
	byte _realbuf[SRC_WIDTH*SRC_HEIGHT];
	BOOL ddrawInit();
	void ddrawReleaseSurfaces();
	void ddrawRelease();
	void ddrawUpdateBuffer();
#endif
};

#if USE_DIRECTX

static unsigned char GetLowestBit(unsigned long p)
{
  unsigned char pos = 0;
  while((p & 1) == 0) {
	++pos;
	p >>= 1;
  }
  return pos;
}
#endif

void Error(const char *msg) {
	OutputDebugString(msg);
	MessageBoxA(0, msg, "Error", MB_ICONSTOP);
	exit(1);
}

int sel;
Scumm scumm;
ScummDebugger debugger;
Gui gui;
SoundEngine sound;
SOUND_DRIVER_TYPE snd_driv;

WndMan wm[1];
byte veryFastMode;

void modifyslot(int sel, int what);

int mapKey(int key) {
	if (key>=VK_F1 && key<=VK_F9) {
		return key - VK_F1 + 315;
	}
	return key;
}

static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
	WndMan *wm = (WndMan*)GetWindowLong(hWnd, GWL_USERDATA);	
	
	switch (message) 
	{
		case WM_DESTROY:
		case WM_CLOSE:
			exit(0);
			break;

		case WM_KEYDOWN:
			if (wParam>='0' && wParam<='9') {
				wm->_scumm->_saveLoadSlot = wParam - '0';
				if (GetAsyncKeyState(VK_SHIFT)<0) {
					sprintf(wm->_scumm->_saveLoadName, "Quicksave %d", wm->_scumm->_saveLoadSlot);
					wm->_scumm->_saveLoadFlag = 1;
				} else if (GetAsyncKeyState(VK_CONTROL)<0)
					wm->_scumm->_saveLoadFlag = 2;
				wm->_scumm->_saveLoadCompatible = false;
			}

			if (GetAsyncKeyState(VK_CONTROL)<0) {
				if (wParam=='F') {
					wm->_scumm->_fastMode ^= 1;
				}

				if (wParam=='G') {
					veryFastMode ^= 1;
				}

				if (wParam=='D') {
					debugger.attach(wm->_scumm);
				}
				
				if (wParam=='S') {
					wm->_scumm->resourceStats();
				}
			}

			wm->_scumm->_keyPressed = mapKey(wParam);
			break;

		case WM_MOUSEMOVE:
#if USE_DIRECTX
			RECT r;
			GetClientRect(hWnd, &r);
			wm->_scumm->mouse.x = (SRC_WIDTH * ((int16*)&lParam)[0]) / (r.right - r.left);
			wm->_scumm->mouse.y = (SRC_HEIGHT * ((int16*)&lParam)[1]) / (r.bottom - r.top);
#else
			wm->_scumm->mouse.x = ((int16*)&lParam)[0];
			wm->_scumm->mouse.y = ((int16*)&lParam)[1];
#endif
			break;
		case WM_LBUTTONDOWN:
			wm->_scumm->_leftBtnPressed |= msClicked|msDown;
			break;
		case WM_LBUTTONUP:
			wm->_scumm->_leftBtnPressed &= ~msDown;
			break;
		case WM_RBUTTONDOWN:
			wm->_scumm->_rightBtnPressed |= msClicked|msDown;
			break;
		case WM_RBUTTONUP:
			wm->_scumm->_rightBtnPressed &= ~msDown;
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

#if USE_GDI

bool WndMan::allocateDIB(int w, int h) {
	struct {
		BITMAPINFOHEADER bih;
		RGBQUAD rgb[256];
	} d;

	if (dib.hSect)
		return true;

	memset(&d.bih, 0, sizeof(d.bih));
	d.bih.biSize = sizeof(d.bih);
	d.bih.biWidth = w;
	d.bih.biHeight = -h;
	d.bih.biPlanes = 1;
	d.bih.biBitCount = 8;
	d.bih.biCompression = BI_RGB;

	memcpy(d.rgb, dib.pal, 256*sizeof(RGBQUAD));
	dib.new_pal=false;

	dib.hSect = CreateDIBSection(0, (BITMAPINFO*)&d, DIB_RGB_COLORS, (void**)&dib.buf,
		NULL, NULL);

	return dib.hSect != NULL;
}

void WndMan::writeToScreen() {
	RECT r;
	HDC dc,bmpdc;
	HBITMAP bmpOld;
#if DEST_WIDTH==320
	if (_vgabuf) {
		for (int y=0; y<200; y++) {
			memcpy(dib.buf + y*320,_vgabuf + y*320, 320);
		}
	}
#endif

	r.left = r.top = 0;
	r.right = DEST_WIDTH;
	r.bottom = DEST_HEIGHT;

	dc = GetDC(hWnd);
	
	bmpdc = CreateCompatibleDC(dc);
	bmpOld = (HBITMAP)SelectObject(bmpdc, dib.hSect);

	if (dib.new_pal) {
		dib.new_pal = false;
		SetDIBColorTable(bmpdc, 0, 256, dib.pal);
	}

	SetStretchBltMode(dc, BLACKONWHITE);

#if DEST_WIDTH==320
	StretchBlt(dc, r.left, r.top, r.right-r.left, r.bottom-r.top, bmpdc, 0, 0, 320,200, SRCCOPY);
#endif


	SelectObject(bmpdc, bmpOld);
	DeleteDC(bmpdc);
	ReleaseDC(hWnd, dc);
}

void WndMan::setPalette(byte *ctab, int first, int num) {
	int i;

	for (i=0; i<256; i++) {
		dib.pal[i].rgbRed = ctab[i*3+0];
		dib.pal[i].rgbGreen = ctab[i*3+1];
		dib.pal[i].rgbBlue = ctab[i*3+2];
	}

	dib.new_pal = true;
}

#endif

HWND globWnd;

void WndMan::init() {

	/* Retrieve the handle of this module */
	hInst = GetModuleHandle(NULL);

	/* Register the window class */
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(WNDCLASSEX); 
	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC)WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInst;
	wcex.hIcon			= 0;
	wcex.hCursor		= ::LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= 0;	
	wcex.lpszClassName	= "ScummVM";
	wcex.hIconSm		= 0;
	if (!RegisterClassEx(&wcex))
		Error("Cannot register window class!");

#if USE_GDI
	globWnd = hWnd = CreateWindow("ScummVM", "ScummVM", WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, CW_USEDEFAULT, DEST_WIDTH+10, DEST_HEIGHT+30, NULL, NULL, hInst, NULL);
	SetWindowLong(hWnd, GWL_USERDATA, (long)this);

	dib.pal = (RGBQUAD*)calloc(sizeof(RGBQUAD),256);
	dib.new_pal = false;

	if (!allocateDIB(DEST_WIDTH, DEST_HEIGHT))
		Error("allocateDIB failed!");

	ShowWindow(hWnd, SW_SHOW);
#endif


#if USE_DIRECTX

  HWND hwnd;
  globWnd = hwnd = CreateWindow("ScummVM", "ScummVM",
					  WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_SIZEBOX,
					  0, 0, 0, 0,  NULL, NULL, hInst, NULL);
  SetWindowLong(hwnd, GWL_USERDATA, (long)this);

  RECT r;
  SetRect(&r, 0, 0, SRC_WIDTH, SRC_HEIGHT);
  AdjustWindowRectEx(&r, GetWindowStyle(hwnd), GetMenu(hwnd) != NULL, GetWindowExStyle(hwnd));
  MoveWindow(hwnd,
			 (GetSystemMetrics(SM_CXSCREEN) - SRC_WIDTH) / 2, 
             (GetSystemMetrics(SM_CYSCREEN) - SRC_HEIGHT) / 2, 
             r.right - r.left, r.bottom - r.top, FALSE);
  if(!ddrawInit())
	Error("Ddraw init failed!");
  ShowWindow(hwnd, SW_SHOW);
#endif

}


#ifdef USE_DIRECTX


void WndMan::ddrawUpdateBuffer()
{
  DDSURFACEDESC ddsd;
  memset(&ddsd, '\0', sizeof(ddsd));
  ddsd.dwSize = sizeof(ddsd);

  HRESULT hr;
  hr = lpddsSecondary->Lock(NULL, &ddsd, DDLOCK_WAIT|DDLOCK_WRITEONLY|DDLOCK_SURFACEMEMORYPTR, NULL);
  if(hr == DDERR_SURFACELOST) {
	// voir laquelle des surfaces il faut restaurer
	lpddsPrimary->Restore(); 
	lpddsSecondary->Restore();
	// DDERR_WRONGMODE ?, si echoue reinit de tout ? voir la doc...
  }
  else if(hr == DD_OK) {
	byte *p = _vgabuf ? _vgabuf : _realbuf;

	DDPIXELFORMAT ddpf = ddsd.ddpfPixelFormat;
	int Rshift = GetLowestBit(ddpf.dwRBitMask);
	int Gshift = GetLowestBit(ddpf.dwGBitMask);
	int Bshift = GetLowestBit(ddpf.dwBBitMask);

	BYTE *dst = (BYTE*)ddsd.lpSurface;

	int size = ddsd.dwHeight * ddsd.dwWidth;
	int i = 0;
	while(i < size) { 
	  BYTE r = _scumm->_currentPalette[p[i]*3];
	  BYTE g = _scumm->_currentPalette[p[i]*3+1];
	  BYTE b = _scumm->_currentPalette[p[i]*3+2];

	  DWORD pixel = (r << Rshift) | (g << Gshift) | (b << Bshift);

	  switch(ddpf.dwRGBBitCount) {
	  case 32:
	    //dst[0] = (BYTE)((pixel & 0xFF000000) >> 24);
	    //dst[1] = (BYTE)((pixel & 0x00FF0000) >> 16);
	    //dst[2] = (BYTE)((pixel & 0x0000FF00) >> 8);
	    //dst[3] = (BYTE)((pixel & 0x000000FF));
		*((DWORD*)dst) = pixel;
	    break;
	  case 24:
	    dst[0]   = (BYTE)((pixel & 0xFF0000) >> 16);
	    dst[1] = (BYTE)((pixel & 0x00FF00) >> 8);
	    dst[2] = (BYTE)((pixel & 0x0000FF));
	    break;
	  case 16:
	    //dst[0] = (BYTE)((pixel & 0xFF00) >> 8);
	    //dst[1] = (BYTE)((pixel & 0x00FF));
		*((WORD*)dst) = (WORD)pixel;
	    break;
	  }
	  dst += ddpf.dwRGBBitCount >> 3; // / 8

	  i++;
	}
    lpddsSecondary->Unlock(NULL);
  }
}

void WndMan::writeToScreen()
{
  ddrawUpdateBuffer();
  RECT r;
  GetWindowRect(globWnd, &r);
  lpddsPrimary->Blt(&r, lpddsSecondary, NULL, DDBLT_WAIT, NULL);
}


BOOL WndMan::ddrawInit()
{
  DDSURFACEDESC ddsd;
  LPDIRECTDRAWCLIPPER lpddc;

  if(DirectDrawCreate(NULL, &lpdd, NULL) != DD_OK)
	return FALSE;

  if(lpdd->SetCooperativeLevel(globWnd, DDSCL_NORMAL) != DD_OK)
	return FALSE;
  
  memset(&ddsd, '\0', sizeof(ddsd));
  ddsd.dwSize = sizeof(ddsd);
  ddsd.dwFlags = DDSD_CAPS;
  ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_VIDEOMEMORY;
  if(lpdd->CreateSurface(&ddsd, &lpddsPrimary, NULL) != DD_OK)
	return FALSE;

  if(lpdd->CreateClipper(0, &lpddc, NULL) != DD_OK)
	return FALSE;
  if(lpddc->SetHWnd(0, globWnd) != DD_OK)
	return FALSE;
  if(lpddsPrimary->SetClipper(lpddc) != DD_OK)
	return FALSE;
  lpddc->Release();

  memset(&ddsd, '\0', sizeof(ddsd));
  ddsd.dwSize = sizeof(ddsd);
  ddsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT;
  ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  ddsd.dwWidth = SRC_WIDTH;
  ddsd.dwHeight = SRC_HEIGHT;
  if(lpdd->CreateSurface(&ddsd, &lpddsSecondary, NULL) != DD_OK)
	return FALSE;

  memset(_realbuf, '\0', sizeof(_realbuf));
  return TRUE;
}


void WndMan::ddrawReleaseSurfaces()
{
  if(lpddsPrimary != NULL) lpddsPrimary->Release();
  if(lpddsSecondary != NULL) lpddsSecondary->Release();
}


void WndMan::ddrawRelease()
{
  ddrawReleaseSurfaces();
  if(lpdd != NULL) lpdd->Release();
}
#endif



bool WndMan::handleMessage() {
	MSG msg;

	if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		return false;

	if (msg.message==WM_QUIT) {
		terminated=true;
		exit(1);
		return true;
	}

	TranslateMessage(&msg);
	DispatchMessage(&msg);

	return true;
}


#if USE_DIRECTX
unsigned long rdtsc_timer;

void _declspec(naked) beginpentiumtest() {
	_asm {
		rdtsc
		mov rdtsc_timer,eax
		ret
	}
}

int _declspec(naked) endpentiumtest() {
	_asm {
		rdtsc
		sub eax,rdtsc_timer
		ret
	}
}
#endif

void decompressMask(byte *d, byte *s, int w=320, int h=144) {
	int x,y;
	
	for (y=0; y<h; y++) {
		byte *p = s+y*40;
		byte *pd = d + y*320;
		byte bits = 0x80, bdata = *p++;
		for (x=0; x<w; x++) {
			*pd++ = (bdata & bits) ? 128 : 0;
			bits>>=1;
			if (!bits) {
				bdata = *p++;
				bits=0x80;
			}
		}
	}
}

void outputlittlemask(byte *mask, int w, int h) {
	byte *old = wm->_vgabuf;
	wm->_vgabuf = NULL;
#if !(USE_DIRECTX)
	decompressMask(wm->dib.buf, mask, w, h);
#else
	memset(wm->_realbuf, '\0', sizeof(wm->_realbuf));
	decompressMask(wm->_realbuf, mask, w, h);
#endif
	wm->writeToScreen();	
	wm->_vgabuf = old;
}

void outputdisplay2(Scumm *s, int disp) {
	byte *old = wm->_vgabuf;

	byte buf[64000];

	switch(disp) {
	case 0:
		wm->_vgabuf = buf;
		memcpy(buf, wm->_vgabuf, 64000);
		memcpy(buf,s->getResourceAddress(rtBuffer, 5),320*200);
		break;
	case 1:
		wm->_vgabuf = buf;
		memcpy(buf, wm->_vgabuf, 64000);
		memcpy(buf,s->getResourceAddress(rtBuffer, 1),320*200);
		break;
	case 2:
		wm->_vgabuf = NULL;
#if !(USE_DIRECTX)
		decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+s->_screenStartStrip);
#else
		memset(wm->_realbuf, '\0', sizeof(wm->_realbuf));
		decompressMask(wm->_realbuf, s->getResourceAddress(rtBuffer, 9)+s->_screenStartStrip);
#endif
		break;
	case 3:
		wm->_vgabuf = NULL;
#if !(USE_DIRECTX)
		decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+8160+s->_screenStartStrip);
#else
		memset(wm->_realbuf, '\0', sizeof(wm->_realbuf));
		decompressMask(wm->_realbuf, s->getResourceAddress(rtBuffer, 9)+8160+s->_screenStartStrip);
#endif
		break;
	case 4:
		wm->_vgabuf = NULL;
#if !(USE_DIRECTX)
		decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+8160*2+s->_screenStartStrip);
#else
		memset(wm->_realbuf, '\0', sizeof(wm->_realbuf));
		decompressMask(wm->_realbuf, s->getResourceAddress(rtBuffer, 9)+8160*2+s->_screenStartStrip);
#endif
		break;
	case 5:
		wm->_vgabuf = NULL;
#if !(USE_DIRECTX)
		decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+8160*3+s->_screenStartStrip);
#else
		memset(wm->_realbuf, '\0', sizeof(wm->_realbuf));
		decompressMask(wm->_realbuf, s->getResourceAddress(rtBuffer, 9)+8160*2+s->_screenStartStrip);
#endif
		break;
	}
	wm->writeToScreen();	
	wm->_vgabuf = old;
}

void blitToScreen(Scumm *s, byte *src,int x, int y, int w, int h) {
	byte *dst;
	SDL_Rect *r;
	int i;

	dst = (byte*)wm->_vgabuf + y*320 + x;

	do {
		memcpy(dst, src, w);
		dst += 320;
		src += 320;
	} while (--h);

}

void setShakePos(Scumm *s, int shake_pos) {}


int clock;

void updateScreen(Scumm *s) {
	if (s->_palDirtyMax != -1) {
#if !USE_DIRECTX
	  wm->setPalette(s->_currentPalette, 0, 256);	
#endif
		s->_palDirtyMax = -1;
	}

	wm->writeToScreen();
}

void waitForTimer(Scumm *s, int delay) {
	wm->handleMessage();
	if (!veryFastMode) {
		assert(delay<5000);
		if (s->_fastMode)
			delay=10;
		Sleep(delay);
	} 
}

void initGraphics(Scumm *s, bool fullScreen) {
	if(fullScreen)
		warning("Use SDL for fullscreen support");
}

void drawMouse(Scumm *s, int, int, int, byte*, bool) {
}

void drawMouse(Scumm *s, int x, int y, int w, int h, byte *buf, bool visible) {
}

void fill_buffer(int16 *buf, int len) {
	scumm.mixWaves(buf, len);
}

void WndMan::prepare_header(WAVEHDR *wh, int i) {
	memset(wh, 0, sizeof(WAVEHDR));
	wh->lpData = (char*)malloc(BUFFER_SIZE);
	wh->dwBufferLength = BUFFER_SIZE;

	waveOutPrepareHeader(_handle, wh, sizeof(WAVEHDR));

	fill_buffer((int16*)wh->lpData, wh->dwBufferLength>>1);
	waveOutWrite(_handle, wh, sizeof(WAVEHDR));
}

void WndMan::sound_init() {
	WAVEFORMATEX wfx;

	memset(&wfx, 0, sizeof(wfx));
	wfx.wFormatTag = WAVE_FORMAT_PCM;
	wfx.nChannels = 1;
	wfx.nSamplesPerSec = SAMPLES_PER_SEC;
	wfx.nAvgBytesPerSec = SAMPLES_PER_SEC * BITS_PER_SAMPLE / 8;
	wfx.wBitsPerSample = BITS_PER_SAMPLE;
	wfx.nBlockAlign = BITS_PER_SAMPLE * 1 / 8;

	CreateThread(NULL, 0, (unsigned long (__stdcall *)(void *))&sound_thread, this, 0, &_threadId);
	SetThreadPriority((void*)_threadId, THREAD_PRIORITY_HIGHEST);

	_event = CreateEvent(NULL, false, false, NULL);

	memset(_hdr,0,sizeof(_hdr));
	
	waveOutOpen(&_handle, WAVE_MAPPER, &wfx, (long)_event, (long)this, CALLBACK_EVENT );

	prepare_header(&_hdr[0], 0);
	prepare_header(&_hdr[1], 1);
}

DWORD _stdcall WndMan::sound_thread(WndMan *wm) {
	int i;
	bool signaled;
	int time = GetTickCount(), cur;

	while (1) {

		if (!snd_driv.wave_based()) {
			cur = GetTickCount();
			while (time < cur) {
				sound.on_timer();
				time += 10;
			}
		}

		signaled = WaitForSingleObject(wm->_event, time - cur) == WAIT_OBJECT_0;

		if (signaled) {
			for(i=0; i<2; i++) {
				WAVEHDR *hdr = &wm->_hdr[i];
				if (hdr->dwFlags & WHDR_DONE) {
					fill_buffer((int16*)hdr->lpData, hdr->dwBufferLength>>1);
					waveOutWrite(wm->_handle, hdr, sizeof(WAVEHDR));
				}
			}
		}
	}
}


#undef main
int main(int argc, char* argv[]) {
	int delta;

	wm->init();
	wm->_vgabuf = (byte*)calloc(320,200);
	wm->_scumm = &scumm;

	sound.initialize(&scumm,&snd_driv);

	wm->sound_init();

	scumm._gui = &gui;
	scumm.scummMain(argc, argv);
	gui.init(&scumm);

	delta = 0;
	do {
		updateScreen(&scumm);

		waitForTimer(&scumm, delta*15);

		if (gui._active) {
			gui.loop();
			delta = 3;
		} else {
			delta = scumm.scummLoop(delta);
		}
	} while(1);

	return 0;
}

