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;
}
//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
// Bevel parameter is currently unused but presumedly would support
// filleted and chamfered corners
@@ -661,6 +725,117 @@ LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F3
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,
@@ -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)
{
// 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;
}
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 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
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;
}
@@ -2435,6 +2690,11 @@ BOOL LLVolume::isFlat(S32 face)
}
bool LLVolumeParams::isSculpt() const
{
return mSculptID.notNull();
}
bool LLVolumeParams::operator==(const LLVolumeParams &params) const
{
return ( (getPathParams() == params.getPathParams()) &&
@@ -2468,7 +2728,6 @@ bool LLVolumeParams::operator<(const LLVolumeParams &params) const
return mSculptID < params.mSculptID;
}
return mSculptType < params.mSculptType;
@@ -3469,6 +3728,23 @@ S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
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
{
BOOL profile_open = getProfile().isOpen();
@@ -3526,6 +3802,20 @@ S32 LLVolume::getNumTriangleIndices() const
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()
//-----------------------------------------------------------------------------
@@ -4311,11 +4601,28 @@ BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const
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 sd = LLSD();
sd["path"] = mPathParams;
sd["profile"] = mProfileParams;
sd["sculpt"] = sculptAsLLSD();
return sd;
}
@@ -4323,6 +4630,8 @@ bool LLVolumeParams::fromLLSD(LLSD& sd)
{
mPathParams.fromLLSD(sd["path"]);
mProfileParams.fromLLSD(sd["profile"]);
sculptFromLLSD(sd["sculpt"]);
return true;
}
@@ -4365,6 +4674,12 @@ const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f; // 1/9 unity
// for collison purposes
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 hollow = mProfileParams.getHollow();