diff options
Diffstat (limited to 'indra/llimage/llimagedxt.cpp')
-rw-r--r-- | indra/llimage/llimagedxt.cpp | 1048 |
1 files changed, 524 insertions, 524 deletions
diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index 07e44c615c..20543c6ff7 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -1,524 +1,524 @@ -/** - * @file llimagedxt.cpp - * - * $LicenseInfo:firstyear=2001&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$ - */ - -#include "linden_common.h" - -#include "llimagedxt.h" -#include "llmemory.h" - -//static -void LLImageDXT::checkMinWidthHeight(EFileFormat format, S32& width, S32& height) -{ - S32 mindim = (format >= FORMAT_DXT1 && format <= FORMAT_DXR5) ? 4 : 1; - width = llmax(width, mindim); - height = llmax(height, mindim); -} - -//static -S32 LLImageDXT::formatBits(EFileFormat format) -{ - switch (format) - { - case FORMAT_DXT1: return 4; - case FORMAT_DXR1: return 4; - case FORMAT_I8: return 8; - case FORMAT_A8: return 8; - case FORMAT_DXT3: return 8; - case FORMAT_DXR3: return 8; - case FORMAT_DXR5: return 8; - case FORMAT_DXT5: return 8; - case FORMAT_RGB8: return 24; - case FORMAT_RGBA8: return 32; - default: - LL_ERRS() << "LLImageDXT::Unknown format: " << format << LL_ENDL; - return 0; - } -}; - -//static -S32 LLImageDXT::formatBytes(EFileFormat format, S32 width, S32 height) -{ - checkMinWidthHeight(format, width, height); - S32 bytes = ((width*height*formatBits(format)+7)>>3); - S32 aligned = (bytes+3)&~3; - return aligned; -} - -//static -S32 LLImageDXT::formatComponents(EFileFormat format) -{ - switch (format) - { - case FORMAT_DXT1: return 3; - case FORMAT_DXR1: return 3; - case FORMAT_I8: return 1; - case FORMAT_A8: return 1; - case FORMAT_DXT3: return 4; - case FORMAT_DXR3: return 4; - case FORMAT_DXT5: return 4; - case FORMAT_DXR5: return 4; - case FORMAT_RGB8: return 3; - case FORMAT_RGBA8: return 4; - default: - LL_ERRS() << "LLImageDXT::Unknown format: " << format << LL_ENDL; - return 0; - } -}; - -// static -LLImageDXT::EFileFormat LLImageDXT::getFormat(S32 fourcc) -{ - switch(fourcc) - { - case 0x20203849: return FORMAT_I8; - case 0x20203841: return FORMAT_A8; - case 0x20424752: return FORMAT_RGB8; - case 0x41424752: return FORMAT_RGBA8; - case 0x31525844: return FORMAT_DXR1; - case 0x32525844: return FORMAT_DXR2; - case 0x33525844: return FORMAT_DXR3; - case 0x34525844: return FORMAT_DXR4; - case 0x35525844: return FORMAT_DXR5; - case 0x31545844: return FORMAT_DXT1; - case 0x32545844: return FORMAT_DXT2; - case 0x33545844: return FORMAT_DXT3; - case 0x34545844: return FORMAT_DXT4; - case 0x35545844: return FORMAT_DXT5; - default: return FORMAT_UNKNOWN; - } -} - -//static -S32 LLImageDXT::getFourCC(EFileFormat format) -{ - switch(format) - { - case FORMAT_I8: return 0x20203849; - case FORMAT_A8: return 0x20203841; - case FORMAT_RGB8: return 0x20424752; - case FORMAT_RGBA8: return 0x41424752; - case FORMAT_DXR1: return 0x31525844; - case FORMAT_DXR2: return 0x32525844; - case FORMAT_DXR3: return 0x33525844; - case FORMAT_DXR4: return 0x34525844; - case FORMAT_DXR5: return 0x35525844; - case FORMAT_DXT1: return 0x31545844; - case FORMAT_DXT2: return 0x32545844; - case FORMAT_DXT3: return 0x33545844; - case FORMAT_DXT4: return 0x34545844; - case FORMAT_DXT5: return 0x35545844; - default: return 0x00000000; - } -} - -//static -void LLImageDXT::calcDiscardWidthHeight(S32 discard_level, EFileFormat format, S32& width, S32& height) -{ - while (discard_level > 0 && width > 1 && height > 1) - { - discard_level--; - width >>= 1; - height >>= 1; - } - checkMinWidthHeight(format, width, height); -} - -//static -S32 LLImageDXT::calcNumMips(S32 width, S32 height) -{ - S32 nmips = 0; - while (width > 0 && height > 0) - { - width >>= 1; - height >>= 1; - nmips++; - } - return nmips; -} - -//============================================================================ - -LLImageDXT::LLImageDXT() - : LLImageFormatted(IMG_CODEC_DXT), - mFileFormat(FORMAT_UNKNOWN), - mHeaderSize(0) -{ -} - -LLImageDXT::~LLImageDXT() -{ -} - -// virtual -bool LLImageDXT::updateData() -{ - resetLastError(); - - LLImageDataLock lock(this); - - U8* data = getData(); - S32 data_size = getDataSize(); - - if (!data || !data_size) - { - setLastError("LLImageDXT uninitialized"); - return false; - } - - S32 width, height, miplevelmax; - dxtfile_header_t* header = (dxtfile_header_t*)data; - if (header->fourcc != 0x20534444) - { - dxtfile_header_old_t* oldheader = (dxtfile_header_old_t*)header; - mHeaderSize = sizeof(dxtfile_header_old_t); - mFileFormat = EFileFormat(oldheader->format); - miplevelmax = llmin(oldheader->maxlevel,MAX_IMAGE_MIP); - width = oldheader->maxwidth; - height = oldheader->maxheight; - } - else - { - mHeaderSize = sizeof(dxtfile_header_t); - mFileFormat = getFormat(header->pixel_fmt.fourcc); - miplevelmax = llmin(header->num_mips-1,MAX_IMAGE_MIP); - width = header->maxwidth; - height = header->maxheight; - } - - if (data_size < mHeaderSize) - { - LL_ERRS() << "LLImageDXT: not enough data" << LL_ENDL; - } - S32 ncomponents = formatComponents(mFileFormat); - setSize(width, height, ncomponents); - - S32 discard = calcDiscardLevelBytes(data_size); - discard = llmin(discard, miplevelmax); - setDiscardLevel(discard); - - return true; -} - -// discard: 0 = largest (last) mip -S32 LLImageDXT::getMipOffset(S32 discard) -{ - if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXT5) - { - LL_ERRS() << "getMipOffset called with old (unsupported) format" << LL_ENDL; - } - S32 width = getWidth(), height = getHeight(); - S32 num_mips = calcNumMips(width, height); - discard = llclamp(discard, 0, num_mips-1); - S32 last_mip = num_mips-1-discard; - llassert(mHeaderSize > 0); - S32 offset = mHeaderSize; - for (S32 mipidx = num_mips-1; mipidx >= 0; mipidx--) - { - if (mipidx < last_mip) - { - offset += formatBytes(mFileFormat, width, height); - } - width >>= 1; - height >>= 1; - } - return offset; -} - -void LLImageDXT::setFormat() -{ - S32 ncomponents = getComponents(); - switch (ncomponents) - { - case 3: mFileFormat = FORMAT_DXR1; break; - case 4: mFileFormat = FORMAT_DXR3; break; - default: LL_ERRS() << "LLImageDXT::setFormat called with ncomponents = " << ncomponents << LL_ENDL; - } - mHeaderSize = calcHeaderSize(); -} - -// virtual -bool LLImageDXT::decode(LLImageRaw* raw_image, F32 time) -{ - // *TODO: Test! This has been tweaked since its intial inception, - // but we don't use it any more! - llassert_always(raw_image); - - if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5) - { - LL_WARNS() << "Attempt to decode compressed LLImageDXT to Raw (unsupported)" << LL_ENDL; - return false; - } - - LLImageDataSharedLock lockIn(this); - LLImageDataLock lockOut(raw_image); - - S32 width = getWidth(), height = getHeight(); - S32 ncomponents = getComponents(); - U8* data = NULL; - if (mDiscardLevel >= 0) - { - data = getData() + getMipOffset(mDiscardLevel); - calcDiscardWidthHeight(mDiscardLevel, mFileFormat, width, height); - } - else - { - data = getData() + getMipOffset(0); - } - S32 image_size = formatBytes(mFileFormat, width, height); - - if ((!getData()) || (data + image_size > getData() + getDataSize())) - { - setLastError("LLImageDXT trying to decode an image with not enough data!"); - return false; - } - - if (!raw_image->resize(width, height, ncomponents)) - { - setLastError("llImageDXT failed to resize image!"); - return false; - } - memcpy(raw_image->getData(), data, image_size); /* Flawfinder: ignore */ - - return true; -} - -bool LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard) -{ - if (discard < 0) - { - discard = mDiscardLevel; - } - else if (discard < mDiscardLevel) - { - LL_ERRS() << "Request for invalid discard level" << LL_ENDL; - } - - LLImageDataSharedLock lock(this); - - U8* data = getData() + getMipOffset(discard); - S32 width = 0; - S32 height = 0; - calcDiscardWidthHeight(discard, mFileFormat, width, height); - raw = new LLImageRaw(data, width, height, getComponents()); - return true; -} - -bool LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_mips) -{ - llassert_always(raw_image); - - S32 ncomponents = raw_image->getComponents(); - EFileFormat format; - switch (ncomponents) - { - case 1: - format = FORMAT_A8; - break; - case 3: - format = FORMAT_RGB8; - break; - case 4: - format = FORMAT_RGBA8; - break; - default: - LL_ERRS() << "LLImageDXT::encode: Unhandled channel number: " << ncomponents << LL_ENDL; - return 0; - } - - LLImageDataLock lock(this); - - S32 width = raw_image->getWidth(); - S32 height = raw_image->getHeight(); - - if (explicit_mips) - { - height = (height/3)*2; - } - - setSize(width, height, ncomponents); - mHeaderSize = sizeof(dxtfile_header_t); - mFileFormat = format; - - S32 nmips = calcNumMips(width, height); - S32 w = width; - S32 h = height; - - S32 totbytes = mHeaderSize; - for (S32 mip=0; mip<nmips; mip++) - { - totbytes += formatBytes(format,w,h); - w >>= 1; - h >>= 1; - } - - allocateData(totbytes); - - U8* data = getData(); - dxtfile_header_t* header = (dxtfile_header_t*)data; - llassert(mHeaderSize > 0); - memset(header, 0, mHeaderSize); - header->fourcc = 0x20534444; - header->pixel_fmt.fourcc = getFourCC(format); - header->num_mips = nmips; - header->maxwidth = width; - header->maxheight = height; - - U8* prev_mipdata = 0; - w = width, h = height; - for (S32 mip=0; mip<nmips; mip++) - { - U8* mipdata = data + getMipOffset(mip); - S32 bytes = formatBytes(format, w, h); - if (mip==0) - { - memcpy(mipdata, raw_image->getData(), bytes); /* Flawfinder: ignore */ - } - else if (explicit_mips) - { - extractMip(raw_image->getData(), mipdata, width, height, w, h, format); - } - else - { - generateMip(prev_mipdata, mipdata, w, h, ncomponents); - } - w >>= 1; - h >>= 1; - checkMinWidthHeight(format, w, h); - prev_mipdata = mipdata; - } - - return true; -} - -// virtual -bool LLImageDXT::encode(const LLImageRaw* raw_image, F32 time) -{ - return encodeDXT(raw_image, time, false); -} - -// virtual -bool LLImageDXT::convertToDXR() -{ - EFileFormat newformat = FORMAT_UNKNOWN; - switch (mFileFormat) - { - case FORMAT_DXR1: - case FORMAT_DXR2: - case FORMAT_DXR3: - case FORMAT_DXR4: - case FORMAT_DXR5: - return false; // nothing to do - case FORMAT_DXT1: newformat = FORMAT_DXR1; break; - case FORMAT_DXT2: newformat = FORMAT_DXR2; break; - case FORMAT_DXT3: newformat = FORMAT_DXR3; break; - case FORMAT_DXT4: newformat = FORMAT_DXR4; break; - case FORMAT_DXT5: newformat = FORMAT_DXR5; break; - default: - LL_WARNS() << "convertToDXR: can not convert format: " << llformat("0x%08x",getFourCC(mFileFormat)) << LL_ENDL; - return false; - } - mFileFormat = newformat; - - LLImageDataLock lock(this); - - S32 width = getWidth(), height = getHeight(); - S32 nmips = calcNumMips(width,height); - S32 total_bytes = getDataSize(); - U8* olddata = getData(); - U8* newdata = (U8*)ll_aligned_malloc_16(total_bytes); - if (!newdata) - { - LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS() << "Out of memory in LLImageDXT::convertToDXR()" << LL_ENDL; - return false; - } - llassert(total_bytes > 0); - memset(newdata, 0, total_bytes); - memcpy(newdata, olddata, mHeaderSize); /* Flawfinder: ignore */ - for (S32 mip=0; mip<nmips; mip++) - { - S32 bytes = formatBytes(mFileFormat, width, height); - S32 newoffset = getMipOffset(mip); - S32 oldoffset = mHeaderSize + (total_bytes - newoffset - bytes); - memcpy(newdata + newoffset, olddata + oldoffset, bytes); /* Flawfinder: ignore */ - width >>= 1; - height >>= 1; - } - dxtfile_header_t* header = (dxtfile_header_t*)newdata; - header->pixel_fmt.fourcc = getFourCC(newformat); - setData(newdata, total_bytes); - updateData(); - return true; -} - -// virtual -S32 LLImageDXT::calcHeaderSize() -{ - return llmax(sizeof(dxtfile_header_old_t), sizeof(dxtfile_header_t)); -} - -// virtual -S32 LLImageDXT::calcDataSize(S32 discard_level) -{ - if (mFileFormat == FORMAT_UNKNOWN) - { - LL_ERRS() << "calcDataSize called with unloaded LLImageDXT" << LL_ENDL; - return 0; - } - if (discard_level < 0) - { - discard_level = mDiscardLevel; - } - S32 bytes = getMipOffset(discard_level); // size of header + previous mips - S32 w = getWidth() >> discard_level; - S32 h = getHeight() >> discard_level; - bytes += formatBytes(mFileFormat,w,h); - return bytes; -} - -//============================================================================ - -//static -void LLImageDXT::extractMip(const U8 *indata, U8* mipdata, int width, int height, - int mip_width, int mip_height, EFileFormat format) -{ - int initial_offset = formatBytes(format, width, height); - int line_width = formatBytes(format, width, 1); - int mip_line_width = formatBytes(format, mip_width, 1); - int line_offset = 0; - - for (int ww=width>>1; ww>mip_width; ww>>=1) - { - line_offset += formatBytes(format, ww, 1); - } - - for (int h=0;h<mip_height;++h) - { - int start_offset = initial_offset + line_width * h + line_offset; - memcpy(mipdata + mip_line_width*h, indata + start_offset, mip_line_width); /* Flawfinder: ignore */ - } -} - -//============================================================================ +/**
+ * @file llimagedxt.cpp
+ *
+ * $LicenseInfo:firstyear=2001&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$
+ */
+
+#include "linden_common.h"
+
+#include "llimagedxt.h"
+#include "llmemory.h"
+
+//static
+void LLImageDXT::checkMinWidthHeight(EFileFormat format, S32& width, S32& height)
+{
+ S32 mindim = (format >= FORMAT_DXT1 && format <= FORMAT_DXR5) ? 4 : 1;
+ width = llmax(width, mindim);
+ height = llmax(height, mindim);
+}
+
+//static
+S32 LLImageDXT::formatBits(EFileFormat format)
+{
+ switch (format)
+ {
+ case FORMAT_DXT1: return 4;
+ case FORMAT_DXR1: return 4;
+ case FORMAT_I8: return 8;
+ case FORMAT_A8: return 8;
+ case FORMAT_DXT3: return 8;
+ case FORMAT_DXR3: return 8;
+ case FORMAT_DXR5: return 8;
+ case FORMAT_DXT5: return 8;
+ case FORMAT_RGB8: return 24;
+ case FORMAT_RGBA8: return 32;
+ default:
+ LL_ERRS() << "LLImageDXT::Unknown format: " << format << LL_ENDL;
+ return 0;
+ }
+};
+
+//static
+S32 LLImageDXT::formatBytes(EFileFormat format, S32 width, S32 height)
+{
+ checkMinWidthHeight(format, width, height);
+ S32 bytes = ((width*height*formatBits(format)+7)>>3);
+ S32 aligned = (bytes+3)&~3;
+ return aligned;
+}
+
+//static
+S32 LLImageDXT::formatComponents(EFileFormat format)
+{
+ switch (format)
+ {
+ case FORMAT_DXT1: return 3;
+ case FORMAT_DXR1: return 3;
+ case FORMAT_I8: return 1;
+ case FORMAT_A8: return 1;
+ case FORMAT_DXT3: return 4;
+ case FORMAT_DXR3: return 4;
+ case FORMAT_DXT5: return 4;
+ case FORMAT_DXR5: return 4;
+ case FORMAT_RGB8: return 3;
+ case FORMAT_RGBA8: return 4;
+ default:
+ LL_ERRS() << "LLImageDXT::Unknown format: " << format << LL_ENDL;
+ return 0;
+ }
+};
+
+// static
+LLImageDXT::EFileFormat LLImageDXT::getFormat(S32 fourcc)
+{
+ switch(fourcc)
+ {
+ case 0x20203849: return FORMAT_I8;
+ case 0x20203841: return FORMAT_A8;
+ case 0x20424752: return FORMAT_RGB8;
+ case 0x41424752: return FORMAT_RGBA8;
+ case 0x31525844: return FORMAT_DXR1;
+ case 0x32525844: return FORMAT_DXR2;
+ case 0x33525844: return FORMAT_DXR3;
+ case 0x34525844: return FORMAT_DXR4;
+ case 0x35525844: return FORMAT_DXR5;
+ case 0x31545844: return FORMAT_DXT1;
+ case 0x32545844: return FORMAT_DXT2;
+ case 0x33545844: return FORMAT_DXT3;
+ case 0x34545844: return FORMAT_DXT4;
+ case 0x35545844: return FORMAT_DXT5;
+ default: return FORMAT_UNKNOWN;
+ }
+}
+
+//static
+S32 LLImageDXT::getFourCC(EFileFormat format)
+{
+ switch(format)
+ {
+ case FORMAT_I8: return 0x20203849;
+ case FORMAT_A8: return 0x20203841;
+ case FORMAT_RGB8: return 0x20424752;
+ case FORMAT_RGBA8: return 0x41424752;
+ case FORMAT_DXR1: return 0x31525844;
+ case FORMAT_DXR2: return 0x32525844;
+ case FORMAT_DXR3: return 0x33525844;
+ case FORMAT_DXR4: return 0x34525844;
+ case FORMAT_DXR5: return 0x35525844;
+ case FORMAT_DXT1: return 0x31545844;
+ case FORMAT_DXT2: return 0x32545844;
+ case FORMAT_DXT3: return 0x33545844;
+ case FORMAT_DXT4: return 0x34545844;
+ case FORMAT_DXT5: return 0x35545844;
+ default: return 0x00000000;
+ }
+}
+
+//static
+void LLImageDXT::calcDiscardWidthHeight(S32 discard_level, EFileFormat format, S32& width, S32& height)
+{
+ while (discard_level > 0 && width > 1 && height > 1)
+ {
+ discard_level--;
+ width >>= 1;
+ height >>= 1;
+ }
+ checkMinWidthHeight(format, width, height);
+}
+
+//static
+S32 LLImageDXT::calcNumMips(S32 width, S32 height)
+{
+ S32 nmips = 0;
+ while (width > 0 && height > 0)
+ {
+ width >>= 1;
+ height >>= 1;
+ nmips++;
+ }
+ return nmips;
+}
+
+//============================================================================
+
+LLImageDXT::LLImageDXT()
+ : LLImageFormatted(IMG_CODEC_DXT),
+ mFileFormat(FORMAT_UNKNOWN),
+ mHeaderSize(0)
+{
+}
+
+LLImageDXT::~LLImageDXT()
+{
+}
+
+// virtual
+bool LLImageDXT::updateData()
+{
+ resetLastError();
+
+ LLImageDataLock lock(this);
+
+ U8* data = getData();
+ S32 data_size = getDataSize();
+
+ if (!data || !data_size)
+ {
+ setLastError("LLImageDXT uninitialized");
+ return false;
+ }
+
+ S32 width, height, miplevelmax;
+ dxtfile_header_t* header = (dxtfile_header_t*)data;
+ if (header->fourcc != 0x20534444)
+ {
+ dxtfile_header_old_t* oldheader = (dxtfile_header_old_t*)header;
+ mHeaderSize = sizeof(dxtfile_header_old_t);
+ mFileFormat = EFileFormat(oldheader->format);
+ miplevelmax = llmin(oldheader->maxlevel,MAX_IMAGE_MIP);
+ width = oldheader->maxwidth;
+ height = oldheader->maxheight;
+ }
+ else
+ {
+ mHeaderSize = sizeof(dxtfile_header_t);
+ mFileFormat = getFormat(header->pixel_fmt.fourcc);
+ miplevelmax = llmin(header->num_mips-1,MAX_IMAGE_MIP);
+ width = header->maxwidth;
+ height = header->maxheight;
+ }
+
+ if (data_size < mHeaderSize)
+ {
+ LL_ERRS() << "LLImageDXT: not enough data" << LL_ENDL;
+ }
+ S32 ncomponents = formatComponents(mFileFormat);
+ setSize(width, height, ncomponents);
+
+ S32 discard = calcDiscardLevelBytes(data_size);
+ discard = llmin(discard, miplevelmax);
+ setDiscardLevel(discard);
+
+ return true;
+}
+
+// discard: 0 = largest (last) mip
+S32 LLImageDXT::getMipOffset(S32 discard)
+{
+ if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXT5)
+ {
+ LL_ERRS() << "getMipOffset called with old (unsupported) format" << LL_ENDL;
+ }
+ S32 width = getWidth(), height = getHeight();
+ S32 num_mips = calcNumMips(width, height);
+ discard = llclamp(discard, 0, num_mips-1);
+ S32 last_mip = num_mips-1-discard;
+ llassert(mHeaderSize > 0);
+ S32 offset = mHeaderSize;
+ for (S32 mipidx = num_mips-1; mipidx >= 0; mipidx--)
+ {
+ if (mipidx < last_mip)
+ {
+ offset += formatBytes(mFileFormat, width, height);
+ }
+ width >>= 1;
+ height >>= 1;
+ }
+ return offset;
+}
+
+void LLImageDXT::setFormat()
+{
+ S32 ncomponents = getComponents();
+ switch (ncomponents)
+ {
+ case 3: mFileFormat = FORMAT_DXR1; break;
+ case 4: mFileFormat = FORMAT_DXR3; break;
+ default: LL_ERRS() << "LLImageDXT::setFormat called with ncomponents = " << ncomponents << LL_ENDL;
+ }
+ mHeaderSize = calcHeaderSize();
+}
+
+// virtual
+bool LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
+{
+ // *TODO: Test! This has been tweaked since its intial inception,
+ // but we don't use it any more!
+ llassert_always(raw_image);
+
+ if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5)
+ {
+ LL_WARNS() << "Attempt to decode compressed LLImageDXT to Raw (unsupported)" << LL_ENDL;
+ return false;
+ }
+
+ LLImageDataSharedLock lockIn(this);
+ LLImageDataLock lockOut(raw_image);
+
+ S32 width = getWidth(), height = getHeight();
+ S32 ncomponents = getComponents();
+ U8* data = NULL;
+ if (mDiscardLevel >= 0)
+ {
+ data = getData() + getMipOffset(mDiscardLevel);
+ calcDiscardWidthHeight(mDiscardLevel, mFileFormat, width, height);
+ }
+ else
+ {
+ data = getData() + getMipOffset(0);
+ }
+ S32 image_size = formatBytes(mFileFormat, width, height);
+
+ if ((!getData()) || (data + image_size > getData() + getDataSize()))
+ {
+ setLastError("LLImageDXT trying to decode an image with not enough data!");
+ return false;
+ }
+
+ if (!raw_image->resize(width, height, ncomponents))
+ {
+ setLastError("llImageDXT failed to resize image!");
+ return false;
+ }
+ memcpy(raw_image->getData(), data, image_size); /* Flawfinder: ignore */
+
+ return true;
+}
+
+bool LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard)
+{
+ if (discard < 0)
+ {
+ discard = mDiscardLevel;
+ }
+ else if (discard < mDiscardLevel)
+ {
+ LL_ERRS() << "Request for invalid discard level" << LL_ENDL;
+ }
+
+ LLImageDataSharedLock lock(this);
+
+ U8* data = getData() + getMipOffset(discard);
+ S32 width = 0;
+ S32 height = 0;
+ calcDiscardWidthHeight(discard, mFileFormat, width, height);
+ raw = new LLImageRaw(data, width, height, getComponents());
+ return true;
+}
+
+bool LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_mips)
+{
+ llassert_always(raw_image);
+
+ S32 ncomponents = raw_image->getComponents();
+ EFileFormat format;
+ switch (ncomponents)
+ {
+ case 1:
+ format = FORMAT_A8;
+ break;
+ case 3:
+ format = FORMAT_RGB8;
+ break;
+ case 4:
+ format = FORMAT_RGBA8;
+ break;
+ default:
+ LL_ERRS() << "LLImageDXT::encode: Unhandled channel number: " << ncomponents << LL_ENDL;
+ return 0;
+ }
+
+ LLImageDataLock lock(this);
+
+ S32 width = raw_image->getWidth();
+ S32 height = raw_image->getHeight();
+
+ if (explicit_mips)
+ {
+ height = (height/3)*2;
+ }
+
+ setSize(width, height, ncomponents);
+ mHeaderSize = sizeof(dxtfile_header_t);
+ mFileFormat = format;
+
+ S32 nmips = calcNumMips(width, height);
+ S32 w = width;
+ S32 h = height;
+
+ S32 totbytes = mHeaderSize;
+ for (S32 mip=0; mip<nmips; mip++)
+ {
+ totbytes += formatBytes(format,w,h);
+ w >>= 1;
+ h >>= 1;
+ }
+
+ allocateData(totbytes);
+
+ U8* data = getData();
+ dxtfile_header_t* header = (dxtfile_header_t*)data;
+ llassert(mHeaderSize > 0);
+ memset(header, 0, mHeaderSize);
+ header->fourcc = 0x20534444;
+ header->pixel_fmt.fourcc = getFourCC(format);
+ header->num_mips = nmips;
+ header->maxwidth = width;
+ header->maxheight = height;
+
+ U8* prev_mipdata = 0;
+ w = width, h = height;
+ for (S32 mip=0; mip<nmips; mip++)
+ {
+ U8* mipdata = data + getMipOffset(mip);
+ S32 bytes = formatBytes(format, w, h);
+ if (mip==0)
+ {
+ memcpy(mipdata, raw_image->getData(), bytes); /* Flawfinder: ignore */
+ }
+ else if (explicit_mips)
+ {
+ extractMip(raw_image->getData(), mipdata, width, height, w, h, format);
+ }
+ else
+ {
+ generateMip(prev_mipdata, mipdata, w, h, ncomponents);
+ }
+ w >>= 1;
+ h >>= 1;
+ checkMinWidthHeight(format, w, h);
+ prev_mipdata = mipdata;
+ }
+
+ return true;
+}
+
+// virtual
+bool LLImageDXT::encode(const LLImageRaw* raw_image, F32 time)
+{
+ return encodeDXT(raw_image, time, false);
+}
+
+// virtual
+bool LLImageDXT::convertToDXR()
+{
+ EFileFormat newformat = FORMAT_UNKNOWN;
+ switch (mFileFormat)
+ {
+ case FORMAT_DXR1:
+ case FORMAT_DXR2:
+ case FORMAT_DXR3:
+ case FORMAT_DXR4:
+ case FORMAT_DXR5:
+ return false; // nothing to do
+ case FORMAT_DXT1: newformat = FORMAT_DXR1; break;
+ case FORMAT_DXT2: newformat = FORMAT_DXR2; break;
+ case FORMAT_DXT3: newformat = FORMAT_DXR3; break;
+ case FORMAT_DXT4: newformat = FORMAT_DXR4; break;
+ case FORMAT_DXT5: newformat = FORMAT_DXR5; break;
+ default:
+ LL_WARNS() << "convertToDXR: can not convert format: " << llformat("0x%08x",getFourCC(mFileFormat)) << LL_ENDL;
+ return false;
+ }
+ mFileFormat = newformat;
+
+ LLImageDataLock lock(this);
+
+ S32 width = getWidth(), height = getHeight();
+ S32 nmips = calcNumMips(width,height);
+ S32 total_bytes = getDataSize();
+ U8* olddata = getData();
+ U8* newdata = (U8*)ll_aligned_malloc_16(total_bytes);
+ if (!newdata)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS() << "Out of memory in LLImageDXT::convertToDXR()" << LL_ENDL;
+ return false;
+ }
+ llassert(total_bytes > 0);
+ memset(newdata, 0, total_bytes);
+ memcpy(newdata, olddata, mHeaderSize); /* Flawfinder: ignore */
+ for (S32 mip=0; mip<nmips; mip++)
+ {
+ S32 bytes = formatBytes(mFileFormat, width, height);
+ S32 newoffset = getMipOffset(mip);
+ S32 oldoffset = mHeaderSize + (total_bytes - newoffset - bytes);
+ memcpy(newdata + newoffset, olddata + oldoffset, bytes); /* Flawfinder: ignore */
+ width >>= 1;
+ height >>= 1;
+ }
+ dxtfile_header_t* header = (dxtfile_header_t*)newdata;
+ header->pixel_fmt.fourcc = getFourCC(newformat);
+ setData(newdata, total_bytes);
+ updateData();
+ return true;
+}
+
+// virtual
+S32 LLImageDXT::calcHeaderSize()
+{
+ return llmax(sizeof(dxtfile_header_old_t), sizeof(dxtfile_header_t));
+}
+
+// virtual
+S32 LLImageDXT::calcDataSize(S32 discard_level)
+{
+ if (mFileFormat == FORMAT_UNKNOWN)
+ {
+ LL_ERRS() << "calcDataSize called with unloaded LLImageDXT" << LL_ENDL;
+ return 0;
+ }
+ if (discard_level < 0)
+ {
+ discard_level = mDiscardLevel;
+ }
+ S32 bytes = getMipOffset(discard_level); // size of header + previous mips
+ S32 w = getWidth() >> discard_level;
+ S32 h = getHeight() >> discard_level;
+ bytes += formatBytes(mFileFormat,w,h);
+ return bytes;
+}
+
+//============================================================================
+
+//static
+void LLImageDXT::extractMip(const U8 *indata, U8* mipdata, int width, int height,
+ int mip_width, int mip_height, EFileFormat format)
+{
+ int initial_offset = formatBytes(format, width, height);
+ int line_width = formatBytes(format, width, 1);
+ int mip_line_width = formatBytes(format, mip_width, 1);
+ int line_offset = 0;
+
+ for (int ww=width>>1; ww>mip_width; ww>>=1)
+ {
+ line_offset += formatBytes(format, ww, 1);
+ }
+
+ for (int h=0;h<mip_height;++h)
+ {
+ int start_offset = initial_offset + line_width * h + line_offset;
+ memcpy(mipdata + mip_line_width*h, indata + start_offset, mip_line_width); /* Flawfinder: ignore */
+ }
+}
+
+//============================================================================
|