1 //////////////////////////////////////////////
\r
4 // Includes backbuffer resizing suggested by Guillaume Werlé
\r
6 // NOTE: for MS compilers you will need the DirectX SDK v9
\r
7 // for Dev-C++ you will need the DirecX v9.0c DevPak
\r
11 #include <d3dx9.h> // see the note above
\r
12 #include <mmsystem.h>
\r
14 #include "MainFrm.h"
\r
15 #include "resource.h"
\r
23 if( m_pd3dDevice != NULL)
\r
24 m_pd3dDevice->Release();
\r
30 HWND CView::Create(CWnd* pParent)
\r
32 // Called by CFrame::OnCreate.
\r
33 // The window is created when the thread resumes.
\r
34 StartThread(pParent);
\r
38 void CView::OnCreate()
\r
40 SetIconLarge(IDW_MAIN);
\r
41 SetIconSmall(IDW_MAIN);
\r
43 // Initialize Direct3D
\r
44 if( SUCCEEDED( InitD3D( m_hWnd ) ) )
\r
46 // Create the scene geometry
\r
47 if( SUCCEEDED( InitGeometry() ) )
\r
50 ShowWindow(SW_SHOWDEFAULT);
\r
55 TRACE(_T("Failed to initialize DirectX\n"));
\r
58 void CView::PreCreate(CREATESTRUCT &cs)
\r
66 //-----------------------------------------------------------------------------
\r
68 // Desc: Initializes Direct3D
\r
69 //-----------------------------------------------------------------------------
\r
70 HRESULT CView::InitD3D( HWND hWnd )
\r
72 // Create the D3D object.
\r
73 if( NULL == ( m_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
\r
76 CRect rc = GetClientRect();
\r
78 // Set up the structure used to create the D3DDevice
\r
79 ZeroMemory( &m_d3dpp, sizeof(m_d3dpp) );
\r
80 m_d3dpp.Windowed = TRUE;
\r
81 m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
\r
82 m_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
\r
83 m_d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
\r
84 m_d3dpp.BackBufferWidth = rc.Width();
\r
85 m_d3dpp.BackBufferHeight = rc.Height();
\r
87 // Create the D3DDevice
\r
88 if( FAILED( m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
\r
89 // D3DCREATE_SOFTWARE_VERTEXPROCESSING,
\r
90 D3DCREATE_HARDWARE_VERTEXPROCESSING,
\r
91 &m_d3dpp, &m_pd3dDevice ) ) )
\r
96 SetupDefaultRenderStates();
\r
102 //-----------------------------------------------------------------------------
\r
103 // Name: InitGeometry()
\r
104 // Desc: Creates the scene geometry
\r
105 //-----------------------------------------------------------------------------
\r
106 HRESULT CView::InitGeometry()
\r
108 // Initialize three vertices for rendering a triangle
\r
109 CUSTOMVERTEX g_Vertices[] =
\r
111 { -1.0f,-1.0f, 0.0f, 0xffff0000, },
\r
112 { 1.0f,-1.0f, 0.0f, 0xff0000ff, },
\r
113 { 0.0f, 1.0f, 0.0f, 0xffffffff, },
\r
116 // Create the vertex buffer.
\r
117 if( FAILED( m_pd3dDevice->CreateVertexBuffer( 3*sizeof(CUSTOMVERTEX),
\r
118 0, D3DFVF_XYZ | D3DFVF_DIFFUSE,
\r
119 D3DPOOL_MANAGED, &m_pVB, NULL ) ) )
\r
124 // Fill the vertex buffer.
\r
126 if( FAILED( m_pVB->Lock( 0, sizeof(g_Vertices), (void**)&pVertices, 0 ) ) )
\r
128 memcpy( pVertices, g_Vertices, sizeof(g_Vertices) );
\r
134 //-----------------------------------------------------------------------------
\r
135 // Name: SetupMatrices()
\r
136 // Desc: Sets up the world, view, and projection transform Matrices.
\r
137 //-----------------------------------------------------------------------------
\r
138 void CView::SetupMatrices()
\r
140 // For our world matrix, we will just rotate the object about the y-axis.
\r
141 D3DXMATRIXA16 matWorld;
\r
143 // Set up the rotation matrix to generate 1 full rotation (2*PI radians)
\r
144 // every 1000 ms. To avoid the loss of precision inherent in very high
\r
145 // floating point numbers, the system time is modulated by the rotation
\r
146 // period before conversion to a radian angle.
\r
147 UINT iTime = timeGetTime() % 1000;
\r
149 FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 1000.0f;
\r
150 D3DXMatrixRotationY( &matWorld, fAngle );
\r
151 m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
\r
153 // Set up our view matrix. A view matrix can be defined given an eye point,
\r
154 // a point to lookat, and a direction for which way is up. Here, we set the
\r
155 // eye five units back along the z-axis and up three units, look at the
\r
156 // origin, and define "up" to be in the y-direction.
\r
157 D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f );
\r
158 D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
\r
159 D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
\r
160 D3DXMATRIXA16 matView;
\r
161 D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
\r
162 m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
\r
164 // For the projection matrix, we set up a perspective transform (which
\r
165 // transforms geometry from 3D view space to 2D viewport space, with
\r
166 // a perspective divide making objects smaller in the distance). To build
\r
167 // a perpsective transform, we need the field of view (1/4 pi is common),
\r
168 // the aspect ratio, and the near and far clipping planes (which define at
\r
169 // what distances geometry should be no longer be rendered).
\r
170 D3DXMATRIXA16 matProj;
\r
171 D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );
\r
172 m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
\r
175 //-----------------------------------------------------------------------------
\r
177 // Desc: Draws the scene
\r
178 //-----------------------------------------------------------------------------
\r
179 void CView::Render()
\r
183 HRESULT hResult = m_pd3dDevice->TestCooperativeLevel();
\r
188 CRect rcClient = GetClientRect();
\r
189 bool bNeedResize = m_d3dpp.BackBufferWidth != rcClient.Width() || m_d3dpp.BackBufferHeight != rcClient.Height();
\r
192 m_d3dpp.BackBufferWidth = rcClient.Width();
\r
193 m_d3dpp.BackBufferHeight = rcClient.Height();
\r
194 if ( !SUCCEEDED( m_pd3dDevice->Reset(&m_d3dpp) ) )
\r
195 TRACE(_T("Failed to reset the DirectX device\n"));
\r
198 // Clear the backbuffer to a black color
\r
199 if (D3D_OK !=m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 ))
\r
200 TRACE(_T("Failed to clear back buffer\n"));
\r
203 if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
\r
205 // Setup the world, view, and projection Matrices
\r
208 SetupDefaultRenderStates();
\r
210 // Render the vertex buffer contents
\r
211 m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(CUSTOMVERTEX) );
\r
212 m_pd3dDevice->SetFVF( D3DFVF_XYZ | D3DFVF_DIFFUSE );
\r
213 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 );
\r
216 m_pd3dDevice->EndScene();
\r
219 TRACE(_T("Failed to render the scene\n"));
\r
221 // Present the backbuffer contents to the display
\r
222 m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
\r
225 case D3DERR_DEVICELOST:
\r
226 TRACE(_T("Got D3DERR_DEVICELOST\n"));
\r
228 case D3DERR_DEVICENOTRESET:
\r
229 TRACE(_T("Got D3DERR_DEVICENOTRESET\n"));
\r
230 m_pd3dDevice->Reset(&m_d3dpp); // Reset the DX device
\r
233 TRACE(_T("Direct3D device is in an invalid state\n"));
\r
237 // Slow the thread (otherwise it runs it a tight loop)
\r
242 void CView::StartThread(CWnd* pParent)
\r
244 m_pParent = pParent;
\r
245 SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
\r
249 BOOL CView::InitInstance()
\r
251 // This function runs when the thread starts
\r
253 // Create the view window
\r
254 CWnd::Create(m_pParent);
\r
256 m_pParent->PostMessage(UWM_VIEWCREATED, 0, 0);
\r
258 return TRUE; // return TRUE to run the message loop
\r
261 int CView::MessageLoop()
\r
262 // Here we override CThread::MessageLoop to accommodate the special needs of DirectX
\r
265 while( Msg.message!=WM_QUIT )
\r
267 if( PeekMessage(&Msg, NULL, 0U, 0U, PM_REMOVE))
\r
269 ::TranslateMessage(&Msg);
\r
270 ::DispatchMessage(&Msg);
\r
275 return LOWORD(Msg.wParam);
\r
278 LRESULT CView::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
\r
284 ::PostQuitMessage( 0 );
\r
288 return WndProcDefault(uMsg, wParam, lParam);
\r
291 void CView::SetupDefaultRenderStates()
\r
293 // Turn off culling, so we see the front and back of the triangle
\r
294 m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
\r
296 // Turn off D3D lighting, since we are providing our own vertex colors
\r
297 m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
\r