summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llprimitive/CMakeLists.txt2
-rw-r--r--indra/llprimitive/llmodelloader.h6
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/gltf/asset.cpp20
-rw-r--r--indra/newview/gltf/asset.h3
-rw-r--r--indra/newview/gltf/llgltfloader.cpp (renamed from indra/llprimitive/llgltfloader.cpp)301
-rw-r--r--indra/newview/gltf/llgltfloader.h (renamed from indra/llprimitive/llgltfloader.h)15
-rw-r--r--indra/newview/llfilepicker.cpp2
-rw-r--r--indra/newview/llfloatermodelpreview.cpp6
-rw-r--r--indra/newview/llmodelpreview.cpp2
10 files changed, 291 insertions, 68 deletions
diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt
index 3d8e02cb16..e13f0bbd96 100644
--- a/indra/llprimitive/CMakeLists.txt
+++ b/indra/llprimitive/CMakeLists.txt
@@ -12,7 +12,6 @@ include(TinyGLTF)
set(llprimitive_SOURCE_FILES
lldaeloader.cpp
- llgltfloader.cpp
llgltfmaterial.cpp
llmaterialid.cpp
llmaterial.cpp
@@ -32,7 +31,6 @@ set(llprimitive_SOURCE_FILES
set(llprimitive_HEADER_FILES
CMakeLists.txt
lldaeloader.h
- llgltfloader.h
llgltfmaterial.h
llgltfmaterial_templates.h
legacy_object_types.h
diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h
index 530e61e2b8..73ec0ed1f4 100644
--- a/indra/llprimitive/llmodelloader.h
+++ b/indra/llprimitive/llmodelloader.h
@@ -111,6 +111,7 @@ public:
bool mCacheOnlyHitIfRigged; // ignore cached SLM if it does not contain rig info (and we want rig info)
model_list mModelList;
+ // The scene is pretty much what ends up getting loaded for upload. Basically assign things to this guy if you want something uploaded.
scene mScene;
typedef std::queue<LLPointer<LLModel> > model_queue;
@@ -119,9 +120,14 @@ public:
model_queue mPhysicsQ;
//map of avatar joints as named in COLLADA assets to internal joint names
+ // Do not use this for anything other than looking up the name of a joint. This is populated elsewhere.
JointMap mJointMap;
+
+ // The joint list is what you want to use to actually setup the specific joint transformations.
JointTransformMap& mJointList;
JointNameSet& mJointsFromNode;
+
+
U32 mMaxJointsPerMesh;
LLModelLoader(
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 98151e2f4d..dee3d5ed59 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -76,6 +76,7 @@ set(viewer_SOURCE_FILES
gltf/accessor.cpp
gltf/primitive.cpp
gltf/animation.cpp
+ gltf/llgltfloader.cpp
groupchatlistener.cpp
llaccountingcostmanager.cpp
llaisapi.cpp
@@ -746,6 +747,7 @@ set(viewer_HEADER_FILES
gltf/buffer_util.h
gltf/primitive.h
gltf/animation.h
+ gltf/llgltfloader.h
llaccountingcost.h
llaccountingcostmanager.h
llaisapi.h
diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp
index c210b9c61d..beccb02bd4 100644
--- a/indra/newview/gltf/asset.cpp
+++ b/indra/newview/gltf/asset.cpp
@@ -472,11 +472,14 @@ void Asset::update()
for (auto& image : mImages)
{
- if (image.mTexture.notNull())
- { // HACK - force texture to be loaded full rez
- // TODO: calculate actual vsize
- image.mTexture->addTextureStats(2048.f * 2048.f);
- image.mTexture->setBoostLevel(LLViewerTexture::BOOST_HIGH);
+ if (image.mLoadIntoTexturePipe)
+ {
+ if (image.mTexture.notNull())
+ { // HACK - force texture to be loaded full rez
+ // TODO: calculate actual vsize
+ image.mTexture->addTextureStats(2048.f * 2048.f);
+ image.mTexture->setBoostLevel(LLViewerTexture::BOOST_HIGH);
+ }
}
}
}
@@ -603,6 +606,7 @@ bool Asset::prep()
if (vertex_count[variant] > 0)
{
U32 mat_idx = mat_id + 1;
+ #if 0
LLVertexBuffer* vb = new LLVertexBuffer(attribute_mask);
rd.mBatches[variant][mat_idx].mVertexBuffer = vb;
@@ -624,6 +628,7 @@ bool Asset::prep()
vb->unmapBuffer();
vb->unbind();
+ #endif
}
}
}
@@ -634,10 +639,10 @@ bool Asset::prep()
{
for (auto& primitive : mesh.mPrimitives)
{
- llassert(primitive.mVertexBuffer.notNull());
+ //llassert(primitive.mVertexBuffer.notNull());
}
}
-
+ #if 0
// build render batches
for (S32 node_id = 0; node_id < mNodes.size(); ++node_id)
{
@@ -664,6 +669,7 @@ bool Asset::prep()
}
}
}
+ #endif
return true;
}
diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h
index 27821659db..e70fffa986 100644
--- a/indra/newview/gltf/asset.h
+++ b/indra/newview/gltf/asset.h
@@ -286,6 +286,7 @@ namespace LL
void serialize(boost::json::object& dst) const;
};
+ // Image is for images that we want to load for the given asset. This acts as an interface into the viewer's texture pipe.
class Image
{
public:
@@ -301,6 +302,8 @@ namespace LL
S32 mBits = -1;
S32 mPixelType = -1;
+ bool mLoadIntoTexturePipe = false;
+
LLPointer<LLViewerFetchedTexture> mTexture;
const Image& operator=(const Value& src);
diff --git a/indra/llprimitive/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp
index 480012699a..2db803ef3e 100644
--- a/indra/llprimitive/llgltfloader.cpp
+++ b/indra/newview/gltf/llgltfloader.cpp
@@ -25,6 +25,8 @@
*/
#include "llgltfloader.h"
+#include "meshoptimizer.h"
+#include <glm/gtc/packing.hpp>
// Import & define single-header gltf import/export lib
#define TINYGLTF_IMPLEMENTATION
@@ -106,16 +108,7 @@ bool LLGLTFLoader::OpenFile(const std::string &filename)
std::string filename_lc(filename);
LLStringUtil::toLower(filename_lc);
- // Load a tinygltf model fom a file. Assumes that the input filename has already been
- // been sanitized to one of (.gltf , .glb) extensions, so does a simple find to distinguish.
- if (std::string::npos == filename_lc.rfind(".gltf"))
- { // file is binary
- mGltfLoaded = loader.LoadBinaryFromFile(&mGltfModel, &error_msg, &warn_msg, filename);
- }
- else
- { // file is ascii
- mGltfLoaded = loader.LoadASCIIFromFile(&mGltfModel, &error_msg, &warn_msg, filename);
- }
+ mGltfLoaded = mGLTFAsset.load(filename);
if (!mGltfLoaded)
{
@@ -129,10 +122,14 @@ bool LLGLTFLoader::OpenFile(const std::string &filename)
mMeshesLoaded = parseMeshes();
if (mMeshesLoaded) uploadMeshes();
+ /*
mMaterialsLoaded = parseMaterials();
if (mMaterialsLoaded) uploadMaterials();
+ */
+
+ setLoadState(DONE);
- return (mMeshesLoaded || mMaterialsLoaded);
+ return (mMeshesLoaded);
}
bool LLGLTFLoader::parseMeshes()
@@ -143,71 +140,262 @@ bool LLGLTFLoader::parseMeshes()
LLVolumeParams volume_params;
volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
- for (tinygltf::Mesh mesh : mGltfModel.meshes)
+ mTransform.setIdentity();
+
+ // Populate the joints from skins first.
+ // There's not many skins - and you can pretty easily iterate through the nodes from that.
+ for (auto skin : mGLTFAsset.mSkins)
+ {
+ populateJointFromSkin(skin);
+ }
+
+ for (auto node : mGLTFAsset.mNodes)
{
- LLModel *pModel = new LLModel(volume_params, 0.f);
+ LLMatrix4 transformation;
+ material_map mats;
+ auto meshidx = node.mMesh;
- if (populateModelFromMesh(pModel, mesh) &&
- (LLModel::NO_ERRORS == pModel->getStatus()) &&
- validate_model(pModel))
+ if (meshidx >= 0)
{
- mModelList.push_back(pModel);
- }
- else
- {
- setLoadState(ERROR_MODEL + pModel->getStatus());
- delete(pModel);
- return false;
+ if (mGLTFAsset.mMeshes.size() > meshidx)
+ {
+ LLModel* pModel = new LLModel(volume_params, 0.f);
+ auto mesh = mGLTFAsset.mMeshes[meshidx];
+ if (populateModelFromMesh(pModel, mesh, node, mats) && (LLModel::NO_ERRORS == pModel->getStatus()) && validate_model(pModel))
+ {
+ mModelList.push_back(pModel);
+ LLMatrix4 saved_transform = mTransform;
+
+ // This will make sure the matrix is always valid from the node.
+ node.makeMatrixValid();
+
+ LLMatrix4 gltf_transform = LLMatrix4(glm::value_ptr(node.mMatrix));
+ mTransform = gltf_transform;
+
+ // GLTF is +Y up, SL is +Z up
+ LLMatrix4 rotation;
+ rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f);
+ mTransform *= rotation;
+
+ transformation = mTransform;
+
+ // adjust the transformation to compensate for mesh normalization
+ LLVector3 mesh_scale_vector;
+ LLVector3 mesh_translation_vector;
+ pModel->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector);
+
+ LLMatrix4 mesh_translation;
+ mesh_translation.setTranslation(mesh_translation_vector);
+ mesh_translation *= transformation;
+ transformation = mesh_translation;
+
+ LLMatrix4 mesh_scale;
+ mesh_scale.initScale(mesh_scale_vector);
+ mesh_scale *= transformation;
+ transformation = mesh_scale;
+
+ if (transformation.determinant() < 0)
+ { // negative scales are not supported
+ LL_INFOS() << "Negative scale detected, unsupported post-normalization transform. domInstance_geometry: "
+ << pModel->mLabel << LL_ENDL;
+ LLSD args;
+ args["Message"] = "NegativeScaleNormTrans";
+ args["LABEL"] = pModel->mLabel;
+ mWarningsArray.append(args);
+
+ }
+
+ mScene[transformation].push_back(LLModelInstance(pModel, pModel->mLabel, transformation, mats));
+ stretch_extents(pModel, transformation);
+ mTransform = saved_transform;
+ }
+ else
+ {
+ setLoadState(ERROR_MODEL + pModel->getStatus());
+ delete (pModel);
+ return false;
+ }
+ }
}
}
+
return true;
}
-bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const tinygltf::Mesh &mesh)
+void LLGLTFLoader::populateJointFromSkin(const LL::GLTF::Skin& skin)
+{
+ for (auto joint : skin.mJoints)
+ {
+ auto jointNode = mGLTFAsset.mNodes[joint];
+ jointNode.makeMatrixValid();
+
+ mJointList[jointNode.mName] = LLMatrix4(glm::value_ptr(jointNode.mMatrix));
+ mJointsFromNode.push_front(jointNode.mName);
+ }
+}
+
+bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh& mesh, const LL::GLTF::Node& nodeno, material_map& mats)
{
- pModel->mLabel = mesh.name;
- int pos_idx;
- tinygltf::Accessor indices_a, positions_a, normals_a, uv0_a, color0_a;
+ pModel->mLabel = mesh.mName;
+ pModel->ClearFacesAndMaterials();
- auto prims = mesh.primitives;
+ auto skinIdx = nodeno.mSkin;
+
+ auto prims = mesh.mPrimitives;
for (auto prim : prims)
{
- if (prim.indices >= 0) indices_a = mGltfModel.accessors[prim.indices];
-
- pos_idx = (prim.attributes.count("POSITION") > 0) ? prim.attributes.at("POSITION") : -1;
- if (pos_idx >= 0)
+ // Unfortunately, SLM does not support 32 bit indices. Filter out anything that goes beyond 16 bit.
+ if (prim.getVertexCount() < USHRT_MAX)
{
- positions_a = mGltfModel.accessors[pos_idx];
- if (TINYGLTF_COMPONENT_TYPE_FLOAT != positions_a.componentType)
- continue;
- auto positions_bv = mGltfModel.bufferViews[positions_a.bufferView];
- auto positions_buf = mGltfModel.buffers[positions_bv.buffer];
- //auto type = positions_vb.
- //if (positions_buf.name
- }
+ // So primitives already have all of the data we need for a given face in SL land.
+ // Primitives may only ever have a single material assigned to them - as the relation is 1:1 in terms of intended draw call
+ // count. Just go ahead and populate faces direct from the GLTF primitives here. -Geenz 2025-04-07
+ LLVolumeFace face;
+ LLVolumeFace::VertexMapData::PointMap point_map;
+
+ std::vector<GLTFVertex> vertices;
+ std::vector<U16> indices;
+
+ LLImportMaterial impMat;
-#if 0
- int norm_idx, tan_idx, uv0_idx, uv1_idx, color0_idx, color1_idx;
- norm_idx = (prim.attributes.count("NORMAL") > 0) ? prim.attributes.at("NORMAL") : -1;
- tan_idx = (prim.attributes.count("TANGENT") > 0) ? prim.attributes.at("TANGENT") : -1;
- uv0_idx = (prim.attributes.count("TEXCOORDS_0") > 0) ? prim.attributes.at("TEXCOORDS_0") : -1;
- uv1_idx = (prim.attributes.count("TEXCOORDS_1") > 0) ? prim.attributes.at("TEXCOORDS_1") : -1;
- color0_idx = (prim.attributes.count("COLOR_0") > 0) ? prim.attributes.at("COLOR_0") : -1;
- color1_idx = (prim.attributes.count("COLOR_1") > 0) ? prim.attributes.at("COLOR_1") : -1;
-#endif
-
- if (prim.mode == TINYGLTF_MODE_TRIANGLES)
- {
- //auto pos = mesh. TODO resume here DJH 2022-04
+ LL::GLTF::Material* material = nullptr;
+
+ if (prim.mMaterial >= 0)
+ material = &mGLTFAsset.mMaterials[prim.mMaterial];
+
+ impMat.mDiffuseColor = LLColor4::white;
+
+ for (U32 i = 0; i < prim.getVertexCount(); i++)
+ {
+ GLTFVertex vert;
+ vert.position = glm::vec3(prim.mPositions[i][0], prim.mPositions[i][1], prim.mPositions[i][2]);
+ vert.normal = glm::vec3(prim.mNormals[i][0], prim.mNormals[i][1], prim.mNormals[i][2]);
+ vert.uv0 = glm::vec2(prim.mTexCoords0[i][0],-prim.mTexCoords0[i][1]);
+
+ if (skinIdx >= 0)
+ {
+ auto accessorIdx = prim.mAttributes["JOINTS_0"];
+ LL::GLTF::Accessor::ComponentType componentType = LL::GLTF::Accessor::ComponentType::UNSIGNED_BYTE;
+ if (accessorIdx >= 0)
+ {
+ auto accessor = mGLTFAsset.mAccessors[accessorIdx];
+ componentType = accessor.mComponentType;
+ }
+
+ // The GLTF spec allows for either an unsigned byte for joint indices, or an unsigned short.
+ // Detect and unpack accordingly.
+ if (componentType == LL::GLTF::Accessor::ComponentType::UNSIGNED_BYTE)
+ {
+ auto ujoint = glm::unpackUint4x8((U32)(prim.mJoints[i] & 0xFFFFFFFF));
+ vert.joints = glm::u16vec4(ujoint.x, ujoint.y, ujoint.z, ujoint.w);
+ }
+ else if (componentType == LL::GLTF::Accessor::ComponentType::UNSIGNED_SHORT)
+ {
+ vert.joints = glm::unpackUint4x16(prim.mJoints[i]);
+ }
+
+ vert.weights = glm::vec4(prim.mWeights[i]);
+ }
+
+ vertices.push_back(vert);
+ }
+
+ for (U32 i = 0; i < prim.getIndexCount(); i++)
+ {
+ indices.push_back(prim.mIndexArray[i]);
+ }
+
+ std::vector<LLVolumeFace::VertexData> faceVertices;
+ glm::vec3 min = glm::vec3(0);
+ glm::vec3 max = glm::vec3(0);
+
+ for (U32 i = 0; i < vertices.size(); i++)
+ {
+ LLVolumeFace::VertexData vert;
+
+ if (vertices[i].position.x > max.x)
+ max.x = vertices[i].position.x;
+ if (vertices[i].position.y > max.y)
+ max.y = vertices[i].position.y;
+ if (vertices[i].position.z > max.z)
+ max.z = vertices[i].position.z;
+
+
+ if (vertices[i].position.x < min.x)
+ min.x = vertices[i].position.x;
+ if (vertices[i].position.y < min.y)
+ min.y = vertices[i].position.y;
+ if (vertices[i].position.z < min.z)
+ min.z = vertices[i].position.z;
+
+ LLVector4a position = LLVector4a(vertices[i].position.x, vertices[i].position.y, vertices[i].position.z);
+ LLVector4a normal = LLVector4a(vertices[i].normal.x, vertices[i].normal.y, vertices[i].normal.z);
+ vert.setPosition(position);
+ vert.setNormal(normal);
+ vert.mTexCoord = LLVector2(vertices[i].uv0.x, vertices[i].uv0.y);
+ faceVertices.push_back(vert);
+
+
+ // create list of weights that influence this vertex
+ LLModel::weight_list weight_list;
+
+ weight_list.push_back(LLModel::JointWeight(vertices[i].joints.x, vertices[i].weights.x));
+ weight_list.push_back(LLModel::JointWeight(vertices[i].joints.y, vertices[i].weights.y));
+ weight_list.push_back(LLModel::JointWeight(vertices[i].joints.z, vertices[i].weights.z));
+ weight_list.push_back(LLModel::JointWeight(vertices[i].joints.w, vertices[i].weights.w));
+
+ std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater());
+
+
+ std::vector<LLModel::JointWeight> wght;
+ F32 total = 0.f;
+
+ for (U32 i = 0; i < llmin((U32)4, (U32)weight_list.size()); ++i)
+ { // take up to 4 most significant weights
+ // Ported from the DAE loader - however, GLTF right now only supports up to four weights per vertex.
+ if (weight_list[i].mWeight > 0.f)
+ {
+ wght.push_back(weight_list[i]);
+ total += weight_list[i].mWeight;
+ }
+ }
+
+ F32 scale = 1.f / total;
+ if (scale != 1.f)
+ { // normalize weights
+ for (U32 i = 0; i < wght.size(); ++i)
+ {
+ wght[i].mWeight *= scale;
+ }
+ }
+
+ pModel->mSkinWeights[LLVector3(vertices[i].position)] = wght;
+ }
+
+ face.fillFromLegacyData(faceVertices, indices);
+ face.mExtents[0] = LLVector4a(min.x, min.y, min.z, 0);
+ face.mExtents[1] = LLVector4a(max.x, max.y, max.z, 0);
+
+ pModel->getVolumeFaces().push_back(face);
+ pModel->getMaterialList().push_back("mat" + std::to_string(prim.mMaterial));
+ mats["mat" + std::to_string(prim.mMaterial)] = impMat;
+ }
+ else {
+ LL_INFOS() << "Unable to process mesh due to 16-bit index limits" << LL_ENDL;
+ LLSD args;
+ args["Message"] = "ParsingErrorBadElement";
+ mWarningsArray.append(args);
+ return false;
}
}
- //pModel->addFace()
- return false;
+ return true;
}
bool LLGLTFLoader::parseMaterials()
{
+ return true;
+ /*
if (!mGltfLoaded) return false;
// fill local texture data structures
@@ -329,12 +517,13 @@ bool LLGLTFLoader::parseMaterials()
}
return true;
+ */
}
// TODO: convert raw vertex buffers to UUIDs
void LLGLTFLoader::uploadMeshes()
{
- llassert(0);
+ //llassert(0);
}
// convert raw image buffers to texture UUIDs & assemble into a render material
diff --git a/indra/llprimitive/llgltfloader.h b/indra/newview/gltf/llgltfloader.h
index 66671d1c5a..519f2d8a07 100644
--- a/indra/llprimitive/llgltfloader.h
+++ b/indra/newview/gltf/llgltfloader.h
@@ -29,6 +29,8 @@
#include "tinygltf/tiny_gltf.h"
+#include "asset.h"
+
#include "llglheaders.h"
#include "llmodelloader.h"
@@ -137,7 +139,17 @@ class LLGLTFLoader : public LLModelLoader
virtual bool OpenFile(const std::string &filename);
+ struct GLTFVertex
+ {
+ glm::vec3 position;
+ glm::vec3 normal;
+ glm::vec2 uv0;
+ glm::u16vec4 joints;
+ glm::vec4 weights;
+ };
+
protected:
+ LL::GLTF::Asset mGLTFAsset;
tinygltf::Model mGltfModel;
bool mGltfLoaded;
bool mMeshesLoaded;
@@ -155,7 +167,8 @@ private:
void uploadMeshes();
bool parseMaterials();
void uploadMaterials();
- bool populateModelFromMesh(LLModel* pModel, const tinygltf::Mesh &mesh);
+ bool populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh &mesh, const LL::GLTF::Node &node, material_map& mats);
+ void populateJointFromSkin(const LL::GLTF::Skin& skin);
LLUUID imageBufferToTextureUUID(const gltf_texture& tex);
// bool mPreprocessGLTF;
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 716e6cd9e3..09a2206cd7 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -59,7 +59,7 @@ LLFilePicker LLFilePicker::sInstance;
#define XML_FILTER L"XML files (*.xml)\0*.xml\0"
#define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0"
#define RAW_FILTER L"RAW files (*.raw)\0*.raw\0"
-#define MODEL_FILTER L"Model files (*.dae)\0*.dae\0"
+#define MODEL_FILTER L"Model files (*.dae, *.gltf, *.glb)\0*.dae;*.gltf;*.glb\0"
#define MATERIAL_FILTER L"GLTF Files (*.gltf; *.glb)\0*.gltf;*.glb\0"
#define HDRI_FILTER L"HDRI Files (*.exr)\0*.exr\0"
#define MATERIAL_TEXTURES_FILTER L"GLTF Import (*.gltf; *.glb; *.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.gltf;*.glb;*.tga;*.bmp;*.jpg;*.jpeg;*.png\0"
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 8332a430e6..96f9ddbf8a 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -64,6 +64,7 @@
#include "llcallbacklist.h"
#include "llviewertexteditor.h"
#include "llviewernetwork.h"
+#include "llmaterialeditor.h"
//static
@@ -113,6 +114,11 @@ void LLMeshFilePicker::notify(const std::vector<std::string>& filenames)
if (filenames.size() > 0)
{
mMP->loadModel(filenames[0], mLOD);
+
+ if (filenames[0].substr(filenames[0].length() - 4) == ".glb" || filenames[0].substr(filenames[0].length() - 5) == ".gltf")
+ {
+ LLMaterialEditor::loadMaterialFromFile(filenames[0], -1);
+ }
}
else
{
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 0dbfa50769..7ccd299135 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -30,7 +30,7 @@
#include "llmodelloader.h"
#include "lldaeloader.h"
-#include "llgltfloader.h"
+#include "gltf/llgltfloader.h"
#include "llfloatermodelpreview.h"
#include "llagent.h"