phoenix-firestorm/indra/newview/gltf/asset.h

386 lines
14 KiB
C++

#pragma once
/**
* @file asset.h
* @brief LL GLTF Implementation
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2024, 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 "llvertexbuffer.h"
#include "llvolumeoctree.h"
#include "../lltinygltfhelper.h"
#include "accessor.h"
#include "primitive.h"
#include "animation.h"
#include "boost/json.hpp"
#include "common.h"
extern F32SecondsImplicit gFrameTimeSeconds;
// wingdi defines OPAQUE, which conflicts with our enum
#if defined(OPAQUE)
#undef OPAQUE
#endif
// LL GLTF Implementation
namespace LL
{
namespace GLTF
{
class Asset;
class Material
{
public:
enum class AlphaMode
{
OPAQUE,
MASK,
BLEND
};
class TextureInfo
{
public:
S32 mIndex = INVALID_INDEX;
S32 mTexCoord = 0;
bool operator==(const TextureInfo& rhs) const;
bool operator!=(const TextureInfo& rhs) const;
const TextureInfo& operator=(const tinygltf::TextureInfo& src);
const TextureInfo& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class NormalTextureInfo : public TextureInfo
{
public:
F32 mScale = 1.0f;
const NormalTextureInfo& operator=(const tinygltf::NormalTextureInfo& src);
const NormalTextureInfo& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class OcclusionTextureInfo : public TextureInfo
{
public:
F32 mStrength = 1.0f;
const OcclusionTextureInfo& operator=(const tinygltf::OcclusionTextureInfo& src);
const OcclusionTextureInfo& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class PbrMetallicRoughness
{
public:
vec4 mBaseColorFactor = vec4(1.f,1.f,1.f,1.f);
TextureInfo mBaseColorTexture;
F32 mMetallicFactor = 1.0f;
F32 mRoughnessFactor = 1.0f;
TextureInfo mMetallicRoughnessTexture;
bool operator==(const PbrMetallicRoughness& rhs) const;
bool operator!=(const PbrMetallicRoughness& rhs) const;
const PbrMetallicRoughness& operator=(const tinygltf::PbrMetallicRoughness& src);
const PbrMetallicRoughness& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
// 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;
vec3 mEmissiveFactor = vec3(0.f, 0.f, 0.f);
AlphaMode mAlphaMode = AlphaMode::OPAQUE;
F32 mAlphaCutoff = 0.5f;
bool mDoubleSided = false;
// bind for rendering
void bind(Asset& asset);
const Material& operator=(const tinygltf::Material& src);
const Material& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
void allocateGLResources(Asset& asset);
};
class Mesh
{
public:
std::vector<Primitive> mPrimitives;
std::vector<double> mWeights;
std::string mName;
const Mesh& operator=(const tinygltf::Mesh& src);
const Mesh& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
void allocateGLResources(Asset& asset);
};
class Node
{
public:
mat4 mMatrix = glm::identity<mat4>(); //local transform
mat4 mRenderMatrix; //transform for rendering
mat4 mAssetMatrix; //transform from local to asset space
mat4 mAssetMatrixInv; //transform from asset to local space
vec3 mTranslation = vec3(0,0,0);
quat mRotation = glm::identity<quat>();
vec3 mScale = vec3(1.f,1.f,1.f);
// if true, mMatrix is valid and up to date
bool mMatrixValid = false;
// if true, translation/rotation/scale are valid and up to date
bool mTRSValid = false;
bool mNeedsApplyMatrix = false;
std::vector<S32> mChildren;
S32 mParent = INVALID_INDEX;
S32 mMesh = INVALID_INDEX;
S32 mSkin = INVALID_INDEX;
std::string mName;
const Node& operator=(const tinygltf::Node& src);
const Node& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
// Set mRenderMatrix to a transform that can be used for the current render pass
// modelview -- parent's render matrix
void updateRenderTransforms(Asset& asset, const mat4& modelview);
// update mAssetMatrix and mAssetMatrixInv
void updateTransforms(Asset& asset, const mat4& parentMatrix);
// ensure mMatrix is valid -- if mMatrixValid is false and mTRSValid is true, will update mMatrix to match Translation/Rotation/Scale
void makeMatrixValid();
// ensure Translation/Rotation/Scale are valid -- if mTRSValid is false and mMatrixValid is true, will update Translation/Rotation/Scale to match mMatrix
void makeTRSValid();
// Set rotation of this node
// SIDE EFFECT: invalidates mMatrix
void setRotation(const quat& rotation);
// Set translation of this node
// SIDE EFFECT: invalidates mMatrix
void setTranslation(const vec3& translation);
// Set scale of this node
// SIDE EFFECT: invalidates mMatrix
void setScale(const vec3& scale);
};
class Skin
{
public:
S32 mInverseBindMatrices = INVALID_INDEX;
S32 mSkeleton = INVALID_INDEX;
std::vector<S32> mJoints;
std::string mName;
std::vector<mat4> mInverseBindMatricesData;
void allocateGLResources(Asset& asset);
void uploadMatrixPalette(Asset& asset, Node& node);
const Skin& operator=(const tinygltf::Skin& src);
const Skin& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class Scene
{
public:
std::vector<S32> mNodes;
std::string mName;
const Scene& operator=(const tinygltf::Scene& src);
const Scene& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
void updateTransforms(Asset& asset);
void updateRenderTransforms(Asset& asset, const mat4& modelview);
};
class Texture
{
public:
S32 mSampler = INVALID_INDEX;
S32 mSource = INVALID_INDEX;
std::string mName;
const Texture& operator=(const tinygltf::Texture& src);
const Texture& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class Sampler
{
public:
S32 mMagFilter = LINEAR;
S32 mMinFilter = LINEAR_MIPMAP_LINEAR;
S32 mWrapS = REPEAT;
S32 mWrapT = REPEAT;
std::string mName;
const Sampler& operator=(const tinygltf::Sampler& src);
const Sampler& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class Image
{
public:
std::string mName;
std::string mUri;
std::string mMimeType;
S32 mBufferView = INVALID_INDEX;
std::vector<U8> mData;
S32 mWidth = -1;
S32 mHeight = -1;
S32 mComponent = -1;
S32 mBits = -1;
S32 mPixelType = -1;
LLPointer<LLViewerFetchedTexture> mTexture;
const Image& operator=(const tinygltf::Image& src);
const Image& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
// save image clear local data, and set uri
void decompose(Asset& asset, const std::string& filename);
// erase the buffer view associated with this image
// free any associated resources
// preserve only uri and name
void clearData(Asset& asset);
void allocateGLResources();
};
// C++ representation of a GLTF Asset
class Asset
{
public:
static const std::string minVersion_default;
std::vector<Scene> mScenes;
std::vector<Node> mNodes;
std::vector<Mesh> mMeshes;
std::vector<Material> mMaterials;
std::vector<Buffer> mBuffers;
std::vector<BufferView> mBufferViews;
std::vector<Texture> mTextures;
std::vector<Sampler> mSamplers;
std::vector<Image> mImages;
std::vector<Accessor> mAccessors;
std::vector<Animation> mAnimations;
std::vector<Skin> mSkins;
std::string mVersion;
std::string mGenerator;
std::string mMinVersion;
std::string mCopyright;
S32 mDefaultScene = INVALID_INDEX;
Value mExtras;
U32 mPendingBuffers = 0;
// the last time update() was called according to gFrameTimeSeconds
F32 mLastUpdateTime = gFrameTimeSeconds;
// prepare the asset for rendering
void allocateGLResources(const std::string& filename = "", const tinygltf::Model& model = tinygltf::Model());
// Called periodically (typically once per frame)
// Any ongoing work (such as animations) should be handled here
// NOT guaranteed to be called every frame
// MAY be called more than once per frame
// Upon return, all Node Matrix transforms should be up to date
void update();
// update asset-to-node and node-to-asset transforms
void updateTransforms();
// update node render transforms
void updateRenderTransforms(const mat4& modelview);
void render(bool opaque, bool rigged = false);
void renderOpaque();
void renderTransparent();
// return the index of the node that the line segment intersects with, or -1 if no hit
// input and output values must be in this asset's local coordinate frame
S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
LLVector4a* intersection = nullptr, // return the intersection point
LLVector2* tex_coord = nullptr, // return the texture coordinates of the intersection point
LLVector4a* normal = nullptr, // return the surface normal at the intersection point
LLVector4a* tangent = nullptr, // return the surface tangent at the intersection point
S32* primitive_hitp = nullptr // return the index of the primitive that was hit
);
Asset() = default;
Asset(const tinygltf::Model& src);
Asset(const Value& src);
const Asset& operator=(const tinygltf::Model& src);
const Asset& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
// save the asset to a tinygltf model
void save(tinygltf::Model& dst);
// decompose the asset to the given .gltf file
void decompose(const std::string& filename);
// remove the bufferview at the given index
// updates all bufferview indices in this Asset as needed
void eraseBufferView(S32 bufferView);
};
Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode);
std::string enum_to_gltf_alpha_mode(Material::AlphaMode alpha_mode);
}
}