lltexlayerparams.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. /**
  2. * @file lltexlayerparams.cpp
  3. * @brief Texture layer parameters
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2010, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "linden_common.h"
  33. #include "lltexlayerparams.h"
  34. #include "llavatarappearance.h"
  35. #include "llimagetga.h"
  36. #include "llquantize.h"
  37. #include "lltexlayer.h"
  38. #include "lltexturemanagerbridge.h"
  39. #include "llrenderutils.h"
  40. #include "hbtracy.h"
  41. #include "llwearable.h"
  42. //-----------------------------------------------------------------------------
  43. // LLTexLayerParam
  44. //-----------------------------------------------------------------------------
  45. LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface* layer)
  46. : LLViewerVisualParam(),
  47. mTexLayer(layer),
  48. mAvatarAppearance(NULL)
  49. {
  50. if (mTexLayer)
  51. {
  52. mAvatarAppearance = mTexLayer->getTexLayerSet()->getAvatarAppearance();
  53. }
  54. else
  55. {
  56. llerrs << "LLTexLayerParam constructor passed with NULL reference for layer !"
  57. << llendl;
  58. }
  59. }
  60. LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance* appearance)
  61. : LLViewerVisualParam(),
  62. mTexLayer(NULL),
  63. mAvatarAppearance(appearance)
  64. {
  65. }
  66. LLTexLayerParam::LLTexLayerParam(const LLTexLayerParam& other)
  67. : LLViewerVisualParam(other),
  68. mTexLayer(other.mTexLayer),
  69. mAvatarAppearance(other.mAvatarAppearance)
  70. {
  71. }
  72. bool LLTexLayerParam::setInfo(LLViewerVisualParamInfo* info,
  73. bool add_to_appearance)
  74. {
  75. LLViewerVisualParam::setInfo(info);
  76. if (add_to_appearance)
  77. {
  78. mAvatarAppearance->addVisualParam( this);
  79. this->setParamLocation(mAvatarAppearance->isSelf() ? LOC_AV_SELF
  80. : LOC_AV_OTHER);
  81. }
  82. return true;
  83. }
  84. //-----------------------------------------------------------------------------
  85. // LLTexLayerParamAlpha
  86. //-----------------------------------------------------------------------------
  87. // static
  88. LLTexLayerParamAlpha::param_alpha_ptr_list_t LLTexLayerParamAlpha::sInstances;
  89. // static
  90. void LLTexLayerParamAlpha::dumpCacheByteCount()
  91. {
  92. S32 gl_bytes = 0;
  93. getCacheByteCount( &gl_bytes);
  94. llinfos << "Processed Alpha Texture Cache GL:" << gl_bytes / 1024 << "KB"
  95. << llendl;
  96. }
  97. // static
  98. void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes)
  99. {
  100. *gl_bytes = 0;
  101. for (param_alpha_ptr_list_t::iterator iter = sInstances.begin(),
  102. end = sInstances.end();
  103. iter != end; ++iter)
  104. {
  105. LLTexLayerParamAlpha* instance = *iter;
  106. LLGLTexture* tex = instance->mCachedProcessedTexture;
  107. if (tex)
  108. {
  109. S32 bytes = (S32)tex->getWidth() * tex->getHeight() * tex->getComponents();
  110. if (tex->hasGLTexture())
  111. {
  112. *gl_bytes += bytes;
  113. }
  114. }
  115. }
  116. }
  117. LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer)
  118. : LLTexLayerParam(layer),
  119. mCachedProcessedTexture(NULL),
  120. mStaticImageTGA(),
  121. mStaticImageRaw(),
  122. mNeedsCreateTexture(false),
  123. mStaticImageInvalid(false),
  124. mAvgDistortionVec(1.f, 1.f, 1.f),
  125. mCachedEffectiveWeight(0.f)
  126. {
  127. sInstances.push_front(this);
  128. }
  129. LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance)
  130. : LLTexLayerParam(appearance),
  131. mCachedProcessedTexture(NULL),
  132. mStaticImageTGA(),
  133. mStaticImageRaw(),
  134. mNeedsCreateTexture(false),
  135. mStaticImageInvalid(false),
  136. mAvgDistortionVec(1.f, 1.f, 1.f),
  137. mCachedEffectiveWeight(0.f)
  138. {
  139. sInstances.push_front(this);
  140. }
  141. LLTexLayerParamAlpha::LLTexLayerParamAlpha(const LLTexLayerParamAlpha& other)
  142. : LLTexLayerParam(other),
  143. mCachedProcessedTexture(other.mCachedProcessedTexture),
  144. mStaticImageTGA(other.mStaticImageTGA),
  145. mStaticImageRaw(other.mStaticImageRaw),
  146. mNeedsCreateTexture(other.mNeedsCreateTexture),
  147. mStaticImageInvalid(other.mStaticImageInvalid),
  148. mAvgDistortionVec(other.mAvgDistortionVec),
  149. mCachedEffectiveWeight(other.mCachedEffectiveWeight)
  150. {
  151. sInstances.push_front(this);
  152. }
  153. LLTexLayerParamAlpha::~LLTexLayerParamAlpha()
  154. {
  155. deleteCaches();
  156. sInstances.remove(this);
  157. }
  158. //virtual
  159. LLViewerVisualParam* LLTexLayerParamAlpha::cloneParam(LLWearable* wearable) const
  160. {
  161. return new LLTexLayerParamAlpha(*this);
  162. }
  163. void LLTexLayerParamAlpha::deleteCaches()
  164. {
  165. mStaticImageTGA = NULL; // deletes image
  166. mCachedProcessedTexture = NULL;
  167. mStaticImageRaw = NULL;
  168. mNeedsCreateTexture = false;
  169. }
  170. bool LLTexLayerParamAlpha::getMultiplyBlend() const
  171. {
  172. return ((LLTexLayerParamAlphaInfo*)getInfo())->mMultiplyBlend;
  173. }
  174. void LLTexLayerParamAlpha::setWeight(F32 weight, bool upload_bake)
  175. {
  176. if (mIsAnimating || mTexLayer == NULL)
  177. {
  178. return;
  179. }
  180. F32 min_weight = getMinWeight();
  181. F32 max_weight = getMaxWeight();
  182. F32 new_weight = llclamp(weight, min_weight, max_weight);
  183. U8 cur_u8 = F32_to_U8(mCurWeight, min_weight, max_weight);
  184. U8 new_u8 = F32_to_U8(new_weight, min_weight, max_weight);
  185. if (cur_u8 != new_u8)
  186. {
  187. mCurWeight = new_weight;
  188. // only trigger a baked texture update if we're changing a wearable's
  189. // visual param.
  190. if ((mAvatarAppearance->getSex() & getSex()) &&
  191. mAvatarAppearance->isSelf() && !mIsDummy)
  192. {
  193. mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(),
  194. upload_bake);
  195. mTexLayer->invalidateMorphMasks();
  196. }
  197. }
  198. }
  199. void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value,
  200. bool upload_bake)
  201. {
  202. // do not animate dummy parameters
  203. if (mIsDummy)
  204. {
  205. setWeight(target_value, upload_bake);
  206. return;
  207. }
  208. mTargetWeight = target_value;
  209. setWeight(target_value, upload_bake);
  210. mIsAnimating = true;
  211. if (mNext)
  212. {
  213. mNext->setAnimationTarget(target_value, upload_bake);
  214. }
  215. }
  216. void LLTexLayerParamAlpha::animate(F32 delta, bool upload_bake)
  217. {
  218. if (mNext)
  219. {
  220. mNext->animate(delta, upload_bake);
  221. }
  222. }
  223. bool LLTexLayerParamAlpha::getSkip() const
  224. {
  225. if (!mTexLayer)
  226. {
  227. return true;
  228. }
  229. const LLAvatarAppearance* appearance = mTexLayer->getTexLayerSet()->getAvatarAppearance();
  230. if (((LLTexLayerParamAlphaInfo*)getInfo())->mSkipIfZeroWeight)
  231. {
  232. F32 effective_weight = (appearance->getSex() & getSex()) ? mCurWeight
  233. : getDefaultWeight();
  234. if (is_approx_zero(effective_weight))
  235. {
  236. return true;
  237. }
  238. }
  239. LLWearableType::EType type = (LLWearableType::EType)getWearableType();
  240. if (type != LLWearableType::WT_INVALID &&
  241. !appearance->isWearingWearableType(type))
  242. {
  243. return true;
  244. }
  245. return false;
  246. }
  247. bool LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
  248. {
  249. LL_TRACY_TIMER(TRC_TEX_LAYER_PARAM_ALPHA);
  250. bool success = true;
  251. if (!mTexLayer)
  252. {
  253. return success;
  254. }
  255. F32 effective_weight = (mTexLayer->getTexLayerSet()->getAvatarAppearance()->getSex() & getSex()) ? mCurWeight
  256. : getDefaultWeight();
  257. bool weight_changed = effective_weight != mCachedEffectiveWeight;
  258. if (getSkip())
  259. {
  260. return success;
  261. }
  262. gGL.flush();
  263. LLTexLayerParamAlphaInfo* info = (LLTexLayerParamAlphaInfo*)getInfo();
  264. if (info->mMultiplyBlend)
  265. {
  266. // Multiplication: approximates a min() function
  267. gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO);
  268. }
  269. else
  270. {
  271. // Addition: approximates a max() function
  272. gGL.setSceneBlendType(LLRender::BT_ADD);
  273. }
  274. if (!info->mStaticImageFileName.empty() && !mStaticImageInvalid)
  275. {
  276. if (mStaticImageTGA.isNull())
  277. {
  278. // Don't load the image file until we actually need it the first
  279. // time. Like now.
  280. mStaticImageTGA = gTexLayerStaticImageList.getImageTGA(info->mStaticImageFileName);
  281. if (mStaticImageTGA.notNull())
  282. {
  283. // We now have something in one of our caches
  284. LLTexLayerSet::sHasCaches = true;
  285. }
  286. else
  287. {
  288. llwarns << "Unable to load static file: "
  289. << info->mStaticImageFileName << llendl;
  290. mStaticImageInvalid = true; // don't try again.
  291. return false;
  292. }
  293. }
  294. const S32 image_tga_width = mStaticImageTGA->getWidth();
  295. const S32 image_tga_height = mStaticImageTGA->getHeight();
  296. if (weight_changed || mCachedProcessedTexture.isNull() ||
  297. mCachedProcessedTexture->getWidth() != image_tga_width ||
  298. mCachedProcessedTexture->getHeight() != image_tga_height)
  299. {
  300. mCachedEffectiveWeight = effective_weight;
  301. if (!mCachedProcessedTexture)
  302. {
  303. mCachedProcessedTexture = NULL;
  304. if (gTextureManagerBridgep)
  305. {
  306. mCachedProcessedTexture = gTextureManagerBridgep->getLocalTexture(image_tga_width,
  307. image_tga_height,
  308. 1, false);
  309. }
  310. if (mCachedProcessedTexture.notNull())
  311. {
  312. // We now have something in one of our caches
  313. LLTexLayerSet::sHasCaches = true;
  314. mCachedProcessedTexture->setExplicitFormat(GL_ALPHA8,
  315. GL_ALPHA);
  316. }
  317. else
  318. {
  319. llwarns << "Unable to get local texture for: "
  320. << info->mStaticImageFileName << llendl;
  321. mStaticImageTGA = NULL;
  322. mStaticImageInvalid = true; // don't try again.
  323. return false;
  324. }
  325. }
  326. // Applies domain and effective weight to data as it is decoded.
  327. // Also resizes the raw image if needed.
  328. mStaticImageRaw = NULL;
  329. mStaticImageRaw = new LLImageRaw;
  330. mStaticImageTGA->decodeAndProcess(mStaticImageRaw, info->mDomain,
  331. effective_weight);
  332. mNeedsCreateTexture = true;
  333. LL_DEBUGS("TexLayerParams") << "Built Cached Alpha: "
  334. << info->mStaticImageFileName << ": ("
  335. << mStaticImageRaw->getWidth() << ", "
  336. << mStaticImageRaw->getHeight()
  337. << ") - Domain: " << info->mDomain
  338. << " - Weight: " << effective_weight
  339. << LL_ENDL;
  340. }
  341. if (mCachedProcessedTexture)
  342. {
  343. LLTexUnit* unit0 = gGL.getTexUnit(0);
  344. // Create the GL texture, and then hang onto it for future use.
  345. if (mNeedsCreateTexture)
  346. {
  347. mCachedProcessedTexture->createGLTexture(0, mStaticImageRaw);
  348. mNeedsCreateTexture = false;
  349. unit0->bind(mCachedProcessedTexture);
  350. mCachedProcessedTexture->setAddressMode(LLTexUnit::TAM_CLAMP);
  351. }
  352. unit0->bind(mCachedProcessedTexture);
  353. gl_rect_2d_simple_tex(width, height);
  354. unit0->unbind(LLTexUnit::TT_TEXTURE);
  355. }
  356. // Do not keep the cache for other people's avatars
  357. // (it is not really a "cache" in that case, but the logic is the same)
  358. if (!mAvatarAppearance->isSelf())
  359. {
  360. mCachedProcessedTexture = NULL;
  361. }
  362. }
  363. else
  364. {
  365. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  366. gGL.color4f(0.f, 0.f, 0.f, effective_weight);
  367. gl_rect_2d_simple(width, height);
  368. }
  369. stop_glerror();
  370. return success;
  371. }
  372. //-----------------------------------------------------------------------------
  373. // LLTexLayerParamAlphaInfo
  374. //-----------------------------------------------------------------------------
  375. LLTexLayerParamAlphaInfo::LLTexLayerParamAlphaInfo()
  376. : mMultiplyBlend(false),
  377. mSkipIfZeroWeight(false),
  378. mDomain(0.f)
  379. {
  380. }
  381. bool LLTexLayerParamAlphaInfo::parseXml(LLXmlTreeNode* node)
  382. {
  383. llassert(node->hasName("param") && node->getChildByName("param_alpha"));
  384. if (!LLViewerVisualParamInfo::parseXml(node))
  385. {
  386. return false;
  387. }
  388. LLXmlTreeNode* param_alpha_node = node->getChildByName("param_alpha");
  389. if (!param_alpha_node)
  390. {
  391. return false;
  392. }
  393. // NOTE: don't load the image file until it's actually needed.
  394. static LLStdStringHandle tga_file_string = LLXmlTree::addAttributeString("tga_file");
  395. param_alpha_node->getFastAttributeString(tga_file_string,
  396. mStaticImageFileName);
  397. static LLStdStringHandle multiply_blend_string = LLXmlTree::addAttributeString("multiply_blend");
  398. param_alpha_node->getFastAttributeBool(multiply_blend_string,
  399. mMultiplyBlend);
  400. static LLStdStringHandle skip_if_zero_string = LLXmlTree::addAttributeString("skip_if_zero");
  401. param_alpha_node->getFastAttributeBool(skip_if_zero_string,
  402. mSkipIfZeroWeight);
  403. static LLStdStringHandle domain_string = LLXmlTree::addAttributeString("domain");
  404. param_alpha_node->getFastAttributeF32(domain_string, mDomain);
  405. return true;
  406. }
  407. LLTexLayerParamColor::LLTexLayerParamColor(LLTexLayerInterface* layer)
  408. : LLTexLayerParam(layer),
  409. mAvgDistortionVec(1.f, 1.f, 1.f)
  410. {
  411. }
  412. LLTexLayerParamColor::LLTexLayerParamColor(LLAvatarAppearance* appearance)
  413. : LLTexLayerParam(appearance),
  414. mAvgDistortionVec(1.f, 1.f, 1.f)
  415. {
  416. }
  417. LLTexLayerParamColor::LLTexLayerParamColor(const LLTexLayerParamColor& other)
  418. : LLTexLayerParam(other),
  419. mAvgDistortionVec(other.mAvgDistortionVec)
  420. {
  421. }
  422. //virtual
  423. LLViewerVisualParam* LLTexLayerParamColor::cloneParam(LLWearable* wearable) const
  424. {
  425. return new LLTexLayerParamColor(*this);
  426. }
  427. LLColor4 LLTexLayerParamColor::getNetColor() const
  428. {
  429. const LLTexLayerParamColorInfo* info = (LLTexLayerParamColorInfo*)getInfo();
  430. llassert(info->mNumColors >= 1);
  431. F32 effective_weight = mAvatarAppearance && (mAvatarAppearance->getSex() & getSex()) ? mCurWeight
  432. : getDefaultWeight();
  433. S32 index_last = info->mNumColors - 1;
  434. F32 scaled_weight = effective_weight * index_last;
  435. S32 index_start = (S32) scaled_weight;
  436. S32 index_end = index_start + 1;
  437. if (index_start == index_last)
  438. {
  439. return info->mColors[index_last];
  440. }
  441. else
  442. {
  443. F32 weight = scaled_weight - index_start;
  444. const LLColor4 *start = &info->mColors[index_start];
  445. const LLColor4 *end = &info->mColors[index_end];
  446. return LLColor4((1.f - weight) * start->mV[VX] + weight * end->mV[VX],
  447. (1.f - weight) * start->mV[VY] + weight * end->mV[VY],
  448. (1.f - weight) * start->mV[VZ] + weight * end->mV[VZ],
  449. (1.f - weight) * start->mV[VW] + weight * end->mV[VW]);
  450. }
  451. }
  452. void LLTexLayerParamColor::setWeight(F32 weight, bool upload_bake)
  453. {
  454. if (mIsAnimating)
  455. {
  456. return;
  457. }
  458. const LLTexLayerParamColorInfo* info = (LLTexLayerParamColorInfo*)getInfo();
  459. F32 min_weight = getMinWeight();
  460. F32 max_weight = getMaxWeight();
  461. F32 new_weight = llclamp(weight, min_weight, max_weight);
  462. U8 cur_u8 = F32_to_U8(mCurWeight, min_weight, max_weight);
  463. U8 new_u8 = F32_to_U8(new_weight, min_weight, max_weight);
  464. if (cur_u8 != new_u8)
  465. {
  466. mCurWeight = new_weight;
  467. if (info->mNumColors <= 0)
  468. {
  469. // This will happen when we set the default weight the first time.
  470. return;
  471. }
  472. // only trigger a baked texture update if we're changing a wearable's
  473. // visual param.
  474. if ((mAvatarAppearance->getSex() & getSex()) &&
  475. mAvatarAppearance->isSelf() && !mIsDummy)
  476. {
  477. onGlobalColorChanged(upload_bake);
  478. if (mTexLayer)
  479. {
  480. mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(),
  481. upload_bake);
  482. }
  483. }
  484. }
  485. }
  486. void LLTexLayerParamColor::setAnimationTarget(F32 target_value,
  487. bool upload_bake)
  488. {
  489. // set value first then set interpolating flag to ignore further updates
  490. mTargetWeight = target_value;
  491. setWeight(target_value, upload_bake);
  492. mIsAnimating = true;
  493. if (mNext)
  494. {
  495. mNext->setAnimationTarget(target_value, upload_bake);
  496. }
  497. }
  498. void LLTexLayerParamColor::animate(F32 delta, bool upload_bake)
  499. {
  500. if (mNext)
  501. {
  502. mNext->animate(delta, upload_bake);
  503. }
  504. }
  505. //-----------------------------------------------------------------------------
  506. // LLTexLayerParamColorInfo
  507. //-----------------------------------------------------------------------------
  508. LLTexLayerParamColorInfo::LLTexLayerParamColorInfo()
  509. : mOperation(LLTexLayerParamColor::OP_ADD),
  510. mNumColors(0)
  511. {
  512. }
  513. bool LLTexLayerParamColorInfo::parseXml(LLXmlTreeNode* node)
  514. {
  515. llassert(node->hasName("param") && node->getChildByName("param_color"));
  516. if (!LLViewerVisualParamInfo::parseXml(node))
  517. {
  518. return false;
  519. }
  520. LLXmlTreeNode* param_color_node = node->getChildByName("param_color");
  521. if (!param_color_node)
  522. {
  523. return false;
  524. }
  525. std::string op_string;
  526. static LLStdStringHandle operation_string = LLXmlTree::addAttributeString("operation");
  527. if (param_color_node->getFastAttributeString(operation_string, op_string))
  528. {
  529. LLStringUtil::toLower(op_string);
  530. if (op_string == "add")
  531. {
  532. mOperation = LLTexLayerParamColor::OP_ADD;
  533. }
  534. else if (op_string == "multiply")
  535. {
  536. mOperation = LLTexLayerParamColor::OP_MULTIPLY;
  537. }
  538. else if (op_string == "blend")
  539. {
  540. mOperation = LLTexLayerParamColor::OP_BLEND;
  541. }
  542. }
  543. mNumColors = 0;
  544. LLColor4U color4u;
  545. for (LLXmlTreeNode* child = param_color_node->getChildByName("value");
  546. child; child = param_color_node->getNextNamedChild())
  547. {
  548. if (mNumColors < MAX_COLOR_VALUES)
  549. {
  550. static LLStdStringHandle color_string = LLXmlTree::addAttributeString("color");
  551. if (child->getFastAttributeColor4U(color_string, color4u))
  552. {
  553. mColors[mNumColors++].set(color4u);
  554. }
  555. }
  556. }
  557. if (!mNumColors)
  558. {
  559. llwarns << "<param_color> is missing <value> sub-elements" << llendl;
  560. return false;
  561. }
  562. if (mOperation == LLTexLayerParamColor::OP_BLEND && mNumColors != 1)
  563. {
  564. llwarns << "<param_color> with operation\"blend\" must have exactly one <value>"
  565. << llendl;
  566. return false;
  567. }
  568. return true;
  569. }