summaryrefslogtreecommitdiff
path: root/indra/llprimitive
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llprimitive')
-rw-r--r--indra/llprimitive/CMakeLists.txt2
-rw-r--r--indra/llprimitive/lldaeloader.cpp11
-rw-r--r--indra/llprimitive/lldaeloader.h30
-rw-r--r--indra/llprimitive/llgltfloader.cpp404
-rw-r--r--indra/llprimitive/llgltfloader.h206
-rw-r--r--indra/llprimitive/llmodel.cpp194
-rw-r--r--indra/llprimitive/llmodel.h11
-rw-r--r--indra/llprimitive/llmodelloader.cpp191
-rw-r--r--indra/llprimitive/llmodelloader.h15
9 files changed, 419 insertions, 645 deletions
diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt
index 627f3513dc..b084098532 100644
--- a/indra/llprimitive/CMakeLists.txt
+++ b/indra/llprimitive/CMakeLists.txt
@@ -34,7 +34,6 @@ endif ()
set(llprimitive_SOURCE_FILES
lldaeloader.cpp
- llgltfloader.cpp
llgltfmaterial.cpp
llmaterialid.cpp
llmaterial.cpp
@@ -54,7 +53,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/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index 0759447902..a11f9b5ca2 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -880,9 +880,10 @@ LLDAELoader::LLDAELoader(
void* opaque_userdata,
JointTransformMap& jointTransformMap,
JointNameSet& jointsFromNodes,
- std::map<std::string, std::string>& jointAliasMap,
+ std::map<std::string, std::string, std::less<>>& jointAliasMap,
U32 maxJointsPerMesh,
U32 modelLimit,
+ U32 debugMode,
bool preprocess)
: LLModelLoader(
filename,
@@ -895,8 +896,9 @@ LLDAELoader::LLDAELoader(
jointTransformMap,
jointsFromNodes,
jointAliasMap,
- maxJointsPerMesh),
- mGeneratedModelLimit(modelLimit),
+ maxJointsPerMesh,
+ modelLimit,
+ debugMode),
mPreprocessDAE(preprocess)
{
}
@@ -1680,6 +1682,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
{
materials[model->mMaterialList[i]] = LLImportMaterial();
}
+ // todo: likely a bug here, shouldn't be using suffixed label, see how it gets used in other places.
mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials));
stretch_extents(model, transformation);
}
@@ -2412,7 +2415,7 @@ std::string LLDAELoader::getElementLabel(daeElement *element)
}
// static
-size_t LLDAELoader::getSuffixPosition(std::string label)
+size_t LLDAELoader::getSuffixPosition(const std::string &label)
{
if ((label.find("_LOD") != -1) || (label.find("_PHYS") != -1))
{
diff --git a/indra/llprimitive/lldaeloader.h b/indra/llprimitive/lldaeloader.h
index 92152fb8b8..82eb76c8e9 100644
--- a/indra/llprimitive/lldaeloader.h
+++ b/indra/llprimitive/lldaeloader.h
@@ -49,19 +49,20 @@ public:
dae_model_map mModelsMap;
LLDAELoader(
- std::string filename,
- S32 lod,
- LLModelLoader::load_callback_t load_cb,
- LLModelLoader::joint_lookup_func_t joint_lookup_func,
- LLModelLoader::texture_load_func_t texture_load_func,
- LLModelLoader::state_callback_t state_cb,
- void* opaque_userdata,
- JointTransformMap& jointTransformMap,
- JointNameSet& jointsFromNodes,
- std::map<std::string, std::string>& jointAliasMap,
- U32 maxJointsPerMesh,
- U32 modelLimit,
- bool preprocess);
+ std::string filename,
+ S32 lod,
+ LLModelLoader::load_callback_t load_cb,
+ LLModelLoader::joint_lookup_func_t joint_lookup_func,
+ LLModelLoader::texture_load_func_t texture_load_func,
+ LLModelLoader::state_callback_t state_cb,
+ void* opaque_userdata,
+ JointTransformMap& jointTransformMap,
+ JointNameSet& jointsFromNodes,
+ std::map<std::string, std::string, std::less<>>& jointAliasMap,
+ U32 maxJointsPerMesh,
+ U32 modelLimit,
+ U32 debugMode,
+ bool preprocess);
virtual ~LLDAELoader() ;
virtual bool OpenFile(const std::string& filename);
@@ -99,13 +100,12 @@ protected:
bool loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& models_out, U32 submodel_limit);
static std::string getElementLabel(daeElement *element);
- static size_t getSuffixPosition(std::string label);
+ static size_t getSuffixPosition(const std::string& label);
static std::string getLodlessLabel(daeElement *element);
static std::string preprocessDAE(std::string filename);
private:
- U32 mGeneratedModelLimit; // Attempt to limit amount of generated submodels
bool mPreprocessDAE;
};
diff --git a/indra/llprimitive/llgltfloader.cpp b/indra/llprimitive/llgltfloader.cpp
deleted file mode 100644
index 480012699a..0000000000
--- a/indra/llprimitive/llgltfloader.cpp
+++ /dev/null
@@ -1,404 +0,0 @@
-/**
- * @file LLGLTFLoader.cpp
- * @brief LLGLTFLoader class implementation
- *
- * $LicenseInfo:firstyear=2022&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2022, 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 "llgltfloader.h"
-
-// Import & define single-header gltf import/export lib
-#define TINYGLTF_IMPLEMENTATION
-#define TINYGLTF_USE_CPP14 // default is C++ 11
-
-// tinygltf by default loads image files using STB
-#define STB_IMAGE_IMPLEMENTATION
-// to use our own image loading:
-// 1. replace this definition with TINYGLTF_NO_STB_IMAGE
-// 2. provide image loader callback with TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)
-
-// tinygltf saves image files using STB
-#define STB_IMAGE_WRITE_IMPLEMENTATION
-// similarly, can override with TINYGLTF_NO_STB_IMAGE_WRITE and TinyGLTF::SetImageWriter(fxn, data)
-
-// Additionally, disable inclusion of STB header files entirely with
-// TINYGLTF_NO_INCLUDE_STB_IMAGE
-// TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE
-#include "tinygltf/tiny_gltf.h"
-
-
-// TODO: includes inherited from dae loader. Validate / prune
-
-#include "llsdserialize.h"
-#include "lljoint.h"
-
-#include "llmatrix4a.h"
-
-#include <boost/regex.hpp>
-#include <boost/algorithm/string/replace.hpp>
-
-static const std::string lod_suffix[LLModel::NUM_LODS] =
-{
- "_LOD0",
- "_LOD1",
- "_LOD2",
- "",
- "_PHYS",
-};
-
-
-LLGLTFLoader::LLGLTFLoader(std::string filename,
- S32 lod,
- LLModelLoader::load_callback_t load_cb,
- LLModelLoader::joint_lookup_func_t joint_lookup_func,
- LLModelLoader::texture_load_func_t texture_load_func,
- LLModelLoader::state_callback_t state_cb,
- void * opaque_userdata,
- JointTransformMap & jointTransformMap,
- JointNameSet & jointsFromNodes,
- std::map<std::string, std::string> &jointAliasMap,
- U32 maxJointsPerMesh,
- U32 modelLimit) //,
- //bool preprocess)
- : LLModelLoader( filename,
- lod,
- load_cb,
- joint_lookup_func,
- texture_load_func,
- state_cb,
- opaque_userdata,
- jointTransformMap,
- jointsFromNodes,
- jointAliasMap,
- maxJointsPerMesh ),
- //mPreprocessGLTF(preprocess),
- mMeshesLoaded(false),
- mMaterialsLoaded(false)
-{
-}
-
-LLGLTFLoader::~LLGLTFLoader() {}
-
-bool LLGLTFLoader::OpenFile(const std::string &filename)
-{
- tinygltf::TinyGLTF loader;
- std::string error_msg;
- std::string warn_msg;
- 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);
- }
-
- if (!mGltfLoaded)
- {
- if (!warn_msg.empty())
- LL_WARNS("GLTF_IMPORT") << "gltf load warning: " << warn_msg.c_str() << LL_ENDL;
- if (!error_msg.empty())
- LL_WARNS("GLTF_IMPORT") << "gltf load error: " << error_msg.c_str() << LL_ENDL;
- return false;
- }
-
- mMeshesLoaded = parseMeshes();
- if (mMeshesLoaded) uploadMeshes();
-
- mMaterialsLoaded = parseMaterials();
- if (mMaterialsLoaded) uploadMaterials();
-
- return (mMeshesLoaded || mMaterialsLoaded);
-}
-
-bool LLGLTFLoader::parseMeshes()
-{
- if (!mGltfLoaded) return false;
-
- // 2022-04 DJH Volume params from dae example. TODO understand PCODE
- LLVolumeParams volume_params;
- volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
-
- for (tinygltf::Mesh mesh : mGltfModel.meshes)
- {
- LLModel *pModel = new LLModel(volume_params, 0.f);
-
- if (populateModelFromMesh(pModel, mesh) &&
- (LLModel::NO_ERRORS == pModel->getStatus()) &&
- validate_model(pModel))
- {
- mModelList.push_back(pModel);
- }
- else
- {
- setLoadState(ERROR_MODEL + pModel->getStatus());
- delete(pModel);
- return false;
- }
- }
- return true;
-}
-
-bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const tinygltf::Mesh &mesh)
-{
- pModel->mLabel = mesh.name;
- int pos_idx;
- tinygltf::Accessor indices_a, positions_a, normals_a, uv0_a, color0_a;
-
- auto prims = mesh.primitives;
- 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)
- {
- 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
- }
-
-#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
- }
- }
-
- //pModel->addFace()
- return false;
-}
-
-bool LLGLTFLoader::parseMaterials()
-{
- if (!mGltfLoaded) return false;
-
- // fill local texture data structures
- mSamplers.clear();
- for (auto in_sampler : mGltfModel.samplers)
- {
- gltf_sampler sampler;
- sampler.magFilter = in_sampler.magFilter > 0 ? in_sampler.magFilter : GL_LINEAR;
- sampler.minFilter = in_sampler.minFilter > 0 ? in_sampler.minFilter : GL_LINEAR;;
- sampler.wrapS = in_sampler.wrapS;
- sampler.wrapT = in_sampler.wrapT;
- sampler.name = in_sampler.name; // unused
- mSamplers.push_back(sampler);
- }
-
- mImages.clear();
- for (auto in_image : mGltfModel.images)
- {
- gltf_image image;
- image.numChannels = in_image.component;
- image.bytesPerChannel = in_image.bits >> 3; // Convert bits to bytes
- image.pixelType = in_image.pixel_type; // Maps exactly, i.e. TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE == GL_UNSIGNED_BYTE, etc
- image.size = static_cast<U32>(in_image.image.size());
- image.height = in_image.height;
- image.width = in_image.width;
- image.data = in_image.image.data();
-
- if (in_image.as_is)
- {
- LL_WARNS("GLTF_IMPORT") << "Unsupported image encoding" << LL_ENDL;
- return false;
- }
-
- if (image.size != image.height * image.width * image.numChannels * image.bytesPerChannel)
- {
- LL_WARNS("GLTF_IMPORT") << "Image size error" << LL_ENDL;
- return false;
- }
-
- mImages.push_back(image);
- }
-
- mTextures.clear();
- for (auto in_tex : mGltfModel.textures)
- {
- gltf_texture tex;
- tex.imageIdx = in_tex.source;
- tex.samplerIdx = in_tex.sampler;
- tex.imageUuid.setNull();
-
- if (tex.imageIdx >= mImages.size() || tex.samplerIdx >= mSamplers.size())
- {
- LL_WARNS("GLTF_IMPORT") << "Texture sampler/image index error" << LL_ENDL;
- return false;
- }
-
- mTextures.push_back(tex);
- }
-
- // parse each material
- for (tinygltf::Material gltf_material : mGltfModel.materials)
- {
- gltf_render_material mat;
- mat.name = gltf_material.name;
-
- tinygltf::PbrMetallicRoughness& pbr = gltf_material.pbrMetallicRoughness;
- mat.hasPBR = true; // Always true, for now
-
- mat.baseColor.set(pbr.baseColorFactor.data());
- mat.hasBaseTex = pbr.baseColorTexture.index >= 0;
- mat.baseColorTexIdx = pbr.baseColorTexture.index;
- mat.baseColorTexCoords = pbr.baseColorTexture.texCoord;
-
- mat.metalness = pbr.metallicFactor;
- mat.roughness = pbr.roughnessFactor;
- mat.hasMRTex = pbr.metallicRoughnessTexture.index >= 0;
- mat.metalRoughTexIdx = pbr.metallicRoughnessTexture.index;
- mat.metalRoughTexCoords = pbr.metallicRoughnessTexture.texCoord;
-
- mat.normalScale = gltf_material.normalTexture.scale;
- mat.hasNormalTex = gltf_material.normalTexture.index >= 0;
- mat.normalTexIdx = gltf_material.normalTexture.index;
- mat.normalTexCoords = gltf_material.normalTexture.texCoord;
-
- mat.occlusionScale = gltf_material.occlusionTexture.strength;
- mat.hasOcclusionTex = gltf_material.occlusionTexture.index >= 0;
- mat.occlusionTexIdx = gltf_material.occlusionTexture.index;
- mat.occlusionTexCoords = gltf_material.occlusionTexture.texCoord;
-
- mat.emissiveColor.set(gltf_material.emissiveFactor.data());
- mat.hasEmissiveTex = gltf_material.emissiveTexture.index >= 0;
- mat.emissiveTexIdx = gltf_material.emissiveTexture.index;
- mat.emissiveTexCoords = gltf_material.emissiveTexture.texCoord;
-
- mat.alphaMode = gltf_material.alphaMode;
- mat.alphaMask = gltf_material.alphaCutoff;
-
- if ((mat.hasNormalTex && (mat.normalTexIdx >= mTextures.size())) ||
- (mat.hasOcclusionTex && (mat.occlusionTexIdx >= mTextures.size())) ||
- (mat.hasEmissiveTex && (mat.emissiveTexIdx >= mTextures.size())) ||
- (mat.hasBaseTex && (mat.baseColorTexIdx >= mTextures.size())) ||
- (mat.hasMRTex && (mat.metalRoughTexIdx >= mTextures.size())))
- {
- LL_WARNS("GLTF_IMPORT") << "Texture resource index error" << LL_ENDL;
- return false;
- }
-
- if ((mat.hasNormalTex && (mat.normalTexCoords > 2)) || // mesh can have up to 3 sets of UV
- (mat.hasOcclusionTex && (mat.occlusionTexCoords > 2)) ||
- (mat.hasEmissiveTex && (mat.emissiveTexCoords > 2)) ||
- (mat.hasBaseTex && (mat.baseColorTexCoords > 2)) ||
- (mat.hasMRTex && (mat.metalRoughTexCoords > 2)))
- {
- LL_WARNS("GLTF_IMPORT") << "Image texcoord index error" << LL_ENDL;
- return false;
- }
-
- mMaterials.push_back(mat);
- }
-
- return true;
-}
-
-// TODO: convert raw vertex buffers to UUIDs
-void LLGLTFLoader::uploadMeshes()
-{
- llassert(0);
-}
-
-// convert raw image buffers to texture UUIDs & assemble into a render material
-void LLGLTFLoader::uploadMaterials()
-{
- for (gltf_render_material mat : mMaterials) // Initially 1 material per gltf file, but design for multiple
- {
- if (mat.hasBaseTex)
- {
- gltf_texture& gtex = mTextures[mat.baseColorTexIdx];
- if (gtex.imageUuid.isNull())
- {
- gtex.imageUuid = imageBufferToTextureUUID(gtex);
- }
- }
-
- if (mat.hasMRTex)
- {
- gltf_texture& gtex = mTextures[mat.metalRoughTexIdx];
- if (gtex.imageUuid.isNull())
- {
- gtex.imageUuid = imageBufferToTextureUUID(gtex);
- }
- }
-
- if (mat.hasNormalTex)
- {
- gltf_texture& gtex = mTextures[mat.normalTexIdx];
- if (gtex.imageUuid.isNull())
- {
- gtex.imageUuid = imageBufferToTextureUUID(gtex);
- }
- }
-
- if (mat.hasOcclusionTex)
- {
- gltf_texture& gtex = mTextures[mat.occlusionTexIdx];
- if (gtex.imageUuid.isNull())
- {
- gtex.imageUuid = imageBufferToTextureUUID(gtex);
- }
- }
-
- if (mat.hasEmissiveTex)
- {
- gltf_texture& gtex = mTextures[mat.emissiveTexIdx];
- if (gtex.imageUuid.isNull())
- {
- gtex.imageUuid = imageBufferToTextureUUID(gtex);
- }
- }
- }
-}
-
-LLUUID LLGLTFLoader::imageBufferToTextureUUID(const gltf_texture& tex)
-{
- //gltf_image& image = mImages[tex.imageIdx];
- //gltf_sampler& sampler = mSamplers[tex.samplerIdx];
-
- // fill an LLSD container with image+sampler data
-
- // upload texture
-
- // retrieve UUID
-
- return LLUUID::null;
-}
diff --git a/indra/llprimitive/llgltfloader.h b/indra/llprimitive/llgltfloader.h
deleted file mode 100644
index 66671d1c5a..0000000000
--- a/indra/llprimitive/llgltfloader.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/**
- * @file LLGLTFLoader.h
- * @brief LLGLTFLoader class definition
- *
- * $LicenseInfo:firstyear=2022&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2022, 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_LLGLTFLoader_H
-#define LL_LLGLTFLoader_H
-
-#include "tinygltf/tiny_gltf.h"
-
-#include "llglheaders.h"
-#include "llmodelloader.h"
-
-// gltf_* structs are temporary, used to organize the subset of data that eventually goes into the material LLSD
-
-class gltf_sampler
-{
-public:
- // Uses GL enums
- S32 minFilter; // GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR or GL_LINEAR_MIPMAP_LINEAR
- S32 magFilter; // GL_NEAREST or GL_LINEAR
- S32 wrapS; // GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT or GL_REPEAT
- S32 wrapT; // GL_CLAMP_TO_EDGE, GL_MIRRORED_REPEAT or GL_REPEAT
- //S32 wrapR; // Found in some sample files, but not part of glTF 2.0 spec. Ignored.
- std::string name; // optional, currently unused
- // extensions and extras are sampler optional fields that we don't support - at least initially
-};
-
-class gltf_image
-{
-public:// Note that glTF images are defined with row 0 at the top (opposite of OpenGL)
- U8* data; // ptr to decoded image data
- U32 size; // in bytes, regardless of channel width
- U32 width;
- U32 height;
- U32 numChannels; // range 1..4
- U32 bytesPerChannel; // converted from gltf "bits", expects only 8, 16 or 32 as input
- U32 pixelType; // one of (TINYGLTF_COMPONENT_TYPE)_UNSIGNED_BYTE, _UNSIGNED_SHORT, _UNSIGNED_INT, or _FLOAT
-};
-
-class gltf_texture
-{
-public:
- U32 imageIdx;
- U32 samplerIdx;
- LLUUID imageUuid = LLUUID::null;
-};
-
-class gltf_render_material
-{
-public:
- std::string name;
-
- // scalar values
- LLColor4 baseColor; // linear encoding. Multiplied with vertex color, if present.
- double metalness;
- double roughness;
- double normalScale; // scale applies only to X,Y components of normal
- double occlusionScale; // strength multiplier for occlusion
- LLColor4 emissiveColor; // emissive mulitiplier, assumed linear encoding (spec 2.0 is silent)
- std::string alphaMode; // "OPAQUE", "MASK" or "BLEND"
- double alphaMask; // alpha cut-off
-
- // textures
- U32 baseColorTexIdx; // always sRGB encoded
- U32 metalRoughTexIdx; // always linear, roughness in G channel, metalness in B channel
- U32 normalTexIdx; // linear, valid range R[0-1], G[0-1], B[0.5-1]. Normal = texel * 2 - vec3(1.0)
- U32 occlusionTexIdx; // linear, occlusion in R channel, 0 meaning fully occluded, 1 meaning not occluded
- U32 emissiveTexIdx; // always stored as sRGB, in nits (candela / meter^2)
-
- // texture coordinates
- U32 baseColorTexCoords;
- U32 metalRoughTexCoords;
- U32 normalTexCoords;
- U32 occlusionTexCoords;
- U32 emissiveTexCoords;
-
- // TODO: Add traditional (diffuse, normal, specular) UUIDs here, or add this struct to LL_TextureEntry??
-
- bool hasPBR;
- bool hasBaseTex, hasMRTex, hasNormalTex, hasOcclusionTex, hasEmissiveTex;
-
- // This field is populated after upload
- LLUUID material_uuid = LLUUID::null;
-
-};
-
-class gltf_mesh
-{
-public:
- std::string name;
-
- // TODO add mesh import DJH 2022-04
-
-};
-
-class LLGLTFLoader : public LLModelLoader
-{
- public:
- typedef std::map<std::string, LLImportMaterial> material_map;
-
- LLGLTFLoader(std::string filename,
- S32 lod,
- LLModelLoader::load_callback_t load_cb,
- LLModelLoader::joint_lookup_func_t joint_lookup_func,
- LLModelLoader::texture_load_func_t texture_load_func,
- LLModelLoader::state_callback_t state_cb,
- void * opaque_userdata,
- JointTransformMap & jointTransformMap,
- JointNameSet & jointsFromNodes,
- std::map<std::string, std::string> &jointAliasMap,
- U32 maxJointsPerMesh,
- U32 modelLimit); //,
- //bool preprocess );
- virtual ~LLGLTFLoader();
-
- virtual bool OpenFile(const std::string &filename);
-
-protected:
- tinygltf::Model mGltfModel;
- bool mGltfLoaded;
- bool mMeshesLoaded;
- bool mMaterialsLoaded;
-
- std::vector<gltf_mesh> mMeshes;
- std::vector<gltf_render_material> mMaterials;
-
- std::vector<gltf_texture> mTextures;
- std::vector<gltf_image> mImages;
- std::vector<gltf_sampler> mSamplers;
-
-private:
- bool parseMeshes();
- void uploadMeshes();
- bool parseMaterials();
- void uploadMaterials();
- bool populateModelFromMesh(LLModel* pModel, const tinygltf::Mesh &mesh);
- LLUUID imageBufferToTextureUUID(const gltf_texture& tex);
-
- // bool mPreprocessGLTF;
-
- /* Below inherited from dae loader - unknown if/how useful here
-
- void processElement(gltfElement *element, bool &badElement, GLTF *gltf);
- void processGltfModel(LLModel *model, GLTF *gltf, gltfElement *pRoot, gltfMesh *mesh, gltfSkin *skin);
-
- material_map getMaterials(LLModel *model, gltfInstance_geometry *instance_geo, GLTF *gltf);
- LLImportMaterial profileToMaterial(gltfProfile_COMMON *material, GLTF *gltf);
- LLColor4 getGltfColor(gltfElement *element);
-
- gltfElement *getChildFromElement(gltfElement *pElement, std::string const &name);
-
- bool isNodeAJoint(gltfNode *pNode);
- void processJointNode(gltfNode *pNode, std::map<std::string, LLMatrix4> &jointTransforms);
- void extractTranslation(gltfTranslate *pTranslate, LLMatrix4 &transform);
- void extractTranslationViaElement(gltfElement *pTranslateElement, LLMatrix4 &transform);
- void extractTranslationViaSID(gltfElement *pElement, LLMatrix4 &transform);
- void buildJointToNodeMappingFromScene(gltfElement *pRoot);
- void processJointToNodeMapping(gltfNode *pNode);
- void processChildJoints(gltfNode *pParentNode);
-
- bool verifyCount(int expected, int result);
-
- // Verify that a controller matches vertex counts
- bool verifyController(gltfController *pController);
-
- static bool addVolumeFacesFromGltfMesh(LLModel *model, gltfMesh *mesh, LLSD &log_msg);
- static bool createVolumeFacesFromGltfMesh(LLModel *model, gltfMesh *mesh);
-
- static LLModel *loadModelFromGltfMesh(gltfMesh *mesh);
-
- // Loads a mesh breaking it into one or more models as necessary
- // to get around volume face limitations while retaining >8 materials
- //
- bool loadModelsFromGltfMesh(gltfMesh *mesh, std::vector<LLModel *> &models_out, U32 submodel_limit);
-
- static std::string getElementLabel(gltfElement *element);
- static size_t getSuffixPosition(std::string label);
- static std::string getLodlessLabel(gltfElement *element);
-
- static std::string preprocessGLTF(std::string filename);
- */
-
-};
-#endif // LL_LLGLTFLLOADER_H
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 6b4bb3a8b0..4c0f3edb62 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -334,6 +334,162 @@ void LLModel::normalizeVolumeFaces()
}
}
+void LLModel::normalizeVolumeFacesAndWeights()
+{
+ if (!mVolumeFaces.empty())
+ {
+ LLVector4a min, max;
+
+ // For all of the volume faces
+ // in the model, loop over
+ // them and see what the extents
+ // of the volume along each axis.
+ min = mVolumeFaces[0].mExtents[0];
+ max = mVolumeFaces[0].mExtents[1];
+
+ for (U32 i = 1; i < mVolumeFaces.size(); ++i)
+ {
+ LLVolumeFace& face = mVolumeFaces[i];
+
+ update_min_max(min, max, face.mExtents[0]);
+ update_min_max(min, max, face.mExtents[1]);
+
+ if (face.mTexCoords)
+ {
+ LLVector2& min_tc = face.mTexCoordExtents[0];
+ LLVector2& max_tc = face.mTexCoordExtents[1];
+
+ min_tc = face.mTexCoords[0];
+ max_tc = face.mTexCoords[0];
+
+ for (S32 j = 1; j < face.mNumVertices; ++j)
+ {
+ update_min_max(min_tc, max_tc, face.mTexCoords[j]);
+ }
+ }
+ else
+ {
+ face.mTexCoordExtents[0].set(0, 0);
+ face.mTexCoordExtents[1].set(1, 1);
+ }
+ }
+
+ // Now that we have the extents of the model
+ // we can compute the offset needed to center
+ // the model at the origin.
+
+ // Compute center of the model
+ // and make it negative to get translation
+ // needed to center at origin.
+ LLVector4a trans;
+ trans.setAdd(min, max);
+ trans.mul(-0.5f);
+
+ // Compute the total size along all
+ // axes of the model.
+ LLVector4a size;
+ size.setSub(max, min);
+
+ // Prevent division by zero.
+ F32 x = size[0];
+ F32 y = size[1];
+ F32 z = size[2];
+ F32 w = size[3];
+ if (fabs(x) < F_APPROXIMATELY_ZERO)
+ {
+ x = 1.0;
+ }
+ if (fabs(y) < F_APPROXIMATELY_ZERO)
+ {
+ y = 1.0;
+ }
+ if (fabs(z) < F_APPROXIMATELY_ZERO)
+ {
+ z = 1.0;
+ }
+ size.set(x, y, z, w);
+
+ // Compute scale as reciprocal of size
+ LLVector4a scale;
+ scale.splat(1.f);
+ scale.div(size);
+
+ LLVector4a inv_scale(1.f);
+ inv_scale.div(scale);
+
+ for (U32 i = 0; i < mVolumeFaces.size(); ++i)
+ {
+ LLVolumeFace& face = mVolumeFaces[i];
+
+ // We shrink the extents so
+ // that they fall within
+ // the unit cube.
+ // VFExtents change
+ face.mExtents[0].add(trans);
+ face.mExtents[0].mul(scale);
+
+ face.mExtents[1].add(trans);
+ face.mExtents[1].mul(scale);
+
+ // For all the positions, we scale
+ // the positions to fit within the unit cube.
+ LLVector4a* pos = (LLVector4a*)face.mPositions;
+ LLVector4a* norm = (LLVector4a*)face.mNormals;
+ LLVector4a* t = (LLVector4a*)face.mTangents;
+
+ for (S32 j = 0; j < face.mNumVertices; ++j)
+ {
+ pos[j].add(trans);
+ pos[j].mul(scale);
+ if (norm && !norm[j].equals3(LLVector4a::getZero()))
+ {
+ norm[j].mul(inv_scale);
+ norm[j].normalize3();
+ }
+
+ if (t)
+ {
+ F32 w = t[j].getF32ptr()[3];
+ t[j].mul(inv_scale);
+ t[j].normalize3();
+ t[j].getF32ptr()[3] = w;
+ }
+ }
+ }
+
+ weight_map old_weights = mSkinWeights;
+ mSkinWeights.clear();
+ mPosition.clear();
+
+ for (auto& weights : old_weights)
+ {
+ LLVector4a pos(weights.first.mV[VX], weights.first.mV[VY], weights.first.mV[VZ]);
+ pos.add(trans);
+ pos.mul(scale);
+ LLVector3 scaled_pos(pos.getF32ptr());
+ mPosition.push_back(scaled_pos);
+ mSkinWeights[scaled_pos] = weights.second;
+ }
+
+ // mNormalizedScale is the scale at which
+ // we would need to multiply the model
+ // by to get the original size of the
+ // model instead of the normalized size.
+ LLVector4a normalized_scale;
+ normalized_scale.splat(1.f);
+ normalized_scale.div(scale);
+ mNormalizedScale.set(normalized_scale.getF32ptr());
+ mNormalizedTranslation.set(trans.getF32ptr());
+ mNormalizedTranslation *= -1.f;
+
+ // remember normalized scale so original dimensions can be recovered for mesh processing (i.e. tangent generation)
+ for (auto& face : mVolumeFaces)
+ {
+ face.mNormalizedScale = mNormalizedScale;
+ }
+ }
+}
+
void LLModel::getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out) const
{
scale_out = mNormalizedScale;
@@ -662,7 +818,7 @@ LLSD LLModel::writeModel(
bool upload_skin,
bool upload_joints,
bool lock_scale_if_joint_position,
- bool nowrite,
+ EWriteModelMode write_mode,
bool as_slm,
int submodel_id)
{
@@ -941,10 +1097,10 @@ LLSD LLModel::writeModel(
}
}
- return writeModelToStream(ostr, mdl, nowrite, as_slm);
+ return writeModelToStream(ostr, mdl, write_mode, as_slm);
}
-LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, bool nowrite, bool as_slm)
+LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, EWriteModelMode write_mode, bool as_slm)
{
std::string::size_type cur_offset = 0;
@@ -1006,7 +1162,11 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, bool nowrite, bo
}
}
- if (!nowrite)
+ if (write_mode == WRITE_HUMAN)
+ {
+ ostr << mdl;
+ }
+ else if (write_mode == WRITE_BINARY)
{
LLSDSerialize::toBinary(header, ostr);
@@ -1561,11 +1721,21 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_positi
{
ret["joint_names"][i] = mJointNames[i];
+ // For model to work at all there must be a matching bind matrix,
+ // so supply an indentity one if it isn't true
+ // Note: can build an actual bind matrix from joints
+ const LLMatrix4a& inv_bind = mInvBindMatrix.size() > i ? mInvBindMatrix[i] : LLMatrix4a::identity();
+ if (i >= mInvBindMatrix.size())
+ {
+ LL_WARNS("MESHSKININFO") << "Joint index " << i << " (" << mJointNames[i] << ") exceeds inverse bind matrix size "
+ << mInvBindMatrix.size() << LL_ENDL;
+ }
+
for (U32 j = 0; j < 4; j++)
{
for (U32 k = 0; k < 4; k++)
{
- ret["inverse_bind_matrix"][i][j*4+k] = mInvBindMatrix[i].mMatrix[j][k];
+ ret["inverse_bind_matrix"][i][j * 4 + k] = inv_bind.mMatrix[j][k];
}
}
}
@@ -1578,15 +1748,25 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_positi
}
}
- if ( include_joints && mAlternateBindMatrix.size() > 0 )
+ // optional 'joint overrides'
+ if (include_joints && mAlternateBindMatrix.size() > 0)
{
for (U32 i = 0; i < mJointNames.size(); ++i)
{
+ // If there is not enough to match mJointNames,
+ // either supply no alternate matrixes at all or supply
+ // replacements
+ const LLMatrix4a& alt_bind = mAlternateBindMatrix.size() > i ? mAlternateBindMatrix[i] : LLMatrix4a::identity();
+ if (i >= mAlternateBindMatrix.size())
+ {
+ LL_WARNS("MESHSKININFO") << "Joint index " << i << " (" << mJointNames[i] << ") exceeds alternate bind matrix size "
+ << mAlternateBindMatrix.size() << LL_ENDL;
+ }
for (U32 j = 0; j < 4; j++)
{
for (U32 k = 0; k < 4; k++)
{
- ret["alt_inverse_bind_matrix"][i][j*4+k] = mAlternateBindMatrix[i].mMatrix[j][k];
+ ret["alt_inverse_bind_matrix"][i][j * 4 + k] = alt_bind.mMatrix[j][k];
}
}
}
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index 4b5d079b48..a4ba6acd7e 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -162,6 +162,12 @@ public:
bool loadSkinInfo(LLSD& header, std::istream& is);
bool loadDecomposition(LLSD& header, std::istream& is);
+ enum EWriteModelMode
+ {
+ WRITE_NO = 0,
+ WRITE_BINARY,
+ WRITE_HUMAN,
+ };
static LLSD writeModel(
std::ostream& ostr,
LLModel* physics,
@@ -173,14 +179,14 @@ public:
bool upload_skin,
bool upload_joints,
bool lock_scale_if_joint_position,
- bool nowrite = false,
+ EWriteModelMode write_mode = WRITE_BINARY,
bool as_slm = false,
int submodel_id = 0);
static LLSD writeModelToStream(
std::ostream& ostr,
LLSD& mdl,
- bool nowrite = false, bool as_slm = false);
+ EWriteModelMode write_mode = WRITE_BINARY, bool as_slm = false);
void ClearFacesAndMaterials() { mVolumeFaces.clear(); mMaterialList.clear(); }
@@ -204,6 +210,7 @@ public:
void sortVolumeFacesByMaterialName();
void normalizeVolumeFaces();
+ void normalizeVolumeFacesAndWeights();
void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL);
void remapVolumeFaces();
void optimizeVolumeFaces();
diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp
index 84adec4da5..9521fec54f 100644
--- a/indra/llprimitive/llmodelloader.cpp
+++ b/indra/llprimitive/llmodelloader.cpp
@@ -113,7 +113,9 @@ LLModelLoader::LLModelLoader(
JointTransformMap& jointTransformMap,
JointNameSet& jointsFromNodes,
JointMap& legalJointNamesMap,
- U32 maxJointsPerMesh)
+ U32 maxJointsPerMesh,
+ U32 modelLimit,
+ U32 debugMode)
: mJointList( jointTransformMap )
, mJointsFromNode( jointsFromNodes )
, LLThread("Model Loader")
@@ -133,6 +135,8 @@ LLModelLoader::LLModelLoader(
, mNoOptimize(false)
, mCacheOnlyHitIfRigged(false)
, mMaxJointsPerMesh(maxJointsPerMesh)
+, mGeneratedModelLimit(modelLimit)
+, mDebugMode(debugMode)
, mJointMap(legalJointNamesMap)
{
assert_main_thread();
@@ -149,7 +153,44 @@ LLModelLoader::~LLModelLoader()
void LLModelLoader::run()
{
mWarningsArray.clear();
- doLoadModel();
+ try
+ {
+ doLoadModel();
+ }
+ // Model loader isn't mission critical, so we just log all exceptions
+ catch (const LLException& e)
+ {
+ LL_WARNS("THREAD") << "LLException in model loader: " << e.what() << "" << LL_ENDL;
+ LLSD args;
+ args["Message"] = "UnknownException";
+ args["FILENAME"] = mFilename;
+ args["EXCEPTION"] = e.what();
+ mWarningsArray.append(args);
+ setLoadState(ERROR_PARSING);
+ }
+ catch (const std::exception& e)
+ {
+ LL_WARNS() << "Exception in LLModelLoader::run: " << e.what() << LL_ENDL;
+ LLSD args;
+ args["Message"] = "UnknownException";
+ args["FILENAME"] = mFilename;
+ args["EXCEPTION"] = e.what();
+ mWarningsArray.append(args);
+ setLoadState(ERROR_PARSING);
+ }
+ catch (...)
+ {
+ LOG_UNHANDLED_EXCEPTION("LLModelLoader");
+ LLSD args;
+ args["Message"] = "UnknownException";
+ args["FILENAME"] = mFilename;
+ args["EXCEPTION"] = "Unknown exception";
+ mWarningsArray.append(args);
+ setLoadState(ERROR_PARSING);
+ }
+
+ // todo: we are inside of a thread, push this into main thread worker,
+ // not into doOnIdleOneTime that laks tread safety
doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
}
@@ -201,7 +242,9 @@ bool LLModelLoader::doLoadModel()
}
}
- return OpenFile(mFilename);
+ bool res = OpenFile(mFilename);
+ dumpDebugData(); // conditional on mDebugMode
+ return res;
}
void LLModelLoader::setLoadState(U32 state)
@@ -466,6 +509,148 @@ bool LLModelLoader::isRigSuitableForJointPositionUpload( const std::vector<std::
return true;
}
+void LLModelLoader::dumpDebugData()
+{
+ if (mDebugMode == 0)
+ {
+ return;
+ }
+
+ std::string log_file = mFilename + "_importer.txt";
+ LLStringUtil::toLower(log_file);
+ llofstream file;
+ file.open(log_file.c_str());
+ if (!file)
+ {
+ LL_WARNS() << "dumpDebugData failed to open file " << log_file << LL_ENDL;
+ return;
+ }
+ file << "Importing: " << mFilename << "\n";
+
+ std::map<std::string, LLMatrix4a> inv_bind;
+ std::map<std::string, LLMatrix4a> alt_bind;
+ for (LLPointer<LLModel>& mdl : mModelList)
+ {
+
+ file << "Model name: " << mdl->mLabel << "\n";
+ const LLMeshSkinInfo& skin_info = mdl->mSkinInfo;
+ file << "Shape Bind matrix: " << skin_info.mBindShapeMatrix << "\n";
+ file << "Skin Weights count: " << (S32)mdl->mSkinWeights.size() << "\n";
+
+ // some objects might have individual bind matrices,
+ // but for now it isn't accounted for
+ size_t joint_count = skin_info.mJointNames.size();
+ for (size_t i = 0; i< joint_count;i++)
+ {
+ const std::string& joint = skin_info.mJointNames[i];
+ if (skin_info.mInvBindMatrix.size() > i)
+ {
+ inv_bind[joint] = skin_info.mInvBindMatrix[i];
+ }
+ if (skin_info.mAlternateBindMatrix.size() > i)
+ {
+ alt_bind[joint] = skin_info.mAlternateBindMatrix[i];
+ }
+ }
+ }
+
+ file << "\nInv Bind matrices.\n";
+ for (auto& bind : inv_bind)
+ {
+ file << "Joint: " << bind.first << " Matrix: " << bind.second << "\n";
+ }
+
+ file << "\nAlt Bind matrices.\n";
+ for (auto& bind : alt_bind)
+ {
+ file << "Joint: " << bind.first << " Matrix: " << bind.second << "\n";
+ }
+
+ if (mDebugMode == 2)
+ {
+ S32 model_count = 0;
+ for (LLPointer<LLModel>& mdl : mModelList)
+ {
+ const LLVolume::face_list_t &face_list = mdl->getVolumeFaces();
+ for (S32 face = 0; face < face_list.size(); face++)
+ {
+ const LLVolumeFace& vf = face_list[face];
+ file << "\nModel: " << mdl->mLabel
+ << " face " << face
+ << " has " << vf.mNumVertices
+ << " vertices and " << vf.mNumIndices
+ << " indices " << "\n";
+
+ file << "\nPositions for model: " << mdl->mLabel << " face " << face << "\n";
+
+ for (S32 pos = 0; pos < vf.mNumVertices; ++pos)
+ {
+ file << vf.mPositions[pos] << " ";
+ }
+
+ file << "\n\nIndices for model: " << mdl->mLabel << " face " << face << "\n";
+
+ for (S32 ind = 0; ind < vf.mNumIndices; ++ind)
+ {
+ file << vf.mIndices[ind] << " ";
+ }
+ }
+
+ file << "\n\nWeights for model: " << mdl->mLabel;
+ for (auto& weights : mdl->mSkinWeights)
+ {
+ file << "\nVertex: " << weights.first << " Weights: ";
+ for (auto& weight : weights.second)
+ {
+ file << weight.mJointIdx << ":" << weight.mWeight << " ";
+ }
+ }
+
+ file << "\n";
+ model_count++;
+ if (model_count == 5)
+ {
+ file << "Too many models, stopping at 5.\n";
+ break;
+ }
+ }
+ }
+ else if (mDebugMode > 2)
+ {
+ file << "\nModel LLSDs\n";
+ S32 model_count = 0;
+ // some files contain too many models, so stop at 5.
+ for (LLPointer<LLModel>& mdl : mModelList)
+ {
+ const LLMeshSkinInfo& skin_info = mdl->mSkinInfo;
+ size_t joint_count = skin_info.mJointNames.size();
+ size_t alt_count = skin_info.mAlternateBindMatrix.size();
+
+ LLModel::writeModel(
+ file,
+ nullptr,
+ mdl,
+ nullptr,
+ nullptr,
+ nullptr,
+ mdl->mPhysics,
+ joint_count > 0,
+ alt_count > 0,
+ false,
+ LLModel::WRITE_HUMAN,
+ false,
+ mdl->mSubmodelID);
+
+ file << "\n";
+ model_count++;
+ if (model_count == 5)
+ {
+ file << "Too many models, stopping at 5.\n";
+ break;
+ }
+ }
+ }
+}
//called in the main thread
void LLModelLoader::loadTextures()
diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h
index 530e61e2b8..06a17f006e 100644
--- a/indra/llprimitive/llmodelloader.h
+++ b/indra/llprimitive/llmodelloader.h
@@ -36,7 +36,7 @@ class LLJoint;
typedef std::map<std::string, LLMatrix4> JointTransformMap;
typedef std::map<std::string, LLMatrix4>::iterator JointTransformMapIt;
-typedef std::map<std::string, std::string> JointMap;
+typedef std::map<std::string, std::string, std::less<>> JointMap;
typedef std::deque<std::string> JointNameSet;
const S32 SLM_SUPPORTED_VERSION = 3;
@@ -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,10 +120,16 @@ 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;
+ U32 mDebugMode; // see dumDebugData() for details
LLModelLoader(
std::string filename,
@@ -135,7 +142,9 @@ public:
JointTransformMap& jointTransformMap,
JointNameSet& jointsFromNodes,
JointMap& legalJointNamesMap,
- U32 maxJointsPerMesh);
+ U32 maxJointsPerMesh,
+ U32 modelLimit,
+ U32 debugMode);
virtual ~LLModelLoader();
virtual void setNoNormalize() { mNoNormalize = true; }
@@ -192,6 +201,7 @@ public:
const LLSD logOut() const { return mWarningsArray; }
void clearLog() { mWarningsArray.clear(); }
+ void dumpDebugData();
protected:
@@ -203,6 +213,7 @@ protected:
bool mRigValidJointUpload;
U32 mLegacyRigFlags;
+ U32 mGeneratedModelLimit; // Attempt to limit amount of generated submodels
bool mNoNormalize;
bool mNoOptimize;