#1357 GLTF Export Prototype
parent
66ccc1ed83
commit
5e2bac01cb
|
|
@ -81,8 +81,6 @@ namespace LL
|
|||
|
||||
S32 mSampler = INVALID_INDEX;
|
||||
Target mTarget;
|
||||
std::string mTargetPath;
|
||||
std::string mName;
|
||||
|
||||
const Channel& operator=(const tinygltf::AnimationChannel& src)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,6 +33,267 @@
|
|||
|
||||
using namespace LL::GLTF;
|
||||
|
||||
|
||||
namespace LL
|
||||
{
|
||||
namespace GLTF
|
||||
{
|
||||
template <typename T, typename U>
|
||||
void copy(const std::vector<T>& src, std::vector<U>& dst)
|
||||
{
|
||||
dst.resize(src.size());
|
||||
for (U32 i = 0; i < src.size(); ++i)
|
||||
{
|
||||
copy(src[i], dst[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void copy(const Node& src, tinygltf::Node& dst)
|
||||
{
|
||||
if (src.mMatrixValid)
|
||||
{
|
||||
if (!src.mMatrix.asMatrix4().isIdentity())
|
||||
{
|
||||
dst.matrix.resize(16);
|
||||
for (U32 i = 0; i < 16; ++i)
|
||||
{
|
||||
dst.matrix[i] = src.mMatrix.getF32ptr()[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (src.mTRSValid)
|
||||
{
|
||||
if (!src.mRotation.equals(glh::quaternionf::identity(), FLT_EPSILON))
|
||||
{
|
||||
dst.rotation.resize(4);
|
||||
for (U32 i = 0; i < 4; ++i)
|
||||
{
|
||||
dst.rotation[i] = src.mRotation.get_value()[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (src.mTranslation != glh::vec3f(0.f, 0.f, 0.f))
|
||||
{
|
||||
dst.translation.resize(3);
|
||||
for (U32 i = 0; i < 3; ++i)
|
||||
{
|
||||
dst.translation[i] = src.mTranslation.v[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (src.mScale != glh::vec3f(1.f, 1.f, 1.f))
|
||||
{
|
||||
dst.scale.resize(3);
|
||||
for (U32 i = 0; i < 3; ++i)
|
||||
{
|
||||
dst.scale[i] = src.mScale.v[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dst.children = src.mChildren;
|
||||
dst.mesh = src.mMesh;
|
||||
dst.skin = src.mSkin;
|
||||
dst.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Scene& src, tinygltf::Scene& dst)
|
||||
{
|
||||
dst.nodes = src.mNodes;
|
||||
dst.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Primitive& src, tinygltf::Primitive& dst)
|
||||
{
|
||||
for (auto& attrib : src.mAttributes)
|
||||
{
|
||||
dst.attributes[attrib.first] = attrib.second;
|
||||
}
|
||||
dst.indices = src.mIndices;
|
||||
dst.material = src.mMaterial;
|
||||
dst.mode = src.mMode;
|
||||
}
|
||||
|
||||
void copy(const Mesh& src, tinygltf::Mesh& mesh)
|
||||
{
|
||||
copy(src.mPrimitives, mesh.primitives);
|
||||
mesh.weights = src.mWeights;
|
||||
mesh.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Material::TextureInfo& src, tinygltf::TextureInfo& dst)
|
||||
{
|
||||
dst.index = src.mIndex;
|
||||
dst.texCoord = src.mTexCoord;
|
||||
}
|
||||
|
||||
void copy(const Material::OcclusionTextureInfo& src, tinygltf::OcclusionTextureInfo& dst)
|
||||
{
|
||||
dst.index = src.mIndex;
|
||||
dst.texCoord = src.mTexCoord;
|
||||
dst.strength = src.mStrength;
|
||||
}
|
||||
|
||||
void copy(const Material::NormalTextureInfo& src, tinygltf::NormalTextureInfo& dst)
|
||||
{
|
||||
dst.index = src.mIndex;
|
||||
dst.texCoord = src.mTexCoord;
|
||||
dst.scale = src.mScale;
|
||||
}
|
||||
|
||||
void copy(const Material::PbrMetallicRoughness& src, tinygltf::PbrMetallicRoughness& dst)
|
||||
{
|
||||
dst.baseColorFactor = { src.mBaseColorFactor.v[0], src.mBaseColorFactor.v[1], src.mBaseColorFactor.v[2], src.mBaseColorFactor.v[3] };
|
||||
copy(src.mBaseColorTexture, dst.baseColorTexture);
|
||||
dst.metallicFactor = src.mMetallicFactor;
|
||||
dst.roughnessFactor = src.mRoughnessFactor;
|
||||
copy(src.mMetallicRoughnessTexture, dst.metallicRoughnessTexture);
|
||||
}
|
||||
|
||||
void copy(const Material& src, tinygltf::Material& material)
|
||||
{
|
||||
material.name = src.mName;
|
||||
|
||||
material.emissiveFactor = { src.mEmissiveFactor.v[0], src.mEmissiveFactor.v[1], src.mEmissiveFactor.v[2] };
|
||||
copy(src.mPbrMetallicRoughness, material.pbrMetallicRoughness);
|
||||
copy(src.mNormalTexture, material.normalTexture);
|
||||
copy(src.mEmissiveTexture, material.emissiveTexture);
|
||||
}
|
||||
|
||||
void copy(const Texture& src, tinygltf::Texture& texture)
|
||||
{
|
||||
texture.sampler = src.mSampler;
|
||||
texture.source = src.mSource;
|
||||
texture.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Sampler& src, tinygltf::Sampler& sampler)
|
||||
{
|
||||
sampler.magFilter = src.mMagFilter;
|
||||
sampler.minFilter = src.mMinFilter;
|
||||
sampler.wrapS = src.mWrapS;
|
||||
sampler.wrapT = src.mWrapT;
|
||||
sampler.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Skin& src, tinygltf::Skin& skin)
|
||||
{
|
||||
skin.joints = src.mJoints;
|
||||
skin.inverseBindMatrices = src.mInverseBindMatrices;
|
||||
skin.skeleton = src.mSkeleton;
|
||||
skin.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Accessor& src, tinygltf::Accessor& accessor)
|
||||
{
|
||||
accessor.bufferView = src.mBufferView;
|
||||
accessor.byteOffset = src.mByteOffset;
|
||||
accessor.componentType = src.mComponentType;
|
||||
accessor.minValues = src.mMin;
|
||||
accessor.maxValues = src.mMax;
|
||||
|
||||
accessor.count = src.mCount;
|
||||
accessor.type = src.mType;
|
||||
accessor.normalized = src.mNormalized;
|
||||
accessor.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Animation::Sampler& src, tinygltf::AnimationSampler& sampler)
|
||||
{
|
||||
sampler.input = src.mInput;
|
||||
sampler.output = src.mOutput;
|
||||
sampler.interpolation = src.mInterpolation;
|
||||
}
|
||||
|
||||
void copy(const Animation::Channel& src, tinygltf::AnimationChannel& channel)
|
||||
{
|
||||
channel.sampler = src.mSampler;
|
||||
channel.target_node = src.mTarget.mNode;
|
||||
channel.target_path = src.mTarget.mPath;
|
||||
}
|
||||
|
||||
void copy(const Animation& src, tinygltf::Animation& animation)
|
||||
{
|
||||
animation.name = src.mName;
|
||||
|
||||
copy(src.mSamplers, animation.samplers);
|
||||
|
||||
U32 channel_count = src.mRotationChannels.size() + src.mTranslationChannels.size() + src.mScaleChannels.size();
|
||||
|
||||
animation.channels.resize(channel_count);
|
||||
|
||||
U32 idx = 0;
|
||||
for (U32 i = 0; i < src.mTranslationChannels.size(); ++i)
|
||||
{
|
||||
copy(src.mTranslationChannels[i], animation.channels[idx++]);
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < src.mRotationChannels.size(); ++i)
|
||||
{
|
||||
copy(src.mRotationChannels[i], animation.channels[idx++]);
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < src.mScaleChannels.size(); ++i)
|
||||
{
|
||||
copy(src.mScaleChannels[i], animation.channels[idx++]);
|
||||
}
|
||||
}
|
||||
|
||||
void copy(const Buffer& src, tinygltf::Buffer& buffer)
|
||||
{
|
||||
buffer.uri = src.mUri;
|
||||
buffer.data = src.mData;
|
||||
buffer.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const BufferView& src, tinygltf::BufferView& bufferView)
|
||||
{
|
||||
bufferView.buffer = src.mBuffer;
|
||||
bufferView.byteOffset = src.mByteOffset;
|
||||
bufferView.byteLength = src.mByteLength;
|
||||
bufferView.byteStride = src.mByteStride;
|
||||
bufferView.target = src.mTarget;
|
||||
bufferView.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Image& src, tinygltf::Image& image)
|
||||
{
|
||||
image.name = src.mName;
|
||||
image.width = src.mWidth;
|
||||
image.height = src.mHeight;
|
||||
image.component = src.mComponent;
|
||||
image.bits = src.mBits;
|
||||
image.pixel_type = src.mPixelType;
|
||||
|
||||
image.image = src.mData;
|
||||
image.bufferView = src.mBufferView;
|
||||
image.mimeType = src.mMimeType;
|
||||
image.uri = src.mUri;
|
||||
}
|
||||
|
||||
void copy(const Asset & src, tinygltf::Model& dst)
|
||||
{
|
||||
dst.defaultScene = src.mDefaultScene;
|
||||
dst.asset.copyright = src.mCopyright;
|
||||
dst.asset.version = src.mVersion;
|
||||
dst.asset.minVersion = src.mMinVersion;
|
||||
dst.asset.generator = "Linden Lab Experimental GLTF Export";
|
||||
|
||||
copy(src.mScenes, dst.scenes);
|
||||
copy(src.mNodes, dst.nodes);
|
||||
copy(src.mMeshes, dst.meshes);
|
||||
copy(src.mMaterials, dst.materials);
|
||||
copy(src.mBuffers, dst.buffers);
|
||||
copy(src.mBufferViews, dst.bufferViews);
|
||||
copy(src.mTextures, dst.textures);
|
||||
copy(src.mSamplers, dst.samplers);
|
||||
copy(src.mImages, dst.images);
|
||||
copy(src.mAccessors, dst.accessors);
|
||||
copy(src.mAnimations, dst.animations);
|
||||
copy(src.mSkins, dst.skins);
|
||||
}
|
||||
}
|
||||
}
|
||||
void Scene::updateTransforms(Asset& asset)
|
||||
{
|
||||
LLMatrix4a identity;
|
||||
|
|
@ -237,6 +498,8 @@ void Node::makeMatrixValid()
|
|||
mMatrix.loadu(t.m);
|
||||
mMatrixValid = true;
|
||||
}
|
||||
|
||||
llassert(mMatrixValid);
|
||||
}
|
||||
|
||||
void Node::makeTRSValid()
|
||||
|
|
@ -252,6 +515,8 @@ void Node::makeTRSValid()
|
|||
mRotation.set_value(t);
|
||||
mTRSValid = true;
|
||||
}
|
||||
|
||||
llassert(mTRSValid);
|
||||
}
|
||||
|
||||
void Node::setRotation(const glh::quaternionf& q)
|
||||
|
|
@ -318,6 +583,7 @@ const Node& Node::operator=(const tinygltf::Node& src)
|
|||
{
|
||||
// node specifies no transformation, set to identity
|
||||
mMatrix.setIdentity();
|
||||
mMatrixValid = true;
|
||||
}
|
||||
|
||||
mChildren = src.children;
|
||||
|
|
@ -467,6 +733,14 @@ void Asset::allocateGLResources(const std::string& filename, const tinygltf::Mod
|
|||
|
||||
const Asset& Asset::operator=(const tinygltf::Model& src)
|
||||
{
|
||||
mVersion = src.asset.version;
|
||||
mMinVersion = src.asset.minVersion;
|
||||
mGenerator = src.asset.generator;
|
||||
mCopyright = src.asset.copyright;
|
||||
|
||||
mDefaultScene = src.defaultScene;
|
||||
|
||||
|
||||
mScenes.resize(src.scenes.size());
|
||||
for (U32 i = 0; i < src.scenes.size(); ++i)
|
||||
{
|
||||
|
|
@ -542,9 +816,67 @@ const Asset& Asset::operator=(const tinygltf::Model& src)
|
|||
return *this;
|
||||
}
|
||||
|
||||
void Asset::save(tinygltf::Model& dst)
|
||||
{
|
||||
LL::GLTF::copy(*this, dst);
|
||||
}
|
||||
|
||||
|
||||
const Material::TextureInfo& Material::TextureInfo::operator=(const tinygltf::TextureInfo& src)
|
||||
{
|
||||
mIndex = src.index;
|
||||
mTexCoord = src.texCoord;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const tinygltf::OcclusionTextureInfo& src)
|
||||
{
|
||||
mIndex = src.index;
|
||||
mTexCoord = src.texCoord;
|
||||
mStrength = src.strength;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const tinygltf::NormalTextureInfo& src)
|
||||
{
|
||||
mIndex = src.index;
|
||||
mTexCoord = src.texCoord;
|
||||
mScale = src.scale;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Material::PbrMetallicRoughness& Material::PbrMetallicRoughness::operator=(const tinygltf::PbrMetallicRoughness& src)
|
||||
{
|
||||
if (src.baseColorFactor.size() == 4)
|
||||
{
|
||||
mBaseColorFactor.set_value(src.baseColorFactor[0], src.baseColorFactor[1], src.baseColorFactor[2], src.baseColorFactor[3]);
|
||||
}
|
||||
|
||||
mBaseColorTexture = src.baseColorTexture;
|
||||
mMetallicFactor = src.metallicFactor;
|
||||
mRoughnessFactor = src.roughnessFactor;
|
||||
mMetallicRoughnessTexture = src.metallicRoughnessTexture;
|
||||
|
||||
return *this;
|
||||
}
|
||||
const Material& Material::operator=(const tinygltf::Material& src)
|
||||
{
|
||||
mName = src.name;
|
||||
|
||||
if (src.emissiveFactor.size() == 3)
|
||||
{
|
||||
mEmissiveFactor.set_value(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2]);
|
||||
}
|
||||
|
||||
mPbrMetallicRoughness = src.pbrMetallicRoughness;
|
||||
mNormalTexture = src.normalTexture;
|
||||
mOcclusionTexture = src.occlusionTexture;
|
||||
mEmissiveTexture = src.emissiveTexture;
|
||||
|
||||
mAlphaMode = src.alphaMode;
|
||||
mAlphaCutoff = src.alphaCutoff;
|
||||
mDoubleSided = src.doubleSided;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,11 +45,59 @@ namespace LL
|
|||
class Material
|
||||
{
|
||||
public:
|
||||
class TextureInfo
|
||||
{
|
||||
public:
|
||||
S32 mIndex = INVALID_INDEX;
|
||||
S32 mTexCoord = 0;
|
||||
|
||||
const TextureInfo& operator=(const tinygltf::TextureInfo& src);
|
||||
};
|
||||
|
||||
class NormalTextureInfo : public TextureInfo
|
||||
{
|
||||
public:
|
||||
F32 mScale = 1.0f;
|
||||
|
||||
const NormalTextureInfo& operator=(const tinygltf::NormalTextureInfo& src);
|
||||
};
|
||||
|
||||
class OcclusionTextureInfo : public TextureInfo
|
||||
{
|
||||
public:
|
||||
F32 mStrength = 1.0f;
|
||||
|
||||
const OcclusionTextureInfo& operator=(const tinygltf::OcclusionTextureInfo& src);
|
||||
};
|
||||
|
||||
class PbrMetallicRoughness
|
||||
{
|
||||
public:
|
||||
glh::vec4f mBaseColorFactor = glh::vec4f(1.f,1.f,1.f,1.f);
|
||||
TextureInfo mBaseColorTexture;
|
||||
F32 mMetallicFactor = 1.0f;
|
||||
F32 mRoughnessFactor = 1.0f;
|
||||
TextureInfo mMetallicRoughnessTexture;
|
||||
const PbrMetallicRoughness& operator=(const tinygltf::PbrMetallicRoughness& src);
|
||||
};
|
||||
|
||||
|
||||
// use LLFetchedGLTFMaterial for now, but eventually we'll want to use
|
||||
// a more flexible GLTF material implementation instead of the fixed packing
|
||||
// version we use for sharable GLTF material assets
|
||||
LLPointer<LLFetchedGLTFMaterial> mMaterial;
|
||||
PbrMetallicRoughness mPbrMetallicRoughness;
|
||||
NormalTextureInfo mNormalTexture;
|
||||
OcclusionTextureInfo mOcclusionTexture;
|
||||
TextureInfo mEmissiveTexture;
|
||||
|
||||
|
||||
std::string mName;
|
||||
glh::vec3f mEmissiveFactor = glh::vec3f(0.f, 0.f, 0.f);
|
||||
std::string mAlphaMode = "OPAQUE";
|
||||
F32 mAlphaCutoff = 0.5f;
|
||||
bool mDoubleSided = false;
|
||||
|
||||
|
||||
const Material& operator=(const tinygltf::Material& src);
|
||||
|
||||
|
|
@ -179,11 +227,16 @@ namespace LL
|
|||
std::string mName;
|
||||
std::string mUri;
|
||||
std::string mMimeType;
|
||||
|
||||
S32 mBufferView = INVALID_INDEX;
|
||||
|
||||
std::vector<U8> mData;
|
||||
S32 mWidth;
|
||||
S32 mHeight;
|
||||
S32 mComponent;
|
||||
S32 mBits;
|
||||
S32 mPixelType;
|
||||
|
||||
LLPointer<LLViewerFetchedTexture> mTexture;
|
||||
|
||||
const Image& operator=(const tinygltf::Image& src)
|
||||
|
|
@ -196,7 +249,8 @@ namespace LL
|
|||
mHeight = src.height;
|
||||
mComponent = src.component;
|
||||
mBits = src.bits;
|
||||
|
||||
mBufferView = src.bufferView;
|
||||
mPixelType = src.pixel_type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -224,6 +278,13 @@ namespace LL
|
|||
std::vector<Animation> mAnimations;
|
||||
std::vector<Skin> mSkins;
|
||||
|
||||
std::string mVersion;
|
||||
std::string mGenerator;
|
||||
std::string mMinVersion;
|
||||
std::string mCopyright;
|
||||
|
||||
S32 mDefaultScene = INVALID_INDEX;
|
||||
|
||||
// the last time update() was called according to gFrameTimeSeconds
|
||||
F32 mLastUpdateTime = gFrameTimeSeconds;
|
||||
|
||||
|
|
@ -258,6 +319,9 @@ namespace LL
|
|||
);
|
||||
|
||||
const Asset& operator=(const tinygltf::Model& src);
|
||||
|
||||
// save the asset to a tinygltf model
|
||||
void save(tinygltf::Model& dst);
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,11 +66,50 @@ void GLTFSceneManager::load()
|
|||
}
|
||||
},
|
||||
LLFilePicker::FFLOAD_GLTF,
|
||||
true);
|
||||
false);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotificationsUtil::add("GLTFPreviewSelection");
|
||||
LLNotificationsUtil::add("GLTFOpenSelection");
|
||||
}
|
||||
}
|
||||
|
||||
void GLTFSceneManager::saveAs()
|
||||
{
|
||||
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
|
||||
if (obj && obj->mGLTFAsset.notNull())
|
||||
{
|
||||
LLFilePickerReplyThread::startPicker(
|
||||
[](const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)
|
||||
{
|
||||
if (LLAppViewer::instance()->quitRequested())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (filenames.size() > 0)
|
||||
{
|
||||
GLTFSceneManager::instance().save(filenames[0]);
|
||||
}
|
||||
},
|
||||
LLFilePicker::FFSAVE_GLTF,
|
||||
"scene.gltf");
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotificationsUtil::add("GLTFSaveSelection");
|
||||
}
|
||||
}
|
||||
|
||||
void GLTFSceneManager::save(const std::string& filename)
|
||||
{
|
||||
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
|
||||
if (obj && obj->mGLTFAsset.notNull())
|
||||
{
|
||||
Asset* asset = obj->mGLTFAsset;
|
||||
tinygltf::Model model;
|
||||
asset->save(model);
|
||||
|
||||
LLTinyGLTFHelper::saveModel(filename, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ namespace LL
|
|||
void load(); // open filepicker to choose asset
|
||||
void load(const std::string& filename); // load asset from filename
|
||||
|
||||
void saveAs(); // open filepicker and choose file to save selected asset to
|
||||
void save(const std::string& filename); // save selected asset to filename
|
||||
|
||||
void update();
|
||||
void render(bool opaque, bool rigged = false);
|
||||
void renderOpaque();
|
||||
|
|
|
|||
|
|
@ -790,7 +790,7 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension,
|
|||
case LLFilePicker::FFSAVE_GLTF:
|
||||
type = "\?\?\?\?";
|
||||
creator = "\?\?\?\?";
|
||||
extension = "glb";
|
||||
extension = "glb,gltf";
|
||||
break;
|
||||
|
||||
case LLFilePicker::FFSAVE_XML:
|
||||
|
|
|
|||
|
|
@ -248,6 +248,43 @@ bool LLTinyGLTFHelper::loadModel(const std::string& filename, tinygltf::Model& m
|
|||
return false;
|
||||
}
|
||||
|
||||
bool LLTinyGLTFHelper::saveModel(const std::string& filename, tinygltf::Model& model_in)
|
||||
{
|
||||
std::string exten = gDirUtilp->getExtension(filename);
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (exten == "gltf" || exten == "glb")
|
||||
{
|
||||
tinygltf::TinyGLTF writer;
|
||||
|
||||
std::string filename_lc = filename;
|
||||
LLStringUtil::toLower(filename_lc);
|
||||
|
||||
|
||||
bool embed_images = false;
|
||||
bool embed_buffers = false;
|
||||
bool pretty_print = true;
|
||||
bool write_binary = false;
|
||||
|
||||
|
||||
if (std::string::npos == filename_lc.rfind(".gltf"))
|
||||
{ // file is binary
|
||||
embed_images = embed_buffers = write_binary = true;
|
||||
}
|
||||
|
||||
success = writer.WriteGltfSceneToFile(&model_in, filename, embed_images, embed_buffers, pretty_print, write_binary);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
LL_WARNS("GLTF") << "Failed to save" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool LLTinyGLTFHelper::getMaterialFromModel(
|
||||
const std::string& filename,
|
||||
const tinygltf::Model& model_in,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ namespace LLTinyGLTFHelper
|
|||
LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index, bool flip = true);
|
||||
|
||||
bool loadModel(const std::string& filename, tinygltf::Model& model_out);
|
||||
bool saveModel(const std::string& filename, tinygltf::Model& model_in);
|
||||
|
||||
bool getMaterialFromModel(
|
||||
const std::string& filename,
|
||||
|
|
|
|||
|
|
@ -7980,7 +7980,7 @@ class LLAdvancedClickHDRIPreview: public view_listener_t
|
|||
};
|
||||
|
||||
|
||||
class LLAdvancedClickGLTFScenePreview : public view_listener_t
|
||||
class LLAdvancedClickGLTFOpen: public view_listener_t
|
||||
{
|
||||
bool handleEvent(const LLSD& userdata)
|
||||
{
|
||||
|
|
@ -7990,6 +7990,16 @@ class LLAdvancedClickGLTFScenePreview : public view_listener_t
|
|||
}
|
||||
};
|
||||
|
||||
class LLAdvancedClickGLTFSaveAs : public view_listener_t
|
||||
{
|
||||
bool handleEvent(const LLSD& userdata)
|
||||
{
|
||||
// open personal lighting floater when previewing an HDRI (keeps HDRI from implicitly unloading when opening build tools)
|
||||
LL::GLTFSceneManager::instance().saveAs();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// these are used in the gl menus to set control values that require shader recompilation
|
||||
class LLToggleShaderControl : public view_listener_t
|
||||
{
|
||||
|
|
@ -9637,7 +9647,8 @@ void initialize_menus()
|
|||
view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile");
|
||||
view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark");
|
||||
view_listener_t::addMenu(new LLAdvancedClickHDRIPreview(), "Advanced.ClickHDRIPreview");
|
||||
view_listener_t::addMenu(new LLAdvancedClickGLTFScenePreview(), "Advanced.ClickGLTFScenePreview");
|
||||
view_listener_t::addMenu(new LLAdvancedClickGLTFOpen(), "Advanced.ClickGLTFOpen");
|
||||
view_listener_t::addMenu(new LLAdvancedClickGLTFSaveAs(), "Advanced.ClickGLTFSaveAs");
|
||||
view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache");
|
||||
view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain");
|
||||
|
||||
|
|
|
|||
|
|
@ -4379,7 +4379,7 @@ LLMatrix4a LLViewerObject::getGLTFAssetToAgentTransform() const
|
|||
LLMatrix4 root;
|
||||
root.initScale(getScale());
|
||||
root.rotate(getRenderRotation());
|
||||
root.translate(getPositionAgent());
|
||||
root.translate(getRenderPosition());
|
||||
|
||||
LLMatrix4a mat;
|
||||
mat.loadu((F32*)root.mMatrix);
|
||||
|
|
@ -4403,7 +4403,7 @@ LLMatrix4a LLViewerObject::getAgentToGLTFAssetTransform() const
|
|||
scale.mV[1] = 1.f / scale.mV[1];
|
||||
scale.mV[2] = 1.f / scale.mV[2];
|
||||
|
||||
root.translate(-getPositionAgent());
|
||||
root.translate(-getRenderPosition());
|
||||
root.rotate(~getRenderRotation());
|
||||
|
||||
LLMatrix4 scale_mat;
|
||||
|
|
|
|||
|
|
@ -2844,6 +2844,24 @@ function="World.EnvPreset"
|
|||
parameter="mem_leaking" />
|
||||
</menu_item_call>
|
||||
</menu>
|
||||
<menu
|
||||
create_jump_keys="true"
|
||||
label="GLTF"
|
||||
name="GLTF"
|
||||
tear_off="true">
|
||||
<menu_item_call
|
||||
label="Open..."
|
||||
name="Open...">
|
||||
<menu_item_call.on_click
|
||||
function="Advanced.ClickGLTFOpen" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="Save As..."
|
||||
name="Save As...">
|
||||
<menu_item_call.on_click
|
||||
function="Advanced.ClickGLTFSaveAs" />
|
||||
</menu_item_call>
|
||||
</menu>
|
||||
<menu
|
||||
create_jump_keys="true"
|
||||
label="Render Tests"
|
||||
|
|
@ -2896,12 +2914,6 @@ function="World.EnvPreset"
|
|||
<menu_item_call.on_click
|
||||
function="Advanced.ClickHDRIPreview" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="GLTF Scene Preview"
|
||||
name="GLTF Scene Preview">
|
||||
<menu_item_call.on_click
|
||||
function="Advanced.ClickGLTFScenePreview" />
|
||||
</menu_item_call>
|
||||
</menu>
|
||||
<menu
|
||||
create_jump_keys="true"
|
||||
|
|
|
|||
|
|
@ -12408,7 +12408,7 @@ are wearing now.
|
|||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="GLTFPreviewSelection"
|
||||
name="GLTFOpenSelection"
|
||||
type="alert">
|
||||
You must select an object to act as a handle to the GLTF asset you are previewing.
|
||||
<tag>fail</tag>
|
||||
|
|
@ -12417,4 +12417,15 @@ are wearing now.
|
|||
yestext="OK"/>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="GLTFSaveSelection"
|
||||
type="alert">
|
||||
You must select an object that has a GLTF asset associated with it.
|
||||
<tag>fail</tag>
|
||||
<usetemplate
|
||||
name="okbutton"
|
||||
yestext="OK"/>
|
||||
</notification>
|
||||
|
||||
</notifications>
|
||||
|
|
|
|||
Loading…
Reference in New Issue