Fleshed out llvolume a bit more. Added some utility functions.

This commit is contained in:
Shyotl
2011-07-20 23:53:09 -05:00
parent a399452d20
commit dfa850931a
2 changed files with 332 additions and 4 deletions

View File

@@ -405,6 +405,70 @@ LLProfile::Face* LLProfile::addFace(S32 i, S32 count, F32 scaleU, S16 faceID, BO
return face; return face;
} }
//static
S32 LLProfile::getNumNGonPoints(const LLProfileParams& params, S32 sides, F32 offset, F32 bevel, F32 ang_scale, S32 split)
{ // this is basically LLProfile::genNGon stripped down to only the operations that influence the number of points
LLMemType m1(LLMemType::MTYPE_VOLUME);
S32 np = 0;
// Generate an n-sided "circular" path.
// 0 is (1,0), and we go counter-clockwise along a circular path from there.
F32 t, t_step, t_first, t_fraction;
F32 begin = params.getBegin();
F32 end = params.getEnd();
t_step = 1.0f / sides;
t_first = floor(begin * sides) / (F32)sides;
// pt1 is the first point on the fractional face.
// Starting t and ang values for the first face
t = t_first;
// Increment to the next point.
// pt2 is the end point on the fractional face
t += t_step;
t_fraction = (begin - t_first)*sides;
// Only use if it's not almost exactly on an edge.
if (t_fraction < 0.9999f)
{
np++;
}
// There's lots of potential here for floating point error to generate unneeded extra points - DJS 04/05/02
while (t < end)
{
// Iterate through all the integer steps of t.
np++;
t += t_step;
}
t_fraction = (end - (t - t_step))*sides;
// Find the fraction that we need to add to the end point.
t_fraction = (end - (t - t_step))*sides;
if (t_fraction > 0.0001f)
{
np++;
}
// If we're sliced, the profile is open.
if ((end - begin)*ang_scale < 0.99f)
{
if (params.getHollow() <= 0)
{
// put center point if not hollow.
np++;
}
}
return np;
}
// What is the bevel parameter used for? - DJS 04/05/02 // What is the bevel parameter used for? - DJS 04/05/02
// Bevel parameter is currently unused but presumedly would support // Bevel parameter is currently unused but presumedly would support
// filleted and chamfered corners // filleted and chamfered corners
@@ -661,6 +725,117 @@ LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F3
return face; return face;
} }
//static
S32 LLProfile::getNumPoints(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split,
BOOL is_sculpted, S32 sculpt_size)
{ // this is basically LLProfile::generate stripped down to only operations that influence the number of points
LLMemType m1(LLMemType::MTYPE_VOLUME);
if (detail < MIN_LOD)
{
detail = MIN_LOD;
}
// Generate the face data
F32 hollow = params.getHollow();
S32 np = 0;
switch (params.getCurveType() & LL_PCODE_PROFILE_MASK)
{
case LL_PCODE_PROFILE_SQUARE:
{
np = getNumNGonPoints(params, 4,-0.375, 0, 1, split);
if (hollow)
{
np *= 2;
}
}
break;
case LL_PCODE_PROFILE_ISOTRI:
case LL_PCODE_PROFILE_RIGHTTRI:
case LL_PCODE_PROFILE_EQUALTRI:
{
np = getNumNGonPoints(params, 3,0, 0, 1, split);
if (hollow)
{
np *= 2;
}
}
break;
case LL_PCODE_PROFILE_CIRCLE:
{
// If this has a square hollow, we should adjust the
// number of faces a bit so that the geometry lines up.
U8 hole_type=0;
F32 circle_detail = MIN_DETAIL_FACES * detail;
if (hollow)
{
hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK;
if (hole_type == LL_PCODE_HOLE_SQUARE)
{
// Snap to the next multiple of four sides,
// so that corners line up.
circle_detail = llceil(circle_detail / 4.0f) * 4.0f;
}
}
S32 sides = (S32)circle_detail;
if (is_sculpted)
sides = sculpt_size;
np = getNumNGonPoints(params, sides);
if (hollow)
{
np *= 2;
}
}
break;
case LL_PCODE_PROFILE_CIRCLE_HALF:
{
// If this has a square hollow, we should adjust the
// number of faces a bit so that the geometry lines up.
U8 hole_type=0;
// Number of faces is cut in half because it's only a half-circle.
F32 circle_detail = MIN_DETAIL_FACES * detail * 0.5f;
if (hollow)
{
hole_type = params.getCurveType() & LL_PCODE_HOLE_MASK;
if (hole_type == LL_PCODE_HOLE_SQUARE)
{
// Snap to the next multiple of four sides (div 2),
// so that corners line up.
circle_detail = llceil(circle_detail / 2.0f) * 2.0f;
}
}
np = getNumNGonPoints(params, llfloor(circle_detail), 0.5f, 0.f, 0.5f);
if (hollow)
{
np *= 2;
}
// Special case for openness of sphere
if ((params.getEnd() - params.getBegin()) < 1.f)
{
}
else if (!hollow)
{
np++;
}
}
break;
default:
break;
};
return np;
}
BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split, BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split,
@@ -1122,6 +1297,32 @@ LLPath::~LLPath()
{ {
} }
S32 LLPath::getNumNGonPoints(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale)
{ //this is basically LLPath::genNGon stripped down to only operations that influence the number of points added
S32 ret = 0;
F32 step= 1.0f / sides;
F32 t = params.getBegin();
ret = 1;
t+=step;
// Snap to a quantized parameter, so that cut does not
// affect most sample points.
t = ((S32)(t * sides)) / (F32)sides;
// Run through the non-cut dependent points.
while (t < params.getEnd())
{
ret++;
t+=step;
}
ret++;
return ret;
}
void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale)
{ {
// Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane. // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane.
@@ -1299,6 +1500,56 @@ const LLVector2 LLPathParams::getEndScale() const
return end_scale; return end_scale;
} }
S32 LLPath::getNumPoints(const LLPathParams& params, F32 detail)
{ // this is basically LLPath::generate stripped down to only the operations that influence the number of points
LLMemType m1(LLMemType::MTYPE_VOLUME);
if (detail < MIN_LOD)
{
detail = MIN_LOD;
}
S32 np = 2; // hardcode for line
// Is this 0xf0 mask really necessary? DK 03/02/05
switch (params.getCurveType() & 0xf0)
{
default:
case LL_PCODE_PATH_LINE:
{
// Take the begin/end twist into account for detail.
np = llfloor(fabs(params.getTwistBegin() - params.getTwist()) * 3.5f * (detail-0.5f)) + 2;
}
break;
case LL_PCODE_PATH_CIRCLE:
{
// Increase the detail as the revolutions and twist increase.
F32 twist_mag = fabs(params.getTwistBegin() - params.getTwist());
S32 sides = (S32)llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * params.getRevolutions());
np = sides;
}
break;
case LL_PCODE_PATH_CIRCLE2:
{
//genNGon(params, llfloor(MIN_DETAIL_FACES * detail), 4.f, 0.f);
np = getNumNGonPoints(params, llfloor(MIN_DETAIL_FACES * detail));
}
break;
case LL_PCODE_PATH_TEST:
np = 5;
break;
};
return np;
}
BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split,
BOOL is_sculpted, S32 sculpt_size) BOOL is_sculpted, S32 sculpt_size)
{ {
@@ -2394,7 +2645,11 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components,
// don't test lowest LOD to support legacy content DEV-33670 // don't test lowest LOD to support legacy content DEV-33670
if (mDetail > SCULPT_MIN_AREA_DETAIL) if (mDetail > SCULPT_MIN_AREA_DETAIL)
{ {
if (sculptGetSurfaceArea() < SCULPT_MIN_AREA) F32 area = sculptGetSurfaceArea();
const F32 SCULPT_MAX_AREA = 384.f;
if (area < SCULPT_MIN_AREA || area > SCULPT_MAX_AREA)
{ {
data_is_empty = TRUE; data_is_empty = TRUE;
} }
@@ -2435,6 +2690,11 @@ BOOL LLVolume::isFlat(S32 face)
} }
bool LLVolumeParams::isSculpt() const
{
return mSculptID.notNull();
}
bool LLVolumeParams::operator==(const LLVolumeParams &params) const bool LLVolumeParams::operator==(const LLVolumeParams &params) const
{ {
return ( (getPathParams() == params.getPathParams()) && return ( (getPathParams() == params.getPathParams()) &&
@@ -2468,7 +2728,6 @@ bool LLVolumeParams::operator<(const LLVolumeParams &params) const
return mSculptID < params.mSculptID; return mSculptID < params.mSculptID;
} }
return mSculptType < params.mSculptType; return mSculptType < params.mSculptType;
@@ -3469,6 +3728,23 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
return index; return index;
} }
void LLVolume::getLoDTriangleCounts(const LLVolumeParams& params, S32* counts)
{ //attempt to approximate the number of triangles that will result from generating a volume LoD set for the
//supplied LLVolumeParams -- inaccurate, but a close enough approximation for determining streaming cost
F32 detail[] = {1.f, 1.5f, 2.5f, 4.f};
for (S32 i = 0; i < 4; i++)
{
S32 count = 0;
S32 path_points = LLPath::getNumPoints(params.getPathParams(), detail[i]);
S32 profile_points = LLProfile::getNumPoints(params.getProfileParams(), false, detail[i]);
count = (profile_points-1)*2*(path_points-1);
count += profile_points*2;
counts[i] = count;
}
}
S32 LLVolume::getNumTriangleIndices() const S32 LLVolume::getNumTriangleIndices() const
{ {
BOOL profile_open = getProfile().isOpen(); BOOL profile_open = getProfile().isOpen();
@@ -3526,6 +3802,20 @@ S32 LLVolume::getNumTriangleIndices() const
return count; return count;
} }
S32 LLVolume::getNumTriangles() const
{
U32 triangle_count = 0;
for (S32 i = 0; i < getNumVolumeFaces(); ++i)
{
triangle_count += getVolumeFace(i).mIndices.size()/3;
}
return triangle_count;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// generateSilhouetteVertices() // generateSilhouetteVertices()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -4311,11 +4601,28 @@ BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const
return TRUE; return TRUE;
} }
LLSD LLVolumeParams::sculptAsLLSD() const
{
LLSD sd = LLSD();
sd["id"] = getSculptID();
sd["type"] = getSculptType();
return sd;
}
bool LLVolumeParams::sculptFromLLSD(LLSD& sd)
{
setSculptID(sd["id"].asUUID(), (U8)sd["type"].asInteger());
return true;
}
LLSD LLVolumeParams::asLLSD() const LLSD LLVolumeParams::asLLSD() const
{ {
LLSD sd = LLSD(); LLSD sd = LLSD();
sd["path"] = mPathParams; sd["path"] = mPathParams;
sd["profile"] = mProfileParams; sd["profile"] = mProfileParams;
sd["sculpt"] = sculptAsLLSD();
return sd; return sd;
} }
@@ -4323,6 +4630,8 @@ bool LLVolumeParams::fromLLSD(LLSD& sd)
{ {
mPathParams.fromLLSD(sd["path"]); mPathParams.fromLLSD(sd["path"]);
mProfileParams.fromLLSD(sd["profile"]); mProfileParams.fromLLSD(sd["profile"]);
sculptFromLLSD(sd["sculpt"]);
return true; return true;
} }
@@ -4365,6 +4674,12 @@ const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity
// for collison purposes // for collison purposes
BOOL LLVolumeParams::isConvex() const BOOL LLVolumeParams::isConvex() const
{ {
if (!getSculptID().isNull())
{
// can't determine, be safe and say no:
return FALSE;
}
F32 path_length = mPathParams.getEnd() - mPathParams.getBegin(); F32 path_length = mPathParams.getEnd() - mPathParams.getBegin();
F32 hollow = mProfileParams.getHollow(); F32 hollow = mProfileParams.getHollow();

View File

@@ -578,6 +578,9 @@ public:
BOOL importLegacyStream(std::istream& input_stream); BOOL importLegacyStream(std::istream& input_stream);
BOOL exportLegacyStream(std::ostream& output_stream) const; BOOL exportLegacyStream(std::ostream& output_stream) const;
LLSD sculptAsLLSD() const;
bool sculptFromLLSD(LLSD& sd);
LLSD asLLSD() const; LLSD asLLSD() const;
operator LLSD() const { return asLLSD(); } operator LLSD() const { return asLLSD(); }
bool fromLLSD(LLSD& sd); bool fromLLSD(LLSD& sd);
@@ -637,7 +640,7 @@ public:
const F32& getSkew() const { return mPathParams.getSkew(); } const F32& getSkew() const { return mPathParams.getSkew(); }
const LLUUID& getSculptID() const { return mSculptID; } const LLUUID& getSculptID() const { return mSculptID; }
const U8& getSculptType() const { return mSculptType; } const U8& getSculptType() const { return mSculptType; }
bool isSculpt() const;
BOOL isConvex() const; BOOL isConvex() const;
// 'begin' and 'end' should be in range [0, 1] (they will be clamped) // 'begin' and 'end' should be in range [0, 1] (they will be clamped)
@@ -686,6 +689,9 @@ public:
BOOL isFlat(S32 face) const { return (mFaces[face].mCount == 2); } BOOL isFlat(S32 face) const { return (mFaces[face].mCount == 2); }
BOOL isOpen() const { return mOpen; } BOOL isOpen() const { return mOpen; }
void setDirty() { mDirty = TRUE; } void setDirty() { mDirty = TRUE; }
static S32 getNumPoints(const LLProfileParams& params, BOOL path_open, F32 detail = 1.0f, S32 split = 0,
BOOL is_sculpted = FALSE, S32 sculpt_size = 0);
BOOL generate(const LLProfileParams& params, BOOL path_open, F32 detail = 1.0f, S32 split = 0, BOOL generate(const LLProfileParams& params, BOOL path_open, F32 detail = 1.0f, S32 split = 0,
BOOL is_sculpted = FALSE, S32 sculpt_size = 0); BOOL is_sculpted = FALSE, S32 sculpt_size = 0);
BOOL isConcave() const { return mConcave; } BOOL isConcave() const { return mConcave; }
@@ -710,6 +716,7 @@ public:
protected: protected:
void genNormals(const LLProfileParams& params); void genNormals(const LLProfileParams& params);
static S32 getNumNGonPoints(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0);
void genNGon(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0); void genNGon(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0);
Face* addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split = 0); Face* addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split = 0);
@@ -752,6 +759,9 @@ public:
virtual ~LLPath(); virtual ~LLPath();
static S32 getNumPoints(const LLPathParams& params, F32 detail);
static S32 getNumNGonPoints(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f);
void genNGon(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f); void genNGon(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f);
virtual BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0, virtual BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0,
BOOL is_sculpted = FALSE, S32 sculpt_size = 0); BOOL is_sculpted = FALSE, S32 sculpt_size = 0);
@@ -895,11 +905,14 @@ public:
S32 getSculptLevel() const { return mSculptLevel; } S32 getSculptLevel() const { return mSculptLevel; }
void setSculptLevel(S32 level) { mSculptLevel = level; } void setSculptLevel(S32 level) { mSculptLevel = level; }
S32 *getTriangleIndices(U32 &num_indices) const; S32 *getTriangleIndices(U32 &num_indices) const;
// returns number of triangle indeces required for path/profile mesh // returns number of triangle indeces required for path/profile mesh
S32 getNumTriangleIndices() const; S32 getNumTriangleIndices() const;
static void getLoDTriangleCounts(const LLVolumeParams& params, S32* counts);
S32 getNumTriangles() const;
void generateSilhouetteVertices(std::vector<LLVector3> &vertices, void generateSilhouetteVertices(std::vector<LLVector3> &vertices,
std::vector<LLVector3> &normals, std::vector<LLVector3> &normals,