diff options
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/llcommon/llstrider.h | 2 | ||||
| -rw-r--r-- | indra/llmath/llvolumeoctree.h | 2 | ||||
| -rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 43 | ||||
| -rw-r--r-- | indra/llrender/llvertexbuffer.h | 8 | ||||
| -rw-r--r-- | indra/newview/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | indra/newview/gltf/accessor.cpp | 66 | ||||
| -rw-r--r-- | indra/newview/gltf/accessor.h | 95 | ||||
| -rw-r--r-- | indra/newview/gltf/animation.cpp | 287 | ||||
| -rw-r--r-- | indra/newview/gltf/animation.h | 181 | ||||
| -rw-r--r-- | indra/newview/gltf/asset.cpp | 375 | ||||
| -rw-r--r-- | indra/newview/gltf/asset.h | 295 | ||||
| -rw-r--r-- | indra/newview/gltf/buffer_util.h | 402 | ||||
| -rw-r--r-- | indra/newview/gltf/primitive.cpp | 488 | ||||
| -rw-r--r-- | indra/newview/gltf/primitive.h | 57 | ||||
| -rw-r--r-- | indra/newview/gltfscenemanager.cpp | 23 | ||||
| -rw-r--r-- | indra/newview/gltfscenemanager.h | 5 | ||||
| -rw-r--r-- | indra/newview/llappviewer.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/lldrawpoolalpha.cpp | 9 | ||||
| -rw-r--r-- | indra/newview/lldrawpoolpbropaque.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/pipeline.cpp | 4 | 
20 files changed, 1702 insertions, 647 deletions
| diff --git a/indra/llcommon/llstrider.h b/indra/llcommon/llstrider.h index ed9284d2c5..e7522484e6 100644 --- a/indra/llcommon/llstrider.h +++ b/indra/llcommon/llstrider.h @@ -37,8 +37,8 @@ template <class Object> class LLStrider  	};  	U32     mSkip;  public: -  	LLStrider()  { mObjectp = NULL; mSkip = sizeof(Object); }  +    LLStrider(Object* first) { mObjectp = first; mSkip = sizeof(Object); }  	~LLStrider() { }   	const LLStrider<Object>& operator =  (Object *first)    { mObjectp = first; return *this;} diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h index d6f536b9ca..0bbb793896 100644 --- a/indra/llmath/llvolumeoctree.h +++ b/indra/llmath/llvolumeoctree.h @@ -62,7 +62,7 @@ public:  	LL_ALIGN_16(LLVector4a mPositionGroup);  	const LLVector4a* mV[3]; -	U16 mIndex[3]; +	U32 mIndex[3];  	F32 mRadius;  	mutable S32 mBinIndex; diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index dda3c1532d..1d81c3778b 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -741,8 +741,8 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi      llassert(mGLBuffer == sGLRenderBuffer);      llassert(mGLIndices == sGLRenderIndices);      gGL.syncMatrices(); -    glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, -        (GLvoid*) (indices_offset * sizeof(U16))); +    glDrawRangeElements(sGLMode[mode], start, end, count, mIndicesType, +        (GLvoid*) (indices_offset * (size_t) mIndicesStride));  }  void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const @@ -1139,7 +1139,7 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)  }  // flush the given byte range -//  target -- "targret" parameter for glBufferSubData +//  target -- "target" parameter for glBufferSubData  //  start -- first byte to copy  //  end -- last byte to copy (NOT last byte + 1)  //  data -- mMappedData or mMappedIndexData @@ -1301,6 +1301,8 @@ bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, U32 index,  }  bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, U32 index, S32 count)  { +    llassert(mIndicesStride == 2); // cannot access 32-bit indices with U16 strider +    llassert(mIndicesType == GL_UNSIGNED_SHORT);  	return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count);  }  bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, U32 index, S32 count) @@ -1507,4 +1509,39 @@ void LLVertexBuffer::setColorData(const LLColor4U* data)      flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR], mOffsets[TYPE_COLOR] + sTypeSize[TYPE_COLOR] * getNumVerts() - 1, (U8*) data);  } +void LLVertexBuffer::setNormalData(const LLVector4a* data) +{ +    llassert(sGLRenderBuffer == mGLBuffer); +    flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_NORMAL], mOffsets[TYPE_NORMAL] + sTypeSize[TYPE_NORMAL] * getNumVerts() - 1, (U8*) data); +} + +void LLVertexBuffer::setTangentData(const LLVector4a* data) +{ +    llassert(sGLRenderBuffer == mGLBuffer); +    flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TANGENT], mOffsets[TYPE_TANGENT] + sTypeSize[TYPE_TANGENT] * getNumVerts() - 1, (U8*) data); +} + +void LLVertexBuffer::setWeight4Data(const LLVector4a* data) +{ +    llassert(sGLRenderBuffer == mGLBuffer); +    flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_WEIGHT4], mOffsets[TYPE_WEIGHT4] + sTypeSize[TYPE_WEIGHT4] * getNumVerts() - 1, (U8*) data); +} + +void LLVertexBuffer::setIndexData(const U16* data) +{ +    llassert(sGLRenderIndices == mGLIndices); +    flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U16) * getNumIndices() - 1, (U8*) data); +} + +void LLVertexBuffer::setIndexData(const U32* data) +{ +    llassert(sGLRenderIndices == mGLIndices); +    if (mIndicesType != GL_UNSIGNED_INT) +    { // HACK -- vertex buffers are initialized as 16-bit indices, but can be switched to 32-bit indices +        mIndicesType = GL_UNSIGNED_INT; +        mIndicesStride = 4; +        mNumIndices /= 2; +    } +    flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U32) * getNumIndices() - 1, (U8*)data); +} diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index cc59e322ed..669d89aabf 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -190,9 +190,13 @@ public:  	bool getClothWeightStrider(LLStrider<LLVector4>& strider, U32 index=0, S32 count = -1);      void setPositionData(const LLVector4a* data); +    void setNormalData(const LLVector4a* data); +    void setTangentData(const LLVector4a* data); +    void setWeight4Data(const LLVector4a* data);      void setTexCoordData(const LLVector2* data);      void setColorData(const LLColor4U* data); - +    void setIndexData(const U16* data); +    void setIndexData(const U32* data);  	U32 getNumVerts() const					{ return mNumVerts; }  	U32 getNumIndices() const				{ return mNumIndices; } @@ -224,6 +228,8 @@ protected:      U32		mGLIndices = 0;		// GL IBO handle      U32		mNumVerts = 0;		// Number of vertices allocated      U32		mNumIndices = 0;	// Number of indices allocated +    U32     mIndicesType = GL_UNSIGNED_SHORT; // type of indices in index buffer +    U32     mIndicesStride = 2;     // size of each index in bytes      U32		mOffsets[TYPE_MAX]; // byte offsets into mMappedData of each attribute      U8* mMappedData = nullptr;	// pointer to currently mapped data (NULL if unmapped) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ed617ba70e..b15ee235bd 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -76,7 +76,9 @@ endif (NOT HAVOK_TPV)  set(viewer_SOURCE_FILES      gltfscenemanager.cpp      gltf/asset.cpp +    gltf/accessor.cpp      gltf/primitive.cpp +    gltf/animation.cpp      groupchatlistener.cpp      llaccountingcostmanager.cpp      llaisapi.cpp @@ -733,7 +735,10 @@ set(viewer_HEADER_FILES      gltfscenemanager.h      groupchatlistener.h      gltf/asset.h +    gltf/accessor.h +    gltf/buffer_util.h      gltf/primitive.h +    gltf/animation.h      llaccountingcost.h      llaccountingcostmanager.h      llaisapi.h diff --git a/indra/newview/gltf/accessor.cpp b/indra/newview/gltf/accessor.cpp new file mode 100644 index 0000000000..55d36b7a32 --- /dev/null +++ b/indra/newview/gltf/accessor.cpp @@ -0,0 +1,66 @@ +/** + * @file accessor.cpp + * @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 "../llviewerprecompiledheaders.h" + +#include "asset.h" + +using namespace LL::GLTF; + +const Buffer& Buffer::operator=(const tinygltf::Buffer& src) +{ +    mData = src.data; +    mName = src.name; +    mUri = src.uri; +    return *this; +} + +const BufferView& BufferView::operator=(const tinygltf::BufferView& src) +{ +    mBuffer = src.buffer; +    mByteLength = src.byteLength; +    mByteOffset = src.byteOffset; +    mByteStride = src.byteStride; +    mTarget = src.target; +    mName = src.name; +    return *this; +} + +const Accessor& Accessor::operator=(const tinygltf::Accessor& src) +{ +    mBufferView = src.bufferView; +    mByteOffset = src.byteOffset; +    mComponentType = src.componentType; +    mCount = src.count; +    mType = src.type; +    mNormalized = src.normalized; +    mName = src.name; +    mMax = src.maxValues; +    mMin = src.minValues; + +    return *this; +} + diff --git a/indra/newview/gltf/accessor.h b/indra/newview/gltf/accessor.h new file mode 100644 index 0000000000..9b8265d8da --- /dev/null +++ b/indra/newview/gltf/accessor.h @@ -0,0 +1,95 @@ +#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 "../lltinygltfhelper.h" +#include "llstrider.h" + +// LL GLTF Implementation +namespace LL +{ +    namespace GLTF +    { +        class Asset; + +        constexpr S32 INVALID_INDEX = -1; + +        class Buffer +        { +        public: +            std::vector<U8> mData; +            std::string mName; +            std::string mUri; + +            const Buffer& operator=(const tinygltf::Buffer& src); +        }; + +        class BufferView +        { +        public: +            S32 mBuffer = INVALID_INDEX; +            S32 mByteLength; +            S32 mByteOffset; +            S32 mByteStride; +            S32 mTarget; +            S32 mComponentType; + +            std::string mName; + +            const BufferView& operator=(const tinygltf::BufferView& src); +             +        }; +         +        class Accessor +        { +        public: +            S32 mBufferView = INVALID_INDEX; +            S32 mByteOffset; +            S32 mComponentType; +            S32 mCount; +            std::vector<double> mMax; +            std::vector<double> mMin; + +            enum class Type : S32 +            { +                SCALAR = TINYGLTF_TYPE_SCALAR, +                VEC2 = TINYGLTF_TYPE_VEC2, +                VEC3 = TINYGLTF_TYPE_VEC3, +                VEC4 = TINYGLTF_TYPE_VEC4, +                MAT2 = TINYGLTF_TYPE_MAT2, +                MAT3 = TINYGLTF_TYPE_MAT3, +                MAT4 = TINYGLTF_TYPE_MAT4 +            }; + +            S32 mType; +            bool mNormalized; +            std::string mName; + +            const Accessor& operator=(const tinygltf::Accessor& src); +        }; +    } +} diff --git a/indra/newview/gltf/animation.cpp b/indra/newview/gltf/animation.cpp new file mode 100644 index 0000000000..da6d02b356 --- /dev/null +++ b/indra/newview/gltf/animation.cpp @@ -0,0 +1,287 @@ +/** + * @file animation.cpp + * @brief LL GLTF Animation 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 "../llviewerprecompiledheaders.h" + +#include "asset.h" +#include "buffer_util.h" + +using namespace LL::GLTF; + +void Animation::allocateGLResources(Asset& asset) +{ +    if (!mSamplers.empty()) +    { +        mMinTime = FLT_MAX; +        mMaxTime = -FLT_MAX; +        for (auto& sampler : mSamplers) +        { +            sampler.allocateGLResources(asset); +            mMinTime = llmin(sampler.mMinTime, mMinTime); +            mMaxTime = llmax(sampler.mMaxTime, mMaxTime); +        } +    } +    else +    { +        mMinTime = mMaxTime = 0.f; +    } + +    for (auto& channel : mRotationChannels) +    { +        channel.allocateGLResources(asset, mSamplers[channel.mSampler]); +    } + +    for (auto& channel : mTranslationChannels) +    { +        channel.allocateGLResources(asset, mSamplers[channel.mSampler]); +    } +} + +void Animation::update(Asset& asset, F32 dt) +{ +    mTime += dt; + +    apply(asset, mTime); +} + +void Animation::apply(Asset& asset, float time) +{ +    // convert time to animation loop time +    time = fmod(time, mMaxTime - mMinTime) + mMinTime; + +    // apply each channel +    for (auto& channel : mRotationChannels) +    { +        channel.apply(asset, mSamplers[channel.mSampler], time); +    } + +    for (auto& channel : mTranslationChannels) +    { +        channel.apply(asset, mSamplers[channel.mSampler], time); +    } +}; + + +void Animation::Sampler::allocateGLResources(Asset& asset) +{ +    Accessor& accessor = asset.mAccessors[mInput]; +    mMinTime = accessor.mMin[0]; +    mMaxTime = accessor.mMax[0]; + +    mFrameTimes.resize(accessor.mCount); + +    LLStrider<F32> frame_times = mFrameTimes.data(); +    copy(asset, accessor, frame_times); +} + +void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F32& t) +{ +    if (time < mMinTime) +    { +        frameIndex = 0; +        t = 0.0f; +        return; +    } + +    if (mFrameTimes.size() > 1) +    { +        if (time > mMaxTime) +        { +            frameIndex = mFrameTimes.size() - 2; +            t = 1.0f; +            return; +        } + +        frameIndex = mFrameTimes.size() - 2; +        t = 1.f; + +        for (U32 i = 0; i < mFrameTimes.size() - 1; i++) +        { +            if (time >= mFrameTimes[i] && time < mFrameTimes[i + 1]) +            { +                frameIndex = i; +                t = (time - mFrameTimes[i]) / (mFrameTimes[i + 1] - mFrameTimes[i]); +                return; +            } +        } +    } +    else +    { +        frameIndex = 0; +        t = 0.0f; +    } +} + +void Animation::RotationChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler) +{ +    Accessor& accessor = asset.mAccessors[sampler.mOutput]; + +    copy(asset, accessor, mRotations); +} + +void Animation::RotationChannel::apply(Asset& asset, Sampler& sampler, F32 time) +{ +    U32 frameIndex; +    F32 t; + +    Node& node = asset.mNodes[mTarget.mNode]; + +    sampler.getFrameInfo(asset, time, frameIndex, t); + +    if (sampler.mFrameTimes.size() == 1) +    { +        node.setRotation(mRotations[0]); +    } +    else +    { +        // interpolate +        LLQuaternion q0(mRotations[frameIndex].get_value()); +        LLQuaternion q1(mRotations[frameIndex + 1].get_value()); + +        LLQuaternion qf = slerp(t, q0, q1); + +        qf.normalize(); +        node.setRotation(glh::quaternionf(qf.mQ)); +    } +} + +void Animation::TranslationChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler) +{ +    Accessor& accessor = asset.mAccessors[sampler.mOutput]; + +    copy(asset, accessor, mTranslations); +} + +void Animation::TranslationChannel::apply(Asset& asset, Sampler& sampler, F32 time) +{ +    U32 frameIndex; +    F32 t; + +    Node& node = asset.mNodes[mTarget.mNode]; + +    sampler.getFrameInfo(asset, time, frameIndex, t); + +    if (sampler.mFrameTimes.size() == 1) +    { +        node.setTranslation(mTranslations[0]); +    } +    else +    { +        // interpolate +        const glh::vec3f& v0 = mTranslations[frameIndex]; +        const glh::vec3f& v1 = mTranslations[frameIndex + 1]; + +        glh::vec3f vf = v0 + t * (v1 - v0); + +        node.setTranslation(vf); +    } +} + +void Animation::ScaleChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler) +{ +    Accessor& accessor = asset.mAccessors[sampler.mOutput]; + +    copy(asset, accessor, mScales); +} + +void Animation::ScaleChannel::apply(Asset& asset, Sampler& sampler, F32 time) +{ +    U32 frameIndex; +    F32 t; + +    Node& node = asset.mNodes[mTarget.mNode]; + +    sampler.getFrameInfo(asset, time, frameIndex, t); + +    if (sampler.mFrameTimes.size() == 1) +    { +        node.setScale(mScales[0]); +    } +    else +    { +        // interpolate +        const glh::vec3f& v0 = mScales[frameIndex]; +        const glh::vec3f& v1 = mScales[frameIndex + 1]; + +        glh::vec3f vf = v0 + t * (v1 - v0); + +        node.setScale(vf); +    } +} + +const Animation& Animation::operator=(const tinygltf::Animation& src) +{ +    mName = src.name; + +    mSamplers.resize(src.samplers.size()); +    for (U32 i = 0; i < src.samplers.size(); ++i) +    { +        mSamplers[i] = src.samplers[i]; +    } + +    for (U32 i = 0; i < src.channels.size(); ++i) +    { +        if (src.channels[i].target_path == "rotation") +        { +            mRotationChannels.push_back(RotationChannel()); +            mRotationChannels.back() = src.channels[i]; +        } + +        if (src.channels[i].target_path == "translation") +        { +            mTranslationChannels.push_back(TranslationChannel()); +            mTranslationChannels.back() = src.channels[i]; +        } + +        if (src.channels[i].target_path == "scale") +        { +            mScaleChannels.push_back(ScaleChannel()); +            mScaleChannels.back() = src.channels[i]; +        } +    } + +    return *this; +} + +void Skin::allocateGLResources(Asset& asset) +{ +    if (mInverseBindMatrices != INVALID_INDEX) +    { +        Accessor& accessor = asset.mAccessors[mInverseBindMatrices]; +        copy(asset, accessor, mInverseBindMatricesData); +    } +} + +const Skin& Skin::operator=(const tinygltf::Skin& src) +{ +    mName = src.name; +    mSkeleton = src.skeleton; +    mInverseBindMatrices = src.inverseBindMatrices; +    mJoints = src.joints; + +    return *this; +} + diff --git a/indra/newview/gltf/animation.h b/indra/newview/gltf/animation.h new file mode 100644 index 0000000000..869eae963a --- /dev/null +++ b/indra/newview/gltf/animation.h @@ -0,0 +1,181 @@ +#pragma once + +/** + * @file animation.h + * @brief LL GLTF Animation 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 "accessor.h" + +// LL GLTF Implementation +namespace LL +{ +    namespace GLTF +    { +        class Asset; + +        class Animation +        { +        public: +            class Sampler +            { +            public: +                std::vector<F32> mFrameTimes; + +                F32 mMinTime = -FLT_MAX; +                F32 mMaxTime = FLT_MAX; + +                S32 mInput = INVALID_INDEX; +                S32 mOutput = INVALID_INDEX; +                std::string mInterpolation; + +                void allocateGLResources(Asset& asset); + +                const Sampler& operator=(const tinygltf::AnimationSampler& src) +                { +                    mInput = src.input; +                    mOutput = src.output; +                    mInterpolation = src.interpolation; + +                    return *this; +                } + +                // get the frame index and time for the specified time +                // asset -- the asset to reference for Accessors +                // time -- the animation time to get the frame info for +                // frameIndex -- index of the closest frame that precedes the specified time +                // t - interpolant value between the frameIndex and the next frame +                void getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F32& t); +            }; + +            class Channel +            { +            public: +                class Target +                { +                public: +                    S32 mNode = INVALID_INDEX; +                    std::string mPath; +                }; + +                S32 mSampler = INVALID_INDEX; +                Target mTarget; +                std::string mTargetPath; +                std::string mName; + +                const Channel& operator=(const tinygltf::AnimationChannel& src) +                { +                    mSampler = src.sampler; + +                    mTarget.mNode = src.target_node; +                    mTarget.mPath = src.target_path; + +                    return *this; +                } + +            }; + +            class RotationChannel : public Channel +            { +            public: +                std::vector<glh::quaternionf> mRotations; + +                const RotationChannel& operator=(const tinygltf::AnimationChannel& src) +                { +                    Channel::operator=(src); +                    return *this; +                } + +                // prepare data needed for rendering +                // asset -- asset to reference for Accessors +                // sampler -- Sampler associated with this channel +                void allocateGLResources(Asset& asset, Sampler& sampler); + +                void apply(Asset& asset, Sampler& sampler, F32 time); +            }; + +            class TranslationChannel : public Channel +            { +            public: +                std::vector<glh::vec3f> mTranslations; + +                const TranslationChannel& operator=(const tinygltf::AnimationChannel& src) +                { +                    Channel::operator=(src); +                    return *this; +                } + +                // prepare data needed for rendering +                // asset -- asset to reference for Accessors +                // sampler -- Sampler associated with this channel +                void allocateGLResources(Asset& asset, Sampler& sampler); + +                void apply(Asset& asset, Sampler& sampler, F32 time); +            }; + +            class ScaleChannel : public Channel +            { +            public: +                std::vector<glh::vec3f> mScales; + +                const ScaleChannel& operator=(const tinygltf::AnimationChannel& src) +                { +                    Channel::operator=(src); +                    return *this; +                } + +                // prepare data needed for rendering +                // asset -- asset to reference for Accessors +                // sampler -- Sampler associated with this channel +                void allocateGLResources(Asset& asset, Sampler& sampler); + +                void apply(Asset& asset, Sampler& sampler, F32 time); +            }; + +            std::string mName; +            std::vector<Sampler> mSamplers; + +            // min/max time values for all samplers combined +            F32 mMinTime = 0.f; +            F32 mMaxTime = 0.f; +             +            // current time of the animation +            F32 mTime = 0.f; + +            std::vector<RotationChannel> mRotationChannels; +            std::vector<TranslationChannel> mTranslationChannels; +            std::vector<ScaleChannel> mScaleChannels; + +            const Animation& operator=(const tinygltf::Animation& src); +             +            void allocateGLResources(Asset& asset); + +            void update(Asset& asset, float dt); + +            // apply this animation at the specified time +            void apply(Asset& asset, F32 time); +        }; + +    } +} diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 7181c5fa53..313e82bf01 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -28,6 +28,8 @@  #include "asset.h"  #include "llvolumeoctree.h" +#include "../llviewershadermgr.h" +#include "../llviewercontrol.h"  using namespace LL::GLTF; @@ -66,6 +68,7 @@ LLMatrix4a inverse(const LLMatrix4a& mat);  void Node::updateTransforms(Asset& asset, const LLMatrix4a& parentMatrix)  { +    makeMatrixValid();      matMul(mMatrix, parentMatrix, mAssetMatrix);      mAssetMatrixInv = inverse(mAssetMatrix); @@ -99,7 +102,7 @@ void Asset::updateRenderTransforms(const LLMatrix4a& modelview)      // use mAssetMatrix to update render transforms from node list      for (auto& node : mNodes)      { -        if (node.mMesh != INVALID_INDEX) +        //if (node.mMesh != INVALID_INDEX)          {              matMul(node.mAssetMatrix, modelview, node.mRenderMatrix);          } @@ -211,6 +214,67 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,      return node_hit;  } + +void Node::makeMatrixValid() +{ +    if (!mMatrixValid && mTRSValid) +    { +        glh::matrix4f rot; +        mRotation.get_value(rot); + +        glh::matrix4f trans; +        trans.set_translate(mTranslation); + +        glh::matrix4f sc; +        sc.set_scale(mScale); + +        glh::matrix4f t; +        //t = sc * rot * trans;  +        //t = trans * rot * sc; // best so far, still wrong on negative scale +        //t = sc * trans * rot; +        t = trans * sc * rot; + +        mMatrix.loadu(t.m); +        mMatrixValid = true; +    } +} + +void Node::makeTRSValid() +{ +    if (!mTRSValid && mMatrixValid) +    { +        glh::matrix4f t(mMatrix.getF32ptr()); + +        glh::vec4f p = t.get_column(3); +        mTranslation.set_value(p.v[0], p.v[1], p.v[2]); + +        mScale.set_value(t.get_column(0).length(), t.get_column(1).length(), t.get_column(2).length()); +        mRotation.set_value(t); +        mTRSValid = true; +    } +} + +void Node::setRotation(const glh::quaternionf& q) +{ +    makeTRSValid(); +    mRotation = q; +    mMatrixValid = false; +} + +void Node::setTranslation(const glh::vec3f& t) +{ +    makeTRSValid(); +    mTranslation = t; +    mMatrixValid = false; +} + +void Node::setScale(const glh::vec3f& s) +{ +    makeTRSValid(); +    mScale = s; +    mMatrixValid = false; +} +  const Node& Node::operator=(const tinygltf::Node& src)  {      F32* dstMatrix = mMatrix.getF32ptr(); @@ -222,48 +286,33 @@ const Node& Node::operator=(const tinygltf::Node& src)          {              dstMatrix[i] = (F32)src.matrix[i];          } + +        mMatrixValid = true;      }      else if (!src.rotation.empty() || !src.translation.empty() || !src.scale.empty())      {          // node has rotation/translation/scale, convert to matrix -        glh::quaternionf rotation;          if (src.rotation.size() == 4)          { -            rotation = glh::quaternionf((F32)src.rotation[0], (F32)src.rotation[1], (F32)src.rotation[2], (F32)src.rotation[3]); +            mRotation = glh::quaternionf((F32)src.rotation[0], (F32)src.rotation[1], (F32)src.rotation[2], (F32)src.rotation[3]);          } -        glh::vec3f translation;          if (src.translation.size() == 3)          { -            translation = glh::vec3f((F32)src.translation[0], (F32)src.translation[1], (F32)src.translation[2]); +            mTranslation = glh::vec3f((F32)src.translation[0], (F32)src.translation[1], (F32)src.translation[2]);          }          glh::vec3f scale;          if (src.scale.size() == 3)          { -            scale = glh::vec3f((F32)src.scale[0], (F32)src.scale[1], (F32)src.scale[2]); +            mScale = glh::vec3f((F32)src.scale[0], (F32)src.scale[1], (F32)src.scale[2]);          }          else          { -            scale.set_value(1.f, 1.f, 1.f); +            mScale.set_value(1.f, 1.f, 1.f);          } -        glh::matrix4f rot; -        rotation.get_value(rot); - -        glh::matrix4f trans; -        trans.set_translate(translation); - -        glh::matrix4f sc; -        sc.set_scale(scale); - -        glh::matrix4f t; -        //t = sc * rot * trans;  -        //t = trans * rot * sc; // best so far, still wrong on negative scale -        //t = sc * trans * rot; -        t = trans * sc * rot; - -        mMatrix.loadu(t.m); +        mTRSValid = true;      }      else      { @@ -273,21 +322,50 @@ const Node& Node::operator=(const tinygltf::Node& src)      mChildren = src.children;      mMesh = src.mesh; +    mSkin = src.skin;      mName = src.name;      return *this;  } -void Asset::render(bool opaque) +void Asset::render(bool opaque, bool rigged)  { +    if (rigged) +    { +        gGL.loadIdentity(); +    } +      for (auto& node : mNodes)      { +        if (node.mSkin != INVALID_INDEX) +        { +            if (rigged) +            { +                Skin& skin = mSkins[node.mSkin]; +                skin.uploadMatrixPalette(*this, node); +            } +            else +            { +                //skip static nodes if we're rendering rigged +                continue; +            } +        } +        else if (rigged) +        { +            // skip rigged nodes if we're not rendering rigged +            continue; +        } + +          if (node.mMesh != INVALID_INDEX)          {              Mesh& mesh = mMeshes[node.mMesh];              for (auto& primitive : mesh.mPrimitives)              { -                gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix); +                if (!rigged) +                { +                    gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix); +                }                  bool cull = true;                  if (primitive.mMaterial != INVALID_INDEX)                  { @@ -336,4 +414,251 @@ void Asset::renderTransparent()      render(false);  } +void Asset::update() +{ +    F32 dt = gFrameTimeSeconds - mLastUpdateTime; + +    if (dt > 0.f) +    { +        mLastUpdateTime = gFrameTimeSeconds; +        if (mAnimations.size() > 0) +        { +            static LLCachedControl<U32> anim_idx(gSavedSettings, "GLTFAnimationIndex", 0); +            static LLCachedControl<F32> anim_speed(gSavedSettings, "GLTFAnimationSpeed", 1.f); + +            U32 idx = llclamp(anim_idx(), 0U, mAnimations.size() - 1); +            mAnimations[idx].update(*this, dt*anim_speed); +        } + +        updateTransforms(); +    } +} + +void Asset::allocateGLResources(const std::string& filename, const tinygltf::Model& model) +{ +    // do images first as materials may depend on images +    for (auto& image : mImages) +    { +        image.allocateGLResources(); +    } + +    // do materials before meshes as meshes may depend on materials +    for (U32 i = 0; i < mMaterials.size(); ++i) +    { +        mMaterials[i].allocateGLResources(*this); +        LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true); +    } + +    for (auto& mesh : mMeshes) +    { +        mesh.allocateGLResources(*this); +    } + +    for (auto& animation : mAnimations) +    { +        animation.allocateGLResources(*this); +    } + +    for (auto& skin : mSkins) +    { +        skin.allocateGLResources(*this); +    } +} + +const Asset& Asset::operator=(const tinygltf::Model& src) +{ +    mScenes.resize(src.scenes.size()); +    for (U32 i = 0; i < src.scenes.size(); ++i) +    { +        mScenes[i] = src.scenes[i]; +    } + +    mNodes.resize(src.nodes.size()); +    for (U32 i = 0; i < src.nodes.size(); ++i) +    { +        mNodes[i] = src.nodes[i]; +    } + +    mMeshes.resize(src.meshes.size()); +    for (U32 i = 0; i < src.meshes.size(); ++i) +    { +        mMeshes[i] = src.meshes[i]; +    } + +    mMaterials.resize(src.materials.size()); +    for (U32 i = 0; i < src.materials.size(); ++i) +    { +        mMaterials[i] = src.materials[i]; +    } + +    mBuffers.resize(src.buffers.size()); +    for (U32 i = 0; i < src.buffers.size(); ++i) +    { +        mBuffers[i] = src.buffers[i]; +    } + +    mBufferViews.resize(src.bufferViews.size()); +    for (U32 i = 0; i < src.bufferViews.size(); ++i) +    { +        mBufferViews[i] = src.bufferViews[i]; +    } + +    mTextures.resize(src.textures.size()); +    for (U32 i = 0; i < src.textures.size(); ++i) +    { +        mTextures[i] = src.textures[i]; +    } + +    mSamplers.resize(src.samplers.size()); +    for (U32 i = 0; i < src.samplers.size(); ++i) +    { +        mSamplers[i] = src.samplers[i]; +    } + +    mImages.resize(src.images.size()); +    for (U32 i = 0; i < src.images.size(); ++i) +    { +        mImages[i] = src.images[i]; +    } + +    mAccessors.resize(src.accessors.size()); +    for (U32 i = 0; i < src.accessors.size(); ++i) +    { +        mAccessors[i] = src.accessors[i]; +    } + +    mAnimations.resize(src.animations.size()); +    for (U32 i = 0; i < src.animations.size(); ++i) +    { +        mAnimations[i] = src.animations[i]; +    } + +    mSkins.resize(src.skins.size()); +    for (U32 i = 0; i < src.skins.size(); ++i) +    { +        mSkins[i] = src.skins[i]; +    } +  +    return *this; +} + +const Material& Material::operator=(const tinygltf::Material& src) +{ +    mName = src.name; +    return *this; +} + +void Material::allocateGLResources(Asset& asset) +{ +    // allocate material +    mMaterial = new LLFetchedGLTFMaterial(); +} + +const Mesh& Mesh::operator=(const tinygltf::Mesh& src) +{ +    mPrimitives.resize(src.primitives.size()); +    for (U32 i = 0; i < src.primitives.size(); ++i) +    { +        mPrimitives[i] = src.primitives[i]; +    } + +    mWeights = src.weights; +    mName = src.name; + +    return *this; +} + +void Mesh::allocateGLResources(Asset& asset) +{ +    for (auto& primitive : mPrimitives) +    { +        primitive.allocateGLResources(asset); +    } +} + +const Scene& Scene::operator=(const tinygltf::Scene& src) +{ +    mNodes = src.nodes; +    mName = src.name; + +    return *this; +} + +const Texture& Texture::operator=(const tinygltf::Texture& src) +{ +    mSampler = src.sampler; +    mSource = src.source; +    mName = src.name; + +    return *this; +} + +const Sampler& Sampler::operator=(const tinygltf::Sampler& src) +{ +    mMagFilter = src.magFilter; +    mMinFilter = src.minFilter; +    mWrapS = src.wrapS; +    mWrapT = src.wrapT; +    mName = src.name; + +    return *this; +} + +void Skin::uploadMatrixPalette(Asset& asset, Node& node) +{ +    // prepare matrix palette + +    // modelview will be applied by the shader, so assume matrix palette is in asset space +    std::vector<glh::matrix4f> t_mp; + +    t_mp.resize(mJoints.size()); + +    for (U32 i = 0; i < mJoints.size(); ++i) +    { +        Node& joint = asset.mNodes[mJoints[i]]; +         +        //t_mp[i].set_value(joint.mRenderMatrix.getF32ptr()); +        //t_mp[i] = t_mp[i] * mInverseBindMatricesData[i]; + +        //t_mp[i].set_value(joint.mRenderMatrix.getF32ptr()); +        //t_mp[i] = mInverseBindMatricesData[i] * t_mp[i]; + +        t_mp[i].set_value(joint.mRenderMatrix.getF32ptr()); +        t_mp[i] = t_mp[i] * mInverseBindMatricesData[i]; + +    } + +    std::vector<F32> glmp; + +    glmp.resize(mJoints.size() * 12); + +    F32* mp = glmp.data(); + +    for (U32 i = 0; i < mJoints.size(); ++i) +    { +        F32* m = (F32*)t_mp[i].m; + +        U32 idx = i * 12; + +        mp[idx + 0] = m[0]; +        mp[idx + 1] = m[1]; +        mp[idx + 2] = m[2]; +        mp[idx + 3] = m[12]; + +        mp[idx + 4] = m[4]; +        mp[idx + 5] = m[5]; +        mp[idx + 6] = m[6]; +        mp[idx + 7] = m[13]; + +        mp[idx + 8] = m[8]; +        mp[idx + 9] = m[9]; +        mp[idx + 10] = m[10]; +        mp[idx + 11] = m[14]; +    } + +    LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, +        mJoints.size(), +        FALSE, +        (GLfloat*)glmp.data()); +} diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h index acf9ba77df..6e576a1ffe 100644 --- a/indra/newview/gltf/asset.h +++ b/indra/newview/gltf/asset.h @@ -29,86 +29,19 @@  #include "llvertexbuffer.h"  #include "llvolumeoctree.h"  #include "../lltinygltfhelper.h" +#include "accessor.h"  #include "primitive.h" +#include "animation.h" + +extern F32SecondsImplicit		gFrameTimeSeconds;  // LL GLTF Implementation  namespace LL  {      namespace GLTF      { -        constexpr S32 INVALID_INDEX = -1; -          class Asset; -        class Buffer -        { -        public: -            std::vector<U8> mData; -            std::string mName; -            std::string mUri; - -            const Buffer& operator=(const tinygltf::Buffer& src) -            { -                mData = src.data; -                mName = src.name; -                mUri = src.uri; -                return *this; -            } -        }; - -        class BufferView -        { -        public: -            S32 mBuffer = INVALID_INDEX; -            S32 mByteLength; -            S32 mByteOffset; -            S32 mByteStride; -            S32 mTarget; -            S32 mComponentType; - -            std::string mName; - -            const BufferView& operator=(const tinygltf::BufferView& src) -            { -                mBuffer = src.buffer; -                mByteLength = src.byteLength; -                mByteOffset = src.byteOffset; -                mByteStride = src.byteStride; -                mTarget = src.target; -                mName = src.name; -                return *this; -            } -        }; - -        class Accessor -        { -        public: -            S32 mBufferView = INVALID_INDEX; -            S32 mByteOffset; -            S32 mComponentType; -            S32 mCount; -            std::vector<double> mMax; -            std::vector<double> mMin; -            S32 mType; -            bool mNormalized; -            std::string mName; - -            const Accessor& operator=(const tinygltf::Accessor& src) -            { -                mBufferView = src.bufferView; -                mByteOffset = src.byteOffset; -                mComponentType = src.componentType; -                mCount = src.count; -                mType = src.type; -                mNormalized = src.normalized; -                mName = src.name; -                mMax = src.maxValues; -                mMin = src.maxValues; - -                return *this; -            } -        }; -          class Material          {          public: @@ -118,17 +51,9 @@ namespace LL              LLPointer<LLFetchedGLTFMaterial> mMaterial;              std::string mName; -            const Material& operator=(const tinygltf::Material& src) -            { -                mName = src.name; -                return *this; -            } - -            void allocateGLResources(Asset& asset) -            { -                // allocate material -                mMaterial = new LLFetchedGLTFMaterial(); -            } +            const Material& operator=(const tinygltf::Material& src); +             +            void allocateGLResources(Asset& asset);          };          class Mesh @@ -138,28 +63,9 @@ namespace LL              std::vector<double> mWeights;              std::string mName; -            const Mesh& operator=(const tinygltf::Mesh& src) -            { -                mPrimitives.resize(src.primitives.size()); -                for (U32 i = 0; i < src.primitives.size(); ++i) -                { -                    mPrimitives[i] = src.primitives[i]; -                } - -                mWeights = src.weights; -                mName = src.name; - -                return *this; -            } - -            void allocateGLResources(Asset& asset) -            { -                for (auto& primitive : mPrimitives) -                { -                    primitive.allocateGLResources(asset); -                } -            } - +            const Mesh& operator=(const tinygltf::Mesh& src); +             +            void allocateGLResources(Asset& asset);          };          class Node @@ -170,10 +76,24 @@ namespace LL              LLMatrix4a mAssetMatrix; //transform from local to asset space              LLMatrix4a mAssetMatrixInv; //transform from asset to local space +            glh::vec3f mTranslation; +            glh::quaternionf mRotation; +            glh::vec3f mScale; + +            // 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); @@ -184,26 +104,51 @@ namespace LL              // update mAssetMatrix and mAssetMatrixInv              void updateTransforms(Asset& asset, const LLMatrix4a& 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 glh::quaternionf& rotation); + +            // Set translation of this node +            // SIDE EFFECT: invalidates mMatrix +            void setTranslation(const glh::vec3f& translation); + +            // Set scale of this node +            // SIDE EFFECT: invalidates mMatrix +            void setScale(const glh::vec3f& scale);          }; -        class Scene +        class Skin          {          public: -            std::vector<S32> mNodes; +            S32 mInverseBindMatrices = INVALID_INDEX; +            S32 mSkeleton = INVALID_INDEX; +            std::vector<S32> mJoints;              std::string mName; +            std::vector<glh::matrix4f> mInverseBindMatricesData; -            const Scene& operator=(const tinygltf::Scene& src) -            { -                mNodes = src.nodes; -                mName = src.name; +            void allocateGLResources(Asset& asset); +            void uploadMatrixPalette(Asset& asset, Node& node); -                return *this; -            } +            const Skin& operator=(const tinygltf::Skin& src); +        }; + +        class Scene +        { +        public: +            std::vector<S32> mNodes; +            std::string mName; +            const Scene& operator=(const tinygltf::Scene& src); +                          void updateTransforms(Asset& asset);              void updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview); -                      };          class Texture @@ -213,14 +158,7 @@ namespace LL              S32 mSource = INVALID_INDEX;              std::string mName; -            const Texture& operator=(const tinygltf::Texture& src) -            { -                mSampler = src.sampler; -                mSource = src.source; -                mName = src.name; - -                return *this; -            } +            const Texture& operator=(const tinygltf::Texture& src);          };          class Sampler @@ -232,16 +170,7 @@ namespace LL              S32 mWrapT;              std::string mName; -            const Sampler& operator=(const tinygltf::Sampler& src) -            { -                mMagFilter = src.magFilter; -                mMinFilter = src.minFilter; -                mWrapS = src.wrapS; -                mWrapT = src.wrapT; -                mName = src.name; - -                return *this; -            } +            const Sampler& operator=(const tinygltf::Sampler& src);          };          class Image @@ -292,27 +221,21 @@ namespace LL              std::vector<Sampler> mSamplers;              std::vector<Image> mImages;              std::vector<Accessor> mAccessors; +            std::vector<Animation> mAnimations; +            std::vector<Skin> mSkins; -            void allocateGLResources(const std::string& filename, const tinygltf::Model& model) -            { -                // do images first as materials may depend on images -                for (auto& image : mImages) -                { -                    image.allocateGLResources(); -                } - -                // do materials before meshes as meshes may depend on materials -                for (U32 i = 0; i < mMaterials.size(); ++i) -                { -                    mMaterials[i].allocateGLResources(*this); -                    LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true); -                } - -                for (auto& mesh : mMeshes) -                { -                    mesh.allocateGLResources(*this); -                } -            } +            // 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); +             +            // 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(); @@ -320,7 +243,7 @@ namespace LL              // update node render transforms              void updateRenderTransforms(const LLMatrix4a& modelview); -            void render(bool opaque); +            void render(bool opaque, bool rigged = false);              void renderOpaque();              void renderTransparent(); @@ -334,70 +257,8 @@ namespace LL                  S32* primitive_hitp = nullptr           // return the index of the primitive that was hit              ); -            const Asset& operator=(const tinygltf::Model& src) -            { -                mScenes.resize(src.scenes.size()); -                for (U32 i = 0; i < src.scenes.size(); ++i) -                { -                    mScenes[i] = src.scenes[i]; -                } - -                mNodes.resize(src.nodes.size()); -                for (U32 i = 0; i < src.nodes.size(); ++i) -                { -                    mNodes[i] = src.nodes[i]; -                } - -                mMeshes.resize(src.meshes.size()); -                for (U32 i = 0; i < src.meshes.size(); ++i) -                { -                    mMeshes[i] = src.meshes[i]; -                } - -                mMaterials.resize(src.materials.size()); -                for (U32 i = 0; i < src.materials.size(); ++i) -                { -                    mMaterials[i] = src.materials[i]; -                } - -                mBuffers.resize(src.buffers.size()); -                for (U32 i = 0; i < src.buffers.size(); ++i) -                { -                    mBuffers[i] = src.buffers[i]; -                } - -                mBufferViews.resize(src.bufferViews.size()); -                for (U32 i = 0; i < src.bufferViews.size(); ++i) -                { -                    mBufferViews[i] = src.bufferViews[i]; -                } - -                mTextures.resize(src.textures.size()); -                for (U32 i = 0; i < src.textures.size(); ++i) -                { -                    mTextures[i] = src.textures[i]; -                } - -                mSamplers.resize(src.samplers.size()); -                for (U32 i = 0; i < src.samplers.size(); ++i) -                { -                    mSamplers[i] = src.samplers[i]; -                } - -                mImages.resize(src.images.size()); -                for (U32 i = 0; i < src.images.size(); ++i) -                { -                    mImages[i] = src.images[i]; -                } - -                mAccessors.resize(src.accessors.size()); -                for (U32 i = 0; i < src.accessors.size(); ++i) -                { -                    mAccessors[i] = src.accessors[i]; -                } - -                return *this; -            } +            const Asset& operator=(const tinygltf::Model& src); +                      };      }  } diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h new file mode 100644 index 0000000000..4e6f5901e7 --- /dev/null +++ b/indra/newview/gltf/buffer_util.h @@ -0,0 +1,402 @@ +#pragma once + +/** + * @file buffer_util.inl + * @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$ + */ + +// inline template implementations for copying data out of GLTF buffers +// DO NOT include from header files to avoid the need to rebuild the whole project +// whenever we add support for more types + +#ifdef _MSC_VER +#define LL_FUNCSIG __FUNCSIG__  +#else +#define LL_FUNCSIG __PRETTY_FUNCTION__ +#endif + +namespace LL +{ +    namespace GLTF +    { +        // copy one Scalar from src to dst +        template<class S, class T> +        static void copyScalar(S* src, T& dst) +        { +            LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; +        } + +        // copy one vec2 from src to dst +        template<class S, class T> +        static void copyVec2(S* src, T& dst) +        { +            LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; +        } + +        // copy one vec3 from src to dst +        template<class S, class T> +        static void copyVec3(S* src, T& dst) +        { +            LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; +        } + +        // copy one vec4 from src to dst +        template<class S, class T> +        static void copyVec4(S* src, T& dst) +        { +            LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; +        } + +        // copy one vec2 from src to dst +        template<class S, class T> +        static void copyMat2(S* src, T& dst) +        { +            LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; +        } + +        // copy one vec3 from src to dst +        template<class S, class T> +        static void copyMat3(S* src, T& dst) +        { +            LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; +        } + +        // copy one vec4 from src to dst +        template<class S, class T> +        static void copyMat4(S* src, T& dst) +        { +            LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; +        } + +        //========================================================================================================= +        // concrete implementations for different types of source and destination +        //========================================================================================================= + +// suppress unused function warning -- clang complains here but these specializations are definitely used +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + +        template<> +        void copyScalar<F32, F32>(F32* src, F32& dst) +        { +            dst = *src; +        } + +        template<> +        void copyScalar<U32, U32>(U32* src, U32& dst) +        { +            dst = *src; +        } + +        template<> +        void copyScalar<U32, U16>(U32* src, U16& dst) +        { +            dst = *src; +        } + +        template<> +        void copyScalar<U16, U16>(U16* src, U16& dst) +        { +            dst = *src; +        } + +        template<> +        void copyScalar<U16, U32>(U16* src, U32& dst) +        { +            dst = *src; +        } + +        template<> +        void copyScalar<U8, U16>(U8* src, U16& dst) +        { +            dst = *src; +        } + +        template<> +        void copyScalar<U8, U32>(U8* src, U32& dst) +        { +            dst = *src; +        } + +        template<> +        void copyVec2<F32, LLVector2>(F32* src, LLVector2& dst) +        { +            dst.set(src[0], src[1]); +        } + +        template<> +        void copyVec3<F32, glh::vec3f>(F32* src, glh::vec3f& dst) +        { +            dst.set_value(src[0], src[1], src[2]); +        } + +        template<> +        void copyVec3<F32, LLVector4a>(F32* src, LLVector4a& dst) +        { +            dst.load3(src); +        } + +        template<> +        void copyVec3<U16, LLColor4U>(U16* src, LLColor4U& dst) +        { +            dst.set(src[0], src[1], src[2], 255); +        } + +        template<> +        void copyVec4<U8, LLColor4U>(U8* src, LLColor4U& dst) +        { +            dst.set(src[0], src[1], src[2], src[3]); +        } + +        template<> +        void copyVec4<U16, LLColor4U>(U16* src, LLColor4U& dst) +        { +            dst.set(src[0], src[1], src[2], src[3]); +        } + +        template<> +        void copyVec4<F32, LLColor4U>(F32* src, LLColor4U& dst) +        { +            dst.set(src[0]*255, src[1]*255, src[2]*255, src[3]*255); +        } + +        template<> +        void copyVec4<F32, LLVector4a>(F32* src, LLVector4a& dst) +        { +            dst.loadua(src); +        } + +        template<> +        void copyVec4<U16, LLVector4a>(U16* src, LLVector4a& dst) +        { +            dst.set(src[0], src[1], src[2], src[3]); +        } + +        template<> +        void copyVec4<U8, LLVector4a>(U8* src, LLVector4a& dst) +        { +            dst.set(src[0], src[1], src[2], src[3]); +        } + +        template<> +        void copyVec4<F32, glh::quaternionf>(F32* src, glh::quaternionf& dst) +        { +            dst.set_value(src); +        } + +        template<> +        void copyMat4<F32, glh::matrix4f>(F32* src, glh::matrix4f& dst) +        { +            dst.set_value(src); +        } + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +        //========================================================================================================= + +        // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy +        template<class S, class T> +        static void copyScalar(S* src, LLStrider<T> dst, S32 stride, S32 count) +        { +            for (S32 i = 0; i < count; ++i) +            { +                copyScalar(src, *dst); +                dst++; +                src = (S*)((U8*)src + stride); +            } +        } + +        // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy +        template<class S, class T> +        static void copyVec2(S* src, LLStrider<T> dst, S32 stride, S32 count) +        { +            for (S32 i = 0; i < count; ++i) +            { +                copyVec2(src, *dst); +                dst++; +                src = (S*)((U8*)src + stride); +            } +        } + +        // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy +        template<class S, class T> +        static void copyVec3(S* src, LLStrider<T> dst, S32 stride, S32 count) +        { +            for (S32 i = 0; i < count; ++i) +            { +                copyVec3(src, *dst); +                dst++; +                src = (S*)((U8*)src + stride); +            } +        } + +        // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy +        template<class S, class T> +        static void copyVec4(S* src, LLStrider<T> dst, S32 stride, S32 count) +        { +            for (S32 i = 0; i < count; ++i) +            { +                copyVec4(src, *dst); +                dst++; +                src = (S*)((U8*)src + stride); +            } +        } + +        // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy +        template<class S, class T> +        static void copyMat2(S* src, LLStrider<T> dst, S32 stride, S32 count) +        { +            for (S32 i = 0; i < count; ++i) +            { +                copyMat2(src, *dst); +                dst++; +                src = (S*)((U8*)src + stride); +            } +        } + +        // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy +        template<class S, class T> +        static void copyMat3(S* src, LLStrider<T> dst, S32 stride, S32 count) +        { +            for (S32 i = 0; i < count; ++i) +            { +                copyMat3(src, *dst); +                dst++; +                src = (S*)((U8*)src + stride); +            } +        } + +        // copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy +        template<class S, class T> +        static void copyMat4(S* src, LLStrider<T> dst, S32 stride, S32 count) +        { +            for (S32 i = 0; i < count; ++i) +            { +                copyMat4(src, *dst); +                dst++; +                src = (S*)((U8*)src + stride); +            } +        } + +        template<class S, class T> +        static void copy(Asset& asset, Accessor& accessor, const S* src, LLStrider<T>& dst, S32 byteStride) +        { +            if (accessor.mType == (S32)Accessor::Type::SCALAR) +            { +                S32 stride = byteStride == 0 ? sizeof(S) * 1 : byteStride; +                copyScalar((S*)src, dst, stride, accessor.mCount); +            } +            else if (accessor.mType == (S32)Accessor::Type::VEC2) +            { +                S32 stride = byteStride == 0 ? sizeof(S) * 2 : byteStride; +                copyVec2((S*)src, dst, stride, accessor.mCount); +            } +            else if (accessor.mType == (S32)Accessor::Type::VEC3) +            { +                S32 stride = byteStride == 0 ? sizeof(S) * 3 : byteStride; +                copyVec3((S*)src, dst, stride, accessor.mCount); +            } +            else if (accessor.mType == (S32)Accessor::Type::VEC4) +            { +                S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride; +                copyVec4((S*)src, dst, stride, accessor.mCount); +            } +            else if (accessor.mType == (S32)Accessor::Type::MAT2) +            { +                S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride; +                copyMat2((S*)src, dst, stride, accessor.mCount); +            } +            else if (accessor.mType == (S32)Accessor::Type::MAT3) +            { +                S32 stride = byteStride == 0 ? sizeof(S) * 9 : byteStride; +                copyMat3((S*)src, dst, stride, accessor.mCount); +            } +            else if (accessor.mType == (S32)Accessor::Type::MAT4) +            { +                S32 stride = byteStride == 0 ? sizeof(S) * 16 : byteStride; +                copyMat4((S*)src, dst, stride, accessor.mCount); +            } +            else +            { +                LL_ERRS("GLTF") << "Unsupported accessor type" << LL_ENDL; +            } +        } + +        // copy data from accessor to strider +        template<class T> +        static void copy(Asset& asset, Accessor& accessor, LLStrider<T>& dst) +        { +            const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView]; +            const Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; +            const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset; + +            if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_FLOAT) +            { +                LL::GLTF::copy(asset, accessor, (const F32*)src, dst, bufferView.mByteStride); +            } +            else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) +            { +                LL::GLTF::copy(asset, accessor, (const U16*)src, dst, bufferView.mByteStride); +            } +            else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) +            { +                LL::GLTF::copy(asset, accessor, (const U32*)src, dst, bufferView.mByteStride); +            } +            else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) +            { +                LL::GLTF::copy(asset, accessor, (const U8*)src, dst, bufferView.mByteStride); +            } +            else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_SHORT) +            { +                LL::GLTF::copy(asset, accessor, (const S16*)src, dst, bufferView.mByteStride); +            } +            else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_BYTE) +            { +                LL::GLTF::copy(asset, accessor, (const S8*)src, dst, bufferView.mByteStride); +            } +            else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_DOUBLE) +            { +                LL::GLTF::copy(asset, accessor, (const F64*)src, dst, bufferView.mByteStride); +            } +            else +            { +                LL_ERRS("GLTF") << "Unsupported component type" << LL_ENDL; +            } +        } + +        // copy data from accessor to vector +        template<class T> +        static void copy(Asset& asset, Accessor& accessor, std::vector<T>& dst) +        { +            dst.resize(accessor.mCount); +            LLStrider<T> strider = dst.data(); +            copy(asset, accessor, strider); +        } +    } +} + diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index b5d59e1b24..b57a0af18d 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -27,163 +27,12 @@  #include "../llviewerprecompiledheaders.h"  #include "asset.h" +#include "buffer_util.h" +  #include "../lltinygltfhelper.h"  using namespace LL::GLTF; -#ifdef _MSC_VER -#define LL_FUNCSIG __FUNCSIG__  -#else -#define LL_FUNCSIG __PRETTY_FUNCTION__ -#endif - -// copy one vec3 from src to dst -template<class S, class T> -void copyVec2(S* src, T& dst) -{ -    LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; -} - -// copy one vec3 from src to dst -template<class S, class T> -void copyVec3(S* src, T& dst) -{ -    LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; -} - -// copy one vec4 from src to dst -template<class S, class T> -void copyVec4(S* src, T& dst) -{ -    LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; -} - -template<> -void copyVec2<F32, LLVector2>(F32* src, LLVector2& dst) -{ -    dst.set(src[0], src[1]); -} - -template<> -void copyVec3<F32, LLVector4a>(F32* src, LLVector4a& dst) -{ -    dst.load3(src); -} - -template<> -void copyVec3<U16, LLColor4U>(U16* src, LLColor4U& dst) -{ -    dst.set(src[0], src[1], src[2], 255); -} - -template<> -void copyVec4<F32, LLVector4a>(F32* src, LLVector4a& dst) -{ -    dst.loadua(src); -} - -// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy -template<class S, class T> -void copyVec2(S* src, LLStrider<T> dst, S32 stride, S32 count) -{ -    for (S32 i = 0; i < count; ++i) -    { -        copyVec2(src, *dst); -        dst++; -        src = (S*)((U8*)src + stride); -    } -} - -// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy -template<class S, class T> -void copyVec3(S* src, LLStrider<T> dst, S32 stride, S32 count) -{ -    for (S32 i = 0; i < count; ++i) -    { -        copyVec3(src, *dst); -        dst++; -        src = (S*)((U8*)src + stride); -    } -} - -// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy -template<class S, class T> -void copyVec4(S* src, LLStrider<T> dst, S32 stride, S32 count) -{ -    for (S32 i = 0; i < count; ++i) -    { -        copyVec3(src, *dst); -        dst++; -        src = (S*)((U8*)src + stride); -    } -} - -template<class S, class T> -void copyAttributeArray(Asset& asset, const Accessor& accessor, const S* src, LLStrider<T>& dst, S32 byteStride) -{ -    if (accessor.mType == TINYGLTF_TYPE_VEC2) -    { -        S32 stride = byteStride == 0 ? sizeof(S) * 2 : byteStride; -        copyVec2((S*)src, dst, stride, accessor.mCount); -    } -    else if (accessor.mType == TINYGLTF_TYPE_VEC3) -    { -        S32 stride = byteStride == 0 ? sizeof(S) * 3 : byteStride; -        copyVec3((S*)src, dst, stride, accessor.mCount); -    } -    else if (accessor.mType == TINYGLTF_TYPE_VEC4) -    { -        S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride; -        copyVec4((S*)src, dst, stride, accessor.mCount); -    } -    else -    { -        LL_ERRS("GLTF") << "Unsupported accessor type" << LL_ENDL; -    } -} - -template <class T> -void Primitive::copyAttribute(Asset& asset, S32 accessorIdx, LLStrider<T>& dst) -{ -    const Accessor& accessor = asset.mAccessors[accessorIdx]; -    const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView]; -    const Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; -    const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset; - -    if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_FLOAT) -    { -        copyAttributeArray(asset, accessor, (const F32*)src, dst, bufferView.mByteStride); -    } -    else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) -    { -        copyAttributeArray(asset, accessor, (const U16*)src, dst, bufferView.mByteStride); -    } -    else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) -    { -        copyAttributeArray(asset, accessor, (const U32*)src, dst, bufferView.mByteStride); -    } -    else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) -    { -        copyAttributeArray(asset, accessor, (const U8*)src, dst, bufferView.mByteStride); -    } -    else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_SHORT) -    { -        copyAttributeArray(asset, accessor, (const S16*)src, dst, bufferView.mByteStride); -    } -    else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_BYTE) -    { -        copyAttributeArray(asset, accessor, (const S8*)src, dst, bufferView.mByteStride); -    } -    else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_DOUBLE) -    { -        copyAttributeArray(asset, accessor, (const F64*)src, dst, bufferView.mByteStride); -    } -    else -    { -        LL_ERRS("GLTF") << "Unsupported component type" << LL_ENDL; -    } -} -  void Primitive::allocateGLResources(Asset& asset)  {      // allocate vertex buffer @@ -192,219 +41,138 @@ void Primitive::allocateGLResources(Asset& asset)      // For our engine, though, it's better to rearrange the buffers at load time into a layout that's more consistent.      // The GLTF native approach undoubtedly works well if you can count on VAOs, but VAOs perform much worse with our scenes. -    // get the number of vertices -    U32 numVertices = 0; -    if (!mAttributes.empty()) -    { -        auto it = mAttributes.begin(); -        const Accessor& accessor = asset.mAccessors[it->second]; -        numVertices = accessor.mCount; -    } - -    // get the number of indices -    U32 numIndices = 0; -    if (mIndices != INVALID_INDEX) -    { -        const Accessor& accessor = asset.mAccessors[mIndices]; -        numIndices = accessor.mCount; -    } - -    // create vertex buffer -    mVertexBuffer = new LLVertexBuffer(ATTRIBUTE_MASK); -    mVertexBuffer->allocateBuffer(numVertices, numIndices); - -    bool needs_color = true; -    bool needs_texcoord = true; -    bool needs_normal = true; -    bool needs_tangent = true; -      // load vertex data      for (auto& it : mAttributes)      {          const std::string& attribName = it.first; +        Accessor& accessor = asset.mAccessors[it.second];          // load vertex data          if (attribName == "POSITION")          { -            // load position data -            LLStrider<LLVector4a> dst; -            mVertexBuffer->getVertexStrider(dst); - -            copyAttribute(asset, it.second, dst); +            copy(asset, accessor, mPositions);          }          else if (attribName == "NORMAL")          { -            needs_normal = false; -            // load normal data -            LLStrider<LLVector4a> dst; -            mVertexBuffer->getNormalStrider(dst); - -            copyAttribute(asset, it.second, dst); +            copy(asset, accessor, mNormals);          }          else if (attribName == "TANGENT")          { -            needs_tangent = false; -            // load tangent data - -            LLStrider<LLVector4a> dst; -            mVertexBuffer->getTangentStrider(dst); - -            copyAttribute(asset, it.second, dst); +            copy(asset, accessor, mTangents);          }          else if (attribName == "COLOR_0")          { -            needs_color = false; -            // load color data - -            LLStrider<LLColor4U> dst; -            mVertexBuffer->getColorStrider(dst); - -            copyAttribute(asset, it.second, dst); +            copy(asset, accessor, mColors);          }          else if (attribName == "TEXCOORD_0")          { -            needs_texcoord = false; -            // load texcoord data -            LLStrider<LLVector2> dst; -            mVertexBuffer->getTexCoord0Strider(dst); - -            LLStrider<LLVector2> tc = dst; -            copyAttribute(asset, it.second, dst); - -            // convert to OpenGL coordinate space -            for (U32 i = 0; i < numVertices; ++i) -            { -                tc->mV[1] = 1.0f - tc->mV[1];; -                tc++; -            } +            copy(asset, accessor, mTexCoords); +        } +        else if (attribName == "JOINTS_0") +        { +            copy(asset, accessor, mJoints); +        } +        else if (attribName == "WEIGHTS_0") +        { +            copy(asset, accessor, mWeights);          }      }      // copy index buffer      if (mIndices != INVALID_INDEX)      { -        const Accessor& accessor = asset.mAccessors[mIndices]; -        const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView]; -        const Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; +        Accessor& accessor = asset.mAccessors[mIndices]; +        copy(asset, accessor, mIndexArray); +    } -        const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset; +    U32 mask = ATTRIBUTE_MASK; +     +    if (!mWeights.empty()) +    { +        mask |= LLVertexBuffer::MAP_WEIGHT4; +    } -        LLStrider<U16> dst; -        mVertexBuffer->getIndexStrider(dst); -        mIndexArray.resize(numIndices); +    mVertexBuffer = new LLVertexBuffer(mask); +    mVertexBuffer->allocateBuffer(mPositions.size(), mIndexArray.size()*2); // double the size of the index buffer for 32-bit indices -        if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) -        { -            for (U32 i = 0; i < numIndices; ++i) -            { -                *(dst++) = (U16) * (U32*)src; -                src += sizeof(U32); -            } -        } -        else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) -        { -            for (U32 i = 0; i < numIndices; ++i) -            { -                *(dst++) = *(U16*)src; -                src += sizeof(U16); -            } -        } -        else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) -        { -            for (U32 i = 0; i < numIndices; ++i) -            { -                *(dst++) = *(U8*)src; -                src += sizeof(U8); -            } -        } -        else -        { -            LL_ERRS("GLTF") << "Unsupported component type for indices" << LL_ENDL; -        } +    mVertexBuffer->setBuffer(); +    mVertexBuffer->setPositionData(mPositions.data()); -        U16* idx = (U16*)mVertexBuffer->getMappedIndices(); -        for (U32 i = 0; i < numIndices; ++i) -        { -            mIndexArray[i] = idx[i]; -        } +    if (!mIndexArray.empty()) +    { +        mVertexBuffer->setIndexData(mIndexArray.data());      } -    // fill in default values for missing attributes -    if (needs_color) -    { // set default color -        LLStrider<LLColor4U> dst; -        mVertexBuffer->getColorStrider(dst); -        for (U32 i = 0; i < numVertices; ++i) -        { -            *(dst++) = LLColor4U(255, 255, 255, 255); -        } +    if (mTexCoords.empty()) +    { +        mTexCoords.resize(mPositions.size()); +    } + +    // flip texcoord y, upload, then flip back (keep the off-spec data in vram only) +    for (auto& tc : mTexCoords) +    { +        tc[1] = 1.f - tc[1];      } +    mVertexBuffer->setTexCoordData(mTexCoords.data()); +    for (auto& tc : mTexCoords) +    { +        tc[1] = 1.f - tc[1]; +    } + +    if (mColors.empty()) +    { +        mColors.resize(mPositions.size(), LLColor4U::white); +    } +          // bake material basecolor into color array      if (mMaterial != INVALID_INDEX)      {          const Material& material = asset.mMaterials[mMaterial];          LLColor4 baseColor = material.mMaterial->mBaseColor; -        LLStrider<LLColor4U> dst; -        mVertexBuffer->getColorStrider(dst); - -        for (U32 i = 0; i < numVertices; ++i) +        for (auto& dst : mColors)          { -            LLColor4 col = *dst; -            *dst = LLColor4U(baseColor * col); -            dst++; +            dst = LLColor4U(baseColor * LLColor4(dst));          }      } -    if (needs_texcoord) -    { // set default texcoord -        LLStrider<LLVector2> dst; -        mVertexBuffer->getTexCoord0Strider(dst); -        for (U32 i = 0; i < numVertices; ++i) -        { -            *(dst++) = LLVector2(0.0f, 0.0f); -        } -    } +    mVertexBuffer->setColorData(mColors.data()); -    if (needs_normal) -    { // set default normal -        LLStrider<LLVector4a> dst; -        mVertexBuffer->getNormalStrider(dst); -        for (U32 i = 0; i < numVertices; ++i) -        { -            *(dst++) = LLVector4a(0.0f, 0.0f, 1.0f, 0.0f); -        } +    if (mNormals.empty()) +    { +        mNormals.resize(mPositions.size(), LLVector4a(0, 0, 1, 0));      } +     +    mVertexBuffer->setNormalData(mNormals.data()); -    if (needs_tangent) -    {  // TODO: generate tangents if needed -        LLStrider<LLVector4a> dst; -        mVertexBuffer->getTangentStrider(dst); -        for (U32 i = 0; i < numVertices; ++i) -        { -            *(dst++) = LLVector4a(1.0f, 0.0f, 0.0f, 1.0f); -        } +    if (mTangents.empty()) +    { +        // TODO: generate tangents if needed +        mTangents.resize(mPositions.size(), LLVector4a(1, 0, 0, 1));      } -    mPositions.resize(numVertices); -    mTexCoords.resize(numVertices); -    mNormals.resize(numVertices); -    mTangents.resize(numVertices); +    mVertexBuffer->setTangentData(mTangents.data()); -    LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX)); -    LLVector2* tc = (LLVector2*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_TEXCOORD0)); -    LLVector4a* norm = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_NORMAL)); -    LLVector4a* tangent = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_TANGENT)); -    for (U32 i = 0; i < numVertices; ++i) +    if (!mWeights.empty())      { -        mPositions[i] = pos[i]; -        mTexCoords[i] = tc[i]; -        mNormals[i] = norm[i]; -        mTangents[i] = tangent[i]; +        std::vector<LLVector4a> weight_data; +        weight_data.resize(mWeights.size()); + +        F32 max_weight = 1.f - FLT_EPSILON*100.f; +        LLVector4a maxw(max_weight, max_weight, max_weight, max_weight); +        for (U32 i = 0; i < mWeights.size(); ++i) +        { +            LLVector4a& w = weight_data[i]; +            w.setMin(mWeights[i], maxw); +            w.add(mJoints[i]); +        }; + +        mVertexBuffer->setWeight4Data(weight_data.data());      } +          createOctree(); -    mVertexBuffer->unmapBuffer(); +    mVertexBuffer->unbind();  }  void initOctreeTriangle(LLVolumeTriangle* tri, F32 scaler, S32 i0, S32 i1, S32 i2, const LLVector4a& v0, const LLVector4a& v1, const LLVector4a& v2) @@ -456,20 +224,17 @@ void Primitive::createOctree()          // Initialize all the triangles we need          mOctreeTriangles.resize(num_triangles); -        LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX)); -        U16* indices = (U16*)mVertexBuffer->getMappedIndices(); -          for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index)          { //for each triangle              const U32 index = triangle_index * 3;              LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; -            S32 i0 = indices[index]; -            S32 i1 = indices[index + 1]; -            S32 i2 = indices[index + 2]; +            S32 i0 = mIndexArray[index]; +            S32 i1 = mIndexArray[index + 1]; +            S32 i2 = mIndexArray[index + 2]; -            const LLVector4a& v0 = pos[i0]; -            const LLVector4a& v1 = pos[i1]; -            const LLVector4a& v2 = pos[i2]; +            const LLVector4a& v0 = mPositions[i0]; +            const LLVector4a& v1 = mPositions[i1]; +            const LLVector4a& v2 = mPositions[i2];              initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); @@ -483,20 +248,17 @@ void Primitive::createOctree()          // Initialize all the triangles we need          mOctreeTriangles.resize(num_triangles); -        LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX)); -        U16* indices = (U16*)mVertexBuffer->getMappedIndices(); -          for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index)          { //for each triangle              const U32 index = triangle_index + 2;              LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; -            S32 i0 = indices[index]; -            S32 i1 = indices[index - 1]; -            S32 i2 = indices[index - 2]; +            S32 i0 = mIndexArray[index]; +            S32 i1 = mIndexArray[index - 1]; +            S32 i2 = mIndexArray[index - 2]; -            const LLVector4a& v0 = pos[i0]; -            const LLVector4a& v1 = pos[i1]; -            const LLVector4a& v2 = pos[i2]; +            const LLVector4a& v0 = mPositions[i0]; +            const LLVector4a& v1 = mPositions[i1]; +            const LLVector4a& v2 = mPositions[i2];              initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); @@ -510,20 +272,17 @@ void Primitive::createOctree()          // Initialize all the triangles we need          mOctreeTriangles.resize(num_triangles); -        LLVector4a* pos = (LLVector4a*)(mVertexBuffer->getMappedData() + mVertexBuffer->getOffset(LLVertexBuffer::TYPE_VERTEX)); -        U16* indices = (U16*)mVertexBuffer->getMappedIndices(); -          for (U32 triangle_index = 0; triangle_index < num_triangles; ++triangle_index)          { //for each triangle              const U32 index = triangle_index + 2;              LLVolumeTriangle* tri = &mOctreeTriangles[triangle_index]; -            S32 i0 = indices[0]; -            S32 i1 = indices[index - 1]; -            S32 i2 = indices[index - 2]; +            S32 i0 = mIndexArray[0]; +            S32 i1 = mIndexArray[index - 1]; +            S32 i2 = mIndexArray[index - 2]; -            const LLVector4a& v0 = pos[i0]; -            const LLVector4a& v1 = pos[i1]; -            const LLVector4a& v2 = pos[i2]; +            const LLVector4a& v0 = mPositions[i0]; +            const LLVector4a& v1 = mPositions[i1]; +            const LLVector4a& v2 = mPositions[i2];              initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); @@ -571,7 +330,7 @@ const LLVolumeTriangle* Primitive::lineSegmentIntersect(const LLVector4a& start,      face.mTexCoords = mTexCoords.data();      face.mNormals = mNormals.data();      face.mTangents = mTangents.data(); -    face.mIndices = mIndexArray.data(); +    face.mIndices = nullptr; // unreferenced      face.mNumIndices = mIndexArray.size();      face.mNumVertices = mPositions.size(); @@ -592,3 +351,50 @@ Primitive::~Primitive()      mOctree = nullptr;  } + +const Primitive& Primitive::operator=(const tinygltf::Primitive& src) +{ +    // load material +    mMaterial = src.material; + +    // load mode +    mMode = src.mode; + +    // load indices +    mIndices = src.indices; + +    // load attributes +    for (auto& it : src.attributes) +    { +        mAttributes[it.first] = it.second; +    } + +    switch (mMode) +    { +    case TINYGLTF_MODE_POINTS: +        mGLMode = LLRender::POINTS; +        break; +    case TINYGLTF_MODE_LINE: +        mGLMode = LLRender::LINES; +        break; +    case TINYGLTF_MODE_LINE_LOOP: +        mGLMode = LLRender::LINE_LOOP; +        break; +    case TINYGLTF_MODE_LINE_STRIP: +        mGLMode = LLRender::LINE_STRIP; +        break; +    case TINYGLTF_MODE_TRIANGLES: +        mGLMode = LLRender::TRIANGLES; +        break; +    case TINYGLTF_MODE_TRIANGLE_STRIP: +        mGLMode = LLRender::TRIANGLE_STRIP; +        break; +    case TINYGLTF_MODE_TRIANGLE_FAN: +        mGLMode = LLRender::TRIANGLE_FAN; +        break; +    default: +        mGLMode = GL_TRIANGLES; +    } + +    return *this; +} diff --git a/indra/newview/gltf/primitive.h b/indra/newview/gltf/primitive.h index 7c47d9dac5..07e8e7deb2 100644 --- a/indra/newview/gltf/primitive.h +++ b/indra/newview/gltf/primitive.h @@ -56,7 +56,10 @@ namespace LL              std::vector<LLVector4a> mNormals;              std::vector<LLVector4a> mTangents;              std::vector<LLVector4a> mPositions; -            std::vector<U16> mIndexArray; +            std::vector<LLVector4a> mJoints; +            std::vector<LLVector4a> mWeights; +            std::vector<LLColor4U> mColors; +            std::vector<U32> mIndexArray;              // raycast acceleration structure              LLPointer<LLVolumeOctree> mOctree; @@ -68,11 +71,6 @@ namespace LL              S32 mIndices = -1;              std::unordered_map<std::string, int> mAttributes; -            // copy the attribute in the given BufferView to the given destination -            // assumes destination has enough storage for the attribute -            template<class T> -            void copyAttribute(Asset& asset, S32 bufferViewIdx, LLStrider<T>& dst); -                          // create octree based on vertex buffer              // must be called before buffer is unmapped and after buffer is populated with good data              void createOctree(); @@ -87,52 +85,7 @@ namespace LL                  LLVector4a* tangent = NULL             // return the surface tangent at the intersection point              ); -            const Primitive& operator=(const tinygltf::Primitive& src) -            { -                // load material -                mMaterial = src.material; - -                // load mode -                mMode = src.mode; - -                // load indices -                mIndices = src.indices; - -                // load attributes -                for (auto& it : src.attributes) -                { -                    mAttributes[it.first] = it.second; -                } - -                switch (mMode) -                { -                case TINYGLTF_MODE_POINTS: -                    mGLMode = LLRender::POINTS; -                    break; -                case TINYGLTF_MODE_LINE: -                    mGLMode = LLRender::LINES; -                    break; -                case TINYGLTF_MODE_LINE_LOOP: -                    mGLMode = LLRender::LINE_LOOP; -                    break; -                case TINYGLTF_MODE_LINE_STRIP: -                    mGLMode = LLRender::LINE_STRIP; -                    break; -                case TINYGLTF_MODE_TRIANGLES: -                    mGLMode = LLRender::TRIANGLES; -                    break; -                case TINYGLTF_MODE_TRIANGLE_STRIP: -                    mGLMode = LLRender::TRIANGLE_STRIP; -                    break; -                case TINYGLTF_MODE_TRIANGLE_FAN: -                    mGLMode = LLRender::TRIANGLE_FAN; -                    break; -                default: -                    mGLMode = GL_TRIANGLES; -                } - -                return *this; -            } +            const Primitive& operator=(const tinygltf::Primitive& src);              void allocateGLResources(Asset& asset);          }; diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index 8273c707f9..4e3439ea5c 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -82,6 +82,7 @@ void GLTFSceneManager::load(const std::string& filename)      LLPointer<Asset> asset = new Asset();      *asset = model; +    gDebugProgram.bind(); // bind a shader to satisfy LLVertexBuffer assertions      asset->allocateGLResources(filename, model);      asset->updateTransforms(); @@ -114,7 +115,25 @@ void GLTFSceneManager::renderAlpha()      render(false);  } -void GLTFSceneManager::render(bool opaque) +void GLTFSceneManager::update() +{ +    for (U32 i = 0; i < mObjects.size(); ++i) +    { +        if (mObjects[i]->isDead() || mObjects[i]->mGLTFAsset == nullptr) +        { +            mObjects.erase(mObjects.begin() + i); +            --i; +            continue; +        } + +        Asset* asset = mObjects[i]->mGLTFAsset; + +        asset->update(); +      +    } +} + +void GLTFSceneManager::render(bool opaque, bool rigged)  {      // for debugging, just render the whole scene as opaque      // by traversing the whole scenegraph @@ -144,7 +163,7 @@ void GLTFSceneManager::render(bool opaque)          matMul(mat, modelview, modelview);          asset->updateRenderTransforms(modelview); -        asset->render(opaque); +        asset->render(opaque, rigged);          gGL.popMatrix();      } diff --git a/indra/newview/gltfscenemanager.h b/indra/newview/gltfscenemanager.h index 4e9013834b..d286f335e4 100644 --- a/indra/newview/gltfscenemanager.h +++ b/indra/newview/gltfscenemanager.h @@ -36,9 +36,12 @@ namespace LL      public:          ~GLTFSceneManager();          // load GLTF file from disk +                  void load(); // open filepicker to choose asset          void load(const std::string& filename); // load asset from filename -        void render(bool opaque); + +        void update(); +        void render(bool opaque, bool rigged = false);          void renderOpaque();          void renderAlpha(); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 46b95601af..c4c7d5675f 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4857,6 +4857,7 @@ void LLAppViewer::idle()          if (!(logoutRequestSent() && hasSavedFinalSnapshot()))  		{  			gObjectList.update(gAgent); +            LL::GLTFSceneManager::instance().update();  		}  	} diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 81014e9d6e..9418cead76 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -261,10 +261,13 @@ void LLDrawPoolAlpha::forwardRender(bool rigged)      mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;       // }      gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); -    if (write_depth) -    { // draw GLTF scene to depth buffer +    if (rigged) +    { // draw GLTF scene to depth buffer before rigged alpha          gPipeline.bindDeferredShader(gDeferredPBRAlphaProgram); -        LL::GLTFSceneManager::instance().renderAlpha(); +        LL::GLTFSceneManager::instance().render(false, false); + +        gPipeline.bindDeferredShader(*gDeferredPBRAlphaProgram.mRiggedVariant); +        LL::GLTFSceneManager::instance().render(false, true);      }      // If the face is more than 90% transparent, then don't update the Depth buffer for Dof diff --git a/indra/newview/lldrawpoolpbropaque.cpp b/indra/newview/lldrawpoolpbropaque.cpp index a32382af92..a32b6b1687 100644 --- a/indra/newview/lldrawpoolpbropaque.cpp +++ b/indra/newview/lldrawpoolpbropaque.cpp @@ -61,6 +61,7 @@ void LLDrawPoolGLTFPBR::renderDeferred(S32 pass)      gDeferredPBROpaqueProgram.bind(true); +    LL::GLTFSceneManager::instance().render(true, true);      pushRiggedGLTFBatches(mRenderType + 1);  } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index fd8a2e3ffc..341c9706f8 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -6593,6 +6593,10 @@ void LLPipeline::renderGLTFObjects(U32 type, bool texture, bool rigged)      {          LL::GLTFSceneManager::instance().renderOpaque();      } +    else +    { +        LL::GLTFSceneManager::instance().render(true, true); +    }  }  // Currently only used for shadows -Cosmic,2023-04-19 | 
