PDA

View Full Version : This translucency code is killing me


Bachus
2002.09.18, 10:10 AM
So I want to add the ability to draw sprites and tiles translucent. So rather than coming up with my own method, I thought I would just use BlitPixie, since BlitPixie rocks. The only real problem I saw was that my game uses GWorlds (ie, I'm not using SpriteWorld) and BlitPixie doesn't. So I created my own procedure to get the data I needed out of the GWorlds and then call the BlitPixie translucency code. And it almost works. When I copy an entire GWorld to another GWorld it works just fine. But when I try to copy just part of a GWorld to another it fails and draws nothing. I've been fiddling with the code for the past day and I just can't figure out what I'm missing. So if anybody can point out what I'm missing I'd be most appreciative.


void BlitTranslucent16(GWorldPtr srcGW, GWorldPtr destGW, Rect srcRect, Rect dstRect, unsigned short transLevel)
{
unsigned short *src;
unsigned short *dst;

PixMapHandle srcPixMapHandle = GetGWorldPixMap(srcGW);
PixMapHandle dstPixMapHandle = GetGWorldPixMap(destGW);
unsigned long srcRowBytes = (*srcPixMapHandle)->rowBytes & 0x3FFF;
unsigned long dstRowBytes = (*dstPixMapHandle)->rowBytes & 0x3FFF;
UInt16 *srcBaseAddr = (UInt16*)GetPixBaseAddr(srcPixMapHandle);
UInt16 *dstBaseAddr = (UInt16*)GetPixBaseAddr(dstPixMapHandle);

unsigned long source, dest;
unsigned short alpha;
short i, j;
short width, height;

LockPixels(srcPixMapHandle);
LockPixels(dstPixMapHandle);

alpha = ((transLevel >> 8) & 0xFF);
height = srcRect.bottom - srcRect.top;
width = srcRect.right - srcRect.left;

src = ((UInt16*)(srcBaseAddr + (srcRowBytes * srcRect.top) + (srcRect.left << 1)));
dst = ((UInt16*)(dstBaseAddr + (dstRowBytes * dstRect.top) + (dstRect.left << 1)));

srcRowBytes -= (unsigned long)(width << 1);
dstRowBytes -= (unsigned long)(width << 1);

for(j = 0; j < height; j++)
{
for(i = 0; i < width; i++)
{
source = *src++;
dest = *dst;

if(source != 0x0000) // Don't draw black
BLEND_PIXELS_16( source, dest, alpha );

*dst++ = dest;
}

src = (unsigned short *)((char *)src + srcRowBytes);
dst = (unsigned short *)((char *)dst + dstRowBytes);
}

UnlockPixels(dstPixMapHandle);
UnlockPixels(srcPixMapHandle);
}

Hog
2002.09.18, 11:28 AM
well, apart from the BLEND_PIXELS_16(...) part, the code sure seems to be working, make sure you actually set "dest"

ibullard
2002.09.18, 11:48 AM
I see nothing wrong with the code, but I suggest not accessing memory when you don't have to. Instead of reading dest in and then writing dest even when the pixel in transparent, try this:

for(i = 0; i < width; i++)
{
source = *src++;
if(source != 0x0000) // Don't draw black
{
dest = *dst;
BLEND_PIXELS_16( source, dest, alpha );
*dst = dest;
}
*dst++;
}

Bachus
2002.09.18, 08:10 PM
So here's the working code:


void BlitTranslucent16(GWorldPtr srcGW, GWorldPtr destGW, Rect srcRect, Rect dstRect, unsigned short transLevel)
{
unsigned short *src = 0;
unsigned short *dst = 0;
unsigned short *srcRowStart = 0;
unsigned short *dstRowStart = 0;

PixMapHandle srcPixMapHandle = GetGWorldPixMap(srcGW);
PixMapHandle dstPixMapHandle = GetGWorldPixMap(destGW);
unsigned long srcRowBytes = (*srcPixMapHandle)->rowBytes & 0x3FFF;
unsigned long dstRowBytes = (*dstPixMapHandle)->rowBytes & 0x3FFF;
UInt8 *srcBaseAddr = (UInt8*)GetPixBaseAddr(srcPixMapHandle);
UInt8 *dstBaseAddr = (UInt8*)GetPixBaseAddr(dstPixMapHandle);

unsigned long source, dest;
unsigned short alpha;
short i, j;
short width, height;

LockPixels(srcPixMapHandle);
LockPixels(dstPixMapHandle);
ForeColor(blackColor);
BackColor(whiteColor);

alpha = ((transLevel >> 8) & 0xFF);
height = srcRect.bottom - srcRect.top;
width = srcRect.right - srcRect.left;

srcRowStart = ((UInt16*)(srcBaseAddr + (srcRowBytes * srcRect.top) + (srcRect.left << 1)));
dstRowStart = ((UInt16*)(dstBaseAddr + (dstRowBytes * dstRect.top) + (dstRect.left << 1)));

src = srcRowStart;
dst = dstRowStart;

for(j = 0; j < height; j++)
{
src = srcRowStart;
dst = dstRowStart;

for(i = 0; i < width; i++)
{
source = *src;

if(source != 0x0000)
{
dest = *dst;
BLEND_PIXELS_16( source, dest, alpha );
*dst = dest;
}

*src++;
*dst++;
}

srcRowStart = (unsigned short *)((char *)srcRowStart + srcRowBytes);
dstRowStart = (unsigned short *)((char *)dstRowStart + dstRowBytes);
}

UnlockPixels(dstPixMapHandle);
UnlockPixels(srcPixMapHandle);
}


A bunch of little changes (made mostly for aesthetic reasons, none of them fixed the problem). What did fix it? Changing these two lines from this:


UInt16 *srcBaseAddr = (UInt16*)GetPixBaseAddr(srcPixMapHandle);
UInt16 *dstBaseAddr = (UInt16*)GetPixBaseAddr(dstPixMapHandle);


To this:


UInt8 *srcBaseAddr = (UInt8*)GetPixBaseAddr(srcPixMapHandle);
UInt8 *dstBaseAddr = (UInt8*)GetPixBaseAddr(dstPixMapHandle);


It's days like these that I hate programming.

Hog
2002.09.19, 05:34 AM
ofcourse i.e:
src = (UInt16*)(((UInt16*)srcBaseAddr) + (srcRowBytes * srcRect.top) + (srcRect.left << 1));
is just not the same as:
src = (UInt16*)(((UInt8*)srcBaseAddr) + (srcRowBytes * srcRect.top) + (srcRect.left << 1));

must have not noticed that.
if you want to make it look more aesthetic and avoid such problems in the first place you should write something like:


void BlitTranslucent16(GWorldPtr srcGW, GWorldPtr destGW, Rect srcRect, Rect dstRect, unsigned short transLevel)
{
UInt16 *src;
UInt16 *dst;

PixMapHandle srcPixMapHandle = GetGWorldPixMap(srcGW);
PixMapHandle dstPixMapHandle = GetGWorldPixMap(destGW);
UInt32 srcRowWidth = ((*srcPixMapHandle)->rowBytes & 0x3FFF)>>1;
UInt32 dstRowWidth = ((*dstPixMapHandle)->rowBytes & 0x3FFF)>>1;
UInt16 *srcBaseAddr = (UInt16*)GetPixBaseAddr(srcPixMapHandle);
UInt16 *dstBaseAddr = (UInt16*)GetPixBaseAddr(dstPixMapHandle);

UInt16 alpha,source;
UInt16 i,j;
UInt16 width, height;

LockPixels(srcPixMapHandle);
LockPixels(dstPixMapHandle);

alpha = ((transLevel >> 8) & 0xFF);
height = srcRect.bottom - srcRect.top;
width = srcRect.right - srcRect.left;

src = srcBaseAddr + srcRowWidth * srcRect.top + srcRect.left;
dst = dstBaseAddr + dstRowWidth * dstRect.top + dstRect.left;

srcRowWidth -= width;
dstRowWidth -= width;

for(j = 0; j < height; j++)
{
for(i = 0; i < width; i++)
{
source = *src++;
if(source) // Don't draw black
BLEND_PIXELS_16(source,*dst,alpha);

dst++;
}

src += srcRowWidth;
dst += dstRowWidth;
}

UnlockPixels(dstPixMapHandle);
UnlockPixels(srcPixMapHandle);
}