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.
This commit is contained in:
@@ -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 ;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -7865,17 +7865,6 @@ Found in Advanced->Rendering->Info Displays</string>
|
||||
<key>Value</key>
|
||||
<integer>64</integer>
|
||||
</map>
|
||||
<key>KeepAspectForSnapshot</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Use full window when taking snapshot, regardless of requested image size</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>LandBrushSize</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -8046,6 +8035,17 @@ Found in Advanced->Rendering->Info Displays</string>
|
||||
<key>Value</key>
|
||||
<string>0.0.0</string>
|
||||
</map>
|
||||
<key>LastSnapshotToFeedAspect</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>The aspect ratio spinner value for snapshots uploaded to my.secondlife.com</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<integer>1.33333</integer>
|
||||
</map>
|
||||
<key>LastSnapshotToFeedHeight</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -8068,6 +8068,17 @@ Found in Advanced->Rendering->Info Displays</string>
|
||||
<key>Value</key>
|
||||
<integer>700</integer>
|
||||
</map>
|
||||
<key>LastSnapshotToEmailAspect</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>The aspect ratio spinner value for snapshots sent by email</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>LastSnapshotToEmailHeight</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -8090,6 +8101,17 @@ Found in Advanced->Rendering->Info Displays</string>
|
||||
<key>Value</key>
|
||||
<integer>1024</integer>
|
||||
</map>
|
||||
<key>LastSnapshotToDiskAspect</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>The aspect ratio spinner value for snapshots written to disk</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>LastSnapshotToDiskHeight</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -8112,6 +8134,17 @@ Found in Advanced->Rendering->Info Displays</string>
|
||||
<key>Value</key>
|
||||
<integer>1024</integer>
|
||||
</map>
|
||||
<key>LastSnapshotToInventoryAspect</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>The aspect ratio spinner value for snapshots uploaded to inventory</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>LastSnapshotToInventoryHeight</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -13409,6 +13442,17 @@ Found in Advanced->Rendering->Info Displays</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SnapshotFeedLastAspect</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Take next feed snapshot at this aspect</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SnapshotFeedLastResolution</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -13442,6 +13486,17 @@ Found in Advanced->Rendering->Info Displays</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SnapshotLocalLastAspect</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Take next local snapshot at this aspect</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SnapshotLocalLastResolution</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -13453,6 +13508,17 @@ Found in Advanced->Rendering->Info Displays</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SnapshotPostcardLastAspect</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Take next postcard snapshot at this aspect</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SnapshotPostcardLastResolution</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -13475,6 +13541,17 @@ Found in Advanced->Rendering->Info Displays</string>
|
||||
<key>Value</key>
|
||||
<integer>75</integer>
|
||||
</map>
|
||||
<key>SnapshotTextureLastAspect</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Take next texture snapshot at this aspect</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>SnapshotTextureLastResolution</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -901,7 +901,8 @@ void LLFloaterReporter::takeScreenshot()
|
||||
const S32 IMAGE_HEIGHT = 768;
|
||||
|
||||
LLPointer<LLImageRaw> 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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,
|
||||
|
||||
@@ -4120,7 +4120,7 @@ BOOL LLViewerWindow::saveSnapshot( const std::string& filepath, S32 image_width,
|
||||
llinfos << "Saving snapshot to: " << filepath << llendl;
|
||||
|
||||
LLPointer<LLImageRaw> 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<bool> 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();
|
||||
}
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater bottom="-300" can_close="true" can_drag_on_left="false" can_minimize="false"
|
||||
can_resize="false" follows="left|top" height="566" name="Snapshot"
|
||||
can_resize="false" follows="left|top" height="629" name="Snapshot"
|
||||
rect_control="FloaterSnapshotRect" title="Snapshot Preview" width="219">
|
||||
<text bottom="-177" right="-6" height="25" name="file_size_label" halign="right" width="120">
|
||||
<text bottom="-201" right="-6" height="25" name="file_size_label" halign="right" width="120">
|
||||
File size: [SIZE] KB
|
||||
</text>
|
||||
<text bottom="-171" height="15" left="10" name="type_label" halign="left">
|
||||
Destination
|
||||
<text bottom="-195" height="15" left="10" name="type_label" halign="left">
|
||||
Target
|
||||
</text>
|
||||
<radio_group bottom_delta="-79" follows="left|top" height="79" label="Snapshot type"
|
||||
left="10" name="snapshot_type_radio" width="200">
|
||||
@@ -18,7 +18,7 @@
|
||||
</radio_item>
|
||||
<radio_item bottom="-57" height="16" name="texture">
|
||||
Save to my inventory ([UPLOADFEE])
|
||||
</radio_item>
|
||||
</radio_item>
|
||||
<radio_item bottom="-76" height="16" name="local">
|
||||
Save to my hard drive
|
||||
</radio_item>
|
||||
@@ -49,7 +49,7 @@
|
||||
tool_tip="Advanced Options. Default uses current window size." width="80" />
|
||||
<text bottom_delta="-20" follows="top|left" height="15" left="10" name="type_label2"
|
||||
width="115">
|
||||
Size
|
||||
Target size
|
||||
</text>
|
||||
<text bottom_delta="0" follows="top|left" height="15" left="130" name="format_label"
|
||||
width="70">
|
||||
@@ -105,20 +105,32 @@
|
||||
</combo_box>
|
||||
<combo_box bottom_delta="0" follows="left|top" height="20" label="Resolution" left="10"
|
||||
name="texture_size_combo" width="115">
|
||||
<combo_item name="CurrentWindow" value="[i0,i0]">
|
||||
Current Window
|
||||
<combo_item name="128x128" value="[i128,i128]">
|
||||
128x128 (1:1)
|
||||
</combo_item>
|
||||
<combo_item name="Small(128x128)" value="[i128,i128]">
|
||||
Small (128x128)
|
||||
<combo_item name="256x256" value="[i256,i256]">
|
||||
256x256 (1:1)
|
||||
</combo_item>
|
||||
<combo_item name="Medium(256x256)" value="[i256,i256]">
|
||||
Medium (256x256)
|
||||
<combo_item name="512x512" value="[i512,i512]">
|
||||
512x512 (1:1)
|
||||
</combo_item>
|
||||
<combo_item name="Large(512x512)" value="[i512,i512]">
|
||||
Large (512x512)
|
||||
<combo_item name="256x128" value="[i256,i128]">
|
||||
256x128 (2:1)
|
||||
</combo_item>
|
||||
<combo_item name="Custom" value="[i-1,i-1]">
|
||||
Custom
|
||||
<combo_item name="512x256" value="[i512,i256]">
|
||||
512x256 (2:1)
|
||||
</combo_item>
|
||||
<combo_item name="128x256" value="[i128,i256]">
|
||||
128x256 (1:2)
|
||||
</combo_item>
|
||||
<combo_item name="256x512" value="[i256,i512]">
|
||||
256x512 (1:2)
|
||||
</combo_item>
|
||||
<combo_item name="512x128" value="[i512,i128]">
|
||||
512x128 (4:1)
|
||||
</combo_item>
|
||||
<combo_item name="128x512" value="[i128,i512]">
|
||||
128x512 (1:4)
|
||||
</combo_item>
|
||||
</combo_box>
|
||||
<combo_box bottom_delta="0" follows="left|top" height="20" label="Resolution" left="10"
|
||||
@@ -173,9 +185,93 @@
|
||||
<spinner bottom_delta="0" decimal_digits="0" follows="left|top" height="20"
|
||||
increment="32" label="Height" label_width="35" left="110" max_val="6016"
|
||||
min_val="32" name="snapshot_height" width="95" allow_text_entry="false"/>
|
||||
<check_box bottom_delta="-20" follows="left|top" label="Constrain Proportions" left="10"
|
||||
name="keep_aspect_check" />
|
||||
<slider bottom_delta="-20" decimal_digits="0" follows="left|top" height="15"
|
||||
<text bottom_delta="-18" follows="top|left" height="15" left="10" name="type_label3"
|
||||
width="115">
|
||||
Target aspect ratio
|
||||
</text>
|
||||
<combo_box bottom_delta="-22" follows="left|top" height="20" label="Aspect" left="10"
|
||||
name="feed_aspect_combo" width="115">
|
||||
<combo_item name="4:3" value="1.33333">
|
||||
4:3
|
||||
</combo_item>
|
||||
<combo_item name="Custom" value="-1">
|
||||
Custom
|
||||
</combo_item>
|
||||
</combo_box>
|
||||
<combo_box bottom_delta="0" follows="left|top" height="20" label="Aspect" left="10"
|
||||
name="postcard_aspect_combo" width="115">
|
||||
<combo_item name="4:3" value="0">
|
||||
Default
|
||||
</combo_item>
|
||||
<combo_item name="Custom" value="-1">
|
||||
Custom
|
||||
</combo_item>
|
||||
</combo_box>
|
||||
<combo_box bottom_delta="0" follows="left|top" height="20" label="Aspect" left="10"
|
||||
name="texture_aspect_combo" width="115">
|
||||
<combo_item name="CurrentWindow" value="0">
|
||||
Current Window
|
||||
</combo_item>
|
||||
<combo_item name="1:1" value="1">
|
||||
1:1
|
||||
</combo_item>
|
||||
<combo_item name="4:3" value="1.33333">
|
||||
4:3 (profile & feed)
|
||||
</combo_item>
|
||||
<combo_item name="10:7" value="1.42857">
|
||||
10:7
|
||||
</combo_item>
|
||||
<combo_item name="3:2" value="1.5">
|
||||
3:2
|
||||
</combo_item>
|
||||
<combo_item name="16:10" value="1.6">
|
||||
16:10
|
||||
</combo_item>
|
||||
<combo_item name="16:9" value="1.77778">
|
||||
16:9
|
||||
</combo_item>
|
||||
<combo_item name="2:1" value="2">
|
||||
2:1
|
||||
</combo_item>
|
||||
<combo_item name="Custom" value="-1">
|
||||
Custom
|
||||
</combo_item>
|
||||
</combo_box>
|
||||
<combo_box bottom_delta="0" follows="left|top" height="20" label="Aspect" left="10"
|
||||
name="local_aspect_combo" width="115">
|
||||
<combo_item name="CurrentWindow" value="[i0,i0]">
|
||||
Current Window
|
||||
</combo_item>
|
||||
<combo_item name="1:1" value="1">
|
||||
1:1
|
||||
</combo_item>
|
||||
<combo_item name="4:3" value="1.33333">
|
||||
4:3 (profile & feed)
|
||||
</combo_item>
|
||||
<combo_item name="10:7" value="1.42857">
|
||||
10:7
|
||||
</combo_item>
|
||||
<combo_item name="3:2" value="1.5">
|
||||
3:2
|
||||
</combo_item>
|
||||
<combo_item name="16:10" value="1.6">
|
||||
16:10
|
||||
</combo_item>
|
||||
<combo_item name="16:9" value="1.77778">
|
||||
16:9
|
||||
</combo_item>
|
||||
<combo_item name="2:1" value="2">
|
||||
2:1
|
||||
</combo_item>
|
||||
<combo_item name="Custom" value="-1">
|
||||
Custom
|
||||
</combo_item>
|
||||
</combo_box>
|
||||
<spinner bottom_delta="0" decimal_digits="5" follows="left|top" height="20"
|
||||
increment="0.01" label="" left="130" max_val="32"
|
||||
min_val="0.03125" name="aspect_ratio" width="64" allow_text_entry="false"/>
|
||||
<text bottom_delta="10" left="196">:1</text>
|
||||
<slider bottom_delta="-30" decimal_digits="0" follows="left|top" height="15"
|
||||
increment="1" initial_val="75" label="Image Quality" left="10"
|
||||
max_val="100" min_val="0" name="image_quality_slider" width="210" />
|
||||
<text bottom_delta="-28" follows="left|top" height="20" left="10"
|
||||
|
||||
Reference in New Issue
Block a user