summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMerov Linden <merov@lindenlab.com>2014-01-28 10:19:57 -0800
committerMerov Linden <merov@lindenlab.com>2014-01-28 10:19:57 -0800
commit6bf3cb875cef4da7c35850ebbea5100dc5244601 (patch)
tree538280be6e5dafda5f648d985f7e8104690c718d
parentff3edd06d2c824a32753e689de3369abf593c684 (diff)
ACME-1195 : WIP : Lazy evaluate intermediate images in snapshot preview so perf is better in common cases, allow thumbnail to be computed from grabed frame (for SL Share), thumbnail display still buggy in SL Share
-rwxr-xr-xindra/llimage/llimage.cpp80
-rwxr-xr-xindra/llimage/llimage.h3
-rw-r--r--indra/newview/llfloaterfacebook.cpp3
-rw-r--r--indra/newview/llfloaterflickr.cpp4
-rwxr-xr-xindra/newview/llfloatersnapshot.cpp5
-rw-r--r--indra/newview/llfloatertwitter.cpp6
-rw-r--r--indra/newview/llsnapshotlivepreview.cpp443
-rw-r--r--indra/newview/llsnapshotlivepreview.h14
8 files changed, 318 insertions, 240 deletions
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index c8a05e1fae..18e08b94a6 100755
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -449,18 +449,8 @@ void LLImageRaw::verticalFlip()
void LLImageRaw::expandToPowerOfTwo(S32 max_dim, BOOL scale_image)
{
// Find new sizes
- S32 new_width = MIN_IMAGE_SIZE;
- S32 new_height = MIN_IMAGE_SIZE;
-
- while( (new_width < getWidth()) && (new_width < max_dim) )
- {
- new_width <<= 1;
- }
-
- while( (new_height < getHeight()) && (new_height < max_dim) )
- {
- new_height <<= 1;
- }
+ S32 new_width = expandDimToPowerOfTwo(getWidth(), max_dim);
+ S32 new_height = expandDimToPowerOfTwo(getHeight(), max_dim);
scale( new_width, new_height, scale_image );
}
@@ -468,55 +458,61 @@ void LLImageRaw::expandToPowerOfTwo(S32 max_dim, BOOL scale_image)
void LLImageRaw::contractToPowerOfTwo(S32 max_dim, BOOL scale_image)
{
// Find new sizes
- S32 new_width = max_dim;
- S32 new_height = max_dim;
-
- while( (new_width > getWidth()) && (new_width > MIN_IMAGE_SIZE) )
- {
- new_width >>= 1;
- }
-
- while( (new_height > getHeight()) && (new_height > MIN_IMAGE_SIZE) )
- {
- new_height >>= 1;
- }
+ S32 new_width = contractDimToPowerOfTwo(getWidth(), MIN_IMAGE_SIZE);
+ S32 new_height = contractDimToPowerOfTwo(getHeight(), MIN_IMAGE_SIZE);
scale( new_width, new_height, scale_image );
}
-void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim)
+// static
+S32 LLImageRaw::biasedDimToPowerOfTwo(S32 curr_dim, S32 max_dim)
{
// Strong bias towards rounding down (to save bandwidth)
// No bias would mean THRESHOLD == 1.5f;
- const F32 THRESHOLD = 1.75f;
-
+ const F32 THRESHOLD = 1.75f;
+
// Find new sizes
- S32 larger_w = max_dim; // 2^n >= mWidth
- S32 smaller_w = max_dim; // 2^(n-1) <= mWidth
- while( (smaller_w > getWidth()) && (smaller_w > MIN_IMAGE_SIZE) )
+ S32 larger_dim = max_dim; // 2^n >= curr_dim
+ S32 smaller_dim = max_dim; // 2^(n-1) <= curr_dim
+ while( (smaller_dim > curr_dim) && (smaller_dim > MIN_IMAGE_SIZE) )
{
- larger_w = smaller_w;
- smaller_w >>= 1;
+ larger_dim = smaller_dim;
+ smaller_dim >>= 1;
}
- S32 new_width = ( (F32)getWidth() / smaller_w > THRESHOLD ) ? larger_w : smaller_w;
+ return ( ((F32)curr_dim / (F32)smaller_dim) > THRESHOLD ) ? larger_dim : smaller_dim;
+}
+// static
+S32 LLImageRaw::expandDimToPowerOfTwo(S32 curr_dim, S32 max_dim)
+{
+ S32 new_dim = MIN_IMAGE_SIZE;
+ while( (new_dim < curr_dim) && (new_dim < max_dim) )
+ {
+ new_dim <<= 1;
+ }
+ return new_dim;
+}
- S32 larger_h = max_dim; // 2^m >= mHeight
- S32 smaller_h = max_dim; // 2^(m-1) <= mHeight
- while( (smaller_h > getHeight()) && (smaller_h > MIN_IMAGE_SIZE) )
+// static
+S32 LLImageRaw::contractDimToPowerOfTwo(S32 curr_dim, S32 min_dim)
+{
+ S32 new_dim = MAX_IMAGE_SIZE;
+ while( (new_dim > curr_dim) && (new_dim > min_dim) )
{
- larger_h = smaller_h;
- smaller_h >>= 1;
+ new_dim >>= 1;
}
- S32 new_height = ( (F32)getHeight() / smaller_h > THRESHOLD ) ? larger_h : smaller_h;
+ return new_dim;
+}
+void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim)
+{
+ // Find new sizes
+ S32 new_width = biasedDimToPowerOfTwo(getWidth(),max_dim);
+ S32 new_height = biasedDimToPowerOfTwo(getHeight(),max_dim);
scale( new_width, new_height );
}
-
-
-
// Calculates (U8)(255*(a/255.f)*(b/255.f) + 0.5f). Thanks, Jim Blinn!
inline U8 LLImageRaw::fastFractionalMult( U8 a, U8 b )
{
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index 2277afc585..c1ba1e3c21 100755
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -205,6 +205,9 @@ public:
void verticalFlip();
+ 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);
diff --git a/indra/newview/llfloaterfacebook.cpp b/indra/newview/llfloaterfacebook.cpp
index 7bf74ef6ba..9676dfaf93 100644
--- a/indra/newview/llfloaterfacebook.cpp
+++ b/indra/newview/llfloaterfacebook.cpp
@@ -257,8 +257,6 @@ void LLFacebookPhotoPanel::draw()
gl_draw_scaled_image(offset_x, offset_y,
thumbnail_w, thumbnail_h,
previewp->getThumbnailImage(), color % alpha);
-
- previewp->drawPreviewRect(offset_x, offset_y) ;
}
// Update the visibility of the working (computing preview) label
@@ -303,6 +301,7 @@ void LLFacebookPhotoPanel::onVisibilityChange(const LLSD& new_visibility)
previewp->setSnapshotType(previewp->SNAPSHOT_WEB);
previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
previewp->setSnapshotQuality(mQuality, false);
+ previewp->setThumbnailSubsampled(TRUE); // We want the preview to reflect the *saved* image
previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect());
updateControls();
diff --git a/indra/newview/llfloaterflickr.cpp b/indra/newview/llfloaterflickr.cpp
index c34124caf5..fbf4d758be 100644
--- a/indra/newview/llfloaterflickr.cpp
+++ b/indra/newview/llfloaterflickr.cpp
@@ -160,8 +160,6 @@ void LLFlickrPhotoPanel::draw()
gl_draw_scaled_image(offset_x, offset_y,
thumbnail_w, thumbnail_h,
previewp->getThumbnailImage(), color % alpha);
-
- previewp->drawPreviewRect(offset_x, offset_y) ;
}
// Update the visibility of the working (computing preview) label
@@ -204,7 +202,7 @@ void LLFlickrPhotoPanel::onVisibilityChange(const LLSD& new_visibility)
previewp->setSnapshotType(previewp->SNAPSHOT_WEB);
previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
- //previewp->setSnapshotQuality(98);
+ previewp->setThumbnailSubsampled(TRUE); // We want the preview to reflect the *saved* image
previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect());
updateControls();
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index c3efc26991..7ba5fc7b87 100755
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -436,9 +436,8 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
image_res_tb->setVisible(got_snap);
if (got_snap)
{
- LLPointer<LLImageRaw> img = previewp->getEncodedImage();
- image_res_tb->setTextArg("[WIDTH]", llformat("%d", img->getWidth()));
- image_res_tb->setTextArg("[HEIGHT]", llformat("%d", img->getHeight()));
+ image_res_tb->setTextArg("[WIDTH]", llformat("%d", previewp->getEncodedImageWidth()));
+ image_res_tb->setTextArg("[HEIGHT]", llformat("%d", previewp->getEncodedImageHeight()));
}
floater->getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : floater->getString("unknown"));
diff --git a/indra/newview/llfloatertwitter.cpp b/indra/newview/llfloatertwitter.cpp
index ea263566a6..68bc4f1c3c 100644
--- a/indra/newview/llfloatertwitter.cpp
+++ b/indra/newview/llfloatertwitter.cpp
@@ -150,8 +150,6 @@ void LLTwitterPhotoPanel::draw()
gl_draw_scaled_image(offset_x, offset_y,
thumbnail_w, thumbnail_h,
previewp->getThumbnailImage(), color % alpha);
-
- previewp->drawPreviewRect(offset_x, offset_y) ;
}
// Update the visibility of the working (computing preview) label
@@ -190,11 +188,11 @@ void LLTwitterPhotoPanel::onVisibilityChange(const LLSD& new_visibility)
LLSnapshotLivePreview::Params p;
p.rect(full_screen_rect);
LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p);
- mPreviewHandle = previewp->getHandle();
+ mPreviewHandle = previewp->getHandle();
previewp->setSnapshotType(previewp->SNAPSHOT_WEB);
previewp->setSnapshotFormat(LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG);
- //previewp->setSnapshotQuality(98);
+ previewp->setThumbnailSubsampled(TRUE); // We want the preview to reflect the *saved* image
previewp->setThumbnailPlaceholderRect(mThumbnailPlaceholder->getRect());
updateControls();
diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp
index ee74dbdb0f..4463dfdc38 100644
--- a/indra/newview/llsnapshotlivepreview.cpp
+++ b/indra/newview/llsnapshotlivepreview.cpp
@@ -78,6 +78,7 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLSnapshotLivePreview::Param
mThumbnailImage(NULL) ,
mThumbnailWidth(0),
mThumbnailHeight(0),
+ mThumbnailSubsampled(FALSE),
mPreviewImageEncoded(NULL),
mFormattedImage(NULL),
mShineCountdown(0),
@@ -126,14 +127,7 @@ LLSnapshotLivePreview::~LLSnapshotLivePreview()
void LLSnapshotLivePreview::setMaxImageSize(S32 size)
{
- if(size < MAX_SNAPSHOT_IMAGE_SIZE)
- {
- mMaxImageSize = size;
- }
- else
- {
- mMaxImageSize = MAX_SNAPSHOT_IMAGE_SIZE ;
- }
+ mMaxImageSize = llmin(size,(S32)(MAX_SNAPSHOT_IMAGE_SIZE));
}
LLViewerTexture* LLSnapshotLivePreview::getCurrentImage()
@@ -141,32 +135,17 @@ LLViewerTexture* LLSnapshotLivePreview::getCurrentImage()
return mViewerImage[mCurImageIndex];
}
-F32 LLSnapshotLivePreview::getAspect()
-{
- F32 image_aspect_ratio = ((F32)getWidth()) / ((F32)getHeight());
- F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight());
-
- if (!mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot"))
- {
- return image_aspect_ratio;
- }
- else
- {
- return window_aspect_ratio;
- }
-}
-
F32 LLSnapshotLivePreview::getImageAspect()
{
if (!getCurrentImage())
{
return 0.f;
}
-
- return getAspect() ;
+ // mKeepAspectRatio) == gSavedSettings.getBOOL("KeepAspectForSnapshot"))
+ return (mKeepAspectRatio ? ((F32)getRect().getWidth()) / ((F32)getRect().getHeight()) : ((F32)getWidth()) / ((F32)getHeight()));
}
-void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail, F32 delay)
+void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail, F32 delay)
{
// Invalidate current image.
lldebugs << "updateSnapshot: mSnapshotUpToDate = " << getSnapshotUpToDate() << llendl;
@@ -483,58 +462,49 @@ BOOL LLSnapshotLivePreview::setThumbnailImageSize()
{
return FALSE ;
}
- S32 window_width = gViewerWindow->getWindowWidthRaw() ;
- S32 window_height = gViewerWindow->getWindowHeightRaw() ;
+ S32 width = (mThumbnailSubsampled ? mPreviewImage->getWidth() : gViewerWindow->getWindowWidthRaw());
+ S32 height = (mThumbnailSubsampled ? mPreviewImage->getHeight() : gViewerWindow->getWindowHeightRaw()) ;
- F32 window_aspect_ratio = ((F32)window_width) / ((F32)window_height);
+ F32 aspect_ratio = ((F32)width) / ((F32)height);
// UI size for thumbnail
// *FIXME: the rect does not change, so maybe there's no need to recalculate max w/h.
- const LLRect& thumbnail_rect = mThumbnailPlaceholderRect;
- S32 max_width = thumbnail_rect.getWidth();
- S32 max_height = thumbnail_rect.getHeight();
+ //const LLRect& thumbnail_rect = mThumbnailPlaceholderRect;
+ S32 max_width = mThumbnailPlaceholderRect.getWidth();
+ S32 max_height = mThumbnailPlaceholderRect.getHeight();
- if (window_aspect_ratio > (F32)max_width / max_height)
+ if (aspect_ratio > (F32)max_width / (F32)max_height)
{
// image too wide, shrink to width
mThumbnailWidth = max_width;
- mThumbnailHeight = llround((F32)max_width / window_aspect_ratio);
+ mThumbnailHeight = llround((F32)max_width / aspect_ratio);
}
else
{
// image too tall, shrink to height
mThumbnailHeight = max_height;
- mThumbnailWidth = llround((F32)max_height * window_aspect_ratio);
+ mThumbnailWidth = llround((F32)max_height * aspect_ratio);
}
- if(mThumbnailWidth > window_width || mThumbnailHeight > window_height)
+ if (mThumbnailWidth > width || mThumbnailHeight > height)
{
return FALSE ;//if the window is too small, ignore thumbnail updating.
}
S32 left = 0 , top = mThumbnailHeight, right = mThumbnailWidth, bottom = 0 ;
- if(!mKeepAspectRatio)
+ if(!mKeepAspectRatio && !mThumbnailSubsampled)
{
- F32 ratio_x = (F32)getWidth() / window_width ;
- F32 ratio_y = (F32)getHeight() / window_height ;
+ F32 ratio_x = (F32)getWidth() / width ;
+ F32 ratio_y = (F32)getHeight() / height ;
- //if(getWidth() > window_width ||
- // getHeight() > window_height )
- {
- if(ratio_x > ratio_y)
- {
- top = (S32)(top * ratio_y / ratio_x) ;
- }
- else
- {
- right = (S32)(right * ratio_x / ratio_y) ;
- }
- }
- //else
- //{
- // right = (S32)(right * ratio_x) ;
- // top = (S32)(top * ratio_y) ;
- //}
+ if (ratio_x > ratio_y)
+ {
+ top = (S32)(top * ratio_y / ratio_x) ;
+ }
+ else
+ {
+ right = (S32)(right * ratio_x / ratio_y) ;
+ }
left = (S32)((mThumbnailWidth - right) * 0.5f) ;
bottom = (S32)((mThumbnailHeight - top) * 0.5f) ;
top += bottom ;
@@ -576,18 +546,41 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update)
}
LLPointer<LLImageRaw> raw = new LLImageRaw;
- if(!gViewerWindow->thumbnailSnapshot(raw,
- mThumbnailWidth, mThumbnailHeight,
- gSavedSettings.getBOOL("RenderUIInSnapshot"),
- FALSE,
- mSnapshotBufferType) )
- {
- raw = NULL ;
- }
-
- if(raw)
+
+ if (mThumbnailSubsampled)
+ {
+ // The thumbnail is be a subsampled version of the preview (used in SL Share previews, i.e. Flickr, Twitter, Facebook)
+ raw->resize( mPreviewImage->getWidth(),
+ mPreviewImage->getHeight(),
+ mPreviewImage->getComponents());
+ raw->copy(mPreviewImage);
+ // Scale to the thumbnal size modulo a power of 2
+ S32 width = LLImageRaw::expandDimToPowerOfTwo(mThumbnailWidth,MAX_IMAGE_SIZE);
+ S32 height = LLImageRaw::expandDimToPowerOfTwo(mThumbnailHeight,MAX_IMAGE_SIZE);
+ if (!raw->scale(width, height))
+ {
+ raw = NULL ;
+ }
+ }
+ else
+ {
+ // The thumbnail is a screen view with screen grab positioning preview
+ if(!gViewerWindow->thumbnailSnapshot(raw,
+ mThumbnailWidth, mThumbnailHeight,
+ gSavedSettings.getBOOL("RenderUIInSnapshot"),
+ FALSE,
+ mSnapshotBufferType) )
+ {
+ raw = NULL ;
+ }
+ else
+ {
+ raw->expandToPowerOfTwo();
+ }
+ }
+
+ if (raw)
{
- raw->expandToPowerOfTwo();
// Filter the thumbnail
if (getFilter() != "")
{
@@ -650,26 +643,22 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
}
// time to produce a snapshot
- previewp->setThumbnailImageSize();
+ //previewp->setThumbnailImageSize();
lldebugs << "producing snapshot" << llendl;
+ llinfos << "Merov : producing snapshot" << llendl;
if (!previewp->mPreviewImage)
{
previewp->mPreviewImage = new LLImageRaw;
}
- if (!previewp->mPreviewImageEncoded)
- {
- previewp->mPreviewImageEncoded = new LLImageRaw;
- }
-
previewp->setVisible(FALSE);
previewp->setEnabled(FALSE);
previewp->getWindow()->incBusyCount();
previewp->setImageScaled(FALSE);
- // grab the raw image and encode it into desired format
+ // grab the raw image
if(gViewerWindow->rawSnapshot(
previewp->mPreviewImage,
previewp->getWidth(),
@@ -681,123 +670,60 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
previewp->mSnapshotBufferType,
previewp->getMaxImageSize()))
{
- previewp->mPreviewImageEncoded->resize(
- previewp->mPreviewImage->getWidth(),
- previewp->mPreviewImage->getHeight(),
- previewp->mPreviewImage->getComponents());
+ // Invalidate/delete any existing encoded image
+ previewp->mPreviewImageEncoded = NULL;
+ // Invalidate/delete any existing formatted image
+ previewp->mFormattedImage = NULL;
+ // Update the data size
+ previewp->estimateDataSize();
- if(previewp->getSnapshotType() == SNAPSHOT_TEXTURE)
- {
- lldebugs << "Encoding new image of format J2C" << llendl;
- LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
- LLPointer<LLImageRaw> scaled = new LLImageRaw(
- previewp->mPreviewImage->getData(),
- previewp->mPreviewImage->getWidth(),
- previewp->mPreviewImage->getHeight(),
- previewp->mPreviewImage->getComponents());
-
- scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE);
- previewp->setImageScaled(TRUE);
- if (formatted->encode(scaled, 0.f))
- {
- previewp->mDataSize = formatted->getDataSize();
- formatted->decode(previewp->mPreviewImageEncoded, 0);
- }
- }
- else
- {
- // Apply the filter to mPreviewImage
- if (previewp->getFilter() != "")
+ // Full size preview is set: get the decoded image result and save it for animation
+ if (gSavedSettings.getBOOL("UseFreezeFrame"))
+ {
+ // Get the decoded version of the formatted image
+ previewp->getEncodedImage();
+
+ // We need to scale that a bit for display...
+ LLPointer<LLImageRaw> scaled = new LLImageRaw(
+ previewp->mPreviewImageEncoded->getData(),
+ previewp->mPreviewImageEncoded->getWidth(),
+ previewp->mPreviewImageEncoded->getHeight(),
+ previewp->mPreviewImageEncoded->getComponents());
+
+ if (!scaled->isBufferInvalid())
{
- std::string filter_path = LLImageFiltersManager::getInstance()->getFilterPath(previewp->getFilter());
- if (filter_path != "")
+ // leave original image dimensions, just scale up texture buffer
+ if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024)
{
- LLImageFilter filter(filter_path);
- filter.executeFilter(previewp->mPreviewImage);
+ // go ahead and shrink image to appropriate power of 2 for display
+ scaled->biasedScaleToPowerOfTwo(1024);
+ previewp->setImageScaled(TRUE);
}
else
{
- llwarns << "Couldn't find a path to the following filter : " << previewp->getFilter() << llendl;
+ // expand image but keep original image data intact
+ scaled->expandToPowerOfTwo(1024, FALSE);
}
- }
-
- // delete any existing image
- previewp->mFormattedImage = NULL;
- // now create the new one of the appropriate format.
- LLFloaterSnapshot::ESnapshotFormat format = previewp->getSnapshotFormat();
- lldebugs << "Encoding new image of format " << format << llendl;
- switch(format)
- {
- case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
- previewp->mFormattedImage = new LLImagePNG();
- break;
- case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
- previewp->mFormattedImage = new LLImageJPEG(previewp->mSnapshotQuality);
- break;
- case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
- previewp->mFormattedImage = new LLImageBMP();
- break;
- }
- if (previewp->mFormattedImage->encode(previewp->mPreviewImage, 0))
- {
- previewp->mDataSize = previewp->mFormattedImage->getDataSize();
- // special case BMP to copy instead of decode otherwise decode will crash.
- if(format == LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP)
- {
- previewp->mPreviewImageEncoded->copy(previewp->mPreviewImage);
- }
- else
- {
- previewp->mFormattedImage->decode(previewp->mPreviewImageEncoded, 0);
- }
- }
- }
+ previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
+ LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex];
+ gGL.getTexUnit(0)->bind(curr_preview_image);
+ curr_preview_image->setFilteringOption(previewp->getSnapshotType() == SNAPSHOT_TEXTURE ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT);
+ curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
- LLPointer<LLImageRaw> scaled = new LLImageRaw(
- previewp->mPreviewImageEncoded->getData(),
- previewp->mPreviewImageEncoded->getWidth(),
- previewp->mPreviewImageEncoded->getHeight(),
- previewp->mPreviewImageEncoded->getComponents());
-
- if(!scaled->isBufferInvalid())
- {
- // leave original image dimensions, just scale up texture buffer
- if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024)
- {
- // go ahead and shrink image to appropriate power of 2 for display
- scaled->biasedScaleToPowerOfTwo(1024);
- previewp->setImageScaled(TRUE);
- }
- else
- {
- // expand image but keep original image data intact
- scaled->expandToPowerOfTwo(1024, FALSE);
- }
-
- previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
- LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex];
- gGL.getTexUnit(0)->bind(curr_preview_image);
- if (previewp->getSnapshotType() != SNAPSHOT_TEXTURE)
- {
- curr_preview_image->setFilteringOption(LLTexUnit::TFO_POINT);
- }
- else
- {
- curr_preview_image->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
- }
- curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
-
- previewp->mSnapshotUpToDate = TRUE;
- previewp->generateThumbnailImage(TRUE) ;
-
- previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();
- previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
- }
+ previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();
+ previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
+ }
+ }
+ // K, the snapshot is updated...
+ previewp->mSnapshotUpToDate = TRUE;
+
+ // We need to update the thumbnail though
+ previewp->setThumbnailImageSize();
+ previewp->generateThumbnailImage(TRUE) ;
}
previewp->getWindow()->decBusyCount();
- // only show fullscreen preview when in freeze frame mode
- previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame"));
+ previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame")); // only show fullscreen preview when in freeze frame mode
previewp->mSnapshotDelayTimer.stop();
previewp->mSnapshotActive = FALSE;
@@ -806,6 +732,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
previewp->generateThumbnailImage() ;
}
lldebugs << "done creating snapshot" << llendl;
+ llinfos << "Merov : Done creating snapshot" << llendl;
LLFloaterSnapshot::postUpdate();
LLFloaterFacebook::postUpdate();
LLFloaterFlickr::postUpdate();
@@ -814,6 +741,153 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
return TRUE;
}
+S32 LLSnapshotLivePreview::getEncodedImageWidth() const
+{
+ S32 width = getWidth();
+ if (getSnapshotType() == SNAPSHOT_TEXTURE)
+ {
+ width = LLImageRaw::biasedDimToPowerOfTwo(width,MAX_TEXTURE_SIZE);
+ }
+ return width;
+}
+S32 LLSnapshotLivePreview::getEncodedImageHeight() const
+{
+ S32 height = getHeight();
+ if (getSnapshotType() == SNAPSHOT_TEXTURE)
+ {
+ height = LLImageRaw::biasedDimToPowerOfTwo(height,MAX_TEXTURE_SIZE);
+ }
+ return height;
+}
+
+LLPointer<LLImageRaw> LLSnapshotLivePreview::getEncodedImage()
+{
+ if (!mPreviewImageEncoded)
+ {
+ mPreviewImageEncoded = new LLImageRaw;
+
+ mPreviewImageEncoded->resize(
+ mPreviewImage->getWidth(),
+ mPreviewImage->getHeight(),
+ mPreviewImage->getComponents());
+
+ if (getSnapshotType() == SNAPSHOT_TEXTURE)
+ {
+ // We don't store the intermediate formatted image in mFormattedImage in the J2C case
+ lldebugs << "Encoding new image of format J2C" << llendl;
+ LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
+ // Copy the preview
+ LLPointer<LLImageRaw> scaled = new LLImageRaw(
+ mPreviewImage->getData(),
+ mPreviewImage->getWidth(),
+ mPreviewImage->getHeight(),
+ mPreviewImage->getComponents());
+ // Scale it as required by J2C
+ scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE);
+ setImageScaled(TRUE);
+ // Compress to J2C
+ if (formatted->encode(scaled, 0.f))
+ {
+ // We can update the data size precisely at that point
+ mDataSize = formatted->getDataSize();
+ // Decompress back
+ formatted->decode(mPreviewImageEncoded, 0);
+ }
+ }
+ else
+ {
+ // Update mFormattedImage if necessary
+ getFormattedImage();
+ if (getSnapshotFormat() == LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP)
+ {
+ // BMP hack : copy instead of decode otherwise decode will crash.
+ mPreviewImageEncoded->copy(mPreviewImage);
+ }
+ else
+ {
+ // Decode back
+ mFormattedImage->decode(mPreviewImageEncoded, 0);
+ }
+ }
+ }
+ return mPreviewImageEncoded;
+}
+
+// We actually estimate the data size so that we do not require actual compression when showing the preview
+// Note : whenever formatted image is computed, mDataSize will be updated to reflect the true size
+void LLSnapshotLivePreview::estimateDataSize()
+{
+ // Compression ratio
+ F32 ratio = 1.0;
+
+ if (getSnapshotType() == SNAPSHOT_TEXTURE)
+ {
+ ratio = 8.0; // This is what we shoot for when compressing to J2C
+ }
+ else
+ {
+ LLFloaterSnapshot::ESnapshotFormat format = getSnapshotFormat();
+ switch (format)
+ {
+ case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
+ ratio = 3.0; // Average observed PNG compression ratio
+ break;
+ case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
+ // Observed from JPG compression tests
+ ratio = (110 - mSnapshotQuality) / 2;
+ break;
+ case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
+ ratio = 1.0; // No compression with BMP
+ break;
+ }
+ }
+ mDataSize = (S32)((F32)mPreviewImage->getDataSize() / ratio);
+}
+
+LLPointer<LLImageFormatted> LLSnapshotLivePreview::getFormattedImage()
+{
+ if (!mFormattedImage)
+ {
+ // Apply the filter to mPreviewImage
+ if (getFilter() != "")
+ {
+ std::string filter_path = LLImageFiltersManager::getInstance()->getFilterPath(getFilter());
+ if (filter_path != "")
+ {
+ LLImageFilter filter(filter_path);
+ filter.executeFilter(mPreviewImage);
+ }
+ else
+ {
+ llwarns << "Couldn't find a path to the following filter : " << getFilter() << llendl;
+ }
+ }
+
+ // Create the new formatted image of the appropriate format.
+ LLFloaterSnapshot::ESnapshotFormat format = getSnapshotFormat();
+ lldebugs << "Encoding new image of format " << format << llendl;
+
+ switch (format)
+ {
+ case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
+ mFormattedImage = new LLImagePNG();
+ break;
+ case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
+ mFormattedImage = new LLImageJPEG(mSnapshotQuality);
+ break;
+ case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
+ mFormattedImage = new LLImageBMP();
+ break;
+ }
+ if (mFormattedImage->encode(mPreviewImage, 0))
+ {
+ // We can update the data size precisely at that point
+ mDataSize = mFormattedImage->getDataSize();
+ }
+ }
+ return mFormattedImage;
+}
+
void LLSnapshotLivePreview::setSize(S32 w, S32 h)
{
lldebugs << "setSize(" << w << ", " << h << ")" << llendl;
@@ -875,12 +949,14 @@ void LLSnapshotLivePreview::saveTexture()
}
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_SNAPSHOT_COUNT );
-
- mDataSize = 0;
}
BOOL LLSnapshotLivePreview::saveLocal()
{
+ // Update mFormattedImage if necessary
+ getFormattedImage();
+
+ // Save the formatted image
BOOL success = gViewerWindow->saveImageNumbered(mFormattedImage);
if(success)
@@ -892,6 +968,9 @@ BOOL LLSnapshotLivePreview::saveLocal()
void LLSnapshotLivePreview::saveWeb()
{
+ // Update mFormattedImage if necessary
+ getFormattedImage();
+
// *FIX: Will break if the window closes because of CloseSnapshotOnKeep!
// Needs to pass on ownership of the image.
LLImageJPEG* jpg = dynamic_cast<LLImageJPEG*>(mFormattedImage.get());
diff --git a/indra/newview/llsnapshotlivepreview.h b/indra/newview/llsnapshotlivepreview.h
index 6addc87de2..4fd6dedeed 100644
--- a/indra/newview/llsnapshotlivepreview.h
+++ b/indra/newview/llsnapshotlivepreview.h
@@ -70,6 +70,9 @@ public:
void getSize(S32& w, S32& h) const;
S32 getWidth() const { return mWidth[mCurImageIndex]; }
S32 getHeight() const { return mHeight[mCurImageIndex]; }
+ S32 getEncodedImageWidth() const;
+ S32 getEncodedImageHeight() const;
+ void estimateDataSize();
S32 getDataSize() const { return mDataSize; }
void setMaxImageSize(S32 size) ;
S32 getMaxImageSize() {return mMaxImageSize ;}
@@ -83,9 +86,10 @@ public:
S32 getThumbnailHeight() const { return mThumbnailHeight ; }
BOOL getThumbnailLock() const { return mThumbnailUpdateLock ; }
BOOL getThumbnailUpToDate() const { return mThumbnailUpToDate ;}
+ void setThumbnailSubsampled(BOOL subsampled) { mThumbnailSubsampled = subsampled; }
+
LLViewerTexture* getCurrentImage();
F32 getImageAspect();
- F32 getAspect() ;
const LLRect& getImageRect() const { return mImageRect[mCurImageIndex]; }
BOOL isImageScaled() const { return mImageScaled[mCurImageIndex]; }
void setImageScaled(BOOL scaled) { mImageScaled[mCurImageIndex] = scaled; }
@@ -96,14 +100,14 @@ public:
bool setSnapshotQuality(S32 quality, bool set_by_user = true);
void setSnapshotBufferType(LLViewerWindow::ESnapshotType type) { mSnapshotBufferType = type; }
void setFilter(std::string filter_name) { mFilterName = filter_name; }
- std::string getFilter() { return mFilterName; }
+ std::string getFilter() const { return mFilterName; }
void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f);
void saveWeb();
void saveTexture();
BOOL saveLocal();
- LLPointer<LLImageFormatted> getFormattedImage() const { return mFormattedImage; }
- LLPointer<LLImageRaw> getEncodedImage() const { return mPreviewImageEncoded; }
+ LLPointer<LLImageFormatted> getFormattedImage();
+ LLPointer<LLImageRaw> getEncodedImage();
/// Sets size of preview thumbnail image and thhe surrounding rect.
void setThumbnailPlaceholderRect(const LLRect& rect) {mThumbnailPlaceholderRect = rect; }
@@ -135,8 +139,10 @@ private:
BOOL mThumbnailUpdateLock ;
BOOL mThumbnailUpToDate ;
LLRect mThumbnailPlaceholderRect;
+ BOOL mThumbnailSubsampled; // TRUE is the thumbnail is a subsampled version of the mPreviewImage
S32 mCurImageIndex;
+ // The logic is mPreviewImage (raw frame) -> mFormattedImage (formatted / filtered) -> mPreviewImageEncoded (decoded back, to show artifacts)
LLPointer<LLImageRaw> mPreviewImage;
LLPointer<LLImageRaw> mPreviewImageEncoded;
LLPointer<LLImageFormatted> mFormattedImage;