Search

2012年10月13日 星期六

wxWidgets With DirectX9 HLSL

    今天翻到以前用MFC+D3D9寫練習用的繪圖引擎,想改寫成wxWidgets版本,只要用wxWindow的GetHandle得到該平台的Handle就可以Create D3D Device了,還有一個是GetHWND意思一樣,要Create D3D10 Device也一樣,然後設定Vertex Shader or Pixel Shader就是D3D Device的事了。

render_data.h


#ifndef __RENDER_DATA__
#define __RENDER_DATA__

#define SAFE_RELEASE(x) if (x){x->Release();x = NULL;}

struct VertexTexture
{
float Position[3];
float Texcoord[2];
};

VertexTexture quad[4] =
{
{{-1.0f, -1.0f, 0.0f},{0.0f, 1.0f}},
{{ 1.0f, -1.0f, 0.0f},{1.0f, 1.0f}},
{{-1.0f,  1.0f, 0.0f},{0.0f, 0.0f}},
{{ 1.0f,  1.0f, 0.0f},{1.0f, 0.0f}}
};

#endif


shader.hlsl


sampler2D Sampler;

uniform float4x4 world_view_proj_matrix : register(c0);

struct VS_INPUT
{
float3 Position : POSITION;
float2 Texcoord : TEXCOORD;
};

struct VS_OUTPUT
{
float4 Position : POSITION;
float2 Texcoord : TEXCOORD0;
};

VS_OUTPUT VS(VS_INPUT In)
{
VS_OUTPUT Out;

Out.Position = mul(world_view_proj_matrix,float4(In.Position, 1.0f));
Out.Texcoord = In.Texcoord;

return Out;
}

float4 PS(VS_OUTPUT In) : COLOR
{
float4 color = tex2D(Sampler, In.Texcoord);

return color;
}



wxDirectX9.h


#ifndef __WX_DIRECT_X__
#define __WX_DIRECT_X__

#include <wx/wx.h>

#include <D3D9.h>
#include <D3DX9.h>

#include "render_data.h"

namespace{
HWND g_hwnd = NULL;

LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pD3DDevice = NULL;
D3DPRESENT_PARAMETERS g_pD3DPresent;
LPDIRECT3DTEXTURE9 g_pTexture = NULL;

LPDIRECT3DVERTEXSHADER9 g_pVertexShaderDX9 = NULL;
LPDIRECT3DPIXELSHADER9  g_pPixelShaderDX9 = NULL;
}

class App:public wxApp
{
public:

bool OnInit();
int OnExit();
};

class Viewport:public wxPanel
{
public:

Viewport(wxWindow*,wxSize);
~Viewport();
void Reset(wxSizeEvent&);
void Updata(wxIdleEvent&);
void Render(wxEraseEvent&);
void InitDX9State();

private:

D3DXVECTOR3 eye;
D3DXVECTOR3 lookat;
D3DXVECTOR3 up;

D3DXMATRIX world_matrix;
D3DXMATRIX view_matrix;
D3DXMATRIX projection_matrix;

static const unsigned long fps = 60;
unsigned long begin,last;

float angle;

DECLARE_EVENT_TABLE()
};

class Frame:public wxFrame
{
public:

Frame(const wxString&,wxSize);
~Frame();

void OnExit(wxCommandEvent&);

bool InitD3D9Device();
void ReleaseD3D9Device();
LPDIRECT3DVERTEXSHADER9 LoadVertexShaderDX9(const wxString&,const wxString&,const wxString&);
LPDIRECT3DPIXELSHADER9 LoadPixelShaderDX9(const wxString&,const wxString&,const wxString&);

void CreateUI();

private:
Viewport *viewport;

DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE(Viewport,wxPanel)
EVT_IDLE(Viewport::Updata)
EVT_ERASE_BACKGROUND(Viewport::Render)
EVT_SIZE(Viewport::Reset)
END_EVENT_TABLE()

BEGIN_EVENT_TABLE(Frame,wxFrame)
EVT_MENU(wxID_EXIT,Frame::OnExit)
END_EVENT_TABLE()

IMPLEMENT_APP(App)
DECLARE_APP(App)

#endif


wxDirectX9.cpp


#include "wxDirectX9.h"

bool App::OnInit()
{
Frame *frame = new Frame(wxT("wxDirectX9"),wxSize(512,512));

frame->Show(true);

return true;
}

int App::OnExit()
{
return wxApp::OnExit();
}

Frame::Frame(const wxString &title,wxSize size):wxFrame(NULL,wxID_ANY,title,wxDefaultPosition,size)
{
viewport = new Viewport(this,size);
g_hwnd = (HWND)viewport->GetHandle();

InitD3D9Device();

g_pVertexShaderDX9 = LoadVertexShaderDX9(wxT("shader.hlsl"),wxT("VS"),wxT("vs_3_0"));
g_pPixelShaderDX9 = LoadPixelShaderDX9(wxT("shader.hlsl"),wxT("PS"),wxT("ps_3_0"));

viewport->InitDX9State();

CreateUI();
}

Frame::~Frame()
{
ReleaseD3D9Device();
}

void Frame::CreateUI()
{
wxMenu *file = new wxMenu;
file->Append(wxID_EXIT,wxT("E&xit\tAlt-q"),wxT("Exit"));

wxMenuBar *bar = new wxMenuBar;
bar->Append(file,wxT("File"));
SetMenuBar(bar);
}

void Frame::OnExit(wxCommandEvent &event)
{
Close();
}

bool Frame::InitD3D9Device()
{
if(g_hwnd == NULL){
return false;
}

RECT rect;
GetWindowRect(g_hwnd,&rect);

float width = rect.right - rect.left;
float height = rect.bottom - rect.top;
if ( width == 0 || height == 0 ){
return false;
}

if( NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) ){
return false;
}

ZeroMemory(&g_pD3DPresent, sizeof(g_pD3DPresent));
g_pD3DPresent.Windowed = TRUE;
g_pD3DPresent.SwapEffect = D3DSWAPEFFECT_DISCARD;
g_pD3DPresent.BackBufferFormat = D3DFMT_UNKNOWN;
g_pD3DPresent.BackBufferCount = 1;
g_pD3DPresent.EnableAutoDepthStencil = TRUE;
g_pD3DPresent.AutoDepthStencilFormat = D3DFMT_D24S8;
g_pD3DPresent.MultiSampleType = (D3DMULTISAMPLE_TYPE)0;
g_pD3DPresent.hDeviceWindow = g_hwnd;

bool device_initialized = false;

const int device_types = 4;

struct sDeviceType
{
D3DDEVTYPE type;
DWORD behavior;
};

sDeviceType device_type[device_types] =
{
{D3DDEVTYPE_HAL,D3DCREATE_HARDWARE_VERTEXPROCESSING},
{D3DDEVTYPE_HAL,D3DCREATE_MIXED_VERTEXPROCESSING},
{D3DDEVTYPE_HAL,D3DCREATE_SOFTWARE_VERTEXPROCESSING},
{D3DDEVTYPE_REF,D3DCREATE_SOFTWARE_VERTEXPROCESSING}
};

for (int type=0;type < device_types;++type)
{
if(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,device_type[type].type,g_hwnd,device_type[type].behavior,&g_pD3DPresent,&g_pD3DDevice) == D3D_OK)
{
device_initialized = true;
break;
}
}

return device_initialized;
}

void Frame::ReleaseD3D9Device()
{
SAFE_RELEASE(g_pD3DDevice);
SAFE_RELEASE(g_pD3D);
SAFE_RELEASE(g_pVertexShaderDX9);
SAFE_RELEASE(g_pPixelShaderDX9);
SAFE_RELEASE(g_pTexture);
}

LPDIRECT3DVERTEXSHADER9 Frame::LoadVertexShaderDX9(const wxString &filename,const wxString &entry,const wxString &profile)
{
LPD3DXBUFFER shader = NULL;
LPD3DXBUFFER error_msg = NULL;
DWORD flags = 0;

HRESULT result = D3DXCompileShaderFromFile(filename.wc_str(),NULL,NULL,entry.mb_str(),profile.mb_str(),flags,&shader,&error_msg,NULL);

if(result != S_OK){return NULL;}

LPDIRECT3DVERTEXSHADER9 vertex_shader = NULL;
result = g_pD3DDevice->CreateVertexShader((DWORD*)shader->GetBufferPointer(),&vertex_shader);

if(result != S_OK){return NULL;}

shader->Release();

return vertex_shader;
}

LPDIRECT3DPIXELSHADER9 Frame::LoadPixelShaderDX9(const wxString &filename,const wxString &entry,const wxString &profile)
{
LPD3DXBUFFER shader = NULL;
LPD3DXBUFFER error_msg = NULL;
DWORD flags = 0;

HRESULT result = D3DXCompileShaderFromFile(filename.wc_str(),NULL,NULL,entry.mb_str(),profile.mb_str(),flags,&shader,&error_msg,NULL);

if(result != S_OK){return NULL;}

LPDIRECT3DPIXELSHADER9 pixel_shader = NULL;
result = g_pD3DDevice->CreatePixelShader((DWORD*)shader->GetBufferPointer(),&pixel_shader);

if(result != S_OK){return NULL;}

shader->Release();

return pixel_shader;
}

Viewport::Viewport(wxWindow *parent,wxSize size):wxPanel(parent,wxID_ANY,wxDefaultPosition,size),eye(0.0f, 3.0f, 3.0f),lookat(0.0f, 0.0f, 0.0f),up(0.0f, -1.0f, 0.0f)
{
begin = last = 0;
angle = 0.0f;
}

Viewport::~Viewport()
{
}

void Viewport::InitDX9State()
{
int width,height;
GetSize(&width,&height);
float aspect = (float)height / (float)width;

D3DXMatrixPerspectiveFovRH(&projection_matrix,45.0f * (3.141592654f/180.0f),aspect,0.1f,10.0f);

D3DXMatrixLookAtRH(&view_matrix,&eye,&lookat,&up);

D3DXMatrixIdentity(&world_matrix);

D3DXMATRIX world_view_proj_matrix = world_matrix * view_matrix * projection_matrix;

g_pD3DDevice->SetVertexShaderConstantF(0,(float*)&world_view_proj_matrix,4);

g_pD3DDevice->SetSamplerState(0,  D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_pD3DDevice->SetSamplerState(0,  D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_pD3DDevice->SetSamplerState(0,  D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

g_pD3DDevice->SetSamplerState(0,  D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
g_pD3DDevice->SetSamplerState(0,  D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);

g_pD3DDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

D3DXCreateTextureFromFileEx(g_pD3DDevice,L"lena.bmp",
D3DX_DEFAULT,D3DX_DEFAULT,D3DX_DEFAULT,0,D3DFMT_UNKNOWN,
D3DPOOL_MANAGED,D3DX_DEFAULT,
D3DX_DEFAULT,0,NULL, NULL,
&g_pTexture);
}

void Viewport::Updata(wxIdleEvent &event)
{
begin = wxGetLocalTimeMillis().ToLong();
if(begin - last > (1000 / fps)){
static float angle = 0.0f;
angle += 0.01f;
D3DXMatrixRotationZ(&world_matrix,angle);
D3DXMATRIX world_view_proj_matrix =  world_matrix * view_matrix * projection_matrix;
g_pD3DDevice->SetVertexShaderConstantF(0,(float*)&world_view_proj_matrix,4);
}
Refresh();
}

void Viewport::Reset(wxSizeEvent &event)
{
RECT rect;
GetWindowRect(g_hwnd, &rect);

g_pD3DPresent.BackBufferWidth = 0;
g_pD3DPresent.BackBufferHeight = 0;
g_pD3DPresent.BackBufferCount = 1;
g_pD3DDevice->Reset(&g_pD3DPresent);

int width,height;
GetSize(&width,&height);
float aspect = (float)height / (float)width;

D3DXMatrixPerspectiveFovRH(&projection_matrix,45.0f * (3.141592654f/180.0f),aspect,0.1f,10.0f);

D3DXMatrixLookAtRH(&view_matrix,&eye,&lookat,&up);

D3DXMATRIX world_view_proj_matrix = world_matrix * view_matrix * projection_matrix;

g_pD3DDevice->SetVertexShaderConstantF(0,(float*)&world_view_proj_matrix,4);
}

void Viewport::Render(wxEraseEvent &event)
{
g_pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_ARGB(0, 0, 0, 0),1.0f,0);

g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

g_pD3DDevice->BeginScene();

g_pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1);

g_pD3DDevice->SetVertexShader(g_pVertexShaderDX9);
g_pD3DDevice->SetPixelShader(g_pPixelShaderDX9);

g_pD3DDevice->SetTexture(0, g_pTexture);

g_pD3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,2,quad,sizeof(VertexTexture));

g_pD3DDevice->EndScene();

g_pD3DDevice->Present(NULL,NULL,NULL,NULL);
}