Snapshot improvements.

* Warn when it was not possible to make a snapshot because the difference
between the aspect of the required target size and the required target
aspect itself is too large.
* Reset Feed and Postcard Aspect to Default when making a new snapshot.
* Fixed a rounding error that caused one-pixel size error.
This commit is contained in:
Aleric Inglewood
2013-01-01 21:30:13 +01:00
parent 6dcda3595e
commit 5538fe27e5
4 changed files with 76 additions and 23 deletions

View File

@@ -129,7 +129,10 @@ public:
CANNOT_CROP_HORIZONTALLY, CANNOT_CROP_HORIZONTALLY,
CANNOT_CROP_VERTICALLY, CANNOT_CROP_VERTICALLY,
SIZE_TOO_LARGE, SIZE_TOO_LARGE,
CANNOT_RESIZE CANNOT_RESIZE,
DELAYED,
NO_RAW_IMAGE,
ENCODING_FAILED
}; };
U32 typeToMask(ESnapshotType type) const { return 1 << type; } U32 typeToMask(ESnapshotType type) const { return 1 << type; }
@@ -190,7 +193,7 @@ public:
BOOL setThumbnailImageSize(); BOOL setThumbnailImageSize();
void generateThumbnailImage(); void generateThumbnailImage();
EAspectSizeProblem getAspectSizeProblem(S32& width_out, S32& height_out, bool& crop_vertically_out, S32& crop_offset_out); EAspectSizeProblem getAspectSizeProblem(S32& width_out, S32& height_out, bool& crop_vertically_out, S32& crop_offset_out);
void generateFormattedAndFullscreenPreview(bool delayed_formatted = false); EAspectSizeProblem generateFormattedAndFullscreenPreview(bool delayed_formatted = false);
void drawPreviewRect(S32 offset_x, S32 offset_y) ; void drawPreviewRect(S32 offset_x, S32 offset_y) ;
// Returns TRUE when snapshot generated, FALSE otherwise. // Returns TRUE when snapshot generated, FALSE otherwise.
@@ -813,6 +816,9 @@ BOOL LLSnapshotLivePreview::onIdle(LLSnapshotLivePreview* previewp)
// Time to produce a snapshot. // Time to produce a snapshot.
// Reset Feed and Postcard Aspect to Default.
LLFloaterSnapshot::resetFeedAndPostcardAspect();
if (!previewp->mRawSnapshot) if (!previewp->mRawSnapshot)
{ {
previewp->mRawSnapshot = new LLImageRaw; previewp->mRawSnapshot = new LLImageRaw;
@@ -857,8 +863,17 @@ BOOL LLSnapshotLivePreview::onIdle(LLSnapshotLivePreview* previewp)
Dout(dc::notice, "Created a new raw snapshot of size " << previewp->mRawSnapshotWidth << "x" << previewp->mRawSnapshotHeight); Dout(dc::notice, "Created a new raw snapshot of size " << previewp->mRawSnapshotWidth << "x" << previewp->mRawSnapshotHeight);
previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal(); previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();
previewp->generateFormattedAndFullscreenPreview(); EAspectSizeProblem ret = previewp->generateFormattedAndFullscreenPreview();
llassert(previewp->mFormattedUpToDate); // If the required size is too large, we might have to scale up one dimension... So that is ok.
// For example, if the target is 1000x1000 and the aspect is set to 8:1, then the required
// raw snapshot would be 8000x1000, but since 8000 is too large it would end up being only
// 6144x768 (since 6144 is the maximum) and we'll have to stretch the 768 to 1000.
llassert(previewp->mFormattedUpToDate || ret == SIZE_TOO_LARGE || ret == ENCODING_FAILED);
if (!previewp->mFormattedUpToDate && ret == SIZE_TOO_LARGE)
{
// ENCODING_FAILED was already reported.
LLNotificationsUtil::add("ErrorSizeAspectSnapshot");
}
} }
previewp->getWindow()->decBusyCount(); previewp->getWindow()->decBusyCount();
@@ -881,6 +896,19 @@ LLSnapshotLivePreview::EAspectSizeProblem LLSnapshotLivePreview::getAspectSizePr
// The current aspect ratio of mRawSnapshot is: // The current aspect ratio of mRawSnapshot is:
F32 const raw_aspect = (F32)mRawSnapshotWidth / mRawSnapshotHeight; F32 const raw_aspect = (F32)mRawSnapshotWidth / mRawSnapshotHeight;
// The smaller dimension might have been rounded up to 0.5 up or down. Calculate upper and lower limits.
F32 lower_raw_aspect;
F32 upper_raw_aspect;
if (mRawSnapshotWidth < mRawSnapshotHeight)
{
lower_raw_aspect = (mRawSnapshotWidth - 0.5) / mRawSnapshotHeight;
upper_raw_aspect = (mRawSnapshotWidth + 0.5) / mRawSnapshotHeight;
}
else
{
lower_raw_aspect = mRawSnapshotWidth / (mRawSnapshotHeight + 0.5);
upper_raw_aspect = mRawSnapshotWidth / (mRawSnapshotHeight - 0.5);
}
// Find out if mRawSnapshot was cropped already. // Find out if mRawSnapshot was cropped already.
bool const allow_vertical_crop = window_height * raw_aspect >= window_width; // mRawSnapshot was cropped horizontally. bool const allow_vertical_crop = window_height * raw_aspect >= window_width; // mRawSnapshot was cropped horizontally.
bool const allow_horizontal_crop = window_width / raw_aspect >= window_height; // mRawSnapshot was cropped vertically. bool const allow_horizontal_crop = window_width / raw_aspect >= window_height; // mRawSnapshot was cropped vertically.
@@ -889,7 +917,7 @@ LLSnapshotLivePreview::EAspectSizeProblem LLSnapshotLivePreview::getAspectSizePr
// Construct a rectangle size w,h that fits inside mRawSnapshot but has the correct aspect. // Construct a rectangle size w,h that fits inside mRawSnapshot but has the correct aspect.
width_out = mRawSnapshotWidth; width_out = mRawSnapshotWidth;
height_out = mRawSnapshotHeight; height_out = mRawSnapshotHeight;
if (mAspectRatio < raw_aspect) if (mAspectRatio < lower_raw_aspect)
{ {
width_out = llround(width_out * mAspectRatio / raw_aspect); width_out = llround(width_out * mAspectRatio / raw_aspect);
if (width_out < mRawSnapshotWidth) if (width_out < mRawSnapshotWidth)
@@ -899,13 +927,13 @@ LLSnapshotLivePreview::EAspectSizeProblem LLSnapshotLivePreview::getAspectSizePr
if (!allow_horizontal_crop) if (!allow_horizontal_crop)
{ {
Dout(dc::notice, "NOT up to date: required aspect " << mAspectRatio << Dout(dc::notice, "NOT up to date: required aspect " << mAspectRatio <<
" is less than raw aspect " << raw_aspect << " which is already vertically cropped."); " is less than the (lower) raw aspect " << lower_raw_aspect << " which is already vertically cropped.");
return CANNOT_CROP_HORIZONTALLY; return CANNOT_CROP_HORIZONTALLY;
} }
crop_offset_out = (mRawSnapshotWidth - width_out) / 2; crop_offset_out = (mRawSnapshotWidth - width_out) / 2;
} }
} }
else if (mAspectRatio > raw_aspect) else if (mAspectRatio > upper_raw_aspect)
{ {
height_out = llround(height_out * raw_aspect / mAspectRatio); height_out = llround(height_out * raw_aspect / mAspectRatio);
if (height_out < mRawSnapshotHeight) if (height_out < mRawSnapshotHeight)
@@ -913,7 +941,7 @@ LLSnapshotLivePreview::EAspectSizeProblem LLSnapshotLivePreview::getAspectSizePr
if (!allow_vertical_crop) if (!allow_vertical_crop)
{ {
Dout(dc::notice, "NOT up to date: required aspect " << mAspectRatio << Dout(dc::notice, "NOT up to date: required aspect " << mAspectRatio <<
" is larger than raw aspect " << raw_aspect << " which is already horizontally cropped."); " is larger than the (upper) raw aspect " << upper_raw_aspect << " which is already horizontally cropped.");
return CANNOT_CROP_VERTICALLY; return CANNOT_CROP_VERTICALLY;
} }
crop_offset_out = (mRawSnapshotHeight - height_out) / 2; crop_offset_out = (mRawSnapshotHeight - height_out) / 2;
@@ -940,7 +968,7 @@ LLSnapshotLivePreview::EAspectSizeProblem LLSnapshotLivePreview::getAspectSizePr
return ASPECTSIZE_OK; return ASPECTSIZE_OK;
} }
void LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(bool delayed) LLSnapshotLivePreview::EAspectSizeProblem LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(bool delayed)
{ {
DoutEntering(dc::notice, "LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(" << delayed << ")"); DoutEntering(dc::notice, "LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(" << delayed << ")");
mFormattedUpToDate = false; mFormattedUpToDate = false;
@@ -951,7 +979,7 @@ void LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(bool delayed)
if (ret != ASPECTSIZE_OK) if (ret != ASPECTSIZE_OK)
{ {
// Current raw snapshot cannot be used. // Current raw snapshot cannot be used.
return; return ret;
} }
// Determine the required format. // Determine the required format.
@@ -990,7 +1018,7 @@ void LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(bool delayed)
{ {
Dout(dc::notice, "Already up to date."); Dout(dc::notice, "Already up to date.");
mFormattedUpToDate = true; mFormattedUpToDate = true;
return; return ret;
} }
#ifdef CWDEBUG #ifdef CWDEBUG
@@ -1023,13 +1051,13 @@ void LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(bool delayed)
{ {
// Just set mFormattedUpToDate. // Just set mFormattedUpToDate.
Dout(dc::notice, "NOT up to date, but delayed. Returning."); Dout(dc::notice, "NOT up to date, but delayed. Returning.");
return; return DELAYED;
} }
if (!mRawSnapshot) if (!mRawSnapshot)
{ {
Dout(dc::notice, "No raw snapshot exists."); Dout(dc::notice, "No raw snapshot exists.");
return; return NO_RAW_IMAGE;
} }
Dout(dc::notice, "Generating a new formatted image!"); Dout(dc::notice, "Generating a new formatted image!");
@@ -1106,6 +1134,7 @@ void LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(bool delayed)
mFormattedDataSize = 0; mFormattedDataSize = 0;
// Disable upload/save button. // Disable upload/save button.
mFormattedImage = NULL; mFormattedImage = NULL;
ret = ENCODING_FAILED;
LLNotificationsUtil::add("ErrorEncodingSnapshot"); LLNotificationsUtil::add("ErrorEncodingSnapshot");
} }
@@ -1158,7 +1187,7 @@ void LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(bool delayed)
// Return success if mFormattedImage was succesfully generated. // Return success if mFormattedImage was succesfully generated.
mFormattedUpToDate = mFormattedImage; mFormattedUpToDate = mFormattedImage;
return; return ret;
} }
void LLSnapshotLivePreview::setSize(S32 w, S32 h) void LLSnapshotLivePreview::setSize(S32 w, S32 h)
@@ -1527,6 +1556,7 @@ public:
static void setResolution(LLFloaterSnapshot* floater, const std::string& comboname, bool visible, bool update_controls = true); static void setResolution(LLFloaterSnapshot* floater, const std::string& comboname, bool visible, bool update_controls = true);
static void setAspect(LLFloaterSnapshot* floater, const std::string& comboname, bool update_controls = true); static void setAspect(LLFloaterSnapshot* floater, const std::string& comboname, bool update_controls = true);
static void updateControls(LLFloaterSnapshot* floater, bool delayed_formatted = false); static void updateControls(LLFloaterSnapshot* floater, bool delayed_formatted = false);
static void resetFeedAndPostcardAspect(LLFloaterSnapshot* floater);
static void updateLayout(LLFloaterSnapshot* floater); static void updateLayout(LLFloaterSnapshot* floater);
static LLHandle<LLView> sPreviewHandle; static LLHandle<LLView> sPreviewHandle;
@@ -1603,6 +1633,16 @@ void LLFloaterSnapshot::Impl::setAspect(LLFloaterSnapshot* floater, const std::s
updateAspect(combo, floater, update_controls); // to sync spinner with combo updateAspect(combo, floater, update_controls); // to sync spinner with combo
} }
//static
void LLFloaterSnapshot::Impl::resetFeedAndPostcardAspect(LLFloaterSnapshot* floaterp)
{
floaterp->getChild<LLComboBox>("feed_aspect_combo")->setCurrentByIndex(0); // Default
gSavedSettings.setS32("SnapshotFeedLastAspect", 0);
floaterp->getChild<LLComboBox>("postcard_aspect_combo")->setCurrentByIndex(0); // Default
gSavedSettings.setS32("SnapshotPostcardLastAspect", 0);
}
//static //static
void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp) void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp)
{ {
@@ -1614,13 +1654,11 @@ void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp)
{ {
floaterp->getChild<LLComboBox>("feed_size_combo")->setCurrentByIndex(2); // 500x375 floaterp->getChild<LLComboBox>("feed_size_combo")->setCurrentByIndex(2); // 500x375
gSavedSettings.setS32("SnapshotFeedLastResolution", 2); gSavedSettings.setS32("SnapshotFeedLastResolution", 2);
floaterp->getChild<LLComboBox>("feed_aspect_combo")->setCurrentByIndex(0); // Default (500x375)
gSavedSettings.setS32("SnapshotFeedLastAspect", 0);
floaterp->getChild<LLComboBox>("postcard_size_combo")->setCurrentByIndex(0); // Current window floaterp->getChild<LLComboBox>("postcard_size_combo")->setCurrentByIndex(0); // Current window
gSavedSettings.setS32("SnapshotPostcardLastResolution", 0); gSavedSettings.setS32("SnapshotPostcardLastResolution", 0);
floaterp->getChild<LLComboBox>("postcard_aspect_combo")->setCurrentByIndex(0); // Default (current window)
gSavedSettings.setS32("SnapshotPostcardLastAspect", 0); resetFeedAndPostcardAspect(floaterp);
floaterp->getChild<LLComboBox>("texture_size_combo")->setCurrentByIndex(0); // 512x512 (most likely result for current window). floaterp->getChild<LLComboBox>("texture_size_combo")->setCurrentByIndex(0); // 512x512 (most likely result for current window).
gSavedSettings.setS32("SnapshotTextureLastResolution", 0); gSavedSettings.setS32("SnapshotTextureLastResolution", 0);
@@ -2280,9 +2318,9 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool
S32 new_height = 0; S32 new_height = 0;
F32 new_aspect = 0; F32 new_aspect = 0;
LLSnapshotLivePreview* previewp = getPreviewView(view); LLSnapshotLivePreview* previewp = getPreviewView(view);
#if 0 // Broken -- not doing this for now.
LLSnapshotLivePreview::ESnapshotType shot_type = (LLSnapshotLivePreview::ESnapshotType)gSavedSettings.getS32("LastSnapshotType"); LLSnapshotLivePreview::ESnapshotType shot_type = (LLSnapshotLivePreview::ESnapshotType)gSavedSettings.getS32("LastSnapshotType");
#if 0 // Broken -- not doing this for now.
// Is the snapshot was already used (saved or uploaded) and no manual changes // Is the snapshot was already used (saved or uploaded) and no manual changes
// have been made since to the current destination type, and the raw snapshot // have been made since to the current destination type, and the raw snapshot
// is still up to date with regard to visibility of UI, HUD and BufferType etc? // is still up to date with regard to visibility of UI, HUD and BufferType etc?
@@ -2992,6 +3030,12 @@ void LLFloaterSnapshot::updateControls()
Impl::updateControls(sInstance); Impl::updateControls(sInstance);
} }
//static
void LLFloaterSnapshot::resetFeedAndPostcardAspect()
{
Impl::resetFeedAndPostcardAspect(sInstance);
}
BOOL LLFloaterSnapshot::handleKeyHere(KEY key, MASK mask) BOOL LLFloaterSnapshot::handleKeyHere(KEY key, MASK mask)
{ {
static const LLCachedControl<bool> freeze_time("FreezeTime",false); static const LLCachedControl<bool> freeze_time("FreezeTime",false);

View File

@@ -77,6 +77,7 @@ public:
static void savePostcardDone(bool success, int index); static void savePostcardDone(bool success, int index);
static void updateControls(); static void updateControls();
static void resetFeedAndPostcardAspect();
private: private:
class Impl; class Impl;

View File

@@ -4387,15 +4387,15 @@ bool LLViewerWindow::rawRawSnapshot(LLImageRaw *raw,
F32 const window_aspect = (F32)window_width / window_height; F32 const window_aspect = (F32)window_width / window_height;
// snapshot fits precisely inside window, it is the portion of the window with the correct aspect. // snapshot fits precisely inside window, it is the portion of the window with the correct aspect.
S32 snapshot_width = (snapshot_aspect > window_aspect) ? window_width : llround(window_height * snapshot_aspect); F32 snapshot_width = (snapshot_aspect > window_aspect) ? (F32)window_width : window_height * snapshot_aspect;
S32 snapshot_height = (snapshot_aspect < window_aspect) ? window_height : llround(window_width / snapshot_aspect); F32 snapshot_height = (snapshot_aspect < window_aspect) ? (F32)window_height : window_width / snapshot_aspect;
// ratio is the ratio snapshot/image', where image' is a rectangle with aspect snapshot_aspect that precisely contains image. // ratio is the ratio snapshot/image', where image' is a rectangle with aspect snapshot_aspect that precisely contains image.
// Thus image_width' / image_height' == aspect ==> snapshot_width / image_width' == snapshot_height / image_height'. // Thus image_width' / image_height' == aspect ==> snapshot_width / image_width' == snapshot_height / image_height'.
// Since image' precisely contains image, one of them is equal (ie, image_height' = image_height) and the other is larger // Since image' precisely contains image, one of them is equal (ie, image_height' = image_height) and the other is larger
// (or equal) (ie, image_width' >= image_width), and therefore one of snapshot_width / image_width and // (or equal) (ie, image_width' >= image_width), and therefore one of snapshot_width / image_width and
// snapshot_height / image_height is correct, and the other is larger. Therefore, the smallest value of the // snapshot_height / image_height is correct, and the other is larger. Therefore, the smallest value of the
// following equals the ratio we're looking for. // following equals the ratio we're looking for.
F32 ratio = llmin((F32)snapshot_width / image_width, (F32)snapshot_height / image_height); F32 ratio = llmin(snapshot_width / image_width, snapshot_height / image_height);
// buffer equals the largest of image' and snapshot. This is because in the first case we need the higher // buffer equals the largest of image' and snapshot. This is because in the first case we need the higher
// resolution because of the size of the target image, and in the second case there is no reason to go // resolution because of the size of the target image, and in the second case there is no reason to go
// smaller because it takes the same amount of time (and a slightly better quality should result after // smaller because it takes the same amount of time (and a slightly better quality should result after
@@ -4404,7 +4404,7 @@ bool LLViewerWindow::rawRawSnapshot(LLImageRaw *raw,
// and snapshot (which have the same aspect). // and snapshot (which have the same aspect).
for(scale_factor = llmax(1.0f, 1.0f / ratio);; // Initial attempt. for(scale_factor = llmax(1.0f, 1.0f / ratio);; // Initial attempt.
// However, if the buffer turns out to be too large, then clamp it to max_size. // However, if the buffer turns out to be too large, then clamp it to max_size.
scale_factor = llmin((F32)max_size / snapshot_width, (F32)max_size / snapshot_height)) // Clamp scale_factor = llmin(max_size / snapshot_width, max_size / snapshot_height)) // Clamp
{ {
image_buffer_x = llround(snapshot_width * scale_factor); image_buffer_x = llround(snapshot_width * scale_factor);
image_buffer_y = llround(snapshot_height * scale_factor); image_buffer_y = llround(snapshot_height * scale_factor);

View File

@@ -960,6 +960,14 @@ Error processing snapshot data
Error encoding snapshot. Error encoding snapshot.
</notification> </notification>
<notification
icon="alertmodal.tga"
name="ErrorSizeAspectSnapshot"
type="alertmodal">
It is not possible to make a snapshot with this size and aspect.
Try a smaller size or a less stretched aspect.
</notification>
<notification <notification
icon="alertmodal.tga" icon="alertmodal.tga"
name="ErrorUploadingPostcard" name="ErrorUploadingPostcard"