PageRenderTime 302ms CodeModel.GetById 41ms app.highlight 223ms RepoModel.GetById 18ms app.codeStats 3ms

/indra/llprimitive/llprimitive.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1917 lines | 1381 code | 243 blank | 293 comment | 208 complexity | 3929406fa02e4b3fadfe7e2af3d56891 MD5 | raw file
   1/** 
   2 * @file llprimitive.cpp
   3 * @brief LLPrimitive base class
   4 *
   5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "linden_common.h"
  28
  29#include "material_codes.h"
  30#include "llmemtype.h"
  31#include "llerror.h"
  32#include "message.h"
  33#include "llprimitive.h"
  34#include "llvolume.h"
  35#include "legacy_object_types.h"
  36#include "v4coloru.h"
  37#include "llvolumemgr.h"
  38#include "llstring.h"
  39#include "lldatapacker.h"
  40#include "llsdutil_math.h"
  41#include "llprimtexturelist.h"
  42
  43/**
  44 * exported constants
  45 */
  46
  47const F32 OBJECT_CUT_MIN = 0.f;
  48const F32 OBJECT_CUT_MAX = 1.f;
  49const F32 OBJECT_CUT_INC = 0.05f;
  50const F32 OBJECT_MIN_CUT_INC = 0.02f;
  51const F32 OBJECT_ROTATION_PRECISION = 0.05f;
  52
  53const F32 OBJECT_TWIST_MIN = -360.f;
  54const F32 OBJECT_TWIST_MAX =  360.f;
  55const F32 OBJECT_TWIST_INC =   18.f;
  56
  57// This is used for linear paths,
  58// since twist is used in a slightly different manner.
  59const F32 OBJECT_TWIST_LINEAR_MIN	= -180.f;
  60const F32 OBJECT_TWIST_LINEAR_MAX	=  180.f;
  61const F32 OBJECT_TWIST_LINEAR_INC	=    9.f;
  62
  63const F32 OBJECT_MIN_HOLE_SIZE = 0.05f;
  64const F32 OBJECT_MAX_HOLE_SIZE_X = 1.0f;
  65const F32 OBJECT_MAX_HOLE_SIZE_Y = 0.5f;
  66
  67// Revolutions parameters.
  68const F32 OBJECT_REV_MIN = 1.0f;
  69const F32 OBJECT_REV_MAX = 4.0f;
  70const F32 OBJECT_REV_INC = 0.1f;
  71
  72// lights
  73const F32 LIGHT_MIN_RADIUS = 0.0f;
  74const F32 LIGHT_DEFAULT_RADIUS = 5.0f;
  75const F32 LIGHT_MAX_RADIUS = 20.0f;
  76const F32 LIGHT_MIN_FALLOFF = 0.0f;
  77const F32 LIGHT_DEFAULT_FALLOFF = 1.0f;
  78const F32 LIGHT_MAX_FALLOFF = 2.0f;
  79const F32 LIGHT_MIN_CUTOFF = 0.0f;
  80const F32 LIGHT_DEFAULT_CUTOFF = 0.0f;
  81const F32 LIGHT_MAX_CUTOFF = 180.f;
  82
  83// "Tension" => [0,10], increments of 0.1
  84const F32 FLEXIBLE_OBJECT_MIN_TENSION = 0.0f;
  85const F32 FLEXIBLE_OBJECT_DEFAULT_TENSION = 1.0f;
  86const F32 FLEXIBLE_OBJECT_MAX_TENSION = 10.0f; 
  87
  88// "Drag" => [0,10], increments of 0.1
  89const F32 FLEXIBLE_OBJECT_MIN_AIR_FRICTION = 0.0f;
  90const F32 FLEXIBLE_OBJECT_DEFAULT_AIR_FRICTION = 2.0f;
  91const F32 FLEXIBLE_OBJECT_MAX_AIR_FRICTION = 10.0f;
  92
  93// "Gravity" = [-10,10], increments of 0.1
  94const F32 FLEXIBLE_OBJECT_MIN_GRAVITY = -10.0f;
  95const F32 FLEXIBLE_OBJECT_DEFAULT_GRAVITY = 0.3f;
  96const F32 FLEXIBLE_OBJECT_MAX_GRAVITY = 10.0f;
  97
  98// "Wind" = [0,10], increments of 0.1
  99const F32 FLEXIBLE_OBJECT_MIN_WIND_SENSITIVITY = 0.0f;
 100const F32 FLEXIBLE_OBJECT_DEFAULT_WIND_SENSITIVITY = 0.0f;
 101const F32 FLEXIBLE_OBJECT_MAX_WIND_SENSITIVITY = 10.0f;
 102
 103// I'll explain later...
 104const F32 FLEXIBLE_OBJECT_MAX_INTERNAL_TENSION_FORCE = 0.99f; 
 105
 106const F32 FLEXIBLE_OBJECT_DEFAULT_LENGTH = 1.0f;
 107const BOOL FLEXIBLE_OBJECT_DEFAULT_USING_COLLISION_SPHERE = FALSE;
 108const BOOL FLEXIBLE_OBJECT_DEFAULT_RENDERING_COLLISION_SPHERE = FALSE;
 109
 110const S32 MAX_FACE_BITS = 9;
 111
 112const char *SCULPT_DEFAULT_TEXTURE = "be293869-d0d9-0a69-5989-ad27f1946fd4"; // old inverted texture: "7595d345-a24c-e7ef-f0bd-78793792133e";
 113
 114// Texture rotations are sent over the wire as a S16.  This is used to scale the actual float
 115// value to a S16.   Don't use 7FFF as it introduces some odd rounding with 180 since it 
 116// can't be divided by 2.   See DEV-19108
 117const F32	TEXTURE_ROTATION_PACK_FACTOR = ((F32) 0x08000);
 118
 119//static 
 120// LEGACY: by default we use the LLVolumeMgr::gVolumeMgr global
 121// TODO -- eliminate this global from the codebase!
 122LLVolumeMgr* LLPrimitive::sVolumeManager = NULL;
 123
 124// static
 125void LLPrimitive::setVolumeManager( LLVolumeMgr* volume_manager )
 126{
 127	if ( !volume_manager || sVolumeManager )
 128	{
 129		llerrs << "LLPrimitive::sVolumeManager attempting to be set to NULL or it already has been set." << llendl;
 130	}
 131	sVolumeManager = volume_manager;
 132}
 133
 134// static
 135bool LLPrimitive::cleanupVolumeManager()
 136{
 137	BOOL res = FALSE;
 138	if (sVolumeManager) 
 139	{
 140		res = sVolumeManager->cleanup();
 141		delete sVolumeManager;
 142		sVolumeManager = NULL;
 143	}
 144	return res;
 145}
 146
 147
 148//===============================================================
 149LLPrimitive::LLPrimitive()
 150:	mTextureList(),
 151	mNumTEs(0),
 152	mMiscFlags(0)
 153{
 154	mPrimitiveCode = 0;
 155
 156	mMaterial = LL_MCODE_STONE;
 157	mVolumep  = NULL;
 158
 159	mChanged  = UNCHANGED;
 160
 161	mPosition.setVec(0.f,0.f,0.f);
 162	mVelocity.setVec(0.f,0.f,0.f);
 163	mAcceleration.setVec(0.f,0.f,0.f);
 164
 165	mRotation.loadIdentity();
 166	mAngularVelocity.setVec(0.f,0.f,0.f);
 167	
 168	mScale.setVec(1.f,1.f,1.f);
 169}
 170
 171//===============================================================
 172LLPrimitive::~LLPrimitive()
 173{
 174	clearTextureList();
 175	// Cleanup handled by volume manager
 176	if (mVolumep)
 177	{
 178		sVolumeManager->unrefVolume(mVolumep);
 179	}
 180	mVolumep = NULL;
 181}
 182
 183void LLPrimitive::clearTextureList()
 184{
 185}
 186
 187//===============================================================
 188// static
 189LLPrimitive *LLPrimitive::createPrimitive(LLPCode p_code)
 190{
 191	LLMemType m1(LLMemType::MTYPE_PRIMITIVE);
 192	LLPrimitive *retval = new LLPrimitive();
 193	
 194	if (retval)
 195	{
 196		retval->init_primitive(p_code);
 197	}
 198	else
 199	{
 200		llerrs << "primitive allocation failed" << llendl;
 201	}
 202
 203	return retval;
 204}
 205
 206//===============================================================
 207void LLPrimitive::init_primitive(LLPCode p_code)
 208{
 209	LLMemType m1(LLMemType::MTYPE_PRIMITIVE);
 210	clearTextureList();
 211	mPrimitiveCode = p_code;
 212}
 213
 214void LLPrimitive::setPCode(const U8 p_code)
 215{
 216	mPrimitiveCode = p_code;
 217}
 218
 219//===============================================================
 220LLTextureEntry* LLPrimitive::getTE(const U8 index) const
 221{
 222	return mTextureList.getTexture(index);
 223}
 224
 225//===============================================================
 226void LLPrimitive::setNumTEs(const U8 num_tes)
 227{
 228	mTextureList.setSize(num_tes);
 229}
 230
 231//===============================================================
 232void  LLPrimitive::setAllTETextures(const LLUUID &tex_id)
 233{
 234	mTextureList.setAllIDs(tex_id);
 235}
 236
 237//===============================================================
 238void LLPrimitive::setTE(const U8 index, const LLTextureEntry& te)
 239{
 240	mTextureList.copyTexture(index, te);
 241}
 242
 243S32  LLPrimitive::setTETexture(const U8 index, const LLUUID &id)
 244{
 245	return mTextureList.setID(index, id);
 246}
 247
 248S32  LLPrimitive::setTEColor(const U8 index, const LLColor4 &color)
 249{
 250	return mTextureList.setColor(index, color);
 251}
 252
 253S32  LLPrimitive::setTEColor(const U8 index, const LLColor3 &color)
 254{
 255	return mTextureList.setColor(index, color);
 256}
 257
 258S32  LLPrimitive::setTEAlpha(const U8 index, const F32 alpha)
 259{
 260	return mTextureList.setAlpha(index, alpha);
 261}
 262
 263//===============================================================
 264S32  LLPrimitive::setTEScale(const U8 index, const F32 s, const F32 t)
 265{
 266	return mTextureList.setScale(index, s, t);
 267}
 268
 269
 270// BUG: slow - done this way because texture entries have some
 271// voodoo related to texture coords
 272S32 LLPrimitive::setTEScaleS(const U8 index, const F32 s)
 273{
 274	return mTextureList.setScaleS(index, s);
 275}
 276
 277
 278// BUG: slow - done this way because texture entries have some
 279// voodoo related to texture coords
 280S32 LLPrimitive::setTEScaleT(const U8 index, const F32 t)
 281{
 282	return mTextureList.setScaleT(index, t);
 283}
 284
 285
 286//===============================================================
 287S32  LLPrimitive::setTEOffset(const U8 index, const F32 s, const F32 t)
 288{
 289	return mTextureList.setOffset(index, s, t);
 290}
 291
 292
 293// BUG: slow - done this way because texture entries have some
 294// voodoo related to texture coords
 295S32 LLPrimitive::setTEOffsetS(const U8 index, const F32 s)
 296{
 297	return mTextureList.setOffsetS(index, s);
 298}
 299
 300
 301// BUG: slow - done this way because texture entries have some
 302// voodoo related to texture coords
 303S32 LLPrimitive::setTEOffsetT(const U8 index, const F32 t)
 304{
 305	return mTextureList.setOffsetT(index, t);
 306}
 307
 308
 309//===============================================================
 310S32  LLPrimitive::setTERotation(const U8 index, const F32 r)
 311{
 312	return mTextureList.setRotation(index, r);
 313}
 314
 315
 316//===============================================================
 317S32  LLPrimitive::setTEBumpShinyFullbright(const U8 index, const U8 bump)
 318{
 319	return mTextureList.setBumpShinyFullbright(index, bump);
 320}
 321
 322S32  LLPrimitive::setTEMediaTexGen(const U8 index, const U8 media)
 323{
 324	return mTextureList.setMediaTexGen(index, media);
 325}
 326
 327S32  LLPrimitive::setTEBumpmap(const U8 index, const U8 bump)
 328{
 329	return mTextureList.setBumpMap(index, bump);
 330}
 331
 332S32  LLPrimitive::setTEBumpShiny(const U8 index, const U8 bump_shiny)
 333{
 334	return mTextureList.setBumpShiny(index, bump_shiny);
 335}
 336
 337S32  LLPrimitive::setTETexGen(const U8 index, const U8 texgen)
 338{
 339	return mTextureList.setTexGen(index, texgen);
 340}
 341
 342S32  LLPrimitive::setTEShiny(const U8 index, const U8 shiny)
 343{
 344	return mTextureList.setShiny(index, shiny);
 345}
 346
 347S32  LLPrimitive::setTEFullbright(const U8 index, const U8 fullbright)
 348{
 349	return mTextureList.setFullbright(index, fullbright);
 350}
 351
 352S32  LLPrimitive::setTEMediaFlags(const U8 index, const U8 media_flags)
 353{
 354	return mTextureList.setMediaFlags(index, media_flags);
 355}
 356
 357S32 LLPrimitive::setTEGlow(const U8 index, const F32 glow)
 358{
 359	return mTextureList.setGlow(index, glow);
 360}
 361
 362
 363LLPCode LLPrimitive::legacyToPCode(const U8 legacy)
 364{
 365	// TODO: Should this default to something valid?
 366	// Maybe volume?
 367	LLPCode pcode = 0;
 368
 369	switch (legacy)
 370	{
 371		/*
 372	case BOX:
 373		pcode = LL_PCODE_CUBE;
 374		break;
 375	case CYLINDER:
 376		pcode = LL_PCODE_CYLINDER;
 377		break;
 378	case CONE:
 379		pcode = LL_PCODE_CONE;
 380		break;
 381	case HALF_CONE:
 382		pcode = LL_PCODE_CONE_HEMI;
 383		break;
 384	case HALF_CYLINDER:
 385		pcode = LL_PCODE_CYLINDER_HEMI;
 386		break;
 387	case HALF_SPHERE:
 388		pcode = LL_PCODE_SPHERE_HEMI;
 389		break;
 390	case PRISM:
 391		pcode = LL_PCODE_PRISM;
 392		break;
 393	case PYRAMID:
 394		pcode = LL_PCODE_PYRAMID;
 395		break;
 396	case SPHERE:
 397		pcode = LL_PCODE_SPHERE;
 398		break;
 399	case TETRAHEDRON:
 400		pcode = LL_PCODE_TETRAHEDRON;
 401		break;
 402	case DEMON:
 403		pcode = LL_PCODE_LEGACY_DEMON;
 404		break;
 405	case LSL_TEST:
 406		pcode = LL_PCODE_LEGACY_LSL_TEST;
 407		break;
 408	case ORACLE:
 409		pcode = LL_PCODE_LEGACY_ORACLE;
 410		break;
 411	case TEXTBUBBLE:
 412		pcode = LL_PCODE_LEGACY_TEXT_BUBBLE;
 413		break;
 414	case ATOR:
 415		pcode = LL_PCODE_LEGACY_ATOR;
 416		break;
 417	case BASIC_SHOT:
 418		pcode = LL_PCODE_LEGACY_SHOT;
 419		break;
 420	case BIG_SHOT:
 421		pcode = LL_PCODE_LEGACY_SHOT_BIG;
 422		break;
 423	case BIRD:
 424		pcode = LL_PCODE_LEGACY_BIRD;
 425		break;
 426	case ROCK:
 427		pcode = LL_PCODE_LEGACY_ROCK;
 428		break;
 429	case SMOKE:
 430		pcode = LL_PCODE_LEGACY_SMOKE;
 431		break;
 432	case SPARK:
 433		pcode = LL_PCODE_LEGACY_SPARK;
 434		break;
 435		*/
 436	case PRIMITIVE_VOLUME:
 437		pcode = LL_PCODE_VOLUME;
 438		break;
 439	case GRASS:
 440		pcode = LL_PCODE_LEGACY_GRASS;
 441		break;
 442	case PART_SYS:
 443		pcode = LL_PCODE_LEGACY_PART_SYS;
 444		break;
 445	case PLAYER:
 446		pcode = LL_PCODE_LEGACY_AVATAR;
 447		break;
 448	case TREE:
 449		pcode = LL_PCODE_LEGACY_TREE;
 450		break;
 451	case TREE_NEW:
 452		pcode = LL_PCODE_TREE_NEW;
 453		break;
 454	default:
 455		llwarns << "Unknown legacy code " << legacy << " [" << (S32)legacy << "]!" << llendl;
 456	}
 457
 458	return pcode;
 459}
 460
 461U8 LLPrimitive::pCodeToLegacy(const LLPCode pcode)
 462{
 463	U8 legacy;
 464	switch (pcode)
 465	{
 466/*
 467	case LL_PCODE_CUBE:
 468		legacy = BOX;
 469		break;
 470	case LL_PCODE_CYLINDER:
 471		legacy = CYLINDER;
 472		break;
 473	case LL_PCODE_CONE:
 474		legacy = CONE;
 475		break;
 476	case LL_PCODE_CONE_HEMI:
 477		legacy = HALF_CONE;
 478		break;
 479	case LL_PCODE_CYLINDER_HEMI:
 480		legacy = HALF_CYLINDER;
 481		break;
 482	case LL_PCODE_SPHERE_HEMI:
 483		legacy = HALF_SPHERE;
 484		break;
 485	case LL_PCODE_PRISM:
 486		legacy = PRISM;
 487		break;
 488	case LL_PCODE_PYRAMID:
 489		legacy = PYRAMID;
 490		break;
 491	case LL_PCODE_SPHERE:
 492		legacy = SPHERE;
 493		break;
 494	case LL_PCODE_TETRAHEDRON:
 495		legacy = TETRAHEDRON;
 496		break;
 497	case LL_PCODE_LEGACY_ATOR:
 498		legacy = ATOR;
 499		break;
 500	case LL_PCODE_LEGACY_SHOT:
 501		legacy = BASIC_SHOT;
 502		break;
 503	case LL_PCODE_LEGACY_SHOT_BIG:
 504		legacy = BIG_SHOT;
 505		break;
 506	case LL_PCODE_LEGACY_BIRD:
 507		legacy = BIRD;
 508		break;		
 509	case LL_PCODE_LEGACY_DEMON:
 510		legacy = DEMON;
 511		break;
 512	case LL_PCODE_LEGACY_LSL_TEST:
 513		legacy = LSL_TEST;
 514		break;
 515	case LL_PCODE_LEGACY_ORACLE:
 516		legacy = ORACLE;
 517		break;
 518	case LL_PCODE_LEGACY_ROCK:
 519		legacy = ROCK;
 520		break;
 521	case LL_PCODE_LEGACY_TEXT_BUBBLE:
 522		legacy = TEXTBUBBLE;
 523		break;
 524	case LL_PCODE_LEGACY_SMOKE:
 525		legacy = SMOKE;
 526		break;
 527	case LL_PCODE_LEGACY_SPARK:
 528		legacy = SPARK;
 529		break;
 530*/
 531	case LL_PCODE_VOLUME:
 532		legacy = PRIMITIVE_VOLUME;
 533		break;
 534	case LL_PCODE_LEGACY_GRASS:
 535		legacy = GRASS;
 536		break;
 537	case LL_PCODE_LEGACY_PART_SYS:
 538		legacy = PART_SYS;
 539		break;
 540	case LL_PCODE_LEGACY_AVATAR:
 541		legacy = PLAYER;
 542		break;
 543	case LL_PCODE_LEGACY_TREE:
 544		legacy = TREE;
 545		break;
 546	case LL_PCODE_TREE_NEW:
 547		legacy = TREE_NEW;
 548		break;
 549	default:
 550		llwarns << "Unknown pcode " << (S32)pcode << ":" << pcode << "!" << llendl;
 551		return 0;
 552	}
 553	return legacy;
 554}
 555
 556
 557// static
 558// Don't crash or llerrs here!  This function is used for debug strings.
 559std::string LLPrimitive::pCodeToString(const LLPCode pcode)
 560{
 561	std::string pcode_string;
 562
 563	U8 base_code = pcode & LL_PCODE_BASE_MASK;
 564	if (!pcode)
 565	{
 566		pcode_string = "null";
 567	}
 568	else if ((base_code) == LL_PCODE_LEGACY)
 569	{
 570		// It's a legacy object
 571		switch (pcode)
 572		{
 573		case LL_PCODE_LEGACY_GRASS:
 574		  pcode_string = "grass";
 575			break;
 576		case LL_PCODE_LEGACY_PART_SYS:
 577		  pcode_string = "particle system";
 578			break;
 579		case LL_PCODE_LEGACY_AVATAR:
 580		  pcode_string = "avatar";
 581			break;
 582		case LL_PCODE_LEGACY_TEXT_BUBBLE:
 583		  pcode_string = "text bubble";
 584			break;
 585		case LL_PCODE_LEGACY_TREE:
 586		  pcode_string = "tree";
 587			break;
 588		case LL_PCODE_TREE_NEW:
 589		  pcode_string = "tree_new";
 590			break;
 591		default:
 592		  pcode_string = llformat( "unknown legacy pcode %i",(U32)pcode);
 593		}
 594	}
 595	else
 596	{
 597		std::string shape;
 598		std::string mask;
 599		if (base_code == LL_PCODE_CUBE)
 600		{
 601			shape = "cube";
 602		}
 603		else if (base_code == LL_PCODE_CYLINDER)
 604		{
 605			shape = "cylinder";
 606		}
 607		else if (base_code == LL_PCODE_CONE)
 608		{
 609			shape = "cone";
 610		}
 611		else if (base_code == LL_PCODE_PRISM)
 612		{
 613			shape = "prism";
 614		}
 615		else if (base_code == LL_PCODE_PYRAMID)
 616		{
 617			shape = "pyramid";
 618		}
 619		else if (base_code == LL_PCODE_SPHERE)
 620		{
 621			shape = "sphere";
 622		}
 623		else if (base_code == LL_PCODE_TETRAHEDRON)
 624		{
 625			shape = "tetrahedron";
 626		}
 627		else if (base_code == LL_PCODE_VOLUME)
 628		{
 629			shape = "volume";
 630		}
 631		else if (base_code == LL_PCODE_APP)
 632		{
 633			shape = "app";
 634		}
 635		else
 636		{
 637			llwarns << "Unknown base mask for pcode: " << base_code << llendl;
 638		}
 639
 640		U8 mask_code = pcode & (~LL_PCODE_BASE_MASK);
 641		if (base_code == LL_PCODE_APP)
 642		{
 643			mask = llformat( "%x", mask_code);
 644		}
 645		else if (mask_code & LL_PCODE_HEMI_MASK)
 646		{
 647			mask = "hemi";
 648		}
 649		else 
 650		{
 651			mask = llformat( "%x", mask_code);
 652		}
 653
 654		if (mask[0])
 655		{
 656			pcode_string = llformat( "%s-%s", shape.c_str(), mask.c_str());
 657		}
 658		else
 659		{
 660			pcode_string = llformat( "%s", shape.c_str());
 661		}
 662	}
 663
 664	return pcode_string;
 665}
 666
 667
 668void LLPrimitive::copyTEs(const LLPrimitive *primitivep)
 669{
 670	U32 i;
 671	if (primitivep->getExpectedNumTEs() != getExpectedNumTEs())
 672	{
 673		llwarns << "Primitives don't have same expected number of TE's" << llendl;
 674	}
 675	U32 num_tes = llmin(primitivep->getExpectedNumTEs(), getExpectedNumTEs());
 676	if (mTextureList.size() < getExpectedNumTEs())
 677	{
 678		mTextureList.setSize(getExpectedNumTEs());
 679	}
 680	for (i = 0; i < num_tes; i++)
 681	{
 682		mTextureList.copyTexture(i, *(primitivep->getTE(i)));
 683	}
 684}
 685
 686S32	face_index_from_id(LLFaceID face_ID, const std::vector<LLProfile::Face>& faceArray)
 687{
 688	S32 i;
 689	for (i = 0; i < (S32)faceArray.size(); i++)
 690	{
 691		if (faceArray[i].mFaceID == face_ID)
 692		{
 693			return i;
 694		}
 695	}
 696	return -1;
 697}
 698
 699BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume)
 700{
 701	LLMemType m1(LLMemType::MTYPE_VOLUME);
 702	LLVolume *volumep;
 703	if (unique_volume)
 704	{
 705		F32 volume_detail = LLVolumeLODGroup::getVolumeScaleFromDetail(detail);
 706		if (mVolumep.notNull() && volume_params == mVolumep->getParams() && (volume_detail == mVolumep->getDetail()))
 707		{
 708			return FALSE;
 709		}
 710		volumep = new LLVolume(volume_params, volume_detail, FALSE, TRUE);
 711	}
 712	else
 713	{
 714		if (mVolumep.notNull())
 715		{
 716			F32 volume_detail = LLVolumeLODGroup::getVolumeScaleFromDetail(detail);
 717			if (volume_params == mVolumep->getParams() && (volume_detail == mVolumep->getDetail()))
 718			{
 719				return FALSE;
 720			}
 721		}
 722
 723		volumep = sVolumeManager->refVolume(volume_params, detail);
 724		if (volumep == mVolumep)
 725		{
 726			sVolumeManager->unrefVolume( volumep );  // LLVolumeMgr::refVolume() creates a reference, but we don't need a second one.
 727			return TRUE;
 728		}
 729	}
 730
 731	setChanged(GEOMETRY);
 732
 733	
 734	if (!mVolumep)
 735	{
 736		mVolumep = volumep;
 737		//mFaceMask = mVolumep->generateFaceMask();
 738		setNumTEs(mVolumep->getNumFaces());
 739		return TRUE;
 740	}
 741	
 742#if 0 
 743	// #if 0'd out by davep
 744	// this is a lot of cruft to set texture entry values that just stay the same for LOD switch 
 745	// or immediately get overridden by an object update message, also crashes occasionally
 746	U32 old_face_mask = mVolumep->mFaceMask;
 747
 748	S32 face_bit = 0;
 749	S32 cur_mask = 0;
 750
 751	// Grab copies of the old faces from the original shape, ordered by type.
 752	// We will use these to figure out what old texture info gets mapped to new
 753	// faces in the new shape.
 754	std::vector<LLProfile::Face> old_faces; 
 755	for (S32 face = 0; face < mVolumep->getNumFaces(); face++)
 756	{
 757		old_faces.push_back(mVolumep->getProfile().mFaces[face]);
 758	}
 759
 760	// Copy the old texture info off to the side, but not in the order in which
 761	// they live in the mTextureList, rather in order of ther "face id" which
 762	// is the corresponding value of LLVolueParams::LLProfile::mFaces::mIndex.
 763	//
 764	// Hence, some elements of old_tes::mEntryList will be invalid.  It is
 765	// initialized to a size of 9 (max number of possible faces on a volume?)
 766	// and only the ones with valid types are filled in.
 767	LLPrimTextureList old_tes;
 768	old_tes.setSize(9);
 769	for (face_bit = 0; face_bit < 9; face_bit++)
 770	{
 771		cur_mask = 0x1 << face_bit;
 772		if (old_face_mask & cur_mask)
 773		{
 774			S32 te_index = face_index_from_id(cur_mask, old_faces);
 775			old_tes.copyTexture(face_bit, *(getTE(te_index)));
 776			//llinfos << face_bit << ":" << te_index << ":" << old_tes[face_bit].getID() << llendl;
 777		}
 778	}
 779
 780
 781	// build the new object
 782	sVolumeManager->unrefVolume(mVolumep);
 783	mVolumep = volumep;
 784	
 785	U32 new_face_mask = mVolumep->mFaceMask;
 786	S32 i;
 787
 788	if (old_face_mask == new_face_mask) 
 789	{
 790		// nothing to do
 791		return TRUE;
 792	}
 793
 794	if (mVolumep->getNumFaces() == 0 && new_face_mask != 0)
 795	{
 796		llwarns << "Object with 0 faces found...INCORRECT!" << llendl;
 797		setNumTEs(mVolumep->getNumFaces());
 798		return TRUE;
 799	}
 800
 801	// initialize face_mapping
 802	S32 face_mapping[9];
 803	for (face_bit = 0; face_bit < 9; face_bit++)
 804	{
 805		face_mapping[face_bit] = face_bit;
 806	}
 807
 808	// The new shape may have more faces than the original, but we can't just
 809	// add them to the end -- the ordering matters and it may be that we must
 810	// insert the new faces in the middle of the list.  When we add a face it
 811	// will pick up the texture/color info of one of the old faces an so we
 812	// now figure out which old face info gets mapped to each new face, and 
 813	// store in the face_mapping lookup table.
 814	for (face_bit = 0; face_bit < 9; face_bit++)
 815	{
 816		cur_mask = 0x1 << face_bit;
 817		if (!(new_face_mask & cur_mask))
 818		{
 819			// Face doesn't exist in new map.
 820			face_mapping[face_bit] = -1;
 821			continue;
 822		}
 823		else if (old_face_mask & cur_mask)
 824		{
 825			// Face exists in new and old map.
 826			face_mapping[face_bit] = face_bit;
 827			continue;
 828		}
 829
 830		// OK, how we've got a mismatch, where we have to fill a new face with one from
 831		// the old face.
 832		if (cur_mask & (LL_FACE_PATH_BEGIN | LL_FACE_PATH_END | LL_FACE_INNER_SIDE))
 833		{
 834			// It's a top/bottom/hollow interior face.
 835			if (old_face_mask & LL_FACE_PATH_END)
 836			{
 837				face_mapping[face_bit] = 1;
 838				continue;
 839			}
 840			else
 841			{
 842				S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0;
 843				for (i = 0; i < 4; i++)
 844				{
 845					if (old_face_mask & cur_outer_mask)
 846					{
 847						face_mapping[face_bit] = 5 + i;
 848						break;
 849					}
 850					cur_outer_mask <<= 1;
 851				}
 852				if (i == 4)
 853				{
 854					llwarns << "No path end or outer face in volume!" << llendl;
 855				}
 856				continue;
 857			}
 858		}
 859
 860		if (cur_mask & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END))
 861		{
 862			// A cut slice.  Use the hollow interior if we have it.
 863			if (old_face_mask & LL_FACE_INNER_SIDE)
 864			{
 865				face_mapping[face_bit] = 2;
 866				continue;
 867			}
 868
 869			// No interior, use the bottom face.
 870			// Could figure out which of the outer faces was nearest, but that would be harder.
 871			if (old_face_mask & LL_FACE_PATH_END)
 872			{
 873				face_mapping[face_bit] = 1;
 874				continue;
 875			}
 876			else
 877			{
 878				S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0;
 879				for (i = 0; i < 4; i++)
 880				{
 881					if (old_face_mask & cur_outer_mask)
 882					{
 883						face_mapping[face_bit] = 5 + i;
 884						break;
 885					}
 886					cur_outer_mask <<= 1;
 887				}
 888				if (i == 4)
 889				{
 890					llwarns << "No path end or outer face in volume!" << llendl;
 891				}
 892				continue;
 893			}
 894		}
 895
 896		// OK, the face that's missing is an outer face...
 897		// Pull from the nearest adjacent outer face (there's always guaranteed to be one...
 898		S32 cur_outer = face_bit - 5;
 899		S32 min_dist = 5;
 900		S32 min_outer_bit = -1;
 901		S32 i;
 902		for (i = 0; i < 4; i++)
 903		{
 904			if (old_face_mask & (LL_FACE_OUTER_SIDE_0 << i))
 905			{
 906				S32 dist = abs(i - cur_outer);
 907				if (dist < min_dist)
 908				{
 909					min_dist = dist;
 910					min_outer_bit = i + 5;
 911				}
 912			}
 913		}
 914		if (-1 == min_outer_bit)
 915		{
 916			llinfos << (LLVolume *)mVolumep << llendl;
 917			llwarns << "Bad!  No outer faces, impossible!" << llendl;
 918		}
 919		face_mapping[face_bit] = min_outer_bit;
 920	}
 921	
 922
 923	setNumTEs(mVolumep->getNumFaces());
 924	for (face_bit = 0; face_bit < 9; face_bit++)
 925	{
 926		// For each possible face type on the new shape we check to see if that
 927		// face exists and if it does we create a texture entry that is a copy
 928		// of one of the originals.  Since the originals might not have a
 929		// matching face, we use the face_mapping lookup table to figure out
 930		// which face information to copy.
 931		cur_mask = 0x1 << face_bit;
 932		if (new_face_mask & cur_mask)
 933		{
 934			if (-1 == face_mapping[face_bit])
 935			{
 936				llwarns << "No mapping from old face to new face!" << llendl;
 937			}
 938
 939			S32 te_num = face_index_from_id(cur_mask, mVolumep->getProfile().mFaces);
 940			setTE(te_num, *(old_tes.getTexture(face_mapping[face_bit])));
 941		}
 942	}
 943#else
 944	// build the new object
 945	sVolumeManager->unrefVolume(mVolumep);
 946	mVolumep = volumep; 
 947
 948	setNumTEs(mVolumep->getNumFaces());
 949#endif
 950	return TRUE;
 951}
 952
 953BOOL LLPrimitive::setMaterial(U8 material)
 954{
 955	if (material != mMaterial)
 956	{
 957		mMaterial = material;
 958		return TRUE;
 959	}
 960	else
 961	{
 962		return FALSE;
 963	}
 964}
 965
 966const F32 LL_MAX_SCALE_S = 100.0f;
 967const F32 LL_MAX_SCALE_T = 100.0f;
 968S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const
 969{
 970	S32 face_index;
 971	S32 i;
 972	U64 exception_faces;
 973	U8 *start_loc = cur_ptr;
 974
 975	htonmemcpy(cur_ptr,data_ptr + (last_face_index * data_size), type, data_size);
 976	cur_ptr += data_size;
 977	
 978	for (face_index = last_face_index-1; face_index >= 0; face_index--)
 979	{
 980		BOOL already_sent = FALSE;
 981		for (i = face_index+1; i <= last_face_index; i++)
 982		{ 
 983			if (!memcmp(data_ptr+(data_size *face_index), data_ptr+(data_size *i), data_size))
 984			{
 985				already_sent = TRUE;
 986				break;
 987			}
 988		}
 989
 990		if (!already_sent)
 991		{
 992			exception_faces = 0;
 993			for (i = face_index; i >= 0; i--)
 994			{ 
 995				if (!memcmp(data_ptr+(data_size *face_index), data_ptr+(data_size *i), data_size))
 996				{
 997					exception_faces |= ((U64)1 << i); 
 998				}
 999			}
1000			
1001			//assign exception faces to cur_ptr
1002			if (exception_faces >= (0x1 << 7))
1003			{
1004				if (exception_faces >= (0x1 << 14))
1005				{
1006					if (exception_faces >= (0x1 << 21))
1007					{
1008						if (exception_faces >= (0x1 << 28))
1009						{
1010							*cur_ptr++ = (U8)(((exception_faces >> 28) & 0x7F) | 0x80);
1011						}
1012						*cur_ptr++ = (U8)(((exception_faces >> 21) & 0x7F) | 0x80);
1013					}
1014					*cur_ptr++ = (U8)(((exception_faces >> 14) & 0x7F) | 0x80);
1015				}
1016				*cur_ptr++ = (U8)(((exception_faces >> 7) & 0x7F) | 0x80);
1017			}
1018			
1019			*cur_ptr++ = (U8)(exception_faces & 0x7F);
1020			
1021			htonmemcpy(cur_ptr,data_ptr + (face_index * data_size), type, data_size);
1022			cur_ptr += data_size;
1023   		}
1024	}
1025	return (S32)(cur_ptr - start_loc);
1026}
1027
1028S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type)
1029{
1030	U8 *start_loc = cur_ptr;
1031	U64 i;
1032	htonmemcpy(data_ptr,cur_ptr, type,data_size);
1033	cur_ptr += data_size;
1034
1035	for (i = 1; i < face_count; i++)
1036	{
1037		// Already unswizzled, don't need to unswizzle it again!
1038		memcpy(data_ptr+(i*data_size),data_ptr,data_size);	/* Flawfinder: ignore */ 
1039	}
1040	
1041	while ((cur_ptr < buffer_end) && (*cur_ptr != 0))
1042	{
1043//		llinfos << "TE exception" << llendl;
1044		i = 0;
1045		while (*cur_ptr & 0x80)
1046		{
1047			i |= ((*cur_ptr++) & 0x7F);
1048			i = i << 7;
1049		}
1050
1051		i |= *cur_ptr++;
1052
1053		for (S32 j = 0; j < face_count; j++)
1054		{
1055			if (i & 0x01)
1056			{
1057				htonmemcpy(data_ptr+(j*data_size),cur_ptr,type,data_size);
1058//				char foo[64];
1059//				sprintf(foo,"%x %x",*(data_ptr+(j*data_size)), *(data_ptr+(j*data_size)+1));
1060//				llinfos << "Assigning " << foo << " to face " << j << llendl;			
1061			}
1062			i = i >> 1;
1063		}
1064		cur_ptr += data_size;		
1065	}
1066	return (S32)(cur_ptr - start_loc);
1067}
1068
1069
1070// Pack information about all texture entries into container:
1071// { TextureEntry Variable 2 }
1072// Includes information about image ID, color, scale S,T, offset S,T and rotation
1073BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const
1074{
1075	const U32 MAX_TES = 32;
1076
1077	U8     image_ids[MAX_TES*16];
1078	U8     colors[MAX_TES*4];
1079	F32    scale_s[MAX_TES];
1080	F32    scale_t[MAX_TES];
1081	S16    offset_s[MAX_TES];
1082	S16    offset_t[MAX_TES];
1083	S16    image_rot[MAX_TES];
1084	U8	   bump[MAX_TES];
1085	U8	   media_flags[MAX_TES];
1086    U8     glow[MAX_TES];
1087	
1088	const U32 MAX_TE_BUFFER = 4096;
1089	U8 packed_buffer[MAX_TE_BUFFER];
1090	U8 *cur_ptr = packed_buffer;
1091	
1092	S32 last_face_index = llmin((U32) getNumTEs(), MAX_TES) - 1;
1093	
1094	if (last_face_index > -1)
1095	{
1096		// ...if we hit the front, send one image id
1097		S8 face_index;
1098		LLColor4U coloru;
1099		for (face_index = 0; face_index <= last_face_index; face_index++)
1100		{
1101			// Directly sending image_ids is not safe!
1102			memcpy(&image_ids[face_index*16],getTE(face_index)->getID().mData,16);	/* Flawfinder: ignore */ 
1103
1104			// Cast LLColor4 to LLColor4U
1105			coloru.setVec( getTE(face_index)->getColor() );
1106
1107			// Note:  This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
1108			// as all zeros.  However, the subtraction and addition must be done in unsigned
1109			// byte space, not in float space, otherwise off-by-one errors occur. JC
1110			colors[4*face_index]     = 255 - coloru.mV[0];
1111			colors[4*face_index + 1] = 255 - coloru.mV[1];
1112			colors[4*face_index + 2] = 255 - coloru.mV[2];
1113			colors[4*face_index + 3] = 255 - coloru.mV[3];
1114
1115			const LLTextureEntry* te = getTE(face_index);
1116			scale_s[face_index] = (F32) te->mScaleS;
1117			scale_t[face_index] = (F32) te->mScaleT;
1118			offset_s[face_index] = (S16) llround((llclamp(te->mOffsetS,-1.0f,1.0f) * (F32)0x7FFF)) ;
1119			offset_t[face_index] = (S16) llround((llclamp(te->mOffsetT,-1.0f,1.0f) * (F32)0x7FFF)) ;
1120			image_rot[face_index] = (S16) llround(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * TEXTURE_ROTATION_PACK_FACTOR));
1121			bump[face_index] = te->getBumpShinyFullbright();
1122			media_flags[face_index] = te->getMediaTexGen();
1123			glow[face_index] = (U8) llround((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF));
1124		}
1125
1126		cur_ptr += packTEField(cur_ptr, (U8 *)image_ids, sizeof(LLUUID),last_face_index, MVT_LLUUID);
1127		*cur_ptr++ = 0;
1128		cur_ptr += packTEField(cur_ptr, (U8 *)colors, 4 ,last_face_index, MVT_U8);
1129		*cur_ptr++ = 0;
1130		cur_ptr += packTEField(cur_ptr, (U8 *)scale_s, 4 ,last_face_index, MVT_F32);
1131		*cur_ptr++ = 0;
1132		cur_ptr += packTEField(cur_ptr, (U8 *)scale_t, 4 ,last_face_index, MVT_F32);
1133		*cur_ptr++ = 0;
1134		cur_ptr += packTEField(cur_ptr, (U8 *)offset_s, 2 ,last_face_index, MVT_S16Array);
1135		*cur_ptr++ = 0;
1136		cur_ptr += packTEField(cur_ptr, (U8 *)offset_t, 2 ,last_face_index, MVT_S16Array);
1137		*cur_ptr++ = 0;
1138		cur_ptr += packTEField(cur_ptr, (U8 *)image_rot, 2 ,last_face_index, MVT_S16Array);
1139		*cur_ptr++ = 0;
1140		cur_ptr += packTEField(cur_ptr, (U8 *)bump, 1 ,last_face_index, MVT_U8);
1141		*cur_ptr++ = 0;
1142		cur_ptr += packTEField(cur_ptr, (U8 *)media_flags, 1 ,last_face_index, MVT_U8);
1143		*cur_ptr++ = 0;
1144		cur_ptr += packTEField(cur_ptr, (U8 *)glow, 1 ,last_face_index, MVT_U8);
1145	}
1146   	mesgsys->addBinaryDataFast(_PREHASH_TextureEntry, packed_buffer, (S32)(cur_ptr - packed_buffer));
1147
1148	return FALSE;
1149}
1150
1151
1152BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const
1153{
1154	const U32 MAX_TES = 32;
1155
1156	U8     image_ids[MAX_TES*16];
1157	U8     colors[MAX_TES*4];
1158	F32    scale_s[MAX_TES];
1159	F32    scale_t[MAX_TES];
1160	S16    offset_s[MAX_TES];
1161	S16    offset_t[MAX_TES];
1162	S16    image_rot[MAX_TES];
1163	U8	   bump[MAX_TES];
1164	U8	   media_flags[MAX_TES];
1165    U8     glow[MAX_TES];
1166	
1167	const U32 MAX_TE_BUFFER = 4096;
1168	U8 packed_buffer[MAX_TE_BUFFER];
1169	U8 *cur_ptr = packed_buffer;
1170	
1171	S32 last_face_index = getNumTEs() - 1;
1172	
1173	if (last_face_index > -1)
1174	{
1175		// ...if we hit the front, send one image id
1176		S8 face_index;
1177		LLColor4U coloru;
1178		for (face_index = 0; face_index <= last_face_index; face_index++)
1179		{
1180			// Directly sending image_ids is not safe!
1181			memcpy(&image_ids[face_index*16],getTE(face_index)->getID().mData,16);	/* Flawfinder: ignore */ 
1182
1183			// Cast LLColor4 to LLColor4U
1184			coloru.setVec( getTE(face_index)->getColor() );
1185
1186			// Note:  This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
1187			// as all zeros.  However, the subtraction and addition must be done in unsigned
1188			// byte space, not in float space, otherwise off-by-one errors occur. JC
1189			colors[4*face_index]     = 255 - coloru.mV[0];
1190			colors[4*face_index + 1] = 255 - coloru.mV[1];
1191			colors[4*face_index + 2] = 255 - coloru.mV[2];
1192			colors[4*face_index + 3] = 255 - coloru.mV[3];
1193
1194			const LLTextureEntry* te = getTE(face_index);
1195			scale_s[face_index] = (F32) te->mScaleS;
1196			scale_t[face_index] = (F32) te->mScaleT;
1197			offset_s[face_index] = (S16) llround((llclamp(te->mOffsetS,-1.0f,1.0f) * (F32)0x7FFF)) ;
1198			offset_t[face_index] = (S16) llround((llclamp(te->mOffsetT,-1.0f,1.0f) * (F32)0x7FFF)) ;
1199			image_rot[face_index] = (S16) llround(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * TEXTURE_ROTATION_PACK_FACTOR));
1200			bump[face_index] = te->getBumpShinyFullbright();
1201			media_flags[face_index] = te->getMediaTexGen();
1202            glow[face_index] = (U8) llround((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF));
1203		}
1204
1205		cur_ptr += packTEField(cur_ptr, (U8 *)image_ids, sizeof(LLUUID),last_face_index, MVT_LLUUID);
1206		*cur_ptr++ = 0;
1207		cur_ptr += packTEField(cur_ptr, (U8 *)colors, 4 ,last_face_index, MVT_U8);
1208		*cur_ptr++ = 0;
1209		cur_ptr += packTEField(cur_ptr, (U8 *)scale_s, 4 ,last_face_index, MVT_F32);
1210		*cur_ptr++ = 0;
1211		cur_ptr += packTEField(cur_ptr, (U8 *)scale_t, 4 ,last_face_index, MVT_F32);
1212		*cur_ptr++ = 0;
1213		cur_ptr += packTEField(cur_ptr, (U8 *)offset_s, 2 ,last_face_index, MVT_S16Array);
1214		*cur_ptr++ = 0;
1215		cur_ptr += packTEField(cur_ptr, (U8 *)offset_t, 2 ,last_face_index, MVT_S16Array);
1216		*cur_ptr++ = 0;
1217		cur_ptr += packTEField(cur_ptr, (U8 *)image_rot, 2 ,last_face_index, MVT_S16Array);
1218		*cur_ptr++ = 0;
1219		cur_ptr += packTEField(cur_ptr, (U8 *)bump, 1 ,last_face_index, MVT_U8);
1220		*cur_ptr++ = 0;
1221		cur_ptr += packTEField(cur_ptr, (U8 *)media_flags, 1 ,last_face_index, MVT_U8);
1222		*cur_ptr++ = 0;
1223		cur_ptr += packTEField(cur_ptr, (U8 *)glow, 1 ,last_face_index, MVT_U8);
1224	}
1225
1226	dp.packBinaryData(packed_buffer, (S32)(cur_ptr - packed_buffer), "TextureEntry");
1227	return FALSE;
1228}
1229
1230S32 LLPrimitive::unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name)
1231{
1232	return(unpackTEMessage(mesgsys,block_name,-1));
1233}
1234
1235S32 LLPrimitive::unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num)
1236{
1237	// use a negative block_num to indicate a single-block read (a non-variable block)
1238	S32 retval = 0;
1239	const U32 MAX_TES = 32;
1240
1241	// Avoid construction of 32 UUIDs per call. JC
1242
1243	U8     image_data[MAX_TES*16];
1244	U8	  colors[MAX_TES*4];
1245	F32    scale_s[MAX_TES];
1246	F32    scale_t[MAX_TES];
1247	S16    offset_s[MAX_TES];
1248	S16    offset_t[MAX_TES];
1249	S16    image_rot[MAX_TES];
1250	U8	   bump[MAX_TES];
1251	U8	   media_flags[MAX_TES];
1252    U8     glow[MAX_TES];
1253	
1254	const U32 MAX_TE_BUFFER = 4096;
1255	U8 packed_buffer[MAX_TE_BUFFER];
1256	U8 *cur_ptr = packed_buffer;
1257
1258	U32 size;
1259	U32 face_count = 0;
1260
1261	if (block_num < 0)
1262	{
1263		size = mesgsys->getSizeFast(block_name, _PREHASH_TextureEntry);
1264	}
1265	else
1266	{
1267		size = mesgsys->getSizeFast(block_name, block_num, _PREHASH_TextureEntry);
1268	}
1269
1270	if (size == 0)
1271	{
1272		return retval;
1273	}
1274
1275	if (block_num < 0)
1276	{
1277		mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, packed_buffer, 0, 0, MAX_TE_BUFFER);
1278	}
1279	else
1280	{
1281		mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, packed_buffer, 0, block_num, MAX_TE_BUFFER);
1282	}
1283
1284	face_count = getNumTEs();
1285
1286	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_data, 16, face_count, MVT_LLUUID);
1287	cur_ptr++;
1288	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)colors, 4, face_count, MVT_U8);
1289	cur_ptr++;
1290	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_s, 4, face_count, MVT_F32);
1291	cur_ptr++;
1292	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_t, 4, face_count, MVT_F32);
1293	cur_ptr++;
1294	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_s, 2, face_count, MVT_S16Array);
1295	cur_ptr++;
1296	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_t, 2, face_count, MVT_S16Array);
1297	cur_ptr++;
1298	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_rot, 2, face_count, MVT_S16Array);
1299	cur_ptr++;
1300	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)bump, 1, face_count, MVT_U8);
1301	cur_ptr++;
1302	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)media_flags, 1, face_count, MVT_U8);
1303	cur_ptr++;
1304	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)glow, 1, face_count, MVT_U8);
1305	
1306	LLColor4 color;
1307	LLColor4U coloru;
1308	for (U32 i = 0; i < face_count; i++)
1309	{
1310		retval |= setTETexture(i, ((LLUUID*)image_data)[i]);
1311		retval |= setTEScale(i, scale_s[i], scale_t[i]);
1312		retval |= setTEOffset(i, (F32)offset_s[i] / (F32)0x7FFF, (F32) offset_t[i] / (F32) 0x7FFF);
1313		retval |= setTERotation(i, ((F32)image_rot[i] / TEXTURE_ROTATION_PACK_FACTOR) * F_TWO_PI);
1314		retval |= setTEBumpShinyFullbright(i, bump[i]);
1315		retval |= setTEMediaTexGen(i, media_flags[i]);
1316		retval |= setTEGlow(i, (F32)glow[i] / (F32)0xFF);
1317		coloru = LLColor4U(colors + 4*i);
1318
1319		// Note:  This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
1320		// as all zeros.  However, the subtraction and addition must be done in unsigned
1321		// byte space, not in float space, otherwise off-by-one errors occur. JC
1322		color.mV[VRED]		= F32(255 - coloru.mV[VRED])   / 255.f;
1323		color.mV[VGREEN]	= F32(255 - coloru.mV[VGREEN]) / 255.f;
1324		color.mV[VBLUE]		= F32(255 - coloru.mV[VBLUE])  / 255.f;
1325		color.mV[VALPHA]	= F32(255 - coloru.mV[VALPHA]) / 255.f;
1326
1327		retval |= setTEColor(i, color);
1328
1329	}
1330
1331	return retval;
1332}
1333
1334S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
1335{
1336	// use a negative block_num to indicate a single-block read (a non-variable block)
1337	S32 retval = 0;
1338	const U32 MAX_TES = 32;
1339
1340	// Avoid construction of 32 UUIDs per call
1341	static LLUUID image_ids[MAX_TES];
1342
1343	U8     image_data[MAX_TES*16];
1344	U8	   colors[MAX_TES*4];
1345	F32    scale_s[MAX_TES];
1346	F32    scale_t[MAX_TES];
1347	S16    offset_s[MAX_TES];
1348	S16    offset_t[MAX_TES];
1349	S16    image_rot[MAX_TES];
1350	U8	   bump[MAX_TES];
1351	U8	   media_flags[MAX_TES];
1352    U8     glow[MAX_TES];
1353
1354	const U32 MAX_TE_BUFFER = 4096;
1355	U8 packed_buffer[MAX_TE_BUFFER];
1356	U8 *cur_ptr = packed_buffer;
1357
1358	S32 size;
1359	U32 face_count = 0;
1360
1361	if (!dp.unpackBinaryData(packed_buffer, size, "TextureEntry"))
1362	{
1363		retval = TEM_INVALID;
1364		llwarns << "Bad texture entry block!  Abort!" << llendl;
1365		return retval;
1366	}
1367
1368	if (size == 0)
1369	{
1370		return retval;
1371	}
1372
1373	face_count = llmin((U32) getNumTEs(), MAX_TES);
1374	U32 i;
1375
1376	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_data, 16, face_count, MVT_LLUUID);
1377	cur_ptr++;
1378	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)colors, 4, face_count, MVT_U8);
1379	cur_ptr++;
1380	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_s, 4, face_count, MVT_F32);
1381	cur_ptr++;
1382	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_t, 4, face_count, MVT_F32);
1383	cur_ptr++;
1384	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_s, 2, face_count, MVT_S16Array);
1385	cur_ptr++;
1386	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_t, 2, face_count, MVT_S16Array);
1387	cur_ptr++;
1388	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_rot, 2, face_count, MVT_S16Array);
1389	cur_ptr++;
1390	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)bump, 1, face_count, MVT_U8);
1391	cur_ptr++;
1392	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)media_flags, 1, face_count, MVT_U8);
1393	cur_ptr++;
1394	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)glow, 1, face_count, MVT_U8);
1395
1396	for (i = 0; i < face_count; i++)
1397	{
1398		memcpy(image_ids[i].mData,&image_data[i*16],16);	/* Flawfinder: ignore */ 	
1399	}
1400	
1401	LLColor4 color;
1402	LLColor4U coloru;
1403	for (i = 0; i < face_count; i++)
1404	{
1405		retval |= setTETexture(i, image_ids[i]);
1406		retval |= setTEScale(i, scale_s[i], scale_t[i]);
1407		retval |= setTEOffset(i, (F32)offset_s[i] / (F32)0x7FFF, (F32) offset_t[i] / (F32) 0x7FFF);
1408		retval |= setTERotation(i, ((F32)image_rot[i] / TEXTURE_ROTATION_PACK_FACTOR) * F_TWO_PI);
1409		retval |= setTEBumpShinyFullbright(i, bump[i]);
1410		retval |= setTEMediaTexGen(i, media_flags[i]);
1411		retval |= setTEGlow(i, (F32)glow[i] / (F32)0xFF);
1412		coloru = LLColor4U(colors + 4*i);
1413
1414		// Note:  This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
1415		// as all zeros.  However, the subtraction and addition must be done in unsigned
1416		// byte space, not in float space, otherwise off-by-one errors occur. JC
1417		color.mV[VRED]		= F32(255 - coloru.mV[VRED])   / 255.f;
1418		color.mV[VGREEN]	= F32(255 - coloru.mV[VGREEN]) / 255.f;
1419		color.mV[VBLUE]		= F32(255 - coloru.mV[VBLUE])  / 255.f;
1420		color.mV[VALPHA]	= F32(255 - coloru.mV[VALPHA]) / 255.f;
1421
1422		retval |= setTEColor(i, color);
1423	}
1424
1425	return retval;
1426}
1427
1428U8	LLPrimitive::getExpectedNumTEs() const
1429{
1430	U8 expected_face_count = 0;
1431	if (mVolumep)
1432	{
1433		expected_face_count = mVolumep->getNumFaces();
1434	}
1435	return expected_face_count;
1436}
1437
1438void LLPrimitive::copyTextureList(const LLPrimTextureList& other_list)
1439{
1440	mTextureList.copy(other_list);
1441}
1442
1443void LLPrimitive::takeTextureList(LLPrimTextureList& other_list)
1444{
1445	mTextureList.take(other_list);
1446}
1447
1448//============================================================================
1449
1450// Moved from llselectmgr.cpp
1451// BUG: Only works for boxes.
1452// Face numbering for flex boxes as of 1.14.2
1453
1454// static
1455bool LLPrimitive::getTESTAxes(const U8 face, U32* s_axis, U32* t_axis)
1456{
1457	if (face == 0)
1458	{
1459		*s_axis = VX; *t_axis = VY;
1460		return true;
1461	}
1462	else if (face == 1)
1463	{
1464		*s_axis = VX; *t_axis = VZ;
1465		return true;
1466	}
1467	else if (face == 2)
1468	{
1469		*s_axis = VY; *t_axis = VZ;
1470		return true;
1471	}
1472	else if (face == 3)
1473	{
1474		*s_axis = VX; *t_axis = VZ;
1475		return true;
1476	}
1477	else if (face == 4)
1478	{
1479		*s_axis = VY; *t_axis = VZ;
1480		return true;
1481	}
1482	else if (face == 5)
1483	{
1484		*s_axis = VX; *t_axis = VY;
1485		return true;
1486	}
1487	else
1488	{
1489		// unknown face
1490		return false;
1491	}
1492}
1493
1494//============================================================================
1495
1496//static 
1497BOOL LLNetworkData::isValid(U16 param_type, U32 size)
1498{
1499	// ew - better mechanism needed
1500	
1501	switch(param_type)
1502	{
1503	case PARAMS_FLEXIBLE:
1504		return (size == 16);
1505	case PARAMS_LIGHT:
1506		return (size == 16);
1507	case PARAMS_SCULPT:
1508		return (size == 17);
1509	case PARAMS_LIGHT_IMAGE:
1510		return (size == 28);
1511	}
1512	
1513	return FALSE;
1514}
1515
1516//============================================================================
1517
1518LLLightParams::LLLightParams()
1519{
1520	mColor.setToWhite();
1521	mRadius = 10.f;
1522	mCutoff = 0.0f;
1523	mFalloff = 0.75f;
1524
1525	mType = PARAMS_LIGHT;
1526}
1527
1528BOOL LLLightParams::pack(LLDataPacker &dp) const
1529{
1530	LLColor4U color4u(mColor);
1531	dp.packColor4U(color4u, "color");
1532	dp.packF32(mRadius, "radius");
1533	dp.packF32(mCutoff, "cutoff");
1534	dp.packF32(mFalloff, "falloff");
1535	return TRUE;
1536}
1537
1538BOOL LLLightParams::unpack(LLDataPacker &dp)
1539{
1540	LLColor4U color;
1541	dp.unpackColor4U(color, "color");
1542	setColor(LLColor4(color));
1543
1544	F32 radius;
1545	dp.unpackF32(radius, "radius");
1546	setRadius(radius);
1547
1548	F32 cutoff;
1549	dp.unpackF32(cutoff, "cutoff");
1550	setCutoff(cutoff);
1551
1552	F32 falloff;
1553	dp.unpackF32(falloff, "falloff");
1554	setFalloff(falloff);
1555	
1556	return TRUE;
1557}
1558
1559bool LLLightParams::operator==(const LLNetworkData& data) const
1560{
1561	if (data.mType != PARAMS_LIGHT)
1562	{
1563		return false;
1564	}
1565	const LLLightParams *param = (const LLLightParams*)&data;
1566	if (param->mColor != mColor ||
1567		param->mRadius != mRadius ||
1568		param->mCutoff != mCutoff ||
1569		param->mFalloff != mFalloff)
1570	{
1571		return false;
1572	}
1573	return true;
1574}
1575
1576void LLLightParams::copy(const LLNetworkData& data)
1577{
1578	const LLLightParams *param = (LLLightParams*)&data;
1579	mType = param->mType;
1580	mColor = param->mColor;
1581	mRadius = param->mRadius;
1582	mCutoff = param->mCutoff;
1583	mFalloff = param->mFalloff;
1584}
1585
1586LLSD LLLightParams::asLLSD() const
1587{
1588	LLSD sd;
1589	
1590	sd["color"] = ll_sd_from_color4(getColor());
1591	sd["radius"] = getRadius();
1592	sd["falloff"] = getFalloff();
1593	sd["cutoff"] = getCutoff();
1594		
1595	return sd;
1596}
1597
1598bool LLLightParams::fromLLSD(LLSD& sd)
1599{
1600	const char *w;
1601	w = "color";
1602	if (sd.has(w))
1603	{
1604		setColor( ll_color4_from_sd(sd["color"]) );
1605	} else goto fail;
1606	w = "radius";
1607	if (sd.has(w))
1608	{
1609		setRadius( (F32)sd[w].asReal() );
1610	} else goto fail;
1611	w = "falloff";
1612	if (sd.has(w))
1613	{
1614		setFalloff( (F32)sd[w].asReal() );
1615	} else goto fail;
1616	w = "cutoff";
1617	if (sd.has(w))
1618	{
1619		setCutoff( (F32)sd[w].asReal() );
1620	} else goto fail;
1621	
1622	return true;
1623 fail:
1624	return false;
1625}
1626
1627//============================================================================
1628
1629LLFlexibleObjectData::LLFlexibleObjectData()
1630{
1631	mSimulateLOD				= FLEXIBLE_OBJECT_DEFAULT_NUM_SECTIONS;
1632	mGravity					= FLEXIBLE_OBJECT_DEFAULT_GRAVITY;
1633	mAirFriction				= FLEXIBLE_OBJECT_DEFAULT_AIR_FRICTION;
1634	mWindSensitivity			= FLEXIBLE_OBJECT_DEFAULT_WIND_SENSITIVITY;
1635	mTension					= FLEXIBLE_OBJECT_DEFAULT_TENSION;
1636	//mUsingCollisionSphere		= FLEXIBLE_OBJECT_DEFAULT_USING_COLLISION_SPHERE;
1637	//mRenderingCollisionSphere	= FLEXIBLE_OBJECT_DEFAULT_RENDERING_COLLISION_SPHERE;
1638	mUserForce					= LLVector3(0.f, 0.f, 0.f);
1639
1640	mType = PARAMS_FLEXIBLE;
1641}
1642
1643BOOL LLFlexibleObjectData::pack(LLDataPacker &dp) const
1644{
1645	// Custom, uber-svelte pack "softness" in upper bits of tension & drag
1646	U8 bit1 = (mSimulateLOD & 2) << 6;
1647	U8 bit2 = (mSimulateLOD & 1) << 7;
1648	dp.packU8((U8)(mTension*10.01f) + bit1, "tension");
1649	dp.packU8((U8)(mAirFriction*10.01f) + bit2, "drag");
1650	dp.packU8((U8)((mGravity+10.f)*10.01f), "gravity");
1651	dp.packU8((U8)(mWindSensitivity*10.01f), "wind");
1652	dp.packVector3(mUserForce, "userforce");
1653	return TRUE;
1654}
1655
1656BOOL LLFlexibleObjectData::unpack(LLDataPacker &dp)
1657{
1658	U8 tension, friction, gravity, wind;
1659	U8 bit1, bit2;
1660	dp.unpackU8(tension, "tension");	bit1 = (tension >> 6) & 2;
1661										mTension = ((F32)(tension&0x7f))/10.f;
1662	dp.unpackU8(friction, "drag");		bit2 = (friction >> 7) & 1;
1663										mAirFriction = ((F32)(friction&0x7f))/10.f;
1664										mSimulateLOD = bit1 | bit2;
1665	dp.unpackU8(gravity, "gravity");	mGravity = ((F32)gravity)/10.f - 10.f;
1666	dp.unpackU8(wind, "wind");			mWindSensitivity = ((F32)wind)/10.f;
1667	if (dp.hasNext())
1668	{
1669		dp.unpackVector3(mUserForce, "userforce");
1670	}
1671	else
1672	{
1673		mUserForce.setVec(0.f, 0.f, 0.f);
1674	}
1675	return TRUE;
1676}
1677
1678bool LLFlexibleObjectData::operator==(const LLNetworkData& data) const
1679{
1680	if (data.mType != PARAMS_FLEXIBLE)
1681	{
1682		return false;
1683	}
1684	LLFlexibleObjectData *flex_data = (LLFlexibleObjectData*)&data;
1685	return (mSimulateLOD == flex_data->mSimulateLOD &&
1686			mGravity == flex_data->mGravity &&
1687			mAirFriction == flex_data->mAirFriction &&
1688			mWindSensitivity == flex_data->mWindSensitivity &&
1689			mTension == flex_data->mTension &&
1690			mUserForce == flex_data->mUserForce);
1691			//mUsingCollisionSphere == flex_data->mUsingCollisionSphere &&
1692			//mRenderingCollisionSphere == flex_data->mRenderingCollisionSphere
1693}
1694
1695void LLFlexibleObjectData::copy(const LLNetworkData& data)
1696{
1697	const LLFlexibleObjectData *flex_data = (LLFlexibleObjectData*)&data;
1698	mSimulateLOD = flex_data->mSimulateLOD;
1699	mGravity = flex_data->mGravity;
1700	mAirFriction = flex_data->mAirFriction;
1701	mWindSensitivity = flex_data->mWindSensitivity;
1702	mTension = flex_data->mTension;
1703	mUserForce = flex_data->mUserForce;
1704	//mUsingCollisionSphere = flex_data->mUsingCollisionSphere;
1705	//mRenderingCollisionSphere = flex_data->mRenderingCollisionSphere;
1706}
1707
1708LLSD LLFlexibleObjectData::asLLSD() const
1709{
1710	LLSD sd;
1711
1712	sd["air_friction"] = getAirFriction();
1713	sd["gravity"] = getGravity();
1714	sd["simulate_lod"] = getSimulateLOD();
1715	sd["tension"] = getTension();
1716	sd["user_force"] = getUserForce().getValue();
1717	sd["wind_sensitivity"] = getWindSensitivity();
1718	
1719	return sd;
1720}
1721
1722bool LLFlexibleObjectData::fromLLSD(LLSD& sd)
1723{
1724	const char *w;
1725	w = "air_friction";
1726	if (sd.has(w))
1727	{
1728		setAirFriction( (F32)sd[w].asReal() );
1729	} else goto fail;
1730	w = "gravity";
1731	if (sd.has(w))
1732	{
1733		setGravity( (F32)sd[w].asReal() );
1734	} else goto fail;
1735	w = "simulate_lod";
1736	if (sd.has(w))
1737	{
1738		setSimulateLOD( sd[w].asInteger() );
1739	} else goto fail;
1740	w = "tension";
1741	if (sd.has(w))
1742	{
1743		setTension( (F32)sd[w].asReal() );
1744	} else goto fail;
1745	w = "user_force";
1746	if (sd.has(w))
1747	{
1748		LLVector3 user_force = ll_vector3_from_sd(sd[w], 0);
1749		setUserForce( user_force );
1750	} else goto fail;
1751	w = "wind_sensitivity";
1752	if (sd.has(w))
1753	{
1754		setWindSensitivity( (F32)sd[w].asReal() );
1755	} else goto fail;
1756	
1757	return true;
1758 fail:
1759	return false;
1760}
1761
1762//============================================================================
1763
1764LLSculptParams::LLSculptParams()
1765{
1766	mType = PARAMS_SCULPT;
1767	mSculptTexture.set(SCULPT_DEFAULT_TEXTURE);
1768	mSculptType = LL_SCULPT_TYPE_SPHERE;
1769}
1770
1771BOOL LLSculptParams::pack(LLDataPacker &dp) const
1772{
1773	dp.packUUID(mSculptTexture, "texture");
1774	dp.packU8(mSculptType, "type");
1775	
1776	return TRUE;
1777}
1778
1779BOOL LLSculptParams::unpack(LLDataPacker &dp)
1780{
1781	dp.unpackUUID(mSculptTexture, "texture");
1782	dp.unpackU8(mSculptType, "type");
1783	
1784	return TRUE;
1785}
1786
1787bool LLSculptParams::operator==(const LLNetworkData& data) const
1788{
1789	if (data.mType != PARAMS_SCULPT)
1790	{
1791		return false;
1792	}
1793	
1794	const LLSculptParams *param = (const LLSculptParams*)&data;
1795	if ( (param->mSculptTexture != mSculptTexture) ||
1796		 (param->mSculptType != mSculptType) )
1797		 
1798	{
1799		return false;
1800	}
1801	
1802	return true;
1803}
1804
1805void LLSculptParams::copy(const LLNetworkData& data)
1806{
1807	const LLSculptParams *param = (LLSculptParams*)&data;
1808	mSculptTexture = param->mSculptTexture;
1809	mSculptType = param->mSculptType;
1810}
1811
1812
1813
1814LLSD LLSculptParams::asLLSD() const
1815{
1816	LLSD sd;
1817	
1818	sd["texture"] = mSculptTexture;
1819	sd["type"] = mSculptType;
1820		
1821	return sd;
1822}
1823
1824bool LLSculptParams::fromLLSD(LLSD& sd)
1825{
1826	const char *w;
1827	w = "texture";
1828	if (sd.has(w))
1829	{
1830		setSculptTexture( sd[w] );
1831	} else goto fail;
1832	w = "type";
1833	if (sd.has(w))
1834	{
1835		setSculptType( (U8)sd[w].asInteger() );
1836	} else goto fail;
1837	
1838	return true;
1839 fail:
1840	return false;
1841}
1842
1843//============================================================================
1844
1845LLLightImageParams::LLLightImageParams()
1846{
1847	mType = PARAMS_LIGHT_IMAGE;
1848	mParams.setVec(F_PI*0.5f, 0.f, 0.f);
1849}
1850
1851BOOL LLLightImageParams::pack(LLDataPacker &dp) const
1852{
1853	dp.packUUID(mLightTexture, "texture");
1854	dp.packVector3(mParams, "params");
1855
1856	return TRUE;
1857}
1858
1859BOOL LLLightImageParams::unpack(LLDataPacker &dp)
1860{
1861	dp.unpackUUID(mLightTexture, "texture");
1862	dp.unpackVector3(mParams, "params");
1863	
1864	return TRUE;
1865}
1866
1867bool LLLightImageParams::operator==(const LLNetworkData& data) const
1868{
1869	if (data.mType != PARAMS_LIGHT_IMAGE)
1870	{
1871		return false;
1872	}
1873	
1874	const LLLightImageParams *param = (const LLLightImageParams*)&data;
1875	if ( (param->mLightTexture != mLightTexture) )
1876	{
1877		return false;
1878	}
1879
1880	if ( (param->mParams != mParams ) )
1881	{
1882		return false;
1883	}
1884	
1885	return true;
1886}
1887
1888void LLLightImageParams::copy(const LLNetworkData& data)
1889{
1890	const LLLightImageParams *param = (LLLightImageParams*)&data;
1891	mLightTexture = param->mLightTexture;
1892	mParams = param->mParams;
1893}
1894
1895
1896
1897LLSD LLLightImageParams::asLLSD() const
1898{
1899	LLSD sd;
1900	
1901	sd["texture"] = mLightTexture;
1902	sd["params"] = mParams.getValue();
1903		
1904	return sd;
1905}
1906
1907bool LLLightImageParams::fromLLSD(LLSD& sd)
1908{
1909	if (sd.has("texture"))
1910	{
1911		setLightTexture( sd["texture"] );
1912		setParams( LLVector3( sd["params"] ) );
1913		return true;
1914	} 
1915	
1916	return false;
1917}