Ticket #7933: windows.cpp

File windows.cpp, 17.4 KB (added by cyxx, 22 years ago)
Line 
1/* ScummVM - Scumm Interpreter
2 * Copyright (C) 2001 Ludvig Strigeus
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 *
18 * $Header: /cvsroot/scummvm/scummvm/windows.cpp,v 1.24 2001/12/28 15:26:28 strigeus Exp $
19 */
20
21/*
22 (Very ugly) DirectX additions by Gregory Montoir (cyx@frenchkiss.net)
23 The scrolling window seems not correct (bounds are out of the screen)... i'll see...
24 2002.02.12
25 */
26
27#include <windows.h>
28#include <windowsx.h>
29
30#include "stdafx.h"
31#include <assert.h>
32
33#include "scumm.h"
34#include "sound.h"
35#include "gui.h"
36
37#if !defined(ALLOW_GDI)
38#error The GDI driver is not as complete as the SDL driver. You need to define ALLOW_GDI to use this driver.
39#endif
40
41#define SRC_WIDTH 320
42#define SRC_HEIGHT 200
43#define SRC_PITCH (320)
44
45#define DEST_WIDTH 320
46#define DEST_HEIGHT 200
47
48#define USE_DIRECTX 1
49#define USE_DRAWDIB 0
50#define USE_GDI 0
51
52#if USE_DIRECTX
53#include <ddraw.h>
54#endif
55
56#define SAMPLES_PER_SEC 22050
57#define BUFFER_SIZE (8192)
58#define BITS_PER_SAMPLE 16
59
60//static bool shutdown;
61
62
63#if USE_GDI
64typedef struct DIB {
65 HBITMAP hSect;
66 byte *buf;
67 RGBQUAD *pal;
68 bool new_pal;
69} DIB;
70#endif
71
72class WndMan {
73 HMODULE hInst;
74 HWND hWnd;
75
76
77 bool terminated;
78
79#if USE_DIRECTX
80 LPDIRECTDRAW lpdd;
81 LPDIRECTDRAWSURFACE lpddsPrimary;
82 LPDIRECTDRAWSURFACE lpddsSecondary;
83#endif
84
85#if USE_GDI
86public:
87 DIB dib;
88private:
89#endif
90
91public:
92 byte *_vgabuf;
93
94 Scumm *_scumm;
95
96 HANDLE _event;
97 DWORD _threadId;
98 HWAVEOUT _handle;
99 WAVEHDR _hdr[2];
100
101public:
102 void init();
103
104 bool handleMessage();
105 void run();
106 void setPalette(byte *ctab, int first, int num);
107 void writeToScreen();
108
109 void prepare_header(WAVEHDR *wh, int i);
110 void sound_init();
111 static DWORD _stdcall sound_thread(WndMan *wm);
112
113#if USE_GDI
114 bool allocateDIB(int w, int h);
115#endif
116
117#if USE_DIRECTX
118 byte _realbuf[SRC_WIDTH*SRC_HEIGHT];
119 BOOL ddrawInit();
120 void ddrawReleaseSurfaces();
121 void ddrawRelease();
122 void ddrawUpdateBuffer();
123#endif
124};
125
126#if USE_DIRECTX
127
128static unsigned char GetLowestBit(unsigned long p)
129{
130 unsigned char pos = 0;
131 while((p & 1) == 0) {
132 ++pos;
133 p >>= 1;
134 }
135 return pos;
136}
137#endif
138
139void Error(const char *msg) {
140 OutputDebugString(msg);
141 MessageBoxA(0, msg, "Error", MB_ICONSTOP);
142 exit(1);
143}
144
145int sel;
146Scumm scumm;
147ScummDebugger debugger;
148Gui gui;
149SoundEngine sound;
150SOUND_DRIVER_TYPE snd_driv;
151
152WndMan wm[1];
153byte veryFastMode;
154
155void modifyslot(int sel, int what);
156
157int mapKey(int key) {
158 if (key>=VK_F1 && key<=VK_F9) {
159 return key - VK_F1 + 315;
160 }
161 return key;
162}
163
164static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
165 WndMan *wm = (WndMan*)GetWindowLong(hWnd, GWL_USERDATA);
166
167 switch (message)
168 {
169 case WM_DESTROY:
170 case WM_CLOSE:
171 exit(0);
172 break;
173
174 case WM_KEYDOWN:
175 if (wParam>='0' && wParam<='9') {
176 wm->_scumm->_saveLoadSlot = wParam - '0';
177 if (GetAsyncKeyState(VK_SHIFT)<0) {
178 sprintf(wm->_scumm->_saveLoadName, "Quicksave %d", wm->_scumm->_saveLoadSlot);
179 wm->_scumm->_saveLoadFlag = 1;
180 } else if (GetAsyncKeyState(VK_CONTROL)<0)
181 wm->_scumm->_saveLoadFlag = 2;
182 wm->_scumm->_saveLoadCompatible = false;
183 }
184
185 if (GetAsyncKeyState(VK_CONTROL)<0) {
186 if (wParam=='F') {
187 wm->_scumm->_fastMode ^= 1;
188 }
189
190 if (wParam=='G') {
191 veryFastMode ^= 1;
192 }
193
194 if (wParam=='D') {
195 debugger.attach(wm->_scumm);
196 }
197
198 if (wParam=='S') {
199 wm->_scumm->resourceStats();
200 }
201 }
202
203 wm->_scumm->_keyPressed = mapKey(wParam);
204 break;
205
206 case WM_MOUSEMOVE:
207#if USE_DIRECTX
208 RECT r;
209 GetClientRect(hWnd, &r);
210 wm->_scumm->mouse.x = (SRC_WIDTH * ((int16*)&lParam)[0]) / (r.right - r.left);
211 wm->_scumm->mouse.y = (SRC_HEIGHT * ((int16*)&lParam)[1]) / (r.bottom - r.top);
212#else
213 wm->_scumm->mouse.x = ((int16*)&lParam)[0];
214 wm->_scumm->mouse.y = ((int16*)&lParam)[1];
215#endif
216 break;
217 case WM_LBUTTONDOWN:
218 wm->_scumm->_leftBtnPressed |= msClicked|msDown;
219 break;
220 case WM_LBUTTONUP:
221 wm->_scumm->_leftBtnPressed &= ~msDown;
222 break;
223 case WM_RBUTTONDOWN:
224 wm->_scumm->_rightBtnPressed |= msClicked|msDown;
225 break;
226 case WM_RBUTTONUP:
227 wm->_scumm->_rightBtnPressed &= ~msDown;
228 break;
229 default:
230 return DefWindowProc(hWnd, message, wParam, lParam);
231 }
232 return 0;
233}
234
235#if USE_GDI
236
237bool WndMan::allocateDIB(int w, int h) {
238 struct {
239 BITMAPINFOHEADER bih;
240 RGBQUAD rgb[256];
241 } d;
242
243 if (dib.hSect)
244 return true;
245
246 memset(&d.bih, 0, sizeof(d.bih));
247 d.bih.biSize = sizeof(d.bih);
248 d.bih.biWidth = w;
249 d.bih.biHeight = -h;
250 d.bih.biPlanes = 1;
251 d.bih.biBitCount = 8;
252 d.bih.biCompression = BI_RGB;
253
254 memcpy(d.rgb, dib.pal, 256*sizeof(RGBQUAD));
255 dib.new_pal=false;
256
257 dib.hSect = CreateDIBSection(0, (BITMAPINFO*)&d, DIB_RGB_COLORS, (void**)&dib.buf,
258 NULL, NULL);
259
260 return dib.hSect != NULL;
261}
262
263void WndMan::writeToScreen() {
264 RECT r;
265 HDC dc,bmpdc;
266 HBITMAP bmpOld;
267#if DEST_WIDTH==320
268 if (_vgabuf) {
269 for (int y=0; y<200; y++) {
270 memcpy(dib.buf + y*320,_vgabuf + y*320, 320);
271 }
272 }
273#endif
274
275 r.left = r.top = 0;
276 r.right = DEST_WIDTH;
277 r.bottom = DEST_HEIGHT;
278
279 dc = GetDC(hWnd);
280
281 bmpdc = CreateCompatibleDC(dc);
282 bmpOld = (HBITMAP)SelectObject(bmpdc, dib.hSect);
283
284 if (dib.new_pal) {
285 dib.new_pal = false;
286 SetDIBColorTable(bmpdc, 0, 256, dib.pal);
287 }
288
289 SetStretchBltMode(dc, BLACKONWHITE);
290
291#if DEST_WIDTH==320
292 StretchBlt(dc, r.left, r.top, r.right-r.left, r.bottom-r.top, bmpdc, 0, 0, 320,200, SRCCOPY);
293#endif
294
295
296 SelectObject(bmpdc, bmpOld);
297 DeleteDC(bmpdc);
298 ReleaseDC(hWnd, dc);
299}
300
301void WndMan::setPalette(byte *ctab, int first, int num) {
302 int i;
303
304 for (i=0; i<256; i++) {
305 dib.pal[i].rgbRed = ctab[i*3+0];
306 dib.pal[i].rgbGreen = ctab[i*3+1];
307 dib.pal[i].rgbBlue = ctab[i*3+2];
308 }
309
310 dib.new_pal = true;
311}
312
313#endif
314
315HWND globWnd;
316
317void WndMan::init() {
318
319 /* Retrieve the handle of this module */
320 hInst = GetModuleHandle(NULL);
321
322 /* Register the window class */
323 WNDCLASSEX wcex;
324 wcex.cbSize = sizeof(WNDCLASSEX);
325 wcex.style = CS_HREDRAW | CS_VREDRAW;
326 wcex.lpfnWndProc = (WNDPROC)WndProc;
327 wcex.cbClsExtra = 0;
328 wcex.cbWndExtra = 0;
329 wcex.hInstance = hInst;
330 wcex.hIcon = 0;
331 wcex.hCursor = ::LoadCursor(NULL, IDC_ARROW);
332 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
333 wcex.lpszMenuName = 0;
334 wcex.lpszClassName = "ScummVM";
335 wcex.hIconSm = 0;
336 if (!RegisterClassEx(&wcex))
337 Error("Cannot register window class!");
338
339#if USE_GDI
340 globWnd = hWnd = CreateWindow("ScummVM", "ScummVM", WS_OVERLAPPEDWINDOW,
341 CW_USEDEFAULT, CW_USEDEFAULT, DEST_WIDTH+10, DEST_HEIGHT+30, NULL, NULL, hInst, NULL);
342 SetWindowLong(hWnd, GWL_USERDATA, (long)this);
343
344 dib.pal = (RGBQUAD*)calloc(sizeof(RGBQUAD),256);
345 dib.new_pal = false;
346
347 if (!allocateDIB(DEST_WIDTH, DEST_HEIGHT))
348 Error("allocateDIB failed!");
349
350 ShowWindow(hWnd, SW_SHOW);
351#endif
352
353
354#if USE_DIRECTX
355
356 HWND hwnd;
357 globWnd = hwnd = CreateWindow("ScummVM", "ScummVM",
358 WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_SIZEBOX,
359 0, 0, 0, 0, NULL, NULL, hInst, NULL);
360 SetWindowLong(hwnd, GWL_USERDATA, (long)this);
361
362 RECT r;
363 SetRect(&r, 0, 0, SRC_WIDTH, SRC_HEIGHT);
364 AdjustWindowRectEx(&r, GetWindowStyle(hwnd), GetMenu(hwnd) != NULL, GetWindowExStyle(hwnd));
365 MoveWindow(hwnd,
366 (GetSystemMetrics(SM_CXSCREEN) - SRC_WIDTH) / 2,
367 (GetSystemMetrics(SM_CYSCREEN) - SRC_HEIGHT) / 2,
368 r.right - r.left, r.bottom - r.top, FALSE);
369 if(!ddrawInit())
370 Error("Ddraw init failed!");
371 ShowWindow(hwnd, SW_SHOW);
372#endif
373
374}
375
376
377#ifdef USE_DIRECTX
378
379
380void WndMan::ddrawUpdateBuffer()
381{
382 DDSURFACEDESC ddsd;
383 memset(&ddsd, '\0', sizeof(ddsd));
384 ddsd.dwSize = sizeof(ddsd);
385
386 HRESULT hr;
387 hr = lpddsSecondary->Lock(NULL, &ddsd, DDLOCK_WAIT|DDLOCK_WRITEONLY|DDLOCK_SURFACEMEMORYPTR, NULL);
388 if(hr == DDERR_SURFACELOST) {
389 // voir laquelle des surfaces il faut restaurer
390 lpddsPrimary->Restore();
391 lpddsSecondary->Restore();
392 // DDERR_WRONGMODE ?, si echoue reinit de tout ? voir la doc...
393 }
394 else if(hr == DD_OK) {
395 byte *p = _vgabuf ? _vgabuf : _realbuf;
396
397 DDPIXELFORMAT ddpf = ddsd.ddpfPixelFormat;
398 int Rshift = GetLowestBit(ddpf.dwRBitMask);
399 int Gshift = GetLowestBit(ddpf.dwGBitMask);
400 int Bshift = GetLowestBit(ddpf.dwBBitMask);
401
402 BYTE *dst = (BYTE*)ddsd.lpSurface;
403
404 int size = ddsd.dwHeight * ddsd.dwWidth;
405 int i = 0;
406 while(i < size) {
407 BYTE r = _scumm->_currentPalette[p[i]*3];
408 BYTE g = _scumm->_currentPalette[p[i]*3+1];
409 BYTE b = _scumm->_currentPalette[p[i]*3+2];
410
411 DWORD pixel = (r << Rshift) | (g << Gshift) | (b << Bshift);
412
413 switch(ddpf.dwRGBBitCount) {
414 case 32:
415 //dst[0] = (BYTE)((pixel & 0xFF000000) >> 24);
416 //dst[1] = (BYTE)((pixel & 0x00FF0000) >> 16);
417 //dst[2] = (BYTE)((pixel & 0x0000FF00) >> 8);
418 //dst[3] = (BYTE)((pixel & 0x000000FF));
419 *((DWORD*)dst) = pixel;
420 break;
421 case 24:
422 dst[0] = (BYTE)((pixel & 0xFF0000) >> 16);
423 dst[1] = (BYTE)((pixel & 0x00FF00) >> 8);
424 dst[2] = (BYTE)((pixel & 0x0000FF));
425 break;
426 case 16:
427 //dst[0] = (BYTE)((pixel & 0xFF00) >> 8);
428 //dst[1] = (BYTE)((pixel & 0x00FF));
429 *((WORD*)dst) = (WORD)pixel;
430 break;
431 }
432 dst += ddpf.dwRGBBitCount >> 3; // / 8
433
434 i++;
435 }
436 lpddsSecondary->Unlock(NULL);
437 }
438}
439
440void WndMan::writeToScreen()
441{
442 ddrawUpdateBuffer();
443 RECT r;
444 GetWindowRect(globWnd, &r);
445 lpddsPrimary->Blt(&r, lpddsSecondary, NULL, DDBLT_WAIT, NULL);
446}
447
448
449BOOL WndMan::ddrawInit()
450{
451 DDSURFACEDESC ddsd;
452 LPDIRECTDRAWCLIPPER lpddc;
453
454 if(DirectDrawCreate(NULL, &lpdd, NULL) != DD_OK)
455 return FALSE;
456
457 if(lpdd->SetCooperativeLevel(globWnd, DDSCL_NORMAL) != DD_OK)
458 return FALSE;
459
460 memset(&ddsd, '\0', sizeof(ddsd));
461 ddsd.dwSize = sizeof(ddsd);
462 ddsd.dwFlags = DDSD_CAPS;
463 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_VIDEOMEMORY;
464 if(lpdd->CreateSurface(&ddsd, &lpddsPrimary, NULL) != DD_OK)
465 return FALSE;
466
467 if(lpdd->CreateClipper(0, &lpddc, NULL) != DD_OK)
468 return FALSE;
469 if(lpddc->SetHWnd(0, globWnd) != DD_OK)
470 return FALSE;
471 if(lpddsPrimary->SetClipper(lpddc) != DD_OK)
472 return FALSE;
473 lpddc->Release();
474
475 memset(&ddsd, '\0', sizeof(ddsd));
476 ddsd.dwSize = sizeof(ddsd);
477 ddsd.dwFlags = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT;
478 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
479 ddsd.dwWidth = SRC_WIDTH;
480 ddsd.dwHeight = SRC_HEIGHT;
481 if(lpdd->CreateSurface(&ddsd, &lpddsSecondary, NULL) != DD_OK)
482 return FALSE;
483
484 memset(_realbuf, '\0', sizeof(_realbuf));
485 return TRUE;
486}
487
488
489void WndMan::ddrawReleaseSurfaces()
490{
491 if(lpddsPrimary != NULL) lpddsPrimary->Release();
492 if(lpddsSecondary != NULL) lpddsSecondary->Release();
493}
494
495
496void WndMan::ddrawRelease()
497{
498 ddrawReleaseSurfaces();
499 if(lpdd != NULL) lpdd->Release();
500}
501#endif
502
503
504
505bool WndMan::handleMessage() {
506 MSG msg;
507
508 if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
509 return false;
510
511 if (msg.message==WM_QUIT) {
512 terminated=true;
513 exit(1);
514 return true;
515 }
516
517 TranslateMessage(&msg);
518 DispatchMessage(&msg);
519
520 return true;
521}
522
523
524#if USE_DIRECTX
525unsigned long rdtsc_timer;
526
527void _declspec(naked) beginpentiumtest() {
528 _asm {
529 rdtsc
530 mov rdtsc_timer,eax
531 ret
532 }
533}
534
535int _declspec(naked) endpentiumtest() {
536 _asm {
537 rdtsc
538 sub eax,rdtsc_timer
539 ret
540 }
541}
542#endif
543
544void decompressMask(byte *d, byte *s, int w=320, int h=144) {
545 int x,y;
546
547 for (y=0; y<h; y++) {
548 byte *p = s+y*40;
549 byte *pd = d + y*320;
550 byte bits = 0x80, bdata = *p++;
551 for (x=0; x<w; x++) {
552 *pd++ = (bdata & bits) ? 128 : 0;
553 bits>>=1;
554 if (!bits) {
555 bdata = *p++;
556 bits=0x80;
557 }
558 }
559 }
560}
561
562void outputlittlemask(byte *mask, int w, int h) {
563 byte *old = wm->_vgabuf;
564 wm->_vgabuf = NULL;
565#if !(USE_DIRECTX)
566 decompressMask(wm->dib.buf, mask, w, h);
567#else
568 memset(wm->_realbuf, '\0', sizeof(wm->_realbuf));
569 decompressMask(wm->_realbuf, mask, w, h);
570#endif
571 wm->writeToScreen();
572 wm->_vgabuf = old;
573}
574
575void outputdisplay2(Scumm *s, int disp) {
576 byte *old = wm->_vgabuf;
577
578 byte buf[64000];
579
580 switch(disp) {
581 case 0:
582 wm->_vgabuf = buf;
583 memcpy(buf, wm->_vgabuf, 64000);
584 memcpy(buf,s->getResourceAddress(rtBuffer, 5),320*200);
585 break;
586 case 1:
587 wm->_vgabuf = buf;
588 memcpy(buf, wm->_vgabuf, 64000);
589 memcpy(buf,s->getResourceAddress(rtBuffer, 1),320*200);
590 break;
591 case 2:
592 wm->_vgabuf = NULL;
593#if !(USE_DIRECTX)
594 decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+s->_screenStartStrip);
595#else
596 memset(wm->_realbuf, '\0', sizeof(wm->_realbuf));
597 decompressMask(wm->_realbuf, s->getResourceAddress(rtBuffer, 9)+s->_screenStartStrip);
598#endif
599 break;
600 case 3:
601 wm->_vgabuf = NULL;
602#if !(USE_DIRECTX)
603 decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+8160+s->_screenStartStrip);
604#else
605 memset(wm->_realbuf, '\0', sizeof(wm->_realbuf));
606 decompressMask(wm->_realbuf, s->getResourceAddress(rtBuffer, 9)+8160+s->_screenStartStrip);
607#endif
608 break;
609 case 4:
610 wm->_vgabuf = NULL;
611#if !(USE_DIRECTX)
612 decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+8160*2+s->_screenStartStrip);
613#else
614 memset(wm->_realbuf, '\0', sizeof(wm->_realbuf));
615 decompressMask(wm->_realbuf, s->getResourceAddress(rtBuffer, 9)+8160*2+s->_screenStartStrip);
616#endif
617 break;
618 case 5:
619 wm->_vgabuf = NULL;
620#if !(USE_DIRECTX)
621 decompressMask(wm->dib.buf, s->getResourceAddress(rtBuffer, 9)+8160*3+s->_screenStartStrip);
622#else
623 memset(wm->_realbuf, '\0', sizeof(wm->_realbuf));
624 decompressMask(wm->_realbuf, s->getResourceAddress(rtBuffer, 9)+8160*2+s->_screenStartStrip);
625#endif
626 break;
627 }
628 wm->writeToScreen();
629 wm->_vgabuf = old;
630}
631
632void blitToScreen(Scumm *s, byte *src,int x, int y, int w, int h) {
633 byte *dst;
634 SDL_Rect *r;
635 int i;
636
637 dst = (byte*)wm->_vgabuf + y*320 + x;
638
639 do {
640 memcpy(dst, src, w);
641 dst += 320;
642 src += 320;
643 } while (--h);
644
645}
646
647void setShakePos(Scumm *s, int shake_pos) {}
648
649
650int clock;
651
652void updateScreen(Scumm *s) {
653 if (s->_palDirtyMax != -1) {
654#if !USE_DIRECTX
655 wm->setPalette(s->_currentPalette, 0, 256);
656#endif
657 s->_palDirtyMax = -1;
658 }
659
660 wm->writeToScreen();
661}
662
663void waitForTimer(Scumm *s, int delay) {
664 wm->handleMessage();
665 if (!veryFastMode) {
666 assert(delay<5000);
667 if (s->_fastMode)
668 delay=10;
669 Sleep(delay);
670 }
671}
672
673void initGraphics(Scumm *s, bool fullScreen) {
674 if(fullScreen)
675 warning("Use SDL for fullscreen support");
676}
677
678void drawMouse(Scumm *s, int, int, int, byte*, bool) {
679}
680
681void drawMouse(Scumm *s, int x, int y, int w, int h, byte *buf, bool visible) {
682}
683
684void fill_buffer(int16 *buf, int len) {
685 scumm.mixWaves(buf, len);
686}
687
688void WndMan::prepare_header(WAVEHDR *wh, int i) {
689 memset(wh, 0, sizeof(WAVEHDR));
690 wh->lpData = (char*)malloc(BUFFER_SIZE);
691 wh->dwBufferLength = BUFFER_SIZE;
692
693 waveOutPrepareHeader(_handle, wh, sizeof(WAVEHDR));
694
695 fill_buffer((int16*)wh->lpData, wh->dwBufferLength>>1);
696 waveOutWrite(_handle, wh, sizeof(WAVEHDR));
697}
698
699void WndMan::sound_init() {
700 WAVEFORMATEX wfx;
701
702 memset(&wfx, 0, sizeof(wfx));
703 wfx.wFormatTag = WAVE_FORMAT_PCM;
704 wfx.nChannels = 1;
705 wfx.nSamplesPerSec = SAMPLES_PER_SEC;
706 wfx.nAvgBytesPerSec = SAMPLES_PER_SEC * BITS_PER_SAMPLE / 8;
707 wfx.wBitsPerSample = BITS_PER_SAMPLE;
708 wfx.nBlockAlign = BITS_PER_SAMPLE * 1 / 8;
709
710 CreateThread(NULL, 0, (unsigned long (__stdcall *)(void *))&sound_thread, this, 0, &_threadId);
711 SetThreadPriority((void*)_threadId, THREAD_PRIORITY_HIGHEST);
712
713 _event = CreateEvent(NULL, false, false, NULL);
714
715 memset(_hdr,0,sizeof(_hdr));
716
717 waveOutOpen(&_handle, WAVE_MAPPER, &wfx, (long)_event, (long)this, CALLBACK_EVENT );
718
719 prepare_header(&_hdr[0], 0);
720 prepare_header(&_hdr[1], 1);
721}
722
723DWORD _stdcall WndMan::sound_thread(WndMan *wm) {
724 int i;
725 bool signaled;
726 int time = GetTickCount(), cur;
727
728 while (1) {
729
730 if (!snd_driv.wave_based()) {
731 cur = GetTickCount();
732 while (time < cur) {
733 sound.on_timer();
734 time += 10;
735 }
736 }
737
738 signaled = WaitForSingleObject(wm->_event, time - cur) == WAIT_OBJECT_0;
739
740 if (signaled) {
741 for(i=0; i<2; i++) {
742 WAVEHDR *hdr = &wm->_hdr[i];
743 if (hdr->dwFlags & WHDR_DONE) {
744 fill_buffer((int16*)hdr->lpData, hdr->dwBufferLength>>1);
745 waveOutWrite(wm->_handle, hdr, sizeof(WAVEHDR));
746 }
747 }
748 }
749 }
750}
751
752
753#undef main
754int main(int argc, char* argv[]) {
755 int delta;
756
757 wm->init();
758 wm->_vgabuf = (byte*)calloc(320,200);
759 wm->_scumm = &scumm;
760
761 sound.initialize(&scumm,&snd_driv);
762
763 wm->sound_init();
764
765 scumm._gui = &gui;
766 scumm.scummMain(argc, argv);
767 gui.init(&scumm);
768
769 delta = 0;
770 do {
771 updateScreen(&scumm);
772
773 waitForTimer(&scumm, delta*15);
774
775 if (gui._active) {
776 gui.loop();
777 delta = 3;
778 } else {
779 delta = scumm.scummLoop(delta);
780 }
781 } while(1);
782
783 return 0;
784}
785