www.pudn.com > ·ÉÐÐÆ÷Ä£Äâ.rar > 3DWNDNEW.CPP
// 3dWnd.cpp : implementation file
//
#include "stdafx.h"
#include "Basic.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// One-time class registration mechanism using class static members
const char* szDDWndClassName = "DDWindowClass";
static LRESULT CALLBACK DDWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
BOOL C3dWnd::s_bRegistered = C3dWnd::Register();
// static
BOOL C3dWnd::Register()
{
// register the window class we use for
// direct draw windows
WNDCLASS wc;
memset(&wc, 0, sizeof(wc));
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DDWndProc;
wc.hInstance = NULL;
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = szDDWndClassName;
wc.hbrBackground = (HBRUSH)::GetStockObject(GRAY_BRUSH);
return ::RegisterClass(&wc);
}
/////////////////////////////////////////////////////////////////////////////
// Window procedure for Direct Draw child window
static LRESULT CALLBACK DDWndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
#if 0
switch (uiMsg) {
case WM_MOVE:
break;
case WM_SIZE:
break;
default:
break;
}
#endif
return ::DefWindowProc(hWnd, uiMsg, wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////
// C3dWnd
C3dWnd::C3dWnd()
: m_rcClient(0, 0, 0, 0)
{
m_pDD = NULL;
m_pD3D = NULL;
m_pStage = NULL;
m_pScene = NULL;
m_bEnableUpdates = FALSE;
m_iWidth = 320;
m_iHeight = 240;
m_bRepaintAll = TRUE;
m_hwndDD = NULL;
}
C3dWnd::~C3dWnd()
{
}
BEGIN_MESSAGE_MAP(C3dWnd, CWnd)
//{{AFX_MSG_MAP(C3dWnd)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_MOVE()
ON_WM_SIZE()
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL C3dWnd::Create(const char* pszCaption,
DWORD dwStyle,
int x, int y,
int cx, int cy,
CWnd* pParent/*= NULL*/)
{
const char* pszClass = AfxRegisterWndClass(CS_VREDRAW | CS_HREDRAW,
::LoadCursor(NULL, IDC_ARROW),
(HBRUSH)::GetStockObject(GRAY_BRUSH));
return CWnd::CreateEx(0,
pszClass,
pszCaption,
dwStyle,
x, y,
cx, cy,
pParent ? pParent->GetSafeHwnd() : NULL,
NULL);
}
// Create the stage
BOOL C3dWnd::_CreateStage()
{
ASSERT(m_hwndDD);
// Initialise the direct draw objects
m_pDD = new CDirectDraw;
if (!m_pDD->Create()) return FALSE;
// Set the mode for the window
if (!m_pDD->SetWindowedMode(m_hwndDD,
m_iWidth,
m_iHeight)) {
return FALSE;
}
// Create the Direct3D object
m_pD3D = new CDirect3D;
if (!m_pD3D->Create(m_pDD)) return FALSE;
// Set the color model we want
if (! m_pD3D->SetMode(D3DCOLOR_RAMP)) return FALSE;
// Create a stage
m_pStage = new C3dStage;
if (!m_pStage->Create(m_pD3D)) return FALSE;
// attach any current scene
m_pStage->SetScene(m_pScene);
return TRUE;
}
// Release the stage and its related components
void C3dWnd::_ReleaseStage()
{
if (m_pStage) {
m_pStage->SetScene(NULL);
delete m_pStage;
m_pStage = NULL;
}
if (m_pD3D) {
delete m_pD3D;
m_pD3D = NULL;
}
if (m_pDD) {
delete m_pDD;
m_pDD = NULL;
}
}
int C3dWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// create the child window we want direct draw to work with
m_hwndDD = ::CreateWindowEx(0,
szDDWndClassName,
"",
WS_VISIBLE | WS_CHILD,
0, 0,
1, 1,
GetSafeHwnd(),
NULL,
AfxGetInstanceHandle(),
NULL);
ASSERT(m_hwndDD);
// save the initial size and position
m_iWidth = lpCreateStruct->cx;
m_iHeight = lpCreateStruct->cy;
m_rcClient = CRect(lpCreateStruct->x,
lpCreateStruct->y,
lpCreateStruct->x + lpCreateStruct->cx,
lpCreateStruct->y + lpCreateStruct->cy);
// Create the stage
if (!_CreateStage()) return -1;
// Create an initial scene
m_pScene = new C3dScene;
m_pScene->Create();
m_pStage->SetScene(m_pScene);
// Set up the lighting
C3dDirLight dl;
dl.Create(0.1, 0.7, 0.1);
m_pScene->AddChild(&dl);
dl.SetPosition(2, 2, -5);
dl.SetDirection(-1, -1, 1, 0, 1, 0);
m_pScene->SetAmbientLight(0.1, 0.1, 0.1);
// Create a shape to add
C3dShape sh1;
sh1.CreateSphere(1);
m_pScene->AddChild(&sh1);
C3dShape sh2;
sh2.CreateSphere(0.3);
sh2.SetColor(0, 0, 1);
sh1.AddChild(&sh2);
sh2.SetPosition(0, 0, -2);
C3dShape sh3;
sh3.CreateSphere(0.15);
sh3.SetColor(1, 0, 0);
sh1.AddChild(&sh3);
sh3.SetPosition(0, 0, 5);
sh1.SetRotation(1, 1, 0, 0.015);
// Eanble the idle-time rendering
m_bEnableUpdates = TRUE;
return 0;
}
void C3dWnd::OnDestroy()
{
CWnd::OnDestroy();
// Clean up
_ReleaseStage();
}
// Make sure the CWnd object gets destroyed when the window
// is destroyed
void C3dWnd::PostNcDestroy()
{
CWnd::PostNcDestroy();
delete this;
}
// Update the current scene, render it and draw the changes to the screen
// returns TRUE if it has something to do, FALSE if idle
BOOL C3dWnd::Update()
{
if (!m_bEnableUpdates) return FALSE;
if (!m_pScene) {
m_bEnableUpdates = FALSE;
return FALSE;
}
RECT rcFrom;
rcFrom.left = 0;
rcFrom.top = 0;
rcFrom.right = m_iWidth;
rcFrom.bottom = m_iHeight;
// if the window has been resized - force an update
// of the entire area
if (m_bRepaintAll) {
m_pStage->ForceUpdate(&rcFrom);
}
// update the scene
//m_pStage->Clear();
m_pScene->Move();
m_pStage->Render();
BOOL b;
// Blt the back buffer to the front buffer so we
// can see what we rendered
b = m_pDD->GetFrontBuffer()->Blt(&m_rcClient,
m_pDD->GetBackBuffer(),
&rcFrom,
DDBLT_WAIT,
NULL);
m_bRepaintAll = FALSE;
return TRUE;
}
void C3dWnd::OnMove(int x, int y)
{
// Compute the screen coordinates of the client rectangle
m_rcClient = CRect(x, y, x+m_iWidth, y+m_iHeight);
}
void C3dWnd::OnSize(UINT nType, int cx, int cy)
{
if ((cx <= 0) || (cy <= 0)) return;
// resize the child to fit
::MoveWindow(m_hwndDD, 0, 0, cx, cy, FALSE);
if ((cx == m_iWidth) && (cy == m_iHeight)) return;
// Shut down and restart
_ReleaseStage();
// Compute the new screen coordinates
m_iWidth = cx;
m_iHeight = cy;
m_rcClient = CRect(0, 0, m_iWidth, m_iHeight);
ClientToScreen(&m_rcClient);
_CreateStage();
m_bRepaintAll = TRUE;
}
void C3dWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
// Behave as though the window was resized
m_bRepaintAll = TRUE;
}