home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2000 May / PCP163A.iso / Runimage / Cbuilder4 / Examples / DDraw / DDraw1A / MAIN.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-26  |  9.3 KB  |  287 lines

  1. /*
  2.   This is a DirectDraw example program. DirectDraw programs require that you
  3.   have the DirectDraw runtime on your system. The runtime files are available
  4.   from Microsoft's web site, though many machines will have them on them
  5.   already, as they ship with a wide variety of products, including games, the
  6.   future operating systems Windows 98 and Windows NT 5.0. If you are using NT 4,
  7.   you should upgrade to at least Service Pack 3, so that you can have access
  8.   to DirectDraw 3.0, which is part of that Service Pack. Don't
  9.   try to install the DirectDraw runtime on a Windows NT system, instead, get
  10.   the latest Service Pack. The runtime install is meant only for Windows 95 or
  11.   98. One way to tell if you have DirectDraw on your system is to look in the
  12.   Windows/System directory or Winnt/System32 directory for the files DDRAW.DLL
  13.   and DSOUND.DLL.
  14.  
  15.   The purpose of DirectDraw is to allow you to perform very fast graphics
  16.   operations inside the Windows environment. In particular, DirectDraw can
  17.   give you direct access to the video buffers on a video card. For best
  18.   results, you should have at least 2 MB of memory on your video card.
  19.   DirectDraw allows you to create a backbuffer, draw to it, and then
  20.   flip it to the visible area in your video memory. Assuming that you are
  21.   in exclusive mode, and have enough video memory to keep both your primary
  22.   surface and back surface in video RAM, then the flip operation is
  23.   not a copy procedure, but simply changes the address of the block of
  24.   memory referenced by the visible area of your video card's memory. In short
  25.   the operation is very fast, and is guarenteed to happen in sync with
  26.   the refresh operations on your monitor. As a result, you can use DirectDraw
  27.   to perform very smooth animations. For a complete explanation, go to the
  28.   DirectDraw area on Microsoft's web site, or visit my web site at
  29.   http://users.aol.com/charliecal.
  30.  
  31.   The code shown here is the simplest possible DirectDraw program. It is
  32.   modeled closely after the DDX1 example that ships with the Microsoft's
  33.   DirectDraw SDK. I've simply taken their program, and rewritten it to
  34.   compile under a form based environment. In particular, the code uses a
  35.   TTimer object rather than calling SetTimer, and it responds to events
  36.   such as OnKeyDown rather than directly handling WM_KEYDOWN messages.
  37.   The conversion to a form based paradigm makes the code easier to read,
  38.   but doesn't change its underlying structure.
  39.  
  40.   If you do not want to use forms, the DDX1 program will compile unchanged
  41.   under CBuilder. Simply start a standard CBuilder project, remove the main
  42.   form, then replace the code in the Project Source with the code from
  43.   DDX1.cpp, which file ships with Microsoft's SDK. Press compile, and the
  44.   program will run fine.
  45.  
  46.   The code in this project has five methods:
  47.  
  48.   CONSTRUCTOR:
  49.     Perform trivial initialization of variables.
  50.  
  51.   FORMDESTROY:
  52.     Destroy the direct draw surfaces created in the Start method.
  53.  
  54.   START:
  55.     Call DirectDrawCreate, which initializes DirectDraw, and returns a pointer
  56.       to a DirectDraw object.
  57.     Call SetCooperativeLevel to switch into exclusive mode.
  58.     Call SetDisplayMode to switch to 640X480 8 bit resolution.
  59.     Call CreateSurface to create a primary surface
  60.     Call GetAttachedSurface to get a pointer to the back surface
  61.     Paint the front and back surface to black, and paint text to each
  62.       so you can recognize them when they are flipped to the screen.
  63.     Enable the timer.
  64.  
  65.   FORMKEYDOWN:
  66.     Respond to key presses designating the user's desire to switch into
  67.       exclusive mode and begin the demo.
  68.     Respond to the F12 or Esc keys by shutting down the application.
  69.  
  70.   FORMPAINT:
  71.     Paint some simple instructions for the user in the middle of the screen.
  72.     This method is not called while the program is in Exclusive mode.
  73.  
  74.   TIMER1TIMER:
  75.     Flip between the primary and back surfaces. This is the key method in this
  76.     demo as it shows how to swap two different surfaces, which is what you
  77.     want to do in an animated graphics program. This method is somewhat
  78.     misleading, though, because most of the time you will want to swap at
  79.     the fastest rate possible, rather than waiting for the timer to call
  80.     your program and ask you to swap. For instance, a smooth animation
  81.     should have a frame rate of at least 25 frames per second, a rate which
  82.     is not practical to achieve using a timer.
  83.  
  84. */
  85.  
  86. // Includes 
  87. #include <vcl.h>
  88. #include <ddraw.h>
  89. #pragma hdrstop
  90. #include "Main.h"
  91. #pragma resource "*.dfm"
  92.  
  93. //Const
  94. #define TIMER_ID        1
  95. #define TIMER_RATE      500
  96.  
  97. // Global Variables
  98. TForm1 *Form1;
  99.  
  100. ///////////////////////////////////////
  101. // Constructor
  102. ///////////////////////////////////////
  103. __fastcall TForm1::TForm1(TComponent* Owner)
  104.         : TForm(Owner)
  105. {
  106.   lpDD = NULL;
  107.   phase = 0;
  108.   bActive = False;
  109.   FrontMsg = "Front buffer (F12 or Esc to quit)";
  110.   BackMsg = "Back buffer (F12 or Esc to quit)";
  111. }
  112.  
  113. ///////////////////////////////////////
  114. // WM_DESTROY messages
  115. ///////////////////////////////////////
  116. void __fastcall TForm1::FormDestroy(TObject *Sender)
  117. {
  118.   if(lpDD != NULL)
  119.   {
  120.     if(lpDDSPrimary != NULL)
  121.     {
  122.       lpDDSPrimary->Release();
  123.       lpDDSPrimary = NULL;
  124.     }
  125.     lpDD->Release();
  126.     lpDD = NULL;
  127.   }
  128. }
  129.  
  130. ///////////////////////////////////////
  131. // Initialize DirectDraw
  132. ///////////////////////////////////////
  133. void __fastcall TForm1::Start()
  134. {
  135.   HRESULT ddrval;
  136.   DDSURFACEDESC ddsd;
  137.   DDSCAPS ddscaps;
  138.   HDC DC;
  139.   char buf[256];
  140.  
  141.   ddrval = DirectDrawCreate(NULL, &lpDD, NULL);
  142.   if(ddrval == DD_OK)
  143.   {
  144.     // Get exclusive mode
  145.     ddrval = lpDD->SetCooperativeLevel(Handle,
  146.       DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
  147.     if(ddrval == DD_OK)
  148.     {
  149.       ddrval = lpDD->SetDisplayMode(640, 480, 8);
  150.       if(ddrval == DD_OK)
  151.       {
  152.         // Create the primary surface with 1 back buffer
  153.         ddsd.dwSize = sizeof(ddsd);
  154.         ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  155.         ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
  156.                               DDSCAPS_FLIP |
  157.                               DDSCAPS_COMPLEX;
  158.         ddsd.dwBackBufferCount = 1;
  159.         ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL);
  160.         if(ddrval == DD_OK)
  161.         {
  162.           // Get a pointer to the back buffer
  163.           ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  164.           ddrval = lpDDSPrimary->GetAttachedSurface(&ddscaps,
  165.                                                 &lpDDSBack);
  166.           if(ddrval == DD_OK)
  167.           {
  168.             // draw some text.
  169.             if (lpDDSPrimary->GetDC(&DC) == DD_OK)
  170.             {
  171.                 SetBkColor(DC, RGB(0, 0, 255));
  172.                 SetTextColor(DC, RGB(255, 255, 0));
  173.                 TextOut(DC, 0, 0, FrontMsg.c_str(), FrontMsg.Length());
  174.                 lpDDSPrimary->ReleaseDC(DC);
  175.             }
  176.  
  177.             if (lpDDSBack->GetDC(&DC) == DD_OK)
  178.             {
  179.                 SetBkColor(DC, RGB(0, 0, 255));
  180.                 SetTextColor(DC, RGB(255, 255, 0));
  181.                 TextOut(DC, 0, 0, BackMsg.c_str(), BackMsg.Length());
  182.                 lpDDSBack->ReleaseDC(DC);
  183.             }
  184.  
  185.             // Create a timer to flip the pages
  186.             Timer1->Enabled = True;
  187.             bActive = True;
  188.             return;
  189.           }
  190.         }
  191.       }
  192.     }
  193.   }
  194.   wsprintf(buf, "Direct Draw Init Failed (%08lx)\n", ddrval);
  195.   MessageBox(Handle, buf, "ERROR", MB_OK);
  196.   Close();
  197. }
  198.  
  199. ///////////////////////////////////////
  200. // WM_KEYDOWN messages
  201. ///////////////////////////////////////
  202. void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key,
  203.         TShiftState Shift)
  204. {
  205.  
  206.    switch (Key)
  207.    {
  208.      case VK_F3:
  209.        Start();
  210.        break;
  211.  
  212.      case VK_ESCAPE:
  213.      case VK_F12:
  214.        Close();
  215.        break;
  216.    }
  217. }
  218.  
  219. ///////////////////////////////////////
  220. // WM_PAINT messages
  221. ///////////////////////////////////////
  222. void __fastcall TForm1::FormPaint(TObject *Sender)
  223. {
  224.   RECT rc;
  225.   SIZE size;
  226.   char szMsg[] = "Page Flipping Test: Press F3 to start, F12 or Esc to exit";
  227.   
  228.   if (!bActive)
  229.   {
  230.     HDC DC = GetDC(Handle);
  231.     rc = GetClientRect();
  232.     GetTextExtentPoint(DC, szMsg, lstrlen(szMsg), &size);
  233.     SetBkColor(DC, RGB(0, 0, 0));
  234.     SetTextColor(DC, RGB(255, 255, 0));
  235.     TextOut(DC, (rc.right - size.cx)/2, (rc.bottom - size.cy)/2,
  236.       szMsg, sizeof(szMsg)-1);
  237.     ReleaseDC(Handle, DC);
  238.   }
  239. }
  240.  
  241. ///////////////////////////////////////
  242. // WM_TIMER messages
  243. ///////////////////////////////////////
  244. void __fastcall TForm1::Timer1Timer(TObject *Sender)
  245. {
  246.   HDC DC;
  247.  
  248.   if (lpDDSBack->GetDC(&DC) == DD_OK)
  249.   {
  250.     if(phase)
  251.     {
  252.       SetBkColor(DC, RGB(0, 0, 255));
  253.       SetTextColor(DC, RGB(255, 255, 0));
  254.       TextOut(DC, 0, 0, FrontMsg.c_str(), FrontMsg.Length());
  255.       phase = 0;
  256.     }
  257.     else
  258.     {
  259.       SetBkColor(DC, RGB(0, 0, 255));
  260.       SetTextColor(DC, RGB(0, 255, 255));
  261.       TextOut(DC, 0, 0, BackMsg.c_str(), BackMsg.Length());
  262.       phase = 1;
  263.     }
  264.     lpDDSBack->ReleaseDC(DC);
  265.   }
  266.  
  267.   while(1)
  268.   {
  269.     HRESULT ddrval;
  270.     ddrval = lpDDSPrimary->Flip(NULL, 0);
  271.     
  272.     if(ddrval == DD_OK)
  273.       break;
  274.  
  275.     if(ddrval == DDERR_SURFACELOST)
  276.     {
  277.       ddrval = lpDDSPrimary->Restore();
  278.       if(ddrval != DD_OK)
  279.         break;
  280.     }
  281.  
  282.     if(ddrval != DDERR_WASSTILLDRAWING)
  283.       break;
  284.   }
  285. }
  286.  
  287.