I'm trying to implement heightmaps for my engine however I'm having some troubles with bitmap loading code. The bitmap I'm trying to load is 8bit grayscale 250x250 pixels. I've attached the image of what it looks like. (Scroll all the way to the end).
The image on the left (in the debug window) is rendered using software, the image on the right is what the height map comes out to look like (I added the colors on purpose to make it clearer to see), that is rendered in hardware. The photoshop shows the original image and how it's meant to look. I'm not exactly sure where the error is, I'm thinking it's the loading function but it's so straight forward that I just can't find the mistake.
This is some relevant code:
Loading:
int Bitmap::LoadBitmapFromDisk(std::string szFileName)
{
// Open the bitmap file
HANDLE hFile = CreateFileA(szFileName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return 0;
// Read the bitmap file header
DWORD dwBytesRead;
BOOL bOK = ReadFile(hFile, &fileHeader, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL);
//see if the correct byte number was read and that it's actually a bitmap (bfType has to match)
if (!bOK || (dwBytesRead != sizeof(BITMAPFILEHEADER)) || (fileHeader.bfType != 0x4D42))
{
CloseHandle(hFile);
return 0;
}
// Read the bitmap info head
bOK = ReadFile(hFile, &infoHeader, sizeof(BITMAPINFOHEADER), &dwBytesRead, NULL);
if (!bOK || (dwBytesRead != sizeof(BITMAPINFOHEADER)))
{
CloseHandle(hFile);
return 0;
}
// Store the width and height of the bitmap
int m_iWidth = (int)infoHeader.biWidth;
int m_iHeight = (int)infoHeader.biHeight;
unsigned int sz;
SetFilePointer(hFile, fileHeader.bfOffBits, NULL, FILE_BEGIN);
data = (UCHAR*) new unsigned char[infoHeader.biSizeImage];
bOK = ReadFile(hFile, data, infoHeader.biSizeImage, &dwBytesRead, NULL);
//flip the bytes to little endian
if (infoHeader.biBitCount == 32)
{
DWORD* temp = (DWORD*)data;
for (int i = 0; i < infoHeader.biSizeImage / 4; i++)
{
//photoshop saves a,r,g,b into little endian b,g,r,a
//this engine is expecting r,g,b,a so all that's needed is to flip 1st and 3rd bytes
//be careful with this code if the image source program is working in r,g,b,a instead of a,r,g,b
char* byteMem = (char*)&temp[i];
char btemp = byteMem[0];
byteMem[0] = byteMem[2];
byteMem[2] = btemp;
}
}
if (bOK)
return 1;
// Something went wrong, so cleanup everything
return 0;
}
Software Render:
else if (byteCount == 1)
{
UCHAR* sourceStartMem = (UCHAR*)source->GetData();
DWORD* destStartMem = (texture_buffer)+(x1 + y1*lpitch32);
int numColumns = (x2 - x1);
int numRows = (y2 - y1);
for (int row = 0; row < numRows; row++)
{
for (int column = 0; column < numColumns; column++)
{
int r = sourceStartMem[column];
int g = sourceStartMem[column];
int b = sourceStartMem[column];
destStartMem[column] = _RGBA32BIT(r, g, b, 255);
//the RGBA macro is defined like this
//_RGBA32BIT(r, g, b, a) ( (r & 255) + ((g & 255) << 8) + ((b & 255) << 16) + ((a & 255) << 24) )
}
destStartMem += lpitch32;
sourceStartMem += image_width;
}
}
The generation of floor vertex buffer using the height map
//create the vertices
Vertex* floorMesh = new Vertex[dim.x*dim.y];
for (int xdim = 0; xdim < dim.x; xdim++)
{
for (int zdim = 0; zdim < dim.y; zdim++)
{
//height map is just a Bitmap class, GetData returns a UCHAR pointer to the raw pixel array
float height = heightMap.GetData()[xdim + zdim*dim.x];
float color = (height)/ 255.0f;
floorMesh[xdim + zdim*dim.x] = { XMFLOAT3((float)xdim, height , (float)zdim), XMFLOAT2(float(xdim)/dim.x, float(zdim)/dim.y) };
}
}