diff --git a/autobuild.xml b/autobuild.xml index 8b1ec05e18..a8a7eb83b7 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -2098,6 +2098,18 @@ mikktspace + canonical_repo + https://bitbucket.org/lindenlab/3p-mikktspace + copyright + Copyright (C) 2011 by Morten S. Mikkelsen, Copyright (C) 2022 Blender Authors + description + Mikktspace Tangent Generator + license + Apache 2.0 + license_file + mikktspace.txt + name + mikktspace platforms darwin64 @@ -2105,58 +2117,46 @@ archive hash - 6cc1585dba85b0226a2e7033a7e2a2ceaae7c983 + 65edf85c36a10001e32bdee582bec4732137208b hash_algorithm sha1 url - https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-darwin64-5cee1f4.tar.zst + https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-darwin64-8756084692.tar.zst name darwin64 - windows64 - - archive - - hash - 6b7d01ad54e4a88a001f66840c32329cedb28202 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-windows64-5cee1f4.tar.zst - - name - windows64 - linux64 archive hash - edc9782bf209e17ad1845498b42f16d733582082 + fa9dcee4584df7e7271fdf69c08e6fd3122a47fc hash_algorithm sha1 url - https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-linux64-5cee1f4.tar.zst + https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-linux64-8756084692.tar.zst name linux64 + windows64 + + archive + + hash + 130b33a70bdb3a8a188376c6a91840bdb61380a8 + hash_algorithm + sha1 + url + https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-windows64-8756084692.tar.zst + + name + windows64 + - license - Copyright (C) 2011 by Morten S. Mikkelsen - license_file - mikktspace.txt - copyright - Copyright (C) 2011 by Morten S. Mikkelsen version 1 - name - mikktspace - canonical_repo - https://bitbucket.org/lindenlab/3p-mikktspace - description - Mikktspace Tangent Generator minizip-ng @@ -2525,76 +2525,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors description OpenAL Soft is a software implementation of the OpenAL 3D audio API. - openexr - - canonical_repo - https://github.com/secondlife/3p-openexr - copyright - Copyright (c) Contributors to the OpenEXR Project. All rights reserved. - description - OpenEXR provides the specification and reference implementation of the EXR file format, the professional-grade image storage format of the motion picture industry. - license - OpenEXR - license_file - LICENSES/openexr.txt - name - openexr - platforms - - darwin64 - - archive - - hash - 17cd63922214b588d9a36137fadf927237ec0f25 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openexr/releases/download/v1.10/openexr-3.2.2-darwin64-df7544d.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - b092658ab5ec009a5875e8b6e5b7109730ad6846 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openexr/releases/download/v1.10/openexr-3.2.2-linux64-df7544d.tar.zst - - name - linux64 - - windows64 - - archive - - hash - c511ae9a3e401375af2199b498a75f32cebc010f - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openexr/releases/download/v1.10/openexr-3.2.2-windows64-df7544d.tar.zst - - name - windows64 - - - source_type - git - vcs_branch - debug_autobuild - vcs_revision - 5cd1075295c17b5f7085e83d5c16b13c7ecb2eb1 - vcs_url - https://github.com/secondlife/3p-openexr - version - 3.2.2 - openjpeg platforms @@ -3419,6 +3349,46 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors description zlib data compression library for the next generation systems + tinyexr + + platforms + + common + + archive + + hash + 9e0092c6a3aed1cb40a9e26df689c42c68142c9d + hash_algorithm + sha1 + url + https://github.com/secondlife/3p-tinyexr/releases/download/v1.0.8-r1/tinyexr-v1.0.8-common-8755737750.tar.zst + + name + common + + + license + 3-clause BSD + license_file + LICENSES/tinyexr_license.txt + copyright + Copyright (c) 2014 - 2021, Syoyo Fujita and many contributors. + version + v1.0.8 + name + tinyexr + vcs_branch + dependabot/github_actions/secondlife/action-autobuild-4 + vcs_revision + 4dc4d1d90d82a22843e2adf5130f9ecb5ee5769e + vcs_url + https://github.com/secondlife/3p-tinyexr + description + tinyexr import library + source_type + git + package_description diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index f8ba23316b..454c8810f9 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -58,6 +58,8 @@ set(cmake_SOURCE_FILES PulseAudio.cmake Python.cmake TemplateCheck.cmake + TinyEXR.cmake + TinyGLTF.cmake Tut.cmake UI.cmake UnixInstall.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 7c6c02e4df..2828c3db0a 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -61,12 +61,6 @@ if(WINDOWS) glod.dll # restore GLOD libhunspell.dll uriparser.dll - Iex-3_2.dll - IlmThread-3_2.dll - Imath-3_1.dll - OpenEXR-3_2.dll - OpenEXRCore-3_2.dll - OpenEXRUtil-3_2.dll ) # ICU4C (same filenames for 32 and 64 bit builds) diff --git a/indra/cmake/OpenEXR.cmake b/indra/cmake/OpenEXR.cmake deleted file mode 100644 index ee21fac541..0000000000 --- a/indra/cmake/OpenEXR.cmake +++ /dev/null @@ -1,18 +0,0 @@ -# -*- cmake -*- - -include(Prebuilt) - -include_guard() -add_library( ll::openexr INTERFACE IMPORTED ) - -if(USE_CONAN ) - target_link_libraries( ll::openexr INTERFACE CONAN_PKG::openexr ) - return() -endif() - -use_prebuilt_binary(openexr) - -target_link_libraries( ll::openexr INTERFACE Iex-3_2 IlmThread-3_2 Imath-3_1 OpenEXR-3_2 OpenEXRCore-3_2 OpenEXRUtil-3_2) - -target_include_directories( ll::openexr SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/OpenEXR ${LIBS_PREBUILT_DIR}/include/Imath) - diff --git a/indra/cmake/TinyEXR.cmake b/indra/cmake/TinyEXR.cmake new file mode 100644 index 0000000000..e6d142d19d --- /dev/null +++ b/indra/cmake/TinyEXR.cmake @@ -0,0 +1,7 @@ +# -*- cmake -*- +include(Prebuilt) + +use_prebuilt_binary(tinyexr) + +set(TINYEXR_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tinyexr) + 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 LLStrider }; U32 mSkip; public: - LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); } + LLStrider(Object* first) { mObjectp = first; mSkip = sizeof(Object); } ~LLStrider() { } const LLStrider& operator = (Object *first) { mObjectp = first; return *this;} diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h index 2cf50e9cd2..12fc6d570a 100644 --- a/indra/llmath/llmatrix4a.h +++ b/indra/llmath/llmatrix4a.h @@ -34,8 +34,8 @@ class LLMatrix4a { public: - LL_ALIGN_16(LLVector4a mMatrix[4]); - + LL_ALIGN_16(LLVector4a mMatrix[4]); + LLMatrix4a() { @@ -56,6 +56,16 @@ public: return (F32*)&mMatrix; } + inline LLMatrix4& asMatrix4() + { + return *(LLMatrix4*)this; + } + + inline const LLMatrix4& asMatrix4() const + { + return *(LLMatrix4*)this; + } + inline void clear() { mMatrix[0].clear(); diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 0e3900e273..3f2d85aec9 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -53,8 +53,7 @@ #include "lltimer.h" #include "llvolumeoctree.h" -#include "mikktspace/mikktspace.h" -#include "mikktspace/mikktspace.c" // insert mikktspace implementation into llvolume object file +#include "mikktspace/mikktspace.hh" #include "meshoptimizer/meshoptimizer.h" @@ -5474,6 +5473,40 @@ struct MikktData } } } + + uint32_t GetNumFaces() + { + return uint32_t(face->mNumIndices / 3); + } + + uint32_t GetNumVerticesOfFace(const uint32_t face_num) + { + return 3; + } + + mikk::float3 GetPosition(const uint32_t face_num, const uint32_t vert_num) + { + F32* v = p[face_num * 3 + vert_num].mV; + return mikk::float3(v); + } + + mikk::float3 GetTexCoord(const uint32_t face_num, const uint32_t vert_num) + { + F32* uv = tc[face_num * 3 + vert_num].mV; + return mikk::float3(uv[0], uv[1], 1.0f); + } + + mikk::float3 GetNormal(const uint32_t face_num, const uint32_t vert_num) + { + F32* normal = n[face_num * 3 + vert_num].mV; + return mikk::float3(normal); + } + + void SetTangentSpace(const uint32_t face_num, const uint32_t vert_num, mikk::float3 T, bool orientation) + { + S32 i = face_num * 3 + vert_num; + t[i].set(T.x, T.y, T.z, orientation ? 1.0f : -1.0f); + } }; bool LLVolumeFace::cacheOptimize(bool gen_tangents) @@ -5486,62 +5519,9 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) { // generate mikkt space tangents before cache optimizing since the index buffer may change // a bit of a hack to do this here, but this function gets called exactly once for the lifetime of a mesh // and is executed on a background thread - SMikkTSpaceInterface ms; - - ms.m_getNumFaces = [](const SMikkTSpaceContext* pContext) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - LLVolumeFace* face = data->face; - return face->mNumIndices / 3; - }; - - ms.m_getNumVerticesOfFace = [](const SMikkTSpaceContext* pContext, const int iFace) - { - return 3; - }; - - ms.m_getPosition = [](const SMikkTSpaceContext* pContext, float fvPosOut[], const int iFace, const int iVert) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - F32* v = data->p[iFace * 3 + iVert].mV; - fvPosOut[0] = v[0]; - fvPosOut[1] = v[1]; - fvPosOut[2] = v[2]; - }; - - ms.m_getNormal = [](const SMikkTSpaceContext* pContext, float fvNormOut[], const int iFace, const int iVert) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - F32* n = data->n[iFace * 3 + iVert].mV; - fvNormOut[0] = n[0]; - fvNormOut[1] = n[1]; - fvNormOut[2] = n[2]; - }; - - ms.m_getTexCoord = [](const SMikkTSpaceContext* pContext, float fvTexcOut[], const int iFace, const int iVert) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - F32* tc = data->tc[iFace * 3 + iVert].mV; - fvTexcOut[0] = tc[0]; - fvTexcOut[1] = tc[1]; - }; - - ms.m_setTSpaceBasic = [](const SMikkTSpaceContext* pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert) - { - MikktData* data = (MikktData*)pContext->m_pUserData; - S32 i = iFace * 3 + iVert; - - data->t[i].set(fvTangent); - data->t[i].mV[3] = fSign; - }; - - ms.m_setTSpace = nullptr; - MikktData data(this); - - SMikkTSpaceContext ctx = { &ms, &data }; - - genTangSpaceDefault(&ctx); + mikk::Mikktspace ctx(data); + ctx.genTangSpace(); //re-weld meshopt_Stream mos[] = @@ -5562,9 +5542,6 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) if (vert_count < 65535 && vert_count != 0) { - std::vector indices; - indices.resize(mNumIndices); - //copy results back into volume resizeVertices(vert_count); 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/llglslshader.h b/indra/llrender/llglslshader.h index e8529ebadc..ed0f27d143 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -49,7 +49,6 @@ public: bool hasShadows = false; bool hasAmbientOcclusion = false; bool hasSrgb = false; - bool encodesNormal = false; // include: shaders\class1\environment\encodeNormF.glsl bool isDeferred = false; bool hasScreenSpaceReflections = false; bool disableTextureIndex = false; diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 92432b4f38..7e6a829abe 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -2124,10 +2124,6 @@ void LLRender::diffuseColor3f(F32 r, F32 g, F32 b) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,1.f); } - else - { - glColor3f(r,g,b); - } } void LLRender::diffuseColor3fv(const F32* c) @@ -2139,10 +2135,6 @@ void LLRender::diffuseColor3fv(const F32* c) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0], c[1], c[2], 1.f); } - else - { - glColor3fv(c); - } } void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a) @@ -2154,10 +2146,6 @@ void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,a); } - else - { - glColor4f(r,g,b,a); - } } void LLRender::diffuseColor4fv(const F32* c) @@ -2169,10 +2157,6 @@ void LLRender::diffuseColor4fv(const F32* c) { shader->uniform4fv(LLShaderMgr::DIFFUSE_COLOR, 1, c); } - else - { - glColor4fv(c); - } } void LLRender::diffuseColor4ubv(const U8* c) @@ -2184,10 +2168,6 @@ void LLRender::diffuseColor4ubv(const U8* c) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0]/255.f, c[1]/255.f, c[2]/255.f, c[3]/255.f); } - else - { - glColor4ubv(c); - } } void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a) @@ -2199,10 +2179,6 @@ void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r/255.f, g/255.f, b/255.f, a/255.f); } - else - { - glColor4ub(r,g,b,a); - } } diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 2a5dedc315..65c189ee5e 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -264,14 +264,6 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) } } - if (features->encodesNormal) - { - if (!shader->attachFragmentObject("environment/encodeNormF.glsl")) - { - return FALSE; - } - } - if (features->hasAtmospherics || features->isDeferred) { if (!shader->attachFragmentObject("windlight/atmosphericsFuncs.glsl")) { diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index ea6cc796d5..80a19513d0 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -757,8 +757,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 @@ -1155,7 +1155,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 @@ -1317,6 +1317,8 @@ bool LLVertexBuffer::getVertexStrider(LLStrider& strider, U32 index, } bool LLVertexBuffer::getIndexStrider(LLStrider& strider, U32 index, S32 count) { + llassert(mIndicesStride == 2); // cannot access 32-bit indices with U16 strider + llassert(mIndicesType == GL_UNSIGNED_SHORT); return VertexBufferStrider::get(*this, strider, index, count); } bool LLVertexBuffer::getTexCoord0Strider(LLStrider& strider, U32 index, S32 count) @@ -1534,4 +1536,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 4b6f1ad213..52be31831c 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -194,9 +194,13 @@ public: // 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; } @@ -228,6 +232,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 b6a0b1bbaf..a015c97dda 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -35,11 +35,11 @@ include(LLWindow) include(NDOF) include(NVAPI) include(OPENAL) -include(OpenEXR) include(OpenGL) include(OpenSSL) include(PNG) include(TemplateCheck) +include(TinyEXR) include(ThreeJS) include(Tracy) include(UI) @@ -187,7 +187,9 @@ set(viewer_SOURCE_FILES gltfscenemanager.cpp gltf/asset.cpp + gltf/accessor.cpp gltf/primitive.cpp + gltf/animation.cpp groupchatlistener.cpp llaccountingcostmanager.cpp llaisapi.cpp @@ -986,7 +988,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 @@ -2184,12 +2189,6 @@ if (WINDOWS) media_plugin_cef media_plugin_libvlc #media_plugin_example # Don't package example plugin - ${SHARED_LIB_STAGING_DIR}/Iex-3_2.dll - ${SHARED_LIB_STAGING_DIR}/IlmThread-3_2.dll - ${SHARED_LIB_STAGING_DIR}/Imath-3_1.dll - ${SHARED_LIB_STAGING_DIR}/OpenEXR-3_2.dll - ${SHARED_LIB_STAGING_DIR}/OpenEXRCore-3_2.dll - ${SHARED_LIB_STAGING_DIR}/OpenEXRUtil-3_2.dll ) # Only copy OpenJPEG dll if needed @@ -2397,7 +2396,6 @@ target_link_libraries(${VIEWER_BINARY_NAME} ll::bugsplat ll::tracy ll::icu4c - ll::openexr fs::glod # restore GLOD dependencies fs::discord # Discord support ) diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl index c0607d0149..db7597dd74 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl @@ -25,7 +25,7 @@ /*[EXTRA_CODE_HERE]*/ -out vec4 frag_data[3]; +out vec4 frag_data[4]; uniform sampler2D diffuseMap; @@ -35,7 +35,6 @@ in vec3 vary_normal; in vec2 vary_texcoord0; in vec3 vary_position; -vec2 encode_normal(vec3 n); void mirrorClip(vec3 pos); void main() @@ -52,6 +51,7 @@ void main() frag_data[0] = vec4(diff.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); + frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl index 08baf98686..8627ab1852 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl @@ -40,12 +40,12 @@ uniform float kern_scale; in vec2 vary_fragcoord; vec4 getPosition(vec2 pos_screen); -vec3 getNorm(vec2 pos_screen); +vec4 getNorm(vec2 pos_screen); void main() { vec2 tc = vary_fragcoord.xy; - vec3 norm = getNorm(tc); + vec4 norm = getNorm(tc); vec3 pos = getPosition(tc).xyz; vec4 ccol = texture(lightMap, tc).rgba; diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl index a22c174349..8483f257fa 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl @@ -39,8 +39,6 @@ in vec4 vertex_color; in vec2 vary_texcoord0; in vec3 vary_position; -vec2 encode_normal(vec3 n); - void mirrorClip(vec3 pos); void main() { @@ -64,6 +62,6 @@ void main() frag_data[1] = vertex_color.aaaa; // spec //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested vec3 nvn = normalize(tnorm); - frag_data[2] = vec4(encode_normal(nvn), vertex_color.a, GBUFFER_FLAG_HAS_ATMOS); - frag_data[3] = vec4(0); + frag_data[2] = vec4(nvn, GBUFFER_FLAG_HAS_ATMOS); + frag_data[3] = vec4(vertex_color.a, 0, 0, 0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl index f9ebf33b4a..f6696e270c 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl @@ -50,6 +50,7 @@ SOFTWARE. uniform sampler2D normalMap; uniform sampler2D depthMap; +uniform sampler2D emissiveRect; uniform sampler2D projectionMap; // rgba uniform sampler2D brdfLut; @@ -140,40 +141,20 @@ vec2 getScreenCoordinate(vec2 screenpos) return sc - vec2(1.0, 1.0); } -// See: https://aras-p.info/texts/CompactNormalStorage.html -// Method #4: Spheremap Transform, Lambert Azimuthal Equal-Area projection -vec3 getNorm(vec2 screenpos) +vec4 getNorm(vec2 screenpos) { - vec2 enc = texture(normalMap, screenpos.xy).xy; - vec2 fenc = enc*4-2; - float f = dot(fenc,fenc); - float g = sqrt(1-f/4); - vec3 n; - n.xy = fenc*g; - n.z = 1-f/2; - return n; -} - -vec3 getNormalFromPacked(vec4 packedNormalEnvIntensityFlags) -{ - vec2 enc = packedNormalEnvIntensityFlags.xy; - vec2 fenc = enc*4-2; - float f = dot(fenc,fenc); - float g = sqrt(1-f/4); - vec3 n; - n.xy = fenc*g; - n.z = 1-f/2; - return normalize(n); // TODO: Is this normalize redundant? + return texture(normalMap, screenpos.xy); } // return packedNormalEnvIntensityFlags since GBUFFER_FLAG_HAS_PBR needs .w // See: C++: addDeferredAttachments(), GLSL: softenLightF vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity) { - vec4 packedNormalEnvIntensityFlags = texture(normalMap, screenpos.xy); - n = getNormalFromPacked( packedNormalEnvIntensityFlags ); - envIntensity = packedNormalEnvIntensityFlags.z; - return packedNormalEnvIntensityFlags; + vec4 norm = texture(normalMap, screenpos.xy); + n = norm.xyz; + envIntensity = texture(emissiveRect, screenpos.xy).r; + + return norm; } // get linear depth value given a depth buffer sample d and znear and zfar values diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl index e8ead91504..82d5d363d2 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl @@ -37,8 +37,6 @@ in vec3 vary_normal; in vec4 vertex_color; in vec2 vary_texcoord0; -vec2 encode_normal(vec3 n); - void mirrorClip(vec3 pos); void main() @@ -55,7 +53,7 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); // spec vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl index a07c892d8e..788ea633fc 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl @@ -35,8 +35,6 @@ uniform float minimum_alpha; in vec4 vertex_color; in vec2 vary_texcoord0; -vec2 encode_normal(vec3 n); - void mirrorClip(vec3 pos); void main() @@ -53,6 +51,6 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl index 234f096ed5..22e6d60419 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl @@ -34,8 +34,6 @@ uniform sampler2D diffuseMap; in vec3 vary_normal; in vec2 vary_texcoord0; -vec2 encode_normal(vec3 n); - void main() { vec4 col = texture(diffuseMap, vary_texcoord0.xy); @@ -48,7 +46,7 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); // spec vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl index 76776ede2c..799fc62a42 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl @@ -34,7 +34,6 @@ in vec4 vertex_color; in vec2 vary_texcoord0; in vec3 vary_position; -vec2 encode_normal(vec3 n); void mirrorClip(vec3 pos); void main() @@ -45,7 +44,7 @@ void main() frag_data[1] = vertex_color.aaaa; // spec //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, GBUFFER_FLAG_HAS_ATMOS); - frag_data[3] = vec4(0); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); + frag_data[3] = vec4(vertex_color.a, 0, 0, 0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl index b983acf657..3362a180c6 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl @@ -33,7 +33,6 @@ in vec2 vary_texcoord0; in vec3 vary_position; void mirrorClip(vec3 pos); -vec2 encode_normal(vec3 n); vec3 linear_to_srgb(vec3 c); void main() @@ -47,6 +46,6 @@ void main() frag_data[0] = vec4(col, 0.0); frag_data[1] = vec4(spec, vertex_color.a); // spec vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, GBUFFER_FLAG_HAS_ATMOS); - frag_data[3] = vec4(0); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); + frag_data[3] = vec4(vertex_color.a, 0, 0, 0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl index aae595f619..c64f65e32c 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl @@ -37,7 +37,6 @@ uniform sampler2D specularMap; in vec2 vary_texcoord0; vec3 linear_to_srgb(vec3 c); -vec2 encode_normal (vec3 n); void main() { @@ -53,6 +52,6 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = spec; - frag_data[2] = vec4(encode_normal(norm.xyz),0,GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(norm.xyz, GBUFFER_FLAG_HAS_ATMOS); frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl index 0683236460..1d5f810cf3 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl @@ -54,7 +54,6 @@ in vec2 emissive_texcoord; uniform float minimum_alpha; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff() -vec2 encode_normal(vec3 n); vec3 linear_to_srgb(vec3 c); vec3 srgb_to_linear(vec3 c); @@ -110,7 +109,7 @@ void main() // See: C++: addDeferredAttachments(), GLSL: softenLightF frag_data[0] = max(vec4(col, 0.0), vec4(0)); // Diffuse frag_data[1] = max(vec4(spec.rgb,vertex_color.a), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal. - frag_data[2] = max(vec4(encode_normal(tnorm), vertex_color.a, GBUFFER_FLAG_HAS_PBR), vec4(0)); // normal, environment intensity, flags + frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); // normal, environment intensity, flags frag_data[3] = max(vec4(emissive,0), vec4(0)); // PBR sRGB Emissive } diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl index 57c0a6024f..de4745c1c4 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrterrainF.glsl @@ -140,7 +140,6 @@ flat in float vary_sign; in vec4 vary_texcoord0; in vec4 vary_texcoord1; -vec2 encode_normal(vec3 n); void mirrorClip(vec3 position); float terrain_mix(TerrainMix tm, vec4 tms4); @@ -342,7 +341,7 @@ void main() #endif frag_data[0] = max(vec4(mix.col.xyz, 0.0), vec4(0)); // Diffuse frag_data[1] = max(vec4(orm.rgb, base_color_factor_alpha), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal. - frag_data[2] = max(vec4(encode_normal(tnorm), base_color_factor_alpha, GBUFFER_FLAG_HAS_PBR), vec4(0)); // normal, environment intensity, flags + frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); // normal, flags frag_data[3] = max(vec4(emissive,0), vec4(0)); // PBR sRGB Emissive } diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl index 2dba7cb9d9..5f598f84a7 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl @@ -38,7 +38,6 @@ in vec3 vary_normal; in vec4 vary_texcoord0; in vec4 vary_texcoord1; -vec2 encode_normal(vec3 n); void mirrorClip(vec3 position); void main() @@ -61,7 +60,7 @@ void main() frag_data[0] = outColor; frag_data[1] = vec4(0.0,0.0,0.0,-1.0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl index f108faf283..708acd0194 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl @@ -36,8 +36,6 @@ in vec3 vary_position; uniform float minimum_alpha; -vec2 encode_normal(vec3 n); - void mirrorClip(vec3 pos); void main() { @@ -51,6 +49,6 @@ void main() frag_data[0] = vec4(vertex_color.rgb*col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS); frag_data[3] = vec4(0); } diff --git a/indra/newview/app_settings/shaders/class1/environment/encodeNormF.glsl b/indra/newview/app_settings/shaders/class1/environment/encodeNormF.glsl deleted file mode 100644 index 6cd2445522..0000000000 --- a/indra/newview/app_settings/shaders/class1/environment/encodeNormF.glsl +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @file encodeNormF.glsl - * - * $LicenseInfo:firstyear=2018&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2018, 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$ - */ - -// Lambert Azimuthal Equal-Area projection -// See: https://aras-p.info/texts/CompactNormalStorage.html -// Also see: A_bit_more_deferred_-_CryEngine3.ppt -vec2 encode_normal(vec3 n) -{ - float f = sqrt(8 * n.z + 8); - return n.xy / f + 0.5; -} - diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl index 4aef22c296..7a1a54a77a 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl @@ -68,7 +68,6 @@ void waterClip(vec3 pos); vec3 srgb_to_linear(vec3 c); vec3 linear_to_srgb(vec3 c); -vec2 encode_normal (vec3 n); vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color); void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl index 1ea57516a4..1bd5f5a718 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl @@ -35,7 +35,7 @@ in vec2 vary_fragcoord; uniform vec3 sun_dir; uniform float shadow_bias; -vec3 getNorm(vec2 pos_screen); +vec4 getNorm(vec2 pos_screen); vec4 getPosition(vec2 pos_screen); float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen); @@ -45,13 +45,13 @@ void main() { vec2 pos_screen = vary_fragcoord.xy; vec4 pos = getPosition(pos_screen); - vec3 norm = getNorm(pos_screen); + vec4 norm = getNorm(pos_screen); vec4 col; - col.r = sampleDirectionalShadow(pos.xyz, norm, pos_screen); + col.r = sampleDirectionalShadow(pos.xyz, norm.xyz, pos_screen); col.g = 1.0f; - col.b = sampleSpotShadow(pos.xyz, norm, 0, pos_screen); - col.a = sampleSpotShadow(pos.xyz, norm, 1, pos_screen); + col.b = sampleSpotShadow(pos.xyz, norm.xyz, 0, pos_screen); + col.a = sampleSpotShadow(pos.xyz, norm.xyz, 1, pos_screen); frag_color = clamp(col, vec4(0), vec4(1)); } diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl index 0126e09d4c..e0333b6044 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl @@ -32,7 +32,7 @@ out vec4 frag_color; in vec2 vary_fragcoord; vec4 getPosition(vec2 pos_screen); -vec3 getNorm(vec2 pos_screen); +vec4 getNorm(vec2 pos_screen); float sampleDirectionalShadow(vec3 shadow_pos, vec3 norm, vec2 pos_screen); float sampleSpotShadow(vec3 shadow_pos, vec3 norm, int index, vec2 pos_screen); @@ -42,13 +42,13 @@ void main() { vec2 pos_screen = vary_fragcoord.xy; vec4 pos = getPosition(pos_screen); - vec3 norm = getNorm(pos_screen); + vec4 norm = getNorm(pos_screen); vec4 col; - col.r = sampleDirectionalShadow(pos.xyz, norm, pos_screen); - col.g = calcAmbientOcclusion(pos, norm, pos_screen); - col.b = sampleSpotShadow(pos.xyz, norm, 0, pos_screen); - col.a = sampleSpotShadow(pos.xyz, norm, 1, pos_screen); + col.r = sampleDirectionalShadow(pos.xyz, norm.xyz, pos_screen); + col.g = calcAmbientOcclusion(pos, norm.xyz, pos_screen); + col.b = sampleSpotShadow(pos.xyz, norm.xyz, 0, pos_screen); + col.a = sampleSpotShadow(pos.xyz, norm.xyz, 1, pos_screen); frag_color = clamp(col, vec4(0), vec4(1)); } diff --git a/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl index 0b154e82ad..4af57e3b80 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/hazeF.glsl @@ -33,7 +33,7 @@ uniform vec3 moon_dir; uniform int sun_up_factor; in vec2 vary_fragcoord; -vec3 getNorm(vec2 pos_screen); +vec4 getNorm(vec2 pos_screen); vec4 getPositionWithDepth(vec2 pos_screen, float depth); void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); @@ -53,8 +53,7 @@ void main() vec2 tc = vary_fragcoord.xy; float depth = getDepth(tc.xy); vec4 pos = getPositionWithDepth(tc, depth); - vec4 norm = texture(normalMap, tc); - norm.xyz = getNorm(tc); + vec4 norm = getNorm(tc); vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; vec3 color = vec3(0); diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl index 0476b98e10..2a20eb79d2 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl @@ -216,8 +216,6 @@ in vec3 vary_normal; in vec4 vertex_color; in vec2 vary_texcoord0; -vec2 encode_normal(vec3 n); - // get the transformed normal and apply glossiness component from normal map vec3 getNormal(inout float glossiness) { @@ -306,8 +304,6 @@ void main() float glossiness = specular_color.a; vec3 norm = getNormal(glossiness); - vec2 abnormal = encode_normal(norm.xyz); - float emissive = getEmissive(diffcol); #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) @@ -417,10 +413,12 @@ void main() float flag = GBUFFER_FLAG_HAS_ATMOS; - frag_data[0] = vec4(diffcol.rgb, emissive); // gbuffer is sRGB for legacy materials - frag_data[1] = vec4(spec.rgb, glossiness); // XYZ = Specular color. W = Specular exponent. - frag_data[2] = vec4(encode_normal(norm), env, flag);; // XY = Normal. Z = Env. intensity. W = 1 skip atmos (mask off fog) - frag_data[3] = vec4(0); + frag_data[0] = max(vec4(diffcol.rgb, emissive), vec4(0)); // gbuffer is sRGB for legacy materials + frag_data[1] = max(vec4(spec.rgb, glossiness), vec4(0)); // XYZ = Specular color. W = Specular exponent. + frag_data[2] = vec4(norm, flag); // XY = Normal. Z = Env. intensity. W = 1 skip atmos (mask off fog) + frag_data[3] = vec4(env, 0, 0, 0); + #endif } + diff --git a/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl index ec8168465e..edfd6cbced 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/multiPointLightF.glsl @@ -48,7 +48,7 @@ in vec4 vary_fragcoord; void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); float calcLegacyDistanceAttenuation(float distance, float falloff); vec4 getPosition(vec2 pos_screen); -vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity); +vec4 getNorm(vec2 screenpos); vec2 getScreenXY(vec4 clip); vec2 getScreenCoord(vec4 clip); vec3 srgb_to_linear(vec3 c); @@ -74,9 +74,8 @@ void main() discard; } - float envIntensity; // not used for this shader - vec3 n; - vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG() + vec4 norm = getNorm(tc); // need `norm.w` for GET_GBUFFER_FLAG() + vec3 n = norm.xyz; vec4 spec = texture(specularRect, tc); vec3 diffuse = texture(diffuseRect, tc).rgb; diff --git a/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl index 31af1208bd..60be9f4407 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/pointLightF.glsl @@ -52,7 +52,7 @@ uniform vec4 viewport; void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); float calcLegacyDistanceAttenuation(float distance, float falloff); -vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity); +vec4 getNorm(vec2 screenpos); vec4 getPosition(vec2 pos_screen); vec2 getScreenXY(vec4 clip); vec2 getScreenCoord(vec4 clip); @@ -72,9 +72,8 @@ void main() vec2 tc = getScreenCoord(vary_fragcoord); vec3 pos = getPosition(tc).xyz; - float envIntensity; - vec3 n; - vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG() + vec4 norm = getNorm(tc); // need `norm.w` for GET_GBUFFER_FLAG() + vec3 n = norm.xyz; vec3 diffuse = texture(diffuseRect, tc).rgb; vec4 spec = texture(specularRect, tc); diff --git a/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl b/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl index dbf20fe2d8..deb276ef9d 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/screenSpaceReflPostF.glsl @@ -40,14 +40,13 @@ uniform sampler2D specularRect; uniform sampler2D diffuseRect; uniform sampler2D diffuseMap; -vec3 getNorm(vec2 screenpos); +vec4 getNorm(vec2 screenpos); float getDepth(vec2 pos_screen); float linearDepth(float d, float znear, float zfar); float linearDepth01(float d, float znear, float zfar); vec4 getPositionWithDepth(vec2 pos_screen, float depth); vec4 getPosition(vec2 pos_screen); -vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity); float random (vec2 uv); @@ -57,9 +56,7 @@ void main() { vec2 tc = vary_fragcoord.xy; float depth = linearDepth01(getDepth(tc), zNear, zFar); - float envIntensity; - vec3 n; - vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); // need `norm.w` for GET_GBUFFER_FLAG() + vec4 norm = getNorm(tc); // need `norm.w` for GET_GBUFFER_FLAG() vec3 pos = getPositionWithDepth(tc, getDepth(tc)).xyz; vec4 spec = texture(specularRect, tc); vec2 hitpixel; @@ -84,7 +81,7 @@ void main() vec4 collectedColor = vec4(0); - float w = tapScreenSpaceReflection(4, tc, pos, n, collectedColor, diffuseMap, 0); + float w = tapScreenSpaceReflection(4, tc, pos, norm.xyz, collectedColor, diffuseMap, 0); collectedColor.rgb *= specCol.rgb; diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl index 9b9739ba22..96c32734e4 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl @@ -61,7 +61,7 @@ in vec2 vary_fragcoord; uniform mat4 inv_proj; uniform vec2 screen_res; -vec3 getNorm(vec2 pos_screen); +vec4 getNorm(vec2 pos_screen); vec4 getPositionWithDepth(vec2 pos_screen, float depth); void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive); @@ -128,13 +128,13 @@ void main() vec2 tc = vary_fragcoord.xy; float depth = getDepth(tc.xy); vec4 pos = getPositionWithDepth(tc, depth); - vec4 norm = texture(normalMap, tc); - float envIntensity = norm.z; - norm.xyz = getNorm(tc); + vec4 norm = getNorm(tc); + vec3 colorEmissive = texture(emissiveRect, tc).rgb; + float envIntensity = colorEmissive.r; vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir; vec4 baseColor = texture(diffuseRect, tc); - vec4 spec = texture(specularRect, vary_fragcoord.xy); // NOTE: PBR linear Emissive + vec4 spec = texture(specularRect, tc); // NOTE: PBR linear Emissive #if defined(HAS_SUN_SHADOW) || defined(HAS_SSAO) vec2 scol_ambocc = texture(lightMap, vary_fragcoord.xy).rg; @@ -169,12 +169,12 @@ void main() if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) { - vec3 orm = texture(specularRect, tc).rgb; + vec3 orm = spec.rgb; float perceptualRoughness = orm.g; float metallic = orm.b; float ao = orm.r; - vec3 colorEmissive = texture(emissiveRect, tc).rgb; + // PBR IBL float gloss = 1.0 - perceptualRoughness; @@ -192,12 +192,12 @@ void main() else if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_HDRI)) { // actual HDRI sky, just copy color value - color = texture(emissiveRect, tc).rgb; + color = colorEmissive.rgb; } else if (GET_GBUFFER_FLAG(GBUFFER_FLAG_SKIP_ATMOS)) { //should only be true of WL sky, port over base color value and scale for fake HDR - color = texture(emissiveRect, tc).rgb; + color = colorEmissive.rgb; color = srgb_to_linear(color); color *= sky_hdr_scale; } diff --git a/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl index d31b37fb60..319fa86148 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/spotLightF.glsl @@ -72,7 +72,7 @@ uniform mat4 inv_proj; void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist); float calcLegacyDistanceAttenuation(float distance, float falloff); bool clipProjectedLightVars(vec3 center, vec3 pos, out float dist, out float l_dist, out vec3 lv, out vec4 proj_tc ); -vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity); +vec4 getNorm(vec2 screenpos); vec3 getProjectedLightAmbiance(float amb_da, float attenuation, float lit, float nl, float noise, vec2 projected_uv); vec3 getProjectedLightDiffuseColor(float light_distance, vec2 projected_uv ); vec2 getScreenCoord(vec4 clip); @@ -121,9 +121,8 @@ void main() shadow = clamp(shadow, 0.0, 1.0); } - float envIntensity; - vec3 n; - vec4 norm = getNormalEnvIntensityFlags(tc, n, envIntensity); + vec4 norm = getNorm(tc); + vec3 n = norm.xyz; float dist_atten = calcLegacyDistanceAttenuation(dist, falloff); if (dist_atten <= 0.0) @@ -145,7 +144,6 @@ void main() if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR)) { - vec3 colorEmissive = texture(emissiveRect, tc).rgb; vec3 orm = spec.rgb; float perceptualRoughness = orm.g; float metallic = orm.b; @@ -182,6 +180,8 @@ void main() } else { + float envIntensity = texture(emissiveRect, tc).r; + diffuse = srgb_to_linear(diffuse); spec.rgb = srgb_to_linear(spec.rgb); diff --git a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl index f6b8299f91..f6bef1e498 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl @@ -56,7 +56,6 @@ void main() } vec4 pos = getPositionWithDepth(tc, depth); - vec4 norm = texture(normalMap, tc); vec4 fogged = getWaterFogView(pos.xyz); 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 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 mMax; + std::vector 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 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 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 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 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 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 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 mRotationChannels; + std::vector mTranslationChannels; + std::vector 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 092b6e5d4b..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,12 +68,16 @@ LLMatrix4a inverse(const LLMatrix4a& mat); void Node::updateTransforms(Asset& asset, const LLMatrix4a& parentMatrix) { + makeMatrixValid(); matMul(mMatrix, parentMatrix, mAssetMatrix); mAssetMatrixInv = inverse(mAssetMatrix); + S32 my_index = this - &asset.mNodes[0]; + for (auto& childIndex : mChildren) { Node& child = asset.mNodes[childIndex]; + child.mParent = my_index; child.updateTransforms(asset, mAssetMatrix); } } @@ -96,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); } @@ -209,3 +215,450 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, } +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(); + + if (src.matrix.size() == 16) + { + // Node has a transformation matrix, just copy it + for (U32 i = 0; i < 16; ++i) + { + 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 + if (src.rotation.size() == 4) + { + mRotation = glh::quaternionf((F32)src.rotation[0], (F32)src.rotation[1], (F32)src.rotation[2], (F32)src.rotation[3]); + } + + if (src.translation.size() == 3) + { + mTranslation = glh::vec3f((F32)src.translation[0], (F32)src.translation[1], (F32)src.translation[2]); + } + + glh::vec3f scale; + if (src.scale.size() == 3) + { + mScale = glh::vec3f((F32)src.scale[0], (F32)src.scale[1], (F32)src.scale[2]); + } + else + { + mScale.set_value(1.f, 1.f, 1.f); + } + + mTRSValid = true; + } + else + { + // node specifies no transformation, set to identity + mMatrix.setIdentity(); + } + + mChildren = src.children; + mMesh = src.mesh; + mSkin = src.skin; + mName = src.name; + + return *this; +} + +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) + { + if (!rigged) + { + gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix); + } + bool cull = true; + if (primitive.mMaterial != INVALID_INDEX) + { + Material& material = mMaterials[primitive.mMaterial]; + + if ((material.mMaterial->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND) == opaque) + { + continue; + } + material.mMaterial->bind(); + cull = !material.mMaterial->mDoubleSided; + } + else + { + if (!opaque) + { + continue; + } + LLFetchedGLTFMaterial::sDefault.bind(); + } + + LLGLDisable cull_face(!cull ? GL_CULL_FACE : 0); + + primitive.mVertexBuffer->setBuffer(); + if (primitive.mVertexBuffer->getNumIndices() > 0) + { + primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0); + } + else + { + primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts()); + } + + } + } + } +} + +void Asset::renderOpaque() +{ + render(true); +} + +void Asset::renderTransparent() +{ + render(false); +} + +void Asset::update() +{ + F32 dt = gFrameTimeSeconds - mLastUpdateTime; + + if (dt > 0.f) + { + mLastUpdateTime = gFrameTimeSeconds; + if (mAnimations.size() > 0) + { + static LLCachedControl anim_idx(gSavedSettings, "GLTFAnimationIndex", 0); + static LLCachedControl 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 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 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 0f1d4e8993..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 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 mMax; - std::vector 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 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 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,32 +76,27 @@ 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 mChildren; + S32 mParent = INVALID_INDEX; + S32 mMesh = INVALID_INDEX; + S32 mSkin = INVALID_INDEX; + std::string mName; - const Node& operator=(const tinygltf::Node& src) - { - F32* dstMatrix = mMatrix.getF32ptr(); - - if (src.matrix.size() != 16) - { - mMatrix.setIdentity(); - } - else - { - for (U32 i = 0; i < 16; ++i) - { - dstMatrix[i] = (F32)src.matrix[i]; - } - } - - mChildren = src.children; - mMesh = src.mesh; - mName = src.name; - - return *this; - } + const Node& operator=(const tinygltf::Node& src); // Set mRenderMatrix to a transform that can be used for the current render pass // modelview -- parent's render matrix @@ -203,7 +104,39 @@ 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 Skin + { + public: + S32 mInverseBindMatrices = INVALID_INDEX; + S32 mSkeleton = INVALID_INDEX; + std::vector mJoints; + std::string mName; + std::vector mInverseBindMatricesData; + + void allocateGLResources(Asset& asset); + void uploadMatrixPalette(Asset& asset, Node& node); + + const Skin& operator=(const tinygltf::Skin& src); }; class Scene @@ -212,17 +145,10 @@ namespace LL std::vector mNodes; std::string mName; - const Scene& operator=(const tinygltf::Scene& src) - { - mNodes = src.nodes; - mName = src.name; - - return *this; - } - + const Scene& operator=(const tinygltf::Scene& src); + void updateTransforms(Asset& asset); void updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview); - }; class Texture @@ -232,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 @@ -251,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 @@ -311,25 +221,21 @@ namespace LL std::vector mSamplers; std::vector mImages; std::vector mAccessors; + std::vector mAnimations; + std::vector mSkins; - void allocateGLResources(const std::string& filename, const tinygltf::Model& model) - { - for (auto& mesh : mMeshes) - { - mesh.allocateGLResources(*this); - } + // the last time update() was called according to gFrameTimeSeconds + F32 mLastUpdateTime = gFrameTimeSeconds; - for (auto& image : mImages) - { - image.allocateGLResources(); - } - - for (U32 i = 0; i < mMaterials.size(); ++i) - { - mMaterials[i].allocateGLResources(*this); - LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true); - } - } + // 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(); @@ -337,34 +243,9 @@ namespace LL // update node render transforms void updateRenderTransforms(const LLMatrix4a& modelview); - void renderOpaque() - { - for (auto& node : mNodes) - { - if (node.mMesh != INVALID_INDEX) - { - Mesh& mesh = mMeshes[node.mMesh]; - for (auto& primitive : mesh.mPrimitives) - { - gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix); - if (primitive.mMaterial != INVALID_INDEX) - { - Material& material = mMaterials[primitive.mMaterial]; - material.mMaterial->bind(); - } - primitive.mVertexBuffer->setBuffer(); - if (primitive.mVertexBuffer->getNumIndices() > 0) - { - primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0); - } - else - { - primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts()); - } - } - } - } - } + void render(bool opaque, bool rigged = false); + void renderOpaque(); + void renderTransparent(); // return the index of the node that the line segment intersects with, or -1 if no hit // input and output values must be in this asset's local coordinate frame @@ -376,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 + static void copyScalar(S* src, T& dst) + { + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; + } + + // copy one vec2 from src to dst + template + static void copyVec2(S* src, T& dst) + { + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; + } + + // copy one vec3 from src to dst + template + static void copyVec3(S* src, T& dst) + { + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; + } + + // copy one vec4 from src to dst + template + static void copyVec4(S* src, T& dst) + { + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; + } + + // copy one vec2 from src to dst + template + static void copyMat2(S* src, T& dst) + { + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; + } + + // copy one vec3 from src to dst + template + static void copyMat3(S* src, T& dst) + { + LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; + } + + // copy one vec4 from src to dst + template + 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* src, F32& dst) + { + dst = *src; + } + + template<> + void copyScalar(U32* src, U32& dst) + { + dst = *src; + } + + template<> + void copyScalar(U32* src, U16& dst) + { + dst = *src; + } + + template<> + void copyScalar(U16* src, U16& dst) + { + dst = *src; + } + + template<> + void copyScalar(U16* src, U32& dst) + { + dst = *src; + } + + template<> + void copyScalar(U8* src, U16& dst) + { + dst = *src; + } + + template<> + void copyScalar(U8* src, U32& dst) + { + dst = *src; + } + + template<> + void copyVec2(F32* src, LLVector2& dst) + { + dst.set(src[0], src[1]); + } + + template<> + void copyVec3(F32* src, glh::vec3f& dst) + { + dst.set_value(src[0], src[1], src[2]); + } + + template<> + void copyVec3(F32* src, LLVector4a& dst) + { + dst.load3(src); + } + + template<> + void copyVec3(U16* src, LLColor4U& dst) + { + dst.set(src[0], src[1], src[2], 255); + } + + template<> + void copyVec4(U8* src, LLColor4U& dst) + { + dst.set(src[0], src[1], src[2], src[3]); + } + + template<> + void copyVec4(U16* src, LLColor4U& dst) + { + dst.set(src[0], src[1], src[2], src[3]); + } + + template<> + void copyVec4(F32* src, LLColor4U& dst) + { + dst.set(src[0]*255, src[1]*255, src[2]*255, src[3]*255); + } + + template<> + void copyVec4(F32* src, LLVector4a& dst) + { + dst.loadua(src); + } + + template<> + void copyVec4(U16* src, LLVector4a& dst) + { + dst.set(src[0], src[1], src[2], src[3]); + } + + template<> + void copyVec4(U8* src, LLVector4a& dst) + { + dst.set(src[0], src[1], src[2], src[3]); + } + + template<> + void copyVec4(F32* src, glh::quaternionf& dst) + { + dst.set_value(src); + } + + template<> + void copyMat4(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 + static void copyScalar(S* src, LLStrider 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 + static void copyVec2(S* src, LLStrider 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 + static void copyVec3(S* src, LLStrider 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 + static void copyVec4(S* src, LLStrider 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 + static void copyMat2(S* src, LLStrider 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 + static void copyMat3(S* src, LLStrider 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 + static void copyMat4(S* src, LLStrider dst, S32 stride, S32 count) + { + for (S32 i = 0; i < count; ++i) + { + copyMat4(src, *dst); + dst++; + src = (S*)((U8*)src + stride); + } + } + + template + static void copy(Asset& asset, Accessor& accessor, const S* src, LLStrider& 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 + static void copy(Asset& asset, Accessor& accessor, LLStrider& 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 + static void copy(Asset& asset, Accessor& accessor, std::vector& dst) + { + dst.resize(accessor.mCount); + LLStrider strider = dst.data(); + copy(asset, accessor, strider); + } + } +} + diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index 71654dcfdd..b57a0af18d 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -27,148 +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 -void copyVec2(S* src, T& dst) -{ - LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; -} - -// copy one vec3 from src to dst -template -void copyVec3(S* src, T& dst) -{ - LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; -} - -// copy one vec4 from src to dst -template -void copyVec4(S* src, T& dst) -{ - LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL; -} - -template<> -void copyVec2(F32* src, LLVector2& dst) -{ - dst.set(src[0], src[1]); -} - -template<> -void copyVec3(F32* src, LLVector4a& dst) -{ - dst.load3(src); -} - -template<> -void copyVec3(U16* src, LLColor4U& dst) -{ - dst.set(src[0], src[1], src[2], 255); -} - -template<> -void copyVec4(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 -void copyVec2(S* src, LLStrider 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 -void copyVec3(S* src, LLStrider 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 -void copyVec4(S* src, LLStrider dst, S32 stride, S32 count) -{ - for (S32 i = 0; i < count; ++i) - { - copyVec3(src, *dst); - dst++; - src = (S*)((U8*)src + stride); - } -} - -template -void copyAttributeArray(Asset& asset, const Accessor& accessor, const S* src, LLStrider& 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 -void Primitive::copyAttribute(Asset& asset, S32 accessorIdx, LLStrider& 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 - - { - LL_ERRS() << "Unsupported component type" << LL_ENDL; - } -} - void Primitive::allocateGLResources(Asset& asset) { // allocate vertex buffer @@ -177,195 +41,174 @@ 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; - for (auto& it : mAttributes) - { - const Accessor& accessor = asset.mAccessors[it.second]; - numVertices = accessor.mCount; - break; - } - - // 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 dst; - mVertexBuffer->getVertexStrider(dst); - - copyAttribute(asset, it.second, dst); + copy(asset, accessor, mPositions); } else if (attribName == "NORMAL") { - needs_normal = false; - // load normal data - LLStrider dst; - mVertexBuffer->getNormalStrider(dst); - - copyAttribute(asset, it.second, dst); + copy(asset, accessor, mNormals); } else if (attribName == "TANGENT") { - needs_tangent = false; - // load tangent data - - LLStrider 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 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 dst; - mVertexBuffer->getTexCoord0Strider(dst); - - LLStrider 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]; - - const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset; - - LLStrider dst; - mVertexBuffer->getIndexStrider(dst); - mIndexArray.resize(numIndices); - - 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 - { - LL_ERRS("GLTF") << "Unsupported component type for indices" << LL_ENDL; - } - - U16* idx = (U16*)mVertexBuffer->getMappedIndices(); - for (U32 i = 0; i < numIndices; ++i) - { - mIndexArray[i] = idx[i]; - } + Accessor& accessor = asset.mAccessors[mIndices]; + copy(asset, accessor, mIndexArray); } - // fill in default values for missing attributes - if (needs_color) - { // set default color - LLStrider dst; - mVertexBuffer->getColorStrider(dst); - for (U32 i = 0; i < numVertices; ++i) - { - *(dst++) = LLColor4U(255, 255, 255, 255); - } - } - - if (needs_texcoord) - { // set default texcoord - LLStrider dst; - mVertexBuffer->getTexCoord0Strider(dst); - for (U32 i = 0; i < numVertices; ++i) - { - *(dst++) = LLVector2(0.0f, 0.0f); - } - } - - if (needs_normal) - { // set default normal - LLStrider dst; - mVertexBuffer->getNormalStrider(dst); - for (U32 i = 0; i < numVertices; ++i) - { - *(dst++) = LLVector4a(0.0f, 0.0f, 1.0f, 0.0f); - } - } - - if (needs_tangent) - { // TODO: generate tangents if needed - LLStrider dst; - mVertexBuffer->getTangentStrider(dst); - for (U32 i = 0; i < numVertices; ++i) - { - *(dst++) = LLVector4a(1.0f, 0.0f, 0.0f, 1.0f); - } - } - - mPositions.resize(numVertices); - mTexCoords.resize(numVertices); - mNormals.resize(numVertices); - mTangents.resize(numVertices); - - 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) + U32 mask = ATTRIBUTE_MASK; + + if (!mWeights.empty()) { - mPositions[i] = pos[i]; - mTexCoords[i] = tc[i]; - mNormals[i] = norm[i]; - mTangents[i] = tangent[i]; + mask |= LLVertexBuffer::MAP_WEIGHT4; } + + mVertexBuffer = new LLVertexBuffer(mask); + mVertexBuffer->allocateBuffer(mPositions.size(), mIndexArray.size()*2); // double the size of the index buffer for 32-bit indices + + mVertexBuffer->setBuffer(); + mVertexBuffer->setPositionData(mPositions.data()); + + if (!mIndexArray.empty()) + { + mVertexBuffer->setIndexData(mIndexArray.data()); + } + + 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; + for (auto& dst : mColors) + { + dst = LLColor4U(baseColor * LLColor4(dst)); + } + } + + mVertexBuffer->setColorData(mColors.data()); + + if (mNormals.empty()) + { + mNormals.resize(mPositions.size(), LLVector4a(0, 0, 1, 0)); + } + + mVertexBuffer->setNormalData(mNormals.data()); + + if (mTangents.empty()) + { + // TODO: generate tangents if needed + mTangents.resize(mPositions.size(), LLVector4a(1, 0, 0, 1)); + } + + mVertexBuffer->setTangentData(mTangents.data()); + + if (!mWeights.empty()) + { + std::vector 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) +{ + //store pointers to vertex data + tri->mV[0] = &v0; + tri->mV[1] = &v1; + tri->mV[2] = &v2; + + //store indices + tri->mIndex[0] = i0; + tri->mIndex[1] = i1; + tri->mIndex[2] = i2; + + //get minimum point + LLVector4a min = v0; + min.setMin(min, v1); + min.setMin(min, v2); + + //get maximum point + LLVector4a max = v0; + max.setMax(max, v1); + max.setMax(max, v2); + + //compute center + LLVector4a center; + center.setAdd(min, max); + center.mul(0.5f); + + tri->mPositionGroup = center; + + //compute "radius" + LLVector4a size; + size.setSub(max, min); + + tri->mRadius = size.getLength3().getF32() * scaler; } void Primitive::createOctree() @@ -373,62 +216,88 @@ void Primitive::createOctree() // create octree mOctree = new LLVolumeOctree(); + F32 scaler = 0.25f; + if (mMode == TINYGLTF_MODE_TRIANGLES) { - F32 scaler = 0.25f; - const U32 num_triangles = mVertexBuffer->getNumIndices() / 3; // 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]; - const LLVector4a& v0 = pos[indices[index]]; - const LLVector4a& v1 = pos[indices[index + 1]]; - const LLVector4a& v2 = pos[indices[index + 2]]; + S32 i0 = mIndexArray[index]; + S32 i1 = mIndexArray[index + 1]; + S32 i2 = mIndexArray[index + 2]; - //store pointers to vertex data - tri->mV[0] = &v0; - tri->mV[1] = &v1; - tri->mV[2] = &v2; + const LLVector4a& v0 = mPositions[i0]; + const LLVector4a& v1 = mPositions[i1]; + const LLVector4a& v2 = mPositions[i2]; + + initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); + + //insert + mOctree->insert(tri); + } + } + else if (mMode == TINYGLTF_MODE_TRIANGLE_STRIP) + { + const U32 num_triangles = mVertexBuffer->getNumIndices() - 2; + // Initialize all the triangles we need + mOctreeTriangles.resize(num_triangles); - //store indices - tri->mIndex[0] = indices[index]; - tri->mIndex[1] = indices[index + 1]; - tri->mIndex[2] = indices[index + 2]; + 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 = mIndexArray[index]; + S32 i1 = mIndexArray[index - 1]; + S32 i2 = mIndexArray[index - 2]; - //get minimum point - LLVector4a min = v0; - min.setMin(min, v1); - min.setMin(min, v2); + const LLVector4a& v0 = mPositions[i0]; + const LLVector4a& v1 = mPositions[i1]; + const LLVector4a& v2 = mPositions[i2]; - //get maximum point - LLVector4a max = v0; - max.setMax(max, v1); - max.setMax(max, v2); - - //compute center - LLVector4a center; - center.setAdd(min, max); - center.mul(0.5f); - - tri->mPositionGroup = center; - - //compute "radius" - LLVector4a size; - size.setSub(max, min); - - tri->mRadius = size.getLength3().getF32() * scaler; + initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); //insert mOctree->insert(tri); } } + else if (mMode == TINYGLTF_MODE_TRIANGLE_FAN) + { + const U32 num_triangles = mVertexBuffer->getNumIndices() - 2; + // Initialize all the triangles we need + mOctreeTriangles.resize(num_triangles); + + 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 = mIndexArray[0]; + S32 i1 = mIndexArray[index - 1]; + S32 i2 = mIndexArray[index - 2]; + + const LLVector4a& v0 = mPositions[i0]; + const LLVector4a& v1 = mPositions[i1]; + const LLVector4a& v2 = mPositions[i2]; + + initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2); + + //insert + mOctree->insert(tri); + } + } + else if (mMode == TINYGLTF_MODE_POINTS || + mMode == TINYGLTF_MODE_LINE || + mMode == TINYGLTF_MODE_LINE_LOOP || + mMode == TINYGLTF_MODE_LINE_STRIP) + { + // nothing to do, no volume... maybe add some collision geometry around these primitive types? + } + else { LL_ERRS() << "Unsupported Primitive mode" << LL_ENDL; @@ -461,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(); @@ -482,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 mNormals; std::vector mTangents; std::vector mPositions; - std::vector mIndexArray; + std::vector mJoints; + std::vector mWeights; + std::vector mColors; + std::vector mIndexArray; // raycast acceleration structure LLPointer mOctree; @@ -68,11 +71,6 @@ namespace LL S32 mIndices = -1; std::unordered_map mAttributes; - // copy the attribute in the given BufferView to the given destination - // assumes destination has enough storage for the attribute - template - void copyAttribute(Asset& asset, S32 bufferViewIdx, LLStrider& 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 6c44b83646..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 = new Asset(); *asset = model; + gDebugProgram.bind(); // bind a shader to satisfy LLVertexBuffer assertions asset->allocateGLResources(filename, model); asset->updateTransforms(); @@ -91,7 +92,11 @@ void GLTFSceneManager::load(const std::string& filename) if (obj) { // assign to self avatar obj->mGLTFAsset = asset; - mObjects.push_back(obj); + + if (std::find(mObjects.begin(), mObjects.end(), obj) == mObjects.end()) + { + mObjects.push_back(obj); + } } } @@ -100,43 +105,35 @@ GLTFSceneManager::~GLTFSceneManager() mObjects.clear(); } -LLMatrix4a getAssetToAgentTransform(LLViewerObject* obj) -{ - LLMatrix4 root; - root.initScale(obj->getScale()); - root.rotate(obj->getRenderRotation()); - root.translate(obj->getPositionAgent()); - - LLMatrix4a mat; - mat.loadu((F32*) root.mMatrix); - - return mat; -} - -LLMatrix4a getAgentToAssetTransform(LLViewerObject* obj) -{ - LLMatrix4 root; - LLVector3 scale = obj->getScale(); - scale.mV[0] = 1.f / scale.mV[0]; - scale.mV[1] = 1.f / scale.mV[1]; - scale.mV[2] = 1.f / scale.mV[2]; - - root.translate(-obj->getPositionAgent()); - root.rotate(~obj->getRenderRotation()); - - LLMatrix4 scale_mat; - scale_mat.initScale(scale); - - root *= scale_mat; - - - LLMatrix4a mat; - mat.loadu((F32*) root.mMatrix); - - return mat; -} - void GLTFSceneManager::renderOpaque() +{ + render(true); +} + +void GLTFSceneManager::renderAlpha() +{ + render(false); +} + +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 @@ -158,7 +155,7 @@ void GLTFSceneManager::renderOpaque() gGL.pushMatrix(); - LLMatrix4a mat = getAssetToAgentTransform(mObjects[i]); + LLMatrix4a mat = mObjects[i]->getGLTFAssetToAgentTransform(); LLMatrix4a modelview; modelview.loadu(gGLModelView); @@ -166,7 +163,7 @@ void GLTFSceneManager::renderOpaque() matMul(mat, modelview, modelview); asset->updateRenderTransforms(modelview); - asset->renderOpaque(); + asset->render(opaque, rigged); gGL.popMatrix(); } @@ -195,7 +192,7 @@ bool GLTFSceneManager::lineSegmentIntersect(LLVOVolume* obj, Asset* asset, const LLVector4a local_start; LLVector4a local_end; - LLMatrix4a asset_to_agent = getAssetToAgentTransform(obj); + LLMatrix4a asset_to_agent = obj->getGLTFAssetToAgentTransform(); LLMatrix4a agent_to_asset = inverse(asset_to_agent); agent_to_asset.affineTransform(start, local_start); @@ -331,7 +328,7 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset) gGL.pushMatrix(); // get raycast in asset space - LLMatrix4a agent_to_asset = getAgentToAssetTransform(obj); + LLMatrix4a agent_to_asset = obj->getAgentToGLTFAssetTransform(); LLVector4a start; LLVector4a end; @@ -399,7 +396,8 @@ void GLTFSceneManager::renderDebug() { if (!gPipeline.hasRenderDebugMask( LLPipeline::RENDER_DEBUG_BBOXES | - LLPipeline::RENDER_DEBUG_RAYCAST)) + LLPipeline::RENDER_DEBUG_RAYCAST | + LLPipeline::RENDER_DEBUG_NODES)) { return; } @@ -412,6 +410,29 @@ void GLTFSceneManager::renderDebug() gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gPipeline.disableLights(); + // force update all mRenderMatrix, not just nodes with meshes + for (auto& obj : mObjects) + { + if (obj->isDead() || obj->mGLTFAsset == nullptr) + { + continue; + } + + LLMatrix4a mat = obj->getGLTFAssetToAgentTransform(); + + LLMatrix4a modelview; + modelview.loadu(gGLModelView); + + matMul(mat, modelview, modelview); + + Asset* asset = obj->mGLTFAsset; + + for (auto& node : asset->mNodes) + { + matMul(node.mAssetMatrix, modelview, node.mRenderMatrix); + } + } + for (auto& obj : mObjects) { if (obj->isDead() || obj->mGLTFAsset == nullptr) @@ -421,18 +442,91 @@ void GLTFSceneManager::renderDebug() Asset* asset = obj->mGLTFAsset; - - LLMatrix4a mat = getAssetToAgentTransform(obj); + LLMatrix4a mat = obj->getGLTFAssetToAgentTransform(); LLMatrix4a modelview; modelview.loadu(gGLModelView); matMul(mat, modelview, modelview); - asset->updateRenderTransforms(modelview); renderAssetDebug(obj, asset); } + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NODES)) + { //render node hierarchy + + for (U32 i = 0; i < 2; ++i) + { + LLGLDepthTest depth(GL_TRUE, i == 0 ? GL_FALSE : GL_TRUE, i == 0 ? GL_GREATER : GL_LEQUAL); + LLGLState blend(GL_BLEND, i == 0 ? TRUE : FALSE); + + + gGL.pushMatrix(); + + for (auto& obj : mObjects) + { + if (obj->isDead() || obj->mGLTFAsset == nullptr) + { + continue; + } + + LLMatrix4a mat = obj->getGLTFAssetToAgentTransform(); + + LLMatrix4a modelview; + modelview.loadu(gGLModelView); + + matMul(mat, modelview, modelview); + + Asset* asset = obj->mGLTFAsset; + + for (auto& node : asset->mNodes) + { + // force update all mRenderMatrix, not just nodes with meshes + matMul(node.mAssetMatrix, modelview, node.mRenderMatrix); + + gGL.loadMatrix(node.mRenderMatrix.getF32ptr()); + // render x-axis red, y-axis green, z-axis blue + gGL.color4f(1.f, 0.f, 0.f, 0.5f); + gGL.begin(LLRender::LINES); + gGL.vertex3f(0.f, 0.f, 0.f); + gGL.vertex3f(1.f, 0.f, 0.f); + gGL.end(); + gGL.flush(); + + gGL.color4f(0.f, 1.f, 0.f, 0.5f); + gGL.begin(LLRender::LINES); + gGL.vertex3f(0.f, 0.f, 0.f); + gGL.vertex3f(0.f, 1.f, 0.f); + gGL.end(); + gGL.flush(); + + gGL.begin(LLRender::LINES); + gGL.color4f(0.f, 0.f, 1.f, 0.5f); + gGL.vertex3f(0.f, 0.f, 0.f); + gGL.vertex3f(0.f, 0.f, 1.f); + gGL.end(); + gGL.flush(); + + // render path to child nodes cyan + gGL.color4f(0.f, 1.f, 1.f, 0.5f); + gGL.begin(LLRender::LINES); + for (auto& child_idx : node.mChildren) + { + Node& child = asset->mNodes[child_idx]; + gGL.vertex3f(0.f, 0.f, 0.f); + gGL.vertex3fv(child.mMatrix.getTranslation().getF32ptr()); + } + gGL.end(); + gGL.flush(); + } + } + + gGL.popMatrix(); + } + + } + + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) { S32 node_hit = -1; diff --git a/indra/newview/gltfscenemanager.h b/indra/newview/gltfscenemanager.h index 50e1dd93da..d286f335e4 100644 --- a/indra/newview/gltfscenemanager.h +++ b/indra/newview/gltfscenemanager.h @@ -36,9 +36,14 @@ 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 update(); + void render(bool opaque, bool rigged = false); void renderOpaque(); + void renderAlpha(); LLDrawable* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, diff --git a/indra/newview/llagentbenefits.cpp b/indra/newview/llagentbenefits.cpp index cd82be918c..93509d9a87 100644 --- a/indra/newview/llagentbenefits.cpp +++ b/indra/newview/llagentbenefits.cpp @@ -280,19 +280,6 @@ S32 LLAgentBenefits::get2KTextureUploadCost(S32 area) const { return m_texture_upload_cost; } - const S32 TEXTURE_SEGMENTS = 1024; - if (m_2k_texture_upload_cost.size() == TEXTURE_SEGMENTS) - { - S32 index = (S32)llceil(sqrt((F32)area)); - // 1..1024 pixels uses m_texture_upload_cost - // 1025..2048 uses m_2k_texture_upload_cost - // Translate 1025..2048 to 0..1023 of the - // cost array - const S32 PIXELS_TO_2K_ARRAY_TRANLATE = 1025; - index -= PIXELS_TO_2K_ARRAY_TRANLATE; - index = llclamp(index, 0, TEXTURE_SEGMENTS - 1); - return m_2k_texture_upload_cost[index]; - } return m_2k_texture_upload_cost[0]; } diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 04dc4b6d57..1afe380fa9 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -2814,7 +2814,7 @@ void LLAgentCamera::setFocusGlobal(const LLPickInfo& pick) { LLViewerObject* objectp = gObjectList.findObject(pick.mObjectID); - if (objectp) + if (objectp && pick.mGLTFNodeIndex == -1) { // focus on object plus designated offset // which may or may not be same as pick.mPosGlobal diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e32ed573a0..e584ae64ac 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -5722,6 +5722,7 @@ void LLAppViewer::idle() { LLPerfStats::tunedAvatars=0; // reset the number of avatars that have been tweaked. gObjectList.update(gAgent); + LL::GLTFSceneManager::instance().update(); } } diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index b1f903f448..4aa2a5c9d5 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -49,6 +49,7 @@ #include "llspatialpartition.h" #include "llglcommonfunc.h" #include "llvoavatar.h" +#include "gltfscenemanager.h" #include "llenvironment.h" @@ -261,6 +262,15 @@ void LLDrawPoolAlpha::forwardRender(bool rigged) mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); + if (rigged) + { // draw GLTF scene to depth buffer before rigged alpha + gPipeline.bindDeferredShader(gDeferredPBRAlphaProgram); + 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 // We don't want the nearly invisible objects to cause of DoF effects renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, false, rigged); diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index ffc78ec70c..f4ff0a758c 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -704,8 +704,7 @@ void LLBumpImageList::updateImages() { for (bump_image_map_t::iterator iter = mBrightnessEntries.begin(); iter != mBrightnessEntries.end(); ) { - bump_image_map_t::iterator curiter = iter++; - LLViewerTexture* image = curiter->second; + LLViewerTexture* image = iter->second; if( image ) { BOOL destroy = TRUE; @@ -724,9 +723,11 @@ void LLBumpImageList::updateImages() if( destroy ) { //LL_INFOS() << "*** Destroying bright " << (void*)image << LL_ENDL; - mBrightnessEntries.erase(curiter); // deletes the image thanks to reference counting + iter = mBrightnessEntries.erase(iter); // deletes the image thanks to reference counting + continue; } } + ++iter; } for (bump_image_map_t::iterator iter = mDarknessEntries.begin(); iter != mDarknessEntries.end(); ) 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/llfetchedgltfmaterial.cpp b/indra/newview/llfetchedgltfmaterial.cpp index 1ca7ffaec1..1dd1dbabbe 100644 --- a/indra/newview/llfetchedgltfmaterial.cpp +++ b/indra/newview/llfetchedgltfmaterial.cpp @@ -34,6 +34,9 @@ #include "llshadermgr.h" #include "pipeline.h" +//static +LLFetchedGLTFMaterial LLFetchedGLTFMaterial::sDefault; + LLFetchedGLTFMaterial::LLFetchedGLTFMaterial() : LLGLTFMaterial() , mExpectedFlusTime(0.f) diff --git a/indra/newview/llfetchedgltfmaterial.h b/indra/newview/llfetchedgltfmaterial.h index 42c835a416..7550c75b45 100644 --- a/indra/newview/llfetchedgltfmaterial.h +++ b/indra/newview/llfetchedgltfmaterial.h @@ -66,6 +66,8 @@ public: std::set mTextureEntires; + // default material for when assets don't have one + static LLFetchedGLTFMaterial sDefault; protected: // Lifetime management diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp index e2b62cdab8..bf854d275d 100644 --- a/indra/newview/llmanip.cpp +++ b/indra/newview/llmanip.cpp @@ -357,9 +357,16 @@ LLVector3 LLManip::getSavedPivotPoint() const LLVector3 LLManip::getPivotPoint() { + // Pivot point controls - //if (mObjectSelection->getFirstObject() && mObjectSelection->getObjectCount() == 1 && mObjectSelection->getSelectType() != SELECT_TYPE_HUD) + //LLViewerObject* object = mObjectSelection->getFirstObject(); + //if (object && mObjectSelection->getObjectCount() == 1 && mObjectSelection->getSelectType() != SELECT_TYPE_HUD) //{ + // LLSelectNode* select_node = mObjectSelection->getFirstNode(); + // if (select_node->mSelectedGLTFNode != -1) + // { + // return object->getGLTFNodePositionAgent(select_node->mSelectedGLTFNode); + // } // return mObjectSelection->getFirstObject()->getPivotPositionAgent(); //} //return LLSelectMgr::getInstance()->getBBoxOfSelection().getCenterAgent(); @@ -377,7 +384,15 @@ LLVector3 LLManip::getPivotPoint() LLViewerObject* root_object = mObjectSelection->getFirstRootObject(children_ok); if (root_object && (mObjectSelection->getObjectCount() == 1 || sActualRoot) && mObjectSelection->getSelectType() != SELECT_TYPE_HUD) { - pos = root_object->getPivotPositionAgent(); + LLSelectNode* select_node = mObjectSelection->getFirstNode(); + if (select_node->mSelectedGLTFNode != -1) + { + pos = root_object->getGLTFNodePositionAgent(select_node->mSelectedGLTFNode); + } + else + { + pos = root_object->getPivotPositionAgent(); + } scale = root_object->getScale(); rot = root_object->getRotation(); } diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp index 7f37f98568..1ac1992fe0 100644 --- a/indra/newview/llmaniprotate.cpp +++ b/indra/newview/llmaniprotate.cpp @@ -556,6 +556,7 @@ void LLManipRotate::drag( S32 x, S32 y ) BOOL damped = mSmoothRotate; mSmoothRotate = FALSE; + bool gltf_mode = false; for (LLObjectSelection::iterator iter = mObjectSelection->begin(); iter != mObjectSelection->end(); iter++) @@ -569,154 +570,177 @@ void LLManipRotate::drag( S32 x, S32 y ) ((root_object == NULL) || !root_object->isPermanentEnforced()) && (object->isRootEdit() || selectNode->mIndividualSelection)) { - if (!object->isRootEdit()) - { - // child objects should not update if parent is selected - LLViewerObject* editable_root = (LLViewerObject*)object->getParent(); - if (editable_root->isSelected()) - { - // we will be moved properly by our parent, so skip - continue; - } - } - LLQuaternion new_rot = selectNode->mSavedRotation * mRotation; - std::vector& child_positions = object->mUnselectedChildrenPositions ; - std::vector child_rotations; - if (object->isRootEdit() && selectNode->mIndividualSelection) - { - object->saveUnselectedChildrenRotation(child_rotations) ; - object->saveUnselectedChildrenPosition(child_positions) ; - } + if (selectNode->mSelectedGLTFNode != -1) + { + LLQuaternion new_rot = selectNode->mSavedRotation * mRotation; - if (object->getParent() && object->mDrawable.notNull()) - { - LLQuaternion invParentRotation = object->mDrawable->mXform.getParent()->getWorldRotation(); - invParentRotation.transQuat(); + object->setGLTFNodeRotationAgent(selectNode->mSelectedGLTFNode, new_rot); - object->setRotation(new_rot * invParentRotation, damped); - rebuild(object); - } - else - { - object->setRotation(new_rot, damped); - LLVOAvatar* avatar = object->asAvatar(); - if (avatar && avatar->isSelf() - && LLSelectMgr::getInstance()->mAllowSelectAvatar - && !object->getParent()) + gltf_mode = true; + } + else if (!gltf_mode) + { + if (!object->isRootEdit()) { - // Normal avatars use object's orienttion, but self uses - // separate LLCoordFrame - // See LVOAvatar::updateOrientation() - if (gAgentCamera.getFocusOnAvatar()) + // child objects should not update if parent is selected + LLViewerObject* editable_root = (LLViewerObject*)object->getParent(); + if (editable_root->isSelected()) { - //Don't rotate camera with avatar - gAgentCamera.setFocusOnAvatar(false, false, false); + // we will be moved properly by our parent, so skip + continue; } - - LLVector3 at_axis = mAgentSelfAtAxis; - at_axis *= mRotation; - at_axis.mV[VZ] = 0.f; - at_axis.normalize(); - gAgent.resetAxes(at_axis); } - rebuild(object); - } - // for individually selected roots, we need to counterrotate all the children - if (object->isRootEdit() && selectNode->mIndividualSelection) - { - //RN: must do non-damped updates on these objects so relative rotation appears constant - // instead of having two competing slerps making the child objects appear to "wobble" - object->resetChildrenRotationAndPosition(child_rotations, child_positions) ; - } + LLQuaternion new_rot = selectNode->mSavedRotation * mRotation; + std::vector& child_positions = object->mUnselectedChildrenPositions; + std::vector child_rotations; + if (object->isRootEdit() && selectNode->mIndividualSelection) + { + object->saveUnselectedChildrenRotation(child_rotations); + object->saveUnselectedChildrenPosition(child_positions); + } + + if (object->getParent() && object->mDrawable.notNull()) + { + LLQuaternion invParentRotation = object->mDrawable->mXform.getParent()->getWorldRotation(); + invParentRotation.transQuat(); + + object->setRotation(new_rot * invParentRotation, damped); + rebuild(object); + } + else + { + object->setRotation(new_rot, damped); + LLVOAvatar* avatar = object->asAvatar(); + if (avatar && avatar->isSelf() + && LLSelectMgr::getInstance()->mAllowSelectAvatar + && !object->getParent()) + { + // Normal avatars use object's orienttion, but self uses + // separate LLCoordFrame + // See LVOAvatar::updateOrientation() + if (gAgentCamera.getFocusOnAvatar()) + { + //Don't rotate camera with avatar + gAgentCamera.setFocusOnAvatar(false, false, false); + } + + LLVector3 at_axis = mAgentSelfAtAxis; + at_axis *= mRotation; + at_axis.mV[VZ] = 0.f; + at_axis.normalize(); + gAgent.resetAxes(at_axis); + } + rebuild(object); + } + + // for individually selected roots, we need to counterrotate all the children + if (object->isRootEdit() && selectNode->mIndividualSelection) + { + //RN: must do non-damped updates on these objects so relative rotation appears constant + // instead of having two competing slerps making the child objects appear to "wobble" + object->resetChildrenRotationAndPosition(child_rotations, child_positions); + } + } } } // update positions - for (LLObjectSelection::iterator iter = mObjectSelection->begin(); - iter != mObjectSelection->end(); iter++) - { - LLSelectNode* selectNode = *iter; - LLViewerObject* object = selectNode->getObject(); - LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); + if (!gltf_mode) + { + for (LLObjectSelection::iterator iter = mObjectSelection->begin(); + iter != mObjectSelection->end(); iter++) + { + LLSelectNode* selectNode = *iter; + LLViewerObject* object = selectNode->getObject(); + LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); - // to avoid cumulative position changes we calculate the objects new position using its saved position - if (object && object->permMove() && !object->isPermanentEnforced() && - ((root_object == NULL) || !root_object->isPermanentEnforced())) - { - LLVector3 center = gAgent.getPosAgentFromGlobal( mRotationCenter ); - LLVector3 old_position; - LLVector3 new_position; + // to avoid cumulative position changes we calculate the objects new position using its saved position + if (object && object->permMove() && !object->isPermanentEnforced() && + ((root_object == NULL) || !root_object->isPermanentEnforced())) + { + LLVector3 center = gAgent.getPosAgentFromGlobal(mRotationCenter); - if (object->isAttachment() && object->mDrawable.notNull()) - { - // need to work in drawable space to handle selected items from multiple attachments - // (which have no shared frame of reference other than their render positions) - LLXform* parent_xform = object->mDrawable->getXform()->getParent(); - new_position = (selectNode->mSavedPositionLocal * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); - old_position = (object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();//object->getRenderPosition(); - } - else - { - new_position = gAgent.getPosAgentFromGlobal( selectNode->mSavedPositionGlobal ); - old_position = object->getPositionAgent(); - } + LLVector3 old_position; + LLVector3 new_position; - new_position = (new_position - center) * mRotation; // new relative rotated position - new_position += center; - - if (object->isRootEdit() && !object->isAttachment()) - { - LLVector3d new_pos_global = gAgent.getPosGlobalFromAgent(new_position); - new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global); - new_position = gAgent.getPosAgentFromGlobal(new_pos_global); - } + if (selectNode->mSelectedGLTFNode != -1) + { - // for individually selected child objects - if (!object->isRootEdit() && selectNode->mIndividualSelection) - { - LLViewerObject* parentp = (LLViewerObject*)object->getParent(); - if (!parentp->isSelected()) - { - if (object->isAttachment() && object->mDrawable.notNull()) - { - // find position relative to render position of parent - object->setPosition((new_position - parentp->getRenderPosition()) * ~parentp->getRenderRotation()); - rebuild(object); - } - else - { - object->setPositionParent((new_position - parentp->getPositionAgent()) * ~parentp->getRotationRegion()); - rebuild(object); - } - } - } - else if (object->isRootEdit()) - { - if (object->isAttachment() && object->mDrawable.notNull()) - { - LLXform* parent_xform = object->mDrawable->getXform()->getParent(); - object->setPosition((new_position - parent_xform->getWorldPosition()) * ~parent_xform->getWorldRotation()); - rebuild(object); - } - else - { - object->setPositionAgent(new_position); - rebuild(object); - } - } + } + else + { + if (object->isAttachment() && object->mDrawable.notNull()) + { + // need to work in drawable space to handle selected items from multiple attachments + // (which have no shared frame of reference other than their render positions) + LLXform* parent_xform = object->mDrawable->getXform()->getParent(); + new_position = (selectNode->mSavedPositionLocal * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); + old_position = (object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();//object->getRenderPosition(); + } + else + { + new_position = gAgent.getPosAgentFromGlobal(selectNode->mSavedPositionGlobal); + old_position = object->getPositionAgent(); + } - // for individually selected roots, we need to counter-translate all unselected children - if (object->isRootEdit() && selectNode->mIndividualSelection) - { - // only offset by parent's translation as we've already countered parent's rotation - rebuild(object); - object->resetChildrenPosition(old_position - new_position) ; - } - } - } + new_position = (new_position - center) * mRotation; // new relative rotated position + new_position += center; + + if (object->isRootEdit() && !object->isAttachment()) + { + LLVector3d new_pos_global = gAgent.getPosGlobalFromAgent(new_position); + new_pos_global = LLWorld::getInstance()->clipToVisibleRegions(selectNode->mSavedPositionGlobal, new_pos_global); + new_position = gAgent.getPosAgentFromGlobal(new_pos_global); + } + + // for individually selected child objects + if (!object->isRootEdit() && selectNode->mIndividualSelection) + { + LLViewerObject* parentp = (LLViewerObject*)object->getParent(); + if (!parentp->isSelected()) + { + if (object->isAttachment() && object->mDrawable.notNull()) + { + // find position relative to render position of parent + object->setPosition((new_position - parentp->getRenderPosition()) * ~parentp->getRenderRotation()); + rebuild(object); + } + else + { + object->setPositionParent((new_position - parentp->getPositionAgent()) * ~parentp->getRotationRegion()); + rebuild(object); + } + } + } + else if (object->isRootEdit()) + { + if (object->isAttachment() && object->mDrawable.notNull()) + { + LLXform* parent_xform = object->mDrawable->getXform()->getParent(); + object->setPosition((new_position - parent_xform->getWorldPosition()) * ~parent_xform->getWorldRotation()); + rebuild(object); + } + else + { + object->setPositionAgent(new_position); + rebuild(object); + } + } + + // for individually selected roots, we need to counter-translate all unselected children + if (object->isRootEdit() && selectNode->mIndividualSelection) + { + // only offset by parent's translation as we've already countered parent's rotation + rebuild(object); + object->resetChildrenPosition(old_position - new_position); + } + } + } + } + } // store changes to override updates for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin(); @@ -725,12 +749,13 @@ void LLManipRotate::drag( S32 x, S32 y ) LLSelectNode* selectNode = *iter; LLViewerObject*cur = selectNode->getObject(); LLViewerObject *root_object = (cur == NULL) ? NULL : cur->getRootEdit(); - if( cur->permModify() && cur->permMove() && !cur->isPermanentEnforced() && + + if( cur->permModify() && cur->permMove() && !cur->isPermanentEnforced() && ((root_object == NULL) || !root_object->isPermanentEnforced()) && (!cur->isAvatar() || LLSelectMgr::getInstance()->mAllowSelectAvatar)) { - selectNode->mLastRotation = cur->getRotation(); - selectNode->mLastPositionLocal = cur->getPosition(); + selectNode->mLastRotation = cur->getRotation(); + selectNode->mLastPositionLocal = cur->getPosition(); } } diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 62424cfe36..568ad9b2c9 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -676,119 +676,131 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) LLVector3d clamped_relative_move = axis_magnitude * axis_d; // scalar multiply LLVector3 clamped_relative_move_f = (F32)axis_magnitude * axis_f; // scalar multiply - for (LLObjectSelection::iterator iter = mObjectSelection->begin(); - iter != mObjectSelection->end(); iter++) - { - LLSelectNode* selectNode = *iter; - LLViewerObject* object = selectNode->getObject(); - - // Only apply motion to root objects and objects selected - // as "individual". - if (!object->isRootEdit() && !selectNode->mIndividualSelection) - { - continue; - } + for (LLObjectSelection::iterator iter = mObjectSelection->begin(); + iter != mObjectSelection->end(); iter++) + { + LLSelectNode* selectNode = *iter; + LLViewerObject* object = selectNode->getObject(); - if (!object->isRootEdit()) - { - // child objects should not update if parent is selected - LLViewerObject* editable_root = (LLViewerObject*)object->getParent(); - if (editable_root->isSelected()) - { - // we will be moved properly by our parent, so skip - continue; - } - } + if (selectNode->mSelectedGLTFNode != -1) + { + // manipulating a GLTF node + clamped_relative_move_f -= selectNode->mLastMoveLocal; + object->moveGLTFNode(selectNode->mSelectedGLTFNode, clamped_relative_move_f); + selectNode->mLastMoveLocal += clamped_relative_move_f; + } + else + { + // Only apply motion to root objects and objects selected + // as "individual". + if (!object->isRootEdit() && !selectNode->mIndividualSelection) + { + continue; + } - LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); - if (object->permMove() && !object->isPermanentEnforced() && - ((root_object == NULL) || !root_object->isPermanentEnforced())) - { - // handle attachments in local space - if (object->isAttachment() && object->mDrawable.notNull()) - { - // calculate local version of relative move - LLQuaternion objWorldRotation = object->mDrawable->mXform.getParent()->getWorldRotation(); - objWorldRotation.transQuat(); + if (!object->isRootEdit()) + { + // child objects should not update if parent is selected + LLViewerObject* editable_root = (LLViewerObject*)object->getParent(); + if (editable_root->isSelected()) + { + // we will be moved properly by our parent, so skip + continue; + } + } - LLVector3 old_position_local = object->getPosition(); - LLVector3 new_position_local = selectNode->mSavedPositionLocal + (clamped_relative_move_f * objWorldRotation); + LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); + if (object->permMove() && !object->isPermanentEnforced() && + ((root_object == NULL) || !root_object->isPermanentEnforced())) + { + // handle attachments in local space + if (object->isAttachment() && object->mDrawable.notNull()) + { + // calculate local version of relative move + LLQuaternion objWorldRotation = object->mDrawable->mXform.getParent()->getWorldRotation(); + objWorldRotation.transQuat(); - //RN: I forget, but we need to do this because of snapping which doesn't often result - // in position changes even when the mouse moves - object->setPosition(new_position_local); - rebuild(object); - gAgentAvatarp->clampAttachmentPositions(); - new_position_local = object->getPosition(); + LLVector3 old_position_local = object->getPosition(); + LLVector3 new_position_local = selectNode->mSavedPositionLocal + (clamped_relative_move_f * objWorldRotation); - if (selectNode->mIndividualSelection) - { - // counter-translate child objects if we are moving the root as an individual - object->resetChildrenPosition(old_position_local - new_position_local, TRUE) ; - } - } - else - { - // compute new position to send to simulators, but don't set it yet. - // We need the old position to know which simulator to send the move message to. - LLVector3d new_position_global = selectNode->mSavedPositionGlobal + clamped_relative_move; + //RN: I forget, but we need to do this because of snapping which doesn't often result + // in position changes even when the mouse moves + object->setPosition(new_position_local); + rebuild(object); + gAgentAvatarp->clampAttachmentPositions(); + new_position_local = object->getPosition(); - // Don't let object centers go too far underground - F64 min_height = LLWorld::getInstance()->getMinAllowedZ(object, object->getPositionGlobal()); - if (new_position_global.mdV[VZ] < min_height) - { - new_position_global.mdV[VZ] = min_height; - } + if (selectNode->mIndividualSelection) + { + // counter-translate child objects if we are moving the root as an individual + object->resetChildrenPosition(old_position_local - new_position_local, TRUE); + } + } + else + { + // compute new position to send to simulators, but don't set it yet. + // We need the old position to know which simulator to send the move message to. + LLVector3d new_position_global = selectNode->mSavedPositionGlobal + clamped_relative_move; - // For safety, cap heights where objects can be dragged + // Don't let object centers go too far underground + F64 min_height = LLWorld::getInstance()->getMinAllowedZ(object, object->getPositionGlobal()); + if (new_position_global.mdV[VZ] < min_height) + { + new_position_global.mdV[VZ] = min_height; + } + // For safety, cap heights where objects can be dragged // -// if (new_position_global.mdV[VZ] > MAX_OBJECT_Z) -// { -// new_position_global.mdV[VZ] = MAX_OBJECT_Z; -// } - if (new_position_global.mdV[VZ] > LLWorld::getInstance()->getRegionMaxHeight()) - { - new_position_global.mdV[VZ] = LLWorld::getInstance()->getRegionMaxHeight(); - } +// if (new_position_global.mdV[VZ] > MAX_OBJECT_Z) +// { +// new_position_global.mdV[VZ] = MAX_OBJECT_Z; +// } + if (new_position_global.mdV[VZ] > LLWorld::getInstance()->getRegionMaxHeight()) + { + new_position_global.mdV[VZ] = LLWorld::getInstance()->getRegionMaxHeight(); + } + // - // Grass is always drawn on the ground, so clamp its position to the ground - if (object->getPCode() == LL_PCODE_LEGACY_GRASS) - { - new_position_global.mdV[VZ] = LLWorld::getInstance()->resolveLandHeightGlobal(new_position_global) + 1.f; - } - - if (object->isRootEdit()) - { - new_position_global = LLWorld::getInstance()->clipToVisibleRegions(object->getPositionGlobal(), new_position_global); - } - // PR: Only update if changed - LLVector3 old_position_agent = object->getPositionAgent(); - LLVector3 new_position_agent = gAgent.getPosAgentFromGlobal(new_position_global); - if (object->isRootEdit()) - { - // finally, move parent object after children have calculated new offsets - object->setPositionAgent(new_position_agent); - rebuild(object); - } - else - { - LLViewerObject* root_object = object->getRootEdit(); - new_position_agent -= root_object->getPositionAgent(); - new_position_agent = new_position_agent * ~root_object->getRotation(); - object->setPositionParent(new_position_agent, FALSE); - rebuild(object); - } + // Grass is always drawn on the ground, so clamp its position to the ground + if (object->getPCode() == LL_PCODE_LEGACY_GRASS) + { + new_position_global.mdV[VZ] = LLWorld::getInstance()->resolveLandHeightGlobal(new_position_global) + 1.f; + } + + if (object->isRootEdit()) + { + new_position_global = LLWorld::getInstance()->clipToVisibleRegions(object->getPositionGlobal(), new_position_global); + } + + // PR: Only update if changed + LLVector3 old_position_agent = object->getPositionAgent(); + LLVector3 new_position_agent = gAgent.getPosAgentFromGlobal(new_position_global); + if (object->isRootEdit()) + { + // finally, move parent object after children have calculated new offsets + object->setPositionAgent(new_position_agent); + rebuild(object); + } + else + { + LLViewerObject* root_object = object->getRootEdit(); + new_position_agent -= root_object->getPositionAgent(); + new_position_agent = new_position_agent * ~root_object->getRotation(); + object->setPositionParent(new_position_agent, FALSE); + rebuild(object); + } + + if (selectNode->mIndividualSelection) + { + // counter-translate child objects if we are moving the root as an individual + object->resetChildrenPosition(old_position_agent - new_position_agent, TRUE); + } + } + selectNode->mLastPositionLocal = object->getPosition(); + } + } + } - if (selectNode->mIndividualSelection) - { - // counter-translate child objects if we are moving the root as an individual - object->resetChildrenPosition(old_position_agent - new_position_agent, TRUE) ; - } - } - selectNode->mLastPositionLocal = object->getPosition(); - } - } LLSelectMgr::getInstance()->updateSelectionCenter(); gAgentCamera.clearFocusObject(); diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index 3e4992e4e7..5a8f44f5c2 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -41,14 +41,17 @@ #include "llviewermenufile.h" #include "llnotificationsutil.h" - -// load an OpenEXR image from a file -#define IMATH_HALF_NO_LOOKUP_TABLE 1 -#include -#include -#include -#include -#include +#if LL_WINDOWS +#pragma warning (push) +#pragma warning (disable : 4702) // compiler complains unreachable code +#endif +#define TINYEXR_USE_MINIZ 0 +#include "zlib.h" +#define TINYEXR_IMPLEMENTATION +#include "tinyexr/tinyexr.h" +#if LL_WINDOWS +#pragma warning (pop) +#endif LLPointer gEXRImage; @@ -58,55 +61,14 @@ void load_exr(const std::string& filename) gPipeline.mReflectionMapManager.reset(); gPipeline.mReflectionMapManager.initReflectionMaps(); - try { - Imf::InputFile file(filename.c_str()); - Imath::Box2i dw = file.header().dataWindow(); - int width = dw.max.x - dw.min.x + 1; - int height = dw.max.y - dw.min.y + 1; - - Imf::Array2D rPixels; - Imf::Array2D gPixels; - Imf::Array2D bPixels; - - rPixels.resizeErase(height, width); - gPixels.resizeErase(height, width); - bPixels.resizeErase(height, width); - - Imf::FrameBuffer frameBuffer; - - frameBuffer.insert("R", // name - Imf::Slice(Imf::HALF, // type - (char*)(&rPixels[0][0] - // base - dw.min.x - - dw.min.y * width), - sizeof(rPixels[0][0]) * 1, // xStride - sizeof(rPixels[0][0]) * width, // yStride - 1, 1, // x/y sampling - 0.0)); // fillValue - - frameBuffer.insert("G", // name - Imf::Slice(Imf::HALF, // type - (char*)(&gPixels[0][0] - // base - dw.min.x - - dw.min.y * width), - sizeof(gPixels[0][0]) * 1, // xStride - sizeof(gPixels[0][0]) * width, // yStride - 1, 1, // x/y sampling - 0.0)); // fillValue - - frameBuffer.insert("B", // name - Imf::Slice(Imf::HALF, // type - (char*)(&bPixels[0][0] - // base - dw.min.x - - dw.min.y * width), - sizeof(bPixels[0][0]) * 1, // xStride - sizeof(bPixels[0][0]) * width, // yStride - 1, 1, // x/y sampling - FLT_MAX)); // fillValue - - file.setFrameBuffer(frameBuffer); - file.readPixels(dw.min.y, dw.max.y); + float* out; // width * height * RGBA + int width; + int height; + const char* err = NULL; // or nullptr in C++11 + int ret = LoadEXRWithLayer(&out, &width, &height, filename.c_str(), /* layername */ nullptr, &err); + if (ret == TINYEXR_SUCCESS) + { U32 texName = 0; LLImageGL::generateTextures(1, &texName); @@ -117,27 +79,25 @@ void load_exr(const std::string& filename) gGL.getTexUnit(0)->bind(gEXRImage); - std::vector data(width * height * 3); - for (int i = 0; i < width * height; ++i) - { - data[i * 3 + 0] = rPixels[i / width][i % width]; - data[i * 3 + 1] = gPixels[i / width][i % width]; - data[i * 3 + 2] = bPixels[i / width][i % width]; - } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGBA, GL_FLOAT, out); + free(out); // release memory of image data - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, data.data()); - glGenerateMipmap(GL_TEXTURE_2D); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } - catch (const std::exception& e) { + else + { LLSD notif_args; notif_args["WHAT"] = filename; - notif_args["REASON"] = e.what(); + notif_args["REASON"] = "Unknown"; + if (err) + { + notif_args["REASON"] = std::string(err); + FreeEXRErrorMessage(err); // release memory of error message. + } LLNotificationsUtil::add("CannotLoad", notif_args); - return; } } diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 867be77572..62b3b0276f 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -479,7 +479,7 @@ void LLSelectMgr::overrideAvatarUpdates() //----------------------------------------------------------------------------- // Select just the object, not any other group members. //----------------------------------------------------------------------------- -LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S32 face) +LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S32 face, S32 gltf_node, S32 gltf_primitive) { llassert( object ); @@ -504,7 +504,7 @@ LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S3 // Place it in the list and tag it. // This will refresh dialogs. - addAsIndividual(object, face); + addAsIndividual(object, face, TRUE, gltf_node, gltf_primitive); // Stop the object from moving (this anticipates changes on the // simulator in LLTask::userSelect) @@ -1104,7 +1104,7 @@ void LLSelectMgr::addAsFamily(std::vector& objects, BOOL add_to //----------------------------------------------------------------------------- // addAsIndividual() - a single object, face, etc //----------------------------------------------------------------------------- -void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoable) +void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoable, S32 gltf_node, S32 gltf_primitive) { // check to see if object is already in list LLSelectNode *nodep = mSelectedObjects->findNode(objectp); @@ -1151,6 +1151,13 @@ void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoab return; } + // Handle glTF node selection + if (gltf_node >= 0) + { + nodep->selectGLTFNode(gltf_node, gltf_primitive, TRUE); + + } + saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); updateSelectionCenter(); dialog_refresh_all(); @@ -5452,46 +5459,57 @@ void LLSelectMgr::saveSelectedObjectTransform(EActionType action_type) { return true; // skip } - selectNode->mSavedPositionLocal = object->getPosition(); - if (object->isAttachment()) - { - if (object->isRootEdit()) - { - LLXform* parent_xform = object->mDrawable->getXform()->getParent(); - if (parent_xform) - { - selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition()); - } - else - { - selectNode->mSavedPositionGlobal = object->getPositionGlobal(); - } - } - else - { - LLViewerObject* attachment_root = (LLViewerObject*)object->getParent(); - LLXform* parent_xform = attachment_root ? attachment_root->mDrawable->getXform()->getParent() : NULL; - if (parent_xform) - { - LLVector3 root_pos = (attachment_root->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); - LLQuaternion root_rot = (attachment_root->getRotation() * parent_xform->getWorldRotation()); - selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * root_rot) + root_pos); - } - else - { - selectNode->mSavedPositionGlobal = object->getPositionGlobal(); - } - } - selectNode->mSavedRotation = object->getRenderRotation(); - } - else - { - selectNode->mSavedPositionGlobal = object->getPositionGlobal(); - selectNode->mSavedRotation = object->getRotationRegion(); - } - - selectNode->mSavedScale = object->getScale(); - selectNode->saveTextureScaleRatios(mManager->mTextureChannel); + + if (selectNode->mSelectedGLTFNode != -1) + { + // save GLTF node state + object->getGLTFNodeTransformAgent(selectNode->mSelectedGLTFNode, &selectNode->mSavedPositionLocal, &selectNode->mSavedRotation, &selectNode->mSavedScale); + selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent(selectNode->mSavedPositionLocal); + selectNode->mLastMoveLocal.setZero(); + } + else + { + selectNode->mSavedPositionLocal = object->getPosition(); + if (object->isAttachment()) + { + if (object->isRootEdit()) + { + LLXform* parent_xform = object->mDrawable->getXform()->getParent(); + if (parent_xform) + { + selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition()); + } + else + { + selectNode->mSavedPositionGlobal = object->getPositionGlobal(); + } + } + else + { + LLViewerObject* attachment_root = (LLViewerObject*)object->getParent(); + LLXform* parent_xform = attachment_root ? attachment_root->mDrawable->getXform()->getParent() : NULL; + if (parent_xform) + { + LLVector3 root_pos = (attachment_root->getPosition() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition(); + LLQuaternion root_rot = (attachment_root->getRotation() * parent_xform->getWorldRotation()); + selectNode->mSavedPositionGlobal = gAgent.getPosGlobalFromAgent((object->getPosition() * root_rot) + root_pos); + } + else + { + selectNode->mSavedPositionGlobal = object->getPositionGlobal(); + } + } + selectNode->mSavedRotation = object->getRenderRotation(); + } + else + { + selectNode->mSavedPositionGlobal = object->getPositionGlobal(); + selectNode->mSavedRotation = object->getRotationRegion(); + } + + selectNode->mSavedScale = object->getScale(); + selectNode->saveTextureScaleRatios(mManager->mTextureChannel); + } return true; } } func(action_type, this); @@ -6952,8 +6970,7 @@ LLSelectNode::~LLSelectNode() } } - - delete mPermissions; + delete mPermissions; mPermissions = NULL; } @@ -6981,6 +6998,17 @@ void LLSelectNode::selectTE(S32 te_index, BOOL selected) mLastTESelected = te_index; } +void LLSelectNode::selectGLTFNode(S32 node_index, S32 primitive_index, bool selected) +{ + if (node_index < 0) + { + return; + } + + mSelectedGLTFNode = node_index; + mSelectedGLTFPrimitive = primitive_index; +} + BOOL LLSelectNode::isTESelected(S32 te_index) const { if (te_index < 0 || te_index >= mObject->getNumTEs()) diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 5bea652f10..7f53a43abd 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -193,6 +193,7 @@ public: void selectAllTEs(BOOL b); void selectTE(S32 te_index, BOOL selected); + void selectGLTFNode(S32 node_index, S32 primitive_index, bool selected); BOOL isTESelected(S32 te_index) const; bool hasSelectedTE() const { return TE_SELECT_MASK_ALL & mTESelectMask; } S32 getLastSelectedTE() const; @@ -235,6 +236,7 @@ public: S16 mInventorySerial; LLVector3 mSavedPositionLocal; // for interactively modifying object position LLVector3 mLastPositionLocal; + LLVector3 mLastMoveLocal; LLVector3d mSavedPositionGlobal; // for interactively modifying object position LLVector3 mSavedScale; // for interactively modifying object scale LLVector3 mLastScale; @@ -258,6 +260,8 @@ public: std::vector mSilhouetteVertices; // array of vertices to render silhouette of object std::vector mSilhouetteNormals; // array of normals to render silhouette of object BOOL mSilhouetteExists; // need to generate silhouette? + S32 mSelectedGLTFNode = -1; + S32 mSelectedGLTFPrimitive = -1; protected: LLPointer mObject; @@ -601,7 +605,7 @@ public: LLObjectSelectionHandle selectObjectAndFamily(LLViewerObject* object, BOOL add_to_end = FALSE, BOOL ignore_select_owned = FALSE); // For when you want just a child object. - LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES); + LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES, S32 gltf_node = -1, S32 gltf_primitive = -1); // Same as above, but takes a list of objects. Used by rectangle select. LLObjectSelectionHandle selectObjectAndFamily(const std::vector& object_list, BOOL send_to_sim = TRUE); @@ -906,7 +910,7 @@ public: void remove(std::vector& objects); void remove(LLViewerObject* object, S32 te = SELECT_ALL_TES, BOOL undoable = TRUE); void removeAll(); - void addAsIndividual(LLViewerObject* object, S32 te = SELECT_ALL_TES, BOOL undoable = TRUE); + void addAsIndividual(LLViewerObject* object, S32 te = SELECT_ALL_TES, BOOL undoable = TRUE, S32 gltf_node = -1, S32 gltf_primitive = -1); void promoteSelectionToRoot(); void demoteSelectionToIndividuals(); diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp index 885a4c3514..4065d85cbd 100644 --- a/indra/newview/lltinygltfhelper.cpp +++ b/indra/newview/lltinygltfhelper.cpp @@ -87,20 +87,30 @@ void LLTinyGLTFHelper::initFetchedTextures(tinygltf::Material& material, { strip_alpha_channel(mr_img); - if (occlusion_img && material.pbrMetallicRoughness.metallicRoughnessTexture.index != material.occlusionTexture.index) + if (occlusion_img) { - // occlusion is a distinct texture from pbrMetallicRoughness - // pack into mr red channel - int occlusion_idx = material.occlusionTexture.index; - int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index; - if (occlusion_idx != mr_idx) + if (material.pbrMetallicRoughness.metallicRoughnessTexture.index != material.occlusionTexture.index) { - //scale occlusion image to match resolution of mr image - occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight()); + // occlusion is a distinct texture from pbrMetallicRoughness + // pack into mr red channel + int occlusion_idx = material.occlusionTexture.index; + int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index; + if (occlusion_idx != mr_idx) + { + //scale occlusion image to match resolution of mr image + occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight()); - copy_red_channel(occlusion_img, mr_img); + copy_red_channel(occlusion_img, mr_img); + } } } + else + { + // no occlusion, make a white occlusion image + occlusion_img = new LLImageRaw(mr_img->getWidth(), mr_img->getHeight(), 3); + occlusion_img->clear(255, 255, 255); + copy_red_channel(occlusion_img, mr_img); + } } else if (occlusion_img) { diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp index c8f9cfb2c0..d5421d48e2 100644 --- a/indra/newview/lltoolselect.cpp +++ b/indra/newview/lltoolselect.cpp @@ -224,7 +224,7 @@ LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pi if ( ignore_group ) { - LLSelectMgr::getInstance()->selectObjectOnly(object, SELECT_ALL_TES); + LLSelectMgr::getInstance()->selectObjectOnly(object, SELECT_ALL_TES, pick.mGLTFNodeIndex, pick.mGLTFPrimitiveIndex); } else { diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index ec993c6152..6f21970b65 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -905,10 +905,30 @@ U32 render_type_from_string(std::string render_type) { return LLPipeline::RENDER_TYPE_SIMPLE; } + if ("materials" == render_type) + { + return LLPipeline::RENDER_TYPE_MATERIALS; + } else if ("alpha" == render_type) { return LLPipeline::RENDER_TYPE_ALPHA; } + else if ("alpha_mask" == render_type) + { + return LLPipeline::RENDER_TYPE_ALPHA_MASK; + } + else if ("fullbright_alpha_mask" == render_type) + { + return LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK; + } + else if ("fullbright" == render_type) + { + return LLPipeline::RENDER_TYPE_FULLBRIGHT; + } + else if ("glow" == render_type) + { + return LLPipeline::RENDER_TYPE_GLOW; + } else if ("tree" == render_type) { return LLPipeline::RENDER_TYPE_TREE; @@ -1165,6 +1185,10 @@ U64 info_display_from_string(std::string info_display) { return LLPipeline::RENDER_DEBUG_OCTREE; } + else if ("nodes" == info_display) + { + return LLPipeline::RENDER_DEBUG_NODES; + } else if ("shadow frusta" == info_display) { return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 3ec3ccc4ca..182b26c5f6 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -4537,6 +4537,168 @@ const LLVector3 &LLViewerObject::getPositionAgent() const return mPositionAgent; } +LLMatrix4a LLViewerObject::getGLTFAssetToAgentTransform() const +{ + LLMatrix4 root; + root.initScale(getScale()); + root.rotate(getRenderRotation()); + root.translate(getPositionAgent()); + + LLMatrix4a mat; + mat.loadu((F32*)root.mMatrix); + + return mat; +} + +LLVector3 LLViewerObject::getGLTFNodePositionAgent(S32 node_index) const +{ + LLVector3 ret; + getGLTFNodeTransformAgent(node_index, &ret, nullptr, nullptr); + return ret; + +} + +LLMatrix4a LLViewerObject::getAgentToGLTFAssetTransform() const +{ + LLMatrix4 root; + LLVector3 scale = getScale(); + scale.mV[0] = 1.f / scale.mV[0]; + scale.mV[1] = 1.f / scale.mV[1]; + scale.mV[2] = 1.f / scale.mV[2]; + + root.translate(-getPositionAgent()); + root.rotate(~getRenderRotation()); + + LLMatrix4 scale_mat; + scale_mat.initScale(scale); + + root *= scale_mat; + LLMatrix4a mat; + mat.loadu((F32*)root.mMatrix); + + return mat; +} + +LLMatrix4a LLViewerObject::getGLTFNodeTransformAgent(S32 node_index) const +{ + LLMatrix4a mat; + + if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size()) + { + auto& node = mGLTFAsset->mNodes[node_index]; + + LLMatrix4a asset_to_agent = getGLTFAssetToAgentTransform(); + LLMatrix4a node_to_agent; + matMul(node.mAssetMatrix, asset_to_agent, node_to_agent); + + mat = node_to_agent; + } + else + { + mat.setIdentity(); + } + + return mat; +} +void LLViewerObject::getGLTFNodeTransformAgent(S32 node_index, LLVector3* position, LLQuaternion* rotation, LLVector3* scale) const +{ + LLMatrix4a node_to_agent = getGLTFNodeTransformAgent(node_index); + + if (position) + { + LLVector4a p = node_to_agent.getTranslation(); + position->set(p.getF32ptr()); + } + + if (rotation) + { + rotation->set(node_to_agent.asMatrix4()); + } + + if (scale) + { + scale->mV[0] = node_to_agent.mMatrix[0].getLength3().getF32(); + scale->mV[1] = node_to_agent.mMatrix[1].getLength3().getF32(); + scale->mV[2] = node_to_agent.mMatrix[2].getLength3().getF32(); + } +} + +void decomposeMatrix(const LLMatrix4a& mat, LLVector3& position, LLQuaternion& rotation, LLVector3& scale) +{ + LLVector4a p = mat.getTranslation(); + position.set(p.getF32ptr()); + + rotation.set(mat.asMatrix4()); + + scale.mV[0] = mat.mMatrix[0].getLength3().getF32(); + scale.mV[1] = mat.mMatrix[1].getLength3().getF32(); + scale.mV[2] = mat.mMatrix[2].getLength3().getF32(); +} + +void LLViewerObject::setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion& rotation) +{ + if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size()) + { + auto& node = mGLTFAsset->mNodes[node_index]; + + LLMatrix4a agent_to_asset = getAgentToGLTFAssetTransform(); + LLMatrix4a agent_to_node = agent_to_asset; + + if (node.mParent != -1) + { + auto& parent = mGLTFAsset->mNodes[node.mParent]; + matMul(agent_to_asset, parent.mAssetMatrixInv, agent_to_node); + } + + LLQuaternion agent_to_node_rot(agent_to_node.asMatrix4()); + LLQuaternion new_rot; + + new_rot = rotation * agent_to_node_rot; + new_rot.normalize(); + + LLVector3 pos; + LLQuaternion rot; + LLVector3 scale; + decomposeMatrix(node.mMatrix, pos, rot, scale); + + node.mMatrix.asMatrix4().initAll(scale, new_rot, pos); + + mGLTFAsset->updateTransforms(); + } +} + +void LLViewerObject::moveGLTFNode(S32 node_index, const LLVector3& offset) +{ + if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size()) + { + auto& node = mGLTFAsset->mNodes[node_index]; + + LLMatrix4a agent_to_asset = getAgentToGLTFAssetTransform(); + LLMatrix4a agent_to_node; + matMul(agent_to_asset, node.mAssetMatrixInv, agent_to_node); + + LLVector4a origin = LLVector4a::getZero(); + LLVector4a offset_v; + offset_v.load3(offset.mV); + + + agent_to_node.affineTransform(offset_v, offset_v); + agent_to_node.affineTransform(origin, origin); + + offset_v.sub(origin); + offset_v.getF32ptr()[3] = 1.f; + + LLMatrix4a trans; + trans.setIdentity(); + trans.mMatrix[3] = offset_v; + + matMul(trans, node.mMatrix, node.mMatrix); + + // TODO -- only update transforms for this node and its children (or use a dirty flag) + mGLTFAsset->updateTransforms(); + } +} + const LLVector3 &LLViewerObject::getPositionRegion() const { if (!isRoot()) diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 9c28431976..4569fc5716 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -321,6 +321,18 @@ public: virtual const LLVector3 &getPositionAgent() const; virtual const LLVector3 getRenderPosition() const; + LLMatrix4a getAgentToGLTFAssetTransform() const; + LLMatrix4a getGLTFAssetToAgentTransform() const; + LLVector3 getGLTFNodePositionAgent(S32 node_index) const; + LLMatrix4a getGLTFNodeTransformAgent(S32 node_index) const; + void getGLTFNodeTransformAgent(S32 node_index, LLVector3* position, LLQuaternion* rotation, LLVector3* scale) const; + + // move the node at the given index by the given offset in agent space + void moveGLTFNode(S32 node_index, const LLVector3& offset); + + // set the rotation in agent space of the given node + void setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion& rotation); + virtual const LLVector3 getPivotPositionAgent() const; // Usually = to getPositionAgent, unless like flex objects it's not LLViewerObject* getRootEdit() const; diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index aac3e17097..1327b8598f 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -724,7 +724,6 @@ std::string LLViewerShaderMgr::loadBasicShaders() index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsFuncs.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsF.glsl", mShaderLevel[SHADER_WINDLIGHT] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "environment/waterFogF.glsl", mShaderLevel[SHADER_WATER] ) ); - index_channels.push_back(-1); shaders.push_back( make_pair( "environment/encodeNormF.glsl", mShaderLevel[SHADER_ENVIRONMENT] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "environment/srgbF.glsl", mShaderLevel[SHADER_ENVIRONMENT] ) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/deferredUtil.glsl", 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/globalF.glsl", 1)); @@ -1060,7 +1059,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredDiffuseProgram.mName = "Deferred Diffuse Shader"; - gDeferredDiffuseProgram.mFeatures.encodesNormal = true; gDeferredDiffuseProgram.mFeatures.hasSrgb = true; gDeferredDiffuseProgram.mShaderFiles.clear(); gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER)); @@ -1074,7 +1072,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredDiffuseAlphaMaskProgram.mName = "Deferred Diffuse Alpha Mask Shader"; - gDeferredDiffuseAlphaMaskProgram.mFeatures.encodesNormal = true; gDeferredDiffuseAlphaMaskProgram.mShaderFiles.clear(); gDeferredDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER)); gDeferredDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskIndexedF.glsl", GL_FRAGMENT_SHADER)); @@ -1087,7 +1084,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredNonIndexedDiffuseAlphaMaskProgram.mName = "Deferred Diffuse Non-Indexed Alpha Mask Shader"; - gDeferredNonIndexedDiffuseAlphaMaskProgram.mFeatures.encodesNormal = true; gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.clear(); gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER)); gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskF.glsl", GL_FRAGMENT_SHADER)); @@ -1099,7 +1095,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mName = "Deferred Diffuse Non-Indexed Alpha Mask No Color Shader"; - gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mFeatures.encodesNormal = true; gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.clear(); gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("deferred/diffuseNoColorV.glsl", GL_VERTEX_SHADER)); gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskNoColorF.glsl", GL_FRAGMENT_SHADER)); @@ -1111,7 +1106,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredBumpProgram.mName = "Deferred Bump Shader"; - gDeferredBumpProgram.mFeatures.encodesNormal = true; gDeferredBumpProgram.mShaderFiles.clear(); gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpV.glsl", GL_VERTEX_SHADER)); gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER)); @@ -1183,7 +1177,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredMaterialProgram[i].mFeatures.hasSrgb = true; - gDeferredMaterialProgram[i].mFeatures.encodesNormal = true; gDeferredMaterialProgram[i].mFeatures.calculatesAtmospherics = true; gDeferredMaterialProgram[i].mFeatures.hasAtmospherics = true; gDeferredMaterialProgram[i].mFeatures.hasGamma = true; @@ -1217,7 +1210,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredPBROpaqueProgram.mName = "Deferred PBR Opaque Shader"; - gDeferredPBROpaqueProgram.mFeatures.encodesNormal = true; gDeferredPBROpaqueProgram.mFeatures.hasSrgb = true; gDeferredPBROpaqueProgram.mShaderFiles.clear(); @@ -1278,7 +1270,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() shader->mFeatures.hasLighting = false; shader->mFeatures.isAlphaLighting = true; shader->mFeatures.hasSrgb = true; - shader->mFeatures.encodesNormal = true; shader->mFeatures.calculatesAtmospherics = true; shader->mFeatures.hasAtmospherics = true; shader->mFeatures.hasGamma = true; @@ -1349,7 +1340,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredPBRTerrainProgram.mName = llformat("Deferred PBR Terrain Shader %d %s", detail, (mapping == 1 ? "flat" : "triplanar")); - gDeferredPBRTerrainProgram.mFeatures.encodesNormal = true; gDeferredPBRTerrainProgram.mFeatures.hasSrgb = true; gDeferredPBRTerrainProgram.mFeatures.isAlphaLighting = true; gDeferredPBRTerrainProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels @@ -1373,7 +1363,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredTreeProgram.mName = "Deferred Tree Shader"; gDeferredTreeProgram.mShaderFiles.clear(); - gDeferredTreeProgram.mFeatures.encodesNormal = true; gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeV.glsl", GL_VERTEX_SHADER)); gDeferredTreeProgram.mShaderFiles.push_back(make_pair("deferred/treeF.glsl", GL_FRAGMENT_SHADER)); gDeferredTreeProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; @@ -1408,8 +1397,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredImpostorProgram.mName = "Deferred Impostor Shader"; gDeferredImpostorProgram.mFeatures.hasSrgb = true; - gDeferredImpostorProgram.mFeatures.encodesNormal = true; - //gDeferredImpostorProgram.mFeatures.isDeferred = true; gDeferredImpostorProgram.mShaderFiles.clear(); gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorV.glsl", GL_VERTEX_SHADER)); gDeferredImpostorProgram.mShaderFiles.push_back(make_pair("deferred/impostorF.glsl", GL_FRAGMENT_SHADER)); @@ -1571,7 +1558,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() shader->mFeatures.isAlphaLighting = true; shader->mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels shader->mFeatures.hasSrgb = true; - shader->mFeatures.encodesNormal = true; shader->mFeatures.calculatesAtmospherics = true; shader->mFeatures.hasAtmospherics = true; shader->mFeatures.hasGamma = true; @@ -1633,7 +1619,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() shader->mFeatures.hasSrgb = true; shader->mFeatures.isAlphaLighting = true; - shader->mFeatures.encodesNormal = true; shader->mFeatures.hasShadows = use_sun_shadow; shader->mFeatures.hasReflectionProbes = true; shader->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; @@ -1681,7 +1666,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarEyesProgram.mFeatures.hasAtmospherics = true; gDeferredAvatarEyesProgram.mFeatures.disableTextureIndex = true; gDeferredAvatarEyesProgram.mFeatures.hasSrgb = true; - gDeferredAvatarEyesProgram.mFeatures.encodesNormal = true; gDeferredAvatarEyesProgram.mFeatures.hasShadows = true; gDeferredAvatarEyesProgram.mShaderFiles.clear(); @@ -2079,7 +2063,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredTerrainProgram.mName = "Deferred Terrain Shader"; - gDeferredTerrainProgram.mFeatures.encodesNormal = true; gDeferredTerrainProgram.mFeatures.hasSrgb = true; gDeferredTerrainProgram.mFeatures.isAlphaLighting = true; gDeferredTerrainProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels @@ -2099,7 +2082,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredAvatarProgram.mName = "Deferred Avatar Shader"; gDeferredAvatarProgram.mFeatures.hasSkinning = true; - gDeferredAvatarProgram.mFeatures.encodesNormal = true; gDeferredAvatarProgram.mShaderFiles.clear(); gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarV.glsl", GL_VERTEX_SHADER)); gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarF.glsl", GL_FRAGMENT_SHADER)); @@ -2118,7 +2100,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarAlphaProgram.mFeatures.isAlphaLighting = true; gDeferredAvatarAlphaProgram.mFeatures.disableTextureIndex = true; gDeferredAvatarAlphaProgram.mFeatures.hasSrgb = true; - gDeferredAvatarAlphaProgram.mFeatures.encodesNormal = true; gDeferredAvatarAlphaProgram.mFeatures.calculatesAtmospherics = true; gDeferredAvatarAlphaProgram.mFeatures.hasAtmospherics = true; gDeferredAvatarAlphaProgram.mFeatures.hasGamma = true; @@ -2466,7 +2447,6 @@ BOOL LLViewerShaderMgr::loadShadersObject() if (success) { gObjectBumpProgram.mName = "Bump Shader"; - gObjectBumpProgram.mFeatures.encodesNormal = true; gObjectBumpProgram.mShaderFiles.clear(); gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpV.glsl", GL_VERTEX_SHADER)); gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpF.glsl", GL_FRAGMENT_SHADER)); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index c88119ff09..3e72a586a8 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -276,6 +276,8 @@ LLVector2 gDebugRaycastTexCoord; LLVector4a gDebugRaycastNormal; LLVector4a gDebugRaycastTangent; S32 gDebugRaycastFaceHit; +S32 gDebugRaycastGLTFNodeHit; +S32 gDebugRaycastGLTFPrimitiveHit; LLVector4a gDebugRaycastStart; LLVector4a gDebugRaycastEnd; @@ -3836,9 +3838,11 @@ void LLViewerWindow::updateUI() if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) { - gDebugRaycastFaceHit = -1; + gDebugRaycastFaceHit = gDebugRaycastGLTFNodeHit = gDebugRaycastGLTFPrimitiveHit = -1; gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, FALSE, &gDebugRaycastFaceHit, + &gDebugRaycastGLTFNodeHit, + &gDebugRaycastGLTFPrimitiveHit, &gDebugRaycastIntersection, &gDebugRaycastTexCoord, &gDebugRaycastNormal, @@ -5453,6 +5457,8 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de BOOL pick_unselectable, BOOL pick_reflection_probe, S32* face_hit, + S32* gltf_node_hit, + S32* gltf_primitive_hit, LLVector4a *intersection, LLVector2 *uv, LLVector4a *normal, @@ -5553,7 +5559,7 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de if (!found) // if not found in HUD, look in world: { found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe, - face_hit, intersection, uv, normal, tangent); + face_hit, gltf_node_hit, gltf_primitive_hit, intersection, uv, normal, tangent); if (found && !pick_transparent) { gDebugRaycastIntersection = *intersection; @@ -7472,8 +7478,8 @@ LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos, void LLPickInfo::fetchResults() { - S32 face_hit = -1; + LLVector4a intersection, normal; LLVector4a tangent; @@ -7495,8 +7501,8 @@ void LLPickInfo::fetchResults() icon_dist = delta.getLength3().getF32(); } LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f, - NULL, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe, &face_hit, - &intersection, &uv, &normal, &tangent, &start, &end); + nullptr, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe, &face_hit, &mGLTFNodeIndex, &mGLTFPrimitiveIndex, + &intersection, &uv, &normal, &tangent, &start, &end); mPickPt = mMousePt; @@ -7658,6 +7664,8 @@ void LLPickInfo::getSurfaceInfo() if (gViewerWindow->cursorIntersect(ll_round((F32)mMousePt.mX), ll_round((F32)mMousePt.mY), 1024.f, objectp, -1, mPickTransparent, mPickRigged, mPickUnselectable, mPickReflectionProbe, &mObjectFace, + &mGLTFNodeIndex, + &mGLTFPrimitiveIndex, &intersection, &mSTCoords, &normal, diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 7a39d382b7..f9b5db3d2b 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -120,6 +120,8 @@ public: LLUUID mParticleOwnerID; LLUUID mParticleSourceID; S32 mObjectFace; + S32 mGLTFNodeIndex = -1; + S32 mGLTFPrimitiveIndex = -1; LLHUDIcon* mHUDIcon; LLVector3 mIntersection; LLVector2 mUVCoords; @@ -424,6 +426,8 @@ public: BOOL pick_unselectable = TRUE, BOOL pick_reflection_probe = TRUE, S32* face_hit = NULL, + S32* gltf_node_hit = nullptr, + S32* gltf_primitive_hit = nullptr, LLVector4a *intersection = NULL, LLVector2 *uv = NULL, LLVector4a *normal = NULL, diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index dcd91c5316..4dd9d93531 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -353,8 +353,8 @@ bool addDeferredAttachments(LLRenderTarget& target, bool for_impostor = false) { bool valid = true && target.addColorAttachment(GL_RGBA) // frag-data[1] specular OR PBR ORM - && target.addColorAttachment(GL_RGBA16F) // frag_data[2] normal+z+fogmask, See: class1\deferred\materialF.glsl & softenlight - && target.addColorAttachment(GL_RGB16F); // frag_data[3] PBR emissive + && target.addColorAttachment(GL_RGBA16F) // frag_data[2] normal+fogmask, See: class1\deferred\materialF.glsl & softenlight + && target.addColorAttachment(GL_RGB16F); // frag_data[3] PBR emissive OR material env intensity return valid; } @@ -6450,6 +6450,8 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, bool pick_unselectable, bool pick_reflection_probe, S32* face_hit, + S32* gltf_node_hit, + S32* gltf_primitive_hit, LLVector4a* intersection, // return the intersection point LLVector2* tex_coord, // return the texture coordinates of the intersection point LLVector4a* normal, // return the surface normal at the intersection point @@ -6493,15 +6495,6 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, } } - S32 node_hit = -1; - S32 primitive_hit = -1; - LLDrawable* hit = LL::GLTFSceneManager::instance().lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe, &node_hit, &primitive_hit, &position, tex_coord, normal, tangent); - if (hit) - { - drawable = hit; - local_end = position; - } - if (!sPickAvatar) { //save hit info in case we need to restore @@ -6602,6 +6595,25 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, } } + S32 node_hit = -1; + S32 primitive_hit = -1; + LLDrawable* hit = LL::GLTFSceneManager::instance().lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, pick_unselectable, pick_reflection_probe, &node_hit, &primitive_hit, &position, tex_coord, normal, tangent); + if (hit) + { + drawable = hit; + local_end = position; + } + + if (gltf_node_hit) + { + *gltf_node_hit = node_hit; + } + + if (gltf_primitive_hit) + { + *gltf_primitive_hit = primitive_hit; + } + if (intersection) { *intersection = position; @@ -6722,6 +6734,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 @@ -7465,7 +7481,7 @@ void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst) LLVector4a result; result.clear(); - gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, TRUE, NULL, &result); + gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, TRUE, nullptr, nullptr, nullptr, &result); focus_point.set(result.getF32ptr()); } diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index b99fab3179..b209fbb403 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -210,6 +210,8 @@ public: bool pick_unselectable, bool pick_reflection_probe, S32* face_hit, // return the face hit + S32* gltf_node_hit = nullptr, // return the gltf node hit + S32* gltf_primitive_hit = nullptr, // return the gltf primitive hit LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point LLVector4a* normal = NULL, // return the surface normal at the intersection point @@ -620,7 +622,7 @@ public: RENDER_DEBUG_PHYSICS_SHAPES = 0x02000000, RENDER_DEBUG_NORMALS = 0x04000000, RENDER_DEBUG_LOD_INFO = 0x08000000, - RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000, // not used + RENDER_DEBUG_NODES = 0x20000000, RENDER_DEBUG_TEXEL_DENSITY = 0x40000000, RENDER_DEBUG_TRIANGLE_COUNT = 0x80000000, RENDER_DEBUG_IMPOSTORS = 0x100000000, diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml index 664631c79c..fed9ae04f2 100644 --- a/indra/newview/skins/default/xui/de/menu_viewer.xml +++ b/indra/newview/skins/default/xui/de/menu_viewer.xml @@ -342,6 +342,11 @@ + + + + + diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index f165288aa3..7ba59c2dc9 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -3151,7 +3151,57 @@ function="Advanced.ToggleRenderType" parameter="simple" /> - + + + + + + + + + + + + + + + + + + + + @@ -4178,6 +4228,16 @@ function="Advanced.ToggleInfoDisplay" parameter="octree" /> + + + + diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 154b59d680..7c383a0d66 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -705,14 +705,6 @@ class Windows_x86_64_Manifest(ViewerManifest): self.path("libcrypto-1_1-x64.dll") self.path("libssl-1_1-x64.dll") - # OpenEXR - self.path("Iex-3_2.dll") - self.path("IlmThread-3_2.dll") - self.path("Imath-3_1.dll") - self.path("OpenEXR-3_2.dll") - self.path("OpenEXRCore-3_2.dll") - self.path("OpenEXRUtil-3_2.dll") - # HTTP/2 self.path("nghttp2.dll")