From d8bc84adb1ac5bab0b7890beba472d5e9c87ccf7 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Tue, 4 Dec 2012 00:23:08 +0100 Subject: [PATCH] Snapshot fixes and improvements. * Allow to pass -1 to LLImageBase::reallocateData too (default parameter), causing it to allocate what is necessary for the size set (same behavior as allocateData). * Speed up LLImageRaw::scale with factor 2 or 3 by copying the data less often and calling LLImageBase::reallocateData instead of destroying and recreating always. * Fix gl_rect_2d to not decrement top and right with one pixel. * Remove the vague "Constrain Proportions" checkbox and replace it with a new combo box and spinner to explicitly set the target aspect ratio, allowing to set it also to something different than either the window aspect ratio (ie, 1.6) or the target image dimension (1.0 for textures) which was totally lacking when, for example, uploading a profile image (which needs to be 4:3). This also allows to show snapshots on prims of arbitrary aspects. --- indra/llimage/llimage.cpp | 105 +-- indra/llimage/llimage.h | 6 +- indra/llui/llui.cpp | 12 +- indra/newview/app_settings/settings.xml | 99 ++- indra/newview/llfloaterauction.cpp | 4 +- indra/newview/llfloaterreporter.cpp | 3 +- indra/newview/llfloatersnapshot.cpp | 754 ++++++++---------- indra/newview/llviewermenufile.cpp | 3 +- indra/newview/llviewerwindow.cpp | 148 ++-- indra/newview/llviewerwindow.h | 2 +- .../default/xui/en-us/floater_snapshot.xml | 134 +++- 11 files changed, 683 insertions(+), 587 deletions(-) diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 66217f902..4f6950a7d 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -206,6 +206,19 @@ U8* LLImageBase::allocateData(S32 size) // virtual U8* LLImageBase::reallocateData(S32 size) { + if (size == -1) + { + size = mWidth * mHeight * mComponents; + if (size <= 0) + { + llerrs << llformat("LLImageBase::reallocateData called with bad dimensions: %dx%dx%d", mWidth, mHeight, (S32)mComponents) << llendl; + } + } + else if (size <= 0 || (size > 4096 * 4096 * 16 && !mAllowOverSize)) + { + llerrs << "LLImageBase::reallocateData: bad size: " << size << llendl; + } + if(mData && (mDataSize == size)) return mData; @@ -943,76 +956,66 @@ BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) return TRUE; // Nothing to do. } - // Reallocate the data buffer. + U8* old_buffer = NULL; + U8* new_buffer; + S32 const old_width_bytes = old_width * getComponents(); + S32 const new_width_bytes = new_width * getComponents(); + S32 const min_height = llmin(old_height, new_height); + S32 const min_width_bytes = llmin(old_width_bytes, new_width_bytes); if (scale_image_data) { - // Vertical - S32 temp_data_size = old_width * new_height * getComponents(); - llassert_always(temp_data_size > 0); - U8* temp_buffer = new (std::nothrow) U8[ temp_data_size ]; - if (!temp_buffer ) + if (new_height != old_height) { - llerrs << "Out of memory in LLImageRaw::scale()" << llendl; - return FALSE; + // Resize vertically. + old_buffer = LLImageBase::release(); + new_buffer = allocateDataSize(old_width, new_height, getComponents()); + for (S32 col = 0; col < old_width; ++col) + { + copyLineScaled(old_buffer + getComponents() * col, new_buffer + getComponents() * col, old_height, new_height, old_width, old_width); + } + LLImageBase::deleteData(old_buffer); } - for( S32 col = 0; col < old_width; col++ ) + if (new_width != old_width) { - copyLineScaled( getData() + (getComponents() * col), temp_buffer + (getComponents() * col), old_height, new_height, old_width, old_width ); + // Resize horizontally. + old_buffer = LLImageBase::release(); + new_buffer = allocateDataSize(new_width, new_height, getComponents()); + for (S32 row = 0; row < new_height; ++row) + { + copyLineScaled(old_buffer + old_width_bytes * row, new_buffer + new_width_bytes * row, old_width, new_width, 1, 1); + } + LLImageBase::deleteData(old_buffer); } - - deleteData(); - - U8* new_buffer = allocateDataSize(new_width, new_height, getComponents()); - - // Horizontal - for( S32 row = 0; row < new_height; row++ ) - { - copyLineScaled( temp_buffer + (getComponents() * old_width * row), new_buffer + (getComponents() * new_width * row), old_width, new_width, 1, 1 ); - } - - // Clean up - delete[] temp_buffer; } else { - // copy out existing image data - S32 temp_data_size = old_width * old_height * getComponents(); - U8* temp_buffer = new (std::nothrow) U8[ temp_data_size ]; - if (!temp_buffer) + if (new_width == old_width) { - llwarns << "Out of memory in LLImageRaw::scale: old (w, h, c) = (" << old_width << ", " << old_height << ", " << (S32)getComponents() << - ") ; new (w, h, c) = (" << new_width << ", " << new_height << ", " << (S32)getComponents() << ")" << llendl; - - return FALSE ; + setSize(new_width, new_height, getComponents()); + new_buffer = reallocateData(); } - memcpy(temp_buffer, getData(), temp_data_size); /* Flawfinder: ignore */ - - // allocate new image data, will delete old data - U8* new_buffer = allocateDataSize(new_width, new_height, getComponents()); - - for( S32 row = 0; row < new_height; row++ ) + else { - if (row < old_height) + old_buffer = LLImageBase::release(); + new_buffer = allocateDataSize(new_width, new_height, getComponents()); + for (S32 row = 0; row < min_height; ++row) { - memcpy(new_buffer + (new_width * row * getComponents()), temp_buffer + (old_width * row * getComponents()), getComponents() * llmin(old_width, new_width)); /* Flawfinder: ignore */ - if (old_width < new_width) + memcpy(new_buffer + row * new_width_bytes, old_buffer + row * old_width_bytes, min_width_bytes); + if (new_width_bytes > old_width_bytes) { - // pad out rest of row with black - memset(new_buffer + (getComponents() * ((new_width * row) + old_width)), 0, getComponents() * (new_width - old_width)); + // Pad out rest of row with black. + memset(new_buffer + new_width_bytes * row + old_width_bytes, 0, new_width_bytes - old_width_bytes); } } - else - { - // pad remaining rows with black - memset(new_buffer + (new_width * row * getComponents()), 0, new_width * getComponents()); - } + LLImageBase::deleteData(old_buffer); + } + if (new_height > old_height) + { + // Pad remaining rows with black. + memset(new_buffer + new_width_bytes * min_height, 0, new_width_bytes * (new_height - old_height)); } - - // Clean up - delete[] temp_buffer; } - return TRUE ; } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 3782ff1cf..a5fcea97d 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -114,6 +114,8 @@ public: virtual void deleteData(); virtual U8* allocateData(S32 size = -1); virtual U8* reallocateData(S32 size = -1); + static void deleteData(U8* data) { FREE_MEM(sPrivatePoolp, data); } + U8* release() { U8* data = mData; mData = NULL; mDataSize = 0; return data; } // Same as deleteData(), but returns old data. Call deleteData(old_data) to free it. virtual void dump(); virtual void sanityCheck(); @@ -180,7 +182,7 @@ public: /*virtual*/ void deleteData(); /*virtual*/ U8* allocateData(S32 size = -1); - /*virtual*/ U8* reallocateData(S32 size); + /*virtual*/ U8* reallocateData(S32 size = -1); BOOL resize(U16 width, U16 height, S8 components); @@ -287,7 +289,7 @@ public: // LLImageBase /*virtual*/ void deleteData(); /*virtual*/ U8* allocateData(S32 size = -1); - /*virtual*/ U8* reallocateData(S32 size); + /*virtual*/ U8* reallocateData(S32 size = -1); /*virtual*/ void dump(); /*virtual*/ void sanityCheck(); diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index c5cf582e5..e34d1a852 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -201,15 +201,13 @@ void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled ) gGL.begin( LLRender::LINES ); // Verticals - gGL.vertex2i(left + 1, top); - gGL.vertex2i(left + 1, bottom); + gGL.vertex2i(left + 1, top + 1); + gGL.vertex2i(left + 1, bottom + 1); - gGL.vertex2i(right, bottom); - gGL.vertex2i(right, top); + gGL.vertex2i(right + 1, bottom + 1); + gGL.vertex2i(right + 1, top + 1); // Horizontals - top--; - right--; gGL.vertex2i(left, bottom); gGL.vertex2i(right, bottom); @@ -219,8 +217,6 @@ void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled ) } else { - top--; - right--; gGL.begin( LLRender::LINE_STRIP ); gGL.vertex2i(left, top); gGL.vertex2i(left, bottom); diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 6ad0c7bdf..1bd830a96 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7865,17 +7865,6 @@ Found in Advanced->Rendering->Info Displays Value 64 - KeepAspectForSnapshot - - Comment - Use full window when taking snapshot, regardless of requested image size - Persist - 1 - Type - Boolean - Value - 1 - LandBrushSize Comment @@ -8046,6 +8035,17 @@ Found in Advanced->Rendering->Info Displays Value 0.0.0 + LastSnapshotToFeedAspect + + Comment + The aspect ratio spinner value for snapshots uploaded to my.secondlife.com + Persist + 0 + Type + F32 + Value + 1.33333 + LastSnapshotToFeedHeight Comment @@ -8068,6 +8068,17 @@ Found in Advanced->Rendering->Info Displays Value 700 + LastSnapshotToEmailAspect + + Comment + The aspect ratio spinner value for snapshots sent by email + Persist + 0 + Type + F32 + Value + 0 + LastSnapshotToEmailHeight Comment @@ -8090,6 +8101,17 @@ Found in Advanced->Rendering->Info Displays Value 1024 + LastSnapshotToDiskAspect + + Comment + The aspect ratio spinner value for snapshots written to disk + Persist + 0 + Type + F32 + Value + 0 + LastSnapshotToDiskHeight Comment @@ -8112,6 +8134,17 @@ Found in Advanced->Rendering->Info Displays Value 1024 + LastSnapshotToInventoryAspect + + Comment + The aspect ratio spinner value for snapshots uploaded to inventory + Persist + 0 + Type + F32 + Value + 0 + LastSnapshotToInventoryHeight Comment @@ -13409,6 +13442,17 @@ Found in Advanced->Rendering->Info Displays Value 0 + SnapshotFeedLastAspect + + Comment + Take next feed snapshot at this aspect + Persist + 0 + Type + S32 + Value + 0 + SnapshotFeedLastResolution Comment @@ -13442,6 +13486,17 @@ Found in Advanced->Rendering->Info Displays Value 0 + SnapshotLocalLastAspect + + Comment + Take next local snapshot at this aspect + Persist + 0 + Type + S32 + Value + 0 + SnapshotLocalLastResolution Comment @@ -13453,6 +13508,17 @@ Found in Advanced->Rendering->Info Displays Value 0 + SnapshotPostcardLastAspect + + Comment + Take next postcard snapshot at this aspect + Persist + 0 + Type + S32 + Value + 0 + SnapshotPostcardLastResolution Comment @@ -13475,6 +13541,17 @@ Found in Advanced->Rendering->Info Displays Value 75 + SnapshotTextureLastAspect + + Comment + Take next texture snapshot at this aspect + Persist + 0 + Type + S32 + Value + 0 + SnapshotTextureLastResolution Comment diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp index c4121fae9..702688b47 100644 --- a/indra/newview/llfloaterauction.cpp +++ b/indra/newview/llfloaterauction.cpp @@ -180,8 +180,8 @@ void LLFloaterAuction::onClickSnapshot(void* data) BOOL success = gViewerWindow->rawSnapshot(raw, gViewerWindow->getWindowWidth(), gViewerWindow->getWindowHeight(), - TRUE, FALSE, - FALSE, FALSE); + (F32)gViewerWindow->getWindowWidth() / gViewerWindow->getWindowHeight(), + FALSE, FALSE, FALSE); gForceRenderLandFence = FALSE; if (success) diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 9952eadd3..5cdca6b6f 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -901,7 +901,8 @@ void LLFloaterReporter::takeScreenshot() const S32 IMAGE_HEIGHT = 768; LLPointer raw = new LLImageRaw; - if( !gViewerWindow->rawSnapshot(raw, IMAGE_WIDTH, IMAGE_HEIGHT, TRUE, FALSE, TRUE, FALSE)) + // Warning: This crops left and right in case of wide-screen monitor: + if( !gViewerWindow->rawSnapshot(raw, IMAGE_WIDTH, IMAGE_HEIGHT, (F32)IMAGE_WIDTH / IMAGE_HEIGHT, FALSE, TRUE, FALSE)) { llwarns << "Unable to take screenshot" << llendl; return; diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 50f97c7a2..32e955015 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -87,8 +87,8 @@ ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs ///---------------------------------------------------------------------------- -S32 LLFloaterSnapshot::sUIWinHeightLong = 585 ; -S32 LLFloaterSnapshot::sUIWinHeightShort = LLFloaterSnapshot::sUIWinHeightLong - 250 ; +S32 LLFloaterSnapshot::sUIWinHeightLong = 629 ; +S32 LLFloaterSnapshot::sUIWinHeightShort = LLFloaterSnapshot::sUIWinHeightLong - 270 ; S32 LLFloaterSnapshot::sUIWinWidth = 219 ; S32 const THUMBHEIGHT = 159; @@ -136,6 +136,8 @@ public: void setSize(S32 w, S32 h); void getSize(S32& w, S32& h) const; + void setAspect(F32 a); + F32 getAspect() const; void getUsedSize(S32& w, S32& h) const; S32 getDataSize() const { return mFormattedDataSize; } void setMaxImageSize(S32 size) ; @@ -143,7 +145,6 @@ public: ESnapshotType getSnapshotType() const { return mSnapshotType; } LLFloaterSnapshot::ESnapshotFormat getSnapshotFormat() const { return mSnapshotFormat; } - BOOL rawSnapshotUsesTiling(F32 supersample = 1.f) const; BOOL getSnapshotUpToDateExceptForSize() const; BOOL getSnapshotUpToDate() const; BOOL isSnapshotActive() { return mSnapshotActive; } @@ -154,8 +155,8 @@ public: BOOL getThumbnailUpToDate() const { return mThumbnailUpToDate ;} bool getShowFreezeFrameSnapshot() const { return mShowFreezeFrameSnapshot; } LLViewerTexture* getCurrentImage(); - LLRect getImageRect(); BOOL isImageScaled(); + char const* aspectComboName() const; void setSnapshotType(ESnapshotType type) { mSnapshotType = type; } void setSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat type) { mSnapshotFormat = type; } @@ -187,6 +188,7 @@ private: S32 mHeight[2]; BOOL mImageScaled[2]; S32 mMaxImageSize ; + F32 mAspectRatio; //thumbnail image LLPointer mThumbnailImage ; @@ -213,7 +215,7 @@ private: LLFloaterSnapshot::ESnapshotFormat mSnapshotFormat; S32 mUpToDateWidth; S32 mUpToDateHeight; - BOOL mUpToDateUsesTiling; + F32 mUpToDateAspectRatio; BOOL mUpToDateRenderUI; BOOL mUpToDateRenderHUD; LLViewerWindow::ESnapshotType mUpToDateBufferType; @@ -231,7 +233,6 @@ private: public: static std::set sList; - BOOL mKeepAspectRatio ; }; void LLSnapshotLivePreview::setSnapshotBufferType(LLFloaterSnapshot* floater, LLViewerWindow::ESnapshotType type) @@ -248,32 +249,9 @@ void LLSnapshotLivePreview::setSnapshotBufferType(LLFloaterSnapshot* floater, LL } } -// *Currently* LLViewerWindow::rawSnapshot does the exact same thing whether or not -// mKeepAspectRatio is set or not, except for maybe turning on tiling. This function -// determines if that will happen. -BOOL LLSnapshotLivePreview::rawSnapshotUsesTiling(F32 supersample) const -{ - // Assume the width used is the same as last time. Note that when we - // get here via getSnapshotUpToDate() or rawSnapshot() then these are - // just mWidth[0] and mHeight[0]. - S32 image_width = mUpToDateWidth; - S32 image_height = mUpToDateHeight; - // Use same code here as rawSnapshot to determine if tiling will be used. - LLRect const window_rect = gSavedSettings.getBOOL("RenderUIInSnapshot") ? gViewerWindow->getWindowRectRaw() : gViewerWindow->getWorldViewRectRaw(); -#if 1//SHY_MOD // screenshot improvement - F32 internal_scale = llmin(llmax(supersample,1.f),3.f); - // render at specified internal resolution. >1 results in supersampling. - image_height *= internal_scale; - image_width *= internal_scale; -#endif //shy_mod - return mKeepAspectRatio && - (image_width > window_rect.getWidth() || - image_height > window_rect.getHeight()); -} - BOOL LLSnapshotLivePreview::getSnapshotUpToDateExceptForSize() const { - return mUpToDateUsesTiling == rawSnapshotUsesTiling() && + return mUpToDateAspectRatio == mAspectRatio && mUpToDateRenderUI == gSavedSettings.getBOOL("RenderUIInSnapshot") && mUpToDateRenderHUD == gSavedSettings.getBOOL("RenderHUDInSnapshot") && mUpToDateBufferType == mSnapshotBufferType && @@ -308,7 +286,7 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLRect& rect) : mSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat"))), mUpToDateWidth(0), mUpToDateHeight(0), - mUpToDateUsesTiling(FALSE), + mUpToDateAspectRatio(1.0), mUpToDateRenderUI(FALSE), mUpToDateRenderHUD(FALSE), mUpToDateBufferType(LLViewerWindow::SNAPSHOT_TYPE_COLOR), @@ -333,7 +311,6 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLRect& rect) : mImageScaled[1] = FALSE; mMaxImageSize = MAX_SNAPSHOT_IMAGE_SIZE ; - mKeepAspectRatio = gSavedSettings.getBOOL("KeepAspectForSnapshot") ; mThumbnailUpdateLock = FALSE ; mThumbnailUpToDate = FALSE ; updateSnapshot(TRUE,TRUE); //To initialize mImageRect to correct values @@ -368,11 +345,6 @@ LLViewerTexture* LLSnapshotLivePreview::getCurrentImage() return mViewerImage[0]; } -LLRect LLSnapshotLivePreview::getImageRect() -{ - return mImageRect[0]; -} - BOOL LLSnapshotLivePreview::isImageScaled() { return mImageScaled[0]; @@ -384,7 +356,6 @@ void LLSnapshotLivePreview::showFreezeFrameSnapshot(bool show) // If we stop to show the fullscreen "freeze frame" snapshot, play the "fall away" animation. if (mShowFreezeFrameSnapshot && !show) { - Dout(dc::notice, "Starting Fall Animation."); mViewerImage[1] = mViewerImage[0]; mImageScaled[1] = mImageScaled[0]; mImageRect[1] = mImageRect[0]; @@ -402,27 +373,23 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail LLRect& rect = mImageRect[0]; rect.set(0, getRect().getHeight(), getRect().getWidth(), 0); - F32 image_aspect_ratio = ((F32)mWidth[0]) / ((F32)mHeight[0]); F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight()); - if (mKeepAspectRatio) + if (mAspectRatio > window_aspect_ratio) { - if (image_aspect_ratio > window_aspect_ratio) - { - // trim off top and bottom - S32 height_diff = getRect().getHeight() - llround((F32)getRect().getWidth() / image_aspect_ratio); - S32 half_height_diff = height_diff / 2; - rect.mBottom += half_height_diff; - rect.mTop -= height_diff - half_height_diff; - } - else if (image_aspect_ratio < window_aspect_ratio) - { - // trim off left and right - S32 width_diff = getRect().getWidth() - llround((F32)getRect().getHeight() * image_aspect_ratio); - S32 half_width_diff = width_diff / 2; - rect.mLeft += half_width_diff; - rect.mRight -= width_diff - half_width_diff; - } + // trim off top and bottom + S32 height_diff = llround(getRect().getHeight() - (F32)getRect().getWidth() / mAspectRatio); + S32 half_height_diff = llround((getRect().getHeight() - (F32)getRect().getWidth() / mAspectRatio) * 0.5); + rect.mBottom += half_height_diff; + rect.mTop -= height_diff - half_height_diff; + } + else if (mAspectRatio < window_aspect_ratio) + { + // trim off left and right + S32 width_diff = llround(getRect().getWidth() - (F32)getRect().getHeight() * mAspectRatio); + S32 half_width_diff = llround((getRect().getWidth() - (F32)getRect().getHeight() * mAspectRatio) * 0.5f); + rect.mLeft += half_width_diff; + rect.mRight -= width_diff - half_width_diff; } mShineAnimTimer.stop(); @@ -449,41 +416,34 @@ void LLSnapshotLivePreview::setSnapshotQuality(S32 quality) void LLSnapshotLivePreview::drawPreviewRect(S32 offset_x, S32 offset_y) { - F32 line_width ; - glGetFloatv(GL_LINE_WIDTH, &line_width) ; - glLineWidth(2.0f * line_width) ; - LLColor4 color(0.0f, 0.0f, 0.0f, 1.0f) ; - gl_rect_2d( mPreviewRect.mLeft + offset_x, mPreviewRect.mTop + offset_y, - mPreviewRect.mRight + offset_x, mPreviewRect.mBottom + offset_y, color, FALSE ) ; - glLineWidth(line_width) ; - // Draw two alpha rectangles to cover areas outside of the snapshot image. - if(!mKeepAspectRatio) + LLColor4 alpha_color(0.5f, 0.5f, 0.5f, 0.8f); + if (mThumbnailWidth > mPreviewRect.getWidth()) { - LLColor4 alpha_color(0.5f, 0.5f, 0.5f, 0.8f) ; - S32 dwl = 0, dwr = 0 ; - if(mThumbnailWidth > mPreviewRect.getWidth()) - { - dwl = (mThumbnailWidth - mPreviewRect.getWidth()) >> 1 ; - dwr = mThumbnailWidth - mPreviewRect.getWidth() - dwl ; - - gl_rect_2d(mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mTop + offset_y, - mPreviewRect.mLeft + offset_x, mPreviewRect.mBottom + offset_y, alpha_color, TRUE ) ; - gl_rect_2d( mPreviewRect.mRight + offset_x, mPreviewRect.mTop + offset_y, - mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mBottom + offset_y, alpha_color, TRUE ) ; - } - - if(mThumbnailHeight > mPreviewRect.getHeight()) - { - S32 dh = (mThumbnailHeight - mPreviewRect.getHeight()) >> 1 ; - gl_rect_2d(mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mBottom + offset_y , - mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mBottom + offset_y - dh, alpha_color, TRUE ) ; - - dh = mThumbnailHeight - mPreviewRect.getHeight() - dh ; - gl_rect_2d( mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mTop + offset_y + dh, - mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mTop + offset_y, alpha_color, TRUE ) ; - } + gl_rect_2d( offset_x, offset_y, + mPreviewRect.mLeft + offset_x, mThumbnailHeight + offset_y, + alpha_color, TRUE); + gl_rect_2d(mPreviewRect.mRight + offset_x, offset_y, + mThumbnailWidth + offset_x, mThumbnailHeight + offset_y, + alpha_color, TRUE); } + if (mThumbnailHeight > mPreviewRect.getHeight()) + { + gl_rect_2d( offset_x, offset_y, + mThumbnailWidth + offset_x, mPreviewRect.mBottom + offset_y, + alpha_color, TRUE); + gl_rect_2d( offset_x, mPreviewRect.mTop + offset_y, + mThumbnailWidth + offset_x, mThumbnailHeight + offset_y, + alpha_color, TRUE); + } + // Draw border around captured part. + F32 line_width; + glGetFloatv(GL_LINE_WIDTH, &line_width); + glLineWidth(2.0f * line_width); + gl_rect_2d( mPreviewRect.mLeft + offset_x, mPreviewRect.mTop + offset_y, + mPreviewRect.mRight + offset_x, mPreviewRect.mBottom + offset_y, + LLColor4::black, FALSE); + glLineWidth(line_width); } //called when the frame is frozen. @@ -715,33 +675,19 @@ BOOL LLSnapshotLivePreview::setThumbnailImageSize() } S32 left = 0 , top = mThumbnailHeight, right = mThumbnailWidth, bottom = 0 ; - if(!mKeepAspectRatio) + F32 ratio = mAspectRatio * window_height / window_width; + if(ratio > 1.f) { - F32 ratio_x = (F32)mWidth[0] / window_width ; - F32 ratio_y = (F32)mHeight[0] / window_height ; - - //if(mWidth[0] > window_width || - // mHeight[0] > 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) ; - //} - left = (S32)((mThumbnailWidth - right) * 0.5f) ; - bottom = (S32)((mThumbnailHeight - top) * 0.5f) ; - top += bottom ; - right += left ; + top = llround(top / ratio); } + else + { + right = llround(right * ratio); + } + left = (mThumbnailWidth - right + 1) / 2; + bottom = (mThumbnailHeight - top + 1) / 2; + top += bottom ; + right += left ; mPreviewRect.set(left - 1, top + 1, right + 1, bottom - 1) ; return TRUE ; @@ -781,9 +727,9 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update) LLPointer raw = NULL ; S32 w , h ; - w = get_lower_power_two(mThumbnailWidth, 512) * 2 ; - h = get_lower_power_two(mThumbnailHeight, 512) * 2 ; - + // Set w, h to the nearest power of two that is larger or equal to mThumbnailWidth, mThumbnailHeight (but never more than 1024). + w = get_lower_power_two(mThumbnailWidth - 1, 512) * 2 ; // -1 so that w becomes mThumbnailWidth if it is a power of 2, instead of 2 * mThumbnailWidth. + h = get_lower_power_two(mThumbnailHeight - 1, 512) * 2 ; { raw = new LLImageRaw ; if(!gViewerWindow->thumbnailSnapshot(raw, @@ -800,6 +746,7 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update) { mThumbnailImage = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); mThumbnailUpToDate = TRUE ; + Dout(dc::notice, "thumbnailSnapshot(" << w << ", " << h << ", ...) returns " << raw->getWidth() << ", " << raw->getHeight()); } //unlock updating @@ -853,7 +800,6 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) } previewp->setVisible(FALSE); - Dout(dc::notice, "[1] preview DISabled (" << (void*)previewp); previewp->setEnabled(FALSE); previewp->getWindow()->incBusyCount(); @@ -866,18 +812,18 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) previewp->mManualSizeOverride = 0; // Remember with what parameters this snapshot was taken. - previewp->mUpToDateWidth = previewp->mWidth[0]; // These two must be set BEFORE calling rawSnapshotUsesTiling(). + previewp->mUpToDateWidth = previewp->mWidth[0]; previewp->mUpToDateHeight = previewp->mHeight[0]; previewp->mUpToDateRenderUI = gSavedSettings.getBOOL("RenderUIInSnapshot"); previewp->mUpToDateRenderHUD = gSavedSettings.getBOOL("RenderHUDInSnapshot"); previewp->mUpToDateBufferType = previewp->mSnapshotBufferType; - previewp->mUpToDateUsesTiling = previewp->rawSnapshotUsesTiling(); + previewp->mUpToDateAspectRatio = previewp->mAspectRatio; if((previewp->mUpToDateMaxImageSize = gViewerWindow->rawSnapshot( previewp->mPreviewImage, previewp->mUpToDateWidth, previewp->mUpToDateHeight, - previewp->mKeepAspectRatio, + previewp->mUpToDateAspectRatio, previewp->getSnapshotType() == LLSnapshotLivePreview::SNAPSHOT_TEXTURE, // UNUSED previewp->mUpToDateRenderUI, FALSE, @@ -1000,22 +946,17 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) } previewp->getWindow()->decBusyCount(); // only show fullscreen preview when in freeze frame mode - Dout(dc::notice, "Preview setVisible(" << gSavedSettings.getBOOL("FreezeTime") << ")"); previewp->setVisible(gSavedSettings.getBOOL("FreezeTime")); previewp->mSnapshotDelayTimer.stop(); previewp->mSnapshotActive = FALSE; - - if(!previewp->getThumbnailUpToDate()) - { - previewp->generateThumbnailImage() ; - } + previewp->mThumbnailUpToDate = FALSE; + previewp->generateThumbnailImage() ; return TRUE; } void LLSnapshotLivePreview::setSize(S32 w, S32 h) { - Dout(dc::notice, "LLSnapshotLivePreview::setSize(" << w << ", " << h << ")"); mWidth[0] = w; mHeight[0] = h; } @@ -1026,6 +967,16 @@ void LLSnapshotLivePreview::getSize(S32& w, S32& h) const h = mHeight[0]; } +void LLSnapshotLivePreview::setAspect(F32 a) +{ + mAspectRatio = a; +} + +F32 LLSnapshotLivePreview::getAspect() const +{ + return mAspectRatio; +} + void LLSnapshotLivePreview::getUsedSize(S32& w, S32& h) const { w = mUpToDateWidth; @@ -1210,35 +1161,37 @@ public: static void onClickUICheck(LLUICtrl *ctrl, void* data); static void onClickHUDCheck(LLUICtrl *ctrl, void* data); static void onClickKeepOpenCheck(LLUICtrl *ctrl, void* data); - static void onClickKeepAspectCheck(LLUICtrl *ctrl, void* data); static void onCommitQuality(LLUICtrl* ctrl, void* data); static void onCommitFeedResolution(LLUICtrl* ctrl, void* data); static void onCommitPostcardResolution(LLUICtrl* ctrl, void* data); static void onCommitTextureResolution(LLUICtrl* ctrl, void* data); static void onCommitLocalResolution(LLUICtrl* ctrl, void* data); - static void updateResolution(LLUICtrl* ctrl, void* data, bool update_controls = true); + static void onCommitFeedAspect(LLUICtrl* ctrl, void* data); + static void onCommitPostcardAspect(LLUICtrl* ctrl, void* data); + static void onCommitTextureAspect(LLUICtrl* ctrl, void* data); + static void onCommitLocalAspect(LLUICtrl* ctrl, void* data); + static void updateResolution(LLUICtrl* ctrl, void* data); + static void updateAspect(LLUICtrl* ctrl, void* data); static void onCommitFreezeFrame(LLUICtrl* ctrl, void* data); static void onCommitLayerTypes(LLUICtrl* ctrl, void*data); static void onCommitSnapshotType(LLUICtrl* ctrl, void* data); static void onCommitSnapshotFormat(LLUICtrl* ctrl, void* data); static void onCommitCustomResolution(LLUICtrl *ctrl, void* data); - static void resetSnapshotSizeOnUI(LLFloaterSnapshot *view, S32 width, S32 height) ; - static BOOL checkImageSize(LLSnapshotLivePreview* previewp, S32& width, S32& height, BOOL isWidthChanged, S32 max_value); + static void onCommitCustomAspect(LLUICtrl *ctrl, void* data); static LLSnapshotLivePreview* getPreviewView(LLFloaterSnapshot *floater); - static void setResolution(LLFloaterSnapshot* floater, const std::string& comboname, bool update_controls = true); + static void setResolution(LLFloaterSnapshot* floater, const std::string& comboname); + static void setAspect(LLFloaterSnapshot* floater, const std::string& comboname); static void updateControls(LLFloaterSnapshot* floater); static void updateLayout(LLFloaterSnapshot* floater); static LLHandle sPreviewHandle; - static BOOL sAspectRatioCheckOff ; private: static LLSnapshotLivePreview::ESnapshotType getTypeIndex(LLFloaterSnapshot* floater); static ESnapshotFormat getFormatIndex(LLFloaterSnapshot* floater); static void comboSetCustom(LLFloaterSnapshot *floater, const std::string& comboname); static void checkAutoSnapshot(LLSnapshotLivePreview* floater, BOOL update_thumbnail = FALSE); - static void checkAspectRatio(LLFloaterSnapshot *view, S32 index) ; public: std::vector mAvatarPauseHandles; @@ -1249,9 +1202,6 @@ public: // static LLHandle LLFloaterSnapshot::Impl::sPreviewHandle; -//static -BOOL LLFloaterSnapshot::Impl::sAspectRatioCheckOff = FALSE ; - // static LLSnapshotLivePreview* LLFloaterSnapshot::Impl::getPreviewView(LLFloaterSnapshot *floater) { @@ -1293,11 +1243,19 @@ LLFloaterSnapshot::ESnapshotFormat LLFloaterSnapshot::Impl::getFormatIndex(LLFlo } // static -void LLFloaterSnapshot::Impl::setResolution(LLFloaterSnapshot* floater, const std::string& comboname, bool update_controls) +void LLFloaterSnapshot::Impl::setResolution(LLFloaterSnapshot* floater, const std::string& comboname) { LLComboBox* combo = floater->getChild(comboname); combo->setVisible(TRUE); - updateResolution(combo, floater, update_controls); // to sync spinners with combo + updateResolution(combo, floater); // to sync spinners with combo +} + +// static +void LLFloaterSnapshot::Impl::setAspect(LLFloaterSnapshot* floater, const std::string& comboname) +{ + LLComboBox* combo = floater->getChild(comboname); + combo->setVisible(TRUE); + updateAspect(combo, floater); // to sync spinner with combo } //static @@ -1309,19 +1267,25 @@ void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp) if(!gSavedSettings.getBOOL("AdvanceSnapshot")) //set to original window resolution { - checkAspectRatio(floaterp, 0); // 0 means current window size. - floaterp->getChild("feed_size_combo")->setCurrentByIndex(0); gSavedSettings.setS32("SnapshotFeedLastResolution", 0); + floaterp->getChild("feed_aspect_combo")->setCurrentByIndex(0); // 4:3 + gSavedSettings.setS32("SnapshotFeedLastAspect", 0); floaterp->getChild("postcard_size_combo")->setCurrentByIndex(0); gSavedSettings.setS32("SnapshotPostcardLastResolution", 0); + floaterp->getChild("postcard_aspect_combo")->setCurrentByIndex(0); // Default (current window) + gSavedSettings.setS32("SnapshotPostcardLastAspect", 0); floaterp->getChild("texture_size_combo")->setCurrentByIndex(0); gSavedSettings.setS32("SnapshotTextureLastResolution", 0); + floaterp->getChild("texture_aspect_combo")->setCurrentByIndex(0); // Current window + gSavedSettings.setS32("SnapshotTextureLastAspect", 0); floaterp->getChild("local_size_combo")->setCurrentByIndex(0); gSavedSettings.setS32("SnapshotLocalLastResolution", 0); + floaterp->getChild("local_aspect_combo")->setCurrentByIndex(0); // Current window + gSavedSettings.setS32("SnapshotLocalLastAspect", 0); LLSnapshotLivePreview* previewp = getPreviewView(floaterp); S32 w, h; @@ -1345,7 +1309,6 @@ void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp) if (previewp) { previewp->setVisible(TRUE); - Dout(dc::notice, "[1] preview ENabled (" << (void*)previewp); previewp->setEnabled(TRUE); } @@ -1374,7 +1337,6 @@ void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp) if (previewp) { previewp->setVisible(FALSE); - Dout(dc::notice, "[2] preview DISabled (" << (void*)previewp); previewp->setEnabled(FALSE); } @@ -1431,9 +1393,13 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater) ESnapshotFormat shot_format = (ESnapshotFormat)gSavedSettings.getS32("SnapshotFormat"); floater->childSetVisible("feed_size_combo", FALSE); + floater->childSetVisible("feed_aspect_combo", FALSE); floater->childSetVisible("postcard_size_combo", FALSE); + floater->childSetVisible("postcard_aspect_combo", FALSE); floater->childSetVisible("texture_size_combo", FALSE); + floater->childSetVisible("texture_aspect_combo", FALSE); floater->childSetVisible("local_size_combo", FALSE); + floater->childSetVisible("local_aspect_combo", FALSE); LLSnapshotLivePreview* previewp = getPreviewView(floater); if (previewp) @@ -1451,16 +1417,20 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater) switch(shot_type) { case LLSnapshotLivePreview::SNAPSHOT_FEED: - setResolution(floater, "feed_size_combo", false); + setResolution(floater, "feed_size_combo"); + setAspect(floater, "feed_aspect_combo"); break; case LLSnapshotLivePreview::SNAPSHOT_POSTCARD: - setResolution(floater, "postcard_size_combo", false); + setResolution(floater, "postcard_size_combo"); + setAspect(floater, "postcard_aspect_combo"); break; case LLSnapshotLivePreview::SNAPSHOT_TEXTURE: - setResolution(floater, "texture_size_combo", false); + setResolution(floater, "texture_size_combo"); + setAspect(floater, "texture_aspect_combo"); break; case LLSnapshotLivePreview::SNAPSHOT_LOCAL: - setResolution(floater, "local_size_combo", false); + setResolution(floater, "local_size_combo"); + setAspect(floater, "local_aspect_combo"); break; } } @@ -1471,7 +1441,6 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater) floater->childSetVisible("send_btn", shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD); floater->childSetVisible("feed_btn", shot_type == LLSnapshotLivePreview::SNAPSHOT_FEED); floater->childSetVisible("save_btn", shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL); - floater->childSetEnabled("keep_aspect_check", shot_type != LLSnapshotLivePreview::SNAPSHOT_TEXTURE && !sAspectRatioCheckOff); floater->childSetEnabled("layer_types", shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL); BOOL is_local = shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL; @@ -1483,13 +1452,14 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater) floater->childSetVisible("more_btn", !is_advance); // the only item hidden in advanced mode floater->childSetVisible("less_btn", is_advance); floater->childSetVisible("type_label2", is_advance); + floater->childSetVisible("type_label3", is_advance); floater->childSetVisible("format_label", is_advance && is_local); floater->childSetVisible("local_format_combo", is_advance && is_local); floater->childSetVisible("layer_types", is_advance); floater->childSetVisible("layer_type_label", is_advance); floater->childSetVisible("snapshot_width", is_advance); floater->childSetVisible("snapshot_height", is_advance); - floater->childSetVisible("keep_aspect_check", is_advance); + floater->childSetVisible("aspect_ratio", is_advance); floater->childSetVisible("ui_check", is_advance); floater->childSetVisible("hud_check", is_advance); floater->childSetVisible("keep_open_check", is_advance); @@ -1616,6 +1586,62 @@ void LLFloaterSnapshot::Impl::onCommitLocalResolution(LLUICtrl* ctrl, void* data updateResolution(ctrl, data); } +// static +void LLFloaterSnapshot::Impl::onCommitFeedAspect(LLUICtrl* ctrl, void* data) +{ + LLComboBox* combobox = (LLComboBox*)ctrl; + gSavedSettings.setS32("SnapshotFeedLastAspect", combobox->getCurrentIndex()); + LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; + LLSnapshotLivePreview* previewp = getPreviewView(view); + if (previewp && previewp->isUsed()) + { + previewp->addManualOverride(LLSnapshotLivePreview::SNAPSHOT_FEED); + } + updateAspect(ctrl, data); +} + +// static +void LLFloaterSnapshot::Impl::onCommitPostcardAspect(LLUICtrl* ctrl, void* data) +{ + LLComboBox* combobox = (LLComboBox*)ctrl; + gSavedSettings.setS32("SnapshotPostcardLastAspect", combobox->getCurrentIndex()); + LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; + LLSnapshotLivePreview* previewp = getPreviewView(view); + if (previewp && previewp->isUsed()) + { + previewp->addManualOverride(LLSnapshotLivePreview::SNAPSHOT_POSTCARD); + } + updateAspect(ctrl, data); +} + +// static +void LLFloaterSnapshot::Impl::onCommitTextureAspect(LLUICtrl* ctrl, void* data) +{ + LLComboBox* combobox = (LLComboBox*)ctrl; + gSavedSettings.setS32("SnapshotTextureLastAspect", combobox->getCurrentIndex()); + LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; + LLSnapshotLivePreview* previewp = getPreviewView(view); + if (previewp && previewp->isUsed()) + { + previewp->addManualOverride(LLSnapshotLivePreview::SNAPSHOT_TEXTURE); + } + updateAspect(ctrl, data); +} + +// static +void LLFloaterSnapshot::Impl::onCommitLocalAspect(LLUICtrl* ctrl, void* data) +{ + LLComboBox* combobox = (LLComboBox*)ctrl; + gSavedSettings.setS32("SnapshotLocalLastAspect", combobox->getCurrentIndex()); + LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; + LLSnapshotLivePreview* previewp = getPreviewView(view); + if (previewp && previewp->isUsed()) + { + previewp->addManualOverride(LLSnapshotLivePreview::SNAPSHOT_LOCAL); + } + updateAspect(ctrl, data); +} + // static void LLFloaterSnapshot::Impl::onCommitSave(LLUICtrl* ctrl, void* data) { @@ -1789,35 +1815,6 @@ void LLFloaterSnapshot::Impl::onClickKeepOpenCheck(LLUICtrl* ctrl, void* data) gSavedSettings.setBOOL( "CloseSnapshotOnKeep", !check->get() ); } -// static -void LLFloaterSnapshot::Impl::onClickKeepAspectCheck(LLUICtrl* ctrl, void* data) -{ - LLCheckBoxCtrl *check = (LLCheckBoxCtrl *)ctrl; - gSavedSettings.setBOOL( "KeepAspectForSnapshot", check->get() ); - - LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; - if (view) - { - LLSnapshotLivePreview* previewp = getPreviewView(view) ; - if(previewp) - { - previewp->mKeepAspectRatio = gSavedSettings.getBOOL("KeepAspectForSnapshot") ; - - S32 w, h ; - previewp->getSize(w, h) ; - if(checkImageSize(previewp, w, h, TRUE, previewp->getMaxImageSize())) - { - resetSnapshotSizeOnUI(view, w, h) ; - previewp->setSize(w, h) ; - updateControls(view); - } - - previewp->updateSnapshot(FALSE, TRUE); - checkAutoSnapshot(previewp, TRUE); - } - } -} - // static void LLFloaterSnapshot::Impl::onCommitQuality(LLUICtrl* ctrl, void* data) { @@ -1848,52 +1845,6 @@ void LLFloaterSnapshot::Impl::onCommitFreezeFrame(LLUICtrl* ctrl, void* data) updateLayout(view); } -// static -void LLFloaterSnapshot::Impl::checkAspectRatio(LLFloaterSnapshot *view, S32 index) -{ - LLSnapshotLivePreview *previewp = getPreviewView(view) ; - - if(0 == index) //current window size - { - sAspectRatioCheckOff = TRUE ; - view->childSetEnabled("keep_aspect_check", FALSE) ; - view->childSetValue("keep_aspect_check", TRUE); - - if(previewp) - { - previewp->mKeepAspectRatio = TRUE ; - } - } - else if(-1 == index) //custom - { - sAspectRatioCheckOff = FALSE ; - //if(LLSnapshotLivePreview::SNAPSHOT_TEXTURE != gSavedSettings.getS32("LastSnapshotType")) - { - bool custom_keep_aspect_ratio = gSavedSettings.getBOOL("KeepAspectForSnapshot"); - view->childSetEnabled("keep_aspect_check", TRUE) ; - view->childSetValue("keep_aspect_check", custom_keep_aspect_ratio); - - if(previewp) - { - previewp->mKeepAspectRatio = custom_keep_aspect_ratio; - } - } - } - else - { - sAspectRatioCheckOff = TRUE ; - view->childSetEnabled("keep_aspect_check", FALSE) ; - view->childSetValue("keep_aspect_check", FALSE); - - if(previewp) - { - previewp->mKeepAspectRatio = FALSE ; - } - } - - return ; -} - static std::string lastSnapshotWidthName() { switch(gSavedSettings.getS32("LastSnapshotType")) @@ -1904,6 +1855,7 @@ static std::string lastSnapshotWidthName() default: return "LastSnapshotToDiskWidth"; } } + static std::string lastSnapshotHeightName() { switch(gSavedSettings.getS32("LastSnapshotType")) @@ -1915,8 +1867,19 @@ static std::string lastSnapshotHeightName() } } +static std::string lastSnapshotAspectName() +{ + switch(gSavedSettings.getS32("LastSnapshotType")) + { + case LLSnapshotLivePreview::SNAPSHOT_FEED: return "LastSnapshotToFeedAspect"; + case LLSnapshotLivePreview::SNAPSHOT_POSTCARD: return "LastSnapshotToEmailAspect"; + case LLSnapshotLivePreview::SNAPSHOT_TEXTURE: return "LastSnapshotToInventoryAspect"; + default: return "LastSnapshotToDiskAspect"; + } +} + // static -void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool update_controls) +void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data) { LLComboBox* combobox = (LLComboBox*)ctrl; LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; @@ -1931,47 +1894,53 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool LLSnapshotLivePreview* previewp = getPreviewView(view); LLSnapshotLivePreview::ESnapshotType shot_type = (LLSnapshotLivePreview::ESnapshotType)gSavedSettings.getS32("LastSnapshotType"); +#if 0 // AIFIXME bool up_to_date_now = false; bool up_to_date_after_toggling = false; if (previewp && previewp->isUsed() && !previewp->isOverriddenBy(shot_type)) { up_to_date_now = previewp->getSnapshotUpToDateExceptForSize(); - previewp->mKeepAspectRatio = !previewp->mKeepAspectRatio; + previewp->mScaleInsteadOfCrop = !previewp->mScaleInsteadOfCrop; up_to_date_after_toggling = previewp->getSnapshotUpToDateExceptForSize(); - previewp->mKeepAspectRatio = !previewp->mKeepAspectRatio; + previewp->mScaleInsteadOfCrop = !previewp->mScaleInsteadOfCrop; } if (up_to_date_now || up_to_date_after_toggling) { - // need_keep_aspect is set when mKeepAspectRatio makes a difference. + // need_keep_aspect is set when mScaleInsteadOfCrop makes a difference. bool need_keep_aspect = up_to_date_now != up_to_date_after_toggling; - // Force the size, and possibly mKeepAspectRatio, to be the one of the existing snapshot. + // Force the size, and possibly mScaleInsteadOfCrop, to be the one of the existing snapshot. previewp->getUsedSize(used_w, used_h); - LLComboBox* combo_box = NULL; + LLComboBox* size_combo_box = NULL; + LLComboBox* aspect_combo_box = NULL; switch(shot_type) { case LLSnapshotLivePreview::SNAPSHOT_FEED: - combo_box = view->getChild("feed_size_combo"); + size_combo_box = view->getChild("feed_size_combo"); + aspect_combo_box = view->getChild("feed_aspect_combo"); break; case LLSnapshotLivePreview::SNAPSHOT_POSTCARD: - combo_box = view->getChild("postcard_size_combo"); + size_combo_box = view->getChild("postcard_size_combo"); + aspect_combo_box = view->getChild("postcard_aspect_combo"); break; case LLSnapshotLivePreview::SNAPSHOT_TEXTURE: - combo_box = view->getChild("texture_size_combo"); + size_combo_box = view->getChild("texture_size_combo"); + aspect_combo_box = view->getChild("texture_aspect_combo"); break; case LLSnapshotLivePreview::SNAPSHOT_LOCAL: - combo_box = view->getChild("local_size_combo"); + size_combo_box = view->getChild("local_size_combo"); + aspect_combo_box = view->getChild("local_aspect_combo"); break; } S32 index = 0; bool keep_aspect = true; - bool needed_keep_aspect = up_to_date_now ? previewp->mKeepAspectRatio : !previewp->mKeepAspectRatio; // Only valid if need_keep_aspect is true. - S32 const custom = combo_box->getItemCount() - 1; + bool needed_keep_aspect = up_to_date_now ? previewp->mScaleInsteadOfCrop : !previewp->mScaleInsteadOfCrop; // Only valid if need_keep_aspect is true. + S32 const custom = size_combo_box->getItemCount() - (shot_type == LLSnapshotLivePreview::SNAPSHOT_TEXTURE ? 0 : 1); // Texture does not end on 'Custom'. while (index < custom) { if (!need_keep_aspect || keep_aspect == needed_keep_aspect) { - combo_box->setCurrentByIndex(index); + size_combo_box->setCurrentByIndex(index); std::string sdstring = combobox->getSelectedValue(); LLSD sdres; std::stringstream sstream(sdstring); @@ -1985,7 +1954,6 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool } if (width == used_w && height == used_h) { - Dout(dc::notice, "Selected entry " << index << " with size " << width << "x" << height); break; } } @@ -1994,22 +1962,25 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool } if (index == custom) { - combo_box->setCurrentByIndex(index); - Dout(dc::notice, "Selected entry Custom"); + size_combo_box->setCurrentByIndex(index); if (need_keep_aspect) { - // Change mKeepAspectRatio to needed_keep_aspect. + // Change mScaleInsteadOfCrop to needed_keep_aspect. gSavedSettings.setBOOL("KeepAspectForSnapshot", needed_keep_aspect); - checkAspectRatio(view, -1); // -1 means custom. } } } else +#endif { view->getChild("feed_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastResolution")); + view->getChild("feed_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastAspect")); view->getChild("postcard_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastResolution")); + view->getChild("postcard_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastAspect")); view->getChild("texture_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastResolution")); + view->getChild("texture_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastAspect")); view->getChild("local_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastResolution")); + view->getChild("local_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastAspect")); } std::string sdstring = combobox->getSelectedValue(); @@ -2031,7 +2002,7 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool } else if (width == -1 || height == -1) { - if (previewp->isUsed()) + if (previewp->isUsed() && used_w != 0 && used_h != 0) { previewp->setSize(used_w, used_h); } @@ -2047,35 +2018,13 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool previewp->setSize(width, height); } - checkAspectRatio(view, width) ; - previewp->getSize(width, height); - if(checkImageSize(previewp, width, height, TRUE, previewp->getMaxImageSize())) - { - resetSnapshotSizeOnUI(view, width, height) ; - } - if(view->childGetValue("snapshot_width").asInteger() != width || view->childGetValue("snapshot_height").asInteger() != height) { - Dout(dc::notice, "LLFloaterSnapshot::Impl::updateResolution: set width, height to " << width << ", " << height); view->childSetValue("snapshot_width", width); view->childSetValue("snapshot_height", height); } - - if(original_width != width || original_height != height) - { - previewp->setSize(width, height); - - // hide old preview as the aspect ratio could be wrong - checkAutoSnapshot(previewp, FALSE); - getPreviewView(view)->updateSnapshot(FALSE, TRUE); - - if (update_controls) - { - updateControls(view); - } - } } // Set whether or not the spinners can be changed. @@ -2083,8 +2032,7 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool LLSpinCtrl* width_spinner = view->getChild("snapshot_width"); LLSpinCtrl* height_spinner = view->getChild("snapshot_height"); - if ((gSavedSettings.getS32("LastSnapshotType") == LLSnapshotLivePreview::SNAPSHOT_TEXTURE && - combobox->getCurrentIndex() != combobox->getItemCount() - 1) || + if (gSavedSettings.getS32("LastSnapshotType") == LLSnapshotLivePreview::SNAPSHOT_TEXTURE || gSavedSettings.getBOOL("RenderUIInSnapshot") || gSavedSettings.getBOOL("RenderHUDInSnapshot")) { @@ -2103,6 +2051,65 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool } } +// static +void LLFloaterSnapshot::Impl::updateAspect(LLUICtrl* ctrl, void* data) +{ + LLComboBox* combobox = (LLComboBox*)ctrl; + LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; + + if (!view || !combobox) + { + return; + } + + LLSnapshotLivePreview* previewp = getPreviewView(view); + //LLSnapshotLivePreview::ESnapshotType shot_type = (LLSnapshotLivePreview::ESnapshotType)gSavedSettings.getS32("LastSnapshotType"); + + view->getChild("feed_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastAspect")); + view->getChild("postcard_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastAspect")); + view->getChild("texture_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastAspect")); + view->getChild("local_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastAspect")); + + std::string sdstring = combobox->getSelectedValue(); + std::stringstream sstream; + sstream << sdstring; + F32 aspect; + sstream >> aspect; + + if (aspect == -1) // Custom + { + aspect = gSavedSettings.getF32(lastSnapshotAspectName()); + } + if (aspect == 0) // Current window + { + aspect = (F32)gViewerWindow->getWindowDisplayWidth() / gViewerWindow->getWindowDisplayHeight(); + } + + LLSpinCtrl* aspect_spinner = view->getChild("aspect_ratio"); + + // Sync the spinner and cache value. + aspect_spinner->set(aspect); + if (previewp) + { + previewp->setAspect(aspect); + checkAutoSnapshot(previewp, TRUE); + } + + // Set whether or not the spinners can be changed. + if (gSavedSettings.getBOOL("RenderUIInSnapshot") || + gSavedSettings.getBOOL("RenderHUDInSnapshot")) + { + // Disable without making label gray. + aspect_spinner->setAllowEdit(FALSE); + aspect_spinner->setIncrement(0); + } + else + { + aspect_spinner->setAllowEdit(TRUE); + aspect_spinner->setIncrement(llmax(0.01f, lltrunc(aspect) / 100.0f)); + } +} + // static void LLFloaterSnapshot::Impl::onCommitLayerTypes(LLUICtrl* ctrl, void*data) { @@ -2156,107 +2163,26 @@ void LLFloaterSnapshot::Impl::comboSetCustom(LLFloaterSnapshot* floater, const s { gSavedSettings.setS32("SnapshotPostcardLastResolution", combo->getCurrentIndex()); } - else if(comboname == "texture_size_combo") - { - gSavedSettings.setS32("SnapshotTextureLastResolution", combo->getCurrentIndex()); - } else if(comboname == "local_size_combo") { gSavedSettings.setS32("SnapshotLocalLastResolution", combo->getCurrentIndex()); } - - checkAspectRatio(floater, -1); // -1 means custom -} - - - -//static -BOOL LLFloaterSnapshot::Impl::checkImageSize(LLSnapshotLivePreview* previewp, S32& width, S32& height, BOOL isWidthChanged, S32 max_value) -{ - S32 w = width ; - S32 h = height ; - - //if texture, ignore aspect ratio setting, round image size to power of 2. -#if 0 // Don't round texture sizes; textures are commonly stretched in world, profiles, etc and need to be "squashed" during upload, not cropped here - if(LLSnapshotLivePreview::SNAPSHOT_TEXTURE == gSavedSettings.getS32("LastSnapshotType")) + else if(comboname == "feed_aspect_combo") { - if(width > max_value) - { - width = max_value ; - } - if(height > max_value) - { - height = max_value ; - } - - //round to nearest power of 2 based on the direction of movement - // i.e. higher power of two if increasing texture resolution - if(gSavedSettings.getS32("LastSnapshotToInventoryWidth") < width || - gSavedSettings.getS32("LastSnapshotToInventoryHeight") < height) - { - // Up arrow pressed - width = get_next_power_two(width, MAX_TEXTURE_SIZE) ; - height = get_next_power_two(height, MAX_TEXTURE_SIZE) ; - } - else - { - // Down or no change - width = get_lower_power_two(width, MAX_TEXTURE_SIZE) ; - height = get_lower_power_two(height, MAX_TEXTURE_SIZE) ; - } + gSavedSettings.setS32("SnapshotFeedLastAspect", combo->getCurrentIndex()); } - else -#endif - if(previewp && previewp->mKeepAspectRatio) + else if(comboname == "postcard_aspect_combo") { - if(gViewerWindow->getWindowDisplayWidth() < 1 || gViewerWindow->getWindowDisplayHeight() < 1) - { - return FALSE ; - } - - //aspect ratio of the current window - F32 aspect_ratio = (F32)gViewerWindow->getWindowDisplayWidth() / gViewerWindow->getWindowDisplayHeight() ; - - //change another value proportionally - if(isWidthChanged) - { - height = (S32)(width / aspect_ratio) ; - } - else - { - width = (S32)(height * aspect_ratio) ; - } - - //bound w/h by the max_value - if(width > max_value || height > max_value) - { - if(width > height) - { - width = max_value ; - height = (S32)(width / aspect_ratio) ; - } - else - { - height = max_value ; - width = (S32)(height * aspect_ratio) ; - } - } + gSavedSettings.setS32("SnapshotPostcardLastAspect", combo->getCurrentIndex()); } - else + else if(comboname == "texture_aspect_combo") { + gSavedSettings.setS32("SnapshotTextureLastAspect", combo->getCurrentIndex()); + } + else if(comboname == "local_aspect_combo") + { + gSavedSettings.setS32("SnapshotLocalLastAspect", combo->getCurrentIndex()); } - - return (w != width || h != height) ; -} - -//static -void LLFloaterSnapshot::Impl::resetSnapshotSizeOnUI(LLFloaterSnapshot *view, S32 width, S32 height) -{ - DoutEntering(dc::notice, "LLFloaterSnapshot::Impl::resetSnapshotSizeOnUI(" << width << ", " << height << ")"); - view->getChild("snapshot_width")->forceSetValue(width); - view->getChild("snapshot_height")->forceSetValue(height); - gSavedSettings.setS32(lastSnapshotWidthName(), width); - gSavedSettings.setS32(lastSnapshotHeightName(), height); } //static @@ -2265,8 +2191,8 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; if (view) { - S32 w = llfloor((F32)view->childGetValue("snapshot_width").asReal()); - S32 h = llfloor((F32)view->childGetValue("snapshot_height").asReal()); + S32 w = llround(view->childGetValue("snapshot_width").asReal(), 1.0); + S32 h = llround(view->childGetValue("snapshot_height").asReal(), 1.0); LLSnapshotLivePreview* previewp = getPreviewView(view); if (previewp) @@ -2276,44 +2202,12 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat if (w != curw || h != curh) { - BOOL update_ = FALSE ; - //if to upload a snapshot, process spinner input in a special way. -#if 0 // Don't round texture sizes; textures are commonly stretched in world, profiles, etc and need to be "squashed" during upload, not cropped here - if(LLSnapshotLivePreview::SNAPSHOT_TEXTURE == gSavedSettings.getS32("LastSnapshotType")) - { - S32 spinner_increment = (S32)((LLSpinCtrl*)ctrl)->getIncrement() ; - S32 dw = w - curw ; - S32 dh = h - curh ; - dw = (dw == spinner_increment) ? 1 : ((dw == -spinner_increment) ? -1 : 0) ; - dh = (dh == spinner_increment) ? 1 : ((dh == -spinner_increment) ? -1 : 0) ; - - if(dw) - { - w = (dw > 0) ? curw << dw : curw >> -dw ; - update_ = TRUE ; - } - if(dh) - { - h = (dh > 0) ? curh << dh : curh >> -dh ; - update_ = TRUE ; - } - } -#endif previewp->setMaxImageSize((S32)((LLSpinCtrl *)ctrl)->getMaxValue()) ; - - // Check image size changes the value of height and width - if(checkImageSize(previewp, w, h, w != curw, previewp->getMaxImageSize()) - || update_) - { - resetSnapshotSizeOnUI(view, w, h) ; - } - previewp->setSize(w,h); checkAutoSnapshot(previewp, FALSE); previewp->updateSnapshot(FALSE, TRUE); comboSetCustom(view, "feed_size_combo"); comboSetCustom(view, "postcard_size_combo"); - comboSetCustom(view, "texture_size_combo"); comboSetCustom(view, "local_size_combo"); } } @@ -2325,6 +2219,54 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat } } +char const* LLSnapshotLivePreview::aspectComboName() const +{ + char const* result; + switch(mSnapshotType) + { + case SNAPSHOT_FEED: + result = "feed_aspect_combo"; + break; + case SNAPSHOT_POSTCARD: + result = "postcard_aspect_combo"; + break; + case SNAPSHOT_TEXTURE: + result = "texture_aspect_combo"; + break; + case SNAPSHOT_LOCAL: + result = "local_aspect_combo"; + break; + } + return result; +} + +//static +void LLFloaterSnapshot::Impl::onCommitCustomAspect(LLUICtrl *ctrl, void* data) +{ + LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; + if (view) + { + F32 a = view->childGetValue("aspect_ratio").asReal(); + + LLSnapshotLivePreview* previewp = getPreviewView(view); + if (previewp) + { + F32 cura = previewp->getAspect(); + + if (a != cura) + { + previewp->setAspect(a); + previewp->updateSnapshot(FALSE, TRUE); + comboSetCustom(view, previewp->aspectComboName()); + } + } + + gSavedSettings.setF32(lastSnapshotAspectName(), a); + + updateControls(view); + } +} + ///---------------------------------------------------------------------------- /// Class LLFloaterSnapshot ///---------------------------------------------------------------------------- @@ -2380,6 +2322,8 @@ BOOL LLFloaterSnapshot::postBuild() childSetCommitCallback("snapshot_width", Impl::onCommitCustomResolution, this); childSetCommitCallback("snapshot_height", Impl::onCommitCustomResolution, this); + childSetCommitCallback("aspect_ratio", Impl::onCommitCustomAspect, this); + childSetCommitCallback("ui_check", Impl::onClickUICheck, this); childSetValue("ui_check", gSavedSettings.getBOOL("RenderUIInSnapshot")); @@ -2389,14 +2333,10 @@ BOOL LLFloaterSnapshot::postBuild() childSetCommitCallback("keep_open_check", Impl::onClickKeepOpenCheck, this); childSetValue("keep_open_check", !gSavedSettings.getBOOL("CloseSnapshotOnKeep")); - childSetCommitCallback("keep_aspect_check", Impl::onClickKeepAspectCheck, this); - childSetValue("keep_aspect_check", gSavedSettings.getBOOL("KeepAspectForSnapshot")); - childSetCommitCallback("layer_types", Impl::onCommitLayerTypes, this); childSetValue("layer_types", "colors"); childSetEnabled("layer_types", FALSE); - Dout(dc::notice, "LLFloaterSnapshot::postBuild: setting width, height to " << gSavedSettings.getS32(lastSnapshotWidthName()) << ", " << gSavedSettings.getS32(lastSnapshotHeightName())); childSetValue("snapshot_width", gSavedSettings.getS32(lastSnapshotWidthName())); childSetValue("snapshot_height", gSavedSettings.getS32(lastSnapshotHeightName())); @@ -2412,6 +2352,11 @@ BOOL LLFloaterSnapshot::postBuild() childSetCommitCallback("texture_size_combo", Impl::onCommitTextureResolution, this); childSetCommitCallback("local_size_combo", Impl::onCommitLocalResolution, this); + childSetCommitCallback("feed_aspect_combo", Impl::onCommitFeedAspect, this); + childSetCommitCallback("postcard_aspect_combo", Impl::onCommitPostcardAspect, this); + childSetCommitCallback("texture_aspect_combo", Impl::onCommitTextureAspect, this); + childSetCommitCallback("local_aspect_combo", Impl::onCommitLocalAspect, this); + // create preview window LLRect full_screen_rect = sInstance->getRootView()->getRect(); LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(full_screen_rect); @@ -2420,15 +2365,13 @@ BOOL LLFloaterSnapshot::postBuild() sInstance->getRootView()->addChild(previewp); sInstance->getRootView()->addChild(gSnapshotFloaterView); - // gSavedSettings.setBOOL("TemporaryUpload",FALSE); - childSetValue("temp_check",FALSE); - // + childSetValue("temp_check",FALSE); Impl::sPreviewHandle = previewp->getHandle(); impl.updateControls(this); - + return TRUE; } @@ -2448,10 +2391,17 @@ void LLFloaterSnapshot::draw() { if(previewp->getThumbnailImage()) { - S32 offset_x = (getRect().getWidth() - previewp->getThumbnailWidth()) / 2 + 1; - S32 offset_y = getRect().getHeight() - (THUMBHEIGHT + previewp->getThumbnailHeight()) / 2 - 4; + // getRect() includes shadows and the title bar, therefore the real corners are as follows: + S32 const left = 1; + S32 const right = getRect().getWidth() - 1; + S32 const top = getRect().getHeight() - 17; + S32 const bottom = top - THUMBHEIGHT; + // The offset needed to center the thumbnail is: center - thumbnailSize/2 = + S32 offset_x = (left + right - previewp->getThumbnailWidth()) / 2; + S32 offset_y = (bottom + top - previewp->getThumbnailHeight()) / 2; gGL.matrixMode(LLRender::MM_MODELVIEW); + gl_rect_2d(left, top, right, bottom, LLColor4::grey4, true); gl_draw_scaled_image(offset_x, offset_y, previewp->getThumbnailWidth(), previewp->getThumbnailHeight(), previewp->getThumbnailImage(), LLColor4::white); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index fc795f8fb..1e09ef59a 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -527,6 +527,7 @@ class LLFileTakeSnapshotToDisk : public view_listener_t S32 width = gViewerWindow->getWindowDisplayWidth(); S32 height = gViewerWindow->getWindowDisplayHeight(); + F32 ratio = (F32)width / height; F32 supersample = 1.f; if (gSavedSettings.getBOOL("HighResSnapshot")) @@ -546,7 +547,7 @@ class LLFileTakeSnapshotToDisk : public view_listener_t if (gViewerWindow->rawSnapshot(raw, width, height, - TRUE, + ratio, FALSE, gSavedSettings.getBOOL("RenderUIInSnapshot"), FALSE, diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index d245928dc..7e3c58815 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -4120,7 +4120,7 @@ BOOL LLViewerWindow::saveSnapshot( const std::string& filepath, S32 image_width, llinfos << "Saving snapshot to: " << filepath << llendl; LLPointer raw = new LLImageRaw; - BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, do_rebuild); + BOOL success = rawSnapshot(raw, image_width, image_height, (F32)image_width / image_height, FALSE, show_ui, do_rebuild); if (success) { @@ -4156,7 +4156,7 @@ void LLViewerWindow::playSnapshotAnimAndSound() BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) { - return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type); + return rawSnapshot(raw, preview_width, preview_height, (F32)gViewerWindow->getWindowWidthRaw() / gViewerWindow->getWindowHeightRaw(), TRUE, show_ui, do_rebuild, type); // *TODO below code was broken in deferred pipeline /* @@ -4295,9 +4295,9 @@ BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 p return TRUE;*/ } -// Saves the image from the screen to the specified filename and path. +// Saves the image from the screen to the image pointed to by raw. S32 LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, - BOOL keep_window_aspect, BOOL /*is_texture*/, BOOL show_ui, BOOL do_rebuild, ESnapshotType type, S32 max_size, F32 supersample) + F32 snapshot_aspect, BOOL /*is_texture*/, BOOL show_ui, BOOL do_rebuild, ESnapshotType type, S32 max_size, F32 supersample) { if (!raw) { @@ -4339,23 +4339,12 @@ S32 LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_heig // Copy screen to a buffer - // crop sides or top and bottom, if taking a snapshot of different aspect ratio - // from window - LLRect const window_rect = show_ui ? getWindowRectRaw() : getWorldViewRectRaw(); + LLRect const window_rect = show_ui ? getWindowRectRaw() : getWorldViewRectRaw(); S32 const window_width = window_rect.getWidth(); S32 const window_height = window_rect.getHeight(); // SNAPSHOT - S32 snapshot_width = window_width; - S32 snapshot_height = window_height; - F32 scale_factor = 1.0f ; - bool is_tiling = false; - - //fbo method no longer supported. Good riddance - /*LLRenderTarget target; - bool use_fbo = false; - static const LLCachedControl force_tile("SHHighResSnapshotForceTile",false);*/ #if 1//SHY_MOD // screenshot improvement F32 internal_scale = llmin(llmax(supersample,1.f),3.f); @@ -4379,69 +4368,54 @@ S32 LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_heig } } - if(!keep_window_aspect) //image cropping - { - F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ; - snapshot_width = (S32)(ratio * image_width) ; - snapshot_height = (S32)(ratio * image_height) ; - scale_factor = llmax(1.0f, 1.0f / ratio) ; - } - else //the scene(window) proportion needs to be maintained. + S32 buffer_x_offset = 0; + S32 buffer_y_offset = 0; + F32 scale_factor; + S32 image_buffer_x; + S32 image_buffer_y; + S32 max_image_buffer; + + 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. + S32 snapshot_width = (snapshot_aspect > window_aspect) ? window_width : llround(window_height * snapshot_aspect); + S32 snapshot_height = (snapshot_aspect < window_aspect) ? window_height : llround(window_width / snapshot_aspect); + // 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'. + // 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 + // 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. + F32 ratio = llmin((F32)snapshot_width / image_width, (F32)snapshot_height / image_height); + // 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 + // smaller because it takes the same amount of time (and a slightly better quality should result after + // the final scaling). Thus, if ratio < 1 then buffer equals image', otherwise it equals snapshot. + // scale_factor is the ratio buffer/snapshot, and is initiallly equal to the ratio between buffer + // and snapshot (which have the same aspect). + 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. + scale_factor = llmin((F32)max_size / snapshot_width, (F32)max_size / snapshot_height)) // Clamp { - if(image_width > window_width || image_height > window_height) //need to enlarge the scene + image_buffer_x = llround(snapshot_width * scale_factor); + image_buffer_y = llround(snapshot_height * scale_factor); + max_image_buffer = llmax(image_buffer_x, image_buffer_y); + if (max_image_buffer > max_size && // Boundary check to avoid memory overflow. + internal_scale <= 1.f) // SHY_MOD: If supersampling... Don't care about max_size. { - //Unsupported - /*if (!force_tile && gGLManager.mHasFramebufferObject && !show_ui) - { - GLint max_size = 0; - glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &max_size); - - if (image_width <= max_size && image_height <= max_size) //re-project the scene - { - use_fbo = TRUE; - - snapshot_width = image_width; - snapshot_height = image_height; - target.allocate(snapshot_width, snapshot_height, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, TRUE); - window_width = snapshot_width; - window_height = snapshot_height; - scale_factor = 1.f; - mWindowRectRaw.set(0, snapshot_height, snapshot_width, 0); - target.bindTarget(); - } - } - - if(!use_fbo) //no re-projection, so tiling the scene*/ - { - F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ; - snapshot_width = (S32)(ratio * image_width) ; - snapshot_height = (S32)(ratio * image_height) ; - scale_factor = llmax(1.0f, 1.0f / ratio) ; - Dout(dc::warning, "USING TILING FOR SNAPSHOT!"); - is_tiling = true; - } + // Too big, clamp. + continue; } - //else: keep the current scene scale, re-scale it if necessary after reading out. + // Done. + break; } - - S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f); - S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f); + // Center the buffer. + buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f); + buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f); + Dout(dc::notice, "rawSnapshot(" << image_width << ", " << image_height << ", " << snapshot_aspect << "): image_buffer_x = " << image_buffer_x << "; image_buffer_y = " << image_buffer_y); - S32 image_buffer_x = llfloor(snapshot_width*scale_factor) ; - S32 image_buffer_y = llfloor(snapshot_height*scale_factor) ; - S32 max_image_buffer = llmax(image_buffer_x, image_buffer_y); -#if 1//SHY_MOD // screenshot improvement - if(internal_scale <= 1.f) //If supersampling... Don't care about max_size. -#endif //shy_mod - if(max_image_buffer > max_size) //boundary check to avoid memory overflow - { - scale_factor *= llmin((F32)max_size / image_buffer_x, (F32)max_size / image_buffer_y) ; - image_buffer_x = llfloor(snapshot_width*scale_factor) ; - image_buffer_y = llfloor(snapshot_height *scale_factor) ; - } if (image_buffer_x > 0 && image_buffer_y > 0) { - raw->resize(image_buffer_x, image_buffer_y, 3); + raw->resize(image_buffer_x, image_buffer_y, 3); } else { @@ -4452,15 +4426,16 @@ S32 LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_heig return 0; } - BOOL high_res = scale_factor > 1.f; - if (high_res) + BOOL is_tiling = scale_factor > 1.f; + if (is_tiling) { + Dout(dc::warning, "USING TILING FOR SNAPSHOT!"); send_agent_pause(); if (show_ui || !hide_hud) { - //rescale fonts - initFonts(scale_factor); - LLHUDObject::reshapeAll(); + //rescale fonts + initFonts(scale_factor); + LLHUDObject::reshapeAll(); } } @@ -4473,7 +4448,7 @@ S32 LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_heig for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y) { - S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);; + S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height); // handle fractional columns U32 read_height = llmax(0, (window_height - subimage_y_offset) - llmax(0, (window_height * (subimage_y + 1)) - (buffer_y_offset + raw->getHeight()))); @@ -4558,12 +4533,6 @@ S32 LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_heig output_buffer_offset_y += subimage_y_offset; } - /*if (use_fbo) - { - mWindowRect = window_rect; - target.flush(); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - }*/ gDisplaySwapBuffers = FALSE; gDepthDirty = TRUE; @@ -4578,15 +4547,16 @@ S32 LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_heig LLPipeline::sShowHUDAttachments = TRUE; } - if (high_res && (show_ui || !hide_hud)) + if (is_tiling && (show_ui || !hide_hud)) { initFonts(1.f); LLHUDObject::reshapeAll(); } - // Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding) - // Note: this formula depends on the number of components being 3. Not obvious, but it's correct. - image_width += (image_width * 3) % 4; + // Pad image width such that the line length is a multiple of 4 bytes (for BMP encoding). + int n = 4; + for (int c = raw->getComponents(); c % 2 == 0 && n > 1; c /= 2) { n /= 2; } // n /= gcd(n, components) + image_width += (image_width * (n - 1)) % n; // Now n divides image_width, and thus four divides image_width * components, the line length. BOOL ret = TRUE ; // Resize image @@ -4620,7 +4590,7 @@ S32 LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_heig gPipeline.resetDrawOrders(); } - if (high_res) + if (is_tiling) { send_agent_resume(); } diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index f3190b197..8fdd70f7c 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -312,7 +312,7 @@ public: }; BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR); // Returns the largest dimension (x or y) of the buffer (which is never larger than max_size), or 0 on failure. - S32 rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE, + S32 rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, F32 aspect, BOOL is_texture = FALSE, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE, F32 supersample = 1.f ); BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) ; BOOL isSnapshotLocSet() const { return ! sSnapshotDir.empty(); } diff --git a/indra/newview/skins/default/xui/en-us/floater_snapshot.xml b/indra/newview/skins/default/xui/en-us/floater_snapshot.xml index 7998d62aa..f6f1057eb 100644 --- a/indra/newview/skins/default/xui/en-us/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en-us/floater_snapshot.xml @@ -1,12 +1,12 @@ - + File size: [SIZE] KB - - Destination + + Target @@ -18,7 +18,7 @@ Save to my inventory ([UPLOADFEE]) - + Save to my hard drive @@ -49,7 +49,7 @@ tool_tip="Advanced Options. Default uses current window size." width="80" /> - Size + Target size @@ -105,20 +105,32 @@ - - Current Window + + 128x128 (1:1) - - Small (128x128) + + 256x256 (1:1) - - Medium (256x256) + + 512x512 (1:1) - - Large (512x512) + + 256x128 (2:1) - - Custom + + 512x256 (2:1) + + + 128x256 (1:2) + + + 256x512 (1:2) + + + 512x128 (4:1) + + + 128x512 (1:4) - - + Target aspect ratio + + + + 4:3 + + + Custom + + + + + Default + + + Custom + + + + + Current Window + + + 1:1 + + + 4:3 (profile & feed) + + + 10:7 + + + 3:2 + + + 16:10 + + + 16:9 + + + 2:1 + + + Custom + + + + + Current Window + + + 1:1 + + + 4:3 (profile & feed) + + + 10:7 + + + 3:2 + + + 16:10 + + + 16:9 + + + 2:1 + + + Custom + + + + :1 +