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

1. ## 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;
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);

Width = SizeWidth;
Height = SizeHeight;
ZeroMemory(&BitInfo, sizeof(BITMAPINFO));
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. 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?

3. 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.

4. 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?

5. 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.

6. Originally Posted by john.c
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

7. 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) :

+ =

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() {

// 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");
}```

8. 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));
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)
{
Angle.PosX *= M_PI / 180 ;
Angle.PosY *= M_PI / 180 ;
Angle.PosZ *= M_PI / 180 ;

Position3D RotatedPoint;

//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
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:

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

9. I don't feel like going through your code.
And I don't use Windows so I can't run it.

10. 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

11. 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?

12. Originally Posted by john.c