#include <AfxWin.h>
#include <AfxExt.h>
#include <ddraw.h>
#include <d3d.h>
#include <d3drm.h>
#include <d3drmwin.h>
#include "resource.h"
#include "RMApp.h"
#include "RMWin.h"


#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

BEGIN_MESSAGE_MAP(RMWin, CFrameWnd)
	//{{AFX_MSG_MAP(RMWin)
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_ACTIVATE()
	ON_WM_PAINT()
	ON_WM_SIZE()
	ON_WM_MOUSEMOVE()
	ON_WM_ERASEBKGND()
	ON_COMMAND(ID_VIEWPORT1_DISABLED, OnViewport1Disabled)
	ON_COMMAND(ID_VIEWPORT1_FRONT, OnViewport1Front)
	ON_COMMAND(ID_VIEWPORT1_LEFT, OnViewport1Left)
	ON_COMMAND(ID_VIEWPORT1_RIGHT, OnViewport1Right)
	ON_COMMAND(ID_VIEWPORT1_TOP, OnViewport1Top)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

LPDIRECT3DRM RMWin::d3drm;
//LPDIRECT3DRMFRAME RMWin::scene;
//LPDIRECT3DRMDEVICE RMWin::device;
//LPDIRECT3DRMFRAME RMWin::camera;
//LPDIRECT3DRMVIEWPORT RMWin::viewport;

int RMWin::mousex;
int RMWin::mousey;
UINT RMWin::mousestate;


RMWin::RMWin()
{
	Initvars();
	device=0;
	scene=0;
}

RMWin::RMWin(int w, int h)
{
	Initvars();
	winrect.right=w;
	winrect.bottom=h;
}

void RMWin::Initvars()
{
	colormodel=D3DCOLOR_MONO;
	winrect=rectDefault;
    RMApp* pApp = (RMApp*)AfxGetApp();
    pApp->rmwin = this;
	view1setting=VIEWPORT_FRONT;
	view2setting=VIEWPORT_LEFT;
	view3setting=VIEWPORT_TOP;
}

BOOL RMWin::Create(const CString& sTitle,int icon,int menu)
{
	CString sClassName;

	sClassName = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,LoadCursor(0, IDC_ARROW),
			(HBRUSH)(COLOR_WINDOW + 1), LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(icon)));

	BOOL r=CFrameWnd::Create( sClassName, sTitle, WS_OVERLAPPEDWINDOW, winrect, 0, MAKEINTRESOURCE(menu));

	return r;
}

int RMWin::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	HRESULT r;
	r = Direct3DRMCreate(&d3drm);
	if (r!=D3DRM_OK)
	{
		AfxMessageBox("Direct3DRMCreate() failed");
		return -1;
	}
	return 0;
}

BOOL RMWin::CreateDevice()
{
	HRESULT r;
	CWaitCursor cur;

	r = DirectDrawCreateClipper( 0, &clipper, 0 );
	if (r!=D3DRM_OK)
	{
		AfxMessageBox("DirectDrawCreateClipper() failed");
		return FALSE;
	}

	r = clipper->SetHWnd( 0, m_hWnd );
	if (r!=DD_OK)
	{
		AfxMessageBox("clipper->SetHWnd() failed");
		return FALSE;
	}

	RECT rect;
	::GetClientRect( m_hWnd, &rect );

	r = d3drm->CreateDeviceFromClipper( clipper, GetGUID(),
			rect.right, rect.bottom,
			&device );

	if (r!=D3DRM_OK)
	{
		AfxMessageBox("CreateDeviceFromClipper() failed");
		return FALSE;
	}

	device->SetQuality( D3DRMRENDER_GOURAUD );

	HDC hdc = ::GetDC( m_hWnd );
	int bpp = ::GetDeviceCaps( hdc, BITSPIXEL );
	::ReleaseDC( m_hWnd, hdc );

	switch ( bpp )
	{
   	case 1:
		device->SetShades( 4 );
		d3drm->SetDefaultTextureShades( 4 );
		device->SetDither( TRUE );
		break;
	case 8:
		//device->SetDither( FALSE );
		break;
	case 16:
		device->SetShades( 32 );
		d3drm->SetDefaultTextureColors( 64 );
		d3drm->SetDefaultTextureShades( 32 );
		device->SetDither( FALSE );
		break;
	case 24:
	case 32:
		device->SetShades( 256 );
		d3drm->SetDefaultTextureColors( 64 );
		d3drm->SetDefaultTextureShades( 256 );
		device->SetDither( FALSE );
		break;
	}

	d3drm->CreateFrame( 0, &scene );

	if (CreateScene()==FALSE)
	{
		AfxMessageBox("CreateScene() failed");
		return FALSE;
	}

    d3drm->CreateFrame( scene, &camera1 );
    ConfigViewport( camera1, view1setting );

    d3drm->CreateFrame( scene, &camera2 );
    ConfigViewport( camera2, view2setting );

    d3drm->CreateFrame( scene, &camera3 );
    ConfigViewport( camera3, view3setting );

    CreateViewports();

//	ASSERT( camera );
//	ASSERT( viewport );
	return TRUE;
}

void RMWin::OnActivate(UINT state, CWnd* other, BOOL minimize)
{
	LPDIRECT3DRMWINDEVICE windev;
	if (device)
	{
		if (device->QueryInterface( IID_IDirect3DRMWinDevice, (void**)&windev)==0)
		{
			if (windev->HandleActivate((unsigned short)MAKELONG((WORD)state,(WORD)0))!=0)
				AfxMessageBox("windev->HandleActivate() failure");
			windev->Release();
		}
		else
			AfxMessageBox("device->QueryInterface(WinDevice) failure");
	}
	CFrameWnd::OnActivate(state, other, minimize);
}

void RMWin::OnPaint()
{
	static BOOL first = TRUE;
	if (first)
	{
		first = FALSE;
		if (CreateDevice()==FALSE)
			PostQuitMessage(0);
	}

	if (GetUpdateRect( 0, FALSE )==FALSE)
		return;

	if (device)
	{
		LPDIRECT3DRMWINDEVICE windev;
		PAINTSTRUCT ps;
		BeginPaint(&ps);
		if (device->QueryInterface(IID_IDirect3DRMWinDevice, (void**)&windev)==0)
		{
			if (windev->HandlePaint(ps.hdc)!=0)
				AfxMessageBox("windev->HandlePaint() failure");
			windev->Release();
		}
		else
			AfxMessageBox("Failed to create Windows device to handle WM_PAINT");
		EndPaint(&ps);
	}
}

void RMWin::OnSize(UINT type, int cx, int cy)
{
    CFrameWnd::OnSize( type, cx, cy );

    if (!device)
        return;

    int newwidth = cx;
    int newheight = cy;

    if (newwidth && newheight)
    {
        int old_dither = device->GetDither();
        D3DRMRENDERQUALITY old_quality = device->GetQuality();
        int old_shades = device->GetShades();
        viewport1->Release();
        viewport2->Release();
        viewport3->Release();
        device->Release();
        d3drm->CreateDeviceFromClipper( clipper, GetGUID(),
                newwidth, newheight, &device );

        device->SetDither( old_dither );
        device->SetQuality( old_quality );
        device->SetShades( old_shades );

        CreateViewports();
    }
}

void RMWin::OnMouseMove( UINT state, CPoint point )
{
	mousestate = state;
	mousex = point.x;
	mousey = point.y;
}

BOOL RMWin::OnEraseBkgnd( CDC* pDC )
{
	COLORREF bgcolor;
	if (scene)
	{
		D3DCOLOR scenecolor=scene->GetSceneBackground();
		bgcolor=D3DCOLOR_2_COLORREF(scenecolor);
	}
	else
		bgcolor=RGB(0,0,0);

	CBrush br( bgcolor );
	CRect rc;
	GetClientRect(&rc);
	pDC->FillRect(&rc, &br);
	return TRUE;
}

void RMWin::OnDestroy()
{
	if (scene)
	{
		scene->Release();
		scene=0;
	}

	if (device)
	{
		device->Release();
		device=0;
	}

	if (d3drm)
	{
		d3drm->Release();
		d3drm=0;
	}

	if (clipper)
	{
		clipper->Release();
		clipper=0;
	}
}

D3DVALUE RMWin::ScaleMesh( LPDIRECT3DRMMESHBUILDER mesh, D3DVALUE dim)
{
	D3DRMBOX box;
	mesh->GetBox( &box );
	D3DVALUE sizex = box.max.x - box.min.x;
	D3DVALUE sizey = box.max.y - box.min.y;
	D3DVALUE sizez = box.max.z - box.min.z;
	D3DVALUE largedim=D3DVALUE(0);
	if (sizex>largedim)
		largedim=sizex;
	if (sizey>largedim)
		largedim=sizey;
	if (sizez>largedim)
		largedim=sizez;
	D3DVALUE scalefactor = dim/largedim;
	mesh->Scale( scalefactor, scalefactor, scalefactor );
	return scalefactor;
}


GUID* RMWin::GetGUID()
{
	static GUID* lpguid;
	HRESULT r;

	D3DFINDDEVICESEARCH searchdata;
	memset(&searchdata, 0, sizeof searchdata);
	searchdata.dwSize = sizeof searchdata;
	searchdata.dwFlags = D3DFDS_COLORMODEL;
	searchdata.dcmColorModel = colormodel;

	static D3DFINDDEVICERESULT resultdata;
	memset( &resultdata, 0, sizeof resultdata );
	resultdata.dwSize = sizeof resultdata;

	LPDIRECTDRAW ddraw;
	r = DirectDrawCreate( 0, &ddraw, 0 );
	if (r!=DD_OK)
	{
		AfxMessageBox("DirectDrawCreate() failed");
		return 0;
	}

	LPDIRECT3D d3d;
	r = ddraw->QueryInterface( IID_IDirect3D, (void**)&d3d );
	if ( r != D3DRM_OK )
	{
		AfxMessageBox("d3drm->QueryInterface() failed\n");
		ddraw->Release();
		return 0;
	}

	r=d3d->FindDevice( &searchdata, &resultdata );
	if ( r==D3D_OK )
		lpguid = &resultdata.guid;
	else
	{
		AfxMessageBox("FindDevice() failed");
		lpguid=0;
	}

	d3d->Release();
	ddraw->Release();

	return lpguid;
}


void RMWin::ConfigViewport(LPDIRECT3DRMFRAME camera, int view)
{
    if (view==VIEWPORT_FRONT) // 45
    {
        camera->SetPosition( scene,
                D3DVALUE(0), D3DVALUE(25), D3DVALUE(-25) );
        camera->SetOrientation( scene,
                D3DVALUE(0), D3DVALUE(-1), D3DVALUE(1),
                D3DVALUE(0), D3DVALUE(1), D3DVALUE(1) );
    }
    else if (view==VIEWPORT_LEFT) // bottom
    {
        camera->SetPosition( scene,
                D3DVALUE(0), D3DVALUE(-25), D3DVALUE(25) );
        camera->SetOrientation( scene,
                D3DVALUE(0), D3DVALUE(1), D3DVALUE(-1),
                D3DVALUE(0), D3DVALUE(1), D3DVALUE(1) );
    }
    else if (view==VIEWPORT_RIGHT)
    {
        camera->SetPosition( scene,
                D3DVALUE(50), D3DVALUE(0), D3DVALUE(0) );
        camera->SetOrientation( scene,
                D3DVALUE(-1), D3DVALUE(0), D3DVALUE(0),
                D3DVALUE(0), D3DVALUE(1), D3DVALUE(0) );
    }
    else if (view==VIEWPORT_TOP)
    {
        camera->SetPosition( scene,
                D3DVALUE(0), D3DVALUE(50), D3DVALUE(0) );
        camera->SetOrientation( scene,
                D3DVALUE(0), D3DVALUE(-1), D3DVALUE(0),
                D3DVALUE(0), D3DVALUE(0), D3DVALUE(1) );
    }
}

void RMWin::CreateViewports()
{
    int newwidth = device->GetWidth();
    int newheight = device->GetHeight();
    int onethird=newwidth/3;
    int halfheight=newheight/2;
    d3drm->CreateViewport( device, camera1,
            0, 0,
            onethird*2, newheight,
            &viewport1 );
    d3drm->CreateViewport( device, camera2,
            onethird*2, 0,
            onethird, halfheight,
            &viewport2 );
    d3drm->CreateViewport( device, camera3,
            onethird*2, halfheight,
            onethird, halfheight,
            &viewport3 );
}

void RMWin::Render()
{
   scene->Move( D3DVALUE(1.0) );
   if (view1setting!=VIEWPORT_DISABLED)
   {
       viewport1->Clear();
       viewport1->Render( scene );
   }
   if (view2setting!=VIEWPORT_DISABLED)
   {
       viewport2->Clear();
       viewport2->Render( scene );
   }
   if (view3setting!=VIEWPORT_DISABLED)
   {
       viewport3->Clear();
       viewport3->Render( scene );
   }
   device->Update();
}

void RMWin::OnViewport1Disabled()
{
	// TODO: Add your command handler code here
    view1setting=VIEWPORT_DISABLED;
    viewport1->Clear();

}

void RMWin::OnViewport1Front()
{
	// TODO: Add your command handler code here
    view1setting=VIEWPORT_FRONT;
    ConfigViewport( camera1, view1setting );

}

void RMWin::OnViewport1Left()
{
	// TODO: Add your command handler code here
    view1setting=VIEWPORT_LEFT;
    ConfigViewport( camera1, view1setting );

}

void RMWin::OnViewport1Right()
{
	// TODO: Add your command handler code here
    view1setting=VIEWPORT_RIGHT;
    ConfigViewport( camera1, view1setting );

}

void RMWin::OnViewport1Top()
{
	// TODO: Add your command handler code here
    view1setting=VIEWPORT_TOP;
    ConfigViewport( camera1, view1setting );

}
