summaryrefslogtreecommitdiff
path: root/indra/llimage
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llimage')
-rw-r--r--indra/llimage/llimage.cpp199
-rw-r--r--indra/llimage/llimage.h25
2 files changed, 219 insertions, 5 deletions
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index b8b71cde53..acd382d9a8 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -31,6 +31,7 @@
#include "llmath.h"
#include "v4coloru.h"
+#include "v3color.h"
#include "llimagebmp.h"
#include "llimagetga.h"
@@ -1003,6 +1004,28 @@ void LLImageRaw::verticalFlip()
}
+bool LLImageRaw::checkHasTransparentPixels()
+{
+ if (getComponents() != 4)
+ {
+ return false;
+ }
+
+ U8* data = getData();
+ U32 pixels = getWidth() * getHeight();
+
+ // check alpha channel for all 255
+ for (U32 i = 0; i < pixels; ++i)
+ {
+ if (data[i * 4 + 3] != 255)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool LLImageRaw::optimizeAwayAlpha()
{
LLImageDataLock lock(this);
@@ -1042,6 +1065,34 @@ bool LLImageRaw::optimizeAwayAlpha()
return false;
}
+bool LLImageRaw::makeAlpha()
+{
+ if (getComponents() == 3)
+ {
+ U8* data = getData();
+ U32 pixels = getWidth() * getHeight();
+
+ // alpha channel doesn't exist, make a new copy of data with alpha channel
+ U8* new_data = (U8*) ll_aligned_malloc_16(getWidth() * getHeight() * 4);
+
+ for (U32 i = 0; i < pixels; ++i)
+ {
+ U32 di = i * 4;
+ U32 si = i * 3;
+ for (U32 j = 0; j < 3; ++j)
+ {
+ new_data[di+j] = data[si+j];
+ }
+ }
+
+ setDataAndSize(new_data, getWidth(), getHeight(), 3);
+
+ return true;
+ }
+
+ return false;
+}
+
void LLImageRaw::expandToPowerOfTwo(S32 max_dim, bool scale_image)
{
LLImageDataLock lock(this);
@@ -1136,7 +1187,7 @@ void LLImageRaw::composite( const LLImageRaw* src )
return;
}
- llassert(3 == src->getComponents());
+ llassert((3 == src->getComponents()) || (4 == src->getComponents()));
llassert(3 == dst->getComponents());
if( 3 == dst->getComponents() )
@@ -1303,6 +1354,30 @@ void LLImageRaw::fill( const LLColor4U& color )
}
}
+void LLImageRaw::tint( const LLColor3& color )
+{
+ llassert( (3 == getComponents()) || (4 == getComponents()) );
+ if (isBufferInvalid())
+ {
+ LL_WARNS() << "Invalid image buffer" << LL_ENDL;
+ return;
+ }
+
+ S32 pixels = getWidth() * getHeight();
+ const S32 components = getComponents();
+ U8* data = getData();
+ for( S32 i = 0; i < pixels; i++ )
+ {
+ const float c0 = data[0] * color.mV[0];
+ const float c1 = data[1] * color.mV[1];
+ const float c2 = data[2] * color.mV[2];
+ data[0] = llclamp((U8)c0, 0, 255);
+ data[1] = llclamp((U8)c1, 0, 255);
+ data[2] = llclamp((U8)c2, 0, 255);
+ data += components;
+ }
+}
+
LLPointer<LLImageRaw> LLImageRaw::duplicate()
{
if(getNumRefs() < 2)
@@ -1853,6 +1928,72 @@ void LLImageRaw::compositeRowScaled4onto3( const U8* in, U8* out, S32 in_pixel_l
}
}
+
+void LLImageRaw::addEmissive(LLImageRaw* src)
+{
+ LLImageRaw* dst = this; // Just for clarity.
+
+ if (!validateSrcAndDst(__FUNCTION__, src, dst))
+ {
+ return;
+ }
+
+ llassert((3 == src->getComponents()) || (4 == src->getComponents()));
+ llassert(3 == dst->getComponents());
+
+ if( 3 == dst->getComponents() )
+ {
+ if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) )
+ {
+ addEmissiveUnscaled(src);
+ }
+ else
+ {
+ addEmissiveScaled(src);
+ }
+ }
+}
+
+void LLImageRaw::addEmissiveUnscaled(LLImageRaw* src)
+{
+ LLImageRaw* dst = this; // Just for clarity.
+
+ llassert((3 == src->getComponents()) || (4 == src->getComponents()));
+ llassert((3 == dst->getComponents()) || (4 == dst->getComponents()));
+ llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) );
+
+ U8* const src_data = src->getData();
+ U8* const dst_data = dst->getData();
+ for(S32 y = 0; y < dst->getHeight(); ++y)
+ {
+ const S32 src_row_offset = src->getComponents() * src->getWidth() * y;
+ const S32 dst_row_offset = dst->getComponents() * dst->getWidth() * y;
+ for (S32 x = 0; x < dst->getWidth(); ++x)
+ {
+ const S32 src_offset = src_row_offset + (x * src->getComponents());
+ const S32 dst_offset = dst_row_offset + (x * dst->getComponents());
+ U8* const src_pixel = src_data + src_offset;
+ U8* const dst_pixel = dst_data + dst_offset;
+ dst_pixel[0] = llmin(255, dst_pixel[0] + src_pixel[0]);
+ dst_pixel[1] = llmin(255, dst_pixel[1] + src_pixel[1]);
+ dst_pixel[2] = llmin(255, dst_pixel[2] + src_pixel[2]);
+ }
+ }
+}
+
+void LLImageRaw::addEmissiveScaled(LLImageRaw* src)
+{
+ LLImageRaw* dst = this; // Just for clarity.
+
+ llassert( (4 == src->getComponents()) && (3 == dst->getComponents()) );
+
+ LLImageRaw temp(dst->getWidth(), dst->getHeight(), dst->getComponents());
+ llassert_always(temp.getDataSize() > 0);
+ temp.copyScaled(src);
+
+ dst->addEmissiveUnscaled(&temp);
+}
+
// static
bool LLImageRaw::validateSrcAndDst(std::string func, const LLImageRaw* src, const LLImageRaw* dst)
{
@@ -2092,6 +2233,61 @@ LLImageFormatted* LLImageFormatted::createFromType(S8 codec)
}
// static
+S8 LLImageFormatted::getCodecFromMimeType(std::string_view mimetype)
+{
+ if (mimetype == "image/bmp")
+ {
+ return IMG_CODEC_BMP;
+ }
+ else if (mimetype == "image/tga")
+ {
+ return IMG_CODEC_TGA;
+ }
+ else if (mimetype == "image/jpeg")
+ {
+ return IMG_CODEC_JPEG;
+ }
+ else if (mimetype == "image/png")
+ {
+ return IMG_CODEC_PNG;
+ }
+ else if (mimetype == "image/j2c")
+ {
+ return IMG_CODEC_J2C;
+ }
+ else if (mimetype == "image/dxt")
+ {
+ return IMG_CODEC_DXT;
+ }
+ return IMG_CODEC_INVALID;
+}
+
+// static
+LLImageFormatted* LLImageFormatted::createFromMimeType(std::string_view mimetype)
+{
+ S8 codec = getCodecFromMimeType(mimetype);
+ return createFromType(codec);
+}
+
+// static
+LLImageFormatted* LLImageFormatted::loadFromMemory(const U8* data_in, U32 size, std::string_view mimetype)
+{
+ LLImageFormatted* image = createFromMimeType(mimetype);
+ if (image)
+ {
+ U8* data = image->allocateData(size);
+ memcpy(data, data_in, size);
+
+ if (!image->updateData())
+ {
+ delete image;
+ image = NULL;
+ }
+ }
+ return image;
+}
+
+// static
LLImageFormatted* LLImageFormatted::createFromExtension(const std::string& instring)
{
std::string exten;
@@ -2271,6 +2467,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size)
//----------------------------------------------------------------------------
+
bool LLImageFormatted::load(const std::string &filename, int load_size)
{
resetLastError();
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index 37add13ad7..42eecbb97c 100644
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -33,7 +33,7 @@
#include "lltrace.h"
const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2
-const S32 MAX_IMAGE_MIP = 11; // 2048x2048
+const S32 MAX_IMAGE_MIP = 12; // 4096x4096
// *TODO : Use MAX_IMAGE_MIP as max discard level and modify j2c management so that the number
// of levels is read from the header's file, not inferred from its size.
@@ -44,7 +44,7 @@ const S32 MAX_DISCARD_LEVEL = 5;
// and declared right here. Some come from the JPEG2000 spec, some conventions specific to SL.
const S32 MAX_DECOMPOSITION_LEVELS = 32; // Number of decomposition levels cannot exceed 32 according to jpeg2000 spec
const S32 MIN_DECOMPOSITION_LEVELS = 5; // the SL viewer will *crash* trying to decode images with fewer than 5 decomposition levels (unless image is small that is)
-const S32 MAX_PRECINCT_SIZE = 2048; // No reason to be bigger than MAX_IMAGE_SIZE
+const S32 MAX_PRECINCT_SIZE = 4096; // No reason to be bigger than MAX_IMAGE_SIZE
const S32 MIN_PRECINCT_SIZE = 4; // Can't be smaller than MIN_BLOCK_SIZE
const S32 MAX_BLOCK_SIZE = 64; // Max total block size is 4096, hence 64x64 when using square blocks
const S32 MIN_BLOCK_SIZE = 4; // Min block dim is 4 according to jpeg2000 spec
@@ -52,11 +52,11 @@ const S32 MIN_LAYER_SIZE = 2000; // Size of the first quality layer (
const S32 MAX_NB_LAYERS = 64; // Max number of layers we'll entertain in SL (practical limit)
const S32 MIN_IMAGE_SIZE = (1<<MIN_IMAGE_MIP); // 4, only used for expand/contract power of 2
-const S32 MAX_IMAGE_SIZE = (1<<MAX_IMAGE_MIP); // 2048
+const S32 MAX_IMAGE_SIZE = (1<<MAX_IMAGE_MIP); // 4096
const S32 MIN_IMAGE_AREA = MIN_IMAGE_SIZE * MIN_IMAGE_SIZE;
const S32 MAX_IMAGE_AREA = MAX_IMAGE_SIZE * MAX_IMAGE_SIZE;
const S32 MAX_IMAGE_COMPONENTS = 8;
-const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS; //2048 * 2048 * 8 = 16 MB
+const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS; //4096 * 4096 * 8 = 128 MB
// Note! These CANNOT be changed without modifying simulator code
// *TODO: change both to 1024 when SIM texture fetching is deprecated
@@ -71,6 +71,7 @@ const S32 HTTP_PACKET_SIZE = 1496;
class LLImageFormatted;
class LLImageRaw;
class LLColor4U;
+class LLColor3;
typedef enum e_image_codec
{
@@ -225,9 +226,13 @@ public:
void verticalFlip();
+ // Returns true if the image is not fully opaque
+ bool checkHasTransparentPixels();
// if the alpha channel is all 100% opaque, delete it
// returns true if alpha channel was deleted
bool optimizeAwayAlpha();
+ // Create an alpha channel if this image doesn't have one
+ bool makeAlpha();
static S32 biasedDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
static S32 expandDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
@@ -241,6 +246,9 @@ public:
// Fill the buffer with a constant color
void fill( const LLColor4U& color );
+ // Multiply this raw image by the given color
+ void tint( const LLColor3& color );
+
// Copy operations
//duplicate this raw image if refCount > 1.
@@ -272,6 +280,12 @@ public:
// Src and dst can be any size. Src and dst can each have 3 or 4 components.
void composite( const LLImageRaw* src );
+ // Emissive operations used by minimap
+ // Roughly emulates GLTF emissive texture, but is not GLTF-compliant
+ // *TODO: Remove in favor of shader
+ void addEmissive(LLImageRaw* src);
+ void addEmissiveScaled(LLImageRaw* src);
+ void addEmissiveUnscaled(LLImageRaw* src);
protected:
// Src and dst can be any size. Src has 4 components. Dst has 3 components.
void compositeScaled4onto3( const LLImageRaw* src );
@@ -308,7 +322,10 @@ class LLImageFormatted : public LLImageBase
{
public:
static LLImageFormatted* createFromType(S8 codec);
+ static LLImageFormatted* loadFromMemory(const U8* data, U32 size, std::string_view mimetype);
static LLImageFormatted* createFromExtension(const std::string& instring);
+ static LLImageFormatted* createFromMimeType(std::string_view mimetype);
+ static S8 getCodecFromMimeType(std::string_view mimetype);
protected:
/*virtual*/ ~LLImageFormatted();