void update(double time, uint32_t* out, const uint32_t* in1, const uint32_t* in2) { uint8_t *dst = reinterpret_cast<uint8_t*>(out); const uint8_t *src1 = reinterpret_cast<const uint8_t*>(in1); const uint8_t *src2 = reinterpret_cast<const uint8_t*>(in2); for (unsigned int i=0; i<size; ++i) { uint32_t tmp; uint8_t alpha_src1 = src1[3]; uint8_t alpha_src2 = src2[3]; uint8_t alpha_dst; uint8_t w2 = 0xff ^ alpha_src1; // w2 = 255 - alpha_1 // compute destination alpha alpha_dst = dst[3] = INT_MULT(alpha_src1, alpha_src1, tmp) + INT_MULT3(alpha_src2, alpha_src2, w2, tmp); // compute destination values if (alpha_dst == 0) for (int b=0; b<3; ++b) dst[b] = 0; else for (int b=0; b<3; ++b) dst[b] = CLAMP0255( (uint32_t)( (uint32_t) (src1[b] * alpha_src1 + INT_MULT(src2[b], alpha_src2, tmp) * w2) / alpha_dst) ); src1 += 4; src2 += 4; dst += 4; } }
void update(double time, uint32_t* out, const uint32_t* in1, const uint32_t* in2, const uint32_t* in3) { uint8_t *dst = reinterpret_cast<uint8_t*>(out); const uint8_t *src1 = reinterpret_cast<const uint8_t*>(in1); const uint8_t *src2 = reinterpret_cast<const uint8_t*>(in2); for (int i=0; i<size; ++i) { uint32_t tmp; uint8_t alpha_src1 = src1[3]; uint8_t alpha_dst; uint8_t w1 = src2[3]; // compute destination alpha alpha_dst = dst[3] = INT_MULT(alpha_src1, w1, tmp); // compute destination values if (alpha_dst == 0) for (int b=0; b<3; ++b) dst[b] = 0; else for (int b=0; b<3; ++b) dst[b] = CLAMP0255( (uint32_t)( (uint32_t) (INT_MULT(src1[b], alpha_src1, tmp) * w1) / alpha_dst) ); src1 += 4; src2 += 4; dst += 4; } }
/** * * Perform an RGB[A] softlight operation between the pixel sources * in1 and in2. * **/ void update(double time, uint32_t* out, const uint32_t* in1, const uint32_t* in2) { const uint8_t *src1 = reinterpret_cast<const uint8_t*>(in1); const uint8_t *src2 = reinterpret_cast<const uint8_t*>(in2); uint8_t *dst = reinterpret_cast<uint8_t*>(out); uint32_t sizeCounter = size; uint32_t b, tmpS, tmpM, tmp1, tmp2, tmp3; while (sizeCounter--) { for (b = 0; b < ALPHA; b++) { /* Mix multiply and screen */ tmpM = INT_MULT(src1[b], src2[b], tmpM); tmpS = 255 - INT_MULT((255 - src1[b]), (255 - src2[b]), tmp1); dst[b] = INT_MULT((255 - src1[b]), tmpM, tmp2) + INT_MULT(src1[b], tmpS, tmp3); } dst[ALPHA] = MIN(src1[ALPHA], src2[ALPHA]); src1 += NBYTES; src2 += NBYTES; dst += NBYTES; } }
///////////////////////////////////////////////////////// // processDualImage // ///////////////////////////////////////////////////////// void pix_multiply :: processRGBA_RGBA(imageStruct &image, imageStruct &right) { int datasize = image.xsize * image.ysize; unsigned char *leftPix = image.data; unsigned char *rightPix = right.data; while(datasize--) { leftPix[chRed] = INT_MULT(leftPix[chRed], rightPix[chRed]); leftPix[chGreen] = INT_MULT(leftPix[chGreen], rightPix[chGreen]); leftPix[chBlue] = INT_MULT(leftPix[chBlue], rightPix[chBlue]); leftPix += 4; rightPix += 4; } }
Bitmap* SoftGlow::Process2(const Bitmap* src, int radius, float sharpness, float brightness) { assert(src && src->IsValid()); Bitmap* dst = new Bitmap(src->Width(), src->Height(), src->biBitCount, 0, false); assert(dst); //calc sharpness and brightness for (int y = 0; y < src->Height(); y++) { uint8* p0 = src->Get(0, y); uint8* p1 = dst->Get(0, y); for (int x = 0; x < src->Width(); x++) { *(p1 + 0) = (uint8)CalcSharpAndBright(*(p0 + 0), sharpness, brightness); *(p1 + 1) = (uint8)CalcSharpAndBright(*(p0 + 1), sharpness, brightness); *(p1 + 2) = (uint8)CalcSharpAndBright(*(p0 + 2), sharpness, brightness); p0 += src->PixelBytes(); p1 += dst->PixelBytes(); } } //gaussion filter Gaussion(dst, (float)radius); #ifdef _DEBUG dst->Save("f:\\tmp0.bmp"); #endif int temp; for (int y = 0; y < src->Height(); y++) { uint8* p0 = src->Get(0, y); uint8* p1 = dst->Get(0, y); for (int x = 0; x < src->Width(); x++) { //screen op *(p1 + 0) = 255 - INT_MULT((255 - *(p0 + 0)), (255 - *(p1 + 0)), temp); *(p1 + 1) = 255 - INT_MULT((255 - *(p0 + 1)), (255 - *(p1 + 1)), temp); *(p1 + 2) = 255 - INT_MULT((255 - *(p0 + 2)), (255 - *(p1 + 2)), temp); p0 += src->PixelBytes(); p1 += dst->PixelBytes(); } } return dst; }
/** * * Perform an RGB[A] multiply operation between the pixel sources * in1 and in2. * **/ void update(double time, uint32_t* out, const uint32_t* in1, const uint32_t* in2, const uint32_t* in3) { const uint8_t *src1 = reinterpret_cast<const uint8_t*>(in1); const uint8_t *src2 = reinterpret_cast<const uint8_t*>(in2); uint8_t *dst = reinterpret_cast<uint8_t*>(out); uint32_t sizeCounter = size; uint32_t b, tmp; while (sizeCounter--) { for (b = 0; b < ALPHA; b++) dst[b] = INT_MULT(src1[b], src2[b], tmp); dst[ALPHA] = MIN(src1[ALPHA], src2[ALPHA]); src1 += NBYTES; src2 += NBYTES; dst += NBYTES; } }
void alpha_xor(unsigned char *dst, const unsigned char *src1, const unsigned char *src2, unsigned int n) { unsigned int b; unsigned int tmp; unsigned char w1, w2; while (n--) { w1 = (255 - src2[IDX_RGBA_A]); w2 = (255 - src1[IDX_RGBA_A]); for (b=0; b<SIZE_RGBA; ++b) dst[b] = INT_MULT(src1[b], w1, tmp) + INT_MULT(src2[b], w2, tmp); src1+=SIZE_RGBA; src2+=SIZE_RGBA; dst+=SIZE_RGBA; } }
void alpha_premultiply(unsigned char *src, unsigned int n) { unsigned int tmp; while (n--) { for (int i=0; i<SIZE_RGB; ++i) src[i] = INT_MULT(src[i], src[IDX_RGBA_A], tmp); src += SIZE_RGBA; } }
///////////////////////////////////////////////////////// // processDualGray // ///////////////////////////////////////////////////////// void pix_multiply :: processGray_Gray(imageStruct &image, imageStruct &right) { int datasize = image.xsize * image.ysize; unsigned char *leftPix = image.data; unsigned char *rightPix = right.data; while(datasize--) { unsigned int alpha = rightPix[chGray]; leftPix[chGray] = INT_MULT(leftPix[chGray], alpha); leftPix++; rightPix++; } }
void alpha_in(unsigned char *dst, const unsigned char *src1, const unsigned char *src2, unsigned int n) { unsigned int b; unsigned int tmp; unsigned char w1; while (n--) { w1 = src2[IDX_RGBA_A]; for (b=0; b<SIZE_RGBA; ++b) dst[b] = INT_MULT(src1[b], w1, tmp); // dst[IDX_RGBA_A] = INT_MULT(src1[b], w1, tmp);CLAMP0255( ((int)(src1[IDX_RGBA_A] * w1)) / 255 ); src1+=SIZE_RGBA; src2+=SIZE_RGBA; dst+=SIZE_RGBA; } }
void RenderEngine::renderLayer( const Layer* layer, Image *image, int source_x, int source_y, FrameNumber frame, Zoom zoom, void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, Zoom), bool render_background, bool render_transparent, int blend_mode) { // we can't read from this layer if (!layer->isVisible()) return; switch (layer->type()) { case ObjectType::LayerImage: { if ((!render_background && layer->isBackground()) || (!render_transparent && !layer->isBackground())) break; const Cel* cel = static_cast<const LayerImage*>(layer)->getCel(frame); if (cel != NULL) { Image* src_image; // Is the 'preview_image' set to be used with this layer? if ((selected_layer == layer) && (selected_frame == frame) && (preview_image != NULL)) { src_image = preview_image; } // If not, we use the original cel-image from the images' stock else { src_image = cel->image(); } if (src_image) { int t, output_opacity; output_opacity = MID(0, cel->opacity(), 255); output_opacity = INT_MULT(output_opacity, global_opacity, t); ASSERT(src_image->maskColor() == m_sprite->transparentColor()); (*zoomed_func)(image, src_image, m_sprite->getPalette(frame), zoom.apply(cel->x()) - source_x, zoom.apply(cel->y()) - source_y, output_opacity, (blend_mode < 0 ? static_cast<const LayerImage*>(layer)->getBlendMode(): blend_mode), zoom); } } break; } case ObjectType::LayerFolder: { LayerConstIterator it = static_cast<const LayerFolder*>(layer)->getLayerBegin(); LayerConstIterator end = static_cast<const LayerFolder*>(layer)->getLayerEnd(); for (; it != end; ++it) { renderLayer(*it, image, source_x, source_y, frame, zoom, zoomed_func, render_background, render_transparent, blend_mode); } break; } } // Draw extras if (m_document->getExtraCel() && layer == m_currentLayer && frame == m_currentFrame) { Cel* extraCel = m_document->getExtraCel(); if (extraCel->opacity() > 0) { Image* extraImage = m_document->getExtraCelImage(); (*zoomed_func)(image, extraImage, m_sprite->getPalette(frame), zoom.apply(extraCel->x()) - source_x, zoom.apply(extraCel->y()) - source_y, extraCel->opacity(), m_document->getExtraCelBlendMode(), zoom); } } }
Bitmap* SoftGlow::Process1(const Bitmap* src, int radius, float sharpness, float brightness) { assert(src && src->IsValid()); int width = src->Width(); int height = src->Height(); Bitmap* tmp = new Bitmap(width, height, 8); assert(tmp); for (int y = 0; y < height; y++) { uint8* p0 = src->Get(0, y); uint8* p1 = tmp->Get(0, y); for (int x = 0; x < width; x++) { uint8 b = *(p0 + 0); uint8 g = *(p0 + 1); uint8 r = *(p0 + 2); *p1 = (uint8)rgb_to_l(r, g, b); *p1 = (uint8)CalcSharpAndBright(*p1, sharpness, brightness); p0 += src->PixelBytes(); p1 += tmp->PixelBytes(); } } Gaussion(tmp, (float)radius); #ifdef _DEBUG tmp->Save("f:\\tmp0.bmp"); #endif Bitmap* dst = new Bitmap(src->Width(), src->Height(), src->biBitCount); assert(dst); int temp; for (int y = 0; y < height; y++) { uint8* p0 = src->Get(0, y); uint8* p1 = tmp->Get(0, y); uint8* p2 = dst->Get(0, y); for (int x = 0; x < width; x++) { //screen op *(p2 + 0) = 255 - INT_MULT((255 - *(p0 + 0)), (255 - *p1), temp); *(p2 + 1) = 255 - INT_MULT((255 - *(p0 + 1)), (255 - *p1), temp); *(p2 + 2) = 255 - INT_MULT((255 - *(p0 + 2)), (255 - *p1), temp); p0 += src->PixelBytes(); p1 += tmp->PixelBytes(); p2 += dst->PixelBytes(); } } delete tmp; return dst; }
static void softglow (GimpDrawable *drawable, GimpPreview *preview) { GimpPixelRgn src_rgn, dest_rgn; GimpPixelRgn *pr; gint width, height; gint bytes; gboolean has_alpha; guchar *dest; guchar *src, *sp_p, *sp_m; gdouble n_p[5], n_m[5]; gdouble d_p[5], d_m[5]; gdouble bd_p[5], bd_m[5]; gdouble *val_p, *val_m, *vp, *vm; gint x1, y1, x2, y2; gint i, j; gint row, col, b; gint terms; gint progress, max_progress; gint initial_p[4]; gint initial_m[4]; gint tmp; gdouble radius; gdouble std_dev; gdouble val; if (preview) { gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); x2 = x1 + width; y2 = y1 + height; } else { gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = (x2 - x1); height = (y2 - y1); } bytes = drawable->bpp; has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); val_p = g_new (gdouble, MAX (width, height)); val_m = g_new (gdouble, MAX (width, height)); dest = g_new0 (guchar, width * height); progress = 0; max_progress = width * height * 3; /* Initialize the pixel regions. */ gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); for (pr = gimp_pixel_rgns_register (1, &src_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { guchar *src_ptr = src_rgn.data; guchar *dest_ptr = dest + (src_rgn.y - y1) * width + (src_rgn.x - x1); for (row = 0; row < src_rgn.h; row++) { for (col = 0; col < src_rgn.w; col++) { /* desaturate */ if (bytes > 2) dest_ptr[col] = (guchar) gimp_rgb_to_l_int (src_ptr[col * bytes + 0], src_ptr[col * bytes + 1], src_ptr[col * bytes + 2]); else dest_ptr[col] = (guchar) src_ptr[col * bytes]; /* compute sigmoidal transfer */ val = dest_ptr[col] / 255.0; val = 255.0 / (1 + exp (-(SIGMOIDAL_BASE + (svals.sharpness * SIGMOIDAL_RANGE)) * (val - 0.5))); val = val * svals.brightness; dest_ptr[col] = (guchar) CLAMP (val, 0, 255); } src_ptr += src_rgn.rowstride; dest_ptr += width; } if (!preview) { progress += src_rgn.w * src_rgn.h; gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } } /* Calculate the standard deviations */ radius = fabs (svals.glow_radius) + 1.0; std_dev = sqrt (-(radius * radius) / (2 * log (1.0 / 255.0))); /* derive the constants for calculating the gaussian from the std dev */ find_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev); /* First the vertical pass */ for (col = 0; col < width; col++) { memset (val_p, 0, height * sizeof (gdouble)); memset (val_m, 0, height * sizeof (gdouble)); src = dest + col; sp_p = src; sp_m = src + width * (height - 1); vp = val_p; vm = val_m + (height - 1); /* Set up the first vals */ initial_p[0] = sp_p[0]; initial_m[0] = sp_m[0]; for (row = 0; row < height; row++) { gdouble *vpptr, *vmptr; terms = (row < 4) ? row : 4; vpptr = vp; vmptr = vm; for (i = 0; i <= terms; i++) { *vpptr += n_p[i] * sp_p[-i * width] - d_p[i] * vp[-i]; *vmptr += n_m[i] * sp_m[i * width] - d_m[i] * vm[i]; } for (j = i; j <= 4; j++) { *vpptr += (n_p[j] - bd_p[j]) * initial_p[0]; *vmptr += (n_m[j] - bd_m[j]) * initial_m[0]; } sp_p += width; sp_m -= width; vp ++; vm --; } transfer_pixels (val_p, val_m, dest + col, width, height); if (!preview) { progress += height; if ((col % 5) == 0) gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } } for (row = 0; row < height; row++) { memset (val_p, 0, width * sizeof (gdouble)); memset (val_m, 0, width * sizeof (gdouble)); src = dest + row * width; sp_p = src; sp_m = src + width - 1; vp = val_p; vm = val_m + width - 1; /* Set up the first vals */ initial_p[0] = sp_p[0]; initial_m[0] = sp_m[0]; for (col = 0; col < width; col++) { gdouble *vpptr, *vmptr; terms = (col < 4) ? col : 4; vpptr = vp; vmptr = vm; for (i = 0; i <= terms; i++) { *vpptr += n_p[i] * sp_p[-i] - d_p[i] * vp[-i]; *vmptr += n_m[i] * sp_m[i] - d_m[i] * vm[i]; } for (j = i; j <= 4; j++) { *vpptr += (n_p[j] - bd_p[j]) * initial_p[0]; *vmptr += (n_m[j] - bd_m[j]) * initial_m[0]; } sp_p ++; sp_m --; vp ++; vm --; } transfer_pixels (val_p, val_m, dest + row * width, 1, width); if (!preview) { progress += width; if ((row % 5) == 0) gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } } /* Initialize the pixel regions. */ gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, width, height, (preview == NULL), TRUE); for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { guchar *src_ptr = src_rgn.data; guchar *dest_ptr = dest_rgn.data; guchar *blur_ptr = dest + (src_rgn.y - y1) * width + (src_rgn.x - x1); for (row = 0; row < src_rgn.h; row++) { for (col = 0; col < src_rgn.w; col++) { /* screen op */ for (b = 0; b < (has_alpha ? (bytes - 1) : bytes); b++) dest_ptr[col * bytes + b] = 255 - INT_MULT((255 - src_ptr[col * bytes + b]), (255 - blur_ptr[col]), tmp); if (has_alpha) dest_ptr[col * bytes + b] = src_ptr[col * bytes + b]; } src_ptr += src_rgn.rowstride; dest_ptr += dest_rgn.rowstride; blur_ptr += width; } if (preview) { gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), &dest_rgn); } else { progress += src_rgn.w * src_rgn.h; gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } } if (! preview) { /* merge the shadow, update the drawable */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, (x2 - x1), (y2 - y1)); } /* free up buffers */ g_free (val_p); g_free (val_m); g_free (dest); }