This tutorial will show the easiest way to implement the bare minimum of 3D engine features. It is a good way to get started with Direct3D, and you can add complexity to the things you learn here as you get more familiar with DirectX. The tutorial has sections on initializing, textures, lighting, matrices, drawing, and uninitializing Direct3D. It will show the most necessary features of the functions it explains, and will leave out the unneeded complexities. Initializing
There are two options for initializing Direct3D, the easy way and the hard way. The easy way involves three functions. D3DXInitialize()
D3DXInitialize() is called before anything else. It has no parameters, so you don't need any explanation.D3DXCreateContext( DWORD deviceIndex, DWORD flags, HWND hwnd, DWORD width, DWORD height, LPD3DXCONTEXT* ppCtx);
The above function creates a window to the Direct3D world. You can see everything through it, but it shields you from some awful things. deviceIndex
This specifies hardware and software devices, you could enumerate them all. But I recommend you specify D3DX_DEFAULT, and let it decide for you. flags
This is to select fullscreen mode, or windowed mode. hwnd
D3DX_CONTEXT_FULLSCREEN - fullscreen
0 - windowed
This is the only confusing part. When your application first starts, it creates a window. When it creates a window, it returns the handle of the window. This is what Direct3D wants. You don't need to specify an hwnd if it is windowed mode. width, height
These should be obvious. These are the width and height of the window in pixels. In windowed mode these can be anything, but in fullscreen they have to match with certain allowable resolutions. You could enumerate the resolutions, or just try standard ones like 640x480 or 800x600 ppCtx
This is a pointer to a LPD3DXCONTEXT variable. You give it the pointer and it fills it with a valid D3DXCONTEXT. This is what you want from the function and you should save this variable somewhere. It is your gateway to the screen. ID3DXContext::GetD3DDevice()
This function is called to get an interface to the 3d world. Just ask your D3DXCONTEXT, and it will give you a pointer to a IDirect3DDevice7 object. Save this pointer for later use.
This is all for initialization. All of the DirectX functions return a nonzero number if they have an error, and you can get a text description of the error by calling D3DXGetErrorString( int error, int string length, char *pointer to string ). Textures
Loading textures into memory is rather easy with the Utility Library.D3DXCreateTextureFromFile( LPDIRECT3DDEVICE7 pd3dDevice,
LPDWORD pFlags, LPDWORD pWidth,
D3DX_SURFACEFORMAT* pPixelFormat, LPDIRECTDRAWPALETTE pDDPal,
D3DX_FILTERTYPE filterType pd3dDevice
This is the pointer to the to the Direct3dDevice that we got in the initialization. pFlags
Don't bother with this. pWidth, pHeight
Width and heigh in pixels that you want, if you specify D3DX_DEFAULT the width and height will be taken from the file. pPixelFormat
Pass zero as a parameter and DirectX will automatically decide which pixel format to use. pDDPal
Pass zero as a parameter and DirectX will automatically decide which pallete to use ppTexture
This is a pointer to a LPDIRECTDRAWSURFACE7 variable. The function fills this with a pointer to the texture. pNumMipsMaps
This is the number of mipmaps it ends up creating, mipmaps are used for accellerating drawing by using different size images. pSrcName
This is the name of the file you want to load. It can either be a BMP, DIB, or DDS file. filterType
This is related to mipmaps, I would just use D3DX_FT_DEFAULT for default.
This is the only function you need to load a texture. Just remember to save the pointer to the texture that it gives you. Lighting
Until now, many people did all the lighting they needed themselves. But now there is hardware accelerated lighting. If you let DirectX take care of the lighting, it will take full advantage of accellerations.
There are two functions used for lighting- D3DDevice::SetLight(int index, LPD3DLIGHT7 light);
This function sets the characteristics of a light. index
This is the zero base index of the light you want to set. If there is already a light at that index, its properties will be changed. light
This is a pointer to a D3DLIGHT7 structure. The important members of the D3DLIGHT7 structure are. D3DLIGHTTYPE dltType D3DDevice::LightEnable(int index, BOOL state);
This can be a point light, spotlight, or directional light. (D3DLIGHT_POINT, D3DLIGHT_SPOT, D3DLIGHT_DIRECTIONAL) D3DCOLORVALUE dcvDiffuse, dcvSpecular, dcvAmbient
These are the diffuse (general), specular (shiny), and ambient (all around) components of the light. The D3DCOLORVALUE structure has r, g, and b (red, green, blue) components. They are floats from zero to one, with one being full light. D3DVECTOR dvPosition
This is the center of the light, its source. The D3DVECTOR structure has an x, y, and z component. D3DVECTOR dvDirection
The light's direction is a vector, with an x, y and z component. float dvRange
This is the distance before the light no longer affects and object. float dvFalloff
This is how much dimmer the light gets with an increasing angle from its direction. float dvTheta
This is the angle (in radians) to the edge of the light cone.
After the light properties are set, LightEnable() is called. The index is the index of the light you just set, and the state is set to true or false ( true for on). Matrices
The camera and world orientation need to be set.
D3Device::SetTransform( D3DTRANSFORMSTATETYPE TransformState, LPD3DMATRIX Matrix)
The TransformState specifies which matrix is being set, use D3DTRANSFORMSTATE_WORLD to set the world matrix, and D3DTRANSFORMSTATE_VIEW to set the camera matrix.
If you don't know how matrices work, I would recommend more reading at the GameDev.net reference section.
You can use your own matrix code, or use the D3DXMatrixStack which is explained in the DirectX help. Drawing
All drawing uses the DrawPrimitive() function. If you want to draw something with a certain texture on it, first call the D3DDevice::SetTexture() function. Before drawing call D3DDevice::BeginScene() and after drawing call EndScene(), and use DXContext::UpdateFrame() to show your picture. D3DDevice::SetTexture(int stage, LPDIRECTDRAWSURFACE7 Texture)
The stage should be set to zero unless you plan on doing complex texture blending which you probably shouldn't be doing yet if you are reading this tutorial. The Texture pointer should be the pointer that was retrieved in the texture section of this tutorial.
To clear the screen use the DXContext::Clear() method with D3DCLEAR_TARGET and D3DCLEAR_ZBUFFER as arguments.DrawPrimitive( D3DPRIMITIVETYPE PrimitiveType,
DWORD Flags) PrimitiveType
This tells DirectX what to draw. The three most common types are point list, line list, and triangle list. ( D3DPT_POINTLIST, 3DPT_LINELIST, D3DPT_TRIANGLELIST )
This explains what type of data you are passing to the functions. The type you will probably use is D3DFVF_VERTEX. This type has an x, y, and z, a normal, and texture coordinates. Texture coordinates are float values from zero to one, (0,0) is the upper left corner of the texture.
This is a pointer to the list of vertices being drawn. To draw one triangle with vertices v1, v2, v3. The list would have the point v1 followed by v2 followed by v3.
This is the number of vertices in the above list.
Threre aren't any flags that are absolutely necessary to explain. Uninitializing
For any textures you made, and the D3DXContext you retrieved, call their Release() function. Then call D3DXUninitialize(), and you're done.