Ok, this code will run with just the main.cpp file, but will work best with a texture
demo.bmp
, and the shader file
Shader.fx
You will need to grab or make a bitmap image and place it in the working directory, and name it
demo.bmp
. This will texture the quad.
The shader file should also be placed in the working directory.
Note that this code does not use the Z buffer. This means when you draw something, it will always draw on top of whatever is there, even if it should be at the back. This avoids tearing since everything is rendered at z=0.
The shader allows for advanced effects, I used it to render a perfect circle at any resolution, but they allow for almost limitless special effects.
If you want to texture the points, you can set the texture, there is already a
g_pd3dDevice->SetTexture(0, NULL);
, just create a texture and shove it in there. It will need an alpha channel to work however, so use a PNG or something.
The single pixel points are there, but they may be a bit hard to see, depending on the texture. They are also rendered with transparency.
I have provided some commenting, but you seem to have a reasonable handle on the basics of DirectX, so I didn't do to many.
If you need further explanation of any of the code, just post which parts you are having trouble with.
Just shove this code into a new Win32 GUI project and go. There are no special settings.
Main.cpp:
#include <Windows.h>
#include <tchar.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <mmsystem.h> //for timeGetTime to rotate it around
#include <stdio.h>
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "winmm.lib")
typedef struct {
D3DXVECTOR3 vPos;
D3DCOLOR colDiffuse;
D3DXVECTOR2 vUV;
} PicVertex;
typedef struct {
D3DXVECTOR3 vPos;
D3DCOLOR colDiffuse;
D3DXVECTOR2 vUV;
} PointVertex;
typedef struct {
D3DXVECTOR3 vPos;
D3DCOLOR colDiffuse;
} PixelVertex;
#define D3DFVF_PICVERTEX (D3DFVF_DIFFUSE | D3DFVF_XYZ | D3DFVF_TEX1)
#define D3DFVF_PIXELVERTEX (D3DFVF_DIFFUSE | D3DFVF_XYZ)
#define D3DFVF_POINTVERTEX (D3DFVF_DIFFUSE | D3DFVF_XYZ | D3DFVF_TEX1)
#define ADD_POINT_UV(x, y, z, size, col, u, v) { D3DXVECTOR3(x + (u - 0.5f) * size, y + (v - 0.5f) * size, z), col, D3DXVECTOR2(u, v) }
#define ADD_POINT(x, y, z, size, col) \
ADD_POINT_UV(x, y, z, size, col, 0.0f, 1.0f),\
ADD_POINT_UV(x, y, z, size, col, 0.0f, 0.0f),\
ADD_POINT_UV(x, y, z, size, col, 1.0f, 1.0f),\
ADD_POINT_UV(x, y, z, size, col, 1.0f, 1.0f),\
ADD_POINT_UV(x, y, z, size, col, 0.0f, 0.0f),\
ADD_POINT_UV(x, y, z, size, col, 1.0f, 0.0f),
#define ADD_PIXEL(x, y, z, col) { D3DXVECTOR3(x, y, z), col },
LPDIRECT3D9 g_pD3D = NULL; LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; LPDIRECT3DVERTEXBUFFER9 g_pQuadVB = NULL; LPDIRECT3DVERTEXBUFFER9 g_pPixelVB = NULL; LPDIRECT3DVERTEXBUFFER9 g_pPointVB = NULL; LPD3DXEFFECT g_pEffect = NULL; D3DXHANDLE g_pPointEffect = NULL; D3DXHANDLE g_pFFEffect = NULL; LPDIRECT3DVERTEXDECLARATION9 g_pVertexDeclaration = NULL; LPDIRECT3DTEXTURE9 g_pTexture = NULL;
PicVertex aQuad[] = {
{ D3DXVECTOR3(-1.0f, 1.0f, 0.0f), D3DCOLOR_ARGB(255, 255, 255, 255), D3DXVECTOR2(0.0f, 0.0f) },
{ D3DXVECTOR3(-1.0f, -1.0f, 0.0f), D3DCOLOR_ARGB(255, 255, 255, 255), D3DXVECTOR2(0.0f, 1.0f) },
{ D3DXVECTOR3( 1.0f, 1.0f, 0.0f), D3DCOLOR_ARGB(255, 255, 255, 255), D3DXVECTOR2(1.0f, 0.0f) },
{ D3DXVECTOR3( 1.0f, -1.0f, 0.0f), D3DCOLOR_ARGB(255, 255, 255, 255), D3DXVECTOR2(1.0f, 1.0f) }
};
PointVertex g_colPoints[] = {
ADD_POINT(-0.5f, 0.005f, 0.0f, 0.05f, D3DCOLOR_ARGB(180, 255, 0, 0) )
ADD_POINT(-0.5f, 0.055f, 0.0f, 0.05f, D3DCOLOR_ARGB(180, 255, 0, 0) )
ADD_POINT(-0.5f, 0.55f, 0.0f, 0.05f, D3DCOLOR_ARGB(180, 255, 0, 0) )
ADD_POINT(-0.5f, 0.45f, 0.0f, 0.05f, D3DCOLOR_ARGB(180, 255, 0, 0) )
ADD_POINT(-0.5f, 0.40f, 0.0f, 0.025f, D3DCOLOR_ARGB(180, 255, 0, 0) )
ADD_POINT(-0.5f, 0.35f, 0.0f, 0.05f, D3DCOLOR_ARGB(180, 255, 0, 0) )
ADD_POINT(-0.5f, 0.30f, 0.0f, 0.05f, D3DCOLOR_ARGB(180, 255, 0, 0) )
ADD_POINT(-0.5f, 0.25f, 0.0f, 0.012f, D3DCOLOR_ARGB(180, 255, 0, 0) )
ADD_POINT(-0.5f, 0.20f, 0.0f, 0.05f, D3DCOLOR_ARGB(100, 128, 128, 128))
ADD_POINT(-0.5f, 0.15f, 0.0f, 0.05f, D3DCOLOR_ARGB(255, 128, 128, 128))
ADD_POINT(-0.1f, 0.10f, 0.0f, 0.50f, D3DCOLOR_ARGB(180, 0, 0, 0) )
};
PixelVertex g_colPixels[] = {
ADD_PIXEL(0.5f, 0.005f, 0.0f, D3DCOLOR_ARGB(220, 255, 0, 0) )
ADD_PIXEL(0.5f, 0.055f, 0.0f, D3DCOLOR_ARGB(220, 255, 0, 0) )
ADD_PIXEL(0.5f, 0.55f, 0.0f, D3DCOLOR_ARGB(220, 255, 0, 0) )
ADD_PIXEL(0.5f, 0.45f, 0.0f, D3DCOLOR_ARGB(220, 255, 0, 0) )
ADD_PIXEL(0.5f, 0.40f, 0.0f, D3DCOLOR_ARGB(220, 255, 0, 0) )
ADD_PIXEL(0.5f, 0.35f, 0.0f, D3DCOLOR_ARGB(220, 255, 0, 0) )
ADD_PIXEL(0.5f, 0.30f, 0.0f, D3DCOLOR_ARGB(220, 255, 0, 0) )
ADD_PIXEL(0.5f, 0.25f, 0.0f, D3DCOLOR_ARGB(220, 255, 0, 0) )
ADD_PIXEL(0.5f, 0.20f, 0.0f, D3DCOLOR_ARGB(100, 128, 128, 128))
ADD_PIXEL(0.5f, 0.15f, 0.0f, D3DCOLOR_ARGB(255, 128, 128, 128))
ADD_PIXEL(0.5f, 0.10f, 0.0f, D3DCOLOR_ARGB(220, 0, 0, 0) )
};
bool InitD3D(HWND hWnd) {
if ((g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) {
return false;
}
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice))) {
return false;
}
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
LPD3DXBUFFER pErrors;
if (FAILED(D3DXCreateEffectFromFile(g_pd3dDevice, _T("Shader.fx"), NULL, NULL, 0, NULL, &g_pEffect, &pErrors))) {
if (pErrors == NULL) {
MessageBox(HWND_DESKTOP, _T("Shader.fx not found"), _T("Shader missing"), MB_OK | MB_ICONERROR);
} else {
MessageBoxA(HWND_DESKTOP, (LPSTR)pErrors->GetBufferPointer(), "Shader compile error", MB_OK | MB_ICONERROR);
pErrors->Release();
}
} else {
g_pPointEffect = g_pEffect->GetTechniqueByName("Point");
g_pFFEffect = g_pEffect->GetTechniqueByName("FixedFunction");
D3DVERTEXELEMENT9 decl[] = {
{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
{ 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
D3DDECL_END()
};
g_pd3dDevice->CreateVertexDeclaration(decl, &g_pVertexDeclaration);
}
return true;
}
void Cleanup() {
if (g_pEffect != NULL) {
g_pEffect->Release();
}
if (g_pQuadVB != NULL) {
g_pQuadVB->Release();
}
if (g_pPixelVB != NULL) {
g_pPixelVB->Release();
}
if (g_pPointVB != NULL) {
g_pPointVB->Release();
}
if (g_pVertexDeclaration != NULL) {
g_pVertexDeclaration->Release();
}
if (g_pTexture != NULL) {
g_pTexture->Release();
}
if (g_pd3dDevice != NULL) {
g_pd3dDevice->Release();
}
if (g_pD3D != NULL) {
g_pD3D->Release();
}
}
bool InitGeometry() {
void *pVerts;
if (FAILED(g_pd3dDevice->CreateVertexBuffer(sizeof(aQuad), 0, D3DFVF_PICVERTEX, D3DPOOL_DEFAULT, &g_pQuadVB, NULL))) {
return false;
}
if (FAILED(g_pQuadVB->Lock(0, 0, &pVerts, 0))) {
return false;
}
memcpy(pVerts, aQuad, sizeof(aQuad));
g_pQuadVB->Unlock();
if (FAILED(D3DXCreateTextureFromFile(g_pd3dDevice, "demo.bmp", &g_pTexture))) {
MessageBox(HWND_DESKTOP, _T("Place an image named \'demo.bmp\' in the working directory to have a textured plane."), _T("No texture"), MB_OK | MB_ICONWARNING);
}
if (FAILED(g_pd3dDevice->CreateVertexBuffer(sizeof(g_colPixels), 0, D3DFVF_PIXELVERTEX, D3DPOOL_DEFAULT, &g_pPixelVB, NULL))) {
return false;
}
if (FAILED(g_pPixelVB->Lock(0, 0, &pVerts, 0))) {
return false;
}
memcpy(pVerts, g_colPixels, sizeof(g_colPixels));
g_pPixelVB->Unlock();
if (FAILED(g_pd3dDevice->CreateVertexBuffer(sizeof(g_colPoints), 0, D3DFVF_POINTVERTEX, D3DPOOL_DEFAULT, &g_pPointVB, NULL))) {
return false;
}
if (FAILED(g_pPointVB->Lock(0, 0, &pVerts, 0))) {
return false;
}
memcpy(pVerts, g_colPoints, sizeof(g_colPoints));
g_pPointVB->Unlock();
return true;
}
void SetupMatrices() {
D3DXMATRIXA16 matWorld, matView, matProj, matTmp;
D3DXMatrixRotationZ(&matWorld, timeGetTime() / 1000.0f);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);
D3DXVECTOR3 vEyePt(0.0f, -3.0f, -4.0f);
D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);
D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);
D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);
if (g_pEffect != NULL) {
D3DXMATRIXA16 matWoldViewProj = matWorld * matView * matProj;
g_pEffect->SetMatrix("matWorldViewProj", &matWoldViewProj);
}
}
void Render() {
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);
if (SUCCEEDED(g_pd3dDevice->BeginScene())) {
SetupMatrices();
g_pd3dDevice->SetTexture(0, g_pTexture); g_pd3dDevice->SetStreamSource(0, g_pQuadVB, 0, sizeof(PicVertex));
g_pd3dDevice->SetFVF(D3DFVF_PICVERTEX);
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
g_pd3dDevice->SetStreamSource(0, g_pPointVB, 0, sizeof(PointVertex));
if (g_pEffect == NULL) { g_pd3dDevice->SetTexture(0, NULL); g_pd3dDevice->SetFVF(D3DFVF_POINTVERTEX);
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, (sizeof(g_colPoints) / sizeof(g_colPoints[0])) / 3);
} else {
g_pd3dDevice->SetVertexDeclaration(g_pVertexDeclaration);
g_pEffect->SetTechnique(g_pPointEffect);
UINT nPasses; g_pEffect->Begin(&nPasses, 0);
for (UINT nPass = 0; nPass < nPasses; ++nPass) {
g_pEffect->BeginPass(nPass);
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, (sizeof(g_colPoints) / sizeof(g_colPoints[0])) / 3);
g_pEffect->EndPass();
}
g_pEffect->End();
g_pEffect->SetTechnique(g_pFFEffect);
g_pd3dDevice->SetVertexDeclaration(NULL);
}
g_pd3dDevice->SetFVF(D3DFVF_PIXELVERTEX);
g_pd3dDevice->SetStreamSource(0, g_pPixelVB, 0, sizeof(PixelVertex));
g_pd3dDevice->DrawPrimitive(D3DPT_POINTLIST, 0, sizeof(g_colPixels) / sizeof(PixelVertex));
g_pd3dDevice->EndScene();
}
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}
LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_DESTROY:
Cleanup();
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0, 0, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, _T("DotsExample"), NULL };
RegisterClassEx(&wc);
HWND hWnd = CreateWindow(_T("DotsExample"), _T("Points Example - Andrew Brock"), WS_OVERLAPPEDWINDOW, 100, 100, 580, 580, NULL, NULL, wc.hInstance, NULL);
if (InitD3D(hWnd)) {
if (InitGeometry()) {
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message != WM_QUIT) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
Render();
}
}
}
}
UnregisterClass(_T("DotsExample"), wc.hInstance);
return 0;
}
Shader.fx:
float4x4 matWorldViewProj : WORLDVIEWPROJ;
struct VS_OUTPUT {
float4 vPosition : POSITION;
float4 vDiffuse : COLOR;
float2 vTexCoord : TEXCOORD0;
};
VS_OUTPUT VertexShaderPoint(float4 vPos : POSITION, float4 vDiffuse : COLOR, float2 vTexCoord : TEXCOORD0) {
VS_OUTPUT output;
output.vPosition = mul(vPos, matWorldViewProj); output.vDiffuse = vDiffuse; output.vTexCoord = vTexCoord; return output;
}
float4 PixelShaderPoint(VS_OUTPUT input) : COLOR {
float2 len = input.vTexCoord - 0.5;
float dist = len.x * len.x + len.y * len.y; clip(0.25 - dist); return input.vDiffuse;
}
technique Point {
pass P0 {
VertexShader = compile vs_2_0 VertexShaderPoint();
PixelShader = compile ps_2_0 PixelShaderPoint();
}
}
technique FixedFunction {
pass P0 {
VertexShader = NULL;
PixelShader = NULL;
}
}