home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / diex1 / diex1.cpp next >
C/C++ Source or Header  |  1997-07-14  |  14KB  |  518 lines

  1. /**************************************************************************
  2.  
  3.     DIEX1.CPP - DirectInput simple sample 1
  4.  
  5.     Demonstrates an application which receives relative mouse data
  6.     in non-exclusive mode via a game loop.
  7.  
  8.  **************************************************************************/
  9. /**************************************************************************
  10.  
  11.     (C) Copyright 1997 Microsoft Corp.  All rights reserved.
  12.  
  13.     You have a royalty-free right to use, modify, reproduce and
  14.     distribute the Sample Files (and/or any modified version) in
  15.     any way you find useful, provided that you agree that
  16.     Microsoft has no warranty obligations or liability for any
  17.     Sample Application Files which are modified.
  18.  
  19.  **************************************************************************/
  20.  
  21. #include <windows.h>
  22. #include <dinput.h>
  23.  
  24. #include "diex1.h"
  25.  
  26. /****************************************************************************
  27.  *
  28.  *      Global variables
  29.  *
  30.  ****************************************************************************/
  31.  
  32. char c_szClassName[] = "DIEX1";
  33.  
  34. HINSTANCE       g_hinst;                /* My instance handle */
  35. BOOL            g_fPaused = TRUE;       /* Should I be paused? */
  36.  
  37. /****************************************************************************
  38.  *
  39.  *      DirectInput globals
  40.  *
  41.  ****************************************************************************/
  42.  
  43. LPDIRECTINPUT           g_pdi;
  44. LPDIRECTINPUTDEVICE     g_pMouse;
  45. char                    g_szText[1024]; /* What we display in client area */
  46.  
  47. /****************************************************************************
  48.  *
  49.  *      Complain
  50.  *
  51.  *      Whine and moan.
  52.  *
  53.  ****************************************************************************/
  54.  
  55. void
  56. Complain(
  57.     HWND hwndOwner,
  58.     HRESULT hr,
  59.     LPCSTR pszMessage
  60. )
  61. {
  62.     MessageBox(hwndOwner, pszMessage, "DirectInput Sample", MB_OK);
  63. }
  64.  
  65. /****************************************************************************
  66.  *
  67.  *      DIInit
  68.  *
  69.  *      Initialize the DirectInput variables.
  70.  *
  71.  *      This entails the following four functions:
  72.  *
  73.  *          DirectInputCreate
  74.  *          IDirectInput::CreateDevice
  75.  *          IDirectInputDevice::SetDataFormat
  76.  *          IDirectInputDevice::SetCooperativeLevel
  77.  *
  78.  ****************************************************************************/
  79.  
  80. BOOL
  81. DIInit(
  82.     HWND hwnd
  83. )
  84. {
  85.     HRESULT hr;
  86.  
  87.     /*
  88.      *  Register with the DirectInput subsystem and get a pointer
  89.      *  to a IDirectInput interface we can use.
  90.      *
  91.      *  Parameters:
  92.      *
  93.      *      g_hinst
  94.      *
  95.      *          Instance handle to our application or DLL.
  96.      *
  97.      *      DIRECTINPUT_VERSION
  98.      *
  99.      *          The version of DirectInput we were designed for.
  100.      *          We take the value from the <dinput.h> header file.
  101.      *
  102.      *      &g_pdi
  103.      *
  104.      *          Receives pointer to the IDirectInput interface
  105.      *          that was created.
  106.      *
  107.      *      NULL
  108.      *
  109.      *          We do not use OLE aggregation, so this parameter
  110.      *          must be NULL.
  111.      *
  112.      */
  113.     hr = DirectInputCreate(g_hinst, DIRECTINPUT_VERSION, &g_pdi, NULL);
  114.  
  115.     if (FAILED(hr)) {
  116.         Complain(hwnd, hr, "DirectInputCreate");
  117.         return FALSE;
  118.     }
  119.  
  120.     /*
  121.      *  Obtain an interface to the system mouse device.
  122.      *
  123.      *  Parameters:
  124.      *
  125.      *      GUID_SysMouse
  126.      *
  127.      *          The instance GUID for the device we wish to access.
  128.      *          GUID_SysMouse is a predefined instance GUID that
  129.      *          always refers to the system mouse device.
  130.      *
  131.      *      &g_pMouse
  132.      *
  133.      *          Receives pointer to the IDirectInputDevice interface
  134.      *          that was created.
  135.      *
  136.      *      NULL
  137.      *
  138.      *          We do not use OLE aggregation, so this parameter
  139.      *          must be NULL.
  140.      *
  141.      */
  142.     hr = g_pdi->CreateDevice(GUID_SysMouse, &g_pMouse, NULL);
  143.  
  144.     if (FAILED(hr)) {
  145.         Complain(hwnd, hr, "CreateDevice");
  146.         return FALSE;
  147.     }
  148.  
  149.     /*
  150.      *  Set the data format to "mouse format".
  151.      *
  152.      *  A data format specifies which controls on a device we
  153.      *  are interested in, and how they should be reported.
  154.      *
  155.      *  This tells DirectInput that we will be passing a
  156.      *  DIMOUSESTATE structure to IDirectInputDevice::GetDeviceState.
  157.      *
  158.      *  Parameters:
  159.      *
  160.      *      c_dfDIMouse
  161.      *
  162.      *          Predefined data format which describes
  163.      *          a DIMOUSESTATE structure.
  164.      */
  165.     hr = g_pMouse->SetDataFormat(&c_dfDIMouse);
  166.  
  167.     if (FAILED(hr)) {
  168.         Complain(hwnd, hr, "SetDataFormat");
  169.         return FALSE;
  170.     }
  171.  
  172.  
  173.     /*
  174.      *  Set the cooperativity level to let DirectInput know how
  175.      *  this device should interact with the system and with other
  176.      *  DirectInput applications.
  177.      *
  178.      *  Parameters:
  179.      *
  180.      *      DISCL_NONEXCLUSIVE
  181.      *
  182.      *          Retrieve mouse data when acquired, not interfering
  183.      *          with any other applications which are reading mouse
  184.      *          data.
  185.      *
  186.      *      DISCL_FOREGROUND
  187.      *
  188.      *          If the user switches away from our application,
  189.      *          automatically release the mouse back to the system.
  190.      *
  191.      */
  192.     hr = g_pMouse->SetCooperativeLevel(hwnd,
  193.                                        DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
  194.  
  195.     if (FAILED(hr)) {
  196.         Complain(hwnd, hr, "SetCooperativeLevel");
  197.         return FALSE;
  198.     }
  199.  
  200.     return TRUE;
  201.  
  202. }
  203.  
  204. /****************************************************************************
  205.  *
  206.  *      DITerm
  207.  *
  208.  *      Terminate our usage of DirectInput.
  209.  *
  210.  ****************************************************************************/
  211.  
  212. void
  213. DITerm(void)
  214. {
  215.  
  216.     /*
  217.      *  Destroy any lingering IDirectInputDevice object.
  218.      */
  219.     if (g_pMouse) {
  220.  
  221.         /*
  222.          *  Cleanliness is next to godliness.  Unacquire the device
  223.          *  one last time just in case we got really confused and tried
  224.          *  to exit while the device is still acquired.
  225.          */
  226.         g_pMouse->Unacquire();
  227.  
  228.         g_pMouse->Release();
  229.         g_pMouse = NULL;
  230.     }
  231.  
  232.     /*
  233.      *  Destroy any lingering IDirectInput object.
  234.      */
  235.     if (g_pdi) {
  236.         g_pdi->Release();
  237.         g_pdi = NULL;
  238.     }
  239.  
  240. }
  241.  
  242. /****************************************************************************
  243.  *
  244.  *      Ex_OnPaint
  245.  *
  246.  *      Display the current mouse position and button state.
  247.  *
  248.  ****************************************************************************/
  249.  
  250. LRESULT
  251. Ex_OnPaint(
  252.     HWND hwnd
  253. )
  254. {
  255.     PAINTSTRUCT ps;
  256.     HDC hdc = BeginPaint(hwnd, &ps);
  257.  
  258.     if (hdc) {
  259.  
  260.         ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &ps.rcPaint, g_szText,
  261.                    lstrlen(g_szText), NULL);
  262.  
  263.         EndPaint(hwnd, &ps);
  264.     }
  265.  
  266.     return 0;
  267. }
  268.  
  269. /****************************************************************************
  270.  *
  271.  *      Ex_OneFrame
  272.  *
  273.  *      The game plays here.
  274.  *
  275.  *      Our "game" consists entirely of reading mouse data
  276.  *      and displaying it.
  277.  *
  278.  ****************************************************************************/
  279.  
  280. void
  281. Ex_OneFrame(HWND hwnd)
  282. {
  283.  
  284.     if (g_pMouse) {
  285.  
  286.         DIMOUSESTATE dims;          /* DirectInput mouse state structure */
  287.         HRESULT hr;
  288.  
  289.     again:;
  290.         hr = g_pMouse->GetDeviceState(sizeof(DIMOUSESTATE), &dims);
  291.         if (hr == DIERR_INPUTLOST) {
  292.             /*
  293.              *  DirectInput is telling us that the input stream has
  294.              *  been interrupted.  We aren't tracking any state
  295.              *  between polls, so we don't have any special reset
  296.              *  that needs to be done.  We just re-acquire and
  297.              *  try again.
  298.              */
  299.             hr = g_pMouse->Acquire();
  300.             if (SUCCEEDED(hr)) {
  301.                 goto again;
  302.             }
  303.         }
  304.  
  305.         if (SUCCEEDED(hr)) {
  306.             char szBuf[1024];
  307.  
  308.             /*
  309.              *  Build the new status string.
  310.              *
  311.              *  Display mouse coordinates (x, y, z) and buttons.
  312.              */
  313.             wsprintf(szBuf, "(%d, %d, %d) %c %c %c %c",
  314.                      dims.lX, dims.lY, dims.lZ,
  315.                      (dims.rgbButtons[0] & 0x80) ? '0' : ' ',
  316.                      (dims.rgbButtons[1] & 0x80) ? '1' : ' ',
  317.                      (dims.rgbButtons[2] & 0x80) ? '2' : ' ',
  318.                      (dims.rgbButtons[3] & 0x80) ? '3' : ' ');
  319.  
  320.             /*
  321.              *  Trigger a repaint only if the status string changed.
  322.              *  This avoids flicker.
  323.              */
  324.             if (lstrcmp(g_szText, szBuf)) {
  325.                 lstrcpy(g_szText, szBuf);
  326.                 InvalidateRect(hwnd, NULL, TRUE);
  327.             }
  328.         }
  329.     }
  330.  
  331.     /*
  332.      *  Sleep for a few milliseconds to simulate a 30fps frame rate.
  333.      */
  334.     Sleep(1000 / 30);
  335.  
  336. }
  337.  
  338. /****************************************************************************
  339.  *
  340.  *      Ex_SyncAcquire
  341.  *
  342.  *      Acquire or unacquire the mouse, depending on the the g_fPaused
  343.  *      flag.  This synchronizes the device with our internal view of
  344.  *      the world.
  345.  *
  346.  ****************************************************************************/
  347.  
  348. void
  349. Ex_SyncAcquire(HWND hwnd)
  350. {
  351.     if (g_fPaused) {
  352.         if (g_pMouse) g_pMouse->Unacquire();
  353.     } else {
  354.         if (g_pMouse) g_pMouse->Acquire();
  355.     }
  356. }
  357.  
  358. /****************************************************************************
  359.  *
  360.  *      Ex_WndProc
  361.  *
  362.  *      Window procedure for simple sample.
  363.  *
  364.  ****************************************************************************/
  365.  
  366. LRESULT CALLBACK
  367. Ex_WndProc(
  368.     HWND hwnd,
  369.     UINT msg,
  370.     WPARAM wParam,
  371.     LPARAM lParam
  372. )
  373. {
  374.  
  375.     switch (msg) {
  376.  
  377.     case WM_PAINT:      return Ex_OnPaint(hwnd);
  378.  
  379.     /*
  380.      *  WM_ACTIVATE
  381.      *
  382.      *      Windows sends this message when the window becomes
  383.      *      the active window or stops being the active window.
  384.      *
  385.      *      wParam = WA_INACTIVE if window is no longer active
  386.      *
  387.      *      wParam = WA_ACTIVE or WA_CLICKACTIVE if window is now active
  388.      *
  389.      *      If we are losing activation, then pause.
  390.      *
  391.      *      If we are gaining activation, then unpause.
  392.      *
  393.      *      After deciding whether we are paused or unpaused,
  394.      *      tell DirectInput that we don't (paused) or do (unpaused)
  395.      *      want non-exclusive access to the mouse.
  396.      *
  397.      */
  398.     case WM_ACTIVATE:
  399.         g_fPaused = wParam == WA_INACTIVE;
  400.         Ex_SyncAcquire(hwnd);
  401.         break;
  402.  
  403.     case WM_DESTROY:
  404.         PostQuitMessage(0);
  405.         break;
  406.  
  407.     }
  408.  
  409.     return DefWindowProc(hwnd, msg, wParam, lParam);
  410. }
  411.  
  412. /****************************************************************************
  413.  *
  414.  *      AppInit
  415.  *
  416.  *      Set up everything the application needs to get started.
  417.  *
  418.  ****************************************************************************/
  419.  
  420. HWND
  421. AppInit(
  422.     HINSTANCE hinst,
  423.     int nCmdShow
  424. )
  425. {
  426.  
  427.     /*
  428.      *  Save instance handle for future reference.
  429.      */
  430.     g_hinst = hinst;
  431.  
  432.     /*
  433.      *  Set up the window class.
  434.      */
  435.     WNDCLASS wc;
  436.  
  437.     wc.hCursor        = LoadCursor(0, IDC_ARROW);
  438.     wc.hIcon          = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION));
  439.     wc.lpszMenuName   = NULL;
  440.     wc.lpszClassName  = c_szClassName;
  441.     wc.hbrBackground  = 0;
  442.     wc.hInstance      = hinst;
  443.     wc.style          = 0;
  444.     wc.lpfnWndProc    = Ex_WndProc;
  445.     wc.cbClsExtra     = 0;
  446.     wc.cbWndExtra     = 0;
  447.  
  448.     if (!RegisterClass(&wc)) {
  449.         return NULL;
  450.     }
  451.  
  452.     HWND hwnd = CreateWindow(
  453.                     c_szClassName,                  // Class name
  454.                     "DIEX1 - Alt+F4 to exit",       // Caption
  455.                     WS_OVERLAPPEDWINDOW,            // Style
  456.                     CW_USEDEFAULT, CW_USEDEFAULT,   // Position
  457.                     CW_USEDEFAULT, CW_USEDEFAULT,   // Size
  458.                     NULL,                           // No parent
  459.                     NULL,                           // No menu
  460.                     g_hinst,                        // inst handle
  461.                     0                               // no params
  462.                     );
  463.  
  464.     if (!DIInit(hwnd)) {
  465.         DestroyWindow(hwnd);
  466.         return NULL;
  467.     }
  468.  
  469.     ShowWindow(hwnd, nCmdShow);
  470.  
  471.     return hwnd;
  472. }
  473.  
  474. /****************************************************************************
  475.  *
  476.  *      WinMain
  477.  *
  478.  *      Application entry point.
  479.  *
  480.  ****************************************************************************/
  481.  
  482. int PASCAL
  483. WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR szCmdLine, int nCmdShow)
  484. {
  485.     MSG msg;
  486.     msg.wParam = 0;         /* In case something goes horribly wrong */
  487.  
  488.     HWND hwnd = AppInit(hinst, nCmdShow);
  489.  
  490.     if (hwnd) {
  491.  
  492.         /*
  493.          *  Standard game loop.
  494.          */
  495.         for (;;) {
  496.             if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  497.  
  498.                 /* If it's a quit message, we're outta here */
  499.                 if (msg.message == WM_QUIT) {
  500.                     break;
  501.                 } else {
  502.                     TranslateMessage(&msg);
  503.                     DispatchMessage(&msg);
  504.                 }
  505.             } else if (g_fPaused) {
  506.                 WaitMessage();
  507.             } else {
  508.                 Ex_OneFrame(hwnd);
  509.             }
  510.         }
  511.     }
  512.  
  513.     DITerm();
  514.  
  515.     return msg.wParam;
  516.  
  517. }
  518.