llfloaterimagepreview.cpp 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058
  1. /**
  2. * @file llfloaterimagepreview.cpp
  3. * @brief LLFloaterImagePreview class implementation
  4. *
  5. * $LicenseInfo:firstyear=2004&license=viewergpl$
  6. *
  7. * Copyright (c) 2004-2009, 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 "llfloaterimagepreview.h"
  34. #include "llcombobox.h"
  35. #include "llcheckboxctrl.h"
  36. #include "lldir.h"
  37. #include "lleconomy.h"
  38. #include "llimagebmp.h"
  39. #include "llimagejpeg.h"
  40. #include "llimagepng.h"
  41. #include "llimagetga.h"
  42. #include "llinventorytype.h"
  43. #include "llrender.h"
  44. #include "llresizehandle.h" // For RESIZE_HANDLE_WIDTH
  45. #include "lluictrlfactory.h"
  46. #include "llagent.h"
  47. #include "lldrawable.h"
  48. #include "lldrawpoolavatar.h"
  49. #include "llface.h"
  50. #include "hbfloaterthumbnail.h"
  51. #include "llpipeline.h"
  52. #include "lltoolmgr.h"
  53. #include "llviewercamera.h"
  54. #include "llviewercontrol.h"
  55. #include "llviewerobjectlist.h"
  56. #include "llviewerregion.h"
  57. #include "llviewershadermgr.h"
  58. #include "llviewertexturelist.h"
  59. #include "llviewerwindow.h"
  60. #include "llvoavatar.h"
  61. constexpr S32 PREVIEW_BORDER_WIDTH = 2;
  62. constexpr S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) +
  63. PREVIEW_BORDER_WIDTH;
  64. constexpr S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
  65. constexpr S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16;
  66. constexpr S32 PREVIEW_TEXTURE_HEIGHT = 300;
  67. //-----------------------------------------------------------------------------
  68. // LLFloaterImagePreview class
  69. //-----------------------------------------------------------------------------
  70. LLFloaterImagePreview::LLFloaterImagePreview(const std::string& filename)
  71. : HBFloaterUploadAsset(filename, LLInventoryType::IT_TEXTURE)
  72. {
  73. init();
  74. }
  75. LLFloaterImagePreview::LLFloaterImagePreview(const std::string& filename,
  76. const LLUUID& thumb_inv_id)
  77. : HBFloaterUploadAsset(filename, LLInventoryType::IT_NONE), // Not an asset !
  78. mThumbnailInventoryId(thumb_inv_id)
  79. {
  80. init();
  81. }
  82. void LLFloaterImagePreview::init()
  83. {
  84. mAvatarPreview = NULL;
  85. mSculptedPreview = NULL;
  86. mImagep = NULL;
  87. mLastMouseX = mLastMouseY = 0;
  88. loadImage(mFilenameAndPath);
  89. LLUICtrlFactory::getInstance()->buildFloater(this,
  90. "floater_image_preview.xml");
  91. }
  92. bool LLFloaterImagePreview::postBuild()
  93. {
  94. if (!HBFloaterUploadAsset::postBuild())
  95. {
  96. return false;
  97. }
  98. mUploadButton->setLabelArg("[AMOUNT]", llformat("%d", mCost));
  99. mClothingCombo = getChild<LLComboBox>("clothing_type_combo");
  100. mClothingCombo->selectFirstItem();
  101. if (mThumbnailInventoryId.isNull())
  102. {
  103. mClothingCombo->setCommitCallback(onPreviewTypeCommit);
  104. mClothingCombo->setCallbackUserData(this);
  105. }
  106. mPreviewRect.set(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT,
  107. getRect().getWidth() - PREVIEW_HPAD,
  108. PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
  109. mPreviewImageRect.set(0.f, 1.f, 1.f, 0.f);
  110. mTempAssetCheck = getChild<LLCheckBoxCtrl>("temp_check");
  111. bool show_temp_upload = mCost > 0;
  112. if (show_temp_upload)
  113. {
  114. // Temporary texture assets rely on viewer-side baking (it is therefore
  115. // now only possible to upload them in OpenSim). HB
  116. LLViewerRegion* regionp = gAgent.getRegion();
  117. show_temp_upload = regionp && regionp->getCentralBakeVersion() == 0;
  118. }
  119. if (mThumbnailInventoryId.notNull())
  120. {
  121. mTempAssetCheck->setVisible(false);
  122. mClothingCombo->setEnabled(false);
  123. mDescEditor->setText(getString("thumbnail"));
  124. mDescEditor->setEnabled(false);
  125. childSetVisible("lossless_check", false);
  126. }
  127. else if (mRawImagep.notNull())
  128. {
  129. mAvatarPreview = new LLImagePreviewAvatar(256, 256);
  130. mAvatarPreview->setPreviewTarget(LL_JOINT_KEY_PELVIS,
  131. "mUpperBodyMesh0", 2.f, false);
  132. mSculptedPreview = new LLImagePreviewSculpted(256, 256);
  133. mSculptedPreview->setPreviewTarget(mRawImagep, 2.f);
  134. if ((U32)(mRawImagep->getWidth() * mRawImagep->getHeight()) <=
  135. LL_IMAGE_REZ_LOSSLESS_CUTOFF * LL_IMAGE_REZ_LOSSLESS_CUTOFF)
  136. {
  137. childEnable("lossless_check");
  138. }
  139. }
  140. else
  141. {
  142. show_temp_upload = false;
  143. mClothingCombo->setEnabled(false);
  144. mUploadButton->setEnabled(false);
  145. childShow("bad_image_text");
  146. }
  147. mTempAssetCheck->setVisible(show_temp_upload);
  148. return true;
  149. }
  150. LLFloaterImagePreview::~LLFloaterImagePreview()
  151. {
  152. clearAllPreviewTextures();
  153. mRawImagep = NULL;
  154. mAvatarPreview = NULL;
  155. mSculptedPreview = NULL;
  156. mImagep = NULL;
  157. }
  158. //virtual
  159. S32 LLFloaterImagePreview::getExpectedUploadCost() const
  160. {
  161. return LLEconomy::getInstance()->getTextureUploadCost(mRawImagep->getWidth(),
  162. mRawImagep->getHeight());
  163. }
  164. //virtual
  165. void LLFloaterImagePreview::uploadAsset()
  166. {
  167. if (mThumbnailInventoryId.notNull())
  168. {
  169. // Hand over to the thumbnail floater. HB
  170. HBFloaterThumbnail::uploadThumbnail(mThumbnailInventoryId, mRawImagep);
  171. }
  172. else
  173. {
  174. mTempAsset = mTempAssetCheck->getVisible() &&
  175. mTempAssetCheck->getEnabled() && mTempAssetCheck->get();
  176. HBFloaterUploadAsset::uploadAsset();
  177. }
  178. }
  179. //static
  180. void LLFloaterImagePreview::onPreviewTypeCommit(LLUICtrl* ctrl, void* userdata)
  181. {
  182. LLFloaterImagePreview* fp =(LLFloaterImagePreview*)userdata;
  183. if (!fp->mAvatarPreview || !fp->mSculptedPreview)
  184. {
  185. return;
  186. }
  187. S32 which_mode = fp->mClothingCombo->getFirstSelectedIndex();
  188. switch(which_mode)
  189. {
  190. case 0:
  191. break;
  192. case 1:
  193. fp->mAvatarPreview->setPreviewTarget(LL_JOINT_KEY_SKULL, "mHairMesh0",
  194. 0.4f, false);
  195. break;
  196. case 2:
  197. fp->mAvatarPreview->setPreviewTarget(LL_JOINT_KEY_SKULL, "mHeadMesh0",
  198. 0.4f, false);
  199. break;
  200. case 3:
  201. fp->mAvatarPreview->setPreviewTarget(LL_JOINT_KEY_CHEST,
  202. "mUpperBodyMesh0", 1.f, false);
  203. break;
  204. case 4:
  205. fp->mAvatarPreview->setPreviewTarget(LL_JOINT_KEY_KNEELEFT,
  206. "mLowerBodyMesh0", 1.2f, false);
  207. break;
  208. case 5:
  209. fp->mAvatarPreview->setPreviewTarget(LL_JOINT_KEY_SKULL, "mHeadMesh0",
  210. 0.4f, true);
  211. break;
  212. case 6:
  213. fp->mAvatarPreview->setPreviewTarget(LL_JOINT_KEY_CHEST,
  214. "mUpperBodyMesh0", 1.2f, true);
  215. break;
  216. case 7:
  217. fp->mAvatarPreview->setPreviewTarget(LL_JOINT_KEY_KNEELEFT,
  218. "mLowerBodyMesh0", 1.2f, true);
  219. break;
  220. case 8:
  221. fp->mAvatarPreview->setPreviewTarget(LL_JOINT_KEY_KNEELEFT,
  222. "mSkirtMesh0", 1.3f, false);
  223. break;
  224. case 9:
  225. fp->mSculptedPreview->setPreviewTarget(fp->mRawImagep, 2.f);
  226. break;
  227. default:
  228. break;
  229. }
  230. fp->mAvatarPreview->refresh();
  231. fp->mSculptedPreview->refresh();
  232. }
  233. void LLFloaterImagePreview::clearAllPreviewTextures()
  234. {
  235. if (mAvatarPreview)
  236. {
  237. mAvatarPreview->clearPreviewTexture("mHairMesh0");
  238. mAvatarPreview->clearPreviewTexture("mUpperBodyMesh0");
  239. mAvatarPreview->clearPreviewTexture("mLowerBodyMesh0");
  240. mAvatarPreview->clearPreviewTexture("mHeadMesh0");
  241. mAvatarPreview->clearPreviewTexture("mUpperBodyMesh0");
  242. mAvatarPreview->clearPreviewTexture("mLowerBodyMesh0");
  243. mAvatarPreview->clearPreviewTexture("mSkirtMesh0");
  244. }
  245. }
  246. void LLFloaterImagePreview::draw()
  247. {
  248. LLFloater::draw();
  249. if (mRawImagep.isNull())
  250. {
  251. return;
  252. }
  253. LLRect r = getRect();
  254. LLTexUnit* unit0 = gGL.getTexUnit(0);
  255. S32 selected = mClothingCombo->getFirstSelectedIndex();
  256. if (selected <= 0)
  257. {
  258. gl_rect_2d_checkerboard(mPreviewRect);
  259. if (mImagep.notNull())
  260. {
  261. unit0->bindManual(LLTexUnit::TT_TEXTURE, mImagep->getTexName());
  262. }
  263. else
  264. {
  265. mImagep = LLViewerTextureManager::getLocalTexture(mRawImagep.get(),
  266. false);
  267. unit0->unbind(mImagep->getTarget());
  268. unit0->bindManual(LLTexUnit::TT_TEXTURE, mImagep->getTexName());
  269. unit0->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
  270. unit0->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
  271. if (mAvatarPreview)
  272. {
  273. mAvatarPreview->setTexture(mImagep->getTexName());
  274. mSculptedPreview->setTexture(mImagep->getTexName());
  275. }
  276. }
  277. gGL.color3f(1.f, 1.f, 1.f);
  278. gGL.begin(LLRender::TRIANGLES);
  279. {
  280. F32 top = mPreviewImageRect.mTop;
  281. F32 bottom = mPreviewImageRect.mBottom;
  282. F32 left = mPreviewImageRect.mLeft;
  283. F32 right = mPreviewImageRect.mRight;
  284. gGL.texCoord2f(left, top);
  285. gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
  286. gGL.texCoord2f(left, bottom);
  287. gGL.vertex2i(PREVIEW_HPAD,
  288. PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
  289. gGL.texCoord2f(right, bottom);
  290. gGL.vertex2i(r.getWidth() - PREVIEW_HPAD,
  291. PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
  292. gGL.texCoord2f(left, top);
  293. gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
  294. gGL.texCoord2f(right, bottom);
  295. gGL.vertex2i(r.getWidth() - PREVIEW_HPAD,
  296. PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
  297. gGL.texCoord2f(right, top);
  298. gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
  299. }
  300. gGL.end();
  301. unit0->unbind(LLTexUnit::TT_TEXTURE);
  302. }
  303. else if (mAvatarPreview && mSculptedPreview)
  304. {
  305. gGL.color3f(1.f, 1.f, 1.f);
  306. if (selected == 9)
  307. {
  308. unit0->bind(mSculptedPreview);
  309. }
  310. else
  311. {
  312. unit0->bind(mAvatarPreview);
  313. }
  314. gGL.begin(LLRender::TRIANGLES);
  315. {
  316. S32 right = r.getWidth() - PREVIEW_HPAD;
  317. gGL.texCoord2f(0.f, 1.f);
  318. gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
  319. gGL.texCoord2f(0.f, 0.f);
  320. gGL.vertex2i(PREVIEW_HPAD,
  321. PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
  322. gGL.texCoord2f(1.f, 0.f);
  323. gGL.vertex2i(right,
  324. PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
  325. gGL.texCoord2f(0.f, 1.f);
  326. gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT);
  327. gGL.texCoord2f(1.f, 0.f);
  328. gGL.vertex2i(right,
  329. PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD);
  330. gGL.texCoord2f(1.f, 1.f);
  331. gGL.vertex2i(right, PREVIEW_TEXTURE_HEIGHT);
  332. }
  333. gGL.end();
  334. unit0->unbind(LLTexUnit::TT_TEXTURE);
  335. }
  336. }
  337. bool LLFloaterImagePreview::loadImage(const std::string& src_filename)
  338. {
  339. std::string exten = gDirUtil.getExtension(src_filename);
  340. U32 codec = IMG_CODEC_INVALID;
  341. std::string temp_str;
  342. if (exten == "bmp")
  343. {
  344. codec = IMG_CODEC_BMP;
  345. }
  346. else if (exten == "tga")
  347. {
  348. codec = IMG_CODEC_TGA;
  349. }
  350. else if (exten == "jpg" || exten == "jpeg")
  351. {
  352. codec = IMG_CODEC_JPEG;
  353. }
  354. else if (exten == "png")
  355. {
  356. codec = IMG_CODEC_PNG;
  357. }
  358. LLPointer<LLImageRaw> imagep = new LLImageRaw;
  359. switch (codec)
  360. {
  361. case IMG_CODEC_BMP:
  362. {
  363. LLPointer<LLImageBMP> bmp_imagep = new LLImageBMP;
  364. if (!bmp_imagep->load(src_filename))
  365. {
  366. return false;
  367. }
  368. if (!bmp_imagep->decode(imagep))
  369. {
  370. return false;
  371. }
  372. break;
  373. }
  374. case IMG_CODEC_TGA:
  375. {
  376. LLPointer<LLImageTGA> tga_imagep = new LLImageTGA;
  377. if (!tga_imagep->load(src_filename))
  378. {
  379. return false;
  380. }
  381. if (!tga_imagep->decode(imagep))
  382. {
  383. return false;
  384. }
  385. if (tga_imagep->getComponents() != 3 &&
  386. tga_imagep->getComponents() != 4)
  387. {
  388. tga_imagep->setLastError("Image files with less than 3 or more than 4 components are not supported.");
  389. return false;
  390. }
  391. break;
  392. }
  393. case IMG_CODEC_JPEG:
  394. {
  395. LLPointer<LLImageJPEG> jpeg_imagep = new LLImageJPEG;
  396. if (!jpeg_imagep->load(src_filename))
  397. {
  398. return false;
  399. }
  400. if (!jpeg_imagep->decode(imagep))
  401. {
  402. return false;
  403. }
  404. break;
  405. }
  406. case IMG_CODEC_PNG:
  407. {
  408. LLPointer<LLImagePNG> png_imagep = new LLImagePNG;
  409. if (!png_imagep->load(src_filename))
  410. {
  411. return false;
  412. }
  413. if (!png_imagep->decode(imagep))
  414. {
  415. return false;
  416. }
  417. break;
  418. }
  419. default:
  420. return false;
  421. }
  422. imagep->biasedScaleToPowerOfTwo(gAgent.getRegionMaxTextureSize());
  423. mRawImagep = imagep;
  424. return true;
  425. }
  426. bool LLFloaterImagePreview::handleMouseDown(S32 x, S32 y, MASK mask)
  427. {
  428. if (mPreviewRect.pointInRect(x, y))
  429. {
  430. bringToFront(x, y);
  431. gFocusMgr.setMouseCapture(this);
  432. gViewerWindowp->hideCursor();
  433. mLastMouseX = x;
  434. mLastMouseY = y;
  435. return true;
  436. }
  437. return LLFloater::handleMouseDown(x, y, mask);
  438. }
  439. bool LLFloaterImagePreview::handleMouseUp(S32 x, S32 y, MASK mask)
  440. {
  441. gFocusMgr.setMouseCapture(NULL);
  442. gViewerWindowp->showCursor();
  443. return LLFloater::handleMouseUp(x, y, mask);
  444. }
  445. bool LLFloaterImagePreview::handleHover(S32 x, S32 y, MASK mask)
  446. {
  447. MASK local_mask = mask & ~MASK_ALT;
  448. if (mAvatarPreview && hasMouseCapture())
  449. {
  450. if (local_mask == MASK_PAN)
  451. {
  452. // pan here
  453. if (mClothingCombo->getFirstSelectedIndex() <= 0)
  454. {
  455. mPreviewImageRect.translate((F32)(x - mLastMouseX) * -0.005f *
  456. mPreviewImageRect.getWidth(),
  457. (F32)(y - mLastMouseY) * -0.005f *
  458. mPreviewImageRect.getHeight());
  459. }
  460. else
  461. {
  462. mAvatarPreview->pan((F32)(x - mLastMouseX) * -0.005f,
  463. (F32)(y - mLastMouseY) * -0.005f);
  464. mSculptedPreview->pan((F32)(x - mLastMouseX) * -0.005f,
  465. (F32)(y - mLastMouseY) * -0.005f);
  466. }
  467. }
  468. else if (local_mask == MASK_ORBIT)
  469. {
  470. F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f;
  471. F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f;
  472. mAvatarPreview->rotate(yaw_radians, pitch_radians);
  473. mSculptedPreview->rotate(yaw_radians, pitch_radians);
  474. }
  475. else
  476. {
  477. if (mClothingCombo->getFirstSelectedIndex() <= 0)
  478. {
  479. F32 zoom_amt = (F32)(y - mLastMouseY) * -0.002f;
  480. mPreviewImageRect.stretch(zoom_amt);
  481. }
  482. else
  483. {
  484. F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f;
  485. F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f;
  486. mAvatarPreview->rotate(yaw_radians, 0.f);
  487. mAvatarPreview->zoom(zoom_amt);
  488. mSculptedPreview->rotate(yaw_radians, 0.f);
  489. mSculptedPreview->zoom(zoom_amt);
  490. }
  491. }
  492. if (mClothingCombo->getFirstSelectedIndex() <= 0)
  493. {
  494. if (mPreviewImageRect.getWidth() > 1.f)
  495. {
  496. mPreviewImageRect.stretch((1.f -
  497. mPreviewImageRect.getWidth()) *
  498. 0.5f);
  499. }
  500. else if (mPreviewImageRect.getWidth() < 0.1f)
  501. {
  502. mPreviewImageRect.stretch((0.1f -
  503. mPreviewImageRect.getWidth()) *
  504. 0.5f);
  505. }
  506. if (mPreviewImageRect.getHeight() > 1.f)
  507. {
  508. mPreviewImageRect.stretch((1.f -
  509. mPreviewImageRect.getHeight()) *
  510. 0.5f);
  511. }
  512. else if (mPreviewImageRect.getHeight() < 0.1f)
  513. {
  514. mPreviewImageRect.stretch((0.1f -
  515. mPreviewImageRect.getHeight()) *
  516. 0.5f);
  517. }
  518. if (mPreviewImageRect.mLeft < 0.f)
  519. {
  520. mPreviewImageRect.translate(-mPreviewImageRect.mLeft, 0.f);
  521. }
  522. else if (mPreviewImageRect.mRight > 1.f)
  523. {
  524. mPreviewImageRect.translate(1.f - mPreviewImageRect.mRight,
  525. 0.f);
  526. }
  527. if (mPreviewImageRect.mBottom < 0.f)
  528. {
  529. mPreviewImageRect.translate(0.f, -mPreviewImageRect.mBottom);
  530. }
  531. else if (mPreviewImageRect.mTop > 1.f)
  532. {
  533. mPreviewImageRect.translate(0.f, 1.f - mPreviewImageRect.mTop);
  534. }
  535. }
  536. else
  537. {
  538. mAvatarPreview->refresh();
  539. mSculptedPreview->refresh();
  540. }
  541. LLUI::setCursorPositionLocal(this, mLastMouseX, mLastMouseY);
  542. }
  543. if (!mPreviewRect.pointInRect(x, y) || !mAvatarPreview ||
  544. !mSculptedPreview)
  545. {
  546. return LLFloater::handleHover(x, y, mask);
  547. }
  548. else if (local_mask == MASK_ORBIT)
  549. {
  550. gViewerWindowp->setCursor(UI_CURSOR_TOOLCAMERA);
  551. }
  552. else if (local_mask == MASK_PAN)
  553. {
  554. gViewerWindowp->setCursor(UI_CURSOR_TOOLPAN);
  555. }
  556. else
  557. {
  558. gViewerWindowp->setCursor(UI_CURSOR_TOOLZOOMIN);
  559. }
  560. return true;
  561. }
  562. bool LLFloaterImagePreview::handleScrollWheel(S32 x, S32 y, S32 clicks)
  563. {
  564. if (mPreviewRect.pointInRect(x, y) && mAvatarPreview)
  565. {
  566. mAvatarPreview->zoom((F32)clicks * -0.2f);
  567. mAvatarPreview->refresh();
  568. mSculptedPreview->zoom((F32)clicks * -0.2f);
  569. mSculptedPreview->refresh();
  570. }
  571. return true;
  572. }
  573. //-----------------------------------------------------------------------------
  574. // LLImagePreviewAvatar class
  575. //-----------------------------------------------------------------------------
  576. LLImagePreviewAvatar::LLImagePreviewAvatar(S32 width, S32 height)
  577. : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, false)
  578. {
  579. mNeedsUpdate = true;
  580. mTargetJoint = NULL;
  581. mTargetMesh = NULL;
  582. mCameraDistance = 0.f;
  583. mCameraYaw = 0.f;
  584. mCameraPitch = 0.f;
  585. mCameraZoom = 1.f;
  586. mTextureName = 0;
  587. mDummyAvatar =
  588. (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR,
  589. gAgent.getRegion(),
  590. LLViewerObject::CO_FLAG_UI_AVATAR);
  591. if (!mDummyAvatar)
  592. {
  593. llwarns << "Cannot create a dummy avatar !" << llendl;
  594. return;
  595. }
  596. mDummyAvatar->mSpecialRenderMode = 2;
  597. }
  598. LLImagePreviewAvatar::~LLImagePreviewAvatar()
  599. {
  600. if (mDummyAvatar)
  601. {
  602. mDummyAvatar->markDead();
  603. }
  604. }
  605. //virtual
  606. S8 LLImagePreviewAvatar::getType() const
  607. {
  608. return LLViewerDynamicTexture::LL_IMAGE_PREVIEW_AVATAR;
  609. }
  610. void LLImagePreviewAvatar::setPreviewTarget(U32 joint_key,
  611. const std::string& mesh,
  612. F32 distance, bool male)
  613. {
  614. if (!mDummyAvatar) return;
  615. mTargetJoint = mDummyAvatar->mRoot->findJoint(joint_key);
  616. if (mTargetMesh)
  617. {
  618. // Clear out existing test texture on current mesh
  619. mTargetMesh->setTestTexture(0);
  620. }
  621. mDummyAvatar->setVisualParamWeight("male", male ? 1.f : 0.f);
  622. mDummyAvatar->updateVisualParams();
  623. #if 0 // This is a NOP ! HB
  624. mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable);
  625. #endif
  626. LLAvatarJoint* rootp = mDummyAvatar->mRoot;
  627. // Hide all body parts
  628. rootp->setVisible(false, true);
  629. mTargetMesh = dynamic_cast<LLViewerJointMesh*>(rootp->findJoint(mesh));
  630. if (mTargetMesh)
  631. {
  632. // Show target only, with our texture
  633. mTargetMesh->setTestTexture(mTextureName);
  634. mTargetMesh->setVisible(true, false);
  635. }
  636. mCameraDistance = distance;
  637. mCameraZoom = 1.f;
  638. mCameraPitch = 0.f;
  639. mCameraYaw = 0.f;
  640. mCameraOffset.clear();
  641. }
  642. void LLImagePreviewAvatar::clearPreviewTexture(const std::string& mesh_name)
  643. {
  644. if (!mDummyAvatar)
  645. {
  646. return;
  647. }
  648. LLAvatarJoint* rootp = mDummyAvatar->mRoot;
  649. LLViewerJointMesh* meshp =
  650. dynamic_cast<LLViewerJointMesh*>(rootp->findJoint(mesh_name));
  651. if (meshp)
  652. {
  653. // Clear out existing test mesh
  654. meshp->setTestTexture(0);
  655. }
  656. }
  657. bool LLImagePreviewAvatar::render()
  658. {
  659. LLVOAvatar* avatarp = mDummyAvatar.get();
  660. if (!avatarp || avatarp->mDrawable.isNull())
  661. {
  662. return true;
  663. }
  664. mNeedsUpdate = false;
  665. gGL.pushUIMatrix();
  666. gGL.loadUIIdentity();
  667. gGL.matrixMode(LLRender::MM_PROJECTION);
  668. gGL.pushMatrix();
  669. gGL.loadIdentity();
  670. gGL.ortho(0.f, mFullWidth, 0.f, mFullHeight, -1.f, 1.f);
  671. gGL.matrixMode(LLRender::MM_MODELVIEW);
  672. gGL.pushMatrix();
  673. gGL.loadIdentity();
  674. LLGLSUIDefault def;
  675. gUIProgram.bind();
  676. gGL.color4f(0.15f, 0.2f, 0.3f, 1.f);
  677. gl_rect_2d_simple(mFullWidth, mFullHeight);
  678. gGL.color4f(1.f, 1.f, 1.f, 1.f);
  679. gGL.matrixMode(LLRender::MM_PROJECTION);
  680. gGL.popMatrix();
  681. gGL.matrixMode(LLRender::MM_MODELVIEW);
  682. gGL.popMatrix();
  683. gGL.flush();
  684. LLVector3 target_pos = mTargetJoint->getWorldPosition();
  685. LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) *
  686. LLQuaternion(mCameraYaw, LLVector3::z_axis);
  687. LLQuaternion av_rot = avatarp->mPelvisp->getWorldRotation() * camera_rot;
  688. gViewerCamera.setOriginAndLookAt(target_pos +
  689. ((LLVector3(mCameraDistance, 0.f, 0.f) +
  690. mCameraOffset) * av_rot), // Camera
  691. LLVector3::z_axis, // Up
  692. // point of interest
  693. target_pos + mCameraOffset * av_rot);
  694. gViewerCamera.setAspect((F32)mFullWidth / (F32)mFullHeight);
  695. gViewerCamera.setViewNoBroadcast(gViewerCamera.getDefaultFOV() /
  696. mCameraZoom);
  697. gViewerCamera.setPerspective(false, mOrigin.mX, mOrigin.mY, mFullWidth,
  698. mFullHeight, false);
  699. avatarp->updateLOD();
  700. LLVertexBuffer::unbind();
  701. // Do not let environment settings influence our scene lighting.
  702. HBPreviewLighting preview_light;
  703. LLDisableOcclusionCulling no_occlusion;
  704. LLGLDepthTest gls_depth(GL_TRUE);
  705. // Make sure alpha=0 shows avatar material color
  706. LLGLDisable no_blend(GL_BLEND);
  707. LLFace* facep = avatarp->mDrawable->getFace(0);
  708. if (facep) // Paranoia
  709. {
  710. LLDrawPoolAvatar* poolp = (LLDrawPoolAvatar*)facep->getPool();
  711. if (poolp) // More paranoia !
  712. {
  713. // Render only our dummy avatar
  714. poolp->renderAvatars(avatarp);
  715. }
  716. }
  717. gGL.popUIMatrix();
  718. return true;
  719. }
  720. void LLImagePreviewAvatar::refresh()
  721. {
  722. mNeedsUpdate = true;
  723. }
  724. void LLImagePreviewAvatar::rotate(F32 yaw_radians, F32 pitch_radians)
  725. {
  726. mCameraYaw = mCameraYaw + yaw_radians;
  727. mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f,
  728. F_PI_BY_TWO * 0.8f);
  729. }
  730. void LLImagePreviewAvatar::zoom(F32 zoom_amt)
  731. {
  732. mCameraZoom = llclamp(mCameraZoom + zoom_amt, 1.f, 10.f);
  733. }
  734. void LLImagePreviewAvatar::pan(F32 right, F32 up)
  735. {
  736. mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] +
  737. right * mCameraDistance / mCameraZoom,
  738. -1.f, 1.f);
  739. mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] +
  740. up * mCameraDistance / mCameraZoom,
  741. -1.f, 1.f);
  742. }
  743. //-----------------------------------------------------------------------------
  744. // LLImagePreviewSculpted class
  745. //-----------------------------------------------------------------------------
  746. LLImagePreviewSculpted::LLImagePreviewSculpted(S32 width, S32 height)
  747. : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, false)
  748. {
  749. mNeedsUpdate = true;
  750. mCameraDistance = 0.f;
  751. mCameraYaw = 0.f;
  752. mCameraPitch = 0.f;
  753. mCameraZoom = 1.f;
  754. mTextureName = 0;
  755. LLVolumeParams volume_params;
  756. volume_params.setType(LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE);
  757. volume_params.setSculptID(LLUUID::null, LL_SCULPT_TYPE_SPHERE);
  758. constexpr F32 HIGHEST_LOD = 4.f;
  759. mVolume = new LLVolume(volume_params, HIGHEST_LOD);
  760. }
  761. //virtual
  762. S8 LLImagePreviewSculpted::getType() const
  763. {
  764. return LLViewerDynamicTexture::LL_IMAGE_PREVIEW_SCULPTED;
  765. }
  766. void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance)
  767. {
  768. mCameraDistance = distance;
  769. mCameraZoom = 1.f;
  770. mCameraPitch = 0.f;
  771. mCameraYaw = 0.f;
  772. mCameraOffset.clear();
  773. if (imagep)
  774. {
  775. mVolume->sculpt(imagep->getWidth(), imagep->getHeight(),
  776. imagep->getComponents(), imagep->getData(), 0);
  777. }
  778. const LLVolumeFace& vf = mVolume->getVolumeFace(0);
  779. U32 num_indices = vf.mNumIndices;
  780. U32 num_vertices = vf.mNumVertices;
  781. mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX |
  782. LLVertexBuffer::MAP_NORMAL |
  783. LLVertexBuffer::MAP_TEXCOORD0);
  784. if (!mVertexBuffer->allocateBuffer(num_vertices, num_indices))
  785. {
  786. llwarns << "Failed to allocate vertex buffer for image preview with "
  787. << num_vertices << " vertices and " << num_indices
  788. << " indices. Aborting." << llendl;
  789. return;
  790. }
  791. LLStrider<LLVector3> vertex_strider;
  792. LLStrider<LLVector3> normal_strider;
  793. LLStrider<LLVector2> tc_strider;
  794. LLStrider<U16> index_strider;
  795. if (!mVertexBuffer->getVertexStrider(vertex_strider) ||
  796. !mVertexBuffer->getNormalStrider(normal_strider) ||
  797. !mVertexBuffer->getTexCoord0Strider(tc_strider) ||
  798. !mVertexBuffer->getIndexStrider(index_strider))
  799. {
  800. return;
  801. }
  802. // Build vertices and normals
  803. LLStrider<LLVector3> pos;
  804. pos = (LLVector3*)vf.mPositions;
  805. pos.setStride(16);
  806. LLStrider<LLVector3> norm;
  807. norm = (LLVector3*)vf.mNormals;
  808. norm.setStride(16);
  809. LLStrider<LLVector2> tc;
  810. tc = (LLVector2*)vf.mTexCoords;
  811. tc.setStride(8);
  812. for (U32 i = 0; i < num_vertices; i++)
  813. {
  814. *(vertex_strider++) = *pos++;
  815. LLVector3 normal = *norm++;
  816. normal.normalize();
  817. *(normal_strider++) = normal;
  818. *(tc_strider++) = *tc++;
  819. }
  820. // Build indices
  821. for (U16 i = 0; i < num_indices; i++)
  822. {
  823. *(index_strider++) = vf.mIndices[i];
  824. }
  825. mVertexBuffer->unmapBuffer();
  826. }
  827. bool LLImagePreviewSculpted::render()
  828. {
  829. mNeedsUpdate = false;
  830. LLGLSUIDefault def;
  831. LLGLDisable no_blend(GL_BLEND);
  832. LLGLEnable cull(GL_CULL_FACE);
  833. LLGLDepthTest depth(GL_TRUE);
  834. gGL.matrixMode(LLRender::MM_PROJECTION);
  835. gGL.pushMatrix();
  836. gGL.loadIdentity();
  837. gGL.ortho(0.f, mFullWidth, 0.f, mFullHeight, -1.f, 1.f);
  838. gGL.matrixMode(LLRender::MM_MODELVIEW);
  839. gGL.pushMatrix();
  840. gGL.loadIdentity();
  841. gGL.color4f(0.15f, 0.2f, 0.3f, 1.f);
  842. gUIProgram.bind();
  843. gl_rect_2d_simple(mFullWidth, mFullHeight);
  844. gGL.matrixMode(LLRender::MM_PROJECTION);
  845. gGL.popMatrix();
  846. gGL.matrixMode(LLRender::MM_MODELVIEW);
  847. gGL.popMatrix();
  848. glClear(GL_DEPTH_BUFFER_BIT);
  849. LLVector3 target_pos(0, 0, 0);
  850. LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) *
  851. LLQuaternion(mCameraYaw, LLVector3::z_axis);
  852. LLQuaternion av_rot = camera_rot;
  853. gViewerCamera.setOriginAndLookAt(target_pos +
  854. ((LLVector3(mCameraDistance, 0.f, 0.f) +
  855. mCameraOffset) * av_rot), // camera
  856. LLVector3::z_axis, // up
  857. // point of interest
  858. target_pos + mCameraOffset * av_rot);
  859. gViewerCamera.setAspect((F32)mFullWidth / (F32)mFullHeight);
  860. gViewerCamera.setViewNoBroadcast(gViewerCamera.getDefaultFOV() /
  861. mCameraZoom);
  862. gViewerCamera.setPerspective(false, mOrigin.mX, mOrigin.mY, mFullWidth,
  863. mFullHeight, false);
  864. const LLVolumeFace& vf = mVolume->getVolumeFace(0);
  865. U32 num_indices = vf.mNumIndices;
  866. LLVertexBuffer::unbind();
  867. gObjectPreviewProgram.bind();
  868. gPipeline.enableLightsPreview();
  869. gGL.pushMatrix();
  870. constexpr F32 SCALE = 1.25f;
  871. gGL.scalef(SCALE, SCALE, SCALE);
  872. constexpr F32 BRIGHTNESS = 0.9f;
  873. gGL.diffuseColor3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS);
  874. // Note: mask ignored in PBR rendering mode
  875. mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX |
  876. LLVertexBuffer::MAP_NORMAL |
  877. LLVertexBuffer::MAP_TEXCOORD0);
  878. mVertexBuffer->draw(LLRender::TRIANGLES, num_indices, 0);
  879. gGL.popMatrix();
  880. gObjectPreviewProgram.unbind();
  881. stop_glerror();
  882. return true;
  883. }
  884. void LLImagePreviewSculpted::refresh()
  885. {
  886. mNeedsUpdate = true;
  887. }
  888. void LLImagePreviewSculpted::rotate(F32 yaw_radians, F32 pitch_radians)
  889. {
  890. mCameraYaw = mCameraYaw + yaw_radians;
  891. mCameraPitch = llclamp(mCameraPitch + pitch_radians,
  892. F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f);
  893. }
  894. void LLImagePreviewSculpted::zoom(F32 zoom_amt)
  895. {
  896. mCameraZoom = llclamp(mCameraZoom + zoom_amt, 1.f, 10.f);
  897. }
  898. void LLImagePreviewSculpted::pan(F32 right, F32 up)
  899. {
  900. mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] +
  901. right * mCameraDistance / mCameraZoom,
  902. -1.f, 1.f);
  903. mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] +
  904. up * mCameraDistance / mCameraZoom,
  905. -1.f, 1.f);
  906. }