From ed386ae547c225e352c39e8d14921572ee534b0b Mon Sep 17 00:00:00 2001 From: James Cook Date: Fri, 18 Jul 2008 17:50:25 +0000 Subject: merge support-featurettes-snapshot-merge-2 for QAR-754, includes: * featurettes-4 89061:89589 (which is all of featurettes-1, -2, and -3, and part of -4) * gteam-showstoppers-3 91950:91951 (which is all of gteam-showstoppers-1, -2, and -3) * featurettes-5 92149:92150 (patch for last line of chat text not visible in chat history, DEV-17771) * snapshot-3 91988:91991 (which is all of snapshot-1, -2, and -3) Merging revisions 92190-92387 of svn+ssh://svn.lindenlab.com/svn/linden/branches/support-featurettes-snapshot-merge-2 into release, respecting ancestry * QAR-590 Merge Lock Request for Support Sprint * QAR-627 Merge snapshot improvements * QAR-686 Merge Lock request for Featurettes --- indra/newview/app_settings/settings.xml | 132 ++++--- indra/newview/linux_tools/wrapper.sh | 11 + indra/newview/llagent.cpp | 27 +- indra/newview/lldebugview.cpp | 2 +- indra/newview/llfilepicker.cpp | 31 +- indra/newview/llfilepicker.h | 2 + indra/newview/llfloaterland.cpp | 18 +- indra/newview/llfloaterregioninfo.cpp | 75 ++-- indra/newview/llfloaterregioninfo.h | 6 +- indra/newview/llfloatersnapshot.cpp | 557 ++++++++++++++++------------- indra/newview/llfloatersnapshot.h | 15 +- indra/newview/llfloatertools.cpp | 23 ++ indra/newview/llfloatertools.h | 2 + indra/newview/llfloatertopobjects.cpp | 15 +- indra/newview/llimpanel.cpp | 3 +- indra/newview/llstartup.cpp | 275 +++++++------- indra/newview/llstartup.h | 12 +- indra/newview/lltexturectrl.cpp | 6 +- indra/newview/lltoolbrush.cpp | 12 +- indra/newview/llviewermedia.cpp | 43 ++- indra/newview/llviewermedia.h | 9 + indra/newview/llviewermenufile.cpp | 22 +- indra/newview/llviewermessage.cpp | 11 +- indra/newview/llviewerprecompiledheaders.h | 1 + indra/newview/llviewerwindow.cpp | 78 ++-- indra/newview/llviewerwindow.h | 14 +- 26 files changed, 824 insertions(+), 578 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e185d96c98..0269e25658 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1079,16 +1079,16 @@ 0.5 ChatFontSize - - Comment - Size of chat text in chat console (0 = small, 1 = big) - Persist - 1 - Type - S32 - Value - 1 - + + Comment + Size of chat text in chat console (0 = small, 1 = medium, 2 = big) + Persist + 1 + Type + S32 + Value + 1 + ChatFullWidth Comment @@ -1123,16 +1123,16 @@ 1 ChatPersistTime - - Comment - Time for which chat stays visible in console (seconds) - Persist - 1 - Type - F32 - Value - 15.0 - + + Comment + Time for which chat stays visible in console (seconds) + Persist + 1 + Type + F32 + Value + 20 + ChatShowTimestamps Comment @@ -1856,16 +1856,16 @@ 0 ConsoleBackgroundOpacity - - Comment - Opacity of chat console (0.0 = completely transparent, 1.0 = completely opaque) - Persist - 1 - Type - F32 - Value - 0.40000000596 - + + Comment + Opacity of chat console (0.0 = completely transparent, 1.0 = completely opaque) + Persist + 1 + Type + F32 + Value + 0.700 + ConsoleBufferSize Comment @@ -5046,21 +5046,21 @@ 0 ObjectChatColor - - Comment - Color of chat messages from objects - Persist - 1 - Type - Color4 - Value - - 0.699999988079 - 0.899999976158 - 0.699999988079 - 1.0 - - + + Comment + Color of chat messages from objects + Persist + 1 + Type + Color4 + Value + + 1 + 0.5 + 0.0 + 1 + + OpenDebugStatAdvanced Comment @@ -5599,6 +5599,17 @@ Value 0 + LandBrushForce + + Comment + Multiplier for land modification brush force. + Persist + 1 + Type + F32 + Value + 1.0 + RecentItemsSortOrder Comment @@ -6999,16 +7010,16 @@ 1 ShowObjectUpdates - - Comment - Show when update messages are received for individual objects - Persist - 1 - Type - Boolean - Value - 0 - + + Comment + Show when update messages are received for individual objects + Persist + 0 + Type + Boolean + Value + 0 + ShowOverlayTitle Comment @@ -7346,6 +7357,17 @@ Value 0 + SnapshotFormat + + Comment + Save snapshots in this format (0 = PNG, 1 = JPEG, 2 = BMP) + Persist + 1 + Type + S32 + Value + 0 + SnapshotPostcardLastResolution Comment diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index eaa2f61dce..9d2e06b31e 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -33,6 +33,11 @@ ## LL_GL_BLACKLIST which solves your problems. #export LL_GL_BLACKLIST=abcdefghijklmno +## - Some ATI/Radeon users report random X server crashes when the mouse +## cursor changes shape. If you suspect that you are a victim of this +## driver bug, try enabling this option and report whether it helps: +#export LL_ATI_MOUSE_CURSOR_BUG=x + ## Everything below this line is just for advanced troubleshooters. ##------------------------------------------------------------------- @@ -56,6 +61,12 @@ if [ "$GTK_IM_MODULE" = "scim" ]; then export GTK_IM_MODULE=xim fi +## - Automatically work around the ATI mouse cursor crash bug: +## (this workaround is disabled as most fglrx users do not see the bug) +#if lsmod | grep fglrx &>/dev/null ; then +# export LL_ATI_MOUSE_CURSOR_BUG=x +#fi + ## Nothing worth editing below this line. ##------------------------------------------------------------------- diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index e926e97f76..7fb9e57507 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -6438,20 +6438,9 @@ void LLAgent::processAgentInitialWearablesUpdate( LLMessageSystem* mesgsys, void { // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates // that may result from AgentWearablesRequest having been sent more than once. - static BOOL first = TRUE; - if( first ) - { - first = FALSE; - } - else - { - return; - } - - if (gNoRender) - { - return; - } + static bool first = true; + if (!first) return; + first = false; LLUUID agent_id; gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); @@ -6467,16 +6456,6 @@ void LLAgent::processAgentInitialWearablesUpdate( LLMessageSystem* mesgsys, void // Transitional state. Avatars should always have at least their body parts (hair, eyes, shape and skin). // The fact that they don't have any here (only a dummy is sent) implies that this account existed // before we had wearables, or that the database has gotten messed up. - // Deal with this by creating new body parts. - //avatar->createStandardWearables(); - - // no, deal with it by noting that we need to choose a - // gender, but only if an initial outfit load isn't happening. - // This whole check (num_wearables < 4) can probably be deleted. JC - if (gInitialOutfit.empty()) - { - gAgent.setGenderChosen(FALSE); - } return; } diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp index dc160a29ac..ebd708736e 100644 --- a/indra/newview/lldebugview.cpp +++ b/indra/newview/lldebugview.cpp @@ -60,7 +60,7 @@ LLDebugView::LLDebugView(const std::string& name, const LLRect &rect) { LLRect r; - r.set(0, rect.getHeight() - 100, rect.getWidth()/2, 100); + r.set(10, rect.getHeight() - 100, rect.getWidth()/2, 100); mDebugConsolep = new LLConsole("debug console", 20, r, -1, 0.f ); mDebugConsolep->setFollowsBottom(); mDebugConsolep->setFollowsLeft(); diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 344917150f..0f180472fd 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -357,6 +357,26 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename) L"Bitmap Images (*.bmp)\0*.bmp\0" \ L"\0"; break; + case FFSAVE_PNG: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.png", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"png"; + mOFN.lpstrFilter = + L"PNG Images (*.png)\0*.png\0" \ + L"\0"; + break; + case FFSAVE_JPEG: + if (filename.empty()) + { + wcsncpy( mFilesW,L"untitled.jpeg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/ + } + mOFN.lpstrDefExt = L"jpeg"; + mOFN.lpstrFilter = + L"JPEG Images (*.jpeg)\0*.jpeg\0" \ + L"\0"; + break; case FFSAVE_AVI: if (filename.empty()) { @@ -642,7 +662,16 @@ OSStatus LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& fi creator = 'prvw'; extension = CFSTR(".bmp"); break; - + case FFSAVE_JPEG: + type = 'JPEG'; + creator = 'prvw'; + extension = CFSTR(".jpeg"); + break; + case FFSAVE_PNG: + type = 'PNG '; + creator = 'prvw'; + extension = CFSTR(".png"); + break; case FFSAVE_AVI: type = '\?\?\?\?'; creator = '\?\?\?\?'; diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 012524a541..83a9357523 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -107,6 +107,8 @@ public: FFSAVE_COLLADA = 10, FFSAVE_RAW = 11, FFSAVE_J2C = 12, + FFSAVE_PNG = 13, + FFSAVE_JPEG = 14, }; // open the dialog. This is a modal operation diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 58ad07c5bb..5dfbee73a4 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -434,7 +434,7 @@ void LLPanelLandGeneral::refresh() mEditName->setText(LLStringUtil::null); mEditDesc->setEnabled(FALSE); - mEditDesc->setText(LLStringUtil::null); + mEditDesc->setText(getString("no_selection_text")); mTextSalePending->setText(LLStringUtil::null); mTextSalePending->setEnabled(FALSE); @@ -1430,6 +1430,7 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo LLUUID owner_id; BOOL is_group_owned; S32 object_count; + U32 most_recent_time = 0; BOOL is_online; std::string object_count_str; //BOOL b_need_refresh = FALSE; @@ -1447,7 +1448,10 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo msg->getBOOLFast(_PREHASH_Data, _PREHASH_IsGroupOwned, is_group_owned, i); msg->getS32Fast (_PREHASH_Data, _PREHASH_Count, object_count, i); msg->getBOOLFast(_PREHASH_Data, _PREHASH_OnlineStatus, is_online, i); - + if(msg->getNumberOfBlocks("DataExtended")) + { + msg->getU32("DataExtended", "TimeStamp", most_recent_time, i); + } if (owner_id.isNull()) { continue; @@ -1474,6 +1478,9 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo object_count_str = llformat("%d", object_count); row->addColumn(object_count_str, FONT); + + row->addColumn(formatted_time((time_t)most_recent_time), FONT); + if (is_group_owned) { @@ -2165,7 +2172,6 @@ LLPanelLandAccess::LLPanelLandAccess(LLParcelSelectionHandle& parcel) } - BOOL LLPanelLandAccess::postBuild() { childSetCommitCallback("public_access", onCommitPublicAccess, this); @@ -2427,12 +2433,14 @@ void LLPanelLandAccess::refresh_ui() childSetEnabled("AccessList", can_manage_allowed); S32 allowed_list_count = parcel->mAccessList.size(); childSetEnabled("add_allowed", can_manage_allowed && allowed_list_count < PARCEL_MAX_ACCESS_LIST); - childSetEnabled("remove_allowed", can_manage_allowed && allowed_list_count > 0); + BOOL has_selected = mListAccess->getSelectionInterface()->getFirstSelectedIndex() >= 0; + childSetEnabled("remove_allowed", can_manage_allowed && has_selected); childSetEnabled("BannedList", can_manage_banned); S32 banned_list_count = parcel->mBanList.size(); childSetEnabled("add_banned", can_manage_banned && banned_list_count < PARCEL_MAX_ACCESS_LIST); - childSetEnabled("remove_banned", can_manage_banned && banned_list_count > 0); + has_selected = mListBanned->getSelectionInterface()->getFirstSelectedIndex() >= 0; + childSetEnabled("remove_banned", can_manage_banned && has_selected); } } diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index fc3c0952cb..3b2fb43f61 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -816,8 +816,7 @@ BOOL LLPanelRegionDebugInfo::postBuild() initHelpBtn("restart_help", "HelpRegionRestart"); childSetAction("choose_avatar_btn", onClickChooseAvatar, this); - childSetAction("return_scripted_other_land_btn", onClickReturnScriptedOtherLand, this); - childSetAction("return_scripted_all_btn", onClickReturnScriptedAll, this); + childSetAction("return_btn", onClickReturn, this); childSetAction("top_colliders_btn", onClickTopColliders, this); childSetAction("top_scripts_btn", onClickTopScripts, this); childSetAction("restart_btn", onClickRestart, this); @@ -832,10 +831,13 @@ bool LLPanelRegionDebugInfo::refreshFromRegion(LLViewerRegion* region) BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); setCtrlsEnabled(allow_modify); childDisable("apply_btn"); - + childDisable("target_avatar_name"); + childSetEnabled("choose_avatar_btn", allow_modify); - childSetEnabled("return_scripted_other_land_btn", allow_modify && !mTargetAvatar.isNull()); - childSetEnabled("return_scripted_all_btn", allow_modify && !mTargetAvatar.isNull()); + childSetEnabled("return_scripts", allow_modify && !mTargetAvatar.isNull()); + childSetEnabled("return_other_land", allow_modify && !mTargetAvatar.isNull()); + childSetEnabled("return_estate_wide", allow_modify && !mTargetAvatar.isNull()); + childSetEnabled("return_btn", allow_modify && !mTargetAvatar.isNull()); childSetEnabled("top_colliders_btn", allow_modify); childSetEnabled("top_scripts_btn", allow_modify); childSetEnabled("restart_btn", allow_modify); @@ -881,61 +883,56 @@ void LLPanelRegionDebugInfo::callbackAvatarID(const std::vector& na } // static -void LLPanelRegionDebugInfo::onClickReturnScriptedOtherLand(void* data) +void LLPanelRegionDebugInfo::onClickReturn(void* data) { LLPanelRegionDebugInfo* panelp = (LLPanelRegionDebugInfo*) data; if (panelp->mTargetAvatar.isNull()) return; LLStringUtil::format_map_t args; args["[USER_NAME]"] = panelp->childGetValue("target_avatar_name").asString(); - gViewerWindow->alertXml("ReturnScriptedOnOthersLand", args, callbackReturnScriptedOtherLand, data); + gViewerWindow->alertXml("EstateObjectReturn", args, callbackReturn, data); } // static -void LLPanelRegionDebugInfo::callbackReturnScriptedOtherLand( S32 option, void* userdata ) +void LLPanelRegionDebugInfo::callbackReturn( S32 option, void* userdata ) { if (option != 0) return; LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*) userdata; if (!self->mTargetAvatar.isNull()) { - U32 flags = 0; - flags = flags | SWD_OTHERS_LAND_ONLY; - flags = flags | SWD_ALWAYS_RETURN_OBJECTS; - flags |= SWD_SCRIPTED_ONLY; - - send_sim_wide_deletes(self->mTargetAvatar, flags); - } -} + U32 flags = SWD_ALWAYS_RETURN_OBJECTS; -// static -void LLPanelRegionDebugInfo::onClickReturnScriptedAll(void* data) -{ - LLPanelRegionDebugInfo* panelp = (LLPanelRegionDebugInfo*) data; - if (panelp->mTargetAvatar.isNull()) return; - - - LLStringUtil::format_map_t args; - args["[USER_NAME]"] = panelp->childGetValue("target_avatar_name").asString(); - gViewerWindow->alertXml("ReturnScriptedOnAllLand", args, callbackReturnScriptedAll, data); -} - -// static -void LLPanelRegionDebugInfo::callbackReturnScriptedAll( S32 option, void* userdata ) -{ - if (option != 0) return; + if (self->childGetValue("return_scripts").asBoolean()) + { + flags |= SWD_SCRIPTED_ONLY; + } + + if (self->childGetValue("return_other_land").asBoolean()) + { + flags |= SWD_OTHERS_LAND_ONLY; + } - LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*) userdata; - if (!self->mTargetAvatar.isNull()) - { - U32 flags = 0; - flags |= SWD_ALWAYS_RETURN_OBJECTS; - flags |= SWD_SCRIPTED_ONLY; + if (self->childGetValue("return_estate_wide").asBoolean()) + { + // send as estate message - routed by spaceserver to all regions in estate + strings_t strings; + strings.push_back(llformat("%d", flags)); + strings.push_back(self->mTargetAvatar.asString()); - send_sim_wide_deletes(self->mTargetAvatar, flags); + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + + self->sendEstateOwnerMessage(gMessageSystem, "estateobjectreturn", invoice, strings); + } + else + { + // send to this simulator only + send_sim_wide_deletes(self->mTargetAvatar, flags); + } } } + // static void LLPanelRegionDebugInfo::onClickTopColliders(void* data) { diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index 7d05ffa5bc..8bcab111b5 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -186,10 +186,8 @@ protected: static void onClickChooseAvatar(void*); static void callbackAvatarID(const std::vector& names, const std::vector& ids, void* data); - static void onClickReturnScriptedOtherLand(void*); - static void callbackReturnScriptedOtherLand(S32 option, void*); - static void onClickReturnScriptedAll(void*); - static void callbackReturnScriptedAll(S32 option, void*); + static void onClickReturn(void *); + static void callbackReturn(S32 option, void*); static void onClickTopColliders(void*); static void onClickTopScripts(void*); static void onClickRestart(void* data); diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 1f601e6dc1..811fc4eb03 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -68,6 +68,8 @@ #include "llgl.h" #include "llglheaders.h" #include "llimagejpeg.h" +#include "llimagepng.h" +#include "llimagebmp.h" #include "llimagej2c.h" #include "llvfile.h" #include "llvfs.h" @@ -83,7 +85,7 @@ LLSnapshotFloaterView* gSnapshotFloaterView = NULL; LLFloaterSnapshot* LLFloaterSnapshot::sInstance = NULL; -const F32 SNAPSHOT_TIME_DELAY = 1.f; +const F32 AUTO_SNAPSHOT_TIME_DELAY = 1.f; F32 SHINE_TIME = 0.5f; F32 SHINE_WIDTH = 0.6f; @@ -93,6 +95,7 @@ S32 BORDER_WIDTH = 6; const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512 + ///---------------------------------------------------------------------------- /// Class LLSnapshotLivePreview ///---------------------------------------------------------------------------- @@ -103,9 +106,10 @@ public: { SNAPSHOT_POSTCARD, SNAPSHOT_TEXTURE, - SNAPSHOT_BITMAP + SNAPSHOT_LOCAL }; + LLSnapshotLivePreview(const LLRect& rect); ~LLSnapshotLivePreview(); @@ -119,6 +123,7 @@ public: S32 getMaxImageSize() {return mMaxImageSize ;} ESnapshotType getSnapshotType() const { return mSnapshotType; } + LLFloaterSnapshot::ESnapshotFormat getSnapshotFormat() const { return mSnapshotFormat; } BOOL getSnapshotUpToDate() const { return mSnapshotUpToDate; } BOOL isSnapshotActive() { return mSnapshotActive; } LLImageGL* getThumbnailImage() const { return mThumbnailImage ; } @@ -133,9 +138,10 @@ public: BOOL isImageScaled(); void setSnapshotType(ESnapshotType type) { mSnapshotType = type; } + void setSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat type) { mSnapshotFormat = type; } void setSnapshotQuality(S32 quality); void setSnapshotBufferType(LLViewerWindow::ESnapshotType type) { mSnapshotBufferType = type; } - void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE); + void updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail = FALSE, F32 delay = 0.f); LLFloaterPostcard* savePostcard(); void saveTexture(); BOOL saveLocal(); @@ -147,7 +153,7 @@ public: static void onIdle( void* snapshot_preview ); -protected: +private: LLColor4 mColor; LLPointer mViewerImage[2]; LLRect mImageRect[2]; @@ -165,9 +171,9 @@ protected: BOOL mThumbnailUpToDate ; S32 mCurImageIndex; - LLPointer mRawImage; - LLPointer mRawImageEncoded; - LLPointer mJPEGImage; + LLPointer mPreviewImage; + LLPointer mPreviewImageEncoded; + LLPointer mFormattedImage; LLFrameTimer mSnapshotDelayTimer; S32 mShineCountdown; LLFrameTimer mShineAnimTimer; @@ -177,6 +183,7 @@ protected: S32 mSnapshotQuality; S32 mDataSize; ESnapshotType mSnapshotType; + LLFloaterSnapshot::ESnapshotFormat mSnapshotFormat; BOOL mSnapshotUpToDate; LLFrameTimer mFallAnimTimer; LLVector3 mCameraPos; @@ -195,16 +202,17 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLRect& rect) : LLView(std::string("snapshot_live_preview"), rect, FALSE), mColor(1.f, 0.f, 0.f, 0.5f), mCurImageIndex(0), - mRawImage(NULL), + mPreviewImage(NULL), mThumbnailImage(NULL) , - mRawImageEncoded(NULL), - mJPEGImage(NULL), + mPreviewImageEncoded(NULL), + mFormattedImage(NULL), mShineCountdown(0), mFlashAlpha(0.f), mNeedsFlash(TRUE), mSnapshotQuality(gSavedSettings.getS32("SnapshotQuality")), mDataSize(0), mSnapshotType(SNAPSHOT_POSTCARD), + mSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat"))), mSnapshotUpToDate(FALSE), mCameraPos(LLViewerCamera::getInstance()->getOrigin()), mCameraRot(LLViewerCamera::getInstance()->getQuaternion()), @@ -212,6 +220,7 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLRect& rect) : mSnapshotBufferType(LLViewerWindow::SNAPSHOT_TYPE_COLOR), mSnapshotSoundPlayed(false) { + setSnapshotQuality(gSavedSettings.getS32("SnapshotQuality")); mSnapshotDelayTimer.setTimerExpirySec(0.0f); mSnapshotDelayTimer.start(); // gIdleCallbacks.addFunction( &LLSnapshotLivePreview::onIdle, (void*)this ); @@ -233,9 +242,9 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLRect& rect) : LLSnapshotLivePreview::~LLSnapshotLivePreview() { // delete images - mRawImage = NULL; - mRawImageEncoded = NULL; - mJPEGImage = NULL; + mPreviewImage = NULL; + mPreviewImageEncoded = NULL; + mFormattedImage = NULL; // gIdleCallbacks.deleteFunction( &LLSnapshotLivePreview::onIdle, (void*)this ); sList.erase(this); @@ -293,7 +302,7 @@ BOOL LLSnapshotLivePreview::isImageScaled() return mImageScaled[mCurImageIndex]; } -void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail) +void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail, F32 delay) { if (mSnapshotUpToDate) { @@ -333,7 +342,7 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail if (new_snapshot) { mSnapshotDelayTimer.start(); - mSnapshotDelayTimer.setTimerExpirySec(SNAPSHOT_TIME_DELAY); + mSnapshotDelayTimer.setTimerExpirySec(delay); } else if(new_thumbnail) { @@ -347,6 +356,7 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail void LLSnapshotLivePreview::setSnapshotQuality(S32 quality) { + llclamp(quality, 0, 100); if (quality != mSnapshotQuality) { mSnapshotQuality = quality; @@ -396,7 +406,7 @@ void LLSnapshotLivePreview::drawPreviewRect(S32 offset_x, S32 offset_y) void LLSnapshotLivePreview::draw() { if (mViewerImage[mCurImageIndex].notNull() && - mRawImageEncoded.notNull() && + mPreviewImageEncoded.notNull() && mSnapshotUpToDate) { LLColor4 bg_color(0.f, 0.f, 0.3f, 0.4f); @@ -685,8 +695,8 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update) LLPointer raw = NULL ; S32 w , h ; - w = get_nearest_power_two(mThumbnailWidth, 512) * 2 ; - h = get_nearest_power_two(mThumbnailHeight, 512) * 2 ; + w = get_lower_power_two(mThumbnailWidth, 512) * 2 ; + h = get_lower_power_two(mThumbnailHeight, 512) * 2 ; { raw = new LLImageRaw ; @@ -723,131 +733,155 @@ void LLSnapshotLivePreview::onIdle( void* snapshot_preview ) previewp->mCameraPos = new_camera_pos; previewp->mCameraRot = new_camera_rot; // request a new snapshot whenever the camera moves, with a time delay - previewp->updateSnapshot(gSavedSettings.getBOOL("AutoSnapshot")); + BOOL autosnap = gSavedSettings.getBOOL("AutoSnapshot"); + previewp->updateSnapshot(autosnap, FALSE, autosnap ? AUTO_SNAPSHOT_TIME_DELAY : 0.f); + } + + // see if it's time yet to snap the shot and bomb out otherwise. + previewp->mSnapshotActive = + (previewp->mSnapshotDelayTimer.getStarted() && previewp->mSnapshotDelayTimer.hasExpired()) + && !LLToolCamera::getInstance()->hasMouseCapture(); // don't take snapshots while ALT-zoom active + if ( ! previewp->mSnapshotActive) + { + return; } - previewp->mSnapshotActive = (previewp->mSnapshotDelayTimer.getStarted() && - previewp->mSnapshotDelayTimer.hasExpired()); + // time to produce a snapshot - // don't take snapshots while ALT-zoom active - if (LLToolCamera::getInstance()->hasMouseCapture()) + if (!previewp->mPreviewImage) { - previewp->mSnapshotActive = FALSE; + previewp->mPreviewImage = new LLImageRaw; } - if (previewp->mSnapshotActive) + if (!previewp->mPreviewImageEncoded) { - if (!previewp->mRawImage) - { - previewp->mRawImage = new LLImageRaw; - } + previewp->mPreviewImageEncoded = new LLImageRaw; + } - if (!previewp->mRawImageEncoded) + previewp->setVisible(FALSE); + previewp->setEnabled(FALSE); + + previewp->getWindow()->incBusyCount(); + previewp->mImageScaled[previewp->mCurImageIndex] = FALSE; + + // grab the raw image and encode it into desired format + if(gViewerWindow->rawSnapshot( + previewp->mPreviewImage, + previewp->mWidth[previewp->mCurImageIndex], + previewp->mHeight[previewp->mCurImageIndex], + previewp->mKeepAspectRatio,//gSavedSettings.getBOOL("KeepAspectForSnapshot"), + previewp->getSnapshotType() == LLSnapshotLivePreview::SNAPSHOT_TEXTURE, + gSavedSettings.getBOOL("RenderUIInSnapshot"), + FALSE, + previewp->mSnapshotBufferType, + previewp->getMaxImageSize())) + { + previewp->mPreviewImageEncoded->resize( + previewp->mPreviewImage->getWidth(), + previewp->mPreviewImage->getHeight(), + previewp->mPreviewImage->getComponents()); + + if (!gSavedSettings.getBOOL("QuietSnapshotsToDisk")) { - previewp->mRawImageEncoded = new LLImageRaw; + // Always play the sound once, on window open. + // Don't keep playing if automatic + // updates are enabled. It's too invasive. JC + if (!previewp->mSnapshotSoundPlayed + || !gSavedSettings.getBOOL("AutoSnapshot") ) + { + gViewerWindow->playSnapshotAnimAndSound(); + previewp->mSnapshotSoundPlayed = true; + } } - - previewp->setVisible(FALSE); - previewp->setEnabled(FALSE); - previewp->getWindow()->incBusyCount(); - previewp->mImageScaled[previewp->mCurImageIndex] = FALSE; - - // do update - if(gViewerWindow->rawSnapshot(previewp->mRawImage, - previewp->mWidth[previewp->mCurImageIndex], - previewp->mHeight[previewp->mCurImageIndex], - previewp->mKeepAspectRatio,//gSavedSettings.getBOOL("KeepAspectForSnapshot"), - previewp->getSnapshotType() == LLSnapshotLivePreview::SNAPSHOT_TEXTURE, - gSavedSettings.getBOOL("RenderUIInSnapshot"), - FALSE, - previewp->mSnapshotBufferType, - previewp->getMaxImageSize())) + if(previewp->getSnapshotType() == SNAPSHOT_TEXTURE) { - previewp->mRawImageEncoded->resize(previewp->mRawImage->getWidth(), previewp->mRawImage->getHeight(), previewp->mRawImage->getComponents()); - - if (!gSavedSettings.getBOOL("QuietSnapshotsToDisk")) + LLPointer formatted = new LLImageJ2C; + LLPointer scaled = new LLImageRaw( + previewp->mPreviewImage->getData(), + previewp->mPreviewImage->getWidth(), + previewp->mPreviewImage->getHeight(), + previewp->mPreviewImage->getComponents()); + + scaled->biasedScaleToPowerOfTwo(512); + previewp->mImageScaled[previewp->mCurImageIndex] = TRUE; + if (formatted->encode(scaled, 0.f)) { - // Always play the sound once, on window open. - // Don't keep playing if automatic - // updates are enabled. It's too invasive. JC - if (!previewp->mSnapshotSoundPlayed - || !gSavedSettings.getBOOL("AutoSnapshot") ) - { - gViewerWindow->playSnapshotAnimAndSound(); - previewp->mSnapshotSoundPlayed = true; - } + previewp->mDataSize = formatted->getDataSize(); + formatted->decode(previewp->mPreviewImageEncoded, 0); } - - if (previewp->getSnapshotType() == SNAPSHOT_POSTCARD) + } + else + { + // delete any existing image + previewp->mFormattedImage = NULL; + // now create the new one of the appropriate format. + // note: postcards hardcoded to use jpeg always. + LLFloaterSnapshot::ESnapshotFormat format = previewp->getSnapshotType() == SNAPSHOT_POSTCARD + ? LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG : previewp->getSnapshotFormat(); + switch(format) { - // *FIX: just resize and reuse existing jpeg? - previewp->mJPEGImage = NULL; // deletes image - previewp->mJPEGImage = new LLImageJPEG(); - previewp->mJPEGImage->setEncodeQuality(llclamp(previewp->mSnapshotQuality, 0, 100)); - if (previewp->mJPEGImage->encode(previewp->mRawImage, 0.0f)) - { - previewp->mDataSize = previewp->mJPEGImage->getDataSize(); - previewp->mJPEGImage->decode(previewp->mRawImageEncoded, 0.0f); - } + case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG: + previewp->mFormattedImage = new LLImagePNG(); + break; + case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG: + previewp->mFormattedImage = new LLImageJPEG(previewp->mSnapshotQuality); + break; + case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP: + previewp->mFormattedImage = new LLImageBMP(); + break; } - else if (previewp->getSnapshotType() == SNAPSHOT_TEXTURE) + if (previewp->mFormattedImage->encode(previewp->mPreviewImage, 0)) { - LLPointer formatted = new LLImageJ2C; - LLPointer scaled = new LLImageRaw(previewp->mRawImage->getData(), - previewp->mRawImage->getWidth(), - previewp->mRawImage->getHeight(), - previewp->mRawImage->getComponents()); - - scaled->biasedScaleToPowerOfTwo(512); - previewp->mImageScaled[previewp->mCurImageIndex] = TRUE; - if (formatted->encode(scaled, 0.0f)) + // special case BMP to copy instead of decode otherwise decode will crash. + if(format == LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP) { - previewp->mDataSize = formatted->getDataSize(); - formatted->decode(previewp->mRawImageEncoded, 0.0f); + previewp->mPreviewImageEncoded->copy(previewp->mPreviewImage); + } + else + { + previewp->mDataSize = previewp->mFormattedImage->getDataSize(); + previewp->mFormattedImage->decode(previewp->mPreviewImageEncoded, 0); } } - else - { - previewp->mRawImageEncoded->copy(previewp->mRawImage); - previewp->mDataSize = previewp->mRawImage->getDataSize(); - } + } - LLPointer scaled = new LLImageRaw(previewp->mRawImageEncoded->getData(), - previewp->mRawImageEncoded->getWidth(), - previewp->mRawImageEncoded->getHeight(), - previewp->mRawImageEncoded->getComponents()); - - // leave original image dimensions, just scale up texture buffer - if (previewp->mRawImageEncoded->getWidth() > 1024 || previewp->mRawImageEncoded->getHeight() > 1024) - { - // go ahead and shrink image to appropriate power of 2 for display - scaled->biasedScaleToPowerOfTwo(1024); - previewp->mImageScaled[previewp->mCurImageIndex] = TRUE; - } - else - { - // expand image but keep original image data intact - scaled->expandToPowerOfTwo(1024, FALSE); - } + LLPointer scaled = new LLImageRaw( + previewp->mPreviewImageEncoded->getData(), + previewp->mPreviewImageEncoded->getWidth(), + previewp->mPreviewImageEncoded->getHeight(), + previewp->mPreviewImageEncoded->getComponents()); + + // leave original image dimensions, just scale up texture buffer + if (previewp->mPreviewImageEncoded->getWidth() > 1024 || previewp->mPreviewImageEncoded->getHeight() > 1024) + { + // go ahead and shrink image to appropriate power of 2 for display + scaled->biasedScaleToPowerOfTwo(1024); + previewp->mImageScaled[previewp->mCurImageIndex] = TRUE; + } + else + { + // expand image but keep original image data intact + scaled->expandToPowerOfTwo(1024, FALSE); + } - previewp->mViewerImage[previewp->mCurImageIndex] = new LLImageGL(scaled, FALSE); - previewp->mViewerImage[previewp->mCurImageIndex]->setMipFilterNearest(previewp->getSnapshotType() != SNAPSHOT_TEXTURE); - LLViewerImage::bindTexture(previewp->mViewerImage[previewp->mCurImageIndex]); - previewp->mViewerImage[previewp->mCurImageIndex]->setClamp(TRUE, TRUE); + previewp->mViewerImage[previewp->mCurImageIndex] = new LLImageGL(scaled, FALSE); + previewp->mViewerImage[previewp->mCurImageIndex]->setMipFilterNearest(previewp->getSnapshotType() != SNAPSHOT_TEXTURE); + LLViewerImage::bindTexture(previewp->mViewerImage[previewp->mCurImageIndex]); + previewp->mViewerImage[previewp->mCurImageIndex]->setClamp(TRUE, TRUE); - previewp->mSnapshotUpToDate = TRUE; - previewp->generateThumbnailImage(TRUE) ; + previewp->mSnapshotUpToDate = TRUE; + previewp->generateThumbnailImage(TRUE) ; - previewp->mPosTakenGlobal = gAgent.getCameraPositionGlobal(); - previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame - } - previewp->getWindow()->decBusyCount(); - // only show fullscreen preview when in freeze frame mode - previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame")); - previewp->mSnapshotDelayTimer.stop(); - previewp->mSnapshotActive = FALSE; + previewp->mPosTakenGlobal = gAgent.getCameraPositionGlobal(); + previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame } + previewp->getWindow()->decBusyCount(); + // only show fullscreen preview when in freeze frame mode + previewp->setVisible(gSavedSettings.getBOOL("UseFreezeFrame")); + previewp->mSnapshotDelayTimer.stop(); + previewp->mSnapshotActive = FALSE; + if(!previewp->getThumbnailUpToDate()) { previewp->generateThumbnailImage() ; @@ -876,11 +910,16 @@ LLFloaterPostcard* LLSnapshotLivePreview::savePostcard() image_scale.setVec(llmin(1.f, (F32)mWidth[mCurImageIndex] / (F32)getCurrentImage()->getWidth()), llmin(1.f, (F32)mHeight[mCurImageIndex] / (F32)getCurrentImage()->getHeight())); } - - LLFloaterPostcard* floater = LLFloaterPostcard::showFromSnapshot(mJPEGImage, mViewerImage[mCurImageIndex], image_scale, mPosTakenGlobal); + LLImageJPEG* jpg = dynamic_cast(mFormattedImage.get()); + if(!jpg) + { + llwarns << "Formatted image not a JPEG" << llendl; + return NULL; + } + LLFloaterPostcard* floater = LLFloaterPostcard::showFromSnapshot(jpg, mViewerImage[mCurImageIndex], image_scale, mPosTakenGlobal); // relinquish lifetime of viewerimage and jpeg image to postcard floater mViewerImage[mCurImageIndex] = NULL; - mJPEGImage = NULL; + mFormattedImage = NULL; return floater; } @@ -893,10 +932,10 @@ void LLSnapshotLivePreview::saveTexture() LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); LLPointer formatted = new LLImageJ2C; - LLPointer scaled = new LLImageRaw(mRawImage->getData(), - mRawImage->getWidth(), - mRawImage->getHeight(), - mRawImage->getComponents()); + LLPointer scaled = new LLImageRaw(mPreviewImage->getData(), + mPreviewImage->getWidth(), + mPreviewImage->getHeight(), + mPreviewImage->getComponents()); scaled->biasedScaleToPowerOfTwo(512); @@ -928,7 +967,7 @@ void LLSnapshotLivePreview::saveTexture() BOOL LLSnapshotLivePreview::saveLocal() { - return gViewerWindow->saveImageNumbered(mRawImage); + return gViewerWindow->saveImageNumbered(mFormattedImage); } ///---------------------------------------------------------------------------- @@ -951,6 +990,7 @@ public: } static void onClickDiscard(void* data); static void onClickKeep(void* data); + static void onCommitSave(LLUICtrl* ctrl, void* data); static void onClickNewSnapshot(void* data); static void onClickAutoSnap(LLUICtrl *ctrl, void* data); //static void onClickAdvanceSnap(LLUICtrl *ctrl, void* data); @@ -965,6 +1005,7 @@ public: static void onCommitFreezeFrame(LLUICtrl* ctrl, void* data); static void onCommitLayerTypes(LLUICtrl* ctrl, void*data); static void onCommitSnapshotType(LLUICtrl* ctrl, void* data); + static void onCommitSnapshotFormat(LLUICtrl* ctrl, void* data); static void onCommitCustomResolution(LLUICtrl *ctrl, void* data); static void resetSnapshotSizeOnUI(LLFloaterSnapshot *view, S32 width, S32 height) ; static BOOL checkImageSize(LLSnapshotLivePreview* previewp, S32& width, S32& height, BOOL isWidthChanged, S32 max_value); @@ -973,12 +1014,14 @@ public: static void setResolution(LLFloaterSnapshot* floater, const std::string& comboname); static void updateControls(LLFloaterSnapshot* floater); static void updateLayout(LLFloaterSnapshot* floater); + static void updateResolutionTextEntry(LLFloaterSnapshot* floater); static LLHandle sPreviewHandle; static BOOL sAspectRatioCheckOff ; private: static LLSnapshotLivePreview::ESnapshotType getTypeIndex(LLFloaterSnapshot* floater); + static ESnapshotFormat getFormatIndex(LLFloaterSnapshot* floater); static LLViewerWindow::ESnapshotType getLayerType(LLFloaterSnapshot* floater); static void comboSetCustom(LLFloaterSnapshot *floater, const std::string& comboname); static void checkAutoSnapshot(LLSnapshotLivePreview* floater, BOOL update_thumbnail = FALSE); @@ -995,6 +1038,7 @@ LLHandle LLFloaterSnapshot::Impl::sPreviewHandle; //static BOOL LLFloaterSnapshot::Impl::sAspectRatioCheckOff = FALSE ; + // static LLSnapshotLivePreview* LLFloaterSnapshot::Impl::getPreviewView(LLFloaterSnapshot *floater) { @@ -1013,10 +1057,28 @@ LLSnapshotLivePreview::ESnapshotType LLFloaterSnapshot::Impl::getTypeIndex(LLFlo else if (id == "texture") index = LLSnapshotLivePreview::SNAPSHOT_TEXTURE; else if (id == "local") - index = LLSnapshotLivePreview::SNAPSHOT_BITMAP; + index = LLSnapshotLivePreview::SNAPSHOT_LOCAL; + return index; +} + + +// static +LLFloaterSnapshot::ESnapshotFormat LLFloaterSnapshot::Impl::getFormatIndex(LLFloaterSnapshot* floater) +{ + ESnapshotFormat index = SNAPSHOT_FORMAT_PNG; + LLSD value = floater->childGetValue("local_format_combo"); + const std::string id = value.asString(); + if (id == "PNG") + index = SNAPSHOT_FORMAT_PNG; + else if (id == "JPEG") + index = SNAPSHOT_FORMAT_JPEG; + else if (id == "BMP") + index = SNAPSHOT_FORMAT_BMP; return index; } + + // static LLViewerWindow::ESnapshotType LLFloaterSnapshot::Impl::getLayerType(LLFloaterSnapshot* floater) { @@ -1141,10 +1203,10 @@ void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp) // static void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater) { - BOOL is_advance = gSavedSettings.getBOOL("AdvanceSnapshot") ; LLRadioGroup* snapshot_type_radio = floater->getChild("snapshot_type_radio"); snapshot_type_radio->setSelectedIndex(gSavedSettings.getS32("LastSnapshotType")); LLSnapshotLivePreview::ESnapshotType shot_type = getTypeIndex(floater); + ESnapshotFormat shot_format = (ESnapshotFormat)gSavedSettings.getS32("SnapshotFormat"); //getFormatIndex(floater); LLViewerWindow::ESnapshotType layer_type = getLayerType(floater); LLViewerWindow::ESnapshotType layer_type = getLayerType(floater); floater->childSetVisible("postcard_size_combo", FALSE); @@ -1158,114 +1220,102 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater) if (combo) combo->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastResolution")); combo = floater->getChild("local_size_combo"); if (combo) combo->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastResolution")); - - floater->childSetVisible("upload_btn", FALSE); - floater->childSetVisible("send_btn", FALSE); - floater->childSetVisible("save_btn", FALSE); - floater->childSetEnabled("keep_aspect_check", FALSE) ; + combo = floater->getChild("local_format_combo"); + if (combo) combo->selectNthItem(gSavedSettings.getS32("SnapshotFormat")); + + floater->childSetVisible("upload_btn", shot_type == LLSnapshotLivePreview::SNAPSHOT_TEXTURE); + floater->childSetVisible("send_btn", shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD); + floater->childSetVisible("save_btn", shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL); + floater->childSetEnabled("keep_aspect_check", shot_type != LLSnapshotLivePreview::SNAPSHOT_TEXTURE && !sAspectRatioCheckOff); + floater->childSetEnabled("layer_types", shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL); + + BOOL is_advance = gSavedSettings.getBOOL("AdvanceSnapshot"); + BOOL is_local = shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL; + BOOL show_slider = + shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD + || (is_local && shot_format == LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG); + + floater->childSetVisible("more_btn", !is_advance); // the only item hidden in advanced mode + floater->childSetVisible("less_btn", is_advance); + floater->childSetVisible("type_label2", is_advance); + floater->childSetVisible("format_label", is_advance && is_local); + floater->childSetVisible("local_format_combo", is_advance && is_local); + floater->childSetVisible("layer_types", is_advance); + floater->childSetVisible("layer_type_label", is_advance); + floater->childSetVisible("snapshot_width", is_advance); + floater->childSetVisible("snapshot_height", is_advance); + floater->childSetVisible("keep_aspect_check", is_advance); + floater->childSetVisible("ui_check", is_advance); + floater->childSetVisible("hud_check", is_advance); + floater->childSetVisible("keep_open_check", is_advance); + floater->childSetVisible("freeze_frame_check", is_advance); + floater->childSetVisible("auto_snapshot_check", is_advance); + floater->childSetVisible("image_quality_slider", is_advance && show_slider); switch(shot_type) { case LLSnapshotLivePreview::SNAPSHOT_POSTCARD: layer_type = LLViewerWindow::SNAPSHOT_TYPE_COLOR; floater->childSetValue("layer_types", "colors"); - floater->childSetEnabled("layer_types", FALSE); - if(is_advance) { - floater->childSetEnabled("image_quality_slider", TRUE); setResolution(floater, "postcard_size_combo"); - - if(!sAspectRatioCheckOff) - { - floater->childSetEnabled("keep_aspect_check", TRUE) ; - } } - - floater->childSetVisible("send_btn", TRUE); break; case LLSnapshotLivePreview::SNAPSHOT_TEXTURE: layer_type = LLViewerWindow::SNAPSHOT_TYPE_COLOR; floater->childSetValue("layer_types", "colors"); - floater->childSetEnabled("layer_types", FALSE); - floater->childSetEnabled("image_quality_slider", FALSE); - if(is_advance) { setResolution(floater, "texture_size_combo"); } - - floater->childSetVisible("upload_btn", TRUE); break; - case LLSnapshotLivePreview::SNAPSHOT_BITMAP: - floater->childSetEnabled("layer_types", TRUE); - floater->childSetEnabled("image_quality_slider", FALSE); - + case LLSnapshotLivePreview::SNAPSHOT_LOCAL: if(is_advance) { setResolution(floater, "local_size_combo"); - - if(!sAspectRatioCheckOff) - { - floater->childSetEnabled("keep_aspect_check", TRUE) ; - } } - - floater->childSetVisible("save_btn", TRUE); break; default: break; } - if(is_advance) - { - floater->childSetVisible("type_label2", TRUE) ; - floater->childSetVisible("layer_types", TRUE) ; - floater->childSetVisible("layer_type_label", TRUE) ; - floater->childSetVisible("snapshot_width", TRUE) ; - floater->childSetVisible("snapshot_height", TRUE) ; - floater->childSetVisible("keep_aspect_check", TRUE) ; - floater->childSetVisible("ui_check", TRUE) ; - floater->childSetVisible("hud_check", TRUE) ; - floater->childSetVisible("keep_open_check", TRUE) ; - floater->childSetVisible("freeze_frame_check", TRUE) ; - floater->childSetVisible("auto_snapshot_check", TRUE) ; - floater->childSetVisible("image_quality_slider", TRUE); - floater->childSetVisible("more_btn", FALSE); - floater->childSetVisible("less_btn", TRUE); - } - else - { - floater->childSetVisible("type_label2", FALSE) ; - floater->childSetVisible("layer_types", FALSE) ; - floater->childSetVisible("layer_type_label", FALSE) ; - floater->childSetVisible("snapshot_width", FALSE) ; - floater->childSetVisible("snapshot_height", FALSE) ; - floater->childSetVisible("keep_aspect_check", FALSE) ; - floater->childSetVisible("ui_check", FALSE) ; - floater->childSetVisible("hud_check", FALSE) ; - floater->childSetVisible("keep_open_check", FALSE) ; - floater->childSetVisible("freeze_frame_check", FALSE) ; - floater->childSetVisible("auto_snapshot_check", FALSE) ; - floater->childSetVisible("image_quality_slider", FALSE); - floater->childSetVisible("more_btn", TRUE); - floater->childSetVisible("less_btn", FALSE); - } + updateResolutionTextEntry(floater); LLSnapshotLivePreview* previewp = getPreviewView(floater); if (previewp) { previewp->setSnapshotType(shot_type); + previewp->setSnapshotFormat(shot_format); previewp->setSnapshotBufferType(layer_type); } } +// static +void LLFloaterSnapshot::Impl::updateResolutionTextEntry(LLFloaterSnapshot* floater) +{ + LLSpinCtrl* width_spinner = floater->getChild("snapshot_width"); + LLSpinCtrl* height_spinner = floater->getChild("snapshot_height"); + + if(getTypeIndex(floater) == LLSnapshotLivePreview::SNAPSHOT_TEXTURE) + { + width_spinner->setAllowEdit(FALSE); + height_spinner->setAllowEdit(FALSE); + } + else + { + width_spinner->setAllowEdit(TRUE); + height_spinner->setAllowEdit(TRUE); + } +} + // static void LLFloaterSnapshot::Impl::checkAutoSnapshot(LLSnapshotLivePreview* previewp, BOOL update_thumbnail) { if (previewp) - { - previewp->updateSnapshot(gSavedSettings.getBOOL("AutoSnapshot"), update_thumbnail); + { + BOOL autosnap = gSavedSettings.getBOOL("AutoSnapshot"); + previewp->updateSnapshot(autosnap, update_thumbnail, autosnap ? AUTO_SNAPSHOT_TIME_DELAY : 0.f); } } @@ -1279,6 +1329,17 @@ void LLFloaterSnapshot::Impl::onClickDiscard(void* data) } } + +// static +void LLFloaterSnapshot::Impl::onCommitSave(LLUICtrl* ctrl, void* data) +{ + if (ctrl->getValue().asString() == "save as") + { + gViewerWindow->resetSnapshotLoc(); + } + onClickKeep(data); +} + // static void LLFloaterSnapshot::Impl::onClickKeep(void* data) { @@ -1294,7 +1355,7 @@ void LLFloaterSnapshot::Impl::onClickKeep(void* data) LLFloaterPostcard* floater = previewp->savePostcard(); // if still in snapshot mode, put postcard floater in snapshot floaterview // and link it to snapshot floater - if (!gSavedSettings.getBOOL("CloseSnapshotOnKeep")) + if (floater && !gSavedSettings.getBOOL("CloseSnapshotOnKeep")) { gFloaterView->removeChild(floater); gSnapshotFloaterView->addChild(floater); @@ -1610,6 +1671,22 @@ void LLFloaterSnapshot::Impl::onCommitSnapshotType(LLUICtrl* ctrl, void* data) } } + +//static +void LLFloaterSnapshot::Impl::onCommitSnapshotFormat(LLUICtrl* ctrl, void* data) +{ + LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; + if (view) + { + gSavedSettings.setS32("SnapshotFormat", getFormatIndex(view)); + getPreviewView(view)->updateSnapshot(TRUE); + updateControls(view); + } +} + + + + // static void LLFloaterSnapshot::Impl::comboSetCustom(LLFloaterSnapshot* floater, const std::string& comboname) { @@ -1642,9 +1719,21 @@ BOOL LLFloaterSnapshot::Impl::checkImageSize(LLSnapshotLivePreview* previewp, S3 height = max_value ; } - //round to nearest power of 2 - width = get_nearest_power_two(width, MAX_TEXTURE_SIZE) ; - height = get_nearest_power_two(height, MAX_TEXTURE_SIZE) ; + //round to nearest power of 2 based on the direction of movement + // i.e. higher power of two if increasing texture resolution + if(gSavedSettings.getS32("LastSnapshotWidth") < width || + gSavedSettings.getS32("LastSnapshotHeight") < height) + { + // Up arrow pressed + width = get_next_power_two(width, MAX_TEXTURE_SIZE) ; + height = get_next_power_two(height, MAX_TEXTURE_SIZE) ; + } + else + { + // Down or no change + width = get_lower_power_two(width, MAX_TEXTURE_SIZE) ; + height = get_lower_power_two(height, MAX_TEXTURE_SIZE) ; + } } else if(previewp && previewp->mKeepAspectRatio) { @@ -1716,9 +1805,6 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat S32 w = llfloor((F32)view->childGetValue("snapshot_width").asReal()); S32 h = llfloor((F32)view->childGetValue("snapshot_height").asReal()); - gSavedSettings.setS32("LastSnapshotWidth", w); - gSavedSettings.setS32("LastSnapshotHeight", h); - LLSnapshotLivePreview* previewp = getPreviewView(view); if (previewp) { @@ -1750,7 +1836,10 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat } previewp->setMaxImageSize((S32)((LLSpinCtrl *)ctrl)->getMaxValue()) ; - if(checkImageSize(previewp, w, h, w != curw, previewp->getMaxImageSize()) || update_) + + // Check image size changes the value of height and width + if(checkImageSize(previewp, w, h, w != curw, previewp->getMaxImageSize()) + || update_) { resetSnapshotSizeOnUI(view, w, h) ; } @@ -1762,6 +1851,10 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat comboSetCustom(view, "local_size_combo"); } } + + gSavedSettings.setS32("LastSnapshotWidth", w); + gSavedSettings.setS32("LastSnapshotHeight", h); + } } @@ -1800,6 +1893,7 @@ LLFloaterSnapshot::~LLFloaterSnapshot() BOOL LLFloaterSnapshot::postBuild() { childSetCommitCallback("snapshot_type_radio", Impl::onCommitSnapshotType, this); + childSetCommitCallback("local_format_combo", Impl::onCommitSnapshotFormat, this); childSetAction("new_snapshot_btn", Impl::onClickNewSnapshot, this); @@ -1813,7 +1907,7 @@ BOOL LLFloaterSnapshot::postBuild() childSetAction("upload_btn", Impl::onClickKeep, this); childSetAction("send_btn", Impl::onClickKeep, this); - childSetAction("save_btn", Impl::onClickKeep, this); + childSetCommitCallback("save_btn", Impl::onCommitSave, this); childSetAction("discard_btn", Impl::onClickDiscard, this); childSetCommitCallback("image_quality_slider", Impl::onCommitQuality, this); @@ -1860,7 +1954,7 @@ BOOL LLFloaterSnapshot::postBuild() impl.updateControls(this); - return TRUE; + return TRUE; } void LLFloaterSnapshot::draw() @@ -1922,45 +2016,6 @@ void LLFloaterSnapshot::draw() LLFloater::draw(); - // draw snapshot thumbnail if not in fullscreen preview mode - /*if (previewp && previewp->getCurrentImage() && previewp->getSnapshotUpToDate()) - { - F32 aspect = previewp->getImageAspect(); - // UI size for thumbnail - S32 max_width = getRect().getWidth() - 20; - S32 max_height = 90; - - S32 img_render_width = 0; - S32 img_render_height = 0; - if (aspect > max_width / max_height) - { - // image too wide, shrink to width - img_render_width = max_width; - img_render_height = llround((F32)max_width / aspect); - } - else - { - // image too tall, shrink to height - img_render_height = max_height; - img_render_width = llround((F32)max_height * aspect); - } - S32 image_width, image_height; - previewp->getSize(image_width, image_height); - glMatrixMode(GL_TEXTURE); - glPushMatrix(); - { - // handle case where image is only a portion of image buffer - if (!previewp->isImageScaled()) - { - glScalef(llmin(1.f, (F32)image_width / (F32)previewp->getCurrentImage()->getWidth()), llmin(1.f, (F32)image_height / (F32)previewp->getCurrentImage()->getHeight()), 1.f); - } - glMatrixMode(GL_MODELVIEW); - gl_draw_scaled_image((getRect().getWidth() - img_render_width) / 2, getRect().getHeight() - 205 + (max_height - img_render_height) / 2, img_render_width, img_render_height, previewp->getCurrentImage(), LLColor4::white); - } - glMatrixMode(GL_TEXTURE); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - }*/ if (previewp) { if(previewp->getThumbnailImage()) @@ -1990,7 +2045,6 @@ void LLFloaterSnapshot::show(void*) if (!sInstance) { sInstance = new LLFloaterSnapshot(); - LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_snapshot.xml", NULL, FALSE); //move snapshot floater to special purpose snapshotfloaterview gFloaterView->removeChild(sInstance); @@ -1998,6 +2052,14 @@ void LLFloaterSnapshot::show(void*) sInstance->impl.updateLayout(sInstance); } + else // just refresh the snapshot in the existing floater instance (DEV-12255) + { + LLSnapshotLivePreview* preview = LLFloaterSnapshot::Impl::getPreviewView(sInstance); + if(preview) + { + preview->updateSnapshot(TRUE); + } + } sInstance->open(); /* Flawfinder: ignore */ sInstance->focusFirstItem(FALSE); @@ -2023,7 +2085,10 @@ void LLFloaterSnapshot::update() } } -//============================================================================ + +///---------------------------------------------------------------------------- +/// Class LLSnapshotFloaterView +///---------------------------------------------------------------------------- LLSnapshotFloaterView::LLSnapshotFloaterView( const std::string& name, const LLRect& rect ) : LLFloaterView(name, rect) { diff --git a/indra/newview/llfloatersnapshot.h b/indra/newview/llfloatersnapshot.h index a7aee1143c..bbf5c9e40b 100644 --- a/indra/newview/llfloatersnapshot.h +++ b/indra/newview/llfloatersnapshot.h @@ -38,15 +38,23 @@ #include "llimagegl.h" #include "llcharacter.h" + class LLFloaterSnapshot : public LLFloater { public: + typedef enum e_snapshot_format + { + SNAPSHOT_FORMAT_PNG, + SNAPSHOT_FORMAT_JPEG, + SNAPSHOT_FORMAT_BMP + } ESnapshotFormat; + LLFloaterSnapshot(); virtual ~LLFloaterSnapshot(); - virtual BOOL postBuild(); - virtual void draw(); - virtual void onClose(bool app_quitting); + /*virtual*/ BOOL postBuild(); + /*virtual*/ void draw(); + /*virtual*/ void onClose(bool app_quitting); static void show(void*); static void hide(void*); @@ -79,4 +87,5 @@ public: }; extern LLSnapshotFloaterView* gSnapshotFloaterView; + #endif // LL_LLFLOATERSNAPSHOT_H diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index a8192e544c..d193685432 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -54,6 +54,7 @@ #include "llpanelvolume.h" #include "llpanelpermissions.h" #include "llselectmgr.h" +#include "llslider.h" #include "llstatusbar.h" #include "lltabcontainer.h" #include "lltextbox.h" @@ -106,6 +107,7 @@ void click_popup_rotate_reset(void*); void click_popup_rotate_right(void*); void click_popup_dozer_mode(LLUICtrl *, void *user); void click_popup_dozer_size(LLUICtrl *, void *user); +void commit_slider_dozer_force(LLUICtrl *, void*); void click_dozer_size(LLUICtrl *, void*); void click_apply_to_selection(void*); void commit_radio_zoom(LLUICtrl *, void*); @@ -308,6 +310,12 @@ BOOL LLFloaterTools::postBuild() childSetAction("button apply to selection",click_apply_to_selection, (void*)0); mCheckShowOwners = getChild("checkbox show owners"); childSetValue("checkbox show owners",gSavedSettings.getBOOL("ShowParcelOwners")); + + mSliderDozerForce = getChild("slider force"); + childSetCommitCallback("slider force",commit_slider_dozer_force, (void*)0); + // the setting stores the actual force multiplier, but the slider is logarithmic, so we convert here + childSetValue( "slider force", log10(gSavedSettings.getF32("LandBrushForce"))); + childSetAction("button more", click_show_more, this); childSetAction("button less", click_show_more, this); mTab = getChild("Object Info Tabs"); @@ -741,6 +749,11 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) { mCheckShowOwners ->setVisible( land_visible ); } + if (mSliderDozerForce) + { + mSliderDozerForce ->setVisible( land_visible ); + childSetVisible("Strength:", land_visible); + } // // More panel visibility @@ -939,6 +952,16 @@ void click_dozer_size(LLUICtrl *ctrl, void *user) gSavedSettings.setS32("RadioLandBrushSize", size); } +void commit_slider_dozer_force(LLUICtrl *ctrl, void*) +{ + // the slider is logarithmic, so we exponentiate to get the actual force multiplier + F32 dozer_force = pow(10.f, (F32)ctrl->getValue().asReal()); + gSavedSettings.setF32("LandBrushForce", dozer_force); +} + + + + void click_apply_to_selection(void* user) { LLToolBrushLand::getInstance()->modifyLandInSelectionGlobal(); diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h index a6fdc76d9f..81e40c0408 100644 --- a/indra/newview/llfloatertools.h +++ b/indra/newview/llfloatertools.h @@ -48,6 +48,7 @@ class LLPanelContents; class LLPanelFace; class LLPanelLandInfo; class LLComboBox; +class LLSlider; class LLParcelSelection; class LLObjectSelection; @@ -167,6 +168,7 @@ public: LLCheckBoxCtrl *mRadioDozerSmooth; LLCheckBoxCtrl *mRadioDozerNoise; LLCheckBoxCtrl *mRadioDozerRevert; + LLSlider *mSliderDozerForce; LLComboBox *mComboDozerSize; LLButton *mBtnApplyToSelection; diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp index 93622ed94e..3c1b89d04b 100644 --- a/indra/newview/llfloatertopobjects.cpp +++ b/indra/newview/llfloatertopobjects.cpp @@ -44,6 +44,7 @@ #include "lllineeditor.h" #include "lltextbox.h" #include "lltracker.h" +#include "llviewermessage.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "lluictrlfactory.h" @@ -51,6 +52,8 @@ LLFloaterTopObjects* LLFloaterTopObjects::sInstance = NULL; +// Globals +// const U32 TIME_STR_LENGTH = 30; // static void LLFloaterTopObjects::show() @@ -161,6 +164,7 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data) for (S32 block = 0; block < block_count; ++block) { U32 task_local_id; + U32 time_stamp = 0; LLUUID task_id; F32 location_x, location_y, location_z; F32 score; @@ -175,7 +179,11 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data) msg->getF32Fast(_PREHASH_ReportData, _PREHASH_Score, score, block); msg->getStringFast(_PREHASH_ReportData, _PREHASH_TaskName, name_buf, block); msg->getStringFast(_PREHASH_ReportData, _PREHASH_OwnerName, owner_buf, block); - + if(msg->getNumberOfBlocks("DataExtended")) + { + msg->getU32("DataExtended", "TimeStamp", time_stamp, block); + } + LLSD element; element["id"] = task_id; @@ -193,7 +201,10 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data) element["columns"][3]["column"] = "location"; element["columns"][3]["value"] = llformat("<%0.1f,%0.1f,%0.1f>", location_x, location_y, location_z); element["columns"][3]["font"] = "SANSSERIF"; - + element["columns"][3]["column"] = "time"; + element["columns"][3]["value"] = formatted_time((time_t)time_stamp); + element["columns"][3]["font"] = "SANSSERIF"; + list->addElement(element); mObjectListData.append(element); diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 9d8641eb2f..a88a6bbffe 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -1644,12 +1644,13 @@ BOOL LLFloaterIMPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, if(drop) { LLToolDragAndDrop::giveInventory(mOtherParticipantUUID, inv_item); + LLStringUtil::format_map_t args; + gIMMgr->addSystemMessage(mSessionUUID, "inventory_item_offered", args); } } } break; } - default: break; } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index ada8ab5fdc..60e6197bf7 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -209,8 +209,8 @@ static LLHost gAgentSimHost; static BOOL gSkipOptionalUpdate = FALSE; static bool gGotUseCircuitCodeAck = false; -std::string gInitialOutfit; -std::string gInitialOutfitGender; // "male" or "female" +static std::string sInitialOutfit; +static std::string sInitialOutfitGender; // "male" or "female" static bool gUseCircuitCallbackCalled = false; @@ -348,8 +348,6 @@ BOOL idle_startup() static BOOL samename = FALSE; - BOOL do_normal_idle = FALSE; - // HACK: These are things from the main loop that usually aren't done // until initialization is complete, but need to be done here for things // to work. @@ -634,34 +632,26 @@ BOOL idle_startup() // Go to the next startup state - LLStartUp::setStartupState( STATE_MEDIA_INIT ); - return do_normal_idle; + LLStartUp::setStartupState( STATE_BROWSER_INIT ); + return FALSE; } - //--------------------------------------------------------------------- - // LLMediaEngine Init - //--------------------------------------------------------------------- - if (STATE_MEDIA_INIT == LLStartUp::getStartupState()) + if (STATE_BROWSER_INIT == LLStartUp::getStartupState()) { - LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL; - set_startup_status(0.03f, "Initializing Multimedia...", gAgent.mMOTD); + LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingBrowser"); + set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str()); display_startup(); - LLViewerMedia::initClass(); - LLViewerParcelMedia::initClass(); - - if (gViewerWindow) - { - audio_update_volume(true); - } + LLViewerMedia::initBrowser(); LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - return do_normal_idle; + return FALSE; } - if (STATE_LOGIN_SHOW == LLStartUp::getStartupState()) - { + if (STATE_LOGIN_SHOW == LLStartUp::getStartupState()) + { LL_DEBUGS("AppInit") << "Initializing Window" << LL_ENDL; gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); @@ -723,7 +713,7 @@ BOOL idle_startup() gLoginMenuBarView->setEnabled( TRUE ); timeout.reset(); - return do_normal_idle; + return FALSE; } if (STATE_LOGIN_WAIT == LLStartUp::getStartupState()) @@ -733,7 +723,7 @@ BOOL idle_startup() // Sleep so we don't spin the CPU ms_sleep(1); - return do_normal_idle; + return FALSE; } if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState()) @@ -894,13 +884,13 @@ BOOL idle_startup() // skipping over STATE_UPDATE_CHECK because that just waits for input LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); - return do_normal_idle; + return FALSE; } if (STATE_UPDATE_CHECK == LLStartUp::getStartupState()) { // wait for user to give input via dialog box - return do_normal_idle; + return FALSE; } if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState()) @@ -1015,7 +1005,7 @@ BOOL idle_startup() gAcceptTOS = FALSE; gAcceptCriticalMessage = FALSE; LLStartUp::setStartupState( STATE_LOGIN_NO_DATA_YET ); - return do_normal_idle; + return FALSE; } if(STATE_LOGIN_NO_DATA_YET == LLStartUp::getStartupState()) @@ -1035,12 +1025,12 @@ BOOL idle_startup() if(LLUserAuth::E_NO_RESPONSE_YET == error) { LL_DEBUGS("AppInit") << "waiting..." << LL_ENDL; - return do_normal_idle; + return FALSE; } LLStartUp::setStartupState( STATE_LOGIN_DOWNLOADING ); progress += 0.01f; set_startup_status(progress, auth_desc, auth_message); - return do_normal_idle; + return FALSE; } if(STATE_LOGIN_DOWNLOADING == LLStartUp::getStartupState()) @@ -1056,12 +1046,12 @@ BOOL idle_startup() if(LLUserAuth::E_DOWNLOADING == error) { LL_DEBUGS("AppInit") << "downloading..." << LL_ENDL; - return do_normal_idle; + return FALSE; } LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE ); progress += 0.01f; set_startup_status(progress, LLTrans::getString("LoginProcessingResponse"), auth_message); - return do_normal_idle; + return FALSE; } if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState()) @@ -1104,7 +1094,7 @@ BOOL idle_startup() // ignoring the duration & options array for now. // Go back to authenticate. LLStartUp::setStartupState( STATE_LOGIN_AUTHENTICATE ); - return do_normal_idle; + return FALSE; } else { @@ -1216,7 +1206,7 @@ BOOL idle_startup() args["[NUMBER]"] = llformat("%d", sAuthUriNum + 1); auth_desc = LLTrans::getString("LoginAttempt", args); LLStartUp::setStartupState( STATE_LOGIN_AUTHENTICATE ); - return do_normal_idle; + return FALSE; } break; } @@ -1391,12 +1381,14 @@ BOOL idle_startup() it = options[0].find("folder_name"); if(it != it_end) { - gInitialOutfit = (*it).second; + // Initial outfit is a folder in your inventory, + // must be an exact folder-name match. + sInitialOutfit = (*it).second; } it = options[0].find("gender"); if (it != it_end) { - gInitialOutfitGender = (*it).second; + sInitialOutfitGender = (*it).second; } } @@ -1475,7 +1467,7 @@ BOOL idle_startup() // Don't save an incorrect password to disk. save_password_to_disk(NULL); } - return do_normal_idle; + return FALSE; } //--------------------------------------------------------------------- @@ -1533,7 +1525,6 @@ BOOL idle_startup() LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(first_sim_handle); LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; - LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT ); regionp->setSeedCapability(first_sim_seed_cap); LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL; @@ -1545,16 +1536,28 @@ BOOL idle_startup() gAgent.setPositionAgent(agent_start_position_region); display_startup(); - return do_normal_idle; + LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT ); + return FALSE; } + //--------------------------------------------------------------------- + // Load QuickTime/GStreamer and other multimedia engines, can be slow. + // Do it while we're waiting on the network for our seed capability. JC + //--------------------------------------------------------------------- + if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState()) + { + LLStartUp::multimediaInit(); + LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT ); + return FALSE; + } + //--------------------------------------------------------------------- // Wait for Seed Cap Grant //--------------------------------------------------------------------- if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) { - return do_normal_idle; + return FALSE; } @@ -1733,7 +1736,7 @@ BOOL idle_startup() timeout.reset(); - return do_normal_idle; + return FALSE; } //--------------------------------------------------------------------- @@ -1752,7 +1755,7 @@ BOOL idle_startup() { } msg->processAcks(); - return do_normal_idle; + return FALSE; } //--------------------------------------------------------------------- @@ -1791,7 +1794,7 @@ BOOL idle_startup() LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT timeout.reset(); - return do_normal_idle; + return FALSE; } //--------------------------------------------------------------------- @@ -1823,7 +1826,7 @@ BOOL idle_startup() LLStartUp::setStartupState( STATE_INVENTORY_SEND ); } - return do_normal_idle; + return FALSE; } //--------------------------------------------------------------------- @@ -2011,7 +2014,7 @@ BOOL idle_startup() } LLStartUp::setStartupState( STATE_MISC ); - return do_normal_idle; + return FALSE; } @@ -2202,26 +2205,27 @@ BOOL idle_startup() LLStartUp::setStartupState( STATE_PRECACHE ); timeout.reset(); - return do_normal_idle; + return FALSE; } if (STATE_PRECACHE == LLStartUp::getStartupState()) { - do_normal_idle = TRUE; - - // Avoid generic Ruth avatar in Orientation Island by starting - // our outfit load as soon as possible. This will be replaced - // with a more definitive patch from featurettes-4 later. JC + F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY; + + // We now have an inventory skeleton, so if this is a user's first + // login, we can start setting up their clothing and avatar + // appearance. This helps to avoid the generic "Ruth" avatar in + // the orientation island tutorial experience. JC if (gAgent.isFirstLogin() - && !gInitialOutfit.empty() // registration set up an outfit - && gAgent.getAvatarObject() // can't wear clothes until have obj - && !gAgent.isGenderChosen() ) // nothing already loaded + && !sInitialOutfit.empty() // registration set up an outfit + && !sInitialOutfitGender.empty() // and a gender + && gAgent.getAvatarObject() // can't wear clothes without object + && !gAgent.isGenderChosen() ) // nothing already loading { - llinfos << "Wearing initial outfit " << gInitialOutfit << llendl; - callback_choose_gender(-1, NULL); + // Start loading the wearables, textures, gestures + LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender ); } - F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY; // wait precache-delay and for agent's avatar or a lot longer. if(((timeout_frac > 1.f) && gAgent.getAvatarObject()) || (timeout_frac > 3.f)) @@ -2231,49 +2235,80 @@ BOOL idle_startup() else { update_texture_fetch(); - set_startup_status(0.60f + 0.20f * timeout_frac, + set_startup_status(0.60f + 0.30f * timeout_frac, "Loading world...", gAgent.mMOTD); } - return do_normal_idle; + return TRUE; } if (STATE_WEARABLES_WAIT == LLStartUp::getStartupState()) { - do_normal_idle = TRUE; - static LLFrameTimer wearables_timer; const F32 wearables_time = wearables_timer.getElapsedTimeF32(); const F32 MAX_WEARABLES_TIME = 10.f; - if(gAgent.getWearablesLoaded() || !gAgent.isGenderChosen()) + if (!gAgent.isGenderChosen()) { + // No point in waiting for clothing, we don't even + // know what gender we are. Pop a dialog to ask and + // proceed to draw the world. JC + // + // *NOTE: We might hit this case even if we have an + // initial outfit, but if the load hasn't started + // already then something is wrong so fall back + // to generic outfits. JC + gViewerWindow->alertXml("WelcomeChooseSex", + callback_choose_gender, NULL); LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; } - else if (wearables_time > MAX_WEARABLES_TIME) + + if (wearables_time > MAX_WEARABLES_TIME) { + // It's taken too long to load, show the world gViewerWindow->alertXml("ClothingLoading"); LLViewerStats::getInstance()->incStat(LLViewerStats::ST_WEARABLES_TOO_LONG); LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } + + if (gAgent.isFirstLogin()) + { + // wait for avatar to be completely loaded + if (gAgent.getAvatarObject() + && gAgent.getAvatarObject()->isFullyLoaded()) + { + //llinfos << "avatar fully loaded" << llendl; + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } } else { - update_texture_fetch(); - set_startup_status(0.80f + 0.20f * wearables_time / MAX_WEARABLES_TIME, - LLTrans::getString("LoginDownloadingClothing"), - gAgent.mMOTD); + // OK to just get the wearables + if ( gAgent.getWearablesLoaded() ) + { + // We have our clothing, proceed. + //llinfos << "wearables loaded" << llendl; + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } } - return do_normal_idle; + + update_texture_fetch(); + set_startup_status(0.9f + 0.1f * wearables_time / MAX_WEARABLES_TIME, + LLTrans::getString("LoginDownloadingClothing").c_str(), + gAgent.mMOTD.c_str()); + return TRUE; } if (STATE_CLEANUP == LLStartUp::getStartupState()) { set_startup_status(1.0, "", ""); - do_normal_idle = TRUE; - // Let the map know about the inventory. if(gFloaterWorldMap) { @@ -2299,9 +2334,6 @@ BOOL idle_startup() gAgent.requestEnterGodMode(); } - // On first start, ask user for gender - dialog_choose_gender_first_start(); - // Start automatic replay if the flag is set. if (gSavedSettings.getBOOL("StatsAutoRun")) { @@ -2335,11 +2367,11 @@ BOOL idle_startup() LLAppViewer::instance()->initMainloopTimeout("Mainloop Init"); - return do_normal_idle; + return TRUE; } LL_WARNS("AppInit") << "Reached end of idle_startup for state " << LLStartUp::getStartupState() << LL_ENDL; - return do_normal_idle; + return TRUE; } // @@ -3548,55 +3580,47 @@ const std::string MALE_GESTURES_FOLDER = "Male Gestures"; const std::string FEMALE_GESTURES_FOLDER = "Female Gestures"; const std::string MALE_OUTFIT_FOLDER = "Male Shape & Outfit"; const std::string FEMALE_OUTFIT_FOLDER = "Female Shape & Outfit"; -const S32 OPT_USE_INITIAL_OUTFIT = -2; const S32 OPT_CLOSED_WINDOW = -1; const S32 OPT_MALE = 0; const S32 OPT_FEMALE = 1; void callback_choose_gender(S32 option, void* userdata) { - S32 gender = OPT_FEMALE; - std::string outfit; + switch(option) + { + case OPT_MALE: + LLStartUp::loadInitialOutfit( MALE_OUTFIT_FOLDER, "male" ); + break; + + case OPT_FEMALE: + case OPT_CLOSED_WINDOW: + default: + LLStartUp::loadInitialOutfit( FEMALE_OUTFIT_FOLDER, "female" ); + break; + } +} + +void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, + const std::string& gender_name ) +{ + S32 gender = 0; std::string gestures; - if (!gInitialOutfit.empty()) + if (gender_name == "male") { - outfit = gInitialOutfit; - if (gInitialOutfitGender == "male") - { - gender = OPT_MALE; - gestures = MALE_GESTURES_FOLDER; - } - else - { - gender = OPT_FEMALE; - gestures = FEMALE_GESTURES_FOLDER; - } + gender = OPT_MALE; + gestures = MALE_GESTURES_FOLDER; } else { - switch(option) - { - case OPT_MALE: - gender = OPT_MALE; - outfit = MALE_OUTFIT_FOLDER; - gestures = MALE_GESTURES_FOLDER; - break; - - case OPT_FEMALE: - case OPT_CLOSED_WINDOW: - default: - gender = OPT_FEMALE; - outfit = FEMALE_OUTFIT_FOLDER; - gestures = FEMALE_GESTURES_FOLDER; - break; - } + gender = OPT_FEMALE; + gestures = FEMALE_GESTURES_FOLDER; } // try to find the outfit - if not there, create some default // wearables. LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; - LLNameCategoryCollector has_name(outfit); + LLNameCategoryCollector has_name(outfit_folder_name); gInventory.collectDescendentsIf(LLUUID::null, cat_array, item_array, @@ -3608,36 +3632,16 @@ void callback_choose_gender(S32 option, void* userdata) } else { - wear_outfit_by_name(outfit); + wear_outfit_by_name(outfit_folder_name); } wear_outfit_by_name(gestures); wear_outfit_by_name(COMMON_GESTURES_FOLDER); - typedef std::map item_map_t; - item_map_t::iterator gestureIterator; - - // Must be here so they aren't invisible if they close the window. + // This is really misnamed -- it means we have started loading + // an outfit/shape that will give the avatar a gender eventually. JC gAgent.setGenderChosen(TRUE); } - -void dialog_choose_gender_first_start() -{ - if (!gNoRender - && (!gAgent.isGenderChosen())) - { - if (!gInitialOutfit.empty()) - { - gViewerWindow->alertXml("WelcomeNoClothes", - callback_choose_gender, NULL); - } - else - { - gViewerWindow->alertXml("WelcomeChooseSex", - callback_choose_gender, NULL); - } - } -} // Loads a bitmap to display during load // location_id = 0 => last position @@ -3736,6 +3740,19 @@ bool LLStartUp::canGoFullscreen() return gStartupState >= STATE_WORLD_INIT; } +// Initialize all plug-ins except the web browser (which was initialized +// early, before the login screen). JC +void LLStartUp::multimediaInit() +{ + LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingMultimedia"); + set_startup_status(0.50f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); + + LLViewerMedia::initClass(); + LLViewerParcelMedia::initClass(); +} + bool LLStartUp::dispatchURL() { // ok, if we've gotten this far and have a startup URL diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index 38319c8d8a..ea568395d4 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -46,7 +46,7 @@ extern std::string SCREEN_LAST_FILENAME; enum EStartupState{ STATE_FIRST, // Initial startup - STATE_MEDIA_INIT, // Initialzie media library + STATE_BROWSER_INIT, // Initialize web browser for login screen STATE_LOGIN_SHOW, // Show login screen STATE_LOGIN_WAIT, // Wait for user input at login screen STATE_LOGIN_CLEANUP, // Get rid of login screen and start login @@ -57,6 +57,7 @@ enum EStartupState{ STATE_LOGIN_DOWNLOADING, // Waiting for authentication replies to download STATE_LOGIN_PROCESS_RESPONSE, // Check authentication reply STATE_WORLD_INIT, // Start building the world + STATE_MULTIMEDIA_INIT, // Init the rest of multimedia library STATE_SEED_GRANTED_WAIT, // Wait for seed cap grant STATE_SEED_CAP_GRANTED, // Have seed cap grant STATE_WORLD_WAIT, // Waiting for simulator @@ -87,6 +88,15 @@ public: static void setStartupState( S32 state ); static S32 getStartupState() { return gStartupState; }; + static void multimediaInit(); + // Initialize LLViewerMedia multimedia engine. + + // outfit_folder_name can be a folder anywhere in your inventory, + // but the name must be a case-sensitive exact match. + // gender_name is either "male" or "female" + static void loadInitialOutfit( const std::string& outfit_folder_name, + const std::string& gender_name ); + static bool dispatchURL(); // if we have a SLURL or sim string ("Ahern/123/45") that started // the viewer, dispatch it diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 421f0196e3..c522bd0697 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -910,7 +910,7 @@ LLTextureCtrl::LLTextureCtrl( mNeedsRawImageData( FALSE ), mValid( TRUE ), mDirty( FALSE ), - mShowLoadingPlaceholder( FALSE ) + mShowLoadingPlaceholder( TRUE ) { mCaption = new LLTextBox( label, LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 ), @@ -1327,6 +1327,10 @@ void LLTextureCtrl::draw() mTentativeLabel->setVisible( !mTexturep.isNull() && getTentative() ); + + // Show "Loading..." string on the top left corner while this texture is loading. + // Using the discard level, do not show the string if the texture is almost but not + // fully loaded. if ( mTexturep.notNull() && (mShowLoadingPlaceholder == TRUE) && (mTexturep->getDiscardLevel() != 1) && diff --git a/indra/newview/lltoolbrush.cpp b/indra/newview/lltoolbrush.cpp index 1b006822c1..b644e43a64 100644 --- a/indra/newview/lltoolbrush.cpp +++ b/indra/newview/lltoolbrush.cpp @@ -154,7 +154,7 @@ void LLToolBrushLand::modifyLandAtPointGlobal(const LLVector3d &pos_global, regionp->forceUpdate(); // tell the simulator what we've done - F32 seconds = 1.0f / gFPSClamped; + F32 seconds = (1.0f / gFPSClamped) * gSavedSettings.getF32("LandBrushForce"); F32 x_pos = (F32)pos_region.mV[VX]; F32 y_pos = (F32)pos_region.mV[VY]; U8 brush_size = (U8)mBrushIndex; @@ -242,7 +242,7 @@ void LLToolBrushLand::modifyLandInSelectionGlobal() min_region.clamp(0.f, regionp->getWidth()); max_region.clamp(0.f, regionp->getWidth()); - F32 seconds = 1.0f; + F32 seconds = gSavedSettings.getF32("LandBrushForce"); LLSurface &land = regionp->getLand(); char action = E_LAND_LEVEL; @@ -251,21 +251,23 @@ void LLToolBrushLand::modifyLandInSelectionGlobal() case 0: // // average toward mStartingZ action = E_LAND_LEVEL; - seconds = 1.f; + seconds *= 0.25f; break; case 1: action = E_LAND_RAISE; + seconds *= 0.25f; break; case 2: action = E_LAND_LOWER; + seconds *= 0.25f; break; case 3: action = E_LAND_SMOOTH; - seconds = 10.f; + seconds *= 5.0f; break; case 4: action = E_LAND_NOISE; - seconds = 0.5f; + seconds *= 0.5f; break; case 5: action = E_LAND_REVERT; diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index f803ef3a3e..f80eb6e486 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -415,12 +415,44 @@ LLUUID LLViewerMediaImpl::getMediaTextureID() // Wrapper class ////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////////// +// The viewer takes a long time to load the start screen. Part of the problem +// is media initialization -- in particular, QuickTime loads many DLLs and +// hits the disk heavily. So we initialize only the browser component before +// the login screen, then do the rest later when we have a progress bar. JC +// static +void LLViewerMedia::initBrowser() +{ + LLMediaManagerData* init_data = new LLMediaManagerData; + buildMediaManagerData( init_data ); + LLMediaManager::initBrowser( init_data ); + delete init_data; +} + ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerMedia::initClass() { LLMediaManagerData* init_data = new LLMediaManagerData; + buildMediaManagerData( init_data ); + LLMediaManager::initClass( init_data ); + delete init_data; + + LLMediaManager* mm = LLMediaManager::getInstance(); + LLMIMETypes::mime_info_map_t::const_iterator it; + for (it = LLMIMETypes::sMap.begin(); it != LLMIMETypes::sMap.end(); ++it) + { + const std::string& mime_type = it->first; + const LLMIMETypes::LLMIMEInfo& info = it->second; + mm->addMimeTypeImplNameMap( mime_type, info.mImpl ); + } +} +////////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::buildMediaManagerData( LLMediaManagerData* init_data ) +{ // std::string executable_dir = std::string( arg0 ).substr( 0, std::string( arg0 ).find_last_of("\\/") ); // std::string component_dir = std::string( executable_dir ).substr( 0, std::string( executable_dir ).find_last_of("\\/") ); // component_dir = std::string( component_dir ).substr( 0, std::string( component_dir ).find_last_of("\\/") ); @@ -467,17 +499,6 @@ void LLViewerMedia::initClass() std::string profile_name("Second Life"); init_data->setBrowserProfileName( profile_name ); init_data->setBrowserParentWindow( gViewerWindow->getPlatformWindow() ); - - LLMediaManager::initClass( init_data ); - - LLMediaManager* mm = LLMediaManager::getInstance(); - LLMIMETypes::mime_info_map_t::const_iterator it; - for (it = LLMIMETypes::sMap.begin(); it != LLMIMETypes::sMap.end(); ++it) - { - const std::string& mime_type = it->first; - const LLMIMETypes::LLMIMEInfo& info = it->second; - mm->addMimeTypeImplNameMap( mime_type, info.mImpl ); - } } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 67a75c7b0f..3f012fef76 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -34,11 +34,16 @@ #include "llmediabase.h" // for status codes +class LLMediaManagerData; class LLUUID; class LLViewerMedia { public: + // Special case early init for just web browser component + // so we can show login screen. See .cpp file for details. JC + static void initBrowser(); + static void initClass(); static void cleanupClass(); @@ -67,6 +72,10 @@ class LLViewerMedia static void setMimeType(std::string mime_type); static void updateImagesMediaStreams(); + + private: + // Fill in initialization data for LLMediaManager::initClass() + static void buildMediaManagerData( LLMediaManagerData* init_data ); }; #endif // LLVIEWERMEDIA_H diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 00cc94c3d3..7db03c9db4 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -436,9 +436,29 @@ class LLFileTakeSnapshotToDisk : public view_listener_t { gViewerWindow->playSnapshotAnimAndSound(); } + LLImageBase::setSizeOverride(TRUE); - gViewerWindow->saveImageNumbered(raw); + LLPointer formatted; + switch(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat"))) + { + case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG: + formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality")); + break; + case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG: + formatted = new LLImagePNG; + break; + case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP: + formatted = new LLImageBMP; + break; + default: + llwarns << "Unknown Local Snapshot format" << llendl; + LLImageBase::setSizeOverride(FALSE); + return true; + } + + formatted->encode(raw, 0); LLImageBase::setSizeOverride(FALSE); + gViewerWindow->saveImageNumbered(formatted); } return true; } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 114707791b..a082d6f1b5 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1175,8 +1175,17 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) return; } + // Strip any SLURL from the message display. (DEV-2754) + std::string msg = info->mDesc; + int indx = msg.find(" ( http://slurl.com/secondlife/"); + if(indx >= 0) + { + LLStringUtil::truncate(msg, indx); + } + LLStringUtil::format_map_t args; - args["[OBJECTNAME]"] = info->mDesc; + args["[OBJECTNAME]"] = msg; + // must protect against a NULL return from lookupHumanReadable() std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType)); if (!typestr.empty()) diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h index ce0fe2c836..4ab0508fba 100644 --- a/indra/newview/llviewerprecompiledheaders.h +++ b/indra/newview/llviewerprecompiledheaders.h @@ -122,6 +122,7 @@ //#include "llblockencoder.h" #include "llimage.h" #include "llimagebmp.h" +#include "llimagepng.h" #include "llimagej2c.h" #include "llimagejpeg.h" #include "llimagetga.h" diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index b37b66effa..be9e9d4d68 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1517,7 +1517,6 @@ LLViewerWindow::LLViewerWindow( LLViewerWindow::sMovieBaseName = "SLmovie"; LLViewerWindow::sSnapshotDir.clear(); - // create window mWindow = LLWindowManager::createWindow( title, name, x, y, width, height, 0, @@ -4049,14 +4048,14 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d } // Saves an image to the harddrive as "SnapshotX" where X >= 1. -BOOL LLViewerWindow::saveImageNumbered(LLImageRaw *raw, const std::string& extension_in) +BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image) { - if (! raw) + if (!image) { return FALSE; } - std::string extension(extension_in); + std::string extension("." + image->getExtension()); if (extension.empty()) { extension = (gSavedSettings.getBOOL("CompressSnapshotsToDisk")) ? ".j2c" : ".bmp"; @@ -4067,6 +4066,10 @@ BOOL LLViewerWindow::saveImageNumbered(LLImageRaw *raw, const std::string& exten pick_type = LLFilePicker::FFSAVE_J2C; else if (extension == ".bmp") pick_type = LLFilePicker::FFSAVE_BMP; + else if (extension == ".jpg") + pick_type = LLFilePicker::FFSAVE_JPEG; + else if (extension == ".png") + pick_type = LLFilePicker::FFSAVE_PNG; else if (extension == ".tga") pick_type = LLFilePicker::FFSAVE_TGA; else @@ -4112,22 +4115,13 @@ BOOL LLViewerWindow::saveImageNumbered(LLImageRaw *raw, const std::string& exten } while( -1 != err ); // search until the file is not found (i.e., stat() gives an error). - LLPointer formatted_image = LLImageFormatted::createFromExtension(extension); - LLImageBase::setSizeOverride(TRUE); - BOOL success = formatted_image->encode(raw, 0.0f); - if( success ) - { - success = formatted_image->save(filepath); - } - else - { - llwarns << "Unable to encode bmp snapshot" << llendl; - } - LLImageBase::setSizeOverride(FALSE); - - return success; + return image->save(filepath); } +void LLViewerWindow::resetSnapshotLoc() +{ + sSnapshotDir.clear(); +} static S32 BORDERHEIGHT = 0; static S32 BORDERWIDTH = 0; @@ -4430,7 +4424,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei image_buffer_x = llfloor(snapshot_width*scale_factor) ; image_buffer_y = llfloor(snapshot_height *scale_factor) ; } - raw->resize(image_buffer_x, image_buffer_y, type == SNAPSHOT_TYPE_DEPTH ? 4 : 3); + raw->resize(image_buffer_x, image_buffer_y, 3); if(raw->isBufferInvalid()) { return FALSE ; @@ -4476,7 +4470,9 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei } else { - display(do_rebuild, scale_factor, subimage_x+(subimage_y*llceil(scale_factor)), use_fbo); + display(do_rebuild, scale_factor, subimage_x+(subimage_y*llceil(scale_factor)), TRUE); + // Required for showing the GUI in snapshots? See DEV-16350 for details. JC + render_ui_and_swap(); } S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width); @@ -4485,49 +4481,43 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei llmax(0, (window_width * (subimage_x + 1)) - (buffer_x_offset + raw->getWidth()))); for(U32 out_y = 0; out_y < read_height ; out_y++) { + S32 output_buffer_offset = ( + (out_y * (raw->getWidth())) // ...plus iterated y... + + (window_width * subimage_x) // ...plus subimage start in x... + + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y... + - output_buffer_offset_x // ...minus buffer padding x... + - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y... + ) * raw->getComponents(); if (type == SNAPSHOT_TYPE_OBJECT_ID || type == SNAPSHOT_TYPE_COLOR) { glReadPixels( subimage_x_offset, out_y + subimage_y_offset, read_width, 1, GL_RGB, GL_UNSIGNED_BYTE, - raw->getData() + // current output pixel is beginning of buffer... - ( - (out_y * (raw->getWidth())) // ...plus iterated y... - + (window_width * subimage_x) // ...plus subimage start in x... - + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y... - - output_buffer_offset_x // ...minus buffer padding x... - - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y... - ) * 3 // times 3 bytes per pixel + raw->getData() + output_buffer_offset ); } else // SNAPSHOT_TYPE_DEPTH { - S32 output_buffer_offset = ( - (out_y * (raw->getWidth())) // ...plus iterated y... - + (window_width * subimage_x) // ...plus subimage start in x... - + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y... - - output_buffer_offset_x // ...minus buffer padding x... - - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y... - ) * 4; // times 4 bytes per pixel - + LLPointer depth_line_buffer = new LLImageRaw(read_width, 1, sizeof(GL_FLOAT)); // need to store floating point values glReadPixels( subimage_x_offset, out_y + subimage_y_offset, read_width, 1, GL_DEPTH_COMPONENT, GL_FLOAT, - raw->getData() + output_buffer_offset// current output pixel is beginning of buffer... + depth_line_buffer->getData()// current output pixel is beginning of buffer... ); - for (S32 i = output_buffer_offset; i < output_buffer_offset + (S32)read_width * 4; i += 4) + for (S32 i = 0; i < (S32)read_width; i++) { - F32 depth_float = *(F32*)(raw->getData() + i); + F32 depth_float = *(F32*)(depth_line_buffer->getData() + (i * sizeof(F32))); F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float * depth_conversion_factor_2)); U8 depth_byte = F32_to_U8(linear_depth_float, LLViewerCamera::getInstance()->getNear(), LLViewerCamera::getInstance()->getFar()); - *(raw->getData() + i + 0) = depth_byte; - *(raw->getData() + i + 1) = depth_byte; - *(raw->getData() + i + 2) = depth_byte; - *(raw->getData() + i + 3) = 255; + //write converted scanline out to result image + for(S32 j = 0; j < raw->getComponents(); j++) + { + *(raw->getData() + output_buffer_offset + (i * raw->getComponents()) + j) = depth_byte; + } } } } @@ -4565,7 +4555,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei // Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding) // Note: this formula depends on the number of components being 3. Not obvious, but it's correct. - image_width += (image_width * (type == SNAPSHOT_TYPE_DEPTH ? 4 : 3)) % 4 ; + image_width += (image_width * 3) % 4; // Resize image if(llabs(image_width - image_buffer_x) > 4 || llabs(image_height - image_buffer_y) > 4) diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 997ac21dfd..5c0eae61be 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -192,7 +192,7 @@ public: // Hide normal UI when a logon fails, re-show everything when logon is attempted again void setNormalControlsVisible( BOOL visible ); - void setMenuBackgroundColor(bool god_mode = false, bool dev_grid = false); + void setMenuBackgroundColor(bool god_mode = false, bool dev_grid = false); // Handle the application becoming active (frontmost) or inactive //BOOL handleActivate(BOOL activate); @@ -219,18 +219,24 @@ public: static void movieSize(S32 new_width, S32 new_height); + // snapshot functionality. + // perhaps some of this should move to llfloatershapshot? -MG typedef enum e_snapshot_type { SNAPSHOT_TYPE_COLOR, SNAPSHOT_TYPE_DEPTH, SNAPSHOT_TYPE_OBJECT_ID } ESnapshotType; - BOOL saveSnapshot(const std::string& filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR); BOOL rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_IMAGE_SIZE ); - BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) ; - BOOL saveImageNumbered(LLImageRaw *raw, const std::string& extension = std::string()); + + BOOL thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) ; + BOOL saveImageNumbered(LLImageFormatted *image); + + // Reset the directory where snapshots are saved. + // Client will open directory picker on next snapshot save. + void resetSnapshotLoc(); void playSnapshotAnimAndSound(); -- cgit v1.2.3