Bulk of mesh. Excluded via #if MESH_ENABLED. LLModel still needs updated for strided vbos, Collada SDK needs to be wrangled, and misc pieces need to be found and brought over. Skipping inventory stuff until meshes are at least displayable.
This commit is contained in:
@@ -2079,6 +2079,14 @@ LLVolume::LLVolume(const LLVolumeParams ¶ms, const F32 detail, const BOOL ge
|
||||
mFaceMask = 0x0;
|
||||
mDetail = detail;
|
||||
mSculptLevel = -2;
|
||||
#if MESH_ENABLED
|
||||
mIsTetrahedron = FALSE;
|
||||
mLODScaleBias.setVec(1,1,1);
|
||||
mHullPoints = NULL;
|
||||
mHullIndices = NULL;
|
||||
mNumHullPoints = 0;
|
||||
mNumHullIndices = 0;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// set defaults
|
||||
if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
|
||||
@@ -2386,9 +2394,461 @@ bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
|
||||
{
|
||||
//input stream is now pointing at a zlib compressed block of LLSD
|
||||
//decompress block
|
||||
LLSD mdl;
|
||||
if (!unzip_llsd(mdl, is, size))
|
||||
{
|
||||
llwarns << "not a valid mesh asset!" << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
U32 face_count = mdl.size();
|
||||
|
||||
if (face_count == 0)
|
||||
{ //no faces unpacked, treat as failed decode
|
||||
llwarns << "found no faces!" << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
mVolumeFaces.resize(face_count);
|
||||
|
||||
for (U32 i = 0; i < face_count; ++i)
|
||||
{
|
||||
LLVolumeFace& face = mVolumeFaces[i];
|
||||
|
||||
if (mdl[i].has("NoGeometry"))
|
||||
{ //face has no geometry, continue
|
||||
face.resizeIndices(3);
|
||||
face.resizeVertices(1);
|
||||
memset(face.mPositions, 0, sizeof(LLVector4a));
|
||||
memset(face.mNormals, 0, sizeof(LLVector4a));
|
||||
memset(face.mTexCoords, 0, sizeof(LLVector2));
|
||||
memset(face.mIndices, 0, sizeof(U16)*3);
|
||||
continue;
|
||||
}
|
||||
|
||||
LLSD::Binary pos = mdl[i]["Position"];
|
||||
LLSD::Binary norm = mdl[i]["Normal"];
|
||||
LLSD::Binary tc = mdl[i]["TexCoord0"];
|
||||
LLSD::Binary idx = mdl[i]["TriangleList"];
|
||||
|
||||
|
||||
|
||||
//copy out indices
|
||||
face.resizeIndices(idx.size()/2);
|
||||
|
||||
if (idx.empty() || face.mNumIndices < 3)
|
||||
{ //why is there an empty index list?
|
||||
llwarns <<"Empty face present!" << llendl;
|
||||
continue;
|
||||
}
|
||||
|
||||
U16* indices = (U16*) &(idx[0]);
|
||||
U32 count = idx.size()/2;
|
||||
for (U32 j = 0; j < count; ++j)
|
||||
{
|
||||
face.mIndices[j] = indices[j];
|
||||
}
|
||||
|
||||
//copy out vertices
|
||||
U32 num_verts = pos.size()/(3*2);
|
||||
face.resizeVertices(num_verts);
|
||||
|
||||
LLVector3 minp;
|
||||
LLVector3 maxp;
|
||||
LLVector2 min_tc;
|
||||
LLVector2 max_tc;
|
||||
|
||||
minp.setValue(mdl[i]["PositionDomain"]["Min"]);
|
||||
maxp.setValue(mdl[i]["PositionDomain"]["Max"]);
|
||||
LLVector4a min_pos, max_pos;
|
||||
min_pos.load3(minp.mV);
|
||||
max_pos.load3(maxp.mV);
|
||||
|
||||
min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]);
|
||||
max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]);
|
||||
|
||||
LLVector4a pos_range;
|
||||
pos_range.setSub(max_pos, min_pos);
|
||||
LLVector2 tc_range2 = max_tc - min_tc;
|
||||
LLVector4a tc_range;
|
||||
tc_range.set(tc_range2[0], tc_range2[1], tc_range2[0], tc_range2[1]);
|
||||
LLVector4a min_tc4(min_tc[0], min_tc[1], min_tc[0], min_tc[1]);
|
||||
|
||||
LLVector4a* pos_out = face.mPositions;
|
||||
LLVector4a* norm_out = face.mNormals;
|
||||
LLVector4a* tc_out = (LLVector4a*) face.mTexCoords;
|
||||
|
||||
{
|
||||
U16* v = (U16*) &(pos[0]);
|
||||
for (U32 j = 0; j < num_verts; ++j)
|
||||
{
|
||||
pos_out->set((F32) v[0], (F32) v[1], (F32) v[2]);
|
||||
pos_out->div(65535.f);
|
||||
pos_out->mul(pos_range);
|
||||
pos_out->add(min_pos);
|
||||
pos_out++;
|
||||
v += 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
U16* n = (U16*) &(norm[0]);
|
||||
if(n)
|
||||
{
|
||||
for (U32 j = 0; j < num_verts; ++j)
|
||||
{
|
||||
norm_out->set((F32) n[0], (F32) n[1], (F32) n[2]);
|
||||
norm_out->div(65535.f);
|
||||
norm_out->mul(2.f);
|
||||
norm_out->sub(1.f);
|
||||
norm_out++;
|
||||
n += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
U16* t = (U16*) &(tc[0]);
|
||||
if(t)
|
||||
{
|
||||
for (U32 j = 0; j < num_verts; j+=2)
|
||||
{
|
||||
if (j < num_verts-1)
|
||||
{
|
||||
tc_out->set((F32) t[0], (F32) t[1], (F32) t[2], (F32) t[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
tc_out->set((F32) t[0], (F32) t[1], 0.f, 0.f);
|
||||
}
|
||||
|
||||
t += 4;
|
||||
|
||||
tc_out->div(65535.f);
|
||||
tc_out->mul(tc_range);
|
||||
tc_out->add(min_tc4);
|
||||
|
||||
tc_out++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mdl[i].has("Weights"))
|
||||
{
|
||||
face.allocateWeights(num_verts);
|
||||
|
||||
LLSD::Binary weights = mdl[i]["Weights"];
|
||||
|
||||
U32 idx = 0;
|
||||
|
||||
U32 cur_vertex = 0;
|
||||
while (idx < weights.size() && cur_vertex < num_verts)
|
||||
{
|
||||
const U8 END_INFLUENCES = 0xFF;
|
||||
U8 joint = weights[idx++];
|
||||
|
||||
U32 cur_influence = 0;
|
||||
LLVector4 wght(0,0,0,0);
|
||||
|
||||
while (joint != END_INFLUENCES && idx < weights.size())
|
||||
{
|
||||
U16 influence = weights[idx++];
|
||||
influence |= ((U16) weights[idx++] << 8);
|
||||
|
||||
F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f);
|
||||
wght.mV[cur_influence++] = (F32) joint + w;
|
||||
|
||||
if (cur_influence >= 4)
|
||||
{
|
||||
joint = END_INFLUENCES;
|
||||
}
|
||||
else
|
||||
{
|
||||
joint = weights[idx++];
|
||||
}
|
||||
}
|
||||
|
||||
face.mWeights[cur_vertex].loadua(wght.mV);
|
||||
|
||||
cur_vertex++;
|
||||
}
|
||||
|
||||
if (cur_vertex != num_verts || idx != weights.size())
|
||||
{
|
||||
llwarns << "Vertex weight count does not match vertex count!" << llendl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// modifier flags?
|
||||
bool do_mirror = (mParams.getSculptType() & LL_SCULPT_FLAG_MIRROR);
|
||||
bool do_invert = (mParams.getSculptType() &LL_SCULPT_FLAG_INVERT);
|
||||
|
||||
|
||||
// translate to actions:
|
||||
bool do_reflect_x = false;
|
||||
bool do_reverse_triangles = false;
|
||||
bool do_invert_normals = false;
|
||||
|
||||
if (do_mirror)
|
||||
{
|
||||
do_reflect_x = true;
|
||||
do_reverse_triangles = !do_reverse_triangles;
|
||||
}
|
||||
|
||||
if (do_invert)
|
||||
{
|
||||
do_invert_normals = true;
|
||||
do_reverse_triangles = !do_reverse_triangles;
|
||||
}
|
||||
|
||||
// now do the work
|
||||
|
||||
if (do_reflect_x)
|
||||
{
|
||||
LLVector4a* p = (LLVector4a*) face.mPositions;
|
||||
LLVector4a* n = (LLVector4a*) face.mNormals;
|
||||
|
||||
for (S32 i = 0; i < face.mNumVertices; i++)
|
||||
{
|
||||
p[i].mul(-1.0f);
|
||||
n[i].mul(-1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (do_invert_normals)
|
||||
{
|
||||
LLVector4a* n = (LLVector4a*) face.mNormals;
|
||||
|
||||
for (S32 i = 0; i < face.mNumVertices; i++)
|
||||
{
|
||||
n[i].mul(-1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (do_reverse_triangles)
|
||||
{
|
||||
for (U32 j = 0; j < face.mNumIndices; j += 3)
|
||||
{
|
||||
// swap the 2nd and 3rd index
|
||||
S32 swap = face.mIndices[j+1];
|
||||
face.mIndices[j+1] = face.mIndices[j+2];
|
||||
face.mIndices[j+2] = swap;
|
||||
}
|
||||
}
|
||||
|
||||
//calculate bounding box
|
||||
LLVector4a& min = face.mExtents[0];
|
||||
LLVector4a& max = face.mExtents[1];
|
||||
|
||||
if (face.mNumVertices < 3)
|
||||
{ //empty face, use a dummy 1cm (at 1m scale) bounding box
|
||||
min.splat(-0.005f);
|
||||
max.splat(0.005f);
|
||||
}
|
||||
else
|
||||
{
|
||||
min = max = face.mPositions[0];
|
||||
|
||||
for (S32 i = 1; i < face.mNumVertices; ++i)
|
||||
{
|
||||
min.setMin(min, face.mPositions[i]);
|
||||
max.setMax(max, face.mPositions[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mSculptLevel = 0; // success!
|
||||
|
||||
cacheOptimize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void tetrahedron_set_normal(LLVolumeFace::VertexData* cv)
|
||||
{
|
||||
LLVector4a v0;
|
||||
v0.setSub(cv[1].getPosition(), cv[0].getNormal());
|
||||
LLVector4a v1;
|
||||
v1.setSub(cv[2].getNormal(), cv[0].getPosition());
|
||||
|
||||
cv[0].getNormal().setCross3(v0,v1);
|
||||
cv[0].getNormal().normalize3fast();
|
||||
cv[1].setNormal(cv[0].getNormal());
|
||||
cv[2].setNormal(cv[1].getNormal());
|
||||
}
|
||||
|
||||
BOOL LLVolume::isTetrahedron()
|
||||
{
|
||||
return mIsTetrahedron;
|
||||
}
|
||||
|
||||
void LLVolume::makeTetrahedron()
|
||||
{
|
||||
mVolumeFaces.clear();
|
||||
|
||||
LLVolumeFace face;
|
||||
|
||||
F32 x = 0.25f;
|
||||
LLVector4a p[] =
|
||||
{ //unit tetrahedron corners
|
||||
LLVector4a(x,x,x),
|
||||
LLVector4a(-x,-x,x),
|
||||
LLVector4a(-x,x,-x),
|
||||
LLVector4a(x,-x,-x)
|
||||
};
|
||||
|
||||
face.mExtents[0].splat(-x);
|
||||
face.mExtents[1].splat(x);
|
||||
|
||||
LLVolumeFace::VertexData cv[3];
|
||||
|
||||
//set texture coordinates
|
||||
cv[0].mTexCoord = LLVector2(0,0);
|
||||
cv[1].mTexCoord = LLVector2(1,0);
|
||||
cv[2].mTexCoord = LLVector2(0.5f, 0.5f*F_SQRT3);
|
||||
|
||||
|
||||
//side 1
|
||||
cv[0].setPosition(p[1]);
|
||||
cv[1].setPosition(p[0]);
|
||||
cv[2].setPosition(p[2]);
|
||||
|
||||
tetrahedron_set_normal(cv);
|
||||
|
||||
face.resizeVertices(12);
|
||||
face.resizeIndices(12);
|
||||
|
||||
LLVector4a* v = (LLVector4a*) face.mPositions;
|
||||
LLVector4a* n = (LLVector4a*) face.mNormals;
|
||||
LLVector2* tc = (LLVector2*) face.mTexCoords;
|
||||
|
||||
v[0] = cv[0].getPosition();
|
||||
v[1] = cv[1].getPosition();
|
||||
v[2] = cv[2].getPosition();
|
||||
v += 3;
|
||||
|
||||
n[0] = cv[0].getNormal();
|
||||
n[1] = cv[1].getNormal();
|
||||
n[2] = cv[2].getNormal();
|
||||
n += 3;
|
||||
|
||||
tc[0] = cv[0].mTexCoord;
|
||||
tc[1] = cv[1].mTexCoord;
|
||||
tc[2] = cv[2].mTexCoord;
|
||||
tc += 3;
|
||||
|
||||
|
||||
//side 2
|
||||
cv[0].setPosition(p[3]);
|
||||
cv[1].setPosition(p[0]);
|
||||
cv[2].setPosition(p[1]);
|
||||
|
||||
tetrahedron_set_normal(cv);
|
||||
|
||||
v[0] = cv[0].getPosition();
|
||||
v[1] = cv[1].getPosition();
|
||||
v[2] = cv[2].getPosition();
|
||||
v += 3;
|
||||
|
||||
n[0] = cv[0].getNormal();
|
||||
n[1] = cv[1].getNormal();
|
||||
n[2] = cv[2].getNormal();
|
||||
n += 3;
|
||||
|
||||
tc[0] = cv[0].mTexCoord;
|
||||
tc[1] = cv[1].mTexCoord;
|
||||
tc[2] = cv[2].mTexCoord;
|
||||
tc += 3;
|
||||
|
||||
//side 3
|
||||
cv[0].setPosition(p[3]);
|
||||
cv[1].setPosition(p[1]);
|
||||
cv[2].setPosition(p[2]);
|
||||
|
||||
tetrahedron_set_normal(cv);
|
||||
|
||||
v[0] = cv[0].getPosition();
|
||||
v[1] = cv[1].getPosition();
|
||||
v[2] = cv[2].getPosition();
|
||||
v += 3;
|
||||
|
||||
n[0] = cv[0].getNormal();
|
||||
n[1] = cv[1].getNormal();
|
||||
n[2] = cv[2].getNormal();
|
||||
n += 3;
|
||||
|
||||
tc[0] = cv[0].mTexCoord;
|
||||
tc[1] = cv[1].mTexCoord;
|
||||
tc[2] = cv[2].mTexCoord;
|
||||
tc += 3;
|
||||
|
||||
//side 4
|
||||
cv[0].setPosition(p[2]);
|
||||
cv[1].setPosition(p[0]);
|
||||
cv[2].setPosition(p[3]);
|
||||
|
||||
tetrahedron_set_normal(cv);
|
||||
|
||||
v[0] = cv[0].getPosition();
|
||||
v[1] = cv[1].getPosition();
|
||||
v[2] = cv[2].getPosition();
|
||||
v += 3;
|
||||
|
||||
n[0] = cv[0].getNormal();
|
||||
n[1] = cv[1].getNormal();
|
||||
n[2] = cv[2].getNormal();
|
||||
n += 3;
|
||||
|
||||
tc[0] = cv[0].mTexCoord;
|
||||
tc[1] = cv[1].mTexCoord;
|
||||
tc[2] = cv[2].mTexCoord;
|
||||
tc += 3;
|
||||
|
||||
//set index buffer
|
||||
for (U16 i = 0; i < 12; i++)
|
||||
{
|
||||
face.mIndices[i] = i;
|
||||
}
|
||||
|
||||
mVolumeFaces.push_back(face);
|
||||
mSculptLevel = 0;
|
||||
mIsTetrahedron = TRUE;
|
||||
}
|
||||
|
||||
void LLVolume::copyVolumeFaces(const LLVolume* volume)
|
||||
{
|
||||
mVolumeFaces = volume->mVolumeFaces;
|
||||
mSculptLevel = 0;
|
||||
mIsTetrahedron = FALSE;
|
||||
}
|
||||
|
||||
void LLVolume::cacheOptimize()
|
||||
{
|
||||
for (S32 i = 0; i < mVolumeFaces.size(); ++i)
|
||||
{
|
||||
mVolumeFaces[i].cacheOptimize();
|
||||
}
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
S32 LLVolume::getNumFaces() const
|
||||
{
|
||||
#if MESH_ENABLED
|
||||
U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK);
|
||||
|
||||
if (sculpt_type == LL_SCULPT_TYPE_MESH)
|
||||
{
|
||||
return LL_SCULPT_MESH_MAX_FACES;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
return (S32)mProfilep->mFaces.size();
|
||||
}
|
||||
|
||||
@@ -2854,6 +3314,13 @@ bool LLVolumeParams::isSculpt() const
|
||||
return mSculptID.notNull();
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
bool LLVolumeParams::isMeshSculpt() const
|
||||
{
|
||||
return isSculpt() && ((mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH);
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
bool LLVolumeParams::operator==(const LLVolumeParams ¶ms) const
|
||||
{
|
||||
return ( (getPathParams() == params.getPathParams()) &&
|
||||
@@ -3999,6 +4466,13 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
|
||||
vertices.clear();
|
||||
normals.clear();
|
||||
|
||||
#if MESH_ENABLED
|
||||
if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
S32 cur_index = 0;
|
||||
//for each face
|
||||
for (face_list_t::iterator iter = mVolumeFaces.begin();
|
||||
@@ -4191,7 +4665,6 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
|
||||
norm_mat.rotate(n[v2], t);
|
||||
t.normalize3fast();
|
||||
normals.push_back(LLVector3(t[0], t[1], t[2]));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5072,6 +5545,9 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
|
||||
mBinormals(NULL),
|
||||
mTexCoords(NULL),
|
||||
mIndices(NULL),
|
||||
#if MESH_ENABLED
|
||||
mWeights(NULL),
|
||||
#endif //MESH_ENABLED
|
||||
mOctree(NULL)
|
||||
{
|
||||
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
|
||||
@@ -5128,6 +5604,18 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
|
||||
mBinormals = NULL;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
if (src.mWeights)
|
||||
{
|
||||
allocateWeights(src.mNumVertices);
|
||||
LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
ll_aligned_free_16(mWeights);
|
||||
mWeights = NULL;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
}
|
||||
if (mNumIndices)
|
||||
{
|
||||
@@ -5160,6 +5648,10 @@ void LLVolumeFace::freeData()
|
||||
mIndices = NULL;
|
||||
ll_aligned_free_16(mBinormals);
|
||||
mBinormals = NULL;
|
||||
#if MESH_ENABLED
|
||||
ll_aligned_free_16(mWeights);
|
||||
mWeights = NULL;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
delete mOctree;
|
||||
mOctree = NULL;
|
||||
@@ -5685,6 +6177,13 @@ void LLVolumeFace::cacheOptimize()
|
||||
S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
|
||||
LLVector2* tc = (LLVector2*) ll_aligned_malloc_16(size);
|
||||
|
||||
#if MESH_ENABLED
|
||||
LLVector4a* wght = NULL;
|
||||
if (mWeights)
|
||||
{
|
||||
wght = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
LLVector4a* binorm = NULL;
|
||||
if (mBinormals)
|
||||
@@ -5708,6 +6207,12 @@ void LLVolumeFace::cacheOptimize()
|
||||
pos[cur_idx] = mPositions[idx];
|
||||
norm[cur_idx] = mNormals[idx];
|
||||
tc[cur_idx] = mTexCoords[idx];
|
||||
#if MESH_ENABLED
|
||||
if (mWeights)
|
||||
{
|
||||
wght[cur_idx] = mWeights[idx];
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
if (mBinormals)
|
||||
{
|
||||
binorm[cur_idx] = mBinormals[idx];
|
||||
@@ -5725,11 +6230,17 @@ void LLVolumeFace::cacheOptimize()
|
||||
ll_aligned_free_16(mPositions);
|
||||
ll_aligned_free_16(mNormals);
|
||||
ll_aligned_free_16(mTexCoords);
|
||||
#if MESH_ENABLED
|
||||
ll_aligned_free_16(mWeights);
|
||||
#endif //MESH_ENABLED
|
||||
ll_aligned_free_16(mBinormals);
|
||||
|
||||
mPositions = pos;
|
||||
mNormals = norm;
|
||||
mTexCoords = tc;
|
||||
#if MESH_ENABLED
|
||||
mWeights = wght;
|
||||
#endif //MESH_ENABLED
|
||||
mBinormals = binorm;
|
||||
|
||||
//std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks);
|
||||
@@ -6512,6 +7023,14 @@ void LLVolumeFace::allocateBinormals(S32 num_verts)
|
||||
mBinormals = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
void LLVolumeFace::allocateWeights(S32 num_verts)
|
||||
{
|
||||
ll_aligned_free_16(mWeights);
|
||||
mWeights = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
void LLVolumeFace::resizeIndices(S32 num_indices)
|
||||
{
|
||||
ll_aligned_free_16(mIndices);
|
||||
@@ -6673,8 +7192,9 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
|
||||
{
|
||||
resizeVertices(num_vertices);
|
||||
resizeIndices(num_indices);
|
||||
|
||||
//if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH)
|
||||
#if MESH_ENABLED
|
||||
if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH)
|
||||
#endif //MESH_ENABLED
|
||||
{
|
||||
mEdge.resize(num_indices);
|
||||
}
|
||||
|
||||
@@ -191,12 +191,21 @@ const U8 LL_SCULPT_TYPE_SPHERE = 1;
|
||||
const U8 LL_SCULPT_TYPE_TORUS = 2;
|
||||
const U8 LL_SCULPT_TYPE_PLANE = 3;
|
||||
const U8 LL_SCULPT_TYPE_CYLINDER = 4;
|
||||
|
||||
#if MESH_ENABLED
|
||||
const U8 LL_SCULPT_TYPE_MESH = 5;
|
||||
const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
|
||||
LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH;
|
||||
#endif //MESH_ENABLED
|
||||
#if !MESH_ENABLED
|
||||
const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | LL_SCULPT_TYPE_CYLINDER;
|
||||
#endif //!MESH_ENABLED
|
||||
|
||||
const U8 LL_SCULPT_FLAG_INVERT = 64;
|
||||
const U8 LL_SCULPT_FLAG_MIRROR = 128;
|
||||
|
||||
#if MESH_ENABLED
|
||||
const S32 LL_SCULPT_MESH_MAX_FACES = 8;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
class LLProfileParams
|
||||
{
|
||||
@@ -646,6 +655,9 @@ public:
|
||||
const LLUUID& getSculptID() const { return mSculptID; }
|
||||
const U8& getSculptType() const { return mSculptType; }
|
||||
bool isSculpt() const;
|
||||
#if MESH_ENABLED
|
||||
bool isMeshSculpt() const;
|
||||
#endif //MESH_ENABLED
|
||||
BOOL isConvex() const;
|
||||
|
||||
// 'begin' and 'end' should be in range [0, 1] (they will be clamped)
|
||||
@@ -853,6 +865,9 @@ public:
|
||||
|
||||
void resizeVertices(S32 num_verts);
|
||||
void allocateBinormals(S32 num_verts);
|
||||
#if MESH_ENABLED
|
||||
void allocateWeights(S32 num_verts);
|
||||
#endif //MESH_ENABLED
|
||||
void resizeIndices(S32 num_indices);
|
||||
void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx);
|
||||
|
||||
@@ -923,6 +938,14 @@ public:
|
||||
U16* mIndices;
|
||||
|
||||
std::vector<S32> mEdge;
|
||||
|
||||
#if MESH_ENABLED
|
||||
//list of skin weights for rigged volumes
|
||||
// format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight>
|
||||
// mWeights.size() should be empty or match mVertices.size()
|
||||
LLVector4a* mWeights;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
LLOctreeNode<LLVolumeTriangle>* mOctree;
|
||||
|
||||
private:
|
||||
@@ -1053,11 +1076,20 @@ private:
|
||||
protected:
|
||||
BOOL generate();
|
||||
void createVolumeFaces();
|
||||
#if MESH_ENABLED
|
||||
public:
|
||||
virtual bool unpackVolumeFaces(std::istream& is, S32 size);
|
||||
|
||||
virtual void makeTetrahedron();
|
||||
virtual BOOL isTetrahedron();
|
||||
#endif //MESH_ENABLED
|
||||
protected:
|
||||
BOOL mUnique;
|
||||
F32 mDetail;
|
||||
S32 mSculptLevel;
|
||||
#if MESH_ENABLED
|
||||
BOOL mIsTetrahedron;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
LLVolumeParams mParams;
|
||||
LLPath *mPathp;
|
||||
@@ -1067,6 +1099,14 @@ protected:
|
||||
BOOL mGenerateSingleFace;
|
||||
typedef std::vector<LLVolumeFace> face_list_t;
|
||||
face_list_t mVolumeFaces;
|
||||
|
||||
#if MESH_ENABLED
|
||||
public:
|
||||
LLVector4a* mHullPoints;
|
||||
U16* mHullIndices;
|
||||
S32 mNumHullPoints;
|
||||
S32 mNumHullIndices;
|
||||
#endif //MESH_ENABLED
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
const F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f
|
||||
const F32 MIN_OBJECT_Z = -256.f;
|
||||
const F32 DEFAULT_MAX_PRIM_SCALE = 256.f;
|
||||
#if MESH_ENABLED
|
||||
const F32 DEFAULT_MAX_PRIM_SCALE_NO_MESH = DEFAULT_MAX_PRIM_SCALE;
|
||||
#endif //MESH_ENABLED
|
||||
const F32 MIN_PRIM_SCALE = 0.01f;
|
||||
const F32 MAX_PRIM_SCALE = 65536.f; // something very high but not near FLT_MAX
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ include_directories(
|
||||
|
||||
set(llprimitive_SOURCE_FILES
|
||||
llmaterialtable.cpp
|
||||
#llmodel.cpp
|
||||
llprimitive.cpp
|
||||
llprimtexturelist.cpp
|
||||
lltextureanim.cpp
|
||||
@@ -32,6 +33,7 @@ set(llprimitive_HEADER_FILES
|
||||
|
||||
legacy_object_types.h
|
||||
llmaterialtable.h
|
||||
#llmodel.h
|
||||
llprimitive.h
|
||||
llprimtexturelist.h
|
||||
lltextureanim.h
|
||||
|
||||
2318
indra/llprimitive/llmodel.cpp
Normal file
2318
indra/llprimitive/llmodel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
257
indra/llprimitive/llmodel.h
Normal file
257
indra/llprimitive/llmodel.h
Normal file
@@ -0,0 +1,257 @@
|
||||
/**
|
||||
* @file llmodel.h
|
||||
* @brief Model handling class definitions
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLMODEL_H
|
||||
#define LL_LLMODEL_H
|
||||
|
||||
#include "llpointer.h"
|
||||
#include "llvolume.h"
|
||||
#include "v4math.h"
|
||||
#include "m4math.h"
|
||||
|
||||
class daeElement;
|
||||
class domMesh;
|
||||
|
||||
#define MAX_MODEL_FACES 8
|
||||
|
||||
|
||||
class LLMeshSkinInfo
|
||||
{
|
||||
public:
|
||||
LLUUID mMeshID;
|
||||
std::vector<std::string> mJointNames;
|
||||
std::vector<LLMatrix4> mInvBindMatrix;
|
||||
std::vector<LLMatrix4> mAlternateBindMatrix;
|
||||
std::map<std::string, U32> mJointMap;
|
||||
|
||||
LLMeshSkinInfo() { }
|
||||
LLMeshSkinInfo(LLSD& data);
|
||||
void fromLLSD(LLSD& data);
|
||||
LLSD asLLSD(bool include_joints) const;
|
||||
LLMatrix4 mBindShapeMatrix;
|
||||
float mPelvisOffset;
|
||||
};
|
||||
|
||||
class LLModel : public LLVolume
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
LOD_IMPOSTOR = 0,
|
||||
LOD_LOW,
|
||||
LOD_MEDIUM,
|
||||
LOD_HIGH,
|
||||
LOD_PHYSICS,
|
||||
NUM_LODS
|
||||
};
|
||||
|
||||
enum EModelStatus
|
||||
{
|
||||
NO_ERRORS = 0,
|
||||
VERTEX_NUMBER_OVERFLOW, //vertex number is >= 65535.
|
||||
BAD_ELEMENT,
|
||||
INVALID_STATUS
|
||||
} ;
|
||||
|
||||
//convex_hull_decomposition is a vector of convex hulls
|
||||
//each convex hull is a set of points
|
||||
typedef std::vector<std::vector<LLVector3> > convex_hull_decomposition;
|
||||
typedef std::vector<LLVector3> hull;
|
||||
|
||||
class PhysicsMesh
|
||||
{
|
||||
public:
|
||||
std::vector<LLVector3> mPositions;
|
||||
std::vector<LLVector3> mNormals;
|
||||
|
||||
void clear()
|
||||
{
|
||||
mPositions.clear();
|
||||
mNormals.clear();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return mPositions.empty();
|
||||
}
|
||||
};
|
||||
|
||||
class Decomposition
|
||||
{
|
||||
public:
|
||||
Decomposition() { }
|
||||
Decomposition(LLSD& data);
|
||||
void fromLLSD(LLSD& data);
|
||||
LLSD asLLSD() const;
|
||||
bool hasHullList() const;
|
||||
|
||||
void merge(const Decomposition* rhs);
|
||||
|
||||
LLUUID mMeshID;
|
||||
LLModel::convex_hull_decomposition mHull;
|
||||
LLModel::hull mBaseHull;
|
||||
|
||||
std::vector<LLModel::PhysicsMesh> mMesh;
|
||||
LLModel::PhysicsMesh mBaseHullMesh;
|
||||
LLModel::PhysicsMesh mPhysicsShapeMesh;
|
||||
};
|
||||
|
||||
LLModel(LLVolumeParams& params, F32 detail);
|
||||
~LLModel();
|
||||
|
||||
bool loadModel(std::istream& is);
|
||||
bool loadSkinInfo(LLSD& header, std::istream& is);
|
||||
bool loadDecomposition(LLSD& header, std::istream& is);
|
||||
|
||||
static LLSD writeModel(
|
||||
std::ostream& ostr,
|
||||
LLModel* physics,
|
||||
LLModel* high,
|
||||
LLModel* medium,
|
||||
LLModel* low,
|
||||
LLModel* imposotr,
|
||||
const LLModel::Decomposition& decomp,
|
||||
BOOL upload_skin,
|
||||
BOOL upload_joints,
|
||||
BOOL nowrite = FALSE);
|
||||
|
||||
static LLSD writeModelToStream(
|
||||
std::ostream& ostr,
|
||||
LLSD& mdl,
|
||||
BOOL nowrite = FALSE);
|
||||
|
||||
static LLModel* loadModelFromDomMesh(domMesh* mesh);
|
||||
static std::string getElementLabel(daeElement* element);
|
||||
std::string getName() const;
|
||||
EModelStatus getStatus() const {return mStatus;}
|
||||
static std::string getStatusString(U32 status) ;
|
||||
|
||||
void appendFaces(LLModel* model, LLMatrix4& transform, LLMatrix4& normal_transform);
|
||||
void appendFace(const LLVolumeFace& src_face, std::string src_material, LLMatrix4& mat, LLMatrix4& norm_mat);
|
||||
|
||||
void setNumVolumeFaces(S32 count);
|
||||
void setVolumeFaceData(
|
||||
S32 f,
|
||||
LLStrider<LLVector3> pos,
|
||||
LLStrider<LLVector3> norm,
|
||||
LLStrider<LLVector2> tc,
|
||||
LLStrider<U16> ind,
|
||||
U32 num_verts,
|
||||
U32 num_indices);
|
||||
|
||||
void generateNormals(F32 angle_cutoff);
|
||||
|
||||
void addFace(const LLVolumeFace& face);
|
||||
|
||||
void normalizeVolumeFaces();
|
||||
void optimizeVolumeFaces();
|
||||
void offsetMesh( const LLVector3& pivotPoint );
|
||||
void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out);
|
||||
std::vector<std::string> mMaterialList;
|
||||
|
||||
//data used for skin weights
|
||||
class JointWeight
|
||||
{
|
||||
public:
|
||||
S32 mJointIdx;
|
||||
F32 mWeight;
|
||||
|
||||
JointWeight()
|
||||
{
|
||||
mJointIdx = 0;
|
||||
mWeight = 0.f;
|
||||
}
|
||||
|
||||
JointWeight(S32 idx, F32 weight)
|
||||
: mJointIdx(idx), mWeight(weight)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator<(const JointWeight& rhs) const
|
||||
{
|
||||
if (mWeight == rhs.mWeight)
|
||||
{
|
||||
return mJointIdx < rhs.mJointIdx;
|
||||
}
|
||||
|
||||
return mWeight < rhs.mWeight;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct CompareWeightGreater
|
||||
{
|
||||
bool operator()(const JointWeight& lhs, const JointWeight& rhs)
|
||||
{
|
||||
return rhs < lhs; // strongest = first
|
||||
}
|
||||
};
|
||||
|
||||
//copy of position array for this model -- mPosition[idx].mV[X,Y,Z]
|
||||
std::vector<LLVector3> mPosition;
|
||||
|
||||
//map of positions to skin weights --- mSkinWeights[pos].mV[0..4] == <joint_index>.<weight>
|
||||
//joint_index corresponds to mJointList
|
||||
typedef std::vector<JointWeight> weight_list;
|
||||
typedef std::map<LLVector3, weight_list > weight_map;
|
||||
weight_map mSkinWeights;
|
||||
|
||||
//get list of weight influences closest to given position
|
||||
weight_list& getJointInfluences(const LLVector3& pos);
|
||||
|
||||
LLMeshSkinInfo mSkinInfo;
|
||||
|
||||
std::string mRequestedLabel; // name requested in UI, if any.
|
||||
std::string mLabel; // name computed from dae.
|
||||
|
||||
LLVector3 mNormalizedScale;
|
||||
LLVector3 mNormalizedTranslation;
|
||||
|
||||
float mPelvisOffset;
|
||||
// convex hull decomposition
|
||||
S32 mDecompID;
|
||||
|
||||
void setConvexHullDecomposition(
|
||||
const convex_hull_decomposition& decomp);
|
||||
void updateHullCenters();
|
||||
|
||||
LLVector3 mCenterOfHullCenters;
|
||||
std::vector<LLVector3> mHullCenter;
|
||||
U32 mHullPoints;
|
||||
|
||||
//ID for storing this model in a .slm file
|
||||
S32 mLocalID;
|
||||
|
||||
Decomposition mPhysics;
|
||||
|
||||
EModelStatus mStatus ;
|
||||
protected:
|
||||
void addVolumeFacesFromDomMesh(domMesh* mesh);
|
||||
virtual BOOL createVolumeFacesFromDomMesh(domMesh *mesh);
|
||||
};
|
||||
|
||||
#endif //LL_LLMODEL_H
|
||||
@@ -573,7 +573,9 @@ BOOL LLAgentCamera::calcCameraMinDistance(F32 &obj_min_distance)
|
||||
BOOL soft_limit = FALSE; // is the bounding box to be treated literally (volumes) or as an approximation (avatars)
|
||||
|
||||
if (!mFocusObject || mFocusObject->isDead() ||
|
||||
//mFocusObject->isMesh() ||
|
||||
#if MESH_ENABLED
|
||||
mFocusObject->isMesh() ||
|
||||
#endif //MESH_ENABLED
|
||||
gSavedSettings.getBOOL("DisableCameraConstraints"))
|
||||
{
|
||||
obj_min_distance = 0.f;
|
||||
|
||||
@@ -52,6 +52,9 @@
|
||||
#include "llwindow.h"
|
||||
#include "llviewerstats.h"
|
||||
#include "llmd5.h"
|
||||
#if MESH_ENABLED
|
||||
#include "llmeshrepository.h"
|
||||
#endif //MESH_ENABLED
|
||||
#include "llpumpio.h"
|
||||
#include "llimpanel.h"
|
||||
#include "llmimetypes.h"
|
||||
@@ -1110,6 +1113,9 @@ bool LLAppViewer::mainLoop()
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if MESH_ENABLED
|
||||
gMeshRepo.update() ;
|
||||
#endif //MESH_ENABLED
|
||||
if ((LLStartUp::getStartupState() >= STATE_CLEANUP) &&
|
||||
(frameTimer.getElapsedTimeF64() > FRAME_STALL_THRESHOLD))
|
||||
{
|
||||
@@ -1233,6 +1239,11 @@ bool LLAppViewer::cleanup()
|
||||
|
||||
llinfos << "Cleaning Up" << llendflush;
|
||||
|
||||
#if MESH_ENABLED
|
||||
// shut down mesh streamer
|
||||
gMeshRepo.shutdown();
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// Must clean up texture references before viewer window is destroyed.
|
||||
if(LLHUDManager::instanceExists())
|
||||
{
|
||||
@@ -1655,6 +1666,11 @@ bool LLAppViewer::initThreads()
|
||||
LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), sImageDecodeThread, enable_threads && true);
|
||||
LLImage::initClass();
|
||||
|
||||
|
||||
#if MESH_ENABLED
|
||||
// Mesh streaming and caching
|
||||
gMeshRepo.init();
|
||||
#endif //MESH_ENABLED
|
||||
// *FIX: no error handling here!
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -269,6 +269,9 @@ public:
|
||||
REBUILD_GEOMETRY= REBUILD_POSITION|REBUILD_TCOORD|REBUILD_COLOR,
|
||||
REBUILD_MATERIAL= REBUILD_TCOORD|REBUILD_COLOR,
|
||||
REBUILD_ALL = REBUILD_GEOMETRY|REBUILD_VOLUME,
|
||||
#if MESH_ENABLED
|
||||
REBUILD_RIGGED = 0x00008000,
|
||||
#endif //MESH_ENABLED
|
||||
ON_SHIFT_LIST = 0x00010000,
|
||||
BLOCKER = 0x00020000,
|
||||
ACTIVE = 0x00040000,
|
||||
@@ -280,6 +283,9 @@ public:
|
||||
CLEAR_INVISIBLE = 0x01000000, // clear FORCE_INVISIBLE next draw frame
|
||||
REBUILD_SHADOW = 0x02000000,
|
||||
HAS_ALPHA = 0x04000000,
|
||||
#if MESH_ENABLED
|
||||
RIGGED = 0x08000000,
|
||||
#endif //MESH_ENABLED
|
||||
PARTITION_MOVE = 0x10000000,
|
||||
} EDrawableFlags;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,12 @@
|
||||
#include "lldrawpool.h"
|
||||
|
||||
class LLVOAvatar;
|
||||
class LLGLSLShader;
|
||||
class LLFace;
|
||||
class LLMeshSkinInfo;
|
||||
class LLVolume;
|
||||
class LLVolumeFace;
|
||||
|
||||
|
||||
class LLDrawPoolAvatar : public LLFacePool
|
||||
{
|
||||
@@ -102,6 +108,105 @@ public:
|
||||
void endDeferredImpostor();
|
||||
void endDeferredRigid();
|
||||
void endDeferredSkinned();
|
||||
|
||||
void beginPostDeferredAlpha();
|
||||
void endPostDeferredAlpha();
|
||||
|
||||
#if MESH_ENABLED
|
||||
void beginRiggedSimple();
|
||||
void beginRiggedFullbright();
|
||||
void beginRiggedFullbrightShiny();
|
||||
void beginRiggedShinySimple();
|
||||
void beginRiggedAlpha();
|
||||
void beginRiggedFullbrightAlpha();
|
||||
void beginRiggedGlow();
|
||||
void beginDeferredRiggedAlpha();
|
||||
|
||||
void endRiggedSimple();
|
||||
void endRiggedFullbright();
|
||||
void endRiggedFullbrightShiny();
|
||||
void endRiggedShinySimple();
|
||||
void endRiggedAlpha();
|
||||
void endRiggedFullbrightAlpha();
|
||||
void endRiggedGlow();
|
||||
void endDeferredRiggedAlpha();
|
||||
|
||||
void beginDeferredRiggedSimple();
|
||||
void beginDeferredRiggedBump();
|
||||
|
||||
void endDeferredRiggedSimple();
|
||||
void endDeferredRiggedBump();
|
||||
|
||||
void updateRiggedFaceVertexBuffer(LLVOAvatar* avatar,
|
||||
LLFace* facep,
|
||||
const LLMeshSkinInfo* skin,
|
||||
LLVolume* volume,
|
||||
const LLVolumeFace& vol_face);
|
||||
|
||||
void renderRigged(LLVOAvatar* avatar, U32 type, bool glow = false);
|
||||
void renderRiggedSimple(LLVOAvatar* avatar);
|
||||
void renderRiggedAlpha(LLVOAvatar* avatar);
|
||||
void renderRiggedFullbrightAlpha(LLVOAvatar* avatar);
|
||||
void renderRiggedFullbright(LLVOAvatar* avatar);
|
||||
void renderRiggedShinySimple(LLVOAvatar* avatar);
|
||||
void renderRiggedFullbrightShiny(LLVOAvatar* avatar);
|
||||
void renderRiggedGlow(LLVOAvatar* avatar);
|
||||
void renderDeferredRiggedSimple(LLVOAvatar* avatar);
|
||||
void renderDeferredRiggedBump(LLVOAvatar* avatar);
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RIGGED_SIMPLE = 0,
|
||||
RIGGED_FULLBRIGHT,
|
||||
RIGGED_SHINY,
|
||||
RIGGED_FULLBRIGHT_SHINY,
|
||||
RIGGED_GLOW,
|
||||
RIGGED_ALPHA,
|
||||
RIGGED_FULLBRIGHT_ALPHA,
|
||||
RIGGED_DEFERRED_BUMP,
|
||||
RIGGED_DEFERRED_SIMPLE,
|
||||
NUM_RIGGED_PASSES,
|
||||
RIGGED_UNKNOWN,
|
||||
} eRiggedPass;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RIGGED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX |
|
||||
LLVertexBuffer::MAP_NORMAL |
|
||||
LLVertexBuffer::MAP_TEXCOORD0 |
|
||||
LLVertexBuffer::MAP_COLOR |
|
||||
LLVertexBuffer::MAP_WEIGHT4,
|
||||
RIGGED_FULLBRIGHT_MASK = LLVertexBuffer::MAP_VERTEX |
|
||||
LLVertexBuffer::MAP_TEXCOORD0 |
|
||||
LLVertexBuffer::MAP_COLOR |
|
||||
LLVertexBuffer::MAP_WEIGHT4,
|
||||
RIGGED_SHINY_MASK = RIGGED_SIMPLE_MASK,
|
||||
RIGGED_FULLBRIGHT_SHINY_MASK = RIGGED_SIMPLE_MASK,
|
||||
RIGGED_GLOW_MASK = LLVertexBuffer::MAP_VERTEX |
|
||||
LLVertexBuffer::MAP_TEXCOORD0 |
|
||||
LLVertexBuffer::MAP_WEIGHT4,
|
||||
RIGGED_ALPHA_MASK = RIGGED_SIMPLE_MASK,
|
||||
RIGGED_FULLBRIGHT_ALPHA_MASK = RIGGED_FULLBRIGHT_MASK,
|
||||
RIGGED_DEFERRED_BUMP_MASK = LLVertexBuffer::MAP_VERTEX |
|
||||
LLVertexBuffer::MAP_NORMAL |
|
||||
LLVertexBuffer::MAP_TEXCOORD0 |
|
||||
LLVertexBuffer::MAP_BINORMAL |
|
||||
LLVertexBuffer::MAP_COLOR |
|
||||
LLVertexBuffer::MAP_WEIGHT4,
|
||||
RIGGED_DEFERRED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX |
|
||||
LLVertexBuffer::MAP_NORMAL |
|
||||
LLVertexBuffer::MAP_TEXCOORD0 |
|
||||
LLVertexBuffer::MAP_COLOR |
|
||||
LLVertexBuffer::MAP_WEIGHT4,
|
||||
} eRiggedDataMask;
|
||||
|
||||
void addRiggedFace(LLFace* facep, U32 type);
|
||||
void removeRiggedFace(LLFace* facep);
|
||||
|
||||
std::vector<LLFace*> mRiggedFace[NUM_RIGGED_PASSES];
|
||||
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
/*virtual*/ LLViewerTexture *getDebugTexture();
|
||||
/*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
|
||||
@@ -110,6 +215,9 @@ public:
|
||||
|
||||
static BOOL sSkipOpaque;
|
||||
static BOOL sSkipTransparent;
|
||||
static S32 sDiffuseChannel;
|
||||
|
||||
static LLGLSLShader* sVertexProgram;
|
||||
};
|
||||
|
||||
class LLVertexBufferAvatar : public LLVertexBuffer
|
||||
|
||||
@@ -205,7 +205,17 @@ void LLFace::destroy()
|
||||
|
||||
if (mDrawPoolp)
|
||||
{
|
||||
mDrawPoolp->removeFace(this);
|
||||
#if MESH_ENABLED
|
||||
if (this->isState(LLFace::RIGGED) && mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR)
|
||||
{
|
||||
((LLDrawPoolAvatar*) mDrawPoolp)->removeRiggedFace(this);
|
||||
}
|
||||
else
|
||||
#endif //MESH_ENABLED
|
||||
{
|
||||
mDrawPoolp->removeFace(this);
|
||||
}
|
||||
|
||||
mDrawPoolp = NULL;
|
||||
}
|
||||
|
||||
@@ -550,11 +560,40 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
|
||||
}
|
||||
|
||||
glColor4fv(color.mV);
|
||||
mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
|
||||
#if !LL_RELEASE_FOR_DOWNLOAD
|
||||
LLGLState::checkClientArrays("", LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
|
||||
#endif
|
||||
mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
|
||||
#if MESH_ENABLED
|
||||
if (mDrawablep->isState(LLDrawable::RIGGED))
|
||||
{
|
||||
LLVOVolume* volume = mDrawablep->getVOVolume();
|
||||
if (volume)
|
||||
{
|
||||
LLRiggedVolume* rigged = volume->getRiggedVolume();
|
||||
if (rigged)
|
||||
{
|
||||
LLGLEnable offset(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(-1.f, -1.f);
|
||||
glMultMatrixf((F32*) volume->getRelativeXform().mMatrix);
|
||||
const LLVolumeFace& vol_face = rigged->getVolumeFace(getTEOffset());
|
||||
LLVertexBuffer::unbind();
|
||||
glVertexPointer(3, GL_FLOAT, 16, vol_face.mPositions);
|
||||
if (vol_face.mTexCoords)
|
||||
{
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, 8, vol_face.mTexCoords);
|
||||
}
|
||||
glDrawElements(GL_TRIANGLES, vol_face.mNumIndices, GL_UNSIGNED_SHORT, vol_face.mIndices);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif //MESH_ENABLED
|
||||
{
|
||||
mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
|
||||
#if !LL_RELEASE_FOR_DOWNLOAD
|
||||
LLGLState::checkClientArrays("", LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
|
||||
#endif
|
||||
mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
|
||||
}
|
||||
|
||||
gGL.popMatrix();
|
||||
}
|
||||
@@ -733,7 +772,11 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
|
||||
LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
|
||||
|
||||
//get bounding box
|
||||
if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
|
||||
if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION
|
||||
#if MESH_ENABLED
|
||||
| LLDrawable::REBUILD_RIGGED
|
||||
#endif //MESH_ENABLED
|
||||
))
|
||||
{
|
||||
//VECTORIZE THIS
|
||||
LLMatrix4a mat_vert;
|
||||
@@ -1096,6 +1139,9 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
|
||||
LLStrider<LLColor4U> colors;
|
||||
LLStrider<LLVector3> binormals;
|
||||
LLStrider<U16> indicesp;
|
||||
#if MESH_ENABLED
|
||||
LLStrider<LLVector3> weights;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
BOOL full_rebuild = force_rebuild || mDrawablep->isState(LLDrawable::REBUILD_VOLUME);
|
||||
|
||||
@@ -1115,7 +1161,9 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
|
||||
bool rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD);
|
||||
bool rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
|
||||
bool rebuild_binormal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_BINORMAL);
|
||||
|
||||
#if MESH_ENABLED
|
||||
bool rebuild_weights = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_WEIGHT4);
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
const LLTextureEntry *tep = mVObjp->getTE(f);
|
||||
if (!tep) rebuild_color = FALSE; // can't get color when tep is NULL
|
||||
@@ -1133,6 +1181,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
|
||||
{
|
||||
mVertexBuffer->getBinormalStrider(binormals, mGeomIndex);
|
||||
}
|
||||
#if MESH_ENABLED
|
||||
if (rebuild_weights)
|
||||
{
|
||||
mVertexBuffer->getWeight4Strider(weights, mGeomIndex);
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
if (rebuild_tcoord)
|
||||
{
|
||||
@@ -1538,6 +1592,15 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
|
||||
}
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
if (rebuild_weights && vf.mWeights)
|
||||
{
|
||||
for (S32 i = 0; i < num_vertices; i++)
|
||||
{
|
||||
weights[i].set(weights.getF32ptr());
|
||||
}
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
if (rebuild_color)
|
||||
{
|
||||
@@ -1959,3 +2022,68 @@ void LLFace::clearVertexBuffer()
|
||||
mLastVertexBuffer = NULL;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
//static
|
||||
U32 LLFace::getRiggedDataMask(U32 type)
|
||||
{
|
||||
static const U32 rigged_data_mask[] = {
|
||||
LLDrawPoolAvatar::RIGGED_SIMPLE_MASK,
|
||||
LLDrawPoolAvatar::RIGGED_FULLBRIGHT_MASK,
|
||||
LLDrawPoolAvatar::RIGGED_SHINY_MASK,
|
||||
LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY_MASK,
|
||||
LLDrawPoolAvatar::RIGGED_GLOW_MASK,
|
||||
LLDrawPoolAvatar::RIGGED_ALPHA_MASK,
|
||||
LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA_MASK,
|
||||
LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP_MASK,
|
||||
LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE_MASK,
|
||||
};
|
||||
|
||||
llassert(type < sizeof(rigged_data_mask)/sizeof(U32));
|
||||
|
||||
return rigged_data_mask[type];
|
||||
}
|
||||
|
||||
U32 LLFace::getRiggedVertexBufferDataMask() const
|
||||
{
|
||||
U32 data_mask = 0;
|
||||
for (U32 i = 0; i < mRiggedIndex.size(); ++i)
|
||||
{
|
||||
if (mRiggedIndex[i] > -1)
|
||||
{
|
||||
data_mask |= LLFace::getRiggedDataMask(i);
|
||||
}
|
||||
}
|
||||
|
||||
return data_mask;
|
||||
}
|
||||
|
||||
S32 LLFace::getRiggedIndex(U32 type) const
|
||||
{
|
||||
if (mRiggedIndex.empty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
llassert(type < mRiggedIndex.size());
|
||||
|
||||
return mRiggedIndex[type];
|
||||
}
|
||||
|
||||
void LLFace::setRiggedIndex(U32 type, S32 index)
|
||||
{
|
||||
if (mRiggedIndex.empty())
|
||||
{
|
||||
mRiggedIndex.resize(LLDrawPoolAvatar::NUM_RIGGED_PASSES);
|
||||
for (U32 i = 0; i < mRiggedIndex.size(); ++i)
|
||||
{
|
||||
mRiggedIndex[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
llassert(type < mRiggedIndex.size());
|
||||
|
||||
mRiggedIndex[type] = index;
|
||||
}
|
||||
|
||||
|
||||
#endif //MESH_ENABLED
|
||||
@@ -83,6 +83,9 @@ public:
|
||||
HUD_RENDER = 0x0008,
|
||||
USE_FACE_COLOR = 0x0010,
|
||||
TEXTURE_ANIM = 0x0020,
|
||||
#if MESH_ENABLED
|
||||
RIGGED = 0x0040,
|
||||
#endif //MESH_ENABLED
|
||||
};
|
||||
|
||||
static void initClass();
|
||||
@@ -212,6 +215,13 @@ public:
|
||||
void setVertexBuffer(LLVertexBuffer* buffer);
|
||||
void clearVertexBuffer(); //sets mVertexBuffer and mLastVertexBuffer to NULL
|
||||
LLVertexBuffer* getVertexBuffer() const { return mVertexBuffer; }
|
||||
#if MESH_ENABLED
|
||||
U32 getRiggedVertexBufferDataMask() const;
|
||||
S32 getRiggedIndex(U32 type) const;
|
||||
void setRiggedIndex(U32 type, S32 index);
|
||||
|
||||
static U32 getRiggedDataMask(U32 type);
|
||||
#endif //MESH_ENABLED
|
||||
public: //aligned members
|
||||
LLVector4a mExtents[2];
|
||||
|
||||
@@ -264,6 +274,10 @@ private:
|
||||
S32 mTEOffset;
|
||||
|
||||
S32 mReferenceIndex;
|
||||
#if MESH_ENABLED
|
||||
std::vector<S32> mRiggedIndex;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
F32 mVSize;
|
||||
F32 mPixelArea;
|
||||
|
||||
|
||||
@@ -91,6 +91,28 @@ const LLManip::EManipPart MANIPULATOR_IDS[NUM_MANIPULATORS] =
|
||||
};
|
||||
|
||||
|
||||
F32 get_default_max_prim_scale(bool is_flora)
|
||||
{
|
||||
// a bit of a hack, but if it's foilage, we don't want to use the
|
||||
// new larger scale which would result in giant trees and grass
|
||||
#if MESH_ENABLED
|
||||
if (gSavedSettings.getBOOL("MeshEnabled") &&
|
||||
gAgent.getRegion() &&
|
||||
!gAgent.getRegion()->getCapability("GetMesh").empty() &&
|
||||
!gAgent.getRegion()->getCapability("ObjectAdd").empty() &&
|
||||
!is_flora)
|
||||
{
|
||||
return DEFAULT_MAX_PRIM_SCALE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return DEFAULT_MAX_PRIM_SCALE_NO_MESH;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
#if !MESH_ENABLED
|
||||
return DEFAULT_MAX_PRIM_SCALE;
|
||||
#endif //!MESH_ENABLED
|
||||
}
|
||||
|
||||
// static
|
||||
void LLManipScale::setUniform(BOOL b)
|
||||
@@ -953,8 +975,8 @@ void LLManipScale::dragCorner( S32 x, S32 y )
|
||||
mInSnapRegime = FALSE;
|
||||
}
|
||||
|
||||
F32 max_scale_factor = DEFAULT_MAX_PRIM_SCALE / MIN_PRIM_SCALE;
|
||||
F32 min_scale_factor = MIN_PRIM_SCALE / DEFAULT_MAX_PRIM_SCALE;
|
||||
F32 max_scale_factor = get_default_max_prim_scale() / MIN_PRIM_SCALE;
|
||||
F32 min_scale_factor = MIN_PRIM_SCALE / get_default_max_prim_scale();
|
||||
|
||||
// find max and min scale factors that will make biggest object hit max absolute scale and smallest object hit min absolute scale
|
||||
for (LLObjectSelection::iterator iter = mObjectSelection->begin();
|
||||
@@ -966,7 +988,7 @@ void LLManipScale::dragCorner( S32 x, S32 y )
|
||||
{
|
||||
const LLVector3& scale = selectNode->mSavedScale;
|
||||
|
||||
F32 cur_max_scale_factor = llmin( DEFAULT_MAX_PRIM_SCALE / scale.mV[VX], DEFAULT_MAX_PRIM_SCALE / scale.mV[VY], DEFAULT_MAX_PRIM_SCALE / scale.mV[VZ] );
|
||||
F32 cur_max_scale_factor = llmin( get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VX], get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VY], get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VZ] );
|
||||
max_scale_factor = llmin( max_scale_factor, cur_max_scale_factor );
|
||||
|
||||
F32 cur_min_scale_factor = llmax( MIN_PRIM_SCALE / scale.mV[VX], MIN_PRIM_SCALE / scale.mV[VY], MIN_PRIM_SCALE / scale.mV[VZ] );
|
||||
@@ -1263,7 +1285,7 @@ void LLManipScale::stretchFace( const LLVector3& drag_start_agent, const LLVecto
|
||||
|
||||
F32 denom = axis * dir_local;
|
||||
F32 desired_delta_size = is_approx_zero(denom) ? 0.f : (delta_local_mag / denom); // in meters
|
||||
F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE);
|
||||
F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, MIN_PRIM_SCALE, get_default_max_prim_scale(LLPickInfo::isFlora(cur)));
|
||||
// propagate scale constraint back to position offset
|
||||
desired_delta_size = desired_scale - selectNode->mSavedScale.mV[axis_index]; // propagate constraint back to position
|
||||
|
||||
@@ -1964,7 +1986,7 @@ F32 LLManipScale::partToMaxScale( S32 part, const LLBBox &bbox ) const
|
||||
max_extent = bbox_extents.mV[i];
|
||||
}
|
||||
}
|
||||
max_scale_factor = bbox_extents.magVec() * DEFAULT_MAX_PRIM_SCALE / max_extent;
|
||||
max_scale_factor = bbox_extents.magVec() * get_default_max_prim_scale() / max_extent;
|
||||
|
||||
if (getUniform())
|
||||
{
|
||||
@@ -1979,7 +2001,7 @@ F32 LLManipScale::partToMinScale( S32 part, const LLBBox &bbox ) const
|
||||
{
|
||||
LLVector3 bbox_extents = unitVectorToLocalBBoxExtent( partToUnitVector( part ), bbox );
|
||||
bbox_extents.abs();
|
||||
F32 min_extent = DEFAULT_MAX_PRIM_SCALE;
|
||||
F32 min_extent = get_default_max_prim_scale();
|
||||
for (U32 i = VX; i <= VZ; i++)
|
||||
{
|
||||
if (bbox_extents.mV[i] > 0.f && bbox_extents.mV[i] < min_extent)
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
#include "llviewerobject.h"
|
||||
#include "llbbox.h"
|
||||
|
||||
|
||||
F32 get_default_max_prim_scale(bool is_flora = false);
|
||||
|
||||
class LLToolComposite;
|
||||
class LLColor4;
|
||||
|
||||
|
||||
3870
indra/newview/llmeshrepository.cpp
Normal file
3870
indra/newview/llmeshrepository.cpp
Normal file
File diff suppressed because it is too large
Load Diff
552
indra/newview/llmeshrepository.h
Normal file
552
indra/newview/llmeshrepository.h
Normal file
@@ -0,0 +1,552 @@
|
||||
/**
|
||||
* @file llmeshrepository.h
|
||||
* @brief Client-side repository of mesh assets.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_MESH_REPOSITORY_H
|
||||
#define LL_MESH_REPOSITORY_H
|
||||
|
||||
#include "llassettype.h"
|
||||
#include "llmodel.h"
|
||||
#include "lluuid.h"
|
||||
#include "llviewertexture.h"
|
||||
#include "llvolume.h"
|
||||
|
||||
#define LLCONVEXDECOMPINTER_STATIC 1
|
||||
|
||||
#include "llconvexdecomposition.h"
|
||||
|
||||
class LLVOVolume;
|
||||
class LLMeshResponder;
|
||||
class LLCurlRequest;
|
||||
class LLMutex;
|
||||
class LLCondition;
|
||||
class LLVFS;
|
||||
class LLMeshRepository;
|
||||
|
||||
class LLMeshUploadData
|
||||
{
|
||||
public:
|
||||
LLPointer<LLModel> mBaseModel;
|
||||
LLPointer<LLModel> mModel[5];
|
||||
LLUUID mUUID;
|
||||
U32 mRetries;
|
||||
std::string mRSVP;
|
||||
std::string mAssetData;
|
||||
LLSD mPostData;
|
||||
|
||||
LLMeshUploadData()
|
||||
{
|
||||
mRetries = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class LLTextureUploadData
|
||||
{
|
||||
public:
|
||||
LLViewerFetchedTexture* mTexture;
|
||||
LLUUID mUUID;
|
||||
std::string mRSVP;
|
||||
std::string mLabel;
|
||||
U32 mRetries;
|
||||
std::string mAssetData;
|
||||
LLSD mPostData;
|
||||
|
||||
LLTextureUploadData()
|
||||
{
|
||||
mRetries = 0;
|
||||
}
|
||||
|
||||
LLTextureUploadData(LLViewerFetchedTexture* texture, std::string& label)
|
||||
: mTexture(texture), mLabel(label)
|
||||
{
|
||||
mRetries = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class LLImportMaterial
|
||||
{
|
||||
public:
|
||||
LLPointer<LLViewerFetchedTexture> mDiffuseMap;
|
||||
std::string mDiffuseMapFilename;
|
||||
std::string mDiffuseMapLabel;
|
||||
LLColor4 mDiffuseColor;
|
||||
bool mFullbright;
|
||||
|
||||
bool operator<(const LLImportMaterial ¶ms) const;
|
||||
|
||||
LLImportMaterial()
|
||||
: mFullbright(false)
|
||||
{
|
||||
mDiffuseColor.set(1,1,1,1);
|
||||
}
|
||||
|
||||
LLImportMaterial(LLSD& data);
|
||||
|
||||
LLSD asLLSD();
|
||||
};
|
||||
|
||||
class LLModelInstance
|
||||
{
|
||||
public:
|
||||
LLPointer<LLModel> mModel;
|
||||
LLPointer<LLModel> mLOD[5];
|
||||
|
||||
std::string mLabel;
|
||||
|
||||
LLUUID mMeshID;
|
||||
S32 mLocalMeshID;
|
||||
|
||||
LLMatrix4 mTransform;
|
||||
std::vector<LLImportMaterial> mMaterial;
|
||||
|
||||
LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::vector<LLImportMaterial>& materials)
|
||||
: mModel(model), mLabel(label), mTransform(transform), mMaterial(materials)
|
||||
{
|
||||
mLocalMeshID = -1;
|
||||
}
|
||||
|
||||
LLModelInstance(LLSD& data);
|
||||
|
||||
LLSD asLLSD();
|
||||
};
|
||||
|
||||
class LLPhysicsDecomp : public LLThread
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::map<std::string, LLSD> decomp_params;
|
||||
|
||||
class Request : public LLRefCount
|
||||
{
|
||||
public:
|
||||
//input params
|
||||
S32* mDecompID;
|
||||
std::string mStage;
|
||||
std::vector<LLVector3> mPositions;
|
||||
std::vector<U16> mIndices;
|
||||
decomp_params mParams;
|
||||
|
||||
//output state
|
||||
std::string mStatusMessage;
|
||||
std::vector<LLModel::PhysicsMesh> mHullMesh;
|
||||
LLModel::convex_hull_decomposition mHull;
|
||||
|
||||
//status message callback, called from decomposition thread
|
||||
virtual S32 statusCallback(const char* status, S32 p1, S32 p2) = 0;
|
||||
|
||||
//completed callback, called from the main thread
|
||||
virtual void completed() = 0;
|
||||
|
||||
virtual void setStatusMessage(const std::string& msg);
|
||||
};
|
||||
|
||||
LLCondition* mSignal;
|
||||
LLMutex* mMutex;
|
||||
|
||||
bool mInited;
|
||||
bool mQuitting;
|
||||
bool mDone;
|
||||
|
||||
LLPhysicsDecomp();
|
||||
~LLPhysicsDecomp();
|
||||
|
||||
void shutdown();
|
||||
|
||||
void submitRequest(Request* request);
|
||||
static S32 llcdCallback(const char*, S32, S32);
|
||||
void cancel();
|
||||
|
||||
void setMeshData(LLCDMeshData& mesh);
|
||||
void doDecomposition();
|
||||
void doDecompositionSingleHull();
|
||||
|
||||
virtual void run();
|
||||
|
||||
void completeCurrent();
|
||||
void notifyCompleted();
|
||||
|
||||
std::map<std::string, S32> mStageID;
|
||||
|
||||
typedef std::queue<LLPointer<Request> > request_queue;
|
||||
request_queue mRequestQ;
|
||||
|
||||
LLPointer<Request> mCurRequest;
|
||||
|
||||
std::queue<LLPointer<Request> > mCompletedQ;
|
||||
|
||||
};
|
||||
|
||||
class LLMeshRepoThread : public LLThread
|
||||
{
|
||||
public:
|
||||
|
||||
static S32 sActiveHeaderRequests;
|
||||
static S32 sActiveLODRequests;
|
||||
static U32 sMaxConcurrentRequests;
|
||||
|
||||
LLCurlRequest* mCurlRequest;
|
||||
LLMutex* mMutex;
|
||||
LLMutex* mHeaderMutex;
|
||||
LLCondition* mSignal;
|
||||
|
||||
bool mWaiting;
|
||||
|
||||
//map of known mesh headers
|
||||
typedef std::map<LLUUID, LLSD> mesh_header_map;
|
||||
mesh_header_map mMeshHeader;
|
||||
|
||||
std::map<LLUUID, U32> mMeshHeaderSize;
|
||||
std::map<LLUUID, U32> mMeshResourceCost;
|
||||
|
||||
class HeaderRequest
|
||||
{
|
||||
public:
|
||||
const LLVolumeParams mMeshParams;
|
||||
|
||||
HeaderRequest(const LLVolumeParams& mesh_params)
|
||||
: mMeshParams(mesh_params)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator<(const HeaderRequest& rhs) const
|
||||
{
|
||||
return mMeshParams < rhs.mMeshParams;
|
||||
}
|
||||
};
|
||||
|
||||
class LODRequest
|
||||
{
|
||||
public:
|
||||
LLVolumeParams mMeshParams;
|
||||
S32 mLOD;
|
||||
F32 mScore;
|
||||
|
||||
LODRequest(const LLVolumeParams& mesh_params, S32 lod)
|
||||
: mMeshParams(mesh_params), mLOD(lod), mScore(0.f)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct CompareScoreGreater
|
||||
{
|
||||
bool operator()(const LODRequest& lhs, const LODRequest& rhs)
|
||||
{
|
||||
return lhs.mScore > rhs.mScore; // greatest = first
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class LoadedMesh
|
||||
{
|
||||
public:
|
||||
LLPointer<LLVolume> mVolume;
|
||||
LLVolumeParams mMeshParams;
|
||||
S32 mLOD;
|
||||
|
||||
LoadedMesh(LLVolume* volume, const LLVolumeParams& mesh_params, S32 lod)
|
||||
: mVolume(volume), mMeshParams(mesh_params), mLOD(lod)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//set of requested skin info
|
||||
std::set<LLUUID> mSkinRequests;
|
||||
|
||||
//queue of completed skin info requests
|
||||
std::queue<LLMeshSkinInfo> mSkinInfoQ;
|
||||
|
||||
//set of requested decompositions
|
||||
std::set<LLUUID> mDecompositionRequests;
|
||||
|
||||
//set of requested physics shapes
|
||||
std::set<LLUUID> mPhysicsShapeRequests;
|
||||
|
||||
//queue of completed Decomposition info requests
|
||||
std::queue<LLModel::Decomposition*> mDecompositionQ;
|
||||
|
||||
//queue of requested headers
|
||||
std::queue<HeaderRequest> mHeaderReqQ;
|
||||
|
||||
//queue of requested LODs
|
||||
std::queue<LODRequest> mLODReqQ;
|
||||
|
||||
//queue of unavailable LODs (either asset doesn't exist or asset doesn't have desired LOD)
|
||||
std::queue<LODRequest> mUnavailableQ;
|
||||
|
||||
//queue of successfully loaded meshes
|
||||
std::queue<LoadedMesh> mLoadedQ;
|
||||
|
||||
//map of pending header requests and currently desired LODs
|
||||
typedef std::map<LLVolumeParams, std::vector<S32> > pending_lod_map;
|
||||
pending_lod_map mPendingLOD;
|
||||
|
||||
static std::string constructUrl(LLUUID mesh_id);
|
||||
|
||||
LLMeshRepoThread();
|
||||
~LLMeshRepoThread();
|
||||
|
||||
virtual void run();
|
||||
|
||||
void loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
|
||||
bool fetchMeshHeader(const LLVolumeParams& mesh_params);
|
||||
bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
|
||||
bool headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size);
|
||||
bool lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size);
|
||||
bool skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
|
||||
bool decompositionReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
|
||||
bool physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size);
|
||||
LLSD& getMeshHeader(const LLUUID& mesh_id);
|
||||
|
||||
void notifyLoadedMeshes();
|
||||
S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
|
||||
U32 getResourceCost(const LLUUID& mesh_params);
|
||||
|
||||
void loadMeshSkinInfo(const LLUUID& mesh_id);
|
||||
void loadMeshDecomposition(const LLUUID& mesh_id);
|
||||
void loadMeshPhysicsShape(const LLUUID& mesh_id);
|
||||
|
||||
//send request for skin info, returns true if header info exists
|
||||
// (should hold onto mesh_id and try again later if header info does not exist)
|
||||
bool fetchMeshSkinInfo(const LLUUID& mesh_id);
|
||||
|
||||
//send request for decomposition, returns true if header info exists
|
||||
// (should hold onto mesh_id and try again later if header info does not exist)
|
||||
bool fetchMeshDecomposition(const LLUUID& mesh_id);
|
||||
|
||||
//send request for PhysicsShape, returns true if header info exists
|
||||
// (should hold onto mesh_id and try again later if header info does not exist)
|
||||
bool fetchMeshPhysicsShape(const LLUUID& mesh_id);
|
||||
|
||||
|
||||
};
|
||||
|
||||
class LLMeshUploadThread : public LLThread
|
||||
{
|
||||
public:
|
||||
class DecompRequest : public LLPhysicsDecomp::Request
|
||||
{
|
||||
public:
|
||||
LLPointer<LLModel> mModel;
|
||||
LLPointer<LLModel> mBaseModel;
|
||||
|
||||
LLMeshUploadThread* mThread;
|
||||
|
||||
DecompRequest(LLModel* mdl, LLModel* base_model, LLMeshUploadThread* thread);
|
||||
|
||||
S32 statusCallback(const char* status, S32 p1, S32 p2) { return 1; }
|
||||
void completed();
|
||||
};
|
||||
|
||||
LLPointer<DecompRequest> mFinalDecomp;
|
||||
bool mPhysicsComplete;
|
||||
|
||||
typedef std::map<LLPointer<LLModel>, std::vector<LLVector3> > hull_map;
|
||||
hull_map mHullMap;
|
||||
|
||||
typedef std::vector<LLModelInstance> instance_list;
|
||||
instance_list mInstanceList;
|
||||
|
||||
typedef std::map<LLPointer<LLModel>, instance_list> instance_map;
|
||||
instance_map mInstance;
|
||||
|
||||
LLMutex* mMutex;
|
||||
LLCurlRequest* mCurlRequest;
|
||||
S32 mPendingConfirmations;
|
||||
S32 mPendingUploads;
|
||||
S32 mPendingCost;
|
||||
LLVector3 mOrigin;
|
||||
bool mFinished;
|
||||
bool mUploadTextures;
|
||||
bool mUploadSkin;
|
||||
bool mUploadJoints;
|
||||
BOOL mDiscarded ;
|
||||
|
||||
LLHost mHost;
|
||||
std::string mUploadObjectAssetCapability;
|
||||
std::string mNewInventoryCapability;
|
||||
std::string mWholeModelFeeCapability;
|
||||
std::string mWholeModelUploadURL;
|
||||
|
||||
std::queue<LLMeshUploadData> mUploadQ;
|
||||
std::queue<LLMeshUploadData> mConfirmedQ;
|
||||
std::queue<LLModelInstance> mInstanceQ;
|
||||
|
||||
std::queue<LLTextureUploadData> mTextureQ;
|
||||
std::queue<LLTextureUploadData> mConfirmedTextureQ;
|
||||
|
||||
std::map<LLViewerFetchedTexture*, LLTextureUploadData> mTextureMap;
|
||||
|
||||
LLMeshUploadThread(instance_list& data, LLVector3& scale, bool upload_textures,
|
||||
bool upload_skin, bool upload_joints);
|
||||
~LLMeshUploadThread();
|
||||
|
||||
void uploadTexture(LLTextureUploadData& data);
|
||||
void doUploadTexture(LLTextureUploadData& data);
|
||||
void sendCostRequest(LLTextureUploadData& data);
|
||||
void priceResult(LLTextureUploadData& data, const LLSD& content);
|
||||
void onTextureUploaded(LLTextureUploadData& data);
|
||||
|
||||
void uploadModel(LLMeshUploadData& data);
|
||||
void sendCostRequest(LLMeshUploadData& data);
|
||||
void doUploadModel(LLMeshUploadData& data);
|
||||
void onModelUploaded(LLMeshUploadData& data);
|
||||
void createObjects(LLMeshUploadData& data);
|
||||
LLSD createObject(LLModelInstance& instance);
|
||||
void priceResult(LLMeshUploadData& data, const LLSD& content);
|
||||
|
||||
bool finished() { return mFinished; }
|
||||
virtual void run();
|
||||
void preStart();
|
||||
void discard() ;
|
||||
BOOL isDiscarded();
|
||||
|
||||
void doWholeModelUpload();
|
||||
void doIterativeUpload();
|
||||
|
||||
void wholeModelToLLSD(LLSD& dest, bool include_textures);
|
||||
|
||||
void decomposeMeshMatrix(LLMatrix4& transformation,
|
||||
LLVector3& result_pos,
|
||||
LLQuaternion& result_rot,
|
||||
LLVector3& result_scale);
|
||||
};
|
||||
|
||||
class LLMeshRepository
|
||||
{
|
||||
public:
|
||||
|
||||
//metrics
|
||||
static U32 sBytesReceived;
|
||||
static U32 sHTTPRequestCount;
|
||||
static U32 sHTTPRetryCount;
|
||||
static U32 sCacheBytesRead;
|
||||
static U32 sCacheBytesWritten;
|
||||
static U32 sPeakKbps;
|
||||
|
||||
static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1);
|
||||
|
||||
LLMeshRepository();
|
||||
|
||||
void init();
|
||||
void shutdown();
|
||||
S32 update() ;
|
||||
|
||||
//mesh management functions
|
||||
S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1);
|
||||
|
||||
void notifyLoadedMeshes();
|
||||
void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume);
|
||||
void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod);
|
||||
void notifySkinInfoReceived(LLMeshSkinInfo& info);
|
||||
void notifyDecompositionReceived(LLModel::Decomposition* info);
|
||||
|
||||
S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
|
||||
static S32 getActualMeshLOD(LLSD& header, S32 lod);
|
||||
U32 calcResourceCost(LLSD& header);
|
||||
U32 getResourceCost(const LLUUID& mesh_params);
|
||||
const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id);
|
||||
LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);
|
||||
void fetchPhysicsShape(const LLUUID& mesh_id);
|
||||
bool hasPhysicsShape(const LLUUID& mesh_id);
|
||||
|
||||
void buildHull(const LLVolumeParams& params, S32 detail);
|
||||
void buildPhysicsMesh(LLModel::Decomposition& decomp);
|
||||
|
||||
LLSD& getMeshHeader(const LLUUID& mesh_id);
|
||||
|
||||
void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
|
||||
bool upload_skin, bool upload_joints);
|
||||
|
||||
S32 getMeshSize(const LLUUID& mesh_id, S32 lod);
|
||||
|
||||
typedef std::map<LLVolumeParams, std::set<LLUUID> > mesh_load_map;
|
||||
mesh_load_map mLoadingMeshes[4];
|
||||
|
||||
typedef std::map<LLUUID, LLMeshSkinInfo> skin_map;
|
||||
skin_map mSkinMap;
|
||||
|
||||
typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map;
|
||||
decomposition_map mDecompositionMap;
|
||||
|
||||
LLMutex* mMeshMutex;
|
||||
|
||||
std::vector<LLMeshRepoThread::LODRequest> mPendingRequests;
|
||||
|
||||
//list of mesh ids awaiting skin info
|
||||
std::set<LLUUID> mLoadingSkins;
|
||||
|
||||
//list of mesh ids that need to send skin info fetch requests
|
||||
std::queue<LLUUID> mPendingSkinRequests;
|
||||
|
||||
//list of mesh ids awaiting decompositions
|
||||
std::set<LLUUID> mLoadingDecompositions;
|
||||
|
||||
//list of mesh ids that need to send decomposition fetch requests
|
||||
std::queue<LLUUID> mPendingDecompositionRequests;
|
||||
|
||||
//list of mesh ids awaiting physics shapes
|
||||
std::set<LLUUID> mLoadingPhysicsShapes;
|
||||
|
||||
//list of mesh ids that need to send physics shape fetch requests
|
||||
std::queue<LLUUID> mPendingPhysicsShapeRequests;
|
||||
|
||||
U32 mMeshThreadCount;
|
||||
|
||||
void cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header);
|
||||
|
||||
LLMeshRepoThread* mThread;
|
||||
std::vector<LLMeshUploadThread*> mUploads;
|
||||
std::vector<LLMeshUploadThread*> mUploadWaitList;
|
||||
|
||||
LLPhysicsDecomp* mDecompThread;
|
||||
|
||||
class inventory_data
|
||||
{
|
||||
public:
|
||||
LLSD mPostData;
|
||||
LLSD mResponse;
|
||||
|
||||
inventory_data(const LLSD& data, const LLSD& content)
|
||||
: mPostData(data), mResponse(content)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::queue<inventory_data> mInventoryQ;
|
||||
|
||||
std::queue<LLSD> mUploadErrorQ;
|
||||
|
||||
void uploadError(LLSD& args);
|
||||
void updateInventory(inventory_data data);
|
||||
|
||||
std::string mGetMeshCapability;
|
||||
|
||||
};
|
||||
|
||||
extern LLMeshRepository gMeshRepo;
|
||||
|
||||
#endif
|
||||
|
||||
210
indra/newview/llphysicsshapebuilderutil.cpp
Normal file
210
indra/newview/llphysicsshapebuilderutil.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* @file llphysicsshapebuilder.cpp
|
||||
* @brief Generic system to convert LL(Physics)VolumeParams to physics shapes
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llphysicsshapebuilderutil.h"
|
||||
|
||||
/* static */
|
||||
void LLPhysicsShapeBuilderUtil::determinePhysicsShape( const LLPhysicsVolumeParams& volume_params, const LLVector3& scale, PhysicsShapeSpecification& specOut )
|
||||
{
|
||||
const LLProfileParams& profile_params = volume_params.getProfileParams();
|
||||
const LLPathParams& path_params = volume_params.getPathParams();
|
||||
|
||||
specOut.mScale = scale;
|
||||
|
||||
const F32 avgScale = ( scale[VX] + scale[VY] + scale[VZ] )/3.0f;
|
||||
|
||||
// count the scale elements that are small
|
||||
S32 min_size_counts = 0;
|
||||
for (S32 i = 0; i < 3; ++i)
|
||||
{
|
||||
if (scale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE)
|
||||
{
|
||||
++min_size_counts;
|
||||
}
|
||||
}
|
||||
|
||||
const bool profile_complete = ( profile_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) &&
|
||||
( profile_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) );
|
||||
|
||||
const bool path_complete = ( path_params.getBegin() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale ) &&
|
||||
( path_params.getEnd() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) );
|
||||
|
||||
const bool simple_params = ( volume_params.getHollow() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_HOLLOW/avgScale )
|
||||
&& ( fabs(path_params.getShearX()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale )
|
||||
&& ( fabs(path_params.getShearY()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR/avgScale )
|
||||
&& ( !volume_params.isMeshSculpt() && !volume_params.isSculpt() );
|
||||
|
||||
if (simple_params && profile_complete)
|
||||
{
|
||||
// Try to create an implicit shape or convexified
|
||||
bool no_taper = ( fabs(path_params.getScaleX() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale )
|
||||
&& ( fabs(path_params.getScaleY() - 1.0f) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale );
|
||||
|
||||
bool no_twist = ( fabs(path_params.getTwistBegin()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale )
|
||||
&& ( fabs(path_params.getTwistEnd()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST/avgScale);
|
||||
|
||||
// Box
|
||||
if(
|
||||
( profile_params.getCurveType() == LL_PCODE_PROFILE_SQUARE )
|
||||
&& ( path_params.getCurveType() == LL_PCODE_PATH_LINE )
|
||||
&& no_taper
|
||||
&& no_twist
|
||||
)
|
||||
{
|
||||
specOut.mType = PhysicsShapeSpecification::BOX;
|
||||
if ( path_complete )
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Side lengths
|
||||
specOut.mScale[VX] = llmax( scale[VX], SHAPE_BUILDER_MIN_GEOMETRY_SIZE );
|
||||
specOut.mScale[VY] = llmax( scale[VY], SHAPE_BUILDER_MIN_GEOMETRY_SIZE );
|
||||
specOut.mScale[VZ] = llmax( scale[VZ] * (path_params.getEnd() - path_params.getBegin()), SHAPE_BUILDER_MIN_GEOMETRY_SIZE );
|
||||
|
||||
specOut.mCenter.set( 0.f, 0.f, 0.5f * scale[VZ] * ( path_params.getEnd() + path_params.getBegin() - 1.0f ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Sphere
|
||||
if( path_complete
|
||||
&& ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE_HALF )
|
||||
&& ( path_params.getCurveType() == LL_PCODE_PATH_CIRCLE )
|
||||
&& ( fabs(volume_params.getTaper()) <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER/avgScale )
|
||||
&& no_twist
|
||||
)
|
||||
{
|
||||
if ( ( scale[VX] == scale[VZ] )
|
||||
&& ( scale[VY] == scale[VZ] ) )
|
||||
{
|
||||
// perfect sphere
|
||||
specOut.mType = PhysicsShapeSpecification::SPHERE;
|
||||
specOut.mScale = scale;
|
||||
return;
|
||||
}
|
||||
else if (min_size_counts > 1)
|
||||
{
|
||||
// small or narrow sphere -- we can boxify
|
||||
for (S32 i=0; i<3; ++i)
|
||||
{
|
||||
if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE)
|
||||
{
|
||||
// reduce each small dimension size to split the approximation errors
|
||||
specOut.mScale[i] *= 0.75f;
|
||||
}
|
||||
}
|
||||
specOut.mType = PhysicsShapeSpecification::BOX;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Cylinder
|
||||
if( (scale[VX] == scale[VY])
|
||||
&& ( profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE )
|
||||
&& ( path_params.getCurveType() == LL_PCODE_PATH_LINE )
|
||||
&& ( volume_params.getBeginS() <= SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale )
|
||||
&& ( volume_params.getEndS() >= (1.0f - SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT/avgScale) )
|
||||
&& no_taper
|
||||
)
|
||||
{
|
||||
if (min_size_counts > 1)
|
||||
{
|
||||
// small or narrow sphere -- we can boxify
|
||||
for (S32 i=0; i<3; ++i)
|
||||
{
|
||||
if (specOut.mScale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE)
|
||||
{
|
||||
// reduce each small dimension size to split the approximation errors
|
||||
specOut.mScale[i] *= 0.75f;
|
||||
}
|
||||
}
|
||||
|
||||
specOut.mType = PhysicsShapeSpecification::BOX;
|
||||
}
|
||||
else
|
||||
{
|
||||
specOut.mType = PhysicsShapeSpecification::CYLINDER;
|
||||
F32 length = (volume_params.getPathParams().getEnd() - volume_params.getPathParams().getBegin()) * scale[VZ];
|
||||
|
||||
specOut.mScale[VY] = specOut.mScale[VX];
|
||||
specOut.mScale[VZ] = length;
|
||||
// The minus one below fixes the fact that begin and end range from 0 to 1 not -1 to 1.
|
||||
specOut.mCenter.set( 0.f, 0.f, 0.5f * (volume_params.getPathParams().getBegin() + volume_params.getPathParams().getEnd() - 1.f) * scale[VZ] );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (min_size_counts == 3 )
|
||||
// Possible dead code here--who wants to take it out?
|
||||
|| (path_complete
|
||||
&& profile_complete
|
||||
&& ( path_params.getCurveType() == LL_PCODE_PATH_LINE )
|
||||
&& (min_size_counts > 1 ) )
|
||||
)
|
||||
{
|
||||
// it isn't simple but
|
||||
// we might be able to convexify this shape if the path and profile are complete
|
||||
// or the path is linear and both path and profile are complete --> we can boxify it
|
||||
specOut.mType = PhysicsShapeSpecification::BOX;
|
||||
specOut.mScale = scale;
|
||||
return;
|
||||
}
|
||||
|
||||
// Special case for big, very thin objects - bump the small dimensions up to the COLLISION_TOLERANCE
|
||||
if (min_size_counts == 1 // One dimension is small
|
||||
&& avgScale > 3.f) // ... but others are fairly large
|
||||
{
|
||||
for (S32 i = 0; i < 3; ++i)
|
||||
{
|
||||
specOut.mScale[i] = llmax( specOut.mScale[i], COLLISION_TOLERANCE );
|
||||
}
|
||||
}
|
||||
|
||||
if ( volume_params.shouldForceConvex() )
|
||||
{
|
||||
specOut.mType = PhysicsShapeSpecification::USER_CONVEX;
|
||||
}
|
||||
// Make a simpler convex shape if we can.
|
||||
else if (volume_params.isConvex() // is convex
|
||||
|| min_size_counts > 1 ) // two or more small dimensions
|
||||
{
|
||||
specOut.mType = PhysicsShapeSpecification::PRIM_CONVEX;
|
||||
}
|
||||
else if ( volume_params.isSculpt() ) // Is a sculpt of any kind (mesh or legacy)
|
||||
{
|
||||
specOut.mType = volume_params.isMeshSculpt() ? PhysicsShapeSpecification::USER_MESH : PhysicsShapeSpecification::SCULPT;
|
||||
}
|
||||
else // Resort to mesh
|
||||
{
|
||||
specOut.mType = PhysicsShapeSpecification::PRIM_MESH;
|
||||
}
|
||||
}
|
||||
138
indra/newview/llphysicsshapebuilderutil.h
Normal file
138
indra/newview/llphysicsshapebuilderutil.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* @file llphysicsshapebuilder.h
|
||||
* @brief Generic system to convert LL(Physics)VolumeParams to physics shapes
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_PHYSICS_SHAPE_BUILDER_H
|
||||
#define LL_PHYSICS_SHAPE_BUILDER_H
|
||||
|
||||
#include "indra_constants.h"
|
||||
#include "llvolume.h"
|
||||
|
||||
#define USE_SHAPE_QUANTIZATION 0
|
||||
|
||||
#define SHAPE_BUILDER_DEFAULT_VOLUME_DETAIL 1
|
||||
|
||||
#define SHAPE_BUILDER_IMPLICIT_THRESHOLD_HOLLOW 0.10f
|
||||
#define SHAPE_BUILDER_IMPLICIT_THRESHOLD_HOLLOW_SPHERES 0.90f
|
||||
#define SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT 0.05f
|
||||
#define SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER 0.05f
|
||||
#define SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST 0.09f
|
||||
#define SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR 0.05f
|
||||
|
||||
const F32 SHAPE_BUILDER_ENTRY_SNAP_SCALE_BIN_SIZE = 0.15f;
|
||||
const F32 SHAPE_BUILDER_ENTRY_SNAP_PARAMETER_BIN_SIZE = 0.010f;
|
||||
const F32 SHAPE_BUILDER_CONVEXIFICATION_SIZE = 2.f * COLLISION_TOLERANCE;
|
||||
const F32 SHAPE_BUILDER_MIN_GEOMETRY_SIZE = 0.5f * COLLISION_TOLERANCE;
|
||||
|
||||
class LLPhysicsVolumeParams : public LLVolumeParams
|
||||
{
|
||||
public:
|
||||
|
||||
LLPhysicsVolumeParams( const LLVolumeParams& params, bool forceConvex ) :
|
||||
LLVolumeParams( params ),
|
||||
mForceConvex(forceConvex) {}
|
||||
|
||||
bool operator==(const LLPhysicsVolumeParams ¶ms) const
|
||||
{
|
||||
return ( LLVolumeParams::operator==(params) && (mForceConvex == params.mForceConvex) );
|
||||
}
|
||||
|
||||
bool operator!=(const LLPhysicsVolumeParams ¶ms) const
|
||||
{
|
||||
return !operator==(params);
|
||||
}
|
||||
|
||||
bool operator<(const LLPhysicsVolumeParams ¶ms) const
|
||||
{
|
||||
if ( LLVolumeParams::operator!=(params) )
|
||||
{
|
||||
return LLVolumeParams::operator<(params);
|
||||
}
|
||||
return (params.mForceConvex == false) && (mForceConvex == true);
|
||||
}
|
||||
|
||||
bool shouldForceConvex() const { return mForceConvex; }
|
||||
|
||||
private:
|
||||
bool mForceConvex;
|
||||
};
|
||||
|
||||
|
||||
class LLPhysicsShapeBuilderUtil
|
||||
{
|
||||
public:
|
||||
|
||||
class PhysicsShapeSpecification
|
||||
{
|
||||
public:
|
||||
enum ShapeType
|
||||
{
|
||||
// Primitive types
|
||||
BOX,
|
||||
SPHERE,
|
||||
CYLINDER,
|
||||
|
||||
USER_CONVEX, // User specified they wanted the convex hull of the volume
|
||||
|
||||
PRIM_CONVEX, // Either a volume that is inherently convex but not a primitive type, or a shape
|
||||
// with dimensions such that will convexify it anyway.
|
||||
|
||||
SCULPT, // Special case for traditional sculpts--they are the convex hull of a single particular set of volume params
|
||||
|
||||
USER_MESH, // A user mesh. May or may not contain a convex decomposition.
|
||||
|
||||
PRIM_MESH, // A non-convex volume which we have to represent accurately
|
||||
|
||||
INVALID
|
||||
};
|
||||
|
||||
PhysicsShapeSpecification() :
|
||||
mType( INVALID ),
|
||||
mScale( 0.f, 0.f, 0.f ),
|
||||
mCenter( 0.f, 0.f, 0.f ) {}
|
||||
|
||||
bool isConvex() { return (mType != USER_MESH && mType != PRIM_MESH && mType != INVALID); }
|
||||
bool isMesh() { return (mType == USER_MESH) || (mType == PRIM_MESH); }
|
||||
|
||||
ShapeType getType() { return mType; }
|
||||
const LLVector3& getScale() { return mScale; }
|
||||
const LLVector3& getCenter() { return mCenter; }
|
||||
|
||||
private:
|
||||
friend class LLPhysicsShapeBuilderUtil;
|
||||
|
||||
ShapeType mType;
|
||||
|
||||
// Dimensions of an AABB around the shape
|
||||
LLVector3 mScale;
|
||||
|
||||
// Offset of shape from origin of primitive's reference frame
|
||||
LLVector3 mCenter;
|
||||
};
|
||||
|
||||
static void determinePhysicsShape( const LLPhysicsVolumeParams& volume_params, const LLVector3& scale, PhysicsShapeSpecification& specOut );
|
||||
};
|
||||
|
||||
#endif //LL_PHYSICS_SHAPE_BUILDER_H
|
||||
@@ -5457,6 +5457,111 @@ BOOL LLSelectNode::allowOperationOnNode(PermissionBit op, U64 group_proxy_power)
|
||||
return (mPermissions->allowOperationBy(op, proxy_agent_id, group_id));
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
void pushWireframe(LLDrawable* drawable)
|
||||
{
|
||||
if (drawable->isState(LLDrawable::RIGGED))
|
||||
{ //render straight from rigged volume if this is a rigged attachment
|
||||
LLVOVolume* vobj = drawable->getVOVolume();
|
||||
if (vobj)
|
||||
{
|
||||
vobj->updateRiggedVolume();
|
||||
LLRiggedVolume* rigged_volume = vobj->getRiggedVolume();
|
||||
if (rigged_volume)
|
||||
{
|
||||
LLVertexBuffer::unbind();
|
||||
gGL.pushMatrix();
|
||||
glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix);
|
||||
for (S32 i = 0; i < rigged_volume->getNumVolumeFaces(); ++i)
|
||||
{
|
||||
const LLVolumeFace& face = rigged_volume->getVolumeFace(i);
|
||||
glVertexPointer(3, GL_FLOAT, 16, face.mPositions);
|
||||
glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
|
||||
}
|
||||
gGL.popMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (S32 i = 0; i < drawable->getNumFaces(); ++i)
|
||||
{
|
||||
LLFace* face = drawable->getFace(i);
|
||||
if (face->verify())
|
||||
{
|
||||
pushVerts(face, LLVertexBuffer::MAP_VERTEX);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLSelectNode::renderOneWireframe(const LLColor4& color)
|
||||
{
|
||||
LLViewerObject* objectp = getObject();
|
||||
if (!objectp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLDrawable* drawable = objectp->mDrawable;
|
||||
if(!drawable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
gGL.pushMatrix();
|
||||
|
||||
BOOL is_hud_object = objectp->isHUDAttachment();
|
||||
|
||||
if (drawable->isActive())
|
||||
{
|
||||
glLoadMatrixd(gGLModelView);
|
||||
glMultMatrixf((F32*) objectp->getRenderMatrix().mMatrix);
|
||||
}
|
||||
else if (!is_hud_object)
|
||||
{
|
||||
glLoadIdentity();
|
||||
glMultMatrixd(gGLModelView);
|
||||
LLVector3 trans = objectp->getRegion()->getOriginAgent();
|
||||
glTranslatef(trans.mV[0], trans.mV[1], trans.mV[2]);
|
||||
}
|
||||
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
|
||||
if (LLSelectMgr::sRenderHiddenSelections) // && gFloaterTools && gFloaterTools->getVisible())
|
||||
{
|
||||
gGL.blendFunc(LLRender::BF_SOURCE_COLOR, LLRender::BF_ONE);
|
||||
LLGLEnable fog(GL_FOG);
|
||||
glFogi(GL_FOG_MODE, GL_LINEAR);
|
||||
float d = (LLViewerCamera::getInstance()->getPointOfInterest()-LLViewerCamera::getInstance()->getOrigin()).magVec();
|
||||
LLColor4 fogCol = color * (F32)llclamp((LLSelectMgr::getInstance()->getSelectionCenterGlobal()-gAgentCamera.getCameraPositionGlobal()).magVec()/(LLSelectMgr::getInstance()->getBBoxOfSelection().getExtentLocal().magVec()*4), 0.0, 1.0);
|
||||
glFogf(GL_FOG_START, d);
|
||||
glFogf(GL_FOG_END, d*(1 + (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV())));
|
||||
glFogfv(GL_FOG_COLOR, fogCol.mV);
|
||||
|
||||
LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL);
|
||||
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
|
||||
{
|
||||
glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
|
||||
pushWireframe(drawable);
|
||||
}
|
||||
}
|
||||
|
||||
gGL.flush();
|
||||
gGL.setSceneBlendType(LLRender::BT_ALPHA);
|
||||
|
||||
glColor4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
|
||||
LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
|
||||
glPolygonOffset(3.f, 3.f);
|
||||
glLineWidth(3.f);
|
||||
pushWireframe(drawable);
|
||||
glLineWidth(1.f);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
gGL.popMatrix();
|
||||
}
|
||||
#endif MESH_ENABLED
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// renderOneSilhouette()
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -5474,6 +5579,15 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
|
||||
return;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
LLVOVolume* vobj = drawable->getVOVolume();
|
||||
if (vobj && vobj->isMesh())
|
||||
{
|
||||
renderOneWireframe(color);
|
||||
return;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
if (!mSilhouetteExists)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -139,6 +139,9 @@ public:
|
||||
BOOL isTESelected(S32 te_index);
|
||||
S32 getLastSelectedTE();
|
||||
S32 getTESelectMask() { return mTESelectMask; }
|
||||
#if MESH_ENABLED
|
||||
void renderOneWireframe(const LLColor4& color);
|
||||
#endif
|
||||
void renderOneSilhouette(const LLColor4 &color);
|
||||
void setTransient(BOOL transient) { mTransient = transient; }
|
||||
BOOL isTransient() { return mTransient; }
|
||||
|
||||
@@ -2999,7 +2999,12 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */)
|
||||
getTEImage(i)->setBoostLevel(LLViewerTexture::BOOST_SELECTED);
|
||||
}
|
||||
|
||||
if (isSculpted())
|
||||
|
||||
if (isSculpted()
|
||||
#if MESH_ENABLED
|
||||
&& !isMesh()
|
||||
#endif //MESH_ENABLED
|
||||
)
|
||||
{
|
||||
LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
|
||||
LLUUID sculpt_id = sculpt_params->getSculptTexture();
|
||||
@@ -3239,6 +3244,16 @@ const LLVector3 LLViewerObject::getPositionEdit() const
|
||||
|
||||
const LLVector3 LLViewerObject::getRenderPosition() const
|
||||
{
|
||||
#if MESH_ENABLED
|
||||
if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
|
||||
{
|
||||
LLVOAvatar* avatar = getAvatar();
|
||||
if (avatar)
|
||||
{
|
||||
return avatar->getPositionAgent();
|
||||
}
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
if (mDrawable.isNull() || mDrawable->getGeneration() < 0)
|
||||
{
|
||||
return getPositionAgent();
|
||||
@@ -3257,6 +3272,12 @@ const LLVector3 LLViewerObject::getPivotPositionAgent() const
|
||||
const LLQuaternion LLViewerObject::getRenderRotation() const
|
||||
{
|
||||
LLQuaternion ret;
|
||||
#if MESH_ENABLED
|
||||
if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
if (mDrawable.isNull() || mDrawable->isStatic())
|
||||
{
|
||||
ret = getRotationEdit();
|
||||
|
||||
@@ -1495,6 +1495,11 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
|
||||
}
|
||||
capabilityNames.append("GetDisplayNames");
|
||||
capabilityNames.append("GetTexture");
|
||||
#if MESH_ENABLED
|
||||
capabilityNames.append("GetMesh");
|
||||
capabilityNames.append("GetObjectCost");
|
||||
capabilityNames.append("GetObjectPhysicsData");
|
||||
#endif //MESH_ENABLED
|
||||
capabilityNames.append("GroupProposalBallot");
|
||||
|
||||
capabilityNames.append("HomeLocation");
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llagentcamera.h"
|
||||
#if MESH_ENABLED
|
||||
#include "llmeshrepository.h"
|
||||
#endif //MESH_ENABLED
|
||||
#include "llpanellogin.h"
|
||||
#include "llviewerkeyboard.h"
|
||||
#include "llviewerwindow.h"
|
||||
@@ -507,6 +510,24 @@ public:
|
||||
|
||||
ypos += y_inc;
|
||||
|
||||
#if MESH_ENABLED
|
||||
if (gSavedSettings.getBOOL("MeshEnabled"))
|
||||
{
|
||||
addText(xpos, ypos, llformat("%.3f MB Mesh Data Received", LLMeshRepository::sBytesReceived/(1024.f*1024.f)));
|
||||
|
||||
ypos += y_inc;
|
||||
|
||||
addText(xpos, ypos, llformat("%d/%d Mesh HTTP Requests/Retries", LLMeshRepository::sHTTPRequestCount,
|
||||
LLMeshRepository::sHTTPRetryCount));
|
||||
|
||||
ypos += y_inc;
|
||||
|
||||
addText(xpos, ypos, llformat("%.3f/%.3f MB Mesh Cache Read/Write ", LLMeshRepository::sCacheBytesRead/(1024.f*1024.f), LLMeshRepository::sCacheBytesWritten/(1024.f*1024.f)));
|
||||
|
||||
ypos += y_inc;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
LLVertexBuffer::sBindCount = LLImageGL::sBindCount =
|
||||
LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount =
|
||||
gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0;
|
||||
|
||||
@@ -63,6 +63,10 @@
|
||||
#include "llkeyframefallmotion.h"
|
||||
#include "llkeyframestandmotion.h"
|
||||
#include "llkeyframewalkmotion.h"
|
||||
#if MESH_ENABLED
|
||||
#include "llmanipscale.h" // for get_default_max_prim_scale()
|
||||
#include "llmeshrepository.h"
|
||||
#endif //MESH_ENABLED
|
||||
#include "llmutelist.h"
|
||||
#include "llnotify.h"
|
||||
#include "llquantize.h"
|
||||
@@ -1618,7 +1622,11 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
|
||||
if (attached_object && !attached_object->isHUDAttachment())
|
||||
{
|
||||
LLDrawable* drawable = attached_object->mDrawable;
|
||||
if (drawable)
|
||||
if (drawable
|
||||
#if MESH_ENABLED
|
||||
&& !drawable->isState(LLDrawable::RIGGED))
|
||||
#endif //MESH_ENABLED
|
||||
)
|
||||
{
|
||||
LLSpatialBridge* bridge = drawable->getSpatialBridge();
|
||||
if (bridge)
|
||||
@@ -4943,6 +4951,7 @@ bool LLVOAvatar::shouldAlphaMask()
|
||||
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// needsRenderBeam()
|
||||
//------------------------------------------------------------------------
|
||||
@@ -7162,6 +7171,56 @@ void LLVOAvatar::resetHUDAttachments()
|
||||
}
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
void LLVOAvatar::rebuildRiggedAttachments( void )
|
||||
{
|
||||
for ( attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter )
|
||||
{
|
||||
LLViewerJointAttachment* pAttachment = iter->second;
|
||||
LLViewerJointAttachment::attachedobjs_vec_t::iterator attachmentIterEnd = pAttachment->mAttachedObjects.end();
|
||||
|
||||
for ( LLViewerJointAttachment::attachedobjs_vec_t::iterator attachmentIter = pAttachment->mAttachedObjects.begin();
|
||||
attachmentIter != attachmentIterEnd; ++attachmentIter)
|
||||
{
|
||||
const LLViewerObject* pAttachedObject = *attachmentIter;
|
||||
if ( pAttachment && pAttachedObject->mDrawable.notNull() )
|
||||
{
|
||||
gPipeline.markRebuild(pAttachedObject->mDrawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// cleanupAttachedMesh()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )
|
||||
{
|
||||
//If a VO has a skin that we'll reset the joint positions to their default
|
||||
if ( pVO && pVO->mDrawable )
|
||||
{
|
||||
LLVOVolume* pVObj = pVO->mDrawable->getVOVolume();
|
||||
if ( pVObj )
|
||||
{
|
||||
const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID() );
|
||||
if ( pSkinData )
|
||||
{
|
||||
const int jointCnt = pSkinData->mJointNames.size();
|
||||
bool fullRig = ( jointCnt>=20 ) ? true : false;
|
||||
if ( fullRig )
|
||||
{
|
||||
const int bindCnt = pSkinData->mAlternateBindMatrix.size();
|
||||
if ( bindCnt > 0 )
|
||||
{
|
||||
LLVOAvatar::resetJointPositionsToDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// detachObject()
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -10508,6 +10567,13 @@ BOOL LLVOAvatar::updateLOD()
|
||||
return res;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
void LLVOAvatar::updateLODRiggedAttachments( void )
|
||||
{
|
||||
updateLOD();
|
||||
rebuildRiggedAttachments();
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
U32 LLVOAvatar::getPartitionType() const
|
||||
{
|
||||
// Avatars merely exist as drawables in the bridge partition
|
||||
|
||||
@@ -124,6 +124,9 @@ public:
|
||||
/*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
|
||||
virtual BOOL updateLOD();
|
||||
BOOL updateJointLODs();
|
||||
#if MESH_ENABLED
|
||||
void updateLODRiggedAttachments( void );
|
||||
#endif //MESH_ENABLED
|
||||
/*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate.
|
||||
/*virtual*/ void updateTextures();
|
||||
/*virtual*/ S32 setTETexture(const U8 te, const LLUUID& uuid); // If setting a baked texture, need to request it from a non-local sim.
|
||||
@@ -722,12 +725,18 @@ public:
|
||||
void clampAttachmentPositions();
|
||||
BOOL attachObject(LLViewerObject *viewer_object);
|
||||
BOOL detachObject(LLViewerObject *viewer_object);
|
||||
#if MESH_ENABLED
|
||||
void cleanupAttachedMesh( LLViewerObject* pVO );
|
||||
#endif //MESH_ENABLED
|
||||
static LLVOAvatar* findAvatarFromAttachment( LLViewerObject* obj );
|
||||
protected:
|
||||
// [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i
|
||||
LLViewerJointAttachment* getTargetAttachmentPoint(const LLViewerObject* viewer_object) const;
|
||||
// [/RLVa:KB]
|
||||
void lazyAttach();
|
||||
#if MESH_ENABLED
|
||||
void rebuildRiggedAttachments( void );
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Map of attachment points, by ID
|
||||
|
||||
@@ -42,12 +42,13 @@
|
||||
#include "llmaterialtable.h"
|
||||
#include "llprimitive.h"
|
||||
#include "llvolume.h"
|
||||
#include "llvolumeoctree.h"
|
||||
#include "llvolumemgr.h"
|
||||
#include "llvolumemessage.h"
|
||||
#include "material_codes.h"
|
||||
#include "message.h"
|
||||
#include "object_flags.h"
|
||||
#include "llagent.h"
|
||||
#include "llagentconstants.h"
|
||||
#include "lldrawable.h"
|
||||
#include "lldrawpoolbump.h"
|
||||
#include "llface.h"
|
||||
@@ -59,11 +60,21 @@
|
||||
#include "llvector4a.h"
|
||||
#include "llviewercamera.h"
|
||||
#include "llviewertexturelist.h"
|
||||
#include "llviewerobjectlist.h"
|
||||
#include "llviewerregion.h"
|
||||
#include "llviewertextureanim.h"
|
||||
#include "llworld.h"
|
||||
#include "llselectmgr.h"
|
||||
#include "pipeline.h"
|
||||
#include "llsdutil.h"
|
||||
#include "llmatrix4a.h"
|
||||
#include "llagent.h"
|
||||
#if MESH_ENABLED
|
||||
#include "lldrawpoolavatar.h
|
||||
#include "llmeshrepository.h"
|
||||
#include "lldatapacker.h"
|
||||
#include "llvoavatar.h"
|
||||
#endif //MESH_ENABLED
|
||||
#include "llvocache.h"
|
||||
|
||||
// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d)
|
||||
@@ -730,8 +741,35 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
|
||||
return mDrawable;
|
||||
}
|
||||
|
||||
BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume)
|
||||
BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bool unique_volume)
|
||||
{
|
||||
LLVolumeParams volume_params = params_in;
|
||||
S32 lod = mLOD;
|
||||
#if MESH_ENABLED
|
||||
S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1;
|
||||
|
||||
BOOL is404 = FALSE;
|
||||
|
||||
if (isSculpted())
|
||||
{
|
||||
// if it's a mesh
|
||||
if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
|
||||
{ //meshes might not have all LODs, get the force detail to best existing LOD
|
||||
|
||||
LLUUID mesh_id = volume_params.getSculptID();
|
||||
|
||||
//profile and path params don't matter for meshes
|
||||
volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
|
||||
|
||||
lod = gMeshRepo.getActualMeshLOD(volume_params, lod);
|
||||
if (lod == -1)
|
||||
{
|
||||
is404 = TRUE;
|
||||
lod = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
// Check if we need to change implementations
|
||||
bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE);
|
||||
if (is_flexible)
|
||||
@@ -759,13 +797,19 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
|
||||
}
|
||||
}
|
||||
|
||||
if ((LLPrimitive::setVolume(volume_params, mLOD, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
|
||||
#if MESH_ENABLED
|
||||
if (is404)
|
||||
{
|
||||
setIcon(LLViewerTextureManager::getFetchedTextureFromFile("icons/Inv_Mesh.png", TRUE, LLViewerTexture::BOOST_UI));
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
if ((LLPrimitive::setVolume(volume_params, lod, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
|
||||
{
|
||||
mFaceMappingChanged = TRUE;
|
||||
|
||||
if (mVolumeImpl)
|
||||
{
|
||||
mVolumeImpl->onSetVolume(volume_params, detail);
|
||||
mVolumeImpl->onSetVolume(volume_params, detail); //mLOD ?
|
||||
}
|
||||
|
||||
updateSculptTexture();
|
||||
@@ -773,10 +817,31 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
|
||||
if (isSculpted())
|
||||
{
|
||||
updateSculptTexture();
|
||||
|
||||
if (mSculptTexture.notNull())
|
||||
#if MESH_ENABLED
|
||||
// if it's a mesh
|
||||
if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
|
||||
{
|
||||
sculpt();
|
||||
if (getVolume()->getNumVolumeFaces() == 0 || getVolume()->isTetrahedron())
|
||||
{
|
||||
//load request not yet issued, request pipeline load this mesh
|
||||
LLUUID asset_id = volume_params.getSculptID();
|
||||
S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod, last_lod);
|
||||
if (available_lod != lod)
|
||||
{
|
||||
LLPrimitive::setVolume(volume_params, available_lod);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else // otherwise is sculptie
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
|
||||
{
|
||||
if (mSculptTexture.notNull())
|
||||
{
|
||||
sculpt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -789,7 +854,11 @@ void LLVOVolume::updateSculptTexture()
|
||||
{
|
||||
LLPointer<LLViewerFetchedTexture> old_sculpt = mSculptTexture;
|
||||
|
||||
if (isSculpted())
|
||||
if (isSculpted()
|
||||
#if MESH_ENABLED
|
||||
&& !isMesh()
|
||||
#endif //MESH_ENABLED
|
||||
)
|
||||
{
|
||||
LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
|
||||
LLUUID id = sculpt_params->getSculptTexture();
|
||||
@@ -814,8 +883,17 @@ void LLVOVolume::updateSculptTexture()
|
||||
mSculptTexture->addVolume(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
void LLVOVolume::notifyMeshLoaded()
|
||||
{
|
||||
mSculptChanged = TRUE;
|
||||
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// sculpt replaces generate() for sculpted surfaces
|
||||
void LLVOVolume::sculpt()
|
||||
{
|
||||
@@ -907,8 +985,24 @@ BOOL LLVOVolume::calcLOD()
|
||||
|
||||
S32 cur_detail = 0;
|
||||
|
||||
F32 radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
|
||||
F32 distance = mDrawable->mDistanceWRTCamera;
|
||||
F32 radius;
|
||||
F32 distance;
|
||||
|
||||
#if MESH_ENABLED
|
||||
if (mDrawable->isState(LLDrawable::RIGGED))
|
||||
{
|
||||
LLVOAvatar* avatar = getAvatar();
|
||||
distance = avatar->mDrawable->mDistanceWRTCamera;
|
||||
radius = avatar->getBinRadius();
|
||||
}
|
||||
else
|
||||
#endif //MESH_ENABLED
|
||||
{
|
||||
distance = mDrawable->mDistanceWRTCamera;
|
||||
radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
|
||||
}
|
||||
|
||||
|
||||
distance *= sDistanceFactor;
|
||||
|
||||
F32 rampDist = LLVOVolume::sLODFactor * 2;
|
||||
@@ -1072,9 +1166,22 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
|
||||
min.clear();
|
||||
max.clear();
|
||||
|
||||
BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION);
|
||||
BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION
|
||||
#if MESH_ENABLED
|
||||
| LLDrawable::REBUILD_RIGGED
|
||||
#endif //MESH_ENABLED
|
||||
);
|
||||
|
||||
#if MESH_ENABLED
|
||||
LLVolume* volume = mRiggedVolume;
|
||||
if (!volume)
|
||||
{
|
||||
volume = getVolume();
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
#if !MESH_ENABLED
|
||||
LLVolume* volume = getVolume();
|
||||
#endif //!MESH_ENABLED
|
||||
for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
|
||||
{
|
||||
LLFace *face = mDrawable->getFace(i);
|
||||
@@ -1132,8 +1239,27 @@ void LLVOVolume::updateRelativeXform()
|
||||
}
|
||||
|
||||
LLDrawable* drawable = mDrawable;
|
||||
|
||||
|
||||
#if MESH_ENABLED
|
||||
if (drawable->isState(LLDrawable::RIGGED) && mRiggedVolume.notNull())
|
||||
{ //rigged volume (which is in agent space) is used for generating bounding boxes etc
|
||||
//inverse of render matrix should go to partition space
|
||||
mRelativeXform = getRenderMatrix();
|
||||
|
||||
F32* dst = (F32*) mRelativeXformInvTrans.mMatrix;
|
||||
F32* src = (F32*) mRelativeXform.mMatrix;
|
||||
dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2];
|
||||
dst[3] = src[4]; dst[4] = src[5]; dst[5] = src[6];
|
||||
dst[6] = src[8]; dst[7] = src[9]; dst[8] = src[10];
|
||||
|
||||
mRelativeXform.invert();
|
||||
mRelativeXformInvTrans.transpose();
|
||||
}
|
||||
else if (drawable->isActive())
|
||||
#endif //MESH_ENABLED
|
||||
#if !MESH_ENABLED
|
||||
if (drawable->isActive())
|
||||
#endif //!MESH_ENABLED
|
||||
{
|
||||
// setup relative transforms
|
||||
LLQuaternion delta_rot;
|
||||
@@ -1217,6 +1343,17 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
|
||||
{
|
||||
LLFastTimer t(LLFastTimer::FTM_UPDATE_PRIMITIVES);
|
||||
|
||||
#if MESH_ENABLED
|
||||
if (mDrawable->isState(LLDrawable::REBUILD_RIGGED))
|
||||
{
|
||||
{
|
||||
LLFastTimer t(FTM_UPDATE_RIGGED_VOLUME);
|
||||
updateRiggedVolume();
|
||||
}
|
||||
genBBoxes(FALSE);
|
||||
mDrawable->clearState(LLDrawable::REBUILD_RIGGED);
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
if (mVolumeImpl != NULL)
|
||||
{
|
||||
BOOL res;
|
||||
@@ -1882,6 +2019,24 @@ BOOL LLVOVolume::isSculpted() const
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
BOOL LLVOVolume::isMesh() const
|
||||
{
|
||||
if (isSculpted())
|
||||
{
|
||||
LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
|
||||
U8 sculpt_type = sculpt_params->getSculptType();
|
||||
|
||||
if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
|
||||
// mesh is a mesh
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
BOOL LLVOVolume::hasLightTexture() const
|
||||
{
|
||||
if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
|
||||
@@ -1898,6 +2053,12 @@ BOOL LLVOVolume::isVolumeGlobal() const
|
||||
{
|
||||
return mVolumeImpl->isVolumeGlobal() ? TRUE : FALSE;
|
||||
}
|
||||
#if MESH_ENABLED
|
||||
else if (mRiggedVolume.notNull())
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1982,7 +2143,7 @@ void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_p
|
||||
trans_mat.translate(getRegion()->getOriginAgent());
|
||||
}
|
||||
|
||||
volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask());
|
||||
volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask());
|
||||
|
||||
nodep->mSilhouetteExists = TRUE;
|
||||
}
|
||||
@@ -2060,7 +2221,8 @@ U32 LLVOVolume::getHighLODTriangleCount()
|
||||
ret = ref->getNumTriangles();
|
||||
LLPrimitive::getVolumeManager()->unrefVolume(ref);
|
||||
}
|
||||
/*else if (isMesh())
|
||||
#if MESH_ENABLED
|
||||
else if (isMesh())
|
||||
{
|
||||
LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3);
|
||||
if (ref->isTetrahedron() || ref->getNumVolumeFaces() == 0)
|
||||
@@ -2069,7 +2231,8 @@ U32 LLVOVolume::getHighLODTriangleCount()
|
||||
}
|
||||
ret = ref->getNumTriangles();
|
||||
LLPrimitive::getVolumeManager()->unrefVolume(ref);
|
||||
}*/
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
else
|
||||
{ //default sculpts have a constant number of triangles
|
||||
ret = 31*2*31; //31 rows of 31 columns of quads for a 32x32 vertex patch
|
||||
@@ -2283,12 +2446,38 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
|
||||
BOOL ret = FALSE;
|
||||
|
||||
LLVolume* volume = getVolume();
|
||||
|
||||
bool transform = true;
|
||||
|
||||
#if MESH_ENABLED
|
||||
if (mDrawable->isState(LLDrawable::RIGGED))
|
||||
{
|
||||
if (LLFloater::isVisible(gFloaterTools) && getAvatar()->isSelf())
|
||||
{
|
||||
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_RIGGED, TRUE);
|
||||
volume = mRiggedVolume;
|
||||
transform = false;
|
||||
}
|
||||
else
|
||||
{ //cannot pick rigged attachments on other avatars or when not in build mode
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
if (volume)
|
||||
{
|
||||
LLVector3 v_start, v_end, v_dir;
|
||||
|
||||
v_start = agentPositionToVolume(start);
|
||||
v_end = agentPositionToVolume(end);
|
||||
if (transform)
|
||||
{
|
||||
v_start = agentPositionToVolume(start);
|
||||
v_end = agentPositionToVolume(end);
|
||||
}
|
||||
else
|
||||
{
|
||||
v_start = start;
|
||||
v_end = end;
|
||||
}
|
||||
|
||||
LLVector3 p;
|
||||
LLVector3 n;
|
||||
@@ -2348,18 +2537,40 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
|
||||
|
||||
if (intersection != NULL)
|
||||
{
|
||||
*intersection = volumePositionToAgent(p); // must map back to agent space
|
||||
if (transform)
|
||||
{
|
||||
*intersection = volumePositionToAgent(p); // must map back to agent space
|
||||
}
|
||||
else
|
||||
{
|
||||
*intersection = p;
|
||||
}
|
||||
}
|
||||
|
||||
if (normal != NULL)
|
||||
{
|
||||
*normal = volumeDirectionToAgent(n);
|
||||
if (transform)
|
||||
{
|
||||
*normal = volumeDirectionToAgent(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
*normal = n;
|
||||
}
|
||||
|
||||
(*normal).normVec();
|
||||
}
|
||||
|
||||
if (bi_normal != NULL)
|
||||
{
|
||||
*bi_normal = volumeDirectionToAgent(bn);
|
||||
if (transform)
|
||||
{
|
||||
*bi_normal = volumeDirectionToAgent(bn);
|
||||
}
|
||||
else
|
||||
{
|
||||
*bi_normal = bn;
|
||||
}
|
||||
(*bi_normal).normVec();
|
||||
}
|
||||
|
||||
@@ -2377,6 +2588,203 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
bool LLVOVolume::treatAsRigged()
|
||||
{
|
||||
return LLFloater::isVisible(gFloaterTools) &&
|
||||
isAttachment() &&
|
||||
getAvatar() &&
|
||||
getAvatar()->isSelf() &&
|
||||
mDrawable.notNull() &&
|
||||
mDrawable->isState(LLDrawable::RIGGED);
|
||||
}
|
||||
|
||||
LLRiggedVolume* LLVOVolume::getRiggedVolume()
|
||||
{
|
||||
return mRiggedVolume;
|
||||
}
|
||||
|
||||
void LLVOVolume::clearRiggedVolume()
|
||||
{
|
||||
if (mRiggedVolume.notNull())
|
||||
{
|
||||
mRiggedVolume = NULL;
|
||||
updateRelativeXform();
|
||||
}
|
||||
}
|
||||
|
||||
void LLVOVolume::updateRiggedVolume()
|
||||
{
|
||||
//Update mRiggedVolume to match current animation frame of avatar.
|
||||
//Also update position/size in octree.
|
||||
|
||||
if (!treatAsRigged())
|
||||
{
|
||||
clearRiggedVolume();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
LLVolume* volume = getVolume();
|
||||
|
||||
const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID());
|
||||
|
||||
if (!skin)
|
||||
{
|
||||
clearRiggedVolume();
|
||||
return;
|
||||
}
|
||||
|
||||
LLVOAvatar* avatar = getAvatar();
|
||||
|
||||
if (!avatar)
|
||||
{
|
||||
clearRiggedVolume();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mRiggedVolume)
|
||||
{
|
||||
LLVolumeParams p;
|
||||
mRiggedVolume = new LLRiggedVolume(p);
|
||||
updateRelativeXform();
|
||||
}
|
||||
|
||||
mRiggedVolume->update(skin, avatar, volume);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED("Skin");
|
||||
static LLFastTimer::DeclareTimer FTM_RIGGED_OCTREE("Octree");
|
||||
|
||||
void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume)
|
||||
{
|
||||
bool copy = false;
|
||||
if (volume->getNumVolumeFaces() != getNumVolumeFaces())
|
||||
{
|
||||
copy = true;
|
||||
}
|
||||
|
||||
for (S32 i = 0; i < volume->getNumVolumeFaces() && !copy; ++i)
|
||||
{
|
||||
const LLVolumeFace& src_face = volume->getVolumeFace(i);
|
||||
const LLVolumeFace& dst_face = getVolumeFace(i);
|
||||
|
||||
if (src_face.mNumIndices != dst_face.mNumIndices ||
|
||||
src_face.mNumVertices != dst_face.mNumVertices)
|
||||
{
|
||||
copy = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (copy)
|
||||
{
|
||||
copyVolumeFaces(volume);
|
||||
}
|
||||
|
||||
//build matrix palette
|
||||
LLMatrix4a mp[64];
|
||||
LLMatrix4* mat = (LLMatrix4*) mp;
|
||||
|
||||
for (U32 j = 0; j < skin->mJointNames.size(); ++j)
|
||||
{
|
||||
LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
|
||||
if (joint)
|
||||
{
|
||||
mat[j] = skin->mInvBindMatrix[j];
|
||||
mat[j] *= joint->getWorldMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
|
||||
{
|
||||
const LLVolumeFace& vol_face = volume->getVolumeFace(i);
|
||||
|
||||
LLVolumeFace& dst_face = mVolumeFaces[i];
|
||||
|
||||
LLVector4a* weight = vol_face.mWeights;
|
||||
|
||||
LLMatrix4a bind_shape_matrix;
|
||||
bind_shape_matrix.loadu(skin->mBindShapeMatrix);
|
||||
|
||||
LLVector4a* pos = dst_face.mPositions;
|
||||
|
||||
{
|
||||
LLFastTimer t(FTM_SKIN_RIGGED);
|
||||
|
||||
for (U32 j = 0; j < dst_face.mNumVertices; ++j)
|
||||
{
|
||||
LLMatrix4a final_mat;
|
||||
final_mat.clear();
|
||||
|
||||
S32 idx[4];
|
||||
|
||||
LLVector4 wght;
|
||||
|
||||
F32 scale = 0.f;
|
||||
for (U32 k = 0; k < 4; k++)
|
||||
{
|
||||
F32 w = weight[j][k];
|
||||
|
||||
idx[k] = (S32) floorf(w);
|
||||
wght[k] = w - floorf(w);
|
||||
scale += wght[k];
|
||||
}
|
||||
|
||||
wght *= 1.f/scale;
|
||||
|
||||
for (U32 k = 0; k < 4; k++)
|
||||
{
|
||||
F32 w = wght[k];
|
||||
|
||||
LLMatrix4a src;
|
||||
src.setMul(mp[idx[k]], w);
|
||||
|
||||
final_mat.add(src);
|
||||
}
|
||||
|
||||
|
||||
LLVector4a& v = vol_face.mPositions[j];
|
||||
LLVector4a t;
|
||||
LLVector4a dst;
|
||||
bind_shape_matrix.affineTransform(v, t);
|
||||
final_mat.affineTransform(t, dst);
|
||||
pos[j] = dst;
|
||||
}
|
||||
|
||||
//update bounding box
|
||||
LLVector4a& min = dst_face.mExtents[0];
|
||||
LLVector4a& max = dst_face.mExtents[1];
|
||||
|
||||
min = pos[0];
|
||||
max = pos[1];
|
||||
|
||||
for (U32 j = 1; j < dst_face.mNumVertices; ++j)
|
||||
{
|
||||
min.setMin(min, pos[j]);
|
||||
max.setMax(max, pos[j]);
|
||||
}
|
||||
|
||||
dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]);
|
||||
dst_face.mCenter->mul(0.5f);
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
LLFastTimer t(FTM_RIGGED_OCTREE);
|
||||
delete dst_face.mOctree;
|
||||
dst_face.mOctree = NULL;
|
||||
|
||||
LLVector4a size;
|
||||
size.setSub(dst_face.mExtents[1], dst_face.mExtents[0]);
|
||||
size.splat(size.getLength3().getF32()*0.5f);
|
||||
|
||||
dst_face.createOctree(1.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
U32 LLVOVolume::getPartitionType() const
|
||||
{
|
||||
if (isHUDAttachment())
|
||||
@@ -2525,6 +2933,35 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
|
||||
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
|
||||
{
|
||||
LLVOAvatar* avatar = vobj->getAvatar();
|
||||
|
||||
if (avatar)
|
||||
{
|
||||
LLDrawable* drawable = avatar->mDrawable;
|
||||
if (drawable && drawable->getNumFaces() > 0)
|
||||
{
|
||||
LLFace* face = drawable->getFace(0);
|
||||
if (face)
|
||||
{
|
||||
LLDrawPool* drawpool = face->getPool();
|
||||
if (drawpool)
|
||||
{
|
||||
if (drawpool->getType() == LLDrawPool::POOL_AVATAR)
|
||||
{
|
||||
return (LLDrawPoolAvatar*) drawpool;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif //MESH_ENABLED
|
||||
void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
|
||||
{
|
||||
if (LLPipeline::sSkipUpdate)
|
||||
@@ -2591,12 +3028,28 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
|
||||
}
|
||||
|
||||
LLVOVolume* vobj = drawablep->getVOVolume();
|
||||
|
||||
#if MESH_ENABLED
|
||||
if (vobj->getVolume() && vobj->getVolume()->isTetrahedron())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
llassert_always(vobj);
|
||||
vobj->updateTextureVirtualSize();
|
||||
vobj->preRebuild();
|
||||
|
||||
drawablep->clearState(LLDrawable::HAS_ALPHA);
|
||||
|
||||
#if MESH_ENABLED
|
||||
bool rigged = vobj->isAttachment() &&
|
||||
vobj->isMesh() &&
|
||||
gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID());
|
||||
|
||||
bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
|
||||
|
||||
bool is_rigged = false;
|
||||
#endif //MESH_ENABLED
|
||||
//for each face
|
||||
for (S32 i = 0; i < drawablep->getNumFaces(); i++)
|
||||
{
|
||||
@@ -2608,6 +3061,170 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
|
||||
//sum up face verts and indices
|
||||
drawablep->updateFaceSize(i);
|
||||
|
||||
|
||||
#if MESH_ENABLED
|
||||
if (rigged)
|
||||
{
|
||||
if (!facep->isState(LLFace::RIGGED))
|
||||
{ //completely reset vertex buffer
|
||||
facep->clearVertexBuffer();
|
||||
}
|
||||
|
||||
facep->setState(LLFace::RIGGED);
|
||||
is_rigged = true;
|
||||
|
||||
//get drawpool of avatar with rigged face
|
||||
LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
|
||||
|
||||
//Determine if we've received skininfo that contains an
|
||||
//alternate bind matrix - if it does then apply the translational component
|
||||
//to the joints of the avatar.
|
||||
LLVOAvatar* pAvatarVO = vobj->getAvatar();
|
||||
bool pelvisGotSet = false;
|
||||
|
||||
if ( pAvatarVO )
|
||||
{
|
||||
LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
|
||||
const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId );
|
||||
|
||||
if ( pSkinData )
|
||||
{
|
||||
const int bindCnt = pSkinData->mAlternateBindMatrix.size();
|
||||
if ( bindCnt > 0 )
|
||||
{
|
||||
const int jointCnt = pSkinData->mJointNames.size();
|
||||
const F32 pelvisZOffset = pSkinData->mPelvisOffset;
|
||||
bool fullRig = (jointCnt>=20) ? true : false;
|
||||
if ( fullRig )
|
||||
{
|
||||
for ( int i=0; i<jointCnt; ++i )
|
||||
{
|
||||
std::string lookingForJoint = pSkinData->mJointNames[i].c_str();
|
||||
//llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl;
|
||||
LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );
|
||||
if ( pJoint && pJoint->getId() != currentId )
|
||||
{
|
||||
pJoint->setId( currentId );
|
||||
const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();
|
||||
//Set the joint position
|
||||
pJoint->storeCurrentXform( jointPos );
|
||||
//If joint is a pelvis then handle old/new pelvis to foot values
|
||||
if ( lookingForJoint == "mPelvis" )
|
||||
{
|
||||
pJoint->storeCurrentXform( jointPos );
|
||||
if ( !pAvatarVO->hasPelvisOffset() )
|
||||
{
|
||||
pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset );
|
||||
//Trigger to rebuild viewer AV
|
||||
pelvisGotSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//If we've set the pelvis to a new position we need to also rebuild some information that the
|
||||
//viewer does at launch (e.g. body size etc.)
|
||||
if ( pelvisGotSet )
|
||||
{
|
||||
pAvatarVO->postPelvisSetRecalc();
|
||||
}
|
||||
|
||||
if (pool)
|
||||
{
|
||||
const LLTextureEntry* te = facep->getTextureEntry();
|
||||
|
||||
//remove face from old pool if it exists
|
||||
LLDrawPool* old_pool = facep->getPool();
|
||||
if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR)
|
||||
{
|
||||
((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
|
||||
}
|
||||
|
||||
//add face to new pool
|
||||
LLViewerTexture* tex = facep->getTexture();
|
||||
U32 type = gPipeline.getPoolTypeFromTE(te, tex);
|
||||
|
||||
if (type == LLDrawPool::POOL_ALPHA)
|
||||
{
|
||||
if (te->getFullbright())
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
|
||||
}
|
||||
}
|
||||
else if (te->getShiny())
|
||||
{
|
||||
if (te->getFullbright())
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LLPipeline::sRenderDeferred)
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (te->getFullbright())
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
|
||||
}
|
||||
}
|
||||
|
||||
if (te->getGlow())
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
|
||||
}
|
||||
|
||||
if (LLPipeline::sRenderDeferred)
|
||||
{
|
||||
if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
|
||||
{
|
||||
if (te->getBumpmap())
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
|
||||
}
|
||||
else
|
||||
{
|
||||
pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (facep->isState(LLFace::RIGGED))
|
||||
{ //face is not rigged but used to be, remove from rigged face pool
|
||||
LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
|
||||
if (pool)
|
||||
{
|
||||
pool->removeRiggedFace(facep);
|
||||
}
|
||||
facep->clearState(LLFace::RIGGED);
|
||||
}
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
|
||||
{
|
||||
facep->clearVertexBuffer();
|
||||
@@ -2718,6 +3335,17 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
|
||||
facep->clearVertexBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
if (is_rigged)
|
||||
{
|
||||
drawablep->setState(LLDrawable::RIGGED);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawablep->clearState(LLDrawable::RIGGED);
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
}
|
||||
|
||||
group->mBufferUsage = useage;
|
||||
|
||||
@@ -44,12 +44,27 @@
|
||||
class LLViewerTextureAnim;
|
||||
class LLDrawPool;
|
||||
class LLSelectNode;
|
||||
class LLVOAvatar;
|
||||
class LLMeshSkinInfo;
|
||||
|
||||
enum LLVolumeInterfaceType
|
||||
{
|
||||
INTERFACE_FLEXIBLE = 1,
|
||||
};
|
||||
|
||||
#if MESH_ENABLED
|
||||
class LLRiggedVolume : public LLVolume
|
||||
{
|
||||
public:
|
||||
LLRiggedVolume(const LLVolumeParams& params)
|
||||
: LLVolume(params, 0.f)
|
||||
{
|
||||
}
|
||||
|
||||
void update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* src_volume);
|
||||
};
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// Base class for implementations of the volume - Primitive, Flexible Object, etc.
|
||||
class LLVolumeInterface
|
||||
{
|
||||
@@ -181,6 +196,12 @@ public:
|
||||
void updateSculptTexture();
|
||||
void setIndexInTex(S32 index) { mIndexInTex = index ;}
|
||||
void sculpt();
|
||||
#if MESH_ENABLED
|
||||
static void rebuildMeshAssetCallback(LLVFS *vfs,
|
||||
const LLUUID& asset_uuid,
|
||||
LLAssetType::EType type,
|
||||
void* user_data, S32 status, LLExtStat ext_status);
|
||||
#endif //MESH_ENABLED
|
||||
void updateRelativeXform();
|
||||
/*virtual*/ BOOL updateGeometry(LLDrawable *drawable);
|
||||
/*virtual*/ void updateFaceSize(S32 idx);
|
||||
@@ -227,6 +248,9 @@ public:
|
||||
U32 getVolumeInterfaceID() const;
|
||||
virtual BOOL isFlexible() const;
|
||||
virtual BOOL isSculpted() const;
|
||||
#if MESH_ENABLED
|
||||
virtual BOOL isMesh() const;
|
||||
#endif //MESH_ENABLED
|
||||
virtual BOOL hasLightTexture() const;
|
||||
|
||||
BOOL isVolumeGlobal() const;
|
||||
@@ -236,6 +260,35 @@ public:
|
||||
// tag: vaa emerald local_asset_browser
|
||||
void setSculptChanged(BOOL has_changed) { mSculptChanged = has_changed; }
|
||||
|
||||
#if MESH_ENABLED
|
||||
void notifyMeshLoaded();
|
||||
|
||||
// Returns 'true' iff the media data for this object is in flight
|
||||
bool isMediaDataBeingFetched() const;
|
||||
|
||||
// Returns the "last fetched" media version, or -1 if not fetched yet
|
||||
S32 getLastFetchedMediaVersion() const { return mLastFetchedMediaVersion; }
|
||||
|
||||
void addMDCImpl() { ++mMDCImplCount; }
|
||||
void removeMDCImpl() { --mMDCImplCount; }
|
||||
S32 getMDCImplCount() { return mMDCImplCount; }
|
||||
|
||||
|
||||
//rigged volume update (for raycasting)
|
||||
void updateRiggedVolume();
|
||||
LLRiggedVolume* getRiggedVolume();
|
||||
|
||||
//returns true if volume should be treated as a rigged volume
|
||||
// - Build tools are open
|
||||
// - object is an attachment
|
||||
// - object is attached to self
|
||||
// - object is rendered as rigged
|
||||
bool treatAsRigged();
|
||||
|
||||
//clear out rigged volume and revert back to non-rigged state for picking/LOD/distance updates
|
||||
void clearRiggedVolume();
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
protected:
|
||||
S32 computeLODDetail(F32 distance, F32 radius);
|
||||
BOOL calcLOD();
|
||||
@@ -262,7 +315,9 @@ private:
|
||||
LLPointer<LLViewerFetchedTexture> mSculptTexture;
|
||||
LLPointer<LLViewerFetchedTexture> mLightTexture;
|
||||
S32 mIndexInTex;
|
||||
|
||||
#if MESH_ENABLED
|
||||
LLPointer<LLRiggedVolume> mRiggedVolume;
|
||||
#endif //MESH_ENABLED
|
||||
// statics
|
||||
public:
|
||||
static F32 sLODSlopDistanceFactor;// Changing this to zero, effectively disables the LOD transition slop
|
||||
|
||||
@@ -70,6 +70,9 @@
|
||||
#include "llgldbg.h"
|
||||
#include "llhudmanager.h"
|
||||
#include "lllightconstants.h"
|
||||
#if MESH_ENABLED
|
||||
#include "llmeshrepository.h"
|
||||
#endif //MESH_ENABLED
|
||||
#include "llresmgr.h"
|
||||
#include "llselectmgr.h"
|
||||
#include "llsky.h"
|
||||
@@ -2108,6 +2111,9 @@ void LLPipeline::rebuildPriorityGroups()
|
||||
|
||||
assertInitialized();
|
||||
|
||||
#if MESH_ENABLED
|
||||
gMeshRepo.notifyLoadedMeshes();
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
mGroupQ1Locked = true;
|
||||
// Iterate through all drawables on the priority build queue,
|
||||
|
||||
Reference in New Issue
Block a user