summaryrefslogtreecommitdiff
path: root/indra/llprimitive/llprimitive.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/llprimitive/llprimitive.cpp
Print done when done.
Diffstat (limited to 'indra/llprimitive/llprimitive.cpp')
-rw-r--r--indra/llprimitive/llprimitive.cpp1749
1 files changed, 1749 insertions, 0 deletions
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
new file mode 100644
index 0000000000..fa8010eb6b
--- /dev/null
+++ b/indra/llprimitive/llprimitive.cpp
@@ -0,0 +1,1749 @@
+/**
+ * @file llprimitive.cpp
+ * @brief LLPrimitive base class
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "material_codes.h"
+#include "llerror.h"
+#include "message.h"
+#include "llprimitive.h"
+#include "llvolume.h"
+#include "legacy_object_types.h"
+#include "v4coloru.h"
+#include "llvolumemgr.h"
+#include "llstring.h"
+#include "lldatapacker.h"
+
+/**
+ * exported constants
+ */
+
+const F32 OBJECT_CUT_MIN = 0.f;
+const F32 OBJECT_CUT_MAX = 1.f;
+const F32 OBJECT_CUT_INC = 0.05f;
+const F32 OBJECT_MIN_CUT_INC = 0.02f;
+const F32 OBJECT_ROTATION_PRECISION = 0.05f;
+
+const F32 OBJECT_TWIST_MIN = -360.f;
+const F32 OBJECT_TWIST_MAX = 360.f;
+const F32 OBJECT_TWIST_INC = 18.f;
+
+// This is used for linear paths,
+// since twist is used in a slightly different manner.
+const F32 OBJECT_TWIST_LINEAR_MIN = -180.f;
+const F32 OBJECT_TWIST_LINEAR_MAX = 180.f;
+const F32 OBJECT_TWIST_LINEAR_INC = 9.f;
+
+const F32 OBJECT_MIN_HOLE_SIZE = 0.05f;
+const F32 OBJECT_MAX_HOLE_SIZE_X = 1.0f;
+const F32 OBJECT_MAX_HOLE_SIZE_Y = 0.5f;
+
+// Revolutions parameters.
+const F32 OBJECT_REV_MIN = 1.0f;
+const F32 OBJECT_REV_MAX = 4.0f;
+const F32 OBJECT_REV_INC = 0.1f;
+
+// lights
+const F32 LIGHT_MIN_RADIUS = 0.0f;
+const F32 LIGHT_DEFAULT_RADIUS = 5.0f;
+const F32 LIGHT_MAX_RADIUS = 20.0f;
+const F32 LIGHT_MIN_FALLOFF = 0.0f;
+const F32 LIGHT_DEFAULT_FALLOFF = 1.0f;
+const F32 LIGHT_MAX_FALLOFF = 2.0f;
+const F32 LIGHT_MIN_CUTOFF = 0.0f;
+const F32 LIGHT_DEFAULT_CUTOFF = 0.0f;
+const F32 LIGHT_MAX_CUTOFF = 180.f;
+
+// "Tension" => [0,10], increments of 0.1
+const F32 FLEXIBLE_OBJECT_MIN_TENSION = 0.0f;
+const F32 FLEXIBLE_OBJECT_DEFAULT_TENSION = 1.0f;
+const F32 FLEXIBLE_OBJECT_MAX_TENSION = 10.0f;
+
+// "Drag" => [0,10], increments of 0.1
+const F32 FLEXIBLE_OBJECT_MIN_AIR_FRICTION = 0.0f;
+const F32 FLEXIBLE_OBJECT_DEFAULT_AIR_FRICTION = 2.0f;
+const F32 FLEXIBLE_OBJECT_MAX_AIR_FRICTION = 10.0f;
+
+// "Gravity" = [-10,10], increments of 0.1
+const F32 FLEXIBLE_OBJECT_MIN_GRAVITY = -10.0f;
+const F32 FLEXIBLE_OBJECT_DEFAULT_GRAVITY = 0.3f;
+const F32 FLEXIBLE_OBJECT_MAX_GRAVITY = 10.0f;
+
+// "Wind" = [0,10], increments of 0.1
+const F32 FLEXIBLE_OBJECT_MIN_WIND_SENSITIVITY = 0.0f;
+const F32 FLEXIBLE_OBJECT_DEFAULT_WIND_SENSITIVITY = 0.0f;
+const F32 FLEXIBLE_OBJECT_MAX_WIND_SENSITIVITY = 10.0f;
+
+// I'll explain later...
+const F32 FLEXIBLE_OBJECT_MAX_INTERNAL_TENSION_FORCE = 0.99f;
+
+const F32 FLEXIBLE_OBJECT_DEFAULT_LENGTH = 1.0f;
+const BOOL FLEXIBLE_OBJECT_DEFAULT_USING_COLLISION_SPHERE = FALSE;
+const BOOL FLEXIBLE_OBJECT_DEFAULT_RENDERING_COLLISION_SPHERE = FALSE;
+
+
+//===============================================================
+LLPrimitive::LLPrimitive()
+{
+ mPrimitiveCode = 0;
+
+ mMaterial = LL_MCODE_STONE;
+ mVolumep = NULL;
+
+ mChanged = UNCHANGED;
+
+ mPosition.setVec(0.f,0.f,0.f);
+ mVelocity.setVec(0.f,0.f,0.f);
+ mAcceleration.setVec(0.f,0.f,0.f);
+
+ mRotation.loadIdentity();
+ mAngularVelocity.setVec(0.f,0.f,0.f);
+
+ mScale.setVec(1.f,1.f,1.f);
+
+ mNumTEs = 0;
+ mTextureList = NULL;
+}
+
+//===============================================================
+LLPrimitive::~LLPrimitive()
+{
+ if (mTextureList)
+ {
+ delete [] mTextureList;
+ mTextureList = NULL;
+ }
+
+ // Cleanup handled by volume manager
+ if (mVolumep)
+ {
+ gVolumeMgr->cleanupVolume(mVolumep);
+ }
+ mVolumep = NULL;
+}
+
+//===============================================================
+// static
+LLPrimitive *LLPrimitive::createPrimitive(LLPCode p_code)
+{
+ LLPrimitive *retval = new LLPrimitive();
+
+ if (retval)
+ {
+ retval->init(p_code);
+ }
+ else
+ {
+ llerrs << "primitive allocation failed" << llendl;
+ }
+
+ return retval;
+}
+
+//===============================================================
+void LLPrimitive::init(LLPCode p_code)
+{
+ if (mNumTEs)
+ {
+ if (mTextureList)
+ {
+ delete [] mTextureList;
+ }
+ mTextureList = new LLTextureEntry[mNumTEs];
+ }
+
+ mPrimitiveCode = p_code;
+}
+
+void LLPrimitive::setPCode(const U8 p_code)
+{
+ mPrimitiveCode = p_code;
+}
+
+//===============================================================
+const LLTextureEntry * LLPrimitive::getTE(const U8 te_num) const
+{
+ // if we're asking for a non-existent face, return null
+ if (mNumTEs && (te_num< mNumTEs))
+ {
+ return(&mTextureList[te_num]);
+ }
+ else
+ {
+ return(NULL);
+ }
+}
+
+//===============================================================
+void LLPrimitive::setNumTEs(const U8 num_tes)
+{
+ if (num_tes == mNumTEs)
+ {
+ return;
+ }
+
+ // Right now, we don't try and preserve entries when the number of faces
+ // changes.
+
+ if (num_tes)
+ {
+ LLTextureEntry *new_tes;
+ new_tes = new LLTextureEntry[num_tes];
+ U32 i;
+ for (i = 0; i < num_tes; i++)
+ {
+ if (i < mNumTEs)
+ {
+ new_tes[i] = mTextureList[i];
+ }
+ else if (mNumTEs)
+ {
+ new_tes[i] = mTextureList[mNumTEs - 1];
+ }
+ else
+ {
+ new_tes[i] = LLTextureEntry();
+ }
+ }
+ delete[] mTextureList;
+ mTextureList = new_tes;
+ }
+ else
+ {
+ delete[] mTextureList;
+ mTextureList = NULL;
+ }
+
+
+ mNumTEs = num_tes;
+}
+
+//===============================================================
+void LLPrimitive::setAllTETextures(const LLUUID &tex_id)
+{
+ U8 i;
+
+ for (i = 0; i < mNumTEs; i++)
+ {
+ mTextureList[i].setID(tex_id);
+ }
+}
+
+//===============================================================
+void LLPrimitive::setTE(const U8 index, const LLTextureEntry &te)
+{
+ mTextureList[index] = te;
+}
+
+S32 LLPrimitive::setTETexture(const U8 te, const LLUUID &tex_id)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "setting non-existent te " << te << llendl
+ return 0;
+ }
+
+ return mTextureList[te].setID(tex_id);
+}
+
+S32 LLPrimitive::setTEColor(const U8 te, const LLColor4 &color)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "setting non-existent te " << te << llendl
+ return 0;
+ }
+
+ return mTextureList[te].setColor(color);
+}
+
+S32 LLPrimitive::setTEColor(const U8 te, const LLColor3 &color)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "setting non-existent te " << te << llendl
+ return 0;
+ }
+
+ return mTextureList[te].setColor(color);
+}
+
+S32 LLPrimitive::setTEAlpha(const U8 te, const F32 alpha)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "setting non-existent te " << te << llendl
+ return 0;
+ }
+
+ return mTextureList[te].setAlpha(alpha);
+}
+
+//===============================================================
+S32 LLPrimitive::setTEScale(const U8 te, const F32 s, const F32 t)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "Setting nonexistent face" << llendl;
+ return 0;
+ }
+
+ return mTextureList[te].setScale(s,t);
+}
+
+
+// BUG: slow - done this way because texture entries have some
+// voodoo related to texture coords
+S32 LLPrimitive::setTEScaleS(const U8 te, const F32 s)
+{
+ if (te >= mNumTEs)
+ {
+ llwarns << "Setting nonexistent face" << llendl;
+ return 0;
+ }
+
+ F32 ignore, t;
+ mTextureList[te].getScale(&ignore, &t);
+ return mTextureList[te].setScale(s,t);
+}
+
+
+// BUG: slow - done this way because texture entries have some
+// voodoo related to texture coords
+S32 LLPrimitive::setTEScaleT(const U8 te, const F32 t)
+{
+ if (te >= mNumTEs)
+ {
+ llwarns << "Setting nonexistent face" << llendl;
+ return 0;
+ }
+
+ F32 s, ignore;
+ mTextureList[te].getScale(&s, &ignore);
+ return mTextureList[te].setScale(s,t);
+}
+
+
+//===============================================================
+S32 LLPrimitive::setTEOffset(const U8 te, const F32 s, const F32 t)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "Setting nonexistent face" << llendl;
+ return 0;
+ }
+
+ return mTextureList[te].setOffset(s,t);
+}
+
+
+// BUG: slow - done this way because texture entries have some
+// voodoo related to texture coords
+S32 LLPrimitive::setTEOffsetS(const U8 te, const F32 s)
+{
+ if (te >= mNumTEs)
+ {
+ llwarns << "Setting nonexistent face" << llendl;
+ return 0;
+ }
+
+ F32 ignore, t;
+ mTextureList[te].getOffset(&ignore, &t);
+ return mTextureList[te].setOffset(s,t);
+}
+
+
+// BUG: slow - done this way because texture entries have some
+// voodoo related to texture coords
+S32 LLPrimitive::setTEOffsetT(const U8 te, const F32 t)
+{
+ if (te >= mNumTEs)
+ {
+ llwarns << "Setting nonexistent face" << llendl;
+ return 0;
+ }
+
+ F32 s, ignore;
+ mTextureList[te].getOffset(&s, &ignore);
+ return mTextureList[te].setOffset(s,t);
+}
+
+
+//===============================================================
+S32 LLPrimitive::setTERotation(const U8 te, const F32 r)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "Setting nonexistent face" << llendl;
+ return 0;
+ }
+
+ return mTextureList[te].setRotation(r);
+}
+
+
+//===============================================================
+S32 LLPrimitive::setTEBumpShinyFullbright(const U8 te, const U8 bump)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "setting non-existent te " << te << llendl
+ return 0;
+ }
+
+ return mTextureList[te].setBumpShinyFullbright( bump );
+}
+
+S32 LLPrimitive::setTEMediaTexGen(const U8 te, const U8 media)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "setting non-existent te " << te << llendl
+ return 0;
+ }
+
+ return mTextureList[te].setMediaTexGen( media );
+}
+
+S32 LLPrimitive::setTEBumpmap(const U8 te, const U8 bump)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "setting non-existent te " << te << llendl
+ return 0;
+ }
+
+ return mTextureList[te].setBumpmap( bump );
+}
+
+S32 LLPrimitive::setTEBumpShiny(const U8 te, const U8 bump_shiny)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "setting non-existent te " << te << llendl
+ return 0;
+ }
+
+ return mTextureList[te].setBumpShiny( bump_shiny );
+}
+
+S32 LLPrimitive::setTETexGen(const U8 te, const U8 texgen)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "setting non-existent te " << te << llendl
+ return 0;
+ }
+
+ return mTextureList[te].setTexGen( texgen );
+}
+
+S32 LLPrimitive::setTEShiny(const U8 te, const U8 shiny)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "setting non-existent te " << te << llendl
+ return 0;
+ }
+
+ return mTextureList[te].setShiny( shiny );
+}
+
+S32 LLPrimitive::setTEFullbright(const U8 te, const U8 fullbright)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "setting non-existent te " << te << llendl
+ return 0;
+ }
+
+ return mTextureList[te].setFullbright( fullbright );
+}
+
+S32 LLPrimitive::setTEMediaFlags(const U8 te, const U8 media_flags)
+{
+ // if we're asking for a non-existent face, return null
+ if (te >= mNumTEs)
+ {
+ llwarns << "setting non-existent te " << te << llendl
+ return 0;
+ }
+
+ return mTextureList[te].setMediaFlags( media_flags );
+}
+
+
+LLPCode LLPrimitive::legacyToPCode(const U8 legacy)
+{
+ LLPCode pcode = 0;
+
+ switch (legacy)
+ {
+ /*
+ case BOX:
+ pcode = LL_PCODE_CUBE;
+ break;
+ case CYLINDER:
+ pcode = LL_PCODE_CYLINDER;
+ break;
+ case CONE:
+ pcode = LL_PCODE_CONE;
+ break;
+ case HALF_CONE:
+ pcode = LL_PCODE_CONE_HEMI;
+ break;
+ case HALF_CYLINDER:
+ pcode = LL_PCODE_CYLINDER_HEMI;
+ break;
+ case HALF_SPHERE:
+ pcode = LL_PCODE_SPHERE_HEMI;
+ break;
+ case PRISM:
+ pcode = LL_PCODE_PRISM;
+ break;
+ case PYRAMID:
+ pcode = LL_PCODE_PYRAMID;
+ break;
+ case SPHERE:
+ pcode = LL_PCODE_SPHERE;
+ break;
+ case TETRAHEDRON:
+ pcode = LL_PCODE_TETRAHEDRON;
+ break;
+ case DEMON:
+ pcode = LL_PCODE_LEGACY_DEMON;
+ break;
+ case LSL_TEST:
+ pcode = LL_PCODE_LEGACY_LSL_TEST;
+ break;
+ case ORACLE:
+ pcode = LL_PCODE_LEGACY_ORACLE;
+ break;
+ case TEXTBUBBLE:
+ pcode = LL_PCODE_LEGACY_TEXT_BUBBLE;
+ break;
+ case ATOR:
+ pcode = LL_PCODE_LEGACY_ATOR;
+ break;
+ case BASIC_SHOT:
+ pcode = LL_PCODE_LEGACY_SHOT;
+ break;
+ case BIG_SHOT:
+ pcode = LL_PCODE_LEGACY_SHOT_BIG;
+ break;
+ case BIRD:
+ pcode = LL_PCODE_LEGACY_BIRD;
+ break;
+ case ROCK:
+ pcode = LL_PCODE_LEGACY_ROCK;
+ break;
+ case SMOKE:
+ pcode = LL_PCODE_LEGACY_SMOKE;
+ break;
+ case SPARK:
+ pcode = LL_PCODE_LEGACY_SPARK;
+ break;
+ */
+ case PRIMITIVE_VOLUME:
+ pcode = LL_PCODE_VOLUME;
+ break;
+ case GRASS:
+ pcode = LL_PCODE_LEGACY_GRASS;
+ break;
+ case PART_SYS:
+ pcode = LL_PCODE_LEGACY_PART_SYS;
+ break;
+ case PLAYER:
+ pcode = LL_PCODE_LEGACY_AVATAR;
+ break;
+ case TREE:
+ pcode = LL_PCODE_LEGACY_TREE;
+ break;
+ case TREE_NEW:
+ pcode = LL_PCODE_TREE_NEW;
+ break;
+ default:
+ llwarns << "Unknown legacy code " << legacy << "!" << llendl;
+ }
+
+ return pcode;
+}
+
+U8 LLPrimitive::pCodeToLegacy(const LLPCode pcode)
+{
+ U8 legacy;
+ switch (pcode)
+ {
+/*
+ case LL_PCODE_CUBE:
+ legacy = BOX;
+ break;
+ case LL_PCODE_CYLINDER:
+ legacy = CYLINDER;
+ break;
+ case LL_PCODE_CONE:
+ legacy = CONE;
+ break;
+ case LL_PCODE_CONE_HEMI:
+ legacy = HALF_CONE;
+ break;
+ case LL_PCODE_CYLINDER_HEMI:
+ legacy = HALF_CYLINDER;
+ break;
+ case LL_PCODE_SPHERE_HEMI:
+ legacy = HALF_SPHERE;
+ break;
+ case LL_PCODE_PRISM:
+ legacy = PRISM;
+ break;
+ case LL_PCODE_PYRAMID:
+ legacy = PYRAMID;
+ break;
+ case LL_PCODE_SPHERE:
+ legacy = SPHERE;
+ break;
+ case LL_PCODE_TETRAHEDRON:
+ legacy = TETRAHEDRON;
+ break;
+ case LL_PCODE_LEGACY_ATOR:
+ legacy = ATOR;
+ break;
+ case LL_PCODE_LEGACY_SHOT:
+ legacy = BASIC_SHOT;
+ break;
+ case LL_PCODE_LEGACY_SHOT_BIG:
+ legacy = BIG_SHOT;
+ break;
+ case LL_PCODE_LEGACY_BIRD:
+ legacy = BIRD;
+ break;
+ case LL_PCODE_LEGACY_DEMON:
+ legacy = DEMON;
+ break;
+ case LL_PCODE_LEGACY_LSL_TEST:
+ legacy = LSL_TEST;
+ break;
+ case LL_PCODE_LEGACY_ORACLE:
+ legacy = ORACLE;
+ break;
+ case LL_PCODE_LEGACY_ROCK:
+ legacy = ROCK;
+ break;
+ case LL_PCODE_LEGACY_TEXT_BUBBLE:
+ legacy = TEXTBUBBLE;
+ break;
+ case LL_PCODE_LEGACY_SMOKE:
+ legacy = SMOKE;
+ break;
+ case LL_PCODE_LEGACY_SPARK:
+ legacy = SPARK;
+ break;
+*/
+ case LL_PCODE_VOLUME:
+ legacy = PRIMITIVE_VOLUME;
+ break;
+ case LL_PCODE_LEGACY_GRASS:
+ legacy = GRASS;
+ break;
+ case LL_PCODE_LEGACY_PART_SYS:
+ legacy = PART_SYS;
+ break;
+ case LL_PCODE_LEGACY_AVATAR:
+ legacy = PLAYER;
+ break;
+ case LL_PCODE_LEGACY_TREE:
+ legacy = TREE;
+ break;
+ case LL_PCODE_TREE_NEW:
+ legacy = TREE_NEW;
+ break;
+ default:
+ llwarns << "Unknown pcode " << (S32)pcode << ":" << pcode << "!" << llendl;
+ return 0;
+ }
+ return legacy;
+}
+
+
+// static
+// Don't crash or llerrs here! This function is used for debug strings.
+const char * LLPrimitive::pCodeToString(const LLPCode pcode)
+{
+ static char pcode_string[255];
+
+ U8 base_code = pcode & LL_PCODE_BASE_MASK;
+ pcode_string[0] = 0;
+ if (!pcode)
+ {
+ sprintf(pcode_string, "null");
+ }
+ else if ((base_code) == LL_PCODE_LEGACY)
+ {
+ // It's a legacy object
+ switch (pcode)
+ {
+ case LL_PCODE_LEGACY_GRASS:
+ sprintf(pcode_string, "grass");
+ break;
+ case LL_PCODE_LEGACY_PART_SYS:
+ sprintf(pcode_string, "particle system");
+ break;
+ case LL_PCODE_LEGACY_AVATAR:
+ sprintf(pcode_string, "avatar");
+ break;
+ case LL_PCODE_LEGACY_TEXT_BUBBLE:
+ sprintf(pcode_string, "text bubble");
+ break;
+ case LL_PCODE_LEGACY_TREE:
+ sprintf(pcode_string, "tree");
+ break;
+ case LL_PCODE_TREE_NEW:
+ sprintf(pcode_string, "tree_new");
+ break;
+ default:
+ sprintf(pcode_string, "unknown legacy pcode %i",(U32)pcode);
+ }
+ }
+ else
+ {
+ char shape[32];
+ char mask[32];
+ if (base_code == LL_PCODE_CUBE)
+ {
+ sprintf(shape, "cube");
+ }
+ else if (base_code == LL_PCODE_CYLINDER)
+ {
+ sprintf(shape, "cylinder");
+ }
+ else if (base_code == LL_PCODE_CONE)
+ {
+ sprintf(shape, "cone");
+ }
+ else if (base_code == LL_PCODE_PRISM)
+ {
+ sprintf(shape, "prism");
+ }
+ else if (base_code == LL_PCODE_PYRAMID)
+ {
+ sprintf(shape, "pyramid");
+ }
+ else if (base_code == LL_PCODE_SPHERE)
+ {
+ sprintf(shape, "sphere");
+ }
+ else if (base_code == LL_PCODE_TETRAHEDRON)
+ {
+ sprintf(shape, "tetrahedron");
+ }
+ else if (base_code == LL_PCODE_VOLUME)
+ {
+ sprintf(shape, "volume");
+ }
+ else if (base_code == LL_PCODE_APP)
+ {
+ sprintf(shape, "app");
+ }
+ else
+ {
+ llwarns << "Unknown base mask for pcode: " << base_code << llendl;
+ }
+
+ U8 mask_code = pcode & (~LL_PCODE_BASE_MASK);
+ if (base_code == LL_PCODE_APP)
+ {
+ sprintf(mask, "%x", mask_code);
+ }
+ else if (mask_code & LL_PCODE_HEMI_MASK)
+ {
+ sprintf(mask, "hemi");
+ }
+ else if (mask != 0)
+ {
+ sprintf(mask, "%x", mask_code);
+ }
+ else
+ {
+ mask[0] = 0;
+ }
+
+ if (mask[0])
+ {
+ sprintf(pcode_string, "%s-%s", shape, mask);
+ }
+ else
+ {
+ sprintf(pcode_string, "%s", shape);
+ }
+ }
+ return pcode_string;
+}
+
+
+void LLPrimitive::copyTEs(const LLPrimitive *primitivep)
+{
+ U32 i;
+ if (primitivep->getNumTEs() != getNumTEs())
+ {
+ llwarns << "Primitives don't have same number of TE's" << llendl;
+ }
+ U32 num_tes = llmin(primitivep->getNumTEs(), getNumTEs());
+ for (i = 0; i < num_tes; i++)
+ {
+ const LLTextureEntry *tep = primitivep->getTE(i);
+ F32 s, t;
+ setTETexture(i, tep->getID());
+ setTEColor(i, tep->getColor());
+ tep->getScale(&s, &t);
+ setTEScale(i, s, t);
+ tep->getOffset(&s, &t);
+ setTEOffset(i, s, t);
+ setTERotation(i, tep->getRotation());
+ setTEBumpShinyFullbright(i, tep->getBumpShinyFullbright());
+ setTEMediaTexGen(i, tep->getMediaTexGen());
+ }
+}
+
+S32 face_index_from_id(LLFaceID face_ID, const std::vector<LLProfile::Face>& faceArray)
+{
+ S32 i;
+ for (i = 0; i < (S32)faceArray.size(); i++)
+ {
+ if (faceArray[i].mFaceID == face_ID)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume)
+{
+ LLVolume *volumep;
+ if (unique_volume)
+ {
+ F32 volume_detail = LLVolumeLODGroup::getVolumeScaleFromDetail(detail);
+ if (mVolumep.notNull() && volume_params == mVolumep->getParams() && (volume_detail == mVolumep->getDetail()))
+ {
+ return FALSE;
+ }
+ volumep = new LLVolume(volume_params, volume_detail, FALSE, TRUE);
+ }
+ else
+ {
+ if (mVolumep.notNull())
+ {
+ F32 volume_detail = LLVolumeLODGroup::getVolumeScaleFromDetail(detail);
+ if (volume_params == mVolumep->getParams() && (volume_detail == mVolumep->getDetail()))
+ {
+ return FALSE;
+ }
+ }
+
+ volumep = gVolumeMgr->getVolume(volume_params, detail);
+ if (volumep == mVolumep)
+ {
+ gVolumeMgr->cleanupVolume( volumep ); // gVolumeMgr->getVolume() creates a reference, but we don't need a second one.
+ return TRUE;
+ }
+ }
+
+ setChanged(GEOMETRY);
+
+
+ if (!mVolumep)
+ {
+ mVolumep = volumep;
+ //mFaceMask = mVolumep->generateFaceMask();
+ setNumTEs(mVolumep->getNumFaces());
+ return TRUE;
+ }
+
+ U32 old_face_mask = mVolumep->mFaceMask;
+
+ S32 face_bit = 0;
+ S32 cur_mask = 0;
+
+ // grab copies of the old faces so we can determine the TE mappings...
+ std::vector<LLProfile::Face> old_faces; // list of old faces for remapping texture entries
+ LLTextureEntry old_tes[9];
+
+ for (S32 face = 0; face < mVolumep->getNumFaces(); face++)
+ {
+ old_faces.push_back(mVolumep->getProfile().mFaces[face]);
+ }
+
+ for (face_bit = 0; face_bit < 9; face_bit++)
+ {
+ cur_mask = 0x1 << face_bit;
+ if (old_face_mask & cur_mask)
+ {
+ S32 te_index = face_index_from_id(cur_mask, old_faces);
+ old_tes[face_bit] = *getTE(te_index);
+ //llinfos << face_bit << ":" << te_index << ":" << old_tes[face_bit].getID() << llendl;
+ }
+ }
+
+
+ // build the new object
+ gVolumeMgr->cleanupVolume(mVolumep);
+ mVolumep = volumep;
+
+ U32 new_face_mask = mVolumep->mFaceMask;
+ S32 i;
+
+ /*
+ LLString old_mask_string;
+ for (i = 0; i < 9; i++)
+ {
+ if (old_face_mask & (1 << i))
+ {
+ old_mask_string.append("1");
+ }
+ else
+ {
+ old_mask_string.append("0");
+ }
+ }
+ LLString new_mask_string;
+ for (i = 0; i < 9; i++)
+ {
+ if (new_face_mask & (1 << i))
+ {
+ new_mask_string.append("1");
+ }
+ else
+ {
+ new_mask_string.append("0");
+ }
+ }
+
+ llinfos << "old mask: " << old_mask_string << llendl;
+ llinfos << "new mask: " << new_mask_string << llendl;
+ */
+
+
+ if (old_face_mask == new_face_mask)
+ {
+ // nothing to do
+ return TRUE;
+ }
+
+ if (mVolumep->getNumFaces() == 0 && new_face_mask != 0)
+ {
+ llwarns << "Object with 0 faces found...INCORRECT!" << llendl;
+ setNumTEs(mVolumep->getNumFaces());
+ return TRUE;
+ }
+
+
+ S32 face_mapping[9];
+ for (face_bit = 0; face_bit < 9; face_bit++)
+ {
+ face_mapping[face_bit] = face_bit;
+ }
+
+ // Generate the face-type mappings
+ for (face_bit = 0; face_bit < 9; face_bit++)
+ {
+ cur_mask = 0x1 << face_bit;
+ if (!(new_face_mask & cur_mask))
+ {
+ // Face doesn't exist in new map.
+ face_mapping[face_bit] = -1;
+ continue;
+ }
+ else if (old_face_mask & cur_mask)
+ {
+ // Face exists in new and old map.
+ face_mapping[face_bit] = face_bit;
+ continue;
+ }
+
+ // OK, how we've got a mismatch, where we have to fill a new face with one from
+ // the old face.
+ if (cur_mask & (LL_FACE_PATH_BEGIN | LL_FACE_PATH_END | LL_FACE_INNER_SIDE))
+ {
+ // It's a top/bottom/hollow interior face.
+ if (old_face_mask & LL_FACE_PATH_END)
+ {
+ face_mapping[face_bit] = 1;
+ continue;
+ }
+ else
+ {
+ S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0;
+ for (i = 0; i < 4; i++)
+ {
+ if (old_face_mask & cur_outer_mask)
+ {
+ face_mapping[face_bit] = 5 + i;
+ break;
+ }
+ cur_outer_mask <<= 1;
+ }
+ if (i == 4)
+ {
+ llwarns << "No path end or outer face in volume!" << llendl;
+ }
+ continue;
+ }
+ }
+
+ if (cur_mask & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END))
+ {
+ // A cut slice. Use the hollow interior if we have it.
+ if (old_face_mask & LL_FACE_INNER_SIDE)
+ {
+ face_mapping[face_bit] = 2;
+ continue;
+ }
+
+ // No interior, use the bottom face.
+ // Could figure out which of the outer faces was nearest, but that would be harder.
+ if (old_face_mask & LL_FACE_PATH_END)
+ {
+ face_mapping[face_bit] = 1;
+ continue;
+ }
+ else
+ {
+ S32 cur_outer_mask = LL_FACE_OUTER_SIDE_0;
+ for (i = 0; i < 4; i++)
+ {
+ if (old_face_mask & cur_outer_mask)
+ {
+ face_mapping[face_bit] = 5 + i;
+ break;
+ }
+ cur_outer_mask <<= 1;
+ }
+ if (i == 4)
+ {
+ llwarns << "No path end or outer face in volume!" << llendl;
+ }
+ continue;
+ }
+ }
+
+ // OK, the face that's missing is an outer face...
+ // Pull from the nearest adjacent outer face (there's always guaranteed to be one...
+ S32 cur_outer = face_bit - 5;
+ S32 min_dist = 5;
+ S32 min_outer_bit = -1;
+ S32 i;
+ for (i = 0; i < 4; i++)
+ {
+ if (old_face_mask & (LL_FACE_OUTER_SIDE_0 << i))
+ {
+ S32 dist = abs(i - cur_outer);
+ if (dist < min_dist)
+ {
+ min_dist = dist;
+ min_outer_bit = i + 5;
+ }
+ }
+ }
+ if (-1 == min_outer_bit)
+ {
+ llinfos << (LLVolume *)mVolumep << llendl;
+ llwarns << "Bad! No outer faces, impossible!" << llendl;
+ }
+ face_mapping[face_bit] = min_outer_bit;
+ }
+
+
+ setNumTEs(mVolumep->getNumFaces());
+ for (face_bit = 0; face_bit < 9; face_bit++)
+ {
+ cur_mask = 0x1 << face_bit;
+ if (new_face_mask & cur_mask)
+ {
+ if (-1 == face_mapping[face_bit])
+ {
+ llwarns << "No mapping from old face to new face!" << llendl;
+ }
+
+ S32 te_num = face_index_from_id(cur_mask, mVolumep->getProfile().mFaces);
+ setTE(te_num, old_tes[face_mapping[face_bit]]);
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLPrimitive::setMaterial(U8 material)
+{
+ if (material != mMaterial)
+ {
+ mMaterial = material;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+void LLPrimitive::setTEArrays(const U8 size,
+ const LLUUID* image_ids,
+ const F32* scale_s,
+ const F32* scale_t)
+{
+ S32 cur_size = size;
+ if (cur_size > getNumTEs())
+ {
+ llwarns << "Trying to set more TEs than exist!" << llendl;
+ cur_size = getNumTEs();
+ }
+
+ S32 i;
+ // Copy over image information
+ for (i = 0; i < cur_size; i++)
+ {
+ // This is very BAD!!!!!!
+ if (image_ids != NULL)
+ {
+ setTETexture(i,image_ids[i]);
+ }
+ if (scale_s && scale_t)
+ {
+ setTEScale(i, scale_s[i], scale_t[i]);
+ }
+ }
+
+ if (i < getNumTEs())
+ {
+ cur_size--;
+ for (i=i; i < getNumTEs(); i++) // the i=i removes a gcc warning
+ {
+ if (image_ids != NULL)
+ {
+ setTETexture(i, image_ids[cur_size]);
+ }
+ if (scale_s && scale_t)
+ {
+ setTEScale(i, scale_s[cur_size], scale_t[cur_size]);
+ }
+ }
+ }
+}
+
+const F32 LL_MAX_SCALE_S = 100.0f;
+const F32 LL_MAX_SCALE_T = 100.0f;
+S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const
+{
+ S32 face_index;
+ S32 i;
+ U64 exception_faces;
+ U8 *start_loc = cur_ptr;
+
+ htonmemcpy(cur_ptr,data_ptr + (last_face_index * data_size), type, data_size);
+ cur_ptr += data_size;
+
+ for (face_index = last_face_index-1; face_index >= 0; face_index--)
+ {
+ BOOL already_sent = FALSE;
+ for (i = face_index+1; i <= last_face_index; i++)
+ {
+ if (!memcmp(data_ptr+(data_size *face_index), data_ptr+(data_size *i), data_size))
+ {
+ already_sent = TRUE;
+ break;
+ }
+ }
+
+ if (!already_sent)
+ {
+ exception_faces = 0;
+ for (i = face_index; i >= 0; i--)
+ {
+ if (!memcmp(data_ptr+(data_size *face_index), data_ptr+(data_size *i), data_size))
+ {
+ exception_faces |= (1 << i);
+ }
+ }
+
+ //assign exception faces to cur_ptr
+ if (exception_faces >= (0x1 << 7))
+ {
+ if (exception_faces >= (0x1 << 14))
+ {
+ if (exception_faces >= (0x1 << 21))
+ {
+ if (exception_faces >= (0x1 << 28))
+ {
+ *cur_ptr++ = (U8)(((exception_faces >> 28) & 0x7F) | 0x80);
+ }
+ *cur_ptr++ = (U8)(((exception_faces >> 21) & 0x7F) | 0x80);
+ }
+ *cur_ptr++ = (U8)(((exception_faces >> 14) & 0x7F) | 0x80);
+ }
+ *cur_ptr++ = (U8)(((exception_faces >> 7) & 0x7F) | 0x80);
+ }
+
+ *cur_ptr++ = (U8)(exception_faces & 0x7F);
+
+ htonmemcpy(cur_ptr,data_ptr + (face_index * data_size), type, data_size);
+ cur_ptr += data_size;
+ }
+ }
+ return (S32)(cur_ptr - start_loc);
+}
+
+S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type)
+{
+ U8 *start_loc = cur_ptr;
+ U64 i;
+ htonmemcpy(data_ptr,cur_ptr, type,data_size);
+ cur_ptr += data_size;
+
+ for (i = 1; i < face_count; i++)
+ {
+ // Already unswizzled, don't need to unswizzle it again!
+ memcpy(data_ptr+(i*data_size),data_ptr,data_size);
+ }
+
+ while ((cur_ptr < buffer_end) && (*cur_ptr != 0))
+ {
+// llinfos << "TE exception" << llendl;
+ i = 0;
+ while (*cur_ptr & 0x80)
+ {
+ i |= ((*cur_ptr++) & 0x7F);
+ i = i << 7;
+ }
+
+ i |= *cur_ptr++;
+
+ for (S32 j = 0; j < face_count; j++)
+ {
+ if (i & 0x01)
+ {
+ htonmemcpy(data_ptr+(j*data_size),cur_ptr,type,data_size);
+// char foo[64];
+// sprintf(foo,"%x %x",*(data_ptr+(j*data_size)), *(data_ptr+(j*data_size)+1));
+// llinfos << "Assigning " << foo << " to face " << j << llendl;
+ }
+ i = i >> 1;
+ }
+ cur_ptr += data_size;
+ }
+ return (S32)(cur_ptr - start_loc);
+}
+
+
+// Pack information about all texture entries into container:
+// { TextureEntry Variable 2 }
+// Includes information about image ID, color, scale S,T, offset S,T and rotation
+BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const
+{
+ const U32 MAX_TES = 32;
+
+ U8 image_ids[MAX_TES*16];
+ U8 colors[MAX_TES*4];
+ S16 scale_s[MAX_TES];
+ S16 scale_t[MAX_TES];
+ S16 offset_s[MAX_TES];
+ S16 offset_t[MAX_TES];
+ S16 image_rot[MAX_TES];
+ U8 bump[MAX_TES];
+ U8 media_flags[MAX_TES];
+
+ const U32 MAX_TE_BUFFER = 4096;
+ U8 packed_buffer[MAX_TE_BUFFER];
+ U8 *cur_ptr = packed_buffer;
+
+ S32 last_face_index = getNumTEs() - 1;
+
+ if (last_face_index > -1)
+ {
+ // ...if we hit the front, send one image id
+ S8 face_index;
+ LLColor4U coloru;
+ for (face_index = 0; face_index <= last_face_index; face_index++)
+ {
+ // Directly sending image_ids is not safe!
+ memcpy(&image_ids[face_index*16],getTE(face_index)->getID().mData,16);
+
+ // Cast LLColor4 to LLColor4U
+ coloru.setVec( getTE(face_index)->getColor() );
+
+ // Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
+ // as all zeros. However, the subtraction and addition must be done in unsigned
+ // byte space, not in float space, otherwise off-by-one errors occur. JC
+ colors[4*face_index] = 255 - coloru.mV[0];
+ colors[4*face_index + 1] = 255 - coloru.mV[1];
+ colors[4*face_index + 2] = 255 - coloru.mV[2];
+ colors[4*face_index + 3] = 255 - coloru.mV[3];
+
+ const LLTextureEntry* te = getTE(face_index);
+ scale_s[face_index] = (S16) llround(((llclamp(te->mScaleS,-LL_MAX_SCALE_S, LL_MAX_SCALE_S)-1.0f)/(LL_MAX_SCALE_S+1.f) * (F32)0x7FFF));
+ scale_t[face_index] = (S16) llround(((llclamp(te->mScaleT,-LL_MAX_SCALE_T, LL_MAX_SCALE_T)-1.0f)/(LL_MAX_SCALE_T+1.f) * (F32)0x7FFF));
+ offset_s[face_index] = (S16) llround((llclamp(te->mOffsetS,-1.0f,1.0f) * (F32)0x7FFF)) ;
+ offset_t[face_index] = (S16) llround((llclamp(te->mOffsetT,-1.0f,1.0f) * (F32)0x7FFF)) ;
+ image_rot[face_index] = (S16) llround(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * (F32)0x7FFF));
+ bump[face_index] = te->getBumpShinyFullbright();
+ media_flags[face_index] = te->getMediaTexGen();
+// llinfos << "BUMP pack [" << (S32)face_index << "]=" << (S32) bump[face_index] << llendl;
+ }
+
+ cur_ptr += packTEField(cur_ptr, (U8 *)image_ids, sizeof(LLUUID),last_face_index, MVT_LLUUID);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)colors, 4 ,last_face_index, MVT_U8);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)scale_s, 2 ,last_face_index, MVT_S16Array);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)scale_t, 2 ,last_face_index, MVT_S16Array);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)offset_s, 2 ,last_face_index, MVT_S16Array);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)offset_t, 2 ,last_face_index, MVT_S16Array);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)image_rot, 2 ,last_face_index, MVT_S16Array);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)bump, 1 ,last_face_index, MVT_U8);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)media_flags, 1 ,last_face_index, MVT_U8);
+ }
+ mesgsys->addBinaryDataFast(_PREHASH_TextureEntry, packed_buffer, (S32)(cur_ptr - packed_buffer));
+
+ return FALSE;
+}
+
+
+BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const
+{
+ const U32 MAX_TES = 32;
+
+ U8 image_ids[MAX_TES*16];
+ U8 colors[MAX_TES*4];
+ S16 scale_s[MAX_TES];
+ S16 scale_t[MAX_TES];
+ S16 offset_s[MAX_TES];
+ S16 offset_t[MAX_TES];
+ S16 image_rot[MAX_TES];
+ U8 bump[MAX_TES];
+ U8 media_flags[MAX_TES];
+
+ const U32 MAX_TE_BUFFER = 4096;
+ U8 packed_buffer[MAX_TE_BUFFER];
+ U8 *cur_ptr = packed_buffer;
+
+ S32 last_face_index = getNumTEs() - 1;
+
+ if (last_face_index > -1)
+ {
+ // ...if we hit the front, send one image id
+ S8 face_index;
+ LLColor4U coloru;
+ for (face_index = 0; face_index <= last_face_index; face_index++)
+ {
+ // Directly sending image_ids is not safe!
+ memcpy(&image_ids[face_index*16],getTE(face_index)->getID().mData,16);
+
+ // Cast LLColor4 to LLColor4U
+ coloru.setVec( getTE(face_index)->getColor() );
+
+ // Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
+ // as all zeros. However, the subtraction and addition must be done in unsigned
+ // byte space, not in float space, otherwise off-by-one errors occur. JC
+ colors[4*face_index] = 255 - coloru.mV[0];
+ colors[4*face_index + 1] = 255 - coloru.mV[1];
+ colors[4*face_index + 2] = 255 - coloru.mV[2];
+ colors[4*face_index + 3] = 255 - coloru.mV[3];
+
+ const LLTextureEntry* te = getTE(face_index);
+ scale_s[face_index] = (S16) llround(((llclamp(te->mScaleS,-LL_MAX_SCALE_S, LL_MAX_SCALE_S)-1.0f)/(LL_MAX_SCALE_S+1.f) * (F32)0x7FFF));
+ scale_t[face_index] = (S16) llround(((llclamp(te->mScaleT,-LL_MAX_SCALE_T, LL_MAX_SCALE_T)-1.0f)/(LL_MAX_SCALE_T+1.f) * (F32)0x7FFF));
+ offset_s[face_index] = (S16) llround((llclamp(te->mOffsetS,-1.0f,1.0f) * (F32)0x7FFF)) ;
+ offset_t[face_index] = (S16) llround((llclamp(te->mOffsetT,-1.0f,1.0f) * (F32)0x7FFF)) ;
+ image_rot[face_index] = (S16) llround(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * (F32)0x7FFF));
+ bump[face_index] = te->getBumpShinyFullbright();
+ media_flags[face_index] = te->getMediaTexGen();
+
+// llinfos << "BUMP pack (Datapacker) [" << (S32)face_index << "]=" << (S32) bump[face_index] << llendl;
+ }
+
+ cur_ptr += packTEField(cur_ptr, (U8 *)image_ids, sizeof(LLUUID),last_face_index, MVT_LLUUID);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)colors, 4 ,last_face_index, MVT_U8);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)scale_s, 2 ,last_face_index, MVT_S16Array);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)scale_t, 2 ,last_face_index, MVT_S16Array);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)offset_s, 2 ,last_face_index, MVT_S16Array);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)offset_t, 2 ,last_face_index, MVT_S16Array);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)image_rot, 2 ,last_face_index, MVT_S16Array);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)bump, 1 ,last_face_index, MVT_U8);
+ *cur_ptr++ = 0;
+ cur_ptr += packTEField(cur_ptr, (U8 *)media_flags, 1 ,last_face_index, MVT_U8);
+ }
+
+ dp.packBinaryData(packed_buffer, (S32)(cur_ptr - packed_buffer), "TextureEntry");
+ return FALSE;
+}
+
+S32 LLPrimitive::unpackTEMessage(LLMessageSystem *mesgsys, char *block_name)
+{
+ return(unpackTEMessage(mesgsys,block_name,-1));
+}
+
+S32 LLPrimitive::unpackTEMessage(LLMessageSystem *mesgsys, char *block_name, const S32 block_num)
+{
+ // use a negative block_num to indicate a single-block read (a non-variable block)
+ S32 retval = 0;
+ const U32 MAX_TES = 32;
+
+ // Avoid construction of 32 UUIDs per call. JC
+
+ U8 image_data[MAX_TES*16];
+ U8 colors[MAX_TES*4];
+ S16 scale_s[MAX_TES];
+ S16 scale_t[MAX_TES];
+ S16 offset_s[MAX_TES];
+ S16 offset_t[MAX_TES];
+ S16 image_rot[MAX_TES];
+ U8 bump[MAX_TES];
+ U8 media_flags[MAX_TES];
+
+ const U32 MAX_TE_BUFFER = 4096;
+ U8 packed_buffer[MAX_TE_BUFFER];
+ U8 *cur_ptr = packed_buffer;
+
+ U32 size;
+ U32 face_count = 0;
+
+ if (block_num < 0)
+ {
+ size = mesgsys->getSizeFast(block_name, _PREHASH_TextureEntry);
+ }
+ else
+ {
+ size = mesgsys->getSizeFast(block_name, block_num, _PREHASH_TextureEntry);
+ }
+
+ if (size == 0)
+ {
+ return retval;
+ }
+
+ if (block_num < 0)
+ {
+ mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, packed_buffer, 0, 0, MAX_TE_BUFFER);
+ }
+ else
+ {
+ mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, packed_buffer, 0, block_num, MAX_TE_BUFFER);
+ }
+
+ face_count = getNumTEs();
+
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_data, 16, face_count, MVT_LLUUID);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)colors, 4, face_count, MVT_U8);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_s, 2, face_count, MVT_S16Array);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_t, 2, face_count, MVT_S16Array);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_s, 2, face_count, MVT_S16Array);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_t, 2, face_count, MVT_S16Array);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_rot, 2, face_count, MVT_S16Array);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)bump, 1, face_count, MVT_U8);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)media_flags, 1, face_count, MVT_U8);
+
+ LLColor4 color;
+ LLColor4U coloru;
+ for (U32 i = 0; i < face_count; i++)
+ {
+ retval |= setTETexture(i, ((LLUUID*)image_data)[i]);
+ retval |= setTEScale(i,
+ floor((1.0f + ((((F32)scale_s[i] / (F32)0x7FFF)) * (LL_MAX_SCALE_S+1.f))) * 100.f + 0.5f) / 100.f,
+ floor((1.0f + ((((F32)scale_t[i] / (F32)0x7FFF)) * (LL_MAX_SCALE_T+1.f))) * 100.f + 0.5f) / 100.f);
+ retval |= setTEOffset(i, (F32)offset_s[i] / (F32)0x7FFF, (F32) offset_t[i] / (F32) 0x7FFF);
+ retval |= setTERotation(i, ((F32)image_rot[i]/ (F32)0x7FFF) * F_TWO_PI);
+ retval |= setTEBumpShinyFullbright(i, bump[i]);
+ retval |= setTEMediaTexGen(i, media_flags[i]);
+ coloru = LLColor4U(colors + 4*i);
+
+ // Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
+ // as all zeros. However, the subtraction and addition must be done in unsigned
+ // byte space, not in float space, otherwise off-by-one errors occur. JC
+ color.mV[VRED] = F32(255 - coloru.mV[VRED]) / 255.f;
+ color.mV[VGREEN] = F32(255 - coloru.mV[VGREEN]) / 255.f;
+ color.mV[VBLUE] = F32(255 - coloru.mV[VBLUE]) / 255.f;
+ color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f;
+
+ retval |= setTEColor(i, color);
+ }
+
+ return retval;
+}
+
+S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
+{
+ // use a negative block_num to indicate a single-block read (a non-variable block)
+ S32 retval = 0;
+ const U32 MAX_TES = 32;
+
+ // Avoid construction of 32 UUIDs per call
+ static LLUUID image_ids[MAX_TES];
+
+ U8 image_data[MAX_TES*16];
+ U8 colors[MAX_TES*4];
+ S16 scale_s[MAX_TES];
+ S16 scale_t[MAX_TES];
+ S16 offset_s[MAX_TES];
+ S16 offset_t[MAX_TES];
+ S16 image_rot[MAX_TES];
+ U8 bump[MAX_TES];
+ U8 media_flags[MAX_TES];
+
+ const U32 MAX_TE_BUFFER = 4096;
+ U8 packed_buffer[MAX_TE_BUFFER];
+ U8 *cur_ptr = packed_buffer;
+
+ S32 size;
+ U32 face_count = 0;
+
+ if (!dp.unpackBinaryData(packed_buffer, size, "TextureEntry"))
+ {
+ retval = TEM_INVALID;
+ llwarns << "Bad texture entry block! Abort!" << llendl;
+ return retval;
+ }
+
+ if (size == 0)
+ {
+ return retval;
+ }
+
+ face_count = getNumTEs();
+ U32 i;
+
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_data, 16, face_count, MVT_LLUUID);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)colors, 4, face_count, MVT_U8);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_s, 2, face_count, MVT_S16Array);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_t, 2, face_count, MVT_S16Array);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_s, 2, face_count, MVT_S16Array);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_t, 2, face_count, MVT_S16Array);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_rot, 2, face_count, MVT_S16Array);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)bump, 1, face_count, MVT_U8);
+ cur_ptr++;
+ cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)media_flags, 1, face_count, MVT_U8);
+
+ for (i = 0; i < face_count; i++)
+ {
+// llinfos << "BUMP unpack (Datapacker) [" << i << "]=" << S32(bump[i]) <<llendl;
+ memcpy(image_ids[i].mData,&image_data[i*16],16);
+ }
+
+ LLColor4 color;
+ LLColor4U coloru;
+ for (i = 0; i < face_count; i++)
+ {
+ retval |= setTETexture(i, image_ids[i]);
+ retval |= setTEScale(i,
+ floor((1.0f + ((((F32)scale_s[i] / (F32)0x7FFF)) * (LL_MAX_SCALE_S+1.f))) * 100.f + 0.5f) / 100.f,
+ floor((1.0f + ((((F32)scale_t[i] / (F32)0x7FFF)) * (LL_MAX_SCALE_T+1.f))) * 100.f + 0.5f) / 100.f);
+ retval |= setTEOffset(i, (F32)offset_s[i] / (F32)0x7FFF, (F32) offset_t[i] / (F32) 0x7FFF);
+ retval |= setTERotation(i, ((F32)image_rot[i]/ (F32)0x7FFF) * F_TWO_PI);
+ retval |= setTEBumpShinyFullbright(i, bump[i]);
+ retval |= setTEMediaTexGen(i, media_flags[i]);
+ coloru = LLColor4U(colors + 4*i);
+
+ // Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
+ // as all zeros. However, the subtraction and addition must be done in unsigned
+ // byte space, not in float space, otherwise off-by-one errors occur. JC
+ color.mV[VRED] = F32(255 - coloru.mV[VRED]) / 255.f;
+ color.mV[VGREEN] = F32(255 - coloru.mV[VGREEN]) / 255.f;
+ color.mV[VBLUE] = F32(255 - coloru.mV[VBLUE]) / 255.f;
+ color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f;
+
+ retval |= setTEColor(i, color);
+ }
+
+ return retval;
+}
+
+void LLPrimitive::setTextureList(LLTextureEntry *listp)
+{
+ LLTextureEntry* old_texture_list = mTextureList;
+ mTextureList = listp;
+ delete[] old_texture_list;
+}
+
+//============================================================================
+
+LLLightParams::LLLightParams()
+{
+ mColor.setToWhite();
+ mRadius = 10.f;
+ mCutoff = 0.0f;
+ mFalloff = 0.75f;
+
+ mType = PARAMS_LIGHT;
+}
+
+BOOL LLLightParams::pack(LLDataPacker &dp) const
+{
+ LLColor4U color4u(mColor);
+ dp.packColor4U(color4u, "color");
+ dp.packF32(mRadius, "radius");
+ dp.packF32(mCutoff, "cutoff");
+ dp.packF32(mFalloff, "falloff");
+ return TRUE;
+}
+
+BOOL LLLightParams::unpack(LLDataPacker &dp)
+{
+ LLColor4U color4u;
+ dp.unpackColor4U(color4u, "color");
+ mColor = LLColor4(color4u);
+ dp.unpackF32(mRadius, "radius");
+ dp.unpackF32(mCutoff, "cutoff");
+ dp.unpackF32(mFalloff, "falloff");
+ return TRUE;
+}
+
+bool LLLightParams::operator==(const LLNetworkData& data) const
+{
+ if (data.mType != PARAMS_LIGHT)
+ {
+ return false;
+ }
+ const LLLightParams *param = (const LLLightParams*)&data;
+ if (param->mColor != mColor ||
+ param->mRadius != mRadius ||
+ param->mCutoff != mCutoff ||
+ param->mFalloff != mFalloff)
+ {
+ return false;
+ }
+ return true;
+}
+
+void LLLightParams::copy(const LLNetworkData& data)
+{
+ const LLLightParams *param = (LLLightParams*)&data;
+ mType = param->mType;
+ mColor = param->mColor;
+ mRadius = param->mRadius;
+ mCutoff = param->mCutoff;
+ mFalloff = param->mFalloff;
+}
+
+//============================================================================
+
+LLFlexibleObjectData::LLFlexibleObjectData()
+{
+ mSimulateLOD = FLEXIBLE_OBJECT_DEFAULT_NUM_SECTIONS;
+ mGravity = FLEXIBLE_OBJECT_DEFAULT_GRAVITY;
+ mAirFriction = FLEXIBLE_OBJECT_DEFAULT_AIR_FRICTION;
+ mWindSensitivity = FLEXIBLE_OBJECT_DEFAULT_WIND_SENSITIVITY;
+ mTension = FLEXIBLE_OBJECT_DEFAULT_TENSION;
+ //mUsingCollisionSphere = FLEXIBLE_OBJECT_DEFAULT_USING_COLLISION_SPHERE;
+ //mRenderingCollisionSphere = FLEXIBLE_OBJECT_DEFAULT_RENDERING_COLLISION_SPHERE;
+ mUserForce = LLVector3(0.f, 0.f, 0.f);
+
+ mType = PARAMS_FLEXIBLE;
+}
+
+BOOL LLFlexibleObjectData::pack(LLDataPacker &dp) const
+{
+ // Custom, uber-svelte pack "softness" in upper bits of tension & drag
+ U8 bit1 = (mSimulateLOD & 2) << 6;
+ U8 bit2 = (mSimulateLOD & 1) << 7;
+ dp.packU8((U8)(mTension*10.01f) + bit1, "tension");
+ dp.packU8((U8)(mAirFriction*10.01f) + bit2, "drag");
+ dp.packU8((U8)((mGravity+10.f)*10.01f), "gravity");
+ dp.packU8((U8)(mWindSensitivity*10.01f), "wind");
+ dp.packVector3(mUserForce, "userforce");
+ return TRUE;
+}
+
+BOOL LLFlexibleObjectData::unpack(LLDataPacker &dp)
+{
+ U8 tension, friction, gravity, wind;
+ U8 bit1, bit2;
+ dp.unpackU8(tension, "tension"); bit1 = (tension >> 6) & 2;
+ mTension = ((F32)(tension&0x7f))/10.f;
+ dp.unpackU8(friction, "drag"); bit2 = (friction >> 7) & 1;
+ mAirFriction = ((F32)(friction&0x7f))/10.f;
+ mSimulateLOD = bit1 | bit2;
+ dp.unpackU8(gravity, "gravity"); mGravity = ((F32)gravity)/10.f - 10.f;
+ dp.unpackU8(wind, "wind"); mWindSensitivity = ((F32)wind)/10.f;
+ if (dp.hasNext())
+ {
+ dp.unpackVector3(mUserForce, "userforce");
+ }
+ else
+ {
+ mUserForce.setVec(0.f, 0.f, 0.f);
+ }
+ return TRUE;
+}
+
+bool LLFlexibleObjectData::operator==(const LLNetworkData& data) const
+{
+ if (data.mType != PARAMS_FLEXIBLE)
+ {
+ return false;
+ }
+ LLFlexibleObjectData *flex_data = (LLFlexibleObjectData*)&data;
+ return (mSimulateLOD == flex_data->mSimulateLOD &&
+ mGravity == flex_data->mGravity &&
+ mAirFriction == flex_data->mAirFriction &&
+ mWindSensitivity == flex_data->mWindSensitivity &&
+ mTension == flex_data->mTension &&
+ mUserForce == flex_data->mUserForce);
+ //mUsingCollisionSphere == flex_data->mUsingCollisionSphere &&
+ //mRenderingCollisionSphere == flex_data->mRenderingCollisionSphere
+}
+
+void LLFlexibleObjectData::copy(const LLNetworkData& data)
+{
+ const LLFlexibleObjectData *flex_data = (LLFlexibleObjectData*)&data;
+ mSimulateLOD = flex_data->mSimulateLOD;
+ mGravity = flex_data->mGravity;
+ mAirFriction = flex_data->mAirFriction;
+ mWindSensitivity = flex_data->mWindSensitivity;
+ mTension = flex_data->mTension;
+ mUserForce = flex_data->mUserForce;
+ //mUsingCollisionSphere = flex_data->mUsingCollisionSphere;
+ //mRenderingCollisionSphere = flex_data->mRenderingCollisionSphere;
+}