/*==========================================================================
 *
 *  Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
 *
 *  File:       ddex1.cpp
 *  Content:    Direct Draw example program 1.  Creates a Direct Draw 
 *              object and then a primary surface with a back buffer.
 *              Slowly flips between the primary surface and the back
 *              buffer.  Press F12 to terminate the program.
 *
 ***************************************************************************/

#define NAME "DDExample1"
#define TITLE "Direct Draw Example 1"

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <ddraw.h>
#include <stdlib.h>
#include <stdarg.h>

#define IDR_MENU                        102
#define IDM_EXIT                        40001

#define TIMER_ID        1
#define TIMER_RATE      500

LPDIRECTDRAW            lpDD;           // DirectDraw object
LPDIRECTDRAWSURFACE     lpDDSPrimary;   // DirectDraw primary surface
LPDIRECTDRAWSURFACE     lpDDSBack;      // DirectDraw back surface
BOOL                    bActive;        // is application active?

/*
 * finiObjects
 *
 * finished with all objects we use; release them
 */
static void finiObjects( void )
{
    if( lpDD != NULL )
    {
	if( lpDDSPrimary != NULL )
	{
	    IDirectDrawSurface_Release(lpDDSPrimary);
	    lpDDSPrimary = NULL;
	}
	IDirectDraw_Release(lpDD);
	lpDD = NULL;
    }
} /* finiObjects */

char szMsg[] = "Page Flipping Test: Press F12 to exit";
char szFrontMsg[] = "Front buffer (F12 to quit)";
char szBackMsg[] = "Back buffer (F12 to quit)";

LRESULT CALLBACK
WindowProc( HWND hWnd, UINT message, 
			    WPARAM wParam, LPARAM lParam )
{
    PAINTSTRUCT ps;
    RECT        rc;
    SIZE        size;
    static BYTE phase = 0;
    HDC         hdc;

    switch( message )
    {
    case WM_ACTIVATEAPP:
	bActive = wParam;
	break;

    case WM_CREATE:
	break;

    case WM_SETCURSOR:
	SetCursor(NULL);
	return TRUE;

    case WM_TIMER:
	// Flip surfaces
	if( bActive )
	{
	    if (IDirectDrawSurface_GetDC(lpDDSBack, &hdc) == DD_OK)
	    {
		SetBkColor( hdc, RGB( 0, 0, 255 ) );
		SetTextColor( hdc, RGB( 255, 255, 0 ) );
		if( phase )
		{
		    TextOut( hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg) );
		    phase = 0;
		}
		else
		{
		    TextOut( hdc, 0, 0, szBackMsg, lstrlen(szBackMsg) );
		    phase = 1;
		}
		IDirectDrawSurface_ReleaseDC(lpDDSBack, hdc);
	    }

	    while( 1 )
	    {
		HRESULT ddrval;
		ddrval = IDirectDrawSurface_Flip(lpDDSPrimary, NULL, 0);
		if( ddrval == DD_OK )
		{
		    break;
		}
		if( ddrval == DDERR_SURFACELOST )
		{
		    ddrval = IDirectDrawSurface_Restore(lpDDSPrimary);
		    if( ddrval != DD_OK )
		    {
			break;
		    }
		}
		if( ddrval != DDERR_WASSTILLDRAWING )
		{
		    break;
		}
	    }
	}
	break;
 
    case WM_KEYDOWN:
	switch( wParam )
	{
	case VK_ESCAPE:
	case VK_F12:
	    PostMessage(hWnd, WM_CLOSE, 0, 0);
	    break;
	}
	break;

    case WM_PAINT:
	BeginPaint( hWnd, &ps );
	GetClientRect(hWnd, &rc);
	GetTextExtentPoint( ps.hdc, szMsg, lstrlen(szMsg), &size );
	SetBkColor( ps.hdc, RGB( 0, 0, 255 ) );
	SetTextColor( ps.hdc, RGB( 255, 255, 0 ) );
	TextOut( ps.hdc, (rc.right - size.cx)/2, (rc.bottom - size.cy)/2,
	    szMsg, sizeof( szMsg )-1 );
	EndPaint( hWnd, &ps );
	break;

    case WM_DESTROY:
	finiObjects();
	PostQuitMessage( 0 );
	break;
    }

    return DefWindowProc(hWnd, message, wParam, lParam);

} /* WindowProc */

/*
 * doInit - do work required for every instance of the application:
 *                create the window, initialize data
 */
static BOOL doInit( HINSTANCE hInstance, int nCmdShow )
{
    HWND                hwnd;
    WNDCLASSEX            wc;
    DDSURFACEDESC       ddsd;
    DDSCAPS             ddscaps;
    HRESULT             ddrval;
    HDC                 hdc;
    char                buf[256];

    memset (&wc, 0, sizeof(WNDCLASSEX));
    wc.cbSize = sizeof(WNDCLASSEX);
    /*
     * set up and register window class
     */
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon( hInstance, IDI_APPLICATION );
    wc.hCursor = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground = NULL;
    wc.lpszMenuName = NAME;
    wc.lpszClassName = NAME;
    RegisterClassEx( &wc );
    
    printf("Geometry: %dx%d\n", GetSystemMetrics( SM_CXSCREEN ),
	   GetSystemMetrics( SM_CYSCREEN ));
    /*
     * create a window
     */
    hwnd = CreateWindowEx(
	WS_EX_TOPMOST,
	NAME,
	TITLE,
	WS_POPUP,
	0,0,
#if 1
	CW_USEDEFAULT,
	CW_USEDEFAULT,
#else
	GetSystemMetrics( SM_CXSCREEN ),
	GetSystemMetrics( SM_CYSCREEN ),
#endif
	NULL,
	NULL,
	hInstance,
	NULL );

    if( !hwnd )
    {
	    printf("CreateWindowEx() failed!\n");
	    return FALSE;
    }

    ShowWindow( hwnd, nCmdShow );
    UpdateWindow( hwnd );

    /*
     * create the main DirectDraw object
     */
    ddrval = DirectDrawCreate( NULL, &lpDD, NULL );
    if( ddrval == DD_OK )
    {
	// Get exclusive mode
	ddrval = IDirectDraw_SetCooperativeLevel( lpDD, hwnd,
				DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
	if(ddrval == DD_OK )
	{
	    ddrval = IDirectDraw_SetDisplayMode( lpDD, 640, 480, 16 );
	    if( ddrval == DD_OK )
	    {
		// Create the primary surface with 1 back buffer
		ddsd.dwSize = sizeof( ddsd );
		ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
				      DDSCAPS_FLIP | 
				      DDSCAPS_COMPLEX;
		ddsd.dwBackBufferCount = 1;
		ddrval = IDirectDraw_CreateSurface( lpDD, &ddsd, &lpDDSPrimary, NULL );
		if( ddrval == DD_OK )
		{
		    // Get a pointer to the back buffer
		    ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
		    ddrval = IDirectDrawSurface_GetAttachedSurface(lpDDSPrimary, &ddscaps, &lpDDSBack);
		    if( ddrval == DD_OK )
		    {
			// draw some text.
			if (IDirectDrawSurface_GetDC(lpDDSPrimary, &hdc) == DD_OK)
			{
			    SetBkColor( hdc, RGB( 0, 0, 255 ) );
			    SetTextColor( hdc, RGB( 255, 255, 0 ) );
			    TextOut( hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg) );
			    IDirectDrawSurface_ReleaseDC(lpDDSPrimary, hdc);
			}

			if (IDirectDrawSurface_GetDC(lpDDSBack, &hdc) == DD_OK)
			{
			    SetBkColor( hdc, RGB( 0, 0, 255 ) );
			    SetTextColor( hdc, RGB( 255, 255, 0 ) );
			    TextOut( hdc, 0, 0, szBackMsg, lstrlen(szBackMsg) );
			    IDirectDrawSurface_ReleaseDC(lpDDSBack,hdc);
			}

			// Create a timer to flip the pages
			if( SetTimer( hwnd, TIMER_ID, TIMER_RATE, NULL ) )
			{
			     return TRUE;
			}
		    }
		}
	    }
	}
    }

    wsprintf(buf, "Direct Draw Init Failed (%08lx)\n", ddrval );
    MessageBox( hwnd, buf, "ERROR", MB_OK );
    finiObjects();
    DestroyWindow( hwnd );
    return FALSE;
} /* doInit */

/*
 * WinMain - initialization, message loop
 */
int STDCALL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
			LPSTR lpCmdLine, int nCmdShow)
{
    MSG         msg;

    if( !doInit( hInstance, nCmdShow ) )
    {
	    printf("doInit() failed!\n");
	    return FALSE;
    }

    while (GetMessage(&msg, NULL, 0, 0))
    {
	TranslateMessage(&msg);
	DispatchMessage(&msg);
    }

    return msg.wParam;

} /* WinMain */

