Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
716 lvd 1
#include "std.h"
2
 
3
#include "resource.h"
4
#include "emul.h"
5
#include "vars.h"
6
#include "init.h"
7
#include "dx.h"
8
#include "draw.h"
9
#include "dxrend.h"
10
#include "dxrendch.h"
11
#include "dxrframe.h"
12
#include "dxr_text.h"
13
#include "dxr_rsm.h"
14
#include "dxr_advm.h"
15
#include "dxovr.h"
16
#include "dxerr.h"
17
#include "sound.h"
18
#include "savesnd.h"
19
#include "emulkeys.h"
20
#include "util.h"
21
 
22
unsigned char active = 0, pause = 0;
23
 
24
static const DWORD SCU_SCALE1 = 0x10;
25
static const DWORD SCU_SCALE2 = 0x20;
26
static const DWORD SCU_SCALE3 = 0x30;
27
static const DWORD SCU_SCALE4 = 0x40;
28
static const DWORD SCU_LOCK_MOUSE = 0x50;
29
 
30
#define MAXDSPIECE (48000*4/20)
31
#define DSBUFFER_SZ (2*conf.sound.fq*4)
32
 
33
#define SLEEP_DELAY 2
34
 
35
static HMODULE D3d9Dll = 0;
36
static IDirect3D9 *D3d9 = 0;
37
static IDirect3DDevice9 *D3dDev = 0;
38
static IDirect3DTexture9 *Texture = 0;
39
static IDirect3DSurface9 *SurfTexture = 0;
40
 
41
LPDIRECTDRAW2 dd;
42
LPDIRECTDRAWSURFACE sprim, surf0, surf1, surf2;
43
static PVOID SurfMem1 = 0;
44
static ULONG SurfPitch1 = 0;
45
 
46
LPDIRECTINPUTDEVICE dikeyboard;
47
LPDIRECTINPUTDEVICE dimouse;
48
LPDIRECTINPUTDEVICE2 dijoyst;
49
 
50
LPDIRECTSOUND ds;
51
LPDIRECTSOUNDBUFFER dsbf;
52
LPDIRECTDRAWPALETTE pal;
53
LPDIRECTDRAWCLIPPER clip;
54
 
55
static HANDLE EventBufStop = 0;
56
unsigned dsoffset, dsbuffer_sz;
57
 
58
static void FlipBltAlign4();
59
static void FlipBltAlign16();
60
 
61
static void (*FlipBltMethod)() = 0;
62
 
63
static void StartD3d(HWND Wnd);
64
static void DoneD3d(bool DeInitDll = true);
65
static void SetVideoModeD3d(bool Exclusive);
66
 
67
/* ---------------------- renders ------------------------- */
68
 
69
RENDER renders[] =
70
{
71
   { "Normal",                    render_small,   "normal",    RF_DRIVER | RF_1X },
72
   { "Double size",               render_dbl,     "double",    RF_DRIVER | RF_2X },
73
   { "Triple size",               render_3x,      "triple",    RF_DRIVER | RF_3X },
74
   { "Quad size",                 render_quad,    "quad",      RF_DRIVER | RF_4X },
75
   { "Anti-Text64",               render_text,    "text",      RF_DRIVER | RF_2X | RF_USEFONT },
76
   { "Frame resampler",           render_rsm,     "resampler", RF_DRIVER | RF_8BPCH },
77
 
78
   { "TV Emulation",              render_tv,      "tv",        RF_YUY2 | RF_OVR },
79
   { "Bilinear filter (MMX,fullscr)", render_bil, "bilinear",  RF_2X | RF_PALB },
80
   { "Vector scaling (fullscr)",  render_scale,   "scale",     RF_2X },
81
   { "AdvMAME scale (fullscr)",   render_advmame, "advmame",   RF_DRIVER },
82
 
83
   { "Chunky overlay (fast!)",    render_ch_ov,   "ch_ov",     RF_OVR | 0*RF_128x96 | 0*RF_64x48 | RF_BORDER | RF_USE32AS16 },
84
   { "Chunky 32bit hardware (flt,fullscr)", render_ch_hw,   "ch_hw",     RF_CLIP | 0*RF_128x96 | 0*RF_64x48 | RF_BORDER | RF_32 | RF_USEC32 },
85
 
86
   { "Chunky 16bit, low-res, (flt,fullscr)",render_c16bl,   "ch_bl",     RF_16 | RF_BORDER | RF_USEC32 },
87
   { "Chunky 16bit, hi-res, (flt,fullscr)", render_c16b,    "ch_b",      RF_16 | RF_2X | RF_BORDER | RF_USEC32 },
88
   { "Ch4x4 true color (fullscr)",render_c4x32b,  "ch4true",   RF_32 | RF_2X | RF_BORDER | RF_USEC32 },
89
 
90
   { 0,0,0,0 }
91
};
92
 
93
size_t renders_count = _countof(renders);
94
 
95
const RENDER drivers[] =
96
{
97
   { "video memory (8bpp)",  0, "ddraw",  RF_8 },
98
   { "video memory (16bpp)", 0, "ddrawh", RF_16 },
99
   { "video memory (32bpp)", 0, "ddrawt", RF_32 },
100
   { "gdi device context",   0, "gdi",    RF_GDI },
101
   { "overlay",              0, "ovr",    RF_OVR },
102
   { "hardware blitter",     0, "blt",    RF_CLIP },
103
   { "hardware 3d",          0, "d3d",    RF_D3D },
104
   { "hardware 3d exclusive",0, "d3de",   RF_D3DE },
105
   { 0,0,0,0 }
106
};
107
 
108
inline void switch_video()
109
{
110
   static unsigned char eff7 = -1;
111
   if ((comp.pEFF7 ^ eff7) & EFF7_HWMC)
112
   {
113
       video_timing_tables();
114
       eff7 = comp.pEFF7;
115
   }
116
}
117
 
118
static void FlipGdi()
119
{
120
    if (needclr)
121
    {
122
        needclr--;
123
        gdi_frame();
124
    }
125
    renders[conf.render].func(gdibuf, temp.ox*temp.obpp/8); // render to memory buffer
126
    // copy bitmap to gdi dc
127
    SetDIBitsToDevice(temp.gdidc, temp.gx, temp.gy, temp.ox, temp.oy, 0, 0, 0, temp.oy, gdibuf, &gdibmp.header, DIB_RGB_COLORS);
128
}
129
 
130
static void FlipBltAlign16()
131
{
132
   // Отрисовка в буфер выравненный на 16 байт (необходимо для запси через sse2)
133
   renders[conf.render].func(PUCHAR(SurfMem1), SurfPitch1);
134
 
135
restore_lost:;
136
   DDSURFACEDESC desc;
137
   desc.dwSize = sizeof(desc);
138
   HRESULT r = surf1->Lock(0, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_WRITEONLY, 0);
139
   if (r != DD_OK)
140
   {
141
       if(r == DDERR_SURFACELOST)
142
       {
143
           surf1->Restore();
144
           HRESULT r2 = surf1->IsLost();
145
           if(r2 == DDERR_SURFACELOST)
146
               Sleep(1);
147
 
148
           if(r2 == DD_OK || r2 == DDERR_SURFACELOST)
149
               goto restore_lost;
150
       }
151
       if (!active)
152
           return;
153
       printrdd("IDirectDrawSurface2::Lock() [buffer]", r);
154
       exit();
155
   }
156
 
157
   PUCHAR SrcPtr, DstPtr;
158
   SrcPtr = PUCHAR(SurfMem1);
159
   DstPtr = PUCHAR(desc.lpSurface);
160
 
161
   size_t LineSize = temp.ox * (temp.obpp >> 3);
162
   for(unsigned y = 0; y < temp.oy; y++)
163
   {
164
       memcpy(DstPtr, SrcPtr, LineSize);
165
       SrcPtr += SurfPitch1;
166
       DstPtr += desc.lPitch;
167
   }
168
 
169
   r = surf1->Unlock(0);
170
   if(r != DD_OK)
171
   {
172
       if(r == DDERR_SURFACELOST)
173
       {
174
           surf1->Restore();
175
           HRESULT r2 = surf1->IsLost();
176
           if(r2 == DDERR_SURFACELOST)
177
               Sleep(1);
178
 
179
           if(r2 == DD_OK || r2 == DDERR_SURFACELOST)
180
               goto restore_lost;
181
       }
182
       printrdd("IDirectDrawSurface2::Unlock() [buffer]", r);
183
       exit();
184
   }
185
}
186
 
187
static void FlipBltAlign4()
188
{
189
restore_lost:;
190
   DDSURFACEDESC desc;
191
   desc.dwSize = sizeof(desc);
192
   HRESULT r = surf1->Lock(0, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_WRITEONLY, 0);
193
   if (r != DD_OK)
194
   {
195
       if(r == DDERR_SURFACELOST)
196
       {
197
           surf1->Restore();
198
           HRESULT r2 = surf1->IsLost();
199
           if(r2 == DDERR_SURFACELOST)
200
               Sleep(1);
201
 
202
           if(r2 == DD_OK || r2 == DDERR_SURFACELOST)
203
               goto restore_lost;
204
       }
205
       if (!active)
206
           return;
207
       printrdd("IDirectDrawSurface2::Lock() [buffer]", r);
208
       exit();
209
   }
210
 
211
   // Отрисовка в буфер выравненный на 4 байта
212
   renders[conf.render].func(PUCHAR(desc.lpSurface), desc.lPitch);
213
 
214
   r = surf1->Unlock(0);
215
   if(r != DD_OK)
216
   {
217
       if(r == DDERR_SURFACELOST)
218
       {
219
           surf1->Restore();
220
           HRESULT r2 = surf1->IsLost();
221
           if(r2 == DDERR_SURFACELOST)
222
               Sleep(1);
223
 
224
           if(r2 == DD_OK || r2 == DDERR_SURFACELOST)
225
               goto restore_lost;
226
       }
227
       printrdd("IDirectDrawSurface2::Unlock() [buffer]", r);
228
       exit();
229
   }
230
}
231
 
232
static bool CalcFlipRect(LPRECT R)
233
{
234
   int w = temp.client.right - temp.client.left;
235
   int h = temp.client.bottom - temp.client.top;
236
   int n = min(w / temp.ox, h / temp.oy);
237
 
238
   POINT P = { 0, 0 };
239
   ClientToScreen(wnd, &P);
240
   int x0 = P.x;
241
   int y0 = P.y;
242
   R->left = (w - (temp.ox*n)) / 2;
243
   R->right = (w + (temp.ox*n)) / 2;
244
   R->top =  (h - (temp.oy*n)) / 2;
245
   R->bottom = (h + (temp.oy*n)) / 2;
246
   OffsetRect(R, x0, y0);
247
   return IsRectEmpty(R) == FALSE;
248
}
249
 
250
static void FlipBlt()
251
{
252
   HRESULT r;
253
 
254
restore_lost:;
255
   FlipBltMethod();
256
 
257
   assert(!IsRectEmpty(&temp.client));
258
 
259
   static int cnt = 0;
260
 
261
   DDBLTFX Fx;
262
   Fx.dwSize = sizeof(Fx);
263
   Fx.dwDDFX = 0;
264
 
265
   RECT R;
266
   if(!CalcFlipRect(&R))
267
       return;
268
 
269
   // Очистка back буфера
270
   Fx.dwFillColor = 0;
271
   r = surf2->Blt(0, 0, 0, DDBLT_WAIT | DDBLT_ASYNC |  DDBLT_COLORFILL, &Fx);
272
   if (r != DD_OK)
273
   {
274
       if(r == DDERR_SURFACELOST)
275
       {
276
           surf2->Restore();
277
           if(surf2->IsLost() == DDERR_SURFACELOST)
278
               Sleep(1);
279
           goto restore_lost;
280
       }
281
       printrdd("IDirectDrawSurface2::Blt(1)", r);
282
       exit();
283
   }
284
 
285
   // Рисование картинки с масштабированием в n раз из surf1 (320x240) -> surf2 (размер экрана)
286
   r = surf2->Blt(&R, surf1, 0, DDBLT_WAIT | DDBLT_ASYNC | DDBLT_DDFX, &Fx);
287
   if (r != DD_OK)
288
   {
289
       if(r == DDERR_SURFACELOST)
290
       {
291
           surf1->Restore();
292
           surf2->Restore();
293
           if(surf1->IsLost() == DDERR_SURFACELOST || surf2->IsLost() == DDERR_SURFACELOST)
294
               Sleep(1);
295
           goto restore_lost;
296
       }
297
       printrdd("IDirectDrawSurface2::Blt(2)", r);
298
       exit();
299
   }
300
 
301
   // Копирование surf2 на surf0 (экран, размер экрана)
302
   r = surf0->Blt(0, surf2, 0, DDBLT_WAIT | DDBLT_ASYNC | DDBLT_DDFX, &Fx);
303
   if (r != DD_OK)
304
   {
305
       if(r == DDERR_SURFACELOST)
306
       {
307
           surf0->Restore();
308
           surf2->Restore();
309
           if(surf0->IsLost() == DDERR_SURFACELOST || surf2->IsLost() == DDERR_SURFACELOST)
310
               Sleep(1);
311
           goto restore_lost;
312
       }
313
       printrdd("IDirectDrawSurface2::Blt(3)", r);
314
       exit();
315
   }
316
}
317
 
318
static bool CalcFlipRectD3d(LPRECT R)
319
{
320
   int w = temp.client.right - temp.client.left;
321
   int h = temp.client.bottom - temp.client.top;
322
   int n = min(w / temp.ox, h / temp.oy);
323
 
324
   R->left = (w - (temp.ox*n)) / 2;
325
   R->right = (w + (temp.ox*n)) / 2;
326
   R->top =  (h - (temp.oy*n)) / 2;
327
   R->bottom = (h + (temp.oy*n)) / 2;
328
 
329
   return IsRectEmpty(R) == FALSE;
330
}
331
 
332
static void FlipD3d()
333
{
334
    if(!SUCCEEDED(D3dDev->BeginScene()))
335
        return;
336
 
337
    HRESULT Hr;
338
    IDirect3DSurface9 *SurfBackBuffer0 = 0;
339
 
340
    Hr = D3dDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &SurfBackBuffer0);
341
    if (Hr != DD_OK)
342
    { printrdd("IDirect3DDevice9::GetBackBuffer(0)", Hr); exit(); }
343
 
344
    D3DLOCKED_RECT Rect = { 0 };
345
 
346
    Hr = SurfTexture->LockRect(&Rect, 0, D3DLOCK_DISCARD);
347
    if(FAILED(Hr))
348
    {
349
        printrdd("IDirect3DDevice9::LockRect()", Hr);
350
//        __debugbreak();
351
        exit();
352
    }
353
 
354
    renders[conf.render].func((u8 *)Rect.pBits, Rect.Pitch);
355
 
356
    SurfTexture->UnlockRect();
357
 
358
    Hr = D3dDev->ColorFill(SurfBackBuffer0, 0, D3DCOLOR_XRGB(0, 0, 0));
359
    if(FAILED(Hr))
360
    {
361
        printrdd("IDirect3DDevice9::ColorFill()", Hr);
362
//        __debugbreak();
363
        exit();
364
    }
365
 
366
    RECT R;
367
    if(!CalcFlipRectD3d(&R))
368
    {
369
        D3dDev->EndScene();
370
        SurfBackBuffer0->Release();
371
        return;
372
    }
373
 
374
    Hr = D3dDev->StretchRect(SurfTexture, 0, SurfBackBuffer0, &R, D3DTEXF_POINT);
375
    if(FAILED(Hr))
376
    {
377
        printrdd("IDirect3DDevice9::StretchRect()", Hr);
378
//        __debugbreak();
379
        exit();
380
    }
381
    D3dDev->EndScene();
382
 
383
    // Present the backbuffer contents to the display
384
    Hr = D3dDev->Present(0, 0, 0, 0);
385
    SurfBackBuffer0->Release();
386
 
387
    if(FAILED(Hr))
388
    {
389
        if(Hr == D3DERR_DEVICELOST)
390
        {
391
            SetVideoModeD3d((temp.rflags & RF_D3DE) != 0);
392
            return;
393
        }
394
 
395
        printrdd("IDirect3DDevice9::Present()", Hr);
396
//        __debugbreak();
397
        exit();
398
    }
399
}
400
 
401
static void FlipVideoMem()
402
{
403
   // draw direct to video memory, overlay
404
   LPDIRECTDRAWSURFACE drawsurf = conf.flip ? surf1 : surf0;
405
 
406
   DDSURFACEDESC desc;
407
   desc.dwSize = sizeof desc;
408
restore_lost:;
409
   HRESULT r = drawsurf->Lock(0, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT | DDLOCK_WRITEONLY, 0);
410
   if (r != DD_OK)
411
   {
412
      if (!active)
413
          return;
414
      if(r == DDERR_SURFACELOST)
415
      {
416
          drawsurf->Restore();
417
          if(drawsurf->IsLost() == DDERR_SURFACELOST)
418
              Sleep(1);
419
          goto restore_lost;
420
      }
421
      printrdd("IDirectDrawSurface2::Lock()", r);
422
      if (!exitflag)
423
          exit();
424
   }
425
   if (needclr)
426
   {
427
       needclr--;
428
       _render_black((unsigned char*)desc.lpSurface, desc.lPitch);
429
   }
430
   renders[conf.render].func((unsigned char*)desc.lpSurface + desc.lPitch*temp.ody + temp.odx, desc.lPitch);
431
   drawsurf->Unlock(0);
432
 
433
   if (conf.flip) // draw direct to video memory
434
   {
435
      r = surf0->Flip(0, DDFLIP_WAIT);
436
      if (r != DD_OK)
437
      {
438
          if(r == DDERR_SURFACELOST)
439
          {
440
              surf0->Restore();
441
              if(surf0->IsLost() == DDERR_SURFACELOST)
442
                  Sleep(1);
443
              goto restore_lost;
444
          }
445
          printrdd("IDirectDrawSurface2::Flip()", r);
446
          exit();
447
      }
448
   }
449
}
450
 
451
void flip()
452
{
453
   if(temp.Minimized)
454
       return;
455
   switch_video();
456
 
457
   if (conf.flip && (temp.rflags & (RF_GDI | RF_CLIP)))
458
      dd->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, 0);
459
 
460
   if (temp.rflags & RF_GDI) // gdi
461
   {
462
      FlipGdi();
463
      return;
464
   }
465
 
466
   if (surf0 && surf0->IsLost() == DDERR_SURFACELOST)
467
       surf0->Restore();
468
   if (surf1 && surf1->IsLost() == DDERR_SURFACELOST)
469
       surf1->Restore();
470
 
471
   if (temp.rflags & RF_CLIP) // hardware blitter
472
   {
473
      if(IsRectEmpty(&temp.client)) // client area is empty
474
          return;
475
 
476
      FlipBlt();
477
      return;
478
   }
479
 
480
   if (temp.rflags & (RF_D3D | RF_D3DE)) // direct 3d
481
   {
482
      if(IsRectEmpty(&temp.client)) // client area is empty
483
          return;
484
 
485
      FlipD3d();
486
      return;
487
   }
488
 
489
   // draw direct to video memory, overlay
490
   FlipVideoMem();
491
}
492
 
493
static HWAVEOUT hwo = 0;
494
static WAVEHDR wq[MAXWQSIZE];
495
static unsigned char wbuffer[MAXWQSIZE*MAXDSPIECE];
496
static unsigned wqhead, wqtail;
497
 
498
void __fastcall do_sound_none()
499
{
500
 
501
}
502
 
503
void __fastcall do_sound_wave()
504
{
505
   HRESULT r;
506
 
507
   for (;;) // release all done items
508
   {
509
      while ((wqtail != wqhead) && (wq[wqtail].dwFlags & WHDR_DONE))
510
      { // ready!
511
         if ((r = waveOutUnprepareHeader(hwo, &wq[wqtail], sizeof(WAVEHDR))) != MMSYSERR_NOERROR)
512
         {
513
             printrmm("waveOutUnprepareHeader()", r);
514
             exit();
515
         }
516
         if (++wqtail == conf.soundbuffer)
517
             wqtail = 0;
518
      }
519
      if ((wqhead+1)%conf.soundbuffer != wqtail)
520
          break; // some empty item in queue
521
/* [vv]
522
*/
523
      if (conf.sleepidle)
524
          Sleep(SLEEP_DELAY);
525
   }
526
 
527
   if(!spbsize)
528
       return;
529
 
530
//   __debugbreak();
531
   // put new item and play
532
   PCHAR bfpos = PCHAR(wbuffer + wqhead*MAXDSPIECE);
533
   memcpy(bfpos, sndplaybuf, spbsize);
534
   wq[wqhead].lpData = bfpos;
535
   wq[wqhead].dwBufferLength = spbsize;
536
   wq[wqhead].dwFlags = 0;
537
 
538
   if ((r = waveOutPrepareHeader(hwo, &wq[wqhead], sizeof(WAVEHDR))) != MMSYSERR_NOERROR)
539
   {
540
       printrmm("waveOutPrepareHeader()", r);
541
       exit();
542
   }
543
 
544
   if ((r = waveOutWrite(hwo, &wq[wqhead], sizeof(WAVEHDR))) != MMSYSERR_NOERROR)
545
   {
546
       printrmm("waveOutWrite()", r);
547
       exit();
548
   }
549
 
550
   if (++wqhead == conf.soundbuffer)
551
       wqhead = 0;
552
 
553
//  int bs = wqhead-wqtail; if (bs<0)bs+=conf.soundbuffer; if (bs < 8) goto again;
554
 
555
}
556
 
557
// directsound part
558
// begin
559
void restore_sound_buffer()
560
{
561
//   for (;;) {
562
      DWORD status = 0;
563
      dsbf->GetStatus(&status);
564
      if (status & DSBSTATUS_BUFFERLOST)
565
      {
566
          printf("%s\n", __FUNCTION__);
567
          Sleep(18);
568
          dsbf->Restore();
569
          // Sleep(200);
570
      }
571
//      else break;
572
//   }
573
}
574
 
575
void clear_buffer()
576
{
577
//   printf("%s\n", __FUNCTION__);
578
//   __debugbreak();
579
 
580
   restore_sound_buffer();
581
   HRESULT r;
582
   void *ptr1, *ptr2;
583
   DWORD sz1, sz2;
584
   r = dsbf->Lock(0, 0, &ptr1, &sz1, &ptr2, &sz2, DSBLOCK_ENTIREBUFFER);
585
   if (r != DS_OK)
586
       return;
587
   memset(ptr1, 0, sz1);
588
   //memset(ptr2, 0, sz2);
589
   dsbf->Unlock(ptr1, sz1, ptr2, sz2);
590
}
591
 
592
int maxgap;
593
 
594
void __fastcall do_sound_ds()
595
{
596
   HRESULT r;
597
 
598
   do
599
   {
600
      int play, write;
601
      if ((r = dsbf->GetCurrentPosition((DWORD*)&play, (DWORD*)&write)) != DS_OK)
602
      {
603
         if (r == DSERR_BUFFERLOST)
604
         {
605
             restore_sound_buffer();
606
             return;
607
         }
608
 
609
         printrds("IDirectSoundBuffer::GetCurrentPosition()", r);
610
         exit();
611
      }
612
 
613
      int gap = write - play;
614
      if (gap < 0)
615
          gap += dsbuffer_sz;
616
 
617
      int pos = dsoffset - play;
618
      if (pos < 0)
619
          pos += dsbuffer_sz;
620
      maxgap = max(maxgap, gap);
621
 
622
      if (pos < maxgap || pos > 10 * (int)maxgap)
623
      {
624
         dsoffset = 3 * maxgap;
625
         clear_buffer();
626
         dsbf->Stop();
627
         dsbf->SetCurrentPosition(0);
628
         break;
629
      }
630
 
631
      if (pos < 2 * maxgap)
632
          break;
633
 
634
      if ((r = dsbf->Play(0, 0, DSBPLAY_LOOPING)) != DS_OK)
635
      {
636
          if (r == DSERR_BUFFERLOST)
637
          {
638
              restore_sound_buffer();
639
              return;
640
          }
641
 
642
          printrds("IDirectSoundBuffer::Play()", r);
643
          exit();
644
      }
645
 
646
      if ((conf.SyncMode == SM_SOUND) && conf.sleepidle)
647
          Sleep(SLEEP_DELAY);
648
   } while(conf.SyncMode == SM_SOUND);
649
 
650
   dsoffset %= dsbuffer_sz;
651
 
652
   if(!spbsize)
653
       return;
654
 
655
   void *ptr1, *ptr2;
656
   DWORD sz1, sz2;
657
   r = dsbf->Lock(dsoffset, spbsize, &ptr1, &sz1, &ptr2, &sz2, 0);
658
   if (r != DS_OK)
659
   {
660
       if (r == DSERR_BUFFERLOST)
661
       {
662
           restore_sound_buffer();
663
           return;
664
       }
665
//       __debugbreak();
666
       printf("dsbuffer_sz=%d, dsoffset=%d, spbsize=%d\n", dsbuffer_sz, dsoffset, spbsize);
667
       printrds("IDirectSoundBuffer::Lock()", r);
668
       exit();
669
   }
670
   memcpy(ptr1, sndplaybuf, sz1);
671
   if (ptr2)
672
       memcpy(ptr2, ((char *)sndplaybuf)+sz1, sz2);
673
 
674
   r = dsbf->Unlock(ptr1, sz1, ptr2, sz2);
675
   if (r != DS_OK)
676
   {
677
       if (r == DSERR_BUFFERLOST)
678
       {
679
           restore_sound_buffer();
680
           return;
681
       }
682
//       __debugbreak();
683
       printf("dsbuffer_sz=%d, dsoffset=%d, spbsize=%d\n", dsbuffer_sz, dsoffset, spbsize);
684
       printrds("IDirectSoundBuffer::Unlock()", r);
685
       exit();
686
   }
687
 
688
   dsoffset += spbsize;
689
   dsoffset %= dsbuffer_sz;
690
}
691
// directsound part
692
// end
693
 
694
static int OldRflags = 0;
695
 
696
void sound_play()
697
{
698
//   printf("%s\n", __FUNCTION__);
699
   maxgap = 2000;
700
   restart_sound();
701
}
702
 
703
 
704
void sound_stop()
705
{
706
//   printf("%s\n", __FUNCTION__);
707
//   __debugbreak();
708
   if(dsbf)
709
   {
710
      dsbf->Stop(); // don't check
711
      clear_buffer();
712
   }
713
}
714
 
715
void do_sound()
716
{
717
   if (savesndtype == 1)
718
      if (fwrite(sndplaybuf,1,spbsize,savesnd)!=spbsize)
719
         savesnddialog(); // write error - disk full - close file
720
 
721
   conf.sound.do_sound();
722
}
723
 
724
void OnEnterGui()
725
{
726
//    printf("%s->%p\n", __FUNCTION__, D3dDev);
727
    sound_stop();
728
 
729
    // Вывод GUI при активном d3d exclusive режиме
730
    // на время вывода GUI переход в non exclusive fullscreen
731
    if((temp.rflags & RF_D3DE) && D3dDev)
732
    {
733
        OldRflags = temp.rflags;
734
        SetVideoModeD3d(false);
735
        SendMessage(wnd, WM_USER, 0, 0);
736
        flip();
737
    }
738
}
739
 
740
void OnExitGui(bool RestoreVideo)
741
{
742
//    printf("%s->%p, %d\n", __FUNCTION__, D3dDev, RestoreVideo);
743
    sound_play();
744
    if(!RestoreVideo)
745
    {
746
        return;
747
    }
748
 
749
    if(!D3dDev)
750
    {
751
        return;
752
    }
753
 
754
    // Возврат из GUI в d3d exclusive режим
755
    if((temp.rflags & RF_D3DE))
756
    {
757
        SetVideoModeD3d(true);
758
    }
759
 
760
    // Переключение RF_D3DE->RF_D3D (в меню настроек переключен видеодрайвер)
761
    if((OldRflags & RF_D3DE) && (temp.rflags & RF_D3D))
762
    {
763
        SetVideoModeD3d(false);
764
    }
765
}
766
 
767
#define STATUS_PRIVILEGE_NOT_HELD        ((NTSTATUS)0xC0000061L)
768
#define SE_INC_BASE_PRIORITY_PRIVILEGE      (14L)
769
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
770
 
771
typedef NTSTATUS (NTAPI *TRtlAdjustPrivilege)(ULONG Privilege, BOOLEAN Enable, BOOLEAN Client, PBOOLEAN WasEnabled);
772
 
773
void set_priority()
774
{
775
    if (!conf.highpriority || !conf.sleepidle)
776
       return;
777
 
778
    SYSTEM_INFO SysInfo;
779
    GetSystemInfo(&SysInfo);
780
    ULONG Cpus = SysInfo.dwNumberOfProcessors;
781
 
782
    ULONG HighestPriorityClass = HIGH_PRIORITY_CLASS;
783
 
784
    if(Cpus > 1)
785
    {
786
        HMODULE NtDll = GetModuleHandle("ntdll.dll");
787
        TRtlAdjustPrivilege RtlAdjustPrivilege = (TRtlAdjustPrivilege)GetProcAddress(NtDll, "RtlAdjustPrivilege");
788
 
789
        BOOLEAN WasEnabled = FALSE;
790
        NTSTATUS Status = RtlAdjustPrivilege(SE_INC_BASE_PRIORITY_PRIVILEGE, TRUE, FALSE, &WasEnabled);
791
        if(!NT_SUCCESS(Status))
792
        {
793
            err_printf("enabling SE_INC_BASE_PRIORITY_PRIVILEGE, %X", Status);
794
            if(Status == STATUS_PRIVILEGE_NOT_HELD)
795
            {
796
                err_printf("program not run as administrator or SE_INC_BASE_PRIORITY_PRIVILEGE is not enabled via group policy");
797
            }
798
            printf("REALTIME_PRIORITY_CLASS not available, fallback to HIGH_PRIORITY_CLASS\n");
799
        }
800
        else
801
        {
802
            HighestPriorityClass = REALTIME_PRIORITY_CLASS;
803
        }
804
    }
805
 
806
    SetPriorityClass(GetCurrentProcess(), HighestPriorityClass);
807
    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
808
}
809
 
810
void adjust_mouse_cursor()
811
{
812
   unsigned showcurs = conf.input.joymouse || !active || !(conf.fullscr || conf.lockmouse) || dbgbreak;
813
   while (ShowCursor(0) >= 0); // hide cursor
814
   if (showcurs) while (ShowCursor(1) <= 0); // show cursor
815
   if (active && conf.lockmouse && !dbgbreak)
816
   {
817
      RECT rc; GetClientRect(wnd, &rc);
818
      POINT p = { rc.left, rc.top };
819
      ClientToScreen(wnd, &p); rc.left=p.x, rc.top=p.y;
820
      p.x = rc.right, p.y = rc.bottom;
821
      ClientToScreen(wnd, &p); rc.right=p.x, rc.bottom=p.y;
822
      ClipCursor(&rc);
823
   } else ClipCursor(0);
824
}
825
 
826
HCURSOR crs[9];
827
unsigned char mousedirs[9] = { 10, 8, 9, 2, 0, 1, 6, 4, 5 };
828
 
829
void updatebitmap()
830
{
831
   RECT rc;
832
   GetClientRect(wnd, &rc);
833
   DWORD newdx = rc.right - rc.left, newdy = rc.bottom - rc.top;
834
   if (hbm && (bm_dx != newdx || bm_dy != newdy))
835
   {
836
       DeleteObject(hbm);
837
       hbm = 0;
838
   }
839
   if(sprim)
840
       return; // don't trace window contents in overlay mode
841
 
842
   if(hbm)
843
   {
844
        DeleteObject(hbm);
845
        hbm = 0; // keeping bitmap is unsafe - screen paramaters may change
846
   }
847
 
848
   if(!hbm)
849
       hbm = CreateCompatibleBitmap(temp.gdidc, newdx, newdy);
850
 
851
   HDC dc = CreateCompatibleDC(temp.gdidc);
852
 
853
   bm_dx = newdx; bm_dy = newdy;
854
   HGDIOBJ PrevObj = SelectObject(dc, hbm);
855
   //SetDIBColorTable(dc, 0, 0x100, (RGBQUAD*)pal0);
856
   BitBlt(dc, 0, 0, newdx, newdy, temp.gdidc, 0, 0, SRCCOPY);
857
   SelectObject(dc, PrevObj);
858
   DeleteDC(dc);
859
}
860
 
861
/*
862
 movesize.c
863
 These values are indexes that represent rect sides. These indexes are
864
 used as indexes into rgimpiwx and rgimpiwy (which are indexes into the
865
 the rect structure) which tell the move code where to store the new x & y
866
 coordinates. Notice that when two of these values that represent sides
867
 are added together, we get a unique list of contiguous values starting at
868
 1 that represent all the ways we can size a rect. That also leaves 0 free
869
 a initialization value.
870
 
871
 The reason we need rgimpimpiw is for the keyboard interface - we
872
 incrementally decide what our 'move command' is. With the mouse interface
873
 we know immediately because we registered a mouse hit on the segment(s)
874
 we're moving.
875
 
876
     4           5
877
      \ ___3___ /
878
       |       |
879
       1       2
880
       |_______|
881
      /    6    \
882
     7           8
883
*/
884
 
885
static const int rgimpimpiw[] = {1, 3, 2, 6};
886
static const int rgimpiwx[]   =
887
{
888
   0, // WMSZ_KEYSIZE
889
   0, // WMSZ_LEFT
890
   2, // WMSZ_RIGHT
891
  -1, // WMSZ_TOP
892
   0, // WMSZ_TOPLEFT
893
   2, // WMSZ_TOPRIGHT
894
  -1, // WMSZ_BOTTOM
895
   0, // WMSZ_BOTTOMLEFT
896
   2, // WMSZ_BOTTOMRIGHT
897
 
898
};
899
static const int rgimpiwy[]   = {0, -1, -1,  1, 1, 1,  3, 3, 3, 1};
900
 
901
#define WMSZ_KEYSIZE        0           // ;Internal
902
#define WMSZ_LEFT           1
903
#define WMSZ_RIGHT          2
904
#define WMSZ_TOP            3
905
#define WMSZ_TOPLEFT        4
906
#define WMSZ_TOPRIGHT       5
907
#define WMSZ_BOTTOM         6
908
#define WMSZ_BOTTOMLEFT     7
909
#define WMSZ_BOTTOMRIGHT    8
910
#define WMSZ_MOVE           9           // ;Internal
911
#define WMSZ_KEYMOVE        10          // ;Internal
912
#define WMSZ_SIZEFIRST      WMSZ_LEFT   // ;Internal
913
 
914
struct MOVESIZEDATA
915
{
916
    RECT rcDragCursor;
917
    POINT ptMinTrack;
918
    POINT ptMaxTrack;
919
    int cmd;
920
};
921
 
922
static void SizeRectX(MOVESIZEDATA *Msd, ULONG Pt)
923
{
924
    PINT psideDragCursor = ((PINT)(&Msd->rcDragCursor));
925
    /*
926
     * DO HORIZONTAL
927
     */
928
 
929
    /*
930
     * We know what part of the rect we're moving based on
931
     * what's in cmd.  We use cmd as an index into rgimpiw? which
932
     * tells us what part of the rect we're dragging.
933
     */
934
 
935
    /*
936
     * Get the approriate array entry.
937
     */
938
    int index = (int)rgimpiwx[Msd->cmd];   // AX
939
//    printf("Msd.cmd = %d, idx_x=%d\n", Msd->cmd, index);
940
 
941
    /*
942
     * Is it one of the entries we don't map (i.e.  -1)?
943
     */
944
    if (index < 0)
945
        return;
946
 
947
    psideDragCursor[index] = GET_X_LPARAM(Pt);
948
 
949
    int indexOpp = index ^ 0x2;
950
 
951
    /*
952
     * Now check to see if we're below the min or above the max. Get the width
953
     * of the rect in this direction (either x or y) and see if it's bad. If
954
     * so, map the side we're moving to the min or max.
955
     */
956
    int w = psideDragCursor[index] - psideDragCursor[indexOpp];
957
 
958
    if (indexOpp & 0x2)
959
    {
960
        w = -w;
961
    }
962
 
963
    int x;
964
    if(w < Msd->ptMinTrack.x)
965
    {
966
        x = Msd->ptMinTrack.x;
967
    }
968
    else if(w > Msd->ptMaxTrack.x)
969
    {
970
        x = Msd->ptMaxTrack.x;
971
    }
972
    else
973
    {
974
        return;
975
    }
976
 
977
    if (indexOpp & 0x2)
978
    {
979
        x = -x;
980
    }
981
 
982
    psideDragCursor[index] = x + psideDragCursor[indexOpp];
983
}
984
 
985
static void SizeRectY(MOVESIZEDATA *Msd, ULONG Pt)
986
{
987
    PINT psideDragCursor = ((PINT)(&Msd->rcDragCursor));
988
    /*
989
     * DO VERTICAL
990
     */
991
 
992
    /*
993
     * We know what part of the rect we're moving based on
994
     * what's in cmd.  We use cmd as an index into rgimpiw? which
995
     * tells us what part of the rect we're dragging.
996
     */
997
 
998
    /*
999
     * Get the approriate array entry.
1000
     */
1001
    int index = (int)rgimpiwy[Msd->cmd];   // AX
1002
 
1003
//    printf("idx_y=%d\n", index);
1004
    /*
1005
     * Is it one of the entries we don't map (i.e.  -1)?
1006
     */
1007
    if (index < 0)
1008
        return;
1009
 
1010
    psideDragCursor[index] = GET_Y_LPARAM(Pt);
1011
 
1012
    int indexOpp = index ^ 0x2;
1013
 
1014
    /*
1015
     * Now check to see if we're below the min or above the max. Get the width
1016
     * of the rect in this direction (either x or y) and see if it's bad. If
1017
     * so, map the side we're moving to the min or max.
1018
     */
1019
    int h = psideDragCursor[index] - psideDragCursor[indexOpp];
1020
 
1021
    if (indexOpp & 0x2)
1022
    {
1023
        h = -h;
1024
    }
1025
 
1026
    int y;
1027
    if(h < Msd->ptMinTrack.y)
1028
    {
1029
        y = Msd->ptMinTrack.y;
1030
    }
1031
    else if(h > Msd->ptMaxTrack.y)
1032
    {
1033
        y  = Msd->ptMaxTrack.y;
1034
    }
1035
    else
1036
    {
1037
        return;
1038
    }
1039
 
1040
    if (indexOpp & 0x2)
1041
    {
1042
        y = -y;
1043
    }
1044
 
1045
    psideDragCursor[index] = y + psideDragCursor[indexOpp];
1046
}
1047
 
1048
static void SizeRect(MOVESIZEDATA *Msd, ULONG Pt)
1049
{
1050
    if(Msd->cmd >= _countof(rgimpiwx))
1051
    {
1052
        return;
1053
    }
1054
 
1055
    SizeRectX(Msd, Pt);
1056
    SizeRectY(Msd, Pt);
1057
}
1058
 
1059
LRESULT CALLBACK WndProc(HWND hwnd,UINT uMessage,WPARAM wparam,LPARAM lparam)
1060
{
1061
   static bool moving = false;
1062
 
1063
   if(uMessage == WM_QUIT) // never heppens
1064
   {
1065
//       __debugbreak();
1066
//       printf("WM_QUIT\n");
1067
       exit();
1068
   }
1069
 
1070
   if(uMessage == WM_CLOSE) // never heppens
1071
   {
1072
//       __debugbreak();
1073
//       printf("WM_CLOSE\n");
1074
       return 1;
1075
   }
1076
 
1077
#if 1
1078
   if (uMessage == WM_SETFOCUS && !pause)
1079
   {
1080
      active = 1; setpal(0);
1081
//      sound_play();
1082
      adjust_mouse_cursor();
1083
      uMessage = WM_USER;
1084
   }
1085
 
1086
   if (uMessage == WM_KILLFOCUS && !pause)
1087
   {
1088
      if (dd)
1089
          dd->FlipToGDISurface();
1090
      updatebitmap();
1091
      setpal(1);
1092
      active = 0;
1093
//      sound_stop();
1094
      conf.lockmouse = 0;
1095
      adjust_mouse_cursor();
1096
   }
1097
 
1098
   if(uMessage == WM_SIZING)
1099
   {
1100
//       printf("WM_SIZING(0x%X)\n", uMessage);
1101
       return TRUE;
1102
   }
1103
 
1104
   static bool Captured = false;
1105
   static int x = 0, y = 0;
1106
   static ULONG Mode;
1107
   static MOVESIZEDATA Msd;
1108
 
1109
   if(uMessage == WM_LBUTTONUP && Captured)
1110
   {
1111
//       printf("WM_LBUTTONUP(0x%X)\n", uMessage);
1112
       Captured = false;
1113
       ReleaseCapture();
1114
       return 0;
1115
   }
1116
 
1117
   if(uMessage == WM_MOUSEMOVE)
1118
   {
1119
       if(Captured)
1120
       {
1121
//           printf("WM_MOUSEMOVE(0x%X), w=%d\n", uMessage, wparam);
1122
           if(Mode == SC_MOVE)
1123
           {
1124
               POINT p = { GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
1125
               ClientToScreen(hwnd, &p);
1126
//               printf("nx=%d,ny=%d\n", p.x, p.y);
1127
               int dx=p.x-x, dy=p.y-y;
1128
//               printf("dx=%d,dy=%d\n", dx, dy);
1129
               if(dx == 0 && dy == 0)
1130
               {
1131
                   return 0;
1132
               }
1133
               RECT r={};
1134
               GetWindowRect(hwnd, &r);
1135
               SetWindowPos(hwnd, NULL, r.left+dx, r.top+dy, 0, 0, SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSIZE | SWP_NOSENDCHANGING);
1136
               x=p.x;y=p.y;
1137
               return 0;
1138
           }
1139
           else if(Mode == SC_SIZE)
1140
           {
1141
               POINT p = { GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
1142
               ClientToScreen(hwnd, &p);
1143
               ULONG pt = (p.y << 16) | (p.x & 0xFFFF);
1144
               SizeRect(&Msd, pt);
1145
               const RECT &r = Msd.rcDragCursor;
1146
//               printf("r={%d,%d,%d,%d} [%dx%d]\n", r.left, r.top, r.right, r.bottom, r.right - r.left, r.bottom - r.top);
1147
               SetWindowPos(hwnd, NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOSENDCHANGING);
1148
               return 0;
1149
           }
1150
       }
1151
   }
1152
 
1153
   // WM_NCLBUTTONDOWN -> WM_SYSCOMMAND(SC_MOVE) -|-> WM_CAPTURECHANGED -> WM_GETMINMAXINFO -> WM_ENTERSIZEMOVE
1154
   // При получении WM_SYSCOMMAND(SC_MOVE) стандартная процедура обработки сообщения запускает модальный цикл
1155
   if(uMessage == WM_SYSCOMMAND)
1156
   {
1157
//       printf("WM_SYSCOMMAND(0x%X), w=%X, l=%X\n", uMessage, wparam, lparam);
1158
// Кодирование сторон рамки окна для SC_SIZE (код угла получается суммированием кодов смежных сторон)
1159
//     4           5
1160
//      \ ___3___ /
1161
//       |       |
1162
//       1       2
1163
//       |_______|
1164
//      /    6    \
1165
//     7           8
1166
 
1167
       ULONG Cmd = (wparam & 0xFFF0);
1168
       ULONG BrdSide = (wparam & 0xF);
1169
       if(Cmd == SC_MOVE)
1170
       {
1171
           x = GET_X_LPARAM(lparam);
1172
           y = GET_Y_LPARAM(lparam);
1173
           SetCapture(hwnd);
1174
           Captured = true;
1175
           Mode = SC_MOVE;
1176
           return 0;
1177
       }
1178
       else if(Cmd == SC_SIZE)
1179
       {
1180
           Mode = SC_SIZE;
1181
 
1182
           RECT rcWindow;
1183
           GetWindowRect(hwnd, &rcWindow);
1184
           RECT rcClient;
1185
           GetClientRect(hwnd, &rcClient);
1186
           RECT rcDesktop;
1187
           GetWindowRect(GetDesktopWindow(), &rcDesktop);
1188
 
1189
           Msd.cmd = BrdSide;
1190
           CopyRect(&Msd.rcDragCursor, &rcWindow);
1191
           LONG cw = rcClient.right - rcClient.left, ch = rcClient.bottom - rcClient.top;
1192
           LONG ww = rcWindow.right - rcWindow.left, wh = rcWindow.bottom - rcWindow.top;
1193
           LONG dw = rcDesktop.right - rcDesktop.left, dh = rcDesktop.bottom - rcDesktop.top;
1194
           //Msd.ptMinTrack = { LONG(temp.ox) + (ww - cw), LONG(temp.oy) + (wh - ch) };
1195
           Msd.ptMinTrack.x = LONG(temp.ox) + (ww - cw); // lvd
1196
           Msd.ptMinTrack.y = LONG(temp.oy) + (wh - ch); // lvd
1197
           //Msd.ptMaxTrack = { dw, dh };
1198
           Msd.ptMaxTrack.x = dw; //lvd
1199
           Msd.ptMaxTrack.y = dh; //lvd
1200
 
1201
           SetCapture(hwnd);
1202
           Captured = true;
1203
           SizeRect(&Msd, ULONG(lparam));
1204
           return 0;
1205
       }
1206
   }
1207
 
1208
/*
1209
#define WM_NCUAHDRAWCAPTION 0x00AE
1210
#define WM_NCUAHDRAWFRAME   0x00AF
1211
   if(!(uMessage == WM_SIZING || uMessage == WM_SIZE || uMessage == WM_PAINT || uMessage == WM_NCPAINT
1212
     || uMessage == WM_MOUSEMOVE || uMessage == WM_SETCURSOR || uMessage == WM_GETICON
1213
     || uMessage == WM_IME_SETCONTEXT || uMessage == WM_IME_NOTIFY || uMessage == WM_ACTIVATE
1214
     || uMessage == WM_NCUAHDRAWCAPTION || uMessage == WM_NCUAHDRAWFRAME))
1215
   {
1216
       printf("MSG(0x%X)\n", uMessage);
1217
   }
1218
*/
1219
 
1220
   if (conf.input.joymouse)
1221
   {
1222
      if (uMessage == WM_LBUTTONDOWN || uMessage == WM_LBUTTONUP)
1223
      {
1224
         input.mousejoy = (input.mousejoy & 0x0F) | (uMessage == WM_LBUTTONDOWN ? 0x10 : 0);
1225
         input.kjoy = (input.kjoy & 0x0F) | (uMessage == WM_LBUTTONDOWN ? 0x10 : 0);
1226
      }
1227
 
1228
      if (uMessage == WM_MOUSEMOVE)
1229
      {
1230
         RECT rc; GetClientRect(hwnd, &rc);
1231
         unsigned xx = LOWORD(lparam)*3/(rc.right - rc.left);
1232
         unsigned yy = HIWORD(lparam)*3/(rc.bottom - rc.top);
1233
         unsigned nn = yy*3 + xx;
1234
//         SetClassLongPtr(hwnd, GCLP_HCURSOR, (LONG)crs[nn]); //Alone Coder
1235
         SetCursor(crs[nn]); //Alone Coder
1236
         input.mousejoy = (input.mousejoy & 0x10) | mousedirs[nn];
1237
         input.kjoy = (input.kjoy & 0x10) | mousedirs[nn];
1238
         return 0;
1239
      }
1240
   }
1241
   else if (uMessage == WM_LBUTTONDOWN && !conf.lockmouse)
1242
   {
1243
//       printf("%s\n", __FUNCTION__);
1244
       input.nomouse = 20;
1245
       main_mouse();
1246
   }
1247
 
1248
   if(uMessage == WM_ENTERSIZEMOVE)
1249
   {
1250
//       printf("WM_ENTERSIZEMOVE(0x%X)\n", uMessage);
1251
       sound_stop();
1252
   }
1253
 
1254
   if(uMessage == WM_EXITSIZEMOVE)
1255
   {
1256
       sound_play();
1257
   }
1258
 
1259
   if (uMessage == WM_SIZE || uMessage == WM_MOVE || uMessage == WM_USER)
1260
   {
1261
#if 0
1262
      printf("%s(WM_SIZE || WM_MOVE || WM_USER)\n", __FUNCTION__);
1263
      RECT rr = {};
1264
      GetWindowRect(wnd, &rr);
1265
      printf("r={%d,%d,%d,%d} [%dx%d]\n", rr.left, rr.top, rr.right, rr.bottom, rr.right - rr.left, rr.bottom - rr.top);
1266
#endif
1267
 
1268
      GetClientRect(wnd, &temp.client);
1269
      temp.gdx = temp.client.right-temp.client.left;
1270
      temp.gdy = temp.client.bottom-temp.client.top;
1271
      temp.gx = (temp.gdx > temp.ox) ? (temp.gdx-temp.ox)/2 : 0;
1272
      temp.gy = (temp.gdy > temp.oy) ? (temp.gdy-temp.oy)/2 : 0;
1273
      ClientToScreen(wnd, (POINT*)&temp.client.left);
1274
      ClientToScreen(wnd, (POINT*)&temp.client.right);
1275
      adjust_mouse_cursor();
1276
      if (sprim)
1277
          uMessage = WM_PAINT;
1278
      needclr = 2;
1279
 
1280
      if((uMessage == WM_SIZE) && (wparam != SIZE_MINIMIZED) && temp.ox && temp.oy)
1281
      {
1282
          if(wnd && (temp.rflags & RF_D3D)) // skip call from CreateWindow
1283
          {
1284
//              printf("%s(WM_SIZE, temp.rflags & RF_D3D)\n", __FUNCTION__);
1285
              SetVideoModeD3d(false);
1286
          }
1287
      }
1288
   }
1289
 
1290
   if (uMessage == WM_PAINT)
1291
   {
1292
      if (sprim)
1293
      { // background for overlay
1294
         RECT rc;
1295
         GetClientRect(hwnd, &rc);
1296
         HBRUSH br = CreateSolidBrush(RGB(0xFF,0x00,0xFF));
1297
         FillRect(temp.gdidc, &rc, br);
1298
         DeleteObject(br);
1299
         update_overlay();
1300
      }
1301
      else if (hbm && !active)
1302
      {
1303
//       printf("%s, WM_PAINT\n", __FUNCTION__);
1304
         HDC hcom = CreateCompatibleDC(temp.gdidc);
1305
         HGDIOBJ PrevObj = SelectObject(hcom, hbm);
1306
         BitBlt(temp.gdidc, 0, 0, bm_dx, bm_dy, hcom, 0, 0, SRCCOPY);
1307
         SelectObject(hcom, PrevObj);
1308
         DeleteDC(hcom);
1309
      }
1310
   }
1311
 
1312
   if (uMessage == WM_SYSCOMMAND)
1313
   {
1314
//       printf("%s, WM_SYSCOMMAND 0x%04X\n", __FUNCTION__, (ULONG)wparam);
1315
 
1316
      switch(wparam & 0xFFF0)
1317
      {
1318
      case SCU_SCALE1: temp.scale = 1; wnd_resize(1);  return 0;
1319
      case SCU_SCALE2: temp.scale = 2; wnd_resize(2);  return 0;
1320
      case SCU_SCALE3: temp.scale = 3; wnd_resize(3);  return 0;
1321
      case SCU_SCALE4: temp.scale = 4; wnd_resize(4);  return 0;
1322
      case SCU_LOCK_MOUSE: main_mouse();  return 0;
1323
      case SC_CLOSE:
1324
          if(ConfirmExit())
1325
              correct_exit();
1326
      return 0;
1327
      case SC_MINIMIZE: temp.Minimized = true; break;
1328
 
1329
      case SC_RESTORE: temp.Minimized = false; break;
1330
      }
1331
   }
1332
 
1333
   if (uMessage == WM_DROPFILES)
1334
   {
1335
      HDROP hDrop = (HDROP)wparam;
1336
      DragQueryFile(hDrop, 0, droppedFile, sizeof(droppedFile));
1337
      DragFinish(hDrop);
1338
      return 0;
1339
   }
1340
#endif
1341
 
1342
   return DefWindowProc(hwnd, uMessage, wparam, lparam);
1343
}
1344
 
1345
void readdevice(VOID *md, DWORD sz, LPDIRECTINPUTDEVICE dev)
1346
{
1347
   if (!active || !dev)
1348
       return;
1349
   HRESULT r = dev->GetDeviceState(sz, md);
1350
   if(r == DIERR_INPUTLOST || r == DIERR_NOTACQUIRED)
1351
   {
1352
      r = dev->Acquire();
1353
      while(r == DIERR_INPUTLOST)
1354
          r = dev->Acquire();
1355
 
1356
      if(r == DIERR_OTHERAPPHASPRIO) // Приложение находится в background
1357
          return;
1358
 
1359
      if (r != DI_OK)
1360
      {
1361
          printrdi("IDirectInputDevice::Acquire()", r);
1362
          exit();
1363
      }
1364
      r = dev->GetDeviceState(sz, md);
1365
   }
1366
   if(r != DI_OK)
1367
   {
1368
       printrdi("IDirectInputDevice::GetDeviceState()", r);
1369
       exit();
1370
   }
1371
}
1372
 
1373
void readmouse(DIMOUSESTATE *md)
1374
{
1375
   memset(md, 0, sizeof *md);
1376
   readdevice(md, sizeof *md, dimouse);
1377
}
1378
 
1379
void ReadKeyboard(PVOID KbdData)
1380
{
1381
    readdevice(KbdData, 256, dikeyboard);
1382
}
1383
 
1384
void setpal(char system)
1385
{
1386
   if (!active || !dd || !surf0 || !pal) return;
1387
   HRESULT r;
1388
   if (surf0->IsLost() == DDERR_SURFACELOST) surf0->Restore();
1389
   if ((r = pal->SetEntries(0, 0, 0x100, system ? syspalette : pal0)) != DD_OK)
1390
   { printrdd("IDirectDrawPalette::SetEntries()", r); exit(); }
1391
}
1392
 
1393
void trim_right(char *str)
1394
{
1395
   unsigned i; //Alone Coder 0.36.7
1396
   for (/*unsigned*/ i = strlen(str); i && str[i-1] == ' '; i--);
1397
   str[i] = 0;
1398
}
1399
 
1400
#define MAX_MODES 512
1401
struct MODEPARAM {
1402
   unsigned x,y,b,f;
1403
} modes[MAX_MODES];
1404
unsigned max_modes;
1405
 
1406
// Для инициализации fullscreen режима необходимо выполнение несколтких условий:
1407
// 1. Размер окна должен совпадать с разрешением экрана, координаты левого верхнего угла должны быть 0, 0
1408
// 2. Окно должно иметь расширенный стиль WS_EX_TOPMOST
1409
// При не выполнении хотя бы одного из пунктов при возврате из fullscreen к окнному режиму на vista и выше будет 
1410
// откючен DWM и окно приобретет "устаревший" вид бордюра
1411
 
1412
static void SetVideoModeD3d(bool Exclusive)
1413
{
1414
    HRESULT r;
1415
//    printf("%s\n", __FUNCTION__);
1416
 
1417
    if(!wnd)
1418
    {
1419
        __debugbreak();
1420
    }
1421
 
1422
    // release textures if exist
1423
    if(SurfTexture)
1424
    {
1425
        r = SurfTexture->Release();
1426
        if(FAILED(r))
1427
        {
1428
            __debugbreak();
1429
        }
1430
        SurfTexture = 0;
1431
    }
1432
 
1433
    if(Texture)
1434
    {
1435
        r = Texture->Release();
1436
        if(FAILED(r))
1437
        {
1438
            __debugbreak();
1439
        }
1440
        Texture = 0;
1441
    }
1442
 
1443
    bool CreateDevice = false;
1444
    if(!D3dDev)
1445
    {
1446
        CreateDevice = true;
1447
        if(!D3d9)
1448
        {
1449
            StartD3d(wnd);
1450
        }
1451
    }
1452
 
1453
    D3DDISPLAYMODE DispMode;
1454
    r = D3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &DispMode);
1455
    if(r != D3D_OK)
1456
    {
1457
        printrdd("IDirect3D::GetAdapterDisplayMode()", r); exit();
1458
    }
1459
 
1460
    D3DPRESENT_PARAMETERS D3dPp = { 0 };
1461
    if(Exclusive) // exclusive full screen
1462
    {
1463
#if 0
1464
        printf("exclusive full screen (%ux%u %uHz)\n", DispMode.Width, DispMode.Height, temp.ofq);
1465
        RECT rr = { };
1466
        GetWindowRect(wnd, &rr);
1467
        printf("r1={%d,%d,%d,%d} [%dx%d]\n", rr.left, rr.top, rr.right, rr.bottom, rr.right - rr.left, rr.bottom - rr.top);
1468
        printf("SetWindowPos(%p, HWND_TOPMOST, 0, 0, %u, %u)\n", wnd, DispMode.Width, DispMode.Height);
1469
#endif
1470
        if(!SetWindowPos(wnd, HWND_TOPMOST, 0, 0, DispMode.Width, DispMode.Height, 0)) // Установка WS_EX_TOPMOST
1471
        {
1472
            __debugbreak();
1473
        }
1474
#if 0
1475
        rr = { };
1476
        GetWindowRect(wnd, &rr);
1477
        printf("r2={%d,%d,%d,%d} [%dx%d]\n", rr.left, rr.top, rr.right, rr.bottom, rr.right - rr.left, rr.bottom - rr.top);
1478
#endif
1479
        D3dPp.Windowed = FALSE;
1480
        D3dPp.BackBufferWidth = DispMode.Width;
1481
        D3dPp.BackBufferHeight = DispMode.Height;
1482
        D3dPp.BackBufferFormat = DispMode.Format;
1483
        D3dPp.FullScreen_RefreshRateInHz = temp.ofq;
1484
        D3dPp.PresentationInterval = conf.flip ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE;
1485
    }
1486
    else // windowed mode
1487
    {
1488
#if 0
1489
        printf("windowed mode\n");
1490
        RECT rr = { };
1491
        GetWindowRect(wnd, &rr);
1492
        printf("w=%p, r={%d,%d,%d,%d} [%dx%d]\n", wnd, rr.left, rr.top, rr.right, rr.bottom, rr.right - rr.left, rr.bottom - rr.top);
1493
#endif
1494
        D3dPp.Windowed = TRUE;
1495
    }
1496
    D3dPp.SwapEffect = D3DSWAPEFFECT_DISCARD;
1497
    D3dPp.BackBufferCount = 1;
1498
    D3dPp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
1499
    D3dPp.hDeviceWindow = wnd;
1500
 
1501
    if(CreateDevice)
1502
    {
1503
        r = D3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &D3dPp, &D3dDev);
1504
        if(r != D3D_OK)
1505
        {
1506
            printrdd("IDirect3D::CreateDevice()", r);
1507
            exit();
1508
        }
1509
 
1510
        if(!SUCCEEDED(r = D3dDev->TestCooperativeLevel()))
1511
        {
1512
            printrdd("IDirect3DDevice::TestCooperativeLevel()", r);
1513
            exit();
1514
        }
1515
    }
1516
    else // reset existing device
1517
    {
1518
        r = D3D_OK;
1519
        do
1520
        {
1521
            if(r != D3D_OK)
1522
            {
1523
                Sleep(10);
1524
            }
1525
            r = D3dDev->Reset(&D3dPp);
1526
        } while(r == D3DERR_DEVICELOST);
1527
 
1528
        if (r != DD_OK)
1529
        {
1530
            printrdd("IDirect3DDevice9::Reset()", r);
1531
//            __debugbreak();
1532
            exit();
1533
        }
1534
//        printf("D3dDev->Reset(%d, %d)\n", D3dPp.BackBufferWidth, D3dPp.BackBufferHeight);
1535
    }
1536
 
1537
    // recreate textures
1538
//    printf("IDirect3DDevice9::CreateTexture(%d,%d)\n", temp.ox, temp.oy);
1539
    r = D3dDev->CreateTexture(temp.ox, temp.oy, 1, D3DUSAGE_DYNAMIC, DispMode.Format, D3DPOOL_DEFAULT, &Texture, 0);
1540
    if (r != DD_OK)
1541
    { printrdd("IDirect3DDevice9::CreateTexture()", r); exit(); }
1542
    r = Texture->GetSurfaceLevel(0, &SurfTexture);
1543
    if (r != DD_OK)
1544
    { printrdd("IDirect3DTexture::GetSurfaceLevel()", r); exit(); }
1545
    if(!SurfTexture)
1546
        __debugbreak();
1547
}
1548
 
1549
static bool NeedRestoreDisplayMode = false;
1550
 
1551
void set_vidmode()
1552
{
1553
//   printf("%s\n", __FUNCTION__);
1554
   if (pal)
1555
   {
1556
       pal->Release();
1557
       pal = 0;
1558
   }
1559
 
1560
   if (surf2)
1561
   {
1562
       surf2->Release();
1563
       surf2 = 0;
1564
   }
1565
 
1566
   if (surf1)
1567
   {
1568
       surf1->Release();
1569
       surf1 = 0;
1570
   }
1571
 
1572
   if (surf0)
1573
   {
1574
       HRESULT r = surf0->Release();
1575
       if (r != DD_OK)
1576
       { printrdd("surf0->Release()", r); exit(); }
1577
       surf0 = 0;
1578
   }
1579
 
1580
   if (sprim)
1581
   {
1582
       sprim->Release();
1583
       sprim = 0;
1584
   }
1585
 
1586
   if (clip)
1587
   {
1588
       clip->Release();
1589
       clip = 0;
1590
   }
1591
 
1592
   if(SurfTexture)
1593
   {
1594
       SurfTexture->Release();
1595
       SurfTexture = 0;
1596
   }
1597
 
1598
   if(Texture)
1599
   {
1600
       HRESULT r = Texture->Release();
1601
       if(FAILED(r))
1602
       {
1603
           __debugbreak();
1604
       }
1605
       Texture = 0;
1606
   }
1607
 
1608
   HRESULT r;
1609
 
1610
   DDSURFACEDESC desc;
1611
   desc.dwSize = sizeof desc;
1612
   r = dd->GetDisplayMode(&desc);
1613
   if (r != DD_OK) { printrdd("IDirectDraw2::GetDisplayMode()", r); exit(); }
1614
   temp.ofq = desc.dwRefreshRate; // nt only?
1615
   if (!temp.ofq)
1616
       temp.ofq = conf.refresh;
1617
 
1618
   // Проверка наличия hw overlay
1619
   if(drivers[conf.driver].flags & RF_OVR)
1620
   {
1621
       DDCAPS Caps;
1622
       Caps.dwSize = sizeof(Caps);
1623
 
1624
       if((r = dd->GetCaps(&Caps, NULL)) == DD_OK)
1625
       {
1626
           if(Caps.dwMaxVisibleOverlays == 0)
1627
           {
1628
               errexit("HW Overlay not supported");
1629
           }
1630
       }
1631
   }
1632
 
1633
   // select fullscreen, set window style
1634
   if (temp.rflags & RF_DRIVER)
1635
       temp.rflags |= drivers[conf.driver].flags;
1636
   if (!(temp.rflags & (RF_GDI | RF_OVR | RF_CLIP | RF_D3D)))
1637
       conf.fullscr = 1;
1638
   if ((temp.rflags & RF_32) && desc.ddpfPixelFormat.dwRGBBitCount != 32)
1639
       conf.fullscr = 1; // for chunks via blitter
1640
 
1641
   static RECT rc;
1642
   DWORD oldstyle = GetWindowLong(wnd, GWL_STYLE);
1643
   if (oldstyle & WS_CAPTION)
1644
       GetWindowRect(wnd, &rc);
1645
 
1646
   unsigned style = conf.fullscr ? WS_VISIBLE | WS_POPUP : WS_VISIBLE | WS_OVERLAPPEDWINDOW;
1647
   if ((oldstyle ^ style) & WS_CAPTION)
1648
   {
1649
//       printf("set style=%X, fullscr=%d\n", style, conf.fullscr);
1650
       SetWindowLong(wnd, GWL_STYLE, style);
1651
   }
1652
 
1653
   // select exclusive
1654
   char excl = conf.fullscr;
1655
   if ((temp.rflags & RF_CLIP) && (desc.ddpfPixelFormat.dwRGBBitCount == 8))
1656
       excl = 1;
1657
 
1658
   if (!(temp.rflags & (RF_MON | RF_D3D | RF_D3DE)))
1659
   {
1660
      r = dd->SetCooperativeLevel(wnd, excl ? DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN : DDSCL_ALLOWREBOOT | DDSCL_NORMAL);
1661
      if (r != DD_OK) { printrdd("IDirectDraw2::SetCooperativeLevel()", r); exit(); }
1662
   }
1663
 
1664
   // select resolution
1665
   const unsigned size_x[3] = { 256U, conf.mcx_small, conf.mcx_full };
1666
   const unsigned size_y[3] = { 192U, conf.mcy_small, conf.mcy_full };
1667
   temp.ox = temp.scx = size_x[conf.bordersize];
1668
   temp.oy = temp.scy = size_y[conf.bordersize];
1669
 
1670
   if (temp.rflags & RF_2X)
1671
   {
1672
      temp.ox *=2; temp.oy *= 2;
1673
      if (conf.fast_sl && (temp.rflags & RF_DRIVER) && (temp.rflags & (RF_CLIP | RF_OVR)))
1674
          temp.oy /= 2;
1675
   }
1676
 
1677
   if (temp.rflags & RF_3X) temp.ox *= 3, temp.oy *= 3;
1678
   if (temp.rflags & RF_4X) temp.ox *= 4, temp.oy *= 4;
1679
   if (temp.rflags & RF_64x48) temp.ox = 64, temp.oy = 48;
1680
   if (temp.rflags & RF_128x96) temp.ox = 128, temp.oy = 96;
1681
   if (temp.rflags & RF_MON) temp.ox = 640, temp.oy = 480;
1682
 
1683
//   printf("temp.ox=%d, temp.oy=%d\n", temp.ox, temp.oy);
1684
 
1685
   // select color depth
1686
   temp.obpp = 8;
1687
   if (temp.rflags & (RF_CLIP | RF_D3D | RF_D3DE))
1688
       temp.obpp = desc.ddpfPixelFormat.dwRGBBitCount;
1689
   if (temp.rflags & (RF_16 | RF_OVR))
1690
       temp.obpp = 16;
1691
   if (temp.rflags & RF_32)
1692
       temp.obpp = 32;
1693
   if ((temp.rflags & (RF_GDI|RF_8BPCH)) == (RF_GDI|RF_8BPCH))
1694
       temp.obpp = 32;
1695
 
1696
   if (conf.fullscr || ((temp.rflags & RF_MON) && desc.dwHeight < 480))
1697
   {
1698
      // select minimal screen mode
1699
      unsigned newx = 100000, newy = 100000, newfq = conf.refresh ? conf.refresh : temp.ofq, newb = temp.obpp;
1700
      unsigned minx = temp.ox, miny = temp.oy, needb = temp.obpp;
1701
 
1702
      if (temp.rflags & (RF_64x48 | RF_128x96))
1703
      {
1704
         needb = (temp.rflags & RF_16)? 16:32;
1705
         minx = desc.dwWidth; if (minx < 640) minx = 640;
1706
         miny = desc.dwHeight; if (miny < 480) miny = 480;
1707
      }
1708
      // if (temp.rflags & RF_MON) // - ox=640, oy=480 - set above
1709
 
1710
      for (unsigned i = 0; i < max_modes; i++)
1711
      {
1712
         if (modes[i].y < miny || modes[i].x < minx)
1713
             continue;
1714
         if (!(temp.rflags & RF_MON) && modes[i].b != temp.obpp)
1715
             continue;
1716
         if (modes[i].y < conf.minres)
1717
             continue;
1718
 
1719
         if ((modes[i].x < newx || modes[i].y < newy) && (!conf.refresh || (modes[i].f == newfq)))
1720
         {
1721
            newx = modes[i].x, newy = modes[i].y;
1722
            if (!conf.refresh && modes[i].f > newfq)
1723
                newfq = modes[i].f;
1724
         }
1725
      }
1726
 
1727
      if (newx==100000)
1728
      {
1729
          color(CONSCLR_ERROR);
1730
          printf("can't find situable mode for %d x %d * %d bits\n", temp.ox, temp.oy, temp.obpp);
1731
          exit();
1732
      }
1733
 
1734
      // use minimal or current mode
1735
      if (temp.rflags & (RF_OVR | RF_GDI | RF_CLIP | RF_D3D | RF_D3DE))
1736
      {
1737
         // leave screen size, if enough width/height
1738
         newx = desc.dwWidth, newy = desc.dwHeight;
1739
         if (newx < minx || newy < miny)
1740
         {
1741
              newx = minx;
1742
              newy = miny;
1743
         }
1744
         // leave color depth, until specified directly
1745
         if (!(temp.rflags & (RF_16 | RF_32)))
1746
             newb = desc.ddpfPixelFormat.dwRGBBitCount;
1747
      }
1748
 
1749
      if (desc.dwWidth != newx || desc.dwHeight != newy || temp.ofq != newfq || desc.ddpfPixelFormat.dwRGBBitCount != newb)
1750
      {
1751
//         printf("SetDisplayMode:%ux%u %uHz\n", newx, newy, newfq);
1752
         if ((r = dd->SetDisplayMode(newx, newy, newb, newfq, 0)) != DD_OK)
1753
         { printrdd("IDirectDraw2::SetDisplayMode()", r); exit(); }
1754
         GetSystemPaletteEntries(temp.gdidc, 0, 0x100, syspalette);
1755
         if (newfq)
1756
             temp.ofq = newfq;
1757
 
1758
         NeedRestoreDisplayMode = true;
1759
      }
1760
      temp.odx = temp.obpp*(newx - temp.ox)/16, temp.ody = (newy - temp.oy)/2;
1761
      temp.rsx = newx, temp.rsy = newy;
1762
//      printf("vmode=%ux%u %uHz\n", newx, newy, newfq);
1763
//      ShowWindow(wnd, SW_SHOWMAXIMIZED);
1764
//      printf("SetWindowPos(%p, HWND_TOPMOST, 0, 0, %u, %u)\n", wnd, newx, newy);
1765
      if(!SetWindowPos(wnd, HWND_TOPMOST, 0, 0, newx, newy, 0)) // Установка WS_EX_TOPMOST
1766
      {
1767
          __debugbreak();
1768
      }
1769
   }
1770
   else
1771
   {
1772
      // Восстановление предыдущего видеорежима при возврате из fullscreen (если была переустановка видеорежима)
1773
      if(NeedRestoreDisplayMode)
1774
      {
1775
        if ((r = dd->RestoreDisplayMode()) != DD_OK)
1776
        { printrdd("IDirectDraw2::SetDisplayMode()", r); exit(); }
1777
        NeedRestoreDisplayMode = false;
1778
      }
1779
      // restore window position to last saved position in non-fullscreen mode
1780
      ShowWindow(wnd, SW_SHOWNORMAL);
1781
      if (temp.rflags & RF_GDI)
1782
      {
1783
         RECT client = { 0,0, LONG(temp.ox), LONG(temp.oy) };
1784
         AdjustWindowRect(&client, WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0);
1785
         rc.right = rc.left + (client.right - client.left);
1786
         rc.bottom = rc.top + (client.bottom - client.top);
1787
      }
1788
      MoveWindow(wnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, 1);
1789
   }
1790
 
1791
   if (!(temp.rflags & (RF_D3D | RF_D3DE)))
1792
   {
1793
       dd->FlipToGDISurface(); // don't check result
1794
   }
1795
 
1796
   desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
1797
   desc.dwFlags = DDSD_CAPS;
1798
 
1799
   DWORD pl[0x101]; pl[0] = 0x01000300; memcpy(pl+1, pal0, 0x400);
1800
   HPALETTE hpal = CreatePalette((LOGPALETTE*)&pl);
1801
   DeleteObject(SelectPalette(temp.gdidc, hpal, 0));
1802
   RealizePalette(temp.gdidc); // for RF_GDI and for bitmap, used in WM_PAINT
1803
 
1804
   if (temp.rflags & RF_GDI)
1805
   {
1806
 
1807
      gdibmp.header.bmiHeader.biWidth = temp.ox;
1808
      gdibmp.header.bmiHeader.biHeight = -(int)temp.oy;
1809
      gdibmp.header.bmiHeader.biBitCount = temp.obpp;
1810
 
1811
   }
1812
   else if (temp.rflags & RF_OVR)
1813
   {
1814
 
1815
      temp.odx = temp.ody = 0;
1816
      if ((r = dd->CreateSurface(&desc, &sprim, 0)) != DD_OK)
1817
      { printrdd("IDirectDraw2::CreateSurface() [primary,test]", r); exit(); }
1818
 
1819
      desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
1820
      desc.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
1821
      desc.dwWidth = temp.ox, desc.dwHeight = temp.oy;
1822
 
1823
      // conf.flip = 0; // overlay always synchronized without Flip()! on radeon videocards
1824
                        // double flip causes fps drop
1825
 
1826
      if (conf.flip)
1827
      {
1828
         desc.dwBackBufferCount = 1;
1829
         desc.dwFlags |= DDSD_BACKBUFFERCOUNT;
1830
         desc.ddsCaps.dwCaps |= DDSCAPS_FLIP | DDSCAPS_COMPLEX;
1831
      }
1832
 
1833
      static DDPIXELFORMAT ddpfOverlayFormat16 = { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, {16}, {0xF800}, {0x07E0}, {0x001F}, {0} };
1834
      static DDPIXELFORMAT ddpfOverlayFormat15 = { sizeof(DDPIXELFORMAT), DDPF_RGB, 0, {16}, {0x7C00}, {0x03E0}, {0x001F}, {0} };
1835
      static DDPIXELFORMAT ddpfOverlayFormatYUY2 = { sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('Y','U','Y','2'), {0},{0},{0},{0},{0} };
1836
 
1837
      if (temp.rflags & RF_YUY2)
1838
          goto YUY2;
1839
 
1840
      temp.hi15 = 0;
1841
      desc.ddpfPixelFormat = ddpfOverlayFormat16;
1842
      r = dd->CreateSurface(&desc, &surf0, 0);
1843
 
1844
      if (r == DDERR_INVALIDPIXELFORMAT)
1845
      {
1846
         temp.hi15 = 1;
1847
         desc.ddpfPixelFormat = ddpfOverlayFormat15;
1848
         r = dd->CreateSurface(&desc, &surf0, 0);
1849
      }
1850
 
1851
      if (r == DDERR_INVALIDPIXELFORMAT /*&& !(temp.rflags & RF_RGB)*/)
1852
      {
1853
       YUY2:
1854
         temp.hi15 = 2;
1855
         desc.ddpfPixelFormat = ddpfOverlayFormatYUY2;
1856
         r = dd->CreateSurface(&desc, &surf0, 0);
1857
      }
1858
 
1859
      if (r != DD_OK)
1860
      { printrdd("IDirectDraw2::CreateSurface() [overlay]", r); exit(); }
1861
 
1862
   }
1863
   else if(temp.rflags & (RF_D3D | RF_D3DE)) // d3d windowed, d3d full screen exclusive
1864
   {
1865
//      printf("%s(RF_D3D)\n", __FUNCTION__);
1866
      // Сначала нужно отмасштабировать окно до нужного размера, а только потом устанавливать видеорежим
1867
      // т.к. видеорежим определяет размеры back buffer'а из размеров окна.
1868
   }
1869
   else  // blt, direct video mem
1870
   {
1871
//      desc.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
1872
      if (conf.flip && !(temp.rflags & RF_CLIP))
1873
      {
1874
         desc.dwBackBufferCount = 1;
1875
         desc.dwFlags |= DDSD_BACKBUFFERCOUNT;
1876
         desc.ddsCaps.dwCaps |= DDSCAPS_FLIP | DDSCAPS_COMPLEX;
1877
      }
1878
 
1879
      if ((r = dd->CreateSurface(&desc, &surf0, 0)) != DD_OK)
1880
      { printrdd("IDirectDraw2::CreateSurface() [primary1]", r); exit(); }
1881
 
1882
      if (temp.rflags & RF_CLIP)
1883
      {
1884
         DDSURFACEDESC SurfDesc;
1885
         SurfDesc.dwSize = sizeof(SurfDesc);
1886
         if((r = surf0->GetSurfaceDesc(&SurfDesc)) != DD_OK)
1887
         { printrdd("IDirectDrawSurface::GetSurfaceDesc()", r); exit(); }
1888
 
1889
         desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
1890
         desc.dwWidth = SurfDesc.dwWidth; desc.dwHeight = SurfDesc.dwHeight;
1891
         desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
1892
 
1893
         if ((r = dd->CreateSurface(&desc, &surf2, 0)) != DD_OK)
1894
         { printrdd("IDirectDraw2::CreateSurface() [2]", r); exit(); }
1895
 
1896
         r = dd->CreateClipper(0, &clip, 0);
1897
         if (r != DD_OK) { printrdd("IDirectDraw2::CreateClipper()", r); exit(); }
1898
 
1899
         r = clip->SetHWnd(0, wnd);
1900
         if (r != DD_OK) { printrdd("IDirectDraw2::SetHWnd()", r); exit(); }
1901
 
1902
         r = surf0->SetClipper(clip);
1903
         if (r != DD_OK) { printrdd("surf0, IDirectDrawSurface2::SetClipper()", r); exit(); }
1904
 
1905
         r = surf2->SetClipper(clip);
1906
         if (r != DD_OK) { printrdd("surf2, IDirectDrawSurface2::SetClipper()", r); exit(); }
1907
 
1908
         r = dd->GetDisplayMode(&desc);
1909
         if (r != DD_OK) { printrdd("IDirectDraw2::GetDisplayMode()", r); exit(); }
1910
         if ((temp.rflags & RF_32) && desc.ddpfPixelFormat.dwRGBBitCount != 32)
1911
             errexit("video driver requires 32bit color depth on desktop for this mode");
1912
 
1913
         desc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
1914
         desc.dwWidth = temp.ox; desc.dwHeight = temp.oy;
1915
 
1916
         // Видеокарты AMD Radeon HD не поддерживают surface в системной памяти
1917
         // из за этого приходится отдельный буфер в системно памяти и делать программное
1918
         // копирование в surface выделенный в видеопамяти иначе никак не задать выравнивание на 16 байт
1919
         desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
1920
 
1921
#ifdef MOD_SSE2
1922
         if(!(renders[conf.render].flags & RF_1X))
1923
         {
1924
             SurfPitch1 = (temp.ox * temp.obpp) >> 3;
1925
             SurfPitch1 = (SurfPitch1 + 15) & ~15; // Выравнивание на 16
1926
 
1927
             if(SurfMem1)
1928
                 _aligned_free(SurfMem1);
1929
             SurfMem1 = _aligned_malloc(SurfPitch1 * temp.oy, 16);
1930
             FlipBltMethod = FlipBltAlign16;
1931
         }
1932
         else
1933
#endif
1934
         {
1935
             FlipBltMethod = FlipBltAlign4;
1936
         }
1937
 
1938
         r = dd->CreateSurface(&desc, &surf1, 0);
1939
         if (r != DD_OK) { printrdd("IDirectDraw2::CreateSurface()", r); exit(); }
1940
      }
1941
 
1942
      if (temp.obpp == 16)
1943
      {
1944
         DDPIXELFORMAT fm; fm.dwSize = sizeof fm;
1945
         if ((r = surf0->GetPixelFormat(&fm)) != DD_OK)
1946
         { printrdd("IDirectDrawSurface2::GetPixelFormat()", r); exit(); }
1947
 
1948
         if (fm.dwRBitMask == 0xF800 && fm.dwGBitMask == 0x07E0 && fm.dwBBitMask == 0x001F)
1949
            temp.hi15 = 0;
1950
         else if (fm.dwRBitMask == 0x7C00 && fm.dwGBitMask == 0x03E0 && fm.dwBBitMask == 0x001F)
1951
            temp.hi15 = 1;
1952
         else
1953
            errexit("invalid pixel format (need RGB:5-6-5 or URGB:1-5-5-5)");
1954
 
1955
      }
1956
      else if (temp.obpp == 8)
1957
      {
1958
 
1959
         if ((r = dd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256, syspalette, &pal, 0)) != DD_OK)
1960
         { printrdd("IDirectDraw2::CreatePalette()", r); exit(); }
1961
         if ((r = surf0->SetPalette(pal)) != DD_OK)
1962
         { printrdd("IDirectDrawSurface2::SetPalette()", r); exit(); }
1963
      }
1964
   }
1965
 
1966
   if (conf.flip && !(temp.rflags & (RF_GDI|RF_CLIP|RF_D3D|RF_D3DE)))
1967
   {
1968
      DDSCAPS caps = { DDSCAPS_BACKBUFFER };
1969
      if ((r = surf0->GetAttachedSurface(&caps, &surf1)) != DD_OK)
1970
      { printrdd("IDirectDraw2::GetAttachedSurface()", r); exit(); }
1971
   }
1972
 
1973
   // Настраиваем функцию конвертирования из текущего формата в BGR24
1974
   switch(temp.obpp)
1975
   {
1976
   case 8: ConvBgr24 = ConvPal8ToBgr24; break;
1977
   case 16:
1978
       switch(temp.hi15)
1979
       {
1980
       case 0: ConvBgr24 = ConvRgb16ToBgr24; break; // RGB16
1981
       case 1: ConvBgr24 = ConvRgb15ToBgr24; break; // RGB15
1982
       case 2: ConvBgr24 = ConvYuy2ToBgr24; break; // YUY2
1983
       }
1984
   case 32: ConvBgr24 = ConvBgr32ToBgr24; break;
1985
   }
1986
 
1987
   SendMessage(wnd, WM_USER, 0, 0); // setup rectangle for RF_GDI,OVR,CLIP, adjust cursor
1988
   if(!conf.fullscr)
1989
       scale_normal();
1990
 
1991
   if(temp.rflags & (RF_D3D | RF_D3DE)) // d3d windowed, d3d full screen exclusive
1992
   {
1993
       // Сначала нужно отмасштабировать окно до нужного размера, а только потом устанавливать видеорежим
1994
       // т.к. видеорежим определяет размеры back buffer'а из размеров окна.
1995
       SetVideoModeD3d((temp.rflags & RF_D3DE) != 0);
1996
   }
1997
}
1998
 
1999
HRESULT SetDIDwordProperty(LPDIRECTINPUTDEVICE pdev, REFGUID guidProperty,
2000
                   DWORD dwObject, DWORD dwHow, DWORD dwValue)
2001
{
2002
   DIPROPDWORD dipdw;
2003
   dipdw.diph.dwSize       = sizeof(dipdw);
2004
   dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
2005
   dipdw.diph.dwObj        = dwObject;
2006
   dipdw.diph.dwHow        = dwHow;
2007
   dipdw.dwData            = dwValue;
2008
   return pdev->SetProperty(guidProperty, &dipdw.diph);
2009
}
2010
 
2011
BOOL CALLBACK InitJoystickInput(LPCDIDEVICEINSTANCE pdinst, LPVOID pvRef)
2012
{
2013
   HRESULT r;
2014
   LPDIRECTINPUT pdi = (LPDIRECTINPUT)pvRef;
2015
   LPDIRECTINPUTDEVICE dijoyst1;
2016
   LPDIRECTINPUTDEVICE2 dijoyst;
2017
   if ((r = pdi->CreateDevice(pdinst->guidInstance, &dijoyst1, 0)) != DI_OK)
2018
   {
2019
       printrdi("IDirectInput::CreateDevice() (joystick)", r);
2020
       return DIENUM_CONTINUE;
2021
   }
2022
 
2023
   r = dijoyst1->QueryInterface(IID_IDirectInputDevice2, (void**)&dijoyst);
2024
   if (r != S_OK)
2025
   {
2026
      printrdi("IDirectInputDevice::QueryInterface(IID_IDirectInputDevice2) [dx5 not found]", r);
2027
      dijoyst1->Release();
2028
      dijoyst1=0;
2029
      return DIENUM_CONTINUE;
2030
   }
2031
   dijoyst1->Release();
2032
 
2033
   DIDEVICEINSTANCE dide = { sizeof dide };
2034
   if ((r = dijoyst->GetDeviceInfo(&dide)) != DI_OK)
2035
   {
2036
       printrdi("IDirectInputDevice::GetDeviceInfo()", r);
2037
       return DIENUM_STOP;
2038
   }
2039
 
2040
   DIDEVCAPS dc = { sizeof dc };
2041
   if ((r = dijoyst->GetCapabilities(&dc)) != DI_OK)
2042
   {
2043
       printrdi("IDirectInputDevice::GetCapabilities()", r);
2044
       return DIENUM_STOP;
2045
   }
2046
 
2047
   DIPROPDWORD JoyId;
2048
   JoyId.diph.dwSize       = sizeof(JoyId);
2049
   JoyId.diph.dwHeaderSize = sizeof(JoyId.diph);
2050
   JoyId.diph.dwObj        = 0;
2051
   JoyId.diph.dwHow        = DIPH_DEVICE;
2052
   if ((r = dijoyst->GetProperty(DIPROP_JOYSTICKID, &JoyId.diph)) != DI_OK)
2053
   { printrdi("IDirectInputDevice::GetProperty(DIPROP_JOYSTICKID)", r); exit(); }
2054
 
2055
   trim_right(dide.tszInstanceName);
2056
   trim_right(dide.tszProductName);
2057
 
2058
   CharToOem(dide.tszInstanceName, dide.tszInstanceName);
2059
   CharToOem(dide.tszProductName, dide.tszProductName);
2060
   if (strcmp(dide.tszProductName, dide.tszInstanceName))
2061
       strcat(dide.tszInstanceName, ", ");
2062
   else
2063
       dide.tszInstanceName[0] = 0;
2064
 
2065
   bool UseJoy = (JoyId.dwData == conf.input.JoyId);
2066
   color(CONSCLR_HARDINFO);
2067
   printf("%cjoy(%lu): %s%s (%lu axes, %lu buttons, %lu POVs)\n", UseJoy ? '*' : ' ', JoyId.dwData,
2068
      dide.tszInstanceName, dide.tszProductName, dc.dwAxes, dc.dwButtons, dc.dwPOVs);
2069
 
2070
   if(UseJoy)
2071
   {
2072
       if ((r = dijoyst->SetDataFormat(&c_dfDIJoystick)) != DI_OK)
2073
       {
2074
           printrdi("IDirectInputDevice::SetDataFormat() (joystick)", r);
2075
           exit();
2076
       }
2077
 
2078
       if ((r = dijoyst->SetCooperativeLevel(wnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND)) != DI_OK)
2079
       {
2080
           printrdi("IDirectInputDevice::SetCooperativeLevel() (joystick)", r);
2081
           exit();
2082
       }
2083
 
2084
       DIPROPRANGE diprg;
2085
       diprg.diph.dwSize       = sizeof(diprg);
2086
       diprg.diph.dwHeaderSize = sizeof(diprg.diph);
2087
       diprg.diph.dwObj        = DIJOFS_X;
2088
       diprg.diph.dwHow        = DIPH_BYOFFSET;
2089
       diprg.lMin              = -1000;
2090
       diprg.lMax              = +1000;
2091
 
2092
       if ((r = dijoyst->SetProperty(DIPROP_RANGE, &diprg.diph)) != DI_OK)
2093
       { printrdi("IDirectInputDevice::SetProperty(DIPH_RANGE)", r); exit(); }
2094
 
2095
       diprg.diph.dwObj        = DIJOFS_Y;
2096
 
2097
       if ((r = dijoyst->SetProperty(DIPROP_RANGE, &diprg.diph)) != DI_OK)
2098
       { printrdi("IDirectInputDevice::SetProperty(DIPH_RANGE) (y)", r); exit(); }
2099
 
2100
       if ((r = SetDIDwordProperty(dijoyst, DIPROP_DEADZONE, DIJOFS_X, DIPH_BYOFFSET, 2000)) != DI_OK)
2101
       { printrdi("IDirectInputDevice::SetProperty(DIPH_DEADZONE)", r); exit(); }
2102
 
2103
       if ((r = SetDIDwordProperty(dijoyst, DIPROP_DEADZONE, DIJOFS_Y, DIPH_BYOFFSET, 2000)) != DI_OK)
2104
       { printrdi("IDirectInputDevice::SetProperty(DIPH_DEADZONE) (y)", r); exit(); }
2105
       ::dijoyst = dijoyst;
2106
   }
2107
   else
2108
   {
2109
      dijoyst->Release();
2110
   }
2111
   return DIENUM_CONTINUE;
2112
}
2113
 
2114
HRESULT WINAPI callb(LPDDSURFACEDESC surf, void *lpContext)
2115
{
2116
   if (max_modes >= MAX_MODES)
2117
       return DDENUMRET_CANCEL;
2118
   modes[max_modes].x = surf->dwWidth;
2119
   modes[max_modes].y = surf->dwHeight;
2120
   modes[max_modes].b = surf->ddpfPixelFormat.dwRGBBitCount;
2121
   modes[max_modes].f = surf->dwRefreshRate;
2122
   max_modes++;
2123
   return DDENUMRET_OK;
2124
}
2125
 
2126
void scale_normal()
2127
{
2128
    ULONG cmd;
2129
    switch(temp.scale)
2130
    {
2131
    default:
2132
    case 1: cmd = SCU_SCALE1; break;
2133
    case 2: cmd = SCU_SCALE2; break;
2134
    case 3: cmd = SCU_SCALE3; break;
2135
    case 4: cmd = SCU_SCALE4; break;
2136
    }
2137
    SendMessage(wnd, WM_SYSCOMMAND, cmd, 0); // set window size
2138
}
2139
 
2140
#ifdef _DEBUG
2141
#define D3D_DLL_NAME "d3d9d.dll"
2142
#else
2143
#endif
2144
#define D3D_DLL_NAME "d3d9.dll"
2145
 
2146
void DbgPrint(const char *s)
2147
{
2148
    OutputDebugStringA(s);
2149
}
2150
 
2151
static void StartD3d(HWND Wnd)
2152
{
2153
#if 0
2154
    OutputDebugString(__FUNCTION__"\n");
2155
    printf("%s\n", __FUNCTION__);
2156
#endif
2157
    HRESULT r;
2158
    if(!D3d9Dll)
2159
    {
2160
        D3d9Dll = LoadLibrary(D3D_DLL_NAME);
2161
 
2162
        if(!D3d9Dll)
2163
        {
2164
            errexit("unable load d3d9.dll");
2165
        }
2166
    }
2167
 
2168
    if(!D3d9)
2169
    {
2170
        typedef IDirect3D9 * (WINAPI *TDirect3DCreate9)(UINT SDKVersion);
2171
        TDirect3DCreate9 Direct3DCreate9 = (TDirect3DCreate9)GetProcAddress(D3d9Dll, "Direct3DCreate9");
2172
        D3d9 = Direct3DCreate9(D3D_SDK_VERSION);
2173
        if(!D3d9)
2174
            return;
2175
    }
2176
 
2177
}
2178
 
2179
static void CalcWindowSize()
2180
{
2181
    temp.rflags = renders[conf.render].flags;
2182
 
2183
    if (renders[conf.render].func == render_advmame)
2184
    {
2185
        if (conf.videoscale == 2)
2186
            temp.rflags |= RF_2X;
2187
        if (conf.videoscale == 3)
2188
            temp.rflags |= RF_3X;
2189
        if (conf.videoscale == 4)
2190
            temp.rflags |= RF_4X;
2191
    }
2192
    if (temp.rflags & RF_DRIVER)
2193
        temp.rflags |= drivers[conf.driver].flags;
2194
 
2195
    // select resolution
2196
    const unsigned size_x[3] = { 256U, conf.mcx_small, conf.mcx_full };
2197
    const unsigned size_y[3] = { 192U, conf.mcy_small, conf.mcy_full };
2198
    temp.ox = temp.scx = size_x[conf.bordersize];
2199
    temp.oy = temp.scy = size_y[conf.bordersize];
2200
 
2201
    if (temp.rflags & RF_2X)
2202
    {
2203
        temp.ox *=2; temp.oy *= 2;
2204
        if (conf.fast_sl && (temp.rflags & RF_DRIVER) && (temp.rflags & (RF_CLIP | RF_OVR)))
2205
            temp.oy /= 2;
2206
    }
2207
 
2208
    if (temp.rflags & RF_3X) temp.ox *= 3, temp.oy *= 3;
2209
    if (temp.rflags & RF_4X) temp.ox *= 4, temp.oy *= 4;
2210
    if (temp.rflags & RF_64x48) temp.ox = 64, temp.oy = 48;
2211
    if (temp.rflags & RF_128x96) temp.ox = 128, temp.oy = 96;
2212
    if (temp.rflags & RF_MON) temp.ox = 640, temp.oy = 480;
2213
}
2214
 
2215
static BOOL WINAPI DdEnumDevs(GUID *DevGuid, PSTR DrvDesc, PSTR DrvName, PVOID Ctx, HMONITOR Hm)
2216
{
2217
    if(DevGuid)
2218
    {
2219
        memcpy(Ctx, DevGuid, sizeof(GUID));
2220
        return FALSE;
2221
    }
2222
    return TRUE;
2223
}
2224
 
2225
void start_dx()
2226
{
2227
//   printf("%s\n", __FUNCTION__);
2228
   dsbuffer_sz = DSBUFFER_SZ;
2229
 
2230
   WNDCLASSEX  wc = { 0 };
2231
 
2232
   wc.cbSize = sizeof(WNDCLASSEX);
2233
 
2234
   wc.lpfnWndProc = WndProc;
2235
   hIn = wc.hInstance = GetModuleHandle(0);
2236
   wc.lpszClassName = "EMUL_WND";
2237
   wc.hIcon = LoadIcon(hIn, MAKEINTRESOURCE(IDI_ICON2));
2238
   wc.hCursor = LoadCursor(0, IDC_ARROW);
2239
   wc.style = CS_HREDRAW | CS_VREDRAW;
2240
   RegisterClassEx(&wc);
2241
 
2242
   for (int i = 0; i < 9; i++)
2243
      crs[i] = LoadCursor(hIn, MAKEINTRESOURCE(IDC_C0+i));
2244
//Alone Coder 0.36.6
2245
   RECT rect1;
2246
   SystemParametersInfo(SPI_GETWORKAREA, 0, &rect1, 0);
2247
//~
2248
   CalcWindowSize();
2249
 
2250
   int cx = temp.ox*temp.scale, cy = temp.oy*temp.scale;
2251
 
2252
   RECT Client = { 0, 0, cx, cy };
2253
   AdjustWindowRect(&Client, WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0);
2254
   cx = Client.right - Client.left;
2255
   cy = Client.bottom - Client.top;
2256
   int winx = rect1.left + (rect1.right - rect1.left - cx) / 2;
2257
   int winy = rect1.top + (rect1.bottom - rect1.top - cy) / 2;
2258
 
2259
   wnd = CreateWindowEx(0, "EMUL_WND", "UnrealSpeccy", WS_VISIBLE|WS_OVERLAPPEDWINDOW,
2260
                    winx, winy, cx, cy, NULL, NULL, hIn, NULL);
2261
 
2262
   if(!wnd)
2263
   {
2264
       __debugbreak();
2265
   }
2266
 
2267
   DragAcceptFiles(wnd, 1);
2268
 
2269
   temp.gdidc = GetDC(wnd);
2270
   GetSystemPaletteEntries(temp.gdidc, 0, 0x100, syspalette);
2271
 
2272
   HMENU sys = GetSystemMenu(wnd, 0);
2273
   if(sys)
2274
   {
2275
       AppendMenu(sys, MF_SEPARATOR, 0, 0);
2276
       AppendMenu(sys, MF_STRING, SCU_SCALE1, "x1");
2277
       AppendMenu(sys, MF_STRING, SCU_SCALE2, "x2");
2278
       AppendMenu(sys, MF_STRING, SCU_SCALE3, "x3");
2279
       AppendMenu(sys, MF_STRING, SCU_SCALE4, "x4");
2280
       AppendMenu(sys, MF_STRING, SCU_LOCK_MOUSE, "&Lock mouse");
2281
   }
2282
 
2283
   InitCommonControls();
2284
 
2285
   HRESULT r;
2286
   GUID DdDevGuid;
2287
   if((r = DirectDrawEnumerateEx(DdEnumDevs, &DdDevGuid, DDENUM_ATTACHEDSECONDARYDEVICES)) != DD_OK)
2288
   { printrdd("DirectDrawEnumerate()", r); exit(); }
2289
 
2290
   LPDIRECTDRAW dd0;
2291
   if ((r = DirectDrawCreate(0 /*&DdDevGuid*/, &dd0, 0)) != DD_OK)
2292
   { printrdd("DirectDrawCreate()", r); exit(); }
2293
 
2294
   if ((r = dd0->QueryInterface(IID_IDirectDraw2, (void**)&dd)) != DD_OK)
2295
   { printrdd("IDirectDraw::QueryInterface(IID_IDirectDraw2)", r); exit(); }
2296
 
2297
   dd0->Release();
2298
 
2299
   color(CONSCLR_HARDITEM); printf("gfx: ");
2300
 
2301
   char vmodel[MAX_DDDEVICEID_STRING + 32]; *vmodel = 0;
2302
   if (conf.detect_video)
2303
   {
2304
      LPDIRECTDRAW4 dd4;
2305
      if ((r = dd->QueryInterface(IID_IDirectDraw4, (void**)&dd4)) == DD_OK)
2306
      {
2307
         DDDEVICEIDENTIFIER di;
2308
         if (dd4->GetDeviceIdentifier(&di, 0) == DD_OK)
2309
         {
2310
            trim_right(di.szDescription);
2311
            CharToOem(di.szDescription, di.szDescription);
2312
            sprintf(vmodel, "%04lX-%04lX (%s)", di.dwVendorId, di.dwDeviceId, di.szDescription);
2313
         }
2314
         else
2315
             sprintf(vmodel, "unknown device");
2316
         dd4->Release();
2317
      }
2318
      if (*vmodel)
2319
          strcat(vmodel, ", ");
2320
   }
2321
   DDCAPS caps;
2322
   caps.dwSize = sizeof caps;
2323
   dd->GetCaps(&caps, 0);
2324
 
2325
   color(CONSCLR_HARDINFO);
2326
 
2327
   const u32 Vmem = caps.dwVidMemTotal;
2328
   printf("%s%uMb VRAM available\n", vmodel, Vmem/(1024U*1024U)+((Vmem%(1024U*1024U))>512U*1024U));
2329
 
2330
   max_modes = 0;
2331
   dd->EnumDisplayModes(DDEDM_REFRESHRATES | DDEDM_STANDARDVGAMODES, 0, 0, callb);
2332
 
2333
   if((temp.rflags & (RF_D3D | RF_D3DE)))
2334
       StartD3d(wnd);
2335
 
2336
   WAVEFORMATEX wf = { 0 };
2337
   wf.wFormatTag = WAVE_FORMAT_PCM;
2338
   wf.nSamplesPerSec = conf.sound.fq;
2339
   wf.nChannels = 2;
2340
   wf.wBitsPerSample = 16;
2341
   wf.nBlockAlign = 4;
2342
   wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
2343
 
2344
   if (conf.sound.do_sound == do_sound_wave)
2345
   {
2346
      if ((r = waveOutOpen(&hwo, WAVE_MAPPER, &wf, 0, 0, CALLBACK_NULL)) != MMSYSERR_NOERROR)
2347
      { printrmm("waveOutOpen()", r); hwo = 0; goto sfail; }
2348
      wqhead = 0, wqtail = 0;
2349
   }
2350
   else if (conf.sound.do_sound == do_sound_ds)
2351
   {
2352
 
2353
      if ((r = DirectSoundCreate(0, &ds, 0)) != DS_OK)
2354
      { printrds("DirectSoundCreate()", r); goto sfail; }
2355
 
2356
      r = -1;
2357
      if (conf.sound.dsprimary) r = ds->SetCooperativeLevel(wnd, DSSCL_WRITEPRIMARY);
2358
      if (r != DS_OK) r = ds->SetCooperativeLevel(wnd, DSSCL_NORMAL), conf.sound.dsprimary = 0;
2359
      if (r != DS_OK) { printrds("IDirectSound::SetCooperativeLevel()", r); goto sfail; }
2360
 
2361
      DSBUFFERDESC dsdesc = { sizeof(DSBUFFERDESC) };
2362
      r = -1;
2363
 
2364
      if (conf.sound.dsprimary)
2365
      {
2366
 
2367
         dsdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_PRIMARYBUFFER;
2368
         dsdesc.dwBufferBytes = 0;
2369
         dsdesc.lpwfxFormat = 0;
2370
         r = ds->CreateSoundBuffer(&dsdesc, &dsbf, 0);
2371
 
2372
         if (r != DS_OK) { printrds("IDirectSound::CreateSoundBuffer() [primary]", r); }
2373
         else
2374
         {
2375
            r = dsbf->SetFormat(&wf);
2376
            if (r != DS_OK) { printrds("IDirectSoundBuffer::SetFormat()", r); goto sfail; }
2377
            DSBCAPS caps; caps.dwSize = sizeof caps; dsbf->GetCaps(&caps);
2378
            dsbuffer_sz = caps.dwBufferBytes;
2379
         }
2380
      }
2381
 
2382
      if (r != DS_OK)
2383
      {
2384
         dsdesc.lpwfxFormat = &wf;
2385
         dsdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
2386
         dsbuffer_sz = dsdesc.dwBufferBytes = DSBUFFER_SZ;
2387
         if ((r = ds->CreateSoundBuffer(&dsdesc, &dsbf, 0)) != DS_OK)
2388
         {
2389
             printrds("IDirectSound::CreateSoundBuffer()", r);
2390
             goto sfail;
2391
         }
2392
 
2393
         conf.sound.dsprimary = 0;
2394
      }
2395
 
2396
      dsoffset = dsbuffer_sz/4;
2397
 
2398
   }
2399
   else
2400
   {
2401
   sfail:
2402
      conf.sound.do_sound = do_sound_none;
2403
   }
2404
 
2405
   LPDIRECTINPUT di;
2406
   r = DirectInputCreate(hIn,DIRECTINPUT_VERSION,&di,0);
2407
 
2408
   if ((r != DI_OK) && (r = DirectInputCreate(hIn,0x0300,&di,0)) != DI_OK)
2409
   {
2410
       printrdi("DirectInputCreate()", r);
2411
       exit();
2412
   }
2413
 
2414
   if((r = di->CreateDevice(GUID_SysKeyboard, &dikeyboard, 0)) != DI_OK)
2415
   {
2416
       printrdi("IDirectInputDevice::CreateDevice() (keyboard)", r);
2417
       exit();
2418
   }
2419
 
2420
   if((r = dikeyboard->SetDataFormat(&c_dfDIKeyboard)) != DI_OK)
2421
   {
2422
       printrdi("IDirectInputDevice::SetDataFormat() (keyboard)", r);
2423
       exit();
2424
   }
2425
 
2426
   if((r = dikeyboard->SetCooperativeLevel(wnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE)) != DI_OK)
2427
   {
2428
       printrdi("IDirectInputDevice::SetCooperativeLevel() (keyboard)", r);
2429
       exit();
2430
   }
2431
 
2432
   if ((r = di->CreateDevice(GUID_SysMouse, &dimouse, 0)) == DI_OK)
2433
   {
2434
      if ((r = dimouse->SetDataFormat(&c_dfDIMouse)) != DI_OK)
2435
      {
2436
          printrdi("IDirectInputDevice::SetDataFormat() (mouse)", r);
2437
          exit();
2438
      }
2439
 
2440
      if ((r = dimouse->SetCooperativeLevel(wnd, DISCL_FOREGROUND|DISCL_NONEXCLUSIVE)) != DI_OK)
2441
      {
2442
          printrdi("IDirectInputDevice::SetCooperativeLevel() (mouse)", r);
2443
          exit();
2444
      }
2445
      DIPROPDWORD dipdw = { 0 };
2446
      dipdw.diph.dwSize       = sizeof(dipdw);
2447
      dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
2448
      dipdw.diph.dwHow        = DIPH_DEVICE;
2449
      dipdw.dwData            = DIPROPAXISMODE_ABS;
2450
      if ((r = dimouse->SetProperty(DIPROP_AXISMODE, &dipdw.diph)) != DI_OK)
2451
      {
2452
          printrdi("IDirectInputDevice::SetProperty() (mouse)", r);
2453
          exit();
2454
      }
2455
   }
2456
   else
2457
   {
2458
       color(CONSCLR_WARNING);
2459
       printf("warning: no mouse\n");
2460
       dimouse = 0;
2461
   }
2462
 
2463
   if ((r = di->EnumDevices(DIDEVTYPE_JOYSTICK, InitJoystickInput, di, DIEDFL_ATTACHEDONLY)) != DI_OK)
2464
   {
2465
       printrdi("IDirectInput::EnumDevices(DIDEVTYPE_JOYSTICK,...)", r);
2466
       exit();
2467
   }
2468
 
2469
   di->Release();
2470
//[vv]   SetKeyboardState(kbdpc); // fix bug in win95
2471
}
2472
 
2473
static void DoneD3d(bool DeInitDll)
2474
{
2475
//    printf("%s(%d)\n", __FUNCTION__, DeInitDll);
2476
    HRESULT r;
2477
    if(SurfTexture)
2478
    {
2479
        r = SurfTexture->Release();
2480
        if(FAILED(r))
2481
        {
2482
            __debugbreak();
2483
        }
2484
        SurfTexture = 0;
2485
    }
2486
    if(Texture)
2487
    {
2488
        r = Texture->Release();
2489
        if(FAILED(r))
2490
        {
2491
            __debugbreak();
2492
        }
2493
        Texture = 0;
2494
    }
2495
    if(D3dDev)
2496
    {
2497
        r = D3dDev->Release();
2498
        if(FAILED(r))
2499
        {
2500
            __debugbreak();
2501
        }
2502
        D3dDev = 0;
2503
    }
2504
    if(D3d9)
2505
    {
2506
        r = D3d9->Release();
2507
        if(FAILED(r))
2508
        {
2509
            __debugbreak();
2510
        }
2511
        D3d9 = 0;
2512
    }
2513
    if(DeInitDll && D3d9Dll)
2514
    {
2515
        FreeLibrary(D3d9Dll);
2516
        D3d9Dll = 0;
2517
    }
2518
}
2519
 
2520
void done_dx()
2521
{
2522
   sound_stop();
2523
   if (pal) pal->Release(); pal = 0;
2524
   if (surf2) surf2->Release(); surf2 = 0;
2525
   if (surf1) surf1->Release(); surf1 = 0;
2526
   if (surf0) surf0->Release(); surf0 = 0;
2527
   if (sprim) sprim->Release(); sprim = 0;
2528
   if (clip) clip->Release(); clip = 0;
2529
   if (dd) dd->Release(); dd = 0;
2530
   if (SurfMem1) _aligned_free(SurfMem1); SurfMem1 = 0;
2531
   if (dikeyboard) dikeyboard->Unacquire(), dikeyboard->Release(); dikeyboard = 0;
2532
   if (dimouse) dimouse->Unacquire(), dimouse->Release(); dimouse = 0;
2533
   if (dijoyst) dijoyst->Unacquire(), dijoyst->Release(); dijoyst = 0;
2534
   if (hwo) { waveOutReset(hwo); /* waveOutUnprepareHeader()'s ? */ waveOutClose(hwo); }
2535
   if (dsbf) dsbf->Release(); dsbf = 0;
2536
   if (ds) ds->Release(); ds = 0;
2537
   if (hbm) DeleteObject(hbm); hbm = 0;
2538
   if (temp.gdidc) ReleaseDC(wnd, temp.gdidc); temp.gdidc = 0;
2539
   DoneD3d();
2540
   if (wnd) DestroyWindow(wnd);
2541
}