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 20543c6ff7..89299258a6 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 */ + } +} + +//============================================================================ |