scummvm/windows.cpp
Ludvig Strigeus 38e2a886ce very simple full throttle support, use the FULL_THROTTLE define. (will fix later)
modified some actor parts to work better with full throttle (most likely new bugs because of that).
directions are now stored as angles instead of left/right/up/down
implemented loadFlObject (flobjects are currently saved in the savestate, will fix that also)

svn-id: r3505
2001-11-26 19:57:57 +00:00

949 lines
20 KiB
C++

/* 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$
*/
#if USE_DIRECTX
#define INITGUID
#include <ddraw.h>
#endif
#include "stdafx.h"
#include <assert.h>
#if USE_DRAWDIB
#include <vfw.h>
#endif
#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 0
#define USE_DRAWDIB 0
#define USE_GDI 1
#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_GDI
// BITMAPINFO *biHeader;
// byte *BmpBG;
public:
DIB dib;
private:
#endif
#if USE_DRAWDIB
BITMAPINFOHEADER *biHeader;
HDRAWDIB hdb;
#endif
public:
byte *_vgabuf;
Scumm *_scumm;
#if USE_DIRECTX
IDirectDrawSurface4 *MainSurf,*Surf2;
IDirectDraw *DxObject;
IDirectDraw4 *Dx4Object;
IDirectDrawPalette *DxPal;
bool OutOfGame;
void InitDirectX();
#endif
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
};
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;
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:
// TerminateThread((void*)wm->_threadId, 0);
// wm->_scumm->destroy();
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:
wm->_scumm->mouse.x = ((int16*)&lParam)[0];
wm->_scumm->mouse.y = ((int16*)&lParam)[1];
break;
case WM_LBUTTONDOWN:
wm->_scumm->_leftBtnPressed |= 1;
break;
case WM_RBUTTONDOWN:
wm->_scumm->_rightBtnPressed |= 1;
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
#if USE_GDI
void copy_320x200_to_640x400(byte *s, byte *d) {
_asm {
push ebp
mov esi,s
mov edi,d
mov ebp,SRC_HEIGHT
againouter:
mov ebx,320/4
againinner:
mov eax,[esi]
mov dl,ah
mov dh,ah
shl edx,16
mov dl,al
mov dh,al
shr eax,16
mov cl,ah
mov ch,ah
shl ecx,16
mov cl,al
mov ch,al
mov [edi],edx
mov [edi+4],ecx
mov [edi+640],edx
mov [edi+644],ecx
add esi,4
add edi,8
dec ebx
jnz againinner
// add esi,15
add edi,640
dec ebp
jnz againouter
pop ebp
}
}
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 (!BmpBG)
// BmpBG = (byte*)LocalAlloc(LMEM_FIXED, DEST_WIDTH*DEST_HEIGHT);
#if DEST_WIDTH==640
copy_320x200_to_640x400(_vgabuf, dib.buf);
#endif
#if DEST_WIDTH==320
if (_vgabuf) {
for (int y=0; y<200; y++) {
memcpy(dib.buf + y*320,_vgabuf + y*320, 320);
}
}
#endif
// setsel(dib.buf);
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==640
StretchBlt(dc, r.left, r.top, r.right-r.left, r.bottom-r.top, bmpdc, 0, 0, 640,480, SRCCOPY);
#endif
#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
// //StretchDIBits(dc, r.left, r.top, r.right - r.left, r.bottom - r.top, 0, 0, DEST_WIDTH, DEST_HEIGHT, BmpBG, biHeader, DIB_RGB_COLORS, SRCCOPY);
SelectObject(bmpdc, bmpOld);
DeleteDC(bmpdc);
ReleaseDC(hWnd, dc);
}
void WndMan::setPalette(byte *ctab, int first, int num) {
int i;
#if 1
for (i=0; i<256; i++) {
dib.pal[i].rgbRed = ctab[i*3+0]<<2;
dib.pal[i].rgbGreen = ctab[i*3+1]<<2;
dib.pal[i].rgbBlue = ctab[i*3+2]<<2;
}
#else
for (i=0; i<256; i++) {
dib.pal[i].rgbRed = i;
dib.pal[i].rgbGreen = i;
dib.pal[i].rgbBlue = i;
}
#endif
dib.new_pal = true;
}
#endif
#if USE_DIRECTX
void WndMan::writeToScreen() {
RECT r;
DDSURFACEDESC2 dd;
r.left = r.top = 0;
r.right = SRC_WIDTH;
r.bottom = SRC_HEIGHT;
if (OutOfGame) {
if (GetForegroundWindow() != hWnd) return;
OutOfGame = false;
}
dd.dwSize = sizeof(dd);
int j;
do {
j = MainSurf->Lock(NULL, &dd, DDLOCK_WRITEONLY, NULL);
if (j!=DDERR_SURFACELOST) break;
if (MainSurf->Restore() != DD_OK) {
OutOfGame = true;
return;
}
} while (1);
if (j == DD_OK) {
byte *d = (byte*)dd.lpSurface;
byte *s = _vgabuf;
for(int h=SRC_HEIGHT;--h>=0; ) {
memcpy(d, s, SRC_WIDTH);
d+=dd.lPitch;
s+=SRC_PITCH;
}
MainSurf->Unlock(NULL);
}
}
void WndMan::setPalette(byte *ctab, int first, int num) {
PALETTEENTRY pal[256];
for (int i=0; i<256; i++) {
pal[i].peFlags = 0;
pal[i].peRed = *ctab++;
pal[i].peGreen = *ctab++;
pal[i].peBlue = *ctab++;
}
DxPal->SetEntries(0, 0, 256, (PALETTEENTRY*)&pal);
}
IDirectDrawSurface4 *CreateMainSurface(IDirectDraw4 *dd);
void WndMan::InitDirectX() {
if (DirectDrawCreate(NULL, &DxObject, NULL) != DD_OK) Error("DirectDrawCreate failed!");
if (DxObject->QueryInterface(IID_IDirectDraw4, (void**)&Dx4Object) != DD_OK) Error("QueryInterface failed!");
if (Dx4Object->SetCooperativeLevel(hWnd,DDSCL_NORMAL) != DD_OK) Error("SetCooperativeLevel failed!");
DDCAPS ddcaps;
BOOL bHasOverlay, bHasColorKey, bCanStretch;
ddcaps.dwSize = sizeof( ddcaps );
if (Dx4Object->GetCaps(&ddcaps, NULL ) != DD_OK) Error("GetCaps failed!");
/* Determine if the hardware supports overlay surfaces */
bHasOverlay = ddcaps.dwCaps & DDCAPS_OVERLAY;
/* Determine if the hardware supports colorkeying */
bHasColorKey = ((ddcaps.dwCaps & DDCAPS_COLORKEY) == DDCAPS_COLORKEY) ? TRUE : FALSE;
/* Determine if the hardware supports scaling of the overlay surface */
bCanStretch = ((ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) == DDCAPS_OVERLAYSTRETCH) ? TRUE : FALSE;
if ( ( ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYDEST ) ||
( ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYSRC ) ||
( ddcaps.dwCaps & DDCAPS_ALIGNSIZEDEST ) ||
( ddcaps.dwCaps & DDCAPS_ALIGNSIZESRC ) ) {
Error("Alignment restriction!");
}
// Are any overlays available for use?
if ( ddcaps.dwMaxVisibleOverlays ==
ddcaps.dwCurrVisibleOverlays )
{
Error("No overlay free");
}
if (!bHasOverlay || !bHasColorKey || !bCanStretch) {
Error("Bad hardware!");
}
/* Create primary surface */
DDSURFACEDESC2 ddsd;
DDSCAPS ddscaps;
LPDIRECTDRAWSURFACE4 lpFrontBuffer;
LPDIRECTDRAWSURFACE4 lpBackBuffer;
LPDIRECTDRAWSURFACE4 lpPrimary;
HRESULT LastError;
RECT rectOverlaySource, rectOverlayDest;
DDOVERLAYFX ddofx;
// if (!CreateMainSurface(Dx4Object))
// Error("sad");
/* Create the primary surface */
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP |
DDSCAPS_COMPLEX |
DDSCAPS_VIDEOMEMORY;
ddsd.dwBackBufferCount = 1;
if (Dx4Object->CreateSurface(&ddsd, &lpPrimary, NULL) != DD_OK)
Error("Main surface creation failed!");
/* Create a flippable scaleable overlay surface */
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_BACKBUFFERCOUNT | DDSD_PIXELFORMAT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_FLIP | DDSCAPS_COMPLEX | DDSCAPS_VIDEOMEMORY;
ddsd.dwBackBufferCount = 1; /* One back buffer for triple buffering, set to 2 */
ddsd.dwWidth = 320;
ddsd.dwHeight = 240;
// ddsd.ddckCKDestOverlay.dwColorSpaceLowValue = 0x123456;
// ddsd.ddckCKDestOverlay.dwColorSpaceHighValue = 0x123456;
ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
ddsd.ddpfPixelFormat.dwFourCC = 0;
ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
ddsd.ddpfPixelFormat.dwRBitMask = 0x7C00; //0x7C00 is a hexadecimal memory address
ddsd.ddpfPixelFormat.dwGBitMask = 0x03e0;
ddsd.ddpfPixelFormat.dwBBitMask = 0x001F;
ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0;
// ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8;
// ddsd.ddpfPixelFormat.dwRGBBitCount = 8;
if ((LastError = Dx4Object->CreateSurface(&ddsd, &lpFrontBuffer, NULL)) != DD_OK) {
if (LastError==DDERR_NOOVERLAYHW )
Error("No hardware!");
else
Error("2nd surface failed");
}
#if 0
if (Dx4Object->SetCooperativeLevel(hWnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE) != DD_OK) Error("SetCooperativeLevel failed!");
// if (Dx4Object->SetDisplayMode(SRC_WIDTH,SRC_HEIGHT,8,0,DDSDM_STANDARDVGAMODE) != DD_OK) Error("SetDisplayMode failed!");
if (!(MainSurf = CreateMainSurface(Dx4Object))) Error("CreateMainSurface failed!");
if (!(Surf2 = Create2ndSurface(Dx4Object, _vgabuf))) Error("Create 2ndSurface failed!");
if (!(DxPal = CreateGamePalette(Dx4Object))) Error("CreateGamePalette failed!");
if (MainSurf->SetPalette(DxPal) != DD_OK) Error("SetPalette Failed!");
#endif
}
IDirectDrawSurface4 *CreateMainSurface(IDirectDraw4 *dd) {
DDSURFACEDESC2 d;
IDirectDrawSurface4 *ds;
// if(dd->GetGDISurface(&ds) != DD_OK)
// return NULL;
memset(&d, 0, sizeof(d));
d.dwSize = sizeof(d);
d.dwFlags = DDSD_CAPS;
d.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
int i;
if ((i = dd->CreateSurface(&d, &ds, NULL)) != DD_OK)
return NULL;
return ds;
}
IDirectDrawSurface4 *Create2ndSurface(IDirectDraw4 *dd, byte *surfmem) {
DDSURFACEDESC2 d;
IDirectDrawSurface4 *ds;
memset(&d, 0, sizeof(d));
d.dwSize = sizeof(d);
d.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | /*DDSD_LPSURFACE |*/ DDSD_PIXELFORMAT;
d.dwWidth = 640/*SRC_WIDTH*/;
d.dwHeight = 480/*SRC_HEIGHT*/;
d.lPitch = 640;
d.lpSurface = surfmem;
d.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
d.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8;
d.ddpfPixelFormat.dwRGBBitCount = 8;
d.ddsCaps.dwCaps = DDSCAPS_OVERLAY;
int i;
if ((i = dd->CreateSurface(&d, &ds, NULL)) != DD_OK)
return NULL;
return ds;
}
IDirectDrawPalette *CreateGamePalette(IDirectDraw4 *dd) {
PALETTEENTRY pal[256];
int i;
IDirectDrawPalette *p;
memset(&pal, 0, sizeof(pal));
if ((i=dd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256, pal, &p, NULL)) != DD_OK)
return NULL;
return p;
}
#endif
#if USE_DRAWDIB
void WndMan::writeToScreen() {
RECT r;
HDC dc;
r.left = r.top = 0;
r.right = DEST_WIDTH/2;
r.bottom = DEST_HEIGHT/2;
dc = GetDC(hWnd);
DrawDibRealize(hdb, dc, TRUE);
DrawDibDraw(hdb, dc, r.left, r.top, r.right-r.left, r.bottom-r.top, biHeader, _vgabuf, 0, 0, 320, 240, 0);
// StretchDIBits(dc, r.left, r.top, r.right - r.left, r.bottom - r.top, 0, 0, DEST_WIDTH, DEST_HEIGHT, BmpBG, biHeader, DIB_RGB_COLORS, SRCCOPY);
ReleaseDC(hWnd, dc);
}
void WndMan::setPalette(byte *ctab, int first, int num) {
PALETTEENTRY pal[256];
for (int i=0; i < num; i++,ctab+=3) {
pal[i].peFlags = 0;
pal[i].peRed = ctab[0];
pal[i].peGreen = ctab[1];
pal[i].peBlue = ctab[2];
}
DrawDibChangePalette(hdb, 0, 16, pal);
GetLastError();
}
#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_DIRECTX
hWnd = CreateWindow("ScummVM", "ScummVM", 0,
CW_USEDEFAULT, CW_USEDEFAULT, SRC_WIDTH, SRC_HEIGHT, NULL, NULL, hInst, NULL);
SetWindowLong(hWnd, GWL_USERDATA, (long)this);
SetWindowLong(hWnd, GWL_STYLE, 0);
ShowCursor(false);
InitDirectX();
ShowWindow(hWnd, SW_SHOW);
#endif
#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);
// ShowCursor(false);
dib.pal = (RGBQUAD*)calloc(sizeof(RGBQUAD),256);
dib.new_pal = false;
if (!allocateDIB(DEST_WIDTH, DEST_HEIGHT))
Error("allocateDIB failed!");
#if 0
biHeader = (BITMAPINFO*)LocalAlloc(LMEM_FIXED, sizeof(BITMAPINFOHEADER) + 1024 );
memset(biHeader, 0, sizeof(BITMAPINFOHEADER) + 1024);
biHeader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
biHeader->bmiHeader.biWidth = DEST_WIDTH;
biHeader->bmiHeader.biHeight = -DEST_HEIGHT; /* top down */
biHeader->bmiHeader.biPlanes = 1;
biHeader->bmiHeader.biBitCount = 8; /* 256 colors */
biHeader->bmiHeader.biCompression = BI_RGB; /* uncompressed */
#endif
ShowWindow(hWnd, SW_SHOW);
#endif
#if USE_DRAWDIB
hdb = DrawDibOpen();
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);
ShowCursor(false);
biHeader = (BITMAPINFOHEADER*)LocalAlloc(LMEM_FIXED, sizeof(BITMAPINFOHEADER));
memset(biHeader, 0, sizeof(BITMAPINFOHEADER));
biHeader->biSize = sizeof(BITMAPINFOHEADER);
biHeader->biWidth = SRC_PITCH;
biHeader->biHeight = SRC_HEIGHT; /* top down */
biHeader->biPlanes = 1;
biHeader->biBitCount = 8; /* 256 colors */
biHeader->biCompression = BI_RGB; /* uncompressed */
ShowWindow(hWnd, SW_SHOW);
// int k = DrawDibProfileDisplay(biHeader);
// printf("%d\n", k&PD_CAN_STRETCHDIB);
#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;
}
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
}
}
void decompressMask(byte *d, byte *s) {
int x,y;
byte bits = 0x80, bdata = *s++;
for (y=0; y<144; y++)
for (x=0; x<320; x++) {
*d++ = (bdata & bits) ? 128 : 0;
bits>>=1;
if (!bits) {
bdata = *s++;
bits=0x80;
}
}
}
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*144);
break;
case 1:
wm->_vgabuf = buf;
memcpy(buf, wm->_vgabuf, 64000);
memcpy(buf,s->getResourceAddress(rtBuffer, 1),320*144);
break;
case 2:
wm->_vgabuf = NULL;
decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+s->_screenStartStrip);
break;
case 3:
wm->_vgabuf = NULL;
decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+8160+s->_screenStartStrip);
break;
case 4:
wm->_vgabuf = NULL;
decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+8160*2+s->_screenStartStrip);
break;
case 5:
wm->_vgabuf = NULL;
decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+8160*3+s->_screenStartStrip);
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);
}
int clock;
void updateScreen(Scumm *s) {
if (s->_palDirtyMax != -1) {
wm->setPalette(s->_currentPalette, 0, 256);
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) {
memset(buf, 0, len*2);
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;
return 0;
while (1) {
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->sound_init();
wm->_vgabuf = (byte*)calloc(320,200);
wm->_scumm = &scumm;
sound.initialize(&scumm);
scumm._soundDriver = &sound;
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;
}