// Page flipping demo

#define WIN32_LEAN_AND_MEAN 

#include <windows.h>   // include important windows stuff

#include <windowsx.h>

#include <mmsystem.h>

#include <iostream.h> // include important C/C++ stuff

#include <ddraw.h>  // directX include

#define WINDOW_CLASS_NAME "WINXCLASS"  // class name

#define WINDOW_WIDTH  640              // size of window

#define WINDOW_HEIGHT 480

#define SCREEN_WIDTH  640              // size of screen

#define SCREEN_HEIGHT 480

#define SCREEN_BPP    8                // bits per pixel

// these read the keyboard asynchronously

#define KEY_DOWN(vkCode) ((GetAsyncKeyState(vkCode) & 0x8000) ? 1 : 0)

#define KEY_UP(vkCode)   ((GetAsyncKeyState(vkCode) & 0x8000) ? 0 : 1)

typedef unsigned short USHORT;

typedef unsigned short WORD;

typedef unsigned char  UCHAR;

typedef unsigned char  BYTE;

// PROTOTYPES

int GameInit(void *parms=NULL);

int GameShutdown(void *parms=NULL);

int GameMain(void *parms=NULL);

// GLOBALS

HWND mainWindowHandle = NULL; // save the window handle

HINSTANCE mainInstance = NULL; // save the instance

char buffer[80];                // used to print text

LPDIRECTDRAW         lpdd         = NULL;  // dd object

LPDIRECTDRAWSURFACE  lpddsprimary = NULL;  // dd primary surface

LPDIRECTDRAWSURFACE  lpddsback    = NULL;  // dd back surface

LPDIRECTDRAWPALETTE  lpddpal      = NULL;  // a pointer to the created dd palette

DDSURFACEDESC        ddsd;                 // a direct draw surface description struct

DDSCAPS              ddscaps;              // a direct draw surface capabilities struct

HRESULT              ddrval;               // result back from dd calls

UCHAR                *doubleBuffer = NULL; // the double buffer             

// FUNCTIONS

LRESULT CALLBACK WindowProc(HWND hwnd,UINT msg,WPARAM wparam,

                            LPARAM lparam)

{ // this is the main message handler of the system

  PAINTSTRUCT     ps;            // used in WM_PAINT

  HDC             hdc;     // handle to a device context

  // what is the message

  switch(msg)

  { case WM_CREATE:

    { // do initialization stuff here

        return(0);

      } break;

    case WM_PAINT:

      { // start painting

         hdc = BeginPaint(hwnd,&ps);

      // end painting

      EndPaint(hwnd,&ps);

      return(0);

    } break;

    case WM_DESTROY:

   { // kill the application                

     PostQuitMessage(0);

     return(0);

   } break;

   default:break;

  } // end switch

  // process any messages that we didn't take care of

  return (DefWindowProc(hwnd, msg, wparam, lparam));

} // end WinProc

// *************  WINMAIN   *****************

int WINAPI WinMain(HINSTANCE hinstance,HINSTANCE hprevinstance,

                   LPSTR lpcmdline,int ncmdshow)

{ WNDCLASS winclass;    // this will hold the class we create

  HWND      hwnd;            // generic window handle

  MSG       msg;       // generic message

  HDC      hdc;       // generic dc

  PAINTSTRUCT ps;     // generic paintstruct

  // first fill in the window class stucture

  winclass.style              = CS_DBLCLKS | CS_OWNDC |

                          CS_HREDRAW | CS_VREDRAW;

  winclass.lpfnWndProc  = WindowProc;

  winclass.cbClsExtra         = 0;

  winclass.cbWndExtra         = 0;

  winclass.hInstance          = hinstance;

  winclass.hIcon              = LoadIcon(NULL, IDI_APPLICATION);

  winclass.hCursor            = LoadCursor(NULL, IDC_ARROW);

  winclass.hbrBackground      = (HBRUSH)GetStockObject(BLACK_BRUSH);

  winclass.lpszMenuName = NULL;

  winclass.lpszClassName      = WINDOW_CLASS_NAME;

  // register the window class

  if (!RegisterClass(&winclass))

      return(0);

  // create the window, note the use of WS_POPUP

  if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class

                            "Page Flip",  // title

                            WS_POPUP | WS_VISIBLE,

                            0,0,         // x,y

                            WINDOW_WIDTH,  // width

                            WINDOW_HEIGHT, // height

                            NULL,        // handle to parent

                            NULL,        // handle to menu

                            hinstance,// instance

                            NULL)))   // creation parms

      return(0);

  // save the window handle and instance in a global

  mainWindowHandle = hwnd;

  mainInstance      = hinstance;

  // perform all game console specific initialization

  GameInit();

  // enter main event loop

  while(1)

  {   if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))

    {  // test if this is a quit

       if (msg.message == WM_QUIT)

           break;

     

            // translate any accelerator keys

            TranslateMessage(&msg);

            // send the message to the window proc

            DispatchMessage(&msg);

      } // end if

   

    // main game processing goes here

    GameMain();

  } // end while

  // shutdown game and release all resources

  GameShutdown();

  // return to Windows like this

  return(msg.wParam);

} // end WinMain

//**********************************************************

//**********************************************************

// WINX GAME PROGRAMMING CONSOLE FUNCTIONS

int GameInit(void *parms)

{ // this function is where you do all the initialization

  // for your game

  // create object and test for error

  if (DirectDrawCreate(NULL,&lpdd,NULL)!=DD_OK)

     return(0);

  // set cooperation level to windowed mode normal

  if (lpdd->SetCooperativeLevel(mainWindowHandle,

           DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN |

           DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)!=DD_OK)

      return(0);

  // set the display mode

  if (lpdd->SetDisplayMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP)!=DD_OK)

     return(0);

  // Create the primary surface

  memset(&ddsd,0,sizeof(ddsd));

  ddsd.dwSize = sizeof(ddsd);

  // validate capabilities field and backbuffer count

  ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;

  // we want a complex flippable surface structure

  ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |

                        DDSCAPS_COMPLEX;

  ddsd.dwBackBufferCount = 1;

  // create the primary surface

  lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL);

  // query for the backbuffer or secondary surface

  ddscaps.dwCaps = DDSCAPS_BACKBUFFER;

  // get the surface

  lpddsprimary->GetAttachedSurface(&ddscaps,&lpddsback);

  // allocate memory, just like new()

  if ((doubleBuffer = (UCHAR *)malloc(SCREEN_WIDTH*SCREEN_HEIGHT))==NULL)

      return(0);

  // return success

  return(1);

} // end GameInit

int GameShutdown(void *parms)

{ // this function is where you shutdown your game and

  // release all resources that you allocated

  // first release the secondary surface

  if (lpddsback!=NULL)

     lpddsback->Release();

      

  // now release the primary surface

  if (lpddsprimary!=NULL)

     lpddsprimary->Release();

      

  // release the directdraw object

  if (lpdd!=NULL)

     lpdd->Release();

  // free double buffer, like delete()

  if (doubleBuffer!=NULL)

     free(doubleBuffer);

  // return success

  return(1);

} // end GameShutdown

int GameMain(void *parms)

{ // this is the workhorse of your game it will be called

  // continuously in real-time, all the calls for your game go here!

  UCHAR *backbuffer = NULL, // used to draw

        *destPtr    = NULL, // used in line by line copy

        *srcPtr     = NULL; // " "

  // check of user is trying to exit

  if (KEY_DOWN(VK_ESCAPE) || KEY_DOWN(VK_SPACE))

      PostMessage(mainWindowHandle, WM_DESTROY,0,0);

  // erase secondary back buffer

  memset(&ddsd,0,sizeof(ddsd));

  ddsd.dwSize = sizeof(ddsd);

  // lock the secondary surface

  lpddsback->Lock(NULL,&ddsd,

              DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);

  // get video pointer to secondary surface

  backbuffer = (UCHAR *)ddsd.lpSurface;    

  // clear back buffer out

  if (ddsd.lPitch == SCREEN_WIDTH)  // linear memory

      memset(backbuffer,0,SCREEN_WIDTH*SCREEN_HEIGHT);

  else

  { // non-linear memory

    // make copy of video pointer

    destPtr = backbuffer;

    // clear out memory one line at a time

    for (int y=0; y<SCREEN_HEIGHT; y++)

      { // clear nect line

      memset(destPtr,0,SCREEN_WIDTH);

      // advance pointer to next line

      destPtr+=ddsd.lPitch;

    } // end for y

  } // end else

  // perform game logic...

      

  // draw the next frame into the secondary back buffer

  // plot 5000 random pixels

  for (int index=0; index<5000; index++)

  { int   x   = rand()%SCREEN_WIDTH;

    int   y   = rand()%SCREEN_HEIGHT;

    UCHAR col = rand()%256;

    backbuffer[x+y*SCREEN_WIDTH] = col;

  } // end for index

  // unlock secondary buffer

  lpddsback->Unlock(backbuffer);

  // flip pages

  while(lpddsprimary->Flip(NULL, DDFLIP_WAIT)!=DD_OK);

  // wait a sec

  Sleep(50);

  // return success

  return(1);

} // end GameMain