#include #include "blitting.h" static gint BlitRoundIntegerF(gfloat x); static gpointer BlitGetPixelFuncRGBA(gint pixel_op); static void BlitPixelSetRGBA(guint32 *t, const guint32 *s); static void BlitPixelSetAlphaRGBA(guint32 *t, const guint32 *s); static void BlitPixelAlphaRGBA(guint32 *t, const guint32 *s); static void BlitPixelAddRGBA(guint32 *t, const guint32 *s); static void BlitPixelSubtractRGBA(guint32 *t, const guint32 *s); static void BlitPixelBlendRGBA(guint32 *t, const guint32 *s); static void BlitPixelMultiplyRGBA(guint32 *t, const guint32 *s); void BlitClearRGBA( gint pixel_op, guint32 *tar, gint tar_width, gint tar_height, gint tar_bpl, guint32 v ); void BlitImageScaleRGBA( gint pixel_op, guint32 *tar, gint tar_x, gint tar_y, gint tar_width, gint tar_height, gint tar_bpl, const guint32 *src, gint src_x, gint src_y, gint src_width, gint src_height, gint src_bpl, gfloat zoom_x, gfloat zoom_y ); #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h))) #define ABSOLUTE(x) (((x) < 0) ? ((x) * -1) : (x)) /* * Returns x as the rounded off value to the nearest integer value. */ static gint BlitRoundIntegerF(gfloat x) { return((gint)(x + 0.5)); } /* * Returns an opaque pointer to the BlitPixel*RGBA() function based * on pixel_op. * * This function always returns a valid function pointer. */ static gpointer BlitGetPixelFuncRGBA(gint pixel_op) { switch(pixel_op) { case BLIT_PIXEL_OP_SET: return((gpointer)BlitPixelSetRGBA); break; case BLIT_PIXEL_OP_SET_ALPHA: return((gpointer)BlitPixelSetAlphaRGBA); break; case BLIT_PIXEL_OP_ALPHA: return((gpointer)BlitPixelAlphaRGBA); break; case BLIT_PIXEL_OP_ADD: return((gpointer)BlitPixelAddRGBA); break; case BLIT_PIXEL_OP_SUBTRACT: return((gpointer)BlitPixelSubtractRGBA); break; case BLIT_PIXEL_OP_BLEND: return((gpointer)BlitPixelBlendRGBA); break; case BLIT_PIXEL_OP_MULTIPLY: return((gpointer)BlitPixelMultiplyRGBA); break; default: return((gpointer)BlitPixelSetRGBA); break; } } /* * Set target's value to the source's value. */ static void BlitPixelSetRGBA(guint32 *t, const guint32 *s) { *t = *s; } /* * Set target's value to the source's value using the source's * alpha value. The target's alpha value is not modified. */ static void BlitPixelSetAlphaRGBA(guint32 *t, const guint32 *s) { guint8 *t8 = (guint8 *)t; const guint8 *s8 = (guint8 *)s; gfloat ac_s = (gfloat)s8[3] / (gfloat)0xff, ac_t = 1.0f - ac_s; *t = (guint32)( ((guint32)((s8[0] * ac_s) + (t8[0] * ac_t)) << 0) | ((guint32)((s8[1] * ac_s) + (t8[1] * ac_t)) << 8) | ((guint32)((s8[2] * ac_s) + (t8[2] * ac_t)) << 16) | ((guint32)t8[3] << 24) ); } /* * Sets target's alpha value to the source's alpha value, RGB * values are not modified. */ static void BlitPixelAlphaRGBA(guint32 *t, const guint32 *s) { const guint8 *s8 = (guint8 *)s; *t = (guint32)( ((*t) & 0x00ffffff) | ((guint32)s8[3] << 24) ); } /* * Adds the source's RGB values to the target's RGB values, the * alpha value is not modified. */ static void BlitPixelAddRGBA(guint32 *t, const guint32 *s) { guint8 *t8 = (guint8 *)t; const guint8 *s8 = (guint8 *)s; gfloat ac_s = (gfloat)s8[3] / (gfloat)0xff; *t = (guint32)( ((guint32)MIN((gint)(s8[0] * ac_s) + (gint)t8[0], 0xff) << 0) | ((guint32)MIN((gint)(s8[1] * ac_s) + (gint)t8[1], 0xff) << 8) | ((guint32)MIN((gint)(s8[2] * ac_s) + (gint)t8[2], 0xff) << 16) | ((guint32)t8[3] << 24) ); } /* * Subtracts the source's RGB values from the target's RGB values, * the alpha value is not modified. */ static void BlitPixelSubtractRGBA(guint32 *t, const guint32 *s) { guint8 *t8 = (guint8 *)t; const guint8 *s8 = (guint8 *)s; gfloat ac_s = (gfloat)s8[3] / (gfloat)0xff; *t = (guint32)( ((guint32)MAX((gint)t8[0] - (gint)(s8[0] * ac_s), 0x00) << 0) | ((guint32)MAX((gint)t8[1] - (gint)(s8[1] * ac_s), 0x00) << 8) | ((guint32)MAX((gint)t8[2] - (gint)(s8[2] * ac_s), 0x00) << 16) | ((guint32)t8[3] << 24) ); } /* * Averages the source's RGB values with the target's RGB values, * the source's alpha value is taken into consideration but the * target's alpha value is not modified. */ static void BlitPixelBlendRGBA(guint32 *t, const guint32 *s) { guint8 *t8 = (guint8 *)t; const guint8 *s8 = (guint8 *)s; gfloat ac_s = (gfloat)s8[3] / (gfloat)0xff; *t = (guint32)( ((((guint32)(s8[0] * ac_s) + (guint32)t8[0]) / 2) << 0) | ((((guint32)(s8[1] * ac_s) + (guint32)t8[1]) / 2) << 8) | ((((guint32)(s8[2] * ac_s) + (guint32)t8[2]) / 2) << 16) | ((guint32)t8[3] << 24) ); } /* * Multiplies the source's RGB values with the target's RGB values, * the source's alpha value is taken into consideration but the * target's alpha value is not modified. */ static void BlitPixelMultiplyRGBA(guint32 *t, const guint32 *s) { guint8 *t8 = (guint8 *)t; const guint8 *s8 = (guint8 *)s; gfloat ac_s = (gfloat)s8[3] / (gfloat)0xff; *t = (guint32)( (((guint32)(s8[0] * ac_s) * (guint32)t8[0] / 0xff) << 0) | (((guint32)(s8[1] * ac_s) * (guint32)t8[1] / 0xff) << 8) | (((guint32)(s8[2] * ac_s) * (guint32)t8[2] / 0xff) << 16) | ((guint32)t8[3] << 24) ); } /* * Clear entire image buffer with the given value v, no blending. * * RGBA 32 bits (4 bytes). */ void BlitClearRGBA( gint pixel_op, guint32 *tar, gint tar_width, gint tar_height, gint tar_bpl, guint32 v ) { void (*pixel_func)(guint32 *, const guint32 *) = BlitGetPixelFuncRGBA(pixel_op); if(tar == NULL) return; if(tar_bpl <= 0) { gint len = tar_width * tar_height; guint32 *ptr = tar, *end = tar + len; for(; ptr < end; ptr++) pixel_func(ptr, &v); } else { gint x, y; guint8 *tar8 = (guint8 *)tar, *ptr; for(y = 0; y < tar_height; y++) { for(x = 0; x < tar_width; x++) { ptr = &(tar8[ (y * tar_bpl) + (x * 4) ]); pixel_func((guint32 *)ptr, &v); } } } } /* * Copy two image buffer's rectangular areas with scaling. * * RGBA 32 bits (4 bytes). */ void BlitImageScaleRGBA( gint pixel_op, guint32 *tar, gint tar_x, gint tar_y, gint tar_width, gint tar_height, gint tar_bpl, const guint32 *src, gint src_x, gint src_y, gint src_width, gint src_height, gint src_bpl, gfloat zoom_x, gfloat zoom_y ) { void (*pixel_func)(guint32 *, const guint32 *) = BlitGetPixelFuncRGBA(pixel_op); gint src_sk_col, /* Skips, in * 256 */ src_sk_row; gint src_cx, /* Current position, in * 256 */ src_cy, src_w, /* Desired zoomed size, in * 256 */ src_h, src_tw, /* Allocation size, in * 256 */ src_th; gint tar_cx, /* Current position, in * 256 */ tar_cy, tar_w, /* Desired zoomed size, in * 256 */ tar_h, tar_tw, /* Allocation size, in * 256 */ tar_th; if((zoom_x <= 0.0f) || (zoom_y <= 0.0f) || (tar == NULL) || (src == NULL) || (tar_width <= 0) || (tar_height <= 0) || (src_width <= 0) || (src_height <= 0) ) return; /* Convert target and source starting positions to units of * 256 and make sure they are not negative. */ tar_x = MAX(tar_x * 256, 0); tar_y = MAX(tar_y * 256, 0); src_x = MAX(src_x * 256, 0); src_y = MAX(src_y * 256, 0); /* Calculate column and row skips in units of 256, the skips * skips must be positive or else no incrementation will * occure and the loop will run infinately */ src_sk_col = MAX((gint)BlitRoundIntegerF(256.0f / zoom_x), 1); src_sk_row = MAX((gint)BlitRoundIntegerF(256.0f / zoom_y), 1); /* Calculate source and target buffer allocation size in * units of 256 */ src_tw = src_width * 256; src_th = src_height * 256; tar_tw = tar_width * 256; tar_th = tar_height * 256; /* Calculate visible source bounds based on the target * bounds with zoom applied, in units of 256 */ src_w = MIN((gint)(tar_tw / zoom_x) + src_x, src_tw); src_h = MIN((gint)(tar_th / zoom_y) + src_y, src_th); /* Calculate visible target bounds based on the source * bounds with zoom applied, in units of 256 */ tar_w = MIN((gint)(src_tw * zoom_x) + tar_x, tar_tw); tar_h = MIN((gint)(src_th * zoom_y) + tar_y, tar_th); /* Set source and target starting positions in units of 256 */ src_cx = src_x; src_cy = src_y; tar_cx = tar_x; tar_cy = tar_y; /* Check if target and source rectangles are in bounds */ if(((src_x + src_w) >= 0) && ((src_y + src_h) >= 0) && (src_x < src_w) && (src_y < src_h) && ((tar_x + tar_w) >= 0) && ((tar_y + tar_h) >= 0) && (tar_x < tar_w) && (tar_y < tar_h) ) { gint src_bpp = 4, tar_bpp = 4; const guint8 *src_ptr, *src_buf = (const guint8 *)src; guint8 *tar_ptr, *tar_buf = (guint8 *)tar; if(src_bpl <= 0) src_bpl = src_width * src_bpp; if(tar_bpl <= 0) tar_bpl = tar_width * tar_bpp; while((src_cy < src_h) && (tar_cy < tar_h) ) { /* Get pointers to source and target pixels */ src_ptr = &(src_buf[ ((src_cy >> 8) * src_bpl) + ((src_cx >> 8) * src_bpp) ]); tar_ptr = &(tar_buf[ ((tar_cy >> 8) * tar_bpl) + ((tar_cx >> 8) * tar_bpp) ]); /* Set pixel */ pixel_func( (guint32 *)tar_ptr, (const guint32 *)src_ptr ); /* Increment target x column */ tar_cx += 256; /* Go to next target line? */ if(tar_cx >= tar_w) { tar_cy += 256; tar_cx = tar_x; src_cy += src_sk_row; src_cx = src_x; continue; } /* Increment source x column */ src_cx += src_sk_col; /* Go to next source line? */ if(src_cx >= src_w) { tar_cy += 256; tar_cx = tar_x; src_cy += src_sk_row; src_cx = src_x; continue; } } } }