Archived

This topic is now archived and is closed to further replies.

Daishim

16Bit Bitmap Load/Conversion Woes.

Recommended Posts

I'm working on a Bitmap loading wrapper and I've got 8bit images working like a champ, but when I try to convert an image from 24bit to 16 bit, for some reason I'm only seeing half the image, width wise (ie 320x480 of a 640x480 image). I checked all the height and width values and they all appear correct... the code is below, am I missing something or is my conversion code maybe skrewed up somehow? I checked the blitting code and I even manually set them to 640x480 and it didn't affect it. I think that the error is in the conversion code, because I can read the file and then immediatly dump that memory to another file and it's a perfect duplicate image, the distortion comes after the load from disk, the conversion. Atleast that's where I think it's happening. And I know that test1.bmp is really a 24bit bitmap. Grrrr...
// Just some variable and function information
#define CONVERT24TO16(Red,Green,Blue) ((Blue%32) + ((Green%64) << 6) + ((Red%32) << 11))

////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////

class BITMAPFILE
{
	BITMAPFILEHEADER BitmapHeader;
	BITMAPINFO BitmapInfo;

	UCHAR *ImageBits8;
	USHORT *ImageBits16;
	UINT *ImageBits32;

	PALETTEENTRY Palette[256];

	void Flip();

	public:
		BITMAPFILE();
		~BITMAPFILE();

		BITMAPFILEHEADER *GetBitmapFileHeader();

		BITMAPINFO *GetBitmapInfo();

		const UCHAR *GetBits8();
		const USHORT *GetBits16();
		const UINT *GetBits32();

		PALETTEENTRY *GetPalette();

		bool Load(LPSTR FileNameToLoad);
		void Unload();

		bool CopyToDDSurface(BITMAPDDRAWDATA *DDraw);

};

////////////////////////////////////////////////
////////////////////////////////////////////////
////////////////////////////////////////////////

struct BITMAPDDRAWDATA
{
	LPDIRECTDRAW7 DirectDraw;
	LPDIRECTDRAWSURFACE7 DestinationSurface;
	LPDDSURFACEDESC2 DestinationSurfaceDesc;
	LPDIRECTDRAWPALETTE *DestinationSurfacePalette;

};

// This is the loading from the disc code
bool BITMAPFILE::Load(LPSTR FileNameToLoad)
{
	ifstream fin(FileNameToLoad, ios::binary);

	if(!fin)
	{
		return false;

	}

	fin.read((char *) &BitmapHeader, sizeof(BITMAPFILEHEADER));

	if(BitmapHeader.bfType != 0x4D42)
	{
		fin.close();

		return false;

	}

	fin.read((char *) &BitmapInfo.bmiHeader, sizeof(BITMAPINFOHEADER));

	switch(BitmapInfo.bmiHeader.biBitCount)
	{
		case 8:
			{
				fin.read((char *) &Palette, (256 * sizeof(PALETTEENTRY)));

				for(int i = 0; i < 255; i++)
				{
					int TempColor = Palette.peRed;

					Palette[i].peRed = Palette[i].peBlue;
					Palette[i].peBlue = TempColor;

					Palette[i].peFlags = PC_NOCOLLAPSE;

				}

				if(ImageBits8 != NULL)
				{	
					free(ImageBits8);

				}

				if(!(ImageBits8 = (UCHAR *) malloc(BitmapInfo.bmiHeader.biSizeImage)))
				{
					fin.close();

					return false;

				}

				fin.read((char *) ImageBits8, BitmapInfo.bmiHeader.biSizeImage);

				if(BitmapInfo.bmiHeader.biHeight > 0)
				{
					Flip();

				}

				break;

			}

		case 24:
			{
				UCHAR *ImageBuffer = (UCHAR *) malloc(BitmapInfo.bmiHeader.biSizeImage);

				if(ImageBits16 != NULL)
				{
					free(ImageBits16);

				}

				if(!(ImageBits16 = (USHORT *) malloc(BitmapInfo.bmiHeader.biSizeImage)))
				{
					fin.close();

					return false;

				}

				fin.read((char *) ImageBuffer, BitmapInfo.bmiHeader.biSizeImage);

				for(int y = 0; y < BitmapInfo.bmiHeader.biHeight; y++)
				{
					for(int x = 0; x < BitmapInfo.bmiHeader.biWidth; x++)
					{
						UCHAR Blue = (ImageBuffer[((x * 3) + y * BitmapInfo.bmiHeader.biWidth * 3) + 0]) >> 3;
						UCHAR Green = (ImageBuffer[(x * 3) + (y * BitmapInfo.bmiHeader.biWidth * 3) + 1]) >> 3;
						UCHAR Red = (ImageBuffer[(x * 3) + (y * BitmapInfo.bmiHeader.biWidth * 3) + 2]) >> 3;

						USHORT TempPixel = CONVERT24TO16(Red, Green, Blue);

						ImageBits16[x + (y * BitmapInfo.bmiHeader.biWidth >> 1)] = TempPixel;

					}

				}

				free(ImageBuffer);

				ImageBuffer = NULL;
				
				break;

			}

		default:
			{

				break;

			}

	}

	fin.close();
	
	return true;
}

// And here is the copy to DirectDraw Surface code

bool BITMAPFILE::CopyToDDSurface(BITMAPDDRAWDATA *DDraw)
{
	int GraphicWidth = BitmapInfo.bmiHeader.biWidth;
	int GraphicHeight = BitmapInfo.bmiHeader.biHeight;

	if(FAILED(DDraw->DestinationSurface->Lock(NULL, DDraw->DestinationSurfaceDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL)))
	{
		return false;

	}

	switch(BitmapInfo.bmiHeader.biBitCount)
	{
		case 8:
			{
				UCHAR *DDSurface = (UCHAR *) DDraw->DestinationSurfaceDesc->lpSurface;
				const UCHAR *BitmapSurface = ImageBits8;

				for(int y = 0; y < GraphicHeight; y++)
				{
					memcpy((void *) DDSurface, (void *) BitmapSurface, GraphicWidth);

					DDSurface += DDraw->DestinationSurfaceDesc->lPitch;
					BitmapSurface += GraphicWidth;

				}

				DDraw->DestinationSurface->Unlock(NULL);

				if(FAILED(DDraw->DirectDraw->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE, Palette, DDraw->DestinationSurfacePalette, NULL)))
				{
					return false;

				}

				if(FAILED(DDraw->DestinationSurface->SetPalette(*DDraw->DestinationSurfacePalette)))
				{
					return false;

				}

				DDSurface = NULL;
				BitmapSurface = NULL;

				break;

			}

		case 24:
			{
				USHORT *DDSurface = (USHORT *) DDraw->DestinationSurfaceDesc->lpSurface;
				const USHORT *BitmapSurface = ImageBits16;

				for(int y = 0; y < GraphicHeight; y++)
				{
					memcpy((void *) DDSurface, (void *) BitmapSurface, GraphicWidth);

					DDSurface += DDraw->DestinationSurfaceDesc->lPitch;
					BitmapSurface += GraphicWidth;

				}

				DDraw->DestinationSurface->Unlock(NULL);

				DDSurface = NULL;
				BitmapSurface = NULL;

				break;

			}

	}

	return true;

}

// DirectDraw Init stuff
bool VIDEO::Initialize()
{
	FullScreen = true;

	ZeroMemory(&ScreenSurfaceDesc, sizeof(DDSURFACEDESC2));
	ZeroMemory(&BufferSurfaceDesc, sizeof(DDSURFACEDESC2));
	ZeroMemory(&ImageSurfaceDesc, sizeof(DDSURFACEDESC2));

	if(FAILED(DirectDrawCreateEx(NULL, (LPVOID *) &DirectDraw7, IID_IDirectDraw7, NULL)))
	{
		return false;

	}

	if(FullScreen)
	{
		if(FAILED(DirectDraw7->SetCooperativeLevel(hMainWindow, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT)))
		{
			return false;

		}

		if(FAILED(DirectDraw7->SetDisplayMode(640, 480, 16, NULL, NULL)))
		{
			return false;

		}

		ScreenSurfaceDesc.dwSize = sizeof(DDSURFACEDESC2);

		ScreenSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;

		ScreenSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;

		ScreenSurfaceDesc.dwBackBufferCount = 1;

		if(FAILED(DirectDraw7->CreateSurface(&ScreenSurfaceDesc, &ScreenSurface, NULL)))
		{
			return false;

		}

		BufferSurfaceDesc = ScreenSurfaceDesc;

		BufferSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;

		if(FAILED(ScreenSurface->GetAttachedSurface(&BufferSurfaceDesc.ddsCaps, &BufferSurface)))
		{
			return false;

		}

	}
	else
	{
		if(FAILED(DirectDraw7->SetCooperativeLevel(hMainWindow, DDSCL_NORMAL)))
		{
			 return false;

		}

		ScreenSurfaceDesc.dwSize = sizeof(DDSURFACEDESC2);

		ScreenSurfaceDesc.dwFlags = DDSD_CAPS;

		ScreenSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

		if(FAILED(DirectDraw7->CreateSurface(&ScreenSurfaceDesc, &ScreenSurface, NULL)))
		{
			return false;

		}

		BufferSurfaceDesc.dwSize = sizeof(DDSURFACEDESC2);

		BufferSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;

		BufferSurfaceDesc.dwWidth = 640;
		BufferSurfaceDesc.dwHeight = 480;

		BufferSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;

		if(FAILED(DirectDraw7->CreateSurface(&BufferSurfaceDesc, &BufferSurface, NULL)))
		{
			return false;

		}

	}

	// Load Bitmap Code //

	BITMAPFILE NewImage;
	BITMAPDDRAWDATA DDrawInfo;
	
	if(!NewImage.Load("test1.bmp"))
	{
		return false;

	}

	ImageSurfaceDesc.dwSize = sizeof(DDSURFACEDESC2);
	
	ImageSurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;

	ImageSurfaceDesc.dwHeight = NewImage.GetBitmapInfo()->bmiHeader.biHeight;
	ImageSurfaceDesc.dwWidth = NewImage.GetBitmapInfo()->bmiHeader.biWidth;

	ImageSurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;

	if(FAILED(DirectDraw7->CreateSurface(&ImageSurfaceDesc, &ImageSurface, NULL)))
	{
		return false;

	}

	DDrawInfo.DestinationSurface = ImageSurface;
	DDrawInfo.DestinationSurfaceDesc = &ImageSurfaceDesc;
	DDrawInfo.DestinationSurfacePalette = &GraphicsPalette;
	DDrawInfo.DirectDraw = DirectDraw7;

	if(!NewImage.CopyToDDSurface(&DDrawInfo))
	{
		return false;

	}

	ScreenSurface->SetPalette(GraphicsPalette);

	NewImage.Unload();

	// End Load Bitmap Code //

	return true;

}

// DirectDraw Render

void VIDEO::Render()
{
	RECT Source;
	RECT Window;
	
	ZeroMemory(&Window, sizeof(RECT));
	ZeroMemory(&Source, sizeof(RECT));

	Source.right = ImageSurfaceDesc.dwWidth;
	Source.bottom = ImageSurfaceDesc.dwHeight;

	GetWindowRect(hMainWindow, &Window);

	BufferSurface->BltFast(0, 0, ImageSurface, &Source, DDBLTFAST_WAIT);

	if(!FullScreen)
	{
		ScreenSurface->BltFast(Window.left, Window.top, BufferSurface, &Source, DDBLTFAST_WAIT);

	}
	else
	{
		ScreenSurface->Flip(BufferSurface, NULL);

	}

}

 
I know that the 24bit images don't get flipped yet, I'm just trying to have the whole image to flip, but I don't think this could affect it in any way. Any ideas, guesses, random stabs into darkness? ... I'm pulling my hair out over this. [edited by - Daishi on August 9, 2003 2:46:23 AM]

Share this post


Link to post
Share on other sites
I haven''t tried to compile and run, but i see the line

ImageBits16[x + (y * BitmapInfo.bmiHeader.biWidth >> 1)] = TempPixel;

should probably be

ImageBits16[x + (y * BitmapInfo.bmiHeader.biWidth)] = TempPixel;

since ImageBits16 is a USHORT pointer already, so no need to half the line offset.

Share this post


Link to post
Share on other sites
I had tried that before, and I tried again, but when I remove the shift then the image is stretched height wise so that I only see the top-left quarter of the image...

Share this post


Link to post
Share on other sites
Another weird thing is... if I shift the x in the same line as well as the width then the entire width of the image will appear, just in half the screen, so it''s scrunched up on the left half of the screen.

Share this post


Link to post
Share on other sites
remove that shift plus
change those lines in

CopyToDDSurface:

memcpy((void *) DDSurface, (void *) BitmapSurface, GraphicWidth);

to

memcpy((void *) DDSurface, (void *) BitmapSurface, GraphicWidth * 2);

// You''re copying USHORTs now, hence *2

and:

BitmapSurface += GraphicWidth;

to

BitmapSurface += GraphicWidth * 2;

// dito


I hope this time i saw it all

Share this post


Link to post
Share on other sites
::sigh::
You're right it makes sense, but I get a memory error now and nothing gets copied. Does anyone have working code to convert a 24 bit bitmap to a 16 bit bitmap that I could take a look at to see where I'm going off course?

I'm using Tricks of the Windows Game Programming Gurus to do this, but the examples don't work either.

[edited by - Daishi on August 10, 2003 1:20:22 PM]

Share this post


Link to post
Share on other sites
Well, I can get the examples to compile and work now. So I know there isn''t anything wrong with my hardware or anything else. I think I''ve just got some pointer errors. I''m not sure, I''m going to have to create a seperate workspace and throw everything together like the examples and start moving things into functions and see where things go astray, and then I should have my answer. The link to that thread helped a lot, thanks, I don''t know how I missed that one.

Share this post


Link to post
Share on other sites