This translucency code is killing me

Member
Posts: 269
Joined: 2005.04
Post: #1
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.

Code:
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);
}
Quote this message in a reply
Hog
Member
Posts: 151
Joined: 2002.09
Post: #2
well, apart from the BLEND_PIXELS_16(...) part, the code sure seems to be working, make sure you actually set "dest"
Quote this message in a reply
ibullard
Unregistered
 
Post: #3
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:
Code:
        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++;
        }
Quote this message in a reply
Member
Posts: 269
Joined: 2005.04
Post: #4
So here's the working code:

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:

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

To this:

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

It's days like these that I hate programming.
Quote this message in a reply
Hog
Member
Posts: 151
Joined: 2002.09
Post: #5
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:

Code:
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);
}
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Killing the char on the end of a char array wyrmmage 3 3,483 Dec 4, 2006 08:55 PM
Last Post: wyrmmage
  InvalWindowRect() is killing me!! loki74 2 2,472 Jun 29, 2006 03:29 PM
Last Post: loki74