llgltfmaterial.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. /**
  2. * @file llgltfmaterial.cpp
  3. * @brief LLGLTFMaterial implementation
  4. *
  5. * $LicenseInfo:firstyear=2022&license=viewergpl$
  6. *
  7. * Copyright (c) 2022, 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 "linden_common.h"
  33. #include "tinygltf/tiny_gltf.h"
  34. #include "llgltfmaterial.h"
  35. #include "hbxxh.h"
  36. static const char* const GLTF_FILE_EXT_TF = "KHR_texture_transform";
  37. static const char* const GLTF_FILE_EXT_TF_SCALE = "scale";
  38. static const char* const GLTF_FILE_EXT_TF_OFFSET = "offset";
  39. static const char* const GLTF_FILE_EXT_TF_ROTATION = "rotation";
  40. // Special UUID that indicates a null UUID in override data
  41. static const LLUUID GLTF_OVERRIDE_NULL_UUID =
  42. LLUUID("ffffffff-ffff-ffff-ffff-ffffffffffff");
  43. const char* const LLGLTFMaterial::ASSET_TYPE = "GLTF 2.0";
  44. const char* const LLGLTFMaterial::ASSET_VERSION = "1.1";
  45. // Make a static default material for accessors
  46. const LLGLTFMaterial LLGLTFMaterial::sDefault;
  47. LLGLTFMaterial::LLGLTFMaterial()
  48. {
  49. // IMPORTANT: since we use the hash of the member variables memory block of
  50. // this class to detect changes, we must ensure that all its padding bytes
  51. // have been zeroed out. But of course, we must leave the LLRefCount member
  52. // variable untouched (and skip it when hashing), and we cannot either
  53. // touch the local texture overrides map (else we destroy pointers, and
  54. // sundry private data, which would lead to a crash when using that map).
  55. // The variable members have therefore been arranged so that anything,
  56. // starting at mLocalTexDataDigest and up to the end of the members, can be
  57. // safely zeroed. HB
  58. const size_t offset = intptr_t(&mLocalTexDataDigest) - intptr_t(this);
  59. memset((void*)((const char*)this + offset), 0, sizeof(*this) - offset);
  60. // Now that we zeroed out our member variables, we can set the ones that
  61. // should not be zero to their default value. HB
  62. mBaseColor.set(1.f, 1.f, 1.f, 1.f);
  63. mMetallicFactor = mRoughnessFactor = 1.f;
  64. mAlphaCutoff = 0.5f;
  65. for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
  66. {
  67. mTextureTransform[i].mScale.set(1.f, 1.f);
  68. #if 0
  69. mTextureTransform[i].mOffset.clear();
  70. mTextureTransform[i].mRotation = 0.f;
  71. #endif
  72. }
  73. #if 0
  74. mLocalTexDataDigest = 0;
  75. mAlphaMode = ALPHA_MODE_OPAQUE; // This is 0
  76. mOverrideDoubleSided = mOverrideAlphaMode = false;
  77. #endif
  78. }
  79. LLGLTFMaterial& LLGLTFMaterial::operator=(const LLGLTFMaterial& rhs)
  80. {
  81. // We have to do a manual operator= because of LLRefCount
  82. mTextureId = rhs.mTextureId;
  83. mTextureTransform = rhs.mTextureTransform;
  84. mBaseColor = rhs.mBaseColor;
  85. mEmissiveColor = rhs.mEmissiveColor;
  86. mMetallicFactor = rhs.mMetallicFactor;
  87. mRoughnessFactor = rhs.mRoughnessFactor;
  88. mAlphaCutoff = rhs.mAlphaCutoff;
  89. mDoubleSided = rhs.mDoubleSided;
  90. mAlphaMode = rhs.mAlphaMode;
  91. mOverrideDoubleSided = rhs.mOverrideDoubleSided;
  92. mOverrideAlphaMode = rhs.mOverrideAlphaMode;
  93. if (rhs.mTrackingIdToLocalTexture.empty())
  94. {
  95. mTrackingIdToLocalTexture.clear();
  96. mLocalTexDataDigest = 0;
  97. }
  98. else
  99. {
  100. mTrackingIdToLocalTexture = rhs.mTrackingIdToLocalTexture;
  101. updateLocalTexDataDigest();
  102. updateTextureTracking();
  103. }
  104. return *this;
  105. }
  106. void LLGLTFMaterial::updateLocalTexDataDigest()
  107. {
  108. mLocalTexDataDigest = 0;
  109. if (!mTrackingIdToLocalTexture.empty())
  110. {
  111. for (local_tex_map_t::const_iterator
  112. it = mTrackingIdToLocalTexture.begin(),
  113. end = mTrackingIdToLocalTexture.end();
  114. it != end; ++it)
  115. {
  116. mLocalTexDataDigest ^= it->first.getDigest64() ^
  117. it->second.getDigest64();
  118. }
  119. }
  120. }
  121. LLUUID LLGLTFMaterial::getHash() const
  122. {
  123. // *HACK: hash the bytes of this object but do not include the ref count
  124. // neither the local texture overrides (which is a map, with pointers to
  125. // key/value pairs that would change from one LLGLTFMaterial instance to
  126. // the other, even though the key/value pairs could be the same, and stored
  127. // elsewhere in the memory heap or on the stack).
  128. // Note: this does work properly to compare two LLGLTFMaterial instances
  129. // only because the padding bytes between their member variables have been
  130. // dutifully zeroed in the constructor. HB
  131. const size_t offset = intptr_t(&mLocalTexDataDigest) - intptr_t(this);
  132. return HBXXH128::digest((const void*)((const char*)this + offset),
  133. sizeof(*this) - offset);
  134. }
  135. bool LLGLTFMaterial::fromJSON(const std::string& json, std::string& warn_msg,
  136. std::string& error_msg)
  137. {
  138. tinygltf::TinyGLTF gltf;
  139. tinygltf::Model model_in;
  140. if (gltf.LoadASCIIFromString(&model_in, &error_msg, &warn_msg,
  141. json.c_str(), json.length(), ""))
  142. {
  143. setFromModel(model_in, 0);
  144. return true;
  145. }
  146. return false;
  147. }
  148. std::string LLGLTFMaterial::asJSON(bool prettyprint) const
  149. {
  150. tinygltf::TinyGLTF gltf;
  151. tinygltf::Model model_out;
  152. writeToModel(model_out, 0);
  153. // To ensure consistency in asset upload, this should be the only reference
  154. // to WriteGltfSceneToStream in the viewer.
  155. std::ostringstream str;
  156. gltf.WriteGltfSceneToStream(&model_out, str, prettyprint, false);
  157. return str.str();
  158. }
  159. void LLGLTFMaterial::setFromModel(const tinygltf::Model& model, S32 mat_index)
  160. {
  161. if (mat_index < 0 || mat_index > (S32)model.materials.size())
  162. {
  163. return;
  164. }
  165. const tinygltf::Material& mat = model.materials[mat_index];
  166. // Apply base color texture
  167. setFromTexture(model, mat.pbrMetallicRoughness.baseColorTexture,
  168. GLTF_TEXTURE_INFO_BASE_COLOR);
  169. // Apply normal map
  170. setFromTexture(model, mat.normalTexture, GLTF_TEXTURE_INFO_NORMAL);
  171. // Apply metallic-roughness texture
  172. setFromTexture(model, mat.pbrMetallicRoughness.metallicRoughnessTexture,
  173. GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS);
  174. // Apply emissive texture
  175. setFromTexture(model, mat.emissiveTexture, GLTF_TEXTURE_INFO_EMISSIVE);
  176. setAlphaMode(mat.alphaMode);
  177. mAlphaCutoff = llclamp(mat.alphaCutoff, 0.f, 1.f);
  178. mBaseColor.set(mat.pbrMetallicRoughness.baseColorFactor);
  179. mEmissiveColor.set(mat.emissiveFactor);
  180. mMetallicFactor = llclamp(mat.pbrMetallicRoughness.metallicFactor, 0.f,
  181. 1.f);
  182. mRoughnessFactor = llclamp(mat.pbrMetallicRoughness.roughnessFactor, 0.f,
  183. 1.f);
  184. mDoubleSided = mat.doubleSided;
  185. if (mat.extras.IsObject())
  186. {
  187. tinygltf::Value::Object extras =
  188. mat.extras.Get<tinygltf::Value::Object>();
  189. const auto& alpha_mode = extras.find("override_alpha_mode");
  190. if (alpha_mode != extras.end())
  191. {
  192. mOverrideAlphaMode = alpha_mode->second.Get<bool>();
  193. }
  194. const auto& double_sided = extras.find("override_double_sided");
  195. if (double_sided != extras.end())
  196. {
  197. mOverrideDoubleSided = double_sided->second.Get<bool>();
  198. }
  199. }
  200. }
  201. static LLVector2 vec2_from_json(const tinygltf::Value::Object& object,
  202. const char* key, const LLVector2& dflt_value)
  203. {
  204. const auto it = object.find(key);
  205. if (it == object.end())
  206. {
  207. return dflt_value;
  208. }
  209. const tinygltf::Value& vec2_json = std::get<1>(*it);
  210. if (!vec2_json.IsArray() || vec2_json.ArrayLen() < LENGTHOFVECTOR2)
  211. {
  212. return dflt_value;
  213. }
  214. LLVector2 value;
  215. for (U32 i = 0; i < LENGTHOFVECTOR2; ++i)
  216. {
  217. const tinygltf::Value& real_json = vec2_json.Get(i);
  218. if (!real_json.IsReal())
  219. {
  220. return dflt_value;
  221. }
  222. value.mV[i] = (F32)real_json.Get<double>();
  223. }
  224. return value;
  225. }
  226. static F32 float_from_json(const tinygltf::Value::Object& object,
  227. const char* key, const F32 dflt_value)
  228. {
  229. const auto it = object.find(key);
  230. if (it == object.end())
  231. {
  232. return dflt_value;
  233. }
  234. const tinygltf::Value& real_json = std::get<1>(*it);
  235. if (!real_json.IsReal())
  236. {
  237. return dflt_value;
  238. }
  239. return (F32)real_json.GetNumberAsDouble();
  240. }
  241. template<typename T>
  242. std::string gltf_get_texture_image(const tinygltf::Model& model,
  243. const T& tex_info)
  244. {
  245. S32 texture_idx = tex_info.index;
  246. if (texture_idx < 0 || texture_idx >= (S32)model.textures.size())
  247. {
  248. return "";
  249. }
  250. const tinygltf::Texture& texture = model.textures[texture_idx];
  251. // Ignore texture.sampler for now
  252. S32 image_idx = texture.source;
  253. if (image_idx < 0 || image_idx >= (S32)model.images.size())
  254. {
  255. return "";
  256. }
  257. const tinygltf::Image& image = model.images[image_idx];
  258. return image.uri;
  259. }
  260. // NOTE: we use template here as workaround for the different similar texture
  261. // info classes
  262. template<typename T>
  263. void LLGLTFMaterial::setFromTexture(const tinygltf::Model& model,
  264. const T& tex_info, TextureInfo tex_info_id)
  265. {
  266. const std::string uri = gltf_get_texture_image(model, tex_info);
  267. mTextureId[tex_info_id].set(uri);
  268. const tinygltf::Value::Object& ext_obj = tex_info.extensions;
  269. const auto transform_it = ext_obj.find(GLTF_FILE_EXT_TF);
  270. if (transform_it == ext_obj.end())
  271. {
  272. return;
  273. }
  274. const tinygltf::Value& tf_json = std::get<1>(*transform_it);
  275. if (!tf_json.IsObject())
  276. {
  277. return;
  278. }
  279. const tinygltf::Value::Object& tf_obj =
  280. tf_json.Get<tinygltf::Value::Object>();
  281. TextureTransform& transform = mTextureTransform[tex_info_id];
  282. transform.mOffset = vec2_from_json(tf_obj, GLTF_FILE_EXT_TF_OFFSET,
  283. getDefaultTextureOffset());
  284. transform.mScale = vec2_from_json(tf_obj, GLTF_FILE_EXT_TF_SCALE,
  285. getDefaultTextureScale());
  286. transform.mRotation = float_from_json(tf_obj, GLTF_FILE_EXT_TF_ROTATION,
  287. getDefaultTextureRotation());
  288. }
  289. void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const
  290. {
  291. if (model.materials.size() < size_t(mat_index + 1))
  292. {
  293. model.materials.resize(mat_index + 1);
  294. }
  295. tinygltf::Material& mat = model.materials[mat_index];
  296. // Set base color texture
  297. writeToTexture(model, mat.pbrMetallicRoughness.baseColorTexture,
  298. GLTF_TEXTURE_INFO_BASE_COLOR);
  299. // Set normal texture
  300. writeToTexture(model, mat.normalTexture, GLTF_TEXTURE_INFO_NORMAL);
  301. // Set metallic-roughness texture
  302. writeToTexture(model, mat.pbrMetallicRoughness.metallicRoughnessTexture,
  303. GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS);
  304. // Set emissive texture
  305. writeToTexture(model, mat.emissiveTexture, GLTF_TEXTURE_INFO_EMISSIVE);
  306. // Set occlusion texture. Note: this is required for ORM materials for GLTF
  307. // compliance. See:
  308. // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_material_occlusiontexture
  309. writeToTexture(model, mat.occlusionTexture, GLTF_TEXTURE_INFO_OCCLUSION);
  310. mat.alphaMode = getAlphaMode();
  311. mat.alphaCutoff = mAlphaCutoff;
  312. mBaseColor.write(mat.pbrMetallicRoughness.baseColorFactor);
  313. if (mEmissiveColor != LLGLTFMaterial::getDefaultEmissiveColor())
  314. {
  315. mat.emissiveFactor.resize(3);
  316. mEmissiveColor.write(mat.emissiveFactor);
  317. }
  318. mat.pbrMetallicRoughness.metallicFactor = mMetallicFactor;
  319. mat.pbrMetallicRoughness.roughnessFactor = mRoughnessFactor;
  320. mat.doubleSided = mDoubleSided;
  321. // Generate "extras" string
  322. tinygltf::Value::Object extras;
  323. bool write_extras = false;
  324. if (mOverrideAlphaMode && mAlphaMode == getDefaultAlphaMode())
  325. {
  326. extras["override_alpha_mode"] = tinygltf::Value(mOverrideAlphaMode);
  327. write_extras = true;
  328. }
  329. if (mOverrideDoubleSided && mDoubleSided == getDefaultDoubleSided())
  330. {
  331. extras["override_double_sided"] =
  332. tinygltf::Value(mOverrideDoubleSided);
  333. write_extras = true;
  334. }
  335. if (write_extras)
  336. {
  337. mat.extras = tinygltf::Value(extras);
  338. }
  339. model.asset.version = "2.0";
  340. }
  341. template<typename T>
  342. void gltf_allocate_texture_image(tinygltf::Model& model, T& tex_info,
  343. const std::string& uri)
  344. {
  345. const S32 image_idx = model.images.size();
  346. model.images.emplace_back();
  347. model.images[image_idx].uri = uri;
  348. // The texture, not to be confused with the texture info
  349. const S32 texture_idx = model.textures.size();
  350. model.textures.emplace_back();
  351. tinygltf::Texture& texture = model.textures[texture_idx];
  352. texture.source = image_idx;
  353. tex_info.index = texture_idx;
  354. }
  355. template<typename T>
  356. void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& tex_info,
  357. TextureInfo tex_info_id, bool force) const
  358. {
  359. const LLUUID& texture_id = mTextureId[tex_info_id];
  360. const TextureTransform& transform = mTextureTransform[tex_info_id];
  361. const bool is_blank_transform = transform == sDefault.mTextureTransform[0];
  362. // Check if this material matches all the fallback values, and if so, then
  363. // skip including it to reduce material size
  364. if (!force && texture_id.isNull() && is_blank_transform)
  365. {
  366. return;
  367. }
  368. // tinygltf will discard this texture info if there is no valid texture,
  369. // causing potential loss of information for overrides, so ensure one is
  370. // defined. -Cosmic,2023-01-30
  371. gltf_allocate_texture_image(model, tex_info, texture_id.asString());
  372. if (!is_blank_transform)
  373. {
  374. tinygltf::Value::Object transform_map;
  375. transform_map[GLTF_FILE_EXT_TF_OFFSET] =
  376. tinygltf::Value(tinygltf::Value::Array({
  377. tinygltf::Value(transform.mOffset.mV[VX]),
  378. tinygltf::Value(transform.mOffset.mV[VY])
  379. }));
  380. transform_map[GLTF_FILE_EXT_TF_SCALE] =
  381. tinygltf::Value(tinygltf::Value::Array({
  382. tinygltf::Value(transform.mScale.mV[VX]),
  383. tinygltf::Value(transform.mScale.mV[VY])
  384. }));
  385. transform_map[GLTF_FILE_EXT_TF_ROTATION] =
  386. tinygltf::Value(transform.mRotation);
  387. tex_info.extensions[GLTF_FILE_EXT_TF] = tinygltf::Value(transform_map);
  388. }
  389. }
  390. bool LLGLTFMaterial::setBaseMaterial()
  391. {
  392. const LLGLTFMaterial old_override = *this;
  393. *this = sDefault;
  394. setBaseMaterial(old_override);
  395. return *this != old_override;
  396. }
  397. bool LLGLTFMaterial::isClearedForBaseMaterial() const
  398. {
  399. LLGLTFMaterial cleared_override = sDefault;
  400. cleared_override.setBaseMaterial(*this);
  401. return *this == cleared_override;
  402. }
  403. //static
  404. void LLGLTFMaterial::hackOverrideUUID(LLUUID& id)
  405. {
  406. if (id.isNull())
  407. {
  408. id = GLTF_OVERRIDE_NULL_UUID;
  409. }
  410. }
  411. void LLGLTFMaterial::setBaseColorFactor(const LLColor4& baseColor,
  412. bool for_override)
  413. {
  414. mBaseColor.set(baseColor);
  415. mBaseColor.clamp();
  416. if (for_override)
  417. {
  418. // *HACK: nudge off of default value
  419. if (mBaseColor == getDefaultBaseColor())
  420. {
  421. mBaseColor.mV[3] -= FLT_EPSILON;
  422. }
  423. }
  424. }
  425. void LLGLTFMaterial::setAlphaCutoff(F32 cutoff, bool for_override)
  426. {
  427. mAlphaCutoff = llclamp(cutoff, 0.f, 1.f);
  428. if (for_override)
  429. {
  430. // *HACK: nudge off of default value
  431. if (mAlphaCutoff == getDefaultAlphaCutoff())
  432. {
  433. mAlphaCutoff -= FLT_EPSILON;
  434. }
  435. }
  436. }
  437. void LLGLTFMaterial::setEmissiveColorFactor(const LLColor3& emissiveColor,
  438. bool for_override)
  439. {
  440. mEmissiveColor = emissiveColor;
  441. mEmissiveColor.clamp();
  442. if (for_override)
  443. {
  444. // *HACK: nudge off of default value
  445. if (mEmissiveColor == getDefaultEmissiveColor())
  446. {
  447. mEmissiveColor.mV[0] += FLT_EPSILON;
  448. }
  449. }
  450. }
  451. void LLGLTFMaterial::setMetallicFactor(F32 metallic, bool for_override)
  452. {
  453. mMetallicFactor = llclamp(metallic, 0.f,
  454. for_override ? 1.f - FLT_EPSILON : 1.f);
  455. }
  456. void LLGLTFMaterial::setRoughnessFactor(F32 roughness, bool for_override)
  457. {
  458. mRoughnessFactor = llclamp(roughness, 0.f,
  459. for_override ? 1.f - FLT_EPSILON : 1.f);
  460. }
  461. void LLGLTFMaterial::setAlphaMode(const std::string& mode, bool for_override)
  462. {
  463. S32 m = ALPHA_MODE_OPAQUE; //getDefaultAlphaMode();
  464. if (mode == "MASK")
  465. {
  466. m = ALPHA_MODE_MASK;
  467. }
  468. else if (mode == "BLEND")
  469. {
  470. m = ALPHA_MODE_BLEND;
  471. }
  472. setAlphaMode(m, for_override);
  473. }
  474. const char* LLGLTFMaterial::getAlphaMode() const
  475. {
  476. switch (mAlphaMode)
  477. {
  478. default:
  479. case ALPHA_MODE_OPAQUE:
  480. return "OPAQUE";
  481. case ALPHA_MODE_BLEND:
  482. return "BLEND";
  483. case ALPHA_MODE_MASK:
  484. return "MASK";
  485. }
  486. }
  487. void LLGLTFMaterial::setAlphaMode(U32 mode, bool for_override)
  488. {
  489. mAlphaMode = llclamp(mode, ALPHA_MODE_OPAQUE, ALPHA_MODE_MASK);
  490. mOverrideAlphaMode = for_override && mAlphaMode == getDefaultAlphaMode();
  491. }
  492. void LLGLTFMaterial::setDoubleSided(bool double_sided, bool for_override)
  493. {
  494. // Sure, no clamping will ever be needed for a bool, but include the
  495. // setter for consistency with the clamping API
  496. mDoubleSided = double_sided;
  497. mOverrideDoubleSided = for_override &&
  498. mDoubleSided == getDefaultDoubleSided();
  499. }
  500. LLSD LLGLTFMaterial::getOverrideLLSD() const
  501. {
  502. LLSD data;
  503. // Make every effort to shave off bytes here
  504. for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
  505. {
  506. const LLUUID& texture_id = mTextureId[i];
  507. const LLUUID& override_texture_id = mTextureId[i];
  508. if (override_texture_id.notNull() && texture_id != override_texture_id)
  509. {
  510. data["tex"][i] = LLSD::UUID(override_texture_id);
  511. }
  512. }
  513. if (mBaseColor != sDefault.mBaseColor)
  514. {
  515. data["bc"] = mBaseColor.getValue();
  516. }
  517. if (mEmissiveColor != sDefault.mEmissiveColor)
  518. {
  519. data["ec"] = mEmissiveColor.getValue();
  520. }
  521. if (mMetallicFactor != sDefault.mMetallicFactor)
  522. {
  523. data["mf"] = mMetallicFactor;
  524. }
  525. if (mRoughnessFactor != sDefault.mRoughnessFactor)
  526. {
  527. data["rf"] = mRoughnessFactor;
  528. }
  529. if (mAlphaMode != sDefault.mAlphaMode || mOverrideAlphaMode)
  530. {
  531. data["am"] = mAlphaMode;
  532. }
  533. if (mAlphaCutoff != sDefault.mAlphaCutoff)
  534. {
  535. data["ac"] = mAlphaCutoff;
  536. }
  537. if (mDoubleSided != sDefault.mDoubleSided || mOverrideDoubleSided)
  538. {
  539. data["ds"] = mDoubleSided;
  540. }
  541. const LLVector2& def_tex_offset = getDefaultTextureOffset();
  542. const LLVector2& def_tex_scale = getDefaultTextureScale();
  543. const F32 def_tex_rot = getDefaultTextureRotation();
  544. for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
  545. {
  546. if (mTextureTransform[i].mOffset != def_tex_offset)
  547. {
  548. data["ti"][i]["o"] = mTextureTransform[i].mOffset.getValue();
  549. }
  550. if (mTextureTransform[i].mScale != def_tex_scale)
  551. {
  552. data["ti"][i]["s"] = mTextureTransform[i].mScale.getValue();
  553. }
  554. if (mTextureTransform[i].mRotation != def_tex_rot)
  555. {
  556. data["ti"][i]["r"] = mTextureTransform[i].mRotation;
  557. }
  558. }
  559. return data;
  560. }
  561. void LLGLTFMaterial::applyOverrideLLSD(const LLSD& data)
  562. {
  563. if (!data.isDefined())
  564. {
  565. return; // Nothing to do. HB
  566. }
  567. const LLSD& tex = data["tex"];
  568. if (tex.isArray())
  569. {
  570. for (U32 i = 0, count = tex.size(); i < count; ++i)
  571. {
  572. mTextureId[i] = tex[i].asUUID();
  573. }
  574. }
  575. const LLSD& bc = data["bc"];
  576. if (bc.isDefined())
  577. {
  578. mBaseColor.setValue(bc);
  579. if (mBaseColor == getDefaultBaseColor())
  580. {
  581. // *HACK: nudge by epsilon if we receive a default value (indicates
  582. // override to default).
  583. mBaseColor.mV[3] -= FLT_EPSILON;
  584. }
  585. }
  586. const LLSD& ec = data["ec"];
  587. if (ec.isDefined())
  588. {
  589. mEmissiveColor.setValue(ec);
  590. if (mEmissiveColor == getDefaultEmissiveColor())
  591. {
  592. // *HACK: nudge by epsilon if we receive a default value (indicates
  593. // override to default).
  594. mEmissiveColor.mV[0] -= FLT_EPSILON;
  595. }
  596. }
  597. const LLSD& mf = data["mf"];
  598. if (mf.isReal())
  599. {
  600. mMetallicFactor = mf.asReal();
  601. if (mMetallicFactor == getDefaultMetallicFactor())
  602. {
  603. // *HACK: nudge by epsilon if we receive a default value (indicates
  604. // override to default).
  605. mMetallicFactor -= FLT_EPSILON;
  606. }
  607. }
  608. const LLSD& rf = data["rf"];
  609. if (rf.isReal())
  610. {
  611. mRoughnessFactor = rf.asReal();
  612. if (mRoughnessFactor == getDefaultRoughnessFactor())
  613. {
  614. // *HACK: nudge by epsilon if we receive a default value (indicates
  615. // override to default).
  616. mRoughnessFactor -= FLT_EPSILON;
  617. }
  618. }
  619. const LLSD& am = data["am"];
  620. if (am.isInteger())
  621. {
  622. mAlphaMode = am.asInteger();
  623. mOverrideAlphaMode = true;
  624. }
  625. const LLSD& ac = data["ac"];
  626. if (ac.isReal())
  627. {
  628. mAlphaCutoff = ac.asReal();
  629. if (mAlphaCutoff == getDefaultAlphaCutoff())
  630. {
  631. // *HACK: nudge by epsilon if we receive a default value (indicates
  632. // override to default).
  633. mAlphaCutoff -= FLT_EPSILON;
  634. }
  635. }
  636. const LLSD& ds = data["ds"];
  637. if (ds.isBoolean())
  638. {
  639. mDoubleSided = ds.asBoolean();
  640. mOverrideDoubleSided = true;
  641. }
  642. const LLSD& ti = data["ti"];
  643. if (ti.isArray())
  644. {
  645. for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
  646. {
  647. const LLSD& o = ti[i]["o"];
  648. if (o.isDefined())
  649. {
  650. mTextureTransform[i].mOffset.setValue(o);
  651. }
  652. const LLSD& s = ti[i]["s"];
  653. if (s.isDefined())
  654. {
  655. mTextureTransform[i].mScale.setValue(s);
  656. }
  657. const LLSD& r = ti[i]["r"];
  658. if (r.isReal())
  659. {
  660. mTextureTransform[i].mRotation = r.asReal();
  661. }
  662. }
  663. }
  664. }
  665. static void apply_override_id(LLUUID& dst_id, const LLUUID& over_id)
  666. {
  667. if (over_id == GLTF_OVERRIDE_NULL_UUID)
  668. {
  669. dst_id.setNull();
  670. }
  671. else if (over_id.notNull())
  672. {
  673. dst_id = over_id;
  674. }
  675. }
  676. void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat)
  677. {
  678. for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
  679. {
  680. LLUUID& texture_id = mTextureId[i];
  681. const LLUUID& override_texture_id = override_mat.mTextureId[i];
  682. apply_override_id(texture_id, override_texture_id);
  683. }
  684. if (override_mat.mBaseColor != getDefaultBaseColor())
  685. {
  686. mBaseColor = override_mat.mBaseColor;
  687. }
  688. if (override_mat.mEmissiveColor != getDefaultEmissiveColor())
  689. {
  690. mEmissiveColor = override_mat.mEmissiveColor;
  691. }
  692. if (override_mat.mMetallicFactor != getDefaultMetallicFactor())
  693. {
  694. mMetallicFactor = override_mat.mMetallicFactor;
  695. }
  696. if (override_mat.mRoughnessFactor != getDefaultRoughnessFactor())
  697. {
  698. mRoughnessFactor = override_mat.mRoughnessFactor;
  699. }
  700. if (override_mat.mAlphaMode != getDefaultAlphaMode() ||
  701. override_mat.mOverrideAlphaMode)
  702. {
  703. mAlphaMode = override_mat.mAlphaMode;
  704. }
  705. if (override_mat.mAlphaCutoff != getDefaultAlphaCutoff())
  706. {
  707. mAlphaCutoff = override_mat.mAlphaCutoff;
  708. }
  709. if (override_mat.mDoubleSided != getDefaultDoubleSided() ||
  710. override_mat.mOverrideDoubleSided)
  711. {
  712. mDoubleSided = override_mat.mDoubleSided;
  713. }
  714. for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
  715. {
  716. if (override_mat.mTextureTransform[i].mOffset !=
  717. getDefaultTextureOffset())
  718. {
  719. mTextureTransform[i].mOffset =
  720. override_mat.mTextureTransform[i].mOffset;
  721. }
  722. if (override_mat.mTextureTransform[i].mScale !=
  723. getDefaultTextureScale())
  724. {
  725. mTextureTransform[i].mScale =
  726. override_mat.mTextureTransform[i].mScale;
  727. }
  728. if (override_mat.mTextureTransform[i].mRotation !=
  729. getDefaultTextureRotation())
  730. {
  731. mTextureTransform[i].mRotation =
  732. override_mat.mTextureTransform[i].mRotation;
  733. }
  734. }
  735. if (!override_mat.mTrackingIdToLocalTexture.empty())
  736. {
  737. auto it = override_mat.mTrackingIdToLocalTexture.begin();
  738. mTrackingIdToLocalTexture.insert(it, it);
  739. updateLocalTexDataDigest();
  740. updateTextureTracking();
  741. }
  742. }
  743. void LLGLTFMaterial::addLocalTextureTracking(const LLUUID& tracking_id,
  744. const LLUUID& tex_id)
  745. {
  746. mTrackingIdToLocalTexture[tracking_id] = tex_id;
  747. updateLocalTexDataDigest();
  748. }
  749. void LLGLTFMaterial::removeLocalTextureTracking(const LLUUID& tracking_id)
  750. {
  751. mTrackingIdToLocalTexture.erase(tracking_id);
  752. updateLocalTexDataDigest();
  753. }
  754. //virtual
  755. bool LLGLTFMaterial::replaceLocalTexture(const LLUUID& tracking_id,
  756. const LLUUID& old_id,
  757. const LLUUID& new_id)
  758. {
  759. bool seen = false;
  760. for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
  761. {
  762. if (mTextureId[i] == old_id)
  763. {
  764. mTextureId[i] = new_id;
  765. seen = true;
  766. }
  767. else if (mTextureId[i] == new_id)
  768. {
  769. seen = true;
  770. }
  771. }
  772. if (seen)
  773. {
  774. mTrackingIdToLocalTexture[tracking_id] = new_id;
  775. }
  776. else
  777. {
  778. mTrackingIdToLocalTexture.erase(tracking_id);
  779. }
  780. updateLocalTexDataDigest();
  781. return seen;
  782. }