From 6578144b7eda1dae885e5cc172751203b1d16c2d Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 18 Dec 2013 15:55:13 -0800 Subject: ACME-1236 : WIP : Added Gray Scale as an experimental filter in Flickr. Lots of ugly hacks for now --- indra/llimage/llimage.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index c8a05e1fae..e5281feff0 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -933,6 +933,26 @@ BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) return TRUE ; } +// *TODO : Implement real color transform +// Merov : This is temporary code for testing... +void LLImageRaw::colorTransform() +{ + const S32 components = getComponents(); + llassert( components >= 1 && components <= 4 ); + + S32 pixels = getWidth() * getHeight(); + U8* dst_data = getData(); + llinfos << "Merov : Convert the image to Black and White!!! pixels = " << pixels << ", comp = " << components << llendl; + for( S32 i=0; i Date: Fri, 20 Dec 2013 13:49:20 -0800 Subject: ACME-1236 : WIP : Implement colorTransform filter, grayscale and sepia using it, add parameter to llimage_libtest to use filters --- indra/llimage/llimage.cpp | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index e5281feff0..73e6f48a8d 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -30,6 +30,8 @@ #include "llmath.h" #include "v4coloru.h" +#include "m3math.h" +#include "v3math.h" #include "llimagebmp.h" #include "llimagetga.h" @@ -933,22 +935,42 @@ BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) return TRUE ; } -// *TODO : Implement real color transform -// Merov : This is temporary code for testing... -void LLImageRaw::colorTransform() +// Filter Operations +void LLImageRaw::filterGrayScale() +{ + LLMatrix3 gray_scale; + LLVector3 luminosity(0.2125, 0.7154, 0.0721); + gray_scale.setRows(luminosity, luminosity, luminosity); + gray_scale.transpose(); + colorTransform(gray_scale); +} + +void LLImageRaw::filterSepia() +{ + LLMatrix3 sepia; + sepia.setRows(LLVector3(0.3588, 0.7044, 0.1368), + LLVector3(0.2990, 0.5870, 0.1140), + LLVector3(0.2392, 0.4696, 0.0912)); + sepia.transpose(); + colorTransform(sepia); +} + +// Filter Primitives +void LLImageRaw::colorTransform(const LLMatrix3 &transform) { const S32 components = getComponents(); llassert( components >= 1 && components <= 4 ); S32 pixels = getWidth() * getHeight(); U8* dst_data = getData(); - llinfos << "Merov : Convert the image to Black and White!!! pixels = " << pixels << ", comp = " << components << llendl; for( S32 i=0; i Date: Mon, 30 Dec 2013 20:33:33 -0800 Subject: ACME-1236 : WIP : Implement saturation/desaturation transform filter, add it to llimage_libtest for testing --- indra/llimage/llimage.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 73e6f48a8d..4028514898 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -955,6 +955,37 @@ void LLImageRaw::filterSepia() colorTransform(sepia); } +void LLImageRaw::filterSaturate(F32 saturation) +{ + // Matrix to Lij + LLMatrix3 r_a; + LLMatrix3 r_b; + + // 45 degre rotation around z + r_a.setRows(LLVector3(0.7071, 0.7071, 0.0), + LLVector3(-0.7071, 0.7071, 0.0), + LLVector3(0.0, 0.0, 1.0)); + // 54.73 degre rotation around y + r_b.setRows(LLVector3(0.5773, 0.0, -0.8165), + LLVector3(0.0, 1.0, 0.0), + LLVector3(0.8165, 0.0, 0.5773)); + + // Coordinate conversion + LLMatrix3 Lij = r_b * r_a; + LLMatrix3 Lij_inv = Lij; + Lij_inv.transpose(); + + // Local saturation transform + LLMatrix3 s; + s.setRows(LLVector3(saturation, 0.0, 0.0), + LLVector3(0.0, saturation, 0.0), + LLVector3(0.0, 0.0, 1.0)); + + // Global saturation transform + LLMatrix3 transfo = Lij_inv * s * Lij; + colorTransform(transfo); +} + // Filter Primitives void LLImageRaw::colorTransform(const LLMatrix3 &transform) { -- cgit v1.2.3 From 9dca514c0b416c1b15e9a63e6f5af1b52df70b7e Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 1 Jan 2014 17:58:52 -0800 Subject: ACME-1236 : WIP : add filterRotate to rotate hue, add rotate as a valid argument to --filter in llimage_libtest --- indra/llimage/llimage.cpp | 48 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 4028514898..8b7c352437 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -962,13 +962,15 @@ void LLImageRaw::filterSaturate(F32 saturation) LLMatrix3 r_b; // 45 degre rotation around z - r_a.setRows(LLVector3(0.7071, 0.7071, 0.0), - LLVector3(-0.7071, 0.7071, 0.0), - LLVector3(0.0, 0.0, 1.0)); + r_a.setRows(LLVector3( OO_SQRT2, OO_SQRT2, 0.0), + LLVector3(-OO_SQRT2, OO_SQRT2, 0.0), + LLVector3( 0.0, 0.0, 1.0)); // 54.73 degre rotation around y - r_b.setRows(LLVector3(0.5773, 0.0, -0.8165), - LLVector3(0.0, 1.0, 0.0), - LLVector3(0.8165, 0.0, 0.5773)); + float oo_sqrt3 = 1.0f / F_SQRT3; + float sin_54 = F_SQRT2 * oo_sqrt3; + r_b.setRows(LLVector3(oo_sqrt3, 0.0, -sin_54), + LLVector3(0.0, 1.0, 0.0), + LLVector3(sin_54, 0.0, oo_sqrt3)); // Coordinate conversion LLMatrix3 Lij = r_b * r_a; @@ -986,6 +988,40 @@ void LLImageRaw::filterSaturate(F32 saturation) colorTransform(transfo); } +void LLImageRaw::filterRotate(F32 alpha) +{ + // Matrix to Lij + LLMatrix3 r_a; + LLMatrix3 r_b; + + // 45 degre rotation around z + r_a.setRows(LLVector3( OO_SQRT2, OO_SQRT2, 0.0), + LLVector3(-OO_SQRT2, OO_SQRT2, 0.0), + LLVector3( 0.0, 0.0, 1.0)); + // 54.73 degre rotation around y + float oo_sqrt3 = 1.0f / F_SQRT3; + float sin_54 = F_SQRT2 * oo_sqrt3; + r_b.setRows(LLVector3(oo_sqrt3, 0.0, -sin_54), + LLVector3(0.0, 1.0, 0.0), + LLVector3(sin_54, 0.0, oo_sqrt3)); + + // Coordinate conversion + LLMatrix3 Lij = r_b * r_a; + LLMatrix3 Lij_inv = Lij; + Lij_inv.transpose(); + + // Local color rotation transform + LLMatrix3 r; + alpha *= DEG_TO_RAD; + r.setRows(LLVector3( cosf(alpha), sinf(alpha), 0.0), + LLVector3(-sinf(alpha), cosf(alpha), 0.0), + LLVector3( 0.0, 0.0, 1.0)); + + // Global color rotation transform + LLMatrix3 transfo = Lij_inv * r * Lij; + colorTransform(transfo); +} + // Filter Primitives void LLImageRaw::colorTransform(const LLMatrix3 &transform) { -- cgit v1.2.3 From 205a4e3dc63c338c05e27a4806cdfd6f50bac2b6 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 1 Jan 2014 19:42:10 -0800 Subject: ACME-1236 : WIP : add filterGamma, computeHistograms, colorCorrect, implemented filter gamma to llimage_libtest for testing --- indra/llimage/llimage.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 4 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 8b7c352437..d406995f3a 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -97,7 +97,11 @@ LLImageBase::LLImageBase() mHeight(0), mComponents(0), mBadBufferAllocation(false), - mAllowOverSize(false) + mAllowOverSize(false), + mHistoRed(NULL), + mHistoGreen(NULL), + mHistoBlue(NULL), + mHistoBrightness(NULL) { } @@ -105,10 +109,14 @@ LLImageBase::LLImageBase() LLImageBase::~LLImageBase() { deleteData(); // virtual + ll_aligned_free_16(mHistoRed); + ll_aligned_free_16(mHistoGreen); + ll_aligned_free_16(mHistoBlue); + ll_aligned_free_16(mHistoBrightness); } -//static -void LLImageBase::createPrivatePool() +//static +void LLImageBase::createPrivatePool() { if(!sPrivatePoolp) { @@ -1022,6 +1030,18 @@ void LLImageRaw::filterRotate(F32 alpha) colorTransform(transfo); } +void LLImageRaw::filterGamma(F32 gamma) +{ + U8 gamma_lut[256]; + + for (S32 i = 0; i < 256; i++) + { + gamma_lut[i] = (U8)(255.0 * (llclampf((float)(pow((float)(i)/255.0,gamma))))); + } + + colorCorrect(gamma_lut,gamma_lut,gamma_lut); +} + // Filter Primitives void LLImageRaw::colorTransform(const LLMatrix3 &transform) { @@ -1030,7 +1050,7 @@ void LLImageRaw::colorTransform(const LLMatrix3 &transform) S32 pixels = getWidth() * getHeight(); U8* dst_data = getData(); - for( S32 i=0; i= 1 && components <= 4 ); + + S32 pixels = getWidth() * getHeight(); + U8* dst_data = getData(); + for (S32 i = 0; i < pixels; i++) + { + dst_data[VRED] = lut_red[dst_data[VRED]]; + dst_data[VGREEN] = lut_green[dst_data[VGREEN]]; + dst_data[VBLUE] = lut_blue[dst_data[VBLUE]]; + dst_data += components; + } +} + +void LLImageRaw::computeHistograms() +{ + const S32 components = getComponents(); + llassert( components >= 1 && components <= 4 ); + + // Allocate memory for the histograms + if (!mHistoRed) + { + mHistoRed = (U32*) ll_aligned_malloc_16(256*sizeof(U32)); + } + if (!mHistoGreen) + { + mHistoGreen = (U32*) ll_aligned_malloc_16(256*sizeof(U32)); + } + if (!mHistoBlue) + { + mHistoBlue = (U32*) ll_aligned_malloc_16(256*sizeof(U32)); + } + if (!mHistoBrightness) + { + mHistoBrightness = (U32*) ll_aligned_malloc_16(256*sizeof(U32)); + } + + // Initialize them + for (S32 i = 0; i < 256; i++) + { + mHistoRed[i] = 0; + mHistoGreen[i] = 0; + mHistoBlue[i] = 0; + mHistoBrightness[i] = 0; + } + + // Compute them + S32 pixels = getWidth() * getHeight(); + U8* dst_data = getData(); + for (S32 i = 0; i < pixels; i++) + { + mHistoRed[dst_data[VRED]]++; + mHistoGreen[dst_data[VGREEN]]++; + mHistoBlue[dst_data[VBLUE]]++; + // Note: this is a very simple shorthand for brightness but it's OK for our use + S32 brightness = ((S32)(dst_data[VRED]) + (S32)(dst_data[VGREEN]) + (S32)(dst_data[VBLUE])) / 3; + mHistoBrightness[brightness]++; + // next pixel... + dst_data += components; + } +} + void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ) { const S32 components = getComponents(); -- cgit v1.2.3 From d28b92744ee0d4a19a5587585998e5c351f6d300 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 2 Jan 2014 16:14:38 -0800 Subject: ACME-1236 : WIP : added all the color correction filters: colorize, linarize, equalize, contrast, brightness --- indra/llimage/llimage.cpp | 155 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index d406995f3a..5dc9c24f6c 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1042,6 +1042,152 @@ void LLImageRaw::filterGamma(F32 gamma) colorCorrect(gamma_lut,gamma_lut,gamma_lut); } +void LLImageRaw::filterLinearize(F32 tail) +{ + // Get the histogram + U32* histo = getBrightnessHistogram(); + + // Compute cumulated histogram + U32 cumulated_histo[256]; + cumulated_histo[0] = histo[0]; + for (S32 i = 1; i < 256; i++) + { + cumulated_histo[i] = cumulated_histo[i-1] + histo[i]; + } + + // Compute min and max counts minus tail + tail = llclampf(tail); + S32 total = cumulated_histo[255]; + S32 min_c = (S32)((F32)(total) * tail); + S32 max_c = (S32)((F32)(total) * (1.0 - tail)); + + // Find min and max values + S32 min_v = 0; + while (cumulated_histo[min_v] < min_c) + { + min_v++; + } + S32 max_v = 255; + while (cumulated_histo[max_v] > max_c) + { + max_v--; + } + + // Compute linear lookup table + U8 linear_lut[256]; + if (max_v == min_v) + { + // Degenerated binary split case + for (S32 i = 0; i < 256; i++) + { + linear_lut[i] = (i < min_v ? 0 : 255); + } + } + else + { + // Linearize between min and max + F32 slope = 255.0 / (F32)(max_v - min_v); + F32 translate = -min_v * slope; + for (S32 i = 0; i < 256; i++) + { + linear_lut[i] = (U8)(llclampb((S32)(slope*i + translate))); + } + } + + // Apply lookup table + colorCorrect(linear_lut,linear_lut,linear_lut); +} + +void LLImageRaw::filterEqualize(S32 nb_classes) +{ + // Regularize the parameter: must be between 2 and 255 + nb_classes = llmax(nb_classes,2); + nb_classes = llclampb(nb_classes); + + // Get the histogram + U32* histo = getBrightnessHistogram(); + + // Compute cumulated histogram + U32 cumulated_histo[256]; + cumulated_histo[0] = histo[0]; + for (S32 i = 1; i < 256; i++) + { + cumulated_histo[i] = cumulated_histo[i-1] + histo[i]; + } + + // Compute deltas + S32 total = cumulated_histo[255]; + S32 delta_count = total / nb_classes; + S32 current_count = delta_count; + S32 delta_value = 256 / (nb_classes - 1); + S32 current_value = 0; + + // Compute equalized lookup table + U8 equalize_lut[256]; + for (S32 i = 0; i < 256; i++) + { + equalize_lut[i] = (U8)(current_value); + if (cumulated_histo[i] >= current_count) + { + current_count += delta_count; + current_value += delta_value; + current_value = llclampb(current_value); + } + } + + // Apply lookup table + colorCorrect(equalize_lut,equalize_lut,equalize_lut); +} + +void LLImageRaw::filterColorize(const LLColor4U& color) +{ + U8 red_lut[256]; + U8 green_lut[256]; + U8 blue_lut[256]; + + F32 alpha = (F32)(color.mV[3])/255.0; + F32 inv_alpha = 1.0 - alpha; + + F32 red_composite = alpha * (F32)(color.mV[0]); + F32 green_composite = alpha * (F32)(color.mV[1]); + F32 blue_composite = alpha * (F32)(color.mV[2]); + + for (S32 i = 0; i < 256; i++) + { + red_lut[i] = (U8)(llclampb((S32)(inv_alpha*(F32)(i) + red_composite))); + green_lut[i] = (U8)(llclampb((S32)(inv_alpha*(F32)(i) + green_composite))); + blue_lut[i] = (U8)(llclampb((S32)(inv_alpha*(F32)(i) + blue_composite))); + } + + colorCorrect(red_lut,green_lut,blue_lut); +} + +void LLImageRaw::filterContrast(F32 slope) +{ + U8 contrast_lut[256]; + + F32 translate = 128.0 * (1.0 - slope); + + for (S32 i = 0; i < 256; i++) + { + contrast_lut[i] = (U8)(llclampb((S32)(slope*i + translate))); + } + + colorCorrect(contrast_lut,contrast_lut,contrast_lut); +} + +void LLImageRaw::filterBrightness(S32 add) +{ + U8 brightness_lut[256]; + + for (S32 i = 0; i < 256; i++) + { + brightness_lut[i] = (U8)(llclampb((S32)((S32)(i) + add))); + } + + colorCorrect(brightness_lut,brightness_lut,brightness_lut); +} + // Filter Primitives void LLImageRaw::colorTransform(const LLMatrix3 &transform) { @@ -1078,6 +1224,15 @@ void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* } } +U32* LLImageRaw::getBrightnessHistogram() +{ + if (!mHistoBrightness) + { + computeHistograms(); + } + return mHistoBrightness; +} + void LLImageRaw::computeHistograms() { const S32 components = getComponents(); -- cgit v1.2.3 From 1b5fb662927ac84606cf767c8c9ec350e82b656f Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Fri, 3 Jan 2014 14:19:29 -0800 Subject: ACME-1236 : WIP : Added the vignette mode. Can be applied to colorCorrect and color Transform. Added new -v argument to llimage_libtest --- indra/llimage/llimage.cpp | 106 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 90 insertions(+), 16 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 5dc9c24f6c..da22ed5e5b 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -101,7 +101,9 @@ LLImageBase::LLImageBase() mHistoRed(NULL), mHistoGreen(NULL), mHistoBlue(NULL), - mHistoBrightness(NULL) + mHistoBrightness(NULL), + mVignetteMode(VIGNETTE_MODE_NONE), + mVignetteGamma(1.0) { } @@ -1194,17 +1196,44 @@ void LLImageRaw::colorTransform(const LLMatrix3 &transform) const S32 components = getComponents(); llassert( components >= 1 && components <= 4 ); - S32 pixels = getWidth() * getHeight(); + S32 width = getWidth(); + S32 height = getHeight(); + U8* dst_data = getData(); - for (S32 i = 0; i < pixels; i++) + for (S32 j = 0; j < height; j++) { - LLVector3 src((F32)(dst_data[VRED]),(F32)(dst_data[VGREEN]),(F32)(dst_data[VBLUE])); - LLVector3 dst = src * transform; - dst.clamp(0.0f,255.0f); - dst_data[VRED] = dst.mV[VRED]; - dst_data[VGREEN] = dst.mV[VGREEN]; - dst_data[VBLUE] = dst.mV[VBLUE]; - dst_data += components; + for (S32 i = 0; i < width; i++) + { + LLVector3 src((F32)(dst_data[VRED]),(F32)(dst_data[VGREEN]),(F32)(dst_data[VBLUE])); + LLVector3 dst = src * transform; + dst.clamp(0.0f,255.0f); + if (mVignetteMode == VIGNETTE_MODE_NONE) + { + dst_data[VRED] = dst.mV[VRED]; + dst_data[VGREEN] = dst.mV[VGREEN]; + dst_data[VBLUE] = dst.mV[VBLUE]; + } + else + { + F32 alpha = getVignetteAlpha(i,j); + if (mVignetteMode == VIGNETTE_MODE_BLEND) + { + // Blends with the source image on the edges + F32 inv_alpha = 1.0 - alpha; + dst_data[VRED] = inv_alpha * src.mV[VRED] + alpha * dst.mV[VRED]; + dst_data[VGREEN] = inv_alpha * src.mV[VGREEN] + alpha * dst.mV[VGREEN]; + dst_data[VBLUE] = inv_alpha * src.mV[VBLUE] + alpha * dst.mV[VBLUE]; + } + else // VIGNETTE_MODE_FADE + { + // Fade to black on the edges + dst_data[VRED] = alpha * dst.mV[VRED]; + dst_data[VGREEN] = alpha * dst.mV[VGREEN]; + dst_data[VBLUE] = alpha * dst.mV[VBLUE]; + } + } + dst_data += components; + } } } @@ -1213,17 +1242,62 @@ void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* const S32 components = getComponents(); llassert( components >= 1 && components <= 4 ); - S32 pixels = getWidth() * getHeight(); + S32 width = getWidth(); + S32 height = getHeight(); + U8* dst_data = getData(); - for (S32 i = 0; i < pixels; i++) + for (S32 j = 0; j < height; j++) { - dst_data[VRED] = lut_red[dst_data[VRED]]; - dst_data[VGREEN] = lut_green[dst_data[VGREEN]]; - dst_data[VBLUE] = lut_blue[dst_data[VBLUE]]; - dst_data += components; + for (S32 i = 0; i < width; i++) + { + if (mVignetteMode == VIGNETTE_MODE_NONE) + { + dst_data[VRED] = lut_red[dst_data[VRED]]; + dst_data[VGREEN] = lut_green[dst_data[VGREEN]]; + dst_data[VBLUE] = lut_blue[dst_data[VBLUE]]; + } + else + { + F32 alpha = getVignetteAlpha(i,j); + if (mVignetteMode == VIGNETTE_MODE_BLEND) + { + // Blends with the source image on the edges + F32 inv_alpha = 1.0 - alpha; + dst_data[VRED] = inv_alpha * dst_data[VRED] + alpha * lut_red[dst_data[VRED]]; + dst_data[VGREEN] = inv_alpha * dst_data[VGREEN] + alpha * lut_green[dst_data[VGREEN]]; + dst_data[VBLUE] = inv_alpha * dst_data[VBLUE] + alpha * lut_blue[dst_data[VBLUE]]; + } + else // VIGNETTE_MODE_FADE + { + // Fade to black on the edges + dst_data[VRED] = alpha * lut_red[dst_data[VRED]]; + dst_data[VGREEN] = alpha * lut_green[dst_data[VGREEN]]; + dst_data[VBLUE] = alpha * lut_blue[dst_data[VBLUE]]; + } + } + dst_data += components; + } } } +void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma) +{ + mVignetteMode = mode; + mVignetteGamma = gamma; + // We always center the vignette on the image and fits it in the image smallest dimension + mVignetteCenterX = getWidth()/2; + mVignetteCenterY = getHeight()/2; + mVignetteWidth = llmin(getWidth()/2,getHeight()/2); +} + +F32 LLImageRaw::getVignetteAlpha(S32 i, S32 j) +{ + // alpha is a modified gaussian value, with a center and fading in a circular pattern toward the edges + // the gamma parameter controls the intensity of the drop down from alpha 1.0 to 0.0 + F32 d_center_square = (i - mVignetteCenterX)*(i - mVignetteCenterX) + (j - mVignetteCenterY)*(j - mVignetteCenterY); + return powf(F_E, -(powf((d_center_square/(mVignetteWidth*mVignetteWidth)),mVignetteGamma)/2.0f)); +} + U32* LLImageRaw::getBrightnessHistogram() { if (!mHistoBrightness) -- cgit v1.2.3 From 35e30759c82e0fa425e2ee5ba235868a25b44169 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Fri, 3 Jan 2014 15:44:29 -0800 Subject: ACME-1236 : WIP : Added a min value to vignette --- indra/llimage/llimage.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index da22ed5e5b..d84989f9c8 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -103,7 +103,8 @@ LLImageBase::LLImageBase() mHistoBlue(NULL), mHistoBrightness(NULL), mVignetteMode(VIGNETTE_MODE_NONE), - mVignetteGamma(1.0) + mVignetteGamma(1.0), + mVignetteMin(0.0) { } @@ -1280,10 +1281,11 @@ void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* } } -void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma) +void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma, F32 min) { mVignetteMode = mode; mVignetteGamma = gamma; + mVignetteMin = llclampf(min); // We always center the vignette on the image and fits it in the image smallest dimension mVignetteCenterX = getWidth()/2; mVignetteCenterY = getHeight()/2; @@ -1293,9 +1295,11 @@ void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma) F32 LLImageRaw::getVignetteAlpha(S32 i, S32 j) { // alpha is a modified gaussian value, with a center and fading in a circular pattern toward the edges - // the gamma parameter controls the intensity of the drop down from alpha 1.0 to 0.0 + // The gamma parameter controls the intensity of the drop down from alpha 1.0 (center) to 0.0 F32 d_center_square = (i - mVignetteCenterX)*(i - mVignetteCenterX) + (j - mVignetteCenterY)*(j - mVignetteCenterY); - return powf(F_E, -(powf((d_center_square/(mVignetteWidth*mVignetteWidth)),mVignetteGamma)/2.0f)); + F32 alpha = powf(F_E, -(powf((d_center_square/(mVignetteWidth*mVignetteWidth)),mVignetteGamma)/2.0f)); + // We rescale alpha between min and 1.0 so to avoid complete fading if so desired. + return (mVignetteMin + alpha * (1.0 - mVignetteMin)); } U32* LLImageRaw::getBrightnessHistogram() -- cgit v1.2.3 From 90cbda6db0d075dccc2369a68b02919b40f53cca Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Fri, 3 Jan 2014 17:31:04 -0800 Subject: ACME-1236 : WIP : Add 2 new color correction filters. Add a la Instagram composite filters for testing in llimage_libtest --- indra/llimage/llimage.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index d84989f9c8..3d86abb26d 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1045,6 +1045,22 @@ void LLImageRaw::filterGamma(F32 gamma) colorCorrect(gamma_lut,gamma_lut,gamma_lut); } +void LLImageRaw::filterColorBalance(F32 gamma_red, F32 gamma_green, F32 gamma_blue) +{ + U8 gamma_red_lut[256]; + U8 gamma_green_lut[256]; + U8 gamma_blue_lut[256]; + + for (S32 i = 0; i < 256; i++) + { + gamma_red_lut[i] = (U8)(255.0 * (llclampf((float)(pow((float)(i)/255.0,gamma_red))))); + gamma_green_lut[i] = (U8)(255.0 * (llclampf((float)(pow((float)(i)/255.0,gamma_green))))); + gamma_blue_lut[i] = (U8)(255.0 * (llclampf((float)(pow((float)(i)/255.0,gamma_blue))))); + } + + colorCorrect(gamma_red_lut,gamma_green_lut,gamma_blue_lut); +} + void LLImageRaw::filterLinearize(F32 tail) { // Get the histogram @@ -1191,6 +1207,23 @@ void LLImageRaw::filterBrightness(S32 add) colorCorrect(brightness_lut,brightness_lut,brightness_lut); } +void LLImageRaw::filterMinMax(S32 min, S32 max) +{ + U8 contrast_lut[256]; + min = llclampb(min); + max = llclampb(max); + + F32 slope = 255.0/(F32)(max - min); + F32 translate = -slope*min; + + for (S32 i = 0; i < 256; i++) + { + contrast_lut[i] = (U8)(llclampb((S32)(slope*i + translate))); + } + + colorCorrect(contrast_lut,contrast_lut,contrast_lut); +} + // Filter Primitives void LLImageRaw::colorTransform(const LLMatrix3 &transform) { -- cgit v1.2.3 From 3cbd0dfd849a94a789ae70f4bdc176f85cf2ba34 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Mon, 6 Jan 2014 14:46:52 -0800 Subject: ACME-1236 : WIP : Make each color correct filter use a per channel alpha argument, tweak Instagram-like test filters for discussion --- indra/llimage/llimage.cpp | 118 +++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 60 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 3d86abb26d..977bb09b63 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -29,6 +29,7 @@ #include "llimage.h" #include "llmath.h" +#include "v3color.h" #include "v4coloru.h" #include "m3math.h" #include "v3math.h" @@ -1033,19 +1034,7 @@ void LLImageRaw::filterRotate(F32 alpha) colorTransform(transfo); } -void LLImageRaw::filterGamma(F32 gamma) -{ - U8 gamma_lut[256]; - - for (S32 i = 0; i < 256; i++) - { - gamma_lut[i] = (U8)(255.0 * (llclampf((float)(pow((float)(i)/255.0,gamma))))); - } - - colorCorrect(gamma_lut,gamma_lut,gamma_lut); -} - -void LLImageRaw::filterColorBalance(F32 gamma_red, F32 gamma_green, F32 gamma_blue) +void LLImageRaw::filterGamma(F32 gamma, const LLColor3& alpha) { U8 gamma_red_lut[256]; U8 gamma_green_lut[256]; @@ -1053,15 +1042,17 @@ void LLImageRaw::filterColorBalance(F32 gamma_red, F32 gamma_green, F32 gamma_bl for (S32 i = 0; i < 256; i++) { - gamma_red_lut[i] = (U8)(255.0 * (llclampf((float)(pow((float)(i)/255.0,gamma_red))))); - gamma_green_lut[i] = (U8)(255.0 * (llclampf((float)(pow((float)(i)/255.0,gamma_green))))); - gamma_blue_lut[i] = (U8)(255.0 * (llclampf((float)(pow((float)(i)/255.0,gamma_blue))))); + F32 gamma_i = llclampf((float)(pow((float)(i)/255.0,gamma))); + // Blend in with alpha values + gamma_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * 255.0 * gamma_i); + gamma_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * 255.0 * gamma_i); + gamma_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * 255.0 * gamma_i); } colorCorrect(gamma_red_lut,gamma_green_lut,gamma_blue_lut); } -void LLImageRaw::filterLinearize(F32 tail) +void LLImageRaw::filterLinearize(F32 tail, const LLColor3& alpha) { // Get the histogram U32* histo = getBrightnessHistogram(); @@ -1093,13 +1084,19 @@ void LLImageRaw::filterLinearize(F32 tail) } // Compute linear lookup table - U8 linear_lut[256]; + U8 linear_red_lut[256]; + U8 linear_green_lut[256]; + U8 linear_blue_lut[256]; if (max_v == min_v) { // Degenerated binary split case for (S32 i = 0; i < 256; i++) { - linear_lut[i] = (i < min_v ? 0 : 255); + U8 value_i = (i < min_v ? 0 : 255); + // Blend in with alpha values + linear_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); + linear_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); + linear_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); } } else @@ -1109,15 +1106,19 @@ void LLImageRaw::filterLinearize(F32 tail) F32 translate = -min_v * slope; for (S32 i = 0; i < 256; i++) { - linear_lut[i] = (U8)(llclampb((S32)(slope*i + translate))); + U8 value_i = (U8)(llclampb((S32)(slope*i + translate))); + // Blend in with alpha values + linear_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); + linear_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); + linear_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); } } // Apply lookup table - colorCorrect(linear_lut,linear_lut,linear_lut); + colorCorrect(linear_red_lut,linear_green_lut,linear_blue_lut); } -void LLImageRaw::filterEqualize(S32 nb_classes) +void LLImageRaw::filterEqualize(S32 nb_classes, const LLColor3& alpha) { // Regularize the parameter: must be between 2 and 255 nb_classes = llmax(nb_classes,2); @@ -1142,10 +1143,15 @@ void LLImageRaw::filterEqualize(S32 nb_classes) S32 current_value = 0; // Compute equalized lookup table - U8 equalize_lut[256]; + U8 equalize_red_lut[256]; + U8 equalize_green_lut[256]; + U8 equalize_blue_lut[256]; for (S32 i = 0; i < 256; i++) { - equalize_lut[i] = (U8)(current_value); + // Blend in current_value with alpha values + equalize_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * current_value); + equalize_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * current_value); + equalize_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * current_value); if (cumulated_histo[i] >= current_count) { current_count += delta_count; @@ -1155,73 +1161,65 @@ void LLImageRaw::filterEqualize(S32 nb_classes) } // Apply lookup table - colorCorrect(equalize_lut,equalize_lut,equalize_lut); + colorCorrect(equalize_red_lut,equalize_green_lut,equalize_blue_lut); } -void LLImageRaw::filterColorize(const LLColor4U& color) +void LLImageRaw::filterColorize(const LLColor3& color, const LLColor3& alpha) { U8 red_lut[256]; U8 green_lut[256]; U8 blue_lut[256]; - F32 alpha = (F32)(color.mV[3])/255.0; - F32 inv_alpha = 1.0 - alpha; - - F32 red_composite = alpha * (F32)(color.mV[0]); - F32 green_composite = alpha * (F32)(color.mV[1]); - F32 blue_composite = alpha * (F32)(color.mV[2]); + F32 red_composite = 255.0 * alpha.mV[0] * color.mV[0]; + F32 green_composite = 255.0 * alpha.mV[1] * color.mV[1]; + F32 blue_composite = 255.0 * alpha.mV[2] * color.mV[2]; for (S32 i = 0; i < 256; i++) { - red_lut[i] = (U8)(llclampb((S32)(inv_alpha*(F32)(i) + red_composite))); - green_lut[i] = (U8)(llclampb((S32)(inv_alpha*(F32)(i) + green_composite))); - blue_lut[i] = (U8)(llclampb((S32)(inv_alpha*(F32)(i) + blue_composite))); + red_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[0]) * (F32)(i) + red_composite))); + green_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[1]) * (F32)(i) + green_composite))); + blue_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[2]) * (F32)(i) + blue_composite))); } colorCorrect(red_lut,green_lut,blue_lut); } -void LLImageRaw::filterContrast(F32 slope) +void LLImageRaw::filterContrast(F32 slope, const LLColor3& alpha) { - U8 contrast_lut[256]; + U8 contrast_red_lut[256]; + U8 contrast_green_lut[256]; + U8 contrast_blue_lut[256]; F32 translate = 128.0 * (1.0 - slope); for (S32 i = 0; i < 256; i++) { - contrast_lut[i] = (U8)(llclampb((S32)(slope*i + translate))); + U8 value_i = (U8)(llclampb((S32)(slope*i + translate))); + // Blend in with alpha values + contrast_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); + contrast_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); + contrast_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); } - colorCorrect(contrast_lut,contrast_lut,contrast_lut); + colorCorrect(contrast_red_lut,contrast_green_lut,contrast_blue_lut); } -void LLImageRaw::filterBrightness(S32 add) +void LLImageRaw::filterBrightness(S32 add, const LLColor3& alpha) { - U8 brightness_lut[256]; - - for (S32 i = 0; i < 256; i++) - { - brightness_lut[i] = (U8)(llclampb((S32)((S32)(i) + add))); - } - - colorCorrect(brightness_lut,brightness_lut,brightness_lut); -} - -void LLImageRaw::filterMinMax(S32 min, S32 max) -{ - U8 contrast_lut[256]; - min = llclampb(min); - max = llclampb(max); - - F32 slope = 255.0/(F32)(max - min); - F32 translate = -slope*min; + U8 brightness_red_lut[256]; + U8 brightness_green_lut[256]; + U8 brightness_blue_lut[256]; for (S32 i = 0; i < 256; i++) { - contrast_lut[i] = (U8)(llclampb((S32)(slope*i + translate))); + U8 value_i = (U8)(llclampb((S32)((S32)(i) + add))); + // Blend in with alpha values + brightness_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); + brightness_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); + brightness_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); } - colorCorrect(contrast_lut,contrast_lut,contrast_lut); + colorCorrect(brightness_red_lut,brightness_green_lut,brightness_blue_lut); } // Filter Primitives -- cgit v1.2.3 From c2a974f1556906f6ca69afb5942378c8dbf85169 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Tue, 7 Jan 2014 22:10:23 -0800 Subject: ACME-1236 : WIP : Introduced screenFilter, simple creative screening filter --- indra/llimage/llimage.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 977bb09b63..ae3de32788 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1312,6 +1312,52 @@ void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* } } +void LLImageRaw::screenFilter(const S32 wave_length) +{ + const S32 components = getComponents(); + llassert( components >= 1 && components <= 4 ); + + S32 width = getWidth(); + S32 height = getHeight(); + + U8* dst_data = getData(); + for (S32 j = 0; j < height; j++) + { + for (S32 i = 0; i < width; i++) + { + F32 value = (sinf(2*F_PI*i/wave_length)*sinf(2*F_PI*j/wave_length)+1.0)*255.0/2.0; + //F32 value = (sinf(2*F_PI*i/wave_length)+1.0)*255.0/2.0; // will do line + U8 dst_value = (dst_data[VRED] >= (U8)(value) ? 255 : 0); + if (mVignetteMode == VIGNETTE_MODE_NONE) + { + dst_data[VRED] = dst_value; + dst_data[VGREEN] = dst_value; + dst_data[VBLUE] = dst_value; + } + else + { + F32 alpha = getVignetteAlpha(i,j); + if (mVignetteMode == VIGNETTE_MODE_BLEND) + { + // Blends with the source image on the edges + F32 inv_alpha = 1.0 - alpha; + dst_data[VRED] = inv_alpha * dst_data[VRED] + alpha * dst_value; + dst_data[VGREEN] = inv_alpha * dst_data[VGREEN] + alpha * dst_value; + dst_data[VBLUE] = inv_alpha * dst_data[VBLUE] + alpha * dst_value; + } + else // VIGNETTE_MODE_FADE + { + // Fade to black on the edges + dst_data[VRED] = alpha * dst_value; + dst_data[VGREEN] = alpha * dst_value; + dst_data[VBLUE] = alpha * dst_value; + } + } + dst_data += components; + } + } +} + void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma, F32 min) { mVignetteMode = mode; -- cgit v1.2.3 From 3161d822ab1336a347f1bb34574b5c4b8e747799 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 8 Jan 2014 15:41:42 -0800 Subject: ACME-1236 : WIP : Added mode and angle parameter to filterScreen (renamed for consistency) --- indra/llimage/llimage.cpp | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index ae3de32788..a30646d846 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1000,7 +1000,7 @@ void LLImageRaw::filterSaturate(F32 saturation) colorTransform(transfo); } -void LLImageRaw::filterRotate(F32 alpha) +void LLImageRaw::filterRotate(F32 angle) { // Matrix to Lij LLMatrix3 r_a; @@ -1024,9 +1024,9 @@ void LLImageRaw::filterRotate(F32 alpha) // Local color rotation transform LLMatrix3 r; - alpha *= DEG_TO_RAD; - r.setRows(LLVector3( cosf(alpha), sinf(alpha), 0.0), - LLVector3(-sinf(alpha), cosf(alpha), 0.0), + angle *= DEG_TO_RAD; + r.setRows(LLVector3( cosf(angle), sinf(angle), 0.0), + LLVector3(-sinf(angle), cosf(angle), 0.0), LLVector3( 0.0, 0.0, 1.0)); // Global color rotation transform @@ -1312,7 +1312,7 @@ void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* } } -void LLImageRaw::screenFilter(const S32 wave_length) +void LLImageRaw::filterScreen(EScreenMode mode, const S32 wave_length, const F32 angle) { const S32 components = getComponents(); llassert( components >= 1 && components <= 4 ); @@ -1320,14 +1320,28 @@ void LLImageRaw::screenFilter(const S32 wave_length) S32 width = getWidth(); S32 height = getHeight(); + F32 sin = sinf(angle*DEG_TO_RAD); + F32 cos = cosf(angle*DEG_TO_RAD); + U8* dst_data = getData(); for (S32 j = 0; j < height; j++) { for (S32 i = 0; i < width; i++) { - F32 value = (sinf(2*F_PI*i/wave_length)*sinf(2*F_PI*j/wave_length)+1.0)*255.0/2.0; - //F32 value = (sinf(2*F_PI*i/wave_length)+1.0)*255.0/2.0; // will do line + F32 value = 0.0; + F32 d = 0.0; + switch (mode) + { + case SCREEN_MODE_2DSINE: + value = (sinf(2*F_PI*i/wave_length)*sinf(2*F_PI*j/wave_length)+1.0)*255.0/2.0; + break; + case SCREEN_MODE_LINE: + d = sin*i - cos*j; + value = (sinf(2*F_PI*d/wave_length)+1.0)*255.0/2.0; + break; + } U8 dst_value = (dst_data[VRED] >= (U8)(value) ? 255 : 0); + if (mVignetteMode == VIGNETTE_MODE_NONE) { dst_data[VRED] = dst_value; -- cgit v1.2.3 From 70b877da0eccca2e11c810a92c0a928baf802334 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 8 Jan 2014 21:19:21 -0800 Subject: Fix ambiguous pow call (use powf) instead --- indra/llimage/llimage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index a30646d846..14fa71d828 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1042,7 +1042,7 @@ void LLImageRaw::filterGamma(F32 gamma, const LLColor3& alpha) for (S32 i = 0; i < 256; i++) { - F32 gamma_i = llclampf((float)(pow((float)(i)/255.0,gamma))); + F32 gamma_i = llclampf((float)(powf((float)(i)/255.0,gamma))); // Blend in with alpha values gamma_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * 255.0 * gamma_i); gamma_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * 255.0 * gamma_i); -- cgit v1.2.3 From 0c7cab771cb7972ed44eedf0c16133ef082eb9e1 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 9 Jan 2014 21:58:30 -0800 Subject: ACME-1236 : Add lines as a new type of vignette and Brightscan as an example --- indra/llimage/llimage.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 14fa71d828..3105fe3746 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1372,9 +1372,10 @@ void LLImageRaw::filterScreen(EScreenMode mode, const S32 wave_length, const F32 } } -void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma, F32 min) +void LLImageRaw::setVignette(EVignetteMode mode, EVignetteType type, F32 gamma, F32 min) { mVignetteMode = mode; + mVignetteType = type; mVignetteGamma = gamma; mVignetteMin = llclampf(min); // We always center the vignette on the image and fits it in the image smallest dimension @@ -1385,10 +1386,20 @@ void LLImageRaw::setVignette(EVignetteMode mode, F32 gamma, F32 min) F32 LLImageRaw::getVignetteAlpha(S32 i, S32 j) { - // alpha is a modified gaussian value, with a center and fading in a circular pattern toward the edges - // The gamma parameter controls the intensity of the drop down from alpha 1.0 (center) to 0.0 - F32 d_center_square = (i - mVignetteCenterX)*(i - mVignetteCenterX) + (j - mVignetteCenterY)*(j - mVignetteCenterY); - F32 alpha = powf(F_E, -(powf((d_center_square/(mVignetteWidth*mVignetteWidth)),mVignetteGamma)/2.0f)); + F32 alpha = 1.0; + if (mVignetteType == VIGNETTE_TYPE_CENTER) + { + // alpha is a modified gaussian value, with a center and fading in a circular pattern toward the edges + // The gamma parameter controls the intensity of the drop down from alpha 1.0 (center) to 0.0 + F32 d_center_square = (i - mVignetteCenterX)*(i - mVignetteCenterX) + (j - mVignetteCenterY)*(j - mVignetteCenterY); + alpha = powf(F_E, -(powf((d_center_square/(mVignetteWidth*mVignetteWidth)),mVignetteGamma)/2.0f)); + } + else if (mVignetteType == VIGNETTE_TYPE_LINES) + { + // alpha varies according to a squared sine function vertically. + // gamma is interpreted as the wavelength (in pixels) of the sine in that case. + alpha = (sinf(2*F_PI*j/mVignetteGamma) > 0.0 ? 1.0 : 0.0); + } // We rescale alpha between min and 1.0 so to avoid complete fading if so desired. return (mVignetteMin + alpha * (1.0 - mVignetteMin)); } -- cgit v1.2.3 From 7cc64a09a3ca9211354427206f04d157c9ac30a2 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Tue, 14 Jan 2014 21:01:51 -0800 Subject: ACME-1236 : Refactor filters and vignette into llimagefilter, add example filters to llimage_libtest --- indra/llimage/llimage.cpp | 527 +--------------------------------------------- 1 file changed, 1 insertion(+), 526 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 3105fe3746..7981ca7364 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -98,14 +98,7 @@ LLImageBase::LLImageBase() mHeight(0), mComponents(0), mBadBufferAllocation(false), - mAllowOverSize(false), - mHistoRed(NULL), - mHistoGreen(NULL), - mHistoBlue(NULL), - mHistoBrightness(NULL), - mVignetteMode(VIGNETTE_MODE_NONE), - mVignetteGamma(1.0), - mVignetteMin(0.0) + mAllowOverSize(false) { } @@ -113,10 +106,6 @@ LLImageBase::LLImageBase() LLImageBase::~LLImageBase() { deleteData(); // virtual - ll_aligned_free_16(mHistoRed); - ll_aligned_free_16(mHistoGreen); - ll_aligned_free_16(mHistoBlue); - ll_aligned_free_16(mHistoBrightness); } //static @@ -947,520 +936,6 @@ BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) return TRUE ; } -// Filter Operations -void LLImageRaw::filterGrayScale() -{ - LLMatrix3 gray_scale; - LLVector3 luminosity(0.2125, 0.7154, 0.0721); - gray_scale.setRows(luminosity, luminosity, luminosity); - gray_scale.transpose(); - colorTransform(gray_scale); -} - -void LLImageRaw::filterSepia() -{ - LLMatrix3 sepia; - sepia.setRows(LLVector3(0.3588, 0.7044, 0.1368), - LLVector3(0.2990, 0.5870, 0.1140), - LLVector3(0.2392, 0.4696, 0.0912)); - sepia.transpose(); - colorTransform(sepia); -} - -void LLImageRaw::filterSaturate(F32 saturation) -{ - // Matrix to Lij - LLMatrix3 r_a; - LLMatrix3 r_b; - - // 45 degre rotation around z - r_a.setRows(LLVector3( OO_SQRT2, OO_SQRT2, 0.0), - LLVector3(-OO_SQRT2, OO_SQRT2, 0.0), - LLVector3( 0.0, 0.0, 1.0)); - // 54.73 degre rotation around y - float oo_sqrt3 = 1.0f / F_SQRT3; - float sin_54 = F_SQRT2 * oo_sqrt3; - r_b.setRows(LLVector3(oo_sqrt3, 0.0, -sin_54), - LLVector3(0.0, 1.0, 0.0), - LLVector3(sin_54, 0.0, oo_sqrt3)); - - // Coordinate conversion - LLMatrix3 Lij = r_b * r_a; - LLMatrix3 Lij_inv = Lij; - Lij_inv.transpose(); - - // Local saturation transform - LLMatrix3 s; - s.setRows(LLVector3(saturation, 0.0, 0.0), - LLVector3(0.0, saturation, 0.0), - LLVector3(0.0, 0.0, 1.0)); - - // Global saturation transform - LLMatrix3 transfo = Lij_inv * s * Lij; - colorTransform(transfo); -} - -void LLImageRaw::filterRotate(F32 angle) -{ - // Matrix to Lij - LLMatrix3 r_a; - LLMatrix3 r_b; - - // 45 degre rotation around z - r_a.setRows(LLVector3( OO_SQRT2, OO_SQRT2, 0.0), - LLVector3(-OO_SQRT2, OO_SQRT2, 0.0), - LLVector3( 0.0, 0.0, 1.0)); - // 54.73 degre rotation around y - float oo_sqrt3 = 1.0f / F_SQRT3; - float sin_54 = F_SQRT2 * oo_sqrt3; - r_b.setRows(LLVector3(oo_sqrt3, 0.0, -sin_54), - LLVector3(0.0, 1.0, 0.0), - LLVector3(sin_54, 0.0, oo_sqrt3)); - - // Coordinate conversion - LLMatrix3 Lij = r_b * r_a; - LLMatrix3 Lij_inv = Lij; - Lij_inv.transpose(); - - // Local color rotation transform - LLMatrix3 r; - angle *= DEG_TO_RAD; - r.setRows(LLVector3( cosf(angle), sinf(angle), 0.0), - LLVector3(-sinf(angle), cosf(angle), 0.0), - LLVector3( 0.0, 0.0, 1.0)); - - // Global color rotation transform - LLMatrix3 transfo = Lij_inv * r * Lij; - colorTransform(transfo); -} - -void LLImageRaw::filterGamma(F32 gamma, const LLColor3& alpha) -{ - U8 gamma_red_lut[256]; - U8 gamma_green_lut[256]; - U8 gamma_blue_lut[256]; - - for (S32 i = 0; i < 256; i++) - { - F32 gamma_i = llclampf((float)(powf((float)(i)/255.0,gamma))); - // Blend in with alpha values - gamma_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * 255.0 * gamma_i); - gamma_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * 255.0 * gamma_i); - gamma_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * 255.0 * gamma_i); - } - - colorCorrect(gamma_red_lut,gamma_green_lut,gamma_blue_lut); -} - -void LLImageRaw::filterLinearize(F32 tail, const LLColor3& alpha) -{ - // Get the histogram - U32* histo = getBrightnessHistogram(); - - // Compute cumulated histogram - U32 cumulated_histo[256]; - cumulated_histo[0] = histo[0]; - for (S32 i = 1; i < 256; i++) - { - cumulated_histo[i] = cumulated_histo[i-1] + histo[i]; - } - - // Compute min and max counts minus tail - tail = llclampf(tail); - S32 total = cumulated_histo[255]; - S32 min_c = (S32)((F32)(total) * tail); - S32 max_c = (S32)((F32)(total) * (1.0 - tail)); - - // Find min and max values - S32 min_v = 0; - while (cumulated_histo[min_v] < min_c) - { - min_v++; - } - S32 max_v = 255; - while (cumulated_histo[max_v] > max_c) - { - max_v--; - } - - // Compute linear lookup table - U8 linear_red_lut[256]; - U8 linear_green_lut[256]; - U8 linear_blue_lut[256]; - if (max_v == min_v) - { - // Degenerated binary split case - for (S32 i = 0; i < 256; i++) - { - U8 value_i = (i < min_v ? 0 : 255); - // Blend in with alpha values - linear_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); - linear_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); - linear_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); - } - } - else - { - // Linearize between min and max - F32 slope = 255.0 / (F32)(max_v - min_v); - F32 translate = -min_v * slope; - for (S32 i = 0; i < 256; i++) - { - U8 value_i = (U8)(llclampb((S32)(slope*i + translate))); - // Blend in with alpha values - linear_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); - linear_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); - linear_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); - } - } - - // Apply lookup table - colorCorrect(linear_red_lut,linear_green_lut,linear_blue_lut); -} - -void LLImageRaw::filterEqualize(S32 nb_classes, const LLColor3& alpha) -{ - // Regularize the parameter: must be between 2 and 255 - nb_classes = llmax(nb_classes,2); - nb_classes = llclampb(nb_classes); - - // Get the histogram - U32* histo = getBrightnessHistogram(); - - // Compute cumulated histogram - U32 cumulated_histo[256]; - cumulated_histo[0] = histo[0]; - for (S32 i = 1; i < 256; i++) - { - cumulated_histo[i] = cumulated_histo[i-1] + histo[i]; - } - - // Compute deltas - S32 total = cumulated_histo[255]; - S32 delta_count = total / nb_classes; - S32 current_count = delta_count; - S32 delta_value = 256 / (nb_classes - 1); - S32 current_value = 0; - - // Compute equalized lookup table - U8 equalize_red_lut[256]; - U8 equalize_green_lut[256]; - U8 equalize_blue_lut[256]; - for (S32 i = 0; i < 256; i++) - { - // Blend in current_value with alpha values - equalize_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * current_value); - equalize_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * current_value); - equalize_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * current_value); - if (cumulated_histo[i] >= current_count) - { - current_count += delta_count; - current_value += delta_value; - current_value = llclampb(current_value); - } - } - - // Apply lookup table - colorCorrect(equalize_red_lut,equalize_green_lut,equalize_blue_lut); -} - -void LLImageRaw::filterColorize(const LLColor3& color, const LLColor3& alpha) -{ - U8 red_lut[256]; - U8 green_lut[256]; - U8 blue_lut[256]; - - F32 red_composite = 255.0 * alpha.mV[0] * color.mV[0]; - F32 green_composite = 255.0 * alpha.mV[1] * color.mV[1]; - F32 blue_composite = 255.0 * alpha.mV[2] * color.mV[2]; - - for (S32 i = 0; i < 256; i++) - { - red_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[0]) * (F32)(i) + red_composite))); - green_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[1]) * (F32)(i) + green_composite))); - blue_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[2]) * (F32)(i) + blue_composite))); - } - - colorCorrect(red_lut,green_lut,blue_lut); -} - -void LLImageRaw::filterContrast(F32 slope, const LLColor3& alpha) -{ - U8 contrast_red_lut[256]; - U8 contrast_green_lut[256]; - U8 contrast_blue_lut[256]; - - F32 translate = 128.0 * (1.0 - slope); - - for (S32 i = 0; i < 256; i++) - { - U8 value_i = (U8)(llclampb((S32)(slope*i + translate))); - // Blend in with alpha values - contrast_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); - contrast_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); - contrast_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); - } - - colorCorrect(contrast_red_lut,contrast_green_lut,contrast_blue_lut); -} - -void LLImageRaw::filterBrightness(S32 add, const LLColor3& alpha) -{ - U8 brightness_red_lut[256]; - U8 brightness_green_lut[256]; - U8 brightness_blue_lut[256]; - - for (S32 i = 0; i < 256; i++) - { - U8 value_i = (U8)(llclampb((S32)((S32)(i) + add))); - // Blend in with alpha values - brightness_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); - brightness_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); - brightness_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); - } - - colorCorrect(brightness_red_lut,brightness_green_lut,brightness_blue_lut); -} - -// Filter Primitives -void LLImageRaw::colorTransform(const LLMatrix3 &transform) -{ - const S32 components = getComponents(); - llassert( components >= 1 && components <= 4 ); - - S32 width = getWidth(); - S32 height = getHeight(); - - U8* dst_data = getData(); - for (S32 j = 0; j < height; j++) - { - for (S32 i = 0; i < width; i++) - { - LLVector3 src((F32)(dst_data[VRED]),(F32)(dst_data[VGREEN]),(F32)(dst_data[VBLUE])); - LLVector3 dst = src * transform; - dst.clamp(0.0f,255.0f); - if (mVignetteMode == VIGNETTE_MODE_NONE) - { - dst_data[VRED] = dst.mV[VRED]; - dst_data[VGREEN] = dst.mV[VGREEN]; - dst_data[VBLUE] = dst.mV[VBLUE]; - } - else - { - F32 alpha = getVignetteAlpha(i,j); - if (mVignetteMode == VIGNETTE_MODE_BLEND) - { - // Blends with the source image on the edges - F32 inv_alpha = 1.0 - alpha; - dst_data[VRED] = inv_alpha * src.mV[VRED] + alpha * dst.mV[VRED]; - dst_data[VGREEN] = inv_alpha * src.mV[VGREEN] + alpha * dst.mV[VGREEN]; - dst_data[VBLUE] = inv_alpha * src.mV[VBLUE] + alpha * dst.mV[VBLUE]; - } - else // VIGNETTE_MODE_FADE - { - // Fade to black on the edges - dst_data[VRED] = alpha * dst.mV[VRED]; - dst_data[VGREEN] = alpha * dst.mV[VGREEN]; - dst_data[VBLUE] = alpha * dst.mV[VBLUE]; - } - } - dst_data += components; - } - } -} - -void LLImageRaw::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue) -{ - const S32 components = getComponents(); - llassert( components >= 1 && components <= 4 ); - - S32 width = getWidth(); - S32 height = getHeight(); - - U8* dst_data = getData(); - for (S32 j = 0; j < height; j++) - { - for (S32 i = 0; i < width; i++) - { - if (mVignetteMode == VIGNETTE_MODE_NONE) - { - dst_data[VRED] = lut_red[dst_data[VRED]]; - dst_data[VGREEN] = lut_green[dst_data[VGREEN]]; - dst_data[VBLUE] = lut_blue[dst_data[VBLUE]]; - } - else - { - F32 alpha = getVignetteAlpha(i,j); - if (mVignetteMode == VIGNETTE_MODE_BLEND) - { - // Blends with the source image on the edges - F32 inv_alpha = 1.0 - alpha; - dst_data[VRED] = inv_alpha * dst_data[VRED] + alpha * lut_red[dst_data[VRED]]; - dst_data[VGREEN] = inv_alpha * dst_data[VGREEN] + alpha * lut_green[dst_data[VGREEN]]; - dst_data[VBLUE] = inv_alpha * dst_data[VBLUE] + alpha * lut_blue[dst_data[VBLUE]]; - } - else // VIGNETTE_MODE_FADE - { - // Fade to black on the edges - dst_data[VRED] = alpha * lut_red[dst_data[VRED]]; - dst_data[VGREEN] = alpha * lut_green[dst_data[VGREEN]]; - dst_data[VBLUE] = alpha * lut_blue[dst_data[VBLUE]]; - } - } - dst_data += components; - } - } -} - -void LLImageRaw::filterScreen(EScreenMode mode, const S32 wave_length, const F32 angle) -{ - const S32 components = getComponents(); - llassert( components >= 1 && components <= 4 ); - - S32 width = getWidth(); - S32 height = getHeight(); - - F32 sin = sinf(angle*DEG_TO_RAD); - F32 cos = cosf(angle*DEG_TO_RAD); - - U8* dst_data = getData(); - for (S32 j = 0; j < height; j++) - { - for (S32 i = 0; i < width; i++) - { - F32 value = 0.0; - F32 d = 0.0; - switch (mode) - { - case SCREEN_MODE_2DSINE: - value = (sinf(2*F_PI*i/wave_length)*sinf(2*F_PI*j/wave_length)+1.0)*255.0/2.0; - break; - case SCREEN_MODE_LINE: - d = sin*i - cos*j; - value = (sinf(2*F_PI*d/wave_length)+1.0)*255.0/2.0; - break; - } - U8 dst_value = (dst_data[VRED] >= (U8)(value) ? 255 : 0); - - if (mVignetteMode == VIGNETTE_MODE_NONE) - { - dst_data[VRED] = dst_value; - dst_data[VGREEN] = dst_value; - dst_data[VBLUE] = dst_value; - } - else - { - F32 alpha = getVignetteAlpha(i,j); - if (mVignetteMode == VIGNETTE_MODE_BLEND) - { - // Blends with the source image on the edges - F32 inv_alpha = 1.0 - alpha; - dst_data[VRED] = inv_alpha * dst_data[VRED] + alpha * dst_value; - dst_data[VGREEN] = inv_alpha * dst_data[VGREEN] + alpha * dst_value; - dst_data[VBLUE] = inv_alpha * dst_data[VBLUE] + alpha * dst_value; - } - else // VIGNETTE_MODE_FADE - { - // Fade to black on the edges - dst_data[VRED] = alpha * dst_value; - dst_data[VGREEN] = alpha * dst_value; - dst_data[VBLUE] = alpha * dst_value; - } - } - dst_data += components; - } - } -} - -void LLImageRaw::setVignette(EVignetteMode mode, EVignetteType type, F32 gamma, F32 min) -{ - mVignetteMode = mode; - mVignetteType = type; - mVignetteGamma = gamma; - mVignetteMin = llclampf(min); - // We always center the vignette on the image and fits it in the image smallest dimension - mVignetteCenterX = getWidth()/2; - mVignetteCenterY = getHeight()/2; - mVignetteWidth = llmin(getWidth()/2,getHeight()/2); -} - -F32 LLImageRaw::getVignetteAlpha(S32 i, S32 j) -{ - F32 alpha = 1.0; - if (mVignetteType == VIGNETTE_TYPE_CENTER) - { - // alpha is a modified gaussian value, with a center and fading in a circular pattern toward the edges - // The gamma parameter controls the intensity of the drop down from alpha 1.0 (center) to 0.0 - F32 d_center_square = (i - mVignetteCenterX)*(i - mVignetteCenterX) + (j - mVignetteCenterY)*(j - mVignetteCenterY); - alpha = powf(F_E, -(powf((d_center_square/(mVignetteWidth*mVignetteWidth)),mVignetteGamma)/2.0f)); - } - else if (mVignetteType == VIGNETTE_TYPE_LINES) - { - // alpha varies according to a squared sine function vertically. - // gamma is interpreted as the wavelength (in pixels) of the sine in that case. - alpha = (sinf(2*F_PI*j/mVignetteGamma) > 0.0 ? 1.0 : 0.0); - } - // We rescale alpha between min and 1.0 so to avoid complete fading if so desired. - return (mVignetteMin + alpha * (1.0 - mVignetteMin)); -} - -U32* LLImageRaw::getBrightnessHistogram() -{ - if (!mHistoBrightness) - { - computeHistograms(); - } - return mHistoBrightness; -} - -void LLImageRaw::computeHistograms() -{ - const S32 components = getComponents(); - llassert( components >= 1 && components <= 4 ); - - // Allocate memory for the histograms - if (!mHistoRed) - { - mHistoRed = (U32*) ll_aligned_malloc_16(256*sizeof(U32)); - } - if (!mHistoGreen) - { - mHistoGreen = (U32*) ll_aligned_malloc_16(256*sizeof(U32)); - } - if (!mHistoBlue) - { - mHistoBlue = (U32*) ll_aligned_malloc_16(256*sizeof(U32)); - } - if (!mHistoBrightness) - { - mHistoBrightness = (U32*) ll_aligned_malloc_16(256*sizeof(U32)); - } - - // Initialize them - for (S32 i = 0; i < 256; i++) - { - mHistoRed[i] = 0; - mHistoGreen[i] = 0; - mHistoBlue[i] = 0; - mHistoBrightness[i] = 0; - } - - // Compute them - S32 pixels = getWidth() * getHeight(); - U8* dst_data = getData(); - for (S32 i = 0; i < pixels; i++) - { - mHistoRed[dst_data[VRED]]++; - mHistoGreen[dst_data[VGREEN]]++; - mHistoBlue[dst_data[VBLUE]]++; - // Note: this is a very simple shorthand for brightness but it's OK for our use - S32 brightness = ((S32)(dst_data[VRED]) + (S32)(dst_data[VGREEN]) + (S32)(dst_data[VBLUE])) / 3; - mHistoBrightness[brightness]++; - // next pixel... - dst_data += components; - } -} - void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ) { const S32 components = getComponents(); -- cgit v1.2.3 From 4b2e69d8e054134bea7216639effef90b51c3aae Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 15 Jan 2014 10:27:49 -0800 Subject: ACME-1236 : Clean up llimage after refactoring so there's no difference with viewer-release --- indra/llimage/llimage.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 7981ca7364..c8a05e1fae 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -29,10 +29,7 @@ #include "llimage.h" #include "llmath.h" -#include "v3color.h" #include "v4coloru.h" -#include "m3math.h" -#include "v3math.h" #include "llimagebmp.h" #include "llimagetga.h" @@ -108,8 +105,8 @@ LLImageBase::~LLImageBase() deleteData(); // virtual } -//static -void LLImageBase::createPrivatePool() +//static +void LLImageBase::createPrivatePool() { if(!sPrivatePoolp) { -- cgit v1.2.3 From 6bf3cb875cef4da7c35850ebbea5100dc5244601 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Tue, 28 Jan 2014 10:19:57 -0800 Subject: ACME-1195 : WIP : Lazy evaluate intermediate images in snapshot preview so perf is better in common cases, allow thumbnail to be computed from grabed frame (for SL Share), thumbnail display still buggy in SL Share --- indra/llimage/llimage.cpp | 80 ++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 42 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index c8a05e1fae..18e08b94a6 100755 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -449,18 +449,8 @@ void LLImageRaw::verticalFlip() void LLImageRaw::expandToPowerOfTwo(S32 max_dim, BOOL scale_image) { // Find new sizes - S32 new_width = MIN_IMAGE_SIZE; - S32 new_height = MIN_IMAGE_SIZE; - - while( (new_width < getWidth()) && (new_width < max_dim) ) - { - new_width <<= 1; - } - - while( (new_height < getHeight()) && (new_height < max_dim) ) - { - new_height <<= 1; - } + S32 new_width = expandDimToPowerOfTwo(getWidth(), max_dim); + S32 new_height = expandDimToPowerOfTwo(getHeight(), max_dim); scale( new_width, new_height, scale_image ); } @@ -468,55 +458,61 @@ void LLImageRaw::expandToPowerOfTwo(S32 max_dim, BOOL scale_image) void LLImageRaw::contractToPowerOfTwo(S32 max_dim, BOOL scale_image) { // Find new sizes - S32 new_width = max_dim; - S32 new_height = max_dim; - - while( (new_width > getWidth()) && (new_width > MIN_IMAGE_SIZE) ) - { - new_width >>= 1; - } - - while( (new_height > getHeight()) && (new_height > MIN_IMAGE_SIZE) ) - { - new_height >>= 1; - } + S32 new_width = contractDimToPowerOfTwo(getWidth(), MIN_IMAGE_SIZE); + S32 new_height = contractDimToPowerOfTwo(getHeight(), MIN_IMAGE_SIZE); scale( new_width, new_height, scale_image ); } -void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim) +// static +S32 LLImageRaw::biasedDimToPowerOfTwo(S32 curr_dim, S32 max_dim) { // Strong bias towards rounding down (to save bandwidth) // No bias would mean THRESHOLD == 1.5f; - const F32 THRESHOLD = 1.75f; - + const F32 THRESHOLD = 1.75f; + // Find new sizes - S32 larger_w = max_dim; // 2^n >= mWidth - S32 smaller_w = max_dim; // 2^(n-1) <= mWidth - while( (smaller_w > getWidth()) && (smaller_w > MIN_IMAGE_SIZE) ) + S32 larger_dim = max_dim; // 2^n >= curr_dim + S32 smaller_dim = max_dim; // 2^(n-1) <= curr_dim + while( (smaller_dim > curr_dim) && (smaller_dim > MIN_IMAGE_SIZE) ) { - larger_w = smaller_w; - smaller_w >>= 1; + larger_dim = smaller_dim; + smaller_dim >>= 1; } - S32 new_width = ( (F32)getWidth() / smaller_w > THRESHOLD ) ? larger_w : smaller_w; + return ( ((F32)curr_dim / (F32)smaller_dim) > THRESHOLD ) ? larger_dim : smaller_dim; +} +// static +S32 LLImageRaw::expandDimToPowerOfTwo(S32 curr_dim, S32 max_dim) +{ + S32 new_dim = MIN_IMAGE_SIZE; + while( (new_dim < curr_dim) && (new_dim < max_dim) ) + { + new_dim <<= 1; + } + return new_dim; +} - S32 larger_h = max_dim; // 2^m >= mHeight - S32 smaller_h = max_dim; // 2^(m-1) <= mHeight - while( (smaller_h > getHeight()) && (smaller_h > MIN_IMAGE_SIZE) ) +// static +S32 LLImageRaw::contractDimToPowerOfTwo(S32 curr_dim, S32 min_dim) +{ + S32 new_dim = MAX_IMAGE_SIZE; + while( (new_dim > curr_dim) && (new_dim > min_dim) ) { - larger_h = smaller_h; - smaller_h >>= 1; + new_dim >>= 1; } - S32 new_height = ( (F32)getHeight() / smaller_h > THRESHOLD ) ? larger_h : smaller_h; + return new_dim; +} +void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim) +{ + // Find new sizes + S32 new_width = biasedDimToPowerOfTwo(getWidth(),max_dim); + S32 new_height = biasedDimToPowerOfTwo(getHeight(),max_dim); scale( new_width, new_height ); } - - - // Calculates (U8)(255*(a/255.f)*(b/255.f) + 0.5f). Thanks, Jim Blinn! inline U8 LLImageRaw::fastFractionalMult( U8 a, U8 b ) { -- cgit v1.2.3