PageRenderTime 2992ms CodeModel.GetById 193ms app.highlight 2571ms RepoModel.GetById 156ms app.codeStats 54ms

/indra/newview/llfloatersnapshot.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2041 lines | 1596 code | 268 blank | 177 comment | 210 complexity | 73a810ac3a95a1072375168398fbaa4b MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/** 
   2 * @file llfloatersnapshot.cpp
   3 * @brief Snapshot preview window, allowing saving, e-mailing, etc.
   4 *
   5 * $LicenseInfo:firstyear=2004&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "llfloatersnapshot.h"
  30
  31#include "llfloaterreg.h"
  32
  33// Viewer includes
  34#include "llagent.h"
  35#include "llagentcamera.h"
  36#include "llcallbacklist.h"
  37#include "llcriticaldamp.h"
  38#include "llfloaterperms.h"
  39#include "llui.h"
  40#include "llfocusmgr.h"
  41#include "llbutton.h"
  42#include "llcombobox.h"
  43#include "lleconomy.h"
  44#include "lllandmarkactions.h"
  45#include "llpanelsnapshot.h"
  46#include "llsidetraypanelcontainer.h"
  47#include "llsliderctrl.h"
  48#include "llspinctrl.h"
  49#include "llviewercontrol.h"
  50#include "lluictrlfactory.h"
  51#include "llviewerstats.h"
  52#include "llviewercamera.h"
  53#include "llviewerwindow.h"
  54#include "llviewermenufile.h"	// upload_new_resource()
  55#include "llcheckboxctrl.h"
  56#include "llslurl.h"
  57#include "lltoolfocus.h"
  58#include "lltoolmgr.h"
  59#include "llwebsharing.h"
  60#include "llworld.h"
  61#include "llagentui.h"
  62
  63// Linden library includes
  64#include "llfontgl.h"
  65#include "llsys.h"
  66#include "llrender.h"
  67#include "v3dmath.h"
  68#include "llmath.h"
  69#include "lldir.h"
  70#include "llsdserialize.h"
  71#include "llgl.h"
  72#include "llglheaders.h"
  73#include "llimagejpeg.h"
  74#include "llimagepng.h"
  75#include "llimagebmp.h"
  76#include "llimagej2c.h"
  77#include "lllocalcliprect.h"
  78#include "llnotificationsutil.h"
  79#include "llpostcard.h"
  80#include "llresmgr.h"		// LLLocale
  81#include "llvfile.h"
  82#include "llvfs.h"
  83#include "llwebprofile.h"
  84#include "llwindow.h"
  85
  86///----------------------------------------------------------------------------
  87/// Local function declarations, constants, enums, and typedefs
  88///----------------------------------------------------------------------------
  89LLUICtrl* LLFloaterSnapshot::sThumbnailPlaceholder = NULL;
  90LLSnapshotFloaterView* gSnapshotFloaterView = NULL;
  91
  92const F32 AUTO_SNAPSHOT_TIME_DELAY = 1.f;
  93
  94F32 SHINE_TIME = 0.5f;
  95F32 SHINE_WIDTH = 0.6f;
  96F32 SHINE_OPACITY = 0.3f;
  97F32 FALL_TIME = 0.6f;
  98S32 BORDER_WIDTH = 6;
  99
 100const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte
 101const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512
 102
 103static LLDefaultChildRegistry::Register<LLSnapshotFloaterView> r("snapshot_floater_view");
 104
 105///----------------------------------------------------------------------------
 106/// Class LLSnapshotLivePreview 
 107///----------------------------------------------------------------------------
 108class LLSnapshotLivePreview : public LLView
 109{
 110	LOG_CLASS(LLSnapshotLivePreview);
 111public:
 112	enum ESnapshotType
 113	{
 114		SNAPSHOT_POSTCARD,
 115		SNAPSHOT_TEXTURE,
 116		SNAPSHOT_LOCAL,
 117		SNAPSHOT_WEB
 118	};
 119
 120
 121	struct Params : public LLInitParam::Block<Params, LLView::Params>
 122	{
 123		Params()
 124		{
 125			name = "snapshot_live_preview";
 126			mouse_opaque = false;
 127		}
 128	};
 129
 130
 131	LLSnapshotLivePreview(const LLSnapshotLivePreview::Params& p);
 132	~LLSnapshotLivePreview();
 133
 134	/*virtual*/ void draw();
 135	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
 136	
 137	void setSize(S32 w, S32 h);
 138	void setWidth(S32 w) { mWidth[mCurImageIndex] = w; }
 139	void setHeight(S32 h) { mHeight[mCurImageIndex] = h; }
 140	void getSize(S32& w, S32& h) const;
 141	S32 getWidth() const { return mWidth[mCurImageIndex]; }
 142	S32 getHeight() const { return mHeight[mCurImageIndex]; }
 143	S32 getDataSize() const { return mDataSize; }
 144	void setMaxImageSize(S32 size) ;
 145	S32  getMaxImageSize() {return mMaxImageSize ;}
 146	
 147	ESnapshotType getSnapshotType() const { return mSnapshotType; }
 148	LLFloaterSnapshot::ESnapshotFormat getSnapshotFormat() const { return mSnapshotFormat; }
 149	BOOL getSnapshotUpToDate() const { return mSnapshotUpToDate; }
 150	BOOL isSnapshotActive() { return mSnapshotActive; }
 151	LLViewerTexture* getThumbnailImage() const { return mThumbnailImage ; }
 152	S32  getThumbnailWidth() const { return mThumbnailWidth ; }
 153	S32  getThumbnailHeight() const { return mThumbnailHeight ; }
 154	BOOL getThumbnailLock() const { return mThumbnailUpdateLock ; }
 155	BOOL getThumbnailUpToDate() const { return mThumbnailUpToDate ;}
 156	LLViewerTexture* getCurrentImage();
 157	F32 getImageAspect();
 158	F32 getAspect() ;
 159	const LLRect& getImageRect() const { return mImageRect[mCurImageIndex]; }
 160	BOOL isImageScaled() const { return mImageScaled[mCurImageIndex]; }
 161	void setImageScaled(BOOL scaled) { mImageScaled[mCurImageIndex] = scaled; }
 162	const LLVector3d& getPosTakenGlobal() const { return mPosTakenGlobal; }
 163	
 164	void setSnapshotType(ESnapshotType type) { mSnapshotType = type; }
 165	void setSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat type) { mSnapshotFormat = type; }
 166	void setSnapshotQuality(S32 quality);
 167	void setSnapshotBufferType(LLViewerWindow::ESnapshotType type) { mSnapshotBufferType = type; }
 168	void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f);
 169	void saveWeb();
 170	void saveTexture();
 171	BOOL saveLocal();
 172
 173	LLPointer<LLImageFormatted>	getFormattedImage() const { return mFormattedImage; }
 174	LLPointer<LLImageRaw>		getEncodedImage() const { return mPreviewImageEncoded; }
 175
 176	/// Sets size of preview thumbnail image and thhe surrounding rect.
 177	BOOL setThumbnailImageSize() ;
 178	void generateThumbnailImage(BOOL force_update = FALSE) ;
 179	void resetThumbnailImage() { mThumbnailImage = NULL ; }
 180	void drawPreviewRect(S32 offset_x, S32 offset_y) ;
 181
 182	// Returns TRUE when snapshot generated, FALSE otherwise.
 183	static BOOL onIdle( void* snapshot_preview );
 184
 185	// callback for region name resolve
 186	void regionNameCallback(LLImageJPEG* snapshot, LLSD& metadata, const std::string& name, S32 x, S32 y, S32 z);
 187
 188private:
 189	LLColor4					mColor;
 190	LLPointer<LLViewerTexture>	mViewerImage[2]; //used to represent the scene when the frame is frozen.
 191	LLRect						mImageRect[2];
 192	S32							mWidth[2];
 193	S32							mHeight[2];
 194	BOOL						mImageScaled[2];
 195	S32                         mMaxImageSize ;
 196	
 197	//thumbnail image
 198	LLPointer<LLViewerTexture>	mThumbnailImage ;
 199	S32                         mThumbnailWidth ;
 200	S32                         mThumbnailHeight ;
 201	LLRect                      mPreviewRect ;
 202	BOOL                        mThumbnailUpdateLock ;
 203	BOOL                        mThumbnailUpToDate ;
 204
 205	S32							mCurImageIndex;
 206	LLPointer<LLImageRaw>		mPreviewImage;
 207	LLPointer<LLImageRaw>		mPreviewImageEncoded;
 208	LLPointer<LLImageFormatted>	mFormattedImage;
 209	LLFrameTimer				mSnapshotDelayTimer;
 210	S32							mShineCountdown;
 211	LLFrameTimer				mShineAnimTimer;
 212	F32							mFlashAlpha;
 213	BOOL						mNeedsFlash;
 214	LLVector3d					mPosTakenGlobal;
 215	S32							mSnapshotQuality;
 216	S32							mDataSize;
 217	ESnapshotType				mSnapshotType;
 218	LLFloaterSnapshot::ESnapshotFormat	mSnapshotFormat;
 219	BOOL						mSnapshotUpToDate;
 220	LLFrameTimer				mFallAnimTimer;
 221	LLVector3					mCameraPos;
 222	LLQuaternion				mCameraRot;
 223	BOOL						mSnapshotActive;
 224	LLViewerWindow::ESnapshotType mSnapshotBufferType;
 225
 226public:
 227	static std::set<LLSnapshotLivePreview*> sList;
 228	BOOL                        mKeepAspectRatio ;
 229};
 230
 231std::set<LLSnapshotLivePreview*> LLSnapshotLivePreview::sList;
 232
 233LLSnapshotLivePreview::LLSnapshotLivePreview (const LLSnapshotLivePreview::Params& p) 
 234:	LLView(p),
 235	mColor(1.f, 0.f, 0.f, 0.5f), 
 236	mCurImageIndex(0),
 237	mPreviewImage(NULL),
 238	mThumbnailImage(NULL) ,
 239	mThumbnailWidth(0),
 240	mThumbnailHeight(0),
 241	mPreviewImageEncoded(NULL),
 242	mFormattedImage(NULL),
 243	mShineCountdown(0),
 244	mFlashAlpha(0.f),
 245	mNeedsFlash(TRUE),
 246	mSnapshotQuality(gSavedSettings.getS32("SnapshotQuality")),
 247	mDataSize(0),
 248	mSnapshotType(SNAPSHOT_POSTCARD),
 249	mSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat"))),
 250	mSnapshotUpToDate(FALSE),
 251	mCameraPos(LLViewerCamera::getInstance()->getOrigin()),
 252	mCameraRot(LLViewerCamera::getInstance()->getQuaternion()),
 253	mSnapshotActive(FALSE),
 254	mSnapshotBufferType(LLViewerWindow::SNAPSHOT_TYPE_COLOR)
 255{
 256	setSnapshotQuality(gSavedSettings.getS32("SnapshotQuality"));
 257	mSnapshotDelayTimer.setTimerExpirySec(0.0f);
 258	mSnapshotDelayTimer.start();
 259// 	gIdleCallbacks.addFunction( &LLSnapshotLivePreview::onIdle, (void*)this );
 260	sList.insert(this);
 261	setFollowsAll();
 262	mWidth[0] = gViewerWindow->getWindowWidthRaw();
 263	mWidth[1] = gViewerWindow->getWindowWidthRaw();
 264	mHeight[0] = gViewerWindow->getWindowHeightRaw();
 265	mHeight[1] = gViewerWindow->getWindowHeightRaw();
 266	mImageScaled[0] = FALSE;
 267	mImageScaled[1] = FALSE;
 268
 269	mMaxImageSize = MAX_SNAPSHOT_IMAGE_SIZE ;
 270	mKeepAspectRatio = gSavedSettings.getBOOL("KeepAspectForSnapshot") ;
 271	mThumbnailUpdateLock = FALSE ;
 272	mThumbnailUpToDate   = FALSE ;
 273}
 274
 275LLSnapshotLivePreview::~LLSnapshotLivePreview()
 276{
 277	// delete images
 278	mPreviewImage = NULL;
 279	mPreviewImageEncoded = NULL;
 280	mFormattedImage = NULL;
 281
 282// 	gIdleCallbacks.deleteFunction( &LLSnapshotLivePreview::onIdle, (void*)this );
 283	sList.erase(this);
 284}
 285
 286void LLSnapshotLivePreview::setMaxImageSize(S32 size) 
 287{
 288	if(size < MAX_SNAPSHOT_IMAGE_SIZE)
 289	{
 290		mMaxImageSize = size;
 291	}
 292	else
 293	{
 294		mMaxImageSize = MAX_SNAPSHOT_IMAGE_SIZE ;
 295	}
 296}
 297
 298LLViewerTexture* LLSnapshotLivePreview::getCurrentImage()
 299{
 300	return mViewerImage[mCurImageIndex];
 301}
 302
 303F32 LLSnapshotLivePreview::getAspect()
 304{
 305	F32 image_aspect_ratio = ((F32)getWidth()) / ((F32)getHeight());
 306	F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight());
 307
 308	if (!mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot"))
 309	{
 310		return image_aspect_ratio;
 311	}
 312	else
 313	{
 314		return window_aspect_ratio;
 315	}
 316}
 317
 318F32 LLSnapshotLivePreview::getImageAspect()
 319{
 320	if (!getCurrentImage())
 321	{
 322		return 0.f;
 323	}
 324
 325	return getAspect() ;	
 326}
 327
 328void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail, F32 delay) 
 329{
 330	// Invalidate current image.
 331	lldebugs << "updateSnapshot: mSnapshotUpToDate = " << getSnapshotUpToDate() << llendl;
 332	if (getSnapshotUpToDate())
 333	{
 334		S32 old_image_index = mCurImageIndex;
 335		mCurImageIndex = (mCurImageIndex + 1) % 2; 
 336		setSize(mWidth[old_image_index], mHeight[old_image_index]);
 337		mFallAnimTimer.start();		
 338	}
 339	mSnapshotUpToDate = FALSE; 		
 340
 341	// Update snapshot source rect depending on whether we keep the aspect ratio.
 342	LLRect& rect = mImageRect[mCurImageIndex];
 343	rect.set(0, getRect().getHeight(), getRect().getWidth(), 0);
 344
 345	F32 image_aspect_ratio = ((F32)getWidth()) / ((F32)getHeight());
 346	F32 window_aspect_ratio = ((F32)getRect().getWidth()) / ((F32)getRect().getHeight());
 347
 348	if (mKeepAspectRatio)//gSavedSettings.getBOOL("KeepAspectForSnapshot"))
 349	{
 350		if (image_aspect_ratio > window_aspect_ratio)
 351		{
 352			// trim off top and bottom
 353			S32 new_height = llround((F32)getRect().getWidth() / image_aspect_ratio); 
 354			rect.mBottom += (getRect().getHeight() - new_height) / 2;
 355			rect.mTop -= (getRect().getHeight() - new_height) / 2;
 356		}
 357		else if (image_aspect_ratio < window_aspect_ratio)
 358		{
 359			// trim off left and right
 360			S32 new_width = llround((F32)getRect().getHeight() * image_aspect_ratio); 
 361			rect.mLeft += (getRect().getWidth() - new_width) / 2;
 362			rect.mRight -= (getRect().getWidth() - new_width) / 2;
 363		}
 364	}
 365
 366	// Stop shining animation.
 367	mShineAnimTimer.stop();
 368
 369	// Update snapshot if requested.
 370	if (new_snapshot)
 371	{
 372		mSnapshotDelayTimer.start();
 373		mSnapshotDelayTimer.setTimerExpirySec(delay);
 374		LLFloaterSnapshot::preUpdate();
 375	}
 376
 377	// Update thumbnail if requested.
 378	if(new_thumbnail)
 379	{
 380		mThumbnailUpToDate = FALSE ;
 381	}
 382}
 383
 384void LLSnapshotLivePreview::setSnapshotQuality(S32 quality)
 385{
 386	llclamp(quality, 0, 100);
 387	if (quality != mSnapshotQuality)
 388	{
 389		mSnapshotQuality = quality;
 390		gSavedSettings.setS32("SnapshotQuality", quality);
 391		mSnapshotUpToDate = FALSE;
 392	}
 393}
 394
 395void LLSnapshotLivePreview::drawPreviewRect(S32 offset_x, S32 offset_y)
 396{
 397	F32 line_width ; 
 398	glGetFloatv(GL_LINE_WIDTH, &line_width) ;
 399	glLineWidth(2.0f * line_width) ;
 400	LLColor4 color(0.0f, 0.0f, 0.0f, 1.0f) ;
 401	gl_rect_2d( mPreviewRect.mLeft + offset_x, mPreviewRect.mTop + offset_y,
 402				mPreviewRect.mRight + offset_x, mPreviewRect.mBottom + offset_y, color, FALSE ) ;
 403	glLineWidth(line_width) ;
 404
 405	//draw four alpha rectangles to cover areas outside of the snapshot image
 406	if(!mKeepAspectRatio)
 407	{
 408		LLColor4 alpha_color(0.5f, 0.5f, 0.5f, 0.8f) ;
 409		S32 dwl = 0, dwr = 0 ;
 410		if(mThumbnailWidth > mPreviewRect.getWidth())
 411		{
 412			dwl = (mThumbnailWidth - mPreviewRect.getWidth()) >> 1 ;
 413			dwr = mThumbnailWidth - mPreviewRect.getWidth() - dwl ;
 414
 415			gl_rect_2d(mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mTop + offset_y,
 416				mPreviewRect.mLeft + offset_x, mPreviewRect.mBottom + offset_y, alpha_color, TRUE ) ;
 417			gl_rect_2d( mPreviewRect.mRight + offset_x, mPreviewRect.mTop + offset_y,
 418				mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mBottom + offset_y, alpha_color, TRUE ) ;
 419		}
 420
 421		if(mThumbnailHeight > mPreviewRect.getHeight())
 422		{
 423			S32 dh = (mThumbnailHeight - mPreviewRect.getHeight()) >> 1 ;
 424			gl_rect_2d(mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mBottom + offset_y ,
 425				mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mBottom + offset_y - dh, alpha_color, TRUE ) ;
 426
 427			dh = mThumbnailHeight - mPreviewRect.getHeight() - dh ;
 428			gl_rect_2d( mPreviewRect.mLeft + offset_x - dwl, mPreviewRect.mTop + offset_y + dh,
 429				mPreviewRect.mRight + offset_x + dwr, mPreviewRect.mTop + offset_y, alpha_color, TRUE ) ;
 430		}
 431	}
 432}
 433
 434//called when the frame is frozen.
 435void LLSnapshotLivePreview::draw()
 436{
 437	if (getCurrentImage() &&
 438	    mPreviewImageEncoded.notNull() &&
 439	    getSnapshotUpToDate())
 440	{
 441		LLColor4 bg_color(0.f, 0.f, 0.3f, 0.4f);
 442		gl_rect_2d(getRect(), bg_color);
 443		const LLRect& rect = getImageRect();
 444		LLRect shadow_rect = rect;
 445		shadow_rect.stretch(BORDER_WIDTH);
 446		gl_drop_shadow(shadow_rect.mLeft, shadow_rect.mTop, shadow_rect.mRight, shadow_rect.mBottom, LLColor4(0.f, 0.f, 0.f, mNeedsFlash ? 0.f :0.5f), 10);
 447
 448		LLColor4 image_color(1.f, 1.f, 1.f, 1.f);
 449		gGL.color4fv(image_color.mV);
 450		gGL.getTexUnit(0)->bind(getCurrentImage());
 451		// calculate UV scale
 452		F32 uv_width = isImageScaled() ? 1.f : llmin((F32)getWidth() / (F32)getCurrentImage()->getWidth(), 1.f);
 453		F32 uv_height = isImageScaled() ? 1.f : llmin((F32)getHeight() / (F32)getCurrentImage()->getHeight(), 1.f);
 454		gGL.pushMatrix();
 455		{
 456			gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom, 0.f);
 457			gGL.begin(LLRender::QUADS);
 458			{
 459				gGL.texCoord2f(uv_width, uv_height);
 460				gGL.vertex2i(rect.getWidth(), rect.getHeight() );
 461
 462				gGL.texCoord2f(0.f, uv_height);
 463				gGL.vertex2i(0, rect.getHeight() );
 464
 465				gGL.texCoord2f(0.f, 0.f);
 466				gGL.vertex2i(0, 0);
 467
 468				gGL.texCoord2f(uv_width, 0.f);
 469				gGL.vertex2i(rect.getWidth(), 0);
 470			}
 471			gGL.end();
 472		}
 473		gGL.popMatrix();
 474
 475		gGL.color4f(1.f, 1.f, 1.f, mFlashAlpha);
 476		gl_rect_2d(getRect());
 477		if (mNeedsFlash)
 478		{
 479			if (mFlashAlpha < 1.f)
 480			{
 481				mFlashAlpha = lerp(mFlashAlpha, 1.f, LLCriticalDamp::getInterpolant(0.02f));
 482			}
 483			else
 484			{
 485				mNeedsFlash = FALSE;
 486			}
 487		}
 488		else
 489		{
 490			mFlashAlpha = lerp(mFlashAlpha, 0.f, LLCriticalDamp::getInterpolant(0.15f));
 491		}
 492
 493		// Draw shining animation if appropriate.
 494		if (mShineCountdown > 0)
 495		{
 496			mShineCountdown--;
 497			if (mShineCountdown == 0)
 498			{
 499				mShineAnimTimer.start();
 500			}
 501		}
 502		else if (mShineAnimTimer.getStarted())
 503		{
 504			lldebugs << "Drawing shining animation" << llendl;
 505			F32 shine_interp = llmin(1.f, mShineAnimTimer.getElapsedTimeF32() / SHINE_TIME);
 506			
 507			// draw "shine" effect
 508			LLLocalClipRect clip(getLocalRect());
 509			{
 510				// draw diagonal stripe with gradient that passes over screen
 511				S32 x1 = gViewerWindow->getWindowWidthScaled() * llround((clamp_rescale(shine_interp, 0.f, 1.f, -1.f - SHINE_WIDTH, 1.f)));
 512				S32 x2 = x1 + llround(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH);
 513				S32 x3 = x2 + llround(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH);
 514				S32 y1 = 0;
 515				S32 y2 = gViewerWindow->getWindowHeightScaled();
 516
 517				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 518				gGL.begin(LLRender::QUADS);
 519				{
 520					gGL.color4f(1.f, 1.f, 1.f, 0.f);
 521					gGL.vertex2i(x1, y1);
 522					gGL.vertex2i(x1 + gViewerWindow->getWindowWidthScaled(), y2);
 523					gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY);
 524					gGL.vertex2i(x2 + gViewerWindow->getWindowWidthScaled(), y2);
 525					gGL.vertex2i(x2, y1);
 526
 527					gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY);
 528					gGL.vertex2i(x2, y1);
 529					gGL.vertex2i(x2 + gViewerWindow->getWindowWidthScaled(), y2);
 530					gGL.color4f(1.f, 1.f, 1.f, 0.f);
 531					gGL.vertex2i(x3 + gViewerWindow->getWindowWidthScaled(), y2);
 532					gGL.vertex2i(x3, y1);
 533				}
 534				gGL.end();
 535			}
 536
 537			// if we're at the end of the animation, stop
 538			if (shine_interp >= 1.f)
 539			{
 540				mShineAnimTimer.stop();
 541			}
 542		}
 543	}
 544
 545	// draw framing rectangle
 546	{
 547		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 548		gGL.color4f(1.f, 1.f, 1.f, 1.f);
 549		const LLRect& outline_rect = getImageRect();
 550		gGL.begin(LLRender::QUADS);
 551		{
 552			gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
 553			gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
 554			gGL.vertex2i(outline_rect.mRight, outline_rect.mTop);
 555			gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop);
 556
 557			gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom);
 558			gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom);
 559			gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
 560			gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
 561
 562			gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop);
 563			gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom);
 564			gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
 565			gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
 566
 567			gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom);
 568			gGL.vertex2i(outline_rect.mRight, outline_rect.mTop);
 569			gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
 570			gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
 571		}
 572		gGL.end();
 573	}
 574
 575	// draw old image dropping away
 576	if (mFallAnimTimer.getStarted())
 577	{
 578		S32 old_image_index = (mCurImageIndex + 1) % 2;
 579		if (mViewerImage[old_image_index].notNull() && mFallAnimTimer.getElapsedTimeF32() < FALL_TIME)
 580		{
 581			lldebugs << "Drawing fall animation" << llendl;
 582			F32 fall_interp = mFallAnimTimer.getElapsedTimeF32() / FALL_TIME;
 583			F32 alpha = clamp_rescale(fall_interp, 0.f, 1.f, 0.8f, 0.4f);
 584			LLColor4 image_color(1.f, 1.f, 1.f, alpha);
 585			gGL.color4fv(image_color.mV);
 586			gGL.getTexUnit(0)->bind(mViewerImage[old_image_index]);
 587			// calculate UV scale
 588			// *FIX get this to work with old image
 589			BOOL rescale = !mImageScaled[old_image_index] && mViewerImage[mCurImageIndex].notNull();
 590			F32 uv_width = rescale ? llmin((F32)mWidth[old_image_index] / (F32)mViewerImage[mCurImageIndex]->getWidth(), 1.f) : 1.f;
 591			F32 uv_height = rescale ? llmin((F32)mHeight[old_image_index] / (F32)mViewerImage[mCurImageIndex]->getHeight(), 1.f) : 1.f;
 592			gGL.pushMatrix();
 593			{
 594				LLRect& rect = mImageRect[old_image_index];
 595				gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom - llround(getRect().getHeight() * 2.f * (fall_interp * fall_interp)), 0.f);
 596				gGL.rotatef(-45.f * fall_interp, 0.f, 0.f, 1.f);
 597				gGL.begin(LLRender::QUADS);
 598				{
 599					gGL.texCoord2f(uv_width, uv_height);
 600					gGL.vertex2i(rect.getWidth(), rect.getHeight() );
 601
 602					gGL.texCoord2f(0.f, uv_height);
 603					gGL.vertex2i(0, rect.getHeight() );
 604
 605					gGL.texCoord2f(0.f, 0.f);
 606					gGL.vertex2i(0, 0);
 607
 608					gGL.texCoord2f(uv_width, 0.f);
 609					gGL.vertex2i(rect.getWidth(), 0);
 610				}
 611				gGL.end();
 612			}
 613			gGL.popMatrix();
 614		}
 615	}
 616}
 617
 618/*virtual*/ 
 619void LLSnapshotLivePreview::reshape(S32 width, S32 height, BOOL called_from_parent)
 620{
 621	LLRect old_rect = getRect();
 622	LLView::reshape(width, height, called_from_parent);
 623	if (old_rect.getWidth() != width || old_rect.getHeight() != height)
 624	{
 625		lldebugs << "window reshaped, updating thumbnail" << llendl;
 626		updateSnapshot(FALSE, TRUE);
 627	}
 628}
 629
 630BOOL LLSnapshotLivePreview::setThumbnailImageSize()
 631{
 632	if(getWidth() < 10 || getHeight() < 10)
 633	{
 634		return FALSE ;
 635	}
 636	S32 window_width = gViewerWindow->getWindowWidthRaw() ;
 637	S32 window_height = gViewerWindow->getWindowHeightRaw() ;
 638
 639	F32 window_aspect_ratio = ((F32)window_width) / ((F32)window_height);
 640
 641	// UI size for thumbnail
 642	// *FIXME: the rect does not change, so maybe there's no need to recalculate max w/h.
 643	const LLRect& thumbnail_rect = LLFloaterSnapshot::getThumbnailPlaceholderRect();
 644	S32 max_width = thumbnail_rect.getWidth();
 645	S32 max_height = thumbnail_rect.getHeight();
 646
 647	if (window_aspect_ratio > (F32)max_width / max_height)
 648	{
 649		// image too wide, shrink to width
 650		mThumbnailWidth = max_width;
 651		mThumbnailHeight = llround((F32)max_width / window_aspect_ratio);
 652	}
 653	else
 654	{
 655		// image too tall, shrink to height
 656		mThumbnailHeight = max_height;
 657		mThumbnailWidth = llround((F32)max_height * window_aspect_ratio);
 658	}
 659	
 660	if(mThumbnailWidth > window_width || mThumbnailHeight > window_height)
 661	{
 662		return FALSE ;//if the window is too small, ignore thumbnail updating.
 663	}
 664
 665	S32 left = 0 , top = mThumbnailHeight, right = mThumbnailWidth, bottom = 0 ;
 666	if(!mKeepAspectRatio)
 667	{
 668		F32 ratio_x = (F32)getWidth() / window_width ;
 669		F32 ratio_y = (F32)getHeight() / window_height ;
 670
 671		//if(getWidth() > window_width ||
 672		//	getHeight() > window_height )
 673		{
 674			if(ratio_x > ratio_y)
 675			{
 676				top = (S32)(top * ratio_y / ratio_x) ;
 677			}
 678			else
 679			{
 680				right = (S32)(right * ratio_x / ratio_y) ;
 681			}			
 682		}
 683		//else
 684		//{
 685		//	right = (S32)(right * ratio_x) ;
 686		//	top = (S32)(top * ratio_y) ;
 687		//}
 688		left = (S32)((mThumbnailWidth - right) * 0.5f) ;
 689		bottom = (S32)((mThumbnailHeight - top) * 0.5f) ;
 690		top += bottom ;
 691		right += left ;
 692	}
 693	mPreviewRect.set(left - 1, top + 1, right + 1, bottom - 1) ;
 694
 695	return TRUE ;
 696}
 697
 698void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update)
 699{	
 700	if(mThumbnailUpdateLock) //in the process of updating
 701	{
 702		return ;
 703	}
 704	if(getThumbnailUpToDate() && !force_update)//already updated
 705	{
 706		return ;
 707	}
 708	if(getWidth() < 10 || getHeight() < 10)
 709	{
 710		return ;
 711	}
 712
 713	////lock updating
 714	mThumbnailUpdateLock = TRUE ;
 715
 716	if(!setThumbnailImageSize())
 717	{
 718		mThumbnailUpdateLock = FALSE ;
 719		mThumbnailUpToDate = TRUE ;
 720		return ;
 721	}
 722
 723	if(mThumbnailImage)
 724	{
 725		resetThumbnailImage() ;
 726	}		
 727
 728	LLPointer<LLImageRaw> raw = new LLImageRaw;
 729	if(!gViewerWindow->thumbnailSnapshot(raw,
 730							mThumbnailWidth, mThumbnailHeight,
 731							gSavedSettings.getBOOL("RenderUIInSnapshot"),
 732							FALSE,
 733							mSnapshotBufferType) )								
 734	{
 735		raw = NULL ;
 736	}
 737
 738	if(raw)
 739	{
 740		raw->expandToPowerOfTwo();
 741		mThumbnailImage = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); 		
 742		mThumbnailUpToDate = TRUE ;
 743	}
 744
 745	//unlock updating
 746	mThumbnailUpdateLock = FALSE ;		
 747}
 748
 749
 750// Called often. Checks whether it's time to grab a new snapshot and if so, does it.
 751// Returns TRUE if new snapshot generated, FALSE otherwise.
 752//static 
 753BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
 754{
 755	LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)snapshot_preview;
 756	if (previewp->getWidth() == 0 || previewp->getHeight() == 0)
 757	{
 758		llwarns << "Incorrect dimensions: " << previewp->getWidth() << "x" << previewp->getHeight() << llendl;
 759		return FALSE;
 760	}
 761
 762	// If we're in freeze-frame mode and camera has moved, update snapshot.
 763	LLVector3 new_camera_pos = LLViewerCamera::getInstance()->getOrigin();
 764	LLQuaternion new_camera_rot = LLViewerCamera::getInstance()->getQuaternion();
 765	if (gSavedSettings.getBOOL("FreezeTime") && 
 766		(new_camera_pos != previewp->mCameraPos || dot(new_camera_rot, previewp->mCameraRot) < 0.995f))
 767	{
 768		previewp->mCameraPos = new_camera_pos;
 769		previewp->mCameraRot = new_camera_rot;
 770		// request a new snapshot whenever the camera moves, with a time delay
 771		BOOL autosnap = gSavedSettings.getBOOL("AutoSnapshot");
 772		lldebugs << "camera moved, updating thumbnail" << llendl;
 773		previewp->updateSnapshot(
 774			autosnap, // whether a new snapshot is needed or merely invalidate the existing one
 775			FALSE, // or if 1st arg is false, whether to produce a new thumbnail image.
 776			autosnap ? AUTO_SNAPSHOT_TIME_DELAY : 0.f); // shutter delay if 1st arg is true.
 777	}
 778
 779	// see if it's time yet to snap the shot and bomb out otherwise.
 780	previewp->mSnapshotActive = 
 781		(previewp->mSnapshotDelayTimer.getStarted() &&	previewp->mSnapshotDelayTimer.hasExpired())
 782		&& !LLToolCamera::getInstance()->hasMouseCapture(); // don't take snapshots while ALT-zoom active
 783	if ( ! previewp->mSnapshotActive)
 784	{
 785		return FALSE;
 786	}
 787
 788	// time to produce a snapshot
 789	previewp->setThumbnailImageSize();
 790
 791	lldebugs << "producing snapshot" << llendl;
 792	if (!previewp->mPreviewImage)
 793	{
 794		previewp->mPreviewImage = new LLImageRaw;
 795	}
 796
 797	if (!previewp->mPreviewImageEncoded)
 798	{
 799		previewp->mPreviewImageEncoded = new LLImageRaw;
 800	}
 801
 802	previewp->setVisible(FALSE);
 803	previewp->setEnabled(FALSE);
 804	
 805	previewp->getWindow()->incBusyCount();
 806	previewp->setImageScaled(FALSE);
 807
 808	// grab the raw image and encode it into desired format
 809	if(gViewerWindow->rawSnapshot(
 810							previewp->mPreviewImage,
 811							previewp->getWidth(),
 812							previewp->getHeight(),
 813							previewp->mKeepAspectRatio,//gSavedSettings.getBOOL("KeepAspectForSnapshot"),
 814							previewp->getSnapshotType() == LLSnapshotLivePreview::SNAPSHOT_TEXTURE,
 815							gSavedSettings.getBOOL("RenderUIInSnapshot"),
 816							FALSE,
 817							previewp->mSnapshotBufferType,
 818							previewp->getMaxImageSize()))
 819	{
 820		previewp->mPreviewImageEncoded->resize(
 821			previewp->mPreviewImage->getWidth(), 
 822			previewp->mPreviewImage->getHeight(), 
 823			previewp->mPreviewImage->getComponents());
 824
 825		if(previewp->getSnapshotType() == SNAPSHOT_TEXTURE)
 826		{
 827			lldebugs << "Encoding new image of format J2C" << llendl;
 828			LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
 829			LLPointer<LLImageRaw> scaled = new LLImageRaw(
 830				previewp->mPreviewImage->getData(),
 831				previewp->mPreviewImage->getWidth(),
 832				previewp->mPreviewImage->getHeight(),
 833				previewp->mPreviewImage->getComponents());
 834		
 835			scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE);
 836			previewp->setImageScaled(TRUE);
 837			if (formatted->encode(scaled, 0.f))
 838			{
 839				previewp->mDataSize = formatted->getDataSize();
 840				formatted->decode(previewp->mPreviewImageEncoded, 0);
 841			}
 842		}
 843		else
 844		{
 845			// delete any existing image
 846			previewp->mFormattedImage = NULL;
 847			// now create the new one of the appropriate format.
 848			LLFloaterSnapshot::ESnapshotFormat format = previewp->getSnapshotFormat();
 849			lldebugs << "Encoding new image of format " << format << llendl;
 850
 851			switch(format)
 852			{
 853			case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
 854				previewp->mFormattedImage = new LLImagePNG(); 
 855				break;
 856			case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
 857				previewp->mFormattedImage = new LLImageJPEG(previewp->mSnapshotQuality); 
 858				break;
 859			case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
 860				previewp->mFormattedImage = new LLImageBMP(); 
 861				break;
 862			}
 863			if (previewp->mFormattedImage->encode(previewp->mPreviewImage, 0))
 864			{
 865				previewp->mDataSize = previewp->mFormattedImage->getDataSize();
 866				// special case BMP to copy instead of decode otherwise decode will crash.
 867				if(format == LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP)
 868				{
 869					previewp->mPreviewImageEncoded->copy(previewp->mPreviewImage);
 870				}
 871				else
 872				{
 873					previewp->mFormattedImage->decode(previewp->mPreviewImageEncoded, 0);
 874				}
 875			}
 876		}
 877
 878		LLPointer<LLImageRaw> scaled = new LLImageRaw(
 879			previewp->mPreviewImageEncoded->getData(),
 880			previewp->mPreviewImageEncoded->getWidth(),
 881			previewp->mPreviewImageEncoded->getHeight(),
 882			previewp->mPreviewImageEncoded->getComponents());
 883		
 884		if(!scaled->isBufferInvalid())
 885		{
 886			// leave original image dimensions, just scale up texture buffer
 887			if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024)
 888			{
 889				// go ahead and shrink image to appropriate power of 2 for display
 890				scaled->biasedScaleToPowerOfTwo(1024);
 891				previewp->setImageScaled(TRUE);
 892			}
 893			else
 894			{
 895				// expand image but keep original image data intact
 896				scaled->expandToPowerOfTwo(1024, FALSE);
 897			}
 898
 899			previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE);
 900			LLPointer<LLViewerTexture> curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex];
 901			gGL.getTexUnit(0)->bind(curr_preview_image);
 902			if (previewp->getSnapshotType() != SNAPSHOT_TEXTURE)
 903			{
 904				curr_preview_image->setFilteringOption(LLTexUnit::TFO_POINT);
 905			}
 906			else
 907			{
 908				curr_preview_image->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
 909			}
 910			curr_preview_image->setAddressMode(LLTexUnit::TAM_CLAMP);
 911
 912			previewp->mSnapshotUpToDate = TRUE;
 913			previewp->generateThumbnailImage(TRUE) ;
 914
 915			previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();
 916			previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
 917		}
 918	}
 919	previewp->getWindow()->decBusyCount();
 920	// only show fullscreen preview when in freeze frame mode
 921	previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame"));
 922	previewp->mSnapshotDelayTimer.stop();
 923	previewp->mSnapshotActive = FALSE;
 924
 925	if(!previewp->getThumbnailUpToDate())
 926	{
 927		previewp->generateThumbnailImage() ;
 928	}
 929	lldebugs << "done creating snapshot" << llendl;
 930	LLFloaterSnapshot::postUpdate();
 931
 932	return TRUE;
 933}
 934
 935void LLSnapshotLivePreview::setSize(S32 w, S32 h)
 936{
 937	lldebugs << "setSize(" << w << ", " << h << ")" << llendl;
 938	setWidth(w);
 939	setHeight(h);
 940}
 941
 942void LLSnapshotLivePreview::getSize(S32& w, S32& h) const
 943{
 944	w = getWidth();
 945	h = getHeight();
 946}
 947
 948void LLSnapshotLivePreview::saveTexture()
 949{
 950	lldebugs << "saving texture: " << mPreviewImage->getWidth() << "x" << mPreviewImage->getHeight() << llendl;
 951	// gen a new uuid for this asset
 952	LLTransactionID tid;
 953	tid.generate();
 954	LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
 955		
 956	LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
 957	LLPointer<LLImageRaw> scaled = new LLImageRaw(mPreviewImage->getData(),
 958												  mPreviewImage->getWidth(),
 959												  mPreviewImage->getHeight(),
 960												  mPreviewImage->getComponents());
 961	
 962	scaled->biasedScaleToPowerOfTwo(MAX_TEXTURE_SIZE);
 963	lldebugs << "scaled texture to " << scaled->getWidth() << "x" << scaled->getHeight() << llendl;
 964
 965	if (formatted->encode(scaled, 0.0f))
 966	{
 967		LLVFile::writeFile(formatted->getData(), formatted->getDataSize(), gVFS, new_asset_id, LLAssetType::AT_TEXTURE);
 968		std::string pos_string;
 969		LLAgentUI::buildLocationString(pos_string, LLAgentUI::LOCATION_FORMAT_FULL);
 970		std::string who_took_it;
 971		LLAgentUI::buildFullname(who_took_it);
 972		LLAssetStorage::LLStoreAssetCallback callback = NULL;
 973		S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
 974		void *userdata = NULL;
 975		upload_new_resource(tid,	// tid
 976				    LLAssetType::AT_TEXTURE,
 977				    "Snapshot : " + pos_string,
 978				    "Taken by " + who_took_it + " at " + pos_string,
 979				    0,
 980				    LLFolderType::FT_SNAPSHOT_CATEGORY,
 981				    LLInventoryType::IT_SNAPSHOT,
 982				    PERM_ALL,  // Note: Snapshots to inventory is a special case of content upload
 983				    LLFloaterPerms::getGroupPerms(), // that is more permissive than other uploads
 984				    LLFloaterPerms::getEveryonePerms(),
 985				    "Snapshot : " + pos_string,
 986				    callback, expected_upload_cost, userdata);
 987		gViewerWindow->playSnapshotAnimAndSound();
 988	}
 989	else
 990	{
 991		LLNotificationsUtil::add("ErrorEncodingSnapshot");
 992		llwarns << "Error encoding snapshot" << llendl;
 993	}
 994
 995	LLViewerStats::getInstance()->incStat(LLViewerStats::ST_SNAPSHOT_COUNT );
 996	
 997	mDataSize = 0;
 998}
 999
1000BOOL LLSnapshotLivePreview::saveLocal()
1001{
1002	BOOL success = gViewerWindow->saveImageNumbered(mFormattedImage);
1003
1004	if(success)
1005	{
1006		gViewerWindow->playSnapshotAnimAndSound();
1007	}
1008	return success;
1009}
1010
1011void LLSnapshotLivePreview::saveWeb()
1012{
1013	// *FIX: Will break if the window closes because of CloseSnapshotOnKeep!
1014	// Needs to pass on ownership of the image.
1015	LLImageJPEG* jpg = dynamic_cast<LLImageJPEG*>(mFormattedImage.get());
1016	if(!jpg)
1017	{
1018		llwarns << "Formatted image not a JPEG" << llendl;
1019		return;
1020	}
1021
1022	LLSD metadata;
1023	metadata["description"] = getChild<LLLineEditor>("description")->getText();
1024
1025	LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(gAgentCamera.getCameraPositionGlobal(),
1026		boost::bind(&LLSnapshotLivePreview::regionNameCallback, this, jpg, metadata, _1, _2, _3, _4));
1027
1028	gViewerWindow->playSnapshotAnimAndSound();
1029}
1030
1031void LLSnapshotLivePreview::regionNameCallback(LLImageJPEG* snapshot, LLSD& metadata, const std::string& name, S32 x, S32 y, S32 z)
1032{
1033	metadata["slurl"] = LLSLURL(name, LLVector3d(x, y, z)).getSLURLString();
1034
1035	LLWebSharing::instance().shareSnapshot(snapshot, metadata);
1036}
1037
1038///----------------------------------------------------------------------------
1039/// Class LLFloaterSnapshot::Impl
1040///----------------------------------------------------------------------------
1041
1042class LLFloaterSnapshot::Impl
1043{
1044	LOG_CLASS(LLFloaterSnapshot::Impl);
1045public:
1046	typedef enum e_status
1047	{
1048		STATUS_READY,
1049		STATUS_WORKING,
1050		STATUS_FINISHED
1051	} EStatus;
1052
1053	Impl()
1054	:	mAvatarPauseHandles(),
1055		mLastToolset(NULL),
1056		mAspectRatioCheckOff(false),
1057		mNeedRefresh(false),
1058		mStatus(STATUS_READY)
1059	{
1060	}
1061	~Impl()
1062	{
1063		//unpause avatars
1064		mAvatarPauseHandles.clear();
1065
1066	}
1067	static void onClickNewSnapshot(void* data);
1068	static void onClickAutoSnap(LLUICtrl *ctrl, void* data);
1069	//static void onClickAdvanceSnap(LLUICtrl *ctrl, void* data);
1070	static void onClickMore(void* data) ;
1071	static void onClickUICheck(LLUICtrl *ctrl, void* data);
1072	static void onClickHUDCheck(LLUICtrl *ctrl, void* data);
1073	static void applyKeepAspectCheck(LLFloaterSnapshot* view, BOOL checked);
1074	static void updateResolution(LLUICtrl* ctrl, void* data, BOOL do_update = TRUE);
1075	static void onCommitFreezeFrame(LLUICtrl* ctrl, void* data);
1076	static void onCommitLayerTypes(LLUICtrl* ctrl, void*data);
1077	static void onImageQualityChange(LLFloaterSnapshot* view, S32 quality_val);
1078	static void onImageFormatChange(LLFloaterSnapshot* view);
1079	static void applyCustomResolution(LLFloaterSnapshot* view, S32 w, S32 h);
1080	static void onSnapshotUploadFinished(bool status);
1081	static void onSendingPostcardFinished(bool status);
1082	static BOOL checkImageSize(LLSnapshotLivePreview* previewp, S32& width, S32& height, BOOL isWidthChanged, S32 max_value);
1083	static void setImageSizeSpinnersValues(LLFloaterSnapshot *view, S32 width, S32 height) ;
1084	static void updateSpinners(LLFloaterSnapshot* view, LLSnapshotLivePreview* previewp, S32& width, S32& height, BOOL is_width_changed);
1085
1086	static LLPanelSnapshot* getActivePanel(LLFloaterSnapshot* floater, bool ok_if_not_found = true);
1087	static LLSnapshotLivePreview::ESnapshotType getActiveSnapshotType(LLFloaterSnapshot* floater);
1088	static LLFloaterSnapshot::ESnapshotFormat getImageFormat(LLFloaterSnapshot* floater);
1089	static LLSpinCtrl* getWidthSpinner(LLFloaterSnapshot* floater);
1090	static LLSpinCtrl* getHeightSpinner(LLFloaterSnapshot* floater);
1091	static void enableAspectRatioCheckbox(LLFloaterSnapshot* floater, BOOL enable);
1092	static void setAspectRatioCheckboxValue(LLFloaterSnapshot* floater, BOOL checked);
1093
1094	static LLSnapshotLivePreview* getPreviewView(LLFloaterSnapshot *floater);
1095	static void setResolution(LLFloaterSnapshot* floater, const std::string& comboname);
1096	static void updateControls(LLFloaterSnapshot* floater);
1097	static void updateLayout(LLFloaterSnapshot* floater);
1098	static void setStatus(EStatus status, bool ok = true, const std::string& msg = LLStringUtil::null);
1099	EStatus getStatus() const { return mStatus; }
1100	static void setNeedRefresh(LLFloaterSnapshot* floater, bool need);
1101
1102private:
1103	static LLViewerWindow::ESnapshotType getLayerType(LLFloaterSnapshot* floater);
1104	static void comboSetCustom(LLFloaterSnapshot *floater, const std::string& comboname);
1105	static void checkAutoSnapshot(LLSnapshotLivePreview* floater, BOOL update_thumbnail = FALSE);
1106	static void checkAspectRatio(LLFloaterSnapshot *view, S32 index) ;
1107	static void setWorking(LLFloaterSnapshot* floater, bool working);
1108	static void setFinished(LLFloaterSnapshot* floater, bool finished, bool ok = true, const std::string& msg = LLStringUtil::null);
1109
1110
1111public:
1112	std::vector<LLAnimPauseRequest> mAvatarPauseHandles;
1113
1114	LLToolset*	mLastToolset;
1115	LLHandle<LLView> mPreviewHandle;
1116	bool mAspectRatioCheckOff ;
1117	bool mNeedRefresh;
1118	EStatus mStatus;
1119};
1120
1121// static
1122LLPanelSnapshot* LLFloaterSnapshot::Impl::getActivePanel(LLFloaterSnapshot* floater, bool ok_if_not_found)
1123{
1124	LLSideTrayPanelContainer* panel_container = floater->getChild<LLSideTrayPanelContainer>("panel_container");
1125	LLPanelSnapshot* active_panel = dynamic_cast<LLPanelSnapshot*>(panel_container->getCurrentPanel());
1126	if (!ok_if_not_found)
1127	{
1128		llassert_always(active_panel != NULL);
1129	}
1130	return active_panel;
1131}
1132
1133// static
1134LLSnapshotLivePreview::ESnapshotType LLFloaterSnapshot::Impl::getActiveSnapshotType(LLFloaterSnapshot* floater)
1135{
1136	LLSnapshotLivePreview::ESnapshotType type = LLSnapshotLivePreview::SNAPSHOT_WEB;
1137	std::string name;
1138	LLPanelSnapshot* spanel = getActivePanel(floater);
1139
1140	if (spanel)
1141	{
1142		name = spanel->getName();
1143	}
1144
1145	if (name == "panel_snapshot_postcard")
1146	{
1147		type = LLSnapshotLivePreview::SNAPSHOT_POSTCARD;
1148	}
1149	else if (name == "panel_snapshot_inventory")
1150	{
1151		type = LLSnapshotLivePreview::SNAPSHOT_TEXTURE;
1152	}
1153	else if (name == "panel_snapshot_local")
1154	{
1155		type = LLSnapshotLivePreview::SNAPSHOT_LOCAL;
1156	}
1157
1158	return type;
1159}
1160
1161// static
1162LLFloaterSnapshot::ESnapshotFormat LLFloaterSnapshot::Impl::getImageFormat(LLFloaterSnapshot* floater)
1163{
1164	LLPanelSnapshot* active_panel = getActivePanel(floater);
1165	// FIXME: if the default is not PNG, profile uploads may fail.
1166	return active_panel ? active_panel->getImageFormat() : LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG;
1167}
1168
1169// static
1170LLSpinCtrl* LLFloaterSnapshot::Impl::getWidthSpinner(LLFloaterSnapshot* floater)
1171{
1172	LLPanelSnapshot* active_panel = getActivePanel(floater);
1173	return active_panel ? active_panel->getWidthSpinner() : floater->getChild<LLSpinCtrl>("snapshot_width");
1174}
1175
1176// static
1177LLSpinCtrl* LLFloaterSnapshot::Impl::getHeightSpinner(LLFloaterSnapshot* floater)
1178{
1179	LLPanelSnapshot* active_panel = getActivePanel(floater);
1180	return active_panel ? active_panel->getHeightSpinner() : floater->getChild<LLSpinCtrl>("snapshot_height");
1181}
1182
1183// static
1184void LLFloaterSnapshot::Impl::enableAspectRatioCheckbox(LLFloaterSnapshot* floater, BOOL enable)
1185{
1186	LLPanelSnapshot* active_panel = getActivePanel(floater);
1187	if (active_panel)
1188	{
1189		active_panel->enableAspectRatioCheckbox(enable);
1190	}
1191}
1192
1193// static
1194void LLFloaterSnapshot::Impl::setAspectRatioCheckboxValue(LLFloaterSnapshot* floater, BOOL checked)
1195{
1196	LLPanelSnapshot* active_panel = getActivePanel(floater);
1197	if (active_panel)
1198	{
1199		active_panel->getChild<LLUICtrl>(active_panel->getAspectRatioCBName())->setValue(checked);
1200	}
1201}
1202
1203// static
1204LLSnapshotLivePreview* LLFloaterSnapshot::Impl::getPreviewView(LLFloaterSnapshot *floater)
1205{
1206	LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)floater->impl.mPreviewHandle.get();
1207	return previewp;
1208}
1209
1210// static
1211LLViewerWindow::ESnapshotType LLFloaterSnapshot::Impl::getLayerType(LLFloaterSnapshot* floater)
1212{
1213	LLViewerWindow::ESnapshotType type = LLViewerWindow::SNAPSHOT_TYPE_COLOR;
1214	LLSD value = floater->getChild<LLUICtrl>("layer_types")->getValue();
1215	const std::string id = value.asString();
1216	if (id == "colors")
1217		type = LLViewerWindow::SNAPSHOT_TYPE_COLOR;
1218	else if (id == "depth")
1219		type = LLViewerWindow::SNAPSHOT_TYPE_DEPTH;
1220	return type;
1221}
1222
1223// static
1224void LLFloaterSnapshot::Impl::setResolution(LLFloaterSnapshot* floater, const std::string& comboname)
1225{
1226	LLComboBox* combo = floater->getChild<LLComboBox>(comboname);
1227		combo->setVisible(TRUE);
1228	updateResolution(combo, floater, FALSE); // to sync spinners with combo
1229}
1230
1231//static 
1232void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp)
1233{
1234	LLSnapshotLivePreview* previewp = getPreviewView(floaterp);
1235
1236	BOOL advanced = gSavedSettings.getBOOL("AdvanceSnapshot");
1237
1238	// Show/hide advanced options.
1239	LLPanel* advanced_options_panel = floaterp->getChild<LLPanel>("advanced_options_panel");
1240	floaterp->getChild<LLButton>("advanced_options_btn")->setImageOverlay(advanced ? "TabIcon_Open_Off" : "TabIcon_Close_Off");
1241	if (advanced != advanced_options_panel->getVisible())
1242	{
1243		S32 panel_width = advanced_options_panel->getRect().getWidth();
1244		floaterp->getChild<LLPanel>("advanced_options_panel")->setVisible(advanced);
1245		S32 floater_width = floaterp->getRect().getWidth();
1246		floater_width += (advanced ? panel_width : -panel_width);
1247		floaterp->reshape(floater_width, floaterp->getRect().getHeight());
1248	}
1249
1250	if(!advanced) //set to original window resolution
1251	{
1252		previewp->mKeepAspectRatio = TRUE;
1253
1254		floaterp->getChild<LLComboBox>("profile_size_combo")->setCurrentByIndex(0);
1255		floaterp->getChild<LLComboBox>("postcard_size_combo")->setCurrentByIndex(0);
1256		floaterp->getChild<LLComboBox>("texture_size_combo")->setCurrentByIndex(0);
1257		floaterp->getChild<LLComboBox>("local_size_combo")->setCurrentByIndex(0);
1258
1259		LLSnapshotLivePreview* previewp = getPreviewView(floaterp);
1260		previewp->setSize(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw());
1261	}
1262
1263	bool use_freeze_frame = floaterp->getChild<LLUICtrl>("freeze_frame_check")->getValue().asBoolean();
1264
1265	if (use_freeze_frame)
1266	{
1267		// stop all mouse events at fullscreen preview layer
1268		floaterp->getParent()->setMouseOpaque(TRUE);
1269		
1270		// shrink to smaller layout
1271		// *TODO: unneeded?
1272		floaterp->reshape(floaterp->getRect().getWidth(), floaterp->getRect().getHeight());
1273
1274		// can see and interact with fullscreen preview now
1275		if (previewp)
1276		{
1277			previewp->setVisible(TRUE);
1278			previewp->setEnabled(TRUE);
1279		}
1280
1281		//RN: freeze all avatars
1282		LLCharacter* avatarp;
1283		for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
1284			iter != LLCharacter::sInstances.end(); ++iter)
1285		{
1286			avatarp = *iter;
1287			floaterp->impl.mAvatarPauseHandles.push_back(avatarp->requestPause());
1288		}
1289
1290		// freeze everything else
1291		gSavedSettings.setBOOL("FreezeTime", TRUE);
1292
1293		if (LLToolMgr::getInstance()->getCurrentToolset() != gCameraToolset)
1294		{
1295			floaterp->impl.mLastToolset = LLToolMgr::getInstance()->getCurrentToolset();
1296			LLToolMgr::getInstance()->setCurrentToolset(gCameraToolset);
1297		}
1298	}
1299	else // turning off freeze frame mode
1300	{
1301		floaterp->getParent()->setMouseOpaque(FALSE);
1302		// *TODO: unneeded?
1303		floaterp->reshape(floaterp->getRect().getWidth(), floaterp->getRect().getHeight());
1304		if (previewp)
1305		{
1306			previewp->setVisible(FALSE);
1307			previewp->setEnabled(FALSE);
1308		}
1309
1310		//RN: thaw all avatars
1311		floaterp->impl.mAvatarPauseHandles.clear();
1312
1313		// thaw everything else
1314		gSavedSettings.setBOOL("FreezeTime", FALSE);
1315
1316		// restore last tool (e.g. pie menu, etc)
1317		if (floaterp->impl.mLastToolset)
1318		{
1319			LLToolMgr::getInstance()->setCurrentToolset(floaterp->impl.mLastToolset);
1320		}
1321	}
1322}
1323
1324// This is the main function that keeps all the GUI controls in sync with the saved settings.
1325// It should be called anytime a setting is changed that could affect the controls.
1326// No other methods should be changing any of the controls directly except for helpers called by this method.
1327// The basic pattern for programmatically changing the GUI settings is to first set the
1328// appropriate saved settings and then call this method to sync the GUI with them.
1329// FIXME: The above comment seems obsolete now.
1330// static
1331void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
1332{
1333	LLSnapshotLivePreview::ESnapshotType shot_type = getActiveSnapshotType(floater);
1334	ESnapshotFormat shot_format = (ESnapshotFormat)gSavedSettings.getS32("SnapshotFormat");
1335	LLViewerWindow::ESnapshotType layer_type = getLayerType(floater);
1336
1337#if 0
1338	floater->getChildView("share_to_web")->setVisible( gSavedSettings.getBOOL("SnapshotSharingEnabled"));
1339#endif
1340
1341	floater->getChild<LLComboBox>("local_format_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFormat"));
1342	enableAspectRatioCheckbox(floater, !floater->impl.mAspectRatioCheckOff);
1343	setAspectRatioCheckboxValue(floater, gSavedSettings.getBOOL("KeepAspectForSnapshot"));
1344	floater->getChildView("layer_types")->setEnabled(shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL);
1345
1346	LLPanelSnapshot* active_panel = getActivePanel(floater);
1347	if (active_panel)
1348	{
1349		LLSpinCtrl* width_ctrl = getWidthSpinner(floater);
1350		LLSpinCtrl* height_ctrl = getHeightSpinner(floater);
1351
1352		// Initialize spinners.
1353		if (width_ctrl->getValue().asInteger() == 0)
1354		{
1355			S32 w = gViewerWindow->getWindowWidthRaw();
1356			lldebugs << "Initializing width spinner (" << width_ctrl->getName() << "): " << w << llendl;
1357			width_ctrl->setValue(w);
1358		}
1359		if (height_ctrl->getValue().asInteger() == 0)
1360		{
1361			S32 h = gViewerWindow->getWindowHeightRaw();
1362			lldebugs << "Initializing height spinner (" << height_ctrl->getName() << "): " << h << llendl;
1363			height_ctrl->setValue(h);
1364		}
1365
1366		// ?lamp snapshot resolution to window size when showing UI or HUD in snapshot.
1367		if (gSavedSettings.getBOOL("RenderUIInSnapshot") || gSavedSettings.getBOOL("RenderHUDInSnapshot"))
1368		{
1369			S32 width = gViewerWindow->getWindowWidthRaw();
1370			S32 height = gViewerWindow->getWindowHeightRaw();
1371
1372			width_ctrl->setMaxValue(width);
1373
1374			height_ctrl->setMaxValue(height);
1375
1376			if (width_ctrl->getValue().asInteger() > width)
1377			{
1378				width_ctrl->forceSetValue(width);
1379			}
1380			if (height_ctrl->getValue().asInteger() > height)
1381			{
1382				height_ctrl->forceSetValue(height);
1383			}
1384		}
1385		else
1386		{
1387			width_ctrl->setMaxValue(6016);
1388			height_ctrl->setMaxValue(6016);
1389		}
1390	}
1391		
1392	LLSnapshotLivePreview* previewp = getPreviewView(floater);
1393	BOOL got_bytes = previewp && previewp->getDataSize() > 0;
1394	BOOL got_snap = previewp && previewp->getSnapshotUpToDate();
1395
1396	// *TODO: Separate maximum size for Web images from postcards
1397	lldebugs << "Is snapshot up-to-date? " << got_snap << llendl;
1398
1399	LLLocale locale(LLLocale::USER_LOCALE);
1400	std::string bytes_string;
1401	if (got_snap)
1402	{
1403		LLResMgr::getInstance()->getIntegerString(bytes_string, (previewp->getDataSize()) >> 10 );
1404	}
1405
1406	// Update displayed image resolution.
1407	LLTextBox* image_res_tb = floater->getChild<LLTextBox>("image_res_text");
1408	image_res_tb->setVisible(got_snap);
1409	if (got_snap)
1410	{
1411		LLPointer<LLImageRaw> img = previewp->getEncodedImage();
1412		image_res_tb->setTextArg("[WIDTH]", llformat("%d", img->getWidth()));
1413		image_res_tb->setTextArg("[HEIGHT]", llformat("%d", img->getHeight()));
1414	}
1415
1416	floater->getChild<LLUICtrl>("file_size_label")->setTextArg("[SIZE]", got_snap ? bytes_string : floater->getString("unknown"));
1417	floater->getChild<LLUICtrl>("file_size_label")->setColor(
1418		shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD 
1419		&& got_bytes
1420		&& previewp->getDataSize() > MAX_POSTCARD_DATASIZE ? LLUIColor(LLColor4::red) : LLUIColorTable::instance().getColor( "LabelTextColor" ));
1421
1422	// Update the width and height spinners based on the corresponding resolution combos. (?)
1423	switch(shot_type)
1424	{
1425	  case LLSnapshotLivePreview::SNAPSHOT_WEB:
1426		layer_type = LLViewerWindow::SNAPSHOT_TYPE_COLOR;
1427		floater->getChild<LLUICtrl>("layer_types")->setValue("colors");
1428		setResolution(floater, "profile_size_combo");
1429		break;
1430	  case LLSnapshotLivePreview::SNAPSHOT_POSTCARD:
1431		layer_type = LLViewerWindow::SNAPSHOT_TYPE_COLOR;
1432		floater->getChild<LLUICtrl>("layer_types")->setValue("colors");
1433		setResolution(floater, "postcard_size_combo");
1434		break;
1435	  case LLSnapshotLivePreview::SNAPSHOT_TEXTURE:
1436		layer_type = LLViewerWindow::SNAPSHOT_TYPE_COLOR;
1437		floater->getChild<LLUICtrl>("layer_types")->setValue("colors");
1438		setResolution(floater, "texture_size_combo");
1439		break;
1440	  case  LLSnapshotLivePreview::SNAPSHOT_LOCAL:
1441		setResolution(floater, "local_size_combo");
1442		break;
1443	  default:
1444		break;
1445	}
1446
1447	if (previewp)
1448	{
1449		previewp->setSnapshotType(shot_type);
1450		previewp->setSnapshotFormat(shot_format);
1451		previewp->setSnapshotBufferType(layer_type);
1452	}
1453
1454	LLPanelSnapshot* current_panel = Impl::getActivePanel(floater);
1455	if (current_panel)
1456	{
1457		LLSD info;
1458		info["have-snapshot"] = got_snap;
1459		current_panel->updateControls(info);
1460	}
1461	lldebugs << "finished updating controls" << llendl;
1462}
1463
1464// static
1465void LLFloaterSnapshot::Impl::setStatus(EStatus status, bool ok, const std::string& msg)
1466{
1467	LLFloaterSnapshot* floater = LLFloaterSnapshot::getInstance();
1468	switch (status)
1469	{
1470	case STATUS_READY:
1471		setWorking(floater, false);
1472		setFinished(floater, false);
1473		break;
1474	case STATUS_WORKING:
1475		setWorking(floater, true);
1476		setFinished(floater, false);
1477		break;
1478	case STATUS_FINISHED:
1479		setWorking(floater, false);
1480		setFinished(floater, true, ok, msg);
1481		break;
1482	}
1483
1484	floater->impl.mStatus = status;
1485}
1486
1487// static
1488void LLFloaterSnapshot::Impl::setNeedRefresh(LLFloaterSnapshot* floater, bool need)
1489{
1490	if (!floater) return;
1491
1492	// Don't display the "Refresh to save" message if we're in auto-refresh mode.
1493	if (gSavedSettings.getBOOL("AutoSnapshot"))
1494	{
1495		need = false;
1496	}
1497
1498	floater->mRefreshLabel->setVisible(need);
1499	floater->impl.mNeedRefresh = need;
1500}
1501
1502// static
1503void LLFloaterSnapshot::Impl::checkAutoSnapshot(LLSnapshotLivePreview* previewp, BOOL update_thumbnail)
1504{
1505	if (previewp)
1506	{
1507		BOOL autosnap = gSavedSettings.getBOOL("AutoSnapshot");
1508		lldebugs << "updating " << (autosnap ? "snapshot" : "thumbnail")

Large files files are truncated, but you can click here to view the full file