Blending

Let-s spend a few words on blending.

Blending is kind of like bringing blitting a step further.

We don’t want to just copy a pixel from source to destination, but we want to combine the source with the destination in peculiar ways.

The most obvious is transparency – we want to overlay the two colors so that you can still see an hint of the previous color.

But we may also want to perform additive blending, which is kind of what happens when you project two cones of light on the same surface.

Subtractive blending is the opposite. It’s like when you have two differently-colored light sources and two objects create two shadows. When they meet, you have subtractive blending.

WME, in addition to opaque blitting, supports “regular” alpha blending, additive blending and subtractive blending.
Each can have a color modifier as a nice added feature – basically, the input sprite gets multiplied by the colorMod, which acts kind of like a pair of colored lenses.

Of course, the original uses the ready-made blending options provided by DirectX.
We, on the other hand, must roll our own.

Here’s some examples.
For starters, subtractive blending for a single pixel.
There are two special cases which are useful optimization-wise but could be stripped away.

void BlittingTools::blendPixelSubtractive(byte *ina, byte *inr, byte *ing, byte *inb, byte *outa, byte *outr, byte *outg, byte *outb) {
    /*
     * in[argb] = input pixel, a,r,g,b channel;
     * out[argb] = output pixel, a,r,g,b channel;
     */
        // BEGIN OPTIONAL PART
        if (*ina == 0) { // Fully transparent... let's not waste time on this.
 
        } else if (*ina == 255) { // Fully opaque. Forget
            *outa = *outa;
            *outr = MAX(*outr - *inr, 0);
            *outg = MAX(*outg - *ing, 0);
            *outb = MAX(*outb - *inb, 0);
            return;
        } else {
        // END OPTIONAL PART
            *outa = *outa;
            *outb = MAX(*outb - (*inb * *ina >> 8), 0);
            *outg = MAX(*outg - (*ing * *ina >> 8), 0);
            *outr = MAX(*outr - (*inr * *ina >> 8), 0);
            // * ina >> 8 is kind of like * ina / 255, ina
            // goes from 0 - 255, so you end up multiplying by 0...1
            return;
        }
}

Another example, additive with colormod.

void BlittingTools::blendPixelAdditive(byte *ina, byte *inr, byte *ing, byte *inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb) {
 
        if (*ca != 255) {
            *ina = *ina * *ca >> 8;
        }
 
        if (*ina == 0) {
            return;
        } else if (*ina == 255) {
            if (*cb != 255)
                *outb = MIN(*outb + ((*inb * *cb * *ina) >> 16), 255);
            else
                *outb = MIN(*outb + (*inb * *ina >> 8), 255);
 
            if (*cg != 255)
                *outg = MIN(*outg + ((*ing * *cg * *ina) >> 16), 255);
            else
                *outg = MIN(*outg + (*ing * *ina >> 8), 255);
 
            if (*cr != 255)
                *outr = MIN(*outr + ((*inr * *cr * *ina) >> 16), 255);
            else
                *outr = MIN(*outr + (*inr * *ina >> 8), 255);
        }
}