4Jan/100
Rewriting examples: Direct3D tutorial 1 with D3DVERTEXELEMENT9
A while ago a friend asked me how to do something with Direct3D (better known as DirectX) about streams. I really enjoyed it since it was sometime I have worked with my favorite 3D API and so I explained the usage of VertexDeceleration by rewriting the very first tutorial of Direct3D of which you can see the result below
#include <windows.h>
#include <d3d9.h>
#pragma comment(lib, "d3d9.lib")
#include <d3dx9.h>
#pragma comment(lib, "d3dx9.lib")
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("DirectXStreamExample");
HWND hwnd;
MSG msg;
WNDCLASSEX wndclassex = {0};
wndclassex.cbSize = sizeof(WNDCLASSEX);
wndclassex.style = CS_HREDRAW | CS_VREDRAW;
wndclassex.lpfnWndProc = WndProc;
wndclassex.cbClsExtra = 0;
wndclassex.cbWndExtra = 0;
wndclassex.hInstance = hInstance;
wndclassex.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclassex.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclassex.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
wndclassex.lpszMenuName = NULL;
wndclassex.lpszClassName = szAppName;
wndclassex.hIconSm = wndclassex.hIcon;
if (!RegisterClassEx (&wndclassex))
{
MessageBox (NULL, TEXT ("RegisterClassEx failed!"), szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindowEx (WS_EX_OVERLAPPEDWINDOW,
szAppName,
TEXT ("DirectXStreamExample"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
640,
480,
NULL,
NULL,
hInstance,
NULL);
ShowWindow (hwnd, iCmdShow);
UpdateWindow (hwnd);
// Now setup DirectX
IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
D3DPRESENT_PARAMETERS presentParameters;
memset(&presentParameters, 0, sizeof(D3DPRESENT_PARAMETERS));
presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
presentParameters.Windowed = true;
IDirect3DDevice9* device = 0;
d3d9->CreateDevice(0, D3DDEVTYPE_HAL, hwnd, D3DCREATE_MIXED_VERTEXPROCESSING, &presentParameters, &device);
// Create our custom vertex format
struct POSCOLORVERTEX
{
float X, Y, Z, W;
DWORD color;
};
POSCOLORVERTEX vertices[] = {
{150.0f, 50.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(255,0,0)},
{250.0f, 250.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(0,255,0)},
{ 50.0f, 250.0f, 0.5f, 1.0f, D3DCOLOR_XRGB(0,0,255)},
};
// Create a vertex decleration
// Think of a vertex decleration as an object that describes a single custom
// vertex.
// typedef struct _D3DVERTEXELEMENT9
// {
// WORD Stream; // Stream index
// WORD Offset; // Offset in the stream in bytes
// BYTE Type; // Data type
// BYTE Method; // Processing method
// BYTE Usage; // Semantics
// BYTE UsageIndex; // Semantic index
// } D3DVERTEXELEMENT9, *LPD3DVERTEXELEMENT9;
// Example 1: Tutorial 1 of the DirectX SDK
// using weighted position (aka screen coordinates) and colors but without
// using the Fixed Pipeline
D3DVERTEXELEMENT9 PosColorVertexElements[] = {
{0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0},
{0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
D3DDECL_END()
};
#if 0
// Example 2: If you want to add UV it would become something like this:
D3DVERTEXELEMENT9 PosColorUVVertexElements[] = {
{0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0},
{0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
{0, 20, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
D3DDECL_END()
};
// Example 3: And if you want UVs first
D3DVERTEXELEMENT9 PosColorNormalVertexElements[] = {
{0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
{0, 8, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0},
{0, 8+16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
D3DDECL_END()
};
// Example 4: And if you want to send two UV's
D3DVERTEXELEMENT9 PosColorNormalVertexElements[] = {
{0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0},
{0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
{0, 20, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // Maps to TEXCOORD0 in shader
{1, 28, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // Maps to TEXCOORD1 in shader
D3DDECL_END()
};
#endif
IDirect3DVertexDeclaration9* vertexDecleration = 0;
device->CreateVertexDeclaration(PosColorVertexElements, &vertexDecleration);
device->SetVertexDeclaration(vertexDecleration);
// Create vertex buffer
IDirect3DVertexBuffer9* vertexBuffer;
device->CreateVertexBuffer(
3*sizeof(POSCOLORVERTEX),
0,
0, // DON'T pass the FVF code if you are using vertex decleration
D3DPOOL_DEFAULT,
&vertexBuffer,
0);
// Fill the vertex buffer
void* pVertices = 0;
vertexBuffer->Lock(0, sizeof(vertices), (void**)&pVertices, 0);
memcpy(pVertices, vertices, sizeof(vertices));
vertexBuffer->Unlock();
bool keepRunning = true;
while(keepRunning)
{
// Render
device->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
device->BeginScene();
// Rendering of scene objects happens here
// 1. Set the vertex decleration
// 2. Set the stream source
device->SetVertexDeclaration(vertexDecleration);
device->SetStreamSource(0, vertexBuffer, 0, sizeof(POSCOLORVERTEX));
device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
// End the scene
device->EndScene();
device->Present(0,0,0,0);
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if(msg.message == WM_QUIT) keepRunning = false;
else
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
}
vertexBuffer->Release();
vertexDecleration->Release();
device->Release();
d3d9->Release();
return msg.wParam;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
PostQuitMessage (0);
return (0);
}break;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}