/* 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. * * Change Log: * $Log$ * Revision 1.11 2001/11/06 07:47:00 strigeus * fixed integer overflow for large sounds * * Revision 1.10 2001/11/05 20:44:34 strigeus * speech support * * Revision 1.9 2001/11/05 19:21:49 strigeus * bug fixes, * speech in dott * * Revision 1.8 2001/10/26 17:34:50 strigeus * bug fixes, code cleanup * * Revision 1.7 2001/10/23 19:51:50 strigeus * recompile not needed when switching games * debugger skeleton implemented * * Revision 1.6 2001/10/16 20:31:27 strigeus * misc fixes * * Revision 1.5 2001/10/16 10:01:48 strigeus * preliminary DOTT support * * Revision 1.4 2001/10/12 07:24:06 strigeus * fast mode support * * Revision 1.3 2001/10/10 10:02:33 strigeus * alternative mouse cursor * basic save&load * * Revision 1.2 2001/10/09 19:02:28 strigeus * command line parameter support * * Revision 1.1.1.1 2001/10/09 14:30:13 strigeus * * initial revision * * */ #if USE_DIRECTX #define INITGUID #include #endif #include "stdafx.h" #include #if USE_DRAWDIB #include #endif #include "scumm.h" #if defined(USE_IMUSE) #include "sound.h" #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; #if defined(USE_IMUSE) SoundEngine sound; #endif WndMan wm[1]; byte veryFastMode; void modifyslot(int sel, int what); 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_CHAR: wm->_scumm->_keyPressed = wParam; break; case WM_KEYDOWN: if (wParam>='0' && wParam<='9') { wm->_scumm->_saveLoadSlot = wParam - '0'; if (GetAsyncKeyState(VK_SHIFT)<0) wm->_scumm->_saveLoadFlag = 1; else if (GetAsyncKeyState(VK_CONTROL)<0) wm->_scumm->_saveLoadFlag = 2; wm->_scumm->_saveLoadCompatible = false; } 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(); } 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+320*144,s->getResourceAddress(rtBuffer, 7),320*56); break; case 1: wm->_vgabuf = buf; memcpy(buf, wm->_vgabuf, 64000); memcpy(buf+320*144,s->getResourceAddress(rtBuffer, 3),320*56); 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)+5920+s->_screenStartStrip); break; case 4: wm->_vgabuf = NULL; decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+5920*2+s->_screenStartStrip); break; case 5: wm->_vgabuf = NULL; decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+5920*3+s->_screenStartStrip); break; } wm->writeToScreen(); wm->_vgabuf = old; } #if 0 void outputdisplay(Scumm *s) { s->drawMouse(); wm->writeToScreen(); } #endif 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); } #define SAMPLES_PER_SEC 22050 #define BUFFER_SIZE (8192) #define BITS_PER_SAMPLE 16 static void *_sfx_sound; static uint32 _sfx_pos; static uint32 _sfx_size; static uint32 _sfx_fp_speed; static uint32 _sfx_fp_pos; bool isSfxFinished() { return _sfx_size == 0; } void playSfxSound(void *sound, uint32 size, uint rate) { if (_sfx_sound) { free(_sfx_sound); } _sfx_sound = sound; _sfx_pos = 0; _sfx_fp_speed = (1<<16) * rate / 22050; _sfx_fp_pos = 0; while (size&0xFFFF0000) size>>=1, rate>>=1; _sfx_size = size * 22050 / rate; } void mix_sound(int16 *data, uint32 len) { int8 *s; int i; uint32 fp_pos, fp_speed; if (!_sfx_size) 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; } 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) { if (!veryFastMode) { Sleep(5); } s->_scummTimer+=2; wm->handleMessage(); } void initGraphics(Scumm *s) { } void drawMouse(Scumm *s, int, int, int, byte*, bool) { } void fill_buffer(int16 *buf, int len) { #if defined(USE_IMUSE) sound.generate_samples(buf,len); #else memset(buf, 0, len*2); #endif mix_sound(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); _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; while (1) { WaitForSingleObject(wm->_event, INFINITE); 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[]) { scumm._videoMode = 0x13; wm->init(); wm->sound_init(); wm->_vgabuf = (byte*)calloc(320,200); wm->_scumm = &scumm; #if defined(USE_IMUSE) sound.initialize(NULL); scumm._soundDriver = &sound; #endif scumm.scummMain(argc, argv); return 0; }