You need to lock the surface and then compute the offset into the surface or array.
DWORD offset=(y*Surface.MemPitch)+x;
DWORD value=Surface.lpBits[offset];
But to do this you must specify to DirectX that you want a backbuffer that is lockable. Otherwise this code will do nothing.
I will show you with my old Voxel terrain code.
This is a class that encapsulates some aspects of a very simple DirectX back buffer surface.
Code:
#ifndef BACKBUFFER
#define BACKBUFFER
#include <d3dx9.h>
#include "D3DError.h"
class CBackBuffer
{
protected:
IDirect3DDevice9 *Device;
IDirect3DSwapChain9 *SwapChain;
IDirect3DSurface9 *Surface;
D3DSURFACE_DESC BufferDesc;
D3DLOCKED_RECT BLRect;
void *Buffer;
int MemPitch;
public:
CBackBuffer(IDirect3DDevice9 *device);
int Pitch(void) {return MemPitch;};
int Width(void) {return BufferDesc.Width;};
int Height(void) {return BufferDesc.Height;};
void *Lock(void);
HRESULT Unlock();
};
#endif
Code:
#include "CBackBuffer.h"
#include <stdio.h>
CBackBuffer::CBackBuffer(IDirect3DDevice9 *device)
{
Device=device;
Device->GetSwapChain(0,&SwapChain);
SwapChain->GetBackBuffer(D3DADAPTER_DEFAULT,D3DBACKBUFFER_TYPE_MONO,&Surface);
if (!Surface) ::MessageBox(0,"GetBackBuffer Failed",0,0);
if FAILED(Surface->GetDesc(&BufferDesc)) ::MessageBox(0,"GetDesc Failed",0,0);
}
void *CBackBuffer::Lock(void)
{
D3DLOCKED_RECT lrect;
HRESULT hr;
hr=Surface->LockRect(&lrect,0,0);
if FAILED(hr)
{
char *text=D3DError::GetTextFromD3DError(hr);
::MessageBox(0,text,0,0);
return NULL;
}
MemPitch=lrect.Pitch>>2;
return lrect.pBits;
}
HRESULT CBackBuffer::Unlock(void)
{
HRESULT hr=Surface->UnlockRect();
return hr;
}
With this code you should be able to lock the surface and then write to or read from it.
But you don't need to do this to accomplish what that article is talking about.
To ease pain and suffering on your part, I would load the textures into memory using arrays. Then based on the height value, instead of choosing a color, choose an array to extract the actual texel RGBs from. So for a terrain with 6 different textures for heights, you would have 6 different arrays. After you create the final image, you can safely delete the 6 arrays because you don't need them anymore.
Now when you texture your quads you simply iterate through your terrain grid and set each vertex's u,v to correctly index into the texture you just created. The downside to this is that your terrain grid must be the same exact size as your texture size.
I would start by at least getting a flat grid of triangulated quads up and running. Then create simple terrain by displacing the Y component of each vertex either positively or negatively. Once you begin to see how this affects your overall terrain, then just load a greyscale bitmap into memory. All white is high, all black is low. Low means max positive displacement and high means max negative displacement. Iterate through the heightmap and extract the value from the array or heightmap. Set the current vertex Y to correspond with the grey scale color in the image.
It could be as simple as:
Code:
...
float fRatio=(float)HeightMap[offset]/(float)ucharMaxHeight;
float fHeight=255.0f*fRatio;
Vertex[vertexnum].x=XCoord;
Vertex[vertexnum].y=fHeight;
Vertex[vertexnum].z=ZCoord;
...
If you need more help, let me know and I'll explain further.