/** * @file llimage.h * @brief Object for managing images and their textures. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LL_LLIMAGE_H #define LL_LLIMAGE_H #include "lluuid.h" #include "llstring.h" #include "llpointer.h" #include "lltrace.h" constexpr S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2 constexpr 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. constexpr S32 MAX_DISCARD_LEVEL = 5; // JPEG2000 size constraints // Those are declared here as they are germane to other image constraints used in the viewer // and declared right here. Some come from the JPEG2000 spec, some conventions specific to SL. constexpr S32 MAX_DECOMPOSITION_LEVELS = 32; // Number of decomposition levels cannot exceed 32 according to jpeg2000 spec constexpr 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) constexpr S32 MAX_PRECINCT_SIZE = 4096; // No reason to be bigger than MAX_IMAGE_SIZE constexpr S32 MIN_PRECINCT_SIZE = 4; // Can't be smaller than MIN_BLOCK_SIZE constexpr S32 MAX_BLOCK_SIZE = 64; // Max total block size is 4096, hence 64x64 when using square blocks constexpr S32 MIN_BLOCK_SIZE = 4; // Min block dim is 4 according to jpeg2000 spec constexpr S32 MIN_LAYER_SIZE = 2000; // Size of the first quality layer (after header). Must be > to FIRST_PACKET_SIZE!! constexpr S32 MAX_NB_LAYERS = 64; // Max number of layers we'll entertain in SL (practical limit) constexpr S32 MIN_IMAGE_SIZE = (1< class DataLock : LLSharedMutexLockTemplate { public: DataLock(const LLImageBase* image) : LLSharedMutexLockTemplate(image ? &image->mDataMutex : nullptr) { } }; }; using LLImageDataLock = LLImageBase::DataLock; using LLImageDataSharedLock = LLImageBase::DataLock; // Raw representation of an image (used for textures, and other uncompressed formats class LLImageRaw : public LLImageBase { protected: /*virtual*/ ~LLImageRaw(); public: LLImageRaw(); LLImageRaw(U16 width, U16 height, S8 components); LLImageRaw(const U8* data, U16 width, U16 height, S8 components); LLImageRaw(U8 *data, U16 width, U16 height, S8 components, bool no_copy = false); // Construct using createFromFile (used by tools) //LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false); /*virtual*/ void deleteData(); /*virtual*/ U8* allocateData(S32 size = -1); /*virtual*/ U8* reallocateData(S32 size); // use in conjunction with "no_copy" constructor to release data pointer before deleting // so that deletion of this LLImageRaw will not free the memory at the "data" parameter // provided to "no_copy" constructor void releaseData(); bool resize(U16 width, U16 height, S8 components); //U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const; bool setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height, const U8 *data, U32 stride = 0, bool reverse_y = false); void clear(U8 r=0, U8 g=0, U8 b=0, U8 a=255); 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); static S32 contractDimToPowerOfTwo(S32 curr_dim, S32 min_dim = MIN_IMAGE_SIZE); void expandToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, bool scale_image = true); void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, bool scale_image = true); void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE); bool scale(S32 new_width, S32 new_height, bool scale_image = true); LLPointer scaled(S32 new_width, S32 new_height); // 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. LLPointer duplicate(); // Src and dst can be any size. Src and dst can each have 3 or 4 components. void copy( const LLImageRaw* src ); // Src and dst are same size. Src and dst have same number of components. void copyUnscaled( const LLImageRaw* src ); // Src and dst are same size. Src has 4 components. Dst has 3 components. void copyUnscaled4onto3( const LLImageRaw* src ); // Src and dst are same size. Src has 3 components. Dst has 4 components. void copyUnscaled3onto4( const LLImageRaw* src ); // Src and dst are same size. Src has 1 component. Dst has 4 components. // Alpha component is set to source alpha mask component. // RGB components are set to fill color. void copyUnscaledAlphaMask( const LLImageRaw* src, const LLColor4U& fill); // Src and dst can be any size. Src and dst have same number of components. void copyScaled( const LLImageRaw* src ); // Composite operations // 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 ); // Src and dst are same size. Src has 4 components. Dst has 3 components. void compositeUnscaled4onto3( const LLImageRaw* src ); // Src and dst can be any size. Src has 3 components. Dst has 4 components. void copyScaled3onto4( const LLImageRaw* src ); // Src and dst can be any size. Src has 4 components. Dst has 3 components. void copyScaled4onto3( const LLImageRaw* src ); // Create an image from a local file (generally used in tools) //bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false); void copyLineScaled( const U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ); void compositeRowScaled4onto3( const U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len ); static U8 fastFractionalMult(U8 a, U8 b); void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ; public: static S32 sRawImageCount; private: static bool validateSrcAndDst(std::string func, const LLImageRaw* src, const LLImageRaw* dst); }; // Compressed representation of image. // Subclass from this class for the different representations (J2C, bmp) 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(); public: LLImageFormatted(S8 codec); // LLImageBase /*virtual*/ void deleteData(); /*virtual*/ U8* allocateData(S32 size = -1); /*virtual*/ U8* reallocateData(S32 size); /*virtual*/ void dump(); /*virtual*/ void sanityCheck(); // New methods // subclasses must return a prefered file extension (lowercase without a leading dot) virtual std::string getExtension() = 0; // calcHeaderSize() returns the maximum size of header; // 0 indicates we don't have a header and have to read the entire file virtual S32 calcHeaderSize() { return 0; }; // calcDataSize() returns how many bytes to read to load discard_level (including header) virtual S32 calcDataSize(S32 discard_level); // calcDiscardLevelBytes() returns the smallest valid discard level based on the number of input bytes virtual S32 calcDiscardLevelBytes(S32 bytes); // getRawDiscardLevel() by default returns mDiscardLevel, but may be overridden (LLImageJ2C) virtual S8 getRawDiscardLevel() { return mDiscardLevel; } bool load(const std::string& filename, int load_size = 0); bool save(const std::string& filename); virtual bool updateData() = 0; // pure virtual void setData(U8 *data, S32 size); void appendData(U8 *data, S32 size); // Loads first 4 channels. virtual bool decode(LLImageRaw* raw_image, F32 decode_time) = 0; // Subclasses that can handle more than 4 channels should override this function. virtual bool decodeChannels(LLImageRaw* raw_image, F32 decode_time, S32 first_channel, S32 max_channel); virtual bool encode(const LLImageRaw* raw_image, F32 encode_time) = 0; S8 getCodec() const; bool isDecoding() const { return mDecoding; } bool isDecoded() const { return mDecoded; } void setDiscardLevel(S8 discard_level) { mDiscardLevel = discard_level; } S8 getDiscardLevel() const { return mDiscardLevel; } S8 getLevels() const { return mLevels; } void setLevels(S8 nlevels) { mLevels = nlevels; } // setLastError needs to be deferred for J2C images since it may be called from a DLL virtual void resetLastError(); virtual void setLastError(const std::string& message, const std::string& filename = std::string()); protected: bool copyData(U8 *data, S32 size); // calls updateData() protected: S8 mCodec; S8 mDecoding; S8 mDecoded; // unused, but changing LLImage layout requires recompiling static Mac/Linux libs. 2009-01-30 JC S8 mDiscardLevel; // Current resolution level worked on. 0 = full res, 1 = half res, 2 = quarter res, etc... S8 mLevels; // Number of resolution levels in that image. Min is 1. 0 means unknown. public: static S32 sGlobalFormattedMemory; }; #endif