summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRunitaiLinden <davep@lindenlab.com>2024-04-17 16:12:49 -0500
committerGitHub <noreply@github.com>2024-04-17 16:12:49 -0500
commitbc93177ea0788a245554882b6d721eae2e057206 (patch)
tree5b15cf6b55ff8e200e763ae720771f3f91ead8f3
parentd46811d60d8fca4a9908b4e989b14905345928bd (diff)
1176 integrate llgltfnode with selection manager and llmaniptranslate/rotate (#1258)
* #1176 Somewhat working GLTF Node support for translate tool * #1176 Missing file from last commit * #1176 Better translation for rotated nodes. * #1176 Fix for objects snapping back to original position * #1176 GLTF Samples compatibility pass -- attempt at improving rotation manip support, incidental cleanup, GLTF node debug display * #1176 Clean out some unused and not working functions. * #1176 Fix for mac build, incidental cleanup * Mac build fix
-rw-r--r--indra/llmath/llmatrix4a.h14
-rw-r--r--indra/llrender/llrender.cpp24
-rw-r--r--indra/newview/gltf/asset.cpp128
-rw-r--r--indra/newview/gltf/asset.h68
-rw-r--r--indra/newview/gltf/primitive.cpp180
-rw-r--r--indra/newview/gltfscenemanager.cpp153
-rw-r--r--indra/newview/gltfscenemanager.h2
-rw-r--r--indra/newview/llagentcamera.cpp2
-rw-r--r--indra/newview/lldrawpoolalpha.cpp7
-rw-r--r--indra/newview/llfetchedgltfmaterial.cpp3
-rw-r--r--indra/newview/llfetchedgltfmaterial.h2
-rw-r--r--indra/newview/llmanip.cpp8
-rw-r--r--indra/newview/llmaniprotate.cpp293
-rw-r--r--indra/newview/llmaniptranslate.cpp225
-rw-r--r--indra/newview/llselectmgr.cpp118
-rw-r--r--indra/newview/llselectmgr.h9
-rw-r--r--indra/newview/lltinygltfhelper.cpp30
-rw-r--r--indra/newview/lltoolselect.cpp2
-rw-r--r--indra/newview/llviewermenu.cpp4
-rw-r--r--indra/newview/llviewerobject.cpp162
-rw-r--r--indra/newview/llviewerobject.h12
-rw-r--r--indra/newview/llviewerwindow.cpp18
-rw-r--r--indra/newview/llviewerwindow.h4
-rw-r--r--indra/newview/pipeline.cpp32
-rw-r--r--indra/newview/pipeline.h6
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml10
26 files changed, 1043 insertions, 473 deletions
diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h
index 2cf50e9cd2..12fc6d570a 100644
--- a/indra/llmath/llmatrix4a.h
+++ b/indra/llmath/llmatrix4a.h
@@ -34,8 +34,8 @@
class LLMatrix4a
{
public:
- LL_ALIGN_16(LLVector4a mMatrix[4]);
-
+ LL_ALIGN_16(LLVector4a mMatrix[4]);
+
LLMatrix4a()
{
@@ -56,6 +56,16 @@ public:
return (F32*)&mMatrix;
}
+ inline LLMatrix4& asMatrix4()
+ {
+ return *(LLMatrix4*)this;
+ }
+
+ inline const LLMatrix4& asMatrix4() const
+ {
+ return *(LLMatrix4*)this;
+ }
+
inline void clear()
{
mMatrix[0].clear();
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 4d64dc9e10..358b35f36b 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -2068,10 +2068,6 @@ void LLRender::diffuseColor3f(F32 r, F32 g, F32 b)
{
shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,1.f);
}
- else
- {
- glColor3f(r,g,b);
- }
}
void LLRender::diffuseColor3fv(const F32* c)
@@ -2083,10 +2079,6 @@ void LLRender::diffuseColor3fv(const F32* c)
{
shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0], c[1], c[2], 1.f);
}
- else
- {
- glColor3fv(c);
- }
}
void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a)
@@ -2098,10 +2090,6 @@ void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a)
{
shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,a);
}
- else
- {
- glColor4f(r,g,b,a);
- }
}
void LLRender::diffuseColor4fv(const F32* c)
@@ -2113,10 +2101,6 @@ void LLRender::diffuseColor4fv(const F32* c)
{
shader->uniform4fv(LLShaderMgr::DIFFUSE_COLOR, 1, c);
}
- else
- {
- glColor4fv(c);
- }
}
void LLRender::diffuseColor4ubv(const U8* c)
@@ -2128,10 +2112,6 @@ void LLRender::diffuseColor4ubv(const U8* c)
{
shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0]/255.f, c[1]/255.f, c[2]/255.f, c[3]/255.f);
}
- else
- {
- glColor4ubv(c);
- }
}
void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a)
@@ -2143,10 +2123,6 @@ void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a)
{
shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r/255.f, g/255.f, b/255.f, a/255.f);
}
- else
- {
- glColor4ub(r,g,b,a);
- }
}
diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp
index 092b6e5d4b..7181c5fa53 100644
--- a/indra/newview/gltf/asset.cpp
+++ b/indra/newview/gltf/asset.cpp
@@ -69,9 +69,12 @@ void Node::updateTransforms(Asset& asset, const LLMatrix4a& parentMatrix)
matMul(mMatrix, parentMatrix, mAssetMatrix);
mAssetMatrixInv = inverse(mAssetMatrix);
+ S32 my_index = this - &asset.mNodes[0];
+
for (auto& childIndex : mChildren)
{
Node& child = asset.mNodes[childIndex];
+ child.mParent = my_index;
child.updateTransforms(asset, mAssetMatrix);
}
}
@@ -208,4 +211,129 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
return node_hit;
}
+const Node& Node::operator=(const tinygltf::Node& src)
+{
+ F32* dstMatrix = mMatrix.getF32ptr();
+
+ if (src.matrix.size() == 16)
+ {
+ // Node has a transformation matrix, just copy it
+ for (U32 i = 0; i < 16; ++i)
+ {
+ dstMatrix[i] = (F32)src.matrix[i];
+ }
+ }
+ else if (!src.rotation.empty() || !src.translation.empty() || !src.scale.empty())
+ {
+ // node has rotation/translation/scale, convert to matrix
+ glh::quaternionf rotation;
+ if (src.rotation.size() == 4)
+ {
+ rotation = glh::quaternionf((F32)src.rotation[0], (F32)src.rotation[1], (F32)src.rotation[2], (F32)src.rotation[3]);
+ }
+
+ glh::vec3f translation;
+ if (src.translation.size() == 3)
+ {
+ translation = glh::vec3f((F32)src.translation[0], (F32)src.translation[1], (F32)src.translation[2]);
+ }
+
+ glh::vec3f scale;
+ if (src.scale.size() == 3)
+ {
+ scale = glh::vec3f((F32)src.scale[0], (F32)src.scale[1], (F32)src.scale[2]);
+ }
+ else
+ {
+ scale.set_value(1.f, 1.f, 1.f);
+ }
+
+ glh::matrix4f rot;
+ rotation.get_value(rot);
+
+ glh::matrix4f trans;
+ trans.set_translate(translation);
+
+ glh::matrix4f sc;
+ sc.set_scale(scale);
+
+ glh::matrix4f t;
+ //t = sc * rot * trans;
+ //t = trans * rot * sc; // best so far, still wrong on negative scale
+ //t = sc * trans * rot;
+ t = trans * sc * rot;
+
+ mMatrix.loadu(t.m);
+ }
+ else
+ {
+ // node specifies no transformation, set to identity
+ mMatrix.setIdentity();
+ }
+
+ mChildren = src.children;
+ mMesh = src.mesh;
+ mName = src.name;
+
+ return *this;
+}
+
+void Asset::render(bool opaque)
+{
+ for (auto& node : mNodes)
+ {
+ if (node.mMesh != INVALID_INDEX)
+ {
+ Mesh& mesh = mMeshes[node.mMesh];
+ for (auto& primitive : mesh.mPrimitives)
+ {
+ gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix);
+ bool cull = true;
+ if (primitive.mMaterial != INVALID_INDEX)
+ {
+ Material& material = mMaterials[primitive.mMaterial];
+
+ if ((material.mMaterial->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND) == opaque)
+ {
+ continue;
+ }
+ material.mMaterial->bind();
+ cull = !material.mMaterial->mDoubleSided;
+ }
+ else
+ {
+ if (!opaque)
+ {
+ continue;
+ }
+ LLFetchedGLTFMaterial::sDefault.bind();
+ }
+
+ LLGLDisable cull_face(!cull ? GL_CULL_FACE : 0);
+
+ primitive.mVertexBuffer->setBuffer();
+ if (primitive.mVertexBuffer->getNumIndices() > 0)
+ {
+ primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0);
+ }
+ else
+ {
+ primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts());
+ }
+
+ }
+ }
+ }
+}
+
+void Asset::renderOpaque()
+{
+ render(true);
+}
+
+void Asset::renderTransparent()
+{
+ render(false);
+}
+
diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h
index 0f1d4e8993..acf9ba77df 100644
--- a/indra/newview/gltf/asset.h
+++ b/indra/newview/gltf/asset.h
@@ -171,31 +171,12 @@ namespace LL
LLMatrix4a mAssetMatrixInv; //transform from asset to local space
std::vector<S32> mChildren;
+ S32 mParent = INVALID_INDEX;
+
S32 mMesh = INVALID_INDEX;
std::string mName;
- const Node& operator=(const tinygltf::Node& src)
- {
- F32* dstMatrix = mMatrix.getF32ptr();
-
- if (src.matrix.size() != 16)
- {
- mMatrix.setIdentity();
- }
- else
- {
- for (U32 i = 0; i < 16; ++i)
- {
- dstMatrix[i] = (F32)src.matrix[i];
- }
- }
-
- mChildren = src.children;
- mMesh = src.mesh;
- mName = src.name;
-
- return *this;
- }
+ const Node& operator=(const tinygltf::Node& src);
// Set mRenderMatrix to a transform that can be used for the current render pass
// modelview -- parent's render matrix
@@ -314,21 +295,23 @@ namespace LL
void allocateGLResources(const std::string& filename, const tinygltf::Model& model)
{
- for (auto& mesh : mMeshes)
- {
- mesh.allocateGLResources(*this);
- }
-
+ // do images first as materials may depend on images
for (auto& image : mImages)
{
image.allocateGLResources();
}
+ // do materials before meshes as meshes may depend on materials
for (U32 i = 0; i < mMaterials.size(); ++i)
{
mMaterials[i].allocateGLResources(*this);
LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true);
}
+
+ for (auto& mesh : mMeshes)
+ {
+ mesh.allocateGLResources(*this);
+ }
}
// update asset-to-node and node-to-asset transforms
@@ -337,34 +320,9 @@ namespace LL
// update node render transforms
void updateRenderTransforms(const LLMatrix4a& modelview);
- void renderOpaque()
- {
- for (auto& node : mNodes)
- {
- if (node.mMesh != INVALID_INDEX)
- {
- Mesh& mesh = mMeshes[node.mMesh];
- for (auto& primitive : mesh.mPrimitives)
- {
- gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix);
- if (primitive.mMaterial != INVALID_INDEX)
- {
- Material& material = mMaterials[primitive.mMaterial];
- material.mMaterial->bind();
- }
- primitive.mVertexBuffer->setBuffer();
- if (primitive.mVertexBuffer->getNumIndices() > 0)
- {
- primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0);
- }
- else
- {
- primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts());
- }
- }
- }
- }
- }
+ void render(bool opaque);
+ void renderOpaque();
+ void renderTransparent();
// return the index of the node that the line segment intersects with, or -1 if no hit
// input and output values must be in this asset's local coordinate frame
diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp
index 71654dcfdd..b5d59e1b24 100644
--- a/indra/newview/gltf/primitive.cpp
+++ b/indra/newview/gltf/primitive.cpp
@@ -162,10 +162,25 @@ void Primitive::copyAttribute(Asset& asset, S32 accessorIdx, LLStrider<T>& dst)
{
copyAttributeArray(asset, accessor, (const U32*)src, dst, bufferView.mByteStride);
}
+ else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)
+ {
+ copyAttributeArray(asset, accessor, (const U8*)src, dst, bufferView.mByteStride);
+ }
+ else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_SHORT)
+ {
+ copyAttributeArray(asset, accessor, (const S16*)src, dst, bufferView.mByteStride);
+ }
+ else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_BYTE)
+ {
+ copyAttributeArray(asset, accessor, (const S8*)src, dst, bufferView.mByteStride);
+ }
+ else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_DOUBLE)
+ {
+ copyAttributeArray(asset, accessor, (const F64*)src, dst, bufferView.mByteStride);
+ }
else
-
{
- LL_ERRS() << "Unsupported component type" << LL_ENDL;
+ LL_ERRS("GLTF") << "Unsupported component type" << LL_ENDL;
}
}
@@ -179,11 +194,11 @@ void Primitive::allocateGLResources(Asset& asset)
// get the number of vertices
U32 numVertices = 0;
- for (auto& it : mAttributes)
+ if (!mAttributes.empty())
{
- const Accessor& accessor = asset.mAccessors[it.second];
+ auto it = mAttributes.begin();
+ const Accessor& accessor = asset.mAccessors[it->second];
numVertices = accessor.mCount;
- break;
}
// get the number of indices
@@ -294,6 +309,14 @@ void Primitive::allocateGLResources(Asset& asset)
src += sizeof(U16);
}
}
+ else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)
+ {
+ for (U32 i = 0; i < numIndices; ++i)
+ {
+ *(dst++) = *(U8*)src;
+ src += sizeof(U8);
+ }
+ }
else
{
LL_ERRS("GLTF") << "Unsupported component type for indices" << LL_ENDL;
@@ -317,6 +340,22 @@ void Primitive::allocateGLResources(Asset& asset)
}
}
+ // bake material basecolor into color array
+ if (mMaterial != INVALID_INDEX)
+ {
+ const Material& material = asset.mMaterials[mMaterial];
+ LLColor4 baseColor = material.mMaterial->mBaseColor;
+ LLStrider<LLColor4U> dst;
+ mVertexBuffer->getColorStrider(dst);
+
+ for (U32 i = 0; i < numVertices; ++i)
+ {
+ LLColor4 col = *dst;
+ *dst = LLColor4U(baseColor * col);
+ dst++;
+ }
+ }
+
if (needs_texcoord)
{ // set default texcoord
LLStrider<LLVector2> dst;
@@ -368,15 +407,51 @@ void Primitive::allocateGLResources(Asset& asset)
mVertexBuffer->unmapBuffer();
}
+void initOctreeTriangle(LLVolumeTriangle* tri, F32 scaler, S32 i0, S32 i1, S32 i2, const LLVector4a& v0, const LLVector4a& v1, const LLVector4a& v2)
+{
+ //store pointers to vertex data
+ tri->mV[0] = &v0;
+ tri->mV[1] = &v1;
+ tri->mV[2] = &v2;
+
+ //store indices
+ tri->mIndex[0] = i0;
+ tri->mIndex[1] = i1;
+ tri->mIndex[2] = i2;
+
+ //get minimum point
+ LLVector4a min = v0;
+ min.setMin(min, v1);
+ min.setMin(min, v2);
+
+ //get maximum point
+ LLVector4a max = v0;
+ max.setMax(max, v1);
+ max.setMax(max, v2);
+
+ //compute center
+ LLVector4a center;
+ center.setAdd(min, max);
+ center.mul(0.5f);
+
+ tri->mPositionGroup = center;
+
+ //compute "radius"
+ LLVector4a size;
+ size.setSub(max, min);
+
+ tri->mRadius = size.getLength3().getF32() * scaler;
+}
+
void Primitive::createOctree()
{
// create octree
mOctree = new LLVolumeOctree();
+ F32 scaler = 0.25f;
+
if (mMode == TINYGLTF_MODE_TRIANGLES)
{
- F32 scaler = 0.25f;
-
const U32 num_triangles = mVertexBuffer->getNumIndices() / 3;
// Initialize all the triangles we need
mOctreeTriangles.resize(num_triangles);
@@ -388,47 +463,82 @@ void Primitive::createOctree()
{ //for each triangle
const U32 index = triangle_index * 3;
LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index];
- const LLVector4a& v0 = pos[indices[index]];
- const LLVector4a& v1 = pos[indices[index + 1]];
- const LLVector4a& v2 = pos[indices[index + 2]];
+ S32 i0 = indices[index];
+ S32 i1 = indices[index + 1];
+ S32 i2 = indices[index + 2];
+
+ const LLVector4a& v0 = pos[i0];
+ const LLVector4a& v1 = pos[i1];
+ const LLVector4a& v2 = pos[i2];
+
+ initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2);
+
+ //insert
+ mOctree->insert(tri);
+ }
+ }
+ else if (mMode == TINYGLTF_MODE_TRIANGLE_STRIP)
+ {
+ const U32 num_triangles = mVertexBuffer->getNumIndices() - 2;
+ // Initialize all the triangles we need
+ mOctreeTriangles.resize(num_triangles);
- //store pointers to vertex data
- tri->mV[0] = &v0;
- tri->mV[1] = &v1;
- tri->mV[2] = &v2;
+ LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX));
+ U16* indices = (U16*)mVertexBuffer->getMappedIndices();
- //store indices
- tri->mIndex[0] = indices[index];
- tri->mIndex[1] = indices[index + 1];
- tri->mIndex[2] = indices[index + 2];
+ for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index)
+ { //for each triangle
+ const U32 index = triangle_index + 2;
+ LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index];
+ S32 i0 = indices[index];
+ S32 i1 = indices[index - 1];
+ S32 i2 = indices[index - 2];
+
+ const LLVector4a& v0 = pos[i0];
+ const LLVector4a& v1 = pos[i1];
+ const LLVector4a& v2 = pos[i2];
- //get minimum point
- LLVector4a min = v0;
- min.setMin(min, v1);
- min.setMin(min, v2);
+ initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2);
- //get maximum point
- LLVector4a max = v0;
- max.setMax(max, v1);
- max.setMax(max, v2);
+ //insert
+ mOctree->insert(tri);
+ }
+ }
+ else if (mMode == TINYGLTF_MODE_TRIANGLE_FAN)
+ {
+ const U32 num_triangles = mVertexBuffer->getNumIndices() - 2;
+ // Initialize all the triangles we need
+ mOctreeTriangles.resize(num_triangles);
- //compute center
- LLVector4a center;
- center.setAdd(min, max);
- center.mul(0.5f);
+ LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX));
+ U16* indices = (U16*)mVertexBuffer->getMappedIndices();
- tri->mPositionGroup = center;
+ for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index)
+ { //for each triangle
+ const U32 index = triangle_index + 2;
+ LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index];
+ S32 i0 = indices[0];
+ S32 i1 = indices[index - 1];
+ S32 i2 = indices[index - 2];
- //compute "radius"
- LLVector4a size;
- size.setSub(max, min);
+ const LLVector4a& v0 = pos[i0];
+ const LLVector4a& v1 = pos[i1];
+ const LLVector4a& v2 = pos[i2];
- tri->mRadius = size.getLength3().getF32() * scaler;
+ initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2);
//insert
mOctree->insert(tri);
}
}
+ else if (mMode == TINYGLTF_MODE_POINTS ||
+ mMode == TINYGLTF_MODE_LINE ||
+ mMode == TINYGLTF_MODE_LINE_LOOP ||
+ mMode == TINYGLTF_MODE_LINE_STRIP)
+ {
+ // nothing to do, no volume... maybe add some collision geometry around these primitive types?
+ }
+
else
{
LL_ERRS() << "Unsupported Primitive mode" << LL_ENDL;
diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp
index 6c44b83646..8273c707f9 100644
--- a/indra/newview/gltfscenemanager.cpp
+++ b/indra/newview/gltfscenemanager.cpp
@@ -91,7 +91,11 @@ void GLTFSceneManager::load(const std::string& filename)
if (obj)
{ // assign to self avatar
obj->mGLTFAsset = asset;
- mObjects.push_back(obj);
+
+ if (std::find(mObjects.begin(), mObjects.end(), obj) == mObjects.end())
+ {
+ mObjects.push_back(obj);
+ }
}
}
@@ -100,43 +104,17 @@ GLTFSceneManager::~GLTFSceneManager()
mObjects.clear();
}
-LLMatrix4a getAssetToAgentTransform(LLViewerObject* obj)
+void GLTFSceneManager::renderOpaque()
{
- LLMatrix4 root;
- root.initScale(obj->getScale());
- root.rotate(obj->getRenderRotation());
- root.translate(obj->getPositionAgent());
-
- LLMatrix4a mat;
- mat.loadu((F32*) root.mMatrix);
-
- return mat;
+ render(true);
}
-LLMatrix4a getAgentToAssetTransform(LLViewerObject* obj)
+void GLTFSceneManager::renderAlpha()
{
- LLMatrix4 root;
- LLVector3 scale = obj->getScale();
- scale.mV[0] = 1.f / scale.mV[0];
- scale.mV[1] = 1.f / scale.mV[1];
- scale.mV[2] = 1.f / scale.mV[2];
-
- root.translate(-obj->getPositionAgent());
- root.rotate(~obj->getRenderRotation());
-
- LLMatrix4 scale_mat;
- scale_mat.initScale(scale);
-
- root *= scale_mat;
-
-
- LLMatrix4a mat;
- mat.loadu((F32*) root.mMatrix);
-
- return mat;
+ render(false);
}
-void GLTFSceneManager::renderOpaque()
+void GLTFSceneManager::render(bool opaque)
{
// for debugging, just render the whole scene as opaque
// by traversing the whole scenegraph
@@ -158,7 +136,7 @@ void GLTFSceneManager::renderOpaque()
gGL.pushMatrix();
- LLMatrix4a mat = getAssetToAgentTransform(mObjects[i]);
+ LLMatrix4a mat = mObjects[i]->getGLTFAssetToAgentTransform();
LLMatrix4a modelview;
modelview.loadu(gGLModelView);
@@ -166,7 +144,7 @@ void GLTFSceneManager::renderOpaque()
matMul(mat, modelview, modelview);
asset->updateRenderTransforms(modelview);
- asset->renderOpaque();
+ asset->render(opaque);
gGL.popMatrix();
}
@@ -195,7 +173,7 @@ bool GLTFSceneManager::lineSegmentIntersect(LLVOVolume* obj, Asset* asset, const
LLVector4a local_start;
LLVector4a local_end;
- LLMatrix4a asset_to_agent = getAssetToAgentTransform(obj);
+ LLMatrix4a asset_to_agent = obj->getGLTFAssetToAgentTransform();
LLMatrix4a agent_to_asset = inverse(asset_to_agent);
agent_to_asset.affineTransform(start, local_start);
@@ -331,7 +309,7 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset)
gGL.pushMatrix();
// get raycast in asset space
- LLMatrix4a agent_to_asset = getAgentToAssetTransform(obj);
+ LLMatrix4a agent_to_asset = obj->getAgentToGLTFAssetTransform();
LLVector4a start;
LLVector4a end;
@@ -399,7 +377,8 @@ void GLTFSceneManager::renderDebug()
{
if (!gPipeline.hasRenderDebugMask(
LLPipeline::RENDER_DEBUG_BBOXES |
- LLPipeline::RENDER_DEBUG_RAYCAST))
+ LLPipeline::RENDER_DEBUG_RAYCAST |
+ LLPipeline::RENDER_DEBUG_NODES))
{
return;
}
@@ -412,6 +391,7 @@ void GLTFSceneManager::renderDebug()
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gPipeline.disableLights();
+ // force update all mRenderMatrix, not just nodes with meshes
for (auto& obj : mObjects)
{
if (obj->isDead() || obj->mGLTFAsset == nullptr)
@@ -419,20 +399,115 @@ void GLTFSceneManager::renderDebug()
continue;
}
+ LLMatrix4a mat = obj->getGLTFAssetToAgentTransform();
+
+ LLMatrix4a modelview;
+ modelview.loadu(gGLModelView);
+
+ matMul(mat, modelview, modelview);
+
Asset* asset = obj->mGLTFAsset;
+ for (auto& node : asset->mNodes)
+ {
+ matMul(node.mAssetMatrix, modelview, node.mRenderMatrix);
+ }
+ }
+
+ for (auto& obj : mObjects)
+ {
+ if (obj->isDead() || obj->mGLTFAsset == nullptr)
+ {
+ continue;
+ }
+
+ Asset* asset = obj->mGLTFAsset;
- LLMatrix4a mat = getAssetToAgentTransform(obj);
+ LLMatrix4a mat = obj->getGLTFAssetToAgentTransform();
LLMatrix4a modelview;
modelview.loadu(gGLModelView);
matMul(mat, modelview, modelview);
- asset->updateRenderTransforms(modelview);
renderAssetDebug(obj, asset);
}
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NODES))
+ { //render node hierarchy
+
+ for (U32 i = 0; i < 2; ++i)
+ {
+ LLGLDepthTest depth(GL_TRUE, i == 0 ? GL_FALSE : GL_TRUE, i == 0 ? GL_GREATER : GL_LEQUAL);
+ LLGLState blend(GL_BLEND, i == 0 ? TRUE : FALSE);
+
+
+ gGL.pushMatrix();
+
+ for (auto& obj : mObjects)
+ {
+ if (obj->isDead() || obj->mGLTFAsset == nullptr)
+ {
+ continue;
+ }
+
+ LLMatrix4a mat = obj->getGLTFAssetToAgentTransform();
+
+ LLMatrix4a modelview;
+ modelview.loadu(gGLModelView);
+
+ matMul(mat, modelview, modelview);
+
+ Asset* asset = obj->mGLTFAsset;
+
+ for (auto& node : asset->mNodes)
+ {
+ // force update all mRenderMatrix, not just nodes with meshes
+ matMul(node.mAssetMatrix, modelview, node.mRenderMatrix);
+
+ gGL.loadMatrix(node.mRenderMatrix.getF32ptr());
+ // render x-axis red, y-axis green, z-axis blue
+ gGL.color4f(1.f, 0.f, 0.f, 0.5f);
+ gGL.begin(LLRender::LINES);
+ gGL.vertex3f(0.f, 0.f, 0.f);
+ gGL.vertex3f(1.f, 0.f, 0.f);
+ gGL.end();
+ gGL.flush();
+
+ gGL.color4f(0.f, 1.f, 0.f, 0.5f);
+ gGL.begin(LLRender::LINES);
+ gGL.vertex3f(0.f, 0.f, 0.f);
+ gGL.vertex3f(0.f, 1.f, 0.f);
+ gGL.end();
+ gGL.flush();
+
+ gGL.begin(LLRender::LINES);
+ gGL.color4f(0.f, 0.f, 1.f, 0.5f);
+ gGL.vertex3f(0.f, 0.f, 0.f);
+ gGL.vertex3f(0.f, 0.f, 1.f);
+ gGL.end();
+ gGL.flush();
+
+ // render path to child nodes cyan
+ gGL.color4f(0.f, 1.f, 1.f, 0.5f);
+ gGL.begin(LLRender::LINES);
+ for (auto& child_idx : node.mChildren)
+ {
+ Node& child = asset->mNodes[child_idx];
+ gGL.vertex3f(0.f, 0.f, 0.f);
+ gGL.vertex3fv(child.mMatrix.getTranslation().getF32ptr());
+ }
+ gGL.end();
+ gGL.flush();
+ }
+ }
+
+ gGL.popMatrix();
+ }
+
+ }
+
+
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
{
S32 node_hit = -1;
diff --git a/indra/newview/gltfscenemanager.h b/indra/newview/gltfscenemanager.h
index 50e1dd93da..4e9013834b 100644
--- a/indra/newview/gltfscenemanager.h
+++ b/indra/newview/gltfscenemanager.h
@@ -38,7 +38,9 @@ namespace LL
// load GLTF file from disk
void load(); // open filepicker to choose asset
void load(const std::string& filename); // load asset from filename
+ void render(bool opaque);
void renderOpaque();
+ void renderAlpha();
LLDrawable* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
BOOL pick_transparent,
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 8977b145d1..7ddf6c4390 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -2525,7 +2525,7 @@ void LLAgentCamera::setFocusGlobal(const LLPickInfo& pick)
{
LLViewerObject* objectp = gObjectList.findObject(pick.mObjectID);
- if (objectp)
+ if (objectp && pick.mGLTFNodeIndex == -1)
{
// focus on object plus designated offset
// which may or may not be same as pick.mPosGlobal
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 41dc95a8cb..81014e9d6e 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -49,6 +49,7 @@
#include "llspatialpartition.h"
#include "llglcommonfunc.h"
#include "llvoavatar.h"
+#include "gltfscenemanager.h"
#include "llenvironment.h"
@@ -260,6 +261,12 @@ void LLDrawPoolAlpha::forwardRender(bool rigged)
mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+ if (write_depth)
+ { // draw GLTF scene to depth buffer
+ gPipeline.bindDeferredShader(gDeferredPBRAlphaProgram);
+ LL::GLTFSceneManager::instance().renderAlpha();
+ }
+
// If the face is more than 90% transparent, then don't update the Depth buffer for Dof
// We don't want the nearly invisible objects to cause of DoF effects
renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, false, rigged);
diff --git a/indra/newview/llfetchedgltfmaterial.cpp b/indra/newview/llfetchedgltfmaterial.cpp
index 1ca7ffaec1..1dd1dbabbe 100644
--- a/indra/newview/llfetchedgltfmaterial.cpp
+++ b/indra/newview/llfetchedgltfmaterial.cpp
@@ -34,6 +34,9 @@
#include "llshadermgr.h"
#include "pipeline.h"
+//static
+LLFetchedGLTFMaterial LLFetchedGLTFMaterial::sDefault;
+
LLFetchedGLTFMaterial::LLFetchedGLTFMaterial()
: LLGLTFMaterial()
, mExpectedFlusTime(0.f)
diff --git a/indra/newview/llfetchedgltfmaterial.h b/indra/newview/llfetchedgltfmaterial.h
index 42c835a416..7550c75b45 100644
--- a/indra/newview/llfetchedgltfmaterial.h
+++ b/indra/newview/llfetchedgltfmaterial.h
@@ -66,6 +66,8 @@ public:
std::set<LLTextureEntry*> mTextureEntires;
+ // default material for when assets don't have one
+ static LLFetchedGLTFMaterial sDefault;
protected:
// Lifetime management
diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp
index feb691520f..8a284686ad 100644
--- a/indra/newview/llmanip.cpp
+++ b/indra/newview/llmanip.cpp
@@ -355,8 +355,14 @@ LLVector3 LLManip::getSavedPivotPoint() const
LLVector3 LLManip::getPivotPoint()
{
- if (mObjectSelection->getFirstObject() && mObjectSelection->getObjectCount() == 1 && mObjectSelection->getSelectType() != SELECT_TYPE_HUD)
+ LLViewerObject* object = mObjectSelection->getFirstObject();
+ if (object && mObjectSelection->getObjectCount() == 1 && mObjectSelection->getSelectType() != SELECT_TYPE_HUD)
{
+ LLSelectNode* select_node = mObjectSelection->getFirstNode();
+ if (select_node->mSelectedGLTFNode != -1)
+ {
+ return object->getGLTFNodePositionAgent(select_node->mSelectedGLTFNode);
+ }
return mObjectSelection->getFirstObject()->getPivotPositionAgent();
}
return LLSelectMgr::getInstance()->getBBoxOfSelection().getCenterAgent();
diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp
index 7f37f98568..1ac1992fe0 100644
--- a/indra/newview/llmaniprotate.cpp
+++ b/indra/newview/llmaniprotate.cpp
@@ -556,6 +556,7 @@ void LLManipRotate::drag( S32 x, S32 y )
BOOL damped = mSmoothRotate;
mSmoothRotate = FALSE;
+ bool gltf_mode = false;
for (LLObjectSelection::iterator iter = mObjectSelection->begin();
iter != mObjectSelection->end(); iter++)
@@ -569,154 +570,177 @@ void LLManipRotate::drag( S32 x, S32 y )
((root_object == NULL) || !root_object->isPermanentEnforced()) &&
(object->isRootEdit() || selectNode->mIndividualSelection))
{
- if (!object->isRootEdit())
- {
- // child objects should not update if parent is selected
- LLViewerObject* editable_root = (LLViewerObject*)object->getParent();
- if (editable_root->isSelected())
- {
- // we will be moved properly by our parent, so skip
- continue;
- }
- }
- LLQuaternion new_rot = selectNode->mSavedRotation * mRotation;
- std::vector<LLVector3>& child_positions = object->mUnselectedChildrenPositions ;
- std::vector<LLQuaternion> child_rotations;
- if (object->isRootEdit() && selectNode->mIndividualSelection)
- {
- object->saveUnselectedChildrenRotation(child_rotations) ;
- object->saveUnselectedChildrenPosition(child_positions) ;
- }
+ if (selectNode->mSelectedGLTFNode != -1)
+ {
+ LLQuaternion new_rot = selectNode->mSavedRotation * mRotation;
- if (object->getParent() && object->mDrawable.notNull())
- {
- LLQuaternion invParentRotation = object->mDrawable->mXform.getParent()->getWorldRotation();
- invParentRotation.transQuat();
+ object->setGLTFNodeRotationAgent(selectNode->mSelectedGLTFNode, new_rot);
- object->setRotation(new_rot * invParentRotation, damped);
- rebuild(object);
- }
- else
- {
- object->setRotation(new_rot, damped);
- LLVOAvatar* avatar = object->asAvatar();
- if (avatar && avatar->isSelf()
- && LLSelectMgr::getInstance()->mAllowSelectAvatar
- && !object->getParent())
+ gltf_mode = true;
+ }
+ else if (!gltf_mode)
+ {
+ if (!object->isRootEdit())
{
- // Normal avatars use object's orienttion, but self uses
- // separate LLCoordFrame
- // See LVOAvatar::updateOrientation()
- if (gAgentCamera.getFocusOnAvatar())
+ // child objects should not update if parent is selected
+ LLViewerObject* editable_root = (LLViewerObject*)object->getParent();
+ if (editable_root->isSelected())
{
- //Don't rotate camera with avatar
- gAgentCamera.setFocusOnAvatar(false, false, false);
+ // we will be moved properly by our parent, so skip
+ continue;
}
+ }
- LLVector3 at_axis = mAgentSelfAtAxis;
- at_axis *= mRotation;
- at_axis.mV[VZ] = 0.f;
- at_axis.normalize();
- gAgent.resetAxes(at_axis);
+ LLQuaternion new_rot = selectNode->mSavedRotation * mRotation;
+ std::vector<LLVector3>& child_positions = object->mUnselectedChildrenPositions;
+ std::vector<LLQuaternion> child_rotations;
+ if (object->isRootEdit() && selectNode->mIndividualSelection)
+ {
+ object->saveUnselectedChildrenRotation(child_rotations);
+ object->saveUnselectedChildrenPosition(child_positions);
}
- rebuild(object);
- }
- // for individually selected roots, we need to counterrotate all the children
- if (object->isRootEdit() && selectNode->mIndividualSelection)
- {
- //RN: must do non-damped updates on these objects so relative rotation appears constant
- // instead of having two competing slerps making the child objects appear to "wobble"
- object->resetChildrenRotationAndPosition(child_rotations, child_positions) ;
- }
+ if (object->getParent() && object->mDrawable.notNull())
+ {
+ LLQuaternion invParentRotation = object->mDrawable->mXform.getParent()->getWorldRotation();
+ invParentRotation.transQuat();
+
+ object->setRotation(new_rot * invParentRotation, damped);
+ rebuild(object);
+ }
+ else
+ {
+ object->setRotation(new_rot, damped);
+ LLVOAvatar* avatar = object->asAvatar();
+ if (avatar && avatar->isSelf()
+ && LLSelectMgr::getInstance()->mAllowSelectAvatar
+ && !object->getParent())
+ {
+ // Normal avatars use object's orienttion, but self uses
+ // separate LLCoordFrame
+ // See LVOAvatar::updateOrientation()
+ if (gAgentCamera.getFocusOnAvatar())
+ {
+ //Don't rotate camera with avatar
+ gAgentCamera.setFocusOnAvatar(false, false, false);
+ }
+
+ LLVector3 at_axis = mAgentSelfAtAxis;
+ at_axis *= mRotation;
+ at_axis.mV[VZ] = 0.f;
+ at_axis.normalize();
+ gAgent.resetAxes(at_axis);
+ }
+ rebuild(object);
+ }
+
+ // for individually selected roots, we need to counterrotate all the children
+ if (object->isRootEdit() && selectNode->mIndividualSelection)
+ {
+ //RN: must do non-damped updates on these objects so relative rotation appears constant
+ // instead of having two competing slerps making the child objects appear to "wobble"
+ object->resetChildrenRotationAndPosition(child_rotations, child_positions);
+ }
+ }
}
}
// update positions
- for (LLObjectSelection::iterator iter = mObjectSelection->begin();
- iter != mObjectSelection->end(); iter++)
- {
- LLSelectNode* selectNode = *iter;
- LLViewerObject* object = selectNode->getObject();
- LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit();
+ if (!gltf_mode)
+ {
+ for (LLObjectSelection::iterator iter = mObjectSelection->begin();
+ iter != mObjectSelection->end(); iter++)
+ {
+ LLSelectNode* selectNode = *iter;
+ LLViewerObject* object = selectNode->getObject();
+ LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit();
- // to avoid cumulative position changes we calculate the objects new position using its saved position
- if (object && object->permMove() && !object->isPermanentEnforced() &&
- ((root_object == NULL) || !root_object->isPermanentEnforced()))
- {
- LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter );
-
- LLVector3 old_position;
- LLVector3 new_position;
-
- if (object->isAttachment() && object->mDrawable.notNull())
- {
- // need to work in drawable space to handle selected items from multiple attachments
- // (which have no shared frame of reference other than their render positions)
- LLXform* parent_xform = object->mDrawable->getXform()->getParent();
- new_position = (selectNode->mSavedPositionLocal * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
- old_position = (object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();//object->getRenderPosition();
- }
- else
- {
- new_position = gAgent.getPosAgentFromGlobal( selectNode->mSavedPositionGlobal );
- old_position = object->getPositionAgent();
- }
- new_position = (new_position - center) * mRotation; // new relative rotated position
- new_position += center;
-
- if (object->isRootEdit() && !object->isAttachment())
- {
- LLVector3d new_pos_global = gAgent.getPosGlobalFromAgent(new_position);
- new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global);
- new_position = gAgent.getPosAgentFromGlobal(new_pos_global);
- }
+ // to avoid cumulative position changes we calculate the objects new position using its saved position
+ if (object && object->permMove() && !object->isPermanentEnforced() &&
+ ((root_object == NULL) || !root_object->isPermanentEnforced()))
+ {
+ LLVector3 center = gAgent.getPosAgentFromGlobal(mRotationCenter);
- // for individually selected child objects
- if (!object->isRootEdit() && selectNode->mIndividualSelection)
- {
- LLViewerObject* parentp = (LLViewerObject*)object->getParent();
- if (!parentp->isSelected())
- {
- if (object->isAttachment() && object->mDrawable.notNull())
- {
- // find position relative to render position of parent
- object->setPosition((new_position - parentp->getRenderPosition()) * ~parentp->getRenderRotation());
- rebuild(object);
- }
- else
- {
- object->setPositionParent((new_position - parentp->getPositionAgent()) * ~parentp->getRotationRegion());
- rebuild(object);
- }
- }
- }
- else if (object->isRootEdit())
- {
- if (object->isAttachment() && object->mDrawable.notNull())
- {
- LLXform* parent_xform = object->mDrawable->getXform()->getParent();
- object->setPosition((new_position - parent_xform->getWorldPosition()) * ~parent_xform->getWorldRotation());
- rebuild(object);
- }
- else
- {
- object->setPositionAgent(new_position);
- rebuild(object);
- }
- }
+ LLVector3 old_position;
+ LLVector3 new_position;
- // for individually selected roots, we need to counter-translate all unselected children
- if (object->isRootEdit() && selectNode->mIndividualSelection)
- {
- // only offset by parent's translation as we've already countered parent's rotation
- rebuild(object);
- object->resetChildrenPosition(old_position - new_position) ;
- }
- }
- }
+ if (selectNode->mSelectedGLTFNode != -1)
+ {
+
+ }
+ else
+ {
+ if (object->isAttachment() && object->mDrawable.notNull())
+ {
+ // need to work in drawable space to handle selected items from multiple attachments
+ // (which have no shared frame of reference other than their render positions)
+ LLXform* parent_xform = object->mDrawable->getXform()->getParent();
+ new_position = (selectNode->mSavedPositionLocal * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
+ old_position = (object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();//object->getRenderPosition();
+ }
+ else
+ {
+ new_position = gAgent.getPosAgentFromGlobal(selectNode->mSavedPositionGlobal);
+ old_position = object->getPositionAgent();
+ }
+
+ new_position = (new_position - center) * mRotation; // new relative rotated position
+ new_position += center;
+
+ if (object->isRootEdit() && !object->isAttachment())
+ {
+ LLVector3d new_pos_global = gAgent.getPosGlobalFromAgent(new_position);
+ new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global);
+ new_position = gAgent.getPosAgentFromGlobal(new_pos_global);
+ }
+
+ // for individually selected child objects
+ if (!object->isRootEdit() && selectNode->mIndividualSelection)
+ {
+ LLViewerObject* parentp = (LLViewerObject*)object->getParent();
+ if (!parentp->isSelected())
+ {
+ if (object->isAttachment() && object->mDrawable.notNull())
+ {
+ // find position relative to render position of parent
+ object->setPosition((new_position - parentp->getRenderPosition()) * ~parentp->getRenderRotation());
+ rebuild(object);
+ }
+ else
+ {
+ object->setPositionParent((new_position - parentp->getPositionAgent()) * ~parentp->getRotationRegion());
+ rebuild(object);
+ }
+ }
+ }
+ else if (object->isRootEdit())
+ {
+ if (object->isAttachment() && object->mDrawable.notNull())
+ {
+ LLXform* parent_xform = object->mDrawable->getXform()->getParent();
+ object->setPosition((new_position - parent_xform->getWorldPosition()) * ~parent_xform->getWorldRotation());
+ rebuild(object);
+ }
+ else
+ {
+ object->setPositionAgent(new_position);
+ rebuild(object);
+ }
+ }
+
+ // for individually selected roots, we need to counter-translate all unselected children
+ if (object->isRootEdit() && selectNode->mIndividualSelection)
+ {
+ // only offset by parent's translation as we've already countered parent's rotation
+ rebuild(object);
+ object->resetChildrenPosition(old_position - new_position);
+ }
+ }
+ }
+ }
+ }
// store changes to override updates
for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin();
@@ -725,12 +749,13 @@ void LLManipRotate::drag( S32 x, S32 y )
LLSelectNode* selectNode = *iter;
LLViewerObject*cur = selectNode->getObject();
LLViewerObject *root_object = (cur == NULL) ? NULL : cur->getRootEdit();
- if( cur->permModify() && cur->permMove() && !cur->isPermanentEnforced() &&
+
+ if( cur->permModify() && cur->permMove() && !cur->isPermanentEnforced() &&
((root_object == NULL) || !root_object->isPermanentEnforced()) &&
(!cur->isAvatar() || LLSelectMgr::getInstance()->mAllowSelectAvatar))
{
- selectNode->mLastRotation = cur->getRotation();
- selectNode->mLastPositionLocal = cur->getPosition();
+ selectNode->mLastRotation = cur->getRotation();
+ selectNode->mLastPositionLocal = cur->getPosition();
}
}
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index cafb3fef67..9fc5ad502c 100644
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -655,114 +655,125 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask)
LLVector3d clamped_relative_move = axis_magnitude * axis_d; // scalar multiply
LLVector3 clamped_relative_move_f = (F32)axis_magnitude * axis_f; // scalar multiply
- for (LLObjectSelection::iterator iter = mObjectSelection->begin();
- iter != mObjectSelection->end(); iter++)
- {
- LLSelectNode* selectNode = *iter;
- LLViewerObject* object = selectNode->getObject();
-
- // Only apply motion to root objects and objects selected
- // as "individual".
- if (!object->isRootEdit() && !selectNode->mIndividualSelection)
- {
- continue;
- }
-
- if (!object->isRootEdit())
- {
- // child objects should not update if parent is selected
- LLViewerObject* editable_root = (LLViewerObject*)object->getParent();
- if (editable_root->isSelected())
- {
- // we will be moved properly by our parent, so skip
- continue;
- }
- }
-
- LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit();
- if (object->permMove() && !object->isPermanentEnforced() &&
- ((root_object == NULL) || !root_object->isPermanentEnforced()))
- {
- // handle attachments in local space
- if (object->isAttachment() && object->mDrawable.notNull())
- {
- // calculate local version of relative move
- LLQuaternion objWorldRotation = object->mDrawable->mXform.getParent()->getWorldRotation();
- objWorldRotation.transQuat();
-
- LLVector3 old_position_local = object->getPosition();
- LLVector3 new_position_local = selectNode->mSavedPositionLocal + (clamped_relative_move_f * objWorldRotation);
-
- //RN: I forget, but we need to do this because of snapping which doesn't often result
- // in position changes even when the mouse moves
- object->setPosition(new_position_local);
- rebuild(object);
- gAgentAvatarp->clampAttachmentPositions();
- new_position_local = object->getPosition();
-
- if (selectNode->mIndividualSelection)
- {
- // counter-translate child objects if we are moving the root as an individual
- object->resetChildrenPosition(old_position_local - new_position_local, TRUE) ;
- }
- }
- else
- {
- // compute new position to send to simulators, but don't set it yet.
- // We need the old position to know which simulator to send the move message to.
- LLVector3d new_position_global = selectNode->mSavedPositionGlobal + clamped_relative_move;
-
- // Don't let object centers go too far underground
- F64 min_height = LLWorld::getInstance()->getMinAllowedZ(object, object->getPositionGlobal());
- if (new_position_global.mdV[VZ] < min_height)
- {
- new_position_global.mdV[VZ] = min_height;
- }
-
- // For safety, cap heights where objects can be dragged
- if (new_position_global.mdV[VZ] > MAX_OBJECT_Z)
- {
- new_position_global.mdV[VZ] = MAX_OBJECT_Z;
- }
-
- // Grass is always drawn on the ground, so clamp its position to the ground
- if (object->getPCode() == LL_PCODE_LEGACY_GRASS)
- {
- new_position_global.mdV[VZ] = LLWorld::getInstance()->resolveLandHeightGlobal(new_position_global) + 1.f;
- }
-
- if (object->isRootEdit())
- {
- new_position_global = LLWorld::getInstance()->clipToVisibleRegions(object->getPositionGlobal(), new_position_global);
- }
-
- // PR: Only update if changed
- LLVector3 old_position_agent = object->getPositionAgent();
- LLVector3 new_position_agent = gAgent.getPosAgentFromGlobal(new_position_global);
- if (object->isRootEdit())
- {
- // finally, move parent object after children have calculated new offsets
- object->setPositionAgent(new_position_agent);
- rebuild(object);
- }
- else
- {
- LLViewerObject* root_object = object->getRootEdit();
- new_position_agent -= root_object->getPositionAgent();
- new_position_agent = new_position_agent * ~root_object->getRotation();
- object->setPositionParent(new_position_agent, FALSE);
- rebuild(object);
- }
+ for (LLObjectSelection::iterator iter = mObjectSelection->begin();
+ iter != mObjectSelection->end(); iter++)
+ {
+ LLSelectNode* selectNode = *iter;
+ LLViewerObject* object = selectNode->getObject();
+
+ if (selectNode->mSelectedGLTFNode != -1)
+ {
+ // manipulating a GLTF node
+ clamped_relative_move_f -= selectNode->mLastMoveLocal;
+ object->moveGLTFNode(selectNode->mSelectedGLTFNode, clamped_relative_move_f);
+ selectNode->mLastMoveLocal += clamped_relative_move_f;
+ }
+ else
+ {
+ // Only apply motion to root objects and objects selected
+ // as "individual".
+ if (!object->isRootEdit() && !selectNode->mIndividualSelection)
+ {
+ continue;
+ }
+
+ if (!object->isRootEdit())
+ {
+ // child objects should not update if parent is selected
+ LLViewerObject* editable_root = (LLViewerObject*)object->getParent();
+ if (editable_root->isSelected())
+ {
+ // we will be moved properly by our parent, so skip
+ continue;
+ }
+ }
+
+ LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit();
+ if (object->permMove() && !object->isPermanentEnforced() &&
+ ((root_object == NULL) || !root_object->isPermanentEnforced()))
+ {
+ // handle attachments in local space
+ if (object->isAttachment() && object->mDrawable.notNull())
+ {
+ // calculate local version of relative move
+ LLQuaternion objWorldRotation = object->mDrawable->mXform.getParent()->getWorldRotation();
+ objWorldRotation.transQuat();
+
+ LLVector3 old_position_local = object->getPosition();
+ LLVector3 new_position_local = selectNode->mSavedPositionLocal + (clamped_relative_move_f * objWorldRotation);
+
+ //RN: I forget, but we need to do this because of snapping which doesn't often result
+ // in position changes even when the mouse moves
+ object->setPosition(new_position_local);
+ rebuild(object);
+ gAgentAvatarp->clampAttachmentPositions();
+ new_position_local = object->getPosition();
+
+ if (selectNode->mIndividualSelection)
+ {
+ // counter-translate child objects if we are moving the root as an individual
+ object->resetChildrenPosition(old_position_local - new_position_local, TRUE);
+ }
+ }
+ else
+ {
+ // compute new position to send to simulators, but don't set it yet.
+ // We need the old position to know which simulator to send the move message to.
+ LLVector3d new_position_global = selectNode->mSavedPositionGlobal + clamped_relative_move;
+
+ // Don't let object centers go too far underground
+ F64 min_height = LLWorld::getInstance()->getMinAllowedZ(object, object->getPositionGlobal());
+ if (new_position_global.mdV[VZ] < min_height)
+ {
+ new_position_global.mdV[VZ] = min_height;
+ }
+
+ // For safety, cap heights where objects can be dragged
+ if (new_position_global.mdV[VZ] > MAX_OBJECT_Z)
+ {
+ new_position_global.mdV[VZ] = MAX_OBJECT_Z;
+ }
+
+ // Grass is always drawn on the ground, so clamp its position to the ground
+ if (object->getPCode() == LL_PCODE_LEGACY_GRASS)
+ {
+ new_position_global.mdV[VZ] = LLWorld::getInstance()->resolveLandHeightGlobal(new_position_global) + 1.f;
+ }
+
+ if (object->isRootEdit())
+ {
+ new_position_global = LLWorld::getInstance()->clipToVisibleRegions(object->getPositionGlobal(), new_position_global);
+ }
+
+ // PR: Only update if changed
+ LLVector3 old_position_agent = object->getPositionAgent();
+ LLVector3 new_position_agent = gAgent.getPosAgentFromGlobal(new_position_global);
+ if (object->isRootEdit())
+ {
+ // finally, move parent object after children have calculated new offsets
+ object->setPositionAgent(new_position_agent);
+ rebuild(object);
+ }
+ else
+ {
+ LLViewerObject* root_object = object->getRootEdit();
+ new_position_agent -= root_object->getPositionAgent();
+ new_position_agent = new_position_agent * ~root_object->getRotation();
+ object->setPositionParent(new_position_agent, FALSE);
+ rebuild(object);
+ }
+
+ if (selectNode->mIndividualSelection)
+ {
+ // counter-translate child objects if we are moving the root as an individual
+ object->resetChildrenPosition(old_position_agent - new_position_agent, TRUE);
+ }
+ }
+ selectNode->mLastPositionLocal = object->getPosition();
+ }
+ }
+ }
- if (selectNode->mIndividualSelection)
- {
- // counter-translate child objects if we are moving the root as an individual
- object->resetChildrenPosition(old_position_agent - new_position_agent, TRUE) ;
- }
- }
- selectNode->mLastPositionLocal = object->getPosition();
- }
- }
LLSelectMgr::getInstance()->updateSelectionCenter();
gAgentCamera.clearFocusObject();
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 471601f16f..20b00974e1 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -456,7 +456,7 @@ void LLSelectMgr::overrideAvatarUpdates()
//-----------------------------------------------------------------------------
// Select just the object, not any other group members.
//-----------------------------------------------------------------------------
-LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S32 face)
+LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S32 face, S32 gltf_node, S32 gltf_primitive)
{
llassert( object );
@@ -481,7 +481,7 @@ LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S3
// Place it in the list and tag it.
// This will refresh dialogs.
- addAsIndividual(object, face);
+ addAsIndividual(object, face, TRUE, gltf_node, gltf_primitive);
// Stop the object from moving (this anticipates changes on the
// simulator in LLTask::userSelect)
@@ -1033,7 +1033,7 @@ void LLSelectMgr::addAsFamily(std::vector<LLViewerObject*>& objects, BOOL add_to
//-----------------------------------------------------------------------------
// addAsIndividual() - a single object, face, etc
//-----------------------------------------------------------------------------
-void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoable)
+void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoable, S32 gltf_node, S32 gltf_primitive)
{
// check to see if object is already in list
LLSelectNode *nodep = mSelectedObjects->findNode(objectp);
@@ -1080,6 +1080,13 @@ void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoab
return;
}
+ // Handle glTF node selection
+ if (gltf_node >= 0)
+ {
+ nodep->selectGLTFNode(gltf_node, gltf_primitive, TRUE);
+
+ }
+
saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK);
updateSelectionCenter();
dialog_refresh_all();
@@ -5211,46 +5218,57 @@ void LLSelectMgr::saveSelectedObjectTransform(EActionType action_type)
{
return true; // skip
}
- selectNode->mSavedPositionLocal = object->getPosition();
- if (object->isAttachment())
- {
- if (object->isRootEdit())
- {
- LLXform* parent_xform = object->mDrawable->getXform()->getParent();
- if (parent_xform)
- {
- selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition());
- }
- else
- {
- selectNode->mSavedPositionGlobal = object->getPositionGlobal();
- }
- }
- else
- {
- LLViewerObject* attachment_root = (LLViewerObject*)object->getParent();
- LLXform* parent_xform = attachment_root ? attachment_root->mDrawable->getXform()->getParent() : NULL;
- if (parent_xform)
- {
- LLVector3 root_pos = (attachment_root->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
- LLQuaternion root_rot = (attachment_root->getRotation() * parent_xform->getWorldRotation());
- selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * root_rot) + root_pos);
- }
- else
- {
- selectNode->mSavedPositionGlobal = object->getPositionGlobal();
- }
- }
- selectNode->mSavedRotation = object->getRenderRotation();
- }
- else
- {
- selectNode->mSavedPositionGlobal = object->getPositionGlobal();
- selectNode->mSavedRotation = object->getRotationRegion();
- }
-
- selectNode->mSavedScale = object->getScale();
- selectNode->saveTextureScaleRatios(mManager->mTextureChannel);
+
+ if (selectNode->mSelectedGLTFNode != -1)
+ {
+ // save GLTF node state
+ object->getGLTFNodeTransformAgent(selectNode->mSelectedGLTFNode, &selectNode->mSavedPositionLocal, &selectNode->mSavedRotation, &selectNode->mSavedScale);
+ selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent(selectNode->mSavedPositionLocal);
+ selectNode->mLastMoveLocal.setZero();
+ }
+ else
+ {
+ selectNode->mSavedPositionLocal = object->getPosition();
+ if (object->isAttachment())
+ {
+ if (object->isRootEdit())
+ {
+ LLXform* parent_xform = object->mDrawable->getXform()->getParent();
+ if (parent_xform)
+ {
+ selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition());
+ }
+ else
+ {
+ selectNode->mSavedPositionGlobal = object->getPositionGlobal();
+ }
+ }
+ else
+ {
+ LLViewerObject* attachment_root = (LLViewerObject*)object->getParent();
+ LLXform* parent_xform = attachment_root ? attachment_root->mDrawable->getXform()->getParent() : NULL;
+ if (parent_xform)
+ {
+ LLVector3 root_pos = (attachment_root->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
+ LLQuaternion root_rot = (attachment_root->getRotation() * parent_xform->getWorldRotation());
+ selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * root_rot) + root_pos);
+ }
+ else
+ {
+ selectNode->mSavedPositionGlobal = object->getPositionGlobal();
+ }
+ }
+ selectNode->mSavedRotation = object->getRenderRotation();
+ }
+ else
+ {
+ selectNode->mSavedPositionGlobal = object->getPositionGlobal();
+ selectNode->mSavedRotation = object->getRotationRegion();
+ }
+
+ selectNode->mSavedScale = object->getScale();
+ selectNode->saveTextureScaleRatios(mManager->mTextureChannel);
+ }
return true;
}
} func(action_type, this);
@@ -6682,8 +6700,7 @@ LLSelectNode::~LLSelectNode()
}
}
-
- delete mPermissions;
+ delete mPermissions;
mPermissions = NULL;
}
@@ -6711,6 +6728,17 @@ void LLSelectNode::selectTE(S32 te_index, BOOL selected)
mLastTESelected = te_index;
}
+void LLSelectNode::selectGLTFNode(S32 node_index, S32 primitive_index, bool selected)
+{
+ if (node_index < 0)
+ {
+ return;
+ }
+
+ mSelectedGLTFNode = node_index;
+ mSelectedGLTFPrimitive = primitive_index;
+}
+
BOOL LLSelectNode::isTESelected(S32 te_index) const
{
if (te_index < 0 || te_index >= mObject->getNumTEs())
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index f89209b437..66c794af4c 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -175,6 +175,7 @@ public:
void selectAllTEs(BOOL b);
void selectTE(S32 te_index, BOOL selected);
+ void selectGLTFNode(S32 node_index, S32 primitive_index, bool selected);
BOOL isTESelected(S32 te_index) const;
bool hasSelectedTE() const { return TE_SELECT_MASK_ALL & mTESelectMask; }
S32 getLastSelectedTE() const;
@@ -217,6 +218,7 @@ public:
S16 mInventorySerial;
LLVector3 mSavedPositionLocal; // for interactively modifying object position
LLVector3 mLastPositionLocal;
+ LLVector3 mLastMoveLocal;
LLVector3d mSavedPositionGlobal; // for interactively modifying object position
LLVector3 mSavedScale; // for interactively modifying object scale
LLVector3 mLastScale;
@@ -240,11 +242,14 @@ public:
std::vector<LLVector3> mSilhouetteVertices; // array of vertices to render silhouette of object
std::vector<LLVector3> mSilhouetteNormals; // array of normals to render silhouette of object
BOOL mSilhouetteExists; // need to generate silhouette?
+ S32 mSelectedGLTFNode = -1;
+ S32 mSelectedGLTFPrimitive = -1;
protected:
LLPointer<LLViewerObject> mObject;
S32 mTESelectMask;
S32 mLastTESelected;
+
};
class LLObjectSelection : public LLRefCount
@@ -533,7 +538,7 @@ public:
LLObjectSelectionHandle selectObjectAndFamily(LLViewerObject* object, BOOL add_to_end = FALSE, BOOL ignore_select_owned = FALSE);
// For when you want just a child object.
- LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES);
+ LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES, S32 gltf_node = -1, S32 gltf_primitive = -1);
// Same as above, but takes a list of objects. Used by rectangle select.
LLObjectSelectionHandle selectObjectAndFamily(const std::vector<LLViewerObject*>& object_list, BOOL send_to_sim = TRUE);
@@ -833,7 +838,7 @@ public:
void remove(std::vector<LLViewerObject*>& objects);
void remove(LLViewerObject* object, S32 te = SELECT_ALL_TES, BOOL undoable = TRUE);
void removeAll();
- void addAsIndividual(LLViewerObject* object, S32 te = SELECT_ALL_TES, BOOL undoable = TRUE);
+ void addAsIndividual(LLViewerObject* object, S32 te = SELECT_ALL_TES, BOOL undoable = TRUE, S32 gltf_node = -1, S32 gltf_primitive = -1);
void promoteSelectionToRoot();
void demoteSelectionToIndividuals();
diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp
index 40e6f285a8..49c35165e6 100644
--- a/indra/newview/lltinygltfhelper.cpp
+++ b/indra/newview/lltinygltfhelper.cpp
@@ -87,20 +87,30 @@ void LLTinyGLTFHelper::initFetchedTextures(tinygltf::Material& material,
{
strip_alpha_channel(mr_img);
- if (occlusion_img && material.pbrMetallicRoughness.metallicRoughnessTexture.index != material.occlusionTexture.index)
+ if (occlusion_img)
{
- // occlusion is a distinct texture from pbrMetallicRoughness
- // pack into mr red channel
- int occlusion_idx = material.occlusionTexture.index;
- int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index;
- if (occlusion_idx != mr_idx)
+ if (material.pbrMetallicRoughness.metallicRoughnessTexture.index != material.occlusionTexture.index)
{
- //scale occlusion image to match resolution of mr image
- occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight());
-
- copy_red_channel(occlusion_img, mr_img);
+ // occlusion is a distinct texture from pbrMetallicRoughness
+ // pack into mr red channel
+ int occlusion_idx = material.occlusionTexture.index;
+ int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index;
+ if (occlusion_idx != mr_idx)
+ {
+ //scale occlusion image to match resolution of mr image
+ occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight());
+
+ copy_red_channel(occlusion_img, mr_img);
+ }
}
}
+ else
+ {
+ // no occlusion, make a white occlusion image
+ occlusion_img = new LLImageRaw(mr_img->getWidth(), mr_img->getHeight(), 3);
+ occlusion_img->clear(255, 255, 255);
+ copy_red_channel(occlusion_img, mr_img);
+ }
}
else if (occlusion_img)
{
diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp
index f7455c6cb8..907cec4d17 100644
--- a/indra/newview/lltoolselect.cpp
+++ b/indra/newview/lltoolselect.cpp
@@ -173,7 +173,7 @@ LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pi
if ( ignore_group )
{
- LLSelectMgr::getInstance()->selectObjectOnly(object, SELECT_ALL_TES);
+ LLSelectMgr::getInstance()->selectObjectOnly(object, SELECT_ALL_TES, pick.mGLTFNodeIndex, pick.mGLTFPrimitiveIndex);
}
else
{
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 4cf948f20d..9f377ae3e7 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -996,6 +996,10 @@ U64 info_display_from_string(std::string info_display)
{
return LLPipeline::RENDER_DEBUG_OCTREE;
}
+ else if ("nodes" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_NODES;
+ }
else if ("shadow frusta" == info_display)
{
return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA;
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index cee00db8eb..b66d4b1dab 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -4374,6 +4374,168 @@ const LLVector3 &LLViewerObject::getPositionAgent() const
return mPositionAgent;
}
+LLMatrix4a LLViewerObject::getGLTFAssetToAgentTransform() const
+{
+ LLMatrix4 root;
+ root.initScale(getScale());
+ root.rotate(getRenderRotation());
+ root.translate(getPositionAgent());
+
+ LLMatrix4a mat;
+ mat.loadu((F32*)root.mMatrix);
+
+ return mat;
+}
+
+LLVector3 LLViewerObject::getGLTFNodePositionAgent(S32 node_index) const
+{
+ LLVector3 ret;
+ getGLTFNodeTransformAgent(node_index, &ret, nullptr, nullptr);
+ return ret;
+
+}
+
+LLMatrix4a LLViewerObject::getAgentToGLTFAssetTransform() const
+{
+ LLMatrix4 root;
+ LLVector3 scale = getScale();
+ scale.mV[0] = 1.f / scale.mV[0];
+ scale.mV[1] = 1.f / scale.mV[1];
+ scale.mV[2] = 1.f / scale.mV[2];
+
+ root.translate(-getPositionAgent());
+ root.rotate(~getRenderRotation());
+
+ LLMatrix4 scale_mat;
+ scale_mat.initScale(scale);
+
+ root *= scale_mat;
+ LLMatrix4a mat;
+ mat.loadu((F32*)root.mMatrix);
+
+ return mat;
+}
+
+LLMatrix4a LLViewerObject::getGLTFNodeTransformAgent(S32 node_index) const
+{
+ LLMatrix4a mat;
+
+ if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size())
+ {
+ auto& node = mGLTFAsset->mNodes[node_index];
+
+ LLMatrix4a asset_to_agent = getGLTFAssetToAgentTransform();
+ LLMatrix4a node_to_agent;
+ matMul(node.mAssetMatrix, asset_to_agent, node_to_agent);
+
+ mat = node_to_agent;
+ }
+ else
+ {
+ mat.setIdentity();
+ }
+
+ return mat;
+}
+void LLViewerObject::getGLTFNodeTransformAgent(S32 node_index, LLVector3* position, LLQuaternion* rotation, LLVector3* scale) const
+{
+ LLMatrix4a node_to_agent = getGLTFNodeTransformAgent(node_index);
+
+ if (position)
+ {
+ LLVector4a p = node_to_agent.getTranslation();
+ position->set(p.getF32ptr());
+ }
+
+ if (rotation)
+ {
+ rotation->set(node_to_agent.asMatrix4());
+ }
+
+ if (scale)
+ {
+ scale->mV[0] = node_to_agent.mMatrix[0].getLength3().getF32();
+ scale->mV[1] = node_to_agent.mMatrix[1].getLength3().getF32();
+ scale->mV[2] = node_to_agent.mMatrix[2].getLength3().getF32();
+ }
+}
+
+void decomposeMatrix(const LLMatrix4a& mat, LLVector3& position, LLQuaternion& rotation, LLVector3& scale)
+{
+ LLVector4a p = mat.getTranslation();
+ position.set(p.getF32ptr());
+
+ rotation.set(mat.asMatrix4());
+
+ scale.mV[0] = mat.mMatrix[0].getLength3().getF32();
+ scale.mV[1] = mat.mMatrix[1].getLength3().getF32();
+ scale.mV[2] = mat.mMatrix[2].getLength3().getF32();
+}
+
+void LLViewerObject::setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion& rotation)
+{
+ if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size())
+ {
+ auto& node = mGLTFAsset->mNodes[node_index];
+
+ LLMatrix4a agent_to_asset = getAgentToGLTFAssetTransform();
+ LLMatrix4a agent_to_node = agent_to_asset;
+
+ if (node.mParent != -1)
+ {
+ auto& parent = mGLTFAsset->mNodes[node.mParent];
+ matMul(agent_to_asset, parent.mAssetMatrixInv, agent_to_node);
+ }
+
+ LLQuaternion agent_to_node_rot(agent_to_node.asMatrix4());
+ LLQuaternion new_rot;
+
+ new_rot = rotation * agent_to_node_rot;
+ new_rot.normalize();
+
+ LLVector3 pos;
+ LLQuaternion rot;
+ LLVector3 scale;
+ decomposeMatrix(node.mMatrix, pos, rot, scale);
+
+ node.mMatrix.asMatrix4().initAll(scale, new_rot, pos);
+
+ mGLTFAsset->updateTransforms();
+ }
+}
+
+void LLViewerObject::moveGLTFNode(S32 node_index, const LLVector3& offset)
+{
+ if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size())
+ {
+ auto& node = mGLTFAsset->mNodes[node_index];
+
+ LLMatrix4a agent_to_asset = getAgentToGLTFAssetTransform();
+ LLMatrix4a agent_to_node;
+ matMul(agent_to_asset, node.mAssetMatrixInv, agent_to_node);
+
+ LLVector4a origin = LLVector4a::getZero();
+ LLVector4a offset_v;
+ offset_v.load3(offset.mV);
+
+
+ agent_to_node.affineTransform(offset_v, offset_v);
+ agent_to_node.affineTransform(origin, origin);
+
+ offset_v.sub(origin);
+ offset_v.getF32ptr()[3] = 1.f;
+
+ LLMatrix4a trans;
+ trans.setIdentity();
+ trans.mMatrix[3] = offset_v;
+
+ matMul(trans, node.mMatrix, node.mMatrix);
+
+ // TODO -- only update transforms for this node and its children (or use a dirty flag)
+ mGLTFAsset->updateTransforms();
+ }
+}
+
const LLVector3 &LLViewerObject::getPositionRegion() const
{
if (!isRoot())
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 3d6903d177..64c1ee6633 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -315,6 +315,18 @@ public:
virtual const LLVector3 &getPositionAgent() const;
virtual const LLVector3 getRenderPosition() const;
+ LLMatrix4a getAgentToGLTFAssetTransform() const;
+ LLMatrix4a getGLTFAssetToAgentTransform() const;
+ LLVector3 getGLTFNodePositionAgent(S32 node_index) const;
+ LLMatrix4a getGLTFNodeTransformAgent(S32 node_index) const;
+ void getGLTFNodeTransformAgent(S32 node_index, LLVector3* position, LLQuaternion* rotation, LLVector3* scale) const;
+
+ // move the node at the given index by the given offset in agent space
+ void moveGLTFNode(S32 node_index, const LLVector3& offset);
+
+ // set the rotation in agent space of the given node
+ void setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion& rotation);
+
virtual const LLVector3 getPivotPositionAgent() const; // Usually = to getPositionAgent, unless like flex objects it's not
LLViewerObject* getRootEdit() const;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 1459686f10..a0b0fabb66 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -246,6 +246,8 @@ LLVector2 gDebugRaycastTexCoord;
LLVector4a gDebugRaycastNormal;
LLVector4a gDebugRaycastTangent;
S32 gDebugRaycastFaceHit;
+S32 gDebugRaycastGLTFNodeHit;
+S32 gDebugRaycastGLTFPrimitiveHit;
LLVector4a gDebugRaycastStart;
LLVector4a gDebugRaycastEnd;
@@ -3348,9 +3350,11 @@ void LLViewerWindow::updateUI()
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
{
- gDebugRaycastFaceHit = -1;
+ gDebugRaycastFaceHit = gDebugRaycastGLTFNodeHit = gDebugRaycastGLTFPrimitiveHit = -1;
gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, FALSE,
&gDebugRaycastFaceHit,
+ &gDebugRaycastGLTFNodeHit,
+ &gDebugRaycastGLTFPrimitiveHit,
&gDebugRaycastIntersection,
&gDebugRaycastTexCoord,
&gDebugRaycastNormal,
@@ -4343,6 +4347,8 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
BOOL pick_unselectable,
BOOL pick_reflection_probe,
S32* face_hit,
+ S32* gltf_node_hit,
+ S32* gltf_primitive_hit,
LLVector4a *intersection,
LLVector2 *uv,
LLVector4a *normal,
@@ -4436,7 +4442,7 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
if (!found) // if not found in HUD, look in world:
{
found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe,
- face_hit, intersection, uv, normal, tangent);
+ face_hit, gltf_node_hit, gltf_primitive_hit, intersection, uv, normal, tangent);
if (found && !pick_transparent)
{
gDebugRaycastIntersection = *intersection;
@@ -6140,8 +6146,8 @@ LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos,
void LLPickInfo::fetchResults()
{
-
S32 face_hit = -1;
+
LLVector4a intersection, normal;
LLVector4a tangent;
@@ -6164,8 +6170,8 @@ void LLPickInfo::fetchResults()
}
LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f,
- NULL, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe, &face_hit,
- &intersection, &uv, &normal, &tangent, &start, &end);
+ nullptr, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe, &face_hit, &mGLTFNodeIndex, &mGLTFPrimitiveIndex,
+ &intersection, &uv, &normal, &tangent, &start, &end);
mPickPt = mMousePt;
@@ -6311,6 +6317,8 @@ void LLPickInfo::getSurfaceInfo()
if (gViewerWindow->cursorIntersect(ll_round((F32)mMousePt.mX), ll_round((F32)mMousePt.mY), 1024.f,
objectp, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe,
&mObjectFace,
+ &mGLTFNodeIndex,
+ &mGLTFPrimitiveIndex,
&intersection,
&mSTCoords,
&normal,
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index ad634503ba..2e90c5faeb 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -119,6 +119,8 @@ public:
LLUUID mParticleOwnerID;
LLUUID mParticleSourceID;
S32 mObjectFace;
+ S32 mGLTFNodeIndex = -1;
+ S32 mGLTFPrimitiveIndex = -1;
LLHUDIcon* mHUDIcon;
LLVector3 mIntersection;
LLVector2 mUVCoords;
@@ -423,6 +425,8 @@ public:
BOOL pick_unselectable = TRUE,
BOOL pick_reflection_probe = TRUE,
S32* face_hit = NULL,
+ S32* gltf_node_hit = nullptr,
+ S32* gltf_primitive_hit = nullptr,
LLVector4a *intersection = NULL,
LLVector2 *uv = NULL,
LLVector4a *normal = NULL,
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index ea40365c97..3adf2828f8 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -6309,6 +6309,8 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start,
bool pick_unselectable,
bool pick_reflection_probe,
S32* face_hit,
+ S32* gltf_node_hit,
+ S32* gltf_primitive_hit,
LLVector4a* intersection, // return the intersection point
LLVector2* tex_coord, // return the texture coordinates of the intersection point
LLVector4a* normal, // return the surface normal at the intersection point
@@ -6352,15 +6354,6 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start,
}
}
- S32 node_hit = -1;
- S32 primitive_hit = -1;
- LLDrawable* hit = LL::GLTFSceneManager::instance().lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe, &node_hit, &primitive_hit, &position, tex_coord, normal, tangent);
- if (hit)
- {
- drawable = hit;
- local_end = position;
- }
-
if (!sPickAvatar)
{
//save hit info in case we need to restore
@@ -6461,6 +6454,25 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start,
}
}
+ S32 node_hit = -1;
+ S32 primitive_hit = -1;
+ LLDrawable* hit = LL::GLTFSceneManager::instance().lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe, &node_hit, &primitive_hit, &position, tex_coord, normal, tangent);
+ if (hit)
+ {
+ drawable = hit;
+ local_end = position;
+ }
+
+ if (gltf_node_hit)
+ {
+ *gltf_node_hit = node_hit;
+ }
+
+ if (gltf_primitive_hit)
+ {
+ *gltf_primitive_hit = primitive_hit;
+ }
+
if (intersection)
{
*intersection = position;
@@ -7269,7 +7281,7 @@ void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst)
LLVector4a result;
result.clear();
- gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, TRUE, NULL, &result);
+ gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, TRUE, nullptr, nullptr, nullptr, &result);
focus_point.set(result.getF32ptr());
}
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 817750b4a1..bfa4009a0b 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -210,6 +210,8 @@ public:
bool pick_unselectable,
bool pick_reflection_probe,
S32* face_hit, // return the face hit
+ S32* gltf_node_hit = nullptr, // return the gltf node hit
+ S32* gltf_primitive_hit = nullptr, // return the gltf primitive hit
LLVector4a* intersection = NULL, // return the intersection point
LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
LLVector4a* normal = NULL, // return the surface normal at the intersection point
@@ -615,12 +617,12 @@ public:
RENDER_DEBUG_PHYSICS_SHAPES = 0x02000000,
RENDER_DEBUG_NORMALS = 0x04000000,
RENDER_DEBUG_LOD_INFO = 0x08000000,
- RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000, // not used
+ RENDER_DEBUG_NODES = 0x20000000,
RENDER_DEBUG_TEXEL_DENSITY = 0x40000000,
RENDER_DEBUG_TRIANGLE_COUNT = 0x80000000,
RENDER_DEBUG_IMPOSTORS = 0x100000000,
RENDER_DEBUG_REFLECTION_PROBES = 0x200000000,
- RENDER_DEBUG_PROBE_UPDATES = 0x400000000
+ RENDER_DEBUG_PROBE_UPDATES = 0x400000000,
};
public:
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index c2f04231fc..a366e78a2d 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2889,6 +2889,16 @@ function="World.EnvPreset"
parameter="octree" />
</menu_item_check>
<menu_item_check
+ label="GLTF Nodes"
+ name="GLTF Nodes">
+ <menu_item_check.on_check
+ function="Advanced.CheckInfoDisplay"
+ parameter="nodes" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleInfoDisplay"
+ parameter="nodes" />
+ </menu_item_check>
+ <menu_item_check
label="Shadow Frusta"
name="Shadow Frusta">
<menu_item_check.on_check