C语言画Mandelbrot和Julia集合(DX9SM3加速版)
acmilan2017/06/19软件综合 IP:四川

本来打算用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>


attachment icon dxmandelbrot.zip 14.89MB ZIP 35次下载

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 < 16 && zvar.x * zvar.x + zvar.y * zvar.y <= 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 < && 0.4f; 0.3f; code></=></code>

CPU部分:

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

#include <windows.h>
#include <tchar.h>

// DirectX 9.0c SDK or higher
#include <d3d9.h>
#include <d3dx9.h>
#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(&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,
                                      &d3dpp, &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, &psbuf, &errmsg, NULL);
	if (errmsg)
	{
		MessageBoxA(NULL, (char*)errmsg->lpVtbl->GetBufferPointer(errmsg), "err", MB_ICONERROR);
		errmsg->lpVtbl->Release(errmsg);
		return hr;
	}
	else if (FAILED(hr))
	{
		return hr;
	}
	hr = IDirect3DDevice9_CreatePixelShader(g_pd3dDevice,
		(DWORD*)psbuf->lpVtbl->GetBufferPointer(psbuf), pps);
	psbuf->lpVtbl->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, &g_pVB, NULL);
    if (FAILED(hr))
    {
        return hr;
    }

	hr = IDirect3DVertexBuffer9_Lock(g_pVB, 0, sizeof(vertices), (void**)&pVertices, 0);
    if (FAILED(hr))
        return hr;
    memcpy(pVertices, vertices, sizeof(vertices));
    IDirect3DVertexBuffer9_Unlock(g_pVB);

	CompileAndCreatePS(_T("complexsets.txt"), "ps_mandelbrot", &g_pPSmandelbrot);
	CompileAndCreatePS(_T("complexsets.txt"), "ps_julia", &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(&wc))
		return 0;

	AdjustWindowRect(&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(&msg, sizeof(msg));
            while (msg.message != WM_QUIT)
            {
                if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
                else
				{
                    Render();
				}
            }
        }
    }
    return 0;
}
</d3dx9.h></d3d9.h></tchar.h></windows.h></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 <windows.h>
#include <tchar.h>
#include <d3d9.h>
#include <d3dx9.h>
#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(&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,
                                      &d3dpp, &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, &psbuf, &errmsg);
	if (errmsg)
	{
		MessageBoxA(NULL, (char*)errmsg->lpVtbl->GetBufferPointer(errmsg), "err", MB_ICONERROR);
		errmsg->lpVtbl->Release(errmsg);
		return hr;
	}
	else if (FAILED(hr))
	{
		return hr;
	}
	hr = IDirect3DDevice9_CreatePixelShader(g_pd3dDevice,
		(DWORD*)psbuf->lpVtbl->GetBufferPointer(psbuf), pps);
	psbuf->lpVtbl->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, &g_pVB, NULL);
    if (FAILED(hr))
    {
        return hr;
    }

	hr = IDirect3DVertexBuffer9_Lock(g_pVB, 0, sizeof(vertices), (void**)&pVertices, 0);
    if (FAILED(hr))
        return hr;
    memcpy(pVertices, vertices, sizeof(vertices));
    IDirect3DVertexBuffer9_Unlock(g_pVB);

	AssembleAndCreatePS(_T("ps_mandelbrot.txt"), &g_pPSmandelbrot);
	AssembleAndCreatePS(_T("ps_julia.txt"), &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(&wc))
		return 0;

	AdjustWindowRect(&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(&msg, sizeof(msg));
            while (msg.message != WM_QUIT)
            {
                if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
                else
				{
                    Render();
				}
            }
        }
    }
    return 0;
}
</d3dx9.h></d3d9.h></tchar.h></windows.h></code>

[修改于 7年4个月前 - 2017/08/11 21:27:30]

来自:计算机科学 / 软件综合
1
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,5年10个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}