summaryrefslogtreecommitdiff
path: root/indra/llprimitive
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llprimitive')
-rw-r--r--indra/llprimitive/legacy_object_types.h59
-rw-r--r--indra/llprimitive/llmaterialtable.cpp657
-rw-r--r--indra/llprimitive/llmaterialtable.h116
-rw-r--r--indra/llprimitive/llprimitive.cpp1749
-rw-r--r--indra/llprimitive/llprimitive.h510
-rw-r--r--indra/llprimitive/lltextureanim.cpp221
-rw-r--r--indra/llprimitive/lltextureanim.h54
-rw-r--r--indra/llprimitive/lltextureentry.cpp348
-rw-r--r--indra/llprimitive/lltextureentry.h126
-rw-r--r--indra/llprimitive/lltreeparams.cpp187
-rw-r--r--indra/llprimitive/lltreeparams.h183
-rw-r--r--indra/llprimitive/llvolumemessage.cpp534
-rw-r--r--indra/llprimitive/llvolumemessage.h74
-rw-r--r--indra/llprimitive/llvolumexml.cpp57
-rw-r--r--indra/llprimitive/llvolumexml.h27
-rw-r--r--indra/llprimitive/material_codes.h35
16 files changed, 4937 insertions, 0 deletions
diff --git a/indra/llprimitive/legacy_object_types.h b/indra/llprimitive/legacy_object_types.h
new file mode 100644
index 0000000000..57ace87e89
--- /dev/null
+++ b/indra/llprimitive/legacy_object_types.h
@@ -0,0 +1,59 @@
+/**
+ * @file legacy_object_types.h
+ * @brief Byte codes for basic object and primitive types
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LEGACY_OBJECT_TYPES_H
+#define LL_LEGACY_OBJECT_TYPES_H
+
+const S8 PLAYER = 'c';
+//const S8 BASIC_SHOT = 's';
+//const S8 BIG_SHOT = 'S';
+//const S8 TREE_SHOT = 'g';
+//const S8 PHYSICAL_BALL = 'b';
+
+const S8 TREE = 'T';
+const S8 TREE_NEW = 'R';
+//const S8 SPARK = 'p';
+//const S8 SMOKE = 'q';
+//const S8 BOX = 'x';
+//const S8 CYLINDER = 'y';
+//const S8 CONE = 'o';
+//const S8 SPHERE = 'h';
+//const S8 BIRD = 'r'; // ascii 114
+//const S8 ATOR = 'a';
+//const S8 ROCK = 'k';
+
+const S8 GRASS = 'd';
+const S8 PART_SYS = 'P';
+
+//const S8 ORACLE = 'O';
+//const S8 TEXTBUBBLE = 't'; // Text bubble to show communication
+//const S8 DEMON = 'M'; // Maxwell's demon for scarfing legacy_object_types.h
+//const S8 CUBE = 'f';
+//const S8 LSL_TEST = 'L';
+//const S8 PRISM = '1';
+//const S8 PYRAMID = '2';
+//const S8 TETRAHEDRON = '3';
+//const S8 HALF_CYLINDER = '4';
+//const S8 HALF_CONE = '5';
+//const S8 HALF_SPHERE = '6';
+
+const S8 PRIMITIVE_VOLUME = 'v';
+
+// Misc constants
+
+//const F32 AVATAR_RADIUS = 0.5f;
+//const F32 SHOT_RADIUS = 0.05f;
+//const F32 BIG_SHOT_RADIUS = 0.05f;
+//const F32 TREE_SIZE = 5.f;
+//const F32 BALL_SIZE = 4.f;
+
+//const F32 SHOT_VELOCITY = 100.f;
+//const F32 GRENADE_BLAST_RADIUS = 5.f;
+
+#endif
+
diff --git a/indra/llprimitive/llmaterialtable.cpp b/indra/llprimitive/llmaterialtable.cpp
new file mode 100644
index 0000000000..ebd6306284
--- /dev/null
+++ b/indra/llprimitive/llmaterialtable.cpp
@@ -0,0 +1,657 @@
+/**
+ * @file llmaterialtable.cpp
+ * @brief Table of material names and IDs for viewer
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "llmaterialtable.h"
+#include "material_codes.h"
+#include "sound_ids.h"
+#include "imageids.h"
+
+LLMaterialTable LLMaterialTable::basic(1);
+
+F32 const LLMaterialTable::DEFAULT_FRICTION = 0.5f;
+F32 const LLMaterialTable::DEFAULT_RESTITUTION = 0.4f;
+
+LLMaterialTable::LLMaterialTable()
+{
+}
+
+LLMaterialTable::LLMaterialTable(U8 isBasic)
+{
+ initBasicTable();
+}
+
+LLMaterialTable::~LLMaterialTable()
+{
+ if (mCollisionSoundMatrix)
+ {
+ delete [] mCollisionSoundMatrix;
+ mCollisionSoundMatrix = NULL;
+ }
+
+ if (mSlidingSoundMatrix)
+ {
+ delete [] mSlidingSoundMatrix;
+ mSlidingSoundMatrix = NULL;
+ }
+
+ if (mRollingSoundMatrix)
+ {
+ delete [] mRollingSoundMatrix;
+ mRollingSoundMatrix = NULL;
+ }
+
+ mMaterialInfoList.deleteAllData();
+}
+
+void LLMaterialTable::initBasicTable()
+{
+ add(LL_MCODE_STONE,"Stone", LL_DEFAULT_STONE_UUID);
+ add(LL_MCODE_METAL,"Metal", LL_DEFAULT_METAL_UUID);
+ add(LL_MCODE_GLASS,"Glass", LL_DEFAULT_GLASS_UUID);
+ add(LL_MCODE_WOOD,"Wood", LL_DEFAULT_WOOD_UUID);
+ add(LL_MCODE_FLESH,"Flesh", LL_DEFAULT_FLESH_UUID);
+ add(LL_MCODE_PLASTIC,"Plastic", LL_DEFAULT_PLASTIC_UUID);
+ add(LL_MCODE_RUBBER,"Rubber", LL_DEFAULT_RUBBER_UUID);
+ add(LL_MCODE_LIGHT,"Light", LL_DEFAULT_LIGHT_UUID);
+
+ // specify densities for these materials. . .
+ // these were taken from http://www.mcelwee.net/html/densities_of_various_materials.html
+
+ addDensity(LL_MCODE_STONE,30.f);
+ addDensity(LL_MCODE_METAL,50.f);
+ addDensity(LL_MCODE_GLASS,20.f);
+ addDensity(LL_MCODE_WOOD,10.f);
+ addDensity(LL_MCODE_FLESH,10.f);
+ addDensity(LL_MCODE_PLASTIC,5.f);
+ addDensity(LL_MCODE_RUBBER,0.5f); //
+ addDensity(LL_MCODE_LIGHT,20.f); //
+
+ // add damage and energy values
+ addDamageAndEnergy(LL_MCODE_STONE, 1.f, 1.f, 1.f); // concrete
+ addDamageAndEnergy(LL_MCODE_METAL, 1.f, 1.f, 1.f); // steel
+ addDamageAndEnergy(LL_MCODE_GLASS, 1.f, 1.f, 1.f); // borosilicate glass
+ addDamageAndEnergy(LL_MCODE_WOOD, 1.f, 1.f, 1.f); // southern pine
+ addDamageAndEnergy(LL_MCODE_FLESH, 1.f, 1.f, 1.f); // saltwater
+ addDamageAndEnergy(LL_MCODE_PLASTIC, 1.f, 1.f, 1.f); // HDPE
+ addDamageAndEnergy(LL_MCODE_RUBBER, 1.f, 1.f, 1.f); //
+ addDamageAndEnergy(LL_MCODE_LIGHT, 1.f, 1.f, 1.f); //
+
+ addFriction(LL_MCODE_STONE,0.8f); // concrete
+ addFriction(LL_MCODE_METAL,0.3f); // steel
+ addFriction(LL_MCODE_GLASS,0.2f); // borosilicate glass
+ addFriction(LL_MCODE_WOOD,0.6f); // southern pine
+ addFriction(LL_MCODE_FLESH,0.9f); // saltwater
+ addFriction(LL_MCODE_PLASTIC,0.4f); // HDPE
+ addFriction(LL_MCODE_RUBBER,0.9f); //
+ addFriction(LL_MCODE_LIGHT,0.2f); //
+
+ addRestitution(LL_MCODE_STONE,0.4f); // concrete
+ addRestitution(LL_MCODE_METAL,0.4f); // steel
+ addRestitution(LL_MCODE_GLASS,0.7f); // borosilicate glass
+ addRestitution(LL_MCODE_WOOD,0.5f); // southern pine
+ addRestitution(LL_MCODE_FLESH,0.3f); // saltwater
+ addRestitution(LL_MCODE_PLASTIC,0.7f); // HDPE
+ addRestitution(LL_MCODE_RUBBER,0.9f); //
+ addRestitution(LL_MCODE_LIGHT,0.7f); //
+
+ addShatterSound(LL_MCODE_STONE,LLUUID("ea296329-0f09-4993-af1b-e6784bab1dc9"));
+ addShatterSound(LL_MCODE_METAL,LLUUID("d1375446-1c4d-470b-9135-30132433b678"));
+ addShatterSound(LL_MCODE_GLASS,LLUUID("85cda060-b393-48e6-81c8-2cfdfb275351"));
+ addShatterSound(LL_MCODE_WOOD,LLUUID("6f00669f-15e0-4793-a63e-c03f62fee43a"));
+ addShatterSound(LL_MCODE_FLESH,LLUUID("2d8c6f51-149e-4e23-8413-93a379b42b67"));
+ addShatterSound(LL_MCODE_PLASTIC,LLUUID("d55c7f3c-e1c3-4ddc-9eff-9ef805d9190e"));
+ addShatterSound(LL_MCODE_RUBBER,LLUUID("212b6d1e-8d9c-4986-b3aa-f3c6df8d987d"));
+ addShatterSound(LL_MCODE_LIGHT,LLUUID("d55c7f3c-e1c3-4ddc-9eff-9ef805d9190e"));
+
+ // CollisionSounds
+ mCollisionSoundMatrix = new LLUUID[LL_MCODE_END*LL_MCODE_END];
+ if (mCollisionSoundMatrix)
+ {
+ addCollisionSound(LL_MCODE_STONE, LL_MCODE_STONE, SND_STONE_STONE);
+ addCollisionSound(LL_MCODE_STONE, LL_MCODE_METAL, SND_STONE_METAL);
+ addCollisionSound(LL_MCODE_STONE, LL_MCODE_GLASS, SND_STONE_GLASS);
+ addCollisionSound(LL_MCODE_STONE, LL_MCODE_WOOD, SND_STONE_WOOD);
+ addCollisionSound(LL_MCODE_STONE, LL_MCODE_FLESH, SND_STONE_FLESH);
+ addCollisionSound(LL_MCODE_STONE, LL_MCODE_PLASTIC, SND_STONE_PLASTIC);
+ addCollisionSound(LL_MCODE_STONE, LL_MCODE_RUBBER, SND_STONE_RUBBER);
+ addCollisionSound(LL_MCODE_STONE, LL_MCODE_LIGHT, SND_STONE_PLASTIC);
+
+ addCollisionSound(LL_MCODE_METAL, LL_MCODE_METAL, SND_METAL_METAL);
+ addCollisionSound(LL_MCODE_METAL, LL_MCODE_GLASS, SND_METAL_GLASS);
+ addCollisionSound(LL_MCODE_METAL, LL_MCODE_WOOD, SND_METAL_WOOD);
+ addCollisionSound(LL_MCODE_METAL, LL_MCODE_FLESH, SND_METAL_FLESH);
+ addCollisionSound(LL_MCODE_METAL, LL_MCODE_PLASTIC, SND_METAL_PLASTIC);
+ addCollisionSound(LL_MCODE_METAL, LL_MCODE_LIGHT, SND_METAL_PLASTIC);
+ addCollisionSound(LL_MCODE_METAL, LL_MCODE_RUBBER, SND_METAL_RUBBER);
+
+ addCollisionSound(LL_MCODE_GLASS, LL_MCODE_GLASS, SND_GLASS_GLASS);
+ addCollisionSound(LL_MCODE_GLASS, LL_MCODE_WOOD, SND_GLASS_WOOD);
+ addCollisionSound(LL_MCODE_GLASS, LL_MCODE_FLESH, SND_GLASS_FLESH);
+ addCollisionSound(LL_MCODE_GLASS, LL_MCODE_PLASTIC, SND_GLASS_PLASTIC);
+ addCollisionSound(LL_MCODE_GLASS, LL_MCODE_RUBBER, SND_GLASS_RUBBER);
+ addCollisionSound(LL_MCODE_GLASS, LL_MCODE_LIGHT, SND_GLASS_PLASTIC);
+
+ addCollisionSound(LL_MCODE_WOOD, LL_MCODE_WOOD, SND_WOOD_WOOD);
+ addCollisionSound(LL_MCODE_WOOD, LL_MCODE_FLESH, SND_WOOD_FLESH);
+ addCollisionSound(LL_MCODE_WOOD, LL_MCODE_PLASTIC, SND_WOOD_PLASTIC);
+ addCollisionSound(LL_MCODE_WOOD, LL_MCODE_RUBBER, SND_WOOD_RUBBER);
+ addCollisionSound(LL_MCODE_WOOD, LL_MCODE_LIGHT, SND_WOOD_PLASTIC);
+
+ addCollisionSound(LL_MCODE_FLESH, LL_MCODE_FLESH, SND_FLESH_FLESH);
+ addCollisionSound(LL_MCODE_FLESH, LL_MCODE_PLASTIC, SND_FLESH_PLASTIC);
+ addCollisionSound(LL_MCODE_FLESH, LL_MCODE_RUBBER, SND_FLESH_RUBBER);
+ addCollisionSound(LL_MCODE_FLESH, LL_MCODE_LIGHT, SND_FLESH_PLASTIC);
+
+ addCollisionSound(LL_MCODE_RUBBER, LL_MCODE_RUBBER, SND_RUBBER_RUBBER);
+ addCollisionSound(LL_MCODE_RUBBER, LL_MCODE_PLASTIC, SND_RUBBER_PLASTIC);
+ addCollisionSound(LL_MCODE_RUBBER, LL_MCODE_LIGHT, SND_RUBBER_PLASTIC);
+
+ addCollisionSound(LL_MCODE_PLASTIC, LL_MCODE_PLASTIC, SND_PLASTIC_PLASTIC);
+ addCollisionSound(LL_MCODE_PLASTIC, LL_MCODE_LIGHT, SND_PLASTIC_PLASTIC);
+
+ addCollisionSound(LL_MCODE_LIGHT, LL_MCODE_LIGHT, SND_PLASTIC_PLASTIC);
+ }
+
+ // Sliding Sounds
+ mSlidingSoundMatrix = new LLUUID[LL_MCODE_END*LL_MCODE_END];
+ if (mSlidingSoundMatrix)
+ {
+ addSlidingSound(LL_MCODE_STONE, LL_MCODE_STONE, SND_SLIDE_STONE_STONE);
+ addSlidingSound(LL_MCODE_STONE, LL_MCODE_METAL, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_STONE, LL_MCODE_GLASS, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_STONE, LL_MCODE_WOOD, SND_SLIDE_STONE_WOOD);
+ addSlidingSound(LL_MCODE_STONE, LL_MCODE_FLESH, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_STONE, LL_MCODE_PLASTIC, SND_SLIDE_STONE_PLASTIC);
+ addSlidingSound(LL_MCODE_STONE, LL_MCODE_RUBBER, SND_SLIDE_STONE_RUBBER);
+ addSlidingSound(LL_MCODE_STONE, LL_MCODE_LIGHT, SND_SLIDE_STONE_PLASTIC);
+
+ addSlidingSound(LL_MCODE_METAL, LL_MCODE_METAL, SND_SLIDE_METAL_METAL);
+ addSlidingSound(LL_MCODE_METAL, LL_MCODE_GLASS, SND_SLIDE_METAL_GLASS);
+ addSlidingSound(LL_MCODE_METAL, LL_MCODE_WOOD, SND_SLIDE_METAL_WOOD);
+ addSlidingSound(LL_MCODE_METAL, LL_MCODE_FLESH, SND_SLIDE_METAL_FLESH);
+ addSlidingSound(LL_MCODE_METAL, LL_MCODE_PLASTIC, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_METAL, LL_MCODE_RUBBER, SND_SLIDE_METAL_RUBBER);
+ addSlidingSound(LL_MCODE_METAL, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
+
+ addSlidingSound(LL_MCODE_GLASS, LL_MCODE_GLASS, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_GLASS, LL_MCODE_WOOD, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_GLASS, LL_MCODE_FLESH, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_GLASS, LL_MCODE_PLASTIC, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_GLASS, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_GLASS, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
+
+ addSlidingSound(LL_MCODE_WOOD, LL_MCODE_WOOD, SND_SLIDE_WOOD_WOOD);
+ addSlidingSound(LL_MCODE_WOOD, LL_MCODE_FLESH, SND_SLIDE_WOOD_FLESH);
+ addSlidingSound(LL_MCODE_WOOD, LL_MCODE_PLASTIC, SND_SLIDE_WOOD_PLASTIC);
+ addSlidingSound(LL_MCODE_WOOD, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_WOOD, LL_MCODE_LIGHT, SND_SLIDE_WOOD_PLASTIC);
+
+ addSlidingSound(LL_MCODE_FLESH, LL_MCODE_FLESH, SND_SLIDE_FLESH_FLESH);
+ addSlidingSound(LL_MCODE_FLESH, LL_MCODE_PLASTIC, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_FLESH, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_FLESH, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
+
+ addSlidingSound(LL_MCODE_RUBBER, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_RUBBER, LL_MCODE_PLASTIC, SND_SLIDE_RUBBER_PLASTIC);
+ addSlidingSound(LL_MCODE_RUBBER, LL_MCODE_LIGHT, SND_SLIDE_RUBBER_PLASTIC);
+
+ addSlidingSound(LL_MCODE_PLASTIC, LL_MCODE_PLASTIC, SND_SLIDE_STONE_STONE_01);
+ addSlidingSound(LL_MCODE_PLASTIC, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
+
+ addSlidingSound(LL_MCODE_LIGHT, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
+ }
+
+ // Rolling Sounds
+ mRollingSoundMatrix = new LLUUID[LL_MCODE_END*LL_MCODE_END];
+ if (mRollingSoundMatrix)
+ {
+ addRollingSound(LL_MCODE_STONE, LL_MCODE_STONE, SND_ROLL_STONE_STONE);
+ addRollingSound(LL_MCODE_STONE, LL_MCODE_METAL, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_STONE, LL_MCODE_GLASS, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_STONE, LL_MCODE_WOOD, SND_ROLL_STONE_WOOD);
+ addRollingSound(LL_MCODE_STONE, LL_MCODE_FLESH, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_STONE, LL_MCODE_PLASTIC, SND_ROLL_STONE_PLASTIC);
+ addRollingSound(LL_MCODE_STONE, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_STONE, LL_MCODE_LIGHT, SND_ROLL_STONE_PLASTIC);
+
+ addRollingSound(LL_MCODE_METAL, LL_MCODE_METAL, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_METAL, LL_MCODE_GLASS, SND_ROLL_METAL_GLASS);
+ addRollingSound(LL_MCODE_METAL, LL_MCODE_WOOD, SND_ROLL_METAL_WOOD);
+ addRollingSound(LL_MCODE_METAL, LL_MCODE_FLESH, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_METAL, LL_MCODE_PLASTIC, SND_ROLL_METAL_WOOD);
+ addRollingSound(LL_MCODE_METAL, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_METAL, LL_MCODE_LIGHT, SND_ROLL_METAL_WOOD);
+
+ addRollingSound(LL_MCODE_GLASS, LL_MCODE_GLASS, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_GLASS, LL_MCODE_WOOD, SND_ROLL_GLASS_WOOD);
+ addRollingSound(LL_MCODE_GLASS, LL_MCODE_FLESH, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_GLASS, LL_MCODE_PLASTIC, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_GLASS, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_GLASS, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
+
+ addRollingSound(LL_MCODE_WOOD, LL_MCODE_WOOD, SND_ROLL_WOOD_WOOD);
+ addRollingSound(LL_MCODE_WOOD, LL_MCODE_FLESH, SND_ROLL_WOOD_FLESH);
+ addRollingSound(LL_MCODE_WOOD, LL_MCODE_PLASTIC, SND_ROLL_WOOD_PLASTIC);
+ addRollingSound(LL_MCODE_WOOD, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_WOOD, LL_MCODE_LIGHT, SND_ROLL_WOOD_PLASTIC);
+
+ addRollingSound(LL_MCODE_FLESH, LL_MCODE_FLESH, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_FLESH, LL_MCODE_PLASTIC, SND_ROLL_FLESH_PLASTIC);
+ addRollingSound(LL_MCODE_FLESH, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_FLESH, LL_MCODE_LIGHT, SND_ROLL_FLESH_PLASTIC);
+
+ addRollingSound(LL_MCODE_RUBBER, LL_MCODE_RUBBER, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_RUBBER, LL_MCODE_PLASTIC, SND_SLIDE_STONE_STONE_01);
+ addRollingSound(LL_MCODE_RUBBER, LL_MCODE_LIGHT, SND_SLIDE_STONE_STONE_01);
+
+ addRollingSound(LL_MCODE_PLASTIC, LL_MCODE_PLASTIC, SND_ROLL_PLASTIC_PLASTIC);
+ addRollingSound(LL_MCODE_PLASTIC, LL_MCODE_LIGHT, SND_ROLL_PLASTIC_PLASTIC);
+
+ addRollingSound(LL_MCODE_LIGHT, LL_MCODE_LIGHT, SND_ROLL_PLASTIC_PLASTIC);
+ }
+}
+
+BOOL LLMaterialTable::add(U8 mcode, char* name, const LLUUID &uuid)
+{
+ LLMaterialInfo *infop;
+
+ infop = new LLMaterialInfo(mcode,name,uuid);
+ if (!infop) return FALSE;
+
+ // Add at the end so the order in menus matches the order in this
+ // file. JNC 11.30.01
+ mMaterialInfoList.addDataAtEnd(infop);
+
+ return TRUE;
+}
+
+BOOL LLMaterialTable::addCollisionSound(U8 mcode, U8 mcode2, const LLUUID &uuid)
+{
+ if (mCollisionSoundMatrix && (mcode < LL_MCODE_END) && (mcode2 < LL_MCODE_END))
+ {
+ mCollisionSoundMatrix[mcode * LL_MCODE_END + mcode2] = uuid;
+ if (mcode != mcode2)
+ {
+ mCollisionSoundMatrix[mcode2 * LL_MCODE_END + mcode] = uuid;
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLMaterialTable::addSlidingSound(U8 mcode, U8 mcode2, const LLUUID &uuid)
+{
+ if (mSlidingSoundMatrix && (mcode < LL_MCODE_END) && (mcode2 < LL_MCODE_END))
+ {
+ mSlidingSoundMatrix[mcode * LL_MCODE_END + mcode2] = uuid;
+ if (mcode != mcode2)
+ {
+ mSlidingSoundMatrix[mcode2 * LL_MCODE_END + mcode] = uuid;
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLMaterialTable::addRollingSound(U8 mcode, U8 mcode2, const LLUUID &uuid)
+{
+ if (mRollingSoundMatrix && (mcode < LL_MCODE_END) && (mcode2 < LL_MCODE_END))
+ {
+ mRollingSoundMatrix[mcode * LL_MCODE_END + mcode2] = uuid;
+ if (mcode != mcode2)
+ {
+ mRollingSoundMatrix[mcode2 * LL_MCODE_END + mcode] = uuid;
+ }
+ }
+ return TRUE;
+}
+
+BOOL LLMaterialTable::addShatterSound(U8 mcode, const LLUUID &uuid)
+{
+ LLMaterialInfo *infop;
+
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ infop->mShatterSoundID = uuid;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL LLMaterialTable::addDensity(U8 mcode, const F32 &density)
+{
+ LLMaterialInfo *infop;
+
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ infop->mDensity = density;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL LLMaterialTable::addRestitution(U8 mcode, const F32 &restitution)
+{
+ LLMaterialInfo *infop;
+
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ infop->mRestitution = restitution;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL LLMaterialTable::addFriction(U8 mcode, const F32 &friction)
+{
+ LLMaterialInfo *infop;
+
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ infop->mFriction = friction;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL LLMaterialTable::addDamageAndEnergy(U8 mcode, const F32 &hp_mod, const F32 &damage_mod, const F32 &ep_mod)
+{
+ LLMaterialInfo *infop;
+
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ infop->mHPModifier = hp_mod;
+ infop->mDamageModifier = damage_mod;
+ infop->mEPModifier = ep_mod;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+LLUUID LLMaterialTable::getDefaultTextureID(char* name)
+{
+ LLMaterialInfo *infop;
+
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (!strcmp(name, infop->mName))
+ {
+ return infop->mDefaultTextureID;
+ }
+ }
+
+ return LLUUID::null;
+}
+
+
+LLUUID LLMaterialTable::getDefaultTextureID(U8 mcode)
+{
+ LLMaterialInfo *infop;
+
+ mcode &= LL_MCODE_MASK;
+
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ return infop->mDefaultTextureID;
+ }
+ }
+
+ return LLUUID::null;
+}
+
+
+U8 LLMaterialTable::getMCode(const char* name)
+{
+ LLMaterialInfo *infop;
+
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (!strcmp(name, infop->mName))
+ {
+ return infop->mMCode;
+ }
+ }
+
+ return 0;
+}
+
+
+char* LLMaterialTable::getName(U8 mcode)
+{
+ LLMaterialInfo *infop;
+
+ mcode &= LL_MCODE_MASK;
+
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ return infop->mName;
+ }
+ }
+
+ return NULL;
+}
+
+
+LLUUID LLMaterialTable::getCollisionSoundUUID(U8 mcode, U8 mcode2)
+{
+ mcode &= LL_MCODE_MASK;
+ mcode2 &= LL_MCODE_MASK;
+
+ //llinfos << "code 1: " << ((U32) mcode) << " code 2:" << ((U32) mcode2) << llendl;
+ if (mCollisionSoundMatrix && (mcode < LL_MCODE_END) && (mcode2 < LL_MCODE_END))
+ {
+ return(mCollisionSoundMatrix[mcode * LL_MCODE_END + mcode2]);
+ }
+ else
+ {
+ //llinfos << "Null Sound" << llendl;
+ return(SND_NULL);
+ }
+}
+
+LLUUID LLMaterialTable::getSlidingSoundUUID(U8 mcode, U8 mcode2)
+{
+ mcode &= LL_MCODE_MASK;
+ mcode2 &= LL_MCODE_MASK;
+
+ if (mSlidingSoundMatrix && (mcode < LL_MCODE_END) && (mcode2 < LL_MCODE_END))
+ {
+ return(mSlidingSoundMatrix[mcode * LL_MCODE_END + mcode2]);
+ }
+ else
+ {
+ return(SND_NULL);
+ }
+}
+
+LLUUID LLMaterialTable::getRollingSoundUUID(U8 mcode, U8 mcode2)
+{
+ mcode &= LL_MCODE_MASK;
+ mcode2 &= LL_MCODE_MASK;
+
+ if (mRollingSoundMatrix && (mcode < LL_MCODE_END) && (mcode2 < LL_MCODE_END))
+ {
+ return(mRollingSoundMatrix[mcode * LL_MCODE_END + mcode2]);
+ }
+ else
+ {
+ return(SND_NULL);
+ }
+}
+
+LLUUID LLMaterialTable::getGroundCollisionSoundUUID(U8 mcode)
+{
+ // Create material appropriate sounds for collisions with the ground
+ // For now, simply return a single sound for all materials
+ return SND_STONE_DIRT_02;
+}
+
+LLUUID LLMaterialTable::getGroundSlidingSoundUUID(U8 mcode)
+{
+ // Create material-specific sound for sliding on ground
+ // For now, just return a single sound
+ return SND_SLIDE_STONE_STONE_01;
+}
+
+LLUUID LLMaterialTable::getGroundRollingSoundUUID(U8 mcode)
+{
+ // Create material-specific sound for rolling on ground
+ // For now, just return a single sound
+ return SND_SLIDE_STONE_STONE_01;
+}
+
+LLUUID LLMaterialTable::getCollisionParticleUUID(U8 mcode, U8 mcode2)
+{
+ // Returns an appropriate UUID to use as sprite at collision betweeen objects
+ // For now, just return a single image
+ return IMG_SHOT;
+}
+
+LLUUID LLMaterialTable::getGroundCollisionParticleUUID(U8 mcode)
+{
+ // Returns an appropriate
+ // For now, just return a single sound
+ return IMG_SMOKE_POOF;
+}
+
+
+F32 LLMaterialTable::getDensity(U8 mcode)
+{
+ LLMaterialInfo *infop;
+
+ mcode &= LL_MCODE_MASK;
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ return infop->mDensity;
+ }
+ }
+
+ return 0.f;
+}
+
+F32 LLMaterialTable::getRestitution(U8 mcode)
+{
+ LLMaterialInfo *infop;
+
+ mcode &= LL_MCODE_MASK;
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ return infop->mRestitution;
+ }
+ }
+
+ return LLMaterialTable::DEFAULT_RESTITUTION;
+}
+
+F32 LLMaterialTable::getFriction(U8 mcode)
+{
+ LLMaterialInfo *infop;
+
+ mcode &= LL_MCODE_MASK;
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ return infop->mFriction;
+ }
+ }
+
+ return LLMaterialTable::DEFAULT_FRICTION;
+}
+
+F32 LLMaterialTable::getHPMod(U8 mcode)
+{
+ LLMaterialInfo *infop;
+
+ mcode &= LL_MCODE_MASK;
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ return infop->mHPModifier;
+ }
+ }
+
+ return 1.f;
+}
+
+F32 LLMaterialTable::getDamageMod(U8 mcode)
+{
+ LLMaterialInfo *infop;
+
+ mcode &= LL_MCODE_MASK;
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ return infop->mDamageModifier;
+ }
+ }
+
+ return 1.f;
+}
+
+F32 LLMaterialTable::getEPMod(U8 mcode)
+{
+ LLMaterialInfo *infop;
+
+ mcode &= LL_MCODE_MASK;
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ return infop->mEPModifier;
+ }
+ }
+
+ return 1.f;
+}
+
+LLUUID LLMaterialTable::getShatterSoundUUID(U8 mcode)
+{
+ LLMaterialInfo *infop;
+
+ mcode &= LL_MCODE_MASK;
+ for (infop = mMaterialInfoList.getFirstData(); infop != NULL; infop = mMaterialInfoList.getNextData() )
+ {
+ if (mcode == infop->mMCode)
+ {
+ return infop->mShatterSoundID;
+ }
+ }
+
+ return SND_NULL;
+}
diff --git a/indra/llprimitive/llmaterialtable.h b/indra/llprimitive/llmaterialtable.h
new file mode 100644
index 0000000000..7146be54cf
--- /dev/null
+++ b/indra/llprimitive/llmaterialtable.h
@@ -0,0 +1,116 @@
+/**
+ * @file llmaterialtable.h
+ * @brief Table of material information for the viewer UI
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLMATERIALTABLE_H
+#define LL_LLMATERIALTABLE_H
+
+#include "lluuid.h"
+#include "linked_lists.h"
+#include "llstring.h"
+
+const U32 LLMATERIAL_INFO_NAME_LENGTH = 256;
+
+class LLMaterialInfo
+{
+public:
+ U8 mMCode;
+ char mName[LLMATERIAL_INFO_NAME_LENGTH];
+ LLUUID mDefaultTextureID;
+ LLUUID mShatterSoundID;
+ F32 mDensity; // kg/m^3
+ F32 mFriction;
+ F32 mRestitution;
+
+ // damage and energy constants
+ F32 mHPModifier; // modifier on mass based HP total
+ F32 mDamageModifier; // modifier on KE based damage
+ F32 mEPModifier; // modifier on mass based EP total
+
+ LLMaterialInfo(U8 mcode, char* name, const LLUUID &uuid)
+ {
+ init(mcode,name,uuid);
+ };
+
+ void init(U8 mcode, char* name, const LLUUID &uuid)
+ {
+ mName[0] = 0;
+ mDensity = 1000.f; // default to 1000.0 (water)
+ mHPModifier = 1.f;
+ mDamageModifier = 1.f;
+ mEPModifier = 1.f;
+
+ mMCode = mcode;
+ if (name)
+ {
+ LLString::copy(mName,name,LLMATERIAL_INFO_NAME_LENGTH);
+ }
+ mDefaultTextureID = uuid;
+ };
+
+ ~LLMaterialInfo()
+ {
+ };
+
+};
+
+class LLMaterialTable
+{
+public:
+ LLLinkedList<LLMaterialInfo> mMaterialInfoList;
+ LLUUID *mCollisionSoundMatrix;
+ LLUUID *mSlidingSoundMatrix;
+ LLUUID *mRollingSoundMatrix;
+
+ static const F32 DEFAULT_FRICTION;
+ static const F32 DEFAULT_RESTITUTION;
+
+public:
+ LLMaterialTable();
+ LLMaterialTable(U8); // cheat with an overloaded constructor to build our basic table
+ ~LLMaterialTable();
+
+ void initBasicTable();
+
+ BOOL add(U8 mcode, char* name, const LLUUID &uuid);
+ BOOL addCollisionSound(U8 mcode, U8 mcode2, const LLUUID &uuid);
+ BOOL addSlidingSound(U8 mcode, U8 mcode2, const LLUUID &uuid);
+ BOOL addRollingSound(U8 mcode, U8 mcode2, const LLUUID &uuid);
+ BOOL addShatterSound(U8 mcode, const LLUUID &uuid);
+ BOOL addDensity(U8 mcode, const F32 &density);
+ BOOL addFriction(U8 mcode, const F32 &friction);
+ BOOL addRestitution(U8 mcode, const F32 &restitution);
+ BOOL addDamageAndEnergy(U8 mcode, const F32 &hp_mod, const F32 &damage_mod, const F32 &ep_mod);
+
+ LLUUID getDefaultTextureID(char* name); // LLUUID::null if not found
+ LLUUID getDefaultTextureID(U8 mcode); // LLUUID::null if not found
+ U8 getMCode(const char* name); // 0 if not found
+ char* getName(U8 mcode);
+
+ F32 getDensity(U8 mcode); // kg/m^3, 0 if not found
+ F32 getFriction(U8 mcode); // havok values
+ F32 getRestitution(U8 mcode); // havok values
+ F32 getHPMod(U8 mcode);
+ F32 getDamageMod(U8 mcode);
+ F32 getEPMod(U8 mcode);
+
+ LLUUID getCollisionSoundUUID(U8 mcode, U8 mcode2);
+ LLUUID getSlidingSoundUUID(U8 mcode, U8 mcode2);
+ LLUUID getRollingSoundUUID(U8 mcode, U8 mcode2);
+ LLUUID getShatterSoundUUID(U8 mcode); // LLUUID::null if not found
+
+ LLUUID getGroundCollisionSoundUUID(U8 mcode);
+ LLUUID getGroundSlidingSoundUUID(U8 mcode);
+ LLUUID getGroundRollingSoundUUID(U8 mcode);
+ LLUUID getCollisionParticleUUID(U8 mcode, U8 mcode2);
+ LLUUID getGroundCollisionParticleUUID(U8 mcode);
+
+ static LLMaterialTable basic;
+};
+
+#endif
+
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;
+}
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
new file mode 100644
index 0000000000..3ad96bf6e1
--- /dev/null
+++ b/indra/llprimitive/llprimitive.h
@@ -0,0 +1,510 @@
+/**
+ * @file llprimitive.h
+ * @brief LLPrimitive base class
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLPRIMITIVE_H
+#define LL_LLPRIMITIVE_H
+
+#include "lluuid.h"
+#include "v3math.h"
+#include "xform.h"
+#include "message.h"
+#include "llmemory.h"
+#include "llvolume.h"
+#include "lltextureentry.h"
+
+// Moved to stdtypes.h --JC
+// typedef U8 LLPCode;
+class LLMessageSystem;
+class LLVolumeParams;
+class LLColor4;
+class LLColor3;
+class LLTextureEntry;
+class LLDataPacker;
+
+enum LLGeomType // NOTE: same vals as GL Ids
+{
+ LLInvalid = 0,
+ LLLineLoop = 2,
+ LLLineStrip = 3,
+ LLTriangles = 4,
+ LLTriStrip = 5,
+ LLTriFan = 6,
+ LLQuads = 7,
+ LLQuadStrip = 8
+};
+
+class LLVolume;
+
+/**
+ * exported constants
+ */
+extern const F32 OBJECT_CUT_MIN;
+extern const F32 OBJECT_CUT_MAX;
+extern const F32 OBJECT_CUT_INC;
+extern const F32 OBJECT_MIN_CUT_INC;
+extern const F32 OBJECT_ROTATION_PRECISION;
+
+extern const F32 OBJECT_TWIST_MIN;
+extern const F32 OBJECT_TWIST_MAX;
+extern const F32 OBJECT_TWIST_INC;
+
+// This is used for linear paths,
+// since twist is used in a slightly different manner.
+extern const F32 OBJECT_TWIST_LINEAR_MIN;
+extern const F32 OBJECT_TWIST_LINEAR_MAX;
+extern const F32 OBJECT_TWIST_LINEAR_INC;
+
+extern const F32 OBJECT_MIN_HOLE_SIZE;
+extern const F32 OBJECT_MAX_HOLE_SIZE_X;
+extern const F32 OBJECT_MAX_HOLE_SIZE_Y;
+
+// Revolutions parameters.
+extern const F32 OBJECT_REV_MIN;
+extern const F32 OBJECT_REV_MAX;
+extern const F32 OBJECT_REV_INC;
+
+
+//============================================================================
+
+// TomY: Base class for things that pack & unpack themselves
+class LLNetworkData
+{
+public:
+ // Extra parameter IDs
+ enum
+ {
+ PARAMS_FLEXIBLE = 0x10,
+ PARAMS_LIGHT = 0x20
+ };
+
+public:
+ U16 mType;
+ virtual ~LLNetworkData() {};
+ virtual BOOL pack(LLDataPacker &dp) const = 0;
+ virtual BOOL unpack(LLDataPacker &dp) = 0;
+ virtual bool operator==(const LLNetworkData& data) const = 0;
+ virtual void copy(const LLNetworkData& data) = 0;
+};
+
+extern const F32 LIGHT_MIN_RADIUS;
+extern const F32 LIGHT_DEFAULT_RADIUS;
+extern const F32 LIGHT_MAX_RADIUS;
+extern const F32 LIGHT_MIN_FALLOFF;
+extern const F32 LIGHT_DEFAULT_FALLOFF;
+extern const F32 LIGHT_MAX_FALLOFF;
+extern const F32 LIGHT_MIN_CUTOFF;
+extern const F32 LIGHT_DEFAULT_CUTOFF;
+extern const F32 LIGHT_MAX_CUTOFF;
+
+class LLLightParams : public LLNetworkData
+{
+protected:
+ LLColor4 mColor; // alpha = intensity
+ F32 mRadius;
+ F32 mFalloff;
+ F32 mCutoff;
+
+public:
+ LLLightParams();
+ /*virtual*/ BOOL pack(LLDataPacker &dp) const;
+ /*virtual*/ BOOL unpack(LLDataPacker &dp);
+ /*virtual*/ bool operator==(const LLNetworkData& data) const;
+ /*virtual*/ void copy(const LLNetworkData& data);
+
+ void setColor(const LLColor4& color) { mColor = color; mColor.clamp(); }
+ void setRadius(F32 radius) { mRadius = llclamp(radius, LIGHT_MIN_RADIUS, LIGHT_MAX_RADIUS); }
+ void setFalloff(F32 falloff) { mFalloff = llclamp(falloff, LIGHT_MIN_FALLOFF, LIGHT_MAX_FALLOFF); }
+ void setCutoff(F32 cutoff) { mCutoff = llclamp(cutoff, LIGHT_MIN_CUTOFF, LIGHT_MAX_CUTOFF); }
+
+ LLColor4 getColor() const { return mColor; }
+ F32 getRadius() const { return mRadius; }
+ F32 getFalloff() const { return mFalloff; }
+ F32 getCutoff() const { return mCutoff; }
+};
+
+//-------------------------------------------------
+// This structure is also used in the part of the
+// code that creates new flexible objects.
+//-------------------------------------------------
+
+// These were made into enums so that they could be used as fixed size
+// array bounds.
+enum EFlexibleObjectConst
+{
+ // "Softness" => [0,3], increments of 1
+ // Represents powers of 2: 0 -> 1, 3 -> 8
+ FLEXIBLE_OBJECT_MIN_SECTIONS = 0,
+ FLEXIBLE_OBJECT_DEFAULT_NUM_SECTIONS = 2,
+ FLEXIBLE_OBJECT_MAX_SECTIONS = 3
+};
+
+// "Tension" => [0,10], increments of 0.1
+extern const F32 FLEXIBLE_OBJECT_MIN_TENSION;
+extern const F32 FLEXIBLE_OBJECT_DEFAULT_TENSION;
+extern const F32 FLEXIBLE_OBJECT_MAX_TENSION;
+
+// "Drag" => [0,10], increments of 0.1
+extern const F32 FLEXIBLE_OBJECT_MIN_AIR_FRICTION;
+extern const F32 FLEXIBLE_OBJECT_DEFAULT_AIR_FRICTION;
+extern const F32 FLEXIBLE_OBJECT_MAX_AIR_FRICTION;
+
+// "Gravity" = [-10,10], increments of 0.1
+extern const F32 FLEXIBLE_OBJECT_MIN_GRAVITY;
+extern const F32 FLEXIBLE_OBJECT_DEFAULT_GRAVITY;
+extern const F32 FLEXIBLE_OBJECT_MAX_GRAVITY;
+
+// "Wind" = [0,10], increments of 0.1
+extern const F32 FLEXIBLE_OBJECT_MIN_WIND_SENSITIVITY;
+extern const F32 FLEXIBLE_OBJECT_DEFAULT_WIND_SENSITIVITY;
+extern const F32 FLEXIBLE_OBJECT_MAX_WIND_SENSITIVITY;
+
+extern const F32 FLEXIBLE_OBJECT_MAX_INTERNAL_TENSION_FORCE;
+
+extern const F32 FLEXIBLE_OBJECT_DEFAULT_LENGTH;
+extern const BOOL FLEXIBLE_OBJECT_DEFAULT_USING_COLLISION_SPHERE;
+extern const BOOL FLEXIBLE_OBJECT_DEFAULT_RENDERING_COLLISION_SPHERE;
+
+
+class LLFlexibleObjectData : public LLNetworkData
+{
+protected:
+ S32 mSimulateLOD; // 2^n = number of simulated sections
+ F32 mGravity;
+ F32 mAirFriction; // higher is more stable, but too much looks like it's underwater
+ F32 mWindSensitivity; // interacts with tension, air friction, and gravity
+ F32 mTension; //interacts in complex ways with other parameters
+ LLVector3 mUserForce; // custom user-defined force vector
+ //BOOL mUsingCollisionSphere;
+ //BOOL mRenderingCollisionSphere;
+
+public:
+ void setSimulateLOD(S32 lod) { mSimulateLOD = llclamp(lod, (S32)FLEXIBLE_OBJECT_MIN_SECTIONS, (S32)FLEXIBLE_OBJECT_MAX_SECTIONS); }
+ void setGravity(F32 gravity) { mGravity = llclamp(gravity, FLEXIBLE_OBJECT_MIN_GRAVITY, FLEXIBLE_OBJECT_MAX_GRAVITY); }
+ void setAirFriction(F32 friction) { mAirFriction = llclamp(friction, FLEXIBLE_OBJECT_MIN_AIR_FRICTION, FLEXIBLE_OBJECT_MAX_AIR_FRICTION); }
+ void setWindSensitivity(F32 wind) { mWindSensitivity = llclamp(wind, FLEXIBLE_OBJECT_MIN_WIND_SENSITIVITY, FLEXIBLE_OBJECT_MAX_WIND_SENSITIVITY); }
+ void setTension(F32 tension) { mTension = llclamp(tension, FLEXIBLE_OBJECT_MIN_TENSION, FLEXIBLE_OBJECT_MAX_TENSION); }
+ void setUserForce(LLVector3 &force) { mUserForce = force; }
+
+ S32 getSimulateLOD() const { return mSimulateLOD; }
+ F32 getGravity() const { return mGravity; }
+ F32 getAirFriction() const { return mAirFriction; }
+ F32 getWindSensitivity() const { return mWindSensitivity; }
+ F32 getTension() const { return mTension; }
+ LLVector3 getUserForce() const { return mUserForce; }
+
+ //------ the constructor for the structure ------------
+ LLFlexibleObjectData();
+ BOOL pack(LLDataPacker &dp) const;
+ BOOL unpack(LLDataPacker &dp);
+ bool operator==(const LLNetworkData& data) const;
+ void copy(const LLNetworkData& data);
+};// end of attributes structure
+
+class LLPrimitive : public LLXform
+{
+public:
+ LLPrimitive();
+ virtual ~LLPrimitive();
+
+ static LLPrimitive *createPrimitive(LLPCode p_code);
+ void init(LLPCode p_code);
+
+ void setPCode(const LLPCode pcode);
+ const LLVolume *getVolumeConst() const { return mVolumep; } // HACK for Windoze confusion about ostream operator in LLVolume
+ LLVolume *getVolume() const { return mVolumep; }
+ virtual BOOL setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false);
+
+ // Modify texture entry properties
+ inline BOOL validTE(const U8 te_num) const;
+ const LLTextureEntry *getTE(const U8 te_num) const;
+
+ virtual void setNumTEs(const U8 num_tes);
+ virtual void setAllTETextures(const LLUUID &tex_id);
+ virtual void setTE(const U8 index, const LLTextureEntry &te);
+ virtual S32 setTEColor(const U8 te, const LLColor4 &color);
+ virtual S32 setTEColor(const U8 te, const LLColor3 &color);
+ virtual S32 setTEAlpha(const U8 te, const F32 alpha);
+ virtual S32 setTETexture(const U8 te, const LLUUID &tex_id);
+ virtual S32 setTEScale (const U8 te, const F32 s, const F32 t);
+ virtual S32 setTEScaleS(const U8 te, const F32 s);
+ virtual S32 setTEScaleT(const U8 te, const F32 t);
+ virtual S32 setTEOffset (const U8 te, const F32 s, const F32 t);
+ virtual S32 setTEOffsetS(const U8 te, const F32 s);
+ virtual S32 setTEOffsetT(const U8 te, const F32 t);
+ virtual S32 setTERotation(const U8 te, const F32 r);
+ virtual S32 setTEBumpShinyFullbright(const U8 te, const U8 bump);
+ virtual S32 setTEBumpShiny(const U8 te, const U8 bump);
+ virtual S32 setTEMediaTexGen(const U8 te, const U8 media);
+ virtual S32 setTEBumpmap(const U8 te, const U8 bump);
+ virtual S32 setTETexGen(const U8 te, const U8 texgen);
+ virtual S32 setTEShiny(const U8 te, const U8 shiny);
+ virtual S32 setTEFullbright(const U8 te, const U8 fullbright);
+ virtual S32 setTEMediaFlags(const U8 te, const U8 flags);
+ virtual BOOL setMaterial(const U8 material); // returns TRUE if material changed
+
+ void setTEArrays(const U8 size,
+ const LLUUID* image_ids,
+ const F32* scale_s,
+ const F32* scale_t);
+ void copyTEs(const LLPrimitive *primitive);
+ S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const;
+ S32 unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type);
+ BOOL packTEMessage(LLMessageSystem *mesgsys) const;
+ BOOL packTEMessage(LLDataPacker &dp) const;
+ S32 unpackTEMessage(LLMessageSystem *mesgsys, char *block_name);
+ S32 unpackTEMessage(LLMessageSystem *mesgsys, char *block_name, const S32 block_num); // Variable num of blocks
+ BOOL unpackTEMessage(LLDataPacker &dp);
+
+#ifdef CHECK_FOR_FINITE
+ inline void setPosition(const LLVector3& pos);
+ inline void setPosition(const F32 x, const F32 y, const F32 z);
+ inline void addPosition(const LLVector3& pos);
+
+ inline void setAngularVelocity(const LLVector3& avel);
+ inline void setAngularVelocity(const F32 x, const F32 y, const F32 z);
+ inline void setVelocity(const LLVector3& vel);
+ inline void setVelocity(const F32 x, const F32 y, const F32 z);
+ inline void setVelocityX(const F32 x);
+ inline void setVelocityY(const F32 y);
+ inline void setVelocityZ(const F32 z);
+ inline void addVelocity(const LLVector3& vel);
+ inline void setAcceleration(const LLVector3& accel);
+ inline void setAcceleration(const F32 x, const F32 y, const F32 z);
+#else
+ // Don't override the base LLXForm operators.
+ // Special case for setPosition. If not check-for-finite, fall through to LLXform method.
+ // void setPosition(F32 x, F32 y, F32 z)
+ // void setPosition(LLVector3)
+
+ void setAngularVelocity(const LLVector3& avel) { mAngularVelocity = avel; }
+ void setAngularVelocity(const F32 x, const F32 y, const F32 z) { mAngularVelocity.setVec(x,y,z); }
+ void setVelocity(const LLVector3& vel) { mVelocity = vel; }
+ void setVelocity(const F32 x, const F32 y, const F32 z) { mVelocity.setVec(x,y,z); }
+ void setVelocityX(const F32 x) { mVelocity.mV[VX] = x; }
+ void setVelocityY(const F32 y) { mVelocity.mV[VY] = y; }
+ void setVelocityZ(const F32 z) { mVelocity.mV[VZ] = z; }
+ void addVelocity(const LLVector3& vel) { mVelocity += vel; }
+ void setAcceleration(const LLVector3& accel) { mAcceleration = accel; }
+ void setAcceleration(const F32 x, const F32 y, const F32 z) { mAcceleration.setVec(x,y,z); }
+#endif
+
+ const LLPCode getPCode() const { return mPrimitiveCode; }
+ const char * getPCodeString() const { return pCodeToString(mPrimitiveCode); }
+ const LLVector3& getAngularVelocity() const { return mAngularVelocity; }
+ const LLVector3& getVelocity() const { return mVelocity; }
+ const LLVector3& getAcceleration() const { return mAcceleration; }
+ const U8 getNumTEs() const { return mNumTEs; }
+
+ const U8 getMaterial() const { return mMaterial; }
+
+ void setVolumeType(const U8 code);
+ U8 getVolumeType();
+
+ void setTextureList(LLTextureEntry *listp);
+
+ inline BOOL isAvatar() const;
+
+ static const char *pCodeToString(const LLPCode pcode);
+ static LLPCode legacyToPCode(const U8 legacy);
+ static U8 pCodeToLegacy(const LLPCode pcode);
+
+ inline static BOOL isPrimitive(const LLPCode pcode);
+ inline static BOOL isApp(const LLPCode pcode);
+
+protected:
+ LLPCode mPrimitiveCode; // Primitive code
+ LLVector3 mVelocity; // how fast are we moving?
+ LLVector3 mAcceleration; // are we under constant acceleration?
+ LLVector3 mAngularVelocity; // angular velocity
+ LLPointer<LLVolume> mVolumep;
+ LLTextureEntry *mTextureList; // list of texture GUIDs, scales, offsets
+ U8 mMaterial; // Material code
+ U8 mNumTEs; // # of faces on the primitve
+};
+
+inline BOOL LLPrimitive::isAvatar() const
+{
+ return mPrimitiveCode == LL_PCODE_LEGACY_AVATAR;
+}
+
+// static
+inline BOOL LLPrimitive::isPrimitive(const LLPCode pcode)
+{
+ LLPCode base_type = pcode & LL_PCODE_BASE_MASK;
+
+ if (base_type && (base_type < LL_PCODE_APP))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// static
+inline BOOL LLPrimitive::isApp(const LLPCode pcode)
+{
+ LLPCode base_type = pcode & LL_PCODE_BASE_MASK;
+
+ return (base_type == LL_PCODE_APP);
+}
+
+
+#ifdef CHECK_FOR_FINITE
+// Special case for setPosition. If not check-for-finite, fall through to LLXform method.
+void LLPrimitive::setPosition(const F32 x, const F32 y, const F32 z)
+{
+ if (llfinite(x) && llfinite(y) && llfinite(z))
+ {
+ LLXform::setPosition(x, y, z);
+ }
+ else
+ {
+ llerrs << "Non Finite in LLPrimitive::setPosition(x,y,z) for " << pCodeToString(mPrimitiveCode) << llendl;
+ }
+}
+
+// Special case for setPosition. If not check-for-finite, fall through to LLXform method.
+void LLPrimitive::setPosition(const LLVector3& pos)
+{
+ if (pos.isFinite())
+ {
+ LLXform::setPosition(pos);
+ }
+ else
+ {
+ llerrs << "Non Finite in LLPrimitive::setPosition(LLVector3) for " << pCodeToString(mPrimitiveCode) << llendl;
+ }
+}
+
+void LLPrimitive::setAngularVelocity(const LLVector3& avel)
+{
+ if (avel.isFinite())
+ {
+ mAngularVelocity = avel;
+ }
+ else
+ {
+ llerror("Non Finite in LLPrimitive::setAngularVelocity", 0);
+ }
+}
+
+void LLPrimitive::setAngularVelocity(const F32 x, const F32 y, const F32 z)
+{
+ if (llfinite(x) && llfinite(y) && llfinite(z))
+ {
+ mAngularVelocity.setVec(x,y,z);
+ }
+ else
+ {
+ llerror("Non Finite in LLPrimitive::setAngularVelocity", 0);
+ }
+}
+
+void LLPrimitive::setVelocity(const LLVector3& vel)
+{
+ if (vel.isFinite())
+ {
+ mVelocity = vel;
+ }
+ else
+ {
+ llerrs << "Non Finite in LLPrimitive::setVelocity(LLVector3) for " << pCodeToString(mPrimitiveCode) << llendl;
+ }
+}
+
+void LLPrimitive::setVelocity(const F32 x, const F32 y, const F32 z)
+{
+ if (llfinite(x) && llfinite(y) && llfinite(z))
+ {
+ mVelocity.setVec(x,y,z);
+ }
+ else
+ {
+ llerrs << "Non Finite in LLPrimitive::setVelocity(F32,F32,F32) for " << pCodeToString(mPrimitiveCode) << llendl;
+ }
+}
+
+void LLPrimitive::setVelocityX(const F32 x)
+{
+ if (llfinite(x))
+ {
+ mVelocity.mV[VX] = x;
+ }
+ else
+ {
+ llerror("Non Finite in LLPrimitive::setVelocityX", 0);
+ }
+}
+
+void LLPrimitive::setVelocityY(const F32 y)
+{
+ if (llfinite(y))
+ {
+ mVelocity.mV[VY] = y;
+ }
+ else
+ {
+ llerror("Non Finite in LLPrimitive::setVelocityY", 0);
+ }
+}
+
+void LLPrimitive::setVelocityZ(const F32 z)
+{
+ if (llfinite(z))
+ {
+ mVelocity.mV[VZ] = z;
+ }
+ else
+ {
+ llerror("Non Finite in LLPrimitive::setVelocityZ", 0);
+ }
+}
+
+void LLPrimitive::addVelocity(const LLVector3& vel)
+{
+ if (vel.isFinite())
+ {
+ mVelocity += vel;
+ }
+ else
+ {
+ llerror("Non Finite in LLPrimitive::addVelocity", 0);
+ }
+}
+
+void LLPrimitive::setAcceleration(const LLVector3& accel)
+{
+ if (accel.isFinite())
+ {
+ mAcceleration = accel;
+ }
+ else
+ {
+ llerrs << "Non Finite in LLPrimitive::setAcceleration(LLVector3) for " << pCodeToString(mPrimitiveCode) << llendl;
+ }
+}
+
+void LLPrimitive::setAcceleration(const F32 x, const F32 y, const F32 z)
+{
+ if (llfinite(x) && llfinite(y) && llfinite(z))
+ {
+ mAcceleration.setVec(x,y,z);
+ }
+ else
+ {
+ llerrs << "Non Finite in LLPrimitive::setAcceleration(F32,F32,F32) for " << pCodeToString(mPrimitiveCode) << llendl;
+ }
+}
+#endif // CHECK_FOR_FINITE
+
+inline BOOL LLPrimitive::validTE(const U8 te_num) const
+{
+ return (mNumTEs && te_num < mNumTEs);
+}
+
+#endif
+
diff --git a/indra/llprimitive/lltextureanim.cpp b/indra/llprimitive/lltextureanim.cpp
new file mode 100644
index 0000000000..3e2c80e782
--- /dev/null
+++ b/indra/llprimitive/lltextureanim.cpp
@@ -0,0 +1,221 @@
+/**
+ * @file lltextureanim.cpp
+ * @brief LLTextureAnim base class
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "lltextureanim.h"
+#include "message.h"
+#include "lldatapacker.h"
+
+const S32 TA_BLOCK_SIZE = 16;
+
+LLTextureAnim::LLTextureAnim()
+{
+ reset();
+}
+
+
+LLTextureAnim::~LLTextureAnim()
+{
+}
+
+
+void LLTextureAnim::reset()
+{
+ mMode = 0;
+ mFace = -1;
+ mSizeX = 4;
+ mSizeY = 4;
+ mStart = 0.f;
+ mLength = 0.f;
+ mRate = 1.f;
+}
+
+BOOL LLTextureAnim::equals(const LLTextureAnim &other) const
+{
+ if (mMode != other.mMode)
+ {
+ return FALSE;
+ }
+ if (mFace != other.mFace)
+ {
+ return FALSE;
+ }
+ if (mSizeX != other.mSizeX)
+ {
+ return FALSE;
+ }
+ if (mSizeY != other.mSizeY)
+ {
+ return FALSE;
+ }
+ if (mStart != other.mStart)
+ {
+ return FALSE;
+ }
+ if (mLength != other.mLength)
+ {
+ return FALSE;
+ }
+ if (mRate != other.mRate)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+void LLTextureAnim::packTAMessage(LLMessageSystem *mesgsys) const
+{
+ U8 data[TA_BLOCK_SIZE];
+ data[0] = mMode;
+ data[1] = mFace;
+ data[2] = mSizeX;
+ data[3] = mSizeY;
+ htonmemcpy(data + 4, &mStart, MVT_F32, sizeof(F32));
+ htonmemcpy(data + 8, &mLength, MVT_F32, sizeof(F32));
+ htonmemcpy(data + 12, &mRate, MVT_F32, sizeof(F32));
+
+ mesgsys->addBinaryDataFast(_PREHASH_TextureAnim, data, TA_BLOCK_SIZE);
+}
+
+
+void LLTextureAnim::packTAMessage(LLDataPacker &dp) const
+{
+ U8 data[TA_BLOCK_SIZE];
+ data[0] = mMode;
+ data[1] = mFace;
+ data[2] = mSizeX;
+ data[3] = mSizeY;
+ htonmemcpy(data + 4, &mStart, MVT_F32, sizeof(F32));
+ htonmemcpy(data + 8, &mLength, MVT_F32, sizeof(F32));
+ htonmemcpy(data + 12, &mRate, MVT_F32, sizeof(F32));
+
+ dp.packBinaryData(data, TA_BLOCK_SIZE, "TextureAnimation");
+}
+
+
+void LLTextureAnim::unpackTAMessage(LLMessageSystem *mesgsys, const S32 block_num)
+{
+ S32 size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureAnim);
+
+ if (size != TA_BLOCK_SIZE)
+ {
+ if (size)
+ {
+ llwarns << "Bad size " << size << " for TA block, ignoring." << llendl;
+ }
+ mMode = 0;
+ return;
+ }
+
+ U8 data[TA_BLOCK_SIZE];
+ mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureAnim, data, TA_BLOCK_SIZE, block_num);
+
+ mMode = data[0];
+ mFace = data[1];
+ if (mMode & LLTextureAnim::SMOOTH)
+ {
+ mSizeX = llmax((U8)0, data[2]);
+ mSizeY = llmax((U8)0, data[3]);
+ }
+ else
+ {
+ mSizeX = llmax((U8)1, data[2]);
+ mSizeY = llmax((U8)1, data[3]);
+ }
+ htonmemcpy(&mStart, data + 4, MVT_F32, sizeof(F32));
+ htonmemcpy(&mLength, data + 8, MVT_F32, sizeof(F32));
+ htonmemcpy(&mRate, data + 12, MVT_F32, sizeof(F32));
+}
+
+void LLTextureAnim::unpackTAMessage(LLDataPacker &dp)
+{
+ S32 size;
+ U8 data[TA_BLOCK_SIZE];
+ dp.unpackBinaryData(data, size, "TextureAnimation");
+ if (size != TA_BLOCK_SIZE)
+ {
+ if (size)
+ {
+ llwarns << "Bad size " << size << " for TA block, ignoring." << llendl;
+ }
+ mMode = 0;
+ return;
+ }
+
+ mMode = data[0];
+ mFace = data[1];
+ mSizeX = llmax((U8)1, data[2]);
+ mSizeY = llmax((U8)1, data[3]);
+ htonmemcpy(&mStart, data + 4, MVT_F32, sizeof(F32));
+ htonmemcpy(&mLength, data + 8, MVT_F32, sizeof(F32));
+ htonmemcpy(&mRate, data + 12, MVT_F32, sizeof(F32));
+}
+
+LLSD LLTextureAnim::asLLSD() const
+{
+ LLSD sd;
+ sd["mode"] = mMode;
+ sd["face"] = mFace;
+ sd["sizeX"] = mSizeX;
+ sd["sizeY"] = mSizeY;
+ sd["start"] = mStart;
+ sd["length"] = mLength;
+ sd["rate"] = mRate;
+ return sd;
+}
+
+bool LLTextureAnim::fromLLSD(LLSD& sd)
+{
+ const char *w;
+ w = "mode";
+ if (sd.has(w))
+ {
+ mMode = (U8)sd[w].asInteger();
+ } else goto fail;
+
+ w = "face";
+ if (sd.has(w))
+ {
+ mFace = (S8)sd[w].asInteger();
+ } else goto fail;
+
+ w = "sizeX";
+ if (sd.has(w))
+ {
+ mSizeX = (U8)sd[w].asInteger();
+ } else goto fail;
+
+ w = "sizeY";
+ if (sd.has(w))
+ {
+ mSizeY = (U8)sd[w].asInteger();
+ } else goto fail;
+
+ w = "start";
+ if (sd.has(w))
+ {
+ mStart = (F32)sd[w].asReal();
+ } else goto fail;
+
+ w = "length";
+ if (sd.has(w))
+ {
+ mLength = (F32)sd[w].asReal();
+ } else goto fail;
+
+ w = "rate";
+ if (sd.has(w))
+ {
+ mRate = (F32)sd[w].asReal();
+ } else goto fail;
+
+ return true;
+fail:
+ return false;
+}
diff --git a/indra/llprimitive/lltextureanim.h b/indra/llprimitive/lltextureanim.h
new file mode 100644
index 0000000000..db15642563
--- /dev/null
+++ b/indra/llprimitive/lltextureanim.h
@@ -0,0 +1,54 @@
+/**
+ * @file lltextureanim.h
+ * @brief LLTextureAnim base class
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLTEXTUREANIM_H
+#define LL_LLTEXTUREANIM_H
+
+#include "stdtypes.h"
+#include "llsd.h"
+
+class LLMessageSystem;
+class LLDataPacker;
+
+class LLTextureAnim
+{
+public:
+ LLTextureAnim();
+ virtual ~LLTextureAnim();
+
+ virtual void reset();
+ void packTAMessage(LLMessageSystem *mesgsys) const;
+ void packTAMessage(LLDataPacker &dp) const;
+ void unpackTAMessage(LLMessageSystem *mesgsys, const S32 block_num);
+ void unpackTAMessage(LLDataPacker &dp);
+ BOOL equals(const LLTextureAnim &other) const;
+ LLSD asLLSD() const;
+ operator LLSD() const { return asLLSD(); }
+ bool fromLLSD(LLSD& sd);
+
+ enum
+ {
+ ON = 0x01,
+ LOOP = 0x02,
+ REVERSE = 0x04,
+ PING_PONG = 0x08,
+ SMOOTH = 0x10,
+ ROTATE = 0x20,
+ SCALE = 0x40,
+ };
+
+public:
+ U8 mMode;
+ S8 mFace;
+ U8 mSizeX;
+ U8 mSizeY;
+ F32 mStart;
+ F32 mLength;
+ F32 mRate; // Rate in frames per second.
+};
+#endif
diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp
new file mode 100644
index 0000000000..86952dfdb5
--- /dev/null
+++ b/indra/llprimitive/lltextureentry.cpp
@@ -0,0 +1,348 @@
+/**
+ * @file lltextureentry.cpp
+ * @brief LLTextureEntry base class
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "lltextureentry.h"
+#include "llsdutil.h"
+
+const U8 DEFAULT_BUMP_CODE = 0; // no bump or shininess
+
+const LLTextureEntry LLTextureEntry::null;
+
+//===============================================================
+LLTextureEntry::LLTextureEntry()
+{
+ init(LLUUID::null,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);
+}
+
+LLTextureEntry::LLTextureEntry(const LLUUID& tex_id)
+{
+ init(tex_id,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);
+}
+
+LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs)
+{
+ mID = rhs.mID;
+ mScaleS = rhs.mScaleS;
+ mScaleT = rhs.mScaleT;
+ mOffsetS = rhs.mOffsetS;
+ mOffsetT = rhs.mOffsetT;
+ mRotation = rhs.mRotation;
+ mColor = rhs.mColor;
+ mBump = rhs.mBump;
+ mMediaFlags = rhs.mMediaFlags;
+}
+
+LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs)
+{
+ if (this != &rhs)
+ {
+ mID = rhs.mID;
+ mScaleS = rhs.mScaleS;
+ mScaleT = rhs.mScaleT;
+ mOffsetS = rhs.mOffsetS;
+ mOffsetT = rhs.mOffsetT;
+ mRotation = rhs.mRotation;
+ mColor = rhs.mColor;
+ mBump = rhs.mBump;
+ mMediaFlags = rhs.mMediaFlags;
+ }
+
+ return *this;
+}
+
+void LLTextureEntry::init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 offset_s, F32 offset_t, F32 rotation, U8 bump)
+{
+ setID(tex_id);
+
+ mScaleS = scale_s;
+ mScaleT = scale_t;
+ mOffsetS = offset_s;
+ mOffsetT = offset_t;
+ mRotation = rotation;
+ mBump = bump;
+ mMediaFlags = 0x0;
+
+ setColor(LLColor4(1.f, 1.f, 1.f, 1.f));
+}
+
+LLTextureEntry::~LLTextureEntry()
+{
+}
+
+bool LLTextureEntry::operator!=(const LLTextureEntry &rhs) const
+{
+ if (mID != rhs.mID) return(true);
+ if (mScaleS != rhs.mScaleS) return(true);
+ if (mScaleT != rhs.mScaleT) return(true);
+ if (mOffsetS != rhs.mOffsetS) return(true);
+ if (mOffsetT != rhs.mOffsetT) return(true);
+ if (mRotation != rhs.mRotation) return(true);
+ if (mColor != rhs.mColor) return (true);
+ if (mBump != rhs.mBump) return (true);
+ if (mMediaFlags != rhs.mMediaFlags) return true;
+ return(false);
+}
+
+bool LLTextureEntry::operator==(const LLTextureEntry &rhs) const
+{
+ if (mID != rhs.mID) return(false);
+ if (mScaleS != rhs.mScaleS) return(false);
+ if (mScaleT != rhs.mScaleT) return(false);
+ if (mOffsetS != rhs.mOffsetS) return(false);
+ if (mOffsetT != rhs.mOffsetT) return(false);
+ if (mRotation != rhs.mRotation) return(false);
+ if (mColor != rhs.mColor) return (false);
+ if (mBump != rhs.mBump) return (false);
+ if (mMediaFlags != rhs.mMediaFlags) return false;
+ return(true);
+}
+
+LLSD LLTextureEntry::asLLSD() const
+{
+ LLSD sd;
+
+ sd["imageid"] = getID();
+ sd["colors"] = ll_sd_from_color4(getColor());
+ sd["scales"] = mScaleS;
+ sd["scalet"] = mScaleT;
+ sd["offsets"] = mOffsetS;
+ sd["offsett"] = mOffsetT;
+ sd["imagerot"] = getRotation();
+ sd["bump"] = getBumpShiny();
+ sd["fullbright"] = getFullbright();
+ sd["media_flags"] = getMediaTexGen();
+
+ return sd;
+}
+
+bool LLTextureEntry::fromLLSD(LLSD& sd)
+{
+ const char *w, *x;
+ w = "imageid";
+ if (sd.has(w))
+ {
+ setID( sd[w] );
+ } else goto fail;
+ w = "colors";
+ if (sd.has(w))
+ {
+ setColor( ll_color4_from_sd(sd["colors"]) );
+ } else goto fail;
+ w = "scales";
+ x = "scalet";
+ if (sd.has(w) && sd.has(x))
+ {
+ setScale( (F32)sd[w].asReal(), (F32)sd[x].asReal() );
+ } else goto fail;
+ w = "offsets";
+ x = "offsett";
+ if (sd.has(w) && sd.has(x))
+ {
+ setOffset( (F32)sd[w].asReal(), (F32)sd[x].asReal() );
+ } else goto fail;
+ w = "imagerot";
+ if (sd.has(w))
+ {
+ setRotation( (F32)sd[w].asReal() );
+ } else goto fail;
+ w = "bump";
+ if (sd.has(w))
+ {
+ setBumpShiny( sd[w].asInteger() );
+ } else goto fail;
+ w = "fullbright";
+ if (sd.has(w))
+ {
+ setFullbright( sd[w].asInteger() );
+ } else goto fail;
+ w = "media_flags";
+ if (sd.has(w))
+ {
+ setMediaTexGen( sd[w].asInteger() );
+ } else goto fail;
+
+ return true;
+fail:
+ return false;
+}
+
+S32 LLTextureEntry::setID(const LLUUID &tex_id)
+{
+ if (mID != tex_id)
+ {
+ mID = tex_id;
+ return TEM_CHANGE_TEXTURE;
+ }
+ return 0;
+}
+
+S32 LLTextureEntry::setScale(F32 s, F32 t)
+{
+ S32 retval = 0;
+
+ if ( (mScaleS != s)
+ ||(mScaleT != t))
+ {
+ mScaleS = s;
+ mScaleT = t;
+
+ retval = TEM_CHANGE_TEXTURE;
+ }
+ return retval;
+}
+
+S32 LLTextureEntry::setColor(const LLColor4 &color)
+{
+ if (mColor != color)
+ {
+ mColor = color;
+ return TEM_CHANGE_COLOR;
+ }
+ return 0;
+}
+
+S32 LLTextureEntry::setColor(const LLColor3 &color)
+{
+ if (mColor != color)
+ {
+ // This preserves alpha.
+ mColor.setVec(color);
+ return TEM_CHANGE_COLOR;
+ }
+ return 0;
+}
+
+S32 LLTextureEntry::setAlpha(const F32 alpha)
+{
+ if (mColor.mV[VW] != alpha)
+ {
+ mColor.mV[VW] = alpha;
+ return TEM_CHANGE_COLOR;
+ }
+ return 0;
+}
+
+S32 LLTextureEntry::setOffset(F32 s, F32 t)
+{
+ S32 retval = 0;
+
+ if ( (mOffsetS != s)
+ ||(mOffsetT != t))
+ {
+ mOffsetS = s;
+ mOffsetT = t;
+
+ retval = TEM_CHANGE_TEXTURE;
+ }
+ return retval;
+}
+
+S32 LLTextureEntry::setRotation(F32 theta)
+{
+ if (mRotation != theta)
+ {
+ mRotation = theta;
+ return TEM_CHANGE_TEXTURE;
+ }
+ return 0;
+}
+
+S32 LLTextureEntry::setBumpShinyFullbright(U8 bump)
+{
+ if (mBump != bump)
+ {
+ mBump = bump;
+ return TEM_CHANGE_TEXTURE;
+ }
+ return 0;
+}
+
+S32 LLTextureEntry::setMediaTexGen(U8 media)
+{
+ if (mMediaFlags != media)
+ {
+ mMediaFlags = media;
+ return TEM_CHANGE_TEXTURE;
+ }
+ return 0;
+}
+
+S32 LLTextureEntry::setBumpmap(U8 bump)
+{
+ bump &= TEM_BUMP_MASK;
+ if (getBumpmap() != bump)
+ {
+ mBump &= ~TEM_BUMP_MASK;
+ mBump |= bump;
+ return TEM_CHANGE_TEXTURE;
+ }
+ return 0;
+}
+
+S32 LLTextureEntry::setFullbright(U8 fullbright)
+{
+ fullbright &= TEM_FULLBRIGHT_MASK;
+ if (getFullbright() != fullbright)
+ {
+ mBump &= ~(TEM_FULLBRIGHT_MASK<<TEM_FULLBRIGHT_SHIFT);
+ mBump |= fullbright << TEM_FULLBRIGHT_SHIFT;
+ return TEM_CHANGE_TEXTURE;
+ }
+ return 0;
+}
+
+S32 LLTextureEntry::setShiny(U8 shiny)
+{
+ shiny &= TEM_SHINY_MASK;
+ if (getShiny() != shiny)
+ {
+ mBump &= ~(TEM_SHINY_MASK<<TEM_SHINY_SHIFT);
+ mBump |= shiny << TEM_SHINY_SHIFT;
+ return TEM_CHANGE_TEXTURE;
+ }
+ return 0;
+}
+
+S32 LLTextureEntry::setBumpShiny(U8 bump_shiny)
+{
+ bump_shiny &= TEM_BUMP_SHINY_MASK;
+ if (getBumpShiny() != bump_shiny)
+ {
+ mBump &= ~TEM_BUMP_SHINY_MASK;
+ mBump |= bump_shiny;
+ return TEM_CHANGE_TEXTURE;
+ }
+ return 0;
+}
+
+S32 LLTextureEntry::setMediaFlags(U8 media_flags)
+{
+ media_flags &= TEM_MEDIA_MASK;
+ if (getMediaFlags() != media_flags)
+ {
+ mMediaFlags &= ~TEM_MEDIA_MASK;
+ mMediaFlags |= media_flags;
+ return TEM_CHANGE_TEXTURE;
+ }
+ return 0;
+}
+
+S32 LLTextureEntry::setTexGen(U8 tex_gen)
+{
+ tex_gen &= TEM_TEX_GEN_MASK;
+ if (getTexGen() != tex_gen)
+ {
+ mMediaFlags &= ~TEM_TEX_GEN_MASK;
+ mMediaFlags |= tex_gen;
+ return TEM_CHANGE_TEXTURE;
+ }
+ return 0;
+}
+
diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h
new file mode 100644
index 0000000000..b9558a159a
--- /dev/null
+++ b/indra/llprimitive/lltextureentry.h
@@ -0,0 +1,126 @@
+/**
+ * @file lltextureentry.h
+ * @brief LLTextureEntry base class
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLTEXTUREENTRY_H
+#define LL_LLTEXTUREENTRY_H
+
+#include "lluuid.h"
+#include "v4color.h"
+#include "llsd.h"
+
+const S32 TEM_CHANGE_COLOR = 0x1;
+const S32 TEM_CHANGE_TEXTURE = 0x2;
+const S32 TEM_INVALID = 0x4;
+
+const S32 TEM_BUMPMAP_COUNT = 32;
+
+// The Bump Shiny Fullbright values are bits in an eight bit field:
+// +----------+
+// | SSFBBBBB | S = Shiny, F = Fullbright, B = Bumpmap
+// | 76543210 |
+// +----------+
+const S32 TEM_BUMP_MASK = 0x1f; // 5 bits
+const S32 TEM_FULLBRIGHT_MASK = 0x01; // 1 bit
+const S32 TEM_SHINY_MASK = 0x03; // 2 bits
+const S32 TEM_BUMP_SHINY_MASK = (0xc0 | 0x1f);
+const S32 TEM_FULLBRIGHT_SHIFT = 5;
+const S32 TEM_SHINY_SHIFT = 6;
+
+// The Media Tex Gen values are bits in a bit field:
+// +----------+
+// | .....TTM | M = Media Flags (web page), T = LLTextureEntry::eTexGen, . = unused
+// | 76543210 |
+// +----------+
+const S32 TEM_MEDIA_MASK = 0x01;
+const S32 TEM_TEX_GEN_MASK = 0x06;
+const S32 TEM_TEX_GEN_SHIFT = 1;
+
+
+class LLTextureEntry
+{
+public:
+
+ typedef enum e_texgen
+ {
+ TEX_GEN_DEFAULT = 0x00,
+ TEX_GEN_PLANAR = 0x02,
+ TEX_GEN_SPHERICAL = 0x04,
+ TEX_GEN_CYLINDRICAL = 0x06
+ } eTexGen;
+
+ LLTextureEntry();
+ LLTextureEntry(const LLUUID& tex_id);
+ LLTextureEntry(const LLTextureEntry &rhs);
+
+ LLTextureEntry &operator=(const LLTextureEntry &rhs);
+ ~LLTextureEntry();
+
+ bool operator==(const LLTextureEntry &rhs) const;
+ bool operator!=(const LLTextureEntry &rhs) const;
+
+ LLSD asLLSD() const;
+ operator LLSD() const { return asLLSD(); }
+ bool fromLLSD(LLSD& sd);
+
+ void init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 offset_s, F32 offset_t, F32 rotation, U8 bump);
+
+ // These return a TEM_ flag from above to indicate if something changed.
+ S32 setID (const LLUUID &tex_id);
+ S32 setColor(const LLColor4 &color);
+ S32 setColor(const LLColor3 &color);
+ S32 setAlpha(const F32 alpha);
+ S32 setScale(F32 s, F32 t);
+ S32 setOffset(F32 s, F32 t);
+ S32 setRotation(F32 theta);
+
+ S32 setBumpmap(U8 bump);
+ S32 setFullbright(U8 bump);
+ S32 setShiny(U8 bump);
+ S32 setBumpShiny(U8 bump);
+ S32 setBumpShinyFullbright(U8 bump);
+
+ S32 setMediaFlags(U8 media_flags);
+ S32 setTexGen(U8 texGen);
+ S32 setMediaTexGen(U8 media);
+
+ const LLUUID &getID() const { return mID; }
+ const LLColor4 &getColor() const { return mColor; }
+ void getScale(F32 *s, F32 *t) const { *s = mScaleS; *t = mScaleT; }
+ void getOffset(F32 *s, F32 *t) const { *s = mOffsetS; *t = mOffsetT; }
+ F32 getRotation() const { return mRotation; }
+ void getRotation(F32 *theta) const { *theta = mRotation; }
+
+ U8 getBumpmap() const { return mBump & TEM_BUMP_MASK; }
+ U8 getFullbright() const { return (mBump>>TEM_FULLBRIGHT_SHIFT) & TEM_FULLBRIGHT_MASK; }
+ U8 getShiny() const { return (mBump>>TEM_SHINY_SHIFT) & TEM_SHINY_MASK; }
+ U8 getBumpShiny() const { return mBump & TEM_BUMP_SHINY_MASK; }
+ U8 getBumpShinyFullbright() const { return mBump; }
+
+ U8 getMediaFlags() const { return mMediaFlags & TEM_MEDIA_MASK; }
+ U8 getTexGen() const { return mMediaFlags & TEM_TEX_GEN_MASK; }
+ U8 getMediaTexGen() const { return mMediaFlags; }
+
+ // Media flags
+ enum { MF_NONE = 0x0, MF_WEB_PAGE = 0x1 };
+
+public:
+ F32 mScaleS; // S, T offset
+ F32 mScaleT; // S, T offset
+ F32 mOffsetS; // S, T offset
+ F32 mOffsetT; // S, T offset
+ F32 mRotation; // anti-clockwise rotation in rad about the bottom left corner
+
+ static const LLTextureEntry null;
+protected:
+ LLUUID mID; // Texture GUID
+ LLColor4 mColor;
+ U8 mBump; // Bump map, shiny, and fullbright
+ U8 mMediaFlags; // replace with web page, movie, etc.
+};
+
+#endif
diff --git a/indra/llprimitive/lltreeparams.cpp b/indra/llprimitive/lltreeparams.cpp
new file mode 100644
index 0000000000..ca3de36630
--- /dev/null
+++ b/indra/llprimitive/lltreeparams.cpp
@@ -0,0 +1,187 @@
+/**
+ * @file lltreeparams.cpp
+ * @brief implementation of the LLTreeParams class.
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+//////////////////////////////////////////////////////////////////////
+
+#include "linden_common.h"
+
+#include "llmath.h"
+
+#include "lltreeparams.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+
+LLTreeParams::LLTreeParams()
+{
+
+// llinfos << "TREE PARAMS INITIALIZED" << llendl;
+ // init to basic something or other...
+ mShape = SR_TEND_FLAME;
+ mLevels = 1;
+ mScale = 15;
+ mScaleV = 0;
+
+ mBaseSize = 0.3f;
+
+ mRatio = 0.015f;
+ mRatioPower = 1.3f;
+
+ mLobes = 0;
+ mLobeDepth = .1f;
+
+ mFlare = 1.2f;
+ mFlarePercentage = 0.1f;
+ mFlareRes = 3;
+
+ //mAttractionUp = .5f;
+
+ mBaseSplits = 0;
+
+ mScale0 = 2.0;
+ mScaleV0 = 0.0;
+
+ // level 0
+
+ // scaling
+ mLength[0] = 1.0f;
+ mLengthV[0] = 0;
+ mTaper[0] = 1.0f;
+
+ // stem splits
+ mSegSplits[0] = 0.15f;
+ mSplitAngle[0] = 15.0f;
+ mSplitAngleV[0] = 10.0f;
+
+ mVertices[0] = 5;
+
+ // curvature
+ mCurveRes[0] = 4;
+ mCurve[0] = 0;
+ mCurveV[0] = 25;
+ mCurveBack[0] = 0;
+
+ // level 1
+
+ // scaling
+ mLength[1] = .3f;
+ mLengthV[1] = 0.05f;
+ mTaper[1] = 1.0f;
+
+ // angle params
+ mDownAngle[0] = 60.0f;
+ mDownAngleV[0] = 20.0f;
+ mRotate[0] = 140.0f;
+ mRotateV[0] = 0.0f;
+ mBranches[0] = 35;
+
+ mVertices[1] = 3;
+
+ // stem splits
+ mSplitAngle[1] = 0.0f;
+ mSplitAngleV[1] = 0.0f;
+ mSegSplits[1] = 0.0f;
+
+ // curvature
+ mCurveRes[1] = 4;
+ mCurve[1] = 0;
+ mCurveV[1] = 0;
+ mCurveBack[1] = 40;
+
+ // level 2
+ mLength[2] = .6f;
+ mLengthV[2] = .1f;
+ mTaper[2] = 1;
+
+ mDownAngle[1] = 30;
+ mDownAngleV[1] = 10;
+ mRotate[1] = 140;
+ mRotateV[1] = 0;
+
+ mBranches[1] = 20;
+ mVertices[2] = 3;
+
+ mSplitAngle[2] = 0;
+ mSplitAngleV[2] = 0;
+ mSegSplits[2] = 0;
+
+ mCurveRes[2] = 3;
+ mCurve[2] = 10;
+ mCurveV[2] = 150;
+ mCurveBack[2] = 0;
+
+ // level 3
+ mLength[3] = .4f;
+ mLengthV[3] = 0;
+ mTaper[3] = 1;
+
+ mDownAngle[2] = 45;
+ mDownAngleV[2] = 10;
+ mRotate[2] = 140;
+ mRotateV[2] = 0;
+
+ mBranches[2] = 5;
+ mVertices[3] = 3;
+
+
+ mSplitAngle[3] = 0;
+ mSplitAngleV[3] = 0;
+ mSegSplits[3] = 0;
+
+ mCurveRes[3] = 2;
+ mCurve[3] = 0;
+ mCurveV[3] = 0;
+ mCurveBack[3] = 0;
+
+ mLeaves = 0;
+ mLeafScaleX = 1.0f;
+ mLeafScaleY = 1.0f;
+
+ mLeafQuality = 1.25;
+}
+
+LLTreeParams::~LLTreeParams()
+{
+
+}
+
+F32 LLTreeParams::ShapeRatio(EShapeRatio shape, F32 ratio)
+{
+ switch (shape) {
+ case (SR_CONICAL):
+ return (.2f + .8f * ratio);
+ case (SR_SPHERICAL):
+ return (.2f + .8f * sinf(F_PI*ratio));
+ case (SR_HEMISPHERICAL):
+ return (.2f + .8f * sinf(.5*F_PI*ratio));
+ case (SR_CYLINDRICAL):
+ return (1);
+ case (SR_TAPERED_CYLINDRICAL):
+ return (.5f + .5f * ratio);
+ case (SR_FLAME):
+ if (ratio <= .7f) {
+ return ratio/.7f;
+ } else {
+ return ((1 - ratio)/.3f);
+ }
+ case (SR_INVERSE_CONICAL):
+ return (1 - .8f * ratio);
+ case (SR_TEND_FLAME):
+ if (ratio <= .7) {
+ return (.5f + .5f*(ratio/.7f));
+ } else {
+ return (.5f + .5f * (1 - ratio)/.3f);
+ }
+ case (SR_ENVELOPE):
+ return 1;
+ default:
+ return 1;
+ }
+}
diff --git a/indra/llprimitive/lltreeparams.h b/indra/llprimitive/lltreeparams.h
new file mode 100644
index 0000000000..fa55f584e3
--- /dev/null
+++ b/indra/llprimitive/lltreeparams.h
@@ -0,0 +1,183 @@
+/**
+ * @file lltreeparams.h
+ * @brief Implementation of the LLTreeParams class
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLTREEPARAMS_H
+#define LL_LLTREEPARAMS_H
+
+/* for information about formulas associated with each type
+ * check the Weber + Penn paper
+ */
+typedef enum EShapeRatio { SR_CONICAL, SR_SPHERICAL, SR_HEMISPHERICAL,
+ SR_CYLINDRICAL, SR_TAPERED_CYLINDRICAL, SR_FLAME,
+ SR_INVERSE_CONICAL, SR_TEND_FLAME, SR_ENVELOPE};
+
+const U32 TREE_BLOCK_SIZE = 16;
+
+const U8 MAX_NUM_LEVELS = 4;
+
+class LLTreeParams
+{
+public:
+ LLTreeParams();
+ virtual ~LLTreeParams();
+
+ static F32 ShapeRatio(EShapeRatio shape, F32 ratio);
+
+public:
+
+ // Variables with an asterick (*) cannot be modified without a re-instancing the
+ // trunk/branches
+
+ // Variables with an exclamation point (!) should probably not be modified outside and instead
+ // be tied directly to the species
+
+ // Variables with a tilde (~) should be tied to a range specified by the
+ // species type but still slightly controllable by the user
+
+ // GENERAL
+
+ //! determines length/radius of branches on tree -- ie: general 'shape'
+ EShapeRatio mShape;
+
+ //! number of recursive branch levels...limit to MAX_NUM_LEVELS
+ U8 mLevels;
+
+ //~ percentage of trunk at bottom without branches
+ F32 mBaseSize;
+
+ //~ the general scale + variance of tree
+ F32 mScale, mScaleV;
+
+ // general scale of tree
+ F32 mScale0, mScaleV0;
+
+
+
+ // LOBING
+
+ //*! number of peaks in the radial distance about the perimeter
+ U8 mLobes;
+ // even numbers = obvius symmetry ... use odd numbers
+
+ //*! magnitude of the variations as a fraction of the radius
+ F32 mLobeDepth;
+
+
+
+ // FLARE
+
+ //*! causes exponential expansion near base of trunk
+ F32 mFlare;
+ // scales radius base by min 1 to '1 + flare'
+
+ //*! percentage of the height of the trunk to flair -- likely less than baseSize
+ F32 mFlarePercentage;
+
+ //*! number of cross sections to make for the flair
+ U8 mFlareRes;
+
+
+
+ // LEAVES
+
+ //~ number of leaves to make
+ U8 mLeaves;
+
+ //! scale of the leaves
+ F32 mLeafScaleX, mLeafScaleY;
+
+ // quality/density of leaves
+ F32 mLeafQuality;
+
+ // several params don't have level 0 values
+
+ // BRANCHES
+
+ //~ angle away from parent
+ F32 mDownAngle[MAX_NUM_LEVELS - 1];
+ F32 mDownAngleV[MAX_NUM_LEVELS - 1];
+
+ //~ rotation around parent
+ F32 mRotate[MAX_NUM_LEVELS - 1];
+ F32 mRotateV[MAX_NUM_LEVELS - 1];
+
+ //~ num branches to spawn
+ U8 mBranches[MAX_NUM_LEVELS - 1];
+
+ //~ fractional length of branch. 1 = same length as parent branch
+ F32 mLength[MAX_NUM_LEVELS];
+ F32 mLengthV[MAX_NUM_LEVELS];
+
+ //!~ ratio and ratiopower determine radius/length
+ F32 mRatio, mRatioPower;
+
+ //*! taper of branches
+ F32 mTaper[MAX_NUM_LEVELS];
+ // 0 - non-tapering cylinder
+ // 1 - taper to a point
+ // 2 - taper to a spherical end
+ // 3 - periodic tapering (concatenated spheres)
+
+ //! SEG SPLITTING
+ U8 mBaseSplits; //! num segsplits at first curve cross section of trunk
+ F32 mSegSplits[MAX_NUM_LEVELS]; //~ splits per cross section. 1 = 1 split per section
+ F32 mSplitAngle[MAX_NUM_LEVELS]; //~ angle that splits go from parent (tempered by height)
+ F32 mSplitAngleV[MAX_NUM_LEVELS]; //~ variance of the splits
+
+ // CURVE
+ F32 mCurve[MAX_NUM_LEVELS]; //* general, 1-axis, overall curve of branch
+ F32 mCurveV[MAX_NUM_LEVELS]; //* curve variance at each cross section from general overall curve
+ U8 mCurveRes[MAX_NUM_LEVELS]; //* number of cross sections for curve
+ F32 mCurveBack[MAX_NUM_LEVELS]; //* curveback is amount branch curves back towards
+
+ // vertices per cross section
+ U8 mVertices[MAX_NUM_LEVELS];
+
+ // * no longer useful with pre-instanced branches
+ // specifies upward tendency of branches.
+ //F32 mAttractionUp;
+ // 1 = each branch will slightly go upwards by the end of the branch
+ // >1 = branches tend to go upwards earlier in their length
+ // pruning not implemented
+ // Prune parameters
+ //F32 mPruneRatio;
+ //F32 mPruneWidth, mPruneWidthPeak;
+ //F32 mPrunePowerLow, mPrunePowerHigh;
+
+
+ // NETWORK MESSAGE DATA
+ // Below is the outline for network messages regarding trees.
+ // The general idea is that a user would pick a general 'tree type' (the first variable)
+ // and then several 'open ended' variables like 'branchiness' and 'leafiness'.
+ // The effect that each of these general user variables would then affect the actual
+ // tree parameters (like # branches, # segsplits) in different ways depending on
+ // the tree type selected. Essentially, each tree type should have a formula
+ // that expands the 'leafiness' and 'branchiness' user variables into actual
+ // values for the tree parameters.
+
+ // These formulas aren't made yet and will certainly require some tuning. The
+ // estimates below for the # bits required seems like a good guesstimate.
+
+ // VARIABLE - # bits (range) - VARIABLES AFFECTED
+ // tree type - 5 bits (32) -
+ // branches - 6 bits (64) - numBranches
+ // splits - 6 bits (64) - segsplits
+ // leafiness - 3 bits (8) - numLeaves
+ // branch spread - 5 bits (32) - splitAngle(V), rotate(V)
+ // angle - 5 bits (32) - downAngle(V)
+ // branch length - 6 bits (64) - branchlength(V)
+ // randomness - 7 bits (128) - percentage for randomness of the (V)'s
+ // basesize - 5 bits (32) - basesize
+
+ // total - 48 bits
+
+ //U8 mNetSpecies;
+
+};
+
+#endif
diff --git a/indra/llprimitive/llvolumemessage.cpp b/indra/llprimitive/llvolumemessage.cpp
new file mode 100644
index 0000000000..d2f1e12526
--- /dev/null
+++ b/indra/llprimitive/llvolumemessage.cpp
@@ -0,0 +1,534 @@
+/**
+ * @file llvolumemessage.cpp
+ * @brief LLVolumeMessage base class
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "message.h"
+#include "llvolumemessage.h"
+#include "lldatapacker.h"
+
+//============================================================================
+
+// LLVolumeMessage is just a wrapper class; all members are static
+
+//============================================================================
+
+bool LLVolumeMessage::packProfileParams(
+ const LLProfileParams* params,
+ LLMessageSystem *mesgsys)
+{
+ // Default to cylinder
+ static LLProfileParams defaultparams(LL_PCODE_PROFILE_CIRCLE, U8(0), U8(0), U8(0));
+
+ if (!params)
+ params = &defaultparams;
+
+ U8 tempU8;
+ tempU8 = params->getCurveType();
+ mesgsys->addU8Fast(_PREHASH_ProfileCurve, tempU8);
+
+ tempU8 = (U8) llround( params->getBegin() / CUT_QUANTA);
+ mesgsys->addU8Fast(_PREHASH_ProfileBegin, tempU8);
+
+ tempU8 = 200 - (U8) llround(params->getEnd() / CUT_QUANTA);
+ mesgsys->addU8Fast(_PREHASH_ProfileEnd, tempU8);
+
+ tempU8 = (S8) llround(params->getHollow() / SHEAR_QUANTA);
+ mesgsys->addU8Fast(_PREHASH_ProfileHollow, tempU8);
+
+ return true;
+}
+
+bool LLVolumeMessage::packProfileParams(
+ const LLProfileParams* params,
+ LLDataPacker &dp)
+{
+ // Default to cylinder
+ static LLProfileParams defaultparams(LL_PCODE_PROFILE_CIRCLE, U8(0), U8(0), U8(0));
+
+ if (!params)
+ params = &defaultparams;
+
+ U8 tempU8;
+ tempU8 = params->getCurveType();
+ dp.packU8(tempU8, "Curve");
+
+ tempU8 = (U8) llround( params->getBegin() / CUT_QUANTA);
+ dp.packU8(tempU8, "Begin");
+
+ tempU8 = 200 - (U8) llround(params->getEnd() / CUT_QUANTA);
+ dp.packU8(tempU8, "End");
+
+ tempU8 = (S8) llround(params->getHollow() / SHEAR_QUANTA);
+ dp.packU8(tempU8, "Hollow");
+ return true;
+}
+
+bool LLVolumeMessage::unpackProfileParams(
+ LLProfileParams* params,
+ LLMessageSystem* mesgsys,
+ char* block_name,
+ S32 block_num)
+{
+ bool ok = true;
+ U8 temp_u8;
+ F32 temp_f32;
+
+ mesgsys->getU8Fast(block_name, _PREHASH_ProfileCurve, temp_u8, block_num);
+ params->setCurveType(temp_u8);
+
+ mesgsys->getU8Fast(block_name, _PREHASH_ProfileBegin, temp_u8, block_num);
+ temp_f32 = temp_u8 * CUT_QUANTA;
+ if (temp_f32 > 1.f)
+ {
+ llwarns << "Profile begin out of range: " << temp_f32
+ << ". Clamping to 0.0." << llendl;
+ temp_f32 = 0.f;
+ ok = false;
+ }
+ params->setBegin(temp_f32);
+
+ mesgsys->getU8Fast(block_name, _PREHASH_ProfileEnd, temp_u8, block_num);
+ temp_f32 = temp_u8 * CUT_QUANTA;
+ if (temp_f32 > 1.f)
+ {
+ llwarns << "Profile end out of range: " << 1.f - temp_f32
+ << ". Clamping to 1.0." << llendl;
+ temp_f32 = 1.f;
+ ok = false;
+ }
+ params->setEnd(1.f - temp_f32);
+
+ mesgsys->getU8Fast(block_name, _PREHASH_ProfileHollow, temp_u8, block_num);
+ temp_f32 = temp_u8 * SCALE_QUANTA;
+ if (temp_f32 > 1.f)
+ {
+ llwarns << "Profile hollow out of range: " << temp_f32
+ << ". Clamping to 0.0." << llendl;
+ temp_f32 = 0.f;
+ ok = false;
+ }
+ params->setHollow(temp_f32);
+
+ /*
+ llinfos << "Unpacking Profile Block " << block_num << llendl;
+ llinfos << "Curve: " << (U32)getCurve() << llendl;
+ llinfos << "Begin: " << getBegin() << llendl;
+ llinfos << "End: " << getEnd() << llendl;
+ llinfos << "Hollow: " << getHollow() << llendl;
+ */
+ return ok;
+
+}
+
+bool LLVolumeMessage::unpackProfileParams(
+ LLProfileParams* params,
+ LLDataPacker &dp)
+{
+ bool ok = true;
+ U8 temp_u8;
+ F32 temp_f32;
+
+ dp.unpackU8(temp_u8, "Curve");
+ params->setCurveType(temp_u8);
+
+ dp.unpackU8(temp_u8, "Begin");
+ temp_f32 = temp_u8 * CUT_QUANTA;
+ if (temp_f32 > 1.f)
+ {
+ llwarns << "Profile begin out of range: " << temp_f32 << llendl;
+ llwarns << "Clamping to 0.0" << llendl;
+ temp_f32 = 0.f;
+ ok = false;
+ }
+ params->setBegin(temp_f32);
+
+ dp.unpackU8(temp_u8, "End");
+ temp_f32 = temp_u8 * CUT_QUANTA;
+ if (temp_f32 > 1.f)
+ {
+ llwarns << "Profile end out of range: " << 1.f - temp_f32 << llendl;
+ llwarns << "Clamping to 1.0" << llendl;
+ temp_f32 = 1.f;
+ ok = false;
+ }
+ params->setEnd(1.f - temp_f32);
+
+ dp.unpackU8(temp_u8, "Hollow");
+ temp_f32 = temp_u8 * SCALE_QUANTA;
+ if (temp_f32 > 1.f)
+ {
+ llwarns << "Profile hollow out of range: " << temp_f32 << llendl;
+ llwarns << "Clamping to 0.0" << llendl;
+ temp_f32 = 0.f;
+ ok = false;
+ }
+ params->setHollow(temp_f32);
+
+ return ok;
+}
+
+//============================================================================
+
+// Quantization:
+// For cut begin, range is 0 to 1, quanta is 0.005, 0 maps to 0
+// For cut end, range is 0 to 1, quanta is 0.005, 1 maps to 0
+// For scale, range is 0 to 1, quanta is 0.01, 0 maps to 0, 1 maps to 100
+// For shear, range is -0.5 to 0.5, quanta is 0.01, 0 maps to 0
+// For taper, range is -1 to 1, quanta is 0.01, 0 maps to 0
+bool LLVolumeMessage::packPathParams(
+ const LLPathParams* params,
+ LLMessageSystem *mesgsys)
+{
+ // Default to cylinder with no cut, top same size as bottom, no shear, no twist
+ static LLPathParams defaultparams(LL_PCODE_PATH_LINE, U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), 0);
+ if (!params)
+ params = &defaultparams;
+
+ U8 curve = params->getCurveType();
+ mesgsys->addU8Fast(_PREHASH_PathCurve, curve);
+
+ U8 begin = (U8) llround(params->getBegin() / SCALE_QUANTA);
+ mesgsys->addU8Fast(_PREHASH_PathBegin, begin);
+
+ U8 end = 100 - (U8) llround(params->getEnd() / SCALE_QUANTA);
+ mesgsys->addU8Fast(_PREHASH_PathEnd, end);
+
+ // Avoid truncation problem with direct F32->U8 cast.
+ // (e.g., (U8) (0.50 / 0.01) = (U8) 49.9999999 = 49 not 50.
+
+ U8 pack_scale_x = 200 - (U8) llround(params->getScaleX() / SCALE_QUANTA);
+ mesgsys->addU8Fast(_PREHASH_PathScaleX, pack_scale_x );
+
+ U8 pack_scale_y = 200 - (U8) llround(params->getScaleY() / SCALE_QUANTA);
+ mesgsys->addU8Fast(_PREHASH_PathScaleY, pack_scale_y );
+
+ U8 pack_shear_x = (U8) llround(params->getShearX() / SHEAR_QUANTA);
+ mesgsys->addU8Fast(_PREHASH_PathShearX, pack_shear_x );
+
+ U8 pack_shear_y = (U8) llround(params->getShearY() / SHEAR_QUANTA);
+ mesgsys->addU8Fast(_PREHASH_PathShearY, pack_shear_y );
+
+ S8 twist = (S8) llround(params->getTwist() / SCALE_QUANTA);
+ mesgsys->addS8Fast(_PREHASH_PathTwist, twist);
+
+ S8 twist_begin = (S8) llround(params->getTwistBegin() / SCALE_QUANTA);
+ mesgsys->addS8Fast(_PREHASH_PathTwistBegin, twist_begin);
+
+ S8 radius_offset = (S8) llround(params->getRadiusOffset() / SCALE_QUANTA);
+ mesgsys->addS8Fast(_PREHASH_PathRadiusOffset, radius_offset);
+
+ S8 taper_x = (S8) llround(params->getTaperX() / TAPER_QUANTA);
+ mesgsys->addS8Fast(_PREHASH_PathTaperX, taper_x);
+
+ S8 taper_y = (S8) llround(params->getTaperY() / TAPER_QUANTA);
+ mesgsys->addS8Fast(_PREHASH_PathTaperY, taper_y);
+
+ U8 revolutions = (U8) llround( (params->getRevolutions() - 1.0f) / REV_QUANTA);
+ mesgsys->addU8Fast(_PREHASH_PathRevolutions, revolutions);
+
+ S8 skew = (S8) llround(params->getSkew() / SCALE_QUANTA);
+ mesgsys->addS8Fast(_PREHASH_PathSkew, skew);
+
+ return true;
+}
+
+bool LLVolumeMessage::packPathParams(
+ const LLPathParams* params,
+ LLDataPacker &dp)
+{
+ // Default to cylinder with no cut, top same size as bottom, no shear, no twist
+ static LLPathParams defaultparams(LL_PCODE_PATH_LINE, U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), U8(0), 0);
+ if (!params)
+ params = &defaultparams;
+
+ U8 curve = params->getCurveType();
+ dp.packU8(curve, "Curve");
+
+ U8 begin = (U8) llround(params->getBegin() / SCALE_QUANTA);
+ dp.packU8(begin, "Begin");
+
+ U8 end = 100 - (U8) llround(params->getEnd() / SCALE_QUANTA);
+ dp.packU8(end, "End");
+
+ // Avoid truncation problem with direct F32->U8 cast.
+ // (e.g., (U8) (0.50 / 0.01) = (U8) 49.9999999 = 49 not 50.
+
+ U8 pack_scale_x = 200 - (U8) llround(params->getScaleX() / SCALE_QUANTA);
+ dp.packU8(pack_scale_x, "ScaleX");
+
+ U8 pack_scale_y = 200 - (U8) llround(params->getScaleY() / SCALE_QUANTA);
+ dp.packU8(pack_scale_y, "ScaleY");
+
+ S8 pack_shear_x = (S8) llround(params->getShearX() / SHEAR_QUANTA);
+ dp.packU8(*(U8 *)&pack_shear_x, "ShearX");
+
+ S8 pack_shear_y = (S8) llround(params->getShearY() / SHEAR_QUANTA);
+ dp.packU8(*(U8 *)&pack_shear_y, "ShearY");
+
+ S8 twist = (S8) llround(params->getTwist() / SCALE_QUANTA);
+ dp.packU8(*(U8 *)&twist, "Twist");
+
+ S8 twist_begin = (S8) llround(params->getTwistBegin() / SCALE_QUANTA);
+ dp.packU8(*(U8 *)&twist_begin, "TwistBegin");
+
+ S8 radius_offset = (S8) llround(params->getRadiusOffset() / SCALE_QUANTA);
+ dp.packU8(*(U8 *)&radius_offset, "RadiusOffset");
+
+ S8 taper_x = (S8) llround(params->getTaperX() / TAPER_QUANTA);
+ dp.packU8(*(U8 *)&taper_x, "TaperX");
+
+ S8 taper_y = (S8) llround(params->getTaperY() / TAPER_QUANTA);
+ dp.packU8(*(U8 *)&taper_y, "TaperY");
+
+ U8 revolutions = (U8) llround( (params->getRevolutions() - 1.0f) / REV_QUANTA);
+ dp.packU8(*(U8 *)&revolutions, "Revolutions");
+
+ S8 skew = (S8) llround(params->getSkew() / SCALE_QUANTA);
+ dp.packU8(*(U8 *)&skew, "Skew");
+
+ return true;
+}
+
+bool LLVolumeMessage::unpackPathParams(
+ LLPathParams* params,
+ LLMessageSystem* mesgsys,
+ char* block_name,
+ S32 block_num)
+{
+ U8 curve;
+ mesgsys->getU8Fast(block_name, _PREHASH_PathCurve, curve, block_num);
+ params->setCurveType(curve);
+
+ U8 begin;
+ mesgsys->getU8Fast(block_name, _PREHASH_PathBegin, begin, block_num);
+ params->setBegin((F32)(begin * SCALE_QUANTA));
+
+ U8 end;
+ mesgsys->getU8Fast(block_name, _PREHASH_PathEnd, end, block_num);
+ params->setEnd((F32)((100 - end) * SCALE_QUANTA));
+
+ U8 pack_scale_x, pack_scale_y;
+ mesgsys->getU8Fast(block_name, _PREHASH_PathScaleX, pack_scale_x, block_num);
+ mesgsys->getU8Fast(block_name, _PREHASH_PathScaleY, pack_scale_y, block_num);
+ F32 x = (F32) (200 - pack_scale_x) * SCALE_QUANTA;
+ F32 y = (F32) (200 - pack_scale_y) * SCALE_QUANTA;
+ params->setScale( x, y );
+
+ S8 shear_x_quant, shear_y_quant;
+ mesgsys->getS8Fast(block_name, _PREHASH_PathShearX, shear_x_quant, block_num);
+ mesgsys->getS8Fast(block_name, _PREHASH_PathShearY, shear_y_quant, block_num);
+ F32 shear_x = (F32) shear_x_quant * SHEAR_QUANTA;
+ F32 shear_y = (F32) shear_y_quant * SHEAR_QUANTA;
+ params->setShear( shear_x, shear_y );
+
+ S8 twist;
+ mesgsys->getS8Fast(block_name, _PREHASH_PathTwist, twist, block_num );
+ params->setTwist((F32)(twist * SCALE_QUANTA));
+
+ S8 twist_begin;
+ mesgsys->getS8Fast(block_name, _PREHASH_PathTwistBegin, twist_begin, block_num );
+ params->setTwistBegin((F32)(twist_begin * SCALE_QUANTA));
+
+ S8 radius_offset;
+ mesgsys->getS8Fast(block_name, _PREHASH_PathRadiusOffset, radius_offset, block_num );
+ params->setRadiusOffset((F32)(radius_offset * SCALE_QUANTA));
+
+ S8 taper_x_quant, taper_y_quant;
+ mesgsys->getS8Fast(block_name, _PREHASH_PathTaperX, taper_x_quant, block_num );
+ mesgsys->getS8Fast(block_name, _PREHASH_PathTaperY, taper_y_quant, block_num );
+ F32 taper_x = (F32)(taper_x_quant * TAPER_QUANTA);
+ F32 taper_y = (F32)(taper_y_quant * TAPER_QUANTA);
+ params->setTaper( taper_x, taper_y );
+
+ U8 revolutions;
+ mesgsys->getU8Fast(block_name, _PREHASH_PathRevolutions, revolutions, block_num );
+ params->setRevolutions((F32)(revolutions * REV_QUANTA + 1.0f));
+
+ S8 skew;
+ mesgsys->getS8Fast(block_name, _PREHASH_PathSkew, skew, block_num );
+ params->setSkew((F32)(skew * SCALE_QUANTA));
+
+/*
+ llinfos << "Unpacking Path Block " << block_num << llendl;
+ llinfos << "Curve: " << (U32)params->getCurve() << llendl;
+ llinfos << "Begin: " << params->getBegin() << llendl;
+ llinfos << "End: " << params->getEnd() << llendl;
+ llinfos << "Scale: " << params->getScale() << llendl;
+ llinfos << "Twist: " << params->getTwist() << llendl;
+*/
+
+ return true;
+
+}
+
+bool LLVolumeMessage::unpackPathParams(LLPathParams* params, LLDataPacker &dp)
+{
+ U8 value;
+ S8 svalue;
+ dp.unpackU8(value, "Curve");
+ params->setCurveType( value );
+
+ dp.unpackU8(value, "Begin");
+ params->setBegin((F32)(value * SCALE_QUANTA));
+
+ dp.unpackU8(value, "End");
+ params->setEnd((F32)((100 - value) * SCALE_QUANTA));
+
+ dp.unpackU8(value, "ScaleX");
+ F32 x = (F32) (200 - value) * SCALE_QUANTA;
+ dp.unpackU8(value, "ScaleY");
+ F32 y = (F32) (200 - value) * SCALE_QUANTA;
+ params->setScale( x, y );
+
+ dp.unpackU8(value, "ShearX");
+ svalue = *(S8 *)&value;
+ F32 shear_x = (F32) svalue * SHEAR_QUANTA;
+ dp.unpackU8(value, "ShearY");
+ svalue = *(S8 *)&value;
+ F32 shear_y = (F32) svalue * SHEAR_QUANTA;
+ params->setShear( shear_x, shear_y );
+
+ dp.unpackU8(value, "Twist");
+ svalue = *(S8 *)&value;
+ params->setTwist((F32)(svalue * SCALE_QUANTA));
+
+ dp.unpackU8(value, "TwistBegin");
+ svalue = *(S8 *)&value;
+ params->setTwistBegin((F32)(svalue * SCALE_QUANTA));
+
+ dp.unpackU8(value, "RadiusOffset");
+ svalue = *(S8 *)&value;
+ params->setRadiusOffset((F32)(svalue * SCALE_QUANTA));
+
+ dp.unpackU8(value, "TaperX");
+ svalue = *(S8 *)&value;
+ params->setTaperX((F32)(svalue * TAPER_QUANTA));
+
+ dp.unpackU8(value, "TaperY");
+ svalue = *(S8 *)&value;
+ params->setTaperY((F32)(svalue * TAPER_QUANTA));
+
+ dp.unpackU8(value, "Revolutions");
+ params->setRevolutions((F32)(value * REV_QUANTA + 1.0f));
+
+ dp.unpackU8(value, "Skew");
+ svalue = *(S8 *)&value;
+ params->setSkew((F32)(svalue * SCALE_QUANTA));
+
+ return true;
+}
+
+//============================================================================
+
+// static
+bool LLVolumeMessage::constrainVolumeParams(LLVolumeParams& params)
+{
+ bool ok = true;
+
+ // This is called immediately after an unpack. feed the raw data
+ // through the checked setters to constraint it to a valid set of
+ // volume params.
+ ok &= params.setType(
+ params.getProfileParams().getCurveType(),
+ params.getPathParams().getCurveType());
+ ok &= params.setBeginAndEndS(
+ params.getProfileParams().getBegin(),
+ params.getProfileParams().getEnd());
+ ok &= params.setBeginAndEndT(
+ params.getPathParams().getBegin(),
+ params.getPathParams().getEnd());
+ ok &= params.setHollow(params.getProfileParams().getHollow());
+ ok &= params.setTwistBegin(params.getPathParams().getTwistBegin());
+ ok &= params.setTwistEnd(params.getPathParams().getTwistEnd());
+ ok &= params.setRatio(
+ params.getPathParams().getScaleX(),
+ params.getPathParams().getScaleY());
+ ok &= params.setShear(
+ params.getPathParams().getShearX(),
+ params.getPathParams().getShearY());
+ ok &= params.setTaper(
+ params.getPathParams().getTaperX(),
+ params.getPathParams().getTaperY());
+ ok &= params.setRevolutions(params.getPathParams().getRevolutions());
+ ok &= params.setRadiusOffset(params.getPathParams().getRadiusOffset());
+ ok &= params.setSkew(params.getPathParams().getSkew());
+ if(!ok)
+ {
+ llwarns << "LLVolumeMessage::constrainVolumeParams() - "
+ << "forced to constrain incoming volume params." << llendl;
+ }
+ return ok;
+}
+
+bool LLVolumeMessage::packVolumeParams(const LLVolumeParams* params, LLMessageSystem *mesgsys)
+{
+ // llinfos << "pack volume" << llendl;
+ if (params)
+ {
+ packPathParams(&params->getPathParams(), mesgsys);
+ packProfileParams(&params->getProfileParams(), mesgsys);
+ }
+ else
+ {
+ packPathParams(0, mesgsys);
+ packProfileParams(0, mesgsys);
+ }
+ return true;
+}
+
+bool LLVolumeMessage::packVolumeParams(const LLVolumeParams* params, LLDataPacker &dp)
+{
+ // llinfos << "pack volume" << llendl;
+ if (params)
+ {
+ packPathParams(&params->getPathParams(), dp);
+ packProfileParams(&params->getProfileParams(), dp);
+ }
+ else
+ {
+ packPathParams(0, dp);
+ packProfileParams(0, dp);
+ }
+ return true;
+}
+
+bool LLVolumeMessage::unpackVolumeParams(
+ LLVolumeParams* params,
+ LLMessageSystem* mesgsys,
+ char* block_name,
+ S32 block_num)
+{
+ bool ok = true;
+ ok &= unpackPathParams(
+ &params->getPathParams(),
+ mesgsys,
+ block_name,
+ block_num);
+ ok &= unpackProfileParams(
+ &params->getProfileParams(),
+ mesgsys,
+ block_name,
+ block_num);
+ ok &= constrainVolumeParams(*params);
+
+ return ok;
+}
+
+bool LLVolumeMessage::unpackVolumeParams(
+ LLVolumeParams* params,
+ LLDataPacker &dp)
+{
+ bool ok = true;
+ ok &= unpackPathParams(&params->getPathParams(), dp);
+ ok &= unpackProfileParams(&params->getProfileParams(), dp);
+ ok &= constrainVolumeParams(*params);
+ return ok;
+}
+
+//============================================================================
diff --git a/indra/llprimitive/llvolumemessage.h b/indra/llprimitive/llvolumemessage.h
new file mode 100644
index 0000000000..299d5813a0
--- /dev/null
+++ b/indra/llprimitive/llvolumemessage.h
@@ -0,0 +1,74 @@
+/**
+ * @file llvolumemessage.h
+ * @brief LLVolumeMessage base class
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLVOLUMEMESSAGE_H
+#define LL_LLVOLUMEMESSAGE_H
+
+#include "llvolume.h"
+
+class LLMessageSystem;
+class LLDataPacker;
+
+// wrapper class for some volume/message functions
+class LLVolumeMessage
+{
+protected:
+ // The profile and path params are protected since they do not do
+ // any kind of parameter validation or clamping. Use the public
+ // pack and unpack volume param methods below
+
+ static bool packProfileParams(
+ const LLProfileParams* params,
+ LLMessageSystem* mesgsys);
+ static bool packProfileParams(
+ const LLProfileParams* params,
+ LLDataPacker& dp);
+ static bool unpackProfileParams(
+ LLProfileParams* params,
+ LLMessageSystem* mesgsys,
+ char* block_name,
+ S32 block_num = 0);
+ static bool unpackProfileParams(LLProfileParams* params, LLDataPacker& dp);
+
+ static bool packPathParams(
+ const LLPathParams* params,
+ LLMessageSystem* mesgsys);
+ static bool packPathParams(const LLPathParams* params, LLDataPacker& dp);
+ static bool unpackPathParams(
+ LLPathParams* params,
+ LLMessageSystem* mesgsys,
+ char* block_name,
+ S32 block_num = 0);
+ static bool unpackPathParams(LLPathParams* params, LLDataPacker& dp);
+
+public:
+ /**
+ * @brief This method constrains any volume params to make them valid.
+ *
+ * @param[in,out] Possibly invalid params in, always valid out.
+ * @return Returns true if the in params were valid, and therefore
+ * unchanged.
+ */
+ static bool constrainVolumeParams(LLVolumeParams& params);
+
+ static bool packVolumeParams(
+ const LLVolumeParams* params,
+ LLMessageSystem* mesgsys);
+ static bool packVolumeParams(
+ const LLVolumeParams* params,
+ LLDataPacker& dp);
+ static bool unpackVolumeParams(
+ LLVolumeParams* params,
+ LLMessageSystem* mesgsys,
+ char* block_name,
+ S32 block_num = 0);
+ static bool unpackVolumeParams(LLVolumeParams* params, LLDataPacker &dp);
+};
+
+#endif // LL_LLVOLUMEMESSAGE_H
+
diff --git a/indra/llprimitive/llvolumexml.cpp b/indra/llprimitive/llvolumexml.cpp
new file mode 100644
index 0000000000..3c9d4d3b39
--- /dev/null
+++ b/indra/llprimitive/llvolumexml.cpp
@@ -0,0 +1,57 @@
+/**
+ * @file llvolumexml.cpp
+ * @brief LLVolumeXml base class
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "linden_common.h"
+
+#include "llvolumexml.h"
+
+//============================================================================
+
+// LLVolumeXml is just a wrapper class; all members are static
+
+//============================================================================
+
+LLXMLNode *LLVolumeXml::exportProfileParams(const LLProfileParams* params)
+{
+ LLXMLNode *ret = new LLXMLNode("profile", FALSE);
+
+ ret->createChild("curve_type", TRUE)->setByteValue(1, &params->getCurveType());
+ ret->createChild("interval", FALSE)->setFloatValue(2, &params->getBegin());
+ ret->createChild("hollow", FALSE)->setFloatValue(1, &params->getHollow());
+
+ return ret;
+}
+
+
+LLXMLNode *LLVolumeXml::exportPathParams(const LLPathParams* params)
+{
+ LLXMLNode *ret = new LLXMLNode("path", FALSE);
+ ret->createChild("curve_type", TRUE)->setByteValue(1, &params->getCurveType());
+ ret->createChild("interval", FALSE)->setFloatValue(2, &params->getBegin());
+ ret->createChild("scale", FALSE)->setFloatValue(2, params->getScale().mV);
+ ret->createChild("shear", FALSE)->setFloatValue(2, params->getShear().mV);
+ ret->createChild("twist_interval", FALSE)->setFloatValue(2, &params->getTwistBegin());
+ ret->createChild("radius_offset", FALSE)->setFloatValue(1, &params->getRadiusOffset());
+ ret->createChild("taper", FALSE)->setFloatValue(2, params->getTaper().mV);
+ ret->createChild("revolutions", FALSE)->setFloatValue(1, &params->getRevolutions());
+ ret->createChild("skew", FALSE)->setFloatValue(1, &params->getSkew());
+
+ return ret;
+}
+
+
+LLXMLNode *LLVolumeXml::exportVolumeParams(const LLVolumeParams* params)
+{
+ LLXMLNode *ret = new LLXMLNode("shape", FALSE);
+
+ exportPathParams(&params->getPathParams())->setParent(ret);
+ exportProfileParams(&params->getProfileParams())->setParent(ret);
+
+ return ret;
+}
+
diff --git a/indra/llprimitive/llvolumexml.h b/indra/llprimitive/llvolumexml.h
new file mode 100644
index 0000000000..5d105f148a
--- /dev/null
+++ b/indra/llprimitive/llvolumexml.h
@@ -0,0 +1,27 @@
+/**
+ * @file llvolumexml.h
+ * @brief LLVolumeXml base class
+ *
+ * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_LLVOLUMEXML_H
+#define LL_LLVOLUMEXML_H
+
+#include "llvolume.h"
+#include "llxmlnode.h"
+
+// wrapper class for some volume/message functions
+class LLVolumeXml
+{
+public:
+ static LLXMLNode* exportProfileParams(const LLProfileParams* params);
+
+ static LLXMLNode* exportPathParams(const LLPathParams* params);
+
+ static LLXMLNode* exportVolumeParams(const LLVolumeParams* params);
+};
+
+#endif // LL_LLVOLUMEXML_H
+
diff --git a/indra/llprimitive/material_codes.h b/indra/llprimitive/material_codes.h
new file mode 100644
index 0000000000..f9c05017c2
--- /dev/null
+++ b/indra/llprimitive/material_codes.h
@@ -0,0 +1,35 @@
+/**
+ * @file material_codes.h
+ * @brief Material_codes definitions
+ *
+ * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_MATERIAL_CODES_H
+#define LL_MATERIAL_CODES_H
+
+#include "lluuid.h"
+
+ // material types
+const U8 LL_MCODE_STONE = 0;
+const U8 LL_MCODE_METAL = 1;
+const U8 LL_MCODE_GLASS = 2;
+const U8 LL_MCODE_WOOD = 3;
+const U8 LL_MCODE_FLESH = 4;
+const U8 LL_MCODE_PLASTIC = 5;
+const U8 LL_MCODE_RUBBER = 6;
+const U8 LL_MCODE_LIGHT = 7;
+const U8 LL_MCODE_END = 8;
+const U8 LL_MCODE_MASK = 0x0F;
+
+const LLUUID LL_DEFAULT_STONE_UUID("87c5765b-aa26-43eb-b8c6-c09a1ca6208e");
+const LLUUID LL_DEFAULT_METAL_UUID("6f3c53e9-ba60-4010-8f3e-30f51a762476");
+const LLUUID LL_DEFAULT_GLASS_UUID("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d");
+const LLUUID LL_DEFAULT_WOOD_UUID("89556747-24cb-43ed-920b-47caed15465f");
+const LLUUID LL_DEFAULT_FLESH_UUID("80736669-e4b9-450e-8890-d5169f988a50");
+const LLUUID LL_DEFAULT_PLASTIC_UUID("304fcb4e-7d33-4339-ba80-76d3d22dc11a");
+const LLUUID LL_DEFAULT_RUBBER_UUID("9fae0bc5-666d-477e-9f70-84e8556ec867");
+const LLUUID LL_DEFAULT_LIGHT_UUID("00000000-0000-0000-0000-000000000000");
+
+#endif