cube.cpp
#include "d3dUtility.h" // // Globals // IDirect3DDevice9* Device = 0; /*********************************************************************************** 我们还需要初始化两个全局常量,以定义屏幕的分辨率。 ***********************************************************************************/ const int Width = 640; const int Height = 480; /*********************************************************************************** 首先我们需要初始化两个全局变量,以保存立方体的顶点和索引数据。 ***********************************************************************************/ IDirect3DVertexBuffer9* VB = 0; IDirect3DIndexBuffer9* IB = 0; // // Classes and Structures // /*********************************************************************************** 接下来需要定义顶点结构和该结构的灵活顶点格式。在这个例子中的定点结构中仅包含位置信息。 ***********************************************************************************/ struct Vertex { Vertex(){} Vertex(float x, float y, float z) { _x = x; _y = y; _z = z; } float _x, _y, _z; static const DWORD FVF; }; const DWORD Vertex::FVF = D3DFVF_XYZ; // // Framework Functions框架函数 // /*********************************************************************************** Setup函数创建顶点缓存和索引缓存,然后对缓存进行锁定,将构成立方体的顶点数据以及构成 立方体的三角形单元的索引数据分别写入顶点缓存和索引缓存。然后将摄像机沿Z轴负方向平移 几个单位,以使绘制在世界坐标系原点的立方体处于摄像机的现场内。然后再实施投影变换。最 终,将填充模式的绘制状态设为线框模式。 ***********************************************************************************/ bool Setup() { // // Create vertex and index buffers.创建顶点缓存与索引缓存。 // //顶点缓存用接口IDirect3DVertexBuffer9表示 Device->CreateVertexBuffer( 8 * sizeof(Vertex), //为缓存分配的字节数。这个例子是想让顶点缓存足够存储8个顶点。 D3DUSAGE_WRITEONLY, //指定关于如何使用缓存的一些附加属性。这个例子是规定应用程序对缓存的操作模式为“只写”。 Vertex::FVF, //存储在顶点缓存中顶点的灵活顶点格式。 D3DPOOL_MANAGED, //容纳缓存的内存池。 &VB, //用于接收所创建的顶点缓存的指针。 0); //不使用,该值设为0. //索引缓存用接口IDirect3DIndexBuffer9表示 Device->CreateIndexBuffer( 36 * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, //指定索引的大小。该例子表示为16位索引。 D3DPOOL_MANAGED, &IB, //用于接收所创建的索引缓存的指针。 0); // // Fill the buffers with the cube data. // // define unique vertices: /*********************************************************************************** HRESULT IDirect3DVertexBuffer9::Lock( UINT OffsetToLock, UINT SizeToLock, BYTE **ppbData, DWORD Flags ); HRESULT IDirect3DIndexBuffer9::Lock( UINT OffsetToLock, UINT SizeToLock, BYTE **ppbData, DWORD Flags ); 上述两种方法的参数完全相同。 OffsetToLock 自缓存的起始点到开始锁定的位置的偏移量,单位为字节。 SizeToLock 所要锁定的字节数。 ppbData 指向被锁定的存储区起始位置的指针。 Flags 该标记描述了锁定的方式,可以是0,也可以是下列标记之一或是某种组合。 D3DLOCK_DISCARD 该标记仅用于动态缓存。它指示硬件将缓存内容丢弃, 并返回一个指向重新分配的缓存的指针。该标记十分 有用,因为这允许在我们访问新分配的内存时,硬件 能够继续使用被丢弃的缓存中的数据进行绘制,这样 硬件的绘制就不会中止。 D3DLOCK_NOOVERWRITE 该标记仅用于动态缓存。使用该标记之后,数据只能 以追加方式写入缓存。即不能覆盖当前用于绘制的存 储区中的任何内容。这十分有用,因为它可保证在缓 存中增加数据时,硬件仍可持续进行绘制。 D3DLOCK_READONLY 该标记表示对于所锁定的缓存只可读而不可写。利用 这一点可以做一些内部的优化。 ***********************************************************************************/ Vertex* vertices; VB->Lock(0, 0, (void**)&vertices, 0); // vertices of a unit cube vertices[0] = Vertex(-1.0f, -1.0f, -1.0f); vertices[1] = Vertex(-1.0f, 1.0f, -1.0f); vertices[2] = Vertex( 1.0f, 1.0f, -1.0f); vertices[3] = Vertex( 1.0f, -1.0f, -1.0f); vertices[4] = Vertex(-1.0f, -1.0f, 1.0f); vertices[5] = Vertex(-1.0f, 1.0f, 1.0f); vertices[6] = Vertex( 1.0f, 1.0f, 1.0f); vertices[7] = Vertex( 1.0f, -1.0f, 1.0f); //调用完Lock方法操作结束之后,我们调用Unlock方法对缓存进行解锁。 VB->Unlock(); // define the triangles of the cube: WORD* indices = 0; IB->Lock(0, 0, (void**)&indices, 0); // front side indices[0] = 0; indices[1] = 1; indices[2] = 2; indices[3] = 0; indices[4] = 2; indices[5] = 3; // back side indices[6] = 4; indices[7] = 6; indices[8] = 5; indices[9] = 4; indices[10] = 7; indices[11] = 6; // left side indices[12] = 4; indices[13] = 5; indices[14] = 1; indices[15] = 4; indices[16] = 1; indices[17] = 0; // right side indices[18] = 3; indices[19] = 2; indices[20] = 6; indices[21] = 3; indices[22] = 6; indices[23] = 7; // top indices[24] = 1; indices[25] = 5; indices[26] = 6; indices[27] = 1; indices[28] = 6; indices[29] = 2; // bottom indices[30] = 4; indices[31] = 0; indices[32] = 3; indices[33] = 4; indices[34] = 3; indices[35] = 7; IB->Unlock(); // // Position and aim the camera. // D3DXVECTOR3 position(0.0f, 0.0f, -5.0f); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMATRIX V; D3DXMatrixLookAtLH(&V, &position, &target, &up); Device->SetTransform(D3DTS_VIEW, &V); // // Set the projection matrix. // D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( &proj, D3DX_PI * 0.5f, // 90 - degree (float)Width / (float)Height, 1.0f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &proj); // // Switch to wireframe mode. // Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); return true; } /*********************************************************************************** 最后我们将前面分配的所有内存进行清理操作,即释放顶点缓存和索引缓存接口。 ***********************************************************************************/ void Cleanup() { d3d::Release<IDirect3DVertexBuffer9*>(VB); d3d::Release<IDirect3DIndexBuffer9*>(IB); } /*********************************************************************************** Display方法有两项任务:更新场景和绘制场景。因为我们想让立方体旋转起来,必须在程序生成 的每帧图像中给旋转角一定的增量,从而指定立方体的旋转方式。通过更新每帧图像中立方体的 角度,立方体在每帧图像中就被微微地旋转,从而产生旋转的视觉效果。注意,在这个例子我们 是用世界坐标系来指定立方体的方向。然后,我们调用方法IDirect3DDevice9::DrawIndexedPrimitive 来绘制立方体。 ***********************************************************************************/ bool Display(float timeDelta) { if( Device ) { // // spin the cube: // D3DXMATRIX Rx, Ry; // rotate 45 degrees on x-axis D3DXMatrixRotationX(&Rx, 3.14f / 4.0f); // incremement y-rotation angle each frame static float y = 0.0f; D3DXMatrixRotationY(&Ry, y); y += timeDelta; // reset angle to zero when angle reaches 2*PI if( y >= 6.28f ) y = 0.0f; // combine x- and y-axis rotation transformations. D3DXMATRIX p = Rx * Ry; Device->SetTransform(D3DTS_WORLD, &p); // // draw the scene: // Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene(); Device->SetStreamSource(0, VB, 0, sizeof(Vertex)); Device->SetIndices(IB); Device->SetFVF(Vertex::FVF); // Draw cube. Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12); Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; } // // WndProc // LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_DESTROY: ::PostQuitMessage(0); break; case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); } // // WinMain // int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd) { if(!d3d::InitD3D(hinstance, Width, Height, true, D3DDEVTYPE_HAL, &Device)) { ::MessageBox(0, L"InitD3D() - FAILED", 0, 0); return 0; } if(!Setup()) { ::MessageBox(0, L"Setup() - FAILED", 0, 0); return 0; } d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); return 0; }