llviewerobjectexport.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551
  1. /**
  2. * @file llviewerobjectexport.cpp
  3. * @authors Latif Khalifa (DAE exporter) / Apelsin & Lirusaito (wavefront
  4. * exporter). Backported/adapted/optimized by Henri Beauchamp.
  5. *
  6. * $LicenseInfo:firstyear=2013&license=viewergpl$
  7. *
  8. * Second Life Viewer Source Code
  9. * The source code in this file ("Source Code") is provided by Linden Lab
  10. * to you under the terms of the GNU General Public License, version 2.0
  11. * ("GPL"), unless you have obtained a separate licensing agreement
  12. * ("Other License"), formally executed by you and Linden Lab. Terms of
  13. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  14. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  15. *
  16. * There are special exceptions to the terms and conditions of the GPL as
  17. * it is applied to this Source Code. View the full text of the exception
  18. * in the file doc/FLOSS-exception.txt in this software distribution, or
  19. * online at
  20. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  21. *
  22. * By copying, modifying or distributing this software, you acknowledge
  23. * that you have read and understood your obligations described above,
  24. * and agree to abide by those obligations.
  25. *
  26. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  27. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  28. * COMPLETENESS OR PERFORMANCE.
  29. * $/LicenseInfo$
  30. */
  31. #include "llviewerprecompiledheaders.h"
  32. #include "dae.h"
  33. #include "dom/domCOLLADA.h"
  34. #include "dom/domMatrix.h"
  35. #include "llviewerobjectexport.h"
  36. #include "llavatarappearancedefines.h"
  37. #include "llbutton.h"
  38. #include "llcallbacklist.h"
  39. #include "llcheckboxctrl.h"
  40. #include "llcombobox.h"
  41. #include "lldir.h"
  42. #include "llimagebmp.h"
  43. #include "llimagepng.h"
  44. #include "llimagej2c.h"
  45. #include "llimagejpeg.h"
  46. #include "llimagetga.h"
  47. #include "llnotifications.h"
  48. #include "lltextbox.h"
  49. #include "lluictrlfactory.h"
  50. #include "llvolume.h"
  51. #include "llagent.h"
  52. #include "llface.h"
  53. #include "llfloatertools.h"
  54. #include "hbobjectbackup.h"
  55. #include "llselectmgr.h"
  56. #include "lltexturecache.h"
  57. #include "lltoolcomp.h"
  58. #include "lltoolmgr.h"
  59. #include "llviewercontrol.h"
  60. #include "llviewerobject.h"
  61. #include "llvoavatarself.h"
  62. #include "llvovolume.h"
  63. ///////////////////////////////////////////////////////////////////////////////
  64. // Utility class used by the two exporters
  65. ///////////////////////////////////////////////////////////////////////////////
  66. class v4adapt
  67. {
  68. public:
  69. v4adapt(LLVector4a* vp)
  70. {
  71. mV4aStrider = vp;
  72. }
  73. LL_INLINE LLVector3 operator[](const size_t i)
  74. {
  75. return LLVector3((F32*)&mV4aStrider[i]);
  76. }
  77. private:
  78. LLStrider<LLVector4a> mV4aStrider;
  79. };
  80. ///////////////////////////////////////////////////////////////////////////////
  81. // Texture cache read responder for the Collada exporter & floater
  82. ///////////////////////////////////////////////////////////////////////////////
  83. class ExporterCacheReadResponder : public LLTextureCache::ReadResponder
  84. {
  85. protected:
  86. LOG_CLASS(ExporterCacheReadResponder);
  87. public:
  88. ExporterCacheReadResponder(const LLUUID& id, LLImageFormatted* image,
  89. std::string name, S32 img_type)
  90. : mFormattedImage(image),
  91. mID(id),
  92. mName(name),
  93. mImageType(img_type)
  94. {
  95. setImage(image);
  96. }
  97. void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat,
  98. bool imagelocal) override
  99. {
  100. if (imageformat == IMG_CODEC_TGA &&
  101. mFormattedImage->getCodec() == IMG_CODEC_J2C)
  102. {
  103. llwarns << "FAILED: texture " << mID
  104. << " is formatted as TGA. Not saving." << llendl;
  105. mFormattedImage = NULL;
  106. mImageSize = 0;
  107. return;
  108. }
  109. if (mFormattedImage.notNull())
  110. {
  111. if (mFormattedImage->getCodec() != imageformat)
  112. {
  113. llwarns << "FAILED: texture " << mID
  114. << " is formatted as " << mFormattedImage->getCodec()
  115. << " while expecting " << imageformat
  116. << ". Not saving." << llendl;
  117. mFormattedImage = NULL;
  118. mImageSize = 0;
  119. return;
  120. }
  121. mFormattedImage->appendData(data, datasize);
  122. }
  123. else
  124. {
  125. mFormattedImage = LLImageFormatted::createFromType(imageformat);
  126. mFormattedImage->setData(data, datasize);
  127. }
  128. mImageSize = imagesize;
  129. mImageLocal = imagelocal;
  130. }
  131. void started() override
  132. {
  133. }
  134. void completed(bool success) override
  135. {
  136. if (success && mFormattedImage.notNull() && mImageSize > 0)
  137. {
  138. bool ok = false;
  139. // If we are saving jpeg2000, no need to do anything, just write
  140. // to disk
  141. if (mImageType == LKDAESaver::ft_j2c)
  142. {
  143. mName += "." + mFormattedImage->getExtension();
  144. ok = mFormattedImage->save(mName);
  145. }
  146. // For other formats we need to decode first
  147. else if (mFormattedImage->updateData() &&
  148. mFormattedImage->getWidth() > 0 &&
  149. mFormattedImage->getHeight() > 0 &&
  150. mFormattedImage->getComponents() > 0)
  151. {
  152. LLPointer<LLImageRaw> raw = new LLImageRaw;
  153. raw->resize(mFormattedImage->getWidth(),
  154. mFormattedImage->getHeight(),
  155. mFormattedImage->getComponents());
  156. if (mFormattedImage->decode(raw))
  157. {
  158. LLPointer<LLImageFormatted> img = NULL;
  159. switch (mImageType)
  160. {
  161. case LKDAESaver::ft_tga:
  162. img = new LLImageTGA;
  163. break;
  164. case LKDAESaver::ft_png:
  165. img = new LLImagePNG;
  166. break;
  167. case LKDAESaver::ft_bmp:
  168. img = new LLImageBMP;
  169. break;
  170. case LKDAESaver::ft_jpg:
  171. img = new LLImageJPEG;
  172. }
  173. if (img.notNull() && img->encode(raw))
  174. {
  175. mName += "." + img->getExtension();
  176. ok = img->save(mName);
  177. }
  178. }
  179. }
  180. if (ok)
  181. {
  182. llinfos << "Saved texture to " << mName << llendl;
  183. }
  184. else
  185. {
  186. llwarns << "FAILED to save texture " << mID << llendl;
  187. }
  188. }
  189. else
  190. {
  191. llwarns << "FAILED to save texture " << mID << llendl;
  192. }
  193. }
  194. private:
  195. LLPointer<LLImageFormatted> mFormattedImage;
  196. LLUUID mID;
  197. S32 mImageType;
  198. std::string mName;
  199. };
  200. ///////////////////////////////////////////////////////////////////////////////
  201. // Floater for the Collada exporter
  202. ///////////////////////////////////////////////////////////////////////////////
  203. LKFloaterColladaExport::LKFloaterColladaExport(const LLSD&)
  204. : mTotal(0),
  205. mNumTextures(0),
  206. mNumExportableTextures(0)
  207. {
  208. LLUICtrlFactory::getInstance()->buildFloater(this,
  209. "floater_dae_export.xml");
  210. HBObjectBackup::setDefaultTextures();
  211. }
  212. //virtual
  213. LKFloaterColladaExport::~LKFloaterColladaExport()
  214. {
  215. gIdleCallbacks.deleteFunction(saveTexturesWorker, this);
  216. }
  217. //virtual
  218. bool LKFloaterColladaExport::postBuild()
  219. {
  220. addSelectedObjects();
  221. mTextureExportCheck = getChild<LLCheckBoxCtrl>("export_texture_check");
  222. mTextureExportCheck->setCommitCallback(onTextureExportCheck);
  223. mTextureExportCheck->setCallbackUserData(this);
  224. mTextureTypeCombo = getChild<LLComboBox>("texture_type_combo");
  225. const std::string& name = mTextureTypeCombo->getControlName();
  226. mTextureTypeCombo->setValue(gSavedSettings.getS32(name.c_str()));
  227. mExportButton = getChild<LLButton>("export_btn");
  228. mExportButton->setClickedCallback(onClickExport, this),
  229. mTitle = getString("export_progress");
  230. LLTextBox* text = getChild<LLTextBox>("object_name");
  231. text->setText(mObjectName);
  232. text = getChild<LLTextBox>("prims_count");
  233. text->setText(llformat("%d/%d", mSaver.mObjects.size(), mTotal));
  234. text = getChild<LLTextBox>("textures_count");
  235. text->setText(llformat("%d/%d", mNumExportableTextures, mNumTextures));
  236. onTextureExportCheck(mTextureExportCheck, this);
  237. return true;
  238. }
  239. void LKFloaterColladaExport::addSelectedObjects()
  240. {
  241. if (mSaver.addSelectedObjects(mObjectName, mTotal))
  242. {
  243. mNumTextures = mSaver.mTextures.size();
  244. mNumExportableTextures = 0;
  245. for (LKDAESaver::string_list_t::const_iterator
  246. it = mSaver.mTextureNames.begin(),
  247. end = mSaver.mTextureNames.end();
  248. it != end; ++it)
  249. {
  250. std::string name = *it;
  251. if (!name.empty())
  252. {
  253. ++mNumExportableTextures;
  254. }
  255. }
  256. }
  257. else
  258. {
  259. gNotifications.add("ExportFailed");
  260. close();
  261. }
  262. }
  263. void LKFloaterColladaExport::updateTitleProgress()
  264. {
  265. std::string title = llformat(mTitle.c_str(), mTexturesToSave.size());
  266. setTitle(title);
  267. }
  268. void LKFloaterColladaExport::saveDAE()
  269. {
  270. if (mSaver.saveDAE(mFilename))
  271. {
  272. llinfos << "DAE file saved to: " << mFilename << llendl;
  273. gNotifications.add("ExportSuccessful");
  274. }
  275. else
  276. {
  277. llwarns << "Failed to save the DAE file to: " << mFilename
  278. << llendl;
  279. gNotifications.add("ExportFailed");
  280. }
  281. close();
  282. }
  283. void LKFloaterColladaExport::saveTextures()
  284. {
  285. llinfos << "Saving textures..." << llendl;
  286. mTexturesToSave.clear();
  287. for (S32 i = 0, count = mSaver.mTextures.size(); i < count; ++i)
  288. {
  289. if (!mSaver.mTextureNames[i].empty())
  290. {
  291. mTexturesToSave[mSaver.mTextures[i]] = mSaver.mTextureNames[i];
  292. }
  293. }
  294. S32 img_format = mTextureTypeCombo->getValue().asInteger();
  295. mSaver.mImageFormat = LKDAESaver::image_format_ext[img_format];
  296. constexpr F32 TEXTURE_DOWNLOAD_TIMEOUT = 60.f;
  297. mTimer.setTimerExpirySec(TEXTURE_DOWNLOAD_TIMEOUT);
  298. mTimer.start();
  299. updateTitleProgress();
  300. gIdleCallbacks.addFunction(saveTexturesWorker, this);
  301. }
  302. //static
  303. void LKFloaterColladaExport::onTextureExportCheck(LLUICtrl* ctrl, void* data)
  304. {
  305. LKFloaterColladaExport* self = (LKFloaterColladaExport*)data;
  306. if (self && ctrl)
  307. {
  308. self->mTextureTypeCombo->setEnabled(ctrl->getValue().asBoolean());
  309. }
  310. }
  311. //static
  312. void LKFloaterColladaExport::onClickExport(void* data)
  313. {
  314. LKFloaterColladaExport* self = (LKFloaterColladaExport*)data;
  315. if (self)
  316. {
  317. std::string suggestion =
  318. LLDir::getScrubbedFileName(self->mObjectName) + ".dae";
  319. HBFileSelector::saveFile(HBFileSelector::FFSAVE_DAE, suggestion,
  320. filePickerCallback, data);
  321. }
  322. }
  323. //static
  324. void LKFloaterColladaExport::filePickerCallback(HBFileSelector::ESaveFilter type,
  325. std::string& filename,
  326. void* data)
  327. {
  328. LKFloaterColladaExport* self = (LKFloaterColladaExport*)data;
  329. if (self && !filename.empty())
  330. {
  331. llinfos << "Saving: " << filename << llendl;
  332. self->mFilename = filename;
  333. self->mFolder = gDirUtil.getDirName(filename) + LL_DIR_DELIM_STR;
  334. self->mExportButton->setEnabled(false);
  335. if (self->mTextureExportCheck->get())
  336. {
  337. self->saveTextures();
  338. }
  339. else
  340. {
  341. self->saveDAE();
  342. }
  343. }
  344. }
  345. //static
  346. void LKFloaterColladaExport::saveTexturesWorker(void* data)
  347. {
  348. LKFloaterColladaExport* self = (LKFloaterColladaExport*)data;
  349. if (self->mTexturesToSave.size() == 0)
  350. {
  351. llinfos << "Done saving textures" << llendl;
  352. self->updateTitleProgress();
  353. gIdleCallbacks.deleteFunction(saveTexturesWorker, self);
  354. self->mTimer.stop();
  355. self->saveDAE();
  356. return;
  357. }
  358. LLUUID id = self->mTexturesToSave.begin()->first;
  359. LLViewerTexture* imagep = LLViewerTextureManager::findTexture(id);
  360. if (!imagep)
  361. {
  362. self->mTexturesToSave.erase(id);
  363. self->updateTitleProgress();
  364. self->mTimer.reset();
  365. }
  366. else if (imagep->getDiscardLevel() == 0) // Image download is complete
  367. {
  368. llinfos << "Saving texture " << id << llendl;
  369. LLImageFormatted* img = new LLImageJ2C;
  370. S32 img_type = self->mTextureTypeCombo->getValue();
  371. std::string name = self->mFolder + self->mTexturesToSave[id];
  372. ExporterCacheReadResponder* responder =
  373. new ExporterCacheReadResponder(id, img, name, img_type);
  374. gTextureCachep->readFromCache(id, 0, 999999, responder);
  375. self->mTexturesToSave.erase(id);
  376. self->updateTitleProgress();
  377. self->mTimer.reset();
  378. }
  379. else if (self->mTimer.hasExpired())
  380. {
  381. llwarns << "Timed out downloading texture " << id << llendl;
  382. self->mTexturesToSave.erase(id);
  383. self->updateTitleProgress();
  384. self->mTimer.reset();
  385. }
  386. }
  387. ///////////////////////////////////////////////////////////////////////////////
  388. // Collada exporter
  389. ///////////////////////////////////////////////////////////////////////////////
  390. const std::string LKDAESaver::image_format_ext[] =
  391. {
  392. "tga", "png", "j2c", "bmp", "jpg"
  393. };
  394. void LKDAESaver::add(LLViewerObject* prim, const std::string& name)
  395. {
  396. mObjects.emplace_back(prim, name);
  397. }
  398. void LKDAESaver::updateTextureInfo()
  399. {
  400. mTextures.clear();
  401. mTextureNames.clear();
  402. for (obj_info_t::iterator it = mObjects.begin(), end = mObjects.end();
  403. it != end; ++it)
  404. {
  405. LLViewerObject* obj = it->first;
  406. S32 num_faces = obj->getVolume()->getNumVolumeFaces();
  407. for (S32 f = 0; f < num_faces; ++f)
  408. {
  409. LLTextureEntry* te = obj->getTE(f);
  410. const LLUUID& id = te->getID();
  411. uuid_vec_t::iterator texend = mTextures.end();
  412. if (std::find(mTextures.begin(), texend, id) == texend)
  413. {
  414. mTextures.emplace_back(id);
  415. if (HBObjectBackup::validateAssetPerms(id))
  416. {
  417. mTextureNames.emplace_back(id.asString());
  418. }
  419. else
  420. {
  421. mTextureNames.emplace_back(LLStringUtil::null);
  422. }
  423. }
  424. }
  425. }
  426. }
  427. void LKDAESaver::addSource(daeElement* mesh, const char* src_id,
  428. std::string params, const std::vector<F32>& vals)
  429. {
  430. daeElement* source = mesh->add("source");
  431. source->setAttribute("id", src_id);
  432. daeElement* src_array = source->add("float_array");
  433. src_array->setAttribute("id", llformat("%s-array", src_id).c_str());
  434. src_array->setAttribute("count", llformat("%d", vals.size()).c_str());
  435. domFloat_array* float_array = (domFloat_array*)src_array;
  436. for (S32 i = 0, count = vals.size(); i < count; ++i)
  437. {
  438. float_array->getValue().append(vals[i]);
  439. }
  440. domAccessor* acc =
  441. daeSafeCast<domAccessor>(source->add("technique_common accessor"));
  442. acc->setSource(llformat("#%s-array", src_id).c_str());
  443. acc->setCount(vals.size() / params.size());
  444. acc->setStride(params.size());
  445. for (std::string::iterator it = params.begin(), end = params.end();
  446. it != end; ++it)
  447. {
  448. domElement* px = acc->add("param");
  449. px->setAttribute("name", llformat("%c", *it).c_str());
  450. px->setAttribute("type", "float");
  451. }
  452. }
  453. void LKDAESaver::addPolygons(daeElement* mesh, const char* geom_id,
  454. const char* mat_id, LLViewerObject* obj,
  455. int_list_t* faces_to_include)
  456. {
  457. domPolylist* polylist = daeSafeCast<domPolylist>(mesh->add("polylist"));
  458. polylist->setMaterial(mat_id);
  459. // Vertices semantic
  460. domInputLocalOffset* input =
  461. daeSafeCast<domInputLocalOffset>(polylist->add("input"));
  462. input->setSemantic("VERTEX");
  463. input->setOffset(0);
  464. input->setSource(llformat("#%s-vertices", geom_id).c_str());
  465. // Normals semantic
  466. input = daeSafeCast<domInputLocalOffset>(polylist->add("input"));
  467. input->setSemantic("NORMAL");
  468. input->setOffset(0);
  469. input->setSource(llformat("#%s-normals", geom_id).c_str());
  470. static LLCachedControl<bool> single_uv_map(gSavedSettings,
  471. "DAEExportSingleUVMap");
  472. // UV semantic
  473. input = daeSafeCast<domInputLocalOffset>(polylist->add("input"));
  474. input->setSemantic("TEXCOORD");
  475. input->setOffset(0);
  476. if (single_uv_map)
  477. {
  478. input->setSource("#unified-map0");
  479. }
  480. else
  481. {
  482. input->setSource(llformat("#%s-map0", geom_id).c_str());
  483. }
  484. // Save indices
  485. domP* p = daeSafeCast<domP>(polylist->add("p"));
  486. domPolylist::domVcount* vcount =
  487. daeSafeCast<domPolylist::domVcount>(polylist->add("vcount"));
  488. S32 index_offset = 0;
  489. S32 num_tris = 0;
  490. for (S32 f = 0; f < obj->getVolume()->getNumVolumeFaces(); ++f)
  491. {
  492. if (skipFace(obj->getTE(f))) continue;
  493. const LLVolumeFace* face =
  494. (LLVolumeFace*)&obj->getVolume()->getVolumeFace(f);
  495. if (face &&
  496. (!faces_to_include ||
  497. (std::find(faces_to_include->begin(), faces_to_include->end(),
  498. f) != faces_to_include->end())))
  499. {
  500. for (S32 i = 0; i < face->mNumIndices; ++i)
  501. {
  502. U16 index = index_offset + face->mIndices[i];
  503. (p->getValue()).append(index);
  504. if (i % 3 == 0)
  505. {
  506. (vcount->getValue()).append(3);
  507. ++num_tris;
  508. }
  509. }
  510. }
  511. index_offset += face->mNumVertices;
  512. }
  513. polylist->setCount(num_tris);
  514. }
  515. void LKDAESaver::transformTexCoord(S32 num_vert, LLVector2* coord,
  516. LLVector3* positions, LLVector3* normals,
  517. LLTextureEntry* te, LLVector3 scale)
  518. {
  519. F32 cosine = cosf(te->getRotation());
  520. F32 sine = sinf(te->getRotation());
  521. for (S32 ii = 0; ii < num_vert; ++ii)
  522. {
  523. if (LLTextureEntry::TEX_GEN_PLANAR == te->getTexGen())
  524. {
  525. LLVector3 normal = normals[ii];
  526. LLVector3 pos = positions[ii];
  527. LLVector3 binormal;
  528. F32 d = normal * LLVector3::x_axis;
  529. if (d >= 0.5f || d <= -0.5f)
  530. {
  531. binormal = LLVector3::y_axis;
  532. if (normal.mV[0] < 0.f)
  533. {
  534. binormal *= -1.f;
  535. }
  536. }
  537. else
  538. {
  539. binormal = LLVector3::x_axis;
  540. if (normal.mV[1] > 0.f)
  541. {
  542. binormal *= -1.f;
  543. }
  544. }
  545. LLVector3 tangent = binormal % normal;
  546. LLVector3 scaled_pos = pos.scaledVec(scale);
  547. coord[ii].mV[0] = 1.f + ((binormal * scaled_pos) * 2.f - 0.5f);
  548. coord[ii].mV[1] = -((tangent * scaled_pos) * 2.f - 0.5f);
  549. }
  550. F32 repeatU;
  551. F32 repeatV;
  552. te->getScale(&repeatU, &repeatV);
  553. F32 tX = coord[ii].mV[0] - 0.5f;
  554. F32 tY = coord[ii].mV[1] - 0.5f;
  555. F32 offsetU;
  556. F32 offsetV;
  557. te->getOffset(&offsetU, &offsetV);
  558. coord[ii].mV[0] = (tX * cosine + tY * sine) * repeatU + offsetU + 0.5f;
  559. coord[ii].mV[1] = (-tX * sine + tY * cosine) * repeatV + offsetV + 0.5f;
  560. }
  561. }
  562. bool LKDAESaver::saveDAE(std::string filename)
  563. {
  564. mAllMaterials.clear();
  565. mTotalNumMaterials = 0;
  566. DAE dae;
  567. // First set the filename to save
  568. daeElement* root = dae.add(filename);
  569. // Obligatory elements in header
  570. daeElement* asset = root->add("asset");
  571. // Get ISO format time
  572. time_t rawtime;
  573. time(&rawtime);
  574. struct tm* utc_time = gmtime(&rawtime);
  575. std::string date = llformat("%04d-%02d-%02dT%02d:%02d:%02d",
  576. utc_time->tm_year + 1900, utc_time->tm_mon + 1,
  577. utc_time->tm_mday, utc_time->tm_hour,
  578. utc_time->tm_min, utc_time->tm_sec);
  579. daeElement* created = asset->add("created");
  580. created->setCharData(date);
  581. daeElement* modified = asset->add("modified");
  582. modified->setCharData(date);
  583. daeElement* unit = asset->add("unit");
  584. unit->setAttribute("name", "meter");
  585. unit->setAttribute("value", "1");
  586. daeElement* up_axis = asset->add("up_axis");
  587. up_axis->setCharData("Z_UP");
  588. // File creator
  589. daeElement* contributor = asset->add("contributor");
  590. std::string name;
  591. gAgent.getName(name);
  592. contributor->add("author")->setCharData(name);
  593. contributor->add("authoring_tool")->setCharData(gSecondLife +
  594. " Collada Export");
  595. daeElement* images = root->add("library_images");
  596. daeElement* geom_lib = root->add("library_geometries");
  597. daeElement* effects = root->add("library_effects");
  598. daeElement* materials = root->add("library_materials");
  599. daeElement* scene = root->add("library_visual_scenes visual_scene");
  600. scene->setAttribute("id", "Scene");
  601. scene->setAttribute("name", "Scene");
  602. if (gSavedSettings.getBool("DAEExportTextures"))
  603. {
  604. generateImagesSection(images);
  605. }
  606. bool apply_tex_coord = gSavedSettings.getBool("DAEExportTextureParams");
  607. bool consolidate = gSavedSettings.getBool("DAEExportConsolidateMaterials");
  608. bool single_uv_map = gSavedSettings.getBool("DAEExportSingleUVMap");
  609. S32 prim_nr = 0;
  610. std::string matname;
  611. for (obj_info_t::iterator it = mObjects.begin(), end = mObjects.end();
  612. it != end; ++it)
  613. {
  614. LLViewerObject* obj = it->first;
  615. name = llformat("prim%d", prim_nr++);
  616. const char* geom_id = name.c_str();
  617. daeElement* geom = geom_lib->add("geometry");
  618. geom->setAttribute("id", llformat("%s-mesh", geom_id).c_str());
  619. daeElement* mesh = geom->add("mesh");
  620. std::vector<F32> position_data, normal_data, uv_data;
  621. S32 num_faces = obj->getVolume()->getNumVolumeFaces();
  622. for (S32 f = 0; f < num_faces; ++f)
  623. {
  624. if (skipFace(obj->getTE(f))) continue;
  625. const LLVolumeFace* face =
  626. (LLVolumeFace*)&obj->getVolume()->getVolumeFace(f);
  627. v4adapt verts(face->mPositions);
  628. v4adapt norms(face->mNormals);
  629. LLVector2* new_coord = NULL;
  630. if (apply_tex_coord)
  631. {
  632. new_coord = new LLVector2[face->mNumVertices];
  633. LLVector3* new_pos = new LLVector3[face->mNumVertices];
  634. LLVector3* new_norm = new LLVector3[face->mNumVertices];
  635. for (S32 i = 0; i < face->mNumVertices; ++i)
  636. {
  637. new_pos[i] = verts[i];
  638. new_norm[i] = norms[i];
  639. new_coord[i] = face->mTexCoords[i];
  640. }
  641. transformTexCoord(face->mNumVertices, new_coord, new_pos,
  642. new_norm, obj->getTE(f), obj->getScale());
  643. delete[] new_pos;
  644. delete[] new_norm;
  645. }
  646. for (S32 i = 0, count = face->mNumVertices; i < count; ++i)
  647. {
  648. const LLVector3& v = verts[i];
  649. position_data.push_back(v.mV[VX]);
  650. position_data.push_back(v.mV[VY]);
  651. position_data.push_back(v.mV[VZ]);
  652. const LLVector3& n = norms[i];
  653. normal_data.push_back(n.mV[VX]);
  654. normal_data.push_back(n.mV[VY]);
  655. normal_data.push_back(n.mV[VZ]);
  656. const LLVector2& uv = apply_tex_coord ? new_coord[i]
  657. : face->mTexCoords[i];
  658. uv_data.push_back(uv.mV[VX]);
  659. uv_data.push_back(uv.mV[VY]);
  660. }
  661. if (apply_tex_coord)
  662. {
  663. delete[] new_coord;
  664. }
  665. }
  666. addSource(mesh, llformat("%s-positions", geom_id).c_str(), "XYZ",
  667. position_data);
  668. addSource(mesh, llformat("%s-normals", geom_id).c_str(), "XYZ",
  669. normal_data);
  670. if (single_uv_map)
  671. {
  672. addSource(mesh, "unified-map0", "ST", uv_data);
  673. }
  674. else
  675. {
  676. addSource(mesh, llformat("%s-map0", geom_id).c_str(), "ST",
  677. uv_data);
  678. }
  679. // Add the <vertices> element
  680. daeElement* vert_node = mesh->add("vertices");
  681. vert_node->setAttribute("id",
  682. llformat("%s-vertices", geom_id).c_str());
  683. daeElement* vert_input = vert_node->add("input");
  684. vert_input->setAttribute("semantic", "POSITION");
  685. vert_input->setAttribute("source",
  686. llformat("#%s-positions", geom_id).c_str());
  687. material_list_t obj_mats;
  688. getMaterials(obj, &obj_mats);
  689. // Add triangles
  690. if (consolidate)
  691. {
  692. for (U32 mat = 0; mat < obj_mats.size(); ++mat)
  693. {
  694. int_list_t faces;
  695. getFacesWithMaterial(obj, obj_mats[mat], &faces);
  696. matname = obj_mats[mat].mName + "-material";
  697. addPolygons(mesh, geom_id, matname.c_str(), obj, &faces);
  698. }
  699. }
  700. else
  701. {
  702. S32 mat_nr = 0;
  703. for (S32 f = 0; f < num_faces; ++f)
  704. {
  705. if (!skipFace(obj->getTE(f)))
  706. {
  707. int_list_t faces;
  708. faces.push_back(f);
  709. matname = obj_mats[mat_nr++].mName + "-material";
  710. addPolygons(mesh, geom_id, matname.c_str(), obj, &faces);
  711. }
  712. }
  713. }
  714. daeElement* node = scene->add("node");
  715. node->setAttribute("type", "NODE");
  716. node->setAttribute("id", geom_id);
  717. node->setAttribute("name", geom_id);
  718. // Set tranform matrix (node position, rotation and scale)
  719. domMatrix* matrix = (domMatrix*)node->add("matrix");
  720. LLXform srt;
  721. srt.setScale(obj->getScale());
  722. srt.setPosition(obj->getRenderPosition() + mOffset);
  723. srt.setRotation(obj->getRenderRotation());
  724. LLMatrix4 m4;
  725. srt.getLocalMat4(m4);
  726. for (S32 i = 0; i < 4; ++i)
  727. {
  728. for (S32 j = 0; j < 4; ++j)
  729. {
  730. (matrix->getValue()).append(m4.mMatrix[j][i]);
  731. }
  732. }
  733. // Geometry of the node
  734. daeElement* node_geom = node->add("instance_geometry");
  735. // Bind materials
  736. daeElement* tq = node_geom->add("bind_material technique_common");
  737. for (S32 i = 0, count = obj_mats.size(); i < count; ++i)
  738. {
  739. matname = obj_mats[i].mName + "-material";
  740. daeElement* mat = tq->add("instance_material");
  741. mat->setAttribute("symbol", matname.c_str());
  742. mat->setAttribute("target", ("#" + matname).c_str());
  743. }
  744. node_geom->setAttribute("url", llformat("#%s-mesh", geom_id).c_str());
  745. }
  746. // Effects (face texture, color, alpha)
  747. generateEffects(effects);
  748. // Materials
  749. for (S32 i = 0, count = mAllMaterials.size(); i < count; ++i)
  750. {
  751. daeElement* mat = materials->add("material");
  752. matname = mAllMaterials[i].mName;
  753. mat->setAttribute("id", (matname + "-material").c_str());
  754. daeElement* effect = mat->add("instance_effect");
  755. effect->setAttribute("url", ("#" + matname + "-fx").c_str());
  756. }
  757. root->add("scene instance_visual_scene")->setAttribute("url", "#Scene");
  758. return dae.writeAll();
  759. }
  760. bool LKDAESaver::skipFace(LLTextureEntry* te)
  761. {
  762. static LLCachedControl<bool> no_trans(gSavedSettings,
  763. "DAEExportSkipTransparent");
  764. return no_trans &&
  765. (te->isTransparent() || te->getID() == gTextureTransparent);
  766. }
  767. LKDAESaver::MaterialInfo LKDAESaver::getMaterial(LLTextureEntry* te)
  768. {
  769. static LLCachedControl<bool> consolidate(gSavedSettings,
  770. "DAEExportConsolidateMaterials");
  771. if (consolidate)
  772. {
  773. for (S32 i = 0, count = mAllMaterials.size(); i < count; ++i)
  774. {
  775. if (mAllMaterials[i].matches(te))
  776. {
  777. return mAllMaterials[i];
  778. }
  779. }
  780. }
  781. std::string name = llformat("Material%d", mAllMaterials.size());
  782. mAllMaterials.emplace_back(te->getID(), te->getColor(), name);
  783. return mAllMaterials[mAllMaterials.size() - 1];
  784. }
  785. void LKDAESaver::getMaterials(LLViewerObject* obj, material_list_t* ret)
  786. {
  787. static LLCachedControl<bool> consolidate(gSavedSettings,
  788. "DAEExportConsolidateMaterials");
  789. S32 num_faces = obj->getVolume()->getNumVolumeFaces();
  790. for (S32 f = 0; f < num_faces; ++f)
  791. {
  792. LLTextureEntry* te = obj->getTE(f);
  793. if (!te || skipFace(te))
  794. {
  795. continue;
  796. }
  797. MaterialInfo mat = getMaterial(te);
  798. if (!consolidate ||
  799. std::find(ret->begin(), ret->end(), mat) == ret->end())
  800. {
  801. ret->emplace_back(mat);
  802. }
  803. }
  804. }
  805. void LKDAESaver::getFacesWithMaterial(LLViewerObject* obj,
  806. MaterialInfo& mat, int_list_t* ret)
  807. {
  808. S32 num_faces = obj->getVolume()->getNumVolumeFaces();
  809. for (S32 f = 0; f < num_faces; ++f)
  810. {
  811. if (mat == getMaterial(obj->getTE(f)))
  812. {
  813. ret->push_back(f);
  814. }
  815. }
  816. }
  817. void LKDAESaver::generateEffects(daeElement* effects)
  818. {
  819. // Effects (face color, alpha)
  820. static LLCachedControl<bool> export_textures(gSavedSettings,
  821. "DAEExportTextures");
  822. std::string dae_name;
  823. for (S32 mat = 0, count = mAllMaterials.size(); mat < count; ++mat)
  824. {
  825. LLColor4 color = mAllMaterials[mat].mColor;
  826. domEffect* effect = (domEffect*)effects->add("effect");
  827. effect->setId((mAllMaterials[mat].mName + "-fx").c_str());
  828. daeElement* profile = effect->add("profile_COMMON");
  829. if (export_textures)
  830. {
  831. LLUUID tex_id;
  832. S32 i = 0;
  833. S32 count = mTextures.size();
  834. for ( ; i < count; ++i)
  835. {
  836. if (mAllMaterials[mat].mTextureID == mTextures[i])
  837. {
  838. tex_id = mTextures[i];
  839. break;
  840. }
  841. }
  842. if (!tex_id.isNull() && !mTextureNames[i].empty())
  843. {
  844. dae_name = mTextureNames[i] + "_" + mImageFormat;
  845. daeElement* newparam = profile->add("newparam");
  846. newparam->setAttribute("sid", (dae_name + "-surface").c_str());
  847. daeElement* surface = newparam->add("surface");
  848. surface->setAttribute("type", "2D");
  849. surface->add("init_from")->setCharData(dae_name.c_str());
  850. newparam = profile->add("newparam");
  851. newparam->setAttribute("sid", (dae_name + "-sampler").c_str());
  852. newparam->add("sampler2D source")->setCharData((dae_name +
  853. "-surface").c_str());
  854. }
  855. }
  856. daeElement* t = profile->add("technique");
  857. t->setAttribute("sid", "common");
  858. domElement* phong = t->add("phong");
  859. domElement* diffuse = phong->add("diffuse");
  860. // Only one <color> or <texture> can appear inside diffuse element
  861. if (!dae_name.empty())
  862. {
  863. daeElement* tex = diffuse->add("texture");
  864. tex->setAttribute("texture", (dae_name + "-sampler").c_str());
  865. tex->setAttribute("texcoord", dae_name.c_str());
  866. }
  867. else
  868. {
  869. daeElement* diff_color = diffuse->add("color");
  870. diff_color->setAttribute("sid", "diffuse");
  871. diff_color->setCharData(llformat("%f %f %f %f", color.mV[0],
  872. color.mV[1], color.mV[2],
  873. color.mV[3]).c_str());
  874. phong->add("transparency float")->setCharData(llformat("%f",
  875. color.mV[3]).c_str());
  876. }
  877. }
  878. }
  879. void LKDAESaver::generateImagesSection(daeElement* images)
  880. {
  881. std::string dae_name;
  882. for (S32 i = 0, count = mTextureNames.size(); i < count; ++i)
  883. {
  884. std::string name = mTextureNames[i];
  885. if (name.empty()) continue;
  886. dae_name = name + "_" + mImageFormat;
  887. daeElement* image = images->add("image");
  888. image->setAttribute("id", dae_name.c_str());
  889. image->setAttribute("name", dae_name.c_str());
  890. image->add("init_from")->setCharData(LLURI::escape(name + "." +
  891. mImageFormat));
  892. }
  893. }
  894. bool LKDAESaver::addSelectedObjects(std::string& root_name, U32& total)
  895. {
  896. LLObjectSelectionHandle selection = gSelectMgr.getSelection();
  897. if (selection && selection->getFirstRootObject())
  898. {
  899. mOffset = -selection->getFirstRootObject()->getRenderPosition();
  900. root_name = selection->getFirstRootNode()->mName;
  901. total = 0;
  902. for (LLObjectSelection::iterator iter = selection->begin(),
  903. end = selection->end();
  904. iter != end; ++iter)
  905. {
  906. ++total;
  907. LLSelectNode* node = *iter;
  908. if (node->getObject()->getVolume() &&
  909. HBObjectBackup::validateNode(node))
  910. {
  911. add(node->getObject(), node->mName);
  912. }
  913. }
  914. if (mObjects.empty())
  915. {
  916. return false;
  917. }
  918. updateTextureInfo();
  919. return true;
  920. }
  921. return false;
  922. }
  923. ///////////////////////////////////////////////////////////////////////////////
  924. // Wavefront exporter
  925. ///////////////////////////////////////////////////////////////////////////////
  926. // Same typedef as the protected one in ../llappearance/llavatarappearance.cpp
  927. typedef std::vector<LLAvatarJoint*> avatar_joint_list_t;
  928. ALWavefront::ALWavefront(vert_t v, tri_t t)
  929. : mVertices(v),
  930. mTriangles(t)
  931. {
  932. }
  933. ALWavefront::ALWavefront(const LLVolumeFace* face, const LLXform* transform,
  934. const LLXform* transform_normals)
  935. {
  936. v4adapt verts(face->mPositions);
  937. for (S32 i = 0, count = face->mNumVertices; i < count; ++i)
  938. {
  939. LLVector3 v = verts[i];
  940. mVertices.emplace_back(v, face->mTexCoords[i]);
  941. }
  942. if (transform)
  943. {
  944. Transform(mVertices, transform);
  945. }
  946. v4adapt norms(face->mNormals);
  947. for (S32 i = 0, count = face->mNumVertices; i < count; ++i)
  948. {
  949. mNormals.push_back(norms[i]);
  950. }
  951. if (transform_normals)
  952. {
  953. Transform(mNormals, transform_normals);
  954. }
  955. for (S32 i = 0, count = face->mNumIndices / 3; i < count; ++i)
  956. {
  957. mTriangles.emplace_back(face->mIndices[i * 3],
  958. face->mIndices[i * 3 + 1],
  959. face->mIndices[i * 3 + 2]);
  960. }
  961. }
  962. ALWavefront::ALWavefront(LLFace* face, LLPolyMesh* mesh,
  963. const LLXform* transform,
  964. const LLXform* transform_normals)
  965. {
  966. LLVertexBuffer* vb = face->getVertexBuffer();
  967. if (!mesh && !vb) return;
  968. LLStrider<LLVector3> getVerts;
  969. LLStrider<LLVector3> getNorms;
  970. LLStrider<LLVector2> getCoord;
  971. LLStrider<U16> getIndices;
  972. face->getGeometry(getVerts, getNorms, getCoord, getIndices);
  973. const S32 start = face->getGeomStart();
  974. const S32 end = start + (mesh ? mesh->getNumVertices()
  975. : vb->getNumVerts()) - 1;
  976. for (S32 i = start; i <= end; ++i)
  977. {
  978. mVertices.emplace_back(getVerts[i], getCoord[i]);
  979. }
  980. if (transform)
  981. {
  982. Transform(mVertices, transform);
  983. }
  984. for (S32 i = start; i <= end; ++i)
  985. {
  986. mNormals.push_back(getNorms[i]);
  987. }
  988. if (transform_normals)
  989. {
  990. Transform(mNormals, transform_normals);
  991. }
  992. const S32 pcount = mesh ? mesh->getNumFaces() : vb->getNumIndices() / 3;
  993. const S32 offset = face->getIndicesStart();
  994. for (S32 i = 0; i < pcount; ++i)
  995. {
  996. mTriangles.emplace_back(getIndices[i * 3 + offset] + start,
  997. getIndices[i * 3 + 1 + offset] + start,
  998. getIndices[i * 3 + 2 + offset] + start);
  999. }
  1000. }
  1001. // recursive
  1002. void ALWavefront::Transform(vert_t& v, const LLXform* x)
  1003. {
  1004. LLMatrix4 m;
  1005. x->getLocalMat4(m);
  1006. for (vert_t::iterator it = v.begin(), end = v.end(); it != end; ++it)
  1007. {
  1008. it->first = it->first * m;
  1009. }
  1010. if (const LLXform* xp = x->getParent())
  1011. {
  1012. Transform(v, xp);
  1013. }
  1014. }
  1015. // Recursive
  1016. void ALWavefront::Transform(vec3_t& v, const LLXform* x)
  1017. {
  1018. LLMatrix4 m;
  1019. x->getLocalMat4(m);
  1020. for (vec3_t::iterator it = v.begin(), end = v.end(); it != end; ++it)
  1021. {
  1022. *it = *it * m;
  1023. }
  1024. if (const LLXform* xp = x->getParent())
  1025. {
  1026. Transform(v, xp);
  1027. }
  1028. }
  1029. void ALWavefrontSaver::add(const ALWavefront& obj)
  1030. {
  1031. mWavefrontObjects.push_back(obj);
  1032. }
  1033. void ALWavefrontSaver::add(const LLVolume* vol, const LLXform* transform,
  1034. const LLXform* transform_normals)
  1035. {
  1036. for (S32 i = 0, faces = vol->getNumVolumeFaces(); i < faces; ++i)
  1037. {
  1038. add(ALWavefront(&vol->getVolumeFace(i), transform, transform_normals));
  1039. }
  1040. }
  1041. void ALWavefrontSaver::add(const LLViewerObject* some_vo)
  1042. {
  1043. LLXform v_form;
  1044. v_form.setScale(some_vo->getScale());
  1045. v_form.setPosition(some_vo->getRenderPosition());
  1046. v_form.setRotation(some_vo->getRenderRotation());
  1047. LLXform normfix;
  1048. normfix.setRotation(v_form.getRotation()); // Should work...
  1049. add(some_vo->getVolume(), &v_form, &normfix);
  1050. }
  1051. #if LL_EXPORT_AVATAR_OBJ
  1052. bool ALWavefrontSaver::add(const LLVOAvatar* av_vo, bool with_attachments)
  1053. {
  1054. mOffset = -av_vo->getRenderPosition();
  1055. const avatar_joint_list_t vjv = const_cast<LLVOAvatar*>(av_vo)->getMeshLOD();
  1056. for (avatar_joint_list_t::const_iterator it = vjv.begin(), end = vjv.end();
  1057. it != end; ++it)
  1058. {
  1059. const LLViewerJoint* vj = dynamic_cast<LLViewerJoint*>(*it);
  1060. if (!vj || vj->mMeshParts.empty()) continue;
  1061. // 0 = highest LOD
  1062. LLViewerJointMesh* vjm = dynamic_cast<LLViewerJointMesh*>(vj->mMeshParts[0]);
  1063. if (!vjm) continue;
  1064. vjm->updateJointGeometry();
  1065. LLFace* face = vjm->getFace();
  1066. if (!face) continue;
  1067. // Beware: this is a hack because LLFace has multiple LODs; 'pm'
  1068. // supplies the right number of vertices and triangles !
  1069. LLPolyMesh* pm = vjm->getMesh();
  1070. if (!pm) continue;
  1071. LLXform normfix;
  1072. normfix.setRotation(pm->getRotation());
  1073. // Special case for eyeballs
  1074. static const std::string eyeLname =
  1075. gAvatarAppDictp->getMeshEntry(LLAvatarAppearanceDefines::MESH_ID_EYEBALL_LEFT)->mName;
  1076. static const std::string eyeRname =
  1077. gAvatarAppDictp->getMeshEntry(LLAvatarAppearanceDefines::MESH_ID_EYEBALL_RIGHT)->mName;
  1078. const std::string name = vj->getName();
  1079. LL_DEBUGS("OBJExporter") << "Exporting joint: " << name << LL_ENDL;
  1080. if (name == eyeLname || name == eyeRname)
  1081. {
  1082. LLXform lol;
  1083. lol.setPosition(-mOffset);
  1084. add(ALWavefront(face, pm, &lol, &normfix));
  1085. }
  1086. else
  1087. {
  1088. add(ALWavefront(face, pm, NULL, &normfix));
  1089. }
  1090. }
  1091. if (!with_attachments) return true;
  1092. // Open the edit tools floater so that we can select objects
  1093. gFloaterToolsp->open();
  1094. gToolMgr.setCurrentToolset(gBasicToolset);
  1095. gFloaterToolsp->setEditTool(&gToolCompTranslate);
  1096. struct ff final : public LLSelectedNodeFunctor
  1097. {
  1098. bool apply(LLSelectNode* node) override
  1099. {
  1100. if (!node->mValid)
  1101. {
  1102. llwarns_once << "Invalid extra data for node: " << node
  1103. << llendl;
  1104. }
  1105. return HBObjectBackup::validateNode(node);
  1106. }
  1107. } func;
  1108. bool success = true;
  1109. for (S32 i = 0, count = av_vo->mAttachedObjectsVector.size(); i < count;
  1110. ++i)
  1111. {
  1112. LLViewerObject* obj = av_vo->mAttachedObjectsVector[i].first;
  1113. if (!obj || obj->isHUDAttachment()) continue;
  1114. bool perm_ok = true;
  1115. // Select our attachment
  1116. gSelectMgr.selectObjectAndFamily(obj->getRootEdit());
  1117. //gSelectMgr.getSelection()->ref();
  1118. if (!gSelectMgr.getSelection()->applyToNodes(&func, false))
  1119. {
  1120. llwarns << "Incorrect permission to export attachment: "
  1121. << obj->getID() << llendl;
  1122. success = perm_ok = false;
  1123. }
  1124. //gSelectMgr.getSelection()->unref();
  1125. gSelectMgr.deselectAll();
  1126. if (perm_ok)
  1127. {
  1128. LL_DEBUGS("OBJExporter") << "Exporting attachment: "
  1129. << obj->getID() << LL_ENDL;
  1130. std::vector<LLViewerObject*> prims;
  1131. obj->addThisAndAllChildren(prims);
  1132. for (std::vector<LLViewerObject*>::iterator
  1133. it3 = prims.begin(), end3 = prims.end();
  1134. it3 != end3; ++it3)
  1135. {
  1136. LLViewerObject* pobj = *it3;
  1137. if (!pobj) continue;
  1138. const LLVolume* vol = pobj->getVolume();
  1139. if (!vol) continue;
  1140. LLXform v_form;
  1141. v_form.setScale(pobj->getScale());
  1142. v_form.setPosition(pobj->getRenderPosition());
  1143. v_form.setRotation(pobj->getRenderRotation());
  1144. LLXform normfix;
  1145. normfix.setRotation(v_form.getRotation());
  1146. add(vol, &v_form, &normfix);
  1147. }
  1148. }
  1149. }
  1150. return success;
  1151. }
  1152. #endif
  1153. static bool write_or_bust(LLFILE* fp, const std::string outstring)
  1154. {
  1155. const size_t size = outstring.length();
  1156. if (fwrite(outstring.c_str(), 1, size, fp) != size)
  1157. {
  1158. llwarns << "ALWavefrontSaver::saveToFile(): short write" << llendl;
  1159. return false;
  1160. }
  1161. return true;
  1162. }
  1163. bool ALWavefrontSaver::saveToFile(LLFILE* fp)
  1164. {
  1165. if (!fp) return false;
  1166. static LLCachedControl<bool> swap_yz(gSavedSettings, "OBJExportSwapYZ");
  1167. S32 num = 0;
  1168. S32 index = 0;
  1169. for (std::vector<ALWavefront>::iterator iter = mWavefrontObjects.begin(),
  1170. wend = mWavefrontObjects.end();
  1171. iter != wend; ++iter)
  1172. {
  1173. S32 count = 0;
  1174. std::string name = iter->mName;
  1175. if (name.empty())
  1176. {
  1177. name = llformat("%d", num++);
  1178. }
  1179. // Write Object
  1180. if (!write_or_bust(fp, "o " + name + "\n"))
  1181. {
  1182. return false;
  1183. }
  1184. // Write vertices; swap axes if necessary
  1185. const F64 xm = swap_yz ? -1.0 : 1.0;
  1186. const S32 y = swap_yz ? 2 : 1;
  1187. const S32 z = swap_yz ? 1 : 2;
  1188. for (vert_t::iterator it = iter->mVertices.begin(),
  1189. end = iter->mVertices.end();
  1190. it != end; ++it)
  1191. {
  1192. ++count;
  1193. const LLVector3 v = it->first + mOffset;
  1194. if (!write_or_bust(fp, llformat("v %f %f %f\n",
  1195. v[0] * xm, v[y], v[z])))
  1196. {
  1197. return false;
  1198. }
  1199. }
  1200. for (vec3_t::iterator it = iter->mNormals.begin(),
  1201. end = iter->mNormals.end();
  1202. it != end; ++it)
  1203. {
  1204. const LLVector3 n = *it;
  1205. if (!write_or_bust(fp, llformat("vn %f %f %f\n",
  1206. n[0] * xm, n[y], n[z])))
  1207. {
  1208. return false;
  1209. }
  1210. }
  1211. for (vert_t::iterator it = iter->mVertices.begin(),
  1212. end = iter->mVertices.end();
  1213. it != end; ++it)
  1214. {
  1215. if (!write_or_bust(fp, llformat("vt %f %f\n",
  1216. it->second[0], it->second[1])))
  1217. {
  1218. return false;
  1219. }
  1220. }
  1221. // Write triangles
  1222. for (tri_t::iterator it = iter->mTriangles.begin(),
  1223. end = iter->mTriangles.end();
  1224. it != end; ++it)
  1225. {
  1226. const S32 f1 = it->v0 + index + 1;
  1227. const S32 f2 = it->v1 + index + 1;
  1228. const S32 f3 = it->v2 + index + 1;
  1229. if (!write_or_bust(fp, llformat("f %d/%d/%d %d/%d/%d %d/%d/%d\n",
  1230. f1, f1, f1, f2, f2, f2,
  1231. f3, f3, f3)))
  1232. {
  1233. return false;
  1234. }
  1235. }
  1236. index += count;
  1237. }
  1238. return true;
  1239. }
  1240. //static
  1241. void ALWavefrontSaver::exportSelection()
  1242. {
  1243. LLObjectSelectionHandle selection = gSelectMgr.getSelection();
  1244. if (selection && selection->getFirstRootObject())
  1245. {
  1246. // Destroyed in callback
  1247. ALWavefrontSaver* wfsaver = new ALWavefrontSaver;
  1248. wfsaver->mOffset =
  1249. -selection->getFirstRootObject()->getRenderPosition();
  1250. S32 total = 0;
  1251. S32 included = 0;
  1252. for (LLObjectSelection::iterator iter = selection->begin(),
  1253. end = selection->end();
  1254. iter != end; ++iter)
  1255. {
  1256. ++total;
  1257. LLSelectNode* node = *iter;
  1258. if (node && HBObjectBackup::validateNode(node))
  1259. {
  1260. ++included;
  1261. wfsaver->add(node->getObject());
  1262. }
  1263. }
  1264. if (wfsaver->mWavefrontObjects.empty())
  1265. {
  1266. gNotifications.add("ExportFailed");
  1267. delete wfsaver;
  1268. return;
  1269. }
  1270. std::string suggestion = selection->getFirstRootNode()->mName;
  1271. suggestion = LLDir::getScrubbedFileName(suggestion) + ".obj";
  1272. if (total != included)
  1273. {
  1274. LLSD args;
  1275. args["TOTAL"] = total;
  1276. args["FAILED"] = total - included;
  1277. gNotifications.add("WavefrontExportPartial", args, LLSD(),
  1278. boost::bind(&saveNotificationCallback, _1, _2,
  1279. wfsaver, suggestion));
  1280. }
  1281. else
  1282. {
  1283. saveOpenPicker(wfsaver, suggestion);
  1284. }
  1285. }
  1286. }
  1287. #if LL_EXPORT_AVATAR_OBJ
  1288. //static
  1289. void ALWavefrontSaver::exportAvatar(bool with_attachments)
  1290. {
  1291. LLVOAvatar* avatar = (LLVOAvatar*)gAgentAvatarp;
  1292. if (!avatar) return;
  1293. ALWavefrontSaver* wfsaver = new ALWavefrontSaver; // Destroyed in callback
  1294. bool full = wfsaver->add(avatar, with_attachments);
  1295. if (wfsaver->mWavefrontObjects.empty())
  1296. {
  1297. gNotifications.add("ExportFailed");
  1298. delete wfsaver;
  1299. return;
  1300. }
  1301. std::string suggestion = avatar->getFullname(true);
  1302. suggestion = LLDir::getScrubbedFileName(suggestion) + ".obj";
  1303. if (full)
  1304. {
  1305. saveOpenPicker(wfsaver, suggestion);
  1306. }
  1307. else
  1308. {
  1309. gNotifications.add("WavefrontAvatarExportPartial", LLSD(), LLSD(),
  1310. boost::bind(&saveNotificationCallback, _1, _2,
  1311. wfsaver, suggestion));
  1312. }
  1313. }
  1314. #endif
  1315. //static
  1316. void ALWavefrontSaver::saveNotificationCallback(const LLSD& notification,
  1317. const LLSD& response,
  1318. ALWavefrontSaver* wfsaver,
  1319. std::string name)
  1320. {
  1321. if (LLNotification::getSelectedOption(notification, response) == 0)
  1322. {
  1323. saveOpenPicker(wfsaver, name);
  1324. }
  1325. else
  1326. {
  1327. delete wfsaver;
  1328. }
  1329. }
  1330. //static
  1331. void ALWavefrontSaver::saveOpenPicker(ALWavefrontSaver* wfsaver,
  1332. std::string name)
  1333. {
  1334. HBFileSelector::saveFile(HBFileSelector::FFSAVE_OBJ, name,
  1335. savePickerCallback, (void*)wfsaver);
  1336. }
  1337. //static
  1338. void ALWavefrontSaver::savePickerCallback(HBFileSelector::ESaveFilter type,
  1339. std::string& filename,
  1340. void* userdata)
  1341. {
  1342. ALWavefrontSaver* wfsaver = (ALWavefrontSaver*)userdata;
  1343. if (!wfsaver) return;
  1344. if (userdata && !filename.empty())
  1345. {
  1346. if (LLFILE* fp = LLFile::open(filename, "wb"))
  1347. {
  1348. wfsaver->saveToFile(fp);
  1349. llinfos << "OBJ file saved to: " << filename << llendl;
  1350. gNotifications.add("ExportSuccessful");
  1351. LLFile::close(fp);
  1352. }
  1353. else
  1354. {
  1355. llwarns << "Could not write to file: " << filename
  1356. << "- Export process failed." << llendl;
  1357. gNotifications.add("ExportFailed");
  1358. }
  1359. }
  1360. delete wfsaver;
  1361. }