diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2024-06-11 10:21:19 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2024-06-11 10:21:19 -0400 |
commit | 30f4163b7b576d96533b61d9b31243960fb83f2e (patch) | |
tree | bd5dc1450e08c674a4619d7f16a9a4816005f9c4 /indra/llimage | |
parent | 3d1aac4f5c369e9d402c41f1c790d9015f7c7773 (diff) | |
parent | f5e2708a0fc4e08d3d0a5dc393bbd4bac09e1c55 (diff) |
Merge branch 'main' of github.com:secondlife/viewer into lua-bradfix
to pick up Featurettes promotion + Brad's GitHub Windows build workaround.
Diffstat (limited to 'indra/llimage')
-rw-r--r-- | indra/llimage/llimage.cpp | 144 | ||||
-rw-r--r-- | indra/llimage/llimage.h | 22 |
2 files changed, 161 insertions, 5 deletions
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index c4d7096036..da5b531857 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" @@ -984,6 +985,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() { if (getComponents() == 4) @@ -1021,6 +1044,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) { // Find new sizes @@ -1105,7 +1156,7 @@ void LLImageRaw::composite( LLImageRaw* src ) return; } - llassert(3 == src->getComponents()); + llassert((3 == src->getComponents()) || (4 == src->getComponents())); llassert(3 == dst->getComponents()); if( 3 == dst->getComponents() ) @@ -1263,6 +1314,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) @@ -1794,6 +1869,73 @@ void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S3 } } + +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); +} + + bool LLImageRaw::validateSrcAndDst(std::string func, LLImageRaw* src, LLImageRaw* dst) { if (!src || !dst || src->isBufferInvalid() || dst->isBufferInvalid()) diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 0335be8d2f..9b16711b85 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 { @@ -208,9 +209,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); @@ -224,6 +229,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. @@ -267,6 +275,12 @@ public: // Src and dst are same size. Src has 4 components. Dst has 3 components. void compositeUnscaled4onto3( 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: // Create an image from a local file (generally used in tools) //bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false); |