DX学习笔记(建立三角形图元)

这篇博客是关于DX9的学习笔记,通过创建和填充三角形顶点缓存,建立投影矩阵,以及设置线框模式来绘制三角形。作者提到了d3dUtility.h和d3dUtility.cpp两个关键文件,并提供了代码示例。

这是DX9龙书里面简单的一个例程,其中 d3dUtility.h , d3dUtility.h   为dx9固有框架,在注释里将许多涉及到win32编程的一些知识(方便以后需要时查看)在我的另一篇博客也对框架的一些基本功能进行了一点解释,主要还是边看代码,边看注释吧。http://blog.csdn.net/zero_witty/article/details/51621908


d3dUtility.h

#ifndef __d3dUtilityH__
#define __d3dUtilityH__

#include<d3dx9.h>
#include <string>

namespace d3d
{
	bool InitD3D(
		HINSTANCE hInstance, //当前应用程序实例的句柄
		int width, int height, //后台缓存的表面宽度和高度
		bool windowed, //是否窗口化 
		D3DDEVTYPE deviceType, //D3D设备类型  硬件(HAL)或者引用(REF)或软件(SW)
		IDirect3DDevice9** device);//以创建的设备(用于输出)

	int EnterMsgLoop(
		bool(*ptr_display)(float timeDelta));

	LRESULT CALLBACK WndProc(
		HWND hwnd,
		UINT msg,
		WPARAM wParam,
		LPARAM lParam);

	template<class T>void Release(T t)
	{
		if (t)
		{
			t->Release();
			t = 0;
		}
	}
	template<class T>void Delete(T t)
	{
		if (t)
		{
			delete t;
			t = 0;
		}
	}
}
#endif // __d3dUtilityH__

d3dUtility.cpp

#include "d3dUtility.h"

bool d3d::InitD3D(HINSTANCE hInstance, int width, int height, bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9 **device)
{
	WNDCLASS wc;

	wc.style = CS_HREDRAW | CS_VREDRAW;//窗口类型(当水平长度,垂直长度,或者位置改变,重画整个窗口)
	wc.lpfnWndProc = (WNDPROC)d3d::WndProc;//窗口处理函数
	wc.cbClsExtra = 0;//窗口类无扩展
	wc.cbWndExtra = 0;//窗口实例无扩展
	wc.hInstance = hInstance;//实例句柄
	wc.hIcon = LoadIcon(0, IDI_APPLICATION);//窗口最小化的图标为缺省图标
	wc.hCursor = LoadCursor(0, IDC_ARROW);//窗口采用箭头光标
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//窗口的背景颜色为白色
	wc.lpszMenuName = 0;//窗口无菜单
	wc.lpszClassName = "Direct3D9App"; //窗口类名

	if (!RegisterClass(&wc))//如果注册失败,发出警告
	{
		::MessageBox(0, "RegisterClass() - FALIED", 0, 0);
		/**
		MessageBox(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType);
		hWnd : 消息框拥有的窗口
		lpText :消息框的内容
		lpCaption :消息框的标题
		uType :指定标志中的一个来显示消息框的按钮以及图标(默认,只有一个确认按钮)
		**/
		return false;
	}

	HWND hwnd = 0;
	hwnd = ::CreateWindow("Direct3D9App", "Direct3D9App",
		WS_EX_TOPMOST,//设置窗口风格,将窗口设为置顶
		0, 0, width, height,
		0/*父窗口*/, 0/*菜单*/, hInstance, 0/*扩展*/);
	if (!hwnd)
	{
		::MessageBox(0, "CreateWindow() - FALIED", 0, 0);
		return false;
	}

	::ShowWindow(hwnd, SW_SHOW);
	::UpdateWindow(hwnd);

	HRESULT hr = 0;

	//步骤1:创建 IDirect3D9 对象
	IDirect3D9 *d3d9 = 0;
	d3d9 = Direct3DCreate9(D3D_SDK_VERSION);

	if (!d3d9)
	{
		::MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0);
		return false;
	}

	//步骤2:校验硬件顶点计算

	D3DCAPS9 caps;
	d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);
	//caps会返回装载着当前显卡设备能力的信息

	int vp = 0;
	if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
		vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
	else
		vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

	//步骤3:填充D3DPRESENT_PARAMETERS 结构的初始值

	D3DPRESENT_PARAMETERS d3dpp;
	d3dpp.BackBufferWidth = width;
	d3dpp.BackBufferHeight = height;
	d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
	d3dpp.BackBufferCount = 1;
	d3dpp.MultiSampleQuality = 0;
	d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.hDeviceWindow = hwnd;
	d3dpp.Windowed = windowed;
	d3dpp.EnableAutoDepthStencil = true;//若设置为true,则D3D自动创建并维护深度缓存或模板缓存
	d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;//D24S8用24位表示深度并将8位保留供模板使用
	d3dpp.Flags = 0;
	d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;//刷新频率设为默认值
	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;//当交换链中后台缓存切换到前台缓的时候最大速率设为立即提交


	//步骤 4:创建设备
	hr = d3d9->CreateDevice(
		D3DADAPTER_DEFAULT,//主适配器
		deviceType,
		hwnd,
		vp,
		&d3dpp,
		device);		   //返回创建的设备

	if (FAILED(hr))
	{

		d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

		hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT, deviceType, hwnd, vp, &d3dpp, device);

		if (FAILED(hr))
		{
			d3d9->Release();
			::MessageBox(0, "CreateDevice - FAILED", 0, 0);
			return false;
		}
	}

	d3d9->Release();

	return true;
}

int d3d::EnterMsgLoop(bool(*ptr_display)(float timeDelta))
{
	MSG msg;
	::ZeroMemory(&msg, sizeof(MSG));

	static float lastTime = (float)timeGetTime();

	while (msg.message != WM_QUIT)
	{
		if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);//发出消息
		}
		else
		{
			float currTime = (float)timeGetTime();
			float timeDelta = (currTime - lastTime)*0.001f;

			ptr_display(timeDelta);

			lastTime = currTime;
		}
	}
	return msg.wParam;//来自一条表示退出的消息
}

接下来这个是本个样例的主要内容,主要步骤如下

一 创建三角形顶点缓存,并进行填充(需注意一点是,要注意到UnLock用的顺序,是在访问缓存结束后使用的)

二建立一个投影矩阵

三选择线框模式进行绘画

绘画之前有三个准备工作

①指定数据流输入源

②设置顶点格式

③设置顶点缓存

代码如下:


triangle.cpp

#include"d3dUtility.h"

IDirect3DDevice9* Device = 0;

const int Width = 640;
const int Height = 480;

IDirect3DVertexBuffer9* Triangle = 0;

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;

bool Setup()
{

    Device->CreateVertexBuffer(
        3 * sizeof(Vertex),
        D3DUSAGE_WRITEONLY,//标识
        Vertex::FVF,//顶点点类型
        D3DPOOL_MANAGED,//
        &Triangle,
        0);

    //填充顶点缓存数据
    Vertex* vertices;
    Triangle->Lock(0, 0, (void**)&vertices, 0);

    vertices[0] = Vertex(-1.0f, 0.0f, 2.0f);
    vertices[1] = Vertex(0.0f, 1.0f, 2.0f);
    vertices[2] = Vertex(1.0f, 0.0f, 2.0f);

    Triangle->Unlock();//访问完缓存后记得Unclock();

    //建立投影矩阵

    D3DXMATRIX proj;
    D3DXMatrixPerspectiveFovLH(
        &proj,                             //返回的投影矩阵
        D3DX_PI * 0.5f,                             //视域角的弧度(90度的弧度制)
        (float)Width / (float)Height,                             //宽高比
        1.0f,                             //近裁剪面离坐标原点的距离
        1000.0f);                                                //远裁剪面离坐标原点的距离
    Device->SetTransform(D3DTS_PROJECTION, &proj);

    //建立线框模式绘制状态
    Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);

    return true;
}

void Cleanup()
{
    d3d::Release<IDirect3DVertexBuffer9*>(Triangle);
}

bool Display(float timeDelta)
{
    if (Device)
    {
        Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
        Device->BeginScene();
        //绘制前的准备工作 3个步骤
        //步骤① 指定数据流输入源。将顶点缓存和数据流进行链接,实际上是将几何体的信息传输到绘制流水线中。        
        Device->SetStreamSource(0, Triangle, 0, sizeof(Vertex));//设置顶点数据流输入源
        /**
        HRESULT IDiect3Device9::SetStreamSource(
        UINT StreamNumber ,//标识与顶点缓存建立链接的数据流.
        IDirect3DVertexBuffer9* pStreamData,//指向我们希望与给定数据流建立链接的顶点缓存的指针
        UINT OffsetInBytes, //自数据流起点算起的一个偏移量,单位为字节,指定了将被传输至绘制流水线的顶点数据的起始位置。
        UINT Stride   //将要链接到数据流的顶点缓存中每个元素的大小,单位为字节。
        );
        **/

        //步骤② 设置顶点格式
        Device->SetFVF(Vertex::FVF);
        //步骤③ 设置索引缓存(不过由于这个样例中不使用,故省略)

        //画三角形
        Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

        Device->EndScene();
        Device->Present(0, 0, 0, 0);
    }
    return true;
}

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);
}

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
{
    if (!d3d::InitD3D(hinstance, Width, Height, true, D3DDEVTYPE_HAL, &Device))
    {
        ::MessageBox(0, "InitD3D() - FAILED", 0, 0);
        return 0;
    }
    if (!Setup())
    {
        ::MessageBox(0, "Setup() - FAILED", 0, 0);
        return 0;
    }

    d3d::EnterMsgLoop(Display);

    Cleanup();

    Device->Release();

    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值