SL-17214 initial loader class skeleton
parent
d385c73b6e
commit
8c0163bcb4
|
|
@ -88,7 +88,8 @@ class LLColor4
|
||||||
const LLColor4& set(const LLColor3 &vec); // Sets LLColor4 to LLColor3 vec (no change in alpha)
|
const LLColor4& set(const LLColor3 &vec); // Sets LLColor4 to LLColor3 vec (no change in alpha)
|
||||||
const LLColor4& set(const LLColor3 &vec, F32 a); // Sets LLColor4 to LLColor3 vec, with alpha specified
|
const LLColor4& set(const LLColor3 &vec, F32 a); // Sets LLColor4 to LLColor3 vec, with alpha specified
|
||||||
const LLColor4& set(const F32 *vec); // Sets LLColor4 to vec
|
const LLColor4& set(const F32 *vec); // Sets LLColor4 to vec
|
||||||
const LLColor4& set(const LLColor4U& color4u); // Sets LLColor4 to color4u, rescaled.
|
const LLColor4& set(const F64 *vec); // Sets LLColor4 to (double)vec
|
||||||
|
const LLColor4& set(const LLColor4U& color4u); // Sets LLColor4 to color4u, rescaled.
|
||||||
|
|
||||||
|
|
||||||
const LLColor4& setAlpha(F32 a);
|
const LLColor4& setAlpha(F32 a);
|
||||||
|
|
@ -334,6 +335,15 @@ inline const LLColor4& LLColor4::set(const F32 *vec)
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const LLColor4& LLColor4::set(const F64 *vec)
|
||||||
|
{
|
||||||
|
mV[VX] = static_cast<F32>(vec[VX]);
|
||||||
|
mV[VY] = static_cast<F32>(vec[VY]);
|
||||||
|
mV[VZ] = static_cast<F32>(vec[VZ]);
|
||||||
|
mV[VW] = static_cast<F32>(vec[VW]);
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
// deprecated
|
// deprecated
|
||||||
inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z)
|
inline const LLColor4& LLColor4::setVec(F32 x, F32 y, F32 z)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ include_directories(SYSTEM
|
||||||
|
|
||||||
set(llprimitive_SOURCE_FILES
|
set(llprimitive_SOURCE_FILES
|
||||||
lldaeloader.cpp
|
lldaeloader.cpp
|
||||||
|
llgltfloader.cpp
|
||||||
llmaterialid.cpp
|
llmaterialid.cpp
|
||||||
llmaterial.cpp
|
llmaterial.cpp
|
||||||
llmaterialtable.cpp
|
llmaterialtable.cpp
|
||||||
|
|
@ -46,6 +47,7 @@ set(llprimitive_SOURCE_FILES
|
||||||
set(llprimitive_HEADER_FILES
|
set(llprimitive_HEADER_FILES
|
||||||
CMakeLists.txt
|
CMakeLists.txt
|
||||||
lldaeloader.h
|
lldaeloader.h
|
||||||
|
llgltfloader.h
|
||||||
legacy_object_types.h
|
legacy_object_types.h
|
||||||
llmaterial.h
|
llmaterial.h
|
||||||
llmaterialid.h
|
llmaterialid.h
|
||||||
|
|
|
||||||
|
|
@ -2504,19 +2504,19 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
|
||||||
return (status == LLModel::NO_ERRORS);
|
return (status == LLModel::NO_ERRORS);
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
////static
|
||||||
LLModel* LLDAELoader::loadModelFromDomMesh(domMesh *mesh)
|
//LLModel* LLDAELoader::loadModelFromDomMesh(domMesh *mesh)
|
||||||
{
|
//{
|
||||||
LLVolumeParams volume_params;
|
// LLVolumeParams volume_params;
|
||||||
volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
|
// volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
|
||||||
LLModel* ret = new LLModel(volume_params, 0.f);
|
// LLModel* ret = new LLModel(volume_params, 0.f);
|
||||||
createVolumeFacesFromDomMesh(ret, mesh);
|
// createVolumeFacesFromDomMesh(ret, mesh);
|
||||||
if (ret->mLabel.empty())
|
// if (ret->mLabel.empty())
|
||||||
{
|
// {
|
||||||
ret->mLabel = getElementLabel(mesh);
|
// ret->mLabel = getElementLabel(mesh);
|
||||||
}
|
// }
|
||||||
return ret;
|
// return ret;
|
||||||
}
|
//}
|
||||||
|
|
||||||
//static diff version supports creating multiple models when material counts spill
|
//static diff version supports creating multiple models when material counts spill
|
||||||
// over the 8 face server-side limit
|
// over the 8 face server-side limit
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ protected:
|
||||||
static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh, LLSD& log_msg);
|
static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh, LLSD& log_msg);
|
||||||
static bool createVolumeFacesFromDomMesh(LLModel* model, domMesh *mesh);
|
static bool createVolumeFacesFromDomMesh(LLModel* model, domMesh *mesh);
|
||||||
|
|
||||||
static LLModel* loadModelFromDomMesh(domMesh* mesh);
|
//static LLModel* loadModelFromDomMesh(domMesh* mesh);
|
||||||
|
|
||||||
// Loads a mesh breaking it into one or more models as necessary
|
// Loads a mesh breaking it into one or more models as necessary
|
||||||
// to get around volume face limitations while retaining >8 materials
|
// to get around volume face limitations while retaining >8 materials
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,336 @@
|
||||||
|
/**
|
||||||
|
* @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"
|
||||||
|
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
|
#include "llsdserialize.h"
|
||||||
|
#include "lljoint.h"
|
||||||
|
|
||||||
|
#include "glh/glh_linear.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",
|
||||||
|
};
|
||||||
|
|
||||||
|
const U32 LIMIT_MATERIALS_OUTPUT = 12;
|
||||||
|
|
||||||
|
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 ),
|
||||||
|
mGeneratedModelLimit(modelLimit),
|
||||||
|
//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;
|
||||||
|
|
||||||
|
// 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.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 load warning: " << warn_msg.c_str() << LL_ENDL;
|
||||||
|
if (!error_msg.empty())
|
||||||
|
LL_WARNS() << "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, norm_idx, tan_idx, uv0_idx, uv1_idx, color0_idx, color1_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
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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{ 0 };
|
||||||
|
sampler.magFilter = in_sampler.magFilter;
|
||||||
|
sampler.minFilter = in_sampler.minFilter;
|
||||||
|
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{ 0 };
|
||||||
|
image.numChannels = in_image.component;
|
||||||
|
image.bytesPerChannel = in_image.bits >> 3;
|
||||||
|
image.pixelType = in_image.pixel_type;
|
||||||
|
image.size = 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{ 0 };
|
||||||
|
tex.image_idx = in_tex.source;
|
||||||
|
tex.sampler_idx = in_tex.sampler;
|
||||||
|
|
||||||
|
if (tex.image_idx >= mImages.size() || tex.sampler_idx >= 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{ 0 };
|
||||||
|
mat.name = gltf_material.name;
|
||||||
|
|
||||||
|
mat.normalScale = gltf_material.normalTexture.scale;
|
||||||
|
mat.normalTexIdx = gltf_material.normalTexture.index;
|
||||||
|
mat.normalTexCoordIdx = gltf_material.normalTexture.texCoord;
|
||||||
|
|
||||||
|
mat.occlusionScale = gltf_material.occlusionTexture.strength;
|
||||||
|
mat.occlusionTexIdx = gltf_material.occlusionTexture.index;
|
||||||
|
mat.occlusionTexCoordIdx = gltf_material.occlusionTexture.texCoord;
|
||||||
|
|
||||||
|
mat.emissiveColor.set(gltf_material.emissiveFactor.data());
|
||||||
|
mat.emissiveColorTexIdx = gltf_material.emissiveTexture.index;
|
||||||
|
mat.emissiveColorTexCoordIdx = gltf_material.emissiveTexture.texCoord;
|
||||||
|
|
||||||
|
mat.alphaMode = gltf_material.alphaMode;
|
||||||
|
mat.alphaMask = gltf_material.alphaCutoff;
|
||||||
|
|
||||||
|
tinygltf::PbrMetallicRoughness& pbr = gltf_material.pbrMetallicRoughness;
|
||||||
|
mat.hasPBR = true;
|
||||||
|
|
||||||
|
mat.pbr.baseColor.set(pbr.baseColorFactor.data());
|
||||||
|
mat.pbr.baseColorTexIdx = pbr.baseColorTexture.index;
|
||||||
|
mat.pbr.baseColorTexCoordIdx = pbr.baseColorTexture.texCoord;
|
||||||
|
|
||||||
|
mat.pbr.metalness = pbr.metallicFactor;
|
||||||
|
mat.pbr.roughness = pbr.roughnessFactor;
|
||||||
|
mat.pbr.metalRoughTexIdx = pbr.metallicRoughnessTexture.index;
|
||||||
|
mat.pbr.metalRoughTexCoordIdx = pbr.metallicRoughnessTexture.texCoord;
|
||||||
|
|
||||||
|
if (mat.normalTexIdx >= mTextures.size() ||
|
||||||
|
mat.occlusionTexIdx >= mTextures.size() ||
|
||||||
|
mat.emissiveColorTexIdx >= mTextures.size() ||
|
||||||
|
mat.pbr.baseColorTexIdx >= mTextures.size() ||
|
||||||
|
mat.pbr.metalRoughTexIdx >= mTextures.size())
|
||||||
|
{
|
||||||
|
LL_WARNS("GLTF_IMPORT") << "Texture resource index error" << LL_ENDL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mat.normalTexCoordIdx > 0 || // May have to loosen this condition
|
||||||
|
mat.occlusionTexCoordIdx > 0 ||
|
||||||
|
mat.emissiveColorTexCoordIdx > 0 ||
|
||||||
|
mat.pbr.baseColorTexCoordIdx > 0 ||
|
||||||
|
mat.pbr.metalRoughTexCoordIdx > 0)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: convert raw index buffers to UUIDs
|
||||||
|
void LLGLTFLoader::uploadMaterials()
|
||||||
|
{
|
||||||
|
llassert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,207 @@
|
||||||
|
/**
|
||||||
|
* @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 "llmodelloader.h"
|
||||||
|
|
||||||
|
typedef struct // gltf sampler
|
||||||
|
{ // 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; // seen 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
|
||||||
|
} gltf_sampler;
|
||||||
|
|
||||||
|
typedef struct // gltf image
|
||||||
|
{ // Note that glTF images are defined with row 0 at the top
|
||||||
|
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
|
||||||
|
} gltf_image;
|
||||||
|
|
||||||
|
typedef struct // texture
|
||||||
|
{
|
||||||
|
U32 image_idx;
|
||||||
|
U32 sampler_idx;
|
||||||
|
} gltf_texture;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: 2022-05 DJH add UUIDs for each texture
|
||||||
|
typedef struct // gltf_pbrMR_material
|
||||||
|
{
|
||||||
|
// scalar values
|
||||||
|
LLColor4 baseColor; // linear encoding. Multiplied with vertex color, if present.
|
||||||
|
double metalness;
|
||||||
|
double roughness;
|
||||||
|
|
||||||
|
// textures
|
||||||
|
U32 baseColorTexIdx; // always sRGB encoded
|
||||||
|
U32 baseColorTexCoordIdx;
|
||||||
|
|
||||||
|
U32 metalRoughTexIdx; // always linear, roughness in G channel, metalness in B channel
|
||||||
|
U32 metalRoughTexCoordIdx;
|
||||||
|
} gltf_pbr;
|
||||||
|
|
||||||
|
typedef struct // render material
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
// scalar values
|
||||||
|
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;
|
||||||
|
|
||||||
|
// textures
|
||||||
|
U32 normalTexIdx; // linear, valid range R[0-1], G[0-1], B[0.5-1]. Normal = texel * 2 - vec3(1.0)
|
||||||
|
U32 normalTexCoordIdx;
|
||||||
|
|
||||||
|
U32 occlusionTexIdx; // linear, occlusion in R channel, 0 meaning fully occluded, 1 meaning not occluded
|
||||||
|
U32 occlusionTexCoordIdx;
|
||||||
|
|
||||||
|
U32 emissiveColorTexIdx; // always stored as sRGB, in nits (candela / meter^2)
|
||||||
|
U32 emissiveColorTexCoordIdx;
|
||||||
|
|
||||||
|
// TODO: Add traditional (diffuse, normal, specular) UUIDs here, or add this struct to LL_TextureEntry??
|
||||||
|
|
||||||
|
bool hasPBR;
|
||||||
|
gltf_pbr pbr;
|
||||||
|
|
||||||
|
} gltf_render_material;
|
||||||
|
|
||||||
|
typedef struct // gltf_mesh
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
// TODO DJH 2022-04
|
||||||
|
|
||||||
|
} gltf_mesh;
|
||||||
|
|
||||||
|
class LLGLTFLoader : public LLModelLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::map<std::string, LLImportMaterial> material_map;
|
||||||
|
typedef void gltfElement; // TBD
|
||||||
|
typedef void GLTF; // TBD
|
||||||
|
|
||||||
|
// typedef std::map<gltfElement*, std::vector<LLPointer<LLModel> > > gltf_model_map;
|
||||||
|
// gltf_model_map mModelsMap;
|
||||||
|
|
||||||
|
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:
|
||||||
|
U32 mGeneratedModelLimit; // Attempt to limit amount of generated submodels
|
||||||
|
// bool mPreprocessGLTF;
|
||||||
|
|
||||||
|
bool parseMeshes();
|
||||||
|
void uploadMeshes();
|
||||||
|
bool parseMaterials();
|
||||||
|
void uploadMaterials();
|
||||||
|
bool populateModelFromMesh(LLModel* pModel, const tinygltf::Mesh &mesh);
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
|
@ -160,7 +160,8 @@ bool LLModelLoader::getSLMFilename(const std::string& model_filename, std::strin
|
||||||
std::string::size_type i = model_filename.rfind(".");
|
std::string::size_type i = model_filename.rfind(".");
|
||||||
if (i != std::string::npos)
|
if (i != std::string::npos)
|
||||||
{
|
{
|
||||||
slm_filename.replace(i, model_filename.size()-1, ".slm");
|
slm_filename.resize(i, '\0');
|
||||||
|
slm_filename.append(".slm");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -172,7 +173,7 @@ bool LLModelLoader::getSLMFilename(const std::string& model_filename, std::strin
|
||||||
bool LLModelLoader::doLoadModel()
|
bool LLModelLoader::doLoadModel()
|
||||||
{
|
{
|
||||||
//first, look for a .slm file of the same name that was modified later
|
//first, look for a .slm file of the same name that was modified later
|
||||||
//than the .dae
|
//than the specified model file
|
||||||
|
|
||||||
if (mTrySLM)
|
if (mTrySLM)
|
||||||
{
|
{
|
||||||
|
|
@ -182,13 +183,13 @@ bool LLModelLoader::doLoadModel()
|
||||||
llstat slm_status;
|
llstat slm_status;
|
||||||
if (LLFile::stat(slm_filename, &slm_status) == 0)
|
if (LLFile::stat(slm_filename, &slm_status) == 0)
|
||||||
{ //slm file exists
|
{ //slm file exists
|
||||||
llstat dae_status;
|
llstat model_file_status;
|
||||||
if (LLFile::stat(mFilename, &dae_status) != 0 ||
|
if (LLFile::stat(mFilename, &model_file_status) != 0 ||
|
||||||
dae_status.st_mtime < slm_status.st_mtime)
|
model_file_status.st_mtime < slm_status.st_mtime)
|
||||||
{
|
{
|
||||||
if (loadFromSLM(slm_filename))
|
if (loadFromSLM(slm_filename))
|
||||||
{ //slm successfully loaded, if this fails, fall through and
|
{ //slm successfully loaded, if this fails, fall through and
|
||||||
//try loading from dae
|
//try loading from model file
|
||||||
|
|
||||||
mLod = -1; //successfully loading from an slm implicitly sets all
|
mLod = -1; //successfully loading from an slm implicitly sets all
|
||||||
//LoDs
|
//LoDs
|
||||||
|
|
|
||||||
|
|
@ -55,13 +55,11 @@ LLFilePicker LLFilePicker::sInstance;
|
||||||
#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0"
|
#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0"
|
||||||
#define ANIM_FILTER L"Animations (*.bvh; *.anim)\0*.bvh;*.anim\0"
|
#define ANIM_FILTER L"Animations (*.bvh; *.anim)\0*.bvh;*.anim\0"
|
||||||
#define COLLADA_FILTER L"Scene (*.dae)\0*.dae\0"
|
#define COLLADA_FILTER L"Scene (*.dae)\0*.dae\0"
|
||||||
#ifdef _CORY_TESTING
|
#define GLTF_FILTER L"glTF (*.gltf; *.glb)\0*.gltf;*.glb\0"
|
||||||
#define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0"
|
|
||||||
#endif
|
|
||||||
#define XML_FILTER L"XML files (*.xml)\0*.xml\0"
|
#define XML_FILTER L"XML files (*.xml)\0*.xml\0"
|
||||||
#define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0"
|
#define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0"
|
||||||
#define RAW_FILTER L"RAW files (*.raw)\0*.raw\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 SCRIPT_FILTER L"Script files (*.lsl)\0*.lsl\0"
|
#define SCRIPT_FILTER L"Script files (*.lsl)\0*.lsl\0"
|
||||||
#define DICTIONARY_FILTER L"Dictionary files (*.dic; *.xcu)\0*.dic;*.xcu\0"
|
#define DICTIONARY_FILTER L"Dictionary files (*.dic; *.xcu)\0*.dic;*.xcu\0"
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -193,16 +191,14 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter)
|
||||||
mOFN.lpstrFilter = ANIM_FILTER \
|
mOFN.lpstrFilter = ANIM_FILTER \
|
||||||
L"\0";
|
L"\0";
|
||||||
break;
|
break;
|
||||||
case FFLOAD_COLLADA:
|
case FFLOAD_GLTF:
|
||||||
|
mOFN.lpstrFilter = GLTF_FILTER \
|
||||||
|
L"\0";
|
||||||
|
break;
|
||||||
|
case FFLOAD_COLLADA:
|
||||||
mOFN.lpstrFilter = COLLADA_FILTER \
|
mOFN.lpstrFilter = COLLADA_FILTER \
|
||||||
L"\0";
|
L"\0";
|
||||||
break;
|
break;
|
||||||
#ifdef _CORY_TESTING
|
|
||||||
case FFLOAD_GEOMETRY:
|
|
||||||
mOFN.lpstrFilter = GEOMETRY_FILTER \
|
|
||||||
L"\0";
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case FFLOAD_XML:
|
case FFLOAD_XML:
|
||||||
mOFN.lpstrFilter = XML_FILTER \
|
mOFN.lpstrFilter = XML_FILTER \
|
||||||
L"\0";
|
L"\0";
|
||||||
|
|
@ -480,18 +476,16 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename,
|
||||||
L"XAF Anim File (*.xaf)\0*.xaf\0" \
|
L"XAF Anim File (*.xaf)\0*.xaf\0" \
|
||||||
L"\0";
|
L"\0";
|
||||||
break;
|
break;
|
||||||
#ifdef _CORY_TESTING
|
case FFSAVE_GLTF:
|
||||||
case FFSAVE_GEOMETRY:
|
|
||||||
if (filename.empty())
|
if (filename.empty())
|
||||||
{
|
{
|
||||||
wcsncpy( mFilesW,L"untitled.slg", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
|
wcsncpy( mFilesW,L"untitled.glb", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
|
||||||
}
|
}
|
||||||
mOFN.lpstrDefExt = L"slg";
|
mOFN.lpstrDefExt = L"glb";
|
||||||
mOFN.lpstrFilter =
|
mOFN.lpstrFilter =
|
||||||
L"SLG SL Geometry File (*.slg)\0*.slg\0" \
|
L"glTF Asset File (*.gltf *.glb)\0*.gltf;*.glb\0" \
|
||||||
L"\0";
|
L"\0";
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
case FFSAVE_XML:
|
case FFSAVE_XML:
|
||||||
if (filename.empty())
|
if (filename.empty())
|
||||||
{
|
{
|
||||||
|
|
@ -621,14 +615,13 @@ std::vector<std::string>* LLFilePicker::navOpenFilterProc(ELoadFilter filter) //
|
||||||
allowedv->push_back("bvh");
|
allowedv->push_back("bvh");
|
||||||
allowedv->push_back("anim");
|
allowedv->push_back("anim");
|
||||||
break;
|
break;
|
||||||
|
case FFLOAD_GLTF:
|
||||||
|
allowedv->push_back("gltf");
|
||||||
|
allowedv->push_back("glb");
|
||||||
|
break;
|
||||||
case FFLOAD_COLLADA:
|
case FFLOAD_COLLADA:
|
||||||
allowedv->push_back("dae");
|
allowedv->push_back("dae");
|
||||||
break;
|
break;
|
||||||
#ifdef _CORY_TESTING
|
|
||||||
case FFLOAD_GEOMETRY:
|
|
||||||
allowedv->push_back("slg");
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case FFLOAD_XML:
|
case FFLOAD_XML:
|
||||||
allowedv->push_back("xml");
|
allowedv->push_back("xml");
|
||||||
break;
|
break;
|
||||||
|
|
@ -728,13 +721,11 @@ bool LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filena
|
||||||
extension = "xaf";
|
extension = "xaf";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef _CORY_TESTING
|
case FFSAVE_GLTF:
|
||||||
case FFSAVE_GEOMETRY:
|
|
||||||
type = "\?\?\?\?";
|
type = "\?\?\?\?";
|
||||||
creator = "\?\?\?\?";
|
creator = "\?\?\?\?";
|
||||||
extension = "slg";
|
extension = "glb";
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
|
|
||||||
case FFSAVE_XML:
|
case FFSAVE_XML:
|
||||||
type = "\?\?\?\?";
|
type = "\?\?\?\?";
|
||||||
|
|
@ -1354,10 +1345,13 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking )
|
||||||
case FFLOAD_XML:
|
case FFLOAD_XML:
|
||||||
filtername = add_xml_filter_to_gtkchooser(picker);
|
filtername = add_xml_filter_to_gtkchooser(picker);
|
||||||
break;
|
break;
|
||||||
case FFLOAD_COLLADA:
|
case FFLOAD_GLTF:
|
||||||
filtername = add_collada_filter_to_gtkchooser(picker);
|
filtername = dead_code_should_blow_up_here(picker);
|
||||||
break;
|
break;
|
||||||
case FFLOAD_IMAGE:
|
case FFLOAD_COLLADA:
|
||||||
|
filtername = add_collada_filter_to_gtkchooser(picker);
|
||||||
|
break;
|
||||||
|
case FFLOAD_IMAGE:
|
||||||
filtername = add_imageload_filter_to_gtkchooser(picker);
|
filtername = add_imageload_filter_to_gtkchooser(picker);
|
||||||
break;
|
break;
|
||||||
case FFLOAD_SCRIPT:
|
case FFLOAD_SCRIPT:
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,7 @@ public:
|
||||||
FFLOAD_WAV = 2,
|
FFLOAD_WAV = 2,
|
||||||
FFLOAD_IMAGE = 3,
|
FFLOAD_IMAGE = 3,
|
||||||
FFLOAD_ANIM = 4,
|
FFLOAD_ANIM = 4,
|
||||||
#ifdef _CORY_TESTING
|
FFLOAD_GLTF = 5,
|
||||||
FFLOAD_GEOMETRY = 5,
|
|
||||||
#endif
|
|
||||||
FFLOAD_XML = 6,
|
FFLOAD_XML = 6,
|
||||||
FFLOAD_SLOBJECT = 7,
|
FFLOAD_SLOBJECT = 7,
|
||||||
FFLOAD_RAW = 8,
|
FFLOAD_RAW = 8,
|
||||||
|
|
@ -99,9 +97,7 @@ public:
|
||||||
FFSAVE_BMP = 5,
|
FFSAVE_BMP = 5,
|
||||||
FFSAVE_AVI = 6,
|
FFSAVE_AVI = 6,
|
||||||
FFSAVE_ANIM = 7,
|
FFSAVE_ANIM = 7,
|
||||||
#ifdef _CORY_TESTING
|
FFSAVE_GLTF = 8,
|
||||||
FFSAVE_GEOMETRY = 8,
|
|
||||||
#endif
|
|
||||||
FFSAVE_XML = 9,
|
FFSAVE_XML = 9,
|
||||||
FFSAVE_COLLADA = 10,
|
FFSAVE_COLLADA = 10,
|
||||||
FFSAVE_RAW = 11,
|
FFSAVE_RAW = 11,
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod)
|
LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod)
|
||||||
: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA)
|
: LLFilePickerThread(LLFilePicker::FFLOAD_MODEL)
|
||||||
{
|
{
|
||||||
mMP = mp;
|
mMP = mp;
|
||||||
mLOD = lod;
|
mLOD = lod;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include "llmodelloader.h"
|
#include "llmodelloader.h"
|
||||||
#include "lldaeloader.h"
|
#include "lldaeloader.h"
|
||||||
|
#include "llgltfloader.h"
|
||||||
#include "llfloatermodelpreview.h"
|
#include "llfloatermodelpreview.h"
|
||||||
|
|
||||||
#include "llagent.h"
|
#include "llagent.h"
|
||||||
|
|
@ -732,20 +733,41 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
|
||||||
std::map<std::string, std::string> joint_alias_map;
|
std::map<std::string, std::string> joint_alias_map;
|
||||||
getJointAliases(joint_alias_map);
|
getJointAliases(joint_alias_map);
|
||||||
|
|
||||||
mModelLoader = new LLDAELoader(
|
// three possible file extensions, .dae .gltf .glb
|
||||||
filename,
|
// check for .dae and if not then assume one of the .gl??
|
||||||
lod,
|
if (std::string::npos != filename.rfind(".dae"))
|
||||||
&LLModelPreview::loadedCallback,
|
{
|
||||||
&LLModelPreview::lookupJointByName,
|
mModelLoader = new LLDAELoader(
|
||||||
&LLModelPreview::loadTextures,
|
filename,
|
||||||
&LLModelPreview::stateChangedCallback,
|
lod,
|
||||||
this,
|
&LLModelPreview::loadedCallback,
|
||||||
mJointTransformMap,
|
&LLModelPreview::lookupJointByName,
|
||||||
mJointsFromNode,
|
&LLModelPreview::loadTextures,
|
||||||
joint_alias_map,
|
&LLModelPreview::stateChangedCallback,
|
||||||
LLSkinningUtil::getMaxJointCount(),
|
this,
|
||||||
gSavedSettings.getU32("ImporterModelLimit"),
|
mJointTransformMap,
|
||||||
gSavedSettings.getBOOL("ImporterPreprocessDAE"));
|
mJointsFromNode,
|
||||||
|
joint_alias_map,
|
||||||
|
LLSkinningUtil::getMaxJointCount(),
|
||||||
|
gSavedSettings.getU32("ImporterModelLimit"),
|
||||||
|
gSavedSettings.getBOOL("ImporterPreprocessDAE"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mModelLoader = new LLGLTFLoader(
|
||||||
|
filename,
|
||||||
|
lod,
|
||||||
|
&LLModelPreview::loadedCallback,
|
||||||
|
&LLModelPreview::lookupJointByName,
|
||||||
|
&LLModelPreview::loadTextures,
|
||||||
|
&LLModelPreview::stateChangedCallback,
|
||||||
|
this,
|
||||||
|
mJointTransformMap,
|
||||||
|
mJointsFromNode,
|
||||||
|
joint_alias_map,
|
||||||
|
LLSkinningUtil::getMaxJointCount(),
|
||||||
|
gSavedSettings.getU32("ImporterModelLimit"));
|
||||||
|
}
|
||||||
|
|
||||||
if (force_disable_slm)
|
if (force_disable_slm)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -267,16 +267,11 @@ void handle_reset_view();
|
||||||
|
|
||||||
void handle_duplicate_in_place(void*);
|
void handle_duplicate_in_place(void*);
|
||||||
|
|
||||||
|
|
||||||
void handle_object_owner_self(void*);
|
void handle_object_owner_self(void*);
|
||||||
void handle_object_owner_permissive(void*);
|
void handle_object_owner_permissive(void*);
|
||||||
void handle_object_lock(void*);
|
void handle_object_lock(void*);
|
||||||
void handle_object_asset_ids(void*);
|
void handle_object_asset_ids(void*);
|
||||||
void force_take_copy(void*);
|
void force_take_copy(void*);
|
||||||
#ifdef _CORY_TESTING
|
|
||||||
void force_export_copy(void*);
|
|
||||||
void force_import_geometry(void*);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void handle_force_parcel_owner_to_me(void*);
|
void handle_force_parcel_owner_to_me(void*);
|
||||||
void handle_force_parcel_to_content(void*);
|
void handle_force_parcel_to_content(void*);
|
||||||
|
|
|
||||||
|
|
@ -277,9 +277,6 @@ void LLMediaFilePicker::notify(const std::vector<std::string>& filenames)
|
||||||
static std::string SOUND_EXTENSIONS = "wav";
|
static std::string SOUND_EXTENSIONS = "wav";
|
||||||
static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png";
|
static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png";
|
||||||
static std::string ANIM_EXTENSIONS = "bvh anim";
|
static std::string ANIM_EXTENSIONS = "bvh anim";
|
||||||
#ifdef _CORY_TESTING
|
|
||||||
static std::string GEOMETRY_EXTENSIONS = "slg";
|
|
||||||
#endif
|
|
||||||
static std::string XML_EXTENSIONS = "xml";
|
static std::string XML_EXTENSIONS = "xml";
|
||||||
static std::string SLOBJECT_EXTENSIONS = "slobject";
|
static std::string SLOBJECT_EXTENSIONS = "slobject";
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -301,10 +298,6 @@ std::string build_extensions_string(LLFilePicker::ELoadFilter filter)
|
||||||
return SLOBJECT_EXTENSIONS;
|
return SLOBJECT_EXTENSIONS;
|
||||||
case LLFilePicker::FFLOAD_MODEL:
|
case LLFilePicker::FFLOAD_MODEL:
|
||||||
return MODEL_EXTENSIONS;
|
return MODEL_EXTENSIONS;
|
||||||
#ifdef _CORY_TESTING
|
|
||||||
case LLFilePicker::FFLOAD_GEOMETRY:
|
|
||||||
return GEOMETRY_EXTENSIONS;
|
|
||||||
#endif
|
|
||||||
case LLFilePicker::FFLOAD_XML:
|
case LLFilePicker::FFLOAD_XML:
|
||||||
return XML_EXTENSIONS;
|
return XML_EXTENSIONS;
|
||||||
case LLFilePicker::FFLOAD_ALL:
|
case LLFilePicker::FFLOAD_ALL:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue