Alpha-Blending and Brightness
Site Map Feedback
Painting Alpha-Blended RectanglesPainting Faded Rectangles
Up Colours Drawing Effects Patterns PixelBlock Textures

Draw Translucent Rectangles

Stylish or complex graphics need Alphablending (adding translucency) when drawing. Fortunately, this is not difficult! Colors.h is a short file that provides methods to blend colours, adjust the brightness and select hues from the spectrum for fades (for full color control you should use the gColor class).

When using SetPixel, the original colour of the Pixel being set is overwritten. If, however, you wanted to draw an object which appeared transparent, you'd want to mix the existing colour with the new colour. Transparency, like each of the R,G and B Channels, is a Byte value, 0 represents no Transparency; 255 means totally Transparent (invisible). An object's Transparency is referred to as its Alpha Channel hence the drawing of a transparent object refers to Alphablending. This allows certain optimisations: if Transparency is 0 just use SetPixel; if Transparency is 255 you don't need to do anything at all! When mixing colours evenly (50% Transparency) you are trying to find the average of each RGB component ((R1+R2)/2, (G1+G2)/2, (B1+B2)/2) For our DWORD Colours this can be done very efficiently once it is accepted that rounding errors are insignificant: Use bitwise operations to replicate the sum: RBG1/2+RGB2/2

((Colour1>>1) & 0x7F7F7F)+((Colour2>>1) & 0x7F7F7F)
Masking the most significant bit of each Byte stops overflow. The general equation for all levels of Transparency for each Channel is (R2*Transparency)/256 + (R1*(255-Transparency))/256 A few optimisations can be applied like >>8 instead of /256, and this can be done just once at the end of our equation because it is known that the most significant Byte is unused. Also, 255-Transparency is the same as ~Transparency for our purposes, and this is faster for the processor too.
  DWORD MixColours(DWORD Colour1, DWORD Colour2) {return((Colour1>>1) & 0x7F7F7F)+((Colour2>>1) & 0x7F7F7F);}
  DWORD AlphaBlend(DWORD Paper, DWORD Paint, BYTE Transparency) {
    switch(Transparency) {
      case   0: return Paper;
      case  64: return MixColours(Paper,MixColours(Paper,Paint));
      case 128: return MixColours(Paint,Paper); // When hard-coding 50% transparency, use 128: it's faster than 127.
      case 191: return MixColours(Paint,MixColours(Paint,Paper));
      case 255: return Paint;
      default : register BYTE PaperTransparency=~Transparency;
                return (((((Paint&0x0000FF)*Transparency)+((Paper&0x0000FF)*PaperTransparency))&0x0000FF00)
                      | ((((Paint&0x00FF00)*Transparency)+((Paper&0x00FF00)*PaperTransparency))&0x00FF0000)
                      | ((((Paint&0xFF0000)*Transparency)+((Paper&0xFF0000)*PaperTransparency))&0xFF000000))>>8;
  } }

You can extend CPixelBlock to handle Alphablending with the following code:

  void BlendPixel(int x, int y, int Colour, BYTE Transparency=255) {
    if(!IsValid(x,y)) return;
    DWORD* ptr=&Bits[Width*y+x];
    *ptr=CColors::AlphaBlend(*ptr, Colour, Transparency);
  }

Now you just need the code to paint Rectangles:

public:
  void Rectangle(WORD x, WORD y, WORD dx, WORD dy, DWORD Colour) {
    if((x+dx>=Width) || (y+dy>=Height)) return;
    DWORD* Line=&Bits[x+Width*y];
    for(WORD i=0; i<dy; ++i) {
      DWORD* Pixel=Line;
      for(WORD j=0; j<dx; ++j) *Pixel++=Colour;
      Line+=Width;
    }
  }
// Fades a rectangle from one colour to another. If Top2Bottom is false the fade is Left to Right:
  void Rectangle(WORD x, WORD y, WORD dx, WORD dy, DWORD SttColour, DWORD EndColour, bool Top2Bottom) {
    if((x+dx>=Width) || (y+dy>=Height)) return;
    DWORD* Line=&Bits[x+Width*y];
    for(WORD i=0; i<dy; ++i) {
      DWORD* Pixel=Line;
      BYTE Transparency=(i<<8)/dy;
      for(WORD j=0; j<dx; ++j) *Pixel++=CColors::AlphaBlend(SttColour, EndColour, Top2Bottom ? Transparency : (j<<8)/dx);
      Line+=Width;
    }
  }
// A separate function is used for blended Rectangles to maximise speed for the ordinary Rectangles function.
  void Rectangle(WORD x, WORD y, WORD dx, WORD dy, DWORD Colour, BYTE Transparency) {
    if((x+dx>=Width) || (y+dy>=Height)) return;
    DWORD* Line=&Bits[x+Width*y];
    for(WORD i=0; i<dy; ++i) {
      DWORD* Pixel=Line;
      for(WORD j=0; j<dx; ++j) *Pixel++=CColors::AlphaBlend(*Pixel, Colour, Transparency);
      Line+=Width;
    }
  }
  void Box(WORD x, WORD y, WORD dx, WORD dy, DWORD Colour) { // Rectangular Outline:
    Rectangle(x     ,y     ,dx,   1, Colour);
    Rectangle(x     ,y+dy-1,dx,   1, Colour);
    Rectangle(x     ,y+1   , 1,dy-1, Colour);
    Rectangle(x+dx-1,y+1   , 1,dy-1, Colour);
  }
  void Box(WORD x, WORD y, WORD dx, WORD dy, DWORD Colour, BYTE Transparency) {
    Rectangle(x     ,y     ,dx,   1, Colour, Transparency);
    Rectangle(x     ,y+dy-1,dx,   1, Colour, Transparency);
    Rectangle(x     ,y+1   , 1,dy-2, Colour, Transparency);
    Rectangle(x+dx-1,y+1   , 1,dy-2, Colour, Transparency);
  }

The Drawing, and Patterns sections have further extensions.


THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.