45f9f9211373510d8a65af4abb53555d44a6ac13 braney Fri Jun 18 14:50:34 2021 -0700 fix alpha compositing so draw engine graphs can be composited on top of Javascript drawings (eg. highlights) diff --git src/inc/memgfx.h src/inc/memgfx.h index a36a7e2..c7297c1 100644 --- src/inc/memgfx.h +++ src/inc/memgfx.h @@ -23,50 +23,52 @@ #define MG_WHITE 0xffffffff #define MG_BLACK 0x000000ff #define MG_RED 0xff0000ff #define MG_GREEN 0x00ff00ff #define MG_BLUE 0x0000ffff #define MG_CYAN 0x00ffffff #define MG_MAGENTA 0xff00ffff #define MG_YELLOW 0xffff00ff #define MG_GRAY 0x808080ff #define MAKECOLOR_32_A(r,g,b,a) (((unsigned int)a) | ((unsigned int)b<<8) | ((unsigned int)g << 16) | ((unsigned int)r << 24)) #define MAKECOLOR_32(r,g,b) (((unsigned int)0xff) | ((unsigned int)b<<8) | ((unsigned int)g << 16) | ((unsigned int)r << 24)) #define COLOR_32_RED(c) (((c)>>24)&0xff) #define COLOR_32_GREEN(c) (((c)>>16)&0xff) #define COLOR_32_BLUE(c) (((c)>>8)&0xff) +#define COLOR_32_ALPHA(c) (((c))&0xff) #else // LITTLE ENDIAN machines: #define MG_WHITE 0xffffffff #define MG_BLACK 0xff000000 #define MG_RED 0xff0000ff #define MG_GREEN 0xff00ff00 #define MG_BLUE 0xffff0000 #define MG_CYAN 0xffffff00 #define MG_MAGENTA 0xffff00ff #define MG_YELLOW 0xff00ffff #define MG_GRAY 0xff808080 #define MAKECOLOR_32_A(r,g,b,a) (((unsigned int)a<<24) | ((unsigned int)b<<16) | ((unsigned int)g << 8) | (unsigned int)r) #define MAKECOLOR_32(r,g,b) (((unsigned int)0xff<<24) | ((unsigned int)b<<16) | ((unsigned int)g << 8) | (unsigned int)r) #define COLOR_32_RED(c) ((c)&0xff) #define COLOR_32_GREEN(c) (((c)>>8)&0xff) #define COLOR_32_BLUE(c) (((c)>>16)&0xff) +#define COLOR_32_ALPHA(c) (((c)>>24)&0xff) #endif #define MG_WRITE_MODE_NORMAL 0 #define MG_WRITE_MODE_MULTIPLY (1 << 0) struct rgbColor { unsigned char r, g, b; }; /* HSV and HSL structs can be used for changing lightness, darkness, or * color of RGB colors. Convert RGB->HS[LV], modify hue, saturation, or * value/lightness, then convert back to RGB. * The datatypes were chosen to be fast but also give accurate conversion * back to RGB. @@ -406,23 +408,40 @@ struct rgbColor mgColorIxToRgb(struct memGfx *mg, int colorIx); /* Return rgb value at color index. */ struct rgbColor colorIxToRgb(int colorIx); /* Return rgb value at color index. */ INLINE void mixDot(struct memGfx *img, int x, int y, float frac, Color col) /* Puts a single dot on the image, mixing it with what is already there * based on the frac argument. */ /* Shouldn't this pay attention to the transparency of the current pixel? */ { if ((x < img->clipMinX) || (x >= img->clipMaxX) || (y < img->clipMinY) || (y >= img->clipMaxY)) return; Color *pt = _mgPixAdr(img,x,y); -float invFrac = 1 - frac; -int r = COLOR_32_RED(*pt) * invFrac + COLOR_32_RED(col) * frac; -int g = COLOR_32_GREEN(*pt) * invFrac + COLOR_32_GREEN(col) * frac; -int b = COLOR_32_BLUE(*pt) * invFrac + COLOR_32_BLUE(col) * frac; -mgPutDot(img,x,y,MAKECOLOR_32(r,g,b)); +/* algorithm borrowed from https://en.wikipedia.org/wiki/Alpha_compositing */ +int aA = frac * 255; +int rA = COLOR_32_RED(col); +int gA = COLOR_32_GREEN(col); +int bA = COLOR_32_BLUE(col); + +int aB = COLOR_32_ALPHA(*pt); +int rB = COLOR_32_RED(*pt); +int gB = COLOR_32_GREEN(*pt); +int bB = COLOR_32_BLUE(*pt); + +int aOut = aA + (aB * (255 - aA) / 255); +int rOut, gOut, bOut; +if (aOut == 0) + rOut = gOut = bOut = 0; +else + { + rOut = (rA * aA + rB * aB * (255 - aA) / 255)/aOut ; + gOut = (gA * aA + gB * aB * (255 - aA) / 255)/aOut ; + bOut = (bA * aA + bB * aB * (255 - aA) / 255)/aOut ; + } +mgPutDot(img,x,y,MAKECOLOR_32_A(rOut,gOut,bOut,aOut)); } #endif /* MEMGFX_H */