llpreviewtexture.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:16k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llpreviewtexture.cpp
  3.  * @brief LLPreviewTexture class implementation
  4.  *
  5.  * $LicenseInfo:firstyear=2002&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2002-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llwindow.h"
  34. #include "llpreviewtexture.h"
  35. #include "llagent.h"
  36. #include "llbutton.h"
  37. #include "llcombobox.h"
  38. #include "llfilepicker.h"
  39. #include "llfloaterreg.h"
  40. #include "llimagetga.h"
  41. #include "llinventory.h"
  42. #include "llnotificationsutil.h"
  43. #include "llresmgr.h"
  44. #include "lltrans.h"
  45. #include "lltextbox.h"
  46. #include "lltextureview.h"
  47. #include "llui.h"
  48. #include "llviewerinventory.h"
  49. #include "llviewertexture.h"
  50. #include "llviewertexturelist.h"
  51. #include "lluictrlfactory.h"
  52. #include "llviewerwindow.h"
  53. #include "lllineeditor.h"
  54. const S32 CLIENT_RECT_VPAD = 4;
  55. const F32 SECONDS_TO_SHOW_FILE_SAVED_MSG = 8.f;
  56. const F32 PREVIEW_TEXTURE_MAX_ASPECT = 200.f;
  57. const F32 PREVIEW_TEXTURE_MIN_ASPECT = 0.005f;
  58. LLPreviewTexture::LLPreviewTexture(const LLSD& key)
  59. : LLPreview(key),
  60.   mLoadingFullImage( FALSE ),
  61.   mShowKeepDiscard(FALSE),
  62.   mCopyToInv(FALSE),
  63.   mIsCopyable(FALSE),
  64.   mUpdateDimensions(TRUE),
  65.   mLastHeight(0),
  66.   mLastWidth(0),
  67.   mAspectRatio(0.f),
  68.   mPreviewToSave(FALSE),
  69.   mImage(NULL)
  70. {
  71. updateImageID();
  72. if (key.has("save_as"))
  73. {
  74. mPreviewToSave = TRUE;
  75. }
  76. //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_preview_texture.xml", FALSE);
  77. }
  78. LLPreviewTexture::~LLPreviewTexture()
  79. {
  80. if( mLoadingFullImage )
  81. {
  82. getWindow()->decBusyCount();
  83. }
  84. mImage = NULL;
  85. }
  86. // virtual
  87. BOOL LLPreviewTexture::postBuild()
  88. {
  89. if (mCopyToInv) 
  90. {
  91. getChild<LLButton>("Keep")->setLabel(getString("Copy"));
  92. childSetAction("Keep",LLPreview::onBtnCopyToInv,this);
  93. childSetVisible("Discard", false);
  94. }
  95. else if (mShowKeepDiscard)
  96. {
  97. childSetAction("Keep",onKeepBtn,this);
  98. childSetAction("Discard",onDiscardBtn,this);
  99. }
  100. else
  101. {
  102. childSetVisible("Keep", false);
  103. childSetVisible("Discard", false);
  104. }
  105. childSetAction("save_tex_btn", LLPreviewTexture::onSaveAsBtn, this);
  106. childSetVisible("save_tex_btn", true);
  107. childSetEnabled("save_tex_btn", canSaveAs());
  108. if (!mCopyToInv) 
  109. {
  110. const LLInventoryItem* item = getItem();
  111. if (item)
  112. {
  113. childSetCommitCallback("desc", LLPreview::onText, this);
  114. childSetText("desc", item->getDescription());
  115. childSetPrevalidate("desc", &LLTextValidate::validateASCIIPrintableNoPipe);
  116. }
  117. }
  118. childSetCommitCallback("combo_aspect_ratio", onAspectRatioCommit, this);
  119. LLComboBox* combo = getChild<LLComboBox>("combo_aspect_ratio");
  120. combo->setCurrentByIndex(0);
  121. return LLPreview::postBuild();
  122. }
  123. // static
  124. void LLPreviewTexture::onSaveAsBtn(void* data)
  125. {
  126. LLPreviewTexture* self = (LLPreviewTexture*)data;
  127. self->saveAs();
  128. }
  129. void LLPreviewTexture::draw()
  130. {
  131. if (mUpdateDimensions)
  132. {
  133. updateDimensions();
  134. }
  135. LLPreview::draw();
  136. if (!isMinimized())
  137. {
  138. LLGLSUIDefault gls_ui;
  139. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  140. const LLRect& border = mClientRect;
  141. LLRect interior = mClientRect;
  142. interior.stretch( -PREVIEW_BORDER_WIDTH );
  143. // ...border
  144. gl_rect_2d( border, LLColor4(0.f, 0.f, 0.f, 1.f));
  145. gl_rect_2d_checkerboard( interior );
  146. if ( mImage.notNull() )
  147. {
  148. // Automatically bring up SaveAs dialog if we opened this to save the texture.
  149. if (mPreviewToSave)
  150. {
  151. mPreviewToSave = FALSE;
  152. saveAs();
  153. }
  154. // Draw the texture
  155. glColor3f( 1.f, 1.f, 1.f );
  156. gl_draw_scaled_image(interior.mLeft,
  157. interior.mBottom,
  158. interior.getWidth(),
  159. interior.getHeight(),
  160. mImage);
  161. // Pump the texture priority
  162. F32 pixel_area = mLoadingFullImage ? (F32)MAX_IMAGE_AREA  : (F32)(interior.getWidth() * interior.getHeight() );
  163. mImage->addTextureStats( pixel_area );
  164. // Don't bother decoding more than we can display, unless
  165. // we're loading the full image.
  166. if (!mLoadingFullImage)
  167. {
  168. S32 int_width = interior.getWidth();
  169. S32 int_height = interior.getHeight();
  170. mImage->setKnownDrawSize(int_width, int_height);
  171. }
  172. else
  173. {
  174. // Don't use this feature
  175. mImage->setKnownDrawSize(0, 0);
  176. }
  177. if( mLoadingFullImage )
  178. {
  179. LLFontGL::getFontSansSerif()->renderUTF8(LLTrans::getString("Receiving"), 0,
  180. interior.mLeft + 4, 
  181. interior.mBottom + 4,
  182. LLColor4::white, LLFontGL::LEFT, LLFontGL::BOTTOM,
  183. LLFontGL::NORMAL,
  184. LLFontGL::DROP_SHADOW);
  185. F32 data_progress = mImage->getDownloadProgress() ;
  186. // Draw the progress bar.
  187. const S32 BAR_HEIGHT = 12;
  188. const S32 BAR_LEFT_PAD = 80;
  189. S32 left = interior.mLeft + 4 + BAR_LEFT_PAD;
  190. S32 bar_width = getRect().getWidth() - left - RESIZE_HANDLE_WIDTH - 2;
  191. S32 top = interior.mBottom + 4 + BAR_HEIGHT;
  192. S32 right = left + bar_width;
  193. S32 bottom = top - BAR_HEIGHT;
  194. LLColor4 background_color(0.f, 0.f, 0.f, 0.75f);
  195. LLColor4 decoded_color(0.f, 1.f, 0.f, 1.0f);
  196. LLColor4 downloaded_color(0.f, 0.5f, 0.f, 1.0f);
  197. gl_rect_2d(left, top, right, bottom, background_color);
  198. if (data_progress > 0.0f)
  199. {
  200. // Downloaded bytes
  201. right = left + llfloor(data_progress * (F32)bar_width);
  202. if (right > left)
  203. {
  204. gl_rect_2d(left, top, right, bottom, downloaded_color);
  205. }
  206. }
  207. }
  208. else
  209. if( !mSavedFileTimer.hasExpired() )
  210. {
  211. LLFontGL::getFontSansSerif()->renderUTF8(LLTrans::getString("FileSaved"), 0,
  212. interior.mLeft + 4,
  213. interior.mBottom + 4,
  214. LLColor4::white, LLFontGL::LEFT, LLFontGL::BOTTOM,
  215. LLFontGL::NORMAL,
  216. LLFontGL::DROP_SHADOW);
  217. }
  218. }
  219. }
  220. // virtual
  221. BOOL LLPreviewTexture::canSaveAs() const
  222. {
  223. return mIsCopyable && !mLoadingFullImage && mImage.notNull() && !mImage->isMissingAsset();
  224. }
  225. // virtual
  226. void LLPreviewTexture::saveAs()
  227. {
  228. if( mLoadingFullImage )
  229. return;
  230. LLFilePicker& file_picker = LLFilePicker::instance();
  231. const LLInventoryItem* item = getItem() ;
  232. if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_TGA, item ? LLDir::getScrubbedFileName(item->getName()) : LLStringUtil::null) )
  233. {
  234. // User canceled or we failed to acquire save file.
  235. return;
  236. }
  237. // remember the user-approved/edited file name.
  238. mSaveFileName = file_picker.getFirstFile();
  239. mLoadingFullImage = TRUE;
  240. getWindow()->incBusyCount();
  241. mImage->setLoadedCallback( LLPreviewTexture::onFileLoadedForSave, 
  242. 0, TRUE, FALSE, new LLUUID( mItemUUID ) );
  243. }
  244. // virtual
  245. void LLPreviewTexture::reshape(S32 width, S32 height, BOOL called_from_parent)
  246. {
  247. LLPreview::reshape(width, height, called_from_parent);
  248. LLRect dim_rect;
  249. childGetRect("dimensions", dim_rect);
  250. S32 horiz_pad = 2 * (LLPANEL_BORDER_WIDTH + PREVIEW_PAD) + PREVIEW_RESIZE_HANDLE_SIZE;
  251. // add space for dimensions and aspect ratio
  252. S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD;
  253. LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0);
  254. client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD);
  255. client_rect.mBottom += PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height ;
  256. S32 client_width = client_rect.getWidth();
  257. S32 client_height = client_rect.getHeight();
  258. if (mAspectRatio > 0.f)
  259. {
  260. if(mAspectRatio > 1.f)
  261. {
  262. client_height = llceil((F32)client_width / mAspectRatio);
  263. if(client_height > client_rect.getHeight())
  264. {
  265. client_height = client_rect.getHeight();
  266. client_width = llceil((F32)client_height * mAspectRatio);
  267. }
  268. }
  269. else//mAspectRatio < 1.f
  270. {
  271. client_width = llceil((F32)client_height * mAspectRatio);
  272. if(client_width > client_rect.getWidth())
  273. {
  274. client_width = client_rect.getWidth();
  275. client_height = llceil((F32)client_width / mAspectRatio);
  276. }
  277. }
  278. }
  279. mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() +  (client_height / 2), client_width, client_height);
  280. }
  281. // virtual
  282. void LLPreviewTexture::onFocusReceived()
  283. {
  284. LLPreview::onFocusReceived();
  285. }
  286. void LLPreviewTexture::openToSave()
  287. {
  288. mPreviewToSave = TRUE;
  289. }
  290. // static
  291. void LLPreviewTexture::onFileLoadedForSave(BOOL success, 
  292.    LLViewerFetchedTexture *src_vi,
  293.    LLImageRaw* src, 
  294.    LLImageRaw* aux_src, 
  295.    S32 discard_level,
  296.    BOOL final,
  297.    void* userdata)
  298. {
  299. LLUUID* item_uuid = (LLUUID*) userdata;
  300. LLPreviewTexture* self = LLFloaterReg::findTypedInstance<LLPreviewTexture>("preview_texture", *item_uuid);
  301. if( final || !success )
  302. {
  303. delete item_uuid;
  304. if( self )
  305. {
  306. self->getWindow()->decBusyCount();
  307. self->mLoadingFullImage = FALSE;
  308. }
  309. }
  310. if( self && final && success )
  311. {
  312. LLPointer<LLImageTGA> image_tga = new LLImageTGA;
  313. if( !image_tga->encode( src ) )
  314. {
  315. LLSD args;
  316. args["FILE"] = self->mSaveFileName;
  317. LLNotificationsUtil::add("CannotEncodeFile", args);
  318. }
  319. else if( !image_tga->save( self->mSaveFileName ) )
  320. {
  321. LLSD args;
  322. args["FILE"] = self->mSaveFileName;
  323. LLNotificationsUtil::add("CannotWriteFile", args);
  324. }
  325. else
  326. {
  327. self->mSavedFileTimer.reset();
  328. self->mSavedFileTimer.setTimerExpirySec( SECONDS_TO_SHOW_FILE_SAVED_MSG );
  329. }
  330. self->mSaveFileName.clear();
  331. }
  332. if( self && !success )
  333. {
  334. LLNotificationsUtil::add("CannotDownloadFile");
  335. }
  336. }
  337. // It takes a while until we get height and width information.
  338. // When we receive it, reshape the window accordingly.
  339. void LLPreviewTexture::updateDimensions()
  340. {
  341. if (!mImage)
  342. return;
  343. if(mImage->getFullWidth() == 0 || mImage->getFullHeight() == 0)
  344. {
  345. return;
  346. }
  347. mUpdateDimensions = FALSE;
  348. childSetTextArg("dimensions", "[WIDTH]", llformat("%d", mImage->getFullWidth()));
  349. childSetTextArg("dimensions", "[HEIGHT]", llformat("%d", mImage->getFullHeight()));
  350. LLRect dim_rect;
  351. childGetRect("dimensions", dim_rect);
  352. S32 horiz_pad = 2 * (LLPANEL_BORDER_WIDTH + PREVIEW_PAD) + PREVIEW_RESIZE_HANDLE_SIZE;
  353. // add space for dimensions and aspect ratio
  354. S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD;
  355. S32 screen_width = gFloaterView->getSnapRect().getWidth();
  356. S32 screen_height = gFloaterView->getSnapRect().getHeight();
  357. S32 max_image_width = screen_width - 2*horiz_pad;
  358. S32 max_image_height = screen_height - (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD) 
  359. - (PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height);
  360. S32 client_width = llmin(max_image_width,mImage->getFullWidth());
  361. S32 client_height = llmin(max_image_height,mImage->getFullHeight());
  362. if (mAspectRatio > 0.f)
  363. {
  364. if(mAspectRatio > 1.f)
  365. {
  366. client_height = llceil((F32)client_width / mAspectRatio);
  367. if(client_height > max_image_height)
  368. {
  369. client_height = max_image_height;
  370. client_width = llceil((F32)client_height * mAspectRatio);
  371. }
  372. }
  373. else//mAspectRatio < 1.f
  374. {
  375. client_width = llceil((F32)client_height * mAspectRatio);
  376. if(client_width > max_image_width)
  377. {
  378. client_width = max_image_width;
  379. client_height = llceil((F32)client_width / mAspectRatio);
  380. }
  381. }
  382. }
  383. else
  384. {
  385. if(client_height > max_image_height)
  386. {
  387. F32 ratio = (F32)max_image_height/client_height;
  388. client_height = max_image_height;
  389. client_width = llceil((F32)client_height * ratio);
  390. }
  391. if(client_width > max_image_width)
  392. {
  393. F32 ratio = (F32)max_image_width/client_width;
  394. client_width = max_image_width;
  395. client_height = llceil((F32)client_width * ratio);
  396. }
  397. }
  398. //now back to whole floater
  399. S32 floater_width = llmax(getMinWidth(),client_width + 2*horiz_pad);
  400. S32 floater_height = llmax(getMinHeight(),client_height + (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD)
  401. + (PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height));
  402. //reshape floater
  403. reshape( floater_width, floater_height );
  404. gFloaterView->adjustToFitScreen(this, FALSE);
  405. //setup image rect...
  406. LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0);
  407. client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD);
  408. client_rect.mBottom += PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height ;
  409. mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() +  (client_height / 2), client_width, client_height);
  410. // Hide the aspect ratio label if the window is too narrow
  411. // Assumes the label should be to the right of the dimensions
  412. LLRect aspect_label_rect;
  413. childGetRect("aspect_ratio", aspect_label_rect);
  414. childSetVisible("aspect_ratio", dim_rect.mRight < aspect_label_rect.mLeft);
  415. }
  416. // Return true if everything went fine, false if we somewhat modified the ratio as we bumped on border values
  417. bool LLPreviewTexture::setAspectRatio(const F32 width, const F32 height)
  418. {
  419. mUpdateDimensions = TRUE;
  420. // We don't allow negative width or height. Also, if height is positive but too small, we reset to default
  421. // A default 0.f value for mAspectRatio means "unconstrained" in the rest of the code
  422. if ((width <= 0.f) || (height <= F_APPROXIMATELY_ZERO))
  423. {
  424. mAspectRatio = 0.f;
  425. return false;
  426. }
  427. // Compute and store the ratio
  428. F32 ratio = width / height;
  429. mAspectRatio = llclamp(ratio, PREVIEW_TEXTURE_MIN_ASPECT, PREVIEW_TEXTURE_MAX_ASPECT);
  430. // Return false if we clamped the value, true otherwise
  431. return (ratio == mAspectRatio);
  432. }
  433. void LLPreviewTexture::onAspectRatioCommit(LLUICtrl* ctrl, void* userdata)
  434. {
  435. LLPreviewTexture* self = (LLPreviewTexture*) userdata;
  436. std::string ratio(ctrl->getValue().asString());
  437. std::string::size_type separator(ratio.find_first_of(":/\"));
  438. if (std::string::npos == separator) {
  439. // If there's no separator assume we want an unconstrained ratio
  440. self->setAspectRatio( 0.f, 0.f );
  441. return;
  442. }
  443. F32 width, height;
  444. std::istringstream numerator(ratio.substr(0, separator));
  445. std::istringstream denominator(ratio.substr(separator + 1));
  446. numerator >> width;
  447. denominator >> height;
  448. self->setAspectRatio( width, height );
  449. }
  450. void LLPreviewTexture::loadAsset()
  451. {
  452. mImage = LLViewerTextureManager::getFetchedTexture(mImageID, MIPMAP_TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
  453. mImage->setBoostLevel(LLViewerTexture::BOOST_PREVIEW);
  454. mImage->forceToSaveRawImage(0) ;
  455. mAssetStatus = PREVIEW_ASSET_LOADING;
  456. mUpdateDimensions = TRUE;
  457. updateDimensions();
  458. childSetEnabled("save_tex_btn", canSaveAs());
  459. }
  460. LLPreview::EAssetStatus LLPreviewTexture::getAssetStatus()
  461. {
  462. if (mImage.notNull() && (mImage->getFullWidth() * mImage->getFullHeight() > 0))
  463. {
  464. mAssetStatus = PREVIEW_ASSET_LOADED;
  465. }
  466. return mAssetStatus;
  467. }
  468. void LLPreviewTexture::updateImageID()
  469. {
  470. const LLViewerInventoryItem *item = static_cast<const LLViewerInventoryItem*>(getItem());
  471. if(item)
  472. {
  473. mImageID = item->getAssetUUID();
  474. // here's the old logic...
  475. //mShowKeepDiscard = item->getPermissions().getCreator() != gAgent.getID();
  476. // here's the new logic... 'cos we hate disappearing buttons.
  477. mShowKeepDiscard = TRUE;
  478. mCopyToInv = FALSE;
  479. mIsCopyable = item->checkPermissionsSet(PERM_ITEM_UNRESTRICTED);
  480. }
  481. else // not an item, assume it's an asset id
  482. {
  483. mImageID = mItemUUID;
  484. mShowKeepDiscard = FALSE;
  485. mCopyToInv = TRUE;
  486. mIsCopyable = TRUE;
  487. }
  488. }
  489. /* virtual */
  490. void LLPreviewTexture::setObjectID(const LLUUID& object_id)
  491. {
  492. mObjectUUID = object_id;
  493. const LLUUID old_image_id = mImageID;
  494. // Update what image we're pointing to, such as if we just specified the mObjectID
  495. // that this mItemID is part of.
  496. updateImageID();
  497. // If the imageID has changed, start over and reload the new image.
  498. if (mImageID != old_image_id)
  499. {
  500. mAssetStatus = PREVIEW_ASSET_UNLOADED;
  501. loadAsset();
  502. }
  503. }