Bitmap frustrations

Started by
9 comments, last by Turtlebread 22 years, 9 months ago
Ok, maybe someone new looking at this problem can help me out. I'm loading a bitmap with the following code, and then transfering it to a DDraw surface, and blitting it. The only problem is, there are blank lines on the image blted to the screen. I've narrowed it down to either the bitmap loader or the bitmap to surface function. The bitmap does not have any padding issues(its DWORD aligned) and I am converting to the right 16-bit mode. Heres the coder for the loader:
    
for(iHeight = spBitmap->infoheader.biHeight - 1; iHeight >=0; iHeight --){
   for(iWidth = 0; iWidth < spBitmap->infoheader.biWidth*2; iWidth += 2){
             //read in one pixel, converting it to either RGB 565 or 555 

             //and switching it from BGR to RGB

             file.get((char&)sTemp.blue);
	file.get((char&)sTemp.green);
	file.get((char&)sTemp.red);
	//convert the pixel to 16 bit

	wColor = Convert16(sTemp.red, sTemp.green, sTemp.blue);//Converts it to a 16-bit WORD value

	//store low-end of WORD

				
             spBitmap->buffer[iHeight*spBitmap->infoheader.biWidth+iWidth] = wColor & 0xFF;
             //The buffer is a BYTE buffer that IS big enough to hold everything

	//store high-end of WORD

	spBitmap->buffer[iHeight*spBitmap->infoheader.biWidth+iWidth + 1] = wColor>>8;
				
   }
}
  
And now heres the part that copies the bitmap from buffer to a surface.
  
             wBitmap_Buffer = (WORD*)spBitmap->buffer;//Again, BUFFER points to a BYTE buffer

	wScreen_Buffer = (WORD*)SurfaceDesc.lpSurface; //make the buffer valid

	//Now copy the bitmap to the newly locked surface

	for(y = 0; y < spBitmap->infoheader.biHeight; y++)
	{
		
		//copy the bitmap one line at a time

		memcpy((void*)wScreen_Buffer,
			   (void*)wBitmap_Buffer, 
			   spBitmap->infoheader.biWidth*2);
		//advance pointers

		wScreen_Buffer += SurfaceDesc.lPitch;
		wBitmap_Buffer += spBitmap->infoheader.biWidth;
	
	}
    
Any ideas at this point would be MUCH appreciated. I'm sick of staring at my screen trying to figure out whats wrong. -Chris EDIT: Fixed the formatting Edited by - Turtlebread on August 5, 2001 6:48:46 PM
Advertisement
When you say blank lines do you mean every other line is blank, or that just random lines are blank, or that the lines at the end are blank?

Hi Turtlebread,

I''ve found that the easiest thing to do is to use the loader that comes with the DirectX SDK. There is a function called DDLoadBitmap() in ddutil.h and .cpp that does just what you need. The ddutil files are in some of the sample directories. Just do a search for them and you should find them. Here''s the prototype:


IDirectDrawSurface7 *DDLoadBitmap(IDirectDraw7 *pdd, LPCSTR szBitmap, int dx, int dy);


If I remember correctly dx and dy are used to specify where the bitmap is to be put on the surface. So I put 0,0 it indicate the top left corner. It loads a bitmap from a file specified by szBitmap and puts it onto a surface, and returns a pointer to that surface. Once you have that pointer, you can use it to blt the bitmap to your backbuffer or whatever. Here''s how I used it in my code:


// load bitmap
if((myBitmap = DDLoadBitmap( ddObject, "mybitmap.bmp", 0, 0) ) != NULL )
log << "Bitmap loaded" << endl;
else
{
log << "ERROR: unable to load bitmap" << endl;
return false;
}

Anyway, hope that helps.
Its hard to explain what the .bmps look like when their blted. Heres an example of just a big purple square that I tried to BLT to the screen.

http://www.geocities.com/turtlebread/test2.jpg.


It seems like instead of blank space, its printing garabage values, like the surface is not getting totally written too. And I don't want to use a function to load a bitmap, I'm trying to create one myself, so I have some control over how it is loaded.

Thanks,
-Chris

EDIT: Link didn't work

Edited by - Turtlebread on August 5, 2001 8:35:03 PM
I don''t know what your exact problem is, but there is a differenct way that you could copy the bitmap. I have it in Object Pascal right now, and could convert it to C++, but the functions are windows functions, so you should get it. Oh yeah, and // denotes a comment, nil is null, := assigns variables, assigning Result to something is the same as returning something, and just ask if anything else baffles you.


function DXLoadBitmap(FDirectDraw: IDirectDraw7; const BitmapName: string;
Width, Height: integer): IDirectDrawSurface7;
var
Bitmap: HBitmap; //this is equal to a long int
BM: Windows.TBitmap; //this is equal to a TagBitmap, which is just the bitmap header info
SrfDC, SrcDC: HDC; //handles to device contexts
DDSurface: TDDSurfaceDesc2;//surface description
FSurface: IDirectDrawSurface7;//your surface
begin
// try to load the bitmap as a resource, if that fails, try it as a file
Bitmap:= LoadImage(GetModuleHandle(NIL), PChar(BitmapName),
IMAGE_BITMAP, Width, Height, LR_CREATEDIBSECTION);
try
if Bitmap = 0 then
Bitmap:= LoadImage(0, PChar(BitmapName), IMAGE_BITMAP, Width, Height,
LR_LOADFROMFILE or LR_CREATEDIBSECTION);
// get size of the bitmap
GetObject(Bitmap, SizeOf(BM), @BM);
SrcDC:= CreateCompatibleDC(0);
SelectObject(SrcDC, Bitmap);
FillChar(DDSurface, SizeOf(TDDSurfaceDesc2), 0);
DDSurface.dwSize := SizeOf(TDDSurfaceDesc2);
DDSurface.dwFlags := DDSD_CAPS or DDSD_HEIGHT or DDSD_WIDTH;
DDSurface.dwWidth := Width;
DDSurface.dwHeight := Height;
DDSurface.ddsCaps.dwCaps := DDSCAPS_OFFSCREENPLAIN;
FDirectDraw.CreateSurface(DDSurface, FSurface, nil);
FSurface.GetDC(SrfDC);
try
BitBlt(SrfDC, 0, 0, Width, Height, SrcDC, 0, 0, SRCCOPY);
finally
FSurface.ReleaseDC(SrfDC);
end;
finally
DeleteDC(SrcDC);
Result := FSurface;
if Bitmap <> 0 then DeleteObject(Bitmap);
end;
end;


It sounds to me like you are may be using an integer is being used somewhere where it shouldn''t. That''s just a guess though. Hope this helps.
Sorry that code didn''t indent right. Let me try this again.

function DXLoadBitmap(FDirectDraw: IDirectDraw7; const BitmapName: string;
Width, Height: integer): IDirectDrawSurface7;
var
Bitmap: HBitmap;
BM: Windows.TBitmap;
SrfDC, SrcDC: HDC;
DDSurface: TDDSurfaceDesc2;
FSurface: IDirectDrawSurface7;
begin
// try to load the bitmap as a resource, if that fails, try it as a file
Bitmap:= LoadImage(GetModuleHandle(NIL), PChar(BitmapName),
IMAGE_BITMAP, Width, Height, LR_CREATEDIBSECTION);
try
if Bitmap = 0 then
Bitmap:= LoadImage(0, PChar(BitmapName), IMAGE_BITMAP, Width, Height,
LR_LOADFROMFILE or LR_CREATEDIBSECTION);
// get size of the bitmap
GetObject(Bitmap, SizeOf(BM), @BM);
SrcDC:= CreateCompatibleDC(0);
SelectObject(SrcDC, Bitmap);
FillChar(DDSurface, SizeOf(TDDSurfaceDesc2), 0);
DDSurface.dwSize := SizeOf(TDDSurfaceDesc2);
DDSurface.dwFlags := DDSD_CAPS or DDSD_HEIGHT or DDSD_WIDTH;
DDSurface.dwWidth := Width;
DDSurface.dwHeight := Height;
DDSurface.ddsCaps.dwCaps := DDSCAPS_OFFSCREENPLAIN;
FDirectDraw.CreateSurface(DDSurface, FSurface, nil);
FSurface.GetDC(SrfDC);
try
BitBlt(SrfDC, 0, 0, Width, Height, SrcDC, 0, 0, SRCCOPY);
finally
FSurface.ReleaseDC(SrfDC);
end;
finally
DeleteDC(SrcDC);
Result := FSurface;
if Bitmap <> 0 then
DeleteObject(Bitmap);
end;
end;
Hmm...it seems another little problem has entered the game. Since I''m in 16-bit mode, I''m casting the lpSurface pointer to a WORD. To advance it, I''m adding lPitch to it. However, lPitch is the number of BYTES, and I''m using a WORD pointer. AHA! I thought, now I have it. I''ll just divide lPitch by 2 (16/8) However, it didn''t work. It is STILL showing up wrong, but this leads me to another question. What happens if lPitch is say, 41 bytes. 41/2 = 21.5. This would be very bad, as the WORD pointer couldn''t advance to the right spot. What happens in this situation? Is lPitch ALWAYS going to be even? If not, what happens if yer using a WORD pointer to the surface?

-Chris
Well I can''t really tell without a little more code, but one thing that seems off is your for statement. If you''re reading in a 24-bit bitmap (which it appears you are and then converting it to 16-bit), then the for statement would be...
  for(iWidth=0; iWidth<infoHeader.biWidth*3; iWidth+=3)  

This because there are three bytes, the R, G, and B values.
Working on: DoP
I''m reading in a pixel at a time though, so I should just run through the entire bitmap once. The only reason I''m adding two at a time is because of my BYTE buffer. Anyway, I''ve been running some test, and found out that it reads the first row of pixels fine, and then only the second half. For example, take a 4x4 bitmap
X X X X
0 0 X X
0 0 X X
0 0 X X

The X''s represent the pixels that appear on the screen of a 4x4 bitmap. The problem seems to be somewhere in the bitmap reading loop...Let me know if anyone sees a problem.

-Chris
Aha! It finally works. It was a combination of problems, including the fact I wasn''t taking into account the BYTE buffer addressing. Thanks to all who helped

-Chris

This topic is closed to new replies.

Advertisement