Drawing on Bitmap with Alpha



  • On 24/01/2013 at 14:28, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:    
    Platform:      
    Language(s) :

    ---------
    I can't get the following code to work properly. I want to draw a green line at the bottom line of the
    ObjectDatas' icon when some condition is true. I've tried using BaseBitmap::SetPixel(), but it didn't
    work with images having an alpha-channel. Using BaseBitmap::GetInternalChannel() in combination
    with BaseBitmap::SetAlphaPixel() didn't work either. Possibly because of missing documentation or
    example code, or my stupidness.

    Therefore, I'm using a GeClipMap. But the drawn line is not visible at all (even with images without
    an alpha-channel). What am I doing wrong here?

        void OnGetCustomIcon(BaseObject* op, GetCustomIconData* data) {
            IconData* dIcon = data->dat;
            if (customIcon) {
                dIcon->x = 0;
                dIcon->y = 0;
                dIcon->w = customIcon->GetBw();
                dIcon->h = customIcon->GetBh();
                dIcon->bmp = customIcon;
                data->filled = TRUE;
            }
            else {
     **            // Could the memory leak be located here?**
                GetIcon(Ocontainer, dIcon);    // Load the default bitmap of the plugin.
                if (dIcon->bmp) {
                    BaseBitmap* clone = dIcon->bmp->GetClone();
                    /* We do *not* free the bitmap in dIcon->bmp because it is
                     * references by the iconlib. */
                    dIcon->bmp = clone;
                }
            }
            if (dIcon->bmp) {
                /* Draw colored lines into the bitmap to display that
                 * objects or tags are hidden. */
                GeClipMap* map = GeClipMap::Alloc();
                map->Init(dIcon->bmp);
                map->BeginDraw();
                map->SetColor(167, 255, 36, 255);
      
                LONG width = dIcon->bmp->GetBw();
                LONG height = dIcon->bmp->GetBh();
                if (conditionForHorizontalLineAtTheBottom) {
                    for (LONG i=0; i < width; i++) {
                        map->SetPixel(i, height - 1);
                    }
                }
                if (conditionForVerticalLineOnTheRight) {
                    for (LONG i=0; i < height; i++) {
                        map->SetPixel(i, width - 1);
                    }
                }
     **            // No changes.**
                map->EndDraw();
                BaseBitmap* bmp = map->GetBitmap();
                if (bmp != dIcon->bmp) {
                    BaseBitmap::Free(dIcon->bmp);
                    dIcon->bmp = bmp;
                }
                GeClipMap::Free(map);
            }
            data->filled = TRUE;
        }
    

    Ideas?

    Thanks in advance,
    Niklas



  • On 24/01/2013 at 15:29, xxxxxxxx wrote:

    I started a new try using the BaseBitmap directly, without the GeClipMap. I'm not getting memory
    leaks anymore, but the drawing doesn't really have and effect. While it didn't work at all with the
    clip-map, it works at least for non-alpha bitmaps.

    When loading a custom icon (which is a feature of my ObjectData plugin) without alpha-channel,
    the line is drawn correctly. When the default bitmap is used (which contains an alpha-channel),
    the changes are very minimal. The color is applied, but very very minimal.

    I also notices that the line that should appear on the right side of the icon is not shown at all,
    possibly an algorithmic error I couldn't spot.

        void OnGetCustomIcon(BaseObject* op, GetCustomIconData* data) {
            IconData* dIcon = data->dat;
            BaseBitmap* bmp;
            if (customIcon) {
                if (dIcon->bmp) {
                    // We can not free the previous bitmap, because it leads to a
                    // crash. We copy the custom icon bitmap to the already
                    // present bitmap.
                    bmp = dIcon->bmp;
                    customIcon->CopyTo(bmp);
                }
                else {
                    bmp = customIcon->GetClone();
                }
            }
            else {
                bmp = dIcon->bmp;
                if (!bmp) bmp = BaseBitmap::Alloc();
                if (GetIcon(Ocontainer, dIcon)) {
                    dIcon->bmp->CopyTo(bmp);
                }
            }
      
            if (bmp) {
                // Draw colored lines into the bitmap to display that
                // objects or tags are hidden.
                static const LONG r = 167;
                static const LONG g = 255;
                static const LONG b = 36;
                BaseBitmap* aph = bmp->GetInternalChannel();
                const LONG xdim = bmp->GetBw();
                const LONG ydim = bmp->GetBh();
      
                LONG x, y;
      
                // Bottom line - hidden children
                if (CountNBits(op->GetDown(), NBIT_OHIDE, TRUE, TRUE)) {
                    for (LONG i=0; i < xdim; i++) {
                        x = i;
                        y = ydim - 1;
                        bmp->SetPixel(x, y, r, g, b);
                        if (aph) bmp->SetAlphaPixel(aph, x, y, 255);
                    }
                }
      
                // Right line - hidden tags
                if (CountNBits(op->GetFirstTag(), NBIT_OHIDE, TRUE, TRUE)) {
                    for (LONG i=0; i < ydim; i++) {
                        x = xdim - 2;
                        y = i;
                        bmp->SetPixel(x, y, r, g, b);
                        if (aph) bmp->SetAlphaPixel(aph, x, y, 255);
                    }
                }
      
                // Adjust the IconData.
                dIcon->x = 0;
                dIcon->y = 0;
                dIcon->w = bmp->GetBw();
                dIcon->h = bmp->GetBh();
                dIcon->bmp = bmp;
                data->filled = TRUE;
            }
            else {
                data->filled = FALSE;
            }
        }
    

    1. Default Icon: 
    2. Default Icon with lines: 
    3. Non-alpha image:
    4. Non-alpha image with lines:

    At icon 2. one can see (although hardly) that a horizontal and a vertical line is drawn, but very
    weakly. At icon 4. one can see that the horizontal line is drawn, but not the vertical one.

    Any ideas, input? 🤢

    Thanks in advance,
    Niklas



  • On 24/01/2013 at 16:03, xxxxxxxx wrote:

    why don't you just recreate the the bitmaps from scratch ? get the alpha and rgb arrays
    from your original icon and merge them with a a color and alpha array containing your
    x sign or whatever. then write these two result arrays into a bitmap. this way you can 
    be sure that the original alpha is not interfering with your drawing.



  • On 27/01/2013 at 12:08, xxxxxxxx wrote:

    Hi Ferdinand,

    I think I got what you are thinking of, but I didn't try it yet because it works all of a sudden. I'm not
    quite sure what I did differently, but I actually restructured the code slightly.

        /\*\*
         \* Called from Message() on MSG_GETCUSTOMICON.
         \*/
        void OnGetCustomIcon(BaseObject\* op, GetCustomIconData\* data) {
            IconData\* dIcon = data->dat;
            BaseBitmap\* bmp;
            LONG xoff, yoff, xdim, ydim;
    
            if (customIcon) {
                if (dIcon->bmp) {
                    // We can not free the previous bitmap, because it leads to a
                    // crash. We copy the custom icon bitmap to the already
                    // present bitmap.
                    bmp = dIcon->bmp;
                    customIcon->CopyTo(bmp);
                }
                else {
                    bmp = customIcon->GetClone();
                }
                xoff = 0;
                yoff = 0;
                xdim = bmp->GetBw();
                ydim = bmp->GetBh();
            }
            else {
                bmp = dIcon->bmp;
                if (!bmp) {
                    bmp = BaseBitmap::Alloc();
                    bmp->Init(64, 64);
                }
                if (GetIcon(Ocontainer, dIcon)) {
                    dIcon->bmp->CopyTo(bmp);
                }
                xoff = dIcon->x;
                yoff = dIcon->y;
                xdim = dIcon->w;
                ydim = dIcon->h;
            }
    
            if (bmp) {
                do {
                    // Draw colored lines into the bitmap to display that
                    // objects or tags are hidden.
                    const BaseContainer\* container = op->GetDataInstance();
                    LONG thickness = container->GetLong(OCONTAINER_HINTTHICKNESS);
                    if (thickness <= 0) break;
    
                    const Vector color = container->GetVector(OCONTAINER_HINTCOLOR);
                    const LONG r = (255.0 \* color.x);
                    const LONG g = (255.0 \* color.y);
                    const LONG b = (255.0 \* color.z);
                    BaseBitmap\* aph = bmp->GetInternalChannel();
    
                    thickness = (xdim / 16) \* thickness;
                    LONG x, y;
    
                    // Horizontal line
                    if (CountNBits(op->GetDown(), NBIT_OHIDE, TRUE, TRUE)) {
                        for (LONG i=0; i < xdim; i++) {
                            x = i;
                            for (LONG t=1; t <= thickness; t++) {
                                y = yoff + ydim - t;
                                bmp->SetPixel(x, y, r, g, b);
                                if (aph) bmp->SetAlphaPixel(aph, x, y, 255);
                            }
                        }
                    }
    
                    // Vertical line
                    if (CountNBits(op->GetFirstTag(), NBIT_OHIDE, TRUE, TRUE)) {
                        for (LONG i=0; i < ydim; i++) {
                            y = i;
                            for (LONG t=1; t <= thickness; t++) {
                                x = xoff + xdim - t;
                                bmp->SetPixel(x, y, r, g, b);
                                if (aph) bmp->SetAlphaPixel(aph, x, y, 255);
                            }
                        }
                    }
                } while (FALSE);
    
                // Adjust the IconData.
                dIcon->x = xoff;
                dIcon->y = yoff;
                dIcon->w = xdim;
                dIcon->h = ydim;
                dIcon->bmp = bmp;
                data->filled = TRUE;
            }
            else {
                data->filled = FALSE;
            }
        }
    

    Best,
    Niklas


Log in to reply