Merge branch 'release/materials_featurette' of https://github.com/secondlife/viewer
# Conflicts: # indra/newview/CMakeLists.txt # indra/newview/llmanip.cpp # indra/newview/llmaniptranslate.cpp # indra/newview/llselectmgr.h # indra/newview/pipeline.hmaster
commit
f4250bcfaf
170
autobuild.xml
170
autobuild.xml
|
|
@ -2098,6 +2098,18 @@
|
|||
</map>
|
||||
<key>mikktspace</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-mikktspace</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (C) 2011 by Morten S. Mikkelsen, Copyright (C) 2022 Blender Authors</string>
|
||||
<key>description</key>
|
||||
<string>Mikktspace Tangent Generator</string>
|
||||
<key>license</key>
|
||||
<string>Apache 2.0</string>
|
||||
<key>license_file</key>
|
||||
<string>mikktspace.txt</string>
|
||||
<key>name</key>
|
||||
<string>mikktspace</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
|
|
@ -2105,58 +2117,46 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>6cc1585dba85b0226a2e7033a7e2a2ceaae7c983</string>
|
||||
<string>65edf85c36a10001e32bdee582bec4732137208b</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-darwin64-5cee1f4.tar.zst</string>
|
||||
<string>https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-darwin64-8756084692.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>6b7d01ad54e4a88a001f66840c32329cedb28202</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-windows64-5cee1f4.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
<key>linux64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>edc9782bf209e17ad1845498b42f16d733582082</string>
|
||||
<string>fa9dcee4584df7e7271fdf69c08e6fd3122a47fc</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-mikktspace/releases/download/v1-5cee1f4/mikktspace-1-linux64-5cee1f4.tar.zst</string>
|
||||
<string>https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-linux64-8756084692.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux64</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>130b33a70bdb3a8a188376c6a91840bdb61380a8</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-windows64-8756084692.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>license</key>
|
||||
<string>Copyright (C) 2011 by Morten S. Mikkelsen</string>
|
||||
<key>license_file</key>
|
||||
<string>mikktspace.txt</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (C) 2011 by Morten S. Mikkelsen</string>
|
||||
<key>version</key>
|
||||
<string>1</string>
|
||||
<key>name</key>
|
||||
<string>mikktspace</string>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-mikktspace</string>
|
||||
<key>description</key>
|
||||
<string>Mikktspace Tangent Generator</string>
|
||||
</map>
|
||||
<key>minizip-ng</key>
|
||||
<map>
|
||||
|
|
@ -2525,76 +2525,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>description</key>
|
||||
<string>OpenAL Soft is a software implementation of the OpenAL 3D audio API.</string>
|
||||
</map>
|
||||
<key>openexr</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://github.com/secondlife/3p-openexr</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (c) Contributors to the OpenEXR Project. All rights reserved.</string>
|
||||
<key>description</key>
|
||||
<string>OpenEXR provides the specification and reference implementation of the EXR file format, the professional-grade image storage format of the motion picture industry.</string>
|
||||
<key>license</key>
|
||||
<string>OpenEXR</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/openexr.txt</string>
|
||||
<key>name</key>
|
||||
<string>openexr</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>17cd63922214b588d9a36137fadf927237ec0f25</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-openexr/releases/download/v1.10/openexr-3.2.2-darwin64-df7544d.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>linux64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>b092658ab5ec009a5875e8b6e5b7109730ad6846</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-openexr/releases/download/v1.10/openexr-3.2.2-linux64-df7544d.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux64</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>c511ae9a3e401375af2199b498a75f32cebc010f</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-openexr/releases/download/v1.10/openexr-3.2.2-windows64-df7544d.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>source_type</key>
|
||||
<string>git</string>
|
||||
<key>vcs_branch</key>
|
||||
<string>debug_autobuild</string>
|
||||
<key>vcs_revision</key>
|
||||
<string>5cd1075295c17b5f7085e83d5c16b13c7ecb2eb1</string>
|
||||
<key>vcs_url</key>
|
||||
<string>https://github.com/secondlife/3p-openexr</string>
|
||||
<key>version</key>
|
||||
<string>3.2.2</string>
|
||||
</map>
|
||||
<key>openjpeg</key>
|
||||
<map>
|
||||
<key>platforms</key>
|
||||
|
|
@ -3419,6 +3349,46 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>description</key>
|
||||
<string>zlib data compression library for the next generation systems</string>
|
||||
</map>
|
||||
<key>tinyexr</key>
|
||||
<map>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>common</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>9e0092c6a3aed1cb40a9e26df689c42c68142c9d</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>sha1</string>
|
||||
<key>url</key>
|
||||
<string>https://github.com/secondlife/3p-tinyexr/releases/download/v1.0.8-r1/tinyexr-v1.0.8-common-8755737750.tar.zst</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>common</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>license</key>
|
||||
<string>3-clause BSD</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/tinyexr_license.txt</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (c) 2014 - 2021, Syoyo Fujita and many contributors.</string>
|
||||
<key>version</key>
|
||||
<string>v1.0.8</string>
|
||||
<key>name</key>
|
||||
<string>tinyexr</string>
|
||||
<key>vcs_branch</key>
|
||||
<string>dependabot/github_actions/secondlife/action-autobuild-4</string>
|
||||
<key>vcs_revision</key>
|
||||
<string>4dc4d1d90d82a22843e2adf5130f9ecb5ee5769e</string>
|
||||
<key>vcs_url</key>
|
||||
<string>https://github.com/secondlife/3p-tinyexr</string>
|
||||
<key>description</key>
|
||||
<string>tinyexr import library</string>
|
||||
<key>source_type</key>
|
||||
<string>git</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>package_description</key>
|
||||
<map>
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ set(cmake_SOURCE_FILES
|
|||
PulseAudio.cmake
|
||||
Python.cmake
|
||||
TemplateCheck.cmake
|
||||
TinyEXR.cmake
|
||||
TinyGLTF.cmake
|
||||
Tut.cmake
|
||||
UI.cmake
|
||||
UnixInstall.cmake
|
||||
|
|
|
|||
|
|
@ -61,12 +61,6 @@ if(WINDOWS)
|
|||
glod.dll # <FS:Beq> 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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
use_prebuilt_binary(tinyexr)
|
||||
|
||||
set(TINYEXR_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tinyexr)
|
||||
|
||||
|
|
@ -37,8 +37,8 @@ template <class Object> class LLStrider
|
|||
};
|
||||
U32 mSkip;
|
||||
public:
|
||||
|
||||
LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); }
|
||||
LLStrider(Object* first) { mObjectp = first; mSkip = sizeof(Object); }
|
||||
~LLStrider() { }
|
||||
|
||||
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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<U32> indices;
|
||||
indices.resize(mNumIndices);
|
||||
|
||||
//copy results back into volume
|
||||
resizeVertices(vert_count);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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")) {
|
||||
|
|
|
|||
|
|
@ -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<LLVector4a>& strider, U32 index,
|
|||
}
|
||||
bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, U32 index, S32 count)
|
||||
{
|
||||
llassert(mIndicesStride == 2); // cannot access 32-bit indices with U16 strider
|
||||
llassert(mIndicesType == GL_UNSIGNED_SHORT);
|
||||
return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count);
|
||||
}
|
||||
bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, U32 index, S32 count)
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -194,9 +194,13 @@ public:
|
|||
// </FS:Ansariel>
|
||||
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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 # <FS:Ansariel> 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
|
||||
)
|
||||
|
||||
# <FS:Ansariel> 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 # <FS:Beq/> restore GLOD dependencies
|
||||
fs::discord # <FS:Ansariel> Discord support
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ void main()
|
|||
}
|
||||
|
||||
vec4 pos = getPositionWithDepth(tc, depth);
|
||||
vec4 norm = texture(normalMap, tc);
|
||||
|
||||
vec4 fogged = getWaterFogView(pos.xyz);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#pragma once
|
||||
|
||||
/**
|
||||
* @file asset.h
|
||||
* @brief LL GLTF Implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2024, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "../lltinygltfhelper.h"
|
||||
#include "llstrider.h"
|
||||
|
||||
// LL GLTF Implementation
|
||||
namespace LL
|
||||
{
|
||||
namespace GLTF
|
||||
{
|
||||
class Asset;
|
||||
|
||||
constexpr S32 INVALID_INDEX = -1;
|
||||
|
||||
class Buffer
|
||||
{
|
||||
public:
|
||||
std::vector<U8> mData;
|
||||
std::string mName;
|
||||
std::string mUri;
|
||||
|
||||
const Buffer& operator=(const tinygltf::Buffer& src);
|
||||
};
|
||||
|
||||
class BufferView
|
||||
{
|
||||
public:
|
||||
S32 mBuffer = INVALID_INDEX;
|
||||
S32 mByteLength;
|
||||
S32 mByteOffset;
|
||||
S32 mByteStride;
|
||||
S32 mTarget;
|
||||
S32 mComponentType;
|
||||
|
||||
std::string mName;
|
||||
|
||||
const BufferView& operator=(const tinygltf::BufferView& src);
|
||||
|
||||
};
|
||||
|
||||
class Accessor
|
||||
{
|
||||
public:
|
||||
S32 mBufferView = INVALID_INDEX;
|
||||
S32 mByteOffset;
|
||||
S32 mComponentType;
|
||||
S32 mCount;
|
||||
std::vector<double> mMax;
|
||||
std::vector<double> mMin;
|
||||
|
||||
enum class Type : S32
|
||||
{
|
||||
SCALAR = TINYGLTF_TYPE_SCALAR,
|
||||
VEC2 = TINYGLTF_TYPE_VEC2,
|
||||
VEC3 = TINYGLTF_TYPE_VEC3,
|
||||
VEC4 = TINYGLTF_TYPE_VEC4,
|
||||
MAT2 = TINYGLTF_TYPE_MAT2,
|
||||
MAT3 = TINYGLTF_TYPE_MAT3,
|
||||
MAT4 = TINYGLTF_TYPE_MAT4
|
||||
};
|
||||
|
||||
S32 mType;
|
||||
bool mNormalized;
|
||||
std::string mName;
|
||||
|
||||
const Accessor& operator=(const tinygltf::Accessor& src);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,287 @@
|
|||
/**
|
||||
* @file animation.cpp
|
||||
* @brief LL GLTF Animation Implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2024, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "../llviewerprecompiledheaders.h"
|
||||
|
||||
#include "asset.h"
|
||||
#include "buffer_util.h"
|
||||
|
||||
using namespace LL::GLTF;
|
||||
|
||||
void Animation::allocateGLResources(Asset& asset)
|
||||
{
|
||||
if (!mSamplers.empty())
|
||||
{
|
||||
mMinTime = FLT_MAX;
|
||||
mMaxTime = -FLT_MAX;
|
||||
for (auto& sampler : mSamplers)
|
||||
{
|
||||
sampler.allocateGLResources(asset);
|
||||
mMinTime = llmin(sampler.mMinTime, mMinTime);
|
||||
mMaxTime = llmax(sampler.mMaxTime, mMaxTime);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mMinTime = mMaxTime = 0.f;
|
||||
}
|
||||
|
||||
for (auto& channel : mRotationChannels)
|
||||
{
|
||||
channel.allocateGLResources(asset, mSamplers[channel.mSampler]);
|
||||
}
|
||||
|
||||
for (auto& channel : mTranslationChannels)
|
||||
{
|
||||
channel.allocateGLResources(asset, mSamplers[channel.mSampler]);
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::update(Asset& asset, F32 dt)
|
||||
{
|
||||
mTime += dt;
|
||||
|
||||
apply(asset, mTime);
|
||||
}
|
||||
|
||||
void Animation::apply(Asset& asset, float time)
|
||||
{
|
||||
// convert time to animation loop time
|
||||
time = fmod(time, mMaxTime - mMinTime) + mMinTime;
|
||||
|
||||
// apply each channel
|
||||
for (auto& channel : mRotationChannels)
|
||||
{
|
||||
channel.apply(asset, mSamplers[channel.mSampler], time);
|
||||
}
|
||||
|
||||
for (auto& channel : mTranslationChannels)
|
||||
{
|
||||
channel.apply(asset, mSamplers[channel.mSampler], time);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Animation::Sampler::allocateGLResources(Asset& asset)
|
||||
{
|
||||
Accessor& accessor = asset.mAccessors[mInput];
|
||||
mMinTime = accessor.mMin[0];
|
||||
mMaxTime = accessor.mMax[0];
|
||||
|
||||
mFrameTimes.resize(accessor.mCount);
|
||||
|
||||
LLStrider<F32> frame_times = mFrameTimes.data();
|
||||
copy(asset, accessor, frame_times);
|
||||
}
|
||||
|
||||
void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F32& t)
|
||||
{
|
||||
if (time < mMinTime)
|
||||
{
|
||||
frameIndex = 0;
|
||||
t = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFrameTimes.size() > 1)
|
||||
{
|
||||
if (time > mMaxTime)
|
||||
{
|
||||
frameIndex = mFrameTimes.size() - 2;
|
||||
t = 1.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
frameIndex = mFrameTimes.size() - 2;
|
||||
t = 1.f;
|
||||
|
||||
for (U32 i = 0; i < mFrameTimes.size() - 1; i++)
|
||||
{
|
||||
if (time >= mFrameTimes[i] && time < mFrameTimes[i + 1])
|
||||
{
|
||||
frameIndex = i;
|
||||
t = (time - mFrameTimes[i]) / (mFrameTimes[i + 1] - mFrameTimes[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
frameIndex = 0;
|
||||
t = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::RotationChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler)
|
||||
{
|
||||
Accessor& accessor = asset.mAccessors[sampler.mOutput];
|
||||
|
||||
copy(asset, accessor, mRotations);
|
||||
}
|
||||
|
||||
void Animation::RotationChannel::apply(Asset& asset, Sampler& sampler, F32 time)
|
||||
{
|
||||
U32 frameIndex;
|
||||
F32 t;
|
||||
|
||||
Node& node = asset.mNodes[mTarget.mNode];
|
||||
|
||||
sampler.getFrameInfo(asset, time, frameIndex, t);
|
||||
|
||||
if (sampler.mFrameTimes.size() == 1)
|
||||
{
|
||||
node.setRotation(mRotations[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// interpolate
|
||||
LLQuaternion q0(mRotations[frameIndex].get_value());
|
||||
LLQuaternion q1(mRotations[frameIndex + 1].get_value());
|
||||
|
||||
LLQuaternion qf = slerp(t, q0, q1);
|
||||
|
||||
qf.normalize();
|
||||
node.setRotation(glh::quaternionf(qf.mQ));
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::TranslationChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler)
|
||||
{
|
||||
Accessor& accessor = asset.mAccessors[sampler.mOutput];
|
||||
|
||||
copy(asset, accessor, mTranslations);
|
||||
}
|
||||
|
||||
void Animation::TranslationChannel::apply(Asset& asset, Sampler& sampler, F32 time)
|
||||
{
|
||||
U32 frameIndex;
|
||||
F32 t;
|
||||
|
||||
Node& node = asset.mNodes[mTarget.mNode];
|
||||
|
||||
sampler.getFrameInfo(asset, time, frameIndex, t);
|
||||
|
||||
if (sampler.mFrameTimes.size() == 1)
|
||||
{
|
||||
node.setTranslation(mTranslations[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// interpolate
|
||||
const glh::vec3f& v0 = mTranslations[frameIndex];
|
||||
const glh::vec3f& v1 = mTranslations[frameIndex + 1];
|
||||
|
||||
glh::vec3f vf = v0 + t * (v1 - v0);
|
||||
|
||||
node.setTranslation(vf);
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::ScaleChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler)
|
||||
{
|
||||
Accessor& accessor = asset.mAccessors[sampler.mOutput];
|
||||
|
||||
copy(asset, accessor, mScales);
|
||||
}
|
||||
|
||||
void Animation::ScaleChannel::apply(Asset& asset, Sampler& sampler, F32 time)
|
||||
{
|
||||
U32 frameIndex;
|
||||
F32 t;
|
||||
|
||||
Node& node = asset.mNodes[mTarget.mNode];
|
||||
|
||||
sampler.getFrameInfo(asset, time, frameIndex, t);
|
||||
|
||||
if (sampler.mFrameTimes.size() == 1)
|
||||
{
|
||||
node.setScale(mScales[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// interpolate
|
||||
const glh::vec3f& v0 = mScales[frameIndex];
|
||||
const glh::vec3f& v1 = mScales[frameIndex + 1];
|
||||
|
||||
glh::vec3f vf = v0 + t * (v1 - v0);
|
||||
|
||||
node.setScale(vf);
|
||||
}
|
||||
}
|
||||
|
||||
const Animation& Animation::operator=(const tinygltf::Animation& src)
|
||||
{
|
||||
mName = src.name;
|
||||
|
||||
mSamplers.resize(src.samplers.size());
|
||||
for (U32 i = 0; i < src.samplers.size(); ++i)
|
||||
{
|
||||
mSamplers[i] = src.samplers[i];
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < src.channels.size(); ++i)
|
||||
{
|
||||
if (src.channels[i].target_path == "rotation")
|
||||
{
|
||||
mRotationChannels.push_back(RotationChannel());
|
||||
mRotationChannels.back() = src.channels[i];
|
||||
}
|
||||
|
||||
if (src.channels[i].target_path == "translation")
|
||||
{
|
||||
mTranslationChannels.push_back(TranslationChannel());
|
||||
mTranslationChannels.back() = src.channels[i];
|
||||
}
|
||||
|
||||
if (src.channels[i].target_path == "scale")
|
||||
{
|
||||
mScaleChannels.push_back(ScaleChannel());
|
||||
mScaleChannels.back() = src.channels[i];
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Skin::allocateGLResources(Asset& asset)
|
||||
{
|
||||
if (mInverseBindMatrices != INVALID_INDEX)
|
||||
{
|
||||
Accessor& accessor = asset.mAccessors[mInverseBindMatrices];
|
||||
copy(asset, accessor, mInverseBindMatricesData);
|
||||
}
|
||||
}
|
||||
|
||||
const Skin& Skin::operator=(const tinygltf::Skin& src)
|
||||
{
|
||||
mName = src.name;
|
||||
mSkeleton = src.skeleton;
|
||||
mInverseBindMatrices = src.inverseBindMatrices;
|
||||
mJoints = src.joints;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
#pragma once
|
||||
|
||||
/**
|
||||
* @file animation.h
|
||||
* @brief LL GLTF Animation Implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2024, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "accessor.h"
|
||||
|
||||
// LL GLTF Implementation
|
||||
namespace LL
|
||||
{
|
||||
namespace GLTF
|
||||
{
|
||||
class Asset;
|
||||
|
||||
class Animation
|
||||
{
|
||||
public:
|
||||
class Sampler
|
||||
{
|
||||
public:
|
||||
std::vector<F32> mFrameTimes;
|
||||
|
||||
F32 mMinTime = -FLT_MAX;
|
||||
F32 mMaxTime = FLT_MAX;
|
||||
|
||||
S32 mInput = INVALID_INDEX;
|
||||
S32 mOutput = INVALID_INDEX;
|
||||
std::string mInterpolation;
|
||||
|
||||
void allocateGLResources(Asset& asset);
|
||||
|
||||
const Sampler& operator=(const tinygltf::AnimationSampler& src)
|
||||
{
|
||||
mInput = src.input;
|
||||
mOutput = src.output;
|
||||
mInterpolation = src.interpolation;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// get the frame index and time for the specified time
|
||||
// asset -- the asset to reference for Accessors
|
||||
// time -- the animation time to get the frame info for
|
||||
// frameIndex -- index of the closest frame that precedes the specified time
|
||||
// t - interpolant value between the frameIndex and the next frame
|
||||
void getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F32& t);
|
||||
};
|
||||
|
||||
class Channel
|
||||
{
|
||||
public:
|
||||
class Target
|
||||
{
|
||||
public:
|
||||
S32 mNode = INVALID_INDEX;
|
||||
std::string mPath;
|
||||
};
|
||||
|
||||
S32 mSampler = INVALID_INDEX;
|
||||
Target mTarget;
|
||||
std::string mTargetPath;
|
||||
std::string mName;
|
||||
|
||||
const Channel& operator=(const tinygltf::AnimationChannel& src)
|
||||
{
|
||||
mSampler = src.sampler;
|
||||
|
||||
mTarget.mNode = src.target_node;
|
||||
mTarget.mPath = src.target_path;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class RotationChannel : public Channel
|
||||
{
|
||||
public:
|
||||
std::vector<glh::quaternionf> mRotations;
|
||||
|
||||
const RotationChannel& operator=(const tinygltf::AnimationChannel& src)
|
||||
{
|
||||
Channel::operator=(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// prepare data needed for rendering
|
||||
// asset -- asset to reference for Accessors
|
||||
// sampler -- Sampler associated with this channel
|
||||
void allocateGLResources(Asset& asset, Sampler& sampler);
|
||||
|
||||
void apply(Asset& asset, Sampler& sampler, F32 time);
|
||||
};
|
||||
|
||||
class TranslationChannel : public Channel
|
||||
{
|
||||
public:
|
||||
std::vector<glh::vec3f> mTranslations;
|
||||
|
||||
const TranslationChannel& operator=(const tinygltf::AnimationChannel& src)
|
||||
{
|
||||
Channel::operator=(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// prepare data needed for rendering
|
||||
// asset -- asset to reference for Accessors
|
||||
// sampler -- Sampler associated with this channel
|
||||
void allocateGLResources(Asset& asset, Sampler& sampler);
|
||||
|
||||
void apply(Asset& asset, Sampler& sampler, F32 time);
|
||||
};
|
||||
|
||||
class ScaleChannel : public Channel
|
||||
{
|
||||
public:
|
||||
std::vector<glh::vec3f> mScales;
|
||||
|
||||
const ScaleChannel& operator=(const tinygltf::AnimationChannel& src)
|
||||
{
|
||||
Channel::operator=(src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// prepare data needed for rendering
|
||||
// asset -- asset to reference for Accessors
|
||||
// sampler -- Sampler associated with this channel
|
||||
void allocateGLResources(Asset& asset, Sampler& sampler);
|
||||
|
||||
void apply(Asset& asset, Sampler& sampler, F32 time);
|
||||
};
|
||||
|
||||
std::string mName;
|
||||
std::vector<Sampler> mSamplers;
|
||||
|
||||
// min/max time values for all samplers combined
|
||||
F32 mMinTime = 0.f;
|
||||
F32 mMaxTime = 0.f;
|
||||
|
||||
// current time of the animation
|
||||
F32 mTime = 0.f;
|
||||
|
||||
std::vector<RotationChannel> mRotationChannels;
|
||||
std::vector<TranslationChannel> mTranslationChannels;
|
||||
std::vector<ScaleChannel> mScaleChannels;
|
||||
|
||||
const Animation& operator=(const tinygltf::Animation& src);
|
||||
|
||||
void allocateGLResources(Asset& asset);
|
||||
|
||||
void update(Asset& asset, float dt);
|
||||
|
||||
// apply this animation at the specified time
|
||||
void apply(Asset& asset, F32 time);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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<U32> anim_idx(gSavedSettings, "GLTFAnimationIndex", 0);
|
||||
static LLCachedControl<F32> anim_speed(gSavedSettings, "GLTFAnimationSpeed", 1.f);
|
||||
|
||||
U32 idx = llclamp(anim_idx(), 0U, mAnimations.size() - 1);
|
||||
mAnimations[idx].update(*this, dt*anim_speed);
|
||||
}
|
||||
|
||||
updateTransforms();
|
||||
}
|
||||
}
|
||||
|
||||
void Asset::allocateGLResources(const std::string& filename, const tinygltf::Model& model)
|
||||
{
|
||||
// do images first as materials may depend on images
|
||||
for (auto& image : mImages)
|
||||
{
|
||||
image.allocateGLResources();
|
||||
}
|
||||
|
||||
// do materials before meshes as meshes may depend on materials
|
||||
for (U32 i = 0; i < mMaterials.size(); ++i)
|
||||
{
|
||||
mMaterials[i].allocateGLResources(*this);
|
||||
LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true);
|
||||
}
|
||||
|
||||
for (auto& mesh : mMeshes)
|
||||
{
|
||||
mesh.allocateGLResources(*this);
|
||||
}
|
||||
|
||||
for (auto& animation : mAnimations)
|
||||
{
|
||||
animation.allocateGLResources(*this);
|
||||
}
|
||||
|
||||
for (auto& skin : mSkins)
|
||||
{
|
||||
skin.allocateGLResources(*this);
|
||||
}
|
||||
}
|
||||
|
||||
const Asset& Asset::operator=(const tinygltf::Model& src)
|
||||
{
|
||||
mScenes.resize(src.scenes.size());
|
||||
for (U32 i = 0; i < src.scenes.size(); ++i)
|
||||
{
|
||||
mScenes[i] = src.scenes[i];
|
||||
}
|
||||
|
||||
mNodes.resize(src.nodes.size());
|
||||
for (U32 i = 0; i < src.nodes.size(); ++i)
|
||||
{
|
||||
mNodes[i] = src.nodes[i];
|
||||
}
|
||||
|
||||
mMeshes.resize(src.meshes.size());
|
||||
for (U32 i = 0; i < src.meshes.size(); ++i)
|
||||
{
|
||||
mMeshes[i] = src.meshes[i];
|
||||
}
|
||||
|
||||
mMaterials.resize(src.materials.size());
|
||||
for (U32 i = 0; i < src.materials.size(); ++i)
|
||||
{
|
||||
mMaterials[i] = src.materials[i];
|
||||
}
|
||||
|
||||
mBuffers.resize(src.buffers.size());
|
||||
for (U32 i = 0; i < src.buffers.size(); ++i)
|
||||
{
|
||||
mBuffers[i] = src.buffers[i];
|
||||
}
|
||||
|
||||
mBufferViews.resize(src.bufferViews.size());
|
||||
for (U32 i = 0; i < src.bufferViews.size(); ++i)
|
||||
{
|
||||
mBufferViews[i] = src.bufferViews[i];
|
||||
}
|
||||
|
||||
mTextures.resize(src.textures.size());
|
||||
for (U32 i = 0; i < src.textures.size(); ++i)
|
||||
{
|
||||
mTextures[i] = src.textures[i];
|
||||
}
|
||||
|
||||
mSamplers.resize(src.samplers.size());
|
||||
for (U32 i = 0; i < src.samplers.size(); ++i)
|
||||
{
|
||||
mSamplers[i] = src.samplers[i];
|
||||
}
|
||||
|
||||
mImages.resize(src.images.size());
|
||||
for (U32 i = 0; i < src.images.size(); ++i)
|
||||
{
|
||||
mImages[i] = src.images[i];
|
||||
}
|
||||
|
||||
mAccessors.resize(src.accessors.size());
|
||||
for (U32 i = 0; i < src.accessors.size(); ++i)
|
||||
{
|
||||
mAccessors[i] = src.accessors[i];
|
||||
}
|
||||
|
||||
mAnimations.resize(src.animations.size());
|
||||
for (U32 i = 0; i < src.animations.size(); ++i)
|
||||
{
|
||||
mAnimations[i] = src.animations[i];
|
||||
}
|
||||
|
||||
mSkins.resize(src.skins.size());
|
||||
for (U32 i = 0; i < src.skins.size(); ++i)
|
||||
{
|
||||
mSkins[i] = src.skins[i];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Material& Material::operator=(const tinygltf::Material& src)
|
||||
{
|
||||
mName = src.name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Material::allocateGLResources(Asset& asset)
|
||||
{
|
||||
// allocate material
|
||||
mMaterial = new LLFetchedGLTFMaterial();
|
||||
}
|
||||
|
||||
const Mesh& Mesh::operator=(const tinygltf::Mesh& src)
|
||||
{
|
||||
mPrimitives.resize(src.primitives.size());
|
||||
for (U32 i = 0; i < src.primitives.size(); ++i)
|
||||
{
|
||||
mPrimitives[i] = src.primitives[i];
|
||||
}
|
||||
|
||||
mWeights = src.weights;
|
||||
mName = src.name;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Mesh::allocateGLResources(Asset& asset)
|
||||
{
|
||||
for (auto& primitive : mPrimitives)
|
||||
{
|
||||
primitive.allocateGLResources(asset);
|
||||
}
|
||||
}
|
||||
|
||||
const Scene& Scene::operator=(const tinygltf::Scene& src)
|
||||
{
|
||||
mNodes = src.nodes;
|
||||
mName = src.name;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Texture& Texture::operator=(const tinygltf::Texture& src)
|
||||
{
|
||||
mSampler = src.sampler;
|
||||
mSource = src.source;
|
||||
mName = src.name;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Sampler& Sampler::operator=(const tinygltf::Sampler& src)
|
||||
{
|
||||
mMagFilter = src.magFilter;
|
||||
mMinFilter = src.minFilter;
|
||||
mWrapS = src.wrapS;
|
||||
mWrapT = src.wrapT;
|
||||
mName = src.name;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Skin::uploadMatrixPalette(Asset& asset, Node& node)
|
||||
{
|
||||
// prepare matrix palette
|
||||
|
||||
// modelview will be applied by the shader, so assume matrix palette is in asset space
|
||||
std::vector<glh::matrix4f> t_mp;
|
||||
|
||||
t_mp.resize(mJoints.size());
|
||||
|
||||
for (U32 i = 0; i < mJoints.size(); ++i)
|
||||
{
|
||||
Node& joint = asset.mNodes[mJoints[i]];
|
||||
|
||||
//t_mp[i].set_value(joint.mRenderMatrix.getF32ptr());
|
||||
//t_mp[i] = t_mp[i] * mInverseBindMatricesData[i];
|
||||
|
||||
//t_mp[i].set_value(joint.mRenderMatrix.getF32ptr());
|
||||
//t_mp[i] = mInverseBindMatricesData[i] * t_mp[i];
|
||||
|
||||
t_mp[i].set_value(joint.mRenderMatrix.getF32ptr());
|
||||
t_mp[i] = t_mp[i] * mInverseBindMatricesData[i];
|
||||
|
||||
}
|
||||
|
||||
std::vector<F32> glmp;
|
||||
|
||||
glmp.resize(mJoints.size() * 12);
|
||||
|
||||
F32* mp = glmp.data();
|
||||
|
||||
for (U32 i = 0; i < mJoints.size(); ++i)
|
||||
{
|
||||
F32* m = (F32*)t_mp[i].m;
|
||||
|
||||
U32 idx = i * 12;
|
||||
|
||||
mp[idx + 0] = m[0];
|
||||
mp[idx + 1] = m[1];
|
||||
mp[idx + 2] = m[2];
|
||||
mp[idx + 3] = m[12];
|
||||
|
||||
mp[idx + 4] = m[4];
|
||||
mp[idx + 5] = m[5];
|
||||
mp[idx + 6] = m[6];
|
||||
mp[idx + 7] = m[13];
|
||||
|
||||
mp[idx + 8] = m[8];
|
||||
mp[idx + 9] = m[9];
|
||||
mp[idx + 10] = m[10];
|
||||
mp[idx + 11] = m[14];
|
||||
}
|
||||
|
||||
LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
|
||||
mJoints.size(),
|
||||
FALSE,
|
||||
(GLfloat*)glmp.data());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,86 +29,19 @@
|
|||
#include "llvertexbuffer.h"
|
||||
#include "llvolumeoctree.h"
|
||||
#include "../lltinygltfhelper.h"
|
||||
#include "accessor.h"
|
||||
#include "primitive.h"
|
||||
#include "animation.h"
|
||||
|
||||
extern F32SecondsImplicit gFrameTimeSeconds;
|
||||
|
||||
// LL GLTF Implementation
|
||||
namespace LL
|
||||
{
|
||||
namespace GLTF
|
||||
{
|
||||
constexpr S32 INVALID_INDEX = -1;
|
||||
|
||||
class Asset;
|
||||
|
||||
class Buffer
|
||||
{
|
||||
public:
|
||||
std::vector<U8> mData;
|
||||
std::string mName;
|
||||
std::string mUri;
|
||||
|
||||
const Buffer& operator=(const tinygltf::Buffer& src)
|
||||
{
|
||||
mData = src.data;
|
||||
mName = src.name;
|
||||
mUri = src.uri;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class BufferView
|
||||
{
|
||||
public:
|
||||
S32 mBuffer = INVALID_INDEX;
|
||||
S32 mByteLength;
|
||||
S32 mByteOffset;
|
||||
S32 mByteStride;
|
||||
S32 mTarget;
|
||||
S32 mComponentType;
|
||||
|
||||
std::string mName;
|
||||
|
||||
const BufferView& operator=(const tinygltf::BufferView& src)
|
||||
{
|
||||
mBuffer = src.buffer;
|
||||
mByteLength = src.byteLength;
|
||||
mByteOffset = src.byteOffset;
|
||||
mByteStride = src.byteStride;
|
||||
mTarget = src.target;
|
||||
mName = src.name;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class Accessor
|
||||
{
|
||||
public:
|
||||
S32 mBufferView = INVALID_INDEX;
|
||||
S32 mByteOffset;
|
||||
S32 mComponentType;
|
||||
S32 mCount;
|
||||
std::vector<double> mMax;
|
||||
std::vector<double> mMin;
|
||||
S32 mType;
|
||||
bool mNormalized;
|
||||
std::string mName;
|
||||
|
||||
const Accessor& operator=(const tinygltf::Accessor& src)
|
||||
{
|
||||
mBufferView = src.bufferView;
|
||||
mByteOffset = src.byteOffset;
|
||||
mComponentType = src.componentType;
|
||||
mCount = src.count;
|
||||
mType = src.type;
|
||||
mNormalized = src.normalized;
|
||||
mName = src.name;
|
||||
mMax = src.maxValues;
|
||||
mMin = src.maxValues;
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class Material
|
||||
{
|
||||
public:
|
||||
|
|
@ -118,17 +51,9 @@ namespace LL
|
|||
LLPointer<LLFetchedGLTFMaterial> mMaterial;
|
||||
std::string mName;
|
||||
|
||||
const Material& operator=(const tinygltf::Material& src)
|
||||
{
|
||||
mName = src.name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void allocateGLResources(Asset& asset)
|
||||
{
|
||||
// allocate material
|
||||
mMaterial = new LLFetchedGLTFMaterial();
|
||||
}
|
||||
const Material& operator=(const tinygltf::Material& src);
|
||||
|
||||
void allocateGLResources(Asset& asset);
|
||||
};
|
||||
|
||||
class Mesh
|
||||
|
|
@ -138,28 +63,9 @@ namespace LL
|
|||
std::vector<double> mWeights;
|
||||
std::string mName;
|
||||
|
||||
const Mesh& operator=(const tinygltf::Mesh& src)
|
||||
{
|
||||
mPrimitives.resize(src.primitives.size());
|
||||
for (U32 i = 0; i < src.primitives.size(); ++i)
|
||||
{
|
||||
mPrimitives[i] = src.primitives[i];
|
||||
}
|
||||
|
||||
mWeights = src.weights;
|
||||
mName = src.name;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void allocateGLResources(Asset& asset)
|
||||
{
|
||||
for (auto& primitive : mPrimitives)
|
||||
{
|
||||
primitive.allocateGLResources(asset);
|
||||
}
|
||||
}
|
||||
|
||||
const Mesh& operator=(const tinygltf::Mesh& src);
|
||||
|
||||
void allocateGLResources(Asset& asset);
|
||||
};
|
||||
|
||||
class Node
|
||||
|
|
@ -170,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<S32> 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<S32> mJoints;
|
||||
std::string mName;
|
||||
std::vector<glh::matrix4f> 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<S32> 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<Sampler> mSamplers;
|
||||
std::vector<Image> mImages;
|
||||
std::vector<Accessor> mAccessors;
|
||||
std::vector<Animation> mAnimations;
|
||||
std::vector<Skin> mSkins;
|
||||
|
||||
void allocateGLResources(const std::string& filename, const tinygltf::Model& model)
|
||||
{
|
||||
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);
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,402 @@
|
|||
#pragma once
|
||||
|
||||
/**
|
||||
* @file buffer_util.inl
|
||||
* @brief LL GLTF Implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2024, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// inline template implementations for copying data out of GLTF buffers
|
||||
// DO NOT include from header files to avoid the need to rebuild the whole project
|
||||
// whenever we add support for more types
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define LL_FUNCSIG __FUNCSIG__
|
||||
#else
|
||||
#define LL_FUNCSIG __PRETTY_FUNCTION__
|
||||
#endif
|
||||
|
||||
namespace LL
|
||||
{
|
||||
namespace GLTF
|
||||
{
|
||||
// copy one Scalar from src to dst
|
||||
template<class S, class T>
|
||||
static void copyScalar(S* src, T& dst)
|
||||
{
|
||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||
}
|
||||
|
||||
// copy one vec2 from src to dst
|
||||
template<class S, class T>
|
||||
static void copyVec2(S* src, T& dst)
|
||||
{
|
||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||
}
|
||||
|
||||
// copy one vec3 from src to dst
|
||||
template<class S, class T>
|
||||
static void copyVec3(S* src, T& dst)
|
||||
{
|
||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||
}
|
||||
|
||||
// copy one vec4 from src to dst
|
||||
template<class S, class T>
|
||||
static void copyVec4(S* src, T& dst)
|
||||
{
|
||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||
}
|
||||
|
||||
// copy one vec2 from src to dst
|
||||
template<class S, class T>
|
||||
static void copyMat2(S* src, T& dst)
|
||||
{
|
||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||
}
|
||||
|
||||
// copy one vec3 from src to dst
|
||||
template<class S, class T>
|
||||
static void copyMat3(S* src, T& dst)
|
||||
{
|
||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||
}
|
||||
|
||||
// copy one vec4 from src to dst
|
||||
template<class S, class T>
|
||||
static void copyMat4(S* src, T& dst)
|
||||
{
|
||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||
}
|
||||
|
||||
//=========================================================================================================
|
||||
// concrete implementations for different types of source and destination
|
||||
//=========================================================================================================
|
||||
|
||||
// suppress unused function warning -- clang complains here but these specializations are definitely used
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
template<>
|
||||
void copyScalar<F32, F32>(F32* src, F32& dst)
|
||||
{
|
||||
dst = *src;
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyScalar<U32, U32>(U32* src, U32& dst)
|
||||
{
|
||||
dst = *src;
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyScalar<U32, U16>(U32* src, U16& dst)
|
||||
{
|
||||
dst = *src;
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyScalar<U16, U16>(U16* src, U16& dst)
|
||||
{
|
||||
dst = *src;
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyScalar<U16, U32>(U16* src, U32& dst)
|
||||
{
|
||||
dst = *src;
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyScalar<U8, U16>(U8* src, U16& dst)
|
||||
{
|
||||
dst = *src;
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyScalar<U8, U32>(U8* src, U32& dst)
|
||||
{
|
||||
dst = *src;
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec2<F32, LLVector2>(F32* src, LLVector2& dst)
|
||||
{
|
||||
dst.set(src[0], src[1]);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec3<F32, glh::vec3f>(F32* src, glh::vec3f& dst)
|
||||
{
|
||||
dst.set_value(src[0], src[1], src[2]);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec3<F32, LLVector4a>(F32* src, LLVector4a& dst)
|
||||
{
|
||||
dst.load3(src);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec3<U16, LLColor4U>(U16* src, LLColor4U& dst)
|
||||
{
|
||||
dst.set(src[0], src[1], src[2], 255);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec4<U8, LLColor4U>(U8* src, LLColor4U& dst)
|
||||
{
|
||||
dst.set(src[0], src[1], src[2], src[3]);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec4<U16, LLColor4U>(U16* src, LLColor4U& dst)
|
||||
{
|
||||
dst.set(src[0], src[1], src[2], src[3]);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec4<F32, LLColor4U>(F32* src, LLColor4U& dst)
|
||||
{
|
||||
dst.set(src[0]*255, src[1]*255, src[2]*255, src[3]*255);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec4<F32, LLVector4a>(F32* src, LLVector4a& dst)
|
||||
{
|
||||
dst.loadua(src);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec4<U16, LLVector4a>(U16* src, LLVector4a& dst)
|
||||
{
|
||||
dst.set(src[0], src[1], src[2], src[3]);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec4<U8, LLVector4a>(U8* src, LLVector4a& dst)
|
||||
{
|
||||
dst.set(src[0], src[1], src[2], src[3]);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec4<F32, glh::quaternionf>(F32* src, glh::quaternionf& dst)
|
||||
{
|
||||
dst.set_value(src);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyMat4<F32, glh::matrix4f>(F32* src, glh::matrix4f& dst)
|
||||
{
|
||||
dst.set_value(src);
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
//=========================================================================================================
|
||||
|
||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||
template<class S, class T>
|
||||
static void copyScalar(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||
{
|
||||
for (S32 i = 0; i < count; ++i)
|
||||
{
|
||||
copyScalar(src, *dst);
|
||||
dst++;
|
||||
src = (S*)((U8*)src + stride);
|
||||
}
|
||||
}
|
||||
|
||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||
template<class S, class T>
|
||||
static void copyVec2(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||
{
|
||||
for (S32 i = 0; i < count; ++i)
|
||||
{
|
||||
copyVec2(src, *dst);
|
||||
dst++;
|
||||
src = (S*)((U8*)src + stride);
|
||||
}
|
||||
}
|
||||
|
||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||
template<class S, class T>
|
||||
static void copyVec3(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||
{
|
||||
for (S32 i = 0; i < count; ++i)
|
||||
{
|
||||
copyVec3(src, *dst);
|
||||
dst++;
|
||||
src = (S*)((U8*)src + stride);
|
||||
}
|
||||
}
|
||||
|
||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||
template<class S, class T>
|
||||
static void copyVec4(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||
{
|
||||
for (S32 i = 0; i < count; ++i)
|
||||
{
|
||||
copyVec4(src, *dst);
|
||||
dst++;
|
||||
src = (S*)((U8*)src + stride);
|
||||
}
|
||||
}
|
||||
|
||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||
template<class S, class T>
|
||||
static void copyMat2(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||
{
|
||||
for (S32 i = 0; i < count; ++i)
|
||||
{
|
||||
copyMat2(src, *dst);
|
||||
dst++;
|
||||
src = (S*)((U8*)src + stride);
|
||||
}
|
||||
}
|
||||
|
||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||
template<class S, class T>
|
||||
static void copyMat3(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||
{
|
||||
for (S32 i = 0; i < count; ++i)
|
||||
{
|
||||
copyMat3(src, *dst);
|
||||
dst++;
|
||||
src = (S*)((U8*)src + stride);
|
||||
}
|
||||
}
|
||||
|
||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||
template<class S, class T>
|
||||
static void copyMat4(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||
{
|
||||
for (S32 i = 0; i < count; ++i)
|
||||
{
|
||||
copyMat4(src, *dst);
|
||||
dst++;
|
||||
src = (S*)((U8*)src + stride);
|
||||
}
|
||||
}
|
||||
|
||||
template<class S, class T>
|
||||
static void copy(Asset& asset, Accessor& accessor, const S* src, LLStrider<T>& dst, S32 byteStride)
|
||||
{
|
||||
if (accessor.mType == (S32)Accessor::Type::SCALAR)
|
||||
{
|
||||
S32 stride = byteStride == 0 ? sizeof(S) * 1 : byteStride;
|
||||
copyScalar((S*)src, dst, stride, accessor.mCount);
|
||||
}
|
||||
else if (accessor.mType == (S32)Accessor::Type::VEC2)
|
||||
{
|
||||
S32 stride = byteStride == 0 ? sizeof(S) * 2 : byteStride;
|
||||
copyVec2((S*)src, dst, stride, accessor.mCount);
|
||||
}
|
||||
else if (accessor.mType == (S32)Accessor::Type::VEC3)
|
||||
{
|
||||
S32 stride = byteStride == 0 ? sizeof(S) * 3 : byteStride;
|
||||
copyVec3((S*)src, dst, stride, accessor.mCount);
|
||||
}
|
||||
else if (accessor.mType == (S32)Accessor::Type::VEC4)
|
||||
{
|
||||
S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride;
|
||||
copyVec4((S*)src, dst, stride, accessor.mCount);
|
||||
}
|
||||
else if (accessor.mType == (S32)Accessor::Type::MAT2)
|
||||
{
|
||||
S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride;
|
||||
copyMat2((S*)src, dst, stride, accessor.mCount);
|
||||
}
|
||||
else if (accessor.mType == (S32)Accessor::Type::MAT3)
|
||||
{
|
||||
S32 stride = byteStride == 0 ? sizeof(S) * 9 : byteStride;
|
||||
copyMat3((S*)src, dst, stride, accessor.mCount);
|
||||
}
|
||||
else if (accessor.mType == (S32)Accessor::Type::MAT4)
|
||||
{
|
||||
S32 stride = byteStride == 0 ? sizeof(S) * 16 : byteStride;
|
||||
copyMat4((S*)src, dst, stride, accessor.mCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_ERRS("GLTF") << "Unsupported accessor type" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
// copy data from accessor to strider
|
||||
template<class T>
|
||||
static void copy(Asset& asset, Accessor& accessor, LLStrider<T>& dst)
|
||||
{
|
||||
const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView];
|
||||
const Buffer& buffer = asset.mBuffers[bufferView.mBuffer];
|
||||
const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset;
|
||||
|
||||
if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_FLOAT)
|
||||
{
|
||||
LL::GLTF::copy(asset, accessor, (const F32*)src, dst, bufferView.mByteStride);
|
||||
}
|
||||
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)
|
||||
{
|
||||
LL::GLTF::copy(asset, accessor, (const U16*)src, dst, bufferView.mByteStride);
|
||||
}
|
||||
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT)
|
||||
{
|
||||
LL::GLTF::copy(asset, accessor, (const U32*)src, dst, bufferView.mByteStride);
|
||||
}
|
||||
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)
|
||||
{
|
||||
LL::GLTF::copy(asset, accessor, (const U8*)src, dst, bufferView.mByteStride);
|
||||
}
|
||||
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_SHORT)
|
||||
{
|
||||
LL::GLTF::copy(asset, accessor, (const S16*)src, dst, bufferView.mByteStride);
|
||||
}
|
||||
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_BYTE)
|
||||
{
|
||||
LL::GLTF::copy(asset, accessor, (const S8*)src, dst, bufferView.mByteStride);
|
||||
}
|
||||
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_DOUBLE)
|
||||
{
|
||||
LL::GLTF::copy(asset, accessor, (const F64*)src, dst, bufferView.mByteStride);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_ERRS("GLTF") << "Unsupported component type" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
// copy data from accessor to vector
|
||||
template<class T>
|
||||
static void copy(Asset& asset, Accessor& accessor, std::vector<T>& dst)
|
||||
{
|
||||
dst.resize(accessor.mCount);
|
||||
LLStrider<T> strider = dst.data();
|
||||
copy(asset, accessor, strider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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<class S, class T>
|
||||
void copyVec2(S* src, T& dst)
|
||||
{
|
||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||
}
|
||||
|
||||
// copy one vec3 from src to dst
|
||||
template<class S, class T>
|
||||
void copyVec3(S* src, T& dst)
|
||||
{
|
||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||
}
|
||||
|
||||
// copy one vec4 from src to dst
|
||||
template<class S, class T>
|
||||
void copyVec4(S* src, T& dst)
|
||||
{
|
||||
LL_ERRS() << "TODO: implement " << LL_FUNCSIG << LL_ENDL;
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec2<F32, LLVector2>(F32* src, LLVector2& dst)
|
||||
{
|
||||
dst.set(src[0], src[1]);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec3<F32, LLVector4a>(F32* src, LLVector4a& dst)
|
||||
{
|
||||
dst.load3(src);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec3<U16, LLColor4U>(U16* src, LLColor4U& dst)
|
||||
{
|
||||
dst.set(src[0], src[1], src[2], 255);
|
||||
}
|
||||
|
||||
template<>
|
||||
void copyVec4<F32, LLVector4a>(F32* src, LLVector4a& dst)
|
||||
{
|
||||
dst.loadua(src);
|
||||
}
|
||||
|
||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||
template<class S, class T>
|
||||
void copyVec2(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||
{
|
||||
for (S32 i = 0; i < count; ++i)
|
||||
{
|
||||
copyVec2(src, *dst);
|
||||
dst++;
|
||||
src = (S*)((U8*)src + stride);
|
||||
}
|
||||
}
|
||||
|
||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||
template<class S, class T>
|
||||
void copyVec3(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||
{
|
||||
for (S32 i = 0; i < count; ++i)
|
||||
{
|
||||
copyVec3(src, *dst);
|
||||
dst++;
|
||||
src = (S*)((U8*)src + stride);
|
||||
}
|
||||
}
|
||||
|
||||
// copy from src to dst, stride is the number of bytes between each element in src, count is number of elements to copy
|
||||
template<class S, class T>
|
||||
void copyVec4(S* src, LLStrider<T> dst, S32 stride, S32 count)
|
||||
{
|
||||
for (S32 i = 0; i < count; ++i)
|
||||
{
|
||||
copyVec3(src, *dst);
|
||||
dst++;
|
||||
src = (S*)((U8*)src + stride);
|
||||
}
|
||||
}
|
||||
|
||||
template<class S, class T>
|
||||
void copyAttributeArray(Asset& asset, const Accessor& accessor, const S* src, LLStrider<T>& dst, S32 byteStride)
|
||||
{
|
||||
if (accessor.mType == TINYGLTF_TYPE_VEC2)
|
||||
{
|
||||
S32 stride = byteStride == 0 ? sizeof(S) * 2 : byteStride;
|
||||
copyVec2((S*)src, dst, stride, accessor.mCount);
|
||||
}
|
||||
else if (accessor.mType == TINYGLTF_TYPE_VEC3)
|
||||
{
|
||||
S32 stride = byteStride == 0 ? sizeof(S) * 3 : byteStride;
|
||||
copyVec3((S*)src, dst, stride, accessor.mCount);
|
||||
}
|
||||
else if (accessor.mType == TINYGLTF_TYPE_VEC4)
|
||||
{
|
||||
S32 stride = byteStride == 0 ? sizeof(S) * 4 : byteStride;
|
||||
copyVec4((S*)src, dst, stride, accessor.mCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_ERRS("GLTF") << "Unsupported accessor type" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Primitive::copyAttribute(Asset& asset, S32 accessorIdx, LLStrider<T>& dst)
|
||||
{
|
||||
const Accessor& accessor = asset.mAccessors[accessorIdx];
|
||||
const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView];
|
||||
const Buffer& buffer = asset.mBuffers[bufferView.mBuffer];
|
||||
const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset;
|
||||
|
||||
if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_FLOAT)
|
||||
{
|
||||
copyAttributeArray(asset, accessor, (const F32*)src, dst, bufferView.mByteStride);
|
||||
}
|
||||
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)
|
||||
{
|
||||
copyAttributeArray(asset, accessor, (const U16*)src, dst, bufferView.mByteStride);
|
||||
}
|
||||
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT)
|
||||
{
|
||||
copyAttributeArray(asset, accessor, (const U32*)src, dst, bufferView.mByteStride);
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
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<LLVector4a> dst;
|
||||
mVertexBuffer->getVertexStrider(dst);
|
||||
|
||||
copyAttribute(asset, it.second, dst);
|
||||
copy(asset, accessor, mPositions);
|
||||
}
|
||||
else if (attribName == "NORMAL")
|
||||
{
|
||||
needs_normal = false;
|
||||
// load normal data
|
||||
LLStrider<LLVector4a> dst;
|
||||
mVertexBuffer->getNormalStrider(dst);
|
||||
|
||||
copyAttribute(asset, it.second, dst);
|
||||
copy(asset, accessor, mNormals);
|
||||
}
|
||||
else if (attribName == "TANGENT")
|
||||
{
|
||||
needs_tangent = false;
|
||||
// load tangent data
|
||||
|
||||
LLStrider<LLVector4a> dst;
|
||||
mVertexBuffer->getTangentStrider(dst);
|
||||
|
||||
copyAttribute(asset, it.second, dst);
|
||||
copy(asset, accessor, mTangents);
|
||||
}
|
||||
else if (attribName == "COLOR_0")
|
||||
{
|
||||
needs_color = false;
|
||||
// load color data
|
||||
|
||||
LLStrider<LLColor4U> dst;
|
||||
mVertexBuffer->getColorStrider(dst);
|
||||
|
||||
copyAttribute(asset, it.second, dst);
|
||||
copy(asset, accessor, mColors);
|
||||
}
|
||||
else if (attribName == "TEXCOORD_0")
|
||||
{
|
||||
needs_texcoord = false;
|
||||
// load texcoord data
|
||||
LLStrider<LLVector2> dst;
|
||||
mVertexBuffer->getTexCoord0Strider(dst);
|
||||
|
||||
LLStrider<LLVector2> tc = dst;
|
||||
copyAttribute(asset, it.second, dst);
|
||||
|
||||
// convert to OpenGL coordinate space
|
||||
for (U32 i = 0; i < numVertices; ++i)
|
||||
{
|
||||
tc->mV[1] = 1.0f - tc->mV[1];;
|
||||
tc++;
|
||||
}
|
||||
copy(asset, accessor, mTexCoords);
|
||||
}
|
||||
else if (attribName == "JOINTS_0")
|
||||
{
|
||||
copy(asset, accessor, mJoints);
|
||||
}
|
||||
else if (attribName == "WEIGHTS_0")
|
||||
{
|
||||
copy(asset, accessor, mWeights);
|
||||
}
|
||||
}
|
||||
|
||||
// copy index buffer
|
||||
if (mIndices != INVALID_INDEX)
|
||||
{
|
||||
const Accessor& accessor = asset.mAccessors[mIndices];
|
||||
const BufferView& bufferView = asset.mBufferViews[accessor.mBufferView];
|
||||
const Buffer& buffer = asset.mBuffers[bufferView.mBuffer];
|
||||
|
||||
const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset;
|
||||
|
||||
LLStrider<U16> 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<LLColor4U> dst;
|
||||
mVertexBuffer->getColorStrider(dst);
|
||||
for (U32 i = 0; i < numVertices; ++i)
|
||||
{
|
||||
*(dst++) = LLColor4U(255, 255, 255, 255);
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_texcoord)
|
||||
{ // set default texcoord
|
||||
LLStrider<LLVector2> dst;
|
||||
mVertexBuffer->getTexCoord0Strider(dst);
|
||||
for (U32 i = 0; i < numVertices; ++i)
|
||||
{
|
||||
*(dst++) = LLVector2(0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_normal)
|
||||
{ // set default normal
|
||||
LLStrider<LLVector4a> dst;
|
||||
mVertexBuffer->getNormalStrider(dst);
|
||||
for (U32 i = 0; i < numVertices; ++i)
|
||||
{
|
||||
*(dst++) = LLVector4a(0.0f, 0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_tangent)
|
||||
{ // TODO: generate tangents if needed
|
||||
LLStrider<LLVector4a> dst;
|
||||
mVertexBuffer->getTangentStrider(dst);
|
||||
for (U32 i = 0; i < numVertices; ++i)
|
||||
{
|
||||
*(dst++) = LLVector4a(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
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<LLVector4a> weight_data;
|
||||
weight_data.resize(mWeights.size());
|
||||
|
||||
F32 max_weight = 1.f - FLT_EPSILON*100.f;
|
||||
LLVector4a maxw(max_weight, max_weight, max_weight, max_weight);
|
||||
for (U32 i = 0; i < mWeights.size(); ++i)
|
||||
{
|
||||
LLVector4a& w = weight_data[i];
|
||||
w.setMin(mWeights[i], maxw);
|
||||
w.add(mJoints[i]);
|
||||
};
|
||||
|
||||
mVertexBuffer->setWeight4Data(weight_data.data());
|
||||
}
|
||||
|
||||
createOctree();
|
||||
|
||||
mVertexBuffer->unmapBuffer();
|
||||
mVertexBuffer->unbind();
|
||||
}
|
||||
|
||||
void initOctreeTriangle(LLVolumeTriangle* tri, F32 scaler, S32 i0, S32 i1, S32 i2, const LLVector4a& v0, const LLVector4a& v1, const LLVector4a& v2)
|
||||
{
|
||||
//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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,10 @@ namespace LL
|
|||
std::vector<LLVector4a> mNormals;
|
||||
std::vector<LLVector4a> mTangents;
|
||||
std::vector<LLVector4a> mPositions;
|
||||
std::vector<U16> mIndexArray;
|
||||
std::vector<LLVector4a> mJoints;
|
||||
std::vector<LLVector4a> mWeights;
|
||||
std::vector<LLColor4U> mColors;
|
||||
std::vector<U32> mIndexArray;
|
||||
|
||||
// raycast acceleration structure
|
||||
LLPointer<LLVolumeOctree> mOctree;
|
||||
|
|
@ -68,11 +71,6 @@ namespace LL
|
|||
S32 mIndices = -1;
|
||||
std::unordered_map<std::string, int> mAttributes;
|
||||
|
||||
// copy the attribute in the given BufferView to the given destination
|
||||
// assumes destination has enough storage for the attribute
|
||||
template<class T>
|
||||
void copyAttribute(Asset& asset, S32 bufferViewIdx, LLStrider<T>& dst);
|
||||
|
||||
// create octree based on vertex buffer
|
||||
// must be called before buffer is unmapped and after buffer is populated with good data
|
||||
void createOctree();
|
||||
|
|
@ -87,52 +85,7 @@ namespace LL
|
|||
LLVector4a* tangent = NULL // return the surface tangent at the intersection point
|
||||
);
|
||||
|
||||
const Primitive& operator=(const tinygltf::Primitive& src)
|
||||
{
|
||||
// load material
|
||||
mMaterial = src.material;
|
||||
|
||||
// load mode
|
||||
mMode = src.mode;
|
||||
|
||||
// load indices
|
||||
mIndices = src.indices;
|
||||
|
||||
// load attributes
|
||||
for (auto& it : src.attributes)
|
||||
{
|
||||
mAttributes[it.first] = it.second;
|
||||
}
|
||||
|
||||
switch (mMode)
|
||||
{
|
||||
case TINYGLTF_MODE_POINTS:
|
||||
mGLMode = LLRender::POINTS;
|
||||
break;
|
||||
case TINYGLTF_MODE_LINE:
|
||||
mGLMode = LLRender::LINES;
|
||||
break;
|
||||
case TINYGLTF_MODE_LINE_LOOP:
|
||||
mGLMode = LLRender::LINE_LOOP;
|
||||
break;
|
||||
case TINYGLTF_MODE_LINE_STRIP:
|
||||
mGLMode = LLRender::LINE_STRIP;
|
||||
break;
|
||||
case TINYGLTF_MODE_TRIANGLES:
|
||||
mGLMode = LLRender::TRIANGLES;
|
||||
break;
|
||||
case TINYGLTF_MODE_TRIANGLE_STRIP:
|
||||
mGLMode = LLRender::TRIANGLE_STRIP;
|
||||
break;
|
||||
case TINYGLTF_MODE_TRIANGLE_FAN:
|
||||
mGLMode = LLRender::TRIANGLE_FAN;
|
||||
break;
|
||||
default:
|
||||
mGLMode = GL_TRIANGLES;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
const Primitive& operator=(const tinygltf::Primitive& src);
|
||||
|
||||
void allocateGLResources(Asset& asset);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ void GLTFSceneManager::load(const std::string& filename)
|
|||
LLPointer<Asset> asset = new Asset();
|
||||
*asset = model;
|
||||
|
||||
gDebugProgram.bind(); // bind a shader to satisfy LLVertexBuffer assertions
|
||||
asset->allocateGLResources(filename, model);
|
||||
asset->updateTransforms();
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -5722,6 +5722,7 @@ void LLAppViewer::idle()
|
|||
{
|
||||
LLPerfStats::tunedAvatars=0; // <FS:Beq> reset the number of avatars that have been tweaked.
|
||||
gObjectList.update(gAgent);
|
||||
LL::GLTFSceneManager::instance().update();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(); )
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ void LLDrawPoolGLTFPBR::renderDeferred(S32 pass)
|
|||
|
||||
|
||||
gDeferredPBROpaqueProgram.bind(true);
|
||||
LL::GLTFSceneManager::instance().render(true, true);
|
||||
pushRiggedGLTFBatches(mRenderType + 1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@
|
|||
#include "llshadermgr.h"
|
||||
#include "pipeline.h"
|
||||
|
||||
//static
|
||||
LLFetchedGLTFMaterial LLFetchedGLTFMaterial::sDefault;
|
||||
|
||||
LLFetchedGLTFMaterial::LLFetchedGLTFMaterial()
|
||||
: LLGLTFMaterial()
|
||||
, mExpectedFlusTime(0.f)
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ public:
|
|||
|
||||
std::set<LLTextureEntry*> mTextureEntires;
|
||||
|
||||
// default material for when assets don't have one
|
||||
static LLFetchedGLTFMaterial sDefault;
|
||||
protected:
|
||||
// Lifetime management
|
||||
|
||||
|
|
|
|||
|
|
@ -357,9 +357,16 @@ LLVector3 LLManip::getSavedPivotPoint() const
|
|||
|
||||
LLVector3 LLManip::getPivotPoint()
|
||||
{
|
||||
|
||||
// <FS:KC> 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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<LLVector3>& child_positions = object->mUnselectedChildrenPositions ;
|
||||
std::vector<LLQuaternion> 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<LLVector3>& child_positions = object->mUnselectedChildrenPositions;
|
||||
std::vector<LLQuaternion> 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// <AW: opensim-limits>
|
||||
// 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();
|
||||
}
|
||||
|
||||
// </AW: opensim-limits>
|
||||
// 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();
|
||||
|
|
|
|||
|
|
@ -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 <ImfInputFile.h>
|
||||
#include <ImfArray.h>
|
||||
#include <ImfHeader.h>
|
||||
#include <ImfFrameBuffer.h>
|
||||
#include <iostream>
|
||||
#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<LLImageGL> 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<Imath::half> rPixels;
|
||||
Imf::Array2D<Imath::half> gPixels;
|
||||
Imf::Array2D<Imath::half> 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<F32> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<LLViewerObject*>& 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())
|
||||
|
|
|
|||
|
|
@ -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<LLVector3> mSilhouetteVertices; // array of vertices to render silhouette of object
|
||||
std::vector<LLVector3> mSilhouetteNormals; // array of normals to render silhouette of object
|
||||
BOOL mSilhouetteExists; // need to generate silhouette?
|
||||
S32 mSelectedGLTFNode = -1;
|
||||
S32 mSelectedGLTFPrimitive = -1;
|
||||
|
||||
protected:
|
||||
LLPointer<LLViewerObject> 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<LLViewerObject*>& object_list, BOOL send_to_sim = TRUE);
|
||||
|
|
@ -906,7 +910,7 @@ public:
|
|||
void remove(std::vector<LLViewerObject*>& 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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -342,6 +342,11 @@
|
|||
</menu>
|
||||
<menu label="Darstellungstypen" name="Rendering Types">
|
||||
<menu_item_check label="Einfach" name="Rendering Type Simple"/>
|
||||
<menu_item_check label="Materialien" name="Rendering Type Materials"/>
|
||||
<menu_item_check label="Alpha-Masken" name="Rendering Type Alpha Mask"/>
|
||||
<menu_item_check label="Ganz hell Alpha-Masken" name="Rendering Type Fullbright Alpha Mask"/>
|
||||
<menu_item_check label="Leuchten" name="Rendering Type Glow"/>
|
||||
<menu_item_check label="Ganz hell" name="Rendering Type Fullbright"/>
|
||||
<menu_item_check label="Alpha" name="Rendering Type Alpha"/>
|
||||
<menu_item_check label="Baum" name="Rendering Type Tree"/>
|
||||
<menu_item_check label="Avatare" name="Rendering Type Character"/>
|
||||
|
|
|
|||
|
|
@ -3151,7 +3151,57 @@
|
|||
function="Advanced.ToggleRenderType"
|
||||
parameter="simple" />
|
||||
</menu_item_check>
|
||||
<menu_item_check
|
||||
<menu_item_check
|
||||
label="Materials"
|
||||
name="Rendering Type Materials">
|
||||
<menu_item_check.on_check
|
||||
function="Advanced.CheckRenderType"
|
||||
parameter="materials" />
|
||||
<menu_item_check.on_click
|
||||
function="Advanced.ToggleRenderType"
|
||||
parameter="materials" />
|
||||
</menu_item_check>
|
||||
<menu_item_check
|
||||
label="Alpha Mask"
|
||||
name="Rendering Type Alpha Mask">
|
||||
<menu_item_check.on_check
|
||||
function="Advanced.CheckRenderType"
|
||||
parameter="alpha_mask" />
|
||||
<menu_item_check.on_click
|
||||
function="Advanced.ToggleRenderType"
|
||||
parameter="alpha_mask" />
|
||||
</menu_item_check>
|
||||
<menu_item_check
|
||||
label="Fullbright Alpha Mask"
|
||||
name="Rendering Type Fullbright Alpha Mask">
|
||||
<menu_item_check.on_check
|
||||
function="Advanced.CheckRenderType"
|
||||
parameter="fullbright_alpha_mask" />
|
||||
<menu_item_check.on_click
|
||||
function="Advanced.ToggleRenderType"
|
||||
parameter="fullbright_alpha_mask" />
|
||||
</menu_item_check>
|
||||
<menu_item_check
|
||||
label="Glow"
|
||||
name="Rendering Type Glow">
|
||||
<menu_item_check.on_check
|
||||
function="Advanced.CheckRenderType"
|
||||
parameter="glow" />
|
||||
<menu_item_check.on_click
|
||||
function="Advanced.ToggleRenderType"
|
||||
parameter="glow" />
|
||||
</menu_item_check>
|
||||
<menu_item_check
|
||||
label="Fullbright"
|
||||
name="Rendering Type Fullbright">
|
||||
<menu_item_check.on_check
|
||||
function="Advanced.CheckRenderType"
|
||||
parameter="fullbright" />
|
||||
<menu_item_check.on_click
|
||||
function="Advanced.ToggleRenderType"
|
||||
parameter="fullbright" />
|
||||
</menu_item_check>
|
||||
<menu_item_check
|
||||
label="Alpha"
|
||||
name="Rendering Type Alpha"
|
||||
shortcut="control|alt|shift|2">
|
||||
|
|
@ -4178,6 +4228,16 @@
|
|||
function="Advanced.ToggleInfoDisplay"
|
||||
parameter="octree" />
|
||||
</menu_item_check>
|
||||
<menu_item_check
|
||||
label="GLTF Nodes"
|
||||
name="GLTF Nodes">
|
||||
<menu_item_check.on_check
|
||||
function="Advanced.CheckInfoDisplay"
|
||||
parameter="nodes" />
|
||||
<menu_item_check.on_click
|
||||
function="Advanced.ToggleInfoDisplay"
|
||||
parameter="nodes" />
|
||||
</menu_item_check>
|
||||
<menu_item_check
|
||||
label="Shadow Frusta"
|
||||
name="Shadow Frusta">
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue