So far we have only built single triangles. Sometimes (such as in the last
lesson) we have gotten advanced and drawn two triangles, but they were not connected.
3D models are made out of many triangles connected together to form geometry.
In this lesson, we will cover how to build some simple geometry out of triangles,
and how to move them, rotate them and size them as a whole.
Quad, as we should all know, means four. In geometry, a quad is a four-sided
shape of any kind. The following are each quads.

Image 7.1 - Various Quads
Earlier I said that triangles make up all shapes in a 3D world. If you look
carefully, each of these quads is made up of two triangles placed side by side.

Image 7.2 - Quads Are Dual Triangles
As a matter of fact, this is true of all quads, regardless of shape. These
two triangles combined can make quite a variety of
useful shapes in game programming,
such as building terrain, walls, boxes, and any other shape with four sides.
The prime question is, how do you make them?
We are already familiar with
building triangles, so now let's look at how that code could be changed to draw
a square instead. First, let's look at the init_graphics() function we were
using earlier. This time, it has been changed to represent a quad, rather
than a triangle. Notice there are four points here. The changes, as
usual, are in bold.
// this is the function that puts the 3D models into video RAM
void init_graphics(void)
{
// create the vertices using the CUSTOMVERTEX struct
CUSTOMVERTEX t_vert[] =
{
{ -3.0f, 3.0f, 0.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.0f, 3.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -3.0f, -3.0f, 0.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, -3.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 255), },
};
// create a vertex buffer interface called t_buffer
d3ddev->CreateVertexBuffer(4*sizeof(CUSTOMVERTEX),
// change to 4, instead of 3
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&t_buffer,
NULL);
VOID* pVoid; // a void pointer
// lock t_buffer and load the vertices into it
t_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, t_vert, sizeof(t_vert));
t_buffer->Unlock();
return;
}
Now we have a full square in memory. Now how do we show it? Let's take
a look at the code that draws them from the render_frame() function.
d3ddev->SetStreamSource(0, t_buffer, 0, sizeof(CUSTOMVERTEX));
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
Of course, there is also code to set up the pipeline, but that isn't relevant here.
What is relevant is what is different about the DrawPrimitive() function.
Notice that the first parameter now says D3DPT_TRIANGLESTRIP rather than D3DPT_TRIANGLELIST.
Also notice that the third parameter was changed to a
2.
In case you are foggy on what each of these parameters do, the first parameter says
what kind of primitive is being drawn (see
Lesson 3), the second parameter says
what vertex in the buffer should be started with (0 is the first vertex), and the
third parameter says how many primitives should be drawn. In a triangle strip,
the primitives are triangles, so a 2 means show up to 2 triangles, and stop.
Well, that's the end of the vertex buffer anyway, but if we had put a 1 here, it
would have stopped at one triangle. This is illustrated here:

Image 7.3 - Making Triangles
And that's all there is to building a quad! Now let's combine our quads to
make a cube, our first 3D model!
Combining quads to make a cube is actually simple. If you haven't figured
it out yet, pause for a moment to think about how
you might go about it.
If you still can't think of it, take a look at this code. If you can
think of it, take a look at the code anyway, as building a cube in your head is
far more complex than it seems at first glance (unless you're a cyborg, in which
case you probably aren't reading a third of what I write anyhow).
This first piece of code is in the init_graphics() function:
// create the vertices using the CUSTOMVERTEX struct
CUSTOMVERTEX t_vert[] =
{
// side 1
{ -3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 255), },
// side 2
{ -3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 255), },
// side 3
{ -3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 255), },
// side 4
{ -3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 255), },
// side 5
{ 3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 255), },
// side 6
{ -3.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.0f, -3.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -3.0f, 3.0f, 3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ -3.0f, -3.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 255), },
};
// create a vertex buffer interface called t_buffer
d3ddev->CreateVertexBuffer(24*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&t_buffer,
NULL);
Notice that there is one quad for each side of the cube. Each set of four
vertices represents one quad.
Now how do we draw all this. It can't be one long triangle strip, because,
if you look, there are repeating vertices. In order to make things much simpler,
we split the cube into six quads, meaning that we have to draw them separately (or
the triangle strip would draw all over the place instead of in a straight cube,
try it out).
Anyway, here's how you draw multiple quads from the same vertex buffer.
d3ddev->SetStreamSource(0, t_buffer, 0, sizeof(CUSTOMVERTEX));
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 2);
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 8, 2);
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 12, 2);
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 16, 2);
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 20, 2);
If you put this into your program, you'll get a nice rotating cube (provided you
still have the right transforms there). Here's a picture of a cube I got with
one transform:

Image 7.4 - A Rotating Cube
Try building a cube of your own and spinning it in various ways.
Well, I don't know about you, but I'm really excited! We've built our first
3D object for real! Let's look at a couple more simple models we can make
using quads and triangles.
Let's look at how to build this shape.

Image 7.5 - A Square Pyramid
Here is the code for the vertex buffer:
// create the vertices using the CUSTOMVERTEX
struct CUSTOMVERTEX t_vert[] =
{
// base
{ -3.0f, 0.0f, 3.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -3.0f, 0.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.0f, 0.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.0f, 0.0f, -3.0f, D3DCOLOR_XRGB(0, 255, 255), },
// triangle 1
{ -3.0f, 0.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.0f, 0.0f, 3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 0.0f, 7.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
// triangle 2
{ 3.0f, 0.0f, 3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.0f, 0.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 0.0f, 7.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
// triangle 3
{ 3.0f, 0.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.0f, 0.0f, -3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 0.0f, 7.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
// triangle 4
{ -3.0f, 0.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.0f, 0.0f, 3.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 0.0f, 7.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
};
// create a vertex buffer interface called t_buffer
d3ddev->CreateVertexBuffer(16*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&t_buffer,
NULL);
And then to draw the shape:
d3ddev->SetStreamSource(0, t_buffer, 0, sizeof(CUSTOMVERTEX));
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); // base
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 1); // triangle 1
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 7, 1); // triangle 2
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 10, 1); // triangle 3
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 13, 1); // triangle 4
Take a moment to study how these commands differ from the cube's commands.
Now let's do something a little bit more exciting. We'll take a break from
boring geometry and get into some real stuff. Let's build a "Hypercraft",
which is a ship from the first 3D game I ever wrote (and I've used ever since).
Here's what this ship looks like:

Image 7.6 - The Hypercraft
Here's the code for the vertex buffer:
// create the vertices using the CUSTOMVERTEX
struct CUSTOMVERTEX t_vert[] =
{
// fuselage
{ 3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 0.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 0.0f, 0.0f, 10.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ -3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 255), },
// left gun
{ 3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0), },
// right gun
{ -3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0), },
// bottom of fuselage
{ 0.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 255), },
{ 0.0f, 0.0f, 10.0f, D3DCOLOR_XRGB(255, 0, 0), },
// opposite side of left gun
{ 3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0), },
// opposite side of right gun
{ -3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ -3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0), },
};
// create a vertex buffer interface called t_buffer
d3ddev->CreateVertexBuffer(20*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&t_buffer,
NULL);
And then to draw the shape:
d3ddev->SetStreamSource(0, t_buffer, 0, sizeof(CUSTOMVERTEX));
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); // fuselage
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 1); // left gun
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 7, 1); // right gun
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 10, 2); // bottom of
fuselage
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 14, 1); // other side
of left gun
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 17, 1); // other side
of right gun
And there you have it! We've got a functioning 3D model of a spaceship.
Admittedly it could improve a little on the aerodynamics, but we'll get there for
sure. For now, let's put in a rotation matrix and see what she looks like.
I chose to use the Hypercraft model for this demo. It rotates around much
like a car advertisement, only it looks somewhat more polygonal.
[
Show Code]
// include the basic windows header files and the Direct3D header file
#include <windows.h>
#include <windowsx.h>
#include <d3d9.h>
#include <d3dx9.h>
// define the screen resolution and keyboard macros
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
// include the Direct3D Library files
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")
// global declarations
LPDIRECT3D9 d3d; // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev; // the pointer to the device class
LPDIRECT3DVERTEXBUFFER9 t_buffer = NULL; // the pointer to the vertex
buffer
// function prototypes
void initD3D(HWND hWnd); // sets up and initializes Direct3D
void render_frame(void); // renders a single frame
void cleanD3D(void); // closes Direct3D and releases memory
void init_graphics(void); // 3D declarations
struct CUSTOMVERTEX {FLOAT X, Y, Z; DWORD COLOR;};
#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
hWnd = CreateWindowEx(NULL, L"WindowClass", L"Our Direct3D Program",
WS_EX_TOPMOST | WS_POPUP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
NULL, NULL, hInstance, NULL);
// set up and initialize Direct3D
initD3D(hWnd);
// enter the main loop:
MSG msg;
while(TRUE)
{
DWORD starting_point = GetTickCount();
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
render_frame();
// check the 'escape' key
if(KEY_DOWN(VK_ESCAPE))
PostMessage(hWnd, WM_DESTROY, 0, 0);
while ((GetTickCount() - starting_point) < 25);
}
// clean up DirectX and COM
cleanD3D();
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}
// this function initializes and prepares Direct3D for use
void initD3D(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = FALSE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
// create a device class using this information and the info from
the d3dpp stuct
d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev);
init_graphics(); // call the function to initialize the
Hypercraft
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE); //
turn off the 3D lighting
d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE); //
turn on the z-buffer
return;
}
// this is the function used to render a single frame
void render_frame(void)
{
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0),
1.0f, 0);
d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0,
0), 1.0f, 0);
d3ddev->BeginScene();
// select which vertex format we are using
d3ddev->SetFVF(CUSTOMFVF);
// set the view transform
D3DXMATRIX matView; // the view transform
matrix
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (0.0f, 8.0f, 25.0f), // the camera position
&D3DXVECTOR3 (0.0f, 0.0f, 0.0f),
// the look-at position
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // the up direction
d3ddev->SetTransform(D3DTS_VIEW, &matView); // set the view transform to matView
// set the projection transform
D3DXMATRIX matProjection; // the projection transform matrix
D3DXMatrixPerspectiveFovLH(&matProjection,
D3DXToRadian(45), // the horizontal field of view
(FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, // aspect ratio
1.0f, // the near view-plane
100.0f); // the far view-plane
d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection); // set the projection
// set the world transform
static float index = 0.0f; index+=0.03f; // an ever-increasing float value
D3DXMATRIX matRotateY;
// a matrix to store the rotation for each triangle
D3DXMatrixRotationY(&matRotateY, index);
// the rotation matrix
d3ddev->SetTransform(D3DTS_WORLD, &(matRotateY));
// set the world transform
// select the vertex buffer to display
d3ddev->SetStreamSource(0, t_buffer, 0, sizeof(CUSTOMVERTEX));
// draw the Hypercraft
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); // fuselage
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 1); // left gun
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 7, 1); // right gun
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 10, 2); // bottom of fuselage
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 14, 1); // other side of left gun
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 17, 1); // other side of right gun
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
return;
}
// this is the function that cleans up Direct3D and COM
void cleanD3D(void)
{
t_buffer->Release(); // close and release the
vertex buffer
d3ddev->Release(); // close and release the 3D device
d3d->Release(); // close and release Direct3D
return;
}
// this is the function that puts the 3D models into video RAM
void init_graphics(void)
{
// create the vertices using the CUSTOMVERTEX
struct CUSTOMVERTEX t_vert[] =
{
// fuselage
{ 3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 0.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 0.0f, 0.0f, 10.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ -3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 255), },
// left gun
{ 3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ 2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0), },
// right gun
{ -3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0), },
// bottom of fuselage
{ 0.0f, 3.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 0), },
{ -3.0f, 0.0f, 0.0f, D3DCOLOR_XRGB(0, 255, 255), },
{ 0.0f, 0.0f, 10.0f, D3DCOLOR_XRGB(255, 0, 0), },
// opposite side of left gun
{ 3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ 2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ 3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0), },
// opposite side of right gun
{ -3.2f, -1.0f, -3.0f, D3DCOLOR_XRGB(0, 0, 255), },
{ -2.0f, 1.0f, 2.0f, D3DCOLOR_XRGB(255, 0, 0), },
{ -3.2f, -1.0f, 11.0f, D3DCOLOR_XRGB(0, 255, 0), },
};
// create a vertex buffer interface called t_buffer
d3ddev->CreateVertexBuffer(20*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&t_buffer,
NULL);
VOID* pVoid; // a void pointer
// lock t_buffer and load the vertices into it
t_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, t_vert, sizeof(t_vert));
t_buffer->Unlock();
return;
}
Run the code, and see the family vehicle of the future! Well, maybe the virtual
future. Well, maybe not...

Image 7.7 - The Hypercraft In Action
Wow! Now we are getting somewhere with 3D! Get good at everything up
to this point, and then let's move on and make the Hypercraft look decent with
some cool-looking textures. In the meantime, try doing these exercises:
1. Make a square
2. Make a triangular pyramid
3. Draw 20 copies of your triangular pyramid on the screen at once
4. Add a tail fin in the back of the Hypercraft
5. Design and build your own mini-spaceship
Now let's get on to textures! Let's make this Hypercraft look cool!
Next Lesson: Adding Textures
GO! GO! GO!
© 2006-2009 DirectXTutorial.com. All Rights Reserved.