Subversion Repositories pentevo

Rev

Rev 883 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

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