Thread: how, using Math from differents HBITMAP's, combine the pixels for effects?

  1. #1
    Registered User
    Join Date
    Aug 2013
    Posts
    451

    how, using Math from differents HBITMAP's, combine the pixels for effects?

    imagine that we have 2 pixels from differents HBITMAPS.
    (for transparent, i just avoid the pixel color... it's easy)
    using Math, how can i calculate the AlphaBlend?
    honestly i did several searchs and i'm asking the same question on differents forums... but no luck
    for start i need calculate the Opacy\AlphaBlend.
    heres my actual Bitmap Class(for see if i'm doing some erros on Bitmap creation):
    Code:
    class Bitmap{
        public:
            unsigned int Width =0;
            unsigned int Height =0;
            RGBQUAD *Pixels=NULL;
            HBITMAP HBitmap=NULL;
            HBITMAP OldHBitmap =NULL;
            HDC HDCBitmap;
            BITMAPINFO BitInfo;
            void *BufferMemory=NULL;
    
    
            Bitmap(unsigned int SizeWidth, unsigned int SizeHeight, COLORREF BackColor=RGB(0,0,0))
            {
                New(SizeWidth,SizeHeight,BackColor);
            }
            void Disposed()
            {
                Pixels=NULL;
                VirtualFree(BufferMemory, 0,MEM_RELEASE);
                SelectObject(HDCBitmap, OldHBitmap);
                DeleteDC(HDCBitmap);
                DeleteObject(HBitmap);
            }
    
    
            void New(unsigned int SizeWidth, unsigned int SizeHeight, COLORREF BackColor=RGB(0,0,0))
            { //New HBITMAP:
                int BufferSize = SizeWidth * SizeHeight * sizeof(RGBQUAD);
    
    
                if(BufferMemory) Disposed();
                BufferMemory = VirtualAlloc(0, BufferSize,MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
                Pixels =static_cast<RGBQUAD *> (BufferMemory);
    
    
                Width = SizeWidth;
                Height = SizeHeight;
                ZeroMemory(&BitInfo, sizeof(BITMAPINFO));
                BitInfo.bmiHeader.biSize = sizeof(BitInfo.bmiHeader);
                BitInfo.bmiHeader.biWidth = Width;
                BitInfo.bmiHeader.biHeight = -Height;
                BitInfo.bmiHeader.biPlanes = 1;
                BitInfo.bmiHeader.biBitCount = 32;
                BitInfo.bmiHeader.biCompression = BI_RGB;
                //BitInfo.bmiHeader.biSizeImage =  BitInfo.bmiHeader.biWidth  * (-BitInfo.bmiHeader.biHeight)* sizeof(RGBQUAD);
                HBitmap = CreateBitmap(Width, Height,1,32,Pixels);
                HDCBitmap = CreateCompatibleDC(NULL);
                OldHBitmap= (HBITMAP)SelectObject(HDCBitmap, HBitmap);
                Clear(BackColor);
            }
    
    
            void Clear(COLORREF BackColor=RGB(0,0,0), BYTE AlphaValue=255)
            {
                if(!BufferMemory) return;
                for(unsigned int PosY=0; PosY<Height; PosY++)
                {
                    for(unsigned int PosX=0; PosX<Width; PosX++)
                    {
                        Pixels[PosY*Width + PosX].rgbRed =GetRValue(BackColor);
                        Pixels[PosY*Width + PosX].rgbGreen =GetGValue(BackColor);
                        Pixels[PosY*Width + PosX].rgbBlue =GetBValue(BackColor);
                    }
                }
                SetDIBits(HDCBitmap,HBitmap,0,Height,Pixels,&BitInfo,DIB_RGB_COLORS);
            }
    
    
            void Draw(HDC HDCDestination, int PosX, int PosY, BYTE AlphaValue=5 )
            {
               //AlphaBlendWithTransparentColor (HDCDestination,PosX, PosY, Width, Height,HDCBitmap,PosX, PosY, Width,Height, SourceConstantAlpha, RGB(0,0,0));
                HBRUSH color = CreateSolidBrush(RGB(0,0,255));
                SelectObject(HDCDestination,color);
                Ellipse(HDCBitmap, 0,0,100,100);
    
    
                BLENDFUNCTION bf;
                bf.AlphaFormat = AC_SRC_ALPHA;
                bf.BlendFlags = 0;
                bf.BlendOp = AC_SRC_OVER;
                bf.SourceConstantAlpha = AlphaValue;
                AlphaBlend(HDCDestination, PosX, PosY, Width, Height,HDCBitmap, 0,0,Width, Height, bf);
                DeleteObject(color);
            }
    
    
            void SetPixel(unsigned int PosX, unsigned int PosY, COLORREF Color)
            {
                if(BufferMemory)
                {
                    if(PosX>=Width|| PosX<0) PosX = Width-1;
                    if(PosY>=Height || PosY<0) PosY = Height-1;
                    Pixels[PosY*Width + PosX].rgbRed =GetRValue(Color);
                    Pixels[PosY*Width + PosX].rgbGreen =GetGValue(Color);
                    Pixels[PosY*Width + PosX].rgbBlue =GetBValue(Color);
                }
                SetDIBits(HDCBitmap,HBitmap,0,Height,Pixels,&BitInfo,DIB_RGB_COLORS);
            }
    
    
            RGBQUAD GetPixel(unsigned int PosX, unsigned int PosY)
            {
                if(BufferMemory)
                {
                    if(PosX>=Width|| PosX<0) PosX = Width-1;
                    if(PosY>=Height || PosY<0) PosY = Height-1;
                    return Pixels[PosY*Width + PosX];
                }
            }
    
    
            void DrawLine3D(Position3D Origin, Position3D Destination, COLORREF Color, BYTE Alpha=0)
            {
                if(!BufferMemory) return;
                std::vector<Position3D> GetLineDots = GetLinePoints(Origin, Destination);
                for(unsigned int x=0; x<GetLineDots.size()-1; x++)
                {
                    unsigned int PosX = GetLineDots[x].PosX;
                    unsigned int PosY = GetLineDots[x].PosY;
                    if(PosX>=Width|| PosX<0) PosX = Width-1;
                    if(PosY>=Height || PosY<0) PosY = Height-1;
                    Pixels[PosY*Width + PosX].rgbRed =GetRValue(Color)*Alpha/255;
                    Pixels[PosY*Width + PosX].rgbGreen =GetGValue(Color)*Alpha/255;
                    Pixels[PosY*Width + PosX].rgbBlue =GetBValue(Color)*Alpha/255;
    
    
                }
                SetDIBits(HDCBitmap,HBitmap,0,Height,Pixels,&BitInfo,DIB_RGB_COLORS);
            }
    };

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    on 'RGBQUAD' the 'rgbReserved' can be used for Alpha value?
    RGBQUAD (wingdi.h) - Win32 apps | Microsoft Docs
    so the alpha blend math is:
    R = RTop + RBottom * (1 - Alpha)
    G = GTop + GBottom * (1 - Alpha)
    B = BTop + BBottom * (1 - Alpha)
    ? or i miss something?
    Last edited by joaquim; 04-17-2022 at 09:18 AM.

  4. #4
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    The math looks more like this to me, although I haven't tested it:
    Code:
    // Assuming alpha values are stored as integers from 0 to 255
    const int MaxAlpha = 255;
     
    struct Pixel
    {
        unsigned char r, g, b, a;
    };
     
    // p1 over p2
    Pixel over(Pixel p1, Pixel p2)
    {
        double a1f = (double)p1.a / MaxAlpha;
        double a2f = (double)p2.a / MaxAlpha;
        double a0f = a1f + a2f * (1.0 - a1f);
        Pixel p0;
        p0.r = (p1.r * a1f + p2.r * a2f * (1.0 - a1f)) / a0f;
        p0.g = (p1.g * a1f + p2.g * a2f * (1.0 - a1f)) / a0f;
        p0.b = (p1.b * a1f + p2.b * a2f * (1.0 - a1f)) / a0f;
        p0.a = MaxAlpha;
        return p0;
    }
    As for using the reserved spot in the rgbquad struct, in the description on the page you linked it says that the reserved member must be 0. So apparently at least some of the Windows functions that work with it expect it to be 0.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  5. #5
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    john.c correct me 1 thing: where i add the Alpha Value(between 0 and 255)?
    the 'MaxAlpha' it's 'BYTE' so it's 255 of max.
    but imagine that i need that the alpha be 120... where i add the 120?

  6. #6
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    I'm not sure what you are asking.
    In the code I posted the alpha value would go in the 'a' member of the 'Pixel' struct.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  7. #7
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    Quote Originally Posted by john.c View Post
    I'm not sure what you are asking.
    In the code I posted the alpha value would go in the 'a' member of the 'Pixel' struct.
    see how i test it(i use Color instead Pixel, but it's the same):
    Code:
    struct Color{
        BYTE Blue=0;
        BYTE Green=0;
        BYTE Red=0;
        BYTE Alpha=0;
    
    
        void RGBA(BYTE R, BYTE G, BYTE B, BYTE A)
        {
            Blue=B;
            Green=G;
            Red=R;
            Alpha=A;
        }
        operator COLORREF()
        {
            return RGB(Red,Green, Blue);
        }
    }*LPColor, COLOR, *LPCOLOR;
    
    
    Color RGBA(BYTE R, BYTE G, BYTE B, BYTE A)
    {
        Color clr;
        clr.RGBA(R,G,B,A);
        return clr;
    }
    
    // p1 over p2Color AlphaBlendPixels(Color p1, Color p2, BYTE AlphaValue)
    {
        double a1f = (double)p1.Alpha / 255;
        double a2f = (double)p2.Alpha / 255;
        double a0f = a1f + a2f * (1.0 - a1f);
        Color p0;
        p0.Red = (p1.Red * a1f + p2.Red* a2f * (1.0 - a1f)) / a0f;
        p0.Green = (p1.Green * a1f + p2.Green * a2f * (1.0 - a1f)) / a0f;
        p0.Blue = (p1.Blue * a1f + p2.Blue * a2f * (1.0 - a1f)) / a0f;
        p0.Alpha = AlphaValue;
        return p0;
    }
    Code:
    for(unsigned int Y =0; Y<Height; Y++)            {
                    for(unsigned int X =0; X<Width; X++)
                    {
                        Color TopPixel;
                        TopPixel.Alpha = Pixels[Y*Width + X].Alpha;
                        TopPixel.Red = Pixels[Y*Width + X].Red;
                        TopPixel.Green = Pixels[Y*Width + X].Green;
                        TopPixel.Blue = Pixels[Y*Width + X].Blue;
    
    
                        COLORREF RREFColor = ::GetPixel(HDCDestination, PosX+X, PosY+Y);
                        Color BottomPixel=RGBA(GetRValue(RREFColor),GetGValue(RREFColor),GetBValue(RREFColor),255);
                        AlphaBlendPixels(TopPixel, BottomPixel,AlphaValue );
    
    
                    }
                }
    the top image isn't showed\drawed

  8. #8
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    I don't use windows, but here's a simple version using the binary pnm format.
    I composited laserlight's profile pic (left half alpha 100, right half alpha 200) with awsdert's (alpha 255).
    Result (as a jpg since you can't upload pnm here) :

    how, using Math from differents HBITMAP's, combine the pixels for effects?-laserlight-jpg + how, using Math from differents HBITMAP's, combine the pixels for effects?-awsdert-jpg = how, using Math from differents HBITMAP's, combine the pixels for effects?-laserdert-jpg

    Code:
    #include <iostream>
    #include <iomanip>
    #include <fstream>
    #include <string>
    #include <vector>
    #include <cstdlib>
    using namespace std;
     
    using Byte = unsigned char;
    struct Pixel { Byte r, g, b, a; };
    const Byte MaxAlpha = 255;
     
    struct Image {
        vector<Pixel> pixels;
        unsigned height, width;
        Image(unsigned height, unsigned width)
            : pixels(height * width), height(height), width(width) { }
    };
     
    Image readPNMImage(const string& filename, Byte alpha = MaxAlpha) {
        ifstream f(filename, f.binary);
        if (f.get() != 'P' || f.get() != '6') {
            cerr << "File is not binary PNM.\n";
            exit(EXIT_FAILURE);
        }
        f.ignore(10000, '\n');
        // skip comments between P6 line and dimensions
        while (f.peek() == '#') f.ignore(10000, '\n');
        unsigned height, width, maxval;
        f >> height >> width >> maxval; // assuming maxval is 255
        f.ignore(10000, '\n');
        Image img(height, width);
        for (unsigned h = 0, i = 0; h < height; ++h)
            for (unsigned w = 0; w < width; ++w, ++i) {
                img.pixels[i].r = f.get();
                img.pixels[i].g = f.get();
                img.pixels[i].b = f.get();
                img.pixels[i].a = alpha;
            }
        return img;
    }
     
    void writePNMImage(const Image& img, const string& filename) {
        ofstream f(filename, f.binary);
        f << "P6\n"
          << img.height << ' ' << img.height << '\n'
          << unsigned(MaxAlpha) << '\n';
        for (unsigned i = 0; i < img.pixels.size(); ++i) {
            f.put(img.pixels[i].r);
            f.put(img.pixels[i].g);
            f.put(img.pixels[i].b);
        }
    }
     
    Pixel alphaCompositePixel(Pixel p1, Pixel p2, Byte alpha = MaxAlpha) {
        double a1f = double(p1.a) / MaxAlpha,
               a2f = double(p2.a) / MaxAlpha,
               a0f = a1f + a2f * (1.0 - a1f);
        return {
            Byte((p1.r * a1f + p2.r * a2f * (1.0 - a1f)) / a0f),
            Byte((p1.g * a1f + p2.g * a2f * (1.0 - a1f)) / a0f),
            Byte((p1.b * a1f + p2.b * a2f * (1.0 - a1f)) / a0f),
            alpha
        };
    }
     
    Image alphaComposite(const Image& img1, const Image& img2, Byte alpha = MaxAlpha) {
        // Assuming img1 and img2 have same dimensions.
        Image img(img1.height, img1.width);
        for (unsigned h = 0, i = 0; h < img.height; ++h)
            for (unsigned w = 0; w < img.width; ++w, ++i)
                img.pixels[i] = alphaCompositePixel(img1.pixels[i], img2.pixels[i], alpha);
        return img;
    }
     
    int main() {
        auto img1 = readPNMImage("laserlight.pnm");
        auto img2 = readPNMImage("awsdert.pnm");
    
        // Set left half of img1 alpha to 100, right half to 200
        for (unsigned h = 0, i = 0; h < img1.height; ++h)
            for (unsigned w = 0; w < img1.width; ++w, ++i)
                img1.pixels[i].a = (w < img1.width / 2 ? 100 : 200);
    
        auto img3 = alphaComposite(img1, img2);
        writePNMImage(img3, "output.pnm");
    }
    Last edited by john.c; 04-18-2022 at 06:08 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  9. #9
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    heres the entire code:
    Code:
    #include <iostream>#include <windows.h>
    #include <cmath>
    #include <stdlib.h>
    #include <vector>
    #include <string>
    #include <algorithm>
    
    
    #define M_PI           3.14159265358979323846  /* pi */
    
    
    using  namespace std;
    typedef std::vector<std::vector<unsigned int>>  Vect2D ;
    
    
    
    
    struct Color
    {
        BYTE Blue=0;
        BYTE Green=0;
        BYTE Red=0;
        BYTE Alpha=0;
    
    
        void RGBA(BYTE R, BYTE G, BYTE B, BYTE A)
        {
            Blue=B;
            Green=G;
            Red=R;
            Alpha=A;
        }
        operator COLORREF()
        {
            return RGB(Red,Green, Blue);
        }
    }*LPColor, COLOR, *LPCOLOR;
    
    
    Color RGBA(BYTE R, BYTE G, BYTE B, BYTE A)
    {
        Color clr;
        clr.RGBA(R,G,B,A);
        return clr;
    }
    
    
    struct Position2D
    {
        Position2D()
        {
            //Nothing;
        }
    
    
        Position2D(float X, float Y)
        {
            PosX = X;
            PosY = Y;
        }
        float PosX = 0;
        float PosY = 0;
    };
    
    
    struct Position3D
    {
        float PosX = 0;
        float PosY = 0;
        float PosZ = 0;
    
    
        Position3D()
        {
            //Nothing;
        }
    
    
        Position3D(float X, float Y, float Z)
        {
            PosX = X;
            PosY = Y;
            PosZ = Z;
        }
    
    
        operator Position2D()
        {
            return {PosX, PosY};
        }
    
    
    };
    
    
    std::vector<Position3D> GetLinePoints(Position3D Origin, Position3D Destination)
    {
        //Getting the Line Points Count:
        int LineCountPoints = sqrt(abs(Destination.PosX - Origin.PosX) * abs(Destination.PosX - Origin.PosX)
                                      + abs(Destination.PosY - Origin.PosY) * abs(Destination.PosY - Origin.PosY)
                                      + abs(Destination.PosZ - Origin.PosZ) * abs(Destination.PosZ - Origin.PosZ));
    
    
        //Get the increment for X, Y and Z:
        Position3D Increment;
        Increment.PosX = (Destination.PosX - Origin.PosX) / LineCountPoints;
        Increment.PosY = (Destination.PosY - Origin.PosY) / LineCountPoints;
        Increment.PosZ = (Destination.PosZ - Origin.PosZ) / LineCountPoints;
    
    
        Position3D NextPoint=Origin;
    
    
        std::vector<Position3D> GetPoints;
        GetPoints.push_back(Origin);
        for(int LinePoint =0 ; LinePoint<LineCountPoints; LinePoint++)
        {
            //Get the next point:
            NextPoint.PosX += Increment.PosX;
            NextPoint.PosY += Increment.PosY;
            NextPoint.PosZ += Increment.PosZ;
    
    
            //Round the values:
            Position3D Pos3D;
            Pos3D.PosX = ceil(NextPoint.PosX);
            Pos3D.PosY = ceil(NextPoint.PosY);
            Pos3D.PosZ = ceil(NextPoint.PosZ);
            /*if(Pos3D.PosX <Origin.PosX && Pos3D.PosX > Destination.PosX) break;
            if(Pos3D.PosY <Origin.PosY && Pos3D.PosY > Destination.PosY) break;
            if(Pos3D.PosZ <Origin.PosZ && Pos3D.PosZ > Destination.PosZ) break;*/
            //Add the 3D position on vector:
            GetPoints.push_back(Pos3D);
        }
        return GetPoints;
    }
    
    
    Color AlphaBlendPixels(Color p1, Color p2, BYTE alpha = 255)
    {
        double a1f = double(p1.Alpha) / 255,
               a2f = double(p2.Alpha) / 255,
               a0f = a1f + a2f * (1.0 - a1f);
        BYTE Red = (p1.Red * a1f + p2.Red * a2f * (1.0 - a1f)) / a0f;
        BYTE Green = (p1.Green * a1f + p2.Green * a2f * (1.0 - a1f)) / a0f;
        BYTE Blue = (p1.Blue * a1f + p2.Blue * a2f * (1.0 - a1f)) / a0f;
        BYTE Alpha =alpha;
    
    
        Color clr = RGBA(Red,Green,Blue, Alpha);
    
    
        return clr;
    }
    
    
    class Bitmap
    {
        public:
            unsigned int Width =0;
            unsigned int Height =0;
            Color *Pixels=NULL;
            Color *PixelsResult=NULL;
            HBITMAP HBitmap=NULL;
            HBITMAP OldHBitmap =NULL;
            HDC HDCBitmap;
            BITMAPINFO BitInfo;
            void *BufferMemory=NULL;
    
    
            Bitmap(unsigned int SizeWidth, unsigned int SizeHeight, Color BackColor=RGBA(0,0,0,0))
            {
                New(SizeWidth,SizeHeight,BackColor);
            }
            void Disposed()
            {
                Pixels=NULL;
                VirtualFree(BufferMemory, 0,MEM_RELEASE);
                SelectObject(HDCBitmap, OldHBitmap);
                DeleteDC(HDCBitmap);
                DeleteObject(HBitmap);
            }
    
    
            void New(unsigned int SizeWidth, unsigned int SizeHeight, Color BackColor=RGBA(0,0,0,0))
            {
                int BufferSize = SizeWidth * SizeHeight * sizeof(Color);
    
    
                if(BufferMemory) Disposed();
                BufferMemory = VirtualAlloc(0, BufferSize,MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
                Pixels =static_cast<Color *> (BufferMemory);
    
    
                Width = SizeWidth;
                Height = SizeHeight;
                ZeroMemory(&BitInfo, sizeof(BITMAPINFO));
                BitInfo.bmiHeader.biSize = sizeof(BitInfo.bmiHeader);
                BitInfo.bmiHeader.biWidth = Width;
                BitInfo.bmiHeader.biHeight = -Height;
                BitInfo.bmiHeader.biPlanes = 1;
                BitInfo.bmiHeader.biBitCount = 32;
                BitInfo.bmiHeader.biCompression = BI_RGB;
                //BitInfo.bmiHeader.biSizeImage =  BitInfo.bmiHeader.biWidth  * (-BitInfo.bmiHeader.biHeight)* sizeof(RGBQUAD);
                HBitmap = CreateBitmap(Width, Height,1,32,Pixels);
                HDCBitmap = CreateCompatibleDC(NULL);
                OldHBitmap= (HBITMAP)SelectObject(HDCBitmap, HBitmap);
                Clear(BackColor);
            }
    
    
            void Clear(Color BackColor)
            {
                if(!BufferMemory) return;
                for(unsigned int PosY=0; PosY<Height; PosY++)
                {
                    for(unsigned int PosX=0; PosX<Width; PosX++)
                    {
                        Pixels[PosY*Width + PosX].Red =BackColor.Red;
                        Pixels[PosY*Width + PosX].Green =BackColor.Green;
                        Pixels[PosY*Width + PosX].Blue =BackColor.Blue;
                        Pixels[PosY*Width + PosX].Alpha = BackColor.Alpha;
                    }
                }
                SetDIBits(HDCBitmap,HBitmap,0,Height,Pixels,&BitInfo,DIB_RGB_COLORS);
            }
    
    
            void Draw(HDC HDCDestination, int PosX, int PosY, BYTE AlphaValue=0 )
            {
    
    
                HBRUSH color = CreateSolidBrush(RGB(0,255,0));
                SelectObject(HDCDestination,color);
                Ellipse(HDCBitmap, 0,0,50,50);
                for(unsigned int Y =0; Y<Height; Y++)
                {
                    for(unsigned int X =0; X<Width; X++)
                    {
                           Pixels[Y*Width + X].Alpha =  AlphaValue;
                    }
                }
                BLENDFUNCTION bf;
                bf.AlphaFormat = AC_SRC_ALPHA;//use Alpha pixels... TransparentBlt()
                bf.BlendFlags = 0;
                bf.BlendOp = AC_SRC_OVER;
                bf.SourceConstantAlpha = AlphaValue;// use the AlphaBlend for all pixels
                //AlphaBlend(HDCDestination, PosX, PosY, Width*2, Height*2,HDCBitmap, 0,0,Width, Height, bf);
                int BufferSize = Width * Height * sizeof(Color);
                PixelsResult =(Color*) VirtualAlloc(0, BufferSize,MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
                for(unsigned int Y =0; Y<Height; Y++)
                {
                    for(unsigned int X =0; X<Width; X++)
                    {
                        Color TopPixel;
                        TopPixel.Alpha =Pixels[Y*Width + X].Alpha;
                        TopPixel.Red = Pixels[Y*Width + X].Red;
                        TopPixel.Green = Pixels[Y*Width + X].Green;
                        TopPixel.Blue = Pixels[Y*Width + X].Blue;
    
    
                        COLORREF RREFColor = ::GetPixel(HDCDestination, PosX+X, PosY+Y);
                        Color BottomPixel=RGBA(GetRValue(RREFColor),GetGValue(RREFColor),GetBValue(RREFColor),255);
                        PixelsResult[Y*Width+X] = AlphaBlendPixels(TopPixel, BottomPixel ,AlphaValue );
    
    
                    }
                }
                StretchDIBits(HDCDestination,PosX,PosY+100, Width, Height,0,0,Width, Height,PixelsResult,&BitInfo,DIB_RGB_COLORS,SRCCOPY);
                VirtualFree(PixelsResult, 0,MEM_RELEASE);
                DeleteObject(color);
            }
    
    
            void SetPixel(unsigned int PosX, unsigned int PosY, COLORREF Color)
            {
                if(BufferMemory)
                {
                    if(PosX>=Width|| PosX<0) PosX = Width-1;
                    if(PosY>=Height || PosY<0) PosY = Height-1;
                    Pixels[PosY*Width + PosX].Red =GetRValue(Color);
                    Pixels[PosY*Width + PosX].Green =GetGValue(Color);
                    Pixels[PosY*Width + PosX].Blue =GetBValue(Color);
                }
                SetDIBits(HDCBitmap,HBitmap,0,Height,Pixels,&BitInfo,DIB_RGB_COLORS);
            }
    
    
            Color GetPixel(unsigned int PosX, unsigned int PosY)
            {
                if(BufferMemory)
                {
                    if(PosX>=Width|| PosX<0) PosX = Width-1;
                    if(PosY>=Height || PosY<0) PosY = Height-1;
                    return Pixels[PosY*Width + PosX];
                }
            }
    
    
            void DrawLine3D(Position3D Origin, Position3D Destination, Color LineColor=RGBA(0,0,0,255))
            {
                if(!BufferMemory) return;
                std::vector<Position3D> GetLineDots = GetLinePoints(Origin, Destination);
                for(unsigned int x=0; x<GetLineDots.size()-1; x++)
                {
                    unsigned int PosX = GetLineDots[x].PosX;
                    unsigned int PosY = GetLineDots[x].PosY;
                    if(PosX>=Width|| PosX<0) PosX = Width-1;
                    if(PosY>=Height || PosY<0) PosY = Height-1;
                    Pixels[PosY*Width + PosX].Red =LineColor.Red;
                    Pixels[PosY*Width + PosX].Green =LineColor.Green;
                    Pixels[PosY*Width + PosX].Blue =LineColor.Blue;
                    Pixels[PosY*Width + PosX].Alpha =LineColor.Alpha;
    
    
                }
                SetDIBits(HDCBitmap,HBitmap,0,Height,Pixels,&BitInfo,DIB_RGB_COLORS);
            }
    };
    
    
    Position3D RotationPoints(Position3D Position, Position3D RotationPosition, Position3D Angle)
    {
        //Convert Angles in Radians:
        Angle.PosX *= M_PI / 180 ;
        Angle.PosY *= M_PI / 180 ;
        Angle.PosZ *= M_PI / 180 ;
    
    
        Position3D RotatedPoint;
    
    
        //for add the Rotation Point
        //we must sub the Rotation point with rotation center:
        Position.PosX -= RotationPosition.PosX;
        Position.PosY -= RotationPosition.PosY;
        Position.PosZ -= RotationPosition.PosZ;
    
    
    
    
        //First we rotate the Z:
        RotatedPoint.PosX = Position.PosX * cos(Angle.PosZ)-Position.PosY*sin(Angle.PosZ);
        RotatedPoint.PosY = Position.PosX * sin(Angle.PosZ)+Position.PosY*cos(Angle.PosZ);
        RotatedPoint.PosZ = Position.PosZ;
    
    
        //Second we rotate the Y:
        RotatedPoint.PosX = RotatedPoint.PosX * cos(Angle.PosY)+RotatedPoint.PosZ*sin(Angle.PosY);
        RotatedPoint.PosY = RotatedPoint.PosY;
        RotatedPoint.PosZ = -RotatedPoint.PosX * sin(Angle.PosY)+RotatedPoint.PosZ*cos(Angle.PosY);
    
    
        //Third we rotate the X:
        RotatedPoint.PosX = RotatedPoint.PosX;
        RotatedPoint.PosY = RotatedPoint.PosY * cos(Angle.PosX)-RotatedPoint.PosZ*sin(Angle.PosX);
        RotatedPoint.PosZ = RotatedPoint.PosY * sin(Angle.PosX)+RotatedPoint.PosZ*cos(Angle.PosX);
    
    
        //after rotate the point
        //we add the rotation center:
        RotatedPoint.PosX += RotationPosition.PosX;
        RotatedPoint.PosY += RotationPosition.PosY;
        RotatedPoint.PosZ += RotationPosition.PosZ;
    
    
        return RotatedPoint;
    }
    
    
    
    
    void DrawLine3D(std::vector<std::vector<unsigned int>> &Pixels, Position3D Origin, Position3D Destination, COLORREF Color)
    {
        std::vector<Position3D> GetLineDots = GetLinePoints(Origin, Destination);
        for(unsigned int x=0; x<GetLineDots.size()-1; x++)
        {
            unsigned int X = GetLineDots[x].PosX;
            unsigned int Y = GetLineDots[x].PosY;
    
    
           Pixels[Y][X] =(unsigned int) Color;
        }
    }
    
    
    
    
    void SimpleConstantAlphaBlend(HDC hDC)
    {
      const int size = 100;
    
    
      for (int i=0; i<3; i++)
      {
        RECT  rect = { i*(size+10) + 20, 20+size/3,
                   i*(size+10) + 20 + size, 20+size/3 + size };
    
    
        COLORREF Color[]={ RGB(0xFF,0,0), RGB(0,0xFF,0), RGB(0,0,0xFF) };
    
    
        HBRUSH hBrush = CreateSolidBrush(Color[i]);
        FillRect(hDC, & rect, hBrush);  // three original solid rectangles
        DeleteObject(hBrush);
    
    
        BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255/2, 0 }; // alpha 0.5
        blend.SourceConstantAlpha=120;
    
    
        AlphaBlend(hDC, 360+((3-i)%3)*size/3, 20+i*size/3, size, size,
                   hDC, i*(size+10)+20, 20+size/3, size, size, blend);
      }
    }
    
    
    
    
    int main()
    {
    
    
    
    
        HWND HWNDConsoleWindow = GetConsoleWindow();
        HDC HDCConsoleWindow = GetDC(HWNDConsoleWindow);
        Bitmap Bit(100,100);
        BYTE i=0;
        do
        {
    
    
            SimpleConstantAlphaBlend(HDCConsoleWindow);//draw some rectangles and half of them are AlphaBlend
            //Bit is an image with a circle and the backcolor alpha value is 0 for transparent
            Bit.Draw(HDCConsoleWindow, 100,100,i);
            Sleep(10);
            i++;
            //if(i==255) i=255/2;
            cout << to_string(i)<< "\t";
        }while(!GetAsyncKeyState(VK_ESCAPE));
        return 0;
    }
    now heres the result:
    how, using Math from differents HBITMAP's, combine the pixels for effects?-imagem_2022-04-19_225211385-png
    the white text number are the alpha values.. like you see... the colors aren't alpha blend.. maybe i miss something and i don't understand what
    Last edited by joaquim; 04-19-2022 at 03:49 PM.

  10. #10
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    I don't feel like going through your code.
    And I don't use Windows so I can't run it.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  11. #11
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    i'm sorry, but can you explain better your function?
    Code:
    Pixel alphaCompositePixel(Pixel p1, Pixel p2, Byte alpha = MaxAlpha) 
    {    
              double a1f = double(p1.a) / MaxAlpha,
               a2f = double(p2.a) / MaxAlpha,
               a0f = a1f + a2f * (1.0 - a1f);
        return {
            Byte((p1.r * a1f + p2.r * a2f * (1.0 - a1f)) / a0f),
            Byte((p1.g * a1f + p2.g * a2f * (1.0 - a1f)) / a0f),
            Byte((p1.b * a1f + p2.b * a2f * (1.0 - a1f)) / a0f),
            alpha
        };
    }
    maybe i can make my own function correctly
    Last edited by joaquim; 04-20-2022 at 02:07 PM.

  12. #12
    Registered User
    Join Date
    Dec 2017
    Posts
    1,632
    It's a straightforward implementation of the math from the wikipedia page.
    Anyway, looking through your code I see you use a Windows function called AlphaBlend.
    Why can't you just use that?
    A little inaccuracy saves tons of explanation. - H.H. Munro

  13. #13
    Registered User
    Join Date
    Aug 2013
    Posts
    451
    Quote Originally Posted by john.c View Post
    It's a straightforward implementation of the math from the wikipedia page.
    Anyway, looking through your code I see you use a Windows function called AlphaBlend.
    Why can't you just use that?
    i will tell you why:
    you have 1 image... now, using the rotation math function(i have 1), rotate X, Y and Z the 4 image corners.... try draw the image on screen using the 4 corners!?! we can't... that's why i'm doing the pixels pixels a pixels. the PlgBlt() it's good... but only can draw a perfect rectangle\cube way(use only 3 corners ).
    but if the left corners are more big than the right corners, it will not draw the image correctly... but you can correct me.
    Last edited by joaquim; 04-24-2022 at 10:57 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How to combines differents pieces and form a package
    By sergioms in forum C Programming
    Replies: 9
    Last Post: 09-13-2018, 10:33 AM
  2. Differents results x86 and ARM
    By Eduardo Alfaia in forum C Programming
    Replies: 3
    Last Post: 01-21-2015, 08:46 PM
  3. Replies: 4
    Last Post: 03-13-2010, 05:10 AM
  4. copying differents maps
    By l2u in forum C++ Programming
    Replies: 20
    Last Post: 10-14-2008, 04:59 AM
  5. Using differents API in a program
    By gustavosserra in forum C++ Programming
    Replies: 2
    Last Post: 06-29-2003, 07:30 PM

Tags for this Thread