哈工大C语言大作业曼德勃罗,C语言画Mandelbrot和Julia集合(DX9SM3加速版)

本来打算用Shader Model 2.0,但是经过测试,Shader Model 2.0的功能太原始,连for循环都无法支持,最后只能改用Shader Model 3.0。由于使用了HLSL编译Shader Model 3.0,所以需要VS2002-2010和DirectX 9.0c SDK 2004-2010, 不能使用VC6和DirectX 9.0b SDK。

DX是DirectX的缩写,SM是Shader Model的缩写。

如果改写成DirectX 10/11版本的话,最低应该需要D3D_FEATURE_LEVEL_9_3和ps_4_0_level_9_3,同时还需要编写一个简易的vs_4_0_level_9_3,因为vertex shader和pixel shader在10/11中都不是可选的。

但是由于vs_4_0_level_9_3和ps_4_0_level_9_3不支持通用循环,需要把循环展开成多次条件判断,512的指令数很容易就用超了,对于较复杂的运算,最低建议使用D3D_FEATURE_LEVEL_10_0、vs_4_0和ps_4_0。

<code class="language-txt">vs_1_1 - 128指令

vs_2_0 - 256指令

vs_4_0_level_9_1 - 256指令

vs_2_x - 256指令

vs_4_0_level_9_3 - 256指令

vs_3_0 - 最少512指令,上限到D3DCAPS9.MaxVertexShader30InstructionSlots,支持通用循环

vs_4_0 - 无限制,支持通用循环

ps_2_0 - 32纹理指令+64算术指令

ps_4_0_level_9_1 - 32纹理指令+64算术指令

ps_2_x - 最少96指令,上限到D3DCAPS9.D3DPSHADERCAPS2_0.NumInstructionSlots

ps_4_0_level_9_3 - 512指令

vs_3_0 - 最少512指令,上限到D3DCAPS9.MaxPixelShader30InstructionSlots,支持通用循环

vs_4_0 - 无限制,支持通用循环

</code>

b8edf30ef34454bd55505064ef60a622.png

dxmandelbrot.zip

14.89MB

ZIP

32次下载

GPU部分:

<code class="language-c">// complexsets.txt

float4 ps_mandelbrot(float2 tex : TEXCOORD0) : COLOR0

{

float2 zvar = float2(0, 0);

float i;

for (i = 0; i &lt; 16 &amp;&amp; zvar.x * zvar.x + zvar.y * zvar.y &lt;= 16 4; i++) { float2 zvar2="zvar;" zvar.x="zvar2.x" * zvar2.x - zvar2.y + tex.x; zvar.y="zvar2.x" tex.y; } return float4(i 16.0, 0.0f, 1.0f); float4 ps_julia(float2 tex : texcoord0) color0 zvar="tex;" float i; for (i="0;" i &lt; &amp;&amp; 0.4f; 0.3f; code&gt;&lt;/=&gt;</code>

CPU部分:

<code class="language-c">// main.c

#include &lt;windows.h&gt;

#include &lt;tchar.h&gt;

// DirectX 9.0c SDK or higher

#include &lt;d3d9.h&gt;

#include &lt;d3dx9.h&gt;

#pragma comment(lib, "d3d9.lib")

#pragma comment(lib, "d3dx9.lib")

#pragma comment(linker, "/nodefaultlib:libcp")

LPDIRECT3D9 g_pD3D = NULL;

LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;

LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;

LPDIRECT3DPIXELSHADER9 g_pPSmandelbrot = NULL;

LPDIRECT3DPIXELSHADER9 g_pPSjulia = NULL;

LPDIRECT3DPIXELSHADER9 g_pPS = NULL;

typedef struct CUSTOMVERTEX

{

FLOAT x, y, z, rhw;

FLOAT u, v;

}CUSTOMVERTEX;

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_TEX1)

HRESULT InitD3D(HWND hWnd)

{

D3DPRESENT_PARAMETERS d3dpp;

if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))

return E_FAIL;

ZeroMemory(&amp;d3dpp, sizeof(d3dpp));

d3dpp.Windowed = TRUE;

d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

if (FAILED(IDirect3D9_CreateDevice(g_pD3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,

D3DCREATE_SOFTWARE_VERTEXPROCESSING,

&amp;d3dpp, &amp;g_pd3dDevice)))

{

return E_FAIL;

}

return S_OK;

}

HRESULT CompileAndCreatePS(LPCTSTR filename, LPSTR funcname, LPDIRECT3DPIXELSHADER9 *pps)

{

LPD3DXBUFFER psbuf = NULL, errmsg = NULL;

HRESULT hr = S_OK;

hr = D3DXCompileShaderFromFile(filename, NULL, NULL,

funcname, "ps_3_0", 0, &amp;psbuf, &amp;errmsg, NULL);

if (errmsg)

{

MessageBoxA(NULL, (char*)errmsg-&gt;lpVtbl-&gt;GetBufferPointer(errmsg), "err", MB_ICONERROR);

errmsg-&gt;lpVtbl-&gt;Release(errmsg);

return hr;

}

else if (FAILED(hr))

{

return hr;

}

hr = IDirect3DDevice9_CreatePixelShader(g_pd3dDevice,

(DWORD*)psbuf-&gt;lpVtbl-&gt;GetBufferPointer(psbuf), pps);

psbuf-&gt;lpVtbl-&gt;Release(psbuf);

return S_OK;

}

HRESULT InitRes()

{

CUSTOMVERTEX vertices[] =

{

{ 0.0f, 0.0f, 0.5f, 1.0f, -2.2f, -2.2f, },

{ 480.0f, 0.0f, 0.5f, 1.0f, 2.2f, -2.2f, },

{ 0.0f, 480.0f, 0.5f, 1.0f, -2.2f, 2.2f, },

{ 480.0f, 480.0f, 0.5f, 1.0f, 2.2f, 2.2f, },

};

HRESULT hr = S_OK;

VOID* pVertices;

hr = IDirect3DDevice9_CreateVertexBuffer(g_pd3dDevice, 4*sizeof(CUSTOMVERTEX),

0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &amp;g_pVB, NULL);

if (FAILED(hr))

{

return hr;

}

hr = IDirect3DVertexBuffer9_Lock(g_pVB, 0, sizeof(vertices), (void**)&amp;pVertices, 0);

if (FAILED(hr))

return hr;

memcpy(pVertices, vertices, sizeof(vertices));

IDirect3DVertexBuffer9_Unlock(g_pVB);

CompileAndCreatePS(_T("complexsets.txt"), "ps_mandelbrot", &amp;g_pPSmandelbrot);

CompileAndCreatePS(_T("complexsets.txt"), "ps_julia", &amp;g_pPSjulia);

g_pPS = g_pPSmandelbrot;

return S_OK;

}

VOID Cleanup()

{

if (g_pPSjulia)

IDirect3DPixelShader9_Release(g_pPSjulia);

if (g_pPSmandelbrot)

IDirect3DPixelShader9_Release(g_pPSmandelbrot);

if (g_pVB != NULL)

IDirect3DVertexBuffer9_Release(g_pVB);

if (g_pd3dDevice != NULL)

IDirect3DDevice9_Release(g_pd3dDevice);

if (g_pD3D != NULL)

IDirect3D9_Release(g_pD3D);

}

VOID Render()

{

IDirect3DDevice9_Clear(g_pd3dDevice, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0);

if (SUCCEEDED(IDirect3DDevice9_BeginScene(g_pd3dDevice)))

{

IDirect3DDevice9_SetStreamSource(g_pd3dDevice, 0, g_pVB, 0, sizeof(CUSTOMVERTEX));

IDirect3DDevice9_SetFVF(g_pd3dDevice, D3DFVF_CUSTOMVERTEX);

IDirect3DDevice9_SetPixelShader(g_pd3dDevice, g_pPS);

IDirect3DDevice9_DrawPrimitive(g_pd3dDevice, D3DPT_TRIANGLESTRIP, 0, 2);

IDirect3DDevice9_EndScene(g_pd3dDevice);

}

IDirect3DDevice9_Present(g_pd3dDevice, NULL, NULL, NULL, NULL);

}

LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

switch (msg)

{

case WM_LBUTTONDOWN:

g_pPS = g_pPSmandelbrot;

return 0;

case WM_RBUTTONDOWN:

g_pPS = g_pPSjulia;

return 0;

case WM_DESTROY:

Cleanup();

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hWnd, msg, wParam, lParam);

}

INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szCmdLine, int nShowCmd)

{

WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,

hInst, LoadIcon(NULL, IDI_APPLICATION),

LoadCursor(NULL, IDC_ARROW), NULL, NULL,

_T("MainWndProc"), wc.hIcon };

RECT rc = { 0, 0, 480, 480 };

MSG msg;

HWND hWnd;

if (!RegisterClassEx(&amp;wc))

return 0;

AdjustWindowRect(&amp;rc, WS_OVERLAPPEDWINDOW, FALSE);

hWnd = CreateWindow(wc.lpszClassName, _T("Mandelbrot and Julia"),

WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,

rc.right - rc.left, rc.bottom - rc.top,

NULL, NULL, wc.hInstance, NULL);

if (SUCCEEDED(InitD3D(hWnd)))

{

if (SUCCEEDED(InitRes()))

{

ShowWindow(hWnd, SW_SHOWDEFAULT);

UpdateWindow(hWnd);

ZeroMemory(&amp;msg, sizeof(msg));

while (msg.message != WM_QUIT)

{

if (PeekMessage(&amp;msg, NULL, 0, 0, PM_REMOVE))

{

TranslateMessage(&amp;msg);

DispatchMessage(&amp;msg);

}

else

{

Render();

}

}

}

}

return 0;

}

&lt;/d3dx9.h&gt;&lt;/d3d9.h&gt;&lt;/tchar.h&gt;&lt;/windows.h&gt;</code>

更新:支持Visual C++ 6.0和DirectX 9.0b SDK

通过DirectX 9.0c SDK的fxc将上述HLSL代码编译为Shader Model 3.0 ASM代码,即可支持DirectX 9.0b SDK。

ps_mandelbrot.txt:

<code class="language-asm">// ps_mandelbrot.txt

ps_3_0

def c0, 0, 0, 4, 1

def c1, 0.0625, 0, 0, 0

defi i0, 16, 0, 0, 0

dcl_texcoord v0.xy

mov r0.y, c0.y

mov r0.z, c0.y

mov r0.w, c0.y

rep i0

mul r0.x, r0.z, r0.z

mad r0.x, r0.y, r0.y, r0.x

break_lt c0.z, r0.x

mul r0.x, r0.z, r0.z

mad r0.x, r0.y, r0.y, -r0.x

add r0.x, r0.x, v0.x

dp2add r0.z, r0.y, r0.z, v0.y

add r0.w, r0.w, c0.w

mov r0.y, r0.x

endrep

mul oC0.x, r0.w, c1.x

mov oC0.yzw, c0.xyyw

</code>

ps_julia.txt

<code class="language-asm">// ps_julia.txt

ps_3_0

def c0, 0, 0, 4, 0.400000006

def c1, 0.300000012, 1, 0.0625, 0

defi i0, 16, 0, 0, 0

dcl_texcoord v0.xy

mov r0.y, v0.x

mov r0.z, v0.y

mov r0.w, c0.y

rep i0

mul r0.x, r0.z, r0.z

mad r0.x, r0.y, r0.y, r0.x

break_lt c0.z, r0.x

mul r0.x, r0.z, r0.z

mad r0.x, r0.y, r0.y, -r0.x

add r0.x, r0.x, c0.w

dp2add r0.z, r0.y, r0.z, c1.x

add r0.w, r0.w, c1.y

mov r0.y, r0.x

endrep

mul oC0.x, r0.w, c1.z

mov oC0.yzw, c1.xwwy

</code>

main.c

<code class="language-c">// main.c

#include &lt;windows.h&gt;

#include &lt;tchar.h&gt;

#include &lt;d3d9.h&gt;

#include &lt;d3dx9.h&gt;

#pragma comment(lib, "d3d9.lib")

#pragma comment(lib, "d3dx9.lib")

LPDIRECT3D9 g_pD3D = NULL;

LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;

LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;

LPDIRECT3DPIXELSHADER9 g_pPSmandelbrot = NULL;

LPDIRECT3DPIXELSHADER9 g_pPSjulia = NULL;

LPDIRECT3DPIXELSHADER9 g_pPS = NULL;

typedef struct CUSTOMVERTEX

{

FLOAT x, y, z, rhw;

FLOAT u, v;

}CUSTOMVERTEX;

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_TEX1)

HRESULT InitD3D(HWND hWnd)

{

D3DPRESENT_PARAMETERS d3dpp;

if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))

return E_FAIL;

ZeroMemory(&amp;d3dpp, sizeof(d3dpp));

d3dpp.Windowed = TRUE;

d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

if (FAILED(IDirect3D9_CreateDevice(g_pD3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,

D3DCREATE_SOFTWARE_VERTEXPROCESSING,

&amp;d3dpp, &amp;g_pd3dDevice)))

{

return E_FAIL;

}

return S_OK;

}

HRESULT AssembleAndCreatePS(LPCTSTR filename, LPDIRECT3DPIXELSHADER9 *pps)

{

LPD3DXBUFFER psbuf = NULL, errmsg = NULL;

HRESULT hr = S_OK;

hr = D3DXAssembleShaderFromFile(filename, NULL, NULL, 0, &amp;psbuf, &amp;errmsg);

if (errmsg)

{

MessageBoxA(NULL, (char*)errmsg-&gt;lpVtbl-&gt;GetBufferPointer(errmsg), "err", MB_ICONERROR);

errmsg-&gt;lpVtbl-&gt;Release(errmsg);

return hr;

}

else if (FAILED(hr))

{

return hr;

}

hr = IDirect3DDevice9_CreatePixelShader(g_pd3dDevice,

(DWORD*)psbuf-&gt;lpVtbl-&gt;GetBufferPointer(psbuf), pps);

psbuf-&gt;lpVtbl-&gt;Release(psbuf);

return S_OK;

}

HRESULT InitRes()

{

CUSTOMVERTEX vertices[] =

{

{ 0.0f, 0.0f, 0.5f, 1.0f, -2.2f, -2.2f, },

{ 480.0f, 0.0f, 0.5f, 1.0f, 2.2f, -2.2f, },

{ 0.0f, 480.0f, 0.5f, 1.0f, -2.2f, 2.2f, },

{ 480.0f, 480.0f, 0.5f, 1.0f, 2.2f, 2.2f, },

};

HRESULT hr = S_OK;

VOID* pVertices;

hr = IDirect3DDevice9_CreateVertexBuffer(g_pd3dDevice, 4*sizeof(CUSTOMVERTEX),

0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &amp;g_pVB, NULL);

if (FAILED(hr))

{

return hr;

}

hr = IDirect3DVertexBuffer9_Lock(g_pVB, 0, sizeof(vertices), (void**)&amp;pVertices, 0);

if (FAILED(hr))

return hr;

memcpy(pVertices, vertices, sizeof(vertices));

IDirect3DVertexBuffer9_Unlock(g_pVB);

AssembleAndCreatePS(_T("ps_mandelbrot.txt"), &amp;g_pPSmandelbrot);

AssembleAndCreatePS(_T("ps_julia.txt"), &amp;g_pPSjulia);

g_pPS = g_pPSmandelbrot;

return S_OK;

}

VOID Cleanup()

{

if (g_pPSjulia)

IDirect3DPixelShader9_Release(g_pPSjulia);

if (g_pPSmandelbrot)

IDirect3DPixelShader9_Release(g_pPSmandelbrot);

if (g_pVB != NULL)

IDirect3DVertexBuffer9_Release(g_pVB);

if (g_pd3dDevice != NULL)

IDirect3DDevice9_Release(g_pd3dDevice);

if (g_pD3D != NULL)

IDirect3D9_Release(g_pD3D);

}

VOID Render()

{

IDirect3DDevice9_Clear(g_pd3dDevice, 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0);

if (SUCCEEDED(IDirect3DDevice9_BeginScene(g_pd3dDevice)))

{

IDirect3DDevice9_SetStreamSource(g_pd3dDevice, 0, g_pVB, 0, sizeof(CUSTOMVERTEX));

IDirect3DDevice9_SetFVF(g_pd3dDevice, D3DFVF_CUSTOMVERTEX);

IDirect3DDevice9_SetPixelShader(g_pd3dDevice, g_pPS);

IDirect3DDevice9_DrawPrimitive(g_pd3dDevice, D3DPT_TRIANGLESTRIP, 0, 2);

IDirect3DDevice9_EndScene(g_pd3dDevice);

}

IDirect3DDevice9_Present(g_pd3dDevice, NULL, NULL, NULL, NULL);

}

LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

switch (msg)

{

case WM_LBUTTONDOWN:

g_pPS = g_pPSmandelbrot;

return 0;

case WM_RBUTTONDOWN:

g_pPS = g_pPSjulia;

return 0;

case WM_DESTROY:

Cleanup();

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hWnd, msg, wParam, lParam);

}

INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szCmdLine, int nShowCmd)

{

WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,

hInst, LoadIcon(NULL, IDI_APPLICATION),

LoadCursor(NULL, IDC_ARROW), NULL, NULL,

_T("MainWndProc"), wc.hIcon };

RECT rc = { 0, 0, 480, 480 };

MSG msg;

HWND hWnd;

if (!RegisterClassEx(&amp;wc))

return 0;

AdjustWindowRect(&amp;rc, WS_OVERLAPPEDWINDOW, FALSE);

hWnd = CreateWindow(wc.lpszClassName, _T("Mandelbrot and Julia"),

WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,

rc.right - rc.left, rc.bottom - rc.top,

NULL, NULL, wc.hInstance, NULL);

if (SUCCEEDED(InitD3D(hWnd)))

{

if (SUCCEEDED(InitRes()))

{

ShowWindow(hWnd, SW_SHOWDEFAULT);

UpdateWindow(hWnd);

ZeroMemory(&amp;msg, sizeof(msg));

while (msg.message != WM_QUIT)

{

if (PeekMessage(&amp;msg, NULL, 0, 0, PM_REMOVE))

{

TranslateMessage(&amp;msg);

DispatchMessage(&amp;msg);

}

else

{

Render();

}

}

}

}

return 0;

}

&lt;/d3dx9.h&gt;&lt;/d3d9.h&gt;&lt;/tchar.h&gt;&lt;/windows.h&gt;</code>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值