CRIMP
Artifact [015db4d428]
Not logged in

Artifact 015db4d4288f7114b6482b6e9af0ac69febe5dfa:


alpha_blend_rgba_rgb
Tcl_Obj* imageForeObj
Tcl_Obj* imageBackObj
int alpha

/*
 * Alpha-based blending of two images, foreground, and background, controlled
 * by a scalar (and extern) alpha factor. The result's alpha is the alpha
 * factor attenuated by the background's alpha.
 *
 * alpha is Opacity
 * 255 <=> Fully opaque      <=> imageF
 * 0   <=> Fully transparent <=> imageB
 *
 * => OUT = F*alpha + B*(1-alpha)
 */

crimp_image*     result;
crimp_image*     imageF;
crimp_image*     imageB;
int ralpha, px, py, oxf, oyf, oxb, oyb;
crimp_geometry bb;

crimp_input (imageForeObj, imageF, rgba);
crimp_input (imageBackObj, imageB, rgb);

if (alpha == 255) {
    Tcl_SetObjResult(interp, imageForeObj);
    return TCL_OK;
}
/* alpha == 0: Should return background, but have to return RGBA, not RGB.
 * Easiest handled by falling through into the actual mixer. Better would be
 * to have a loop specialized to the operation (clone the RGB, and add
 * constant opaque alpha).
 */

/*
 * True alpha mixture.
 */

ralpha = 255 - alpha;

crimp_rect_union (&imageF->geo, &imageB->geo, &bb);

result = crimp_new_rgba_at (bb.x, bb.y, bb.w, bb.h);
oxf = crimp_x (imageF);
oyf = crimp_y (imageF);
oxb = crimp_x (imageB);
oyb = crimp_y (imageB);

/*
 * px, py are physical coordinates in the result, starting from 0.
 * The associated logical coordinates in the 2D plane are
 *  lx = px + x(result)
 *  lx = py + y(result)
 * And when we are inside an input its physical coordinates, from the logical are
 *  px = lx - x(input)
 *  py = ly - y(input)
 */

#define MIX(fore,back) ((((fore)*alpha) + ((back)*ralpha))/255)

for (py = 0; py < bb.h; py++) {
    for (px = 0; px < bb.w; px++) {

        int lx = px + bb.x;
        int ly = py + bb.y;

	int inf = crimp_inside (imageF, lx, ly);
	int inb = crimp_inside (imageB, lx, ly);

	/*
	 * The result depends on where we are relative to both input.
	 * Inside of each input we take the respective value of the
	 * pixel. Outside of an input we take BLACK as the value
	 * instead, and TRANSPARENT for the ALPHA.
	 */

	int forer = inf ? R (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreg = inf ? G (imageF, lx - oxf, ly - oyf) : BLACK;
	int foreb = inf ? B (imageF, lx - oxf, ly - oyf) : BLACK;
	int forea = inf ? A (imageF, lx - oxf, ly - oyf) : BLACK;

	int backr = inb ? R (imageB, lx - oxb, ly - oyb) : BLACK;
	int backg = inb ? G (imageB, lx - oxb, ly - oyb) : BLACK;
	int backb = inb ? B (imageB, lx - oxb, ly - oyb) : BLACK;
	int backa = inb ? OPAQUE : TRANSPARENT;

	R (result, px, py) = MIX (forer, backr);
	G (result, px, py) = MIX (foreg, backg);
	B (result, px, py) = MIX (foreb, backb);
	A (result, px, py) = MIX (forea, backa);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;
#undef MIX

/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */