summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/integration_tests/llimage_libtest/1970colorize.xml41
-rwxr-xr-xindra/integration_tests/llimage_libtest/brighten.xml11
-rw-r--r--indra/integration_tests/llimage_libtest/colorize.xml20
-rw-r--r--indra/integration_tests/llimage_libtest/contrast.xml18
-rwxr-xr-xindra/integration_tests/llimage_libtest/darken.xml11
-rw-r--r--indra/integration_tests/llimage_libtest/gamma.xml18
-rw-r--r--indra/integration_tests/llimage_libtest/grayscale.xml14
-rw-r--r--indra/integration_tests/llimage_libtest/horizontalscreen.xml25
-rwxr-xr-xindra/integration_tests/llimage_libtest/linearize.xml11
-rwxr-xr-xindra/integration_tests/llimage_libtest/newsscreen.xml25
-rwxr-xr-xindra/integration_tests/llimage_libtest/posterize.xml18
-rw-r--r--indra/integration_tests/llimage_libtest/rotatecolors180.xml8
-rw-r--r--indra/integration_tests/llimage_libtest/saturate.xml8
-rw-r--r--indra/integration_tests/llimage_libtest/sepia.xml14
-rw-r--r--indra/integration_tests/llimage_libtest/slantedscreen.xml25
-rw-r--r--indra/integration_tests/llimage_libtest/spotlight.xml45
-rw-r--r--indra/integration_tests/llimage_libtest/verticalscreen.xml25
-rwxr-xr-xindra/integration_tests/llimage_libtest/video.xml23
-rwxr-xr-xindra/llimage/llimage.cpp527
-rwxr-xr-xindra/llimage/llimage.h61
-rwxr-xr-xindra/llimage/llimagefilter.cpp641
-rwxr-xr-xindra/llimage/llimagefilter.h50
22 files changed, 956 insertions, 683 deletions
diff --git a/indra/integration_tests/llimage_libtest/1970colorize.xml b/indra/integration_tests/llimage_libtest/1970colorize.xml
new file mode 100644
index 0000000000..0dab2489a0
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/1970colorize.xml
@@ -0,0 +1,41 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.1</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>contrast</string>
+ <real>0.8</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>colorize</string>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>0.5</real>
+ <real>0.0</real>
+ <real>0.0</real>
+ </array>
+ <array>
+ <string>blend</string>
+ <real>10.0</real>
+ <real>0.0</real>
+ </array>
+ <array>
+ <string>colorize</string>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>0.1</real>
+ <real>0.1</real>
+ <real>0.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/brighten.xml b/indra/integration_tests/llimage_libtest/brighten.xml
new file mode 100755
index 0000000000..d17b96d2d7
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/brighten.xml
@@ -0,0 +1,11 @@
+<llsd>
+ <array>
+ <array>
+ <string>brighten</string>
+ <real>50.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/colorize.xml b/indra/integration_tests/llimage_libtest/colorize.xml
new file mode 100644
index 0000000000..18c6cd3425
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/colorize.xml
@@ -0,0 +1,20 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>colorize</string>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>0.2</real>
+ <real>0.0</real>
+ <real>0.2</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/contrast.xml b/indra/integration_tests/llimage_libtest/contrast.xml
new file mode 100644
index 0000000000..8dcdd1a9a9
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/contrast.xml
@@ -0,0 +1,18 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>contrast</string>
+ <real>1.5</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/darken.xml b/indra/integration_tests/llimage_libtest/darken.xml
new file mode 100755
index 0000000000..8d110452e9
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/darken.xml
@@ -0,0 +1,11 @@
+<llsd>
+ <array>
+ <array>
+ <string>darken</string>
+ <real>50.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/gamma.xml b/indra/integration_tests/llimage_libtest/gamma.xml
new file mode 100644
index 0000000000..7505a03027
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/gamma.xml
@@ -0,0 +1,18 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>gamma</string>
+ <real>1.5</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/grayscale.xml b/indra/integration_tests/llimage_libtest/grayscale.xml
new file mode 100644
index 0000000000..984312c4fd
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/grayscale.xml
@@ -0,0 +1,14 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>grayscale</string>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/horizontalscreen.xml b/indra/integration_tests/llimage_libtest/horizontalscreen.xml
new file mode 100644
index 0000000000..ddff4d1977
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/horizontalscreen.xml
@@ -0,0 +1,25 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.1</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>grayscale</string>
+ </array>
+ <array>
+ <string>blend</string>
+ <real>0.0</real>
+ <real>0.0</real>
+ </array>
+ <array>
+ <string>screen</string>
+ <string>line</string>
+ <real>5.0</real>
+ <real>0.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/linearize.xml b/indra/integration_tests/llimage_libtest/linearize.xml
new file mode 100755
index 0000000000..23d0290e07
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/linearize.xml
@@ -0,0 +1,11 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.1</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/newsscreen.xml b/indra/integration_tests/llimage_libtest/newsscreen.xml
new file mode 100755
index 0000000000..8247c34500
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/newsscreen.xml
@@ -0,0 +1,25 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.1</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>grayscale</string>
+ </array>
+ <array>
+ <string>blend</string>
+ <real>0.0</real>
+ <real>0.0</real>
+ </array>
+ <array>
+ <string>screen</string>
+ <string>2Dsine</string>
+ <real>5.0</real>
+ <real>0.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/posterize.xml b/indra/integration_tests/llimage_libtest/posterize.xml
new file mode 100755
index 0000000000..f026278f9e
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/posterize.xml
@@ -0,0 +1,18 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>posterize</string>
+ <real>10.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/rotatecolors180.xml b/indra/integration_tests/llimage_libtest/rotatecolors180.xml
new file mode 100644
index 0000000000..e25029720f
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/rotatecolors180.xml
@@ -0,0 +1,8 @@
+<llsd>
+ <array>
+ <array>
+ <string>rotate</string>
+ <real>180.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/saturate.xml b/indra/integration_tests/llimage_libtest/saturate.xml
new file mode 100644
index 0000000000..b77f07a037
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/saturate.xml
@@ -0,0 +1,8 @@
+<llsd>
+ <array>
+ <array>
+ <string>saturate</string>
+ <real>3.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/sepia.xml b/indra/integration_tests/llimage_libtest/sepia.xml
new file mode 100644
index 0000000000..0304ead015
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/sepia.xml
@@ -0,0 +1,14 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>sepia</string>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/slantedscreen.xml b/indra/integration_tests/llimage_libtest/slantedscreen.xml
new file mode 100644
index 0000000000..63ad01d51d
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/slantedscreen.xml
@@ -0,0 +1,25 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.1</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>grayscale</string>
+ </array>
+ <array>
+ <string>blend</string>
+ <real>0.0</real>
+ <real>0.0</real>
+ </array>
+ <array>
+ <string>screen</string>
+ <string>line</string>
+ <real>5.0</real>
+ <real>45.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/spotlight.xml b/indra/integration_tests/llimage_libtest/spotlight.xml
new file mode 100644
index 0000000000..203130bdee
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/spotlight.xml
@@ -0,0 +1,45 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.1</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>contrast</string>
+ <real>0.8</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>saturate</string>
+ <real>1.5</real>
+ </array>
+ <array>
+ <string>fade</string>
+ <real>1.0</real>
+ <real>0.25</real>
+ </array>
+ <array>
+ <string>saturate</string>
+ <real>0.8</real>
+ </array>
+ <array>
+ <string>contrast</string>
+ <real>1.1</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>brighten</string>
+ <real>30</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/verticalscreen.xml b/indra/integration_tests/llimage_libtest/verticalscreen.xml
new file mode 100644
index 0000000000..71e48df656
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/verticalscreen.xml
@@ -0,0 +1,25 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.1</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>grayscale</string>
+ </array>
+ <array>
+ <string>blend</string>
+ <real>0.0</real>
+ <real>0.0</real>
+ </array>
+ <array>
+ <string>screen</string>
+ <string>line</string>
+ <real>5.0</real>
+ <real>90.0</real>
+ </array>
+ </array>
+</llsd>
diff --git a/indra/integration_tests/llimage_libtest/video.xml b/indra/integration_tests/llimage_libtest/video.xml
new file mode 100755
index 0000000000..8b10687ef5
--- /dev/null
+++ b/indra/integration_tests/llimage_libtest/video.xml
@@ -0,0 +1,23 @@
+<llsd>
+ <array>
+ <array>
+ <string>linearize</string>
+ <real>0.01</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ <array>
+ <string>lines</string>
+ <real>10.0</real>
+ <real>0.0</real>
+ </array>
+ <array>
+ <string>brighten</string>
+ <real>100.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ <real>1.0</real>
+ </array>
+ </array>
+</llsd>
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();
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index a600f2e4a6..4b1da233e1 100755
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -88,25 +88,6 @@ typedef enum e_image_codec
IMG_CODEC_EOF = 8
} EImageCodec;
-typedef enum e_vignette_mode
-{
- VIGNETTE_MODE_NONE = 0,
- VIGNETTE_MODE_BLEND = 1,
- VIGNETTE_MODE_FADE = 2
-} EVignetteMode;
-
-typedef enum e_vignette_type
-{
- VIGNETTE_TYPE_CENTER = 0,
- VIGNETTE_TYPE_LINES = 1
-} EVignetteType;
-
-typedef enum e_screen_mode
-{
- SCREEN_MODE_2DSINE = 0,
- SCREEN_MODE_LINE = 1
-} EScreenMode;
-
//============================================================================
// library initialization class
@@ -171,21 +152,6 @@ protected:
// special accessor to allow direct setting of mData and mDataSize by LLImageFormatted
void setDataAndSize(U8 *data, S32 size);
- // Histograms (if we ever happen to need them)
- U32 *mHistoRed;
- U32 *mHistoGreen;
- U32 *mHistoBlue;
- U32 *mHistoBrightness;
-
- // Vignette filtering
- EVignetteMode mVignetteMode;
- EVignetteType mVignetteType;
- S32 mVignetteCenterX;
- S32 mVignetteCenterY;
- S32 mVignetteWidth;
- F32 mVignetteGamma;
- F32 mVignetteMin;
-
public:
static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels);
@@ -291,30 +257,6 @@ public:
// Src and dst are same size. Src has 4 components. Dst has 3 components.
void compositeUnscaled4onto3( LLImageRaw* src );
-
- // Filter Operations : Transforms
- void filterGrayScale(); // Convert to grayscale
- void filterSepia(); // Convert to sepia
- void filterSaturate(F32 saturation); // < 1.0 desaturates, > 1.0 saturates
- void filterRotate(F32 angle); // Rotates hue according to angle, angle in degrees
-
- // Filter Operations : Color Corrections
- // When specified, the LLColor3 alpha parameter indicates the intensity of the effect for each color channel
- // acting in effect as an alpha blending factor different for each channel. For instance (1.0,0.0,0.0) will apply
- // the effect only to the Red channel. Intermediate values blends the effect with the source color.
- void filterGamma(F32 gamma, const LLColor3& alpha); // Apply gamma to each channel
- void filterLinearize(F32 tail, const LLColor3& alpha); // Use histogram to linearize constrast between min and max values minus tail
- void filterEqualize(S32 nb_classes, const LLColor3& alpha); // Use histogram to equalize constrast between nb_classes throughout the image
- void filterColorize(const LLColor3& color, const LLColor3& alpha); // Colorize with color and alpha per channel
- void filterContrast(F32 slope, const LLColor3& alpha); // Change contrast according to slope: > 1.0 more contrast, < 1.0 less contrast
- void filterBrightness(S32 add, const LLColor3& alpha); // Change brightness according to add: > 0 brighter, < 0 darker
-
- // Filter Primitives
- void colorTransform(const LLMatrix3 &transform);
- void colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue);
- void filterScreen(EScreenMode mode, const S32 wave_length, const F32 angle);
- void setVignette(EVignetteMode mode, EVignetteType type, F32 gamma, F32 min);
- U32* getBrightnessHistogram();
protected:
// Create an image from a local file (generally used in tools)
@@ -327,9 +269,6 @@ protected:
void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
- void computeHistograms();
- F32 getVignetteAlpha(S32 i, S32 j);
-
public:
static S32 sGlobalRawMemory;
static S32 sRawImageCount;
diff --git a/indra/llimage/llimagefilter.cpp b/indra/llimage/llimagefilter.cpp
index e2d281e48d..ed97d9ae17 100755
--- a/indra/llimage/llimagefilter.cpp
+++ b/indra/llimage/llimagefilter.cpp
@@ -40,16 +40,28 @@
//---------------------------------------------------------------------------
LLImageFilter::LLImageFilter() :
- mFilterData(LLSD::emptyArray())
+ mFilterData(LLSD::emptyArray()),
+ mImage(NULL),
+ mHistoRed(NULL),
+ mHistoGreen(NULL),
+ mHistoBlue(NULL),
+ mHistoBrightness(NULL),
+ mVignetteMode(VIGNETTE_MODE_NONE),
+ mVignetteGamma(1.0),
+ mVignetteMin(0.0)
{
}
LLImageFilter::~LLImageFilter()
{
+ mImage = NULL;
+ ll_aligned_free_16(mHistoRed);
+ ll_aligned_free_16(mHistoGreen);
+ ll_aligned_free_16(mHistoBlue);
+ ll_aligned_free_16(mHistoBrightness);
}
/*
- " -f, --filter <name> [<param>]\n"
" Apply the filter <name> to the input images using the optional <param> value. Admissible names:\n"
" - 'grayscale' converts to grayscale (no param).\n"
" - 'sepia' converts to sepia (no param).\n"
@@ -67,86 +79,10 @@ LLImageFilter::~LLImageFilter()
" - 'verticalscreen' applies a vertical screening to the red channel and output to black and white.\n"
" - 'slantedscreen' applies a 45 degrees slanted screening to the red channel and output to black and white.\n"
" - Any other value will be interpreted as a file name describing a sequence of filters and parameters to be applied to the input images.\n"
- " -v, --vignette <name> [<feather> <min>]\n"
+
" Apply a circular central vignette <name> to the filter using the optional <feather> and <min> values. Admissible names:\n"
" - 'blend' : the filter is applied with full intensity in the center and blends with the image to the periphery.\n"
" - 'fade' : the filter is applied with full intensity in the center and fades to black to the periphery.\n"
-
- // Set the vignette if any
- if (vignette_name == "blend")
- {
- raw_image->setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_CENTER,(float)(vignette_param_1),(float)(vignette_param_2));
- }
- else if (vignette_name == "fade")
- {
- raw_image->setVignette(VIGNETTE_MODE_FADE,VIGNETTE_TYPE_CENTER,(float)(vignette_param_1),(float)(vignette_param_2));
- }
-
- // Apply filter if any
- if (filter_name == "sepia")
- {
- raw_image->filterSepia();
- }
- else if (filter_name == "grayscale")
- {
- raw_image->filterGrayScale();
- }
- else if (filter_name == "saturate")
- {
- raw_image->filterSaturate((float)(filter_param));
- }
- else if (filter_name == "rotate")
- {
- raw_image->filterRotate((float)(filter_param));
- }
- else if (filter_name == "gamma")
- {
- raw_image->filterGamma((float)(filter_param),LLColor3::white);
- }
- else if (filter_name == "colorize")
- {
- // For testing, we just colorize in the red channel, modulate by the alpha passed as a parameter
- LLColor3 color(1.0,0.0,0.0);
- LLColor3 alpha((F32)(filter_param),0.0,0.0);
- raw_image->filterColorize(color,alpha);
- }
- else if (filter_name == "contrast")
- {
- raw_image->filterContrast((float)(filter_param),LLColor3::white);
- }
- else if (filter_name == "brighten")
- {
- raw_image->filterBrightness((S32)(filter_param),LLColor3::white);
- }
- else if (filter_name == "darken")
- {
- raw_image->filterBrightness((S32)(-filter_param),LLColor3::white);
- }
- else if (filter_name == "linearize")
- {
- raw_image->filterLinearize((float)(filter_param),LLColor3::white);
- }
- else if (filter_name == "posterize")
- {
- raw_image->filterEqualize((S32)(filter_param),LLColor3::white);
- }
- else if (filter_name == "newsscreen")
- {
- raw_image->filterScreen(SCREEN_MODE_2DSINE,(S32)(filter_param),0.0);
- }
- else if (filter_name == "horizontalscreen")
- {
- raw_image->filterScreen(SCREEN_MODE_LINE,(S32)(filter_param),0.0);
- }
- else if (filter_name == "verticalscreen")
- {
- raw_image->filterScreen(SCREEN_MODE_LINE,(S32)(filter_param),90.0);
- }
- else if (filter_name == "slantedscreen")
- {
- raw_image->filterScreen(SCREEN_MODE_LINE,(S32)(filter_param),45.0);
- }
-
*/
// Load filter from file
@@ -171,6 +107,8 @@ void LLImageFilter::loadFromFile(const std::string& file_path)
// Apply the filter data to the image passed as parameter
void LLImageFilter::executeFilter(LLPointer<LLImageRaw> raw_image)
{
+ mImage = raw_image;
+
//std::cout << "Filter : size = " << mFilterData.size() << std::endl;
for (S32 i = 0; i < mFilterData.size(); ++i)
{
@@ -186,67 +124,67 @@ void LLImageFilter::executeFilter(LLPointer<LLImageRaw> raw_image)
// Execute the filter described on this line
if (filter_name == "blend")
{
- raw_image->setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_CENTER,(float)(mFilterData[i][1].asReal()),(float)(mFilterData[i][2].asReal()));
+ setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_CENTER,(float)(mFilterData[i][1].asReal()),(float)(mFilterData[i][2].asReal()));
}
else if (filter_name == "fade")
{
- raw_image->setVignette(VIGNETTE_MODE_FADE,VIGNETTE_TYPE_CENTER,(float)(mFilterData[i][1].asReal()),(float)(mFilterData[i][2].asReal()));
+ setVignette(VIGNETTE_MODE_FADE,VIGNETTE_TYPE_CENTER,(float)(mFilterData[i][1].asReal()),(float)(mFilterData[i][2].asReal()));
}
else if (filter_name == "lines")
{
- raw_image->setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_LINES,(float)(mFilterData[i][1].asReal()),(float)(mFilterData[i][2].asReal()));
+ setVignette(VIGNETTE_MODE_BLEND,VIGNETTE_TYPE_LINES,(float)(mFilterData[i][1].asReal()),(float)(mFilterData[i][2].asReal()));
}
else if (filter_name == "sepia")
{
- raw_image->filterSepia();
+ filterSepia();
}
else if (filter_name == "grayscale")
{
- raw_image->filterGrayScale();
+ filterGrayScale();
}
else if (filter_name == "saturate")
{
- raw_image->filterSaturate((float)(mFilterData[i][1].asReal()));
+ filterSaturate((float)(mFilterData[i][1].asReal()));
}
else if (filter_name == "rotate")
{
- raw_image->filterRotate((float)(mFilterData[i][1].asReal()));
+ filterRotate((float)(mFilterData[i][1].asReal()));
}
else if (filter_name == "gamma")
{
LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal()));
- raw_image->filterGamma((float)(mFilterData[i][1].asReal()),color);
+ filterGamma((float)(mFilterData[i][1].asReal()),color);
}
else if (filter_name == "colorize")
{
LLColor3 color((float)(mFilterData[i][1].asReal()),(float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()));
LLColor3 alpha((F32)(mFilterData[i][4].asReal()),(float)(mFilterData[i][5].asReal()),(float)(mFilterData[i][6].asReal()));
- raw_image->filterColorize(color,alpha);
+ filterColorize(color,alpha);
}
else if (filter_name == "contrast")
{
LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal()));
- raw_image->filterContrast((float)(mFilterData[i][1].asReal()),color);
+ filterContrast((float)(mFilterData[i][1].asReal()),color);
}
else if (filter_name == "brighten")
{
LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal()));
- raw_image->filterBrightness((S32)(mFilterData[i][1].asReal()),color);
+ filterBrightness((S32)(mFilterData[i][1].asReal()),color);
}
else if (filter_name == "darken")
{
LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal()));
- raw_image->filterBrightness((S32)(-mFilterData[i][1].asReal()),color);
+ filterBrightness((S32)(-mFilterData[i][1].asReal()),color);
}
else if (filter_name == "linearize")
{
LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal()));
- raw_image->filterLinearize((float)(mFilterData[i][1].asReal()),color);
+ filterLinearize((float)(mFilterData[i][1].asReal()),color);
}
else if (filter_name == "posterize")
{
LLColor3 color((float)(mFilterData[i][2].asReal()),(float)(mFilterData[i][3].asReal()),(float)(mFilterData[i][4].asReal()));
- raw_image->filterEqualize((S32)(mFilterData[i][1].asReal()),color);
+ filterEqualize((S32)(mFilterData[i][1].asReal()),color);
}
else if (filter_name == "screen")
{
@@ -260,10 +198,525 @@ void LLImageFilter::executeFilter(LLPointer<LLImageRaw> raw_image)
{
mode = SCREEN_MODE_LINE;
}
- raw_image->filterScreen(mode,(S32)(mFilterData[i][2].asReal()),(F32)(mFilterData[i][3].asReal()));
+ filterScreen(mode,(S32)(mFilterData[i][2].asReal()),(F32)(mFilterData[i][3].asReal()));
}
}
}
+// Filter Primitives
+void LLImageFilter::colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue)
+{
+ const S32 components = mImage->getComponents();
+ llassert( components >= 1 && components <= 4 );
+
+ S32 width = mImage->getWidth();
+ S32 height = mImage->getHeight();
+
+ U8* dst_data = mImage->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 LLImageFilter::colorTransform(const LLMatrix3 &transform)
+{
+ const S32 components = mImage->getComponents();
+ llassert( components >= 1 && components <= 4 );
+
+ S32 width = mImage->getWidth();
+ S32 height = mImage->getHeight();
+
+ U8* dst_data = mImage->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 LLImageFilter::filterScreen(EScreenMode mode, const S32 wave_length, const F32 angle)
+{
+ const S32 components = mImage->getComponents();
+ llassert( components >= 1 && components <= 4 );
+
+ S32 width = mImage->getWidth();
+ S32 height = mImage->getHeight();
+
+ F32 sin = sinf(angle*DEG_TO_RAD);
+ F32 cos = cosf(angle*DEG_TO_RAD);
+
+ U8* dst_data = mImage->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;
+ }
+ }
+}
+
+// Procedural Stencils
+void LLImageFilter::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 = mImage->getWidth()/2;
+ mVignetteCenterY = mImage->getHeight()/2;
+ mVignetteWidth = llmin(mImage->getWidth()/2,mImage->getHeight()/2);
+}
+
+F32 LLImageFilter::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));
+}
+
+// Histograms
+U32* LLImageFilter::getBrightnessHistogram()
+{
+ if (!mHistoBrightness)
+ {
+ computeHistograms();
+ }
+ return mHistoBrightness;
+}
+
+void LLImageFilter::computeHistograms()
+{
+ const S32 components = mImage->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 = mImage->getWidth() * mImage->getHeight();
+ U8* dst_data = mImage->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;
+ }
+}
+
+// Secondary Filters
+void LLImageFilter::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 LLImageFilter::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 LLImageFilter::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 LLImageFilter::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 LLImageFilter::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 LLImageFilter::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 LLImageFilter::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 LLImageFilter::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 LLImageFilter::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 LLImageFilter::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);
+}
//============================================================================
diff --git a/indra/llimage/llimagefilter.h b/indra/llimage/llimagefilter.h
index 5598fa69f5..c67789ede0 100755
--- a/indra/llimage/llimagefilter.h
+++ b/indra/llimage/llimagefilter.h
@@ -29,7 +29,6 @@
#include "llimage.h"
-/*
class LLImageRaw;
class LLColor4U;
class LLColor3;
@@ -53,7 +52,7 @@ typedef enum e_screen_mode
SCREEN_MODE_2DSINE = 0,
SCREEN_MODE_LINE = 1
} EScreenMode;
-*/
+
//============================================================================
// Image Filter
@@ -65,8 +64,55 @@ public:
void loadFromFile(const std::string& file_path);
void executeFilter(LLPointer<LLImageRaw> raw_image);
+
private:
+ // Filter Operations : Transforms
+ void filterGrayScale(); // Convert to grayscale
+ void filterSepia(); // Convert to sepia
+ void filterSaturate(F32 saturation); // < 1.0 desaturates, > 1.0 saturates
+ void filterRotate(F32 angle); // Rotates hue according to angle, angle in degrees
+
+ // Filter Operations : Color Corrections
+ // When specified, the LLColor3 alpha parameter indicates the intensity of the effect for each color channel
+ // acting in effect as an alpha blending factor different for each channel. For instance (1.0,0.0,0.0) will apply
+ // the effect only to the Red channel. Intermediate values blends the effect with the source color.
+ void filterGamma(F32 gamma, const LLColor3& alpha); // Apply gamma to each channel
+ void filterLinearize(F32 tail, const LLColor3& alpha); // Use histogram to linearize constrast between min and max values minus tail
+ void filterEqualize(S32 nb_classes, const LLColor3& alpha); // Use histogram to equalize constrast between nb_classes throughout the image
+ void filterColorize(const LLColor3& color, const LLColor3& alpha); // Colorize with color and alpha per channel
+ void filterContrast(F32 slope, const LLColor3& alpha); // Change contrast according to slope: > 1.0 more contrast, < 1.0 less contrast
+ void filterBrightness(S32 add, const LLColor3& alpha); // Change brightness according to add: > 0 brighter, < 0 darker
+
+ // Filter Primitives
+ void colorTransform(const LLMatrix3 &transform);
+ void colorCorrect(const U8* lut_red, const U8* lut_green, const U8* lut_blue);
+ void filterScreen(EScreenMode mode, const S32 wave_length, const F32 angle);
+
+ // Procedural Stencils
+ void setVignette(EVignetteMode mode, EVignetteType type, F32 gamma, F32 min);
+ F32 getVignetteAlpha(S32 i, S32 j);
+
+ // Histograms
+ U32* getBrightnessHistogram();
+ void computeHistograms();
+
LLSD mFilterData;
+ LLPointer<LLImageRaw> mImage;
+
+ // Histograms (if we ever happen to need them)
+ U32 *mHistoRed;
+ U32 *mHistoGreen;
+ U32 *mHistoBlue;
+ U32 *mHistoBrightness;
+
+ // Vignette filtering
+ EVignetteMode mVignetteMode;
+ EVignetteType mVignetteType;
+ S32 mVignetteCenterX;
+ S32 mVignetteCenterY;
+ S32 mVignetteWidth;
+ F32 mVignetteGamma;
+ F32 mVignetteMin;
};