Merge branch 'project/gltf_development' of https://github.com/secondlife/viewer
# Conflicts: # indra/cmake/Copy3rdPartyLibs.cmake # indra/llappearance/llavatarappearance.cpp # indra/llrender/llvertexbuffer.cpp # indra/newview/llpanelface.cpp # indra/newview/llviewermenu.cpp # indra/newview/llviewertexturelist.cpp # indra/newview/llvocache.cppmaster
commit
1bbe697db7
|
|
@ -3240,11 +3240,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
||||||
<key>archive</key>
|
<key>archive</key>
|
||||||
<map>
|
<map>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<string>9e0092c6a3aed1cb40a9e26df689c42c68142c9d</string>
|
<string>8278a2368136cb12319ca00e7aceb2829bf3ebd8</string>
|
||||||
<key>hash_algorithm</key>
|
<key>hash_algorithm</key>
|
||||||
<string>sha1</string>
|
<string>sha1</string>
|
||||||
<key>url</key>
|
<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>
|
<string>https://github.com/secondlife/3p-tinyexr/releases/download/v1.0.8-ba4bc64/tinyexr-v1.0.8-common-9373975608.tar.zst</string>
|
||||||
</map>
|
</map>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
<string>common</string>
|
<string>common</string>
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,7 @@ Ansariel Hiller
|
||||||
SL-4126
|
SL-4126
|
||||||
SL-20224
|
SL-20224
|
||||||
SL-20524
|
SL-20524
|
||||||
https://github.com/secondlife/viewer/issues/1051
|
secondlife/viewer#1051
|
||||||
Aralara Rajal
|
Aralara Rajal
|
||||||
Arare Chantilly
|
Arare Chantilly
|
||||||
CHUIBUG-191
|
CHUIBUG-191
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,6 @@ if(WINDOWS)
|
||||||
MESSAGE(WARNING "New MSVC_VERSION ${MSVC_VERSION} of MSVC: adapt Copy3rdPartyLibs.cmake")
|
MESSAGE(WARNING "New MSVC_VERSION ${MSVC_VERSION} of MSVC: adapt Copy3rdPartyLibs.cmake")
|
||||||
endif (MSVC80)
|
endif (MSVC80)
|
||||||
|
|
||||||
# <FS:Ansariel> Try using the VC runtime redistributables that came with the VS installation first
|
|
||||||
if (MSVC_TOOLSET_VER AND DEFINED ENV{VCTOOLSREDISTDIR})
|
if (MSVC_TOOLSET_VER AND DEFINED ENV{VCTOOLSREDISTDIR})
|
||||||
if(ADDRESS_SIZE EQUAL 32)
|
if(ADDRESS_SIZE EQUAL 32)
|
||||||
set(redist_find_path "$ENV{VCTOOLSREDISTDIR}x86\\Microsoft.VC${MSVC_TOOLSET_VER}.CRT")
|
set(redist_find_path "$ENV{VCTOOLSREDISTDIR}x86\\Microsoft.VC${MSVC_TOOLSET_VER}.CRT")
|
||||||
|
|
@ -134,7 +133,6 @@ if(WINDOWS)
|
||||||
get_filename_component(redist_path "${redist_find_path}" ABSOLUTE)
|
get_filename_component(redist_path "${redist_find_path}" ABSOLUTE)
|
||||||
MESSAGE(STATUS "VC Runtime redist path: ${redist_path}")
|
MESSAGE(STATUS "VC Runtime redist path: ${redist_path}")
|
||||||
endif (MSVC_TOOLSET_VER AND DEFINED ENV{VCTOOLSREDISTDIR})
|
endif (MSVC_TOOLSET_VER AND DEFINED ENV{VCTOOLSREDISTDIR})
|
||||||
# </FS:Ansariel>
|
|
||||||
|
|
||||||
if(ADDRESS_SIZE EQUAL 32)
|
if(ADDRESS_SIZE EQUAL 32)
|
||||||
# this folder contains the 32bit DLLs.. (yes really!)
|
# this folder contains the 32bit DLLs.. (yes really!)
|
||||||
|
|
@ -158,14 +156,12 @@ if(WINDOWS)
|
||||||
vcruntime${MSVC_VER}.dll
|
vcruntime${MSVC_VER}.dll
|
||||||
vcruntime${MSVC_VER}_1.dll
|
vcruntime${MSVC_VER}_1.dll
|
||||||
)
|
)
|
||||||
# <FS:Ansariel> Try using the VC runtime redistributables that came with the VS installation first
|
|
||||||
if(redist_path AND EXISTS "${redist_path}/${release_msvc_file}")
|
if(redist_path AND EXISTS "${redist_path}/${release_msvc_file}")
|
||||||
MESSAGE(STATUS "Copying redist file from ${redist_path}/${release_msvc_file}")
|
MESSAGE(STATUS "Copying redist file from ${redist_path}/${release_msvc_file}")
|
||||||
to_staging_dirs(
|
to_staging_dirs(
|
||||||
${redist_path}
|
${redist_path}
|
||||||
third_party_targets
|
third_party_targets
|
||||||
${release_msvc_file})
|
${release_msvc_file})
|
||||||
# </FS:Ansariel>
|
|
||||||
elseif(EXISTS "${registry_path}/${release_msvc_file}")
|
elseif(EXISTS "${registry_path}/${release_msvc_file}")
|
||||||
MESSAGE(STATUS "Copying redist file from ${registry_path}/${release_msvc_file}")
|
MESSAGE(STATUS "Copying redist file from ${registry_path}/${release_msvc_file}")
|
||||||
to_staging_dirs(
|
to_staging_dirs(
|
||||||
|
|
|
||||||
|
|
@ -496,21 +496,69 @@ void LLAvatarAppearance::computeBodySize()
|
||||||
mCurrBodySizeState["mAnkleLeft scale"] = mAnkleLeftp->getScale();
|
mCurrBodySizeState["mAnkleLeft scale"] = mAnkleLeftp->getScale();
|
||||||
mCurrBodySizeState["mFootLeft pos"] = mFootLeftp->getPosition();
|
mCurrBodySizeState["mFootLeft pos"] = mFootLeftp->getPosition();
|
||||||
|
|
||||||
F32 old_height = mBodySize.mV[VZ];
|
LLVector3 pelvis_scale = mPelvisp->getScale();
|
||||||
|
|
||||||
|
// some of the joints have not been cached
|
||||||
|
LLVector3 skull = mSkullp->getPosition();
|
||||||
|
//LLVector3 skull_scale = mSkullp->getScale();
|
||||||
|
|
||||||
|
LLVector3 neck = mNeckp->getPosition();
|
||||||
|
LLVector3 neck_scale = mNeckp->getScale();
|
||||||
|
|
||||||
|
LLVector3 chest = mChestp->getPosition();
|
||||||
|
LLVector3 chest_scale = mChestp->getScale();
|
||||||
|
|
||||||
|
// the rest of the joints have been cached
|
||||||
|
LLVector3 head = mHeadp->getPosition();
|
||||||
|
LLVector3 head_scale = mHeadp->getScale();
|
||||||
|
|
||||||
|
LLVector3 torso = mTorsop->getPosition();
|
||||||
|
LLVector3 torso_scale = mTorsop->getScale();
|
||||||
|
|
||||||
|
LLVector3 hip = mHipLeftp->getPosition();
|
||||||
|
LLVector3 hip_scale = mHipLeftp->getScale();
|
||||||
|
|
||||||
|
LLVector3 knee = mKneeLeftp->getPosition();
|
||||||
|
LLVector3 knee_scale = mKneeLeftp->getScale();
|
||||||
|
|
||||||
|
LLVector3 ankle = mAnkleLeftp->getPosition();
|
||||||
|
LLVector3 ankle_scale = mAnkleLeftp->getScale();
|
||||||
|
|
||||||
|
LLVector3 foot = mFootLeftp->getPosition();
|
||||||
|
|
||||||
F32 old_offset = mAvatarOffset.mV[VZ];
|
F32 old_offset = mAvatarOffset.mV[VZ];
|
||||||
|
|
||||||
// TODO: Measure the real depth and width
|
|
||||||
mPelvisToFoot = computePelvisToFoot();
|
|
||||||
F32 new_height = computeBodyHeight();
|
|
||||||
mBodySize.set(DEFAULT_AGENT_DEPTH, DEFAULT_AGENT_WIDTH, new_height);
|
|
||||||
// [RLVa:KB] - Checked: 2013-03-03 (RLVa-1.4.8)
|
// [RLVa:KB] - Checked: 2013-03-03 (RLVa-1.4.8)
|
||||||
F32 new_offset = getAvatarOffset();
|
mAvatarOffset.mV[VZ] = getAvatarOffset();
|
||||||
// [/RLVa:KB]
|
// [/RLVa:KB]
|
||||||
// F32 new_offset = getVisualParamWeight(AVATAR_HOVER);
|
// mAvatarOffset.mV[VZ] = getVisualParamWeight(AVATAR_HOVER);
|
||||||
mAvatarOffset.set(0, 0, new_offset);
|
|
||||||
|
|
||||||
if (mBodySize.mV[VZ] != old_height || new_offset != old_offset)
|
mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] -
|
||||||
|
knee.mV[VZ] * hip_scale.mV[VZ] -
|
||||||
|
ankle.mV[VZ] * knee_scale.mV[VZ] -
|
||||||
|
foot.mV[VZ] * ankle_scale.mV[VZ];
|
||||||
|
|
||||||
|
LLVector3 new_body_size;
|
||||||
|
new_body_size.mV[VZ] = mPelvisToFoot +
|
||||||
|
// the sqrt(2) correction below is an approximate
|
||||||
|
// correction to get to the top of the head
|
||||||
|
F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) +
|
||||||
|
head.mV[VZ] * neck_scale.mV[VZ] +
|
||||||
|
neck.mV[VZ] * chest_scale.mV[VZ] +
|
||||||
|
chest.mV[VZ] * torso_scale.mV[VZ] +
|
||||||
|
torso.mV[VZ] * pelvis_scale.mV[VZ];
|
||||||
|
|
||||||
|
// TODO -- measure the real depth and width
|
||||||
|
new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH;
|
||||||
|
new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH;
|
||||||
|
|
||||||
|
mAvatarOffset.mV[VX] = 0.0f;
|
||||||
|
mAvatarOffset.mV[VY] = 0.0f;
|
||||||
|
|
||||||
|
if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ])
|
||||||
{
|
{
|
||||||
|
mBodySize = new_body_size;
|
||||||
|
|
||||||
// <FS:Ansariel> [Legacy Bake]
|
// <FS:Ansariel> [Legacy Bake]
|
||||||
bodySizeChanged();
|
bodySizeChanged();
|
||||||
|
|
||||||
|
|
@ -518,29 +566,6 @@ void LLAvatarAppearance::computeBodySize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
F32 LLAvatarAppearance::computeBodyHeight()
|
|
||||||
{
|
|
||||||
F32 result = mPelvisToFoot +
|
|
||||||
// all these relative positions usually are positive
|
|
||||||
mPelvisp->getScale().mV[VZ] * mTorsop->getPosition().mV[VZ] +
|
|
||||||
mTorsop->getScale().mV[VZ] * mChestp->getPosition().mV[VZ] +
|
|
||||||
mChestp->getScale().mV[VZ] * mNeckp->getPosition().mV[VZ] +
|
|
||||||
mNeckp->getScale().mV[VZ] * mHeadp->getPosition().mV[VZ] +
|
|
||||||
mHeadp->getScale().mV[VZ] * mSkullp->getPosition().mV[VZ] * 2;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
F32 LLAvatarAppearance::computePelvisToFoot()
|
|
||||||
{
|
|
||||||
F32 result =
|
|
||||||
// all these relative positions usually are negative
|
|
||||||
mPelvisp->getScale().mV[VZ] * mHipLeftp->getPosition().mV[VZ] +
|
|
||||||
mHipLeftp->getScale().mV[VZ] * mKneeLeftp->getPosition().mV[VZ] +
|
|
||||||
mKneeLeftp->getScale().mV[VZ] * mAnkleLeftp->getPosition().mV[VZ] +
|
|
||||||
mAnkleLeftp->getScale().mV[VZ] * mFootLeftp->getPosition().mV[VZ] / 2;
|
|
||||||
return -result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// [RLVa:KB] - Checked: 2013-03-03 (RLVa-1.4.8)
|
// [RLVa:KB] - Checked: 2013-03-03 (RLVa-1.4.8)
|
||||||
F32 LLAvatarAppearance::getAvatarOffset() /*const*/
|
F32 LLAvatarAppearance::getAvatarOffset() /*const*/
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -153,8 +153,6 @@ public:
|
||||||
void compareJointStateMaps(joint_state_map_t& last_state,
|
void compareJointStateMaps(joint_state_map_t& last_state,
|
||||||
joint_state_map_t& curr_state);
|
joint_state_map_t& curr_state);
|
||||||
void computeBodySize();
|
void computeBodySize();
|
||||||
F32 computeBodyHeight();
|
|
||||||
F32 computePelvisToFoot();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef std::vector<LLAvatarJoint*> avatar_joint_list_t;
|
typedef std::vector<LLAvatarJoint*> avatar_joint_list_t;
|
||||||
|
|
|
||||||
|
|
@ -592,9 +592,10 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
|
||||||
switch (signum)
|
switch (signum)
|
||||||
{
|
{
|
||||||
case SIGCHLD:
|
case SIGCHLD:
|
||||||
|
case SIGHUP:
|
||||||
if (LLApp::sLogInSignal)
|
if (LLApp::sLogInSignal)
|
||||||
{
|
{
|
||||||
LL_INFOS() << "Signal handler - Got SIGCHLD from " << info->si_pid << LL_ENDL;
|
LL_INFOS() << "Signal handler - Got SIGCHLD or SIGHUP from " << info->si_pid << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -609,11 +610,10 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
|
||||||
raise(signum);
|
raise(signum);
|
||||||
return;
|
return;
|
||||||
case SIGINT:
|
case SIGINT:
|
||||||
case SIGHUP:
|
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
if (LLApp::sLogInSignal)
|
if (LLApp::sLogInSignal)
|
||||||
{
|
{
|
||||||
LL_WARNS() << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << LL_ENDL;
|
LL_WARNS() << "Signal handler - Got SIGINT, or TERM, exiting gracefully" << LL_ENDL;
|
||||||
}
|
}
|
||||||
// Graceful exit
|
// Graceful exit
|
||||||
// Just set our state to quitting, not error
|
// Just set our state to quitting, not error
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,6 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
// std headers
|
// std headers
|
||||||
// external library headers
|
// external library headers
|
||||||
#include <boost/bind.hpp>
|
|
||||||
#include <boost/scoped_ptr.hpp>
|
|
||||||
#include <boost/tokenizer.hpp>
|
|
||||||
// other Linden headers
|
// other Linden headers
|
||||||
#include "llerror.h"
|
#include "llerror.h"
|
||||||
#include "llstring.h"
|
#include "llstring.h"
|
||||||
|
|
@ -64,7 +61,9 @@ public:
|
||||||
// Pass it a callback to our connect() method, so it can send events
|
// Pass it a callback to our connect() method, so it can send events
|
||||||
// from a particular LLEventPump to the plugin without having to know
|
// from a particular LLEventPump to the plugin without having to know
|
||||||
// this class or method name.
|
// this class or method name.
|
||||||
mListener(new LLLeapListener(boost::bind(&LLLeapImpl::connect, this, _1, _2)))
|
mListener(new LLLeapListener(
|
||||||
|
[this](LLEventPump& pump, const std::string& listener)
|
||||||
|
{ return connect(pump, listener); }))
|
||||||
{
|
{
|
||||||
// Rule out unpopulated Params block
|
// Rule out unpopulated Params block
|
||||||
if (! cparams.executable.isProvided())
|
if (! cparams.executable.isProvided())
|
||||||
|
|
@ -93,7 +92,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for child "termination" right away to catch launch errors.
|
// Listen for child "termination" right away to catch launch errors.
|
||||||
mDonePump.listen("LLLeap", boost::bind(&LLLeapImpl::bad_launch, this, _1));
|
mDonePump.listen("LLLeap", [this](const LLSD& data){ return bad_launch(data); });
|
||||||
|
|
||||||
// Okay, launch child.
|
// Okay, launch child.
|
||||||
// Get a modifiable copy of params block to set files and postend.
|
// Get a modifiable copy of params block to set files and postend.
|
||||||
|
|
@ -113,7 +112,7 @@ public:
|
||||||
|
|
||||||
// Okay, launch apparently worked. Change our mDonePump listener.
|
// Okay, launch apparently worked. Change our mDonePump listener.
|
||||||
mDonePump.stopListening("LLLeap");
|
mDonePump.stopListening("LLLeap");
|
||||||
mDonePump.listen("LLLeap", boost::bind(&LLLeapImpl::done, this, _1));
|
mDonePump.listen("LLLeap", [this](const LLSD& data){ return done(data); });
|
||||||
|
|
||||||
// Child might pump large volumes of data through either stdout or
|
// Child might pump large volumes of data through either stdout or
|
||||||
// stderr. Don't bother copying all that data into notification event.
|
// stderr. Don't bother copying all that data into notification event.
|
||||||
|
|
@ -128,13 +127,9 @@ public:
|
||||||
|
|
||||||
// Listening on stdout is stateful. In general, we're either waiting
|
// Listening on stdout is stateful. In general, we're either waiting
|
||||||
// for the length prefix or waiting for the specified length of data.
|
// for the length prefix or waiting for the specified length of data.
|
||||||
// We address that with two different listener methods -- one of which
|
mReadPrefix = true;
|
||||||
// is blocked at any given time.
|
|
||||||
mStdoutConnection = childout.getPump()
|
mStdoutConnection = childout.getPump()
|
||||||
.listen("prefix", boost::bind(&LLLeapImpl::rstdout, this, _1));
|
.listen("LLLeap", [this](const LLSD& data){ return rstdout(data); });
|
||||||
mStdoutDataConnection = childout.getPump()
|
|
||||||
.listen("data", boost::bind(&LLLeapImpl::rstdoutData, this, _1));
|
|
||||||
mBlocker.reset(new LLEventPump::Blocker(mStdoutDataConnection));
|
|
||||||
|
|
||||||
// Log anything sent up through stderr. When a typical program
|
// Log anything sent up through stderr. When a typical program
|
||||||
// encounters an error, it writes its error message to stderr and
|
// encounters an error, it writes its error message to stderr and
|
||||||
|
|
@ -142,7 +137,7 @@ public:
|
||||||
// interpreter behaves that way. More generally, though, a plugin
|
// interpreter behaves that way. More generally, though, a plugin
|
||||||
// author can log whatever s/he wants to the viewer log using stderr.
|
// author can log whatever s/he wants to the viewer log using stderr.
|
||||||
mStderrConnection = childerr.getPump()
|
mStderrConnection = childerr.getPump()
|
||||||
.listen("LLLeap", boost::bind(&LLLeapImpl::rstderr, this, _1));
|
.listen("LLLeap", [this](const LLSD& data){ return rstderr(data); });
|
||||||
|
|
||||||
// For our lifespan, intercept any LL_ERRS so we can notify plugin
|
// For our lifespan, intercept any LL_ERRS so we can notify plugin
|
||||||
mRecorder = LLError::addGenericRecorder(
|
mRecorder = LLError::addGenericRecorder(
|
||||||
|
|
@ -255,120 +250,120 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial state of stateful listening on child stdout: wait for a length
|
// Stateful listening on child stdout:
|
||||||
// prefix, followed by ':'.
|
// wait for a length prefix, followed by ':'.
|
||||||
bool rstdout(const LLSD& data)
|
bool rstdout(const LLSD&)
|
||||||
{
|
{
|
||||||
LLProcess::ReadPipe& childout(mChild->getReadPipe(LLProcess::STDOUT));
|
LLProcess::ReadPipe& childout(mChild->getReadPipe(LLProcess::STDOUT));
|
||||||
// It's possible we got notified of a couple digit characters without
|
while (childout.size())
|
||||||
// seeing the ':' -- unlikely, but still. Until we see ':', keep
|
|
||||||
// waiting.
|
|
||||||
if (childout.contains(':'))
|
|
||||||
{
|
{
|
||||||
std::istream& childstream(childout.get_istream());
|
/*----------------- waiting for length prefix ------------------*/
|
||||||
// Saw ':', read length prefix and store in mExpect.
|
if (mReadPrefix)
|
||||||
size_t expect;
|
|
||||||
childstream >> expect;
|
|
||||||
int colon(childstream.get());
|
|
||||||
if (colon != ':')
|
|
||||||
{
|
{
|
||||||
// Protocol failure. Clear out the rest of the pending data in
|
// It's possible we got notified of a couple digit characters without
|
||||||
// childout (well, up to a max length) to log what was wrong.
|
// seeing the ':' -- unlikely, but still. Until we see ':', keep
|
||||||
LLProcess::ReadPipe::size_type
|
// waiting.
|
||||||
readlen((std::min)(childout.size(), LLProcess::ReadPipe::size_type(80)));
|
if (! childout.contains(':'))
|
||||||
bad_protocol(STRINGIZE(expect << char(colon) << childout.read(readlen)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Saw length prefix, saw colon, life is good. Now wait for
|
|
||||||
// that length of data to arrive.
|
|
||||||
mExpect = expect;
|
|
||||||
LL_DEBUGS("LLLeap") << "got length, waiting for "
|
|
||||||
<< mExpect << " bytes of data" << LL_ENDL;
|
|
||||||
// Block calls to this method; resetting mBlocker unblocks
|
|
||||||
// calls to the other method.
|
|
||||||
mBlocker.reset(new LLEventPump::Blocker(mStdoutConnection));
|
|
||||||
// Go check if we've already received all the advertised data.
|
|
||||||
if (childout.size())
|
|
||||||
{
|
{
|
||||||
LLSD updata(data);
|
if (childout.contains('\n'))
|
||||||
updata["len"] = LLSD::Integer(childout.size());
|
{
|
||||||
rstdoutData(updata);
|
// Since this is the initial listening state, this is where we'd
|
||||||
|
// arrive if the child isn't following protocol at all -- say
|
||||||
|
// because the user specified 'ls' or some darn thing.
|
||||||
|
bad_protocol(childout.getline());
|
||||||
|
}
|
||||||
|
// Either way, stop looping.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (childout.contains('\n'))
|
|
||||||
{
|
|
||||||
// Since this is the initial listening state, this is where we'd
|
|
||||||
// arrive if the child isn't following protocol at all -- say
|
|
||||||
// because the user specified 'ls' or some darn thing.
|
|
||||||
bad_protocol(childout.getline());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// State in which we listen on stdout for the specified length of data to
|
// Saw ':', read length prefix and store in mExpect.
|
||||||
// arrive.
|
std::istream& childstream(childout.get_istream());
|
||||||
bool rstdoutData(const LLSD& data)
|
size_t expect;
|
||||||
{
|
childstream >> expect;
|
||||||
LLProcess::ReadPipe& childout(mChild->getReadPipe(LLProcess::STDOUT));
|
int colon(childstream.get());
|
||||||
// Until we've accumulated the promised length of data, keep waiting.
|
if (colon != ':')
|
||||||
if (childout.size() >= mExpect)
|
{
|
||||||
{
|
// Protocol failure. Clear out the rest of the pending data in
|
||||||
// Ready to rock and roll.
|
// childout (well, up to a max length) to log what was wrong.
|
||||||
LL_DEBUGS("LLLeap") << "needed " << mExpect << " bytes, got "
|
LLProcess::ReadPipe::size_type
|
||||||
<< childout.size() << ", parsing LLSD" << LL_ENDL;
|
readlen((std::min)(childout.size(),
|
||||||
LLSD data;
|
LLProcess::ReadPipe::size_type(80)));
|
||||||
#if 1
|
bad_protocol(stringize(expect, char(colon), childout.read(readlen)));
|
||||||
// specifically require notation LLSD from child
|
break;
|
||||||
LLPointer<LLSDParser> parser(new LLSDNotationParser());
|
}
|
||||||
S32 parse_status(parser->parse(childout.get_istream(), data, mExpect));
|
else
|
||||||
if (parse_status == LLSDParser::PARSE_FAILURE)
|
{
|
||||||
#else
|
// Saw length prefix, saw colon, life is good. Now wait for
|
||||||
// SL-18330: accept any valid LLSD serialization format from child
|
// that length of data to arrive.
|
||||||
// Unfortunately this runs into trouble we have not yet debugged.
|
mExpect = expect;
|
||||||
bool parse_status(LLSDSerialize::deserialize(data, childout.get_istream(), mExpect));
|
LL_DEBUGS("LLLeap") << "got length, waiting for "
|
||||||
if (! parse_status)
|
<< mExpect << " bytes of data" << LL_ENDL;
|
||||||
#endif
|
// Transition to "read data" mode and loop back to check
|
||||||
{
|
// if we've already received all the advertised data.
|
||||||
bad_protocol("unparseable LLSD data");
|
mReadPrefix = false;
|
||||||
}
|
continue;
|
||||||
else if (! (data.isMap() && data["pump"].isString() && data.has("data")))
|
}
|
||||||
{
|
|
||||||
// we got an LLSD object, but it lacks required keys
|
|
||||||
bad_protocol("missing 'pump' or 'data'");
|
|
||||||
}
|
}
|
||||||
|
/*----------------- saw prefix, wait for data ------------------*/
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try
|
// Until we've accumulated the promised length of data, keep waiting.
|
||||||
|
if (childout.size() < mExpect)
|
||||||
{
|
{
|
||||||
// The LLSD object we got from our stream contains the
|
break;
|
||||||
// keys we need.
|
|
||||||
LLEventPumps::instance().obtain(data["pump"]).post(data["data"]);
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& err)
|
|
||||||
|
// We have the data we were told to expect! Ready to rock and roll.
|
||||||
|
LL_DEBUGS("LLLeap") << "needed " << mExpect << " bytes, got "
|
||||||
|
<< childout.size() << ", parsing LLSD" << LL_ENDL;
|
||||||
|
LLSD data;
|
||||||
|
#if 1
|
||||||
|
// specifically require notation LLSD from child
|
||||||
|
LLPointer<LLSDParser> parser(new LLSDNotationParser());
|
||||||
|
S32 parse_status(parser->parse(childout.get_istream(), data, mExpect));
|
||||||
|
if (parse_status == LLSDParser::PARSE_FAILURE)
|
||||||
|
#else
|
||||||
|
// SL-18330: accept any valid LLSD serialization format from child
|
||||||
|
// Unfortunately this runs into trouble we have not yet debugged.
|
||||||
|
bool parse_status(LLSDSerialize::deserialize(data, childout.get_istream(), mExpect));
|
||||||
|
if (! parse_status)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
// No plugin should be allowed to crash the viewer by
|
bad_protocol("unparseable LLSD data");
|
||||||
// driving an exception -- intentionally or not.
|
break;
|
||||||
LOG_UNHANDLED_EXCEPTION(stringize("handling request ", data));
|
|
||||||
// Whether or not the plugin added a "reply" key to the
|
|
||||||
// request, send a reply. We happen to know who originated
|
|
||||||
// this request, and the reply LLEventPump of interest.
|
|
||||||
// Not our problem if the plugin ignores the reply event.
|
|
||||||
data["reply"] = mReplyPump.getName();
|
|
||||||
sendReply(llsd::map("error",
|
|
||||||
stringize(LLError::Log::classname(err), ": ", err.what())),
|
|
||||||
data);
|
|
||||||
}
|
}
|
||||||
// Block calls to this method; resetting mBlocker unblocks
|
else if (! (data.isMap() && data["pump"].isString() && data.has("data")))
|
||||||
// calls to the other method.
|
|
||||||
mBlocker.reset(new LLEventPump::Blocker(mStdoutDataConnection));
|
|
||||||
// Go check for any more pending events in the buffer.
|
|
||||||
if (childout.size())
|
|
||||||
{
|
{
|
||||||
LLSD updata(data);
|
// we got an LLSD object, but it lacks required keys
|
||||||
data["len"] = LLSD::Integer(childout.size());
|
bad_protocol("missing 'pump' or 'data'");
|
||||||
rstdout(updata);
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// The LLSD object we got from our stream contains the
|
||||||
|
// keys we need.
|
||||||
|
LLEventPumps::instance().obtain(data["pump"]).post(data["data"]);
|
||||||
|
}
|
||||||
|
catch (const std::exception& err)
|
||||||
|
{
|
||||||
|
// No plugin should be allowed to crash the viewer by
|
||||||
|
// driving an exception -- intentionally or not.
|
||||||
|
LOG_UNHANDLED_EXCEPTION(stringize("handling request ", data));
|
||||||
|
// Whether or not the plugin added a "reply" key to the
|
||||||
|
// request, send a reply. We happen to know who originated
|
||||||
|
// this request, and the reply LLEventPump of interest.
|
||||||
|
// Not our problem if the plugin ignores the reply event.
|
||||||
|
data["reply"] = mReplyPump.getName();
|
||||||
|
sendReply(llsd::map("error",
|
||||||
|
stringize(LLError::Log::classname(err), ": ", err.what())),
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
// Transition to "read prefix" mode and go check for any
|
||||||
|
// more pending events in the buffer.
|
||||||
|
mReadPrefix = true;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -453,7 +448,8 @@ private:
|
||||||
// child's stdin, suitably enriched with the pump name on which it was
|
// child's stdin, suitably enriched with the pump name on which it was
|
||||||
// received.
|
// received.
|
||||||
return pump.listen(listener,
|
return pump.listen(listener,
|
||||||
boost::bind(&LLLeapImpl::wstdin, this, pump.getName(), _1));
|
[this, name=pump.getName()](const LLSD& data)
|
||||||
|
{ return wstdin(name, data); });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string mDesc;
|
std::string mDesc;
|
||||||
|
|
@ -461,11 +457,11 @@ private:
|
||||||
LLEventStream mReplyPump;
|
LLEventStream mReplyPump;
|
||||||
LLProcessPtr mChild;
|
LLProcessPtr mChild;
|
||||||
LLTempBoundListener
|
LLTempBoundListener
|
||||||
mStdinConnection, mStdoutConnection, mStdoutDataConnection, mStderrConnection;
|
mStdinConnection, mStdoutConnection, mStderrConnection;
|
||||||
std::unique_ptr<LLEventPump::Blocker> mBlocker;
|
|
||||||
LLProcess::ReadPipe::size_type mExpect;
|
LLProcess::ReadPipe::size_type mExpect;
|
||||||
LLError::RecorderPtr mRecorder;
|
LLError::RecorderPtr mRecorder;
|
||||||
std::unique_ptr<LLLeapListener> mListener;
|
std::unique_ptr<LLLeapListener> mListener;
|
||||||
|
bool mReadPrefix;
|
||||||
};
|
};
|
||||||
|
|
||||||
// These must follow the declaration of LLLeapImpl, so they may as well be last.
|
// These must follow the declaration of LLLeapImpl, so they may as well be last.
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ namespace LLProfiler
|
||||||
|
|
||||||
#define LL_LABEL_OBJECT_GL(type, name, length, label)
|
#define LL_LABEL_OBJECT_GL(type, name, length, label)
|
||||||
|
|
||||||
#if LL_PROFILER_CONFIGURATION > 1
|
#if !LL_DARWIN && LL_PROFILER_CONFIGURATION > 1
|
||||||
#define LL_PROFILE_ALLOC(ptr, size) TracyAlloc(ptr, size)
|
#define LL_PROFILE_ALLOC(ptr, size) TracyAlloc(ptr, size)
|
||||||
#define LL_PROFILE_FREE(ptr) TracyFree(ptr)
|
#define LL_PROFILE_FREE(ptr) TracyFree(ptr)
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -830,7 +830,7 @@ std::string utf8str_showBytesUTF8(const std::string& utf8str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for any emoji symbol, return true if found
|
// Search for any emoji symbol, return true if found
|
||||||
bool wstring_has_emoji(const LLWString& wstr)
|
bool wstring_has_emoji(LLWStringView wstr)
|
||||||
{
|
{
|
||||||
for (const llwchar& wch : wstr)
|
for (const llwchar& wch : wstr)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -456,6 +456,7 @@ template<class T> std::string LLStringUtilBase<T>::sLocale;
|
||||||
typedef LLStringUtilBase<char> LLStringUtil;
|
typedef LLStringUtilBase<char> LLStringUtil;
|
||||||
typedef LLStringUtilBase<llwchar> LLWStringUtil;
|
typedef LLStringUtilBase<llwchar> LLWStringUtil;
|
||||||
typedef std::basic_string<llwchar> LLWString;
|
typedef std::basic_string<llwchar> LLWString;
|
||||||
|
typedef std::basic_string_view<llwchar> LLWStringView;
|
||||||
|
|
||||||
//@ Use this where we want to disallow input in the form of "foo"
|
//@ Use this where we want to disallow input in the form of "foo"
|
||||||
// This is used to catch places where english text is embedded in the code
|
// This is used to catch places where english text is embedded in the code
|
||||||
|
|
@ -762,7 +763,7 @@ LL_COMMON_API llwchar utf8str_to_wchar(const std::string& utf8str, size_t offset
|
||||||
|
|
||||||
LL_COMMON_API std::string utf8str_showBytesUTF8(const std::string& utf8str);
|
LL_COMMON_API std::string utf8str_showBytesUTF8(const std::string& utf8str);
|
||||||
|
|
||||||
LL_COMMON_API bool wstring_has_emoji(const LLWString& wstr);
|
LL_COMMON_API bool wstring_has_emoji(LLWStringView wstr);
|
||||||
|
|
||||||
LL_COMMON_API bool wstring_remove_emojis(LLWString& wstr);
|
LL_COMMON_API bool wstring_remove_emojis(LLWString& wstr);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ class LLMutex;
|
||||||
|
|
||||||
const S32 UUID_BYTES = 16;
|
const S32 UUID_BYTES = 16;
|
||||||
const S32 UUID_WORDS = 4;
|
const S32 UUID_WORDS = 4;
|
||||||
const S32 UUID_STR_LENGTH = 37; // actually wrong, should be 36 and use size below
|
const S32 UUID_STR_LENGTH = 37; // number of bytes needed to store a UUID as a string
|
||||||
const S32 UUID_STR_SIZE = 37;
|
const S32 UUID_STR_SIZE = 36; // .size() of a UUID in a std::string
|
||||||
const S32 UUID_BASE85_LENGTH = 21; // including the trailing NULL.
|
const S32 UUID_BASE85_LENGTH = 21; // including the trailing NULL.
|
||||||
|
|
||||||
struct uuid_time_t {
|
struct uuid_time_t {
|
||||||
|
|
|
||||||
|
|
@ -47,11 +47,11 @@ namespace tut
|
||||||
// the timestamp for each one -- but since we're passing explicit
|
// the timestamp for each one -- but since we're passing explicit
|
||||||
// timestamps, make the queue reorder them.
|
// timestamps, make the queue reorder them.
|
||||||
auto now{ Queue::Clock::now() };
|
auto now{ Queue::Clock::now() };
|
||||||
queue.push(Queue::TimeTuple(now + 200ms, "ghi"));
|
queue.push(Queue::TimeTuple(now + 200ms, "ghi"s));
|
||||||
// Given the various push() overloads, you have to match the type
|
// Given the various push() overloads, you have to match the type
|
||||||
// exactly: conversions are ambiguous.
|
// exactly: conversions are ambiguous.
|
||||||
queue.push("abc"s);
|
queue.push(now, "abc"s);
|
||||||
queue.push(now + 100ms, "def");
|
queue.push(now + 100ms, "def"s);
|
||||||
queue.close();
|
queue.close();
|
||||||
auto entry = queue.pop();
|
auto entry = queue.pop();
|
||||||
ensure_equals("failed to pop first", std::get<0>(entry), "abc"s);
|
ensure_equals("failed to pop first", std::get<0>(entry), "abc"s);
|
||||||
|
|
|
||||||
|
|
@ -2274,6 +2274,61 @@ LLImageFormatted* LLImageFormatted::createFromType(S8 codec)
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
S8 LLImageFormatted::getCodecFromMimeType(std::string_view mimetype)
|
||||||
|
{
|
||||||
|
if (mimetype == "image/bmp")
|
||||||
|
{
|
||||||
|
return IMG_CODEC_BMP;
|
||||||
|
}
|
||||||
|
else if (mimetype == "image/tga")
|
||||||
|
{
|
||||||
|
return IMG_CODEC_TGA;
|
||||||
|
}
|
||||||
|
else if (mimetype == "image/jpeg")
|
||||||
|
{
|
||||||
|
return IMG_CODEC_JPEG;
|
||||||
|
}
|
||||||
|
else if (mimetype == "image/png")
|
||||||
|
{
|
||||||
|
return IMG_CODEC_PNG;
|
||||||
|
}
|
||||||
|
else if (mimetype == "image/j2c")
|
||||||
|
{
|
||||||
|
return IMG_CODEC_J2C;
|
||||||
|
}
|
||||||
|
else if (mimetype == "image/dxt")
|
||||||
|
{
|
||||||
|
return IMG_CODEC_DXT;
|
||||||
|
}
|
||||||
|
return IMG_CODEC_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
LLImageFormatted* LLImageFormatted::createFromMimeType(std::string_view mimetype)
|
||||||
|
{
|
||||||
|
S8 codec = getCodecFromMimeType(mimetype);
|
||||||
|
return createFromType(codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
LLImageFormatted* LLImageFormatted::loadFromMemory(const U8* data_in, U32 size, std::string_view mimetype)
|
||||||
|
{
|
||||||
|
LLImageFormatted* image = createFromMimeType(mimetype);
|
||||||
|
if (image)
|
||||||
|
{
|
||||||
|
U8* data = image->allocateData(size);
|
||||||
|
memcpy(data, data_in, size);
|
||||||
|
|
||||||
|
if (!image->updateData())
|
||||||
|
{
|
||||||
|
delete image;
|
||||||
|
image = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
LLImageFormatted* LLImageFormatted::createFromExtension(const std::string& instring)
|
LLImageFormatted* LLImageFormatted::createFromExtension(const std::string& instring)
|
||||||
{
|
{
|
||||||
|
|
@ -2457,6 +2512,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size)
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
bool LLImageFormatted::load(const std::string &filename, int load_size)
|
bool LLImageFormatted::load(const std::string &filename, int load_size)
|
||||||
{
|
{
|
||||||
resetLastError();
|
resetLastError();
|
||||||
|
|
|
||||||
|
|
@ -332,7 +332,10 @@ class LLImageFormatted : public LLImageBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static LLImageFormatted* createFromType(S8 codec);
|
static LLImageFormatted* createFromType(S8 codec);
|
||||||
|
static LLImageFormatted* loadFromMemory(const U8* data, U32 size, std::string_view mimetype);
|
||||||
static LLImageFormatted* createFromExtension(const std::string& instring);
|
static LLImageFormatted* createFromExtension(const std::string& instring);
|
||||||
|
static LLImageFormatted* createFromMimeType(std::string_view mimetype);
|
||||||
|
static S8 getCodecFromMimeType(std::string_view mimetype);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/*virtual*/ ~LLImageFormatted();
|
/*virtual*/ ~LLImageFormatted();
|
||||||
|
|
|
||||||
|
|
@ -270,36 +270,23 @@ public:
|
||||||
inline bool allowModifyBy(const LLUUID &agent_id) const;
|
inline bool allowModifyBy(const LLUUID &agent_id) const;
|
||||||
inline bool allowCopyBy(const LLUUID& agent_id) const;
|
inline bool allowCopyBy(const LLUUID& agent_id) const;
|
||||||
inline bool allowMoveBy(const LLUUID& agent_id) const;
|
inline bool allowMoveBy(const LLUUID& agent_id) const;
|
||||||
|
|
||||||
inline bool allowModifyBy(const LLUUID &agent_id, const LLUUID& group) const;
|
inline bool allowModifyBy(const LLUUID &agent_id, const LLUUID& group) const;
|
||||||
inline bool allowCopyBy(const LLUUID& agent_id, const LLUUID& group) const;
|
inline bool allowCopyBy(const LLUUID& agent_id, const LLUUID& group) const;
|
||||||
inline bool allowMoveBy(const LLUUID &agent_id, const LLUUID &group) const;
|
inline bool allowMoveBy(const LLUUID &agent_id, const LLUUID &group) const;
|
||||||
inline bool allowExportBy(const LLUUID& agent_id) const; // <FS:CR> OpenSim export permission
|
|
||||||
|
|
||||||
// This somewhat specialized function is meant for testing if the
|
// This somewhat specialized function is meant for testing if the
|
||||||
// current owner is allowed to transfer to the specified agent id.
|
// current owner is allowed to transfer to the specified agent id.
|
||||||
inline bool allowTransferTo(const LLUUID &agent_id) const;
|
inline bool allowTransferTo(const LLUUID &agent_id) const;
|
||||||
|
|
||||||
//
|
// Returns true if the object can exported by the given agent
|
||||||
// DEPRECATED.
|
// (e.g. saved as a local .gltf file)
|
||||||
//
|
// The current test should return true if the agent is the owner
|
||||||
// These return true if the given agent can perform the function.
|
// AND the creator of the object.
|
||||||
// They also return true if the object isn't owned, or the
|
inline bool allowExportBy(const LLUUID& agent_id) const;
|
||||||
// requesting agent is a system agent. See llpermissionsflags.h
|
#ifdef OPENSIM
|
||||||
// for bits.
|
inline bool allowOpenSimExportBy(const LLUUID& agent_id) const; // <FS:CR> OpenSim export permission
|
||||||
//bool allowDeleteBy(const LLUUID& agent_id) const { return allowModifyBy(agent_id); }
|
#endif
|
||||||
//bool allowEditBy(const LLUUID& agent_id) const { return allowModifyBy(agent_id); }
|
|
||||||
// saves last owner and sets current owner
|
|
||||||
//bool setOwner(const LLUUID& agent, const LLUUID& owner);
|
|
||||||
// This method saves the last owner, sets the current owner to the
|
|
||||||
// one provided, and sets the base mask as indicated.
|
|
||||||
//bool setOwner(const LLUUID& agent, const LLUUID& owner, U32 new_base_mask);
|
|
||||||
|
|
||||||
// Attempt to set or clear the given bitmask. Returns true if you
|
|
||||||
// are allowed to modify the permissions. If you attempt to turn
|
|
||||||
// on bits not allowed by the base bits, the function will return
|
|
||||||
// true, but those bits will not be set.
|
|
||||||
//bool setGroupBits( const LLUUID& agent, bool set, PermissionMask bits);
|
|
||||||
//bool setEveryoneBits(const LLUUID& agent, bool set, PermissionMask bits);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// MISC METHODS and OPERATORS
|
// MISC METHODS and OPERATORS
|
||||||
|
|
@ -354,6 +341,20 @@ bool LLPermissions::allowMoveBy(const LLUUID& agent) const
|
||||||
return allowOperationBy(PERM_MOVE, agent, LLUUID::null);
|
return allowOperationBy(PERM_MOVE, agent, LLUUID::null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LLPermissions::allowExportBy(const LLUUID& agent) const
|
||||||
|
{
|
||||||
|
return agent == mOwner && agent == mCreator;
|
||||||
|
}
|
||||||
|
|
||||||
|
// <FS:CR> Opensim Export Permissions
|
||||||
|
#ifdef OPENSIM
|
||||||
|
bool LLPermissions::allowOpenSimExportBy(const LLUUID& agent) const
|
||||||
|
{
|
||||||
|
return ((mCreator == agent) ? true : (allowOperationBy(PERM_EXPORT, agent, LLUUID::null)));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// </FS:CR>
|
||||||
|
|
||||||
bool LLPermissions::allowTransferTo(const LLUUID &agent_id) const
|
bool LLPermissions::allowTransferTo(const LLUUID &agent_id) const
|
||||||
{
|
{
|
||||||
if (mIsGroupOwned)
|
if (mIsGroupOwned)
|
||||||
|
|
@ -366,13 +367,6 @@ bool LLPermissions::allowTransferTo(const LLUUID &agent_id) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// <FS:CR> Opensim Export Permissions
|
|
||||||
bool LLPermissions::allowExportBy(const LLUUID& agent) const
|
|
||||||
{
|
|
||||||
return ((mCreator == agent) ? true : (allowOperationBy(PERM_EXPORT, agent, LLUUID::null)));
|
|
||||||
}
|
|
||||||
// </FS:CR>
|
|
||||||
|
|
||||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// Class LLAggregatePermissions
|
// Class LLAggregatePermissions
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,39 @@ public:
|
||||||
return !(*this == rhs);
|
return !(*this == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LLVector4a& operator+=(const LLVector4a& rhs)
|
||||||
|
{
|
||||||
|
add(rhs);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LLVector4a& operator-=(const LLVector4a& rhs)
|
||||||
|
{
|
||||||
|
sub(rhs);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVector4a operator+(const LLVector4a& rhs) const
|
||||||
|
{
|
||||||
|
LLVector4a result = *this;
|
||||||
|
result.add(rhs);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVector4a operator-(const LLVector4a& rhs) const
|
||||||
|
{
|
||||||
|
LLVector4a result = *this;
|
||||||
|
result.sub(rhs);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVector4a cross3(const LLVector4a& b) const
|
||||||
|
{
|
||||||
|
LLVector4a result;
|
||||||
|
result.setCross3(*this, b);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////
|
////////////////////////////////////
|
||||||
// LOAD/STORE
|
// LOAD/STORE
|
||||||
////////////////////////////////////
|
////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle, LL
|
||||||
U32 idx1 = tri->mIndex[1];
|
U32 idx1 = tri->mIndex[1];
|
||||||
U32 idx2 = tri->mIndex[2];
|
U32 idx2 = tri->mIndex[2];
|
||||||
|
|
||||||
if (mTexCoord != NULL)
|
if (mTexCoord != NULL && mFace->mTexCoords)
|
||||||
{
|
{
|
||||||
LLVector2* tc = (LLVector2*) mFace->mTexCoords;
|
LLVector2* tc = (LLVector2*) mFace->mTexCoords;
|
||||||
*mTexCoord = ((1.f - a - b) * tc[idx0] +
|
*mTexCoord = ((1.f - a - b) * tc[idx0] +
|
||||||
|
|
@ -160,7 +160,7 @@ void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle, LL
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNormal != NULL)
|
if (mNormal != NULL && mFace->mNormals)
|
||||||
{
|
{
|
||||||
LLVector4a* norm = mFace->mNormals;
|
LLVector4a* norm = mFace->mNormals;
|
||||||
|
|
||||||
|
|
@ -180,7 +180,7 @@ void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle, LL
|
||||||
*mNormal = n1;
|
*mNormal = n1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mTangent != NULL)
|
if (mTangent != NULL && mFace->mTangents)
|
||||||
{
|
{
|
||||||
LLVector4a* tangents = mFace->mTangents;
|
LLVector4a* tangents = mFace->mTangents;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -681,7 +681,7 @@ void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data)
|
void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data) const
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED;
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
llassert(data.isUndefined());
|
llassert(data.isUndefined());
|
||||||
|
|
@ -690,7 +690,7 @@ void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& d
|
||||||
|
|
||||||
for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
|
for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
|
||||||
{
|
{
|
||||||
LLUUID& texture_id = mTextureId[i];
|
const LLUUID& texture_id = mTextureId[i];
|
||||||
const LLUUID& override_texture_id = override_mat.mTextureId[i];
|
const LLUUID& override_texture_id = override_mat.mTextureId[i];
|
||||||
if (override_texture_id.notNull() && override_texture_id != texture_id)
|
if (override_texture_id.notNull() && override_texture_id != texture_id)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ public:
|
||||||
// Get the given override on this LLGLTFMaterial as LLSD
|
// Get the given override on this LLGLTFMaterial as LLSD
|
||||||
// override_mat -- the override source data
|
// override_mat -- the override source data
|
||||||
// data -- output LLSD object (should be passed in empty)
|
// data -- output LLSD object (should be passed in empty)
|
||||||
void getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data);
|
void getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data) const;
|
||||||
|
|
||||||
// For base materials only (i.e. assets). Clears transforms to
|
// For base materials only (i.e. assets). Clears transforms to
|
||||||
// default since they're not supported in assets yet.
|
// default since they're not supported in assets yet.
|
||||||
|
|
|
||||||
|
|
@ -1274,6 +1274,11 @@ bool LLGLManager::initGL()
|
||||||
glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples);
|
glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples);
|
||||||
glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
|
glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
|
||||||
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
|
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
|
||||||
|
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &mMaxUniformBlockSize);
|
||||||
|
|
||||||
|
// sanity clamp max uniform block size to 64k just in case
|
||||||
|
// there's some implementation that reports a crazy value
|
||||||
|
mMaxUniformBlockSize = llmin(mMaxUniformBlockSize, 65536);
|
||||||
|
|
||||||
if (mGLVersion >= 4.59f)
|
if (mGLVersion >= 4.59f)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,7 @@ public:
|
||||||
S32 mGLMaxIndexRange;
|
S32 mGLMaxIndexRange;
|
||||||
S32 mGLMaxTextureSize;
|
S32 mGLMaxTextureSize;
|
||||||
F32 mMaxAnisotropy = 0.f;
|
F32 mMaxAnisotropy = 0.f;
|
||||||
|
S32 mMaxUniformBlockSize = 0;
|
||||||
|
|
||||||
// GL 4.x capabilities
|
// GL 4.x capabilities
|
||||||
bool mHasCubeMapArray = false;
|
bool mHasCubeMapArray = false;
|
||||||
|
|
@ -169,13 +170,18 @@ void assert_glerror();
|
||||||
|
|
||||||
void clear_glerror();
|
void clear_glerror();
|
||||||
|
|
||||||
//#if LL_DEBUG
|
|
||||||
# define stop_glerror() assert_glerror()
|
# define stop_glerror() assert_glerror()
|
||||||
# define llglassertok() assert_glerror()
|
# define llglassertok() assert_glerror()
|
||||||
//#else
|
|
||||||
//# define stop_glerror()
|
// stop_glerror is still needed on OS X but has performance implications
|
||||||
//# define llglassertok()
|
// use macro below to conditionally add stop_glerror to non-release builds
|
||||||
//#endif
|
// on OS X
|
||||||
|
#if LL_DARWIN && !LL_RELEASE_FOR_DOWNLOAD
|
||||||
|
#define STOP_GLERROR stop_glerror()
|
||||||
|
#else
|
||||||
|
#define STOP_GLERROR
|
||||||
|
#endif
|
||||||
|
|
||||||
#define llglassertok_always() assert_glerror()
|
#define llglassertok_always() assert_glerror()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -381,13 +381,10 @@ void LLGLSLShader::unloadInternal()
|
||||||
stop_glerror();
|
stop_glerror();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LLGLSLShader::createShader(std::vector<LLStaticHashedString>* attributes,
|
bool LLGLSLShader::createShader()
|
||||||
std::vector<LLStaticHashedString>* uniforms,
|
|
||||||
U32 varying_count,
|
|
||||||
const char** varyings)
|
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
|
||||||
|
|
||||||
unloadInternal();
|
unloadInternal();
|
||||||
|
|
||||||
sInstances.insert(this);
|
sInstances.insert(this);
|
||||||
|
|
@ -454,11 +451,11 @@ bool LLGLSLShader::createShader(std::vector<LLStaticHashedString>* attributes,
|
||||||
// Map attributes and uniforms
|
// Map attributes and uniforms
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
success = mapAttributes(attributes);
|
success = mapAttributes();
|
||||||
}
|
}
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
success = mapUniforms(uniforms);
|
success = mapUniforms();
|
||||||
}
|
}
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
|
|
@ -469,7 +466,7 @@ bool LLGLSLShader::createShader(std::vector<LLStaticHashedString>* attributes,
|
||||||
{
|
{
|
||||||
LL_SHADER_LOADING_WARNS() << "Failed to link using shader level " << mShaderLevel << " trying again using shader level " << (mShaderLevel - 1) << LL_ENDL;
|
LL_SHADER_LOADING_WARNS() << "Failed to link using shader level " << mShaderLevel << " trying again using shader level " << (mShaderLevel - 1) << LL_ENDL;
|
||||||
mShaderLevel--;
|
mShaderLevel--;
|
||||||
return createShader(attributes, uniforms);
|
return createShader();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -602,7 +599,7 @@ void LLGLSLShader::attachObjects(GLuint* objects, S32 count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString>* attributes)
|
bool LLGLSLShader::mapAttributes()
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
|
||||||
|
|
||||||
|
|
@ -621,11 +618,10 @@ bool LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString>* attrib
|
||||||
}
|
}
|
||||||
|
|
||||||
mAttribute.clear();
|
mAttribute.clear();
|
||||||
U32 numAttributes = (attributes == NULL) ? 0 : attributes->size();
|
|
||||||
#if LL_RELEASE_WITH_DEBUG_INFO
|
#if LL_RELEASE_WITH_DEBUG_INFO
|
||||||
mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size() + numAttributes, { -1, NULL });
|
mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size(), { -1, NULL });
|
||||||
#else
|
#else
|
||||||
mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size() + numAttributes, -1);
|
mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size(), -1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
|
|
@ -649,19 +645,6 @@ bool LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString>* attrib
|
||||||
LL_DEBUGS("ShaderUniform") << "Attribute " << name << " assigned to channel " << index << LL_ENDL;
|
LL_DEBUGS("ShaderUniform") << "Attribute " << name << " assigned to channel " << index << LL_ENDL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (attributes != NULL)
|
|
||||||
{
|
|
||||||
for (U32 i = 0; i < numAttributes; i++)
|
|
||||||
{
|
|
||||||
const char* name = (*attributes)[i].String().c_str();
|
|
||||||
S32 index = glGetAttribLocation(mProgramObject, name);
|
|
||||||
if (index != -1)
|
|
||||||
{
|
|
||||||
mAttribute[LLShaderMgr::instance()->mReservedAttribs.size() + i] = index;
|
|
||||||
LL_DEBUGS("ShaderUniform") << "Attribute " << name << " assigned to channel " << index << LL_ENDL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -669,7 +652,7 @@ bool LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString>* attrib
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLGLSLShader::mapUniform(GLint index, const vector<LLStaticHashedString>* uniforms)
|
void LLGLSLShader::mapUniform(GLint index)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
|
||||||
|
|
||||||
|
|
@ -756,21 +739,6 @@ void LLGLSLShader::mapUniform(GLint index, const vector<LLStaticHashedString>* u
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uniforms != NULL)
|
|
||||||
{
|
|
||||||
for (U32 i = 0; i < uniforms->size(); i++)
|
|
||||||
{
|
|
||||||
if ((mUniform[i + LLShaderMgr::instance()->mReservedUniforms.size()] == -1)
|
|
||||||
&& ((*uniforms)[i].String() == name))
|
|
||||||
{
|
|
||||||
//found it
|
|
||||||
mUniform[i + LLShaderMgr::instance()->mReservedUniforms.size()] = location;
|
|
||||||
mTexture[i + LLShaderMgr::instance()->mReservedUniforms.size()] = mapUniformTextureChannel(location, type, size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -830,7 +798,7 @@ GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type, GLint
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LLGLSLShader::mapUniforms(const vector<LLStaticHashedString>* uniforms)
|
bool LLGLSLShader::mapUniforms()
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
|
||||||
|
|
||||||
|
|
@ -843,9 +811,8 @@ bool LLGLSLShader::mapUniforms(const vector<LLStaticHashedString>* uniforms)
|
||||||
mTexture.clear();
|
mTexture.clear();
|
||||||
mValue.clear();
|
mValue.clear();
|
||||||
//initialize arrays
|
//initialize arrays
|
||||||
U32 numUniforms = (uniforms == NULL) ? 0 : uniforms->size();
|
mUniform.resize(LLShaderMgr::instance()->mReservedUniforms.size(), -1);
|
||||||
mUniform.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1);
|
mTexture.resize(LLShaderMgr::instance()->mReservedUniforms.size(), -1);
|
||||||
mTexture.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1);
|
|
||||||
|
|
||||||
bind();
|
bind();
|
||||||
|
|
||||||
|
|
@ -946,26 +913,26 @@ bool LLGLSLShader::mapUniforms(const vector<LLStaticHashedString>* uniforms)
|
||||||
|
|
||||||
if (specularDiff || bumpLessDiff || envLessDiff || refLessDiff)
|
if (specularDiff || bumpLessDiff || envLessDiff || refLessDiff)
|
||||||
{
|
{
|
||||||
mapUniform(diffuseMap, uniforms);
|
mapUniform(diffuseMap);
|
||||||
skip_index.insert(diffuseMap);
|
skip_index.insert(diffuseMap);
|
||||||
|
|
||||||
if (-1 != specularMap) {
|
if (-1 != specularMap) {
|
||||||
mapUniform(specularMap, uniforms);
|
mapUniform(specularMap);
|
||||||
skip_index.insert(specularMap);
|
skip_index.insert(specularMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 != bumpMap) {
|
if (-1 != bumpMap) {
|
||||||
mapUniform(bumpMap, uniforms);
|
mapUniform(bumpMap);
|
||||||
skip_index.insert(bumpMap);
|
skip_index.insert(bumpMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 != environmentMap) {
|
if (-1 != environmentMap) {
|
||||||
mapUniform(environmentMap, uniforms);
|
mapUniform(environmentMap);
|
||||||
skip_index.insert(environmentMap);
|
skip_index.insert(environmentMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 != reflectionMap) {
|
if (-1 != reflectionMap) {
|
||||||
mapUniform(reflectionMap, uniforms);
|
mapUniform(reflectionMap);
|
||||||
skip_index.insert(reflectionMap);
|
skip_index.insert(reflectionMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -979,21 +946,29 @@ bool LLGLSLShader::mapUniforms(const vector<LLStaticHashedString>* uniforms)
|
||||||
if (skip_index.end() != skip_index.find(i)) continue;
|
if (skip_index.end() != skip_index.find(i)) continue;
|
||||||
//........................................................................................
|
//........................................................................................
|
||||||
|
|
||||||
mapUniform(i, uniforms);
|
mapUniform(i);
|
||||||
}
|
}
|
||||||
//........................................................................................................................................
|
//........................................................................................................................................
|
||||||
|
|
||||||
if (mFeatures.hasReflectionProbes) // Set up block binding, in a way supported by Apple (rather than binding = 1 in .glsl).
|
// Set up block binding, in a way supported by Apple (rather than binding = 1 in .glsl).
|
||||||
{ // See slide 35 and more of https://docs.huihoo.com/apple/wwdc/2011/session_420__advances_in_opengl_for_mac_os_x_lion.pdf
|
// See slide 35 and more of https://docs.huihoo.com/apple/wwdc/2011/session_420__advances_in_opengl_for_mac_os_x_lion.pdf
|
||||||
static const GLuint BLOCKBINDING = 1; //picked by us
|
const char* ubo_names[] =
|
||||||
//Get the index, similar to a uniform location
|
{
|
||||||
GLuint UBOBlockIndex = glGetUniformBlockIndex(mProgramObject, "ReflectionProbes");
|
"ReflectionProbes", // UB_REFLECTION_PROBES
|
||||||
|
"GLTFJoints", // UB_GLTF_JOINTS
|
||||||
|
};
|
||||||
|
|
||||||
|
llassert(LL_ARRAY_SIZE(ubo_names) == NUM_UNIFORM_BLOCKS);
|
||||||
|
|
||||||
|
for (U32 i = 0; i < NUM_UNIFORM_BLOCKS; ++i)
|
||||||
|
{
|
||||||
|
GLuint UBOBlockIndex = glGetUniformBlockIndex(mProgramObject, ubo_names[i]);
|
||||||
if (UBOBlockIndex != GL_INVALID_INDEX)
|
if (UBOBlockIndex != GL_INVALID_INDEX)
|
||||||
{
|
{
|
||||||
//Set this index to a binding index
|
glUniformBlockBinding(mProgramObject, UBOBlockIndex, i);
|
||||||
glUniformBlockBinding(mProgramObject, UBOBlockIndex, BLOCKBINDING);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unbind();
|
unbind();
|
||||||
|
|
||||||
LL_DEBUGS("ShaderUniform") << "Total Uniform Size: " << mTotalUniformSize << LL_ENDL;
|
LL_DEBUGS("ShaderUniform") << "Total Uniform Size: " << mTotalUniformSize << LL_ENDL;
|
||||||
|
|
@ -1049,6 +1024,13 @@ void LLGLSLShader::bind()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLGLSLShader::bind(U8 variant)
|
||||||
|
{
|
||||||
|
llassert(mGLTFVariants.size() == LLGLSLShader::NUM_GLTF_VARIANTS);
|
||||||
|
llassert(variant < LLGLSLShader::NUM_GLTF_VARIANTS);
|
||||||
|
mGLTFVariants[variant].bind();
|
||||||
|
}
|
||||||
|
|
||||||
void LLGLSLShader::bind(bool rigged)
|
void LLGLSLShader::bind(bool rigged)
|
||||||
{
|
{
|
||||||
if (rigged)
|
if (rigged)
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ public:
|
||||||
bool hasTransport = false; // implies no lighting (it's possible to have neither though)
|
bool hasTransport = false; // implies no lighting (it's possible to have neither though)
|
||||||
bool hasSkinning = false;
|
bool hasSkinning = false;
|
||||||
bool hasObjectSkinning = false;
|
bool hasObjectSkinning = false;
|
||||||
|
bool mGLTF = false;
|
||||||
bool hasAtmospherics = false;
|
bool hasAtmospherics = false;
|
||||||
bool hasGamma = false;
|
bool hasGamma = false;
|
||||||
bool hasShadows = false;
|
bool hasShadows = false;
|
||||||
|
|
@ -145,6 +146,14 @@ public:
|
||||||
SG_COUNT
|
SG_COUNT
|
||||||
} eGroup;
|
} eGroup;
|
||||||
|
|
||||||
|
enum UniformBlock : GLuint
|
||||||
|
{
|
||||||
|
UB_REFLECTION_PROBES,
|
||||||
|
UB_GLTF_JOINTS,
|
||||||
|
NUM_UNIFORM_BLOCKS
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static std::set<LLGLSLShader*> sInstances;
|
static std::set<LLGLSLShader*> sInstances;
|
||||||
static bool sProfileEnabled;
|
static bool sProfileEnabled;
|
||||||
|
|
||||||
|
|
@ -175,17 +184,14 @@ public:
|
||||||
// If force_read is true, will force an immediate readback (severe performance penalty)
|
// If force_read is true, will force an immediate readback (severe performance penalty)
|
||||||
bool readProfileQuery(bool for_runtime = false, bool force_read = false);
|
bool readProfileQuery(bool for_runtime = false, bool force_read = false);
|
||||||
|
|
||||||
bool createShader(std::vector<LLStaticHashedString>* attributes,
|
bool createShader();
|
||||||
std::vector<LLStaticHashedString>* uniforms,
|
|
||||||
U32 varying_count = 0,
|
|
||||||
const char** varyings = NULL);
|
|
||||||
bool attachFragmentObject(std::string object);
|
bool attachFragmentObject(std::string object);
|
||||||
bool attachVertexObject(std::string object);
|
bool attachVertexObject(std::string object);
|
||||||
void attachObject(GLuint object);
|
void attachObject(GLuint object);
|
||||||
void attachObjects(GLuint* objects = NULL, S32 count = 0);
|
void attachObjects(GLuint* objects = NULL, S32 count = 0);
|
||||||
bool mapAttributes(const std::vector<LLStaticHashedString>* attributes);
|
bool mapAttributes();
|
||||||
bool mapUniforms(const std::vector<LLStaticHashedString>*);
|
bool mapUniforms();
|
||||||
void mapUniform(GLint index, const std::vector<LLStaticHashedString>*);
|
void mapUniform(GLint index);
|
||||||
void uniform1i(U32 index, GLint i);
|
void uniform1i(U32 index, GLint i);
|
||||||
void uniform1f(U32 index, GLfloat v);
|
void uniform1f(U32 index, GLfloat v);
|
||||||
void fastUniform1f(U32 index, GLfloat v);
|
void fastUniform1f(U32 index, GLfloat v);
|
||||||
|
|
@ -318,6 +324,24 @@ public:
|
||||||
// this pointer should be set to whichever shader represents this shader's rigged variant
|
// this pointer should be set to whichever shader represents this shader's rigged variant
|
||||||
LLGLSLShader* mRiggedVariant = nullptr;
|
LLGLSLShader* mRiggedVariant = nullptr;
|
||||||
|
|
||||||
|
// variants for use by GLTF renderer
|
||||||
|
// bit 0 = alpha mode blend (1) or opaque (0)
|
||||||
|
// bit 1 = rigged (1) or static (0)
|
||||||
|
// bit 2 = unlit (1) or lit (0)
|
||||||
|
struct GLTFVariant
|
||||||
|
{
|
||||||
|
constexpr static U8 ALPHA_BLEND = 1;
|
||||||
|
constexpr static U8 RIGGED = 2;
|
||||||
|
constexpr static U8 UNLIT = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr static U8 NUM_GLTF_VARIANTS = 8;
|
||||||
|
|
||||||
|
std::vector<LLGLSLShader> mGLTFVariants;
|
||||||
|
|
||||||
|
//helper to bind GLTF variant
|
||||||
|
void bind(U8 variant);
|
||||||
|
|
||||||
// hacky flag used for optimization in LLDrawPoolAlpha
|
// hacky flag used for optimization in LLDrawPoolAlpha
|
||||||
bool mCanBindFast = false;
|
bool mCanBindFast = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,10 @@ LLGLTexture::LLGLTexture(const LLImageRaw* raw, bool usemipmaps)
|
||||||
mUseMipMaps = usemipmaps ;
|
mUseMipMaps = usemipmaps ;
|
||||||
// Create an empty image of the specified size and width
|
// Create an empty image of the specified size and width
|
||||||
mGLTexturep = new LLImageGL(raw, usemipmaps) ;
|
mGLTexturep = new LLImageGL(raw, usemipmaps) ;
|
||||||
|
mFullWidth = mGLTexturep->getWidth();
|
||||||
|
mFullHeight = mGLTexturep->getHeight();
|
||||||
|
mComponents = mGLTexturep->getComponents();
|
||||||
|
setTexelsPerImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
LLGLTexture::~LLGLTexture()
|
LLGLTexture::~LLGLTexture()
|
||||||
|
|
|
||||||
|
|
@ -1012,6 +1012,7 @@ void LLRender::syncLightState()
|
||||||
|
|
||||||
void LLRender::syncMatrices()
|
void LLRender::syncMatrices()
|
||||||
{
|
{
|
||||||
|
STOP_GLERROR;
|
||||||
static const U32 name[] =
|
static const U32 name[] =
|
||||||
{
|
{
|
||||||
LLShaderMgr::MODELVIEW_MATRIX,
|
LLShaderMgr::MODELVIEW_MATRIX,
|
||||||
|
|
@ -1034,8 +1035,6 @@ void LLRender::syncMatrices()
|
||||||
|
|
||||||
if (shader)
|
if (shader)
|
||||||
{
|
{
|
||||||
//llassert(shader);
|
|
||||||
|
|
||||||
bool mvp_done = false;
|
bool mvp_done = false;
|
||||||
|
|
||||||
U32 i = MM_MODELVIEW;
|
U32 i = MM_MODELVIEW;
|
||||||
|
|
@ -1156,6 +1155,7 @@ void LLRender::syncMatrices()
|
||||||
syncLightState();
|
syncLightState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
STOP_GLERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
|
void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z)
|
||||||
|
|
@ -1628,6 +1628,7 @@ void LLRender::end()
|
||||||
}
|
}
|
||||||
void LLRender::flush()
|
void LLRender::flush()
|
||||||
{
|
{
|
||||||
|
STOP_GLERROR;
|
||||||
if (mCount > 0)
|
if (mCount > 0)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
|
||||||
|
|
@ -1738,6 +1739,9 @@ void LLRender::flush()
|
||||||
vb->setColorData(mColorsp.get());
|
vb->setColorData(mColorsp.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LL_DARWIN
|
||||||
|
vb->unmapBuffer();
|
||||||
|
#endif
|
||||||
vb->unbind();
|
vb->unbind();
|
||||||
|
|
||||||
sVBCache[vhash] = { vb , std::chrono::steady_clock::now() };
|
sVBCache[vhash] = { vb , std::chrono::steady_clock::now() };
|
||||||
|
|
|
||||||
|
|
@ -1163,6 +1163,7 @@ void LLShaderMgr::initAttribsAndUniforms()
|
||||||
mReservedAttribs.push_back("weight");
|
mReservedAttribs.push_back("weight");
|
||||||
mReservedAttribs.push_back("weight4");
|
mReservedAttribs.push_back("weight4");
|
||||||
mReservedAttribs.push_back("clothing");
|
mReservedAttribs.push_back("clothing");
|
||||||
|
mReservedAttribs.push_back("joint");
|
||||||
mReservedAttribs.push_back("texture_index");
|
mReservedAttribs.push_back("texture_index");
|
||||||
|
|
||||||
//matrix state
|
//matrix state
|
||||||
|
|
@ -1231,6 +1232,9 @@ void LLShaderMgr::initAttribsAndUniforms()
|
||||||
mReservedUniforms.push_back("diffuseMap");
|
mReservedUniforms.push_back("diffuseMap");
|
||||||
mReservedUniforms.push_back("altDiffuseMap");
|
mReservedUniforms.push_back("altDiffuseMap");
|
||||||
mReservedUniforms.push_back("specularMap");
|
mReservedUniforms.push_back("specularMap");
|
||||||
|
mReservedUniforms.push_back("metallicRoughnessMap");
|
||||||
|
mReservedUniforms.push_back("normalMap");
|
||||||
|
mReservedUniforms.push_back("occlusionMap");
|
||||||
mReservedUniforms.push_back("emissiveMap");
|
mReservedUniforms.push_back("emissiveMap");
|
||||||
mReservedUniforms.push_back("bumpMap");
|
mReservedUniforms.push_back("bumpMap");
|
||||||
mReservedUniforms.push_back("bumpMap2");
|
mReservedUniforms.push_back("bumpMap2");
|
||||||
|
|
@ -1242,7 +1246,6 @@ void LLShaderMgr::initAttribsAndUniforms()
|
||||||
mReservedUniforms.push_back("heroProbes");
|
mReservedUniforms.push_back("heroProbes");
|
||||||
mReservedUniforms.push_back("cloud_noise_texture");
|
mReservedUniforms.push_back("cloud_noise_texture");
|
||||||
mReservedUniforms.push_back("cloud_noise_texture_next");
|
mReservedUniforms.push_back("cloud_noise_texture_next");
|
||||||
mReservedUniforms.push_back("fullbright");
|
|
||||||
mReservedUniforms.push_back("lightnorm");
|
mReservedUniforms.push_back("lightnorm");
|
||||||
mReservedUniforms.push_back("sunlight_color");
|
mReservedUniforms.push_back("sunlight_color");
|
||||||
mReservedUniforms.push_back("ambient_color");
|
mReservedUniforms.push_back("ambient_color");
|
||||||
|
|
@ -1354,7 +1357,6 @@ void LLShaderMgr::initAttribsAndUniforms()
|
||||||
|
|
||||||
llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW5+1);
|
llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW5+1);
|
||||||
|
|
||||||
mReservedUniforms.push_back("normalMap");
|
|
||||||
mReservedUniforms.push_back("positionMap");
|
mReservedUniforms.push_back("positionMap");
|
||||||
mReservedUniforms.push_back("diffuseRect");
|
mReservedUniforms.push_back("diffuseRect");
|
||||||
mReservedUniforms.push_back("specularRect");
|
mReservedUniforms.push_back("specularRect");
|
||||||
|
|
@ -1367,7 +1369,6 @@ void LLShaderMgr::initAttribsAndUniforms()
|
||||||
mReservedUniforms.push_back("bloomMap");
|
mReservedUniforms.push_back("bloomMap");
|
||||||
mReservedUniforms.push_back("projectionMap");
|
mReservedUniforms.push_back("projectionMap");
|
||||||
mReservedUniforms.push_back("norm_mat");
|
mReservedUniforms.push_back("norm_mat");
|
||||||
mReservedUniforms.push_back("texture_gamma");
|
|
||||||
|
|
||||||
mReservedUniforms.push_back("specular_color");
|
mReservedUniforms.push_back("specular_color");
|
||||||
mReservedUniforms.push_back("env_intensity");
|
mReservedUniforms.push_back("env_intensity");
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,9 @@ public:
|
||||||
DIFFUSE_MAP, // "diffuseMap"
|
DIFFUSE_MAP, // "diffuseMap"
|
||||||
ALTERNATE_DIFFUSE_MAP, // "altDiffuseMap"
|
ALTERNATE_DIFFUSE_MAP, // "altDiffuseMap"
|
||||||
SPECULAR_MAP, // "specularMap"
|
SPECULAR_MAP, // "specularMap"
|
||||||
|
METALLIC_ROUGHNESS_MAP, // "metallicRoughnessMap"
|
||||||
|
NORMAL_MAP, // "normalMap"
|
||||||
|
OCCLUSION_MAP, // "occlusionMap"
|
||||||
EMISSIVE_MAP, // "emissiveMap"
|
EMISSIVE_MAP, // "emissiveMap"
|
||||||
BUMP_MAP, // "bumpMap"
|
BUMP_MAP, // "bumpMap"
|
||||||
BUMP_MAP2, // "bumpMap2"
|
BUMP_MAP2, // "bumpMap2"
|
||||||
|
|
@ -104,7 +107,6 @@ public:
|
||||||
HERO_PROBE, // "heroProbes"
|
HERO_PROBE, // "heroProbes"
|
||||||
CLOUD_NOISE_MAP, // "cloud_noise_texture"
|
CLOUD_NOISE_MAP, // "cloud_noise_texture"
|
||||||
CLOUD_NOISE_MAP_NEXT, // "cloud_noise_texture_next"
|
CLOUD_NOISE_MAP_NEXT, // "cloud_noise_texture_next"
|
||||||
FULLBRIGHT, // "fullbright"
|
|
||||||
LIGHTNORM, // "lightnorm"
|
LIGHTNORM, // "lightnorm"
|
||||||
SUNLIGHT_COLOR, // "sunlight_color"
|
SUNLIGHT_COLOR, // "sunlight_color"
|
||||||
AMBIENT, // "ambient_color"
|
AMBIENT, // "ambient_color"
|
||||||
|
|
@ -202,7 +204,6 @@ public:
|
||||||
DEFERRED_SHADOW3, // "shadowMap3"
|
DEFERRED_SHADOW3, // "shadowMap3"
|
||||||
DEFERRED_SHADOW4, // "shadowMap4"
|
DEFERRED_SHADOW4, // "shadowMap4"
|
||||||
DEFERRED_SHADOW5, // "shadowMap5"
|
DEFERRED_SHADOW5, // "shadowMap5"
|
||||||
DEFERRED_NORMAL, // "normalMap"
|
|
||||||
DEFERRED_POSITION, // "positionMap"
|
DEFERRED_POSITION, // "positionMap"
|
||||||
DEFERRED_DIFFUSE, // "diffuseRect"
|
DEFERRED_DIFFUSE, // "diffuseRect"
|
||||||
DEFERRED_SPECULAR, // "specularRect"
|
DEFERRED_SPECULAR, // "specularRect"
|
||||||
|
|
@ -215,7 +216,6 @@ public:
|
||||||
DEFERRED_BLOOM, // "bloomMap"
|
DEFERRED_BLOOM, // "bloomMap"
|
||||||
DEFERRED_PROJECTION, // "projectionMap"
|
DEFERRED_PROJECTION, // "projectionMap"
|
||||||
DEFERRED_NORM_MATRIX, // "norm_mat"
|
DEFERRED_NORM_MATRIX, // "norm_mat"
|
||||||
TEXTURE_GAMMA, // "texture_gamma"
|
|
||||||
SPECULAR_COLOR, // "specular_color"
|
SPECULAR_COLOR, // "specular_color"
|
||||||
ENVIRONMENT_INTENSITY, // "env_intensity"
|
ENVIRONMENT_INTENSITY, // "env_intensity"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -290,6 +290,62 @@ static GLuint gen_buffer()
|
||||||
|
|
||||||
#define ANALYZE_VBO_POOL 0
|
#define ANALYZE_VBO_POOL 0
|
||||||
|
|
||||||
|
#if LL_DARWIN
|
||||||
|
|
||||||
|
// experimental -- disable VBO pooling on OS X and use glMapBuffer
|
||||||
|
class LLVBOPool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
U64 mAllocated = 0;
|
||||||
|
|
||||||
|
U64 getVramBytesUsed()
|
||||||
|
{
|
||||||
|
return mAllocated;
|
||||||
|
}
|
||||||
|
|
||||||
|
void allocate(GLenum type, U32 size, GLuint& name, U8*& data)
|
||||||
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
|
||||||
|
STOP_GLERROR;
|
||||||
|
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
|
||||||
|
llassert(name == 0); // non zero name indicates a gl name that wasn't freed
|
||||||
|
llassert(data == nullptr); // non null data indicates a buffer that wasn't freed
|
||||||
|
llassert(size >= 2); // any buffer size smaller than a single index is nonsensical
|
||||||
|
|
||||||
|
mAllocated += size;
|
||||||
|
|
||||||
|
{ //allocate a new buffer
|
||||||
|
LL_PROFILE_GPU_ZONE("vbo alloc");
|
||||||
|
// ON OS X, we don't allocate a VBO until the last possible moment
|
||||||
|
// in unmapBuffer
|
||||||
|
data = (U8*) ll_aligned_malloc_16(size);
|
||||||
|
STOP_GLERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(GLenum type, U32 size, GLuint name, U8* data)
|
||||||
|
{
|
||||||
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
|
||||||
|
llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
|
||||||
|
llassert(size >= 2);
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
ll_aligned_free_16(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
mAllocated -= size;
|
||||||
|
STOP_GLERROR;
|
||||||
|
if (name)
|
||||||
|
{
|
||||||
|
glDeleteBuffers(1, &name);
|
||||||
|
}
|
||||||
|
STOP_GLERROR;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
class LLVBOPool
|
class LLVBOPool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -509,9 +565,8 @@ public:
|
||||||
mIBOPool.clear();
|
mIBOPool.clear();
|
||||||
mVBOPool.clear();
|
mVBOPool.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static LLVBOPool* sVBOPool = nullptr;
|
static LLVBOPool* sVBOPool = nullptr;
|
||||||
|
|
||||||
|
|
@ -545,6 +600,7 @@ const U32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
|
||||||
sizeof(F32), // TYPE_WEIGHT,
|
sizeof(F32), // TYPE_WEIGHT,
|
||||||
sizeof(LLVector4), // TYPE_WEIGHT4,
|
sizeof(LLVector4), // TYPE_WEIGHT4,
|
||||||
sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
|
sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
|
||||||
|
sizeof(U64), // TYPE_JOINT,
|
||||||
sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes
|
sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -562,6 +618,7 @@ static const std::string vb_type_name[] =
|
||||||
"TYPE_WEIGHT",
|
"TYPE_WEIGHT",
|
||||||
"TYPE_WEIGHT4",
|
"TYPE_WEIGHT4",
|
||||||
"TYPE_CLOTHWEIGHT",
|
"TYPE_CLOTHWEIGHT",
|
||||||
|
"TYPE_JOINT"
|
||||||
"TYPE_TEXTURE_INDEX",
|
"TYPE_TEXTURE_INDEX",
|
||||||
"TYPE_MAX",
|
"TYPE_MAX",
|
||||||
"TYPE_INDEX",
|
"TYPE_INDEX",
|
||||||
|
|
@ -645,6 +702,8 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto
|
||||||
}
|
}
|
||||||
// </FS:Ansariel>
|
// </FS:Ansariel>
|
||||||
|
|
||||||
|
STOP_GLERROR;
|
||||||
|
|
||||||
gGL.syncMatrices();
|
gGL.syncMatrices();
|
||||||
|
|
||||||
U32 mask = LLVertexBuffer::MAP_VERTEX;
|
U32 mask = LLVertexBuffer::MAP_VERTEX;
|
||||||
|
|
@ -703,6 +762,7 @@ bool LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
#if 0 // not a reliable test for VBOs that are not backed by a CPU buffer
|
||||||
U16* idx = (U16*) mMappedIndexData+indices_offset;
|
U16* idx = (U16*) mMappedIndexData+indices_offset;
|
||||||
for (U32 i = 0; i < count; ++i)
|
for (U32 i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -740,6 +800,7 @@ bool LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -757,8 +818,10 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
|
||||||
llassert(mGLBuffer == sGLRenderBuffer);
|
llassert(mGLBuffer == sGLRenderBuffer);
|
||||||
llassert(mGLIndices == sGLRenderIndices);
|
llassert(mGLIndices == sGLRenderIndices);
|
||||||
gGL.syncMatrices();
|
gGL.syncMatrices();
|
||||||
|
STOP_GLERROR;
|
||||||
glDrawRangeElements(sGLMode[mode], start, end, count, mIndicesType,
|
glDrawRangeElements(sGLMode[mode], start, end, count, mIndicesType,
|
||||||
(GLvoid*) (indices_offset * (size_t) mIndicesStride));
|
(GLvoid*) (indices_offset * (size_t) mIndicesStride));
|
||||||
|
STOP_GLERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
|
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
|
||||||
|
|
@ -774,7 +837,9 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
|
||||||
llassert(mGLIndices == sGLRenderIndices);
|
llassert(mGLIndices == sGLRenderIndices);
|
||||||
|
|
||||||
gGL.syncMatrices();
|
gGL.syncMatrices();
|
||||||
|
STOP_GLERROR;
|
||||||
glDrawArrays(sGLMode[mode], first, count);
|
glDrawArrays(sGLMode[mode], first, count);
|
||||||
|
STOP_GLERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
//static
|
||||||
|
|
@ -797,9 +862,10 @@ void LLVertexBuffer::initClass(LLWindow* window)
|
||||||
//static
|
//static
|
||||||
void LLVertexBuffer::unbind()
|
void LLVertexBuffer::unbind()
|
||||||
{
|
{
|
||||||
|
STOP_GLERROR;
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
STOP_GLERROR;
|
||||||
sGLRenderBuffer = 0;
|
sGLRenderBuffer = 0;
|
||||||
sGLRenderIndices = 0;
|
sGLRenderIndices = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1052,8 +1118,7 @@ bool LLVertexBuffer::updateNumIndices(U32 nindices)
|
||||||
|
|
||||||
bool LLVertexBuffer::allocateBuffer(U32 nverts, U32 nindices)
|
bool LLVertexBuffer::allocateBuffer(U32 nverts, U32 nindices)
|
||||||
{
|
{
|
||||||
if (nverts < 0 || nindices < 0 ||
|
if (nverts < 0 || nindices < 0)
|
||||||
nverts > 65536)
|
|
||||||
{
|
{
|
||||||
LL_ERRS() << "Bad vertex buffer allocation: " << nverts << " : " << nindices << LL_ENDL;
|
LL_ERRS() << "Bad vertex buffer allocation: " << nverts << " : " << nindices << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
@ -1096,6 +1161,7 @@ U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 inde
|
||||||
count = mNumVerts - index;
|
count = mNumVerts - index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !LL_DARWIN
|
||||||
U32 start = mOffsets[type] + sTypeSize[type] * index;
|
U32 start = mOffsets[type] + sTypeSize[type] * index;
|
||||||
U32 end = start + sTypeSize[type] * count-1;
|
U32 end = start + sTypeSize[type] * count-1;
|
||||||
|
|
||||||
|
|
@ -1116,7 +1182,7 @@ U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 inde
|
||||||
//didn't expand an existing region, make a new one
|
//didn't expand an existing region, make a new one
|
||||||
mMappedVertexRegions.push_back({ start, end });
|
mMappedVertexRegions.push_back({ start, end });
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return mMappedData+mOffsets[type]+sTypeSize[type]*index;
|
return mMappedData+mOffsets[type]+sTypeSize[type]*index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1130,6 +1196,7 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
|
||||||
count = mNumIndices-index;
|
count = mNumIndices-index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !LL_DARWIN
|
||||||
U32 start = sizeof(U16) * index;
|
U32 start = sizeof(U16) * index;
|
||||||
U32 end = start + sizeof(U16) * count-1;
|
U32 end = start + sizeof(U16) * count-1;
|
||||||
|
|
||||||
|
|
@ -1150,6 +1217,7 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
|
||||||
//didn't expand an existing region, make a new one
|
//didn't expand an existing region, make a new one
|
||||||
mMappedIndexRegions.push_back({ start, end });
|
mMappedIndexRegions.push_back({ start, end });
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return mMappedIndexData + sizeof(U16)*index;
|
return mMappedIndexData + sizeof(U16)*index;
|
||||||
}
|
}
|
||||||
|
|
@ -1158,9 +1226,17 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
|
||||||
// target -- "target" parameter for glBufferSubData
|
// target -- "target" parameter for glBufferSubData
|
||||||
// start -- first byte to copy
|
// start -- first byte to copy
|
||||||
// end -- last byte to copy (NOT last byte + 1)
|
// end -- last byte to copy (NOT last byte + 1)
|
||||||
// data -- mMappedData or mMappedIndexData
|
// data -- data to be flushed
|
||||||
static void flush_vbo(GLenum target, U32 start, U32 end, void* data)
|
// dst -- mMappedData or mMappedIndexData
|
||||||
|
static void flush_vbo(GLenum target, U32 start, U32 end, void* data, U8* dst)
|
||||||
{
|
{
|
||||||
|
#if LL_DARWIN
|
||||||
|
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb memcpy");
|
||||||
|
STOP_GLERROR;
|
||||||
|
// copy into mapped buffer
|
||||||
|
memcpy(dst+start, data, end-start+1);
|
||||||
|
#else
|
||||||
|
// skip mapped data and stream to GPU via glBufferSubData
|
||||||
if (end != 0)
|
if (end != 0)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData");
|
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData");
|
||||||
|
|
@ -1179,10 +1255,12 @@ static void flush_vbo(GLenum target, U32 start, U32 end, void* data)
|
||||||
glBufferSubData(target, i, size, (U8*) data + (i-start));
|
glBufferSubData(target, i, size, (U8*) data + (i-start));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVertexBuffer::unmapBuffer()
|
void LLVertexBuffer::unmapBuffer()
|
||||||
{
|
{
|
||||||
|
STOP_GLERROR;
|
||||||
struct SortMappedRegion
|
struct SortMappedRegion
|
||||||
{
|
{
|
||||||
bool operator()(const MappedRegion& lhs, const MappedRegion& rhs)
|
bool operator()(const MappedRegion& lhs, const MappedRegion& rhs)
|
||||||
|
|
@ -1191,9 +1269,51 @@ void LLVertexBuffer::unmapBuffer()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if LL_DARWIN
|
||||||
|
STOP_GLERROR;
|
||||||
|
if (mMappedData)
|
||||||
|
{
|
||||||
|
if (mGLBuffer)
|
||||||
|
{
|
||||||
|
glDeleteBuffers(1, &mGLBuffer);
|
||||||
|
}
|
||||||
|
mGLBuffer = gen_buffer();
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
|
||||||
|
sGLRenderBuffer = mGLBuffer;
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, mSize, mMappedData, GL_STATIC_DRAW);
|
||||||
|
}
|
||||||
|
else if (mGLBuffer != sGLRenderBuffer)
|
||||||
|
{
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
|
||||||
|
sGLRenderBuffer = mGLBuffer;
|
||||||
|
}
|
||||||
|
STOP_GLERROR;
|
||||||
|
|
||||||
|
if (mMappedIndexData)
|
||||||
|
{
|
||||||
|
if (mGLIndices)
|
||||||
|
{
|
||||||
|
glDeleteBuffers(1, &mGLIndices);
|
||||||
|
}
|
||||||
|
|
||||||
|
mGLIndices = gen_buffer();
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
|
||||||
|
sGLRenderIndices = mGLIndices;
|
||||||
|
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mMappedIndexData, GL_STATIC_DRAW);
|
||||||
|
}
|
||||||
|
else if (mGLIndices != sGLRenderIndices)
|
||||||
|
{
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
|
||||||
|
sGLRenderIndices = mGLIndices;
|
||||||
|
}
|
||||||
|
STOP_GLERROR;
|
||||||
|
#else
|
||||||
|
|
||||||
if (!mMappedVertexRegions.empty())
|
if (!mMappedVertexRegions.empty())
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
|
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
|
||||||
|
|
||||||
if (sGLRenderBuffer != mGLBuffer)
|
if (sGLRenderBuffer != mGLBuffer)
|
||||||
{
|
{
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
|
glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
|
||||||
|
|
@ -1214,14 +1334,13 @@ void LLVertexBuffer::unmapBuffer()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start);
|
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
|
||||||
start = region.mStart;
|
start = region.mStart;
|
||||||
end = region.mEnd;
|
end = region.mEnd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start);
|
flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start, mMappedData);
|
||||||
|
|
||||||
mMappedVertexRegions.clear();
|
mMappedVertexRegions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1248,16 +1367,16 @@ void LLVertexBuffer::unmapBuffer()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start);
|
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
|
||||||
start = region.mStart;
|
start = region.mStart;
|
||||||
end = region.mEnd;
|
end = region.mEnd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start);
|
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start, mMappedIndexData);
|
||||||
|
|
||||||
mMappedIndexRegions.clear();
|
mMappedIndexRegions.clear();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
@ -1389,10 +1508,17 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4a>& strider, U32 i
|
||||||
// Set for rendering
|
// Set for rendering
|
||||||
void LLVertexBuffer::setBuffer()
|
void LLVertexBuffer::setBuffer()
|
||||||
{
|
{
|
||||||
|
STOP_GLERROR;
|
||||||
|
#if LL_DARWIN
|
||||||
|
if (!mGLBuffer)
|
||||||
|
{ // OS X doesn't allocate a buffer until we call unmapBuffer
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
// no data may be pending
|
// no data may be pending
|
||||||
llassert(mMappedVertexRegions.empty());
|
llassert(mMappedVertexRegions.empty());
|
||||||
llassert(mMappedIndexRegions.empty());
|
llassert(mMappedIndexRegions.empty());
|
||||||
|
|
||||||
// a shader must be bound
|
// a shader must be bound
|
||||||
llassert(LLGLSLShader::sCurBoundShaderPtr);
|
llassert(LLGLSLShader::sCurBoundShaderPtr);
|
||||||
|
|
||||||
|
|
@ -1421,12 +1547,15 @@ void LLVertexBuffer::setBuffer()
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
|
||||||
sGLRenderIndices = mGLIndices;
|
sGLRenderIndices = mGLIndices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STOP_GLERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// virtual (default)
|
// virtual (default)
|
||||||
void LLVertexBuffer::setupVertexBuffer()
|
void LLVertexBuffer::setupVertexBuffer()
|
||||||
{
|
{
|
||||||
|
STOP_GLERROR;
|
||||||
U8* base = nullptr;
|
U8* base = nullptr;
|
||||||
|
|
||||||
U32 data_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask;
|
U32 data_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask;
|
||||||
|
|
@ -1498,6 +1627,12 @@ void LLVertexBuffer::setupVertexBuffer()
|
||||||
void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT4]);
|
void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT4]);
|
||||||
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
|
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
|
||||||
}
|
}
|
||||||
|
if (data_mask & MAP_JOINT)
|
||||||
|
{
|
||||||
|
AttributeType loc = TYPE_JOINT;
|
||||||
|
void* ptr = (void*)(base + mOffsets[TYPE_JOINT]);
|
||||||
|
glVertexAttribIPointer(loc, 4, GL_UNSIGNED_SHORT, LLVertexBuffer::sTypeSize[TYPE_JOINT], ptr);
|
||||||
|
}
|
||||||
if (data_mask & MAP_CLOTHWEIGHT)
|
if (data_mask & MAP_CLOTHWEIGHT)
|
||||||
{
|
{
|
||||||
AttributeType loc = TYPE_CLOTHWEIGHT;
|
AttributeType loc = TYPE_CLOTHWEIGHT;
|
||||||
|
|
@ -1516,59 +1651,84 @@ void LLVertexBuffer::setupVertexBuffer()
|
||||||
void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
|
void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
|
||||||
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
|
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
|
||||||
}
|
}
|
||||||
|
STOP_GLERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVertexBuffer::setPositionData(const LLVector4a* data)
|
void LLVertexBuffer::setPositionData(const LLVector4a* data)
|
||||||
{
|
{
|
||||||
|
#if !LL_DARWIN
|
||||||
llassert(sGLRenderBuffer == mGLBuffer);
|
llassert(sGLRenderBuffer == mGLBuffer);
|
||||||
flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts()-1, (U8*) data);
|
#endif
|
||||||
|
flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts()-1, (U8*) data, mMappedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVertexBuffer::setTexCoordData(const LLVector2* data)
|
void LLVertexBuffer::setTexCoordData(const LLVector2* data)
|
||||||
{
|
{
|
||||||
|
#if !LL_DARWIN
|
||||||
llassert(sGLRenderBuffer == mGLBuffer);
|
llassert(sGLRenderBuffer == mGLBuffer);
|
||||||
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts() - 1, (U8*)data);
|
#endif
|
||||||
|
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts() - 1, (U8*)data, mMappedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVertexBuffer::setColorData(const LLColor4U* data)
|
void LLVertexBuffer::setColorData(const LLColor4U* data)
|
||||||
{
|
{
|
||||||
|
#if !LL_DARWIN
|
||||||
llassert(sGLRenderBuffer == mGLBuffer);
|
llassert(sGLRenderBuffer == mGLBuffer);
|
||||||
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR], mOffsets[TYPE_COLOR] + sTypeSize[TYPE_COLOR] * getNumVerts() - 1, (U8*) data);
|
#endif
|
||||||
|
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR], mOffsets[TYPE_COLOR] + sTypeSize[TYPE_COLOR] * getNumVerts() - 1, (U8*) data, mMappedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVertexBuffer::setNormalData(const LLVector4a* data)
|
void LLVertexBuffer::setNormalData(const LLVector4a* data)
|
||||||
{
|
{
|
||||||
|
#if !LL_DARWIN
|
||||||
llassert(sGLRenderBuffer == mGLBuffer);
|
llassert(sGLRenderBuffer == mGLBuffer);
|
||||||
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_NORMAL], mOffsets[TYPE_NORMAL] + sTypeSize[TYPE_NORMAL] * getNumVerts() - 1, (U8*) data);
|
#endif
|
||||||
|
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_NORMAL], mOffsets[TYPE_NORMAL] + sTypeSize[TYPE_NORMAL] * getNumVerts() - 1, (U8*) data, mMappedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVertexBuffer::setTangentData(const LLVector4a* data)
|
void LLVertexBuffer::setTangentData(const LLVector4a* data)
|
||||||
{
|
{
|
||||||
|
#if !LL_DARWIN
|
||||||
llassert(sGLRenderBuffer == mGLBuffer);
|
llassert(sGLRenderBuffer == mGLBuffer);
|
||||||
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TANGENT], mOffsets[TYPE_TANGENT] + sTypeSize[TYPE_TANGENT] * getNumVerts() - 1, (U8*) data);
|
#endif
|
||||||
|
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TANGENT], mOffsets[TYPE_TANGENT] + sTypeSize[TYPE_TANGENT] * getNumVerts() - 1, (U8*) data, mMappedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVertexBuffer::setWeight4Data(const LLVector4a* data)
|
void LLVertexBuffer::setWeight4Data(const LLVector4a* data)
|
||||||
{
|
{
|
||||||
|
#if !LL_DARWIN
|
||||||
llassert(sGLRenderBuffer == mGLBuffer);
|
llassert(sGLRenderBuffer == mGLBuffer);
|
||||||
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_WEIGHT4], mOffsets[TYPE_WEIGHT4] + sTypeSize[TYPE_WEIGHT4] * getNumVerts() - 1, (U8*) data);
|
#endif
|
||||||
|
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_WEIGHT4], mOffsets[TYPE_WEIGHT4] + sTypeSize[TYPE_WEIGHT4] * getNumVerts() - 1, (U8*) data, mMappedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LLVertexBuffer::setJointData(const U64* data)
|
||||||
|
{
|
||||||
|
#if !LL_DARWIN
|
||||||
|
llassert(sGLRenderBuffer == mGLBuffer);
|
||||||
|
#endif
|
||||||
|
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_JOINT], mOffsets[TYPE_JOINT] + sTypeSize[TYPE_JOINT] * getNumVerts() - 1, (U8*) data, mMappedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVertexBuffer::setIndexData(const U16* data)
|
void LLVertexBuffer::setIndexData(const U16* data)
|
||||||
{
|
{
|
||||||
|
#if !LL_DARWIN
|
||||||
llassert(sGLRenderIndices == mGLIndices);
|
llassert(sGLRenderIndices == mGLIndices);
|
||||||
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U16) * getNumIndices() - 1, (U8*) data);
|
#endif
|
||||||
|
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U16) * getNumIndices() - 1, (U8*) data, mMappedIndexData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVertexBuffer::setIndexData(const U32* data)
|
void LLVertexBuffer::setIndexData(const U32* data)
|
||||||
{
|
{
|
||||||
|
#if !LL_DARWIN
|
||||||
llassert(sGLRenderIndices == mGLIndices);
|
llassert(sGLRenderIndices == mGLIndices);
|
||||||
|
#endif
|
||||||
if (mIndicesType != GL_UNSIGNED_INT)
|
if (mIndicesType != GL_UNSIGNED_INT)
|
||||||
{ // HACK -- vertex buffers are initialized as 16-bit indices, but can be switched to 32-bit indices
|
{ // HACK -- vertex buffers are initialized as 16-bit indices, but can be switched to 32-bit indices
|
||||||
mIndicesType = GL_UNSIGNED_INT;
|
mIndicesType = GL_UNSIGNED_INT;
|
||||||
mIndicesStride = 4;
|
mIndicesStride = 4;
|
||||||
mNumIndices /= 2;
|
mNumIndices /= 2;
|
||||||
}
|
}
|
||||||
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U32) * getNumIndices() - 1, (U8*)data);
|
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U32) * getNumIndices() - 1, (U8*)data, mMappedIndexData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,7 @@ public:
|
||||||
TYPE_WEIGHT, // "weight"
|
TYPE_WEIGHT, // "weight"
|
||||||
TYPE_WEIGHT4, // "weight4"
|
TYPE_WEIGHT4, // "weight4"
|
||||||
TYPE_CLOTHWEIGHT, // "clothing"
|
TYPE_CLOTHWEIGHT, // "clothing"
|
||||||
|
TYPE_JOINT, // "joint"
|
||||||
TYPE_TEXTURE_INDEX, // "texture_index"
|
TYPE_TEXTURE_INDEX, // "texture_index"
|
||||||
TYPE_MAX, // TYPE_MAX is the size/boundary marker for attributes that go in the vertex buffer
|
TYPE_MAX, // TYPE_MAX is the size/boundary marker for attributes that go in the vertex buffer
|
||||||
TYPE_INDEX, // TYPE_INDEX is beyond _MAX because it lives in a separate (index) buffer
|
TYPE_INDEX, // TYPE_INDEX is beyond _MAX because it lives in a separate (index) buffer
|
||||||
|
|
@ -129,6 +130,7 @@ public:
|
||||||
MAP_WEIGHT = (1<<TYPE_WEIGHT),
|
MAP_WEIGHT = (1<<TYPE_WEIGHT),
|
||||||
MAP_WEIGHT4 = (1<<TYPE_WEIGHT4),
|
MAP_WEIGHT4 = (1<<TYPE_WEIGHT4),
|
||||||
MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT),
|
MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT),
|
||||||
|
MAP_JOINT = (1<<TYPE_JOINT),
|
||||||
MAP_TEXTURE_INDEX = (1<<TYPE_TEXTURE_INDEX),
|
MAP_TEXTURE_INDEX = (1<<TYPE_TEXTURE_INDEX),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -197,6 +199,7 @@ public:
|
||||||
void setNormalData(const LLVector4a* data);
|
void setNormalData(const LLVector4a* data);
|
||||||
void setTangentData(const LLVector4a* data);
|
void setTangentData(const LLVector4a* data);
|
||||||
void setWeight4Data(const LLVector4a* data);
|
void setWeight4Data(const LLVector4a* data);
|
||||||
|
void setJointData(const U64* data);
|
||||||
void setTexCoordData(const LLVector2* data);
|
void setTexCoordData(const LLVector2* data);
|
||||||
void setColorData(const LLColor4U* data);
|
void setColorData(const LLColor4U* data);
|
||||||
void setIndexData(const U16* data);
|
void setIndexData(const U16* data);
|
||||||
|
|
|
||||||
|
|
@ -361,14 +361,8 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
|
||||||
mGLReady = true;
|
mGLReady = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialzie DXGI adapter (for querying available VRAM)
|
// Use DXGI to check memory (because WMI doesn't report more than 4Gb)
|
||||||
void initDX();
|
void checkDXMem();
|
||||||
|
|
||||||
// initialize D3D (if DXGI cannot be used)
|
|
||||||
void initD3D();
|
|
||||||
|
|
||||||
//clean up DXGI/D3D resources
|
|
||||||
void cleanupDX();
|
|
||||||
|
|
||||||
/// called by main thread to post work to this window thread
|
/// called by main thread to post work to this window thread
|
||||||
template <typename CALLABLE>
|
template <typename CALLABLE>
|
||||||
|
|
@ -417,12 +411,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
|
||||||
// *HACK: Attempt to prevent startup crashes by deferring memory accounting
|
// *HACK: Attempt to prevent startup crashes by deferring memory accounting
|
||||||
// until after some graphics setup. See SL-20177. -Cosmic,2023-09-18
|
// until after some graphics setup. See SL-20177. -Cosmic,2023-09-18
|
||||||
bool mGLReady = false;
|
bool mGLReady = false;
|
||||||
|
bool mGotGLBuffer = false;
|
||||||
|
|
||||||
U32 mMaxVRAM = 0; // maximum amount of vram to allow in the "budget", or 0 for no maximum (see updateVRAMUsage)
|
U32 mMaxVRAM = 0; // maximum amount of vram to allow in the "budget", or 0 for no maximum (see updateVRAMUsage)
|
||||||
|
|
||||||
IDXGIAdapter3* mDXGIAdapter = nullptr;
|
|
||||||
LPDIRECT3D9 mD3D = nullptr;
|
|
||||||
LPDIRECT3DDEVICE9 mD3DDevice = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -4741,39 +4732,55 @@ private:
|
||||||
std::string mPrev;
|
std::string mPrev;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Print hardware debug info about available graphics adapters in ordinal order
|
void LLWindowWin32::LLWindowWin32Thread::checkDXMem()
|
||||||
void debugEnumerateGraphicsAdapters()
|
|
||||||
{
|
{
|
||||||
LL_INFOS("Window") << "Enumerating graphics adapters..." << LL_ENDL;
|
if (!mGLReady || mGotGLBuffer) { return; }
|
||||||
|
|
||||||
IDXGIFactory1* factory;
|
IDXGIFactory4* p_factory = nullptr;
|
||||||
HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory);
|
|
||||||
if (FAILED(res) || !factory)
|
HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&p_factory);
|
||||||
|
|
||||||
|
if (FAILED(res))
|
||||||
{
|
{
|
||||||
LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL;
|
LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
IDXGIAdapter3* p_dxgi_adapter = nullptr;
|
||||||
UINT graphics_adapter_index = 0;
|
UINT graphics_adapter_index = 0;
|
||||||
IDXGIAdapter3* dxgi_adapter;
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
res = factory->EnumAdapters(graphics_adapter_index, reinterpret_cast<IDXGIAdapter**>(&dxgi_adapter));
|
res = p_factory->EnumAdapters(graphics_adapter_index, reinterpret_cast<IDXGIAdapter**>(&p_dxgi_adapter));
|
||||||
if (FAILED(res))
|
if (FAILED(res))
|
||||||
{
|
{
|
||||||
if (graphics_adapter_index == 0)
|
if (graphics_adapter_index == 0)
|
||||||
{
|
{
|
||||||
LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL;
|
LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
LL_INFOS("Window") << "Done enumerating graphics adapters" << LL_ENDL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (graphics_adapter_index == 0) // Should it check largest one isntead of first?
|
||||||
|
{
|
||||||
|
DXGI_QUERY_VIDEO_MEMORY_INFO info;
|
||||||
|
p_dxgi_adapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info);
|
||||||
|
|
||||||
|
// Alternatively use GetDesc from below to get adapter's memory
|
||||||
|
UINT64 budget_mb = info.Budget / (1024 * 1024);
|
||||||
|
if (gGLManager.mVRAM < (S32)budget_mb)
|
||||||
|
{
|
||||||
|
gGLManager.mVRAM = (S32)budget_mb;
|
||||||
|
LL_INFOS("RenderInit") << "New VRAM Budget (DX9): " << gGLManager.mVRAM << " MB" << LL_ENDL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LL_INFOS("RenderInit") << "VRAM Budget (DX9): " << budget_mb
|
||||||
|
<< " MB, current (WMI): " << gGLManager.mVRAM << " MB" << LL_ENDL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DXGI_ADAPTER_DESC desc;
|
DXGI_ADAPTER_DESC desc;
|
||||||
dxgi_adapter->GetDesc(&desc);
|
p_dxgi_adapter->GetDesc(&desc);
|
||||||
std::wstring description_w((wchar_t*)desc.Description);
|
std::wstring description_w((wchar_t*)desc.Description);
|
||||||
std::string description(description_w.begin(), description_w.end());
|
std::string description(description_w.begin(), description_w.end());
|
||||||
LL_INFOS("Window") << "Graphics adapter index: " << graphics_adapter_index << ", "
|
LL_INFOS("Window") << "Graphics adapter index: " << graphics_adapter_index << ", "
|
||||||
|
|
@ -4786,10 +4793,10 @@ void debugEnumerateGraphicsAdapters()
|
||||||
<< "SharedSystemMemory: " << desc.SharedSystemMemory / 1024 / 1024 << LL_ENDL;
|
<< "SharedSystemMemory: " << desc.SharedSystemMemory / 1024 / 1024 << LL_ENDL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dxgi_adapter)
|
if (p_dxgi_adapter)
|
||||||
{
|
{
|
||||||
dxgi_adapter->Release();
|
p_dxgi_adapter->Release();
|
||||||
dxgi_adapter = NULL;
|
p_dxgi_adapter = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -4800,95 +4807,12 @@ void debugEnumerateGraphicsAdapters()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (factory)
|
if (p_factory)
|
||||||
{
|
{
|
||||||
factory->Release();
|
p_factory->Release();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LLWindowWin32::LLWindowWin32Thread::initDX()
|
|
||||||
{
|
|
||||||
if (!mGLReady) { return; }
|
|
||||||
|
|
||||||
if (mDXGIAdapter == NULL)
|
|
||||||
{
|
|
||||||
debugEnumerateGraphicsAdapters();
|
|
||||||
|
|
||||||
IDXGIFactory4* pFactory = nullptr;
|
|
||||||
|
|
||||||
HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&pFactory);
|
|
||||||
|
|
||||||
if (FAILED(res))
|
|
||||||
{
|
|
||||||
LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res = pFactory->EnumAdapters(0, reinterpret_cast<IDXGIAdapter**>(&mDXGIAdapter));
|
|
||||||
if (FAILED(res))
|
|
||||||
{
|
|
||||||
LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LL_INFOS() << "EnumAdapters success" << LL_ENDL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pFactory)
|
|
||||||
{
|
|
||||||
pFactory->Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LLWindowWin32::LLWindowWin32Thread::initD3D()
|
|
||||||
{
|
|
||||||
if (!mGLReady) { return; }
|
|
||||||
|
|
||||||
if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandleThrd != 0)
|
|
||||||
{
|
|
||||||
mD3D = Direct3DCreate9(D3D_SDK_VERSION);
|
|
||||||
|
|
||||||
D3DPRESENT_PARAMETERS d3dpp;
|
|
||||||
|
|
||||||
ZeroMemory(&d3dpp, sizeof(d3dpp));
|
|
||||||
d3dpp.Windowed = TRUE;
|
|
||||||
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
|
||||||
|
|
||||||
HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandleThrd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice);
|
|
||||||
|
|
||||||
if (FAILED(res))
|
|
||||||
{
|
|
||||||
LL_WARNS() << "(fallback) CreateDevice failed: 0x" << std::hex << res << LL_ENDL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LL_INFOS() << "(fallback) CreateDevice success" << LL_ENDL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LLWindowWin32::LLWindowWin32Thread::cleanupDX()
|
|
||||||
{
|
|
||||||
//clean up DXGI/D3D resources
|
|
||||||
if (mDXGIAdapter)
|
|
||||||
{
|
|
||||||
mDXGIAdapter->Release();
|
|
||||||
mDXGIAdapter = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mD3DDevice)
|
mGotGLBuffer = true;
|
||||||
{
|
|
||||||
mD3DDevice->Release();
|
|
||||||
mD3DDevice = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mD3D)
|
|
||||||
{
|
|
||||||
mD3D->Release();
|
|
||||||
mD3D = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLWindowWin32::LLWindowWin32Thread::run()
|
void LLWindowWin32::LLWindowWin32Thread::run()
|
||||||
|
|
@ -4907,15 +4831,11 @@ void LLWindowWin32::LLWindowWin32Thread::run()
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
|
||||||
|
|
||||||
// lazily call initD3D inside this loop to catch when mGLReady has been set to true
|
// Check memory budget using DirectX
|
||||||
initDX();
|
checkDXMem();
|
||||||
|
|
||||||
if (mWindowHandleThrd != 0)
|
if (mWindowHandleThrd != 0)
|
||||||
{
|
{
|
||||||
// lazily call initD3D inside this loop to catch when mWindowHandle has been set, and mGLReady has been set to true
|
|
||||||
// *TODO: Shutdown if this fails when mWindowHandle exists
|
|
||||||
initD3D();
|
|
||||||
|
|
||||||
MSG msg;
|
MSG msg;
|
||||||
BOOL status;
|
BOOL status;
|
||||||
if (mhDCThrd == 0)
|
if (mhDCThrd == 0)
|
||||||
|
|
@ -4955,8 +4875,6 @@ void LLWindowWin32::LLWindowWin32Thread::run()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanupDX();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
|
void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
|
||||||
|
|
@ -5056,7 +4974,6 @@ void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
|
||||||
// very unsafe
|
// very unsafe
|
||||||
TerminateThread(pair.second.native_handle(), 0);
|
TerminateThread(pair.second.native_handle(), 0);
|
||||||
pair.second.detach();
|
pair.second.detach();
|
||||||
cleanupDX();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL;
|
LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL;
|
||||||
|
|
|
||||||
|
|
@ -618,6 +618,7 @@ set(viewer_SOURCE_FILES
|
||||||
llpathfindingobject.cpp
|
llpathfindingobject.cpp
|
||||||
llpathfindingobjectlist.cpp
|
llpathfindingobjectlist.cpp
|
||||||
llpathfindingpathtool.cpp
|
llpathfindingpathtool.cpp
|
||||||
|
llpbrterrainfeatures.cpp
|
||||||
llpersistentnotificationstorage.cpp
|
llpersistentnotificationstorage.cpp
|
||||||
llphysicsmotion.cpp
|
llphysicsmotion.cpp
|
||||||
llphysicsshapebuilderutil.cpp
|
llphysicsshapebuilderutil.cpp
|
||||||
|
|
@ -1406,6 +1407,7 @@ set(viewer_HEADER_FILES
|
||||||
llpathfindingobject.h
|
llpathfindingobject.h
|
||||||
llpathfindingobjectlist.h
|
llpathfindingobjectlist.h
|
||||||
llpathfindingpathtool.h
|
llpathfindingpathtool.h
|
||||||
|
llpbrterrainfeatures.h
|
||||||
llpersistentnotificationstorage.h
|
llpersistentnotificationstorage.h
|
||||||
llphysicsmotion.h
|
llphysicsmotion.h
|
||||||
llphysicsshapebuilderutil.h
|
llphysicsshapebuilderutil.h
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
7.1.8
|
7.1.9
|
||||||
|
|
|
||||||
|
|
@ -12816,6 +12816,17 @@ Change of this parameter will affect the layout of buttons in notification toast
|
||||||
<key>Value</key>
|
<key>Value</key>
|
||||||
<real>8.0</real>
|
<real>8.0</real>
|
||||||
</map>
|
</map>
|
||||||
|
<key>RenderTerrainPBRTransformsEnabled</key>
|
||||||
|
<map>
|
||||||
|
<key>Comment</key>
|
||||||
|
<string>EXPERIMENTAL: Enable PBR Terrain texture transforms.</string>
|
||||||
|
<key>Persist</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>Type</key>
|
||||||
|
<string>Boolean</string>
|
||||||
|
<key>Value</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</map>
|
||||||
<key>RenderTerrainPBRNormalsEnabled</key>
|
<key>RenderTerrainPBRNormalsEnabled</key>
|
||||||
<map>
|
<map>
|
||||||
<key>Comment</key>
|
<key>Comment</key>
|
||||||
|
|
@ -22832,7 +22843,7 @@ Change of this parameter will affect the layout of buttons in notification toast
|
||||||
<key>GLTFEnabled</key>
|
<key>GLTFEnabled</key>
|
||||||
<map>
|
<map>
|
||||||
<key>Comment</key>
|
<key>Comment</key>
|
||||||
<string>Enable GLTF support. Set by SimulatorFeatures</string>
|
<string>Enable GLTF support. Set to true by simulator if the simulator you are connected to supports GLTF Asset upload. WARNING: Manually setting this to true will enable buttons that can drain your L$ balance by implicitly uploading textures without asking.</string>
|
||||||
<key>Persist</key>
|
<key>Persist</key>
|
||||||
<integer>0</integer>
|
<integer>0</integer>
|
||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
|
|
|
||||||
|
|
@ -142,18 +142,9 @@ vec2 getScreenCoordinate(vec2 screenpos)
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 getNorm(vec2 screenpos)
|
vec4 getNorm(vec2 screenpos)
|
||||||
{
|
|
||||||
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 norm = texture(normalMap, screenpos.xy);
|
vec4 norm = texture(normalMap, screenpos.xy);
|
||||||
n = norm.xyz;
|
norm.xyz = normalize(norm.xyz);
|
||||||
envIntensity = texture(emissiveRect, screenpos.xy).r;
|
|
||||||
|
|
||||||
return norm;
|
return norm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -496,6 +487,43 @@ vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
|
||||||
return clamp(color, vec3(0), vec3(10));
|
return clamp(color, vec3(0), vec3(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3 pbrCalcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
|
||||||
|
float perceptualRoughness,
|
||||||
|
float metallic,
|
||||||
|
vec3 n, // normal
|
||||||
|
vec3 p, // pixel position
|
||||||
|
vec3 v, // view vector (negative normalized pixel position)
|
||||||
|
vec3 lp, // light position
|
||||||
|
vec3 ld, // light direction (for spotlights)
|
||||||
|
vec3 lightColor,
|
||||||
|
float lightSize, float falloff, float is_pointlight, float ambiance)
|
||||||
|
{
|
||||||
|
vec3 color = vec3(0,0,0);
|
||||||
|
|
||||||
|
vec3 lv = lp.xyz - p;
|
||||||
|
|
||||||
|
float lightDist = length(lv);
|
||||||
|
|
||||||
|
float dist = lightDist / lightSize;
|
||||||
|
if (dist <= 1.0)
|
||||||
|
{
|
||||||
|
lv /= lightDist;
|
||||||
|
|
||||||
|
float dist_atten = calcLegacyDistanceAttenuation(dist, falloff);
|
||||||
|
|
||||||
|
// spotlight coefficient.
|
||||||
|
float spot = max(dot(-ld, lv), is_pointlight);
|
||||||
|
// spot*spot => GL_SPOT_EXPONENT=2
|
||||||
|
float spot_atten = spot*spot;
|
||||||
|
|
||||||
|
vec3 intensity = spot_atten * dist_atten * lightColor * 3.0; //magic number to balance with legacy materials
|
||||||
|
|
||||||
|
color = intensity*pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, lv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor, inout vec3 specularColor)
|
void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor, inout vec3 specularColor)
|
||||||
{
|
{
|
||||||
vec3 f0 = vec3(0.04);
|
vec3 f0 = vec3(0.04);
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,6 @@ uniform vec4[2] texture_emissive_transform;
|
||||||
|
|
||||||
out vec3 vary_fragcoord;
|
out vec3 vary_fragcoord;
|
||||||
|
|
||||||
uniform float near_clip;
|
|
||||||
|
|
||||||
in vec3 position;
|
in vec3 position;
|
||||||
in vec4 diffuse_color;
|
in vec4 diffuse_color;
|
||||||
in vec3 normal;
|
in vec3 normal;
|
||||||
|
|
@ -88,7 +86,7 @@ void main()
|
||||||
#endif
|
#endif
|
||||||
gl_Position = vert;
|
gl_Position = vert;
|
||||||
|
|
||||||
vary_fragcoord.xyz = vert.xyz + vec3(0,0,near_clip);
|
vary_fragcoord.xyz = vert.xyz;
|
||||||
|
|
||||||
base_color_texcoord = texture_transform(texcoord0, texture_base_color_transform, texture_matrix0);
|
base_color_texcoord = texture_transform(texcoord0, texture_base_color_transform, texture_matrix0);
|
||||||
normal_texcoord = texture_transform(texcoord0, texture_normal_transform, texture_matrix0);
|
normal_texcoord = texture_transform(texcoord0, texture_normal_transform, texture_matrix0);
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ void main()
|
||||||
rm_factors[3] = vec2(roughnessFactors.w, metallicFactors.w);
|
rm_factors[3] = vec2(roughnessFactors.w, metallicFactors.w);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PBRMix mix = init_pbr_mix();
|
PBRMix pbr_mix = init_pbr_mix();
|
||||||
PBRMix mix2;
|
PBRMix mix2;
|
||||||
TerrainCoord terrain_texcoord;
|
TerrainCoord terrain_texcoord;
|
||||||
switch (tm.type & MIX_X)
|
switch (tm.type & MIX_X)
|
||||||
|
|
@ -233,7 +233,7 @@ void main()
|
||||||
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
||||||
mix2.vNt = mikktspace(mix2.vNt, vary_tangents[0]);
|
mix2.vNt = mikktspace(mix2.vNt, vary_tangents[0]);
|
||||||
#endif
|
#endif
|
||||||
mix = mix_pbr(mix, mix2, tm.weight.x);
|
pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.x);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -275,7 +275,7 @@ void main()
|
||||||
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
||||||
mix2.vNt = mikktspace(mix2.vNt, vary_tangents[1]);
|
mix2.vNt = mikktspace(mix2.vNt, vary_tangents[1]);
|
||||||
#endif
|
#endif
|
||||||
mix = mix_pbr(mix, mix2, tm.weight.y);
|
pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.y);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -317,7 +317,7 @@ void main()
|
||||||
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
||||||
mix2.vNt = mikktspace(mix2.vNt, vary_tangents[2]);
|
mix2.vNt = mikktspace(mix2.vNt, vary_tangents[2]);
|
||||||
#endif
|
#endif
|
||||||
mix = mix_pbr(mix, mix2, tm.weight.z);
|
pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.z);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -359,21 +359,21 @@ void main()
|
||||||
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
||||||
mix2.vNt = mikktspace(mix2.vNt, vary_tangents[3]);
|
mix2.vNt = mikktspace(mix2.vNt, vary_tangents[3]);
|
||||||
#endif
|
#endif
|
||||||
mix = mix_pbr(mix, mix2, tm.weight.w);
|
pbr_mix = mix_pbr(pbr_mix, mix2, tm.weight.w);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
float minimum_alpha = terrain_mix(tm, minimum_alphas);
|
float minimum_alpha = terrain_mix(tm, minimum_alphas);
|
||||||
if (mix.col.a < minimum_alpha)
|
if (pbr_mix.col.a < minimum_alpha)
|
||||||
{
|
{
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
float base_color_factor_alpha = terrain_mix(tm, vec4(baseColorFactors[0].z, baseColorFactors[1].z, baseColorFactors[2].z, baseColorFactors[3].z));
|
float base_color_factor_alpha = terrain_mix(tm, vec4(baseColorFactors[0].z, baseColorFactors[1].z, baseColorFactors[2].z, baseColorFactors[3].z));
|
||||||
|
|
||||||
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_NORMAL)
|
||||||
vec3 tnorm = normalize(mix.vNt);
|
vec3 tnorm = normalize(pbr_mix.vNt);
|
||||||
#else
|
#else
|
||||||
vec3 tnorm = vary_normal;
|
vec3 tnorm = vary_normal;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -381,21 +381,21 @@ void main()
|
||||||
|
|
||||||
|
|
||||||
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_EMISSIVE)
|
||||||
#define emissive mix.emissive
|
#define mix_emissive pbr_mix.emissive
|
||||||
#else
|
#else
|
||||||
#define emissive vec3(0)
|
#define mix_emissive vec3(0)
|
||||||
#endif
|
#endif
|
||||||
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
|
#if (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_OCCLUSION)
|
||||||
#define orm mix.orm
|
#define mix_orm pbr_mix.orm
|
||||||
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
#elif (TERRAIN_PBR_DETAIL >= TERRAIN_PBR_DETAIL_METALLIC_ROUGHNESS)
|
||||||
#define orm vec3(1.0, mix.rm)
|
#define mix_orm vec3(1.0, pbr_mix.rm)
|
||||||
#else
|
#else
|
||||||
// Matte plastic potato terrain
|
// Matte plastic potato terrain
|
||||||
#define orm vec3(1.0, 1.0, 0.0)
|
#define mix_orm vec3(1.0, 1.0, 0.0)
|
||||||
#endif
|
#endif
|
||||||
frag_data[0] = max(vec4(mix.col.xyz, 0.0), vec4(0)); // Diffuse
|
frag_data[0] = max(vec4(pbr_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[1] = max(vec4(mix_orm.rgb, base_color_factor_alpha), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal.
|
||||||
frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); // normal, flags
|
frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); // normal, flags
|
||||||
frag_data[3] = max(vec4(emissive,0), vec4(0)); // PBR sRGB Emissive
|
frag_data[3] = max(vec4(mix_emissive,0), vec4(0)); // PBR sRGB Emissive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ void main()
|
||||||
|
|
||||||
outColor.a = 0.0; // yes, downstream atmospherics
|
outColor.a = 0.0; // yes, downstream atmospherics
|
||||||
|
|
||||||
frag_data[0] = outColor;
|
frag_data[0] = max(outColor, vec4(0));
|
||||||
frag_data[1] = vec4(0.0,0.0,0.0,-1.0);
|
frag_data[1] = vec4(0.0,0.0,0.0,-1.0);
|
||||||
vec3 nvn = normalize(vary_normal);
|
vec3 nvn = normalize(vary_normal);
|
||||||
frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS);
|
frag_data[2] = vec4(nvn.xyz, GBUFFER_FLAG_HAS_ATMOS);
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,9 @@ vec2 texgen_object(vec4 vpos, mat4 mat, vec4 tp0, vec4 tp1)
|
||||||
|
|
||||||
tcoord.x = dot(vpos, tp0);
|
tcoord.x = dot(vpos, tp0);
|
||||||
tcoord.y = dot(vpos, tp1);
|
tcoord.y = dot(vpos, tp1);
|
||||||
|
tcoord.z = 0;
|
||||||
|
tcoord.w = 1;
|
||||||
|
|
||||||
tcoord = mat * tcoord;
|
tcoord = mat * tcoord;
|
||||||
|
|
||||||
return tcoord.xy;
|
return tcoord.xy;
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@
|
||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uniform sampler2D exposureMap;
|
|
||||||
|
|
||||||
vec3 srgb_to_linear(vec3 cs)
|
vec3 srgb_to_linear(vec3 cs)
|
||||||
{
|
{
|
||||||
vec3 low_range = cs / vec3(12.92);
|
vec3 low_range = cs / vec3(12.92);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,300 @@
|
||||||
|
/**
|
||||||
|
* @file pbrmetallicroughnessF.glsl
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2022, 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$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*[EXTRA_CODE_HERE]*/
|
||||||
|
|
||||||
|
|
||||||
|
// GLTF pbrMetallicRoughness implementation
|
||||||
|
|
||||||
|
|
||||||
|
// ==================================
|
||||||
|
// needed by all variants
|
||||||
|
// ==================================
|
||||||
|
uniform sampler2D diffuseMap; //always in sRGB space
|
||||||
|
uniform sampler2D emissiveMap;
|
||||||
|
uniform vec3 emissiveColor;
|
||||||
|
in vec3 vary_position;
|
||||||
|
in vec4 vertex_color;
|
||||||
|
in vec2 base_color_texcoord;
|
||||||
|
in vec2 emissive_texcoord;
|
||||||
|
uniform float minimum_alpha;
|
||||||
|
|
||||||
|
void mirrorClip(vec3 pos);
|
||||||
|
vec3 linear_to_srgb(vec3 c);
|
||||||
|
vec3 srgb_to_linear(vec3 c);
|
||||||
|
// ==================================
|
||||||
|
|
||||||
|
|
||||||
|
// ==================================
|
||||||
|
// needed by all lit variants
|
||||||
|
// ==================================
|
||||||
|
#ifndef UNLIT
|
||||||
|
uniform sampler2D normalMap;
|
||||||
|
uniform sampler2D metallicRoughnessMap;
|
||||||
|
uniform sampler2D occlusionMap;
|
||||||
|
uniform float metallicFactor;
|
||||||
|
uniform float roughnessFactor;
|
||||||
|
in vec3 vary_normal;
|
||||||
|
in vec3 vary_tangent;
|
||||||
|
flat in float vary_sign;
|
||||||
|
in vec2 normal_texcoord;
|
||||||
|
in vec2 metallic_roughness_texcoord;
|
||||||
|
#endif
|
||||||
|
// ==================================
|
||||||
|
|
||||||
|
|
||||||
|
// ==================================
|
||||||
|
// needed by all alpha variants
|
||||||
|
// ==================================
|
||||||
|
#ifdef ALPHA_BLEND
|
||||||
|
in vec3 vary_fragcoord;
|
||||||
|
uniform vec4 clipPlane;
|
||||||
|
uniform float clipSign;
|
||||||
|
void waterClip(vec3 pos);
|
||||||
|
void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
|
||||||
|
vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color);
|
||||||
|
#endif
|
||||||
|
// ==================================
|
||||||
|
|
||||||
|
|
||||||
|
// ==================================
|
||||||
|
// needed by lit alpha
|
||||||
|
// ==================================
|
||||||
|
#if defined(ALPHA_BLEND) && !defined(UNLIT)
|
||||||
|
|
||||||
|
#ifdef HAS_SUN_SHADOW
|
||||||
|
uniform sampler2D lightMap;
|
||||||
|
uniform vec2 screen_res;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Lights
|
||||||
|
// See: LLRender::syncLightState()
|
||||||
|
uniform vec4 light_position[8];
|
||||||
|
uniform vec3 light_direction[8]; // spot direction
|
||||||
|
uniform vec4 light_attenuation[8]; // linear, quadratic, is omni, unused, See: LLPipeline::setupHWLights() and syncLightState()
|
||||||
|
uniform vec3 light_diffuse[8];
|
||||||
|
uniform vec2 light_deferred_attenuation[8]; // light size and falloff
|
||||||
|
|
||||||
|
uniform int sun_up_factor;
|
||||||
|
uniform vec3 sun_dir;
|
||||||
|
uniform vec3 moon_dir;
|
||||||
|
|
||||||
|
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);
|
||||||
|
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
|
||||||
|
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
|
||||||
|
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear);
|
||||||
|
|
||||||
|
void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor, inout vec3 specularColor);
|
||||||
|
|
||||||
|
vec3 pbrBaseLight(vec3 diffuseColor,
|
||||||
|
vec3 specularColor,
|
||||||
|
float metallic,
|
||||||
|
vec3 pos,
|
||||||
|
vec3 norm,
|
||||||
|
float perceptualRoughness,
|
||||||
|
vec3 light_dir,
|
||||||
|
vec3 sunlit,
|
||||||
|
float scol,
|
||||||
|
vec3 radiance,
|
||||||
|
vec3 irradiance,
|
||||||
|
vec3 colorEmissive,
|
||||||
|
float ao,
|
||||||
|
vec3 additive,
|
||||||
|
vec3 atten);
|
||||||
|
|
||||||
|
vec3 pbrCalcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
|
||||||
|
float perceptualRoughness,
|
||||||
|
float metallic,
|
||||||
|
vec3 n, // normal
|
||||||
|
vec3 p, // pixel position
|
||||||
|
vec3 v, // view vector (negative normalized pixel position)
|
||||||
|
vec3 lp, // light position
|
||||||
|
vec3 ld, // light direction (for spotlights)
|
||||||
|
vec3 lightColor,
|
||||||
|
float lightSize, float falloff, float is_pointlight, float ambiance);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
// ==================================
|
||||||
|
|
||||||
|
|
||||||
|
// ==================================
|
||||||
|
// output definition
|
||||||
|
// ==================================
|
||||||
|
#if defined(ALPHA_BLEND) || defined(UNLIT)
|
||||||
|
out vec4 frag_color;
|
||||||
|
#else
|
||||||
|
out vec4 frag_data[4];
|
||||||
|
#endif
|
||||||
|
// ==================================
|
||||||
|
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
|
||||||
|
// ==================================
|
||||||
|
// all variants
|
||||||
|
// mirror clip
|
||||||
|
// base color
|
||||||
|
// masking
|
||||||
|
// emissive
|
||||||
|
// ==================================
|
||||||
|
vec3 pos = vary_position;
|
||||||
|
mirrorClip(pos);
|
||||||
|
|
||||||
|
vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba;
|
||||||
|
basecolor.rgb = srgb_to_linear(basecolor.rgb);
|
||||||
|
basecolor *= vertex_color;
|
||||||
|
|
||||||
|
if (basecolor.a < minimum_alpha)
|
||||||
|
{
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 emissive = emissiveColor;
|
||||||
|
emissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb);
|
||||||
|
// ==================================
|
||||||
|
|
||||||
|
// ==================================
|
||||||
|
// all lit variants
|
||||||
|
// prepare norm
|
||||||
|
// prepare orm
|
||||||
|
// ==================================
|
||||||
|
#ifndef UNLIT
|
||||||
|
// from mikktspace.com
|
||||||
|
vec3 vNt = texture(normalMap, normal_texcoord.xy).xyz*2.0-1.0;
|
||||||
|
float sign = vary_sign;
|
||||||
|
vec3 vN = vary_normal;
|
||||||
|
vec3 vT = vary_tangent.xyz;
|
||||||
|
|
||||||
|
vec3 vB = sign * cross(vN, vT);
|
||||||
|
vec3 norm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
|
||||||
|
norm *= gl_FrontFacing ? 1.0 : -1.0;
|
||||||
|
|
||||||
|
// RGB = Occlusion, Roughness, Metal
|
||||||
|
// default values, see LLViewerTexture::sDefaultPBRORMImagep
|
||||||
|
// occlusion 1.0
|
||||||
|
// roughness 0.0
|
||||||
|
// metal 0.0
|
||||||
|
vec3 orm = texture(metallicRoughnessMap, metallic_roughness_texcoord.xy).rgb;
|
||||||
|
orm.r = texture(occlusionMap, metallic_roughness_texcoord.xy).r;
|
||||||
|
orm.g *= roughnessFactor;
|
||||||
|
orm.b *= metallicFactor;
|
||||||
|
#endif
|
||||||
|
// ==================================
|
||||||
|
|
||||||
|
// ==================================
|
||||||
|
// non alpha output
|
||||||
|
// ==================================
|
||||||
|
#ifndef ALPHA_BLEND
|
||||||
|
#ifdef UNLIT
|
||||||
|
vec4 color = basecolor;
|
||||||
|
color.rgb += emissive.rgb;
|
||||||
|
frag_color = color;
|
||||||
|
#else
|
||||||
|
frag_data[0] = max(vec4(basecolor.rgb, 0.0), vec4(0));
|
||||||
|
frag_data[1] = max(vec4(orm.rgb,0.0), vec4(0));
|
||||||
|
frag_data[2] = vec4(norm, GBUFFER_FLAG_HAS_PBR);
|
||||||
|
frag_data[3] = max(vec4(emissive,0), vec4(0));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// ==================================
|
||||||
|
// alpha implementation
|
||||||
|
// ==================================
|
||||||
|
#ifdef ALPHA_BLEND
|
||||||
|
|
||||||
|
float scol = 1.0;
|
||||||
|
vec3 sunlit;
|
||||||
|
vec3 amblit;
|
||||||
|
vec3 additive;
|
||||||
|
vec3 atten;
|
||||||
|
|
||||||
|
vec3 light_dir;
|
||||||
|
|
||||||
|
#ifdef UNLIT
|
||||||
|
light_dir = vec3(0,0,1);
|
||||||
|
vec3 norm = vec3(0,0,1);
|
||||||
|
#else
|
||||||
|
light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
calcAtmosphericVarsLinear(pos.xyz, norm, light_dir, sunlit, amblit, additive, atten);
|
||||||
|
|
||||||
|
#ifndef UNLIT
|
||||||
|
vec3 sunlit_linear = srgb_to_linear(sunlit);
|
||||||
|
|
||||||
|
vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
|
||||||
|
|
||||||
|
#ifdef HAS_SUN_SHADOW
|
||||||
|
scol = sampleDirectionalShadow(pos.xyz, norm.xyz, frag);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float perceptualRoughness = orm.g * roughnessFactor;
|
||||||
|
float metallic = orm.b * metallicFactor;
|
||||||
|
|
||||||
|
// PBR IBL
|
||||||
|
float gloss = 1.0 - perceptualRoughness;
|
||||||
|
vec3 irradiance = vec3(0);
|
||||||
|
vec3 radiance = vec3(0);
|
||||||
|
sampleReflectionProbes(irradiance, radiance, vary_position.xy*0.5+0.5, pos.xyz, norm.xyz, gloss, true, amblit);
|
||||||
|
|
||||||
|
vec3 diffuseColor;
|
||||||
|
vec3 specularColor;
|
||||||
|
calcDiffuseSpecular(basecolor.rgb, metallic, diffuseColor, specularColor);
|
||||||
|
|
||||||
|
vec3 v = -normalize(pos.xyz);
|
||||||
|
|
||||||
|
vec3 color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, emissive, orm.r, additive, atten);
|
||||||
|
|
||||||
|
vec3 light = vec3(0);
|
||||||
|
|
||||||
|
// Punctual lights
|
||||||
|
#define LIGHT_LOOP(i) light += pbrCalcPointLightOrSpotLight(diffuseColor, specularColor, perceptualRoughness, metallic, norm.xyz, pos.xyz, v, light_position[i].xyz, light_direction[i].xyz, light_diffuse[i].rgb, light_deferred_attenuation[i].x, light_deferred_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w);
|
||||||
|
|
||||||
|
LIGHT_LOOP(1)
|
||||||
|
LIGHT_LOOP(2)
|
||||||
|
LIGHT_LOOP(3)
|
||||||
|
LIGHT_LOOP(4)
|
||||||
|
LIGHT_LOOP(5)
|
||||||
|
LIGHT_LOOP(6)
|
||||||
|
LIGHT_LOOP(7)
|
||||||
|
|
||||||
|
color.rgb += light.rgb;
|
||||||
|
|
||||||
|
color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb;
|
||||||
|
|
||||||
|
float a = basecolor.a*vertex_color.a;
|
||||||
|
|
||||||
|
frag_color = max(vec4(color.rgb,a), vec4(0));
|
||||||
|
#else // UNLIT
|
||||||
|
vec4 color = basecolor;
|
||||||
|
color.rgb += emissive.rgb;
|
||||||
|
frag_color = color;
|
||||||
|
#endif
|
||||||
|
#endif // ALPHA_BLEND
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,171 @@
|
||||||
|
/**
|
||||||
|
* @file pbrmetallicroughnessV.glsl
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
|
||||||
|
* Second Life Viewer Source Code
|
||||||
|
* Copyright (C) 2022, 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$
|
||||||
|
*/
|
||||||
|
|
||||||
|
// GLTF pbrMetallicRoughness implementation
|
||||||
|
|
||||||
|
uniform mat4 modelview_matrix;
|
||||||
|
|
||||||
|
#ifdef HAS_SKIN
|
||||||
|
uniform mat4 projection_matrix;
|
||||||
|
#else
|
||||||
|
uniform mat3 normal_matrix;
|
||||||
|
uniform mat4 modelview_projection_matrix;
|
||||||
|
#endif
|
||||||
|
uniform mat4 texture_matrix0;
|
||||||
|
|
||||||
|
uniform vec4[2] texture_base_color_transform;
|
||||||
|
uniform vec4[2] texture_normal_transform;
|
||||||
|
uniform vec4[2] texture_metallic_roughness_transform;
|
||||||
|
uniform vec4[2] texture_emissive_transform;
|
||||||
|
|
||||||
|
in vec3 position;
|
||||||
|
in vec4 diffuse_color;
|
||||||
|
in vec2 texcoord0;
|
||||||
|
out vec2 base_color_texcoord;
|
||||||
|
out vec2 emissive_texcoord;
|
||||||
|
out vec4 vertex_color;
|
||||||
|
out vec3 vary_position;
|
||||||
|
|
||||||
|
#ifndef UNLIT
|
||||||
|
in vec3 normal;
|
||||||
|
in vec4 tangent;
|
||||||
|
out vec2 normal_texcoord;
|
||||||
|
out vec2 metallic_roughness_texcoord;
|
||||||
|
out vec3 vary_tangent;
|
||||||
|
flat out float vary_sign;
|
||||||
|
out vec3 vary_normal;
|
||||||
|
vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef ALPHA_BLEND
|
||||||
|
out vec3 vary_fragcoord;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_SKIN
|
||||||
|
in uvec4 joint;
|
||||||
|
in vec4 weight4;
|
||||||
|
|
||||||
|
layout (std140) uniform GLTFJoints
|
||||||
|
{
|
||||||
|
// list of OBBs for user override probes
|
||||||
|
mat3x4 gltf_joints[MAX_JOINTS_PER_GLTF_OBJECT];
|
||||||
|
};
|
||||||
|
|
||||||
|
mat4 getGLTFSkinTransform()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
vec4 w = weight4;
|
||||||
|
|
||||||
|
uint i1 = joint.x;
|
||||||
|
uint i2 = joint.y;
|
||||||
|
uint i3 = joint.z;
|
||||||
|
uint i4 = joint.w;
|
||||||
|
|
||||||
|
mat3 mat = mat3(gltf_joints[i1])*w.x;
|
||||||
|
mat += mat3(gltf_joints[i2])*w.y;
|
||||||
|
mat += mat3(gltf_joints[i3])*w.z;
|
||||||
|
mat += mat3(gltf_joints[i4])*w.w;
|
||||||
|
|
||||||
|
vec3 trans = vec3(gltf_joints[i1][0].w,gltf_joints[i1][1].w,gltf_joints[i1][2].w)*w.x;
|
||||||
|
trans += vec3(gltf_joints[i2][0].w,gltf_joints[i2][1].w,gltf_joints[i2][2].w)*w.y;
|
||||||
|
trans += vec3(gltf_joints[i3][0].w,gltf_joints[i3][1].w,gltf_joints[i3][2].w)*w.z;
|
||||||
|
trans += vec3(gltf_joints[i4][0].w,gltf_joints[i4][1].w,gltf_joints[i4][2].w)*w.w;
|
||||||
|
|
||||||
|
mat4 ret;
|
||||||
|
|
||||||
|
ret[0] = vec4(mat[0], 0);
|
||||||
|
ret[1] = vec4(mat[1], 0);
|
||||||
|
ret[2] = vec4(mat[2], 0);
|
||||||
|
ret[3] = vec4(trans, 1.0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
#ifdef IS_AMD_CARD
|
||||||
|
// If it's AMD make sure the GLSL compiler sees the arrays referenced once by static index. Otherwise it seems to optimise the storage awawy which leads to unfun crashes and artifacts.
|
||||||
|
mat3x4 dummy1 = gltf_joints[0];
|
||||||
|
mat3x4 dummy2 = gltf_joints[MAX_JOINTS_PER_GLTF_OBJECT-1];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
#ifdef HAS_SKIN
|
||||||
|
mat4 mat = getGLTFSkinTransform();
|
||||||
|
|
||||||
|
mat = modelview_matrix * mat;
|
||||||
|
|
||||||
|
vec3 pos = (mat*vec4(position.xyz,1.0)).xyz;
|
||||||
|
vary_position = pos;
|
||||||
|
|
||||||
|
vec4 vert = projection_matrix * vec4(pos, 1.0);
|
||||||
|
gl_Position = vert;
|
||||||
|
|
||||||
|
#else
|
||||||
|
vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz;
|
||||||
|
//transform vertex
|
||||||
|
vec4 vert = modelview_projection_matrix * vec4(position.xyz, 1.0);
|
||||||
|
gl_Position = vert;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
base_color_texcoord = texture_transform(texcoord0, texture_base_color_transform, texture_matrix0);
|
||||||
|
emissive_texcoord = texture_transform(texcoord0, texture_emissive_transform, texture_matrix0);
|
||||||
|
|
||||||
|
#ifndef UNLIT
|
||||||
|
normal_texcoord = texture_transform(texcoord0, texture_normal_transform, texture_matrix0);
|
||||||
|
metallic_roughness_texcoord = texture_transform(texcoord0, texture_metallic_roughness_transform, texture_matrix0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef UNLIT
|
||||||
|
#ifdef HAS_SKIN
|
||||||
|
vec3 n = (mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz;
|
||||||
|
vec3 t = (mat*vec4(tangent.xyz+position.xyz,1.0)).xyz-pos.xyz;
|
||||||
|
#else //HAS_SKIN
|
||||||
|
vec3 n = normal_matrix * normal;
|
||||||
|
vec3 t = normal_matrix * tangent.xyz;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
n = normalize(n);
|
||||||
|
vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0));
|
||||||
|
vary_sign = tangent.w;
|
||||||
|
vary_normal = n;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vertex_color = diffuse_color;
|
||||||
|
#ifdef ALPHA_BLEND
|
||||||
|
vary_fragcoord = vert.xyz;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
/**
|
/**
|
||||||
* @file class1\deferred\pbralphaF.glsl
|
* @file class1\deferred\pbralphaF.glsl
|
||||||
*
|
*
|
||||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||||
* Second Life Viewer Source Code
|
* Second Life Viewer Source Code
|
||||||
* Copyright (C) 2022, Linden Research, Inc.
|
* Copyright (C) 2022, Linden Research, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation;
|
* License as published by the Free Software Foundation;
|
||||||
* version 2.1 of the License only.
|
* version 2.1 of the License only.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
*
|
||||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
@ -87,7 +87,7 @@ vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color);
|
||||||
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);
|
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);
|
float calcLegacyDistanceAttenuation(float distance, float falloff);
|
||||||
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
|
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
|
||||||
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
|
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
|
||||||
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear);
|
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear);
|
||||||
|
|
||||||
void mirrorClip(vec3 pos);
|
void mirrorClip(vec3 pos);
|
||||||
|
|
@ -111,15 +111,15 @@ vec3 pbrBaseLight(vec3 diffuseColor,
|
||||||
vec3 additive,
|
vec3 additive,
|
||||||
vec3 atten);
|
vec3 atten);
|
||||||
|
|
||||||
vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
|
vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
|
||||||
float perceptualRoughness,
|
float perceptualRoughness,
|
||||||
float metallic,
|
float metallic,
|
||||||
vec3 n, // normal
|
vec3 n, // normal
|
||||||
vec3 v, // surface point to camera
|
vec3 v, // surface point to camera
|
||||||
vec3 l); //surface point to light
|
vec3 l); //surface point to light
|
||||||
|
|
||||||
vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
|
vec3 pbrCalcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
|
||||||
float perceptualRoughness,
|
float perceptualRoughness,
|
||||||
float metallic,
|
float metallic,
|
||||||
vec3 n, // normal
|
vec3 n, // normal
|
||||||
vec3 p, // pixel position
|
vec3 p, // pixel position
|
||||||
|
|
@ -127,33 +127,7 @@ vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
|
||||||
vec3 lp, // light position
|
vec3 lp, // light position
|
||||||
vec3 ld, // light direction (for spotlights)
|
vec3 ld, // light direction (for spotlights)
|
||||||
vec3 lightColor,
|
vec3 lightColor,
|
||||||
float lightSize, float falloff, float is_pointlight, float ambiance)
|
float lightSize, float falloff, float is_pointlight, float ambiance);
|
||||||
{
|
|
||||||
vec3 color = vec3(0,0,0);
|
|
||||||
|
|
||||||
vec3 lv = lp.xyz - p;
|
|
||||||
|
|
||||||
float lightDist = length(lv);
|
|
||||||
|
|
||||||
float dist = lightDist / lightSize;
|
|
||||||
if (dist <= 1.0)
|
|
||||||
{
|
|
||||||
lv /= lightDist;
|
|
||||||
|
|
||||||
float dist_atten = calcLegacyDistanceAttenuation(dist, falloff);
|
|
||||||
|
|
||||||
// spotlight coefficient.
|
|
||||||
float spot = max(dot(-ld, lv), is_pointlight);
|
|
||||||
// spot*spot => GL_SPOT_EXPONENT=2
|
|
||||||
float spot_atten = spot*spot;
|
|
||||||
|
|
||||||
vec3 intensity = spot_atten * dist_atten * lightColor * 3.0; //magic number to balance with legacy materials
|
|
||||||
|
|
||||||
color = intensity*pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, lv);
|
|
||||||
}
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
|
@ -181,7 +155,7 @@ void main()
|
||||||
float sign = vary_sign;
|
float sign = vary_sign;
|
||||||
vec3 vN = vary_normal;
|
vec3 vN = vary_normal;
|
||||||
vec3 vT = vary_tangent.xyz;
|
vec3 vT = vary_tangent.xyz;
|
||||||
|
|
||||||
vec3 vB = sign * cross(vN, vT);
|
vec3 vB = sign * cross(vN, vT);
|
||||||
vec3 norm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
|
vec3 norm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
|
||||||
|
|
||||||
|
|
@ -218,7 +192,7 @@ void main()
|
||||||
vec3 irradiance = vec3(0);
|
vec3 irradiance = vec3(0);
|
||||||
vec3 radiance = vec3(0);
|
vec3 radiance = vec3(0);
|
||||||
sampleReflectionProbes(irradiance, radiance, vary_position.xy*0.5+0.5, pos.xyz, norm.xyz, gloss, true, amblit);
|
sampleReflectionProbes(irradiance, radiance, vary_position.xy*0.5+0.5, pos.xyz, norm.xyz, gloss, true, amblit);
|
||||||
|
|
||||||
vec3 diffuseColor;
|
vec3 diffuseColor;
|
||||||
vec3 specularColor;
|
vec3 specularColor;
|
||||||
calcDiffuseSpecular(col.rgb, metallic, diffuseColor, specularColor);
|
calcDiffuseSpecular(col.rgb, metallic, diffuseColor, specularColor);
|
||||||
|
|
@ -230,7 +204,7 @@ void main()
|
||||||
vec3 light = vec3(0);
|
vec3 light = vec3(0);
|
||||||
|
|
||||||
// Punctual lights
|
// Punctual lights
|
||||||
#define LIGHT_LOOP(i) light += calcPointLightOrSpotLight(diffuseColor, specularColor, perceptualRoughness, metallic, norm.xyz, pos.xyz, v, light_position[i].xyz, light_direction[i].xyz, light_diffuse[i].rgb, light_deferred_attenuation[i].x, light_deferred_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w);
|
#define LIGHT_LOOP(i) light += pbrCalcPointLightOrSpotLight(diffuseColor, specularColor, perceptualRoughness, metallic, norm.xyz, pos.xyz, v, light_position[i].xyz, light_direction[i].xyz, light_diffuse[i].rgb, light_deferred_attenuation[i].x, light_deferred_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w);
|
||||||
|
|
||||||
LIGHT_LOOP(1)
|
LIGHT_LOOP(1)
|
||||||
LIGHT_LOOP(2)
|
LIGHT_LOOP(2)
|
||||||
|
|
@ -245,7 +219,7 @@ void main()
|
||||||
color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb;
|
color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb;
|
||||||
|
|
||||||
float a = basecolor.a*vertex_color.a;
|
float a = basecolor.a*vertex_color.a;
|
||||||
|
|
||||||
frag_color = max(vec4(color.rgb,a), vec4(0));
|
frag_color = max(vec4(color.rgb,a), vec4(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -295,7 +269,7 @@ void main()
|
||||||
// emissiveMap here is a vanilla RGB texture encoded as sRGB, manually convert to linear
|
// emissiveMap here is a vanilla RGB texture encoded as sRGB, manually convert to linear
|
||||||
colorEmissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb);
|
colorEmissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb);
|
||||||
|
|
||||||
|
|
||||||
float a = basecolor.a*vertex_color.a;
|
float a = basecolor.a*vertex_color.a;
|
||||||
color += colorEmissive;
|
color += colorEmissive;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,6 @@ uniform float is_mirror;
|
||||||
|
|
||||||
uniform vec3 sun_dir;
|
uniform vec3 sun_dir;
|
||||||
uniform vec3 moon_dir;
|
uniform vec3 moon_dir;
|
||||||
in vec2 vary_fragcoord;
|
|
||||||
|
|
||||||
uniform mat4 proj_mat;
|
uniform mat4 proj_mat;
|
||||||
uniform mat4 inv_proj;
|
uniform mat4 inv_proj;
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ bool FSExportPermsCheck::canExportNode(LLSelectNode* node, bool dae)
|
||||||
{
|
{
|
||||||
case EXPORT_ALLOWED:
|
case EXPORT_ALLOWED:
|
||||||
{
|
{
|
||||||
exportable = node->mPermissions->allowExportBy(gAgent.getID());
|
exportable = node->mPermissions->allowOpenSimExportBy(gAgentID);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/// TODO: Once enough grids adopt a version supporting exports, get consensus
|
/// TODO: Once enough grids adopt a version supporting exports, get consensus
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
# Linden Lab GLTF Implementation
|
# Linden Lab GLTF Implementation
|
||||||
|
|
||||||
Currently in prototype stage. Much functionality is missing (blend shapes,
|
Currently in prototype stage. Much functionality is missing (blend shapes,
|
||||||
multiple texture coordinates, etc).
|
multiple texture coordinates, etc).
|
||||||
|
|
||||||
GLTF Specification can be found here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html.
|
GLTF Specification can be found here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html.
|
||||||
If this implementation disagrees with the GLTF Specification, the specification is correct.
|
If this implementation disagrees with the GLTF Specification, the specification is correct.
|
||||||
|
|
||||||
Class structure and naming should match the GLTF Specification as closely as possible while
|
Class structure and naming should match the GLTF Specification as closely as possible while
|
||||||
conforming to the LL coding standards. All code in headers should be contained in the
|
conforming to the LL coding standards. All code in headers should be contained in the
|
||||||
LL::GLTF namespace.
|
LL::GLTF namespace.
|
||||||
|
|
||||||
The implementation serves both the client and the server.
|
The implementation serves both the client and the server.
|
||||||
|
|
@ -18,7 +18,7 @@ The implementation serves both the client and the server.
|
||||||
- The implementation MUST use the same indexing scheme as the GLTF specification. Do not store pointers where the
|
- The implementation MUST use the same indexing scheme as the GLTF specification. Do not store pointers where the
|
||||||
- GLTF specification stores indices, store indices.
|
- GLTF specification stores indices, store indices.
|
||||||
- Limit dependencies on llcommon as much as possible. Prefer std::, boost::, and (soon) glm:: over LL facsimiles.
|
- Limit dependencies on llcommon as much as possible. Prefer std::, boost::, and (soon) glm:: over LL facsimiles.
|
||||||
- Usage of LLSD is forbidden in the LL::GLTF namespace.
|
- Usage of LLSD is forbidden in the LL::GLTF namespace.
|
||||||
- Use "using namespace" liberally in .cpp files, but never in .h files.
|
- Use "using namespace" liberally in .cpp files, but never in .h files.
|
||||||
- "using Foo = Bar" is permissible in .h files within the LL::GLTF namespace.
|
- "using Foo = Bar" is permissible in .h files within the LL::GLTF namespace.
|
||||||
|
|
||||||
|
|
@ -69,14 +69,14 @@ Parameters to "write" and "copy" MUST be ordered "src" before "dst"
|
||||||
so the code reads as "write src to dst" and "copy src to dst".
|
so the code reads as "write src to dst" and "copy src to dst".
|
||||||
|
|
||||||
When reading string constants from GLTF json (i.e. "OPAQUE", "TRIANGLES"), these
|
When reading string constants from GLTF json (i.e. "OPAQUE", "TRIANGLES"), these
|
||||||
strings should be converted to enums inside operator=. It is permissible to
|
strings should be converted to enums inside operator=. It is permissible to
|
||||||
store the original strings during prototyping to aid in development, but eventually
|
store the original strings during prototyping to aid in development, but eventually
|
||||||
we'll purge these strings from the implementation. However, implementations MUST
|
we'll purge these strings from the implementation. However, implementations MUST
|
||||||
preserve any and all "name" members.
|
preserve any and all "name" members.
|
||||||
|
|
||||||
"write" and "copy" implementations MUST be stored in buffer_util.h.
|
"write" and "copy" implementations MUST be stored in buffer_util.h.
|
||||||
As implementers encounter new data types, you'll see compiler errors
|
As implementers encounter new data types, you'll see compiler errors
|
||||||
pointing at templates in buffer_util.h. See vec3 as a known good
|
pointing at templates in buffer_util.h. See vec3 as a known good
|
||||||
example of how to add support for a new type (there are bad examples, so beware):
|
example of how to add support for a new type (there are bad examples, so beware):
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -120,29 +120,29 @@ inline bool write(const vec3& src, Value& dst)
|
||||||
|
|
||||||
Speed is important, but so is safety. In writers, try to avoid redundant copies
|
Speed is important, but so is safety. In writers, try to avoid redundant copies
|
||||||
(prefer resize over push_back, convert dst to an empty array and fill it, don't
|
(prefer resize over push_back, convert dst to an empty array and fill it, don't
|
||||||
make an array on the stack and copy it into dst).
|
make an array on the stack and copy it into dst).
|
||||||
|
|
||||||
boost::json WILL throw exceptions if you call as_foo() on a mismatched type but
|
boost::json WILL throw exceptions if you call as_foo() on a mismatched type but
|
||||||
WILL NOT throw exceptions on get_foo with a mismatched type. ALWAYS check is_foo
|
WILL NOT throw exceptions on get_foo with a mismatched type. ALWAYS check is_foo
|
||||||
before calling as_foo or get_foo. DO NOT add exception handlers. If boost throws
|
before calling as_foo or get_foo. DO NOT add exception handlers. If boost throws
|
||||||
an exception in serialization, the fix is to add type checks. If we see a large
|
an exception in serialization, the fix is to add type checks. If we see a large
|
||||||
number of crash reports from boost::json exceptions, each of those reports
|
number of crash reports from boost::json exceptions, each of those reports
|
||||||
indicates a place where we're missing "is_foo" checks. They are gold. Do not
|
indicates a place where we're missing "is_foo" checks. They are gold. Do not
|
||||||
bury them with an exception handler.
|
bury them with an exception handler.
|
||||||
|
|
||||||
DO NOT rely on existing type conversion tools in the LL codebase -- LL data models
|
DO NOT rely on existing type conversion tools in the LL codebase -- LL data models
|
||||||
conflict with the GLTF specification so we MUST provide conversions independent of
|
conflict with the GLTF specification so we MUST provide conversions independent of
|
||||||
our existing implementations.
|
our existing implementations.
|
||||||
|
|
||||||
### JSON Serialization ###
|
### JSON Serialization ###
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
NEVER include buffer_util.h from a header.
|
NEVER include buffer_util.h from a header.
|
||||||
|
|
||||||
Loading from and saving to disk (import/export) is currently done using tinygltf, but this is not a long term
|
Loading from and saving to disk (import/export) is currently done using tinygltf, but this is not a long term
|
||||||
solution. Eventually the implementation should rely solely on boost::json for reading and writing .gltf
|
solution. Eventually the implementation should rely solely on boost::json for reading and writing .gltf
|
||||||
files and should handle .bin files natively.
|
files and should handle .bin files natively.
|
||||||
|
|
||||||
When serializing Images and Buffers to the server, clients MUST store a single UUID "uri" field and nothing else.
|
When serializing Images and Buffers to the server, clients MUST store a single UUID "uri" field and nothing else.
|
||||||
The server MUST reject any data that violates this requirement.
|
The server MUST reject any data that violates this requirement.
|
||||||
|
|
@ -152,5 +152,5 @@ Servers MAY reject Assets that contain Buffers with unreferenced data.
|
||||||
|
|
||||||
... to be continued.
|
... to be continued.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include "asset.h"
|
#include "asset.h"
|
||||||
#include "buffer_util.h"
|
#include "buffer_util.h"
|
||||||
|
#include "llfilesystem.h"
|
||||||
|
|
||||||
using namespace LL::GLTF;
|
using namespace LL::GLTF;
|
||||||
using namespace boost::json;
|
using namespace boost::json;
|
||||||
|
|
@ -107,6 +108,8 @@ void Buffer::erase(Asset& asset, S32 offset, S32 length)
|
||||||
|
|
||||||
mData.erase(mData.begin() + offset, mData.begin() + offset + length);
|
mData.erase(mData.begin() + offset, mData.begin() + offset + length);
|
||||||
|
|
||||||
|
mByteLength = mData.size();
|
||||||
|
|
||||||
for (BufferView& view : asset.mBufferViews)
|
for (BufferView& view : asset.mBufferViews)
|
||||||
{
|
{
|
||||||
if (view.mBuffer == idx)
|
if (view.mBuffer == idx)
|
||||||
|
|
@ -119,6 +122,103 @@ void Buffer::erase(Asset& asset, S32 offset, S32 length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Buffer::prep(Asset& asset)
|
||||||
|
{
|
||||||
|
if (mByteLength == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLUUID id;
|
||||||
|
if (mUri.size() == UUID_STR_SIZE && LLUUID::parseUUID(mUri, &id) && id.notNull())
|
||||||
|
{ // loaded from an asset, fetch the buffer data from the asset store
|
||||||
|
LLFileSystem file(id, LLAssetType::AT_GLTF_BIN, LLFileSystem::READ);
|
||||||
|
|
||||||
|
if (mByteLength > file.getSize())
|
||||||
|
{
|
||||||
|
LL_WARNS("GLTF") << "Unexpected glbin size: " << id << " is " << file.getSize() << " bytes, expected " << mByteLength << LL_ENDL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mData.resize(mByteLength);
|
||||||
|
if (!file.read((U8*)mData.data(), mData.size()))
|
||||||
|
{
|
||||||
|
LL_WARNS("GLTF") << "Failed to load buffer data from asset: " << id << LL_ENDL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mUri.find("data:") == 0)
|
||||||
|
{ // loaded from a data URI, load the texture from the data
|
||||||
|
LL_WARNS() << "Data URIs not yet supported" << LL_ENDL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (!asset.mFilename.empty() &&
|
||||||
|
!mUri.empty()) // <-- uri could be empty if we're loading from .glb
|
||||||
|
{
|
||||||
|
std::string dir = gDirUtilp->getDirName(asset.mFilename);
|
||||||
|
std::string bin_file = dir + gDirUtilp->getDirDelimiter() + mUri;
|
||||||
|
|
||||||
|
std::ifstream file(bin_file, std::ios::binary);
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
LL_WARNS("GLTF") << "Failed to open file: " << bin_file << LL_ENDL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.seekg(0, std::ios::end);
|
||||||
|
if (mByteLength > file.tellg())
|
||||||
|
{
|
||||||
|
LL_WARNS("GLTF") << "Unexpected file size: " << bin_file << " is " << file.tellg() << " bytes, expected " << mByteLength << LL_ENDL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
mData.resize(mByteLength);
|
||||||
|
file.read((char*)mData.data(), mData.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// POSTCONDITION: on success, mData.size == mByteLength
|
||||||
|
llassert(mData.size() == mByteLength);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Buffer::save(Asset& asset, const std::string& folder)
|
||||||
|
{
|
||||||
|
if (mUri.substr(0, 5) == "data:")
|
||||||
|
{
|
||||||
|
LL_WARNS("GLTF") << "Data URIs not yet supported" << LL_ENDL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string bin_file = folder + gDirUtilp->getDirDelimiter();
|
||||||
|
|
||||||
|
if (mUri.empty())
|
||||||
|
{
|
||||||
|
if (mName.empty())
|
||||||
|
{
|
||||||
|
S32 idx = this - &asset.mBuffers[0];
|
||||||
|
mUri = llformat("buffer_%d.bin", idx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mUri = mName + ".bin";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bin_file += mUri;
|
||||||
|
|
||||||
|
std::ofstream file(bin_file, std::ios::binary);
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
LL_WARNS("GLTF") << "Failed to open file: " << bin_file << LL_ENDL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.write((char*)mData.data(), mData.size());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Buffer::serialize(object& dst) const
|
void Buffer::serialize(object& dst) const
|
||||||
{
|
{
|
||||||
write(mName, "name", dst);
|
write(mName, "name", dst);
|
||||||
|
|
@ -132,23 +232,15 @@ const Buffer& Buffer::operator=(const Value& src)
|
||||||
{
|
{
|
||||||
copy(src, "name", mName);
|
copy(src, "name", mName);
|
||||||
copy(src, "uri", mUri);
|
copy(src, "uri", mUri);
|
||||||
|
copy(src, "byteLength", mByteLength);
|
||||||
// NOTE: DO NOT attempt to handle the uri here.
|
|
||||||
|
// NOTE: DO NOT attempt to handle the uri here.
|
||||||
// The uri is a reference to a file that is not loaded until
|
// The uri is a reference to a file that is not loaded until
|
||||||
// after the json document is parsed
|
// after the json document is parsed
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Buffer& Buffer::operator=(const tinygltf::Buffer& src)
|
|
||||||
{
|
|
||||||
mData = src.data;
|
|
||||||
mName = src.name;
|
|
||||||
mUri = src.uri;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BufferView::serialize(object& dst) const
|
void BufferView::serialize(object& dst) const
|
||||||
{
|
{
|
||||||
write_always(mBuffer, "buffer", dst);
|
write_always(mBuffer, "buffer", dst);
|
||||||
|
|
@ -173,43 +265,6 @@ const BufferView& BufferView::operator=(const Value& src)
|
||||||
return *this;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Accessor::Type tinygltf_type_to_enum(S32 type)
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case TINYGLTF_TYPE_SCALAR:
|
|
||||||
return Accessor::Type::SCALAR;
|
|
||||||
case TINYGLTF_TYPE_VEC2:
|
|
||||||
return Accessor::Type::VEC2;
|
|
||||||
case TINYGLTF_TYPE_VEC3:
|
|
||||||
return Accessor::Type::VEC3;
|
|
||||||
case TINYGLTF_TYPE_VEC4:
|
|
||||||
return Accessor::Type::VEC4;
|
|
||||||
case TINYGLTF_TYPE_MAT2:
|
|
||||||
return Accessor::Type::MAT2;
|
|
||||||
case TINYGLTF_TYPE_MAT3:
|
|
||||||
return Accessor::Type::MAT3;
|
|
||||||
case TINYGLTF_TYPE_MAT4:
|
|
||||||
return Accessor::Type::MAT4;
|
|
||||||
}
|
|
||||||
|
|
||||||
LL_WARNS("GLTF") << "Unknown tinygltf accessor type: " << type << LL_ENDL;
|
|
||||||
llassert(false);
|
|
||||||
|
|
||||||
return Accessor::Type::SCALAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Accessor::serialize(object& dst) const
|
void Accessor::serialize(object& dst) const
|
||||||
{
|
{
|
||||||
write(mName, "name", dst);
|
write(mName, "name", dst);
|
||||||
|
|
@ -240,18 +295,3 @@ const Accessor& Accessor::operator=(const Value& src)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Accessor& Accessor::operator=(const tinygltf::Accessor& src)
|
|
||||||
{
|
|
||||||
mBufferView = src.bufferView;
|
|
||||||
mByteOffset = src.byteOffset;
|
|
||||||
mComponentType = src.componentType;
|
|
||||||
mCount = src.count;
|
|
||||||
mType = tinygltf_type_to_enum(src.type);
|
|
||||||
mNormalized = src.normalized;
|
|
||||||
mName = src.name;
|
|
||||||
mMax = src.maxValues;
|
|
||||||
mMin = src.minValues;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@
|
||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../lltinygltfhelper.h"
|
|
||||||
#include "llstrider.h"
|
#include "llstrider.h"
|
||||||
#include "boost/json.hpp"
|
#include "boost/json.hpp"
|
||||||
|
|
||||||
|
|
@ -51,9 +50,12 @@ namespace LL
|
||||||
// also updates all buffer views in given asset that reference this buffer
|
// also updates all buffer views in given asset that reference this buffer
|
||||||
void erase(Asset& asset, S32 offset, S32 length);
|
void erase(Asset& asset, S32 offset, S32 length);
|
||||||
|
|
||||||
|
bool prep(Asset& asset);
|
||||||
|
|
||||||
void serialize(boost::json::object& obj) const;
|
void serialize(boost::json::object& obj) const;
|
||||||
const Buffer& operator=(const Value& value);
|
const Buffer& operator=(const Value& value);
|
||||||
const Buffer& operator=(const tinygltf::Buffer& src);
|
|
||||||
|
bool save(Asset& asset, const std::string& folder);
|
||||||
};
|
};
|
||||||
|
|
||||||
class BufferView
|
class BufferView
|
||||||
|
|
@ -69,37 +71,44 @@ namespace LL
|
||||||
|
|
||||||
void serialize(boost::json::object& obj) const;
|
void serialize(boost::json::object& obj) const;
|
||||||
const BufferView& operator=(const Value& value);
|
const BufferView& operator=(const Value& value);
|
||||||
const BufferView& operator=(const tinygltf::BufferView& src);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Accessor
|
class Accessor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
S32 mBufferView = INVALID_INDEX;
|
enum class Type : U8
|
||||||
S32 mByteOffset = 0;
|
|
||||||
S32 mComponentType = 0;
|
|
||||||
S32 mCount = 0;
|
|
||||||
std::vector<double> mMax;
|
|
||||||
std::vector<double> mMin;
|
|
||||||
|
|
||||||
enum class Type : S32
|
|
||||||
{
|
{
|
||||||
SCALAR = TINYGLTF_TYPE_SCALAR,
|
SCALAR,
|
||||||
VEC2 = TINYGLTF_TYPE_VEC2,
|
VEC2,
|
||||||
VEC3 = TINYGLTF_TYPE_VEC3,
|
VEC3,
|
||||||
VEC4 = TINYGLTF_TYPE_VEC4,
|
VEC4,
|
||||||
MAT2 = TINYGLTF_TYPE_MAT2,
|
MAT2,
|
||||||
MAT3 = TINYGLTF_TYPE_MAT3,
|
MAT3,
|
||||||
MAT4 = TINYGLTF_TYPE_MAT4
|
MAT4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ComponentType : U32
|
||||||
|
{
|
||||||
|
BYTE = 5120,
|
||||||
|
UNSIGNED_BYTE = 5121,
|
||||||
|
SHORT = 5122,
|
||||||
|
UNSIGNED_SHORT = 5123,
|
||||||
|
UNSIGNED_INT = 5125,
|
||||||
|
FLOAT = 5126
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<double> mMax;
|
||||||
|
std::vector<double> mMin;
|
||||||
|
std::string mName;
|
||||||
|
S32 mBufferView = INVALID_INDEX;
|
||||||
|
S32 mByteOffset = 0;
|
||||||
|
ComponentType mComponentType = ComponentType::BYTE;
|
||||||
|
S32 mCount = 0;
|
||||||
Type mType = Type::SCALAR;
|
Type mType = Type::SCALAR;
|
||||||
bool mNormalized = false;
|
bool mNormalized = false;
|
||||||
std::string mName;
|
|
||||||
|
|
||||||
void serialize(boost::json::object& obj) const;
|
void serialize(boost::json::object& obj) const;
|
||||||
const Accessor& operator=(const Value& value);
|
const Accessor& operator=(const Value& value);
|
||||||
const Accessor& operator=(const tinygltf::Accessor& src);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// convert from "SCALAR", "VEC2", etc to Accessor::Type
|
// convert from "SCALAR", "VEC2", etc to Accessor::Type
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,12 @@
|
||||||
|
|
||||||
#include "asset.h"
|
#include "asset.h"
|
||||||
#include "buffer_util.h"
|
#include "buffer_util.h"
|
||||||
|
#include "../llskinningutil.h"
|
||||||
|
|
||||||
using namespace LL::GLTF;
|
using namespace LL::GLTF;
|
||||||
using namespace boost::json;
|
using namespace boost::json;
|
||||||
|
|
||||||
void Animation::allocateGLResources(Asset& asset)
|
bool Animation::prep(Asset& asset)
|
||||||
{
|
{
|
||||||
if (!mSamplers.empty())
|
if (!mSamplers.empty())
|
||||||
{
|
{
|
||||||
|
|
@ -40,7 +41,10 @@ void Animation::allocateGLResources(Asset& asset)
|
||||||
mMaxTime = -FLT_MAX;
|
mMaxTime = -FLT_MAX;
|
||||||
for (auto& sampler : mSamplers)
|
for (auto& sampler : mSamplers)
|
||||||
{
|
{
|
||||||
sampler.allocateGLResources(asset);
|
if (!sampler.prep(asset))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
mMinTime = llmin(sampler.mMinTime, mMinTime);
|
mMinTime = llmin(sampler.mMinTime, mMinTime);
|
||||||
mMaxTime = llmax(sampler.mMaxTime, mMaxTime);
|
mMaxTime = llmax(sampler.mMaxTime, mMaxTime);
|
||||||
}
|
}
|
||||||
|
|
@ -52,13 +56,21 @@ void Animation::allocateGLResources(Asset& asset)
|
||||||
|
|
||||||
for (auto& channel : mRotationChannels)
|
for (auto& channel : mRotationChannels)
|
||||||
{
|
{
|
||||||
channel.allocateGLResources(asset, mSamplers[channel.mSampler]);
|
if (!channel.prep(asset, mSamplers[channel.mSampler]))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& channel : mTranslationChannels)
|
for (auto& channel : mTranslationChannels)
|
||||||
{
|
{
|
||||||
channel.allocateGLResources(asset, mSamplers[channel.mSampler]);
|
if (!channel.prep(asset, mSamplers[channel.mSampler]))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::update(Asset& asset, F32 dt)
|
void Animation::update(Asset& asset, F32 dt)
|
||||||
|
|
@ -85,7 +97,7 @@ void Animation::apply(Asset& asset, float time)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void Animation::Sampler::allocateGLResources(Asset& asset)
|
bool Animation::Sampler::prep(Asset& asset)
|
||||||
{
|
{
|
||||||
Accessor& accessor = asset.mAccessors[mInput];
|
Accessor& accessor = asset.mAccessors[mInput];
|
||||||
mMinTime = accessor.mMin[0];
|
mMinTime = accessor.mMin[0];
|
||||||
|
|
@ -95,6 +107,8 @@ void Animation::Sampler::allocateGLResources(Asset& asset)
|
||||||
|
|
||||||
LLStrider<F32> frame_times = mFrameTimes.data();
|
LLStrider<F32> frame_times = mFrameTimes.data();
|
||||||
copy(asset, accessor, frame_times);
|
copy(asset, accessor, frame_times);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -120,16 +134,6 @@ const Animation::Sampler& Animation::Sampler::operator=(const Value& src)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Animation::Sampler& Animation::Sampler::operator=(const tinygltf::AnimationSampler& src)
|
|
||||||
{
|
|
||||||
mInput = src.input;
|
|
||||||
mOutput = src.output;
|
|
||||||
mInterpolation = src.interpolation;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Animation::Channel::Target::operator==(const Channel::Target& rhs) const
|
bool Animation::Channel::Target::operator==(const Channel::Target& rhs) const
|
||||||
{
|
{
|
||||||
return mNode == rhs.mNode && mPath == rhs.mPath;
|
return mNode == rhs.mNode && mPath == rhs.mPath;
|
||||||
|
|
@ -172,17 +176,6 @@ const Animation::Channel& Animation::Channel::operator=(const Value& src)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Animation::Channel& Animation::Channel::operator=(const tinygltf::AnimationChannel& src)
|
|
||||||
{
|
|
||||||
mSampler = src.sampler;
|
|
||||||
|
|
||||||
mTarget.mNode = src.target_node;
|
|
||||||
mTarget.mPath = src.target_path;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F32& t)
|
void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F32& t)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED;
|
LL_PROFILE_ZONE_SCOPED;
|
||||||
|
|
@ -223,11 +216,13 @@ void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::RotationChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler)
|
bool Animation::RotationChannel::prep(Asset& asset, Animation::Sampler& sampler)
|
||||||
{
|
{
|
||||||
Accessor& accessor = asset.mAccessors[sampler.mOutput];
|
Accessor& accessor = asset.mAccessors[sampler.mOutput];
|
||||||
|
|
||||||
copy(asset, accessor, mRotations);
|
copy(asset, accessor, mRotations);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::RotationChannel::apply(Asset& asset, Sampler& sampler, F32 time)
|
void Animation::RotationChannel::apply(Asset& asset, Sampler& sampler, F32 time)
|
||||||
|
|
@ -254,11 +249,13 @@ void Animation::RotationChannel::apply(Asset& asset, Sampler& sampler, F32 time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::TranslationChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler)
|
bool Animation::TranslationChannel::prep(Asset& asset, Animation::Sampler& sampler)
|
||||||
{
|
{
|
||||||
Accessor& accessor = asset.mAccessors[sampler.mOutput];
|
Accessor& accessor = asset.mAccessors[sampler.mOutput];
|
||||||
|
|
||||||
copy(asset, accessor, mTranslations);
|
copy(asset, accessor, mTranslations);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::TranslationChannel::apply(Asset& asset, Sampler& sampler, F32 time)
|
void Animation::TranslationChannel::apply(Asset& asset, Sampler& sampler, F32 time)
|
||||||
|
|
@ -286,11 +283,13 @@ void Animation::TranslationChannel::apply(Asset& asset, Sampler& sampler, F32 ti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::ScaleChannel::allocateGLResources(Asset& asset, Animation::Sampler& sampler)
|
bool Animation::ScaleChannel::prep(Asset& asset, Animation::Sampler& sampler)
|
||||||
{
|
{
|
||||||
Accessor& accessor = asset.mAccessors[sampler.mOutput];
|
Accessor& accessor = asset.mAccessors[sampler.mOutput];
|
||||||
|
|
||||||
copy(asset, accessor, mScales);
|
copy(asset, accessor, mScales);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::ScaleChannel::apply(Asset& asset, Sampler& sampler, F32 time)
|
void Animation::ScaleChannel::apply(Asset& asset, Sampler& sampler, F32 time)
|
||||||
|
|
@ -364,47 +363,80 @@ const Animation& Animation::operator=(const Value& src)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Animation& Animation::operator=(const tinygltf::Animation& src)
|
Skin::~Skin()
|
||||||
{
|
{
|
||||||
mName = src.name;
|
if (mUBO)
|
||||||
|
|
||||||
mSamplers.resize(src.samplers.size());
|
|
||||||
for (U32 i = 0; i < src.samplers.size(); ++i)
|
|
||||||
{
|
{
|
||||||
mSamplers[i] = src.samplers[i];
|
glDeleteBuffers(1, &mUBO);
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
void Skin::uploadMatrixPalette(Asset& asset)
|
||||||
|
{
|
||||||
|
// prepare matrix palette
|
||||||
|
|
||||||
|
U32 max_joints = LLSkinningUtil::getMaxGLTFJointCount();
|
||||||
|
|
||||||
|
if (mUBO == 0)
|
||||||
|
{
|
||||||
|
glGenBuffers(1, &mUBO);
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 joint_count = llmin(max_joints, mJoints.size());
|
||||||
|
|
||||||
|
std::vector<mat4> t_mp;
|
||||||
|
|
||||||
|
t_mp.resize(joint_count);
|
||||||
|
|
||||||
|
for (U32 i = 0; i < joint_count; ++i)
|
||||||
|
{
|
||||||
|
Node& joint = asset.mNodes[mJoints[i]];
|
||||||
|
// build matrix palette in asset space
|
||||||
|
t_mp[i] = joint.mAssetMatrix * mInverseBindMatricesData[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<F32> glmp;
|
||||||
|
|
||||||
|
glmp.resize(joint_count * 12);
|
||||||
|
|
||||||
|
F32* mp = glmp.data();
|
||||||
|
|
||||||
|
for (U32 i = 0; i < joint_count; ++i)
|
||||||
|
{
|
||||||
|
F32* m = glm::value_ptr(t_mp[i]);
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindBuffer(GL_UNIFORM_BUFFER, mUBO);
|
||||||
|
glBufferData(GL_UNIFORM_BUFFER, glmp.size() * sizeof(F32), glmp.data(), GL_STREAM_DRAW);
|
||||||
|
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Skin::prep(Asset& asset)
|
||||||
{
|
{
|
||||||
if (mInverseBindMatrices != INVALID_INDEX)
|
if (mInverseBindMatrices != INVALID_INDEX)
|
||||||
{
|
{
|
||||||
Accessor& accessor = asset.mAccessors[mInverseBindMatrices];
|
Accessor& accessor = asset.mAccessors[mInverseBindMatrices];
|
||||||
copy(asset, accessor, mInverseBindMatricesData);
|
copy(asset, accessor, mInverseBindMatricesData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Skin& Skin::operator=(const Value& src)
|
const Skin& Skin::operator=(const Value& src)
|
||||||
|
|
@ -419,16 +451,6 @@ const Skin& Skin::operator=(const Value& src)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Skin& Skin::operator=(const tinygltf::Skin& src)
|
|
||||||
{
|
|
||||||
mName = src.name;
|
|
||||||
mSkeleton = src.skeleton;
|
|
||||||
mInverseBindMatrices = src.inverseBindMatrices;
|
|
||||||
mJoints = src.joints;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Skin::serialize(object& obj) const
|
void Skin::serialize(object& obj) const
|
||||||
{
|
{
|
||||||
write(mInverseBindMatrices, "inverseBindMatrices", obj, INVALID_INDEX);
|
write(mInverseBindMatrices, "inverseBindMatrices", obj, INVALID_INDEX);
|
||||||
|
|
|
||||||
|
|
@ -49,12 +49,10 @@ namespace LL
|
||||||
S32 mOutput = INVALID_INDEX;
|
S32 mOutput = INVALID_INDEX;
|
||||||
std::string mInterpolation;
|
std::string mInterpolation;
|
||||||
|
|
||||||
void allocateGLResources(Asset& asset);
|
bool prep(Asset& asset);
|
||||||
|
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
const Sampler& operator=(const Value& value);
|
const Sampler& operator=(const Value& value);
|
||||||
const Sampler& operator=(const tinygltf::AnimationSampler& src);
|
|
||||||
|
|
||||||
|
|
||||||
// get the frame index and time for the specified time
|
// get the frame index and time for the specified time
|
||||||
// asset -- the asset to reference for Accessors
|
// asset -- the asset to reference for Accessors
|
||||||
|
|
@ -85,7 +83,6 @@ namespace LL
|
||||||
|
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
const Channel& operator=(const Value& value);
|
const Channel& operator=(const Value& value);
|
||||||
const Channel& operator=(const tinygltf::AnimationChannel& src);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RotationChannel : public Channel
|
class RotationChannel : public Channel
|
||||||
|
|
@ -96,16 +93,10 @@ namespace LL
|
||||||
|
|
||||||
std::vector<quat> mRotations;
|
std::vector<quat> mRotations;
|
||||||
|
|
||||||
const RotationChannel& operator=(const tinygltf::AnimationChannel& src)
|
|
||||||
{
|
|
||||||
Channel::operator=(src);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare data needed for rendering
|
// prepare data needed for rendering
|
||||||
// asset -- asset to reference for Accessors
|
// asset -- asset to reference for Accessors
|
||||||
// sampler -- Sampler associated with this channel
|
// sampler -- Sampler associated with this channel
|
||||||
void allocateGLResources(Asset& asset, Sampler& sampler);
|
bool prep(Asset& asset, Sampler& sampler);
|
||||||
|
|
||||||
void apply(Asset& asset, Sampler& sampler, F32 time);
|
void apply(Asset& asset, Sampler& sampler, F32 time);
|
||||||
};
|
};
|
||||||
|
|
@ -118,16 +109,10 @@ namespace LL
|
||||||
|
|
||||||
std::vector<vec3> mTranslations;
|
std::vector<vec3> mTranslations;
|
||||||
|
|
||||||
const TranslationChannel& operator=(const tinygltf::AnimationChannel& src)
|
|
||||||
{
|
|
||||||
Channel::operator=(src);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare data needed for rendering
|
// prepare data needed for rendering
|
||||||
// asset -- asset to reference for Accessors
|
// asset -- asset to reference for Accessors
|
||||||
// sampler -- Sampler associated with this channel
|
// sampler -- Sampler associated with this channel
|
||||||
void allocateGLResources(Asset& asset, Sampler& sampler);
|
bool prep(Asset& asset, Sampler& sampler);
|
||||||
|
|
||||||
void apply(Asset& asset, Sampler& sampler, F32 time);
|
void apply(Asset& asset, Sampler& sampler, F32 time);
|
||||||
};
|
};
|
||||||
|
|
@ -140,16 +125,10 @@ namespace LL
|
||||||
|
|
||||||
std::vector<vec3> mScales;
|
std::vector<vec3> mScales;
|
||||||
|
|
||||||
const ScaleChannel& operator=(const tinygltf::AnimationChannel& src)
|
|
||||||
{
|
|
||||||
Channel::operator=(src);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare data needed for rendering
|
// prepare data needed for rendering
|
||||||
// asset -- asset to reference for Accessors
|
// asset -- asset to reference for Accessors
|
||||||
// sampler -- Sampler associated with this channel
|
// sampler -- Sampler associated with this channel
|
||||||
void allocateGLResources(Asset& asset, Sampler& sampler);
|
bool prep(Asset& asset, Sampler& sampler);
|
||||||
|
|
||||||
void apply(Asset& asset, Sampler& sampler, F32 time);
|
void apply(Asset& asset, Sampler& sampler, F32 time);
|
||||||
};
|
};
|
||||||
|
|
@ -160,7 +139,7 @@ namespace LL
|
||||||
// min/max time values for all samplers combined
|
// min/max time values for all samplers combined
|
||||||
F32 mMinTime = 0.f;
|
F32 mMinTime = 0.f;
|
||||||
F32 mMaxTime = 0.f;
|
F32 mMaxTime = 0.f;
|
||||||
|
|
||||||
// current time of the animation
|
// current time of the animation
|
||||||
F32 mTime = 0.f;
|
F32 mTime = 0.f;
|
||||||
|
|
||||||
|
|
@ -170,9 +149,8 @@ namespace LL
|
||||||
|
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
const Animation& operator=(const Value& value);
|
const Animation& operator=(const Value& value);
|
||||||
const Animation& operator=(const tinygltf::Animation& src);
|
|
||||||
|
bool prep(Asset& asset);
|
||||||
void allocateGLResources(Asset& asset);
|
|
||||||
|
|
||||||
void update(Asset& asset, float dt);
|
void update(Asset& asset, float dt);
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -28,12 +28,12 @@
|
||||||
|
|
||||||
#include "llvertexbuffer.h"
|
#include "llvertexbuffer.h"
|
||||||
#include "llvolumeoctree.h"
|
#include "llvolumeoctree.h"
|
||||||
#include "../lltinygltfhelper.h"
|
|
||||||
#include "accessor.h"
|
#include "accessor.h"
|
||||||
#include "primitive.h"
|
#include "primitive.h"
|
||||||
#include "animation.h"
|
#include "animation.h"
|
||||||
#include "boost/json.hpp"
|
#include "boost/json.hpp"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "../llviewertexture.h"
|
||||||
|
|
||||||
extern F32SecondsImplicit gFrameTimeSeconds;
|
extern F32SecondsImplicit gFrameTimeSeconds;
|
||||||
|
|
||||||
|
|
@ -49,10 +49,26 @@ namespace LL
|
||||||
{
|
{
|
||||||
class Asset;
|
class Asset;
|
||||||
|
|
||||||
|
class Extension
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// true if this extension is present in the gltf file
|
||||||
|
// otherwise false
|
||||||
|
bool mPresent = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class Material
|
class Material
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
class Unlit : public Extension // KHR_materials_unlit implementation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const Unlit& operator=(const Value& src);
|
||||||
|
void serialize(boost::json::object& dst) const;
|
||||||
|
};
|
||||||
|
|
||||||
enum class AlphaMode
|
enum class AlphaMode
|
||||||
{
|
{
|
||||||
OPAQUE,
|
OPAQUE,
|
||||||
|
|
@ -69,7 +85,6 @@ namespace LL
|
||||||
bool operator==(const TextureInfo& rhs) const;
|
bool operator==(const TextureInfo& rhs) const;
|
||||||
bool operator!=(const TextureInfo& rhs) const;
|
bool operator!=(const TextureInfo& rhs) const;
|
||||||
|
|
||||||
const TextureInfo& operator=(const tinygltf::TextureInfo& src);
|
|
||||||
const TextureInfo& operator=(const Value& src);
|
const TextureInfo& operator=(const Value& src);
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
@ -79,7 +94,6 @@ namespace LL
|
||||||
public:
|
public:
|
||||||
F32 mScale = 1.0f;
|
F32 mScale = 1.0f;
|
||||||
|
|
||||||
const NormalTextureInfo& operator=(const tinygltf::NormalTextureInfo& src);
|
|
||||||
const NormalTextureInfo& operator=(const Value& src);
|
const NormalTextureInfo& operator=(const Value& src);
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
@ -89,7 +103,6 @@ namespace LL
|
||||||
public:
|
public:
|
||||||
F32 mStrength = 1.0f;
|
F32 mStrength = 1.0f;
|
||||||
|
|
||||||
const OcclusionTextureInfo& operator=(const tinygltf::OcclusionTextureInfo& src);
|
|
||||||
const OcclusionTextureInfo& operator=(const Value& src);
|
const OcclusionTextureInfo& operator=(const Value& src);
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
@ -105,35 +118,25 @@ namespace LL
|
||||||
|
|
||||||
bool operator==(const PbrMetallicRoughness& rhs) const;
|
bool operator==(const PbrMetallicRoughness& rhs) const;
|
||||||
bool operator!=(const PbrMetallicRoughness& rhs) const;
|
bool operator!=(const PbrMetallicRoughness& rhs) const;
|
||||||
const PbrMetallicRoughness& operator=(const tinygltf::PbrMetallicRoughness& src);
|
|
||||||
const PbrMetallicRoughness& operator=(const Value& src);
|
const PbrMetallicRoughness& operator=(const Value& src);
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// use LLFetchedGLTFMaterial for now, but eventually we'll want to use
|
|
||||||
// a more flexible GLTF material implementation instead of the fixed packing
|
|
||||||
// version we use for sharable GLTF material assets
|
|
||||||
LLPointer<LLFetchedGLTFMaterial> mMaterial;
|
|
||||||
PbrMetallicRoughness mPbrMetallicRoughness;
|
PbrMetallicRoughness mPbrMetallicRoughness;
|
||||||
NormalTextureInfo mNormalTexture;
|
NormalTextureInfo mNormalTexture;
|
||||||
OcclusionTextureInfo mOcclusionTexture;
|
OcclusionTextureInfo mOcclusionTexture;
|
||||||
TextureInfo mEmissiveTexture;
|
TextureInfo mEmissiveTexture;
|
||||||
|
|
||||||
|
|
||||||
std::string mName;
|
std::string mName;
|
||||||
vec3 mEmissiveFactor = vec3(0.f, 0.f, 0.f);
|
vec3 mEmissiveFactor = vec3(0.f, 0.f, 0.f);
|
||||||
AlphaMode mAlphaMode = AlphaMode::OPAQUE;
|
AlphaMode mAlphaMode = AlphaMode::OPAQUE;
|
||||||
F32 mAlphaCutoff = 0.5f;
|
F32 mAlphaCutoff = 0.5f;
|
||||||
bool mDoubleSided = false;
|
bool mDoubleSided = false;
|
||||||
|
Unlit mUnlit;
|
||||||
|
|
||||||
// bind for rendering
|
|
||||||
void bind(Asset& asset);
|
|
||||||
const Material& operator=(const tinygltf::Material& src);
|
|
||||||
const Material& operator=(const Value& src);
|
const Material& operator=(const Value& src);
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
|
|
||||||
void allocateGLResources(Asset& asset);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Mesh
|
class Mesh
|
||||||
|
|
@ -143,11 +146,10 @@ namespace LL
|
||||||
std::vector<double> mWeights;
|
std::vector<double> mWeights;
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
const Mesh& operator=(const tinygltf::Mesh& src);
|
|
||||||
const Mesh& operator=(const Value& src);
|
const Mesh& operator=(const Value& src);
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
|
|
||||||
void allocateGLResources(Asset& asset);
|
bool prep(Asset& asset);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Node
|
class Node
|
||||||
|
|
@ -178,7 +180,6 @@ namespace LL
|
||||||
|
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
const Node& operator=(const tinygltf::Node& src);
|
|
||||||
const Node& operator=(const Value& src);
|
const Node& operator=(const Value& src);
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
|
|
||||||
|
|
@ -211,16 +212,19 @@ namespace LL
|
||||||
class Skin
|
class Skin
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
~Skin();
|
||||||
|
|
||||||
S32 mInverseBindMatrices = INVALID_INDEX;
|
S32 mInverseBindMatrices = INVALID_INDEX;
|
||||||
S32 mSkeleton = INVALID_INDEX;
|
S32 mSkeleton = INVALID_INDEX;
|
||||||
|
|
||||||
|
U32 mUBO = 0;
|
||||||
std::vector<S32> mJoints;
|
std::vector<S32> mJoints;
|
||||||
std::string mName;
|
std::string mName;
|
||||||
std::vector<mat4> mInverseBindMatricesData;
|
std::vector<mat4> mInverseBindMatricesData;
|
||||||
|
|
||||||
void allocateGLResources(Asset& asset);
|
bool prep(Asset& asset);
|
||||||
void uploadMatrixPalette(Asset& asset, Node& node);
|
void uploadMatrixPalette(Asset& asset);
|
||||||
|
|
||||||
const Skin& operator=(const tinygltf::Skin& src);
|
|
||||||
const Skin& operator=(const Value& src);
|
const Skin& operator=(const Value& src);
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
@ -231,7 +235,6 @@ namespace LL
|
||||||
std::vector<S32> mNodes;
|
std::vector<S32> mNodes;
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
const Scene& operator=(const tinygltf::Scene& src);
|
|
||||||
const Scene& operator=(const Value& src);
|
const Scene& operator=(const Value& src);
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
|
|
||||||
|
|
@ -246,7 +249,6 @@ namespace LL
|
||||||
S32 mSource = INVALID_INDEX;
|
S32 mSource = INVALID_INDEX;
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
const Texture& operator=(const tinygltf::Texture& src);
|
|
||||||
const Texture& operator=(const Value& src);
|
const Texture& operator=(const Value& src);
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
@ -260,7 +262,6 @@ namespace LL
|
||||||
S32 mWrapT = REPEAT;
|
S32 mWrapT = REPEAT;
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
|
||||||
const Sampler& operator=(const tinygltf::Sampler& src);
|
|
||||||
const Sampler& operator=(const Value& src);
|
const Sampler& operator=(const Value& src);
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
};
|
};
|
||||||
|
|
@ -274,7 +275,6 @@ namespace LL
|
||||||
|
|
||||||
S32 mBufferView = INVALID_INDEX;
|
S32 mBufferView = INVALID_INDEX;
|
||||||
|
|
||||||
std::vector<U8> mData;
|
|
||||||
S32 mWidth = -1;
|
S32 mWidth = -1;
|
||||||
S32 mHeight = -1;
|
S32 mHeight = -1;
|
||||||
S32 mComponent = -1;
|
S32 mComponent = -1;
|
||||||
|
|
@ -283,19 +283,20 @@ namespace LL
|
||||||
|
|
||||||
LLPointer<LLViewerFetchedTexture> mTexture;
|
LLPointer<LLViewerFetchedTexture> mTexture;
|
||||||
|
|
||||||
const Image& operator=(const tinygltf::Image& src);
|
|
||||||
const Image& operator=(const Value& src);
|
const Image& operator=(const Value& src);
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
|
|
||||||
// save image clear local data, and set uri
|
// save image to disk
|
||||||
void decompose(Asset& asset, const std::string& filename);
|
// may remove image data from bufferviews and convert to
|
||||||
|
// file uri if necessary
|
||||||
|
bool save(Asset& asset, const std::string& filename);
|
||||||
|
|
||||||
// erase the buffer view associated with this image
|
// erase the buffer view associated with this image
|
||||||
// free any associated resources
|
// free any associated GLTF resources
|
||||||
// preserve only uri and name
|
// preserve only uri and name
|
||||||
void clearData(Asset& asset);
|
void clearData(Asset& asset);
|
||||||
|
|
||||||
void allocateGLResources();
|
bool prep(Asset& asset);
|
||||||
};
|
};
|
||||||
|
|
||||||
// C++ representation of a GLTF Asset
|
// C++ representation of a GLTF Asset
|
||||||
|
|
@ -316,22 +317,28 @@ namespace LL
|
||||||
std::vector<Accessor> mAccessors;
|
std::vector<Accessor> mAccessors;
|
||||||
std::vector<Animation> mAnimations;
|
std::vector<Animation> mAnimations;
|
||||||
std::vector<Skin> mSkins;
|
std::vector<Skin> mSkins;
|
||||||
|
std::vector<std::string> mExtensionsUsed;
|
||||||
|
std::vector<std::string> mExtensionsRequired;
|
||||||
|
|
||||||
std::string mVersion;
|
std::string mVersion;
|
||||||
std::string mGenerator;
|
std::string mGenerator;
|
||||||
std::string mMinVersion;
|
std::string mMinVersion;
|
||||||
std::string mCopyright;
|
std::string mCopyright;
|
||||||
|
|
||||||
S32 mDefaultScene = INVALID_INDEX;
|
S32 mScene = INVALID_INDEX;
|
||||||
Value mExtras;
|
Value mExtras;
|
||||||
|
|
||||||
U32 mPendingBuffers = 0;
|
U32 mPendingBuffers = 0;
|
||||||
|
|
||||||
|
// local file this asset was loaded from (if any)
|
||||||
|
std::string mFilename;
|
||||||
|
|
||||||
// the last time update() was called according to gFrameTimeSeconds
|
// the last time update() was called according to gFrameTimeSeconds
|
||||||
F32 mLastUpdateTime = gFrameTimeSeconds;
|
F32 mLastUpdateTime = gFrameTimeSeconds;
|
||||||
|
|
||||||
// prepare the asset for rendering
|
|
||||||
void allocateGLResources(const std::string& filename = "", const tinygltf::Model& model = tinygltf::Model());
|
// prepare for first time use
|
||||||
|
bool prep();
|
||||||
|
|
||||||
// Called periodically (typically once per frame)
|
// Called periodically (typically once per frame)
|
||||||
// Any ongoing work (such as animations) should be handled here
|
// Any ongoing work (such as animations) should be handled here
|
||||||
|
|
@ -346,10 +353,6 @@ namespace LL
|
||||||
// update node render transforms
|
// update node render transforms
|
||||||
void updateRenderTransforms(const mat4& modelview);
|
void updateRenderTransforms(const mat4& modelview);
|
||||||
|
|
||||||
void render(bool opaque, bool rigged = false);
|
|
||||||
void renderOpaque();
|
|
||||||
void renderTransparent();
|
|
||||||
|
|
||||||
// return the index of the node that the line segment intersects with, or -1 if no hit
|
// 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
|
// input and output values must be in this asset's local coordinate frame
|
||||||
S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
|
S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
|
||||||
|
|
@ -361,22 +364,33 @@ namespace LL
|
||||||
);
|
);
|
||||||
|
|
||||||
Asset() = default;
|
Asset() = default;
|
||||||
Asset(const tinygltf::Model& src);
|
|
||||||
Asset(const Value& src);
|
Asset(const Value& src);
|
||||||
|
|
||||||
const Asset& operator=(const tinygltf::Model& src);
|
// load from given file
|
||||||
|
// accepts .gltf and .glb files
|
||||||
|
// Any existing data will be lost
|
||||||
|
// returns result of prep() on success
|
||||||
|
bool load(std::string_view filename);
|
||||||
|
|
||||||
|
// load .glb contents from memory
|
||||||
|
// data - binary contents of .glb file
|
||||||
|
// returns result of prep() on success
|
||||||
|
bool loadBinary(const std::string& data);
|
||||||
|
|
||||||
const Asset& operator=(const Value& src);
|
const Asset& operator=(const Value& src);
|
||||||
void serialize(boost::json::object& dst) const;
|
void serialize(boost::json::object& dst) const;
|
||||||
|
|
||||||
// save the asset to a tinygltf model
|
// save the asset to the given .gltf file
|
||||||
void save(tinygltf::Model& dst);
|
// saves images and bins alongside the gltf file
|
||||||
|
bool save(const std::string& filename);
|
||||||
// decompose the asset to the given .gltf file
|
|
||||||
void decompose(const std::string& filename);
|
|
||||||
|
|
||||||
// remove the bufferview at the given index
|
// remove the bufferview at the given index
|
||||||
// updates all bufferview indices in this Asset as needed
|
// updates all bufferview indices in this Asset as needed
|
||||||
void eraseBufferView(S32 bufferView);
|
void eraseBufferView(S32 bufferView);
|
||||||
|
|
||||||
|
// return true if this Asset has been loaded as a local preview
|
||||||
|
// Local previews may be uploaded or exported to disk
|
||||||
|
bool isLocalPreview() { return !mFilename.empty(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode);
|
Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode);
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
// whenever we add support for more types
|
// whenever we add support for more types
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define LL_FUNCSIG __FUNCSIG__
|
#define LL_FUNCSIG __FUNCSIG__
|
||||||
#else
|
#else
|
||||||
#define LL_FUNCSIG __PRETTY_FUNCTION__
|
#define LL_FUNCSIG __PRETTY_FUNCTION__
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -170,6 +170,16 @@ namespace LL
|
||||||
dst.set(src[0], src[1], src[2], src[3]);
|
dst.set(src[0], src[1], src[2], src[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void copyVec4<U16, U64>(U16* src, U64& dst)
|
||||||
|
{
|
||||||
|
U16* data = (U16*)&dst;
|
||||||
|
data[0] = src[0];
|
||||||
|
data[1] = src[1];
|
||||||
|
data[2] = src[2];
|
||||||
|
data[3] = src[3];
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline void copyVec4<U16, LLColor4U>(U16* src, LLColor4U& dst)
|
inline void copyVec4<U16, LLColor4U>(U16* src, LLColor4U& dst)
|
||||||
{
|
{
|
||||||
|
|
@ -353,37 +363,29 @@ namespace LL
|
||||||
const Buffer& buffer = asset.mBuffers[bufferView.mBuffer];
|
const Buffer& buffer = asset.mBuffers[bufferView.mBuffer];
|
||||||
const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset;
|
const U8* src = buffer.mData.data() + bufferView.mByteOffset + accessor.mByteOffset;
|
||||||
|
|
||||||
if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_FLOAT)
|
switch (accessor.mComponentType)
|
||||||
{
|
{
|
||||||
LL::GLTF::copy(asset, accessor, (const F32*)src, dst, bufferView.mByteStride);
|
case Accessor::ComponentType::FLOAT:
|
||||||
}
|
copy(asset, accessor, (const F32*)src, dst, bufferView.mByteStride);
|
||||||
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)
|
break;
|
||||||
{
|
case Accessor::ComponentType::UNSIGNED_INT:
|
||||||
LL::GLTF::copy(asset, accessor, (const U16*)src, dst, bufferView.mByteStride);
|
copy(asset, accessor, (const U32*)src, dst, bufferView.mByteStride);
|
||||||
}
|
break;
|
||||||
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT)
|
case Accessor::ComponentType::SHORT:
|
||||||
{
|
copy(asset, accessor, (const S16*)src, dst, bufferView.mByteStride);
|
||||||
LL::GLTF::copy(asset, accessor, (const U32*)src, dst, bufferView.mByteStride);
|
break;
|
||||||
}
|
case Accessor::ComponentType::UNSIGNED_SHORT:
|
||||||
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)
|
copy(asset, accessor, (const U16*)src, dst, bufferView.mByteStride);
|
||||||
{
|
break;
|
||||||
LL::GLTF::copy(asset, accessor, (const U8*)src, dst, bufferView.mByteStride);
|
case Accessor::ComponentType::BYTE:
|
||||||
}
|
copy(asset, accessor, (const S8*)src, dst, bufferView.mByteStride);
|
||||||
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_SHORT)
|
break;
|
||||||
{
|
case Accessor::ComponentType::UNSIGNED_BYTE:
|
||||||
LL::GLTF::copy(asset, accessor, (const S16*)src, dst, bufferView.mByteStride);
|
copy(asset, accessor, (const U8*)src, dst, bufferView.mByteStride);
|
||||||
}
|
break;
|
||||||
else if (accessor.mComponentType == TINYGLTF_COMPONENT_TYPE_BYTE)
|
default:
|
||||||
{
|
LL_ERRS("GLTF") << "Invalid component type" << LL_ENDL;
|
||||||
LL::GLTF::copy(asset, accessor, (const S8*)src, dst, bufferView.mByteStride);
|
break;
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -400,7 +402,7 @@ namespace LL
|
||||||
//=========================================================================================================
|
//=========================================================================================================
|
||||||
// boost::json copying utilities
|
// boost::json copying utilities
|
||||||
// ========================================================================================================
|
// ========================================================================================================
|
||||||
|
|
||||||
//====================== unspecialized base template, single value ===========================
|
//====================== unspecialized base template, single value ===========================
|
||||||
|
|
||||||
// to/from Value
|
// to/from Value
|
||||||
|
|
@ -517,6 +519,104 @@ namespace LL
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// to/from extension
|
||||||
|
|
||||||
|
// for internal use only, use copy_extensions instead
|
||||||
|
template<typename T>
|
||||||
|
inline bool _copy_extension(const boost::json::object& extensions, std::string_view member, T* dst)
|
||||||
|
{
|
||||||
|
if (extensions.contains(member))
|
||||||
|
{
|
||||||
|
return copy(extensions.at(member), *dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy all extensions from src.extensions to provided destinations
|
||||||
|
// Usage:
|
||||||
|
// copy_extensions(src,
|
||||||
|
// "KHR_materials_unlit", &mUnlit,
|
||||||
|
// "KHR_materials_pbrSpecularGlossiness", &mPbrSpecularGlossiness);
|
||||||
|
// returns true if any of the extensions are copied
|
||||||
|
template<class... Types>
|
||||||
|
inline bool copy_extensions(const boost::json::value& src, Types... args)
|
||||||
|
{
|
||||||
|
// extract the extensions object (don't assume it exists and verify that it is an object)
|
||||||
|
if (src.is_object())
|
||||||
|
{
|
||||||
|
boost::json::object obj = src.get_object();
|
||||||
|
if (obj.contains("extensions"))
|
||||||
|
{
|
||||||
|
const boost::json::value& extensions = obj.at("extensions");
|
||||||
|
if (extensions.is_object())
|
||||||
|
{
|
||||||
|
const boost::json::object& ext_obj = extensions.as_object();
|
||||||
|
bool success = false;
|
||||||
|
// copy each extension, return true if any of them succeed, do not short circuit on success
|
||||||
|
U32 count = sizeof...(args);
|
||||||
|
for (U32 i = 0; i < count; i += 2)
|
||||||
|
{
|
||||||
|
if (_copy_extension(ext_obj, args...))
|
||||||
|
{
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// internal use aonly, use write_extensions instead
|
||||||
|
template<typename T>
|
||||||
|
inline bool _write_extension(boost::json::object& extensions, const T* src, string_view member)
|
||||||
|
{
|
||||||
|
if (src->mPresent)
|
||||||
|
{
|
||||||
|
Value v;
|
||||||
|
if (write(*src, v))
|
||||||
|
{
|
||||||
|
extensions[member] = v;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write all extensions to dst.extensions
|
||||||
|
// Usage:
|
||||||
|
// write_extensions(dst,
|
||||||
|
// "KHR_materials_unlit", mUnlit,
|
||||||
|
// "KHR_materials_pbrSpecularGlossiness", mPbrSpecularGlossiness);
|
||||||
|
// returns true if any of the extensions are written
|
||||||
|
template<class... Types>
|
||||||
|
inline bool write_extensions(boost::json::object& dst, Types... args)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
boost::json::object extensions;
|
||||||
|
U32 count = sizeof...(args) - 1;
|
||||||
|
|
||||||
|
for (U32 i = 0; i < count; i += 2)
|
||||||
|
{
|
||||||
|
if (_write_extension(extensions, args...))
|
||||||
|
{
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
dst["extensions"] = extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
// conditionally write a member to an object if the member
|
// conditionally write a member to an object if the member
|
||||||
// is not the default value
|
// is not the default value
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
@ -528,7 +628,7 @@ namespace LL
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline bool write(const std::unordered_map<std::string, T>& src, string_view member, boost::json::object& dst, const std::unordered_map<std::string, T>& default_value = std::unordered_map<std::string, T>())
|
inline bool write(const std::unordered_map<std::string, T>& src, string_view member, boost::json::object& dst, const std::unordered_map<std::string, T>& default_value = std::unordered_map<std::string, T>())
|
||||||
{
|
{
|
||||||
|
|
@ -571,6 +671,44 @@ namespace LL
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Accessor::ComponentType
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, Accessor::ComponentType& dst)
|
||||||
|
{
|
||||||
|
if (src.is_int64())
|
||||||
|
{
|
||||||
|
dst = (Accessor::ComponentType)src.get_int64();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const Accessor::ComponentType& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = (S32)src;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Primitive::Mode
|
||||||
|
template<>
|
||||||
|
inline bool copy(const Value& src, Primitive::Mode& dst)
|
||||||
|
{
|
||||||
|
if (src.is_int64())
|
||||||
|
{
|
||||||
|
dst = (Primitive::Mode)src.get_int64();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool write(const Primitive::Mode& src, Value& dst)
|
||||||
|
{
|
||||||
|
dst = (S32)src;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// vec4
|
// vec4
|
||||||
template<>
|
template<>
|
||||||
inline bool copy(const Value& src, vec4& dst)
|
inline bool copy(const Value& src, vec4& dst)
|
||||||
|
|
@ -580,14 +718,17 @@ namespace LL
|
||||||
const boost::json::array& arr = src.as_array();
|
const boost::json::array& arr = src.as_array();
|
||||||
if (arr.size() == 4)
|
if (arr.size() == 4)
|
||||||
{
|
{
|
||||||
if (arr[0].is_double() &&
|
vec4 v;
|
||||||
arr[1].is_double() &&
|
std::error_code ec;
|
||||||
arr[2].is_double() &&
|
|
||||||
arr[3].is_double())
|
v.x = arr[0].to_number<F32>(ec); if (ec) return false;
|
||||||
{
|
v.y = arr[1].to_number<F32>(ec); if (ec) return false;
|
||||||
dst = vec4(arr[0].get_double(), arr[1].get_double(), arr[2].get_double(), arr[3].get_double());
|
v.z = arr[2].to_number<F32>(ec); if (ec) return false;
|
||||||
return true;
|
v.w = arr[3].to_number<F32>(ec); if (ec) return false;
|
||||||
}
|
|
||||||
|
dst = v;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -615,17 +756,13 @@ namespace LL
|
||||||
const boost::json::array& arr = src.as_array();
|
const boost::json::array& arr = src.as_array();
|
||||||
if (arr.size() == 4)
|
if (arr.size() == 4)
|
||||||
{
|
{
|
||||||
if (arr[0].is_double() &&
|
std::error_code ec;
|
||||||
arr[1].is_double() &&
|
dst.x = arr[0].to_number<F32>(ec); if (ec) return false;
|
||||||
arr[2].is_double() &&
|
dst.y = arr[1].to_number<F32>(ec); if (ec) return false;
|
||||||
arr[3].is_double())
|
dst.z = arr[2].to_number<F32>(ec); if (ec) return false;
|
||||||
{
|
dst.w = arr[3].to_number<F32>(ec); if (ec) return false;
|
||||||
dst.x = arr[0].get_double();
|
|
||||||
dst.y = arr[1].get_double();
|
return true;
|
||||||
dst.z = arr[2].get_double();
|
|
||||||
dst.w = arr[3].get_double();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -654,12 +791,13 @@ namespace LL
|
||||||
const boost::json::array& arr = src.as_array();
|
const boost::json::array& arr = src.as_array();
|
||||||
if (arr.size() == 3)
|
if (arr.size() == 3)
|
||||||
{
|
{
|
||||||
if (arr[0].is_double() &&
|
std::error_code ec;
|
||||||
arr[1].is_double() &&
|
vec3 t;
|
||||||
arr[2].is_double())
|
t.x = arr[0].to_number<F32>(ec); if (ec) return false;
|
||||||
{
|
t.y = arr[1].to_number<F32>(ec); if (ec) return false;
|
||||||
dst = vec3(arr[0].get_double(), arr[1].get_double(), arr[2].get_double());
|
t.z = arr[2].to_number<F32>(ec); if (ec) return false;
|
||||||
}
|
|
||||||
|
dst = t;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -701,12 +839,10 @@ namespace LL
|
||||||
template<>
|
template<>
|
||||||
inline bool copy(const Value& src, F32& dst)
|
inline bool copy(const Value& src, F32& dst)
|
||||||
{
|
{
|
||||||
if (src.is_double())
|
std::error_code ec;
|
||||||
{
|
F32 t = src.to_number<F32>(ec); if (ec) return false;
|
||||||
dst = src.get_double();
|
dst = t;
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
@ -740,12 +876,10 @@ namespace LL
|
||||||
template<>
|
template<>
|
||||||
inline bool copy(const Value& src, F64& dst)
|
inline bool copy(const Value& src, F64& dst)
|
||||||
{
|
{
|
||||||
if (src.is_double())
|
std::error_code ec;
|
||||||
{
|
F64 t = src.to_number<F64>(ec); if (ec) return false;
|
||||||
dst = src.get_double();
|
dst = t;
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
@ -830,11 +964,9 @@ namespace LL
|
||||||
|
|
||||||
for (U32 i = 0; i < arr.size(); ++i)
|
for (U32 i = 0; i < arr.size(); ++i)
|
||||||
{
|
{
|
||||||
if (arr[i].is_double())
|
std::error_code ec;
|
||||||
{
|
p[i] = arr[i].to_number<F32>(ec);
|
||||||
p[i] = arr[i].get_double();
|
if (ec)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -881,7 +1013,7 @@ namespace LL
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// ========================================================================================================
|
// ========================================================================================================
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
#include "glm/ext/quaternion_float.hpp"
|
#include "glm/ext/quaternion_float.hpp"
|
||||||
#include "glm/gtx/quaternion.hpp"
|
#include "glm/gtx/quaternion.hpp"
|
||||||
#include "glm/gtx/matrix_decompose.hpp"
|
#include "glm/gtx/matrix_decompose.hpp"
|
||||||
|
#include <boost/json.hpp>
|
||||||
|
|
||||||
// Common types and constants used in the GLTF implementation
|
// Common types and constants used in the GLTF implementation
|
||||||
namespace LL
|
namespace LL
|
||||||
|
|
@ -60,7 +61,23 @@ namespace LL
|
||||||
constexpr S32 MIRRORED_REPEAT = 33648;
|
constexpr S32 MIRRORED_REPEAT = 33648;
|
||||||
constexpr S32 REPEAT = 10497;
|
constexpr S32 REPEAT = 10497;
|
||||||
|
|
||||||
|
|
||||||
class Asset;
|
class Asset;
|
||||||
|
class Material;
|
||||||
|
class Mesh;
|
||||||
|
class Node;
|
||||||
|
class Scene;
|
||||||
|
class Texture;
|
||||||
|
class Sampler;
|
||||||
|
class Image;
|
||||||
|
class Animation;
|
||||||
|
class Skin;
|
||||||
|
class Camera;
|
||||||
|
class Light;
|
||||||
|
class Primitive;
|
||||||
|
class Accessor;
|
||||||
|
class BufferView;
|
||||||
|
class Buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation;
|
* License as published by the Free Software Foundation;
|
||||||
* version 2.1 of the License only.
|
* version 2.1 of the License only.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
|
@ -30,12 +30,205 @@
|
||||||
#include "buffer_util.h"
|
#include "buffer_util.h"
|
||||||
#include "../llviewershadermgr.h"
|
#include "../llviewershadermgr.h"
|
||||||
|
|
||||||
#include "../lltinygltfhelper.h"
|
#include "mikktspace/mikktspace.hh"
|
||||||
|
|
||||||
|
#include "meshoptimizer/meshoptimizer.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace LL::GLTF;
|
using namespace LL::GLTF;
|
||||||
using namespace boost::json;
|
using namespace boost::json;
|
||||||
|
|
||||||
void Primitive::allocateGLResources(Asset& asset)
|
|
||||||
|
// Mesh data useful for Mikktspace tangent generation (and flat normal generation)
|
||||||
|
struct MikktMesh
|
||||||
|
{
|
||||||
|
std::vector<LLVector3> p;
|
||||||
|
std::vector<LLVector3> n;
|
||||||
|
std::vector<LLVector2> tc;
|
||||||
|
std::vector<LLVector4> w;
|
||||||
|
std::vector<LLVector4> t;
|
||||||
|
std::vector<LLColor4U> c;
|
||||||
|
std::vector<U64> j;
|
||||||
|
|
||||||
|
// initialize from src primitive and make an unrolled triangle list
|
||||||
|
// returns false if the Primitive cannot be converted to a triangle list
|
||||||
|
bool copy(const Primitive* prim)
|
||||||
|
{
|
||||||
|
bool indexed = !prim->mIndexArray.empty();
|
||||||
|
U32 vert_count = indexed ? prim->mIndexArray.size() : prim->mPositions.size();
|
||||||
|
|
||||||
|
if (prim->mMode != Primitive::Mode::TRIANGLES)
|
||||||
|
{
|
||||||
|
LL_WARNS("GLTF") << "Unsupported primitive mode for conversion to triangles: " << (S32) prim->mMode << LL_ENDL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.resize(vert_count);
|
||||||
|
n.resize(vert_count);
|
||||||
|
tc.resize(vert_count);
|
||||||
|
c.resize(vert_count);
|
||||||
|
|
||||||
|
bool has_normals = !prim->mNormals.empty();
|
||||||
|
if (has_normals)
|
||||||
|
{
|
||||||
|
n.resize(vert_count);
|
||||||
|
}
|
||||||
|
bool has_tangents = !prim->mTangents.empty();
|
||||||
|
if (has_tangents)
|
||||||
|
{
|
||||||
|
t.resize(vert_count);
|
||||||
|
}
|
||||||
|
bool rigged = !prim->mWeights.empty();
|
||||||
|
if (rigged)
|
||||||
|
{
|
||||||
|
w.resize(vert_count);
|
||||||
|
j.resize(vert_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < vert_count; ++i)
|
||||||
|
{
|
||||||
|
U32 idx = indexed ? prim->mIndexArray[i] : i;
|
||||||
|
|
||||||
|
p[i].set(prim->mPositions[idx].getF32ptr());
|
||||||
|
tc[i].set(prim->mTexCoords[idx]);
|
||||||
|
c[i] = prim->mColors[idx];
|
||||||
|
|
||||||
|
if (has_normals)
|
||||||
|
{
|
||||||
|
n[i].set(prim->mNormals[idx].getF32ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rigged)
|
||||||
|
{
|
||||||
|
w[i].set(prim->mWeights[idx].getF32ptr());
|
||||||
|
j[i] = prim->mJoints[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void genNormals()
|
||||||
|
{
|
||||||
|
U32 tri_count = p.size() / 3;
|
||||||
|
for (U32 i = 0; i < tri_count; ++i)
|
||||||
|
{
|
||||||
|
LLVector3 v0 = p[i * 3];
|
||||||
|
LLVector3 v1 = p[i * 3 + 1];
|
||||||
|
LLVector3 v2 = p[i * 3 + 2];
|
||||||
|
|
||||||
|
LLVector3 normal = (v1 - v0) % (v2 - v0);
|
||||||
|
normal.normalize();
|
||||||
|
|
||||||
|
n[i * 3] = normal;
|
||||||
|
n[i * 3 + 1] = normal;
|
||||||
|
n[i * 3 + 2] = normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void genTangents()
|
||||||
|
{
|
||||||
|
t.resize(p.size());
|
||||||
|
mikk::Mikktspace ctx(*this);
|
||||||
|
ctx.genTangSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
// write to target primitive as an indexed triangle list
|
||||||
|
// Only modifies runtime data, does not modify the original GLTF data
|
||||||
|
void write(Primitive* prim) const
|
||||||
|
{
|
||||||
|
//re-weld
|
||||||
|
meshopt_Stream mos[] =
|
||||||
|
{
|
||||||
|
{ &p[0], sizeof(LLVector3), sizeof(LLVector3) },
|
||||||
|
{ &n[0], sizeof(LLVector3), sizeof(LLVector3) },
|
||||||
|
{ &t[0], sizeof(LLVector4), sizeof(LLVector4) },
|
||||||
|
{ &tc[0], sizeof(LLVector2), sizeof(LLVector2) },
|
||||||
|
{ &c[0], sizeof(LLColor4U), sizeof(LLColor4U) },
|
||||||
|
{ w.empty() ? nullptr : &w[0], sizeof(LLVector4), sizeof(LLVector4) },
|
||||||
|
{ j.empty() ? nullptr : &j[0], sizeof(U64), sizeof(U64) }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<U32> remap;
|
||||||
|
remap.resize(p.size());
|
||||||
|
|
||||||
|
U32 stream_count = w.empty() ? 5 : 7;
|
||||||
|
|
||||||
|
size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, p.size(), p.size(), mos, stream_count);
|
||||||
|
|
||||||
|
prim->mTexCoords.resize(vert_count);
|
||||||
|
prim->mNormals.resize(vert_count);
|
||||||
|
prim->mTangents.resize(vert_count);
|
||||||
|
prim->mPositions.resize(vert_count);
|
||||||
|
prim->mColors.resize(vert_count);
|
||||||
|
if (!w.empty())
|
||||||
|
{
|
||||||
|
prim->mWeights.resize(vert_count);
|
||||||
|
prim->mJoints.resize(vert_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
prim->mIndexArray.resize(remap.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < remap.size(); ++i)
|
||||||
|
{
|
||||||
|
U32 src_idx = i;
|
||||||
|
U32 dst_idx = remap[i];
|
||||||
|
|
||||||
|
prim->mIndexArray[i] = dst_idx;
|
||||||
|
|
||||||
|
prim->mPositions[dst_idx].load3(p[src_idx].mV);
|
||||||
|
prim->mNormals[dst_idx].load3(n[src_idx].mV);
|
||||||
|
prim->mTexCoords[dst_idx] = tc[src_idx];
|
||||||
|
prim->mTangents[dst_idx].loadua(t[src_idx].mV);
|
||||||
|
prim->mColors[dst_idx] = c[src_idx];
|
||||||
|
|
||||||
|
if (!w.empty())
|
||||||
|
{
|
||||||
|
prim->mWeights[dst_idx].loadua(w[src_idx].mV);
|
||||||
|
prim->mJoints[dst_idx] = j[src_idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prim->mGLMode = LLRender::TRIANGLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetNumFaces()
|
||||||
|
{
|
||||||
|
return uint32_t(p.size()/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 Primitive::prep(Asset& asset)
|
||||||
{
|
{
|
||||||
// allocate vertex buffer
|
// allocate vertex buffer
|
||||||
// We diverge from the intent of the GLTF format here to work with our existing render pipeline
|
// We diverge from the intent of the GLTF format here to work with our existing render pipeline
|
||||||
|
|
@ -85,28 +278,23 @@ void Primitive::allocateGLResources(Asset& asset)
|
||||||
{
|
{
|
||||||
Accessor& accessor = asset.mAccessors[mIndices];
|
Accessor& accessor = asset.mAccessors[mIndices];
|
||||||
copy(asset, accessor, mIndexArray);
|
copy(asset, accessor, mIndexArray);
|
||||||
|
|
||||||
|
for (auto& idx : mIndexArray)
|
||||||
|
{
|
||||||
|
if (idx >= mPositions.size())
|
||||||
|
{
|
||||||
|
LL_WARNS("GLTF") << "Invalid index array" << LL_ENDL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
U32 mask = ATTRIBUTE_MASK;
|
U32 mask = LLVertexBuffer::MAP_VERTEX;
|
||||||
|
|
||||||
if (!mWeights.empty())
|
if (!mWeights.empty())
|
||||||
{
|
{
|
||||||
mask |= LLVertexBuffer::MAP_WEIGHT4;
|
mask |= LLVertexBuffer::MAP_WEIGHT4;
|
||||||
}
|
mask |= LLVertexBuffer::MAP_JOINT;
|
||||||
|
|
||||||
if (LLGLSLShader::sCurBoundShaderPtr == nullptr)
|
|
||||||
{ // make sure a shader is bound to satisfy mVertexBuffer->setBuffer
|
|
||||||
gDebugProgram.bind();
|
|
||||||
}
|
|
||||||
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())
|
if (mTexCoords.empty())
|
||||||
|
|
@ -114,23 +302,21 @@ void Primitive::allocateGLResources(Asset& asset)
|
||||||
mTexCoords.resize(mPositions.size());
|
mTexCoords.resize(mPositions.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// flip texcoord y, upload, then flip back (keep the off-spec data in vram only)
|
// TODO: support more than one texcoord set (or no texcoords)
|
||||||
for (auto& tc : mTexCoords)
|
mask |= LLVertexBuffer::MAP_TEXCOORD0;
|
||||||
{
|
|
||||||
tc[1] = 1.f - tc[1];
|
|
||||||
}
|
|
||||||
mVertexBuffer->setTexCoordData(mTexCoords.data());
|
|
||||||
|
|
||||||
for (auto& tc : mTexCoords)
|
|
||||||
{
|
|
||||||
tc[1] = 1.f - tc[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mColors.empty())
|
if (mColors.empty())
|
||||||
{
|
{
|
||||||
mColors.resize(mPositions.size(), LLColor4U::white);
|
mColors.resize(mPositions.size(), LLColor4U::white);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: support colorless vertex buffers
|
||||||
|
mask |= LLVertexBuffer::MAP_COLOR;
|
||||||
|
|
||||||
|
mShaderVariant = 0;
|
||||||
|
|
||||||
|
bool unlit = false;
|
||||||
|
|
||||||
// bake material basecolor into color array
|
// bake material basecolor into color array
|
||||||
if (mMaterial != INVALID_INDEX)
|
if (mMaterial != INVALID_INDEX)
|
||||||
{
|
{
|
||||||
|
|
@ -140,45 +326,140 @@ void Primitive::allocateGLResources(Asset& asset)
|
||||||
{
|
{
|
||||||
dst = LLColor4U(baseColor * LLColor4(dst));
|
dst = LLColor4U(baseColor * LLColor4(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (material.mUnlit.mPresent)
|
||||||
|
{ // material uses KHR_materials_unlit
|
||||||
|
mShaderVariant |= LLGLSLShader::GLTFVariant::UNLIT;
|
||||||
|
unlit = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mNormals.empty() && !unlit)
|
||||||
|
{
|
||||||
|
mTangents.clear();
|
||||||
|
|
||||||
|
if (mMode == Mode::POINTS || mMode == Mode::LINES || mMode == Mode::LINE_LOOP || mMode == Mode::LINE_STRIP)
|
||||||
|
{ //no normals and no surfaces, this primitive is unlit
|
||||||
|
mTangents.clear();
|
||||||
|
mShaderVariant |= LLGLSLShader::GLTFVariant::UNLIT;
|
||||||
|
unlit = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// unroll into non-indexed array of flat shaded triangles
|
||||||
|
MikktMesh data;
|
||||||
|
if (!data.copy(this))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.genNormals();
|
||||||
|
data.genTangents();
|
||||||
|
data.write(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTangents.empty() && !unlit)
|
||||||
|
{ // NOTE: must be done last because tangent generation rewrites the other arrays
|
||||||
|
// adapted from usage of Mikktspace in llvolume.cpp
|
||||||
|
if (mMode == Mode::POINTS || mMode == Mode::LINES || mMode == Mode::LINE_LOOP || mMode == Mode::LINE_STRIP)
|
||||||
|
{
|
||||||
|
// for points and lines, just make sure tangent is perpendicular to normal
|
||||||
|
mTangents.resize(mNormals.size());
|
||||||
|
LLVector4a up(0.f, 0.f, 1.f, 0.f);
|
||||||
|
LLVector4a left(1.f, 0.f, 0.f, 0.f);
|
||||||
|
for (U32 i = 0; i < mNormals.size(); ++i)
|
||||||
|
{
|
||||||
|
if (fabsf(mNormals[i].getF32ptr()[2]) < 0.999f)
|
||||||
|
{
|
||||||
|
mTangents[i] = up.cross3(mNormals[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mTangents[i] = left.cross3(mNormals[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mTangents[i].getF32ptr()[3] = 1.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MikktMesh data;
|
||||||
|
if (!data.copy(this))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.genTangents();
|
||||||
|
data.write(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mNormals.empty())
|
||||||
|
{
|
||||||
|
mask |= LLVertexBuffer::MAP_NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mTangents.empty())
|
||||||
|
{
|
||||||
|
mask |= LLVertexBuffer::MAP_TANGENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LLGLSLShader::sCurBoundShaderPtr == nullptr)
|
||||||
|
{ // make sure a shader is bound to satisfy mVertexBuffer->setBuffer
|
||||||
|
gDebugProgram.bind();
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
mVertexBuffer->setColorData(mColors.data());
|
mVertexBuffer->setColorData(mColors.data());
|
||||||
|
|
||||||
if (mNormals.empty())
|
if (!mNormals.empty())
|
||||||
{
|
{
|
||||||
mNormals.resize(mPositions.size(), LLVector4a(0, 0, 1, 0));
|
mVertexBuffer->setNormalData(mNormals.data());
|
||||||
}
|
}
|
||||||
|
if (!mTangents.empty())
|
||||||
mVertexBuffer->setNormalData(mNormals.data());
|
|
||||||
|
|
||||||
if (mTangents.empty())
|
|
||||||
{
|
{
|
||||||
// TODO: generate tangents if needed
|
mVertexBuffer->setTangentData(mTangents.data());
|
||||||
mTangents.resize(mPositions.size(), LLVector4a(1, 0, 0, 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mVertexBuffer->setTangentData(mTangents.data());
|
|
||||||
|
|
||||||
if (!mWeights.empty())
|
if (!mWeights.empty())
|
||||||
{
|
{
|
||||||
std::vector<LLVector4a> weight_data;
|
mShaderVariant |= LLGLSLShader::GLTFVariant::RIGGED;
|
||||||
weight_data.resize(mWeights.size());
|
mVertexBuffer->setWeight4Data(mWeights.data());
|
||||||
|
mVertexBuffer->setJointData(mJoints.data());
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 (!mIndexArray.empty())
|
||||||
|
{
|
||||||
|
mVertexBuffer->setIndexData(mIndexArray.data());
|
||||||
|
}
|
||||||
|
|
||||||
createOctree();
|
createOctree();
|
||||||
|
|
||||||
mVertexBuffer->unbind();
|
mVertexBuffer->unbind();
|
||||||
|
|
||||||
|
Material& material = asset.mMaterials[mMaterial];
|
||||||
|
if (material.mAlphaMode == Material::AlphaMode::BLEND)
|
||||||
|
{
|
||||||
|
mShaderVariant |= LLGLSLShader::GLTFVariant::ALPHA_BLEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initOctreeTriangle(LLVolumeTriangle* tri, F32 scaler, S32 i0, S32 i1, S32 i2, const LLVector4a& v0, const LLVector4a& v1, const LLVector4a& v2)
|
void initOctreeTriangle(LLVolumeTriangle* tri, F32 scaler, S32 i0, S32 i1, S32 i2, const LLVector4a& v0, const LLVector4a& v1, const LLVector4a& v2)
|
||||||
|
|
@ -224,7 +505,7 @@ void Primitive::createOctree()
|
||||||
|
|
||||||
F32 scaler = 0.25f;
|
F32 scaler = 0.25f;
|
||||||
|
|
||||||
if (mMode == TINYGLTF_MODE_TRIANGLES)
|
if (mMode == Mode::TRIANGLES)
|
||||||
{
|
{
|
||||||
const U32 num_triangles = mVertexBuffer->getNumIndices() / 3;
|
const U32 num_triangles = mVertexBuffer->getNumIndices() / 3;
|
||||||
// Initialize all the triangles we need
|
// Initialize all the triangles we need
|
||||||
|
|
@ -241,14 +522,14 @@ void Primitive::createOctree()
|
||||||
const LLVector4a& v0 = mPositions[i0];
|
const LLVector4a& v0 = mPositions[i0];
|
||||||
const LLVector4a& v1 = mPositions[i1];
|
const LLVector4a& v1 = mPositions[i1];
|
||||||
const LLVector4a& v2 = mPositions[i2];
|
const LLVector4a& v2 = mPositions[i2];
|
||||||
|
|
||||||
initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2);
|
initOctreeTriangle(tri, scaler, i0, i1, i2, v0, v1, v2);
|
||||||
|
|
||||||
//insert
|
//insert
|
||||||
mOctree->insert(tri);
|
mOctree->insert(tri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (mMode == TINYGLTF_MODE_TRIANGLE_STRIP)
|
else if (mMode == Mode::TRIANGLE_STRIP)
|
||||||
{
|
{
|
||||||
const U32 num_triangles = mVertexBuffer->getNumIndices() - 2;
|
const U32 num_triangles = mVertexBuffer->getNumIndices() - 2;
|
||||||
// Initialize all the triangles we need
|
// Initialize all the triangles we need
|
||||||
|
|
@ -272,7 +553,7 @@ void Primitive::createOctree()
|
||||||
mOctree->insert(tri);
|
mOctree->insert(tri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (mMode == TINYGLTF_MODE_TRIANGLE_FAN)
|
else if (mMode == Mode::TRIANGLE_FAN)
|
||||||
{
|
{
|
||||||
const U32 num_triangles = mVertexBuffer->getNumIndices() - 2;
|
const U32 num_triangles = mVertexBuffer->getNumIndices() - 2;
|
||||||
// Initialize all the triangles we need
|
// Initialize all the triangles we need
|
||||||
|
|
@ -296,14 +577,14 @@ void Primitive::createOctree()
|
||||||
mOctree->insert(tri);
|
mOctree->insert(tri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (mMode == TINYGLTF_MODE_POINTS ||
|
else if (mMode == Mode::POINTS ||
|
||||||
mMode == TINYGLTF_MODE_LINE ||
|
mMode == Mode::LINES ||
|
||||||
mMode == TINYGLTF_MODE_LINE_LOOP ||
|
mMode == Mode::LINE_LOOP ||
|
||||||
mMode == TINYGLTF_MODE_LINE_STRIP)
|
mMode == Mode::LINE_STRIP)
|
||||||
{
|
{
|
||||||
// nothing to do, no volume... maybe add some collision geometry around these primitive types?
|
// nothing to do, no volume... maybe add some collision geometry around these primitive types?
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LL_ERRS() << "Unsupported Primitive mode" << LL_ENDL;
|
LL_ERRS() << "Unsupported Primitive mode" << LL_ENDL;
|
||||||
|
|
@ -357,23 +638,23 @@ Primitive::~Primitive()
|
||||||
mOctree = nullptr;
|
mOctree = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
U32 gltf_mode_to_gl_mode(U32 mode)
|
LLRender::eGeomModes gltf_mode_to_gl_mode(Primitive::Mode mode)
|
||||||
{
|
{
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case TINYGLTF_MODE_POINTS:
|
case Primitive::Mode::POINTS:
|
||||||
return LLRender::POINTS;
|
return LLRender::POINTS;
|
||||||
case TINYGLTF_MODE_LINE:
|
case Primitive::Mode::LINES:
|
||||||
return LLRender::LINES;
|
return LLRender::LINES;
|
||||||
case TINYGLTF_MODE_LINE_LOOP:
|
case Primitive::Mode::LINE_LOOP:
|
||||||
return LLRender::LINE_LOOP;
|
return LLRender::LINE_LOOP;
|
||||||
case TINYGLTF_MODE_LINE_STRIP:
|
case Primitive::Mode::LINE_STRIP:
|
||||||
return LLRender::LINE_STRIP;
|
return LLRender::LINE_STRIP;
|
||||||
case TINYGLTF_MODE_TRIANGLES:
|
case Primitive::Mode::TRIANGLES:
|
||||||
return LLRender::TRIANGLES;
|
return LLRender::TRIANGLES;
|
||||||
case TINYGLTF_MODE_TRIANGLE_STRIP:
|
case Primitive::Mode::TRIANGLE_STRIP:
|
||||||
return LLRender::TRIANGLE_STRIP;
|
return LLRender::TRIANGLE_STRIP;
|
||||||
case TINYGLTF_MODE_TRIANGLE_FAN:
|
case Primitive::Mode::TRIANGLE_FAN:
|
||||||
return LLRender::TRIANGLE_FAN;
|
return LLRender::TRIANGLE_FAN;
|
||||||
default:
|
default:
|
||||||
return LLRender::TRIANGLES;
|
return LLRender::TRIANGLES;
|
||||||
|
|
@ -383,7 +664,7 @@ U32 gltf_mode_to_gl_mode(U32 mode)
|
||||||
void Primitive::serialize(boost::json::object& dst) const
|
void Primitive::serialize(boost::json::object& dst) const
|
||||||
{
|
{
|
||||||
write(mMaterial, "material", dst, -1);
|
write(mMaterial, "material", dst, -1);
|
||||||
write(mMode, "mode", dst, TINYGLTF_MODE_TRIANGLES);
|
write(mMode, "mode", dst, Primitive::Mode::TRIANGLES);
|
||||||
write(mIndices, "indices", dst, INVALID_INDEX);
|
write(mIndices, "indices", dst, INVALID_INDEX);
|
||||||
write(mAttributes, "attributes", dst);
|
write(mAttributes, "attributes", dst);
|
||||||
}
|
}
|
||||||
|
|
@ -402,24 +683,3 @@ const Primitive& Primitive::operator=(const Value& src)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
mGLMode = gltf_mode_to_gl_mode(mMode);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -38,27 +38,31 @@ namespace LL
|
||||||
using Value = boost::json::value;
|
using Value = boost::json::value;
|
||||||
class Asset;
|
class Asset;
|
||||||
|
|
||||||
constexpr U32 ATTRIBUTE_MASK =
|
|
||||||
LLVertexBuffer::MAP_VERTEX |
|
|
||||||
LLVertexBuffer::MAP_NORMAL |
|
|
||||||
LLVertexBuffer::MAP_TEXCOORD0 |
|
|
||||||
LLVertexBuffer::MAP_TANGENT |
|
|
||||||
LLVertexBuffer::MAP_COLOR;
|
|
||||||
|
|
||||||
class Primitive
|
class Primitive
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum class Mode : U8
|
||||||
|
{
|
||||||
|
POINTS,
|
||||||
|
LINES,
|
||||||
|
LINE_LOOP,
|
||||||
|
LINE_STRIP,
|
||||||
|
TRIANGLES,
|
||||||
|
TRIANGLE_STRIP,
|
||||||
|
TRIANGLE_FAN
|
||||||
|
};
|
||||||
|
|
||||||
~Primitive();
|
~Primitive();
|
||||||
|
|
||||||
// GPU copy of mesh data
|
// GPU copy of mesh data
|
||||||
LLPointer<LLVertexBuffer> mVertexBuffer;
|
LLPointer<LLVertexBuffer> mVertexBuffer;
|
||||||
|
|
||||||
// CPU copy of mesh data
|
// CPU copy of mesh data, keep these as LLVector types for compatibility with raycasting code
|
||||||
std::vector<LLVector2> mTexCoords;
|
std::vector<LLVector2> mTexCoords;
|
||||||
std::vector<LLVector4a> mNormals;
|
std::vector<LLVector4a> mNormals;
|
||||||
std::vector<LLVector4a> mTangents;
|
std::vector<LLVector4a> mTangents;
|
||||||
std::vector<LLVector4a> mPositions;
|
std::vector<LLVector4a> mPositions;
|
||||||
std::vector<LLVector4a> mJoints;
|
std::vector<U64> mJoints;
|
||||||
std::vector<LLVector4a> mWeights;
|
std::vector<LLVector4a> mWeights;
|
||||||
std::vector<LLColor4U> mColors;
|
std::vector<LLColor4U> mColors;
|
||||||
std::vector<U32> mIndexArray;
|
std::vector<U32> mIndexArray;
|
||||||
|
|
@ -66,18 +70,22 @@ namespace LL
|
||||||
// raycast acceleration structure
|
// raycast acceleration structure
|
||||||
LLPointer<LLVolumeOctree> mOctree;
|
LLPointer<LLVolumeOctree> mOctree;
|
||||||
std::vector<LLVolumeTriangle> mOctreeTriangles;
|
std::vector<LLVolumeTriangle> mOctreeTriangles;
|
||||||
|
|
||||||
S32 mMaterial = -1;
|
S32 mMaterial = -1;
|
||||||
S32 mMode = TINYGLTF_MODE_TRIANGLES; // default to triangles
|
Mode mMode = Mode::TRIANGLES; // default to triangles
|
||||||
U32 mGLMode = LLRender::TRIANGLES;
|
LLRender::eGeomModes mGLMode = LLRender::TRIANGLES; // for use with LLRender
|
||||||
S32 mIndices = -1;
|
S32 mIndices = -1;
|
||||||
|
|
||||||
|
// shader variant according to LLGLSLShader::GLTFVariant flags
|
||||||
|
U8 mShaderVariant = 0;
|
||||||
|
|
||||||
std::unordered_map<std::string, S32> mAttributes;
|
std::unordered_map<std::string, S32> mAttributes;
|
||||||
|
|
||||||
// create octree based on vertex buffer
|
// create octree based on vertex buffer
|
||||||
// must be called before buffer is unmapped and after buffer is populated with good data
|
// must be called before buffer is unmapped and after buffer is populated with good data
|
||||||
void createOctree();
|
void createOctree();
|
||||||
|
|
||||||
//get the LLVolumeTriangle that intersects with the given line segment at the point
|
//get the LLVolumeTriangle that intersects with the given line segment at the point
|
||||||
//closest to start. Moves end to the point of intersection. Returns nullptr if no intersection.
|
//closest to start. Moves end to the point of intersection. Returns nullptr if no intersection.
|
||||||
//Line segment must be in the same coordinate frame as this Primitive
|
//Line segment must be in the same coordinate frame as this Primitive
|
||||||
const LLVolumeTriangle* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
|
const LLVolumeTriangle* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
|
||||||
|
|
@ -86,12 +94,11 @@ namespace LL
|
||||||
LLVector4a* normal = NULL, // return the surface normal at the intersection point
|
LLVector4a* normal = NULL, // return the surface normal at the intersection point
|
||||||
LLVector4a* tangent = NULL // return the surface tangent at the intersection point
|
LLVector4a* tangent = NULL // return the surface tangent at the intersection point
|
||||||
);
|
);
|
||||||
|
|
||||||
void serialize(boost::json::object& obj) const;
|
void serialize(boost::json::object& obj) const;
|
||||||
const Primitive& operator=(const Value& src);
|
const Primitive& operator=(const Value& src);
|
||||||
const Primitive& operator=(const tinygltf::Primitive& src);
|
|
||||||
|
|
||||||
void allocateGLResources(Asset& asset);
|
bool prep(Asset& asset);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,32 +107,6 @@ void GLTFSceneManager::saveAs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLTFSceneManager::decomposeSelection()
|
|
||||||
{
|
|
||||||
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
|
|
||||||
if (obj && obj->mGLTFAsset)
|
|
||||||
{
|
|
||||||
LLFilePickerReplyThread::startPicker(
|
|
||||||
[](const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)
|
|
||||||
{
|
|
||||||
if (LLAppViewer::instance()->quitRequested())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (filenames.size() > 0)
|
|
||||||
{
|
|
||||||
GLTFSceneManager::instance().decomposeSelection(filenames[0]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
LLFilePicker::FFSAVE_GLTF,
|
|
||||||
"scene.gltf");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LLNotificationsUtil::add("GLTFSaveSelection");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTFSceneManager::uploadSelection()
|
void GLTFSceneManager::uploadSelection()
|
||||||
{
|
{
|
||||||
if (mUploadingAsset)
|
if (mUploadingAsset)
|
||||||
|
|
@ -153,77 +127,86 @@ void GLTFSceneManager::uploadSelection()
|
||||||
|
|
||||||
for (auto& image : asset.mImages)
|
for (auto& image : asset.mImages)
|
||||||
{
|
{
|
||||||
if (!image.mData.empty())
|
if (image.mTexture.notNull())
|
||||||
{
|
{
|
||||||
mPendingImageUploads++;
|
mPendingImageUploads++;
|
||||||
|
|
||||||
LLPointer<LLImageRaw> raw = new LLImageRaw(image.mWidth, image.mHeight, image.mComponent);
|
LLPointer<LLImageRaw> raw;
|
||||||
U8* data = raw->allocateData();
|
|
||||||
llassert_always(image.mData.size() == raw->getDataSize());
|
|
||||||
memcpy(data, image.mData.data(), image.mData.size());
|
|
||||||
|
|
||||||
// for GLTF native content, store image in GLTF orientation
|
if (image.mBufferView != INVALID_INDEX)
|
||||||
raw->verticalFlip();
|
|
||||||
|
|
||||||
LLPointer<LLImageJ2C> j2c = LLViewerTextureList::convertToUploadFile(raw);
|
|
||||||
|
|
||||||
std::string buffer;
|
|
||||||
buffer.assign((const char*)j2c->getData(), j2c->getDataSize());
|
|
||||||
|
|
||||||
LLUUID asset_id = LLUUID::generateNewID();
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
S32 idx = (S32)(&image - &asset.mImages[0]);
|
|
||||||
|
|
||||||
if (image.mName.empty())
|
|
||||||
{
|
{
|
||||||
|
BufferView& view = asset.mBufferViews[image.mBufferView];
|
||||||
|
Buffer& buffer = asset.mBuffers[view.mBuffer];
|
||||||
|
|
||||||
name = llformat("Image_%d", idx);
|
raw = LLViewerTextureManager::getRawImageFromMemory(buffer.mData.data() + view.mByteOffset, view.mByteLength, image.mMimeType);
|
||||||
|
|
||||||
|
image.clearData(asset);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
name = image.mName;
|
raw = image.mTexture->getCachedRawImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason)
|
if (raw.notNull())
|
||||||
{
|
{
|
||||||
// TODO: handle failure
|
LLPointer<LLImageJ2C> j2c = LLViewerTextureList::convertToUploadFile(raw);
|
||||||
mPendingImageUploads--;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
std::string buffer;
|
||||||
|
buffer.assign((const char*)j2c->getData(), j2c->getDataSize());
|
||||||
|
|
||||||
LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, idx, raw, j2c](LLUUID assetId, LLSD response)
|
LLUUID asset_id = LLUUID::generateNewID();
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
S32 idx = (S32)(&image - &asset.mImages[0]);
|
||||||
|
|
||||||
|
if (image.mName.empty())
|
||||||
{
|
{
|
||||||
if (mUploadingAsset && mUploadingAsset->mImages.size() > idx)
|
|
||||||
|
name = llformat("Image_%d", idx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = image.mName;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason)
|
||||||
{
|
{
|
||||||
mUploadingAsset->mImages[idx].mUri = assetId.asString();
|
// TODO: handle failure
|
||||||
mPendingImageUploads--;
|
mPendingImageUploads--;
|
||||||
}
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(j2c);
|
|
||||||
|
|
||||||
LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewBufferedResourceUploadInfo>(
|
LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, idx, raw, j2c](LLUUID assetId, LLSD response)
|
||||||
buffer,
|
{
|
||||||
asset_id,
|
if (mUploadingAsset && mUploadingAsset->mImages.size() > idx)
|
||||||
name,
|
{
|
||||||
name,
|
mUploadingAsset->mImages[idx].mUri = assetId.asString();
|
||||||
0,
|
mPendingImageUploads--;
|
||||||
LLFolderType::FT_TEXTURE,
|
}
|
||||||
LLInventoryType::IT_TEXTURE,
|
};
|
||||||
LLAssetType::AT_TEXTURE,
|
|
||||||
LLFloaterPerms::getNextOwnerPerms("Uploads"),
|
|
||||||
LLFloaterPerms::getGroupPerms("Uploads"),
|
|
||||||
LLFloaterPerms::getEveryonePerms("Uploads"),
|
|
||||||
expected_upload_cost,
|
|
||||||
false,
|
|
||||||
finish,
|
|
||||||
failure));
|
|
||||||
|
|
||||||
upload_new_resource(uploadInfo);
|
S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(j2c);
|
||||||
|
|
||||||
image.clearData(asset);
|
LLResourceUploadInfo::ptr_t uploadInfo(std::make_shared<LLNewBufferedResourceUploadInfo>(
|
||||||
|
buffer,
|
||||||
|
asset_id,
|
||||||
|
name,
|
||||||
|
name,
|
||||||
|
0,
|
||||||
|
LLFolderType::FT_TEXTURE,
|
||||||
|
LLInventoryType::IT_TEXTURE,
|
||||||
|
LLAssetType::AT_TEXTURE,
|
||||||
|
LLFloaterPerms::getNextOwnerPerms("Uploads"),
|
||||||
|
LLFloaterPerms::getGroupPerms("Uploads"),
|
||||||
|
LLFloaterPerms::getEveryonePerms("Uploads"),
|
||||||
|
expected_upload_cost,
|
||||||
|
false,
|
||||||
|
finish,
|
||||||
|
failure));
|
||||||
|
|
||||||
|
upload_new_resource(uploadInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,62 +280,45 @@ void GLTFSceneManager::uploadSelection()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLTFSceneManager::decomposeSelection(const std::string& filename)
|
|
||||||
{
|
|
||||||
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
|
|
||||||
if (obj && obj->mGLTFAsset)
|
|
||||||
{
|
|
||||||
// copy asset out for decomposition
|
|
||||||
Asset asset = *obj->mGLTFAsset;
|
|
||||||
|
|
||||||
// decompose the asset into component parts
|
|
||||||
asset.decompose(filename);
|
|
||||||
|
|
||||||
// copy decomposed asset into tinygltf for serialization
|
|
||||||
tinygltf::Model model;
|
|
||||||
asset.save(model);
|
|
||||||
|
|
||||||
LLTinyGLTFHelper::saveModel(filename, model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GLTFSceneManager::save(const std::string& filename)
|
void GLTFSceneManager::save(const std::string& filename)
|
||||||
{
|
{
|
||||||
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
|
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
|
||||||
if (obj && obj->mGLTFAsset)
|
if (obj && obj->mGLTFAsset)
|
||||||
{
|
{
|
||||||
Asset* asset = obj->mGLTFAsset.get();
|
Asset* asset = obj->mGLTFAsset.get();
|
||||||
tinygltf::Model model;
|
if (!asset->save(filename))
|
||||||
asset->save(model);
|
{
|
||||||
|
LLNotificationsUtil::add("GLTFSaveFailed");
|
||||||
LLTinyGLTFHelper::saveModel(filename, model);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLTFSceneManager::load(const std::string& filename)
|
void GLTFSceneManager::load(const std::string& filename)
|
||||||
{
|
{
|
||||||
tinygltf::Model model;
|
|
||||||
LLTinyGLTFHelper::loadModel(filename, model);
|
|
||||||
|
|
||||||
std::shared_ptr<Asset> asset = std::make_shared<Asset>();
|
std::shared_ptr<Asset> asset = std::make_shared<Asset>();
|
||||||
*asset = model;
|
|
||||||
|
|
||||||
gDebugProgram.bind(); // bind a shader to satisfy LLVertexBuffer assertions
|
if (asset->load(filename))
|
||||||
asset->allocateGLResources(filename, model);
|
{
|
||||||
asset->updateTransforms();
|
gDebugProgram.bind(); // bind a shader to satisfy LLVertexBuffer assertions
|
||||||
|
asset->updateTransforms();
|
||||||
|
|
||||||
// hang the asset off the currently selected object, or off of the avatar if no object is selected
|
// hang the asset off the currently selected object, or off of the avatar if no object is selected
|
||||||
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
|
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
|
||||||
|
|
||||||
if (obj)
|
if (obj)
|
||||||
{ // assign to self avatar
|
{ // assign to self avatar
|
||||||
obj->mGLTFAsset = asset;
|
obj->mGLTFAsset = asset;
|
||||||
obj->markForUpdate();
|
obj->markForUpdate();
|
||||||
if (std::find(mObjects.begin(), mObjects.end(), obj) == mObjects.end())
|
if (std::find(mObjects.begin(), mObjects.end(), obj) == mObjects.end())
|
||||||
{
|
{
|
||||||
mObjects.push_back(obj);
|
mObjects.push_back(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLNotificationsUtil::add("GLTFLoadFailed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GLTFSceneManager::~GLTFSceneManager()
|
GLTFSceneManager::~GLTFSceneManager()
|
||||||
|
|
@ -392,32 +358,26 @@ void GLTFSceneManager::onGLTFBinLoadComplete(const LLUUID& id, LLAssetType::ETyp
|
||||||
// find the Buffer with the given id in the asset
|
// find the Buffer with the given id in the asset
|
||||||
if (obj->mGLTFAsset)
|
if (obj->mGLTFAsset)
|
||||||
{
|
{
|
||||||
for (auto& buffer : obj->mGLTFAsset->mBuffers)
|
obj->mGLTFAsset->mPendingBuffers--;
|
||||||
|
|
||||||
|
|
||||||
|
if (obj->mGLTFAsset->mPendingBuffers == 0)
|
||||||
{
|
{
|
||||||
LLUUID buffer_id;
|
if (obj->mGLTFAsset->prep())
|
||||||
if (LLUUID::parseUUID(buffer.mUri, &buffer_id) && buffer_id == id)
|
|
||||||
{
|
{
|
||||||
LLFileSystem file(id, asset_type, LLFileSystem::READ);
|
GLTFSceneManager& mgr = GLTFSceneManager::instance();
|
||||||
|
if (std::find(mgr.mObjects.begin(), mgr.mObjects.end(), obj) == mgr.mObjects.end())
|
||||||
buffer.mData.resize(file.getSize());
|
|
||||||
file.read((U8*)buffer.mData.data(), buffer.mData.size());
|
|
||||||
|
|
||||||
obj->mGLTFAsset->mPendingBuffers--;
|
|
||||||
|
|
||||||
if (obj->mGLTFAsset->mPendingBuffers == 0)
|
|
||||||
{
|
{
|
||||||
obj->mGLTFAsset->allocateGLResources();
|
GLTFSceneManager::instance().mObjects.push_back(obj);
|
||||||
GLTFSceneManager& mgr = GLTFSceneManager::instance();
|
|
||||||
if (std::find(mgr.mObjects.begin(), mgr.mObjects.end(), obj) == mgr.mObjects.end())
|
|
||||||
{
|
|
||||||
GLTFSceneManager::instance().mObjects.push_back(obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LL_WARNS("GLTF") << "Failed to prepare GLTF asset: " << id << LL_ENDL;
|
||||||
|
obj->mGLTFAsset = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -492,30 +452,9 @@ void GLTFSceneManager::update()
|
||||||
{
|
{
|
||||||
if (mPendingImageUploads == 0 && mPendingBinaryUploads == 0)
|
if (mPendingImageUploads == 0 && mPendingBinaryUploads == 0)
|
||||||
{
|
{
|
||||||
std::string filename(gDirUtilp->getTempDir() + "/upload.gltf");
|
|
||||||
#if 0
|
|
||||||
tinygltf::Model model;
|
|
||||||
mUploadingAsset->save(model);
|
|
||||||
|
|
||||||
tinygltf::TinyGLTF writer;
|
|
||||||
|
|
||||||
writer.WriteGltfSceneToFile(&model, filename, false, false, true, false);
|
|
||||||
#else
|
|
||||||
boost::json::object obj;
|
boost::json::object obj;
|
||||||
mUploadingAsset->serialize(obj);
|
mUploadingAsset->serialize(obj);
|
||||||
std::string json = boost::json::serialize(obj, {});
|
std::string buffer = boost::json::serialize(obj, {});
|
||||||
|
|
||||||
{
|
|
||||||
std::ofstream o(filename);
|
|
||||||
o << json;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::ifstream t(filename);
|
|
||||||
std::stringstream str;
|
|
||||||
str << t.rdbuf();
|
|
||||||
|
|
||||||
std::string buffer = str.str();
|
|
||||||
|
|
||||||
LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason)
|
LLNewBufferedResourceUploadInfo::uploadFailure_f failure = [this](LLUUID assetId, LLSD response, std::string reason)
|
||||||
{
|
{
|
||||||
|
|
@ -589,7 +528,26 @@ void GLTFSceneManager::update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLTFSceneManager::render(bool opaque, bool rigged)
|
void GLTFSceneManager::render(bool opaque, bool rigged, bool unlit)
|
||||||
|
{
|
||||||
|
U8 variant = 0;
|
||||||
|
if (rigged)
|
||||||
|
{
|
||||||
|
variant |= LLGLSLShader::GLTFVariant::RIGGED;
|
||||||
|
}
|
||||||
|
if (!opaque)
|
||||||
|
{
|
||||||
|
variant |= LLGLSLShader::GLTFVariant::ALPHA_BLEND;
|
||||||
|
}
|
||||||
|
if (unlit)
|
||||||
|
{
|
||||||
|
variant |= LLGLSLShader::GLTFVariant::UNLIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
render(variant);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLTFSceneManager::render(U8 variant)
|
||||||
{
|
{
|
||||||
// for debugging, just render the whole scene as opaque
|
// for debugging, just render the whole scene as opaque
|
||||||
// by traversing the whole scenegraph
|
// by traversing the whole scenegraph
|
||||||
|
|
@ -598,6 +556,8 @@ void GLTFSceneManager::render(bool opaque, bool rigged)
|
||||||
|
|
||||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||||
|
|
||||||
|
bool rigged = variant & LLGLSLShader::GLTFVariant::RIGGED;
|
||||||
|
|
||||||
for (U32 i = 0; i < mObjects.size(); ++i)
|
for (U32 i = 0; i < mObjects.size(); ++i)
|
||||||
{
|
{
|
||||||
if (mObjects[i]->isDead() || mObjects[i]->mGLTFAsset == nullptr)
|
if (mObjects[i]->isDead() || mObjects[i]->mGLTFAsset == nullptr)
|
||||||
|
|
@ -608,7 +568,6 @@ void GLTFSceneManager::render(bool opaque, bool rigged)
|
||||||
}
|
}
|
||||||
|
|
||||||
Asset* asset = mObjects[i]->mGLTFAsset.get();
|
Asset* asset = mObjects[i]->mGLTFAsset.get();
|
||||||
|
|
||||||
gGL.pushMatrix();
|
gGL.pushMatrix();
|
||||||
|
|
||||||
LLMatrix4a mat = mObjects[i]->getGLTFAssetToAgentTransform();
|
LLMatrix4a mat = mObjects[i]->getGLTFAssetToAgentTransform();
|
||||||
|
|
@ -620,12 +579,172 @@ void GLTFSceneManager::render(bool opaque, bool rigged)
|
||||||
|
|
||||||
mat4 mdv = glm::make_mat4(modelview.getF32ptr());
|
mat4 mdv = glm::make_mat4(modelview.getF32ptr());
|
||||||
asset->updateRenderTransforms(mdv);
|
asset->updateRenderTransforms(mdv);
|
||||||
asset->render(opaque, rigged);
|
|
||||||
|
if (rigged)
|
||||||
|
{ // provide a modelview matrix that goes from asset to camera space for rigged render passes
|
||||||
|
// (matrix palettes are in asset space)
|
||||||
|
gGL.loadMatrix(glm::value_ptr(mdv));
|
||||||
|
}
|
||||||
|
render(*asset, variant);
|
||||||
|
|
||||||
gGL.popMatrix();
|
gGL.popMatrix();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLTFSceneManager::render(Asset& asset, U8 variant)
|
||||||
|
{
|
||||||
|
bool opaque = !(variant & LLGLSLShader::GLTFVariant::ALPHA_BLEND);
|
||||||
|
bool rigged = variant & LLGLSLShader::GLTFVariant::RIGGED;
|
||||||
|
|
||||||
|
if (opaque)
|
||||||
|
{
|
||||||
|
gGLTFPBRMetallicRoughnessProgram.bind(variant);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // alpha shaders need all the shadow map setup etc
|
||||||
|
gPipeline.bindDeferredShader(gGLTFPBRMetallicRoughnessProgram.mGLTFVariants[variant]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& node : asset.mNodes)
|
||||||
|
{
|
||||||
|
if (node.mSkin != INVALID_INDEX)
|
||||||
|
{
|
||||||
|
if (rigged)
|
||||||
|
{
|
||||||
|
Skin& skin = asset.mSkins[node.mSkin];
|
||||||
|
glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_JOINTS, skin.mUBO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.mMesh != INVALID_INDEX)
|
||||||
|
{
|
||||||
|
Mesh& mesh = asset.mMeshes[node.mMesh];
|
||||||
|
for (auto& primitive : mesh.mPrimitives)
|
||||||
|
{
|
||||||
|
if (primitive.mShaderVariant != variant)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rigged)
|
||||||
|
{
|
||||||
|
gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix));
|
||||||
|
}
|
||||||
|
bool cull = true;
|
||||||
|
if (primitive.mMaterial != INVALID_INDEX)
|
||||||
|
{
|
||||||
|
Material& material = asset.mMaterials[primitive.mMaterial];
|
||||||
|
bind(asset, material);
|
||||||
|
|
||||||
|
cull = !material.mDoubleSided;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bindTexture(Asset& asset, S32 uniform, Material::TextureInfo& info, LLViewerTexture* fallback)
|
||||||
|
{
|
||||||
|
if (info.mIndex != INVALID_INDEX)
|
||||||
|
{
|
||||||
|
LLViewerTexture* tex = asset.mImages[asset.mTextures[info.mIndex].mSource].mTexture;
|
||||||
|
if (tex)
|
||||||
|
{
|
||||||
|
tex->addTextureStats(2048.f * 2048.f);
|
||||||
|
LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, tex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, fallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, fallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GLTFSceneManager::bind(Asset& asset, Material& material)
|
||||||
|
{
|
||||||
|
// bind for rendering (derived from LLFetchedGLTFMaterial::bind)
|
||||||
|
// glTF 2.0 Specification 3.9.4. Alpha Coverage
|
||||||
|
// mAlphaCutoff is only valid for LLGLTFMaterial::ALPHA_MODE_MASK
|
||||||
|
F32 min_alpha = -1.0;
|
||||||
|
|
||||||
|
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
|
||||||
|
|
||||||
|
if (!LLPipeline::sShadowRender || (material.mAlphaMode == Material::AlphaMode::BLEND))
|
||||||
|
{
|
||||||
|
if (material.mAlphaMode == Material::AlphaMode::MASK)
|
||||||
|
{
|
||||||
|
// dividing the alpha cutoff by transparency here allows the shader to compare against
|
||||||
|
// the alpha value of the texture without needing the transparency value
|
||||||
|
if (material.mPbrMetallicRoughness.mBaseColorFactor.a > 0.f)
|
||||||
|
{
|
||||||
|
min_alpha = material.mAlphaCutoff / material.mPbrMetallicRoughness.mBaseColorFactor.a;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
min_alpha = 1024.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shader->uniform1f(LLShaderMgr::MINIMUM_ALPHA, min_alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
bindTexture(asset, LLShaderMgr::DIFFUSE_MAP, material.mPbrMetallicRoughness.mBaseColorTexture, LLViewerFetchedTexture::sWhiteImagep);
|
||||||
|
|
||||||
|
F32 base_color_packed[8];
|
||||||
|
//mTextureTransform[GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed);
|
||||||
|
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed);
|
||||||
|
shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, (F32*)base_color_packed);
|
||||||
|
|
||||||
|
if (!LLPipeline::sShadowRender)
|
||||||
|
{
|
||||||
|
bindTexture(asset, LLShaderMgr::NORMAL_MAP, material.mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep);
|
||||||
|
bindTexture(asset, LLShaderMgr::METALLIC_ROUGHNESS_MAP, material.mPbrMetallicRoughness.mMetallicRoughnessTexture, LLViewerFetchedTexture::sWhiteImagep);
|
||||||
|
bindTexture(asset, LLShaderMgr::OCCLUSION_MAP, material.mOcclusionTexture, LLViewerFetchedTexture::sWhiteImagep);
|
||||||
|
bindTexture(asset, LLShaderMgr::EMISSIVE_MAP, material.mEmissiveTexture, LLViewerFetchedTexture::sWhiteImagep);
|
||||||
|
|
||||||
|
// NOTE: base color factor is baked into vertex stream
|
||||||
|
|
||||||
|
shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, material.mPbrMetallicRoughness.mRoughnessFactor);
|
||||||
|
shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, material.mPbrMetallicRoughness.mMetallicFactor);
|
||||||
|
shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, glm::value_ptr(material.mEmissiveFactor));
|
||||||
|
|
||||||
|
F32 normal_packed[8];
|
||||||
|
//mTextureTransform[GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed);
|
||||||
|
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed);
|
||||||
|
shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, (F32*)normal_packed);
|
||||||
|
|
||||||
|
F32 metallic_roughness_packed[8];
|
||||||
|
//mTextureTransform[GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed);
|
||||||
|
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed);
|
||||||
|
shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, (F32*)metallic_roughness_packed);
|
||||||
|
|
||||||
|
F32 emissive_packed[8];
|
||||||
|
//mTextureTransform[GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed);
|
||||||
|
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed);
|
||||||
|
shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, (F32*)emissive_packed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LLMatrix4a inverse(const LLMatrix4a& mat)
|
LLMatrix4a inverse(const LLMatrix4a& mat)
|
||||||
{
|
{
|
||||||
glh::matrix4f m((F32*)mat.mMatrix);
|
glh::matrix4f m((F32*)mat.mMatrix);
|
||||||
|
|
|
||||||
|
|
@ -28,17 +28,11 @@
|
||||||
|
|
||||||
#include "llsingleton.h"
|
#include "llsingleton.h"
|
||||||
#include "llviewerobject.h"
|
#include "llviewerobject.h"
|
||||||
|
#include "gltf/common.h"
|
||||||
|
|
||||||
class LLVOVolume;
|
class LLVOVolume;
|
||||||
class LLDrawable;
|
class LLDrawable;
|
||||||
|
|
||||||
namespace LL
|
|
||||||
{
|
|
||||||
namespace GLTF
|
|
||||||
{
|
|
||||||
class Asset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace LL
|
namespace LL
|
||||||
{
|
{
|
||||||
class GLTFSceneManager : public LLSimpleton<GLTFSceneManager>
|
class GLTFSceneManager : public LLSimpleton<GLTFSceneManager>
|
||||||
|
|
@ -52,12 +46,20 @@ namespace LL
|
||||||
|
|
||||||
void saveAs(); // open filepicker and choose file to save selected asset to
|
void saveAs(); // open filepicker and choose file to save selected asset to
|
||||||
void save(const std::string& filename); // save selected asset to filename (suitable for use in external programs)
|
void save(const std::string& filename); // save selected asset to filename (suitable for use in external programs)
|
||||||
void decomposeSelection(); // open file picker and choose a location to decompose to
|
|
||||||
void decomposeSelection(const std::string& filename); // decompose selected asset into simulator-ready .gltf, .bin, and .j2c files
|
|
||||||
void uploadSelection(); // decompose selected asset and upload to simulator
|
void uploadSelection(); // decompose selected asset and upload to simulator
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
void render(bool opaque, bool rigged = false);
|
void render(bool opaque, bool rigged = false, bool unlit = false);
|
||||||
|
|
||||||
|
// render the given variant of all assets
|
||||||
|
// variant - bitmask according to LLGLSLShader::GLTFVariant flags
|
||||||
|
void render(U8 variant);
|
||||||
|
|
||||||
|
void render(LL::GLTF::Asset& asset, U8 variant);
|
||||||
|
|
||||||
|
// bind the given material for rendering
|
||||||
|
void bind(LL::GLTF::Asset& asset, LL::GLTF::Material& material);
|
||||||
|
|
||||||
void renderOpaque();
|
void renderOpaque();
|
||||||
void renderAlpha();
|
void renderAlpha();
|
||||||
|
|
||||||
|
|
@ -73,7 +75,7 @@ namespace LL
|
||||||
LLVector4a* normal, // return the surface normal at the intersection point
|
LLVector4a* normal, // return the surface normal at the intersection point
|
||||||
LLVector4a* tangent); // return the surface tangent at the intersection point
|
LLVector4a* tangent); // return the surface tangent at the intersection point
|
||||||
|
|
||||||
bool lineSegmentIntersect(LLVOVolume* obj, GLTF::Asset* asset, const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32* face_hitp, S32* primitive_hitp,
|
bool lineSegmentIntersect(LLVOVolume* obj, LL::GLTF::Asset* asset, const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32* face_hitp, S32* primitive_hitp,
|
||||||
LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent);
|
LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent);
|
||||||
|
|
||||||
void renderDebug();
|
void renderDebug();
|
||||||
|
|
@ -90,6 +92,8 @@ namespace LL
|
||||||
U32 mPendingImageUploads = 0;
|
U32 mPendingImageUploads = 0;
|
||||||
U32 mPendingBinaryUploads = 0;
|
U32 mPendingBinaryUploads = 0;
|
||||||
U32 mPendingGLTFUploads = 0;
|
U32 mPendingGLTFUploads = 0;
|
||||||
|
|
||||||
|
U32 mJointUBO = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,7 @@ S32 LLAgentBenefits::getTextureUploadCost(const LLViewerTexture* tex) const
|
||||||
return getTextureUploadCost();
|
return getTextureUploadCost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getTextureUploadCost();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
S32 LLAgentBenefits::getTextureUploadCost(const LLImageBase* tex) const
|
S32 LLAgentBenefits::getTextureUploadCost(const LLImageBase* tex) const
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ S32 LLDrawPoolAlpha::getNumPostDeferredPasses()
|
||||||
}
|
}
|
||||||
|
|
||||||
// set some common parameters on the given shader to prepare for alpha rendering
|
// set some common parameters on the given shader to prepare for alpha rendering
|
||||||
static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool deferredEnvironment, F32 water_sign)
|
static void prepare_alpha_shader(LLGLSLShader* shader, bool deferredEnvironment, F32 water_sign)
|
||||||
{
|
{
|
||||||
static LLCachedControl<F32> displayGamma(gSavedSettings, "RenderDeferredDisplayGamma");
|
static LLCachedControl<F32> displayGamma(gSavedSettings, "RenderDeferredDisplayGamma");
|
||||||
F32 gamma = displayGamma;
|
F32 gamma = displayGamma;
|
||||||
|
|
@ -133,15 +133,11 @@ static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool d
|
||||||
{
|
{
|
||||||
shader->setMinimumAlpha(MINIMUM_ALPHA);
|
shader->setMinimumAlpha(MINIMUM_ALPHA);
|
||||||
}
|
}
|
||||||
if (textureGamma)
|
|
||||||
{
|
|
||||||
shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
|
|
||||||
}
|
|
||||||
|
|
||||||
//also prepare rigged variant
|
//also prepare rigged variant
|
||||||
if (shader->mRiggedVariant && shader->mRiggedVariant != shader)
|
if (shader->mRiggedVariant && shader->mRiggedVariant != shader)
|
||||||
{
|
{
|
||||||
prepare_alpha_shader(shader->mRiggedVariant, textureGamma, deferredEnvironment, water_sign);
|
prepare_alpha_shader(shader->mRiggedVariant, deferredEnvironment, water_sign);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,36 +168,36 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
|
||||||
llassert(LLPipeline::sRenderDeferred);
|
llassert(LLPipeline::sRenderDeferred);
|
||||||
|
|
||||||
emissive_shader = &gDeferredEmissiveProgram;
|
emissive_shader = &gDeferredEmissiveProgram;
|
||||||
prepare_alpha_shader(emissive_shader, true, false, water_sign);
|
prepare_alpha_shader(emissive_shader, false, water_sign);
|
||||||
|
|
||||||
pbr_emissive_shader = &gPBRGlowProgram;
|
pbr_emissive_shader = &gPBRGlowProgram;
|
||||||
prepare_alpha_shader(pbr_emissive_shader, true, false, water_sign);
|
prepare_alpha_shader(pbr_emissive_shader, false, water_sign);
|
||||||
|
|
||||||
|
|
||||||
fullbright_shader =
|
fullbright_shader =
|
||||||
(LLPipeline::sImpostorRender) ? &gDeferredFullbrightAlphaMaskProgram :
|
(LLPipeline::sImpostorRender) ? &gDeferredFullbrightAlphaMaskProgram :
|
||||||
(LLPipeline::sRenderingHUDs) ? &gHUDFullbrightAlphaMaskAlphaProgram :
|
(LLPipeline::sRenderingHUDs) ? &gHUDFullbrightAlphaMaskAlphaProgram :
|
||||||
&gDeferredFullbrightAlphaMaskAlphaProgram;
|
&gDeferredFullbrightAlphaMaskAlphaProgram;
|
||||||
prepare_alpha_shader(fullbright_shader, true, true, water_sign);
|
prepare_alpha_shader(fullbright_shader, true, water_sign);
|
||||||
|
|
||||||
simple_shader =
|
simple_shader =
|
||||||
(LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
|
(LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
|
||||||
(LLPipeline::sRenderingHUDs) ? &gHUDAlphaProgram :
|
(LLPipeline::sRenderingHUDs) ? &gHUDAlphaProgram :
|
||||||
&gDeferredAlphaProgram;
|
&gDeferredAlphaProgram;
|
||||||
|
|
||||||
prepare_alpha_shader(simple_shader, false, true, water_sign); //prime simple shader (loads shadow relevant uniforms)
|
prepare_alpha_shader(simple_shader, true, water_sign); //prime simple shader (loads shadow relevant uniforms)
|
||||||
|
|
||||||
LLGLSLShader* materialShader = gDeferredMaterialProgram;
|
LLGLSLShader* materialShader = gDeferredMaterialProgram;
|
||||||
for (int i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
|
for (int i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
|
||||||
{
|
{
|
||||||
prepare_alpha_shader(&materialShader[i], false, true, water_sign);
|
prepare_alpha_shader(&materialShader[i], true, water_sign);
|
||||||
}
|
}
|
||||||
|
|
||||||
pbr_shader =
|
pbr_shader =
|
||||||
(LLPipeline::sRenderingHUDs) ? &gHUDPBRAlphaProgram :
|
(LLPipeline::sRenderingHUDs) ? &gHUDPBRAlphaProgram :
|
||||||
&gDeferredPBRAlphaProgram;
|
&gDeferredPBRAlphaProgram;
|
||||||
|
|
||||||
prepare_alpha_shader(pbr_shader, false, true, water_sign);
|
prepare_alpha_shader(pbr_shader, true, water_sign);
|
||||||
|
|
||||||
// explicitly unbind here so render loop doesn't make assumptions about the last shader
|
// explicitly unbind here so render loop doesn't make assumptions about the last shader
|
||||||
// already being setup for rendering
|
// already being setup for rendering
|
||||||
|
|
@ -264,11 +260,10 @@ void LLDrawPoolAlpha::forwardRender(bool rigged)
|
||||||
|
|
||||||
if (rigged)
|
if (rigged)
|
||||||
{ // draw GLTF scene to depth buffer before rigged alpha
|
{ // draw GLTF scene to depth buffer before rigged alpha
|
||||||
gPipeline.bindDeferredShader(gDeferredPBRAlphaProgram);
|
|
||||||
LL::GLTFSceneManager::instance().render(false, false);
|
LL::GLTFSceneManager::instance().render(false, false);
|
||||||
|
|
||||||
gPipeline.bindDeferredShader(*gDeferredPBRAlphaProgram.mRiggedVariant);
|
|
||||||
LL::GLTFSceneManager::instance().render(false, true);
|
LL::GLTFSceneManager::instance().render(false, true);
|
||||||
|
LL::GLTFSceneManager::instance().render(false, false, true);
|
||||||
|
LL::GLTFSceneManager::instance().render(false, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the face is more than 90% transparent, then don't update the Depth buffer for Dof
|
// If the face is more than 90% transparent, then don't update the Depth buffer for Dof
|
||||||
|
|
|
||||||
|
|
@ -564,7 +564,7 @@ void LLDrawPoolAvatar::beginDeferredImpostor()
|
||||||
|
|
||||||
sVertexProgram = &gDeferredImpostorProgram;
|
sVertexProgram = &gDeferredImpostorProgram;
|
||||||
specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
|
specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
|
||||||
normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
|
normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::NORMAL_MAP);
|
||||||
sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
|
sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
|
||||||
sVertexProgram->bind();
|
sVertexProgram->bind();
|
||||||
sVertexProgram->setMinimumAlpha(0.01f);
|
sVertexProgram->setMinimumAlpha(0.01f);
|
||||||
|
|
@ -575,7 +575,7 @@ void LLDrawPoolAvatar::endDeferredImpostor()
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
|
||||||
|
|
||||||
sShaderLevel = mShaderLevel;
|
sShaderLevel = mShaderLevel;
|
||||||
sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
|
sVertexProgram->disableTexture(LLViewerShaderMgr::NORMAL_MAP);
|
||||||
sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
|
sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
|
||||||
sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
|
sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
|
||||||
gPipeline.unbindDeferredShader(*sVertexProgram);
|
gPipeline.unbindDeferredShader(*sVertexProgram);
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,25 @@
|
||||||
/**
|
/**
|
||||||
* @file lldrawpoolpbropaque.cpp
|
* @file lldrawpoolpbropaque.cpp
|
||||||
* @brief LLDrawPoolGLTFPBR class implementation
|
* @brief LLDrawPoolGLTFPBR class implementation
|
||||||
*
|
*
|
||||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||||
* Second Life Viewer Source Code
|
* Second Life Viewer Source Code
|
||||||
* Copyright (C) 2022, Linden Research, Inc.
|
* Copyright (C) 2022, Linden Research, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation;
|
* License as published by the Free Software Foundation;
|
||||||
* version 2.1 of the License only.
|
* version 2.1 of the License only.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
*
|
||||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
@ -54,11 +54,10 @@ void LLDrawPoolGLTFPBR::renderDeferred(S32 pass)
|
||||||
{
|
{
|
||||||
llassert(!LLPipeline::sRenderingHUDs);
|
llassert(!LLPipeline::sRenderingHUDs);
|
||||||
|
|
||||||
gDeferredPBROpaqueProgram.bind();
|
|
||||||
|
|
||||||
LL::GLTFSceneManager::instance().renderOpaque();
|
LL::GLTFSceneManager::instance().renderOpaque();
|
||||||
pushGLTFBatches(mRenderType);
|
|
||||||
|
|
||||||
|
gDeferredPBROpaqueProgram.bind();
|
||||||
|
pushGLTFBatches(mRenderType);
|
||||||
|
|
||||||
gDeferredPBROpaqueProgram.bind(true);
|
gDeferredPBROpaqueProgram.bind(true);
|
||||||
LL::GLTFSceneManager::instance().render(true, true);
|
LL::GLTFSceneManager::instance().render(true, true);
|
||||||
|
|
|
||||||
|
|
@ -36,43 +36,12 @@
|
||||||
#include "llspatialpartition.h"
|
#include "llspatialpartition.h"
|
||||||
#include "llviewershadermgr.h"
|
#include "llviewershadermgr.h"
|
||||||
#include "llrender.h"
|
#include "llrender.h"
|
||||||
|
#include "gltfscenemanager.h"
|
||||||
|
|
||||||
static LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE_DEFERRED("Deferred Simple");
|
static LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE_DEFERRED("Deferred Simple");
|
||||||
static LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS_DEFERRED("Deferred Grass");
|
static LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS_DEFERRED("Deferred Grass");
|
||||||
|
|
||||||
|
|
||||||
static void setup_simple_shader(LLGLSLShader* shader)
|
|
||||||
{
|
|
||||||
shader->bind();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setup_glow_shader(LLGLSLShader* shader)
|
|
||||||
{
|
|
||||||
setup_simple_shader(shader);
|
|
||||||
if (LLPipeline::sRenderDeferred && !LLPipeline::sRenderingHUDs)
|
|
||||||
{
|
|
||||||
shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setup_fullbright_shader(LLGLSLShader* shader)
|
|
||||||
{
|
|
||||||
setup_glow_shader(shader);
|
|
||||||
|
|
||||||
S32 channel = shader->enableTexture(LLShaderMgr::EXPOSURE_MAP);
|
|
||||||
if (channel > -1)
|
|
||||||
{
|
|
||||||
gGL.getTexUnit(channel)->bind(&gPipeline.mExposureMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LLDrawPoolGlow::renderPostDeferred(S32 pass)
|
void LLDrawPoolGlow::renderPostDeferred(S32 pass)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
|
||||||
|
|
@ -89,12 +58,12 @@ void LLDrawPoolGlow::renderPostDeferred(S32 pass)
|
||||||
gGL.setColorMask(false, true);
|
gGL.setColorMask(false, true);
|
||||||
|
|
||||||
//first pass -- static objects
|
//first pass -- static objects
|
||||||
setup_glow_shader(shader);
|
shader->bind();
|
||||||
pushBatches(LLRenderPass::PASS_GLOW, true, true);
|
pushBatches(LLRenderPass::PASS_GLOW, true, true);
|
||||||
|
|
||||||
// second pass -- rigged objects
|
// second pass -- rigged objects
|
||||||
shader = shader->mRiggedVariant;
|
shader = shader->mRiggedVariant;
|
||||||
setup_glow_shader(shader);
|
shader->bind();
|
||||||
pushRiggedBatches(LLRenderPass::PASS_GLOW_RIGGED, true, true);
|
pushRiggedBatches(LLRenderPass::PASS_GLOW_RIGGED, true, true);
|
||||||
|
|
||||||
gGL.setColorMask(true, false);
|
gGL.setColorMask(true, false);
|
||||||
|
|
@ -133,11 +102,11 @@ void LLDrawPoolSimple::renderDeferred(S32 pass)
|
||||||
LLGLDisable blend(GL_BLEND);
|
LLGLDisable blend(GL_BLEND);
|
||||||
|
|
||||||
//render static
|
//render static
|
||||||
setup_simple_shader(&gDeferredDiffuseProgram);
|
gDeferredDiffuseProgram.bind();
|
||||||
pushBatches(LLRenderPass::PASS_SIMPLE, true, true);
|
pushBatches(LLRenderPass::PASS_SIMPLE, true, true);
|
||||||
|
|
||||||
//render rigged
|
//render rigged
|
||||||
setup_simple_shader(gDeferredDiffuseProgram.mRiggedVariant);
|
gDeferredDiffuseProgram.bind(true);
|
||||||
pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, true, true);
|
pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,11 +119,11 @@ void LLDrawPoolAlphaMask::renderDeferred(S32 pass)
|
||||||
LLGLSLShader* shader = &gDeferredDiffuseAlphaMaskProgram;
|
LLGLSLShader* shader = &gDeferredDiffuseAlphaMaskProgram;
|
||||||
|
|
||||||
//render static
|
//render static
|
||||||
setup_simple_shader(shader);
|
shader->bind();
|
||||||
pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, true, true);
|
pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, true, true);
|
||||||
|
|
||||||
//render rigged
|
//render rigged
|
||||||
setup_simple_shader(shader->mRiggedVariant);
|
shader->bind(true);
|
||||||
pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, true, true);
|
pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,13 +170,13 @@ void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
|
||||||
gGL.setSceneBlendType(LLRender::BT_ALPHA);
|
gGL.setSceneBlendType(LLRender::BT_ALPHA);
|
||||||
|
|
||||||
// render static
|
// render static
|
||||||
setup_fullbright_shader(shader);
|
shader->bind();
|
||||||
pushBatches(LLRenderPass::PASS_FULLBRIGHT, true, true);
|
pushBatches(LLRenderPass::PASS_FULLBRIGHT, true, true);
|
||||||
|
|
||||||
if (!LLPipeline::sRenderingHUDs)
|
if (!LLPipeline::sRenderingHUDs)
|
||||||
{
|
{
|
||||||
// render rigged
|
// render rigged
|
||||||
setup_fullbright_shader(shader->mRiggedVariant);
|
shader->bind(true);
|
||||||
pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, true, true);
|
pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -216,6 +185,10 @@ void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT);
|
||||||
|
|
||||||
|
// render unrigged unlit GLTF
|
||||||
|
LL::GLTFSceneManager::instance().render(true, false, true);
|
||||||
|
LL::GLTFSceneManager::instance().render(true, true, true);
|
||||||
|
|
||||||
LLGLSLShader* shader = nullptr;
|
LLGLSLShader* shader = nullptr;
|
||||||
if (LLPipeline::sRenderingHUDs)
|
if (LLPipeline::sRenderingHUDs)
|
||||||
{
|
{
|
||||||
|
|
@ -229,13 +202,13 @@ void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
|
||||||
LLGLDisable blend(GL_BLEND);
|
LLGLDisable blend(GL_BLEND);
|
||||||
|
|
||||||
// render static
|
// render static
|
||||||
setup_fullbright_shader(shader);
|
shader->bind();
|
||||||
pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, true, true);
|
pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, true, true);
|
||||||
|
|
||||||
if (!LLPipeline::sRenderingHUDs)
|
if (!LLPipeline::sRenderingHUDs)
|
||||||
{
|
{
|
||||||
// render rigged
|
// render rigged
|
||||||
setup_fullbright_shader(shader->mRiggedVariant);
|
shader->bind(true);
|
||||||
pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, true, true);
|
pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1815,15 +1815,15 @@ void LLEnvironment::update(const LLViewerCamera * cam)
|
||||||
end_shaders = LLViewerShaderMgr::instance()->endShaders();
|
end_shaders = LLViewerShaderMgr::instance()->endShaders();
|
||||||
for (shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter)
|
for (shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter)
|
||||||
{
|
{
|
||||||
if ((shaders_iter->mProgramObject != 0)
|
shaders_iter->mUniformsDirty = true;
|
||||||
&& (gPipeline.canUseWindLightShaders()
|
if (shaders_iter->mRiggedVariant)
|
||||||
|| shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER))
|
|
||||||
{
|
{
|
||||||
shaders_iter->mUniformsDirty = true;
|
shaders_iter->mRiggedVariant->mUniformsDirty = true;
|
||||||
if (shaders_iter->mRiggedVariant)
|
}
|
||||||
{
|
|
||||||
shaders_iter->mRiggedVariant->mUniformsDirty = true;
|
for (auto& variant : shaders_iter->mGLTFVariants)
|
||||||
}
|
{
|
||||||
|
variant.mUniformsDirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -657,13 +657,6 @@ void LLFace::renderOneWireframe(const LLColor4 &color, F32 fogCfx, bool wirefram
|
||||||
|
|
||||||
{
|
{
|
||||||
LLGLDisable depth(wireframe_selection ? 0 : GL_BLEND);
|
LLGLDisable depth(wireframe_selection ? 0 : GL_BLEND);
|
||||||
//LLGLEnable stencil(wireframe_selection ? 0 : GL_STENCIL_TEST);
|
|
||||||
|
|
||||||
if (!wireframe_selection)
|
|
||||||
{ //modify wireframe into outline selection mode
|
|
||||||
glStencilFunc(GL_NOTEQUAL, 2, 0xffff);
|
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
|
||||||
}
|
|
||||||
|
|
||||||
LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
|
LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
|
||||||
glPolygonOffset(3.f, 3.f);
|
glPolygonOffset(3.f, 3.f);
|
||||||
|
|
|
||||||
|
|
@ -541,11 +541,11 @@ bool LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename,
|
||||||
case FFSAVE_GLTF:
|
case FFSAVE_GLTF:
|
||||||
if (filename.empty())
|
if (filename.empty())
|
||||||
{
|
{
|
||||||
wcsncpy( mFilesW,L"untitled.glb", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
|
wcsncpy( mFilesW,L"untitled.gltf", FILENAME_BUFFER_SIZE); /*Flawfinder: ignore*/
|
||||||
}
|
}
|
||||||
mOFN.lpstrDefExt = L"glb";
|
mOFN.lpstrDefExt = L"gltf";
|
||||||
mOFN.lpstrFilter =
|
mOFN.lpstrFilter =
|
||||||
L"glTF Asset File (*.gltf *.glb)\0*.gltf;*.glb\0" \
|
L"glTF Asset File (*.gltf)\0*.gltf\0" \
|
||||||
L"\0";
|
L"\0";
|
||||||
break;
|
break;
|
||||||
case FFSAVE_XML:
|
case FFSAVE_XML:
|
||||||
|
|
@ -860,7 +860,7 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension,
|
||||||
case LLFilePicker::FFSAVE_GLTF:
|
case LLFilePicker::FFSAVE_GLTF:
|
||||||
type = "\?\?\?\?";
|
type = "\?\?\?\?";
|
||||||
creator = "\?\?\?\?";
|
creator = "\?\?\?\?";
|
||||||
extension = "glb,gltf";
|
extension = "gltf";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// <FS:TS> Compile fix
|
// <FS:TS> Compile fix
|
||||||
|
|
|
||||||
|
|
@ -589,13 +589,13 @@ void LLFloaterIMSessionTab::appendMessage(const LLChat& chat, const LLSD& args)
|
||||||
mChatHistory->appendMessage(chat, chat_args);
|
mChatHistory->appendMessage(chat, chat_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLFloaterIMSessionTab::updateUsedEmojis(LLWString text)
|
void LLFloaterIMSessionTab::updateUsedEmojis(LLWStringView text)
|
||||||
{
|
{
|
||||||
LLEmojiDictionary* dictionary = LLEmojiDictionary::getInstance();
|
LLEmojiDictionary* dictionary = LLEmojiDictionary::getInstance();
|
||||||
llassert_always(dictionary);
|
llassert_always(dictionary);
|
||||||
|
|
||||||
bool emojiSent = false;
|
bool emojiSent = false;
|
||||||
for (llwchar& c : text)
|
for (const llwchar& c : text)
|
||||||
{
|
{
|
||||||
if (dictionary->isEmoji(c))
|
if (dictionary->isEmoji(c))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ protected:
|
||||||
std::string appendTime();
|
std::string appendTime();
|
||||||
void assignResizeLimits();
|
void assignResizeLimits();
|
||||||
|
|
||||||
void updateUsedEmojis(LLWString text);
|
void updateUsedEmojis(LLWStringView text);
|
||||||
|
|
||||||
S32 mFloaterExtraWidth;
|
S32 mFloaterExtraWidth;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@
|
||||||
#include "llnamelistctrl.h"
|
#include "llnamelistctrl.h"
|
||||||
#include "llnotifications.h"
|
#include "llnotifications.h"
|
||||||
#include "llnotificationsutil.h"
|
#include "llnotificationsutil.h"
|
||||||
|
#include "llpbrterrainfeatures.h"
|
||||||
#include "llregioninfomodel.h"
|
#include "llregioninfomodel.h"
|
||||||
#include "llscrolllistitem.h"
|
#include "llscrolllistitem.h"
|
||||||
#include "llsliderctrl.h"
|
#include "llsliderctrl.h"
|
||||||
|
|
@ -282,7 +283,16 @@ bool LLFloaterRegionInfo::postBuild()
|
||||||
|
|
||||||
panel = new LLPanelRegionTerrainInfo;
|
panel = new LLPanelRegionTerrainInfo;
|
||||||
mInfoPanels.push_back(panel);
|
mInfoPanels.push_back(panel);
|
||||||
panel->buildFromFile("panel_region_terrain.xml");
|
static LLCachedControl<bool> feature_pbr_terrain_enabled(gSavedSettings, "RenderTerrainPBREnabled", false);
|
||||||
|
static LLCachedControl<bool> feature_pbr_terrain_transforms_enabled(gSavedSettings, "RenderTerrainPBRTransformsEnabled", false);
|
||||||
|
if (!feature_pbr_terrain_transforms_enabled || !feature_pbr_terrain_enabled)
|
||||||
|
{
|
||||||
|
panel->buildFromFile("panel_region_terrain.xml");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
panel->buildFromFile("panel_region_terrain_texture_transform.xml");
|
||||||
|
}
|
||||||
mTab->addTabPanel(panel);
|
mTab->addTabPanel(panel);
|
||||||
|
|
||||||
mEnvironmentPanel = new LLPanelRegionEnvironment;
|
mEnvironmentPanel = new LLPanelRegionEnvironment;
|
||||||
|
|
@ -601,6 +611,20 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg)
|
||||||
} // else will rerequest on onOpen either way
|
} // else will rerequest on onOpen either way
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void LLFloaterRegionInfo::sRefreshFromRegion(LLViewerRegion* region)
|
||||||
|
{
|
||||||
|
if (region != gAgent.getRegion()) { return; }
|
||||||
|
|
||||||
|
LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance<LLFloaterRegionInfo>("region_info");
|
||||||
|
if (!floater) { return; }
|
||||||
|
|
||||||
|
if (floater->getVisible() && region == gAgent.getRegion())
|
||||||
|
{
|
||||||
|
floater->refreshFromRegion(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
LLPanelEstateInfo* LLFloaterRegionInfo::getPanelEstate()
|
LLPanelEstateInfo* LLFloaterRegionInfo::getPanelEstate()
|
||||||
{
|
{
|
||||||
|
|
@ -885,6 +909,13 @@ void LLPanelRegionInfo::initCtrl(const std::string& name)
|
||||||
getChild<LLUICtrl>(name)->setCommitCallback(boost::bind(&LLPanelRegionInfo::onChangeAnything, this));
|
getChild<LLUICtrl>(name)->setCommitCallback(boost::bind(&LLPanelRegionInfo::onChangeAnything, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename CTRL>
|
||||||
|
void LLPanelRegionInfo::initAndSetCtrl(CTRL*& ctrl, const std::string& name)
|
||||||
|
{
|
||||||
|
initCtrl(name);
|
||||||
|
ctrl = findChild<CTRL>(name);
|
||||||
|
}
|
||||||
|
|
||||||
void LLPanelRegionInfo::onClickManageTelehub()
|
void LLPanelRegionInfo::onClickManageTelehub()
|
||||||
{
|
{
|
||||||
LLFloaterReg::hideInstance("region_info");
|
LLFloaterReg::hideInstance("region_info");
|
||||||
|
|
@ -1680,11 +1711,17 @@ LLPanelRegionTerrainInfo::LLPanelRegionTerrainInfo()
|
||||||
const LLUUID (&default_textures)[LLVLComposition::ASSET_COUNT] = LLVLComposition::getDefaultTextures();
|
const LLUUID (&default_textures)[LLVLComposition::ASSET_COUNT] = LLVLComposition::getDefaultTextures();
|
||||||
for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
|
for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
|
||||||
{
|
{
|
||||||
|
mTextureDetailCtrl[i] = nullptr;
|
||||||
|
mMaterialDetailCtrl[i] = nullptr;
|
||||||
|
|
||||||
mLastSetTextures[i] = default_textures[i];
|
mLastSetTextures[i] = default_textures[i];
|
||||||
}
|
|
||||||
for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
|
|
||||||
{
|
|
||||||
mLastSetMaterials[i] = BLANK_MATERIAL_ASSET_ID;
|
mLastSetMaterials[i] = BLANK_MATERIAL_ASSET_ID;
|
||||||
|
|
||||||
|
mMaterialScaleUCtrl[i] = nullptr;
|
||||||
|
mMaterialScaleVCtrl[i] = nullptr;
|
||||||
|
mMaterialRotationCtrl[i] = nullptr;
|
||||||
|
mMaterialOffsetUCtrl[i] = nullptr;
|
||||||
|
mMaterialOffsetVCtrl[i] = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1705,15 +1742,18 @@ bool LLPanelRegionTerrainInfo::postBuild()
|
||||||
|
|
||||||
for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
|
for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
|
||||||
{
|
{
|
||||||
buffer = llformat("texture_detail_%d", i);
|
initAndSetCtrl(mTextureDetailCtrl[i], llformat("texture_detail_%d", i));
|
||||||
initCtrl(buffer);
|
if (mTextureDetailCtrl[i])
|
||||||
mTextureDetailCtrl[i] = findChild<LLTextureCtrl>(buffer);
|
{
|
||||||
}
|
mTextureDetailCtrl[i]->setBakeTextureEnabled(false);
|
||||||
for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
|
}
|
||||||
{
|
initAndSetCtrl(mMaterialDetailCtrl[i], llformat("material_detail_%d", i));
|
||||||
buffer = llformat("material_detail_%d", i);
|
|
||||||
initCtrl(buffer);
|
initAndSetCtrl(mMaterialScaleUCtrl[i], llformat("terrain%dScaleU", i));
|
||||||
mMaterialDetailCtrl[i] = findChild<LLTextureCtrl>(buffer);
|
initAndSetCtrl(mMaterialScaleVCtrl[i], llformat("terrain%dScaleV", i));
|
||||||
|
initAndSetCtrl(mMaterialRotationCtrl[i], llformat("terrain%dRotation", i));
|
||||||
|
initAndSetCtrl(mMaterialOffsetUCtrl[i], llformat("terrain%dOffsetU", i));
|
||||||
|
initAndSetCtrl(mMaterialOffsetVCtrl[i], llformat("terrain%dOffsetV", i));
|
||||||
}
|
}
|
||||||
|
|
||||||
for(S32 i = 0; i < CORNER_COUNT; ++i)
|
for(S32 i = 0; i < CORNER_COUNT; ++i)
|
||||||
|
|
@ -1765,6 +1805,17 @@ void LLPanelRegionTerrainInfo::updateForMaterialType()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Toggle visibility of terrain tabs
|
||||||
|
LLTabContainer* terrain_tabs = findChild<LLTabContainer>("terrain_tabs");
|
||||||
|
if (terrain_tabs)
|
||||||
|
{
|
||||||
|
LLPanel* pbr_terrain_repeats_tab = findChild<LLPanel>("terrain_transform_panel");
|
||||||
|
if (pbr_terrain_repeats_tab)
|
||||||
|
{
|
||||||
|
terrain_tabs->setTabVisibility(pbr_terrain_repeats_tab, show_material_controls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Toggle visibility of labels
|
// Toggle visibility of labels
|
||||||
LLUICtrl* texture_label = findChild<LLUICtrl>("detail_texture_text");
|
LLUICtrl* texture_label = findChild<LLUICtrl>("detail_texture_text");
|
||||||
if (texture_label) { texture_label->setVisible(show_texture_controls); }
|
if (texture_label) { texture_label->setVisible(show_texture_controls); }
|
||||||
|
|
@ -1893,6 +1944,21 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
|
||||||
|
{
|
||||||
|
if (!mMaterialScaleUCtrl[i] || !mMaterialScaleVCtrl[i] || !mMaterialRotationCtrl[i] || !mMaterialOffsetUCtrl[i] || !mMaterialOffsetVCtrl[i]) { continue; }
|
||||||
|
const LLGLTFMaterial* mat_override = compp->getMaterialOverride(i);
|
||||||
|
if (!mat_override) { mat_override = &LLGLTFMaterial::sDefault; }
|
||||||
|
|
||||||
|
// Assume all texture transforms have the same value
|
||||||
|
const LLGLTFMaterial::TextureTransform& transform = mat_override->mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR];
|
||||||
|
mMaterialScaleUCtrl[i]->setValue(transform.mScale.mV[VX]);
|
||||||
|
mMaterialScaleVCtrl[i]->setValue(transform.mScale.mV[VY]);
|
||||||
|
mMaterialRotationCtrl[i]->setValue(transform.mRotation * RAD_TO_DEG);
|
||||||
|
mMaterialOffsetUCtrl[i]->setValue(transform.mOffset.mV[VX]);
|
||||||
|
mMaterialOffsetVCtrl[i]->setValue(transform.mOffset.mV[VY]);
|
||||||
|
}
|
||||||
|
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
for(S32 i = 0; i < CORNER_COUNT; ++i)
|
for(S32 i = 0; i < CORNER_COUNT; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -1907,7 +1973,7 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region)
|
||||||
LL_DEBUGS() << "no region set" << LL_ENDL;
|
LL_DEBUGS() << "no region set" << LL_ENDL;
|
||||||
getChild<LLUICtrl>("region_text")->setValue(LLSD(""));
|
getChild<LLUICtrl>("region_text")->setValue(LLSD(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update visibility of terrain swatches, etc
|
// Update visibility of terrain swatches, etc
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
|
|
@ -1922,7 +1988,14 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region)
|
||||||
// virtual
|
// virtual
|
||||||
bool LLPanelRegionTerrainInfo::sendUpdate()
|
bool LLPanelRegionTerrainInfo::sendUpdate()
|
||||||
{
|
{
|
||||||
LL_INFOS() << "LLPanelRegionTerrainInfo::sendUpdate" << LL_ENDL;
|
LL_INFOS() << __FUNCTION__ << LL_ENDL;
|
||||||
|
|
||||||
|
LLUICtrl* apply_btn = getChild<LLUICtrl>("apply_btn");
|
||||||
|
if (apply_btn && !apply_btn->getEnabled())
|
||||||
|
{
|
||||||
|
LL_WARNS() << "Duplicate update, ignored" << LL_ENDL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure user hasn't chosen wacky textures unless we're on Aurora-sim.
|
// Make sure user hasn't chosen wacky textures unless we're on Aurora-sim.
|
||||||
// <FS:CR> Aurora Sim - Region Settings Console
|
// <FS:CR> Aurora Sim - Region Settings Console
|
||||||
|
|
@ -2032,6 +2105,51 @@ bool LLPanelRegionTerrainInfo::sendUpdate()
|
||||||
|
|
||||||
sendEstateOwnerMessage(msg, "texturecommit", invoice, strings);
|
sendEstateOwnerMessage(msg, "texturecommit", invoice, strings);
|
||||||
|
|
||||||
|
// ========================================
|
||||||
|
// POST to ModifyRegion endpoint, if enabled
|
||||||
|
|
||||||
|
static LLCachedControl<bool> feature_pbr_terrain_transforms_enabled(gSavedSettings, "RenderTerrainPBRTransformsEnabled", false);
|
||||||
|
if (material_type == LLTerrainMaterials::Type::PBR && feature_pbr_terrain_transforms_enabled)
|
||||||
|
{
|
||||||
|
LLTerrainMaterials composition;
|
||||||
|
for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
|
||||||
|
{
|
||||||
|
LLPointer<LLGLTFMaterial> mat_override = new LLGLTFMaterial();
|
||||||
|
|
||||||
|
const bool transform_controls_valid = mMaterialScaleUCtrl[i] && mMaterialScaleVCtrl[i] && mMaterialRotationCtrl[i] && mMaterialOffsetUCtrl[i] && mMaterialOffsetVCtrl[i];
|
||||||
|
if (transform_controls_valid)
|
||||||
|
{
|
||||||
|
// Set texture transforms for all texture infos to the same value,
|
||||||
|
// because the PBR terrain shader doesn't currently support
|
||||||
|
// different transforms per texture info. See also
|
||||||
|
// LLDrawPoolTerrain::renderFullShaderPBR .
|
||||||
|
for (U32 tt = 0; tt < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++tt)
|
||||||
|
{
|
||||||
|
LLGLTFMaterial::TextureTransform& transform = mat_override->mTextureTransform[tt];
|
||||||
|
transform.mScale.mV[VX] = mMaterialScaleUCtrl[i]->getValue().asReal();
|
||||||
|
transform.mScale.mV[VY] = mMaterialScaleVCtrl[i]->getValue().asReal();
|
||||||
|
transform.mRotation = mMaterialRotationCtrl[i]->getValue().asReal() * DEG_TO_RAD;
|
||||||
|
transform.mOffset.mV[VX] = mMaterialOffsetUCtrl[i]->getValue().asReal();
|
||||||
|
transform.mOffset.mV[VY] = mMaterialOffsetVCtrl[i]->getValue().asReal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*mat_override == LLGLTFMaterial::sDefault) { mat_override = nullptr; }
|
||||||
|
composition.setMaterialOverride(i, mat_override.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
// queueModify leads to a few messages being sent back and forth:
|
||||||
|
// viewer: POST ModifyRegion
|
||||||
|
// simulator: RegionHandshake
|
||||||
|
// viewer: GET ModifyRegion
|
||||||
|
LLViewerRegion* region = gAgent.getRegion();
|
||||||
|
llassert(region);
|
||||||
|
if (region)
|
||||||
|
{
|
||||||
|
LLPBRTerrainFeatures::queueModify(*region, composition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/**
|
/**
|
||||||
* @file llfloaterregioninfo.h
|
* @file llfloaterregioninfo.h
|
||||||
* @author Aaron Brashears
|
* @author Aaron Brashears
|
||||||
* @brief Declaration of the region info and controls floater and panels.
|
* @brief Declaration of the region info and controls floater and panels.
|
||||||
|
|
@ -6,21 +6,21 @@
|
||||||
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||||
* Second Life Viewer Source Code
|
* Second Life Viewer Source Code
|
||||||
* Copyright (C) 2010, Linden Research, Inc.
|
* Copyright (C) 2010, Linden Research, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation;
|
* License as published by the Free Software Foundation;
|
||||||
* version 2.1 of the License only.
|
* version 2.1 of the License only.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
*
|
||||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
@ -88,6 +88,7 @@ public:
|
||||||
|
|
||||||
// get and process region info if necessary.
|
// get and process region info if necessary.
|
||||||
static void processRegionInfo(LLMessageSystem* msg);
|
static void processRegionInfo(LLMessageSystem* msg);
|
||||||
|
static void sRefreshFromRegion(LLViewerRegion* region);
|
||||||
|
|
||||||
static const LLUUID& getLastInvoice() { return sRequestInvoice; }
|
static const LLUUID& getLastInvoice() { return sRequestInvoice; }
|
||||||
static void nextInvoice() { sRequestInvoice.generate(); }
|
static void nextInvoice() { sRequestInvoice.generate(); }
|
||||||
|
|
@ -107,14 +108,14 @@ public:
|
||||||
|
|
||||||
// from LLPanel
|
// from LLPanel
|
||||||
void refresh() override;
|
void refresh() override;
|
||||||
|
|
||||||
void onRegionChanged();
|
void onRegionChanged();
|
||||||
void requestRegionInfo();
|
void requestRegionInfo();
|
||||||
void enableTopButtons();
|
void enableTopButtons();
|
||||||
void disableTopButtons();
|
void disableTopButtons();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
LLFloaterRegionInfo(const LLSD& seed);
|
LLFloaterRegionInfo(const LLSD& seed);
|
||||||
~LLFloaterRegionInfo();
|
~LLFloaterRegionInfo();
|
||||||
|
|
||||||
|
|
@ -143,30 +144,31 @@ class LLPanelRegionInfo : public LLPanel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LLPanelRegionInfo();
|
LLPanelRegionInfo();
|
||||||
|
|
||||||
void onBtnSet();
|
void onBtnSet();
|
||||||
void onChangeChildCtrl(LLUICtrl* ctrl);
|
void onChangeChildCtrl(LLUICtrl* ctrl);
|
||||||
void onChangeAnything();
|
void onChangeAnything();
|
||||||
static void onChangeText(LLLineEditor* caller, void* user_data);
|
static void onChangeText(LLLineEditor* caller, void* user_data);
|
||||||
|
|
||||||
virtual bool refreshFromRegion(LLViewerRegion* region);
|
virtual bool refreshFromRegion(LLViewerRegion* region);
|
||||||
virtual bool estateUpdate(LLMessageSystem* msg) { return true; }
|
virtual bool estateUpdate(LLMessageSystem* msg) { return true; }
|
||||||
|
|
||||||
bool postBuild() override;
|
bool postBuild() override;
|
||||||
virtual void updateChild(LLUICtrl* child_ctrl);
|
virtual void updateChild(LLUICtrl* child_ctrl);
|
||||||
|
|
||||||
void enableButton(const std::string& btn_name, bool enable = true);
|
void enableButton(const std::string& btn_name, bool enable = true);
|
||||||
void disableButton(const std::string& btn_name);
|
void disableButton(const std::string& btn_name);
|
||||||
|
|
||||||
void onClickManageTelehub();
|
void onClickManageTelehub();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initCtrl(const std::string& name);
|
void initCtrl(const std::string& name);
|
||||||
|
template<typename CTRL> void initAndSetCtrl(CTRL*& ctrl, const std::string& name);
|
||||||
|
|
||||||
// Returns true if update sent and apply button should be
|
// Returns true if update sent and apply button should be
|
||||||
// disabled.
|
// disabled.
|
||||||
virtual bool sendUpdate() { return true; }
|
virtual bool sendUpdate() { return true; }
|
||||||
|
|
||||||
typedef std::vector<std::string> strings_t;
|
typedef std::vector<std::string> strings_t;
|
||||||
//typedef std::vector<U32> integers_t;
|
//typedef std::vector<U32> integers_t;
|
||||||
void sendEstateOwnerMessage(
|
void sendEstateOwnerMessage(
|
||||||
|
|
@ -174,8 +176,8 @@ protected:
|
||||||
const std::string& request,
|
const std::string& request,
|
||||||
const LLUUID& invoice,
|
const LLUUID& invoice,
|
||||||
const strings_t& strings);
|
const strings_t& strings);
|
||||||
|
|
||||||
|
|
||||||
// member data
|
// member data
|
||||||
LLHost mHost;
|
LLHost mHost;
|
||||||
};
|
};
|
||||||
|
|
@ -206,16 +208,16 @@ protected:
|
||||||
|
|
||||||
class LLPanelRegionGeneralInfo : public LLPanelRegionInfo
|
class LLPanelRegionGeneralInfo : public LLPanelRegionInfo
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LLPanelRegionGeneralInfo()
|
LLPanelRegionGeneralInfo()
|
||||||
: LLPanelRegionInfo() {}
|
: LLPanelRegionInfo() {}
|
||||||
~LLPanelRegionGeneralInfo() {}
|
~LLPanelRegionGeneralInfo() {}
|
||||||
|
|
||||||
bool refreshFromRegion(LLViewerRegion* region) override;
|
bool refreshFromRegion(LLViewerRegion* region) override;
|
||||||
|
|
||||||
bool postBuild() override;
|
bool postBuild() override;
|
||||||
|
|
||||||
void onBtnSet();
|
void onBtnSet();
|
||||||
void setObjBonusFactor(F32 object_bonus_factor) {mObjBonusFactor = object_bonus_factor;}
|
void setObjBonusFactor(F32 object_bonus_factor) {mObjBonusFactor = object_bonus_factor;}
|
||||||
|
|
||||||
|
|
@ -243,9 +245,9 @@ public:
|
||||||
~LLPanelRegionDebugInfo() {}
|
~LLPanelRegionDebugInfo() {}
|
||||||
|
|
||||||
bool postBuild() override;
|
bool postBuild() override;
|
||||||
|
|
||||||
bool refreshFromRegion(LLViewerRegion* region) override;
|
bool refreshFromRegion(LLViewerRegion* region) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool sendUpdate() override;
|
bool sendUpdate() override;
|
||||||
|
|
||||||
|
|
@ -259,7 +261,7 @@ protected:
|
||||||
bool callbackRestart(const LLSD& notification, const LLSD& response, const LLSD& seconds); // Ansariel, added seconds for FIRE-1073
|
bool callbackRestart(const LLSD& notification, const LLSD& response, const LLSD& seconds); // Ansariel, added seconds for FIRE-1073
|
||||||
static void onClickCancelRestart(void* data);
|
static void onClickCancelRestart(void* data);
|
||||||
static void onClickDebugConsole(void* data);
|
static void onClickDebugConsole(void* data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LLUUID mTargetAvatar;
|
LLUUID mTargetAvatar;
|
||||||
};
|
};
|
||||||
|
|
@ -273,9 +275,9 @@ class LLPanelRegionTerrainInfo : public LLPanelRegionInfo
|
||||||
public:
|
public:
|
||||||
LLPanelRegionTerrainInfo();
|
LLPanelRegionTerrainInfo();
|
||||||
~LLPanelRegionTerrainInfo() {}
|
~LLPanelRegionTerrainInfo() {}
|
||||||
|
|
||||||
bool postBuild() override;
|
bool postBuild() override;
|
||||||
|
|
||||||
bool refreshFromRegion(LLViewerRegion* region) override; // refresh local settings from region update from simulator
|
bool refreshFromRegion(LLViewerRegion* region) override; // refresh local settings from region update from simulator
|
||||||
void setEnvControls(bool available); // Whether environment settings are available for this region
|
void setEnvControls(bool available); // Whether environment settings are available for this region
|
||||||
|
|
||||||
|
|
@ -284,7 +286,7 @@ public:
|
||||||
bool validateTextureHeights();
|
bool validateTextureHeights();
|
||||||
|
|
||||||
//static void onChangeAnything(LLUICtrl* ctrl, void* userData); // callback for any change, to enable commit button
|
//static void onChangeAnything(LLUICtrl* ctrl, void* userData); // callback for any change, to enable commit button
|
||||||
|
|
||||||
void onSelectMaterialType();
|
void onSelectMaterialType();
|
||||||
void updateForMaterialType();
|
void updateForMaterialType();
|
||||||
|
|
||||||
|
|
@ -307,8 +309,15 @@ private:
|
||||||
LLCheckBoxCtrl* mMaterialTypeCtrl = nullptr;
|
LLCheckBoxCtrl* mMaterialTypeCtrl = nullptr;
|
||||||
LLTextureCtrl* mTextureDetailCtrl[LLTerrainMaterials::ASSET_COUNT];
|
LLTextureCtrl* mTextureDetailCtrl[LLTerrainMaterials::ASSET_COUNT];
|
||||||
LLTextureCtrl* mMaterialDetailCtrl[LLTerrainMaterials::ASSET_COUNT];
|
LLTextureCtrl* mMaterialDetailCtrl[LLTerrainMaterials::ASSET_COUNT];
|
||||||
|
|
||||||
LLUUID mLastSetTextures[LLTerrainMaterials::ASSET_COUNT];
|
LLUUID mLastSetTextures[LLTerrainMaterials::ASSET_COUNT];
|
||||||
LLUUID mLastSetMaterials[LLTerrainMaterials::ASSET_COUNT];
|
LLUUID mLastSetMaterials[LLTerrainMaterials::ASSET_COUNT];
|
||||||
|
|
||||||
|
LLSpinCtrl* mMaterialScaleUCtrl[LLTerrainMaterials::ASSET_COUNT];
|
||||||
|
LLSpinCtrl* mMaterialScaleVCtrl[LLTerrainMaterials::ASSET_COUNT];
|
||||||
|
LLSpinCtrl* mMaterialRotationCtrl[LLTerrainMaterials::ASSET_COUNT];
|
||||||
|
LLSpinCtrl* mMaterialOffsetUCtrl[LLTerrainMaterials::ASSET_COUNT];
|
||||||
|
LLSpinCtrl* mMaterialOffsetVCtrl[LLTerrainMaterials::ASSET_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -317,13 +326,13 @@ class LLPanelEstateInfo : public LLPanelRegionInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void initDispatch(LLDispatcher& dispatch);
|
static void initDispatch(LLDispatcher& dispatch);
|
||||||
|
|
||||||
void onChangeFixedSun();
|
void onChangeFixedSun();
|
||||||
void onChangeUseGlobalTime();
|
void onChangeUseGlobalTime();
|
||||||
void onChangeAccessOverride();
|
void onChangeAccessOverride();
|
||||||
|
|
||||||
void onClickEditSky();
|
void onClickEditSky();
|
||||||
void onClickEditSkyHelp();
|
void onClickEditSkyHelp();
|
||||||
void onClickEditDayCycle();
|
void onClickEditDayCycle();
|
||||||
void onClickEditDayCycleHelp();
|
void onClickEditDayCycleHelp();
|
||||||
|
|
||||||
|
|
@ -335,26 +344,26 @@ public:
|
||||||
void onKickUserCommit(const uuid_vec_t& ids);
|
void onKickUserCommit(const uuid_vec_t& ids);
|
||||||
static void onClickMessageEstate(void* data);
|
static void onClickMessageEstate(void* data);
|
||||||
bool onMessageCommit(const LLSD& notification, const LLSD& response);
|
bool onMessageCommit(const LLSD& notification, const LLSD& response);
|
||||||
|
|
||||||
LLPanelEstateInfo();
|
LLPanelEstateInfo();
|
||||||
~LLPanelEstateInfo() {}
|
~LLPanelEstateInfo() {}
|
||||||
|
|
||||||
void updateControls(LLViewerRegion* region);
|
void updateControls(LLViewerRegion* region);
|
||||||
|
|
||||||
static void updateEstateName(const std::string& name);
|
static void updateEstateName(const std::string& name);
|
||||||
static void updateEstateOwnerName(const std::string& name);
|
static void updateEstateOwnerName(const std::string& name);
|
||||||
|
|
||||||
bool refreshFromRegion(LLViewerRegion* region) override;
|
bool refreshFromRegion(LLViewerRegion* region) override;
|
||||||
bool estateUpdate(LLMessageSystem* msg) override;
|
bool estateUpdate(LLMessageSystem* msg) override;
|
||||||
|
|
||||||
bool postBuild() override;
|
bool postBuild() override;
|
||||||
void updateChild(LLUICtrl* child_ctrl) override;
|
void updateChild(LLUICtrl* child_ctrl) override;
|
||||||
void refresh() override;
|
void refresh() override;
|
||||||
|
|
||||||
void refreshFromEstate();
|
void refreshFromEstate();
|
||||||
|
|
||||||
static bool isLindenEstate();
|
static bool isLindenEstate();
|
||||||
|
|
||||||
const std::string getOwnerName() const;
|
const std::string getOwnerName() const;
|
||||||
void setOwnerName(const std::string& name);
|
void setOwnerName(const std::string& name);
|
||||||
|
|
||||||
|
|
@ -365,7 +374,7 @@ protected:
|
||||||
|
|
||||||
void commitEstateAccess();
|
void commitEstateAccess();
|
||||||
void commitEstateManagers();
|
void commitEstateManagers();
|
||||||
|
|
||||||
bool checkSunHourSlider(LLUICtrl* child_ctrl);
|
bool checkSunHourSlider(LLUICtrl* child_ctrl);
|
||||||
|
|
||||||
U32 mEstateID;
|
U32 mEstateID;
|
||||||
|
|
@ -378,7 +387,7 @@ class LLPanelEstateCovenant : public LLPanelRegionInfo
|
||||||
public:
|
public:
|
||||||
LLPanelEstateCovenant();
|
LLPanelEstateCovenant();
|
||||||
~LLPanelEstateCovenant() {}
|
~LLPanelEstateCovenant() {}
|
||||||
|
|
||||||
bool postBuild() override;
|
bool postBuild() override;
|
||||||
void updateChild(LLUICtrl* child_ctrl) override;
|
void updateChild(LLUICtrl* child_ctrl) override;
|
||||||
bool refreshFromRegion(LLViewerRegion* region) override;
|
bool refreshFromRegion(LLViewerRegion* region) override;
|
||||||
|
|
@ -441,7 +450,7 @@ class LLPanelRegionExperiences : public LLPanelRegionInfo
|
||||||
public:
|
public:
|
||||||
LLPanelRegionExperiences(){}
|
LLPanelRegionExperiences(){}
|
||||||
bool postBuild() override;
|
bool postBuild() override;
|
||||||
|
|
||||||
static bool experienceCoreConfirm(const LLSD& notification, const LLSD& response);
|
static bool experienceCoreConfirm(const LLSD& notification, const LLSD& response);
|
||||||
static void sendEstateExperienceDelta(U32 flags, const LLUUID& agent_id);
|
static void sendEstateExperienceDelta(U32 flags, const LLUUID& agent_id);
|
||||||
|
|
||||||
|
|
@ -506,7 +515,7 @@ private:
|
||||||
void onAllowedSearchEdit(const std::string& search_string);
|
void onAllowedSearchEdit(const std::string& search_string);
|
||||||
void onAllowedGroupsSearchEdit(const std::string& search_string);
|
void onAllowedGroupsSearchEdit(const std::string& search_string);
|
||||||
void onBannedSearchEdit(const std::string& search_string);
|
void onBannedSearchEdit(const std::string& search_string);
|
||||||
|
|
||||||
// Group picker callback is different, can't use core methods below
|
// Group picker callback is different, can't use core methods below
|
||||||
bool addAllowedGroup(const LLSD& notification, const LLSD& response);
|
bool addAllowedGroup(const LLSD& notification, const LLSD& response);
|
||||||
void addAllowedGroup2(LLUUID id);
|
void addAllowedGroup2(LLUUID id);
|
||||||
|
|
|
||||||
|
|
@ -1159,7 +1159,7 @@ F32 gpu_benchmark()
|
||||||
gBenchmarkProgram.mShaderFiles.push_back(std::make_pair("interface/benchmarkV.glsl", GL_VERTEX_SHADER));
|
gBenchmarkProgram.mShaderFiles.push_back(std::make_pair("interface/benchmarkV.glsl", GL_VERTEX_SHADER));
|
||||||
gBenchmarkProgram.mShaderFiles.push_back(std::make_pair("interface/benchmarkF.glsl", GL_FRAGMENT_SHADER));
|
gBenchmarkProgram.mShaderFiles.push_back(std::make_pair("interface/benchmarkF.glsl", GL_FRAGMENT_SHADER));
|
||||||
gBenchmarkProgram.mShaderLevel = 1;
|
gBenchmarkProgram.mShaderLevel = 1;
|
||||||
if (!gBenchmarkProgram.createShader(NULL, NULL))
|
if (!gBenchmarkProgram.createShader())
|
||||||
{
|
{
|
||||||
return -1.f;
|
return -1.f;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ LLHeroProbeManager::~LLHeroProbeManager()
|
||||||
// helper class to seed octree with probes
|
// helper class to seed octree with probes
|
||||||
void LLHeroProbeManager::update()
|
void LLHeroProbeManager::update()
|
||||||
{
|
{
|
||||||
if (!LLPipeline::RenderMirrors || gTeleportDisplay || LLStartUp::getStartupState() < STATE_PRECACHE)
|
if (!LLPipeline::RenderMirrors || !LLPipeline::sReflectionProbesEnabled || gTeleportDisplay || LLStartUp::getStartupState() < STATE_PRECACHE)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -112,7 +112,6 @@ void LLHeroProbeManager::update()
|
||||||
|
|
||||||
LLVector4a probe_pos;
|
LLVector4a probe_pos;
|
||||||
LLVector3 camera_pos = LLViewerCamera::instance().mOrigin;
|
LLVector3 camera_pos = LLViewerCamera::instance().mOrigin;
|
||||||
F32 near_clip = 0.1f;
|
|
||||||
bool probe_present = false;
|
bool probe_present = false;
|
||||||
LLQuaternion cameraOrientation = LLViewerCamera::instance().getQuaternion();
|
LLQuaternion cameraOrientation = LLViewerCamera::instance().getQuaternion();
|
||||||
LLVector3 cameraDirection = LLVector3::z_axis * cameraOrientation;
|
LLVector3 cameraDirection = LLVector3::z_axis * cameraOrientation;
|
||||||
|
|
@ -124,7 +123,7 @@ void LLHeroProbeManager::update()
|
||||||
float camera_center_distance = 99999.f;
|
float camera_center_distance = 99999.f;
|
||||||
for (auto vo : mHeroVOList)
|
for (auto vo : mHeroVOList)
|
||||||
{
|
{
|
||||||
if (vo && !vo->isDead() && vo->mDrawable.notNull())
|
if (vo && !vo->isDead() && vo->mDrawable.notNull() && vo->isReflectionProbe() && vo->getReflectionProbeIsBox())
|
||||||
{
|
{
|
||||||
float distance = (LLViewerCamera::instance().getOrigin() - vo->getPositionAgent()).magVec();
|
float distance = (LLViewerCamera::instance().getOrigin() - vo->getPositionAgent()).magVec();
|
||||||
float center_distance = cameraDirection * (vo->getPositionAgent() - camera_pos);
|
float center_distance = cameraDirection * (vo->getPositionAgent() - camera_pos);
|
||||||
|
|
@ -192,20 +191,15 @@ void LLHeroProbeManager::update()
|
||||||
// Iterate through each face of the cube
|
// Iterate through each face of the cube
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
{
|
{
|
||||||
float cube_facing = fmax(-1, fmin(1.0f, cameraDirection * cubeFaces[i])) * 0.6 + 0.4;
|
float cube_facing = fmax(-1, fmin(1.0f, cameraDirection * cubeFaces[i]));
|
||||||
|
|
||||||
float updateRate;
|
cube_facing = 1 - cube_facing;
|
||||||
if (cube_facing < 0.1f)
|
|
||||||
{
|
mFaceUpdateList[i] = ceilf(cube_facing * gPipeline.RenderHeroProbeConservativeUpdateMultiplier);
|
||||||
updateRate = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
updateRate = ceilf(cube_facing * gPipeline.RenderHeroProbeConservativeUpdateMultiplier);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mFaceUpdateList[i] = updateRate;
|
|
||||||
}
|
mProbes[0]->mOrigin = probe_pos;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -214,20 +208,24 @@ void LLHeroProbeManager::update()
|
||||||
|
|
||||||
mHeroProbeStrength = 1;
|
mHeroProbeStrength = 1;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
probe_pos.load3(camera_pos.mV);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLHeroProbeManager::renderProbes()
|
||||||
|
{
|
||||||
|
if (!LLPipeline::RenderMirrors || !LLPipeline::sReflectionProbesEnabled || gTeleportDisplay ||
|
||||||
|
LLStartUp::getStartupState() < STATE_PRECACHE)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static LLCachedControl<S32> sDetail(gSavedSettings, "RenderHeroReflectionProbeDetail", -1);
|
static LLCachedControl<S32> sDetail(gSavedSettings, "RenderHeroReflectionProbeDetail", -1);
|
||||||
static LLCachedControl<S32> sLevel(gSavedSettings, "RenderHeroReflectionProbeLevel", 3);
|
static LLCachedControl<S32> sLevel(gSavedSettings, "RenderHeroReflectionProbeLevel", 3);
|
||||||
|
|
||||||
if (mNearestHero != nullptr)
|
F32 near_clip = 0.01f;
|
||||||
|
if (mNearestHero != nullptr && (gPipeline.RenderHeroProbeUpdateRate == 0 || (gFrameCount % gPipeline.RenderHeroProbeUpdateRate) == 0) &&
|
||||||
|
!gTeleportDisplay && !gDisconnected && !LLAppViewer::instance()->logoutRequestSent())
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("hpmu - realtime");
|
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("hpmu - realtime");
|
||||||
// Probe 0 is always our mirror probe.
|
|
||||||
mProbes[0]->mOrigin = probe_pos;
|
|
||||||
|
|
||||||
bool radiance_pass = gPipeline.mReflectionMapManager.isRadiancePass();
|
bool radiance_pass = gPipeline.mReflectionMapManager.isRadiancePass();
|
||||||
|
|
||||||
|
|
@ -585,8 +583,6 @@ void LLHeroProbeManager::cleanup()
|
||||||
|
|
||||||
mDefaultProbe = nullptr;
|
mDefaultProbe = nullptr;
|
||||||
mUpdatingProbe = nullptr;
|
mUpdatingProbe = nullptr;
|
||||||
/*
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLHeroProbeManager::doOcclusion()
|
void LLHeroProbeManager::doOcclusion()
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@ public:
|
||||||
// maintain reflection probes
|
// maintain reflection probes
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
|
void renderProbes();
|
||||||
|
|
||||||
// debug display, called from llspatialpartition if reflection
|
// debug display, called from llspatialpartition if reflection
|
||||||
// probe debug display is active
|
// probe debug display is active
|
||||||
void renderDebug();
|
void renderDebug();
|
||||||
|
|
@ -152,5 +154,6 @@ private:
|
||||||
std::vector<LLPointer<LLVOVolume>> mHeroVOList;
|
std::vector<LLPointer<LLVOVolume>> mHeroVOList;
|
||||||
LLPointer<LLVOVolume> mNearestHero;
|
LLPointer<LLVOVolume> mNearestHero;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1100,8 +1100,9 @@ bool LLLocalBitmapMgr::checkTextureDimensions(std::string filename)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
S32 max_width = gSavedSettings.getS32("max_texture_dimension_X");
|
// allow loading up to 4x max rez but implicitly downrez to max rez before upload
|
||||||
S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y");
|
S32 max_width = gSavedSettings.getS32("max_texture_dimension_X")*4;
|
||||||
|
S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y")*4;
|
||||||
|
|
||||||
if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height))
|
if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height))
|
||||||
{
|
{
|
||||||
|
|
@ -1146,6 +1147,20 @@ void LLLocalBitmapMgr::delUnit(LLUUID tracking_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLUUID LLLocalBitmapMgr::getTrackingID(const LLUUID& world_id) const
|
||||||
|
{
|
||||||
|
for (local_list_citer iter = mBitmapList.begin(); iter != mBitmapList.end(); iter++)
|
||||||
|
{
|
||||||
|
LLLocalBitmap* unit = *iter;
|
||||||
|
if (unit->getWorldID() == world_id)
|
||||||
|
{
|
||||||
|
return unit->getTrackingID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return LLUUID::null;
|
||||||
|
}
|
||||||
|
|
||||||
LLUUID LLLocalBitmapMgr::getWorldID(const LLUUID &tracking_id) const
|
LLUUID LLLocalBitmapMgr::getWorldID(const LLUUID &tracking_id) const
|
||||||
{
|
{
|
||||||
LLUUID world_id = LLUUID::null;
|
LLUUID world_id = LLUUID::null;
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,7 @@ public:
|
||||||
void delUnit(LLUUID tracking_id);
|
void delUnit(LLUUID tracking_id);
|
||||||
bool checkTextureDimensions(std::string filename);
|
bool checkTextureDimensions(std::string filename);
|
||||||
|
|
||||||
|
LLUUID getTrackingID(const LLUUID& world_id) const;
|
||||||
LLUUID getWorldID(const LLUUID &tracking_id) const;
|
LLUUID getWorldID(const LLUUID &tracking_id) const;
|
||||||
bool isLocal(const LLUUID& world_id) const;
|
bool isLocal(const LLUUID& world_id) const;
|
||||||
std::string getFilename(const LLUUID &tracking_id) const;
|
std::string getFilename(const LLUUID &tracking_id) const;
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,8 @@ bool LLLocalGLTFMaterial::updateSelf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
materialBegin();
|
||||||
|
materialComplete(true);
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,6 +203,8 @@ bool LLLocalGLTFMaterial::updateSelf()
|
||||||
LLNotificationsUtil::add("LocalBitmapsUpdateFailedFinal", notif_args);
|
LLNotificationsUtil::add("LocalBitmapsUpdateFailedFinal", notif_args);
|
||||||
|
|
||||||
mLinkStatus = LS_BROKEN;
|
mLinkStatus = LS_BROKEN;
|
||||||
|
materialBegin();
|
||||||
|
materialComplete(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -218,6 +222,8 @@ bool LLLocalGLTFMaterial::updateSelf()
|
||||||
LLNotificationsUtil::add("LocalBitmapsUpdateFileNotFound", notif_args);
|
LLNotificationsUtil::add("LocalBitmapsUpdateFileNotFound", notif_args);
|
||||||
|
|
||||||
mLinkStatus = LS_BROKEN;
|
mLinkStatus = LS_BROKEN;
|
||||||
|
materialBegin();
|
||||||
|
materialComplete(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -492,10 +492,7 @@ bool LLMaterialEditor::postBuild()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
getChild<LLUICtrl>("base_color_upload_fee")->setTextArg("[FEE]", llformat("%d", LLAgentBenefitsMgr::current().getTextureUploadCost(mBaseColorFetched)));
|
refreshUploadCost();
|
||||||
getChild<LLUICtrl>("metallic_upload_fee")->setTextArg("[FEE]", llformat("%d", LLAgentBenefitsMgr::current().getTextureUploadCost(mMetallicRoughnessFetched)));
|
|
||||||
getChild<LLUICtrl>("emissive_upload_fee")->setTextArg("[FEE]", llformat("%d", LLAgentBenefitsMgr::current().getTextureUploadCost(mEmissiveFetched)));
|
|
||||||
getChild<LLUICtrl>("normal_upload_fee")->setTextArg("[FEE]", llformat("%d", LLAgentBenefitsMgr::current().getTextureUploadCost(mNormalFetched)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::function<void(LLUICtrl*, void*)> changes_callback = [this](LLUICtrl * ctrl, void* userData)
|
boost::function<void(LLUICtrl*, void*)> changes_callback = [this](LLUICtrl * ctrl, void* userData)
|
||||||
|
|
@ -814,6 +811,37 @@ void LLMaterialEditor::resetUnsavedChanges()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLMaterialEditor::refreshUploadCost()
|
||||||
|
{
|
||||||
|
mExpectedUploadCost = 0;
|
||||||
|
if (mBaseColorTextureUploadId.notNull() && mBaseColorTextureUploadId == getBaseColorId() && mBaseColorFetched)
|
||||||
|
{
|
||||||
|
S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(mBaseColorFetched);
|
||||||
|
mExpectedUploadCost += upload_cost;
|
||||||
|
getChild<LLUICtrl>("base_color_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost));
|
||||||
|
}
|
||||||
|
if (mMetallicTextureUploadId.notNull() && mMetallicTextureUploadId == getMetallicRoughnessId() && mMetallicRoughnessFetched)
|
||||||
|
{
|
||||||
|
S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(mMetallicRoughnessFetched);
|
||||||
|
mExpectedUploadCost += upload_cost;
|
||||||
|
getChild<LLUICtrl>("metallic_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost));
|
||||||
|
}
|
||||||
|
if (mEmissiveTextureUploadId.notNull() && mEmissiveTextureUploadId == getEmissiveId() && mEmissiveFetched)
|
||||||
|
{
|
||||||
|
S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(mEmissiveFetched);
|
||||||
|
mExpectedUploadCost += upload_cost;
|
||||||
|
getChild<LLUICtrl>("emissive_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost));
|
||||||
|
}
|
||||||
|
if (mNormalTextureUploadId.notNull() && mNormalTextureUploadId == getNormalId() && mNormalFetched)
|
||||||
|
{
|
||||||
|
S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(mNormalFetched);
|
||||||
|
mExpectedUploadCost += upload_cost;
|
||||||
|
getChild<LLUICtrl>("normal_upload_fee")->setTextArg("[FEE]", llformat("%d", upload_cost));
|
||||||
|
}
|
||||||
|
|
||||||
|
getChild<LLUICtrl>("total_upload_fee")->setTextArg("[FEE]", llformat("%d", mExpectedUploadCost));
|
||||||
|
}
|
||||||
|
|
||||||
void LLMaterialEditor::markChangesUnsaved(U32 dirty_flag)
|
void LLMaterialEditor::markChangesUnsaved(U32 dirty_flag)
|
||||||
{
|
{
|
||||||
mUnsavedChanges |= dirty_flag;
|
mUnsavedChanges |= dirty_flag;
|
||||||
|
|
@ -844,25 +872,15 @@ void LLMaterialEditor::markChangesUnsaved(U32 dirty_flag)
|
||||||
setCanSave(false);
|
setCanSave(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
mExpectedUploadCost = 0;
|
if ((dirty_flag & MATERIAL_BASE_COLOR_TEX_DIRTY)
|
||||||
if (mBaseColorTextureUploadId.notNull() && mBaseColorTextureUploadId == getBaseColorId() && mBaseColorFetched)
|
|| (dirty_flag & MATERIAL_NORMAL_TEX_DIRTY)
|
||||||
|
|| (dirty_flag & MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY)
|
||||||
|
|| (dirty_flag & MATERIAL_EMISIVE_TEX_DIRTY)
|
||||||
|
|| (dirty_flag == 0)
|
||||||
|
|| (dirty_flag == U32_MAX))
|
||||||
{
|
{
|
||||||
mExpectedUploadCost += LLAgentBenefitsMgr::current().getTextureUploadCost(mBaseColorFetched);
|
refreshUploadCost();
|
||||||
}
|
}
|
||||||
if (mMetallicTextureUploadId.notNull() && mMetallicTextureUploadId == getMetallicRoughnessId() && mMetallicRoughnessFetched)
|
|
||||||
{
|
|
||||||
mExpectedUploadCost += LLAgentBenefitsMgr::current().getTextureUploadCost(mMetallicRoughnessFetched);
|
|
||||||
}
|
|
||||||
if (mEmissiveTextureUploadId.notNull() && mEmissiveTextureUploadId == getEmissiveId() && mEmissiveFetched)
|
|
||||||
{
|
|
||||||
mExpectedUploadCost += LLAgentBenefitsMgr::current().getTextureUploadCost(mEmissiveFetched);
|
|
||||||
}
|
|
||||||
if (mNormalTextureUploadId.notNull() && mNormalTextureUploadId == getNormalId() && mNormalFetched)
|
|
||||||
{
|
|
||||||
mExpectedUploadCost += LLAgentBenefitsMgr::current().getTextureUploadCost(mNormalFetched);
|
|
||||||
}
|
|
||||||
|
|
||||||
getChild<LLUICtrl>("total_upload_fee")->setTextArg("[FEE]", llformat("%d", mExpectedUploadCost));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLMaterialEditor::setCanSaveAs(bool value)
|
void LLMaterialEditor::setCanSaveAs(bool value)
|
||||||
|
|
|
||||||
|
|
@ -288,6 +288,7 @@ private:
|
||||||
// utility function for building a description of the imported material
|
// utility function for building a description of the imported material
|
||||||
// based on what we know about it.
|
// based on what we know about it.
|
||||||
const std::string buildMaterialDescription();
|
const std::string buildMaterialDescription();
|
||||||
|
void refreshUploadCost();
|
||||||
|
|
||||||
void resetUnsavedChanges();
|
void resetUnsavedChanges();
|
||||||
void markChangesUnsaved(U32 dirty_flag);
|
void markChangesUnsaved(U32 dirty_flag);
|
||||||
|
|
|
||||||
|
|
@ -1362,27 +1362,35 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
|
||||||
|
|
||||||
// Texture
|
// Texture
|
||||||
{
|
{
|
||||||
mIsAlpha = false;
|
|
||||||
LLGLenum image_format = GL_RGB;
|
LLGLenum image_format = GL_RGB;
|
||||||
bool identical_image_format = false;
|
bool identical_image_format = false;
|
||||||
LLSelectedTE::getImageFormat(image_format, identical_image_format);
|
bool missing_asset = false;
|
||||||
|
LLSelectedTE::getImageFormat(image_format, identical_image_format, missing_asset);
|
||||||
|
|
||||||
mIsAlpha = false;
|
if (!missing_asset)
|
||||||
switch (image_format)
|
|
||||||
{
|
{
|
||||||
|
mIsAlpha = false;
|
||||||
|
switch (image_format)
|
||||||
|
{
|
||||||
case GL_RGBA:
|
case GL_RGBA:
|
||||||
case GL_ALPHA:
|
case GL_ALPHA:
|
||||||
{
|
{
|
||||||
mIsAlpha = true;
|
mIsAlpha = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GL_RGB: break;
|
case GL_RGB: break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL;
|
LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Don't know image's properties, use material's mode value
|
||||||
|
mIsAlpha = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LLViewerMedia::getInstance()->textureHasMedia(id))
|
if (LLViewerMedia::getInstance()->textureHasMedia(id))
|
||||||
|
|
@ -1428,10 +1436,12 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
|
||||||
mTextureCtrl->setTentative(false);
|
mTextureCtrl->setTentative(false);
|
||||||
mTextureCtrl->setEnabled(editable && !has_pbr_material);
|
mTextureCtrl->setEnabled(editable && !has_pbr_material);
|
||||||
mTextureCtrl->setImageAssetID(id);
|
mTextureCtrl->setImageAssetID(id);
|
||||||
getChildView("combobox alphamode")->setEnabled(editable && mIsAlpha && transparency <= 0.f && !has_pbr_material);
|
|
||||||
getChildView("label alphamode")->setEnabled(editable && mIsAlpha && !has_pbr_material);
|
bool can_change_alpha = editable && mIsAlpha && !missing_asset && !has_pbr_material;
|
||||||
getChildView("maskcutoff")->setEnabled(editable && mIsAlpha && !has_pbr_material);
|
getChildView("combobox alphamode")->setEnabled(can_change_alpha && transparency <= 0.f);
|
||||||
getChildView("label maskcutoff")->setEnabled(editable && mIsAlpha && !has_pbr_material);
|
getChildView("label alphamode")->setEnabled(can_change_alpha);
|
||||||
|
getChildView("maskcutoff")->setEnabled(can_change_alpha);
|
||||||
|
getChildView("label maskcutoff")->setEnabled(can_change_alpha);
|
||||||
|
|
||||||
mTextureCtrl->setBakeTextureEnabled(true);
|
mTextureCtrl->setBakeTextureEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
@ -1454,10 +1464,12 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
|
||||||
mTextureCtrl->setTentative(true);
|
mTextureCtrl->setTentative(true);
|
||||||
mTextureCtrl->setEnabled(editable && !has_pbr_material);
|
mTextureCtrl->setEnabled(editable && !has_pbr_material);
|
||||||
mTextureCtrl->setImageAssetID(id);
|
mTextureCtrl->setImageAssetID(id);
|
||||||
getChildView("combobox alphamode")->setEnabled(editable && mIsAlpha && transparency <= 0.f && !has_pbr_material);
|
|
||||||
getChildView("label alphamode")->setEnabled(editable && mIsAlpha && !has_pbr_material);
|
bool can_change_alpha = editable && mIsAlpha && !missing_asset && !has_pbr_material;
|
||||||
getChildView("maskcutoff")->setEnabled(editable && mIsAlpha && !has_pbr_material);
|
getChildView("combobox alphamode")->setEnabled(can_change_alpha && transparency <= 0.f);
|
||||||
getChildView("label maskcutoff")->setEnabled(editable && mIsAlpha && !has_pbr_material);
|
getChildView("label alphamode")->setEnabled(can_change_alpha);
|
||||||
|
getChildView("maskcutoff")->setEnabled(can_change_alpha);
|
||||||
|
getChildView("label maskcutoff")->setEnabled(can_change_alpha);
|
||||||
|
|
||||||
mTextureCtrl->setBakeTextureEnabled(true);
|
mTextureCtrl->setBakeTextureEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
@ -3508,13 +3520,14 @@ void LLPanelFace::onSelectTexture(const LLSD& data)
|
||||||
|
|
||||||
LLGLenum image_format;
|
LLGLenum image_format;
|
||||||
bool identical_image_format = false;
|
bool identical_image_format = false;
|
||||||
LLSelectedTE::getImageFormat(image_format, identical_image_format);
|
bool missing_asset = false;
|
||||||
|
LLSelectedTE::getImageFormat(image_format, identical_image_format, missing_asset);
|
||||||
|
|
||||||
LLCtrlSelectionInterface* combobox_alphamode =
|
LLCtrlSelectionInterface* combobox_alphamode =
|
||||||
childGetSelectionInterface("combobox alphamode");
|
childGetSelectionInterface("combobox alphamode");
|
||||||
|
|
||||||
U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
|
U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
|
||||||
if (combobox_alphamode)
|
if (combobox_alphamode && !missing_asset)
|
||||||
{
|
{
|
||||||
switch (image_format)
|
switch (image_format)
|
||||||
{
|
{
|
||||||
|
|
@ -5439,19 +5452,51 @@ void LLPanelFace::LLSelectedTE::getFace(LLFace*& face_to_return, bool& identical
|
||||||
identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, face_to_return, false, (LLFace*)nullptr);
|
identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, face_to_return, false, (LLFace*)nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLPanelFace::LLSelectedTE::getImageFormat(LLGLenum& image_format_to_return, bool& identical_face)
|
void LLPanelFace::LLSelectedTE::getImageFormat(LLGLenum& image_format_to_return, bool& identical_face, bool& missing_asset)
|
||||||
{
|
{
|
||||||
LLGLenum image_format{ GL_RGB };
|
struct LLSelectedTEGetmatId : public LLSelectedTEFunctor
|
||||||
struct LLSelectedTEGetImageFormat : public LLSelectedTEGetFunctor<LLGLenum>
|
|
||||||
{
|
{
|
||||||
LLGLenum get(LLViewerObject* object, S32 te_index)
|
LLSelectedTEGetmatId()
|
||||||
|
: mImageFormat(GL_RGB)
|
||||||
|
, mIdentical(true)
|
||||||
|
, mMissingAsset(false)
|
||||||
|
, mFirstRun(true)
|
||||||
{
|
{
|
||||||
LLViewerTexture* image = object->getTEImage(te_index);
|
|
||||||
return image ? image->getPrimaryFormat() : GL_RGB;
|
|
||||||
}
|
}
|
||||||
} get_glenum;
|
bool apply(LLViewerObject* object, S32 te_index) override
|
||||||
identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_glenum, image_format);
|
{
|
||||||
image_format_to_return = image_format;
|
LLViewerTexture* image = object ? object->getTEImage(te_index) : nullptr;
|
||||||
|
LLGLenum format = GL_RGB;
|
||||||
|
bool missing = false;
|
||||||
|
if (image)
|
||||||
|
{
|
||||||
|
format = image->getPrimaryFormat();
|
||||||
|
missing = image->isMissingAsset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mFirstRun)
|
||||||
|
{
|
||||||
|
mFirstRun = false;
|
||||||
|
mImageFormat = format;
|
||||||
|
mMissingAsset = missing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mIdentical &= (mImageFormat == format);
|
||||||
|
mIdentical &= (mMissingAsset == missing);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
LLGLenum mImageFormat;
|
||||||
|
bool mIdentical;
|
||||||
|
bool mMissingAsset;
|
||||||
|
bool mFirstRun;
|
||||||
|
} func;
|
||||||
|
LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func);
|
||||||
|
|
||||||
|
image_format_to_return = func.mImageFormat;
|
||||||
|
identical_face = func.mIdentical;
|
||||||
|
missing_asset = func.mMissingAsset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical)
|
void LLPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical)
|
||||||
|
|
|
||||||
|
|
@ -665,7 +665,7 @@ public:
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void getFace(class LLFace*& face_to_return, bool& identical_face);
|
static void getFace(class LLFace*& face_to_return, bool& identical_face);
|
||||||
static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face);
|
static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face, bool& missing_asset);
|
||||||
static void getTexId(LLUUID& id, bool& identical);
|
static void getTexId(LLUUID& id, bool& identical);
|
||||||
static void getPbrMaterialId(LLUUID& id, bool& identical, bool& has_pbr, bool& has_faces_without_pbr);
|
static void getPbrMaterialId(LLUUID& id, bool& identical, bool& has_pbr, bool& has_faces_without_pbr);
|
||||||
static void getObjectScaleS(F32& scale_s, bool& identical);
|
static void getObjectScaleS(F32& scale_s, bool& identical);
|
||||||
|
|
|
||||||
|
|
@ -391,6 +391,7 @@ void LLPanelVolume::getState( )
|
||||||
|
|
||||||
// Reflection Probe
|
// Reflection Probe
|
||||||
bool is_probe = volobjp && volobjp->isReflectionProbe();
|
bool is_probe = volobjp && volobjp->isReflectionProbe();
|
||||||
|
bool is_mirror = volobjp && volobjp->getReflectionProbeIsMirror();
|
||||||
getChild<LLUICtrl>("Reflection Probe")->setValue(is_probe);
|
getChild<LLUICtrl>("Reflection Probe")->setValue(is_probe);
|
||||||
getChildView("Reflection Probe")->setEnabled(editable && single_volume && volobjp && !volobjp->isMesh());
|
getChildView("Reflection Probe")->setEnabled(editable && single_volume && volobjp && !volobjp->isMesh());
|
||||||
|
|
||||||
|
|
@ -404,9 +405,9 @@ void LLPanelVolume::getState( )
|
||||||
|
|
||||||
getChildView("Probe Dynamic")->setEnabled(probe_enabled);
|
getChildView("Probe Dynamic")->setEnabled(probe_enabled);
|
||||||
getChildView("Probe Update Type")->setEnabled(probe_enabled);
|
getChildView("Probe Update Type")->setEnabled(probe_enabled);
|
||||||
getChildView("Probe Volume Type")->setEnabled(probe_enabled);
|
getChildView("Probe Volume Type")->setEnabled(probe_enabled && !is_mirror);
|
||||||
getChildView("Probe Ambiance")->setEnabled(probe_enabled);
|
getChildView("Probe Ambiance")->setEnabled(probe_enabled && !is_mirror);
|
||||||
getChildView("Probe Near Clip")->setEnabled(probe_enabled);
|
getChildView("Probe Near Clip")->setEnabled(probe_enabled && !is_mirror);
|
||||||
getChildView("Probe Update Label")->setEnabled(probe_enabled);
|
getChildView("Probe Update Label")->setEnabled(probe_enabled);
|
||||||
|
|
||||||
if (!probe_enabled)
|
if (!probe_enabled)
|
||||||
|
|
@ -445,9 +446,6 @@ void LLPanelVolume::getState( )
|
||||||
update_type = "Dynamic Mirror";
|
update_type = "Dynamic Mirror";
|
||||||
}
|
}
|
||||||
|
|
||||||
getChildView("Probe Ambiance")->setEnabled(update_type != "Mirror");
|
|
||||||
getChildView("Probe Near Clip")->setEnabled(update_type != "Mirror");
|
|
||||||
|
|
||||||
getChild<LLComboBox>("Probe Volume Type", true)->setValue(volume_type);
|
getChild<LLComboBox>("Probe Volume Type", true)->setValue(volume_type);
|
||||||
getChild<LLSpinCtrl>("Probe Ambiance", true)->setValue(volobjp->getReflectionProbeAmbiance());
|
getChild<LLSpinCtrl>("Probe Ambiance", true)->setValue(volobjp->getReflectionProbeAmbiance());
|
||||||
getChild<LLSpinCtrl>("Probe Near Clip", true)->setValue(volobjp->getReflectionProbeNearClip());
|
getChild<LLSpinCtrl>("Probe Near Clip", true)->setValue(volobjp->getReflectionProbeNearClip());
|
||||||
|
|
@ -1494,6 +1492,8 @@ void LLPanelVolume::onCommitProbe(LLUICtrl* ctrl, void* userdata)
|
||||||
|
|
||||||
bool is_mirror = update_type.find("Mirror") != std::string::npos;
|
bool is_mirror = update_type.find("Mirror") != std::string::npos;
|
||||||
|
|
||||||
|
self->getChildView("Probe Volume Type")->setEnabled(!is_mirror);
|
||||||
|
|
||||||
volobjp->setReflectionProbeIsDynamic(update_type.find("Dynamic") != std::string::npos);
|
volobjp->setReflectionProbeIsDynamic(update_type.find("Dynamic") != std::string::npos);
|
||||||
volobjp->setReflectionProbeIsMirror(is_mirror);
|
volobjp->setReflectionProbeIsMirror(is_mirror);
|
||||||
|
|
||||||
|
|
@ -1502,7 +1502,7 @@ void LLPanelVolume::onCommitProbe(LLUICtrl* ctrl, void* userdata)
|
||||||
|
|
||||||
std::string shape_type = self->getChild<LLUICtrl>("Probe Volume Type")->getValue().asString();
|
std::string shape_type = self->getChild<LLUICtrl>("Probe Volume Type")->getValue().asString();
|
||||||
|
|
||||||
bool is_box = shape_type == "Box";
|
bool is_box = shape_type == "Box" || is_mirror;
|
||||||
|
|
||||||
if (volobjp->setReflectionProbeIsBox(is_box))
|
if (volobjp->setReflectionProbeIsBox(is_box))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,198 @@
|
||||||
|
/**
|
||||||
|
* @file llpbrterrainfeatures.cpp
|
||||||
|
*
|
||||||
|
* $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 "llpbrterrainfeatures.h"
|
||||||
|
|
||||||
|
#include "llappviewer.h"
|
||||||
|
#include "llgltfmaterial.h"
|
||||||
|
#include "llviewerregion.h"
|
||||||
|
#include "llvlcomposition.h"
|
||||||
|
|
||||||
|
LLPBRTerrainFeatures gPBRTerrainFeatures;
|
||||||
|
|
||||||
|
// static
|
||||||
|
void LLPBRTerrainFeatures::queueQuery(LLViewerRegion& region, void(*done_callback)(LLUUID, bool, const LLModifyRegion&))
|
||||||
|
{
|
||||||
|
llassert(on_main_thread());
|
||||||
|
llassert(LLCoros::on_main_coro());
|
||||||
|
|
||||||
|
LLUUID region_id = region.getRegionID();
|
||||||
|
|
||||||
|
LLCoros::instance().launch("queryRegionCoro",
|
||||||
|
std::bind(&LLPBRTerrainFeatures::queryRegionCoro,
|
||||||
|
region.getCapability("ModifyRegion"),
|
||||||
|
region_id,
|
||||||
|
done_callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void LLPBRTerrainFeatures::queueModify(LLViewerRegion& region, const LLModifyRegion& composition)
|
||||||
|
{
|
||||||
|
llassert(on_main_thread());
|
||||||
|
llassert(LLCoros::on_main_coro());
|
||||||
|
|
||||||
|
LLSD updates = LLSD::emptyMap();
|
||||||
|
|
||||||
|
LLSD override_updates = LLSD::emptyArray();
|
||||||
|
for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
|
||||||
|
{
|
||||||
|
const LLGLTFMaterial* material_override = composition.getMaterialOverride(i);
|
||||||
|
LLSD override_update;
|
||||||
|
if (material_override)
|
||||||
|
{
|
||||||
|
LLGLTFMaterial::sDefault.getOverrideLLSD(*material_override, override_update);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
override_update = LLSD::emptyMap();
|
||||||
|
}
|
||||||
|
override_updates.append(override_update);
|
||||||
|
}
|
||||||
|
updates["overrides"] = override_updates;
|
||||||
|
|
||||||
|
LLCoros::instance().launch("modifyRegionCoro",
|
||||||
|
std::bind(&LLPBRTerrainFeatures::modifyRegionCoro,
|
||||||
|
region.getCapability("ModifyRegion"),
|
||||||
|
updates,
|
||||||
|
nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void LLPBRTerrainFeatures::queryRegionCoro(std::string cap_url, LLUUID region_id, void(*done_callback)(LLUUID, bool, const LLModifyRegion&) )
|
||||||
|
{
|
||||||
|
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
|
||||||
|
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
|
||||||
|
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("queryRegionCoro", httpPolicy));
|
||||||
|
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
|
||||||
|
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
|
||||||
|
LLCore::HttpHeaders::ptr_t httpHeaders;
|
||||||
|
|
||||||
|
httpOpts->setFollowRedirects(true);
|
||||||
|
|
||||||
|
LL_DEBUGS("GLTF") << "Querying features via ModifyRegion endpoint" << LL_ENDL;
|
||||||
|
|
||||||
|
LLSD result = httpAdapter->getAndSuspend(httpRequest, cap_url, httpOpts, httpHeaders);
|
||||||
|
|
||||||
|
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
|
||||||
|
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
|
||||||
|
|
||||||
|
bool success = true;
|
||||||
|
if (!status || !result["success"].asBoolean())
|
||||||
|
{
|
||||||
|
if (result["message"].isUndefined())
|
||||||
|
{
|
||||||
|
LL_WARNS("PBRTerrain") << "Failed to query PBR terrain features." << LL_ENDL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LL_WARNS("PBRTerrain") << "Failed to query PBR terrain features: " << result["message"] << LL_ENDL;
|
||||||
|
}
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLTerrainMaterials* composition = new LLTerrainMaterials();
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
const LLSD& overrides = result["overrides"];
|
||||||
|
if (!overrides.isArray() || overrides.size() < LLTerrainMaterials::ASSET_COUNT)
|
||||||
|
{
|
||||||
|
LL_WARNS("PBRTerrain") << "Invalid composition format: Missing/invalid overrides" << LL_ENDL;
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
|
||||||
|
{
|
||||||
|
const LLSD& override_llsd = overrides[i];
|
||||||
|
LLPointer<LLGLTFMaterial> material_override = new LLGLTFMaterial();
|
||||||
|
material_override->applyOverrideLLSD(override_llsd);
|
||||||
|
if (*material_override == LLGLTFMaterial::sDefault)
|
||||||
|
{
|
||||||
|
material_override = nullptr;
|
||||||
|
}
|
||||||
|
composition->setMaterialOverride(i, material_override.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done_callback)
|
||||||
|
{
|
||||||
|
LLAppViewer::instance()->postToMainCoro([=]()
|
||||||
|
{
|
||||||
|
done_callback(region_id, success, *composition);
|
||||||
|
delete composition;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete composition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void LLPBRTerrainFeatures::modifyRegionCoro(std::string cap_url, LLSD updates, void(*done_callback)(bool) )
|
||||||
|
{
|
||||||
|
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
|
||||||
|
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
|
||||||
|
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("modifyRegionCoro", httpPolicy));
|
||||||
|
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
|
||||||
|
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
|
||||||
|
LLCore::HttpHeaders::ptr_t httpHeaders;
|
||||||
|
|
||||||
|
httpOpts->setFollowRedirects(true);
|
||||||
|
|
||||||
|
LL_DEBUGS("GLTF") << "Applying features via ModifyRegion endpoint: " << updates << LL_ENDL;
|
||||||
|
|
||||||
|
LLSD result = httpAdapter->postAndSuspend(httpRequest, cap_url, updates, httpOpts, httpHeaders);
|
||||||
|
|
||||||
|
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
|
||||||
|
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
|
||||||
|
|
||||||
|
bool success = true;
|
||||||
|
if (!status || !result["success"].asBoolean())
|
||||||
|
{
|
||||||
|
if (result["message"].isUndefined())
|
||||||
|
{
|
||||||
|
LL_WARNS("PBRTerrain") << "Failed to modify PBR terrain features." << LL_ENDL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LL_WARNS("PBRTerrain") << "Failed to modify PBR terrain features: " << result["message"] << LL_ENDL;
|
||||||
|
}
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done_callback)
|
||||||
|
{
|
||||||
|
LLAppViewer::instance()->postToMainCoro([=]()
|
||||||
|
{
|
||||||
|
done_callback(success);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
* @file llpbrterrainfeatures.h
|
||||||
|
*
|
||||||
|
* $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$
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class LLViewerRegion;
|
||||||
|
class LLMessageSystem;
|
||||||
|
class LLModifyRegion;
|
||||||
|
|
||||||
|
// Queries/modifies PBR terrain repeats, possibly other features in the future
|
||||||
|
class LLPBRTerrainFeatures
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void queueQuery(LLViewerRegion& region, void(*done_callback)(LLUUID, bool, const LLModifyRegion&));
|
||||||
|
static void queueModify(LLViewerRegion& region, const LLModifyRegion& composition);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void queryRegionCoro(std::string cap_url, LLUUID region_id, void(*done_callback)(LLUUID, bool, const LLModifyRegion&) );
|
||||||
|
static void modifyRegionCoro(std::string cap_url, LLSD updates, void(*done_callback)(bool) );
|
||||||
|
};
|
||||||
|
|
||||||
|
extern LLPBRTerrainFeatures gPBRTerrainFeatures;
|
||||||
|
|
||||||
|
|
@ -67,7 +67,7 @@ void load_exr(const std::string& filename)
|
||||||
const char* err = NULL; // or nullptr in C++11
|
const char* err = NULL; // or nullptr in C++11
|
||||||
|
|
||||||
int ret = LoadEXRWithLayer(&out, &width, &height, filename.c_str(), /* layername */ nullptr, &err);
|
int ret = LoadEXRWithLayer(&out, &width, &height, filename.c_str(), /* layername */ nullptr, &err);
|
||||||
if (ret == TINYEXR_SUCCESS)
|
if (ret == TINYEXR_SUCCESS)
|
||||||
{
|
{
|
||||||
U32 texName = 0;
|
U32 texName = 0;
|
||||||
LLImageGL::generateTextures(1, &texName);
|
LLImageGL::generateTextures(1, &texName);
|
||||||
|
|
@ -87,12 +87,12 @@ void load_exr(const std::string& filename)
|
||||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LLSD notif_args;
|
LLSD notif_args;
|
||||||
notif_args["WHAT"] = filename;
|
notif_args["WHAT"] = filename;
|
||||||
notif_args["REASON"] = "Unknown";
|
notif_args["REASON"] = "Unknown";
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
notif_args["REASON"] = std::string(err);
|
notif_args["REASON"] = std::string(err);
|
||||||
FreeEXRErrorMessage(err); // release memory of error message.
|
FreeEXRErrorMessage(err); // release memory of error message.
|
||||||
|
|
@ -231,7 +231,7 @@ void LLReflectionMapManager::update()
|
||||||
{
|
{
|
||||||
U32 res = mProbeResolution;
|
U32 res = mProbeResolution;
|
||||||
U32 count = log2((F32)res) + 0.5f;
|
U32 count = log2((F32)res) + 0.5f;
|
||||||
|
|
||||||
mMipChain.resize(count);
|
mMipChain.resize(count);
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -241,7 +241,7 @@ void LLReflectionMapManager::update()
|
||||||
}
|
}
|
||||||
|
|
||||||
llassert(mProbes[0] == mDefaultProbe);
|
llassert(mProbes[0] == mDefaultProbe);
|
||||||
|
|
||||||
LLVector4a camera_pos;
|
LLVector4a camera_pos;
|
||||||
camera_pos.load3(LLViewerCamera::instance().getOrigin().mV);
|
camera_pos.load3(LLViewerCamera::instance().getOrigin().mV);
|
||||||
|
|
||||||
|
|
@ -256,7 +256,7 @@ void LLReflectionMapManager::update()
|
||||||
}
|
}
|
||||||
|
|
||||||
mKillList.clear();
|
mKillList.clear();
|
||||||
|
|
||||||
// process create list
|
// process create list
|
||||||
for (auto& probe : mCreateList)
|
for (auto& probe : mCreateList)
|
||||||
{
|
{
|
||||||
|
|
@ -272,12 +272,12 @@ void LLReflectionMapManager::update()
|
||||||
|
|
||||||
|
|
||||||
bool did_update = false;
|
bool did_update = false;
|
||||||
|
|
||||||
static LLCachedControl<S32> sDetail(gSavedSettings, "RenderReflectionProbeDetail", -1);
|
static LLCachedControl<S32> sDetail(gSavedSettings, "RenderReflectionProbeDetail", -1);
|
||||||
static LLCachedControl<S32> sLevel(gSavedSettings, "RenderReflectionProbeLevel", 3);
|
static LLCachedControl<S32> sLevel(gSavedSettings, "RenderReflectionProbeLevel", 3);
|
||||||
|
|
||||||
bool realtime = sDetail >= (S32)LLReflectionMapManager::DetailLevel::REALTIME;
|
bool realtime = sDetail >= (S32)LLReflectionMapManager::DetailLevel::REALTIME;
|
||||||
|
|
||||||
LLReflectionMap* closestDynamic = nullptr;
|
LLReflectionMap* closestDynamic = nullptr;
|
||||||
|
|
||||||
LLReflectionMap* oldestProbe = nullptr;
|
LLReflectionMap* oldestProbe = nullptr;
|
||||||
|
|
@ -339,7 +339,7 @@ void LLReflectionMapManager::update()
|
||||||
--i;
|
--i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (probe != mDefaultProbe &&
|
if (probe != mDefaultProbe &&
|
||||||
(!probe->isRelevant() || mPaused))
|
(!probe->isRelevant() || mPaused))
|
||||||
{ // skip irrelevant probes (or all non-default probes if paused)
|
{ // skip irrelevant probes (or all non-default probes if paused)
|
||||||
|
|
@ -442,7 +442,7 @@ void LLReflectionMapManager::update()
|
||||||
{
|
{
|
||||||
LLReflectionMap* probe = oldestProbe;
|
LLReflectionMap* probe = oldestProbe;
|
||||||
llassert(probe->mCubeIndex != -1);
|
llassert(probe->mCubeIndex != -1);
|
||||||
|
|
||||||
probe->autoAdjustOrigin();
|
probe->autoAdjustOrigin();
|
||||||
|
|
||||||
sUpdateCount++;
|
sUpdateCount++;
|
||||||
|
|
@ -636,7 +636,7 @@ void LLReflectionMapManager::doProbeUpdate()
|
||||||
llassert(mUpdatingProbe != nullptr);
|
llassert(mUpdatingProbe != nullptr);
|
||||||
|
|
||||||
updateProbeFace(mUpdatingProbe, mUpdatingFace);
|
updateProbeFace(mUpdatingProbe, mUpdatingFace);
|
||||||
|
|
||||||
bool debug_updates = gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PROBE_UPDATES) && mUpdatingProbe->mViewerObject;
|
bool debug_updates = gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PROBE_UPDATES) && mUpdatingProbe->mViewerObject;
|
||||||
|
|
||||||
if (++mUpdatingFace == 6)
|
if (++mUpdatingFace == 6)
|
||||||
|
|
@ -689,11 +689,11 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
|
||||||
touch_default_probe(probe);
|
touch_default_probe(probe);
|
||||||
|
|
||||||
gPipeline.pushRenderTypeMask();
|
gPipeline.pushRenderTypeMask();
|
||||||
|
|
||||||
//only render sky, water, terrain, and clouds
|
//only render sky, water, terrain, and clouds
|
||||||
gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, LLPipeline::RENDER_TYPE_WL_SKY,
|
gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, LLPipeline::RENDER_TYPE_WL_SKY,
|
||||||
LLPipeline::RENDER_TYPE_WATER, LLPipeline::RENDER_TYPE_VOIDWATER, LLPipeline::RENDER_TYPE_CLOUDS, LLPipeline::RENDER_TYPE_TERRAIN, LLPipeline::END_RENDER_TYPES);
|
LLPipeline::RENDER_TYPE_WATER, LLPipeline::RENDER_TYPE_VOIDWATER, LLPipeline::RENDER_TYPE_CLOUDS, LLPipeline::RENDER_TYPE_TERRAIN, LLPipeline::END_RENDER_TYPES);
|
||||||
|
|
||||||
probe->update(mRenderTarget.getWidth(), face);
|
probe->update(mRenderTarget.getWidth(), face);
|
||||||
|
|
||||||
gPipeline.popRenderTypeMask();
|
gPipeline.popRenderTypeMask();
|
||||||
|
|
@ -702,7 +702,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
|
||||||
{
|
{
|
||||||
probe->update(mRenderTarget.getWidth(), face);
|
probe->update(mRenderTarget.getWidth(), face);
|
||||||
}
|
}
|
||||||
|
|
||||||
gPipeline.mRT = &gPipeline.mMainRT;
|
gPipeline.mRT = &gPipeline.mMainRT;
|
||||||
|
|
||||||
S32 sourceIdx = mReflectionProbeCount;
|
S32 sourceIdx = mReflectionProbeCount;
|
||||||
|
|
@ -779,12 +779,12 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
|
||||||
gGL.getTexUnit(diffuseChannel)->bind(&(mMipChain[i - 1]));
|
gGL.getTexUnit(diffuseChannel)->bind(&(mMipChain[i - 1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gReflectionMipProgram.uniform1f(resScale, 1.f/(mProbeResolution*2));
|
gReflectionMipProgram.uniform1f(resScale, 1.f/(mProbeResolution*2));
|
||||||
|
|
||||||
gPipeline.mScreenTriangleVB->setBuffer();
|
gPipeline.mScreenTriangleVB->setBuffer();
|
||||||
gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
|
gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
|
||||||
|
|
||||||
res /= 2;
|
res /= 2;
|
||||||
|
|
||||||
S32 mip = i - (mMipChain.size() - mips);
|
S32 mip = i - (mMipChain.size() - mips);
|
||||||
|
|
@ -874,7 +874,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
|
||||||
|
|
||||||
gIrradianceGenProgram.uniform1i(sSourceIdx, sourceIdx);
|
gIrradianceGenProgram.uniform1i(sSourceIdx, sourceIdx);
|
||||||
gIrradianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD);
|
gIrradianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD);
|
||||||
|
|
||||||
mVertexBuffer->setBuffer();
|
mVertexBuffer->setBuffer();
|
||||||
int start_mip = 0;
|
int start_mip = 0;
|
||||||
// find the mip target to start with based on irradiance map resolution
|
// find the mip target to start with based on irradiance map resolution
|
||||||
|
|
@ -951,7 +951,7 @@ void LLReflectionMapManager::updateNeighbors(LLReflectionMap* probe)
|
||||||
//remove from existing neighbors
|
//remove from existing neighbors
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - clear");
|
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - clear");
|
||||||
|
|
||||||
for (auto& other : probe->mNeighbors)
|
for (auto& other : probe->mNeighbors)
|
||||||
{
|
{
|
||||||
auto const & iter = std::find(other->mNeighbors.begin(), other->mNeighbors.end(), probe);
|
auto const & iter = std::find(other->mNeighbors.begin(), other->mNeighbors.end(), probe);
|
||||||
|
|
@ -1063,7 +1063,7 @@ void LLReflectionMapManager::updateUniforms()
|
||||||
bool is_ambiance_pass = gCubeSnapshot && !isRadiancePass();
|
bool is_ambiance_pass = gCubeSnapshot && !isRadiancePass();
|
||||||
F32 ambscale = is_ambiance_pass ? 0.f : 1.f;
|
F32 ambscale = is_ambiance_pass ? 0.f : 1.f;
|
||||||
F32 radscale = is_ambiance_pass ? 0.5f : 1.f;
|
F32 radscale = is_ambiance_pass ? 0.5f : 1.f;
|
||||||
|
|
||||||
for (auto* refmap : mReflectionMaps)
|
for (auto* refmap : mReflectionMaps)
|
||||||
{
|
{
|
||||||
if (refmap == nullptr)
|
if (refmap == nullptr)
|
||||||
|
|
@ -1194,7 +1194,7 @@ void LLReflectionMapManager::updateUniforms()
|
||||||
{
|
{
|
||||||
// fill in gaps in refBucket
|
// fill in gaps in refBucket
|
||||||
S32 probe_idx = mReflectionProbeCount;
|
S32 probe_idx = mReflectionProbeCount;
|
||||||
|
|
||||||
for (int i = 0; i < 256; ++i)
|
for (int i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
if (i < count)
|
if (i < count)
|
||||||
|
|
@ -1266,7 +1266,7 @@ void LLReflectionMapManager::setUniforms()
|
||||||
{
|
{
|
||||||
updateUniforms();
|
updateUniforms();
|
||||||
}
|
}
|
||||||
glBindBufferBase(GL_UNIFORM_BUFFER, 1, mUBO);
|
glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_REFLECTION_PROBES, mUBO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1441,9 +1441,9 @@ void LLReflectionMapManager::initReflectionMaps()
|
||||||
buff->allocateBuffer(4, 0);
|
buff->allocateBuffer(4, 0);
|
||||||
|
|
||||||
LLStrider<LLVector3> v;
|
LLStrider<LLVector3> v;
|
||||||
|
|
||||||
buff->getVertexStrider(v);
|
buff->getVertexStrider(v);
|
||||||
|
|
||||||
v[0] = LLVector3(-1, -1, -1);
|
v[0] = LLVector3(-1, -1, -1);
|
||||||
v[1] = LLVector3(1, -1, -1);
|
v[1] = LLVector3(1, -1, -1);
|
||||||
v[2] = LLVector3(-1, 1, -1);
|
v[2] = LLVector3(-1, 1, -1);
|
||||||
|
|
@ -1471,7 +1471,7 @@ void LLReflectionMapManager::cleanup()
|
||||||
|
|
||||||
mReflectionMaps.clear();
|
mReflectionMaps.clear();
|
||||||
mUpdatingFace = 0;
|
mUpdatingFace = 0;
|
||||||
|
|
||||||
mDefaultProbe = nullptr;
|
mDefaultProbe = nullptr;
|
||||||
mUpdatingProbe = nullptr;
|
mUpdatingProbe = nullptr;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,6 @@ static std::string click_action_to_string_value(U8 click_action)
|
||||||
default:
|
default:
|
||||||
return "Touch";
|
return "Touch";
|
||||||
}
|
}
|
||||||
return "Touch";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default constructor
|
// Default constructor
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,12 @@ U32 LLSkinningUtil::getMeshJointCount(const LLMeshSkinInfo *skin)
|
||||||
return llmin((U32)getMaxJointCount(), (U32)skin->mJointNames.size());
|
return llmin((U32)getMaxJointCount(), (U32)skin->mJointNames.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
S32 LLSkinningUtil::getMaxGLTFJointCount()
|
||||||
|
{
|
||||||
|
// this is the maximum number of 3x4 matrices than can fit in a UBO
|
||||||
|
return gGLManager.mMaxUniformBlockSize / 48;
|
||||||
|
}
|
||||||
|
|
||||||
void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin)
|
void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin)
|
||||||
{
|
{
|
||||||
if (skin->mInvalidJointsScrubbed)
|
if (skin->mInvalidJointsScrubbed)
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ class LLJointRiggingInfoTab;
|
||||||
namespace LLSkinningUtil
|
namespace LLSkinningUtil
|
||||||
{
|
{
|
||||||
S32 getMaxJointCount();
|
S32 getMaxJointCount();
|
||||||
|
S32 getMaxGLTFJointCount();
|
||||||
U32 getMeshJointCount(const LLMeshSkinInfo *skin);
|
U32 getMeshJointCount(const LLMeshSkinInfo *skin);
|
||||||
void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin);
|
void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin);
|
||||||
void initSkinningMatrixPalette(LLMatrix4a* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar);
|
void initSkinningMatrixPalette(LLMatrix4a* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar);
|
||||||
|
|
|
||||||
|
|
@ -703,7 +703,7 @@ bool LLFloaterTexturePicker::postBuild()
|
||||||
|
|
||||||
getChild<LLComboBox>("l_bake_use_texture_combo_box")->setCommitCallback(onBakeTextureSelect, this);
|
getChild<LLComboBox>("l_bake_use_texture_combo_box")->setCommitCallback(onBakeTextureSelect, this);
|
||||||
|
|
||||||
setBakeTextureEnabled(true);
|
setBakeTextureEnabled(mInventoryPickType != PICK_MATERIAL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2058,7 +2058,7 @@ void LLTextureCtrl::showPicker(bool take_focus)
|
||||||
{
|
{
|
||||||
texture_floaterp->setSetImageAssetIDCallback(boost::bind(&LLTextureCtrl::setImageAssetID, this, _1));
|
texture_floaterp->setSetImageAssetIDCallback(boost::bind(&LLTextureCtrl::setImageAssetID, this, _1));
|
||||||
|
|
||||||
texture_floaterp->setBakeTextureEnabled(mBakeTextureEnabled);
|
texture_floaterp->setBakeTextureEnabled(mBakeTextureEnabled && mInventoryPickType != PICK_MATERIAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLFloater* root_floater = gFloaterView->getParentFloater(this);
|
LLFloater* root_floater = gFloaterView->getParentFloater(this);
|
||||||
|
|
@ -2300,7 +2300,7 @@ void LLTextureCtrl::setBakeTextureEnabled(bool enabled)
|
||||||
LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
|
LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get();
|
||||||
if (floaterp)
|
if (floaterp)
|
||||||
{
|
{
|
||||||
floaterp->setBakeTextureEnabled(enabled);
|
floaterp->setBakeTextureEnabled(enabled && mInventoryPickType != PICK_MATERIAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -770,10 +770,11 @@ void display(bool rebuild, F32 zoom_factor, int subfield, bool for_snapshot)
|
||||||
{
|
{
|
||||||
// Render mirrors and associated hero probes before we render the rest of the scene.
|
// Render mirrors and associated hero probes before we render the rest of the scene.
|
||||||
// This ensures the scene state in the hero probes are exactly the same as the rest of the scene before we render it.
|
// This ensures the scene state in the hero probes are exactly the same as the rest of the scene before we render it.
|
||||||
if (gPipeline.RenderMirrors && !gSnapshot && (gPipeline.RenderHeroProbeUpdateRate == 0 || (gFrameCount % gPipeline.RenderHeroProbeUpdateRate) == 0))
|
if (gPipeline.RenderMirrors && !gSnapshot)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Update hero probes");
|
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Update hero probes");
|
||||||
gPipeline.mHeroProbeManager.update();
|
gPipeline.mHeroProbeManager.update();
|
||||||
|
gPipeline.mHeroProbeManager.renderProbes();
|
||||||
}
|
}
|
||||||
|
|
||||||
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 1");
|
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 1");
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,7 @@
|
||||||
#include "llcleanup.h"
|
#include "llcleanup.h"
|
||||||
#include "llviewershadermgr.h"
|
#include "llviewershadermgr.h"
|
||||||
#include "gltfscenemanager.h"
|
#include "gltfscenemanager.h"
|
||||||
|
#include "gltf/asset.h"
|
||||||
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
|
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
|
||||||
#include "fsavatarrenderpersistence.h"
|
#include "fsavatarrenderpersistence.h"
|
||||||
#include "rlvactions.h"
|
#include "rlvactions.h"
|
||||||
|
|
@ -4016,6 +4017,33 @@ bool enable_gltf()
|
||||||
return enablegltf;
|
return enablegltf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool enable_gltf_save_as()
|
||||||
|
{
|
||||||
|
if (enable_gltf())
|
||||||
|
{
|
||||||
|
LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject();
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
if (obj->mGLTFAsset && obj->mGLTFAsset->isLocalPreview())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LLPermissions* permissions = LLSelectMgr::getInstance()->findObjectPermissions(obj);
|
||||||
|
if (permissions)
|
||||||
|
{
|
||||||
|
return permissions->allowExportBy(gAgent.getID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool enable_gltf_upload()
|
||||||
|
{
|
||||||
|
return enable_gltf_save_as();
|
||||||
|
}
|
||||||
|
|
||||||
class LLSelfRemoveAllAttachments : public view_listener_t
|
class LLSelfRemoveAllAttachments : public view_listener_t
|
||||||
{
|
{
|
||||||
bool handleEvent(const LLSD& userdata)
|
bool handleEvent(const LLSD& userdata)
|
||||||
|
|
@ -10091,15 +10119,6 @@ class LLAdvancedClickGLTFSaveAs : public view_listener_t
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class LLAdvancedClickGLTFDecompose : public view_listener_t
|
|
||||||
{
|
|
||||||
bool handleEvent(const LLSD& userdata)
|
|
||||||
{
|
|
||||||
LL::GLTFSceneManager::instance().decomposeSelection();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class LLAdvancedClickGLTFUpload: public view_listener_t
|
class LLAdvancedClickGLTFUpload: public view_listener_t
|
||||||
{
|
{
|
||||||
bool handleEvent(const LLSD& userdata)
|
bool handleEvent(const LLSD& userdata)
|
||||||
|
|
@ -12583,7 +12602,6 @@ void initialize_menus()
|
||||||
view_listener_t::addMenu(new LLAdvancedClickHDRIPreview(), "Advanced.ClickHDRIPreview");
|
view_listener_t::addMenu(new LLAdvancedClickHDRIPreview(), "Advanced.ClickHDRIPreview");
|
||||||
view_listener_t::addMenu(new LLAdvancedClickGLTFOpen(), "Advanced.ClickGLTFOpen");
|
view_listener_t::addMenu(new LLAdvancedClickGLTFOpen(), "Advanced.ClickGLTFOpen");
|
||||||
view_listener_t::addMenu(new LLAdvancedClickGLTFSaveAs(), "Advanced.ClickGLTFSaveAs");
|
view_listener_t::addMenu(new LLAdvancedClickGLTFSaveAs(), "Advanced.ClickGLTFSaveAs");
|
||||||
view_listener_t::addMenu(new LLAdvancedClickGLTFDecompose(), "Advanced.ClickGLTFDecompose");
|
|
||||||
view_listener_t::addMenu(new LLAdvancedClickGLTFUpload(), "Advanced.ClickGLTFUpload");
|
view_listener_t::addMenu(new LLAdvancedClickGLTFUpload(), "Advanced.ClickGLTFUpload");
|
||||||
view_listener_t::addMenu(new LLAdvancedClickResizeWindow(), "Advanced.ClickResizeWindow");
|
view_listener_t::addMenu(new LLAdvancedClickResizeWindow(), "Advanced.ClickResizeWindow");
|
||||||
view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache");
|
view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache");
|
||||||
|
|
@ -12948,6 +12966,8 @@ void initialize_menus()
|
||||||
enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters));
|
enable.add("EnableSelectInPathfindingCharacters", boost::bind(&enable_object_select_in_pathfinding_characters));
|
||||||
enable.add("Advanced.EnableErrorOSException", boost::bind(&enable_os_exception));
|
enable.add("Advanced.EnableErrorOSException", boost::bind(&enable_os_exception));
|
||||||
enable.add("EnableGLTF", boost::bind(&enable_gltf));
|
enable.add("EnableGLTF", boost::bind(&enable_gltf));
|
||||||
|
enable.add("EnableGLTFSaveAs", boost::bind(&enable_gltf_save_as));
|
||||||
|
enable.add("EnableGLTFUpload", boost::bind(&enable_gltf_upload));
|
||||||
enable.add("EnableBridgeFunction", boost::bind(&enable_bridge_function)); // <FS:CR>
|
enable.add("EnableBridgeFunction", boost::bind(&enable_bridge_function)); // <FS:CR>
|
||||||
|
|
||||||
view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible");
|
view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible");
|
||||||
|
|
|
||||||
|
|
@ -590,192 +590,6 @@ void process_layer_data(LLMessageSystem *mesgsys, void **user_data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// S32 exported_object_count = 0;
|
|
||||||
// S32 exported_image_count = 0;
|
|
||||||
// S32 current_object_count = 0;
|
|
||||||
// S32 current_image_count = 0;
|
|
||||||
|
|
||||||
// extern LLNotifyBox *gExporterNotify;
|
|
||||||
// extern LLUUID gExporterRequestID;
|
|
||||||
// extern std::string gExportDirectory;
|
|
||||||
|
|
||||||
// extern LLUploadDialog *gExportDialog;
|
|
||||||
|
|
||||||
// std::string gExportedFile;
|
|
||||||
|
|
||||||
// std::map<LLUUID, std::string> gImageChecksums;
|
|
||||||
|
|
||||||
// void export_complete()
|
|
||||||
// {
|
|
||||||
// LLUploadDialog::modalUploadFinished();
|
|
||||||
// gExporterRequestID.setNull();
|
|
||||||
// gExportDirectory = "";
|
|
||||||
|
|
||||||
// LLFILE* fXML = LLFile::fopen(gExportedFile, "rb"); /* Flawfinder: ignore */
|
|
||||||
// fseek(fXML, 0, SEEK_END);
|
|
||||||
// long length = ftell(fXML);
|
|
||||||
// fseek(fXML, 0, SEEK_SET);
|
|
||||||
// U8 *buffer = new U8[length + 1];
|
|
||||||
// size_t nread = fread(buffer, 1, length, fXML);
|
|
||||||
// if (nread < (size_t) length)
|
|
||||||
// {
|
|
||||||
// LL_WARNS("Messaging") << "Short read" << LL_ENDL;
|
|
||||||
// }
|
|
||||||
// buffer[nread] = '\0';
|
|
||||||
// fclose(fXML);
|
|
||||||
|
|
||||||
// char *pos = (char *)buffer;
|
|
||||||
// while ((pos = strstr(pos+1, "<sl:image ")) != 0)
|
|
||||||
// {
|
|
||||||
// char *pos_check = strstr(pos, "checksum=\"");
|
|
||||||
|
|
||||||
// if (pos_check)
|
|
||||||
// {
|
|
||||||
// char *pos_uuid = strstr(pos_check, "\">");
|
|
||||||
|
|
||||||
// if (pos_uuid)
|
|
||||||
// {
|
|
||||||
// char image_uuid_str[UUID_STR_SIZE]; /* Flawfinder: ignore */
|
|
||||||
// memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1); /* Flawfinder: ignore */
|
|
||||||
// image_uuid_str[UUID_STR_SIZE-1] = 0;
|
|
||||||
|
|
||||||
// LLUUID image_uuid(image_uuid_str);
|
|
||||||
|
|
||||||
// LL_INFOS("Messaging") << "Found UUID: " << image_uuid << LL_ENDL;
|
|
||||||
|
|
||||||
// std::map<LLUUID, std::string>::iterator itor = gImageChecksums.find(image_uuid);
|
|
||||||
// if (itor != gImageChecksums.end())
|
|
||||||
// {
|
|
||||||
// LL_INFOS("Messaging") << "Replacing with checksum: " << itor->second << LL_ENDL;
|
|
||||||
// if (!itor->second.empty())
|
|
||||||
// {
|
|
||||||
// memcpy(&pos_check[10], itor->second.c_str(), 32); /* Flawfinder: ignore */
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// LLFILE* fXMLOut = LLFile::fopen(gExportedFile, "wb"); /* Flawfinder: ignore */
|
|
||||||
// if (fwrite(buffer, 1, length, fXMLOut) != length)
|
|
||||||
// {
|
|
||||||
// LL_WARNS("Messaging") << "Short write" << LL_ENDL;
|
|
||||||
// }
|
|
||||||
// fclose(fXMLOut);
|
|
||||||
|
|
||||||
// delete [] buffer;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// void exported_item_complete(const LLTSCode status, void *user_data)
|
|
||||||
// {
|
|
||||||
// //std::string *filename = (std::string *)user_data;
|
|
||||||
|
|
||||||
// if (status < LLTS_OK)
|
|
||||||
// {
|
|
||||||
// LL_WARNS("Messaging") << "Export failed!" << LL_ENDL;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// ++current_object_count;
|
|
||||||
// if (current_image_count == exported_image_count && current_object_count == exported_object_count)
|
|
||||||
// {
|
|
||||||
// LL_INFOS("Messaging") << "*** Export complete ***" << LL_ENDL;
|
|
||||||
|
|
||||||
// export_complete();
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// struct exported_image_info
|
|
||||||
// {
|
|
||||||
// LLUUID image_id;
|
|
||||||
// std::string filename;
|
|
||||||
// U32 image_num;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// void exported_j2c_complete(const LLTSCode status, void *user_data)
|
|
||||||
// {
|
|
||||||
// exported_image_info *info = (exported_image_info *)user_data;
|
|
||||||
// LLUUID image_id = info->image_id;
|
|
||||||
// U32 image_num = info->image_num;
|
|
||||||
// std::string filename = info->filename;
|
|
||||||
// delete info;
|
|
||||||
|
|
||||||
// if (status < LLTS_OK)
|
|
||||||
// {
|
|
||||||
// LL_WARNS("Messaging") << "Image download failed!" << LL_ENDL;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// LLFILE* fIn = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */
|
|
||||||
// if (fIn)
|
|
||||||
// {
|
|
||||||
// LLPointer<LLImageJ2C> ImageUtility = new LLImageJ2C;
|
|
||||||
// LLPointer<LLImageTGA> TargaUtility = new LLImageTGA;
|
|
||||||
|
|
||||||
// fseek(fIn, 0, SEEK_END);
|
|
||||||
// S32 length = ftell(fIn);
|
|
||||||
// fseek(fIn, 0, SEEK_SET);
|
|
||||||
// U8 *buffer = ImageUtility->allocateData(length);
|
|
||||||
// if (fread(buffer, 1, length, fIn) != length)
|
|
||||||
// {
|
|
||||||
// LL_WARNS("Messaging") << "Short read" << LL_ENDL;
|
|
||||||
// }
|
|
||||||
// fclose(fIn);
|
|
||||||
// LLFile::remove(filename);
|
|
||||||
|
|
||||||
// // Convert to TGA
|
|
||||||
// LLPointer<LLImageRaw> image = new LLImageRaw();
|
|
||||||
|
|
||||||
// ImageUtility->updateData();
|
|
||||||
// ImageUtility->decode(image, 100000.0f);
|
|
||||||
|
|
||||||
// TargaUtility->encode(image);
|
|
||||||
// U8 *data = TargaUtility->getData();
|
|
||||||
// S32 data_size = TargaUtility->getDataSize();
|
|
||||||
|
|
||||||
// std::string file_path = gDirUtilp->getDirName(filename);
|
|
||||||
|
|
||||||
// std::string output_file = llformat("%s/image-%03d.tga", file_path.c_str(), image_num);//filename;
|
|
||||||
// //S32 name_len = output_file.length();
|
|
||||||
// //strcpy(&output_file[name_len-3], "tga");
|
|
||||||
// LLFILE* fOut = LLFile::fopen(output_file, "wb"); /* Flawfinder: ignore */
|
|
||||||
// char md5_hash_string[33]; /* Flawfinder: ignore */
|
|
||||||
// strcpy(md5_hash_string, "00000000000000000000000000000000"); /* Flawfinder: ignore */
|
|
||||||
// if (fOut)
|
|
||||||
// {
|
|
||||||
// if (fwrite(data, 1, data_size, fOut) != data_size)
|
|
||||||
// {
|
|
||||||
// LL_WARNS("Messaging") << "Short write" << LL_ENDL;
|
|
||||||
// }
|
|
||||||
// fseek(fOut, 0, SEEK_SET);
|
|
||||||
// fclose(fOut);
|
|
||||||
// fOut = LLFile::fopen(output_file, "rb"); /* Flawfinder: ignore */
|
|
||||||
// LLMD5 my_md5_hash(fOut);
|
|
||||||
// my_md5_hash.hex_digest(md5_hash_string);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// gImageChecksums.insert(std::pair<LLUUID, std::string>(image_id, md5_hash_string));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ++current_image_count;
|
|
||||||
// if (current_image_count == exported_image_count && current_object_count == exported_object_count)
|
|
||||||
// {
|
|
||||||
// LL_INFOS("Messaging") << "*** Export textures complete ***" << LL_ENDL;
|
|
||||||
// export_complete();
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
void process_derez_ack(LLMessageSystem*, void**)
|
void process_derez_ack(LLMessageSystem*, void**)
|
||||||
{
|
{
|
||||||
if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount();
|
if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount();
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@
|
||||||
#include "llfloaterregioninfo.h"
|
#include "llfloaterregioninfo.h"
|
||||||
#include "llgltfmateriallist.h"
|
#include "llgltfmateriallist.h"
|
||||||
#include "llhttpnode.h"
|
#include "llhttpnode.h"
|
||||||
|
#include "llpbrterrainfeatures.h"
|
||||||
#include "llregioninfomodel.h"
|
#include "llregioninfomodel.h"
|
||||||
#include "llsdutil.h"
|
#include "llsdutil.h"
|
||||||
#include "llstartup.h"
|
#include "llstartup.h"
|
||||||
|
|
@ -2628,6 +2629,26 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features)
|
||||||
gSavedSettings.setS32("max_texture_dimension_Y", 1024);
|
gSavedSettings.setS32("max_texture_dimension_Y", 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (features.has("PBRTerrainEnabled"))
|
||||||
|
{
|
||||||
|
bool enabled = features["PBRTerrainEnabled"];
|
||||||
|
gSavedSettings.setBOOL("RenderTerrainPBREnabled", enabled);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gSavedSettings.setBOOL("RenderTerrainPBREnabled", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (features.has("PBRMaterialSwatchEnabled"))
|
||||||
|
{
|
||||||
|
bool enabled = features["PBRMaterialSwatchEnabled"];
|
||||||
|
gSavedSettings.setBOOL("UIPreviewMaterial", enabled);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gSavedSettings.setBOOL("UIPreviewMaterial", false);
|
||||||
|
}
|
||||||
|
|
||||||
if (features.has("GLTFEnabled"))
|
if (features.has("GLTFEnabled"))
|
||||||
{
|
{
|
||||||
bool enabled = features["GLTFEnabled"];
|
bool enabled = features["GLTFEnabled"];
|
||||||
|
|
@ -2637,6 +2658,16 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features)
|
||||||
{
|
{
|
||||||
gSavedSettings.setBOOL("GLTFEnabled", false);
|
gSavedSettings.setBOOL("GLTFEnabled", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (features.has("PBRTerrainTransformsEnabled"))
|
||||||
|
{
|
||||||
|
bool enabled = features["PBRTerrainTransformsEnabled"];
|
||||||
|
gSavedSettings.setBOOL("RenderTerrainTransformsPBREnabled", enabled);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gSavedSettings.setBOOL("RenderTerrainTransformsPBREnabled", false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -3342,6 +3373,17 @@ void LLViewerRegion::unpackRegionHandshake()
|
||||||
{
|
{
|
||||||
compp->setParamsReady();
|
compp->setParamsReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLPBRTerrainFeatures::queueQuery(*this, [](LLUUID region_id, bool success, const LLModifyRegion& composition_changes)
|
||||||
|
{
|
||||||
|
if (!success) { return; }
|
||||||
|
LLViewerRegion* region = LLWorld::getInstance()->getRegionFromID(region_id);
|
||||||
|
if (!region) { return; }
|
||||||
|
LLVLComposition* compp = region->getComposition();
|
||||||
|
if (!compp) { return; }
|
||||||
|
compp->apply(composition_changes);
|
||||||
|
LLFloaterRegionInfo::sRefreshFromRegion(region);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -3451,6 +3493,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
|
||||||
capabilityNames.append("MapLayerGod");
|
capabilityNames.append("MapLayerGod");
|
||||||
capabilityNames.append("MeshUploadFlag");
|
capabilityNames.append("MeshUploadFlag");
|
||||||
capabilityNames.append("ModifyMaterialParams");
|
capabilityNames.append("ModifyMaterialParams");
|
||||||
|
capabilityNames.append("ModifyRegion");
|
||||||
capabilityNames.append("NavMeshGenerationStatus");
|
capabilityNames.append("NavMeshGenerationStatus");
|
||||||
capabilityNames.append("NewFileAgentInventory");
|
capabilityNames.append("NewFileAgentInventory");
|
||||||
capabilityNames.append("ObjectAnimation");
|
capabilityNames.append("ObjectAnimation");
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -291,6 +291,9 @@ extern LLGLSLShader gDeferredPBROpaqueProgram;
|
||||||
extern LLGLSLShader gDeferredPBRAlphaProgram;
|
extern LLGLSLShader gDeferredPBRAlphaProgram;
|
||||||
extern LLGLSLShader gHUDPBRAlphaProgram;
|
extern LLGLSLShader gHUDPBRAlphaProgram;
|
||||||
|
|
||||||
|
// GLTF shaders
|
||||||
|
extern LLGLSLShader gGLTFPBRMetallicRoughnessProgram;
|
||||||
|
|
||||||
// Encodes detail level for dropping textures, in accordance with the GLTF spec where possible
|
// Encodes detail level for dropping textures, in accordance with the GLTF spec where possible
|
||||||
// 0 is highest detail, -1 drops emissive, etc
|
// 0 is highest detail, -1 drops emissive, etc
|
||||||
// Dropping metallic roughness is off-spec - Reserve for potato machines as needed
|
// Dropping metallic roughness is off-spec - Reserve for potato machines as needed
|
||||||
|
|
|
||||||
|
|
@ -349,6 +349,18 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const s
|
||||||
return gTextureList.getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id);
|
return gTextureList.getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//static
|
||||||
|
LLImageRaw* LLViewerTextureManager::getRawImageFromMemory(const U8* data, U32 size, std::string_view mimetype)
|
||||||
|
{
|
||||||
|
return gTextureList.getRawImageFromMemory(data, size, mimetype);
|
||||||
|
}
|
||||||
|
|
||||||
|
//static
|
||||||
|
LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromMemory(const U8* data, U32 size, std::string_view mimetype)
|
||||||
|
{
|
||||||
|
return gTextureList.getImageFromMemory(data, size, mimetype);
|
||||||
|
}
|
||||||
|
|
||||||
LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host)
|
LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host)
|
||||||
{
|
{
|
||||||
return gTextureList.getImageFromHost(image_id, f_type, host);
|
return gTextureList.getImageFromHost(image_id, f_type, host);
|
||||||
|
|
|
||||||
|
|
@ -476,8 +476,6 @@ private:
|
||||||
bool mForceCallbackFetch;
|
bool mForceCallbackFetch;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string mLocalFileName;
|
|
||||||
|
|
||||||
S32 mOrigWidth;
|
S32 mOrigWidth;
|
||||||
S32 mOrigHeight;
|
S32 mOrigHeight;
|
||||||
|
|
||||||
|
|
@ -732,6 +730,14 @@ public:
|
||||||
|
|
||||||
static LLViewerFetchedTexture* getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host) ;
|
static LLViewerFetchedTexture* getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host) ;
|
||||||
|
|
||||||
|
// decode a given image data according to given mime type
|
||||||
|
// WARNING: caller is responsible for deleting the returned raw image
|
||||||
|
static LLImageRaw* getRawImageFromMemory(const U8* data, U32 size, std::string_view mimetype);
|
||||||
|
|
||||||
|
// decode given image data according to given mime type
|
||||||
|
// WARNING: caller is responsible for deleting the returned image
|
||||||
|
static LLViewerFetchedTexture* getFetchedTextureFromMemory(const U8* data, U32 size, std::string_view mimetype);
|
||||||
|
|
||||||
static void init() ;
|
static void init() ;
|
||||||
static void cleanup() ;
|
static void cleanup() ;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -368,7 +368,7 @@ void LLViewerTextureList::shutdown()
|
||||||
|
|
||||||
mImageList.clear();
|
mImageList.clear();
|
||||||
|
|
||||||
mInitialized = false; //prevent loading textures again.
|
mInitialized = false ; //prevent loading textures again.
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLViewerTextureList::dump()
|
void LLViewerTextureList::dump()
|
||||||
|
|
@ -526,6 +526,39 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string&
|
||||||
return imagep;
|
return imagep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLImageRaw* LLViewerTextureList::getRawImageFromMemory(const U8* data, U32 size, std::string_view mimetype)
|
||||||
|
{
|
||||||
|
LLPointer<LLImageFormatted> image = LLImageFormatted::loadFromMemory(data, size, mimetype);
|
||||||
|
|
||||||
|
if (image)
|
||||||
|
{
|
||||||
|
LLImageRaw* raw_image = new LLImageRaw();
|
||||||
|
image->decode(raw_image, 0.f);
|
||||||
|
return raw_image;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LLViewerFetchedTexture* LLViewerTextureList::getImageFromMemory(const U8* data, U32 size, std::string_view mimetype)
|
||||||
|
{
|
||||||
|
LLPointer<LLImageRaw> raw_image = getRawImageFromMemory(data, size, mimetype);
|
||||||
|
if (raw_image.notNull())
|
||||||
|
{
|
||||||
|
LLViewerFetchedTexture* imagep = new LLViewerFetchedTexture(raw_image, FTT_LOCAL_FILE, true);
|
||||||
|
addImage(imagep, TEX_LIST_STANDARD);
|
||||||
|
|
||||||
|
imagep->dontDiscard();
|
||||||
|
imagep->setBoostLevel(LLViewerFetchedTexture::BOOST_PREVIEW);
|
||||||
|
return imagep;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,
|
LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,
|
||||||
FTType f_type,
|
FTType f_type,
|
||||||
|
|
@ -1326,63 +1359,63 @@ bool LLViewerTextureList::createUploadFile(const std::string& filename,
|
||||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Load the image
|
// Load the image
|
||||||
LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
|
LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
|
||||||
if (image.isNull())
|
if (image.isNull())
|
||||||
{
|
{
|
||||||
LL_WARNS() << "Couldn't open the image to be uploaded." << LL_ENDL;
|
LL_WARNS() << "Couldn't open the image to be uploaded." << LL_ENDL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!image->load(filename))
|
if (!image->load(filename))
|
||||||
{
|
{
|
||||||
image->setLastError("Couldn't load the image to be uploaded.");
|
image->setLastError("Couldn't load the image to be uploaded.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Decompress or expand it in a raw image structure
|
// Decompress or expand it in a raw image structure
|
||||||
LLPointer<LLImageRaw> raw_image = new LLImageRaw;
|
LLPointer<LLImageRaw> raw_image = new LLImageRaw;
|
||||||
if (!image->decode(raw_image, 0.0f))
|
if (!image->decode(raw_image, 0.0f))
|
||||||
{
|
{
|
||||||
image->setLastError("Couldn't decode the image to be uploaded.");
|
image->setLastError("Couldn't decode the image to be uploaded.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Check the image constraints
|
// Check the image constraints
|
||||||
if ((image->getComponents() != 3) && (image->getComponents() != 4))
|
if ((image->getComponents() != 3) && (image->getComponents() != 4))
|
||||||
{
|
{
|
||||||
image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
|
image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (image->getWidth() < min_image_dimentions || image->getHeight() < min_image_dimentions)
|
if (image->getWidth() < min_image_dimentions || image->getHeight() < min_image_dimentions)
|
||||||
{
|
{
|
||||||
std::string reason = llformat("Images below %d x %d pixels are not allowed. Actual size: %d x %dpx",
|
std::string reason = llformat("Images below %d x %d pixels are not allowed. Actual size: %d x %dpx",
|
||||||
min_image_dimentions,
|
min_image_dimentions,
|
||||||
min_image_dimentions,
|
min_image_dimentions,
|
||||||
image->getWidth(),
|
image->getWidth(),
|
||||||
image->getHeight());
|
image->getHeight());
|
||||||
image->setLastError(reason);
|
image->setLastError(reason);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Convert to j2c (JPEG2000) and save the file locally
|
// Convert to j2c (JPEG2000) and save the file locally
|
||||||
LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image, max_image_dimentions, force_square);
|
LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image, max_image_dimentions, force_square);
|
||||||
if (compressedImage.isNull())
|
if (compressedImage.isNull())
|
||||||
{
|
{
|
||||||
image->setLastError("Couldn't convert the image to jpeg2000.");
|
image->setLastError("Couldn't convert the image to jpeg2000.");
|
||||||
LL_INFOS() << "Couldn't convert to j2c, file : " << filename << LL_ENDL;
|
LL_INFOS() << "Couldn't convert to j2c, file : " << filename << LL_ENDL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!compressedImage->save(out_filename))
|
if (!compressedImage->save(out_filename))
|
||||||
{
|
{
|
||||||
image->setLastError("Couldn't create the jpeg2000 image for upload.");
|
image->setLastError("Couldn't create the jpeg2000 image for upload.");
|
||||||
LL_INFOS() << "Couldn't create output file : " << out_filename << LL_ENDL;
|
LL_INFOS() << "Couldn't create output file : " << out_filename << LL_ENDL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Test to see if the encode and save worked
|
// Test to see if the encode and save worked
|
||||||
LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
|
LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
|
||||||
if (!integrity_test->loadAndValidate(out_filename))
|
if (!integrity_test->loadAndValidate( out_filename ))
|
||||||
{
|
{
|
||||||
image->setLastError("The created jpeg2000 image is corrupt.");
|
image->setLastError("The created jpeg2000 image is corrupt.");
|
||||||
LL_INFOS() << "Image file : " << out_filename << " is corrupt" << LL_ENDL;
|
LL_INFOS() << "Image file : " << out_filename << " is corrupt" << LL_ENDL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -197,6 +197,9 @@ private: // PoundLife - Improved Object Inspect
|
||||||
LLGLenum primary_format = 0,
|
LLGLenum primary_format = 0,
|
||||||
const LLUUID& force_id = LLUUID::null
|
const LLUUID& force_id = LLUUID::null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
LLImageRaw* getRawImageFromMemory(const U8* data, U32 size, std::string_view mimetype);
|
||||||
|
LLViewerFetchedTexture* getImageFromMemory(const U8* data, U32 size, std::string_view mimetype);
|
||||||
|
|
||||||
LLViewerFetchedTexture* createImage(const LLUUID &image_id,
|
LLViewerFetchedTexture* createImage(const LLUUID &image_id,
|
||||||
FTType f_type,
|
FTType f_type,
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,25 @@
|
||||||
/**
|
/**
|
||||||
* @file llvlcomposition.cpp
|
* @file llvlcomposition.cpp
|
||||||
* @brief Viewer-side representation of a composition layer...
|
* @brief Viewer-side representation of a composition layer...
|
||||||
*
|
*
|
||||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||||
* Second Life Viewer Source Code
|
* Second Life Viewer Source Code
|
||||||
* Copyright (C) 2010, Linden Research, Inc.
|
* Copyright (C) 2010, Linden Research, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation;
|
* License as published by the Free Software Foundation;
|
||||||
* version 2.1 of the License only.
|
* version 2.1 of the License only.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
*
|
||||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
@ -115,6 +115,16 @@ LLTerrainMaterials::~LLTerrainMaterials()
|
||||||
unboost();
|
unboost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLTerrainMaterials::apply(const LLModifyRegion& other)
|
||||||
|
{
|
||||||
|
for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
|
||||||
|
{
|
||||||
|
const LLGLTFMaterial* other_override = other.getMaterialOverride(i);
|
||||||
|
LLGLTFMaterial* material_override = other_override ? new LLGLTFMaterial(*other_override) : nullptr;
|
||||||
|
setMaterialOverride(i, material_override);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool LLTerrainMaterials::generateMaterials()
|
bool LLTerrainMaterials::generateMaterials()
|
||||||
{
|
{
|
||||||
if (texturesReady(true, true))
|
if (texturesReady(true, true))
|
||||||
|
|
@ -192,7 +202,7 @@ void LLTerrainMaterials::setDetailAssetID(S32 asset, const LLUUID& id)
|
||||||
mMaterialTexturesSet[asset] = false;
|
mMaterialTexturesSet[asset] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LLGLTFMaterial* LLTerrainMaterials::getMaterialOverride(S32 asset)
|
const LLGLTFMaterial* LLTerrainMaterials::getMaterialOverride(S32 asset) const
|
||||||
{
|
{
|
||||||
return mDetailMaterialOverrides[asset];
|
return mDetailMaterialOverrides[asset];
|
||||||
}
|
}
|
||||||
|
|
@ -461,7 +471,7 @@ bool LLVLComposition::generateHeights(const F32 x, const F32 y,
|
||||||
|
|
||||||
llassert(mSurfacep);
|
llassert(mSurfacep);
|
||||||
|
|
||||||
if (!mSurfacep || !mSurfacep->getRegion())
|
if (!mSurfacep || !mSurfacep->getRegion())
|
||||||
{
|
{
|
||||||
// We don't always have the region yet here....
|
// We don't always have the region yet here....
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -532,7 +542,7 @@ bool LLVLComposition::generateHeights(const F32 x, const F32 y,
|
||||||
vec[1] = (F32)(origin_global.mdV[VY]+location.mV[VY])*xyScaleInv;
|
vec[1] = (F32)(origin_global.mdV[VY]+location.mV[VY])*xyScaleInv;
|
||||||
vec[2] = height*zScaleInv;
|
vec[2] = height*zScaleInv;
|
||||||
//
|
//
|
||||||
// Choose material value by adding to the exact height a random value
|
// Choose material value by adding to the exact height a random value
|
||||||
//
|
//
|
||||||
vec1[0] = vec[0]*(0.2222222222f);
|
vec1[0] = vec[0]*(0.2222222222f);
|
||||||
vec1[1] = vec[1]*(0.2222222222f);
|
vec1[1] = vec[1]*(0.2222222222f);
|
||||||
|
|
@ -874,7 +884,7 @@ bool LLVLComposition::generateMinimapTileLand(const F32 x, const F32 y,
|
||||||
U32 st_comps = 3;
|
U32 st_comps = 3;
|
||||||
U32 st_width = BASE_SIZE;
|
U32 st_width = BASE_SIZE;
|
||||||
U32 st_height = BASE_SIZE;
|
U32 st_height = BASE_SIZE;
|
||||||
|
|
||||||
if (tex_comps != st_comps)
|
if (tex_comps != st_comps)
|
||||||
{
|
{
|
||||||
llassert(false);
|
llassert(false);
|
||||||
|
|
@ -979,7 +989,7 @@ bool LLVLComposition::generateMinimapTileLand(const F32 x, const F32 y,
|
||||||
{
|
{
|
||||||
unboost_minimap_material(mDetailMaterials[i]);
|
unboost_minimap_material(mDetailMaterials[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,25 @@
|
||||||
/**
|
/**
|
||||||
* @file llvlcomposition.h
|
* @file llvlcomposition.h
|
||||||
* @brief Viewer-side representation of a composition layer...
|
* @brief Viewer-side representation of a composition layer...
|
||||||
*
|
*
|
||||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||||
* Second Life Viewer Source Code
|
* Second Life Viewer Source Code
|
||||||
* Copyright (C) 2010, Linden Research, Inc.
|
* Copyright (C) 2010, Linden Research, Inc.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation;
|
* License as published by the Free Software Foundation;
|
||||||
* version 2.1 of the License only.
|
* version 2.1 of the License only.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
*
|
||||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||||
* $/LicenseInfo$
|
* $/LicenseInfo$
|
||||||
*/
|
*/
|
||||||
|
|
@ -38,7 +38,13 @@ class LLViewerFetchedTexture;
|
||||||
class LLGLTFMaterial;
|
class LLGLTFMaterial;
|
||||||
class LLFetchedGLTFMaterial;
|
class LLFetchedGLTFMaterial;
|
||||||
|
|
||||||
class LLTerrainMaterials
|
class LLModifyRegion
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual const LLGLTFMaterial* getMaterialOverride(S32 asset) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LLTerrainMaterials : public LLModifyRegion
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class LLDrawPoolTerrain;
|
friend class LLDrawPoolTerrain;
|
||||||
|
|
@ -46,6 +52,8 @@ public:
|
||||||
LLTerrainMaterials();
|
LLTerrainMaterials();
|
||||||
virtual ~LLTerrainMaterials();
|
virtual ~LLTerrainMaterials();
|
||||||
|
|
||||||
|
void apply(const LLModifyRegion& other);
|
||||||
|
|
||||||
// Heights map into textures (or materials) as 0-1 = first, 1-2 = second, etc.
|
// Heights map into textures (or materials) as 0-1 = first, 1-2 = second, etc.
|
||||||
// So we need to compress heights into this range.
|
// So we need to compress heights into this range.
|
||||||
static const S32 ASSET_COUNT = 4;
|
static const S32 ASSET_COUNT = 4;
|
||||||
|
|
@ -63,7 +71,7 @@ public:
|
||||||
|
|
||||||
virtual LLUUID getDetailAssetID(S32 asset);
|
virtual LLUUID getDetailAssetID(S32 asset);
|
||||||
virtual void setDetailAssetID(S32 asset, const LLUUID& id);
|
virtual void setDetailAssetID(S32 asset, const LLUUID& id);
|
||||||
virtual const LLGLTFMaterial* getMaterialOverride(S32 asset);
|
const LLGLTFMaterial* getMaterialOverride(S32 asset) const override;
|
||||||
virtual void setMaterialOverride(S32 asset, LLGLTFMaterial* mat_override);
|
virtual void setMaterialOverride(S32 asset, LLGLTFMaterial* mat_override);
|
||||||
Type getMaterialType();
|
Type getMaterialType();
|
||||||
bool texturesReady(bool boost, bool strict);
|
bool texturesReady(bool boost, bool strict);
|
||||||
|
|
@ -107,8 +115,8 @@ public:
|
||||||
bool generateHeights(const F32 x, const F32 y, const F32 width, const F32 height);
|
bool generateHeights(const F32 x, const F32 y, const F32 width, const F32 height);
|
||||||
bool generateComposition();
|
bool generateComposition();
|
||||||
// Generate texture from composition values.
|
// Generate texture from composition values.
|
||||||
bool generateMinimapTileLand(const F32 x, const F32 y, const F32 width, const F32 height);
|
bool generateMinimapTileLand(const F32 x, const F32 y, const F32 width, const F32 height);
|
||||||
bool generateTexture(const F32 x, const F32 y, const F32 width, const F32 height);
|
bool generateTexture(const F32 x, const F32 y, const F32 width, const F32 height);
|
||||||
|
|
||||||
// Use these as indeces ito the get/setters below that use 'corner'
|
// Use these as indeces ito the get/setters below that use 'corner'
|
||||||
enum ECorner
|
enum ECorner
|
||||||
|
|
|
||||||
|
|
@ -548,8 +548,19 @@ F32 LLVOCacheEntry::getSquaredPixelThreshold(bool is_front)
|
||||||
return projection_threshold;
|
return projection_threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern bool gCubeSnapshot;
|
||||||
|
|
||||||
bool LLVOCacheEntry::isAnyVisible(const LLVector4a& camera_origin, const LLVector4a& local_camera_origin, F32 dist_threshold)
|
bool LLVOCacheEntry::isAnyVisible(const LLVector4a& camera_origin, const LLVector4a& local_camera_origin, F32 dist_threshold)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
|
// this is ill-conceived and should be removed pending QA
|
||||||
|
// In the name of saving memory, we evict objects that are still within view distance from memory
|
||||||
|
// This results in constant paging of objects in and out of memory, leading to poor performance
|
||||||
|
// and many unacceptable visual glitches when rotating the camera
|
||||||
|
|
||||||
|
// Honestly, the entire VOCache partition system needs to be removed since it doubles the overhead of
|
||||||
|
// the spatial partition system and is redundant to the object cache, but this is a start
|
||||||
|
// - davep 2024.06.07
|
||||||
if( gAgent.getFSAreaSearchActive() ) { return true; } // <FS:Beq/> FIRE-32688 Area Search improvements
|
if( gAgent.getFSAreaSearchActive() ) { return true; } // <FS:Beq/> FIRE-32688 Area Search improvements
|
||||||
LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*)getGroup();
|
LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*)getGroup();
|
||||||
if(!group)
|
if(!group)
|
||||||
|
|
@ -587,6 +598,9 @@ bool LLVOCacheEntry::isAnyVisible(const LLVector4a& camera_origin, const LLVecto
|
||||||
}
|
}
|
||||||
|
|
||||||
return vis;
|
return vis;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLVOCacheEntry::calcSceneContribution(const LLVector4a& camera_origin, bool needs_update, U32 last_update, F32 max_dist)
|
void LLVOCacheEntry::calcSceneContribution(const LLVector4a& camera_origin, bool needs_update, U32 last_update, F32 max_dist)
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue