Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Drawing onto transparent target  (Read 4459 times)

0 Members and 1 Guest are viewing this topic.

Metapyziks

  • Newbie
  • *
  • Posts: 33
    • View Profile
Drawing onto transparent target
« on: December 27, 2009, 10:57:07 pm »
I can't draw onto a texture with Image.Copy() with applyAlpha = true if the area being copied onto has 0 alpha (the alpha is inherited for some reason). Any way to counter this without doing it pixel by pixel?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Drawing onto transparent target
« Reply #1 on: December 28, 2009, 12:03:23 am »
Sorry I don't get it. If applyAlpha is true, it's normal that pixels having 0 alpha don't get copied, they are fully transparent.
Laurent Gomila - SFML developer

Metapyziks

  • Newbie
  • *
  • Posts: 33
    • View Profile
Drawing onto transparent target
« Reply #2 on: December 28, 2009, 12:06:06 am »
Quote from: "Laurent"
Sorry I don't get it. If applyAlpha is true, it's normal that pixels having 0 alpha don't get copied, they are fully transparent.


I mean if the target area has an alpha of 0, a pixel with alpha 255 won't be drawn onto it.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Drawing onto transparent target
« Reply #3 on: December 28, 2009, 12:19:55 am »
Ah I see, sorry.

It's because the alpha value is left unchanged. It's probably wrong, I should rather use the following formula:
Code: [Select]
a = src.a + dst.a * (1 - src.a)

I'll fix this as soon as I can, thanks for your feedback :)

EDIT: fixed in SFML 2
Laurent Gomila - SFML developer

Metapyziks

  • Newbie
  • *
  • Posts: 33
    • View Profile
Drawing onto transparent target
« Reply #4 on: December 28, 2009, 01:12:51 am »
Thanks  :)
Is there a way for me to get this fix?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Drawing onto transparent target
« Reply #5 on: December 28, 2009, 09:00:01 am »
Which version of SFML do you use?
Laurent Gomila - SFML developer

Metapyziks

  • Newbie
  • *
  • Posts: 33
    • View Profile
Drawing onto transparent target
« Reply #6 on: December 28, 2009, 02:58:17 pm »
Quote from: "Laurent"
Which version of SFML do you use?


1.5
I've cheaply fixed it by having the transparent areas made red (none of the images drawn onto it have red in them) and then copy over the red value to be their alpha values, pixel by pixel.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Drawing onto transparent target
« Reply #7 on: December 28, 2009, 03:27:19 pm »
If you want you can fix it yourself and recompile SFML, but then you'll have to distribute your modified version of SFML.
Laurent Gomila - SFML developer

Metapyziks

  • Newbie
  • *
  • Posts: 33
    • View Profile
Drawing onto transparent target
« Reply #8 on: December 28, 2009, 04:23:19 pm »
Just checking if this is right:
Code: [Select]
////////////////////////////////////////////////////////////
/// Copy pixels from another image onto this one.
/// This function does a slow pixel copy and should only
/// be used at initialization time
////////////////////////////////////////////////////////////
void Image::Copy(const Image& Source, unsigned int DestX, unsigned int DestY, const IntRect& SourceRect, bool ApplyAlpha)
{
    // Make sure both images are valid
    if ((Source.myWidth == 0) || (Source.myHeight == 0) || (myWidth == 0) || (myHeight == 0))
        return;

    // Make sure both images have up-to-date arrays
    EnsureArrayUpdate();
    Source.EnsureArrayUpdate();

    // Adjust the source rectangle
    IntRect SrcRect = SourceRect;
    if (SrcRect.GetWidth() == 0 || (SrcRect.GetHeight() == 0))
    {
        SrcRect.Left   = 0;
        SrcRect.Top    = 0;
        SrcRect.Right  = Source.myWidth;
        SrcRect.Bottom = Source.myHeight;
    }
    else
    {
        if (SrcRect.Left   < 0) SrcRect.Left = 0;
        if (SrcRect.Top    < 0) SrcRect.Top  = 0;
        if (SrcRect.Right  > static_cast<int>(Source.myWidth))  SrcRect.Right  = Source.myWidth;
        if (SrcRect.Bottom > static_cast<int>(Source.myHeight)) SrcRect.Bottom = Source.myHeight;
    }

    // Then find the valid bounds of the destination rectangle
    int Width  = SrcRect.GetWidth();
    int Height = SrcRect.GetHeight();
    if (DestX + Width  > myWidth)  Width  = myWidth  - DestX;
    if (DestY + Height > myHeight) Height = myHeight - DestY;

    // Make sure the destination area is valid
    if ((Width <= 0) || (Height <= 0))
        return;

    // Precompute as much as possible
    int          Pitch     = Width * 4;
    int          Rows      = Height;
    int          SrcStride = Source.myWidth * 4;
    int          DstStride = myWidth * 4;
    const Uint8* SrcPixels = Source.GetPixelsPtr() + (SrcRect.Left + SrcRect.Top * Source.myWidth) * 4;
    Uint8*       DstPixels = reinterpret_cast<Uint8*>(&myPixels[0]) + (DestX + DestY * myWidth) * 4;

    // Copy the pixels
    if (ApplyAlpha)
    {
        // Interpolation using alpha values, pixel by pixel (slower)
        for (int i = 0; i < Rows; ++i)
        {
            for (int j = 0; j < Width; ++j)
            {
                // Get a direct pointer to the components of the current pixel
                const Uint8* Src   = SrcPixels + j * 4;
                Uint8*       Dst   = DstPixels + j * 4;

                // Interpolate RGB components using the alpha value of the source pixel
                Uint8 Alpha = Src[3];
                Dst[0] = (Src[0] * Alpha + Dst[0] * (255 - Alpha)) / 255;
                Dst[1] = (Src[1] * Alpha + Dst[1] * (255 - Alpha)) / 255;
                Dst[2] = (Src[2] * Alpha + Dst[2] * (255 - Alpha)) / 255;

                // Get the new alpha value for the destination pixel
                Dst[3] = (Alpha  * Alpha + Dst[3] * (255 - Dst[3])) / 255;
            }

            SrcPixels += SrcStride;
            DstPixels += DstStride;
        }
    }
    else
    {
        // Optimized copy ignoring alpha values, row by row (faster)
        for (int i = 0; i < Rows; ++i)
        {
            memcpy(DstPixels, SrcPixels, Pitch);
            SrcPixels += SrcStride;
            DstPixels += DstStride;
        }
    }

    // The texture will need an update
    myNeedTextureUpdate = true;
}

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Drawing onto transparent target
« Reply #9 on: December 28, 2009, 05:09:42 pm »
This one should be more correct ;)
Code: [Select]
Dst[3] = Alpha  + (Dst[3] * (255 - Alpha)) / 255;
Laurent Gomila - SFML developer

Metapyziks

  • Newbie
  • *
  • Posts: 33
    • View Profile
Drawing onto transparent target
« Reply #10 on: December 28, 2009, 05:20:20 pm »
Quote from: "Laurent"
This one should be more correct ;)
Code: [Select]
Dst[3] = Alpha  + (Dst[3] * (255 - Alpha)) / 255;

Ok, thanks  :)

Edit: I can confirm this works perfectly. Do you want the updated Image.cpp?

My computer studies teacher asked that I fix at least one bug or add a feature to any open source project during the holidays, and I was wondering if it would be ok to use this.