Click to See Complete Forum and Search --> : TransparentBlt problem..


lakis
July 30th, 2005, 11:35 AM
Hello ppl,
here's one more weird problem for me :) I'm creating a CSprite class and have included a Draw function like :

[code]
void DrawBitmap(int xDest,int yDest,bool IsTransparent,COLORREF TransparentColor,int xSource=0, int ySource=0); // function declaration

void CSprite::DrawBitmap(int xDest,int yDest,bool IsTransparent,COLORREF TransparentColor,int xSource, int ySource)
{
if (IsTransparent)
TransparentBlt(m_hDC,xDest,yDest,GetBitmapWidth(),GetBitmapHeight(),m_MemDC,xSource,ySource,GetBitmapWidth(),GetBitmapHeight(),TransparentColor);
else
BitBlt(m_hDC,xDest,yDest,GetBitmapWidth(),GetBitmapHeight(),m_MemDC,xSource,ySource,SRCCOPY);
}
[\code]

The problem lies in the predefined parameters xSource and YSource.Whenever i do sth like :

Sprite->DrawBitmap(0,0,true,RGB(0,0,0));

The sprite is shown properly,but whenever i change it to (for example):

Sprite->DrawBitmap(0,0,true,RGB(0,0,0),100,100);

The result is that the bitmap is not drawn at all.I suppose that this has probably have something to do with TransparentBlt,but does anyone have more info or any suggestions about that ? Thanx for reading anyway ;)

Smasher/Devourer
July 30th, 2005, 01:54 PM
I suspect that this may have something to do with the fact that you're not altering the size of the region to blit, regardless of the position specified in (xSource, ySource). For example, if you have a bitmap that is 400x300 pixels and you call DrawBitmap like so:
Sprite->DrawBitmap(0, 0, true, RGB(0, 0, 0));
then you're telling the function to copy the region of the source image from (0, 0) to (400, 300) to the position (0, 0) on the destination device context. But if you call it like so:
Sprite->DrawBitmap(0, 0, true, RGB(0, 0, 0), 100, 100);
then you're telling the function to copy the region of the source image from (100, 100) to (500, 400) instead. Obviously this region extends beyond the boundaries of your bitmap and is thus invalid. Having never used TransparentBlt(), I'm not sure whether the intended behavior is just to copy that part of the region that does exist, or to fail, but the latter seems likely. If this turn out to be the case, then either allow the user to specify the size of the region to copy in the function's argument list, or rewrite the function to compute it automatically. For example:
void CSprite::DrawBitmap(int xDest, int yDest, bool IsTransparent, COLORREF TransparentColor, int xSource, int ySource)
{
int xSize = GetBitmapWidth() - xSource;
int ySize = GetBitmapHeight() - ySource;

if (IsTransparent)
TransparentBlt(m_hDC, xDest, yDest, xSize, ySize, m_MemDC, xSource, ySource, xSize, ySize, TransparentColor);
else
BitBlt(m_hDC, xDest, yDest, xSize, ySize, m_MemDC, xSource, ySource, SRCCOPY);
}
If this doesn't fix the problem, then call GetLastError() after the call to TransparentBlt() fails and post the error code that you're getting. That should give you some clue as to what's going wrong.

Also, for future reference, please wrap your code in ... tags to make it more readable. ;)

miteshpandey
July 30th, 2005, 01:55 PM
Sprite->DrawBitmap(0,0,true,RGB(0,0,0),100,100);


What's the dimension of your bitmap or MemDC?

If it is less than (100, 100) you will not get any image drawn.

lakis
July 31st, 2005, 06:33 PM
Thanx for the quick answers Smasher and Miteshpandey,

@Smasher:

Oops,i have used the wrong tag in closing the code tag before :) To be sincere i haven't thought of that Smasher.I thought that xSource and ySource are just parameters to indicate the starting positions of the source rectangle to be copied to the destination one.I could only imagine that if the destination rectangle is smaller than the source one,then this could be a problem.This does not seem to be the case since :

Sprite->DrawBitmap(0,0,false,RGB(0,0,0),100,100);

works pretty well.This is why i believe that there's a possible problem in

TransparentBlt.BitBlt works well with the same input.Once more,the function is this one(in tags this time :)):



void CSprite::DrawBitmap(int xDest,int yDest,bool IsTransparent,COLORREF TransparentColor,int xSource, int ySource)
{
if (IsTransparent)
TransparentBlt(m_hDC,xDest,yDest,GetBitmapWidth(),GetBitmapHeight(),m_MemDC,xSource,ySource,GetBitmapWidth(),GetBitmapHeight(),TransparentColor);
else
BitBlt(m_hDC,xDest,yDest,GetBitmapWidth(),GetBitmapHeight(),m_MemDC,xSource,ySource,SRCCOPY);
}




@Miteshpandey:

No,this is certainly not the problem.The dimension is about 300x400 and even if the call is like :

Sprite->DrawBitmap(0,0,true,RGB(0,0,0),1,1);

It still doesn't work..

Smasher/Devourer
July 31st, 2005, 07:12 PM
lakis, did you even try the solution I suggested? Your second post makes it sound as though you've dismissed it without even giving it a try, yet I tried some code myself just now and found that my last post seems to be correct. If I try a TransparentBlt() with an image using (0, 0) as the source location and the bitmap's size (x, y) as the dimensions, the blit succeeds. But if I try the same with the location (1, 1) and the dimensions (x, y), the blit fails, and GetLastError() yields error code 87, ERROR_INVALID_PARAMETER.

lakis
July 31st, 2005, 08:09 PM
Hmm,it seems that i didn't really pay attention at how the parameters in xSource and ySource work in TransparentBlt now that i read your second post.You're right.In fact,my wrong assumption is that the source and destination rectangles should be the same.But if they are the same and i try to move it by x,y units,then it exceeds the boundary,that's what you said,correct ?

To be sincere i didn't really try what you say but for a reason i thought was important.The reason why i didn't try it was that if the call to the function is like :

Sprite->DrawBitmap(0,0,false,RGB(0,0,0),100,100);

the result is a bitmap drawn in the window in which the source rectangle is fit to the destination one by 100 units distance to the x axis and 100 to the y axis just like as i wanted it to be.So,BitBlt works fine here even though the bitmap dimensions are (x,y) and the source x,y are (100,100) as shown in the code below:

BitBlt(m_hDC,xDest,yDest,GetBitmapWidth(),GetBitmapHeight(),m_MemDC,xSource,ySource,SRCCOPY);

So,i thought that TransparentBlt should work in the same way,but as you spotted they are somehow different :/
Sorry to not have tried your proposal before but sometimes the brain gets stuck in false primitive ideas :) I think i now fully understood what you said ;)
Thanx again !

P.S.
Btw,i'm wondering why the same does not happen in BitBlt.Is it because the width and height of the source rectangle are not provided and are computed by the function itself ?

Smasher/Devourer
July 31st, 2005, 09:07 PM
P.S.
Btw,i'm wondering why the same does not happen in BitBlt.Is it because the width and height of the source rectangle are not provided and are computed by the function itself ?
That sounds like the most likely reason. Though, it would certainly be possible for Microsoft to implement TransparentBlt() so that it behaves in a way similar to BitBlt() when a region is given the extends beyond the boundaries of the source image, so anything I could say about their reasons would only be conjecture. I guess it just goes to show that you can't assume an unfamiliar bit of code will behave one way or another, even if your assumptions seem reasonable; you either need to find an answer in the documentation, or try it yourself. ;)

Speaking of documentation, the MSDN entry (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_2y9g.asp) for TransparentBlt() says that on Windows 95/98, it contains a memory leak that can exhaust system resources. If you're not concerned with Windows 9x then you don't need to worry about that, but in case you're working with those old versions of Windows, you should probably be aware of this. There's an MSDN article here (http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B79212) that covers an alternative (and unfortunately more cumbersome) technique, and a CodeGuru thread here (http://www.codeguru.com/forum/showthread.php?t=346808) which discusses the various approaches to this problem.

lakis
August 1st, 2005, 07:23 AM
That sounds like the most likely reason. Though, it would certainly be possible for Microsoft to implement TransparentBlt() so that it behaves in a way similar to BitBlt() when a region is given the extends beyond the boundaries of the source image, so anything I could say about their reasons would only be conjecture. I guess it just goes to show that you can't assume an unfamiliar bit of code will behave one way or another, even if your assumptions seem reasonable; you either need to find an answer in the documentation, or try it yourself.

Yes,you're definately right about that,instincts alone are not enough against the microsoft API :) I should have been aware of that,but the mind plays weird games sometimes ;)

Speaking of documentation, the MSDN entry for TransparentBlt() says that on Windows 95/98, it contains a memory leak that can exhaust system resources. If you're not concerned with Windows 9x then you don't need to worry about that, but in case you're working with those old versions of Windows, you should probably be aware of this. There's an MSDN article here that covers an alternative (and unfortunately more cumbersome) technique, and a CodeGuru thread here which discusses the various approaches to this problem.

Yes,i'm aware of that and my first attempt was to code that according to the masking technique.Since the class is meant to be part of a small game engine and i'm doing the whole work with a friend,i decided to keep it simple for now and maybe enhance it in the future.Btw,i've read that in Win98(though i can't test at the time),there does not happen a mem leak,but only on Win95.If that is really the case,i probably wouldn't mind changing it at all.
(Btw,pretty disturbing all those OS incompatibilities.The same thing applied when i created a region creator.I had to scan every pixel of the bitmap,though there's a great function to do that in winnt and above..)

miteshpandey
August 1st, 2005, 01:33 PM
I think Smasher/Devourer is absolutely correct.

You need to adjust the size passed into the TransparentBlt as described by Smasher/devourer.

I think the BitBlit uses the same technique to calcualate the size of the source.

I don't know why it was left out as a task to do by the programmers in the TransparentBlt.

lakis
August 5th, 2005, 09:55 AM
I don't know why it was left out as a task to do by the programmers in the TransparentBlt.

It seems that TransparentBlt is a simulation of StretchBlt where an alpha value can be given.So,these values are left to the programmer in case he would want to stretch the bitmap i think.Of course,Smasher is correct at what he said.I tried it and worked great ;)

miteshpandey
August 5th, 2005, 02:28 PM
As far as I understand only the destination rectangle is responsible for stretching.


void CSprite::DrawBitmap(int xDest, int yDest, bool IsTransparent, COLORREF TransparentColor, int xSource, int ySource)
{
int xSize = GetBitmapWidth() - xSource;
int ySize = GetBitmapHeight() - ySource;

if (IsTransparent)
TransparentBlt(m_hDC, xDest, yDest, xSize, ySize, m_MemDC, xSource, ySource, xSize, ySize, TransparentColor);
else
BitBlt(m_hDC, xDest, yDest, xSize, ySize, m_MemDC, xSource, ySource, SRCCOPY);
}


The parameters xSize and ySize in the the functions StretchBlt and TransparentBlt allows you to take either the whole or a part of the source image.

Thus referring to to the above code, the following can be deduced.

xSize <= (GetBitmapWidth() - xSource)
ySize <= (GetBitmapHeight() - ySource)

i.e. the xSize should be smaller than or equal to (GetBitmapWidth()-xSource) but never greater otherwise the function will return an error of invalid parameters.

The same applies to ySize.