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 +