PageRenderTime 27ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llpreviewtexture.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 532 lines | 405 code | 73 blank | 54 comment | 42 complexity | 4f295fe2608c07e5bf729b7a8f1bc7ca MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llpreviewtexture.cpp
  3. * @brief LLPreviewTexture class implementation
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llwindow.h"
  28. #include "llpreviewtexture.h"
  29. #include "llagent.h"
  30. #include "llbutton.h"
  31. #include "llcombobox.h"
  32. #include "llfilepicker.h"
  33. #include "llfloaterreg.h"
  34. #include "llimagetga.h"
  35. #include "llinventory.h"
  36. #include "llnotificationsutil.h"
  37. #include "llresmgr.h"
  38. #include "lltrans.h"
  39. #include "lltextbox.h"
  40. #include "lltextureview.h"
  41. #include "llui.h"
  42. #include "llviewerinventory.h"
  43. #include "llviewertexture.h"
  44. #include "llviewertexturelist.h"
  45. #include "lluictrlfactory.h"
  46. #include "llviewerwindow.h"
  47. #include "lllineeditor.h"
  48. const S32 CLIENT_RECT_VPAD = 4;
  49. const F32 SECONDS_TO_SHOW_FILE_SAVED_MSG = 8.f;
  50. const F32 PREVIEW_TEXTURE_MAX_ASPECT = 200.f;
  51. const F32 PREVIEW_TEXTURE_MIN_ASPECT = 0.005f;
  52. LLPreviewTexture::LLPreviewTexture(const LLSD& key)
  53. : LLPreview(key),
  54. mLoadingFullImage( FALSE ),
  55. mShowKeepDiscard(FALSE),
  56. mCopyToInv(FALSE),
  57. mIsCopyable(FALSE),
  58. mUpdateDimensions(TRUE),
  59. mLastHeight(0),
  60. mLastWidth(0),
  61. mAspectRatio(0.f),
  62. mPreviewToSave(FALSE),
  63. mImage(NULL),
  64. mImageOldBoostLevel(LLViewerTexture::BOOST_NONE)
  65. {
  66. updateImageID();
  67. if (key.has("save_as"))
  68. {
  69. mPreviewToSave = TRUE;
  70. }
  71. }
  72. LLPreviewTexture::~LLPreviewTexture()
  73. {
  74. LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList) ;
  75. if( mLoadingFullImage )
  76. {
  77. getWindow()->decBusyCount();
  78. }
  79. mImage->setBoostLevel(mImageOldBoostLevel);
  80. mImage = NULL;
  81. }
  82. // virtual
  83. BOOL LLPreviewTexture::postBuild()
  84. {
  85. if (mCopyToInv)
  86. {
  87. getChild<LLButton>("Keep")->setLabel(getString("Copy"));
  88. childSetAction("Keep",LLPreview::onBtnCopyToInv,this);
  89. getChildView("Discard")->setVisible( false);
  90. }
  91. else if (mShowKeepDiscard)
  92. {
  93. childSetAction("Keep",onKeepBtn,this);
  94. childSetAction("Discard",onDiscardBtn,this);
  95. }
  96. else
  97. {
  98. getChildView("Keep")->setVisible( false);
  99. getChildView("Discard")->setVisible( false);
  100. }
  101. childSetAction("save_tex_btn", LLPreviewTexture::onSaveAsBtn, this);
  102. getChildView("save_tex_btn")->setVisible( true);
  103. getChildView("save_tex_btn")->setEnabled(canSaveAs());
  104. if (!mCopyToInv)
  105. {
  106. const LLInventoryItem* item = getItem();
  107. if (item)
  108. {
  109. childSetCommitCallback("desc", LLPreview::onText, this);
  110. getChild<LLUICtrl>("desc")->setValue(item->getDescription());
  111. getChild<LLLineEditor>("desc")->setPrevalidate(&LLTextValidate::validateASCIIPrintableNoPipe);
  112. }
  113. }
  114. childSetCommitCallback("combo_aspect_ratio", onAspectRatioCommit, this);
  115. LLComboBox* combo = getChild<LLComboBox>("combo_aspect_ratio");
  116. combo->setCurrentByIndex(0);
  117. return LLPreview::postBuild();
  118. }
  119. // static
  120. void LLPreviewTexture::onSaveAsBtn(void* data)
  121. {
  122. LLPreviewTexture* self = (LLPreviewTexture*)data;
  123. self->saveAs();
  124. }
  125. void LLPreviewTexture::draw()
  126. {
  127. updateDimensions();
  128. LLPreview::draw();
  129. if (!isMinimized())
  130. {
  131. LLGLSUIDefault gls_ui;
  132. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  133. const LLRect& border = mClientRect;
  134. LLRect interior = mClientRect;
  135. interior.stretch( -PREVIEW_BORDER_WIDTH );
  136. // ...border
  137. gl_rect_2d( border, LLColor4(0.f, 0.f, 0.f, 1.f));
  138. gl_rect_2d_checkerboard( interior );
  139. if ( mImage.notNull() )
  140. {
  141. // Automatically bring up SaveAs dialog if we opened this to save the texture.
  142. if (mPreviewToSave)
  143. {
  144. mPreviewToSave = FALSE;
  145. saveAs();
  146. }
  147. // Draw the texture
  148. gGL.diffuseColor3f( 1.f, 1.f, 1.f );
  149. gl_draw_scaled_image(interior.mLeft,
  150. interior.mBottom,
  151. interior.getWidth(),
  152. interior.getHeight(),
  153. mImage);
  154. // Pump the texture priority
  155. F32 pixel_area = mLoadingFullImage ? (F32)MAX_IMAGE_AREA : (F32)(interior.getWidth() * interior.getHeight() );
  156. mImage->addTextureStats( pixel_area );
  157. // Don't bother decoding more than we can display, unless
  158. // we're loading the full image.
  159. if (!mLoadingFullImage)
  160. {
  161. S32 int_width = interior.getWidth();
  162. S32 int_height = interior.getHeight();
  163. mImage->setKnownDrawSize(int_width, int_height);
  164. }
  165. else
  166. {
  167. // Don't use this feature
  168. mImage->setKnownDrawSize(0, 0);
  169. }
  170. if( mLoadingFullImage )
  171. {
  172. LLFontGL::getFontSansSerif()->renderUTF8(LLTrans::getString("Receiving"), 0,
  173. interior.mLeft + 4,
  174. interior.mBottom + 4,
  175. LLColor4::white, LLFontGL::LEFT, LLFontGL::BOTTOM,
  176. LLFontGL::NORMAL,
  177. LLFontGL::DROP_SHADOW);
  178. F32 data_progress = mImage->getDownloadProgress() ;
  179. // Draw the progress bar.
  180. const S32 BAR_HEIGHT = 12;
  181. const S32 BAR_LEFT_PAD = 80;
  182. S32 left = interior.mLeft + 4 + BAR_LEFT_PAD;
  183. S32 bar_width = getRect().getWidth() - left - RESIZE_HANDLE_WIDTH - 2;
  184. S32 top = interior.mBottom + 4 + BAR_HEIGHT;
  185. S32 right = left + bar_width;
  186. S32 bottom = top - BAR_HEIGHT;
  187. LLColor4 background_color(0.f, 0.f, 0.f, 0.75f);
  188. LLColor4 decoded_color(0.f, 1.f, 0.f, 1.0f);
  189. LLColor4 downloaded_color(0.f, 0.5f, 0.f, 1.0f);
  190. gl_rect_2d(left, top, right, bottom, background_color);
  191. if (data_progress > 0.0f)
  192. {
  193. // Downloaded bytes
  194. right = left + llfloor(data_progress * (F32)bar_width);
  195. if (right > left)
  196. {
  197. gl_rect_2d(left, top, right, bottom, downloaded_color);
  198. }
  199. }
  200. }
  201. else
  202. if( !mSavedFileTimer.hasExpired() )
  203. {
  204. LLFontGL::getFontSansSerif()->renderUTF8(LLTrans::getString("FileSaved"), 0,
  205. interior.mLeft + 4,
  206. interior.mBottom + 4,
  207. LLColor4::white, LLFontGL::LEFT, LLFontGL::BOTTOM,
  208. LLFontGL::NORMAL,
  209. LLFontGL::DROP_SHADOW);
  210. }
  211. }
  212. }
  213. }
  214. // virtual
  215. BOOL LLPreviewTexture::canSaveAs() const
  216. {
  217. return mIsCopyable && !mLoadingFullImage && mImage.notNull() && !mImage->isMissingAsset();
  218. }
  219. // virtual
  220. void LLPreviewTexture::saveAs()
  221. {
  222. if( mLoadingFullImage )
  223. return;
  224. LLFilePicker& file_picker = LLFilePicker::instance();
  225. const LLInventoryItem* item = getItem() ;
  226. if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_TGA, item ? LLDir::getScrubbedFileName(item->getName()) : LLStringUtil::null) )
  227. {
  228. // User canceled or we failed to acquire save file.
  229. return;
  230. }
  231. // remember the user-approved/edited file name.
  232. mSaveFileName = file_picker.getFirstFile();
  233. mLoadingFullImage = TRUE;
  234. getWindow()->incBusyCount();
  235. mImage->forceToSaveRawImage(0) ;//re-fetch the raw image if the old one is removed.
  236. mImage->setLoadedCallback( LLPreviewTexture::onFileLoadedForSave,
  237. 0, TRUE, FALSE, new LLUUID( mItemUUID ), &mCallbackTextureList );
  238. }
  239. // virtual
  240. void LLPreviewTexture::reshape(S32 width, S32 height, BOOL called_from_parent)
  241. {
  242. LLPreview::reshape(width, height, called_from_parent);
  243. LLRect dim_rect(getChildView("dimensions")->getRect());
  244. S32 horiz_pad = 2 * (LLPANEL_BORDER_WIDTH + PREVIEW_PAD) + PREVIEW_RESIZE_HANDLE_SIZE;
  245. // add space for dimensions and aspect ratio
  246. S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD;
  247. LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0);
  248. client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD);
  249. client_rect.mBottom += PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height ;
  250. S32 client_width = client_rect.getWidth();
  251. S32 client_height = client_rect.getHeight();
  252. if (mAspectRatio > 0.f)
  253. {
  254. if(mAspectRatio > 1.f)
  255. {
  256. client_height = llceil((F32)client_width / mAspectRatio);
  257. if(client_height > client_rect.getHeight())
  258. {
  259. client_height = client_rect.getHeight();
  260. client_width = llceil((F32)client_height * mAspectRatio);
  261. }
  262. }
  263. else//mAspectRatio < 1.f
  264. {
  265. client_width = llceil((F32)client_height * mAspectRatio);
  266. if(client_width > client_rect.getWidth())
  267. {
  268. client_width = client_rect.getWidth();
  269. client_height = llceil((F32)client_width / mAspectRatio);
  270. }
  271. }
  272. }
  273. mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() + (client_height / 2), client_width, client_height);
  274. }
  275. // virtual
  276. void LLPreviewTexture::onFocusReceived()
  277. {
  278. LLPreview::onFocusReceived();
  279. }
  280. void LLPreviewTexture::openToSave()
  281. {
  282. mPreviewToSave = TRUE;
  283. }
  284. // static
  285. void LLPreviewTexture::onFileLoadedForSave(BOOL success,
  286. LLViewerFetchedTexture *src_vi,
  287. LLImageRaw* src,
  288. LLImageRaw* aux_src,
  289. S32 discard_level,
  290. BOOL final,
  291. void* userdata)
  292. {
  293. LLUUID* item_uuid = (LLUUID*) userdata;
  294. LLPreviewTexture* self = LLFloaterReg::findTypedInstance<LLPreviewTexture>("preview_texture", *item_uuid);
  295. if( final || !success )
  296. {
  297. delete item_uuid;
  298. if( self )
  299. {
  300. self->getWindow()->decBusyCount();
  301. self->mLoadingFullImage = FALSE;
  302. }
  303. }
  304. if( self && final && success )
  305. {
  306. LLPointer<LLImageTGA> image_tga = new LLImageTGA;
  307. if( !image_tga->encode( src ) )
  308. {
  309. LLSD args;
  310. args["FILE"] = self->mSaveFileName;
  311. LLNotificationsUtil::add("CannotEncodeFile", args);
  312. }
  313. else if( !image_tga->save( self->mSaveFileName ) )
  314. {
  315. LLSD args;
  316. args["FILE"] = self->mSaveFileName;
  317. LLNotificationsUtil::add("CannotWriteFile", args);
  318. }
  319. else
  320. {
  321. self->mSavedFileTimer.reset();
  322. self->mSavedFileTimer.setTimerExpirySec( SECONDS_TO_SHOW_FILE_SAVED_MSG );
  323. }
  324. self->mSaveFileName.clear();
  325. }
  326. if( self && !success )
  327. {
  328. LLNotificationsUtil::add("CannotDownloadFile");
  329. }
  330. }
  331. // It takes a while until we get height and width information.
  332. // When we receive it, reshape the window accordingly.
  333. void LLPreviewTexture::updateDimensions()
  334. {
  335. if (!mImage)
  336. {
  337. return;
  338. }
  339. if ((mImage->getFullWidth() * mImage->getFullHeight()) == 0)
  340. {
  341. return;
  342. }
  343. // Update the width/height display every time
  344. getChild<LLUICtrl>("dimensions")->setTextArg("[WIDTH]", llformat("%d", mImage->getFullWidth()));
  345. getChild<LLUICtrl>("dimensions")->setTextArg("[HEIGHT]", llformat("%d", mImage->getFullHeight()));
  346. // Reshape the floater only when required
  347. if (mUpdateDimensions)
  348. {
  349. mUpdateDimensions = FALSE;
  350. //reshape floater
  351. reshape(getRect().getWidth(), getRect().getHeight());
  352. gFloaterView->adjustToFitScreen(this, FALSE);
  353. LLRect dim_rect(getChildView("dimensions")->getRect());
  354. LLRect aspect_label_rect(getChildView("aspect_ratio")->getRect());
  355. getChildView("aspect_ratio")->setVisible( dim_rect.mRight < aspect_label_rect.mLeft);
  356. }
  357. }
  358. // Return true if everything went fine, false if we somewhat modified the ratio as we bumped on border values
  359. bool LLPreviewTexture::setAspectRatio(const F32 width, const F32 height)
  360. {
  361. mUpdateDimensions = TRUE;
  362. // We don't allow negative width or height. Also, if height is positive but too small, we reset to default
  363. // A default 0.f value for mAspectRatio means "unconstrained" in the rest of the code
  364. if ((width <= 0.f) || (height <= F_APPROXIMATELY_ZERO))
  365. {
  366. mAspectRatio = 0.f;
  367. return false;
  368. }
  369. // Compute and store the ratio
  370. F32 ratio = width / height;
  371. mAspectRatio = llclamp(ratio, PREVIEW_TEXTURE_MIN_ASPECT, PREVIEW_TEXTURE_MAX_ASPECT);
  372. // Return false if we clamped the value, true otherwise
  373. return (ratio == mAspectRatio);
  374. }
  375. void LLPreviewTexture::onAspectRatioCommit(LLUICtrl* ctrl, void* userdata)
  376. {
  377. LLPreviewTexture* self = (LLPreviewTexture*) userdata;
  378. std::string ratio(ctrl->getValue().asString());
  379. std::string::size_type separator(ratio.find_first_of(":/\\"));
  380. if (std::string::npos == separator) {
  381. // If there's no separator assume we want an unconstrained ratio
  382. self->setAspectRatio( 0.f, 0.f );
  383. return;
  384. }
  385. F32 width, height;
  386. std::istringstream numerator(ratio.substr(0, separator));
  387. std::istringstream denominator(ratio.substr(separator + 1));
  388. numerator >> width;
  389. denominator >> height;
  390. self->setAspectRatio( width, height );
  391. }
  392. void LLPreviewTexture::loadAsset()
  393. {
  394. mImage = LLViewerTextureManager::getFetchedTexture(mImageID, MIPMAP_TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
  395. mImageOldBoostLevel = mImage->getBoostLevel();
  396. mImage->setBoostLevel(LLViewerTexture::BOOST_PREVIEW);
  397. mImage->forceToSaveRawImage(0) ;
  398. mAssetStatus = PREVIEW_ASSET_LOADING;
  399. mUpdateDimensions = TRUE;
  400. updateDimensions();
  401. getChildView("save_tex_btn")->setEnabled(canSaveAs());
  402. }
  403. LLPreview::EAssetStatus LLPreviewTexture::getAssetStatus()
  404. {
  405. if (mImage.notNull() && (mImage->getFullWidth() * mImage->getFullHeight() > 0))
  406. {
  407. mAssetStatus = PREVIEW_ASSET_LOADED;
  408. }
  409. return mAssetStatus;
  410. }
  411. void LLPreviewTexture::updateImageID()
  412. {
  413. const LLViewerInventoryItem *item = static_cast<const LLViewerInventoryItem*>(getItem());
  414. if(item)
  415. {
  416. mImageID = item->getAssetUUID();
  417. // here's the old logic...
  418. //mShowKeepDiscard = item->getPermissions().getCreator() != gAgent.getID();
  419. // here's the new logic... 'cos we hate disappearing buttons.
  420. mShowKeepDiscard = TRUE;
  421. mCopyToInv = FALSE;
  422. mIsCopyable = item->checkPermissionsSet(PERM_ITEM_UNRESTRICTED);
  423. }
  424. else // not an item, assume it's an asset id
  425. {
  426. mImageID = mItemUUID;
  427. mShowKeepDiscard = FALSE;
  428. mCopyToInv = TRUE;
  429. mIsCopyable = TRUE;
  430. }
  431. }
  432. /* virtual */
  433. void LLPreviewTexture::setObjectID(const LLUUID& object_id)
  434. {
  435. mObjectUUID = object_id;
  436. const LLUUID old_image_id = mImageID;
  437. // Update what image we're pointing to, such as if we just specified the mObjectID
  438. // that this mItemID is part of.
  439. updateImageID();
  440. // If the imageID has changed, start over and reload the new image.
  441. if (mImageID != old_image_id)
  442. {
  443. mAssetStatus = PREVIEW_ASSET_UNLOADED;
  444. loadAsset();
  445. }
  446. }