#include <AfxWin.h>
#include <AfxExt.h>
#include <mmsystem.h>
#define INITGUID
#include <ddraw.h>
#include <d3d.h>
#include <d3drm.h>
#include <d3drmwin.h>
#include "FullScreenWin.h"
#include "resource.h"

#pragma comment (lib,"ddraw.lib")
#pragma comment (lib,"d3drm.lib")
#pragma comment (lib,"winmm.lib")

const D3DVALUE PI = D3DVALUE(3.14159265359);
const D3DVALUE CLOSELIM = D3DVALUE(-10);
const D3DVALUE FARLIM = D3DVALUE(20);
const D3DVALUE XOUTLIM = D3DVALUE(15);
const D3DVALUE YOUTLIM = D3DVALUE(10);

const D3DVECTOR trans[]=  // object location for each key frame
{
	{ D3DVALUE(0),        D3DVALUE(0),       FARLIM   },
	{ XOUTLIM,            D3DVALUE(YOUTLIM), CLOSELIM },
	{ D3DVALUE(0),        D3DVALUE(0),       FARLIM   },
	{ -XOUTLIM,           D3DVALUE(YOUTLIM), CLOSELIM },
	{ D3DVALUE(0),        D3DVALUE(0),       FARLIM   },
	{ D3DVALUE(-XOUTLIM), -YOUTLIM,          CLOSELIM },
	{ D3DVALUE(0),        D3DVALUE(0),       FARLIM   },
	{ D3DVALUE(XOUTLIM),  -YOUTLIM,          CLOSELIM },
	{ D3DVALUE(0),        D3DVALUE(0),       FARLIM   },
	{ D3DVALUE(0),        D3DVALUE(0),       CLOSELIM },
	{ D3DVALUE(0),        D3DVALUE(0),       FARLIM   },
};

D3DVECTOR vect[]=   // rotation vector for each key frame
{ 
  { D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) },
  { D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) },
  { D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) },
  { D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) },
  { D3DVALUE(0), D3DVALUE(1), D3DVALUE(0) },
  { D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) },
  { D3DVALUE(0), D3DVALUE(1), D3DVALUE(0) },
  { D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) },
  { D3DVALUE(0), D3DVALUE(1), D3DVALUE(0) },
  { D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) },
  { D3DVALUE(1), D3DVALUE(0), D3DVALUE(0) },
};

const D3DVALUE rot[]= // object rotation at each key frame
{
	PI/2,
	PI,
	-(PI/2),
	PI,
	PI/2,
	PI,
	-(PI/2),
	-PI,
	PI/2,
	PI,
	PI/2,
};

PALETTEENTRY swirlpalette[256]=
{
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 132, 66, },
 { 0, 255, 0, },
 { 0, 255, 255, },
 { 132, 132, 255, },
 { 255, 0, 132, },
 { 255, 255, 255, },
 { 191, 0, 0, },
 { 0, 191, 0, },
 { 191, 191, 0, },
 { 0, 0, 191, },
 { 191, 0, 191, },
 { 0, 191, 191, },
 { 192, 192, 192, },
 { 128, 128, 128, },
 { 255, 0, 0, },
 { 255, 255, 0, },
 { 0, 0, 255, },
 { 255, 0, 255, },
 { 128, 0, 0, },
 { 128, 128, 0, },
 { 0, 128, 0, },
 { 0, 128, 128, },
 { 0, 0, 128, },
 { 128, 0, 128, },
 { 128, 128, 64, },
 { 0, 64, 64, },
 { 0, 128, 255, },
 { 0, 64, 128, },
 { 64, 0, 255, },
 { 128, 64, 0, },
 { 255, 255, 128, },
 { 0, 255, 128, },
 { 128, 255, 255, },
 { 128, 128, 255, },
 { 255, 0, 128, },
 { 255, 128, 64, },
 { 128, 0, 255, },
 { 16, 0, 0, },
 { 0, 160, 0, },
 { 0, 0, 70, },
 { 40, 193, 12, },
 { 168, 191, 247, },
 { 0, 129, 92, },
 { 153, 0, 0, },
 { 0, 191, 247, },
 { 52, 0, 0, },
 { 6, 191, 247, },
 { 6, 0, 70, },
 { 48, 0, 0, },
 { 188, 191, 251, },
 { 0, 191, 248, },
 { 16, 0, 70, },
 { 209, 0, 0, },
 { 0, 25, 224, },
 { 6, 0, 0, },
 { 80, 0, 0, },
 { 76, 0, 91, },
 { 104, 0, 91, },
 { 76, 0, 93, },
 { 28, 0, 91, },
 { 42, 0, 70, },
 { 28, 25, 225, },
 { 76, 0, 70, },
 { 0, 0, 91, },
 { 104, 0, 0, },
 { 165, 0, 91, },
 { 76, 25, 229, },
 { 68, 0, 91, },
 { 51, 0, 91, },
 { 0, 0, 50, },
 { 108, 0, 0, },
 { 90, 0, 91, },
 { 20, 25, 229, },
 { 108, 195, 48, },
 { 49, 0, 91, },
 { 232, 0, 0, },
 { 144, 0, 91, },
 { 240, 25, 231, },
 { 4, 25, 230, },
 { 56, 0, 91, },
 { 79, 130, 228, },
 { 0, 130, 228, },
 { 138, 130, 228, },
 { 142, 25, 224, },
 { 240, 25, 224, },
 { 0, 25, 230, },
 { 84, 0, 0, },
 { 211, 130, 228, },
 { 84, 25, 224, },
 { 212, 0, 0, },
 { 80, 0, 91, },
 { 84, 25, 225, },
 { 20, 130, 228, },
 { 37, 130, 228, },
 { 68, 25, 225, },
 { 20, 0, 0, },
 { 1, 0, 0, },
 { 3, 255, 254, },
 { 10, 255, 255, },
 { 0, 0, 3, },
 { 192, 0, 0, },
 { 224, 70, 0, },
 { 4, 25, 231, },
 { 0, 129, 168, },
 { 51, 0, 0, },
 { 152, 0, 0, },
 { 4, 191, 251, },
 { 222, 0, 0, },
 { 224, 25, 231, },
 { 255, 25, 231, },
 { 51, 0, 70, },
 { 63, 0, 0, },
 { 152, 2, 0, },
 { 120, 0, 0, },
 { 204, 129, 168, },
 { 52, 0, 70, },
 { 202, 0, 70, },
 { 4, 0, 91, },
 { 44, 0, 0, },
 { 200, 0, 0, },
 { 248, 0, 91, },
 { 44, 0, 70, },
 { 220, 2, 0, },
 { 112, 0, 0, },
 { 38, 0, 70, },
 { 131, 0, 0, },
 { 32, 191, 247, },
 { 1, 0, 70, },
 { 240, 0, 0, },
 { 118, 0, 1, },
 { 1, 191, 247, },
 { 125, 0, 0, },
 { 32, 0, 0, },
 { 204, 0, 0, },
 { 240, 0, 70, },
 { 200, 0, 1, },
 { 88, 0, 70, },
 { 109, 0, 70, },
 { 76, 0, 1, },
 { 168, 0, 70, },
 { 236, 0, 0, },
 { 10, 145, 154, },
 { 12, 0, 70, },
 { 112, 0, 91, },
 { 38, 191, 251, },
 { 10, 60, 47, },
 { 86, 6, 116, },
 { 46, 145, 154, },
 { 220, 133, 118, },
 { 0, 63, 200, },
 { 0, 63, 216, },
 { 80, 133, 68, },
 { 83, 1, 23, },
 { 1, 63, 216, },
 { 134, 1, 47, },
 { 23, 74, 225, },
 { 0, 0, 200, },
 { 80, 133, 96, },
 { 224, 63, 200, },
 { 154, 1, 47, },
 { 23, 76, 110, },
 { 47, 19, 100, },
 { 0, 47, 0, },
 { 80, 133, 132, },
 { 80, 133, 144, },
 { 248, 1, 23, },
 { 0, 5, 20, },
 { 2, 0, 0, },
 { 0, 4, 146, },
 { 166, 0, 0, },
 { 0, 133, 210, },
 { 0, 133, 186, },
 { 0, 0, 1, },
 { 198, 0, 0, },
 { 23, 127, 80, },
 { 200, 127, 83, },
 { 47, 47, 7, },
 { 110, 134, 0, },
 { 100, 1, 23, },
 { 0, 1, 47, },
 { 7, 0, 0, },
 { 200, 1, 47, },
 { 0, 0, 95, },
 { 10, 0, 0, },
 { 0, 127, 83, },
 { 22, 121, 41, },
 { 166, 146, 166, },
 { 76, 5, 199, },
 { 119, 17, 172, },
 { 186, 22, 86, },
 { 47, 0, 7, },
 { 95, 0, 200, },
 { 83, 0, 10, },
 { 41, 0, 0, },
 { 166, 0, 22, },
 { 199, 0, 166, },
 { 172, 0, 76, },
 { 86, 0, 119, },
 { 10, 0, 186, },
 { 46, 144, 102, },
 { 0, 144, 102, },
 { 0, 22, 54, },
 { 0, 5, 199, },
 { 253, 255, 254, },
 { 102, 133, 116, },
 { 238, 0, 254, },
 { 120, 5, 199, },
 { 103, 66, 237, },
 { 1, 0, 1, },
 { 54, 0, 0, },
 { 199, 1, 12, },
 { 0, 0, 41, },
 { 0, 19, 64, },
 { 0, 19, 56, },
 { 56, 127, 83, },
 { 47, 63, 207, },
 { 207, 0, 0, },
 { 56, 0, 0, },
 { 56, 1, 47, },
 { 200, 0, 95, },
 { 186, 121, 41, },
 { 62, 21, 30, },
 { 238, 238, 238, },
 { 221, 221, 221, },
 { 204, 204, 204, },
 { 187, 187, 187, },
 { 170, 170, 170, },
 { 153, 153, 153, },
 { 136, 136, 136, },
 { 119, 119, 119, },
 { 102, 102, 102, },
 { 85, 85, 85, },
 { 68, 68, 68, },
 { 51, 51, 51, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
 { 0, 0, 0, },
};

const int menucols = 4;
const int reservedspace=40;
const int menuwidth=320;
const int menuheight=200;
const int colwidth=80;
const int rowheight=20;
const int maxmodes=28;
const char headertext[]="Direct3D FullScreen Demo";
const COLORREF textcolor=RGB(0, 132, 255);
const COLORREF textshadow=RGB(0, 0, 132);
const COLORREF highlightcolor=RGB(255, 255, 255);


BEGIN_MESSAGE_MAP(FullScreenWin, RMWin)
	//{{AFX_MSG_MAP(FullScreenWin)
	ON_WM_KEYDOWN()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


LPDIRECT3DRMANIMATION FullScreenWin::animation;

//-----------------------------------------------------------------------------
// Name: DDColorMatch()
// Desc: Convert a RGB color to a pysical color.
//       We do this by leting GDI SetPixel() do the color matching
//       then we lock the memory and see what it got mapped to.
//-----------------------------------------------------------------------------
extern "C" DWORD
DDColorMatch(IDirectDrawSurface * pdds, COLORREF rgb)
{
    COLORREF                rgbT;
    HDC                     hdc;
    DWORD                   dw = CLR_INVALID;
    DDSURFACEDESC           ddsd;
    HRESULT                 hres;

    //
    //  Use GDI SetPixel to color match for us
    //
    if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
    {
        rgbT = GetPixel(hdc, 0, 0);     // Save current pixel value
        SetPixel(hdc, 0, 0, rgb);       // Set our value
        pdds->ReleaseDC(hdc);
    }

    //
    // Now lock the surface so we can read back the converted color
    //
    ddsd.dwSize = sizeof(ddsd);
    while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) == DDERR_WASSTILLDRAWING)
        ;
    if (hres == DD_OK)
    {
        dw = *(DWORD *) ddsd.lpSurface;                 // Get DWORD
        if (ddsd.ddpfPixelFormat.dwRGBBitCount < 32)
            dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1;  // Mask it to bpp
        pdds->Unlock(NULL);
    }
    //
    //  Now put the color that was there back.
    //
    if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
    {
        SetPixel(hdc, 0, 0, rgbT);
        pdds->ReleaseDC(hdc);
    }
    return dw;
}

//-----------------------------------------------------------------------------
// Name: DDCopyBitmap()
// Desc: Draw a bitmap into a DirectDrawSurface
//-----------------------------------------------------------------------------
extern "C" HRESULT
DDCopyBitmap(IDirectDrawSurface * pdds, HBITMAP hbm, int x, int y,
             int dx, int dy)
{
    HDC                     hdcImage;
    HDC                     hdc;
    BITMAP                  bm;
    DDSURFACEDESC          ddsd;
    HRESULT                 hr;

    if (hbm == NULL || pdds == NULL)
        return E_FAIL;
    //
    // Make sure this surface is restored.
    //
    pdds->Restore();
    //
    // Select bitmap into a memoryDC so we can use it.
    //
    hdcImage = CreateCompatibleDC(NULL);
    if (!hdcImage)
        OutputDebugString("createcompatible dc failed\n");
    SelectObject(hdcImage, hbm);
    //
    // Get size of the bitmap
    //
    GetObject(hbm, sizeof(bm), &bm);
    dx = dx == 0 ? bm.bmWidth : dx;     // Use the passed size, unless zero
    dy = dy == 0 ? bm.bmHeight : dy;
    //
    // Get size of surface.
    //
    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
    pdds->GetSurfaceDesc(&ddsd);

    if ((hr = pdds->GetDC(&hdc)) == DD_OK)
    {
        StretchBlt(hdc, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcImage, x, y,
                   dx, dy, SRCCOPY);
        pdds->ReleaseDC(hdc);
    }
    DeleteDC(hdcImage);
    return hr;
}


//-----------------------------------------------------------------------------
// Name: DDLoadBitmap()
// Desc: Create a DirectDrawSurface from a bitmap resource.
//-----------------------------------------------------------------------------
extern "C" IDirectDrawSurface *
DDLoadBitmap(IDirectDraw * pdd, LPCSTR szBitmap, int dx, int dy)
{
    HBITMAP                 hbm;
    BITMAP                  bm;
    DDSURFACEDESC           ddsd;
    IDirectDrawSurface     *pdds;

    //
    //  Try to load the bitmap as a resource, if that fails, try it as a file
    //
    hbm = (HBITMAP) LoadImage(GetModuleHandle(NULL), szBitmap, IMAGE_BITMAP, dx,
                              dy, LR_CREATEDIBSECTION);
    if (hbm == NULL)
        hbm = (HBITMAP) LoadImage(NULL, szBitmap, IMAGE_BITMAP, dx, dy,
                                  LR_LOADFROMFILE | LR_CREATEDIBSECTION);
    if (hbm == NULL)
        return NULL;
    //
    // Get size of the bitmap
    //
    GetObject(hbm, sizeof(bm), &bm);
    //
    // Create a DirectDrawSurface for this bitmap
    //
    ZeroMemory(&ddsd, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
    ddsd.dwWidth = bm.bmWidth;
    ddsd.dwHeight = bm.bmHeight;
    if (pdd->CreateSurface(&ddsd, &pdds, NULL) != DD_OK)
        return NULL;
    DDCopyBitmap(pdds, hbm, 0, 0, 0, 0);
    DeleteObject(hbm);
    return pdds;
}


//-----------------------------------------------------------------------------
// Name: DDReLoadBitmap()
// Desc: Load a bitmap from a file or resource into a directdraw surface.
//       normaly used to re-load a surface after a restore.
//-----------------------------------------------------------------------------
HRESULT
DDReLoadBitmap(IDirectDrawSurface * pdds, LPCSTR szBitmap)
{
    HBITMAP                 hbm;
    HRESULT                 hr;

    //
    //  Try to load the bitmap as a resource, if that fails, try it as a file
    //
    hbm = (HBITMAP) LoadImage(GetModuleHandle(NULL), szBitmap, IMAGE_BITMAP, 0,
                              0, LR_CREATEDIBSECTION);
    if (hbm == NULL)
        hbm = (HBITMAP) LoadImage(NULL, szBitmap, IMAGE_BITMAP, 0, 0,
                                  LR_LOADFROMFILE | LR_CREATEDIBSECTION);
    if (hbm == NULL)
    {
    //    OutputDebugString("handle is null\n");
        return E_FAIL;
    }
    hr = DDCopyBitmap(pdds, hbm, 0, 0, 0, 0);
    if (hr != DD_OK)
    {
      //  OutputDebugString("ddcopybitmap failed\n");
    }
    DeleteObject(hbm);
    return hr;
}



FullScreenWin::FullScreenWin()
{
	meshbuilder=0;
	animation=0;
	menusurf=0;
	fpssurf=0;
	selectmode=-1;
	displayfps=FALSE;

	UsePalette( swirlpalette );

	largefont = CreateFont( 28, 0, 0, 0,
		FW_NORMAL, FALSE, FALSE, FALSE,
		ANSI_CHARSET,
		OUT_DEFAULT_PRECIS,
		CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY,
		VARIABLE_PITCH,
		"Arial" );

	smallfont = CreateFont( 14, 0, 0, 0,
		FW_NORMAL, FALSE, FALSE, FALSE,
		ANSI_CHARSET,
		OUT_DEFAULT_PRECIS,
		CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY,
		VARIABLE_PITCH,
		"Arial" );
}

BOOL FullScreenWin::CreateScene()
{
	//-------- MENU AND FPS SURFACES --------
	selectmode=GetCurDisplayMode();
	CreateMenuSurface();
	UpdateMenuSurface();

	CreateFPSSurface();

	{
		DWORD w, h, d;
		GetCurDisplayModeDims( w, h, d );

		bmpsurf=DDLoadBitmap(ddraw, "test.bmp", 800, 600);
		if ( bmpsurf==0 )
		{
			TRACE("No load bmp ...\n");
			return FALSE;
		}

		bmpsrect.left=0;
		bmpsrect.top=0;
		bmpsrect.right=w-1;
		bmpsrect.bottom=h-1;
	}

	// ------- MESH --------
	D3DRMLOADRESOURCE resinfo;
	resinfo.hModule=0;
	resinfo.lpName=MAKEINTRESOURCE( IDR_SWIRLMESH );
	resinfo.lpType="MESH";
	d3drm->CreateMeshBuilder( &meshbuilder );
	meshbuilder->Load( &resinfo, 0, D3DRMLOAD_FROMRESOURCE, 0, 0 );
	ScaleMesh( meshbuilder, D3DVALUE(15) );

	//------- MESH FRAME --------
	LPDIRECT3DRMFRAME meshframe;
	d3drm->CreateFrame( scene, &meshframe );
	meshframe->AddVisual( meshbuilder );
	meshframe->SetRotation( scene,
			D3DVALUE(0), D3DVALUE(1), D3DVALUE(0),
			D3DVALUE(.1) );
	meshframe->AddMoveCallback( UpdateAnimation, 0 );

	//-------- ANIMATION ---------
	d3drm->CreateAnimation( &animation );

	for (int i=0; i<11; i++)
	{
		D3DRMQUATERNION	quat;
		D3DRMQuaternionFromRotation( &quat, &vect[i], rot[i] );
		animation->AddRotateKey( D3DVALUE(i), &quat );
		animation->AddPositionKey( D3DVALUE(i), 
				trans[i].x, trans[i].y, trans[i].z  );
	}

	animation->SetOptions( D3DRMANIMATION_SPLINEPOSITION | 
			D3DRMANIMATION_CLOSED | 
			D3DRMANIMATION_POSITION | 
			D3DRMANIMATION_SCALEANDROTATION );
	animation->SetFrame( meshframe );

	meshframe->Release();
	meshframe=0;

	// ---------DIRECTIONAL LIGHT--------
	LPDIRECT3DRMFRAME dlightframe;
	LPDIRECT3DRMLIGHT dlight;

	d3drm->CreateLightRGB(D3DRMLIGHT_DIRECTIONAL,
			D3DVALUE(1.00), D3DVALUE(1.00), D3DVALUE(1.00), 
			&dlight );

	d3drm->CreateFrame( scene, &dlightframe );
	dlightframe->SetOrientation( scene, 
			D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1),
			D3DVALUE(0), D3DVALUE(1), D3DVALUE(0) );
	dlightframe->AddLight( dlight );

	dlightframe->Release();
	dlightframe=0;
	dlight->Release();
	dlight=0;

	//------ CAMERA-----------
	d3drm->CreateFrame( scene, &camera );
	camera->SetPosition( scene, 
			D3DVALUE(0), D3DVALUE(0), D3DVALUE(-50) );
	d3drm->CreateViewport( device, camera, 0, 0,	
			device->GetWidth(), device->GetHeight(), 
			&viewport );

	return TRUE;
}

BOOL FullScreenWin::CreateFPSSurface()
{
	static const char dummystr[]="FPS: 0000";

	HDC hdc = ::GetDC( 0 );
	SelectObject( hdc, smallfont );
	SIZE size;
	GetTextExtentPoint( hdc, dummystr, strlen(dummystr), &size );
	::ReleaseDC( 0, hdc );

	fpsrect.left=0;
	fpsrect.top=0;
	fpsrect.right=size.cx;
	fpsrect.bottom=size.cy;

	fpssurf=CreateSurface( size.cx, size.cy );

	DDCOLORKEY  ddck;
	ddck.dwColorSpaceLowValue = 0;
	ddck.dwColorSpaceHighValue = 0;
	fpssurf->SetColorKey( DDCKEY_SRCBLT, &ddck );

	return TRUE;
}

BOOL FullScreenWin::UpdateFPSSurface()
{
	static const long interval=100;
	static long framecount;
	framecount++;

	if (framecount==interval)
	{
		static DWORD timenow;
		static DWORD timethen;
		timethen=timenow;
		timenow=timeGetTime();

		double seconds=double(timenow-timethen)/(double)1000;
		int fps=(int)((double)framecount/seconds);

		static char buf[10];
		int len=sprintf( buf, "FPS: %d", fps);

		HDC hdc;
		fpssurf->GetDC( &hdc );
		SelectObject( hdc, smallfont );
		SetTextColor( hdc, RGB(255,255,255) );
		SetBkColor( hdc, RGB(0,0,0) );
		SetBkMode( hdc, OPAQUE );
		ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &fpsrect, buf, len, 0 );
		fpssurf->ReleaseDC( hdc );

		displayfps=TRUE;
		framecount=0;
	}

	return TRUE;
}

BOOL FullScreenWin::CreateMenuSurface()
{
	menusurf=CreateSurface( menuwidth, menuheight );

	menurect.left=0;
	menurect.top=0;
	menurect.right=menuwidth;
	menurect.bottom=menuheight;

	DDCOLORKEY  ddck;
	ddck.dwColorSpaceLowValue = 0;
	ddck.dwColorSpaceHighValue = 0;
	menusurf->SetColorKey( DDCKEY_SRCBLT, &ddck );

	return TRUE;
}

BOOL FullScreenWin::UpdateMenuSurface()
{
	char buf[80];
	int len;
	RECT rect;
		
	ClearSurface( menusurf, 0 );

	HDC hdc;
	menusurf->GetDC( &hdc );
	SelectObject( hdc, largefont );
	SetBkMode( hdc, TRANSPARENT );

	SetTextColor( hdc, textshadow );
	ExtTextOut(hdc, 1, 1, 0, 0, headertext, strlen(headertext), 0 );
	SetTextColor( hdc, textcolor );
	ExtTextOut(hdc, 0, 0, 0, 0, headertext, strlen(headertext), 0 );

	SelectObject( hdc, smallfont );

	int nmodes=GetNumDisplayModes();
	if (nmodes>maxmodes)
		nmodes=maxmodes;

	int rows=nmodes/menucols;
	if (nmodes%menucols)
		rows++;

	for (int i=0; i<nmodes; i++)
	{
		rect.left=(i/rows)*colwidth;
		rect.top=(i%rows)*rowheight+reservedspace;
		rect.right=rect.left+colwidth;
		rect.bottom=rect.top+rowheight;
	
		DWORD w,h,d;
		GetDisplayModeDims( i, w, h, d );

		len=sprintf( buf, "%dx%dx%d", w, h, d );

		SetTextColor( hdc, textshadow );
		ExtTextOut(hdc, rect.left+1, rect.top+1, 0, &rect, buf, len, 0 );

		if (i==selectmode)
			SetTextColor( hdc, highlightcolor );
		else
			SetTextColor( hdc, textcolor );
		ExtTextOut(hdc, rect.left, rect.top, 0, &rect, buf, len, 0 );
	}

	rect.left=0;
	rect.right=319;
	rect.top=179;
	rect.bottom=199;

	len=sprintf( buf, "[Arrows]  [Enter]  [W]  [F]  [G]  [Escape]" );
	SetTextColor( hdc, textshadow );
	ExtTextOut(hdc, 1, 180, 0, &rect, buf, len, 0 );
	SetTextColor( hdc, textcolor );
	ExtTextOut(hdc, 0, 179, 0, &rect, buf, len, 0 );
	
	menusurf->ReleaseDC( hdc );

	return TRUE;
}

void FullScreenWin::UpdateAnimation(LPDIRECT3DRMFRAME, void*, D3DVALUE)
{
	static const D3DVALUE inc=D3DVALUE(0.025);
	static D3DVALUE time;
	time+=inc;
	animation->SetTime( time );
}

void FullScreenWin::Render()
{
	if ( primsurf->IsLost() == DDERR_SURFACELOST )
	{
		TRACE("Restoring primsurf...\n");
		primsurf->Restore();
	}

	if ( menusurf->IsLost() == DDERR_SURFACELOST )
	{
		TRACE("Restoring menusurf...\n");
		menusurf->Restore();
		UpdateMenuSurface();
	}

	if ( fpssurf->IsLost() == DDERR_SURFACELOST )
	{
		TRACE("Restoring fpssurf...\n");
		fpssurf->Restore();
	}

	if ( bmpsurf->IsLost() == DDERR_SURFACELOST )
	{
		DWORD w, h, d;
		GetCurDisplayModeDims( w, h, d );

		TRACE("Restoring bmpsurf...\n");
		bmpsurf->Restore();
		DDReLoadBitmap(bmpsurf, "test.bmp");
		bmpsrect.left=0;
		bmpsrect.top=0;
		bmpsrect.right=w-1;
		bmpsrect.bottom=h-1;
	}


	scene->Move(D3DVALUE(1.0));
	viewport->Clear();

	DDBLTFX bltfx;
	memset( &bltfx, 0, sizeof(bltfx) );
	bltfx.dwSize = sizeof(bltfx);
	bltfx.dwFillColor = DDColorMatch(backsurf,
		RGB(192,168,168));
	backsurf->Blt( 0, 0, 0, DDBLT_COLORFILL | DDBLT_WAIT, &bltfx );

	backsurf->BltFast( 0, 0, bmpsurf, &bmpsrect, 
			DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT );

	backsurf->BltFast( 0, 0, menusurf, &menurect, 
			DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT );

	viewport->Render( scene );
	device->Update();

	UpdateFPSSurface();
	if (displayfps)
	{
		DWORD w, h, d;
		GetCurDisplayModeDims( w, h, d );
		backsurf->BltFast( w-fpsrect.right, 
				h-fpsrect.bottom, fpssurf, &fpsrect, 
				DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT );
	}
	


	primsurf->Flip( 0, DDFLIP_WAIT );
}

void FullScreenWin::OnRenderWireframe() 
{
	if (meshbuilder)
		meshbuilder->SetQuality( D3DRMRENDER_WIREFRAME );
}

void FullScreenWin::OnRenderFlat() 
{
	if (meshbuilder)
		meshbuilder->SetQuality( D3DRMRENDER_FLAT );
}

void FullScreenWin::OnRenderGouraud() 
{
	if (meshbuilder)
		meshbuilder->SetQuality( D3DRMRENDER_GOURAUD );
}

void FullScreenWin::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	static int screencapture;
	int newindex;
	int nmodes=GetNumDisplayModes();
	if (nmodes>maxmodes)
		nmodes=maxmodes;

	int rows=nmodes/menucols;
	if (nmodes%menucols)
		rows++;

	switch (nChar)
	{
	case VK_ESCAPE:
		PostMessage( WM_CLOSE );
		break;
	case VK_UP:
		newindex=selectmode-1;
		if (newindex>=0)
		{
			selectmode=newindex;
			UpdateMenuSurface();
		}
		break;
	case VK_DOWN:
		newindex=selectmode+1;
		if (newindex<nmodes)
		{
			selectmode=newindex;
			UpdateMenuSurface();
		}
		break;
	case VK_LEFT:
		newindex=selectmode-rows;
		if (newindex>=0)
		{
			selectmode=newindex;
			UpdateMenuSurface();
		}
		break;
	case VK_RIGHT:

		newindex=selectmode+rows;
		if (newindex<nmodes)
		{
			selectmode=newindex;
			UpdateMenuSurface();
		}
		break;
	case VK_RETURN:
		if (menusurf)
		{
			menusurf->Release();
			menusurf=0;
		}
		if (fpssurf)
		{
			fpssurf->Release();
			fpssurf=0;
		}
		if (bmpsurf)
		{
			bmpsurf->Release();
			bmpsurf=0;
		}
		ActivateDisplayMode( selectmode );
		displayfps=FALSE;
		CreateMenuSurface();
		UpdateMenuSurface();
		CreateFPSSurface();
		break;
	case 'W':
		OnRenderWireframe();
		break;
	case 'F':
		OnRenderFlat();
		break;
	case 'G':
		OnRenderGouraud();
		break;
	case 'S':
		SaveSurface( primsurf, ++screencapture );
		break;
	}

	RMWin::OnKeyDown( nChar, nRepCnt, nFlags );
}

