aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llfloatersnapshot.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llfloatersnapshot.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/llfloatersnapshot.cpp1542
1 files changed, 1542 insertions, 0 deletions
diff --git a/linden/indra/newview/llfloatersnapshot.cpp b/linden/indra/newview/llfloatersnapshot.cpp
new file mode 100644
index 0000000..01f86af
--- /dev/null
+++ b/linden/indra/newview/llfloatersnapshot.cpp
@@ -0,0 +1,1542 @@
1/**
2 * @file llfloatersnapshot.cpp
3 * @brief Snapshot preview window, allowing saving, e-mailing, etc.
4 *
5 * Copyright (c) 2004-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "llfloatersnapshot.h"
31
32#include "llfontgl.h"
33#include "llsys.h"
34#include "llgl.h"
35#include "v3dmath.h"
36#include "lldir.h"
37#include "llsdserialize.h"
38
39#include "llagent.h"
40#include "llcallbacklist.h"
41#include "llcriticaldamp.h"
42#include "llui.h"
43#include "llviewertexteditor.h"
44#include "llfocusmgr.h"
45#include "llbutton.h"
46#include "llcombobox.h"
47#include "llsliderctrl.h"
48#include "llspinctrl.h"
49#include "llviewercontrol.h"
50#include "viewer.h"
51#include "llvieweruictrlfactory.h"
52#include "llviewerstats.h"
53#include "llviewercamera.h"
54#include "llviewerwindow.h"
55#include "llviewermenu.h"
56#include "llfloaterpostcard.h"
57#include "llcheckboxctrl.h"
58#include "llradiogroup.h"
59#include "lltoolfocus.h"
60#include "lltoolmgr.h"
61#include "llworld.h"
62
63#include "llgl.h"
64#include "llglheaders.h"
65#include "llimagejpeg.h"
66#include "llimagej2c.h"
67#include "llvfile.h"
68#include "llvfs.h"
69
70///----------------------------------------------------------------------------
71/// Local function declarations, constants, enums, and typedefs
72///----------------------------------------------------------------------------
73
74LLSnapshotFloaterView* gSnapshotFloaterView = NULL;
75
76LLFloaterSnapshot* LLFloaterSnapshot::sInstance = NULL;
77const F32 SNAPSHOT_TIME_DELAY = 1.f;
78
79F32 SHINE_TIME = 0.5f;
80F32 SHINE_WIDTH = 0.6f;
81F32 SHINE_OPACITY = 0.3f;
82F32 FALL_TIME = 0.6f;
83S32 BORDER_WIDTH = 6;
84
85const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte
86
87///----------------------------------------------------------------------------
88/// Class LLSnapshotLivePreview
89///----------------------------------------------------------------------------
90class LLSnapshotLivePreview : public LLView
91{
92public:
93 enum ESnapshotType
94 {
95 SNAPSHOT_POSTCARD,
96 SNAPSHOT_TEXTURE,
97 SNAPSHOT_BITMAP
98 };
99
100 LLSnapshotLivePreview(const LLRect& rect);
101 ~LLSnapshotLivePreview();
102
103 virtual EWidgetType getWidgetType() const;
104 virtual LLString getWidgetTag() const;
105
106 /*virtual*/ void draw();
107 /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent);
108
109 void setSize(S32 w, S32 h);
110 void getSize(S32& w, S32& h) const;
111 S32 getDataSize() const { return mDataSize; }
112
113 ESnapshotType getSnapshotType() const { return mSnapshotType; }
114 BOOL getSnapshotUpToDate() const { return mSnapshotUpToDate; }
115 BOOL isSnapshotActive() { return mSnapshotActive; }
116 LLImageGL* getCurrentImage();
117 F32 getImageAspect();
118 LLRect getImageRect();
119 BOOL isImageScaled();
120
121 void setSnapshotType(ESnapshotType type) { mSnapshotType = type; }
122 void setSnapshotQuality(S32 quality);
123 void setSnapshotBufferType(LLViewerWindow::ESnapshotType type) { mSnapshotBufferType = type; }
124 void updateSnapshot(BOOL new_snapshot);
125 LLFloaterPostcard* savePostcard();
126 void saveTexture();
127 void saveLocal();
128
129 static void onIdle( void* snapshot_preview );
130
131protected:
132 LLColor4 mColor;
133 LLPointer<LLImageGL> mViewerImage[2];
134 LLRect mImageRect[2];
135 S32 mWidth[2];
136 S32 mHeight[2];
137 BOOL mImageScaled[2];
138
139 S32 mCurImageIndex;
140 LLPointer<LLImageRaw> mRawImage;
141 LLPointer<LLImageRaw> mRawImageEncoded;
142 LLPointer<LLImageJPEG> mJPEGImage;
143 LLFrameTimer mSnapshotDelayTimer;
144 S32 mShineCountdown;
145 LLFrameTimer mShineAnimTimer;
146 F32 mFlashAlpha;
147 BOOL mNeedsFlash;
148 LLVector3d mPosTakenGlobal;
149 S32 mSnapshotQuality;
150 S32 mDataSize;
151 ESnapshotType mSnapshotType;
152 BOOL mSnapshotUpToDate;
153 LLFrameTimer mFallAnimTimer;
154 LLVector3 mCameraPos;
155 LLQuaternion mCameraRot;
156 BOOL mSnapshotActive;
157 LLViewerWindow::ESnapshotType mSnapshotBufferType;
158
159public:
160 static std::set<LLSnapshotLivePreview*> sList;
161};
162
163std::set<LLSnapshotLivePreview*> LLSnapshotLivePreview::sList;
164
165LLSnapshotLivePreview::LLSnapshotLivePreview (const LLRect& rect) :
166 LLView("snapshot_live_preview", rect, FALSE),
167 mColor(1.f, 0.f, 0.f, 0.5f),
168 mCurImageIndex(0),
169 mRawImage(NULL),
170 mRawImageEncoded(NULL),
171 mJPEGImage(NULL),
172 mShineCountdown(0),
173 mFlashAlpha(0.f),
174 mNeedsFlash(TRUE),
175 mSnapshotQuality(gSavedSettings.getS32("SnapshotQuality")),
176 mDataSize(0),
177 mSnapshotType(SNAPSHOT_POSTCARD),
178 mSnapshotUpToDate(FALSE),
179 mCameraPos(gCamera->getOrigin()),
180 mCameraRot(gCamera->getQuaternion()),
181 mSnapshotActive(FALSE),
182 mSnapshotBufferType(LLViewerWindow::SNAPSHOT_TYPE_COLOR)
183{
184 mSnapshotDelayTimer.setTimerExpirySec(0.0f);
185 mSnapshotDelayTimer.start();
186// gIdleCallbacks.addFunction( &LLSnapshotLivePreview::onIdle, (void*)this );
187 sList.insert(this);
188 setFollowsAll();
189 mWidth[0] = gViewerWindow->getWindowDisplayWidth();
190 mWidth[1] = gViewerWindow->getWindowDisplayWidth();
191 mHeight[0] = gViewerWindow->getWindowDisplayHeight();
192 mHeight[1] = gViewerWindow->getWindowDisplayHeight();
193 mImageScaled[0] = FALSE;
194 mImageScaled[1] = FALSE;
195}
196
197LLSnapshotLivePreview::~LLSnapshotLivePreview()
198{
199 // delete images
200 mRawImage = NULL;
201 mRawImageEncoded = NULL;
202 mJPEGImage = NULL;
203
204// gIdleCallbacks.deleteFunction( &LLSnapshotLivePreview::onIdle, (void*)this );
205 sList.erase(this);
206}
207
208LLImageGL* LLSnapshotLivePreview::getCurrentImage()
209{
210 return mViewerImage[mCurImageIndex];
211}
212
213F32 LLSnapshotLivePreview::getImageAspect()
214{
215 if (!mViewerImage[mCurImageIndex])
216 {
217 return 0.f;
218 }
219
220 F32 image_aspect_ratio = ((F32)mWidth[mCurImageIndex]) / ((F32)mHeight[mCurImageIndex]);
221 F32 window_aspect_ratio = ((F32)mRect.getWidth()) / ((F32)mRect.getHeight());
222
223 if (gSavedSettings.getBOOL("KeepAspectForSnapshot"))
224 {
225 return image_aspect_ratio;
226 }
227 else
228 {
229 return window_aspect_ratio;
230 }
231}
232
233LLRect LLSnapshotLivePreview::getImageRect()
234{
235 return mImageRect[mCurImageIndex];
236}
237
238BOOL LLSnapshotLivePreview::isImageScaled()
239{
240 return mImageScaled[mCurImageIndex];
241}
242
243void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot)
244{
245 if (mSnapshotUpToDate)
246 {
247 S32 old_image_index = mCurImageIndex;
248 mCurImageIndex = (mCurImageIndex + 1) % 2;
249 mWidth[mCurImageIndex] = mWidth[old_image_index];
250 mHeight[mCurImageIndex] = mHeight[old_image_index];
251 mFallAnimTimer.start();
252 }
253 mSnapshotUpToDate = FALSE;
254 mShineAnimTimer.stop();
255 if (new_snapshot)
256 {
257 mSnapshotDelayTimer.start();
258 mSnapshotDelayTimer.setTimerExpirySec(SNAPSHOT_TIME_DELAY);
259 }
260
261 LLRect& rect = mImageRect[mCurImageIndex];
262 rect.set(0, mRect.getHeight(), mRect.getWidth(), 0);
263
264 F32 image_aspect_ratio = ((F32)mWidth[mCurImageIndex]) / ((F32)mHeight[mCurImageIndex]);
265 F32 window_aspect_ratio = ((F32)mRect.getWidth()) / ((F32)mRect.getHeight());
266
267 if (gSavedSettings.getBOOL("KeepAspectForSnapshot"))
268 {
269 if (image_aspect_ratio > window_aspect_ratio)
270 {
271 // trim off top and bottom
272 S32 new_height = llround((F32)mRect.getWidth() / image_aspect_ratio);
273 rect.mBottom += (mRect.getHeight() - new_height) / 2;
274 rect.mTop -= (mRect.getHeight() - new_height) / 2;
275 }
276 else if (image_aspect_ratio < window_aspect_ratio)
277 {
278 // trim off left and right
279 S32 new_width = llround((F32)mRect.getHeight() * image_aspect_ratio);
280 rect.mLeft += (mRect.getWidth() - new_width) / 2;
281 rect.mRight -= (mRect.getWidth() - new_width) / 2;
282 }
283 }
284}
285
286void LLSnapshotLivePreview::setSnapshotQuality(S32 quality)
287{
288 if (quality != mSnapshotQuality)
289 {
290 mSnapshotQuality = quality;
291 gSavedSettings.setS32("SnapshotQuality", quality);
292 }
293}
294
295EWidgetType LLSnapshotLivePreview::getWidgetType() const
296{
297 return WIDGET_TYPE_SNAPSHOT_LIVE_PREVIEW;
298}
299
300LLString LLSnapshotLivePreview::getWidgetTag() const
301{
302 return LL_SNAPSHOT_LIVE_PREVIEW_TAG;
303}
304
305void LLSnapshotLivePreview::draw()
306{
307 if(getVisible())
308 {
309 if (mViewerImage[mCurImageIndex].notNull() &&
310 mRawImageEncoded.notNull() &&
311 mSnapshotUpToDate)
312 {
313 LLColor4 bg_color(0.f, 0.f, 0.3f, 0.4f);
314 gl_rect_2d(mRect, bg_color);
315 LLRect &rect = mImageRect[mCurImageIndex];
316 LLRect shadow_rect = mImageRect[mCurImageIndex];
317 shadow_rect.stretch(BORDER_WIDTH);
318 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);
319
320 LLGLSTexture set_texture;
321 LLColor4 image_color(1.f, 1.f, 1.f, 1.f);
322 glColor4fv(image_color.mV);
323 LLViewerImage::bindTexture(mViewerImage[mCurImageIndex]);
324 // calculate UV scale
325 F32 uv_width = mImageScaled[mCurImageIndex] ? 1.f : llmin((F32)mWidth[mCurImageIndex] / (F32)mViewerImage[mCurImageIndex]->getWidth(), 1.f);
326 F32 uv_height = mImageScaled[mCurImageIndex] ? 1.f : llmin((F32)mHeight[mCurImageIndex] / (F32)mViewerImage[mCurImageIndex]->getHeight(), 1.f);
327 glPushMatrix();
328 {
329 glTranslatef((F32)rect.mLeft, (F32)rect.mBottom, 0.f);
330 glBegin(GL_QUADS);
331 {
332 glTexCoord2f(uv_width, uv_height);
333 glVertex2i(rect.getWidth(), rect.getHeight() );
334
335 glTexCoord2f(0.f, uv_height);
336 glVertex2i(0, rect.getHeight() );
337
338 glTexCoord2f(0.f, 0.f);
339 glVertex2i(0, 0);
340
341 glTexCoord2f(uv_width, 0.f);
342 glVertex2i(rect.getWidth(), 0);
343 }
344 glEnd();
345 }
346 glPopMatrix();
347
348 glColor4f(1.f, 1.f, 1.f, mFlashAlpha);
349 gl_rect_2d(mRect);
350 if (mNeedsFlash)
351 {
352 if (mFlashAlpha < 1.f)
353 {
354 mFlashAlpha = lerp(mFlashAlpha, 1.f, LLCriticalDamp::getInterpolant(0.02f));
355 }
356 else
357 {
358 mNeedsFlash = FALSE;
359 }
360 }
361 else
362 {
363 mFlashAlpha = lerp(mFlashAlpha, 0.f, LLCriticalDamp::getInterpolant(0.15f));
364 }
365
366 if (mShineCountdown > 0)
367 {
368 mShineCountdown--;
369 if (mShineCountdown == 0)
370 {
371 mShineAnimTimer.start();
372 }
373 }
374 else if (mShineAnimTimer.getStarted())
375 {
376 //LLDebugVarMessageBox::show("Shine time", &SHINE_TIME, 10.f, 0.1f);
377 //LLDebugVarMessageBox::show("Shine width", &SHINE_WIDTH, 2.f, 0.05f);
378 //LLDebugVarMessageBox::show("Shine opacity", &SHINE_OPACITY, 1.f, 0.05f);
379
380 F32 shine_interp = llmin(1.f, mShineAnimTimer.getElapsedTimeF32() / SHINE_TIME);
381
382 // draw "shine" effect
383 LLGLEnable scissor_test(GL_SCISSOR_TEST);
384 LLUI::setScissorRegionLocal(LLRect(0, mRect.getHeight(), mRect.getWidth(), 0));
385 {
386 // draw diagonal stripe with gradient that passes over screen
387 S32 x1 = gViewerWindow->getWindowWidth() * llround((clamp_rescale(shine_interp, 0.f, 1.f, -1.f - SHINE_WIDTH, 1.f)));
388 S32 x2 = x1 + llround(gViewerWindow->getWindowWidth() * SHINE_WIDTH);
389 S32 x3 = x2 + llround(gViewerWindow->getWindowWidth() * SHINE_WIDTH);
390 S32 y1 = 0;
391 S32 y2 = gViewerWindow->getWindowHeight();
392
393 LLGLSNoTexture no_texture;
394 glBegin(GL_QUADS);
395 {
396 glColor4f(1.f, 1.f, 1.f, 0.f);
397 glVertex2i(x1, y1);
398 glVertex2i(x1 + gViewerWindow->getWindowWidth(), y2);
399 glColor4f(1.f, 1.f, 1.f, SHINE_OPACITY);
400 glVertex2i(x2 + gViewerWindow->getWindowWidth(), y2);
401 glVertex2i(x2, y1);
402
403 glColor4f(1.f, 1.f, 1.f, SHINE_OPACITY);
404 glVertex2i(x2, y1);
405 glVertex2i(x2 + gViewerWindow->getWindowWidth(), y2);
406 glColor4f(1.f, 1.f, 1.f, 0.f);
407 glVertex2i(x3 + gViewerWindow->getWindowWidth(), y2);
408 glVertex2i(x3, y1);
409 }
410 glEnd();
411 }
412
413 if (mShineAnimTimer.getElapsedTimeF32() > SHINE_TIME)
414 {
415 mShineAnimTimer.stop();
416 }
417 }
418 }
419
420 // draw framing rectangle
421 {
422 LLGLSNoTexture no_texture;
423 glColor4f(1.f, 1.f, 1.f, 1.f);
424 LLRect outline_rect = mImageRect[mCurImageIndex];
425 glBegin(GL_QUADS);
426 {
427 glVertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
428 glVertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
429 glVertex2i(outline_rect.mRight, outline_rect.mTop);
430 glVertex2i(outline_rect.mLeft, outline_rect.mTop);
431
432 glVertex2i(outline_rect.mLeft, outline_rect.mBottom);
433 glVertex2i(outline_rect.mRight, outline_rect.mBottom);
434 glVertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
435 glVertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
436
437 glVertex2i(outline_rect.mLeft, outline_rect.mTop);
438 glVertex2i(outline_rect.mLeft, outline_rect.mBottom);
439 glVertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
440 glVertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
441
442 glVertex2i(outline_rect.mRight, outline_rect.mBottom);
443 glVertex2i(outline_rect.mRight, outline_rect.mTop);
444 glVertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH);
445 glVertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH);
446 }
447 glEnd();
448 }
449
450 // draw old image dropping away
451 if (mFallAnimTimer.getStarted())
452 {
453 S32 old_image_index = (mCurImageIndex + 1) % 2;
454 if (mViewerImage[old_image_index].notNull() && mFallAnimTimer.getElapsedTimeF32() < FALL_TIME)
455 {
456 LLGLSTexture texture_set;
457
458 F32 fall_interp = mFallAnimTimer.getElapsedTimeF32() / FALL_TIME;
459 F32 alpha = clamp_rescale(fall_interp, 0.f, 1.f, 0.8f, 0.4f);
460 LLColor4 image_color(1.f, 1.f, 1.f, alpha);
461 glColor4fv(image_color.mV);
462 LLViewerImage::bindTexture(mViewerImage[old_image_index]);
463 // calculate UV scale
464 // *FIX get this to work with old image
465 BOOL rescale = !mImageScaled[old_image_index] && mViewerImage[mCurImageIndex].notNull();
466 F32 uv_width = rescale ? llmin((F32)mWidth[old_image_index] / (F32)mViewerImage[mCurImageIndex]->getWidth(), 1.f) : 1.f;
467 F32 uv_height = rescale ? llmin((F32)mHeight[old_image_index] / (F32)mViewerImage[mCurImageIndex]->getHeight(), 1.f) : 1.f;
468 glPushMatrix();
469 {
470 LLRect& rect = mImageRect[old_image_index];
471 glTranslatef((F32)rect.mLeft, (F32)rect.mBottom - llround(mRect.getHeight() * 2.f * (fall_interp * fall_interp)), 0.f);
472 glRotatef(-45.f * fall_interp, 0.f, 0.f, 1.f);
473 glBegin(GL_QUADS);
474 {
475 glTexCoord2f(uv_width, uv_height);
476 glVertex2i(rect.getWidth(), rect.getHeight() );
477
478 glTexCoord2f(0.f, uv_height);
479 glVertex2i(0, rect.getHeight() );
480
481 glTexCoord2f(0.f, 0.f);
482 glVertex2i(0, 0);
483
484 glTexCoord2f(uv_width, 0.f);
485 glVertex2i(rect.getWidth(), 0);
486 }
487 glEnd();
488 }
489 glPopMatrix();
490 }
491 }
492 }
493}
494
495/*virtual*/
496void LLSnapshotLivePreview::reshape(S32 width, S32 height, BOOL called_from_parent)
497{
498 LLRect old_rect = mRect;
499 LLView::reshape(width, height, called_from_parent);
500 if (old_rect.getWidth() != width || old_rect.getHeight() != height)
501 {
502 updateSnapshot(getSnapshotUpToDate());
503 }
504}
505
506//static
507void LLSnapshotLivePreview::onIdle( void* snapshot_preview )
508{
509 LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)snapshot_preview;
510
511 LLVector3 new_camera_pos = gCamera->getOrigin();
512 LLQuaternion new_camera_rot = gCamera->getQuaternion();
513 if (gSavedSettings.getBOOL("FreezeTime") &&
514 (new_camera_pos != previewp->mCameraPos || dot(new_camera_rot, previewp->mCameraRot) < 0.995f))
515 {
516 previewp->mCameraPos = new_camera_pos;
517 previewp->mCameraRot = new_camera_rot;
518 // request a new snapshot whenever the camera moves, with a time delay
519 previewp->updateSnapshot(gSavedSettings.getBOOL("AutoSnapshot"));
520 }
521
522 previewp->mSnapshotActive = (previewp->mSnapshotDelayTimer.getStarted() &&
523 previewp->mSnapshotDelayTimer.hasExpired());
524
525 // don't take snapshots while ALT-zoom active
526 if (gFocusMgr.getMouseCapture() == gToolCamera)
527 {
528 previewp->mSnapshotActive = FALSE;
529 }
530
531 if (previewp->mSnapshotActive)
532 {
533 if (!previewp->mRawImage)
534 {
535 previewp->mRawImage = new LLImageRaw;
536 }
537
538 if (!previewp->mRawImageEncoded)
539 {
540 previewp->mRawImageEncoded = new LLImageRaw;
541 }
542
543 previewp->setVisible(FALSE);
544 previewp->setEnabled(FALSE);
545
546 previewp->getWindow()->incBusyCount();
547 previewp->mImageScaled[previewp->mCurImageIndex] = FALSE;
548
549 // do update
550 if(gViewerWindow->rawSnapshot(previewp->mRawImage,
551 previewp->mWidth[previewp->mCurImageIndex],
552 previewp->mHeight[previewp->mCurImageIndex],
553 !gSavedSettings.getBOOL("KeepAspectForSnapshot"),
554 gSavedSettings.getBOOL("RenderUIInSnapshot"),
555 FALSE,
556 previewp->mSnapshotBufferType))
557 {
558 previewp->mRawImageEncoded->resize(previewp->mRawImage->getWidth(), previewp->mRawImage->getHeight(), previewp->mRawImage->getComponents());
559
560 if (previewp->getSnapshotType() == SNAPSHOT_POSTCARD)
561 {
562 // *FIX: just resize and reuse existing jpeg?
563 previewp->mJPEGImage = NULL; // deletes image
564 previewp->mJPEGImage = new LLImageJPEG();
565 previewp->mJPEGImage->setEncodeQuality(llclamp(previewp->mSnapshotQuality, 0, 100));
566 if (previewp->mJPEGImage->encode(previewp->mRawImage))
567 {
568 previewp->mDataSize = previewp->mJPEGImage->getDataSize();
569 previewp->mJPEGImage->decode(previewp->mRawImageEncoded);
570 }
571 }
572 else if (previewp->getSnapshotType() == SNAPSHOT_TEXTURE)
573 {
574 LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
575 LLPointer<LLImageRaw> scaled = new LLImageRaw(previewp->mRawImage->getData(),
576 previewp->mRawImage->getWidth(),
577 previewp->mRawImage->getHeight(),
578 previewp->mRawImage->getComponents());
579
580 scaled->biasedScaleToPowerOfTwo(512);
581 previewp->mImageScaled[previewp->mCurImageIndex] = TRUE;
582 if (formatted->encode(scaled))
583 {
584 previewp->mDataSize = formatted->getDataSize();
585 formatted->decode(previewp->mRawImageEncoded);
586 }
587 }
588 else
589 {
590 previewp->mRawImageEncoded->copy(previewp->mRawImage);
591 previewp->mDataSize = previewp->mRawImage->getDataSize();
592 }
593
594 LLPointer<LLImageRaw> scaled = new LLImageRaw(previewp->mRawImageEncoded->getData(),
595 previewp->mRawImageEncoded->getWidth(),
596 previewp->mRawImageEncoded->getHeight(),
597 previewp->mRawImageEncoded->getComponents());
598
599 // leave original image dimensions, just scale up texture buffer
600 if (previewp->mRawImageEncoded->getWidth() > 1024 || previewp->mRawImageEncoded->getHeight() > 1024)
601 {
602 // go ahead and shrink image to appropriate power of 2 for display
603 scaled->biasedScaleToPowerOfTwo(1024);
604 previewp->mImageScaled[previewp->mCurImageIndex] = TRUE;
605 }
606 else
607 {
608 // expand image but keep original image data intact
609 scaled->expandToPowerOfTwo(1024, FALSE);
610 }
611
612 previewp->mViewerImage[previewp->mCurImageIndex] = new LLImageGL(scaled, FALSE);
613 previewp->mViewerImage[previewp->mCurImageIndex]->setMipFilterNearest(previewp->getSnapshotType() != SNAPSHOT_TEXTURE);
614 LLViewerImage::bindTexture(previewp->mViewerImage[previewp->mCurImageIndex]);
615 previewp->mViewerImage[previewp->mCurImageIndex]->setClamp(TRUE, TRUE);
616
617 previewp->mSnapshotUpToDate = TRUE;
618
619 previewp->mPosTakenGlobal = gAgent.getCameraPositionGlobal();
620 previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
621 }
622 previewp->getWindow()->decBusyCount();
623 // only show fullscreen preview when in freeze frame mode
624 previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame"));
625 previewp->mSnapshotDelayTimer.stop();
626 previewp->mSnapshotActive = FALSE;
627 }
628}
629
630void LLSnapshotLivePreview::setSize(S32 w, S32 h)
631{
632 mWidth[mCurImageIndex] = w;
633 mHeight[mCurImageIndex] = h;
634}
635
636void LLSnapshotLivePreview::getSize(S32& w, S32& h) const
637{
638 w = mWidth[mCurImageIndex];
639 h = mHeight[mCurImageIndex];
640}
641
642LLFloaterPostcard* LLSnapshotLivePreview::savePostcard()
643{
644 // calculate and pass in image scale in case image data only use portion
645 // of viewerimage buffer
646 LLVector2 image_scale(1.f, 1.f);
647 if (!isImageScaled())
648 {
649 image_scale.setVec(llmin(1.f, (F32)mWidth[mCurImageIndex] / (F32)getCurrentImage()->getWidth()), llmin(1.f, (F32)mHeight[mCurImageIndex] / (F32)getCurrentImage()->getHeight()));
650 }
651
652
653 LLFloaterPostcard* floater = LLFloaterPostcard::showFromSnapshot(mJPEGImage, mViewerImage[mCurImageIndex], image_scale, mPosTakenGlobal);
654 // relinquish lifetime of viewerimage and jpeg image to postcard floater
655 mViewerImage[mCurImageIndex] = NULL;
656 mJPEGImage = NULL;
657
658 return floater;
659}
660
661void LLSnapshotLivePreview::saveTexture()
662{
663 // gen a new uuid for this asset
664 LLTransactionID tid;
665 tid.generate();
666 LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
667
668 LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
669 LLPointer<LLImageRaw> scaled = new LLImageRaw(mRawImage->getData(),
670 mRawImage->getWidth(),
671 mRawImage->getHeight(),
672 mRawImage->getComponents());
673
674 scaled->biasedScaleToPowerOfTwo(512);
675
676 if (formatted->encode(scaled))
677 {
678 LLVFile::writeFile(formatted->getData(), formatted->getDataSize(), gVFS, new_asset_id, LLAssetType::AT_TEXTURE);
679 std::string pos_string;
680 gAgent.buildLocationString(pos_string);
681 upload_new_resource(tid, // tid
682 LLAssetType::AT_TEXTURE,
683 "Snapshot",
684 pos_string,
685 0,
686 LLAssetType::AT_SNAPSHOT_CATEGORY,
687 LLInventoryType::IT_SNAPSHOT,
688 PERM_ALL,
689 "Snapshot");
690 }
691 else
692 {
693 gViewerWindow->alertXml("ErrorEncodingSnapshot");
694 llwarns << "Error encoding snapshot" << llendl;
695 }
696
697 gViewerStats->incStat(LLViewerStats::ST_SNAPSHOT_COUNT );
698}
699
700void LLSnapshotLivePreview::saveLocal()
701{
702 gViewerWindow->saveImageNumbered(mRawImage);
703}
704
705///----------------------------------------------------------------------------
706/// Class LLFloaterSnapshot::Impl
707///----------------------------------------------------------------------------
708
709class LLFloaterSnapshot::Impl
710{
711public:
712 Impl() : mLastToolset(NULL)
713 {
714 }
715 ~Impl()
716 {
717 //unpause avatars
718 mAvatarPauseHandles.clear();
719
720 }
721 static void onClickDiscard(void* data);
722 static void onClickKeep(void* data);
723 static void onClickNewSnapshot(void* data);
724 static void onClickAutoSnap(LLUICtrl *ctrl, void* data);
725 static void onClickUICheck(LLUICtrl *ctrl, void* data);
726 static void onClickHUDCheck(LLUICtrl *ctrl, void* data);
727 static void onClickKeepOpenCheck(LLUICtrl *ctrl, void* data);
728 static void onClickKeepAspectCheck(LLUICtrl *ctrl, void* data);
729 static void onCommitQuality(LLUICtrl* ctrl, void* data);
730 static void onCommitResolution(LLUICtrl* ctrl, void* data);
731 static void onCommitFreezeFrame(LLUICtrl* ctrl, void* data);
732 static void onCommitLayerTypes(LLUICtrl* ctrl, void*data);
733 static void onCommitSnapshotType(LLUICtrl* ctrl, void* data);
734 static void onCommitCustomResolution(LLUICtrl *ctrl, void* data);
735
736 static LLSnapshotLivePreview* getPreviewView(LLFloaterSnapshot *floater);
737 static void setResolution(LLFloaterSnapshot* floater, const std::string& comboname);
738 static void updateControls(LLFloaterSnapshot* floater);
739 static void updateLayout(LLFloaterSnapshot* floater);
740
741 static LLViewHandle sPreviewHandle;
742
743private:
744 static LLSnapshotLivePreview::ESnapshotType getTypeIndex(LLFloaterSnapshot* floater);
745 static LLViewerWindow::ESnapshotType getLayerType(LLFloaterSnapshot* floater);
746 static void comboSetCustom(LLFloaterSnapshot *floater, const std::string& comboname);
747 static void checkAutoSnapshot(LLSnapshotLivePreview* floater);
748
749public:
750 std::vector<LLAnimPauseRequest> mAvatarPauseHandles;
751
752 LLToolset* mLastToolset;
753};
754
755// static
756LLViewHandle LLFloaterSnapshot::Impl::sPreviewHandle;
757
758// static
759LLSnapshotLivePreview* LLFloaterSnapshot::Impl::getPreviewView(LLFloaterSnapshot *floater)
760{
761 LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)LLView::getViewByHandle(sPreviewHandle);
762 return previewp;
763}
764
765// static
766LLSnapshotLivePreview::ESnapshotType LLFloaterSnapshot::Impl::getTypeIndex(LLFloaterSnapshot* floater)
767{
768 LLSnapshotLivePreview::ESnapshotType index = LLSnapshotLivePreview::SNAPSHOT_POSTCARD;
769 LLSD value = floater->childGetValue("snapshot_type_radio");
770 const std::string id = value.asString();
771 if (id == "postcard")
772 index = LLSnapshotLivePreview::SNAPSHOT_POSTCARD;
773 else if (id == "texture")
774 index = LLSnapshotLivePreview::SNAPSHOT_TEXTURE;
775 else if (id == "local")
776 index = LLSnapshotLivePreview::SNAPSHOT_BITMAP;
777 return index;
778}
779
780// static
781LLViewerWindow::ESnapshotType LLFloaterSnapshot::Impl::getLayerType(LLFloaterSnapshot* floater)
782{
783 LLViewerWindow::ESnapshotType type = LLViewerWindow::SNAPSHOT_TYPE_COLOR;
784 LLSD value = floater->childGetValue("layer_types");
785 const std::string id = value.asString();
786 if (id == "colors")
787 type = LLViewerWindow::SNAPSHOT_TYPE_COLOR;
788 else if (id == "depth")
789 type = LLViewerWindow::SNAPSHOT_TYPE_DEPTH;
790 else if (id == "objects")
791 type = LLViewerWindow::SNAPSHOT_TYPE_OBJECT_ID;
792 return type;
793}
794
795// static
796void LLFloaterSnapshot::Impl::setResolution(LLFloaterSnapshot* floater, const std::string& comboname)
797{
798 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(floater, comboname);
799 if (combo)
800 {
801 combo->setVisible(TRUE);
802 onCommitResolution(combo, floater);
803 }
804}
805
806//static
807void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp)
808{
809 LLSnapshotLivePreview* previewp = getPreviewView(floaterp);
810 if (floaterp->childGetValue("freeze_frame_check").asBoolean())
811 {
812 // stop all mouse events at fullscreen preview layer
813 floaterp->getParent()->setMouseOpaque(TRUE);
814
815 // shrink to smaller layout
816 floaterp->reshape(floaterp->mRect.getWidth(), 410);
817
818 // can see and interact with fullscreen preview now
819 if (previewp)
820 {
821 previewp->setVisible(TRUE);
822 previewp->setEnabled(TRUE);
823 }
824
825 //RN: freeze all avatars
826 LLCharacter* avatarp;
827 for (avatarp = LLCharacter::sInstances.getFirstData(); avatarp; avatarp = LLCharacter::sInstances.getNextData())
828 {
829 sInstance->impl.mAvatarPauseHandles.push_back(avatarp->requestPause());
830 }
831
832 // freeze everything else
833 gSavedSettings.setBOOL("FreezeTime", TRUE);
834
835 if (gCurrentToolset != gCameraToolset)
836 {
837 sInstance->impl.mLastToolset = gCurrentToolset;
838 gCurrentToolset = gCameraToolset;
839 if (gToolMgr)
840 {
841 gToolMgr->useSelectedTool( gCurrentToolset );
842 }
843 }
844 }
845 else // turning off freeze frame mode
846 {
847 floaterp->getParent()->setMouseOpaque(FALSE);
848 floaterp->reshape(floaterp->mRect.getWidth(), 510);
849 if (previewp)
850 {
851 previewp->setVisible(FALSE);
852 previewp->setEnabled(FALSE);
853 }
854
855 //RN: thaw all avatars
856 sInstance->impl.mAvatarPauseHandles.clear();
857
858 // thaw everything else
859 gSavedSettings.setBOOL("FreezeTime", FALSE);
860
861 // restore last tool (e.g. pie menu, etc)
862 if (sInstance->impl.mLastToolset)
863 {
864 gCurrentToolset = sInstance->impl.mLastToolset;
865 if (gToolMgr)
866 {
867 gToolMgr->useSelectedTool( gCurrentToolset );
868 }
869 }
870 }
871}
872
873
874// static
875void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater)
876{
877 LLRadioGroup* snapshot_type_radio = LLUICtrlFactory::getRadioGroupByName(floater, "snapshot_type_radio");
878 snapshot_type_radio->setSelectedIndex(gSavedSettings.getS32("LastSnapshotType"));
879 LLSnapshotLivePreview::ESnapshotType shot_type = getTypeIndex(floater);
880 LLViewerWindow::ESnapshotType layer_type = getLayerType(floater);
881
882 floater->childSetVisible("postcard_size_combo", FALSE);
883 floater->childSetVisible("texture_size_combo", FALSE);
884 floater->childSetVisible("local_size_combo", FALSE);
885
886 LLComboBox* combo;
887 combo = LLUICtrlFactory::getComboBoxByName(floater, "postcard_size_combo");
888 if (combo) combo->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastResolution"));
889 combo = LLUICtrlFactory::getComboBoxByName(floater, "texture_size_combo");
890 if (combo) combo->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastResolution"));
891 combo = LLUICtrlFactory::getComboBoxByName(floater, "local_size_combo");
892 if (combo) combo->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastResolution"));
893
894
895 floater->childSetVisible("upload_btn", FALSE);
896 floater->childSetVisible("send_btn", FALSE);
897 floater->childSetVisible("save_btn", FALSE);
898
899 switch(shot_type)
900 {
901 case LLSnapshotLivePreview::SNAPSHOT_POSTCARD:
902 layer_type = LLViewerWindow::SNAPSHOT_TYPE_COLOR;
903 floater->childSetValue("layer_types", "colors");
904 floater->childSetEnabled("layer_types", FALSE);
905 floater->childSetEnabled("image_quality_slider", TRUE);
906 setResolution(floater, "postcard_size_combo");
907 floater->childSetVisible("send_btn", TRUE);
908 break;
909 case LLSnapshotLivePreview::SNAPSHOT_TEXTURE:
910 layer_type = LLViewerWindow::SNAPSHOT_TYPE_COLOR;
911 floater->childSetValue("layer_types", "colors");
912 floater->childSetEnabled("layer_types", FALSE);
913 floater->childSetEnabled("image_quality_slider", FALSE);
914 setResolution(floater, "texture_size_combo");
915 floater->childSetVisible("upload_btn", TRUE);
916 break;
917 case LLSnapshotLivePreview::SNAPSHOT_BITMAP:
918 floater->childSetEnabled("layer_types", TRUE);
919 floater->childSetEnabled("image_quality_slider", FALSE);
920 setResolution(floater, "local_size_combo");
921 floater->childSetVisible("save_btn", TRUE);
922 break;
923 default:
924 break;
925 }
926 LLSnapshotLivePreview* previewp = getPreviewView(floater);
927 if (previewp)
928 {
929 previewp->setSnapshotType(shot_type);
930 previewp->setSnapshotBufferType(layer_type);
931 }
932}
933
934// static
935void LLFloaterSnapshot::Impl::checkAutoSnapshot(LLSnapshotLivePreview* previewp)
936{
937 if (previewp)
938 {
939 previewp->updateSnapshot(gSavedSettings.getBOOL("AutoSnapshot"));
940 }
941}
942
943// static
944void LLFloaterSnapshot::Impl::onClickDiscard(void* data)
945{
946 LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
947 if (view)
948 {
949 view->close();
950 }
951}
952
953// static
954void LLFloaterSnapshot::Impl::onClickKeep(void* data)
955{
956 LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
957 LLSnapshotLivePreview* previewp = getPreviewView(view);
958
959 if (previewp)
960 {
961 if (previewp->getSnapshotType() == LLSnapshotLivePreview::SNAPSHOT_POSTCARD)
962 {
963 LLFloaterPostcard* floater = previewp->savePostcard();
964 // if still in snapshot mode, put postcard floater in snapshot floaterview
965 // and link it to snapshot floater
966 if (!gSavedSettings.getBOOL("CloseSnapshotOnKeep"))
967 {
968 gFloaterView->removeChild(floater);
969 gSnapshotFloaterView->addChild(floater);
970 view->addDependentFloater(floater, FALSE);
971 }
972 }
973 else if (previewp->getSnapshotType() == LLSnapshotLivePreview::SNAPSHOT_TEXTURE)
974 {
975 previewp->saveTexture();
976 }
977 else
978 {
979 previewp->saveLocal();
980 }
981
982 if (gSavedSettings.getBOOL("CloseSnapshotOnKeep"))
983 {
984 view->close();
985 // only plays sound and anim when keeping a snapshot, and closing the snapshot UI
986 gViewerWindow->playSnapshotAnimAndSound();
987 }
988 else
989 {
990 checkAutoSnapshot(previewp);
991 }
992 }
993
994}
995
996// static
997void LLFloaterSnapshot::Impl::onClickNewSnapshot(void* data)
998{
999 LLSnapshotLivePreview* previewp = getPreviewView((LLFloaterSnapshot *)data);
1000 LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
1001 if (previewp && view)
1002 {
1003 previewp->updateSnapshot(TRUE);
1004 }
1005}
1006
1007// static
1008void LLFloaterSnapshot::Impl::onClickAutoSnap(LLUICtrl *ctrl, void* data)
1009{
1010 LLCheckBoxCtrl *check = (LLCheckBoxCtrl *)ctrl;
1011 gSavedSettings.setBOOL( "AutoSnapshot", check->get() );
1012
1013 LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
1014 if (view)
1015 {
1016 checkAutoSnapshot(getPreviewView(view));
1017 }
1018}
1019
1020// static
1021void LLFloaterSnapshot::Impl::onClickUICheck(LLUICtrl *ctrl, void* data)
1022{
1023 LLCheckBoxCtrl *check = (LLCheckBoxCtrl *)ctrl;
1024 gSavedSettings.setBOOL( "RenderUIInSnapshot", check->get() );
1025
1026 LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
1027 if (view)
1028 {
1029 checkAutoSnapshot(getPreviewView(view));
1030 }
1031}
1032
1033// static
1034void LLFloaterSnapshot::Impl::onClickHUDCheck(LLUICtrl *ctrl, void* data)
1035{
1036 LLCheckBoxCtrl *check = (LLCheckBoxCtrl *)ctrl;
1037 gSavedSettings.setBOOL( "RenderHUDInSnapshot", check->get() );
1038
1039 LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
1040 if (view)
1041 {
1042 checkAutoSnapshot(getPreviewView(view));
1043 }
1044}
1045
1046// static
1047void LLFloaterSnapshot::Impl::onClickKeepOpenCheck(LLUICtrl* ctrl, void* data)
1048{
1049 LLCheckBoxCtrl *check = (LLCheckBoxCtrl *)ctrl;
1050
1051 gSavedSettings.setBOOL( "CloseSnapshotOnKeep", !check->get() );
1052}
1053
1054// static
1055void LLFloaterSnapshot::Impl::onClickKeepAspectCheck(LLUICtrl* ctrl, void* data)
1056{
1057 LLCheckBoxCtrl *check = (LLCheckBoxCtrl *)ctrl;
1058 gSavedSettings.setBOOL( "KeepAspectForSnapshot", check->get() );
1059
1060 LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
1061 if (view)
1062 {
1063 checkAutoSnapshot(getPreviewView(view));
1064 }
1065}
1066
1067// static
1068void LLFloaterSnapshot::Impl::onCommitQuality(LLUICtrl* ctrl, void* data)
1069{
1070 LLSliderCtrl* slider = (LLSliderCtrl*)ctrl;
1071 S32 quality_val = llfloor((F32)slider->getValue().asReal());
1072
1073 LLSnapshotLivePreview* previewp = getPreviewView((LLFloaterSnapshot *)data);
1074 if (previewp)
1075 {
1076 previewp->setSnapshotQuality(quality_val);
1077 }
1078 checkAutoSnapshot(previewp);
1079}
1080
1081// static
1082void LLFloaterSnapshot::Impl::onCommitFreezeFrame(LLUICtrl* ctrl, void* data)
1083{
1084 LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl;
1085 LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
1086
1087 if (!view || !check_box)
1088 {
1089 return;
1090 }
1091
1092 gSavedSettings.setBOOL("UseFreezeFrame", check_box->get());
1093
1094 updateLayout(view);
1095}
1096
1097// static
1098void LLFloaterSnapshot::Impl::onCommitResolution(LLUICtrl* ctrl, void* data)
1099{
1100 LLComboBox* combobox = (LLComboBox*)ctrl;
1101 LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
1102
1103 if (!view || !combobox)
1104 {
1105 return;
1106 }
1107
1108 // save off all selected resolution values
1109 LLComboBox* combo;
1110 combo = LLUICtrlFactory::getComboBoxByName(view, "postcard_size_combo");
1111 gSavedSettings.setS32("SnapshotPostcardLastResolution", combo->getCurrentIndex());
1112 combo = LLUICtrlFactory::getComboBoxByName(view, "texture_size_combo");
1113 gSavedSettings.setS32("SnapshotTextureLastResolution", combo->getCurrentIndex());
1114 combo = LLUICtrlFactory::getComboBoxByName(view, "local_size_combo");
1115 gSavedSettings.setS32("SnapshotLocalLastResolution", combo->getCurrentIndex());
1116
1117 std::string sdstring = combobox->getSimpleSelectedValue();
1118 LLSD sdres;
1119 std::stringstream sstream(sdstring);
1120 LLSDSerialize::fromNotation(sdres, sstream);
1121
1122 S32 width = sdres[0];
1123 S32 height = sdres[1];
1124
1125 LLSnapshotLivePreview* previewp = getPreviewView(view);
1126 if (previewp && combobox->getCurrentIndex() >= 0)
1127 {
1128 if (width == 0 || height == 0)
1129 {
1130 previewp->setSize(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight());
1131 }
1132 else if (width == -1 || height == -1)
1133 {
1134 // leave width and height when entering custom value
1135 }
1136 else
1137 {
1138 previewp->setSize(width, height);
1139 }
1140
1141 previewp->getSize(width, height);
1142 view->childSetValue("snapshot_width", width);
1143 view->childSetValue("snapshot_height", height);
1144 // hide old preview as the aspect ratio could be wrong
1145 checkAutoSnapshot(previewp);
1146 }
1147}
1148
1149// static
1150void LLFloaterSnapshot::Impl::onCommitLayerTypes(LLUICtrl* ctrl, void*data)
1151{
1152 LLComboBox* combobox = (LLComboBox*)ctrl;
1153
1154 LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
1155
1156 if (view)
1157 {
1158 LLSnapshotLivePreview* previewp = getPreviewView(view);
1159 if (previewp)
1160 {
1161 previewp->setSnapshotBufferType((LLViewerWindow::ESnapshotType)combobox->getCurrentIndex());
1162 }
1163 checkAutoSnapshot(previewp);
1164 }
1165}
1166
1167//static
1168void LLFloaterSnapshot::Impl::onCommitSnapshotType(LLUICtrl* ctrl, void* data)
1169{
1170 LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
1171 if (view)
1172 {
1173 gSavedSettings.setS32("LastSnapshotType", getTypeIndex(view));
1174 getPreviewView(view)->updateSnapshot(TRUE);
1175 updateControls(view);
1176 }
1177}
1178
1179// static
1180void LLFloaterSnapshot::Impl::comboSetCustom(LLFloaterSnapshot* floater, const std::string& comboname)
1181{
1182 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(floater, comboname);
1183 if (combo)
1184 {
1185 combo->setCurrentByIndex(combo->getItemCount() - 1);
1186 }
1187}
1188
1189//static
1190void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* data)
1191{
1192 LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
1193 if (view)
1194 {
1195 LLSnapshotLivePreview* previewp = getPreviewView(view);
1196 if (previewp)
1197 {
1198 S32 curw,curh;
1199 previewp->getSize(curw, curh);
1200
1201 S32 w = llfloor((F32)view->childGetValue("snapshot_width").asReal());
1202 S32 h = llfloor((F32)view->childGetValue("snapshot_height").asReal());
1203
1204 if (w != curw || h != curh)
1205 {
1206 previewp->setSize(w,h);
1207 checkAutoSnapshot(previewp);
1208 comboSetCustom(view, "postcard_size_combo");
1209 comboSetCustom(view, "texture_size_combo");
1210 comboSetCustom(view, "local_size_combo");
1211 }
1212 }
1213 }
1214}
1215
1216///----------------------------------------------------------------------------
1217/// Class LLFloaterSnapshot
1218///----------------------------------------------------------------------------
1219
1220// Default constructor
1221LLFloaterSnapshot::LLFloaterSnapshot()
1222 : LLFloater("Snapshot Floater"),
1223 impl (*(new Impl))
1224{
1225}
1226
1227// Destroys the object
1228LLFloaterSnapshot::~LLFloaterSnapshot()
1229{
1230 if (sInstance == this)
1231 {
1232 delete LLView::getViewByHandle(Impl::sPreviewHandle);
1233 Impl::sPreviewHandle = LLViewHandle::sDeadHandle;
1234 sInstance = NULL;
1235 }
1236
1237 //unfreeze everything else
1238 gSavedSettings.setBOOL("FreezeTime", FALSE);
1239
1240 if (impl.mLastToolset)
1241 {
1242 gCurrentToolset = impl.mLastToolset;
1243 if (gToolMgr && gCurrentToolset)
1244 {
1245 gToolMgr->useSelectedTool( gCurrentToolset );
1246 }
1247 }
1248
1249 delete &impl;
1250}
1251
1252BOOL LLFloaterSnapshot::postBuild()
1253{
1254 childSetCommitCallback("snapshot_type_radio", Impl::onCommitSnapshotType, this);
1255
1256 childSetAction("new_snapshot_btn", Impl::onClickNewSnapshot, this);
1257
1258 childSetValue("auto_snapshot_check", gSavedSettings.getBOOL("AutoSnapshot"));
1259 childSetCommitCallback("auto_snapshot_check", Impl::onClickAutoSnap, this);
1260
1261 childSetAction("upload_btn", Impl::onClickKeep, this);
1262 childSetAction("send_btn", Impl::onClickKeep, this);
1263 childSetAction("save_btn", Impl::onClickKeep, this);
1264 childSetAction("discard_btn", Impl::onClickDiscard, this);
1265
1266 childSetCommitCallback("image_quality_slider", Impl::onCommitQuality, this);
1267 childSetValue("image_quality_slider", gSavedSettings.getS32("SnapshotQuality"));
1268
1269 childSetCommitCallback("snapshot_width", Impl::onCommitCustomResolution, this);
1270
1271 childSetCommitCallback("snapshot_height", Impl::onCommitCustomResolution, this);
1272
1273 childSetCommitCallback("ui_check", Impl::onClickUICheck, this);
1274
1275 childSetCommitCallback("hud_check", Impl::onClickHUDCheck, this);
1276 childSetValue("hud_check", gSavedSettings.getBOOL("RenderHUDInSnapshot"));
1277
1278 childSetCommitCallback("keep_open_check", Impl::onClickKeepOpenCheck, this);
1279 childSetValue("keep_open_check", !gSavedSettings.getBOOL("CloseSnapshotOnKeep"));
1280
1281 childSetCommitCallback("keep_aspect_check", Impl::onClickKeepAspectCheck, this);
1282 childSetValue("keep_aspect_check", gSavedSettings.getBOOL("KeepAspectForSnapshot"));
1283
1284 childSetCommitCallback("layer_types", Impl::onCommitLayerTypes, this);
1285 childSetValue("layer_types", "colors");
1286 childSetEnabled("layer_types", FALSE);
1287
1288 childSetValue("snapshot_width", gViewerWindow->getWindowDisplayWidth());
1289 childSetValue("snapshot_height", gViewerWindow->getWindowDisplayHeight());
1290
1291 childSetValue("freeze_frame_check", gSavedSettings.getBOOL("UseFreezeFrame"));
1292 childSetCommitCallback("freeze_frame_check", Impl::onCommitFreezeFrame, this);
1293
1294 childSetCommitCallback("postcard_size_combo", Impl::onCommitResolution, this);
1295 childSetCommitCallback("texture_size_combo", Impl::onCommitResolution, this);
1296 childSetCommitCallback("local_size_combo", Impl::onCommitResolution, this);
1297
1298 // create preview window
1299 LLRect full_screen_rect = sInstance->getRootView()->getRect();
1300 LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(full_screen_rect);
1301 sInstance->getRootView()->removeChild(gSnapshotFloaterView);
1302 // make sure preview is below snapshot floater
1303 sInstance->getRootView()->addChild(previewp);
1304 sInstance->getRootView()->addChild(gSnapshotFloaterView);
1305
1306 Impl::sPreviewHandle = previewp->mViewHandle;
1307
1308 impl.updateControls(this);
1309
1310 return TRUE;
1311}
1312
1313void LLFloaterSnapshot::draw()
1314{
1315 LLSnapshotLivePreview* previewp = impl.getPreviewView(this);
1316
1317 if (previewp && previewp->isSnapshotActive())
1318 {
1319 // don't render snapshot window in snapshot, even if "show ui" is turned on
1320 return;
1321 }
1322
1323 if(getVisible() && !mMinimized)
1324 {
1325 if (previewp && previewp->getDataSize() > 0)
1326 {
1327 LLLocale locale(LLLocale::USER_LOCALE);
1328
1329 LLString bytes_string;
1330 if (previewp->getSnapshotType() == LLSnapshotLivePreview::SNAPSHOT_POSTCARD &&
1331 previewp->getDataSize() > MAX_POSTCARD_DATASIZE)
1332 {
1333 childSetColor("file_size_label", LLColor4::red);
1334 childSetEnabled("send_btn", FALSE);
1335 }
1336 else
1337 {
1338 childSetColor("file_size_label", gColors.getColor( "LabelTextColor" ));
1339 childSetEnabled("send_btn", previewp->getSnapshotUpToDate());
1340 }
1341
1342 //XUI:translate
1343 if (previewp->getSnapshotUpToDate())
1344 {
1345 LLString bytes_string;
1346 gResMgr->getIntegerString(bytes_string, previewp->getDataSize());
1347 childSetTextArg("file_size_label", "[SIZE]", llformat("%s bytes", bytes_string.c_str()));
1348 }
1349 else
1350 {
1351 childSetTextArg("file_size_label", "[SIZE]", "unknown");
1352 childSetColor("file_size_label", gColors.getColor( "LabelTextColor" ));
1353 }
1354 childSetEnabled("upload_btn", previewp->getSnapshotUpToDate());
1355 childSetEnabled("save_btn", previewp->getSnapshotUpToDate());
1356
1357 }
1358 else
1359 {
1360 childSetTextArg("file_size_label", "[SIZE]", "unknown");
1361 childSetEnabled("upload_btn", FALSE);
1362 childSetEnabled("send_btn", FALSE);
1363 childSetEnabled("save_btn", FALSE);
1364 }
1365
1366 BOOL ui_in_snapshot = gSavedSettings.getBOOL("RenderUIInSnapshot");
1367 childSetValue("ui_check", ui_in_snapshot);
1368 childSetToolTip("ui_check", "If selected shows the UI in the snapshot");
1369 }
1370
1371 LLFloater::draw();
1372
1373 // draw snapshot thumbnail if not in fullscreen preview mode
1374 if (!gSavedSettings.getBOOL("UseFreezeFrame") && previewp && previewp->getCurrentImage() && previewp->getSnapshotUpToDate())
1375 {
1376 F32 aspect = previewp->getImageAspect();
1377 // UI size for thumbnail
1378 S32 max_width = mRect.getWidth() - 20;
1379 S32 max_height = 90;
1380
1381 S32 img_render_width = 0;
1382 S32 img_render_height = 0;
1383 if (aspect > max_width / max_height)
1384 {
1385 // image too wide, shrink to width
1386 img_render_width = max_width;
1387 img_render_height = llround((F32)max_width / aspect);
1388 }
1389 else
1390 {
1391 // image too tall, shrink to height
1392 img_render_height = max_height;
1393 img_render_width = llround((F32)max_height * aspect);
1394 }
1395 S32 image_width, image_height;
1396 previewp->getSize(image_width, image_height);
1397 glMatrixMode(GL_TEXTURE);
1398 glPushMatrix();
1399 {
1400 // handle case where image is only a portion of image buffer
1401 if (!previewp->isImageScaled())
1402 {
1403 glScalef(llmin(1.f, (F32)image_width / (F32)previewp->getCurrentImage()->getWidth()), llmin(1.f, (F32)image_height / (F32)previewp->getCurrentImage()->getHeight()), 1.f);
1404 }
1405 glMatrixMode(GL_MODELVIEW);
1406 gl_draw_scaled_image((mRect.getWidth() - img_render_width) / 2, 35 + (max_height - img_render_height) / 2, img_render_width, img_render_height, previewp->getCurrentImage(), LLColor4::white);
1407 }
1408 glMatrixMode(GL_TEXTURE);
1409 glPopMatrix();
1410 glMatrixMode(GL_MODELVIEW);
1411 }
1412}
1413
1414void LLFloaterSnapshot::onClose(bool app_quitting)
1415{
1416 gSnapshotFloaterView->setEnabled(FALSE);
1417 destroy();
1418}
1419
1420// static
1421void LLFloaterSnapshot::show(void*)
1422{
1423 if (!sInstance)
1424 {
1425 sInstance = new LLFloaterSnapshot();
1426
1427 gUICtrlFactory->buildFloater(sInstance, "floater_snapshot.xml", NULL, FALSE);
1428 //move snapshot floater to special purpose snapshotfloaterview
1429 gFloaterView->removeChild(sInstance);
1430 gSnapshotFloaterView->addChild(sInstance);
1431
1432 sInstance->impl.updateLayout(sInstance);
1433 }
1434
1435 sInstance->open();
1436 sInstance->focusFirstItem(FALSE);
1437 gSnapshotFloaterView->setEnabled(TRUE);
1438 gSnapshotFloaterView->adjustToFitScreen(sInstance, FALSE);
1439}
1440
1441void LLFloaterSnapshot::hide(void*)
1442{
1443 if (sInstance && !sInstance->isDead())
1444 {
1445 sInstance->close();
1446 }
1447}
1448
1449//static
1450void LLFloaterSnapshot::update()
1451{
1452 for (std::set<LLSnapshotLivePreview*>::iterator iter = LLSnapshotLivePreview::sList.begin();
1453 iter != LLSnapshotLivePreview::sList.end(); ++iter)
1454 {
1455 LLSnapshotLivePreview::onIdle(*iter);
1456 }
1457}
1458
1459//============================================================================
1460
1461LLSnapshotFloaterView::LLSnapshotFloaterView( const LLString& name, const LLRect& rect ) : LLFloaterView(name, rect)
1462{
1463 setMouseOpaque(TRUE);
1464 setEnabled(FALSE);
1465}
1466
1467LLSnapshotFloaterView::~LLSnapshotFloaterView()
1468{
1469}
1470
1471BOOL LLSnapshotFloaterView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
1472{
1473 // use default handler when not in freeze-frame mode
1474 if(!gSavedSettings.getBOOL("FreezeTime"))
1475 {
1476 return LLFloaterView::handleKey(key, mask, called_from_parent);
1477 }
1478
1479 if (!getEnabled())
1480 {
1481 return FALSE;
1482 }
1483 else
1484 {
1485 if (called_from_parent)
1486 {
1487 // pass all keystrokes down
1488 LLFloaterView::handleKey(key, mask, called_from_parent);
1489 }
1490 else
1491 {
1492 // bounce keystrokes back down
1493 LLFloaterView::handleKey(key, mask, TRUE);
1494 }
1495 return TRUE;
1496 }
1497}
1498
1499BOOL LLSnapshotFloaterView::handleMouseDown(S32 x, S32 y, MASK mask)
1500{
1501 // use default handler when not in freeze-frame mode
1502 if(!gSavedSettings.getBOOL("FreezeTime"))
1503 {
1504 return LLFloaterView::handleMouseDown(x, y, mask);
1505 }
1506 // give floater a change to handle mouse, else camera tool
1507 if (childrenHandleMouseDown(x, y, mask) == NULL)
1508 {
1509 gToolMgr->getCurrentTool(mask)->handleMouseDown( x, y, mask );
1510 }
1511 return TRUE;
1512}
1513
1514BOOL LLSnapshotFloaterView::handleMouseUp(S32 x, S32 y, MASK mask)
1515{
1516 // use default handler when not in freeze-frame mode
1517 if(!gSavedSettings.getBOOL("FreezeTime"))
1518 {
1519 return LLFloaterView::handleMouseUp(x, y, mask);
1520 }
1521 // give floater a change to handle mouse, else camera tool
1522 if (childrenHandleMouseUp(x, y, mask) == NULL)
1523 {
1524 gToolMgr->getCurrentTool(mask)->handleMouseUp( x, y, mask );
1525 }
1526 return TRUE;
1527}
1528
1529BOOL LLSnapshotFloaterView::handleHover(S32 x, S32 y, MASK mask)
1530{
1531 // use default handler when not in freeze-frame mode
1532 if(!gSavedSettings.getBOOL("FreezeTime"))
1533 {
1534 return LLFloaterView::handleHover(x, y, mask);
1535 }
1536 // give floater a change to handle mouse, else camera tool
1537 if (childrenHandleHover(x, y, mask) == NULL)
1538 {
1539 gToolMgr->getCurrentTool(mask)->handleHover( x, y, mask );
1540 }
1541 return TRUE;
1542}