Merge branch 'project/gltf_development' of https://github.com/secondlife/viewer
# Conflicts: # indra/llimage/tests/llimageworker_test.cpp # indra/llmath/llvolume.cpp # indra/newview/llenvironment.cpp # indra/newview/llfetchedgltfmaterial.cpp # indra/newview/llfloaterimagepreview.h # indra/newview/llfloaterregioninfo.h # indra/newview/llmaniprotate.cpp # indra/newview/llselectmgr.h # indra/newview/llsurfacepatch.cpp # indra/newview/lltexturectrl.cpp # indra/newview/lltexturectrl.h # indra/newview/llviewerdisplay.cpp # indra/newview/llviewerobject.cpp # indra/newview/llviewerregion.cpp # indra/newview/llviewerwindow.cpp # indra/newview/llvoicevivox.cpp # indra/newview/llvovolume.cpp # indra/newview/pipeline.cpp # indra/newview/skins/default/xui/en/notifications.xml # scripts/messages/message_template.msg.sha1master
commit
ca63f18bf2
|
|
@ -129,8 +129,7 @@ void LLCommon::initClass()
|
|||
sAprInitialized = true;
|
||||
}
|
||||
LLTimer::initClass();
|
||||
LLThreadSafeRefCount::initThreadSafeRefCount();
|
||||
assert_main_thread(); // Make sure we record the main thread
|
||||
assert_main_thread(); // Make sure we record the main thread
|
||||
if (!sMasterThreadRecorder)
|
||||
{
|
||||
sMasterThreadRecorder = new LLTrace::ThreadRecorder();
|
||||
|
|
@ -144,7 +143,6 @@ void LLCommon::cleanupClass()
|
|||
delete sMasterThreadRecorder;
|
||||
sMasterThreadRecorder = NULL;
|
||||
LLTrace::set_master_thread_recorder(NULL);
|
||||
LLThreadSafeRefCount::cleanupThreadSafeRefCount();
|
||||
SUBSYSTEM_CLEANUP_DBG(LLTimer);
|
||||
if (sAprInitialized)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -61,6 +61,23 @@
|
|||
#include <excpt.h>
|
||||
#endif
|
||||
|
||||
// static
|
||||
bool LLCoros::on_main_coro()
|
||||
{
|
||||
if (!LLCoros::instanceExists() || LLCoros::getName().empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLCoros::on_main_thread_main_coro()
|
||||
{
|
||||
return on_main_coro() && on_main_thread();
|
||||
}
|
||||
|
||||
// static
|
||||
LLCoros::CoroData& LLCoros::get_CoroData(const std::string& caller)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -94,6 +94,16 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
|
|||
|
||||
void cleanupSingleton() override;
|
||||
public:
|
||||
// For debugging, return true if on the main coroutine for the current thread
|
||||
// Code that should not be executed from a coroutine should be protected by
|
||||
// llassert(LLCoros::on_main_coro())
|
||||
static bool on_main_coro();
|
||||
|
||||
// For debugging, return true if on the main thread and not in a coroutine
|
||||
// Non-thread-safe code in the main loop should be protected by
|
||||
// llassert(LLCoros::on_main_thread_main_coro())
|
||||
static bool on_main_thread_main_coro();
|
||||
|
||||
/// The viewer's use of the term "coroutine" became deeply embedded before
|
||||
/// the industry term "fiber" emerged to distinguish userland threads from
|
||||
/// simpler, more transient kinds of coroutines. Semantically they've
|
||||
|
|
|
|||
|
|
@ -511,7 +511,7 @@ namespace
|
|||
LLError::TimeFunction mTimeFunction;
|
||||
|
||||
Recorders mRecorders;
|
||||
LLMutex mRecorderMutex;
|
||||
LLCoros::Mutex mRecorderMutex;
|
||||
|
||||
int mShouldLogCallCounter;
|
||||
|
||||
|
|
@ -1055,7 +1055,7 @@ namespace LLError
|
|||
return;
|
||||
}
|
||||
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
|
||||
LLMutexLock lock(&s->mRecorderMutex);
|
||||
LLCoros::LockType lock(s->mRecorderMutex);
|
||||
s->mRecorders.push_back(recorder);
|
||||
}
|
||||
|
||||
|
|
@ -1066,7 +1066,7 @@ namespace LLError
|
|||
return;
|
||||
}
|
||||
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
|
||||
LLMutexLock lock(&s->mRecorderMutex);
|
||||
LLCoros::LockType lock(s->mRecorderMutex);
|
||||
s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder),
|
||||
s->mRecorders.end());
|
||||
}
|
||||
|
|
@ -1115,7 +1115,7 @@ namespace LLError
|
|||
std::shared_ptr<RECORDER> findRecorder()
|
||||
{
|
||||
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
|
||||
LLMutexLock lock(&s->mRecorderMutex);
|
||||
LLCoros::LockType lock(s->mRecorderMutex);
|
||||
return findRecorderPos<RECORDER>(s).first;
|
||||
}
|
||||
|
||||
|
|
@ -1126,7 +1126,7 @@ namespace LLError
|
|||
bool removeRecorder()
|
||||
{
|
||||
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
|
||||
LLMutexLock lock(&s->mRecorderMutex);
|
||||
LLCoros::LockType lock(s->mRecorderMutex);
|
||||
auto found = findRecorderPos<RECORDER>(s);
|
||||
if (found.first)
|
||||
{
|
||||
|
|
@ -1232,7 +1232,7 @@ namespace
|
|||
|
||||
std::string escaped_message;
|
||||
|
||||
LLMutexLock lock(&s->mRecorderMutex);
|
||||
LLCoros::LockType lock(s->mRecorderMutex);
|
||||
for (LLError::RecorderPtr& r : s->mRecorders)
|
||||
{
|
||||
// <FS:Ansariel> Crash fix
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ std::string LLEventPump::inventName(const std::string& pfx)
|
|||
|
||||
void LLEventPump::clear()
|
||||
{
|
||||
LLMutexLock lock(&mConnectionListMutex);
|
||||
LLCoros::LockType lock(mConnectionListMutex);
|
||||
// Destroy the original LLStandardSignal instance, replacing it with a
|
||||
// whole new one.
|
||||
mSignal = std::make_shared<LLStandardSignal>();
|
||||
|
|
@ -394,7 +394,7 @@ void LLEventPump::reset()
|
|||
{
|
||||
// Resetting mSignal is supposed to disconnect everything on its own
|
||||
// But due to crash on 'reset' added explicit cleanup to get more data
|
||||
LLMutexLock lock(&mConnectionListMutex);
|
||||
LLCoros::LockType lock(mConnectionListMutex);
|
||||
ConnectionMap::const_iterator iter = mConnections.begin();
|
||||
ConnectionMap::const_iterator end = mConnections.end();
|
||||
while (iter!=end)
|
||||
|
|
@ -419,7 +419,7 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL
|
|||
return LLBoundListener();
|
||||
}
|
||||
|
||||
LLMutexLock lock(&mConnectionListMutex);
|
||||
LLCoros::LockType lock(mConnectionListMutex);
|
||||
|
||||
float nodePosition = 1.0;
|
||||
|
||||
|
|
@ -582,7 +582,7 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL
|
|||
|
||||
LLBoundListener LLEventPump::getListener(const std::string& name)
|
||||
{
|
||||
LLMutexLock lock(&mConnectionListMutex);
|
||||
LLCoros::LockType lock(mConnectionListMutex);
|
||||
ConnectionMap::const_iterator found = mConnections.find(name);
|
||||
if (found != mConnections.end())
|
||||
{
|
||||
|
|
@ -594,7 +594,7 @@ LLBoundListener LLEventPump::getListener(const std::string& name)
|
|||
|
||||
void LLEventPump::stopListening(const std::string& name)
|
||||
{
|
||||
LLMutexLock lock(&mConnectionListMutex);
|
||||
LLCoros::LockType lock(mConnectionListMutex);
|
||||
ConnectionMap::iterator found = mConnections.find(name);
|
||||
if (found != mConnections.end())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@
|
|||
#include "llstl.h"
|
||||
#include "llexception.h"
|
||||
#include "llhandle.h"
|
||||
#include "llcoros.h"
|
||||
|
||||
/*==========================================================================*|
|
||||
// override this to allow binding free functions with more parameters
|
||||
|
|
@ -603,7 +604,7 @@ private:
|
|||
LLHandle<LLEventPumps> mRegistry;
|
||||
|
||||
std::string mName;
|
||||
LLMutex mConnectionListMutex;
|
||||
LLCoros::Mutex mConnectionListMutex;
|
||||
|
||||
protected:
|
||||
virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&,
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "llstring.h"
|
||||
#include "llthread.h"
|
||||
#include "llerrorcontrol.h"
|
||||
#include "llcoros.h"
|
||||
|
||||
// fixed buffer implementation
|
||||
class LL_COMMON_API LLFixedBuffer : public LLLineBuffer
|
||||
|
|
@ -61,7 +62,7 @@ protected:
|
|||
void addWLine(const LLWString& line);
|
||||
|
||||
protected:
|
||||
LLMutex mMutex ;
|
||||
LLCoros::Mutex mMutex ;
|
||||
};
|
||||
|
||||
#endif //LL_FIXED_BUFFER_H
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "llmutex.h"
|
||||
#include "llthread.h"
|
||||
#include "lltimer.h"
|
||||
#include "llcoros.h"
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
|
@ -45,7 +46,17 @@ LLMutex::~LLMutex()
|
|||
|
||||
void LLMutex::lock()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
|
||||
// LLMutex is not coroutine aware and should not be used from a coroutine
|
||||
// If your code is running in a coroutine, you should use LLCoros::Mutex instead
|
||||
// NOTE: If the stack trace you're staring at contains non-thread-safe code,
|
||||
// you should use LLAppViewer::instance().postToMainThread() to shuttle execution
|
||||
// back to the main loop.
|
||||
// NOTE: If you got here from seeing this assert in your log and you're not seeing
|
||||
// a stack trace that points here, put a breakpoint in on_main_coro and try again.
|
||||
llassert(LLCoros::on_main_coro());
|
||||
|
||||
if(isSelfLocked())
|
||||
{ //redundant lock
|
||||
mCount++;
|
||||
|
|
@ -67,7 +78,8 @@ void LLMutex::lock()
|
|||
|
||||
void LLMutex::unlock()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
|
||||
if (mCount > 0)
|
||||
{ //not the root unlock
|
||||
mCount--;
|
||||
|
|
|
|||
|
|
@ -89,13 +89,6 @@ private:
|
|||
|
||||
class LL_COMMON_API LLThreadSafeRefCount
|
||||
{
|
||||
public:
|
||||
static void initThreadSafeRefCount(); // creates sMutex
|
||||
static void cleanupThreadSafeRefCount(); // destroys sMutex
|
||||
|
||||
private:
|
||||
static LLMutex* sMutex;
|
||||
|
||||
protected:
|
||||
virtual ~LLThreadSafeRefCount(); // use unref()
|
||||
|
||||
|
|
|
|||
|
|
@ -433,30 +433,6 @@ void LLThread::unlockData()
|
|||
|
||||
//============================================================================
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//static
|
||||
LLMutex* LLThreadSafeRefCount::sMutex = 0;
|
||||
|
||||
//static
|
||||
void LLThreadSafeRefCount::initThreadSafeRefCount()
|
||||
{
|
||||
if (!sMutex)
|
||||
{
|
||||
sMutex = new LLMutex();
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLThreadSafeRefCount::cleanupThreadSafeRefCount()
|
||||
{
|
||||
delete sMutex;
|
||||
sMutex = NULL;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
LLThreadSafeRefCount::LLThreadSafeRefCount() :
|
||||
mRef(0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ namespace tut
|
|||
done = res;
|
||||
*done = false;
|
||||
}
|
||||
virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux, U32)
|
||||
virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux, U32 request_id)
|
||||
{
|
||||
*done = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5440,6 +5440,17 @@ struct MikktData
|
|||
n[i].normalize();
|
||||
tc[i].set(face->mTexCoords[idx]);
|
||||
|
||||
if (idx >= face->mNumVertices)
|
||||
{
|
||||
// invalid index
|
||||
// replace with a valid index to avoid crashes
|
||||
idx = face->mNumVertices - 1;
|
||||
face->mIndices[i] = idx;
|
||||
|
||||
// Needs better logging
|
||||
LL_DEBUGS_ONCE("LLVOLUME") << "Invalid index, substituting" << LL_ENDL;
|
||||
}
|
||||
|
||||
if (face->mWeights)
|
||||
{
|
||||
w[i].set(face->mWeights[idx].getF32ptr());
|
||||
|
|
|
|||
|
|
@ -48,12 +48,6 @@ public:
|
|||
*this = rhs;
|
||||
}
|
||||
|
||||
const LLVolumeTriangle& operator=(const LLVolumeTriangle& rhs)
|
||||
{
|
||||
LL_ERRS() << "Illegal operation!" << LL_ENDL;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~LLVolumeTriangle()
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@
|
|||
#include "llcorehttputil.h"
|
||||
#include "llexception.h"
|
||||
#include "stringize.h"
|
||||
#include "workqueue.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
|
@ -180,19 +181,26 @@ void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLU
|
|||
|
||||
if (LLAvatarNameCache::instanceExists())
|
||||
{
|
||||
if (!success)
|
||||
{ // on any sort of failure add dummy records for any agent IDs
|
||||
// in this request that we do not have cached already
|
||||
std::vector<LLUUID>::const_iterator it = agentIds.begin();
|
||||
for (; it != agentIds.end(); ++it)
|
||||
{
|
||||
const LLUUID& agent_id = *it;
|
||||
LLAvatarNameCache::getInstance()->handleAgentError(agent_id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// dispatch handler execution back to mainloop
|
||||
auto workqueue = LL::WorkQueue::getInstance("mainloop");
|
||||
|
||||
LLAvatarNameCache::getInstance()->handleAvNameCacheSuccess(results, httpResults);
|
||||
if (workqueue)
|
||||
{
|
||||
workqueue->post([=]()
|
||||
{
|
||||
if (!success)
|
||||
{ // on any sort of failure add dummy records for any agent IDs
|
||||
// in this request that we do not have cached already
|
||||
for (const auto& agent_id : agentIds)
|
||||
{
|
||||
LLAvatarNameCache::getInstance()->handleAgentError(agent_id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
LLAvatarNameCache::getInstance()->handleAvNameCacheSuccess(results, httpResults);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const LLCoros::Stop&)
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
#include "llpluginmessageclasses.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "stringize.h"
|
||||
|
||||
#include "llapr.h"
|
||||
|
||||
#include "llrand.h" // <ND/> FIRE-3877; So we can choose a random port number
|
||||
|
|
@ -48,7 +47,7 @@ LLPluginProcessParentOwner::~LLPluginProcessParentOwner()
|
|||
bool LLPluginProcessParent::sUseReadThread = false;
|
||||
apr_pollset_t *LLPluginProcessParent::sPollSet = NULL;
|
||||
bool LLPluginProcessParent::sPollsetNeedsRebuild = false;
|
||||
LLMutex *LLPluginProcessParent::sInstancesMutex;
|
||||
LLCoros::Mutex *LLPluginProcessParent::sInstancesMutex;
|
||||
LLPluginProcessParent::mapInstances_t LLPluginProcessParent::sInstances;
|
||||
LLThread *LLPluginProcessParent::sReadThread = NULL;
|
||||
|
||||
|
|
@ -108,7 +107,7 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
|
|||
{
|
||||
if(!sInstancesMutex)
|
||||
{
|
||||
sInstancesMutex = new LLMutex();
|
||||
sInstancesMutex = new LLCoros::Mutex();
|
||||
}
|
||||
|
||||
mOwner = owner;
|
||||
|
|
@ -178,7 +177,7 @@ LLPluginProcessParent::ptr_t LLPluginProcessParent::create(LLPluginProcessParent
|
|||
|
||||
// Don't add to the global list until fully constructed.
|
||||
{
|
||||
LLMutexLock lock(sInstancesMutex);
|
||||
LLCoros::LockType lock(*sInstancesMutex);
|
||||
sInstances.insert(mapInstances_t::value_type(that.get(), that));
|
||||
}
|
||||
|
||||
|
|
@ -188,7 +187,7 @@ LLPluginProcessParent::ptr_t LLPluginProcessParent::create(LLPluginProcessParent
|
|||
/*static*/
|
||||
void LLPluginProcessParent::shutdown()
|
||||
{
|
||||
LLMutexLock lock(sInstancesMutex);
|
||||
LLCoros::LockType lock(*sInstancesMutex);
|
||||
|
||||
mapInstances_t::iterator it;
|
||||
for (it = sInstances.begin(); it != sInstances.end(); ++it)
|
||||
|
|
@ -246,7 +245,7 @@ bool LLPluginProcessParent::pollTick()
|
|||
{
|
||||
// this grabs a copy of the smart pointer to ourselves to ensure that we do not
|
||||
// get destroyed until after this method returns.
|
||||
LLMutexLock lock(sInstancesMutex);
|
||||
LLCoros::LockType lock(*sInstancesMutex);
|
||||
mapInstances_t::iterator it = sInstances.find(this);
|
||||
if (it != sInstances.end())
|
||||
that = (*it).second;
|
||||
|
|
@ -265,7 +264,7 @@ void LLPluginProcessParent::removeFromProcessing()
|
|||
// Remove from the global list before beginning destruction.
|
||||
{
|
||||
// Make sure to get the global mutex _first_ here, to avoid a possible deadlock against LLPluginProcessParent::poll()
|
||||
LLMutexLock lock(sInstancesMutex);
|
||||
LLCoros::LockType lock(*sInstancesMutex);
|
||||
{
|
||||
LLMutexLock lock2(&mIncomingQueueMutex);
|
||||
sInstances.erase(this);
|
||||
|
|
@ -864,7 +863,7 @@ void LLPluginProcessParent::updatePollset()
|
|||
return;
|
||||
}
|
||||
|
||||
LLMutexLock lock(sInstancesMutex);
|
||||
LLCoros::LockType lock(*sInstancesMutex);
|
||||
|
||||
if(sPollSet)
|
||||
{
|
||||
|
|
@ -987,7 +986,7 @@ void LLPluginProcessParent::poll(F64 timeout)
|
|||
mapInstances_t::iterator it;
|
||||
|
||||
{
|
||||
LLMutexLock lock(sInstancesMutex);
|
||||
LLCoros::LockType lock(*sInstancesMutex);
|
||||
it = sInstances.find(thatId);
|
||||
if (it != sInstances.end())
|
||||
that = (*it).second;
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ private:
|
|||
apr_pollfd_t mPollFD;
|
||||
static apr_pollset_t *sPollSet;
|
||||
static bool sPollsetNeedsRebuild;
|
||||
static LLMutex *sInstancesMutex;
|
||||
static LLCoros::Mutex *sInstancesMutex;
|
||||
static mapInstances_t sInstances;
|
||||
static void dirtyPollSet();
|
||||
static void updatePollset();
|
||||
|
|
|
|||
|
|
@ -120,12 +120,6 @@ public:
|
|||
// heightmaps cannot currently be described as finite enclosed
|
||||
// volumes.
|
||||
// See also LLPanelRegionTerrainInfo::validateMaterials
|
||||
bool mDoubleSided = false;
|
||||
|
||||
|
||||
// These fields are local to viewer and are a part of local bitmap support
|
||||
typedef std::map<LLUUID, LLUUID> local_tex_map_t;
|
||||
local_tex_map_t mTrackingIdToLocalTexture;
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
|||
|
|
@ -759,7 +759,7 @@ static LLTrace::BlockTimerStatHandle FTM_CONSOLE_UPDATE_PARAGRAPHS("Update Conso
|
|||
void LLConsole::update()
|
||||
{
|
||||
{
|
||||
LLMutexLock lock(&mMutex);
|
||||
LLCoros::LockType lock(mMutex);
|
||||
|
||||
while (!mLines.empty())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,6 +30,24 @@
|
|||
|
||||
using namespace LL::GLTF;
|
||||
|
||||
void Buffer::erase(Asset& asset, S32 offset, S32 length)
|
||||
{
|
||||
S32 idx = this - &asset.mBuffers[0];
|
||||
|
||||
mData.erase(mData.begin() + offset, mData.begin() + offset + length);
|
||||
|
||||
for (BufferView& view : asset.mBufferViews)
|
||||
{
|
||||
if (view.mBuffer == idx)
|
||||
{
|
||||
if (view.mByteOffset >= offset)
|
||||
{
|
||||
view.mByteOffset -= length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Buffer& Buffer::operator=(const tinygltf::Buffer& src)
|
||||
{
|
||||
mData = src.data;
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ namespace LL
|
|||
std::string mName;
|
||||
std::string mUri;
|
||||
|
||||
// erase the given range from this buffer.
|
||||
// also updates all buffer views in given asset that reference this buffer
|
||||
void erase(Asset& asset, S32 offset, S32 length);
|
||||
|
||||
const Buffer& operator=(const tinygltf::Buffer& src);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -81,8 +81,6 @@ namespace LL
|
|||
|
||||
S32 mSampler = INVALID_INDEX;
|
||||
Target mTarget;
|
||||
std::string mTargetPath;
|
||||
std::string mName;
|
||||
|
||||
const Channel& operator=(const tinygltf::AnimationChannel& src)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,9 +30,271 @@
|
|||
#include "llvolumeoctree.h"
|
||||
#include "../llviewershadermgr.h"
|
||||
#include "../llviewercontrol.h"
|
||||
#include "../llviewertexturelist.h"
|
||||
|
||||
using namespace LL::GLTF;
|
||||
|
||||
namespace LL
|
||||
{
|
||||
namespace GLTF
|
||||
{
|
||||
template <typename T, typename U>
|
||||
void copy(const std::vector<T>& src, std::vector<U>& dst)
|
||||
{
|
||||
dst.resize(src.size());
|
||||
for (U32 i = 0; i < src.size(); ++i)
|
||||
{
|
||||
copy(src[i], dst[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void copy(const Node& src, tinygltf::Node& dst)
|
||||
{
|
||||
if (src.mMatrixValid)
|
||||
{
|
||||
if (!src.mMatrix.asMatrix4().isIdentity())
|
||||
{
|
||||
dst.matrix.resize(16);
|
||||
for (U32 i = 0; i < 16; ++i)
|
||||
{
|
||||
dst.matrix[i] = src.mMatrix.getF32ptr()[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (src.mTRSValid)
|
||||
{
|
||||
if (!src.mRotation.equals(glh::quaternionf::identity(), FLT_EPSILON))
|
||||
{
|
||||
dst.rotation.resize(4);
|
||||
for (U32 i = 0; i < 4; ++i)
|
||||
{
|
||||
dst.rotation[i] = src.mRotation.get_value()[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (src.mTranslation != glh::vec3f(0.f, 0.f, 0.f))
|
||||
{
|
||||
dst.translation.resize(3);
|
||||
for (U32 i = 0; i < 3; ++i)
|
||||
{
|
||||
dst.translation[i] = src.mTranslation.v[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (src.mScale != glh::vec3f(1.f, 1.f, 1.f))
|
||||
{
|
||||
dst.scale.resize(3);
|
||||
for (U32 i = 0; i < 3; ++i)
|
||||
{
|
||||
dst.scale[i] = src.mScale.v[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dst.children = src.mChildren;
|
||||
dst.mesh = src.mMesh;
|
||||
dst.skin = src.mSkin;
|
||||
dst.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Scene& src, tinygltf::Scene& dst)
|
||||
{
|
||||
dst.nodes = src.mNodes;
|
||||
dst.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Primitive& src, tinygltf::Primitive& dst)
|
||||
{
|
||||
for (auto& attrib : src.mAttributes)
|
||||
{
|
||||
dst.attributes[attrib.first] = attrib.second;
|
||||
}
|
||||
dst.indices = src.mIndices;
|
||||
dst.material = src.mMaterial;
|
||||
dst.mode = src.mMode;
|
||||
}
|
||||
|
||||
void copy(const Mesh& src, tinygltf::Mesh& mesh)
|
||||
{
|
||||
copy(src.mPrimitives, mesh.primitives);
|
||||
mesh.weights = src.mWeights;
|
||||
mesh.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Material::TextureInfo& src, tinygltf::TextureInfo& dst)
|
||||
{
|
||||
dst.index = src.mIndex;
|
||||
dst.texCoord = src.mTexCoord;
|
||||
}
|
||||
|
||||
void copy(const Material::OcclusionTextureInfo& src, tinygltf::OcclusionTextureInfo& dst)
|
||||
{
|
||||
dst.index = src.mIndex;
|
||||
dst.texCoord = src.mTexCoord;
|
||||
dst.strength = src.mStrength;
|
||||
}
|
||||
|
||||
void copy(const Material::NormalTextureInfo& src, tinygltf::NormalTextureInfo& dst)
|
||||
{
|
||||
dst.index = src.mIndex;
|
||||
dst.texCoord = src.mTexCoord;
|
||||
dst.scale = src.mScale;
|
||||
}
|
||||
|
||||
void copy(const Material::PbrMetallicRoughness& src, tinygltf::PbrMetallicRoughness& dst)
|
||||
{
|
||||
dst.baseColorFactor = { src.mBaseColorFactor.v[0], src.mBaseColorFactor.v[1], src.mBaseColorFactor.v[2], src.mBaseColorFactor.v[3] };
|
||||
copy(src.mBaseColorTexture, dst.baseColorTexture);
|
||||
dst.metallicFactor = src.mMetallicFactor;
|
||||
dst.roughnessFactor = src.mRoughnessFactor;
|
||||
copy(src.mMetallicRoughnessTexture, dst.metallicRoughnessTexture);
|
||||
}
|
||||
|
||||
void copy(const Material& src, tinygltf::Material& material)
|
||||
{
|
||||
material.name = src.mName;
|
||||
|
||||
material.emissiveFactor = { src.mEmissiveFactor.v[0], src.mEmissiveFactor.v[1], src.mEmissiveFactor.v[2] };
|
||||
copy(src.mPbrMetallicRoughness, material.pbrMetallicRoughness);
|
||||
copy(src.mNormalTexture, material.normalTexture);
|
||||
copy(src.mEmissiveTexture, material.emissiveTexture);
|
||||
}
|
||||
|
||||
void copy(const Texture& src, tinygltf::Texture& texture)
|
||||
{
|
||||
texture.sampler = src.mSampler;
|
||||
texture.source = src.mSource;
|
||||
texture.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Sampler& src, tinygltf::Sampler& sampler)
|
||||
{
|
||||
sampler.magFilter = src.mMagFilter;
|
||||
sampler.minFilter = src.mMinFilter;
|
||||
sampler.wrapS = src.mWrapS;
|
||||
sampler.wrapT = src.mWrapT;
|
||||
sampler.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Skin& src, tinygltf::Skin& skin)
|
||||
{
|
||||
skin.joints = src.mJoints;
|
||||
skin.inverseBindMatrices = src.mInverseBindMatrices;
|
||||
skin.skeleton = src.mSkeleton;
|
||||
skin.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Accessor& src, tinygltf::Accessor& accessor)
|
||||
{
|
||||
accessor.bufferView = src.mBufferView;
|
||||
accessor.byteOffset = src.mByteOffset;
|
||||
accessor.componentType = src.mComponentType;
|
||||
accessor.minValues = src.mMin;
|
||||
accessor.maxValues = src.mMax;
|
||||
|
||||
accessor.count = src.mCount;
|
||||
accessor.type = src.mType;
|
||||
accessor.normalized = src.mNormalized;
|
||||
accessor.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Animation::Sampler& src, tinygltf::AnimationSampler& sampler)
|
||||
{
|
||||
sampler.input = src.mInput;
|
||||
sampler.output = src.mOutput;
|
||||
sampler.interpolation = src.mInterpolation;
|
||||
}
|
||||
|
||||
void copy(const Animation::Channel& src, tinygltf::AnimationChannel& channel)
|
||||
{
|
||||
channel.sampler = src.mSampler;
|
||||
channel.target_node = src.mTarget.mNode;
|
||||
channel.target_path = src.mTarget.mPath;
|
||||
}
|
||||
|
||||
void copy(const Animation& src, tinygltf::Animation& animation)
|
||||
{
|
||||
animation.name = src.mName;
|
||||
|
||||
copy(src.mSamplers, animation.samplers);
|
||||
|
||||
U32 channel_count = src.mRotationChannels.size() + src.mTranslationChannels.size() + src.mScaleChannels.size();
|
||||
|
||||
animation.channels.resize(channel_count);
|
||||
|
||||
U32 idx = 0;
|
||||
for (U32 i = 0; i < src.mTranslationChannels.size(); ++i)
|
||||
{
|
||||
copy(src.mTranslationChannels[i], animation.channels[idx++]);
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < src.mRotationChannels.size(); ++i)
|
||||
{
|
||||
copy(src.mRotationChannels[i], animation.channels[idx++]);
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < src.mScaleChannels.size(); ++i)
|
||||
{
|
||||
copy(src.mScaleChannels[i], animation.channels[idx++]);
|
||||
}
|
||||
}
|
||||
|
||||
void copy(const Buffer& src, tinygltf::Buffer& buffer)
|
||||
{
|
||||
buffer.uri = src.mUri;
|
||||
buffer.data = src.mData;
|
||||
buffer.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const BufferView& src, tinygltf::BufferView& bufferView)
|
||||
{
|
||||
bufferView.buffer = src.mBuffer;
|
||||
bufferView.byteOffset = src.mByteOffset;
|
||||
bufferView.byteLength = src.mByteLength;
|
||||
bufferView.byteStride = src.mByteStride;
|
||||
bufferView.target = src.mTarget;
|
||||
bufferView.name = src.mName;
|
||||
}
|
||||
|
||||
void copy(const Image& src, tinygltf::Image& image)
|
||||
{
|
||||
image.name = src.mName;
|
||||
image.width = src.mWidth;
|
||||
image.height = src.mHeight;
|
||||
image.component = src.mComponent;
|
||||
image.bits = src.mBits;
|
||||
image.pixel_type = src.mPixelType;
|
||||
|
||||
image.image = src.mData;
|
||||
image.bufferView = src.mBufferView;
|
||||
image.mimeType = src.mMimeType;
|
||||
image.uri = src.mUri;
|
||||
}
|
||||
|
||||
void copy(const Asset & src, tinygltf::Model& dst)
|
||||
{
|
||||
dst.defaultScene = src.mDefaultScene;
|
||||
dst.asset.copyright = src.mCopyright;
|
||||
dst.asset.version = src.mVersion;
|
||||
dst.asset.minVersion = src.mMinVersion;
|
||||
dst.asset.generator = "Linden Lab Experimental GLTF Export";
|
||||
dst.asset.extras = src.mExtras;
|
||||
|
||||
copy(src.mScenes, dst.scenes);
|
||||
copy(src.mNodes, dst.nodes);
|
||||
copy(src.mMeshes, dst.meshes);
|
||||
copy(src.mMaterials, dst.materials);
|
||||
copy(src.mBuffers, dst.buffers);
|
||||
copy(src.mBufferViews, dst.bufferViews);
|
||||
copy(src.mTextures, dst.textures);
|
||||
copy(src.mSamplers, dst.samplers);
|
||||
copy(src.mImages, dst.images);
|
||||
copy(src.mAccessors, dst.accessors);
|
||||
copy(src.mAnimations, dst.animations);
|
||||
copy(src.mSkins, dst.skins);
|
||||
}
|
||||
}
|
||||
}
|
||||
void Scene::updateTransforms(Asset& asset)
|
||||
{
|
||||
LLMatrix4a identity;
|
||||
|
|
@ -237,6 +499,8 @@ void Node::makeMatrixValid()
|
|||
mMatrix.loadu(t.m);
|
||||
mMatrixValid = true;
|
||||
}
|
||||
|
||||
llassert(mMatrixValid);
|
||||
}
|
||||
|
||||
void Node::makeTRSValid()
|
||||
|
|
@ -252,6 +516,8 @@ void Node::makeTRSValid()
|
|||
mRotation.set_value(t);
|
||||
mTRSValid = true;
|
||||
}
|
||||
|
||||
llassert(mTRSValid);
|
||||
}
|
||||
|
||||
void Node::setRotation(const glh::quaternionf& q)
|
||||
|
|
@ -318,6 +584,7 @@ const Node& Node::operator=(const tinygltf::Node& src)
|
|||
{
|
||||
// node specifies no transformation, set to identity
|
||||
mMatrix.setIdentity();
|
||||
mMatrixValid = true;
|
||||
}
|
||||
|
||||
mChildren = src.children;
|
||||
|
|
@ -467,6 +734,15 @@ void Asset::allocateGLResources(const std::string& filename, const tinygltf::Mod
|
|||
|
||||
const Asset& Asset::operator=(const tinygltf::Model& src)
|
||||
{
|
||||
mVersion = src.asset.version;
|
||||
mMinVersion = src.asset.minVersion;
|
||||
mGenerator = src.asset.generator;
|
||||
mCopyright = src.asset.copyright;
|
||||
mExtras = src.asset.extras;
|
||||
|
||||
mDefaultScene = src.defaultScene;
|
||||
|
||||
|
||||
mScenes.resize(src.scenes.size());
|
||||
for (U32 i = 0; i < src.scenes.size(); ++i)
|
||||
{
|
||||
|
|
@ -542,9 +818,167 @@ const Asset& Asset::operator=(const tinygltf::Model& src)
|
|||
return *this;
|
||||
}
|
||||
|
||||
void Asset::save(tinygltf::Model& dst)
|
||||
{
|
||||
LL::GLTF::copy(*this, dst);
|
||||
}
|
||||
|
||||
void Asset::decompose(const std::string& filename)
|
||||
{
|
||||
// get folder path
|
||||
std::string folder = gDirUtilp->getDirName(filename);
|
||||
|
||||
// decompose images
|
||||
for (auto& image : mImages)
|
||||
{
|
||||
image.decompose(*this, folder);
|
||||
}
|
||||
}
|
||||
|
||||
void Asset::eraseBufferView(S32 bufferView)
|
||||
{
|
||||
mBufferViews.erase(mBufferViews.begin() + bufferView);
|
||||
|
||||
for (auto& accessor : mAccessors)
|
||||
{
|
||||
if (accessor.mBufferView > bufferView)
|
||||
{
|
||||
accessor.mBufferView--;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& image : mImages)
|
||||
{
|
||||
if (image.mBufferView > bufferView)
|
||||
{
|
||||
image.mBufferView--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Image::decompose(Asset& asset, const std::string& folder)
|
||||
{
|
||||
std::string name = mName;
|
||||
if (name.empty())
|
||||
{
|
||||
S32 idx = this - asset.mImages.data();
|
||||
name = llformat("image_%d", idx);
|
||||
}
|
||||
|
||||
if (mBufferView != INVALID_INDEX)
|
||||
{
|
||||
// save original image
|
||||
BufferView& bufferView = asset.mBufferViews[mBufferView];
|
||||
Buffer& buffer = asset.mBuffers[bufferView.mBuffer];
|
||||
|
||||
std::string extension;
|
||||
|
||||
if (mMimeType == "image/jpeg")
|
||||
{
|
||||
extension = ".jpg";
|
||||
}
|
||||
else if (mMimeType == "image/png")
|
||||
{
|
||||
extension = ".png";
|
||||
}
|
||||
else
|
||||
{
|
||||
extension = ".bin";
|
||||
}
|
||||
|
||||
std::string filename = folder + "/" + name + "." + extension;
|
||||
|
||||
// set URI to non-j2c file for now, but later we'll want to reference the j2c hash
|
||||
mUri = name + "." + extension;
|
||||
|
||||
std::ofstream file(filename, std::ios::binary);
|
||||
file.write((const char*)buffer.mData.data() + bufferView.mByteOffset, bufferView.mByteLength);
|
||||
|
||||
buffer.erase(asset, bufferView.mByteOffset, bufferView.mByteLength);
|
||||
|
||||
asset.eraseBufferView(mBufferView);
|
||||
}
|
||||
|
||||
if (!mData.empty())
|
||||
{
|
||||
// save j2c image
|
||||
std::string filename = folder + "/" + name + ".j2c";
|
||||
|
||||
LLPointer<LLImageRaw> raw = new LLImageRaw(mWidth, mHeight, mComponent);
|
||||
U8* data = raw->allocateData();
|
||||
llassert(mData.size() == raw->getDataSize());
|
||||
memcpy(data, mData.data(), mData.size());
|
||||
|
||||
LLViewerTextureList::createUploadFile(raw, filename, 4096);
|
||||
|
||||
mData.clear();
|
||||
}
|
||||
|
||||
mWidth = -1;
|
||||
mHeight = -1;
|
||||
mComponent = -1;
|
||||
mBits = -1;
|
||||
mPixelType = -1;
|
||||
mMimeType = "";
|
||||
|
||||
}
|
||||
|
||||
const Material::TextureInfo& Material::TextureInfo::operator=(const tinygltf::TextureInfo& src)
|
||||
{
|
||||
mIndex = src.index;
|
||||
mTexCoord = src.texCoord;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const tinygltf::OcclusionTextureInfo& src)
|
||||
{
|
||||
mIndex = src.index;
|
||||
mTexCoord = src.texCoord;
|
||||
mStrength = src.strength;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const tinygltf::NormalTextureInfo& src)
|
||||
{
|
||||
mIndex = src.index;
|
||||
mTexCoord = src.texCoord;
|
||||
mScale = src.scale;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Material::PbrMetallicRoughness& Material::PbrMetallicRoughness::operator=(const tinygltf::PbrMetallicRoughness& src)
|
||||
{
|
||||
if (src.baseColorFactor.size() == 4)
|
||||
{
|
||||
mBaseColorFactor.set_value(src.baseColorFactor[0], src.baseColorFactor[1], src.baseColorFactor[2], src.baseColorFactor[3]);
|
||||
}
|
||||
|
||||
mBaseColorTexture = src.baseColorTexture;
|
||||
mMetallicFactor = src.metallicFactor;
|
||||
mRoughnessFactor = src.roughnessFactor;
|
||||
mMetallicRoughnessTexture = src.metallicRoughnessTexture;
|
||||
|
||||
return *this;
|
||||
}
|
||||
const Material& Material::operator=(const tinygltf::Material& src)
|
||||
{
|
||||
mName = src.name;
|
||||
|
||||
if (src.emissiveFactor.size() == 3)
|
||||
{
|
||||
mEmissiveFactor.set_value(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2]);
|
||||
}
|
||||
|
||||
mPbrMetallicRoughness = src.pbrMetallicRoughness;
|
||||
mNormalTexture = src.normalTexture;
|
||||
mOcclusionTexture = src.occlusionTexture;
|
||||
mEmissiveTexture = src.emissiveTexture;
|
||||
|
||||
mAlphaMode = src.alphaMode;
|
||||
mAlphaCutoff = src.alphaCutoff;
|
||||
mDoubleSided = src.doubleSided;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,11 +45,59 @@ namespace LL
|
|||
class Material
|
||||
{
|
||||
public:
|
||||
class TextureInfo
|
||||
{
|
||||
public:
|
||||
S32 mIndex = INVALID_INDEX;
|
||||
S32 mTexCoord = 0;
|
||||
|
||||
const TextureInfo& operator=(const tinygltf::TextureInfo& src);
|
||||
};
|
||||
|
||||
class NormalTextureInfo : public TextureInfo
|
||||
{
|
||||
public:
|
||||
F32 mScale = 1.0f;
|
||||
|
||||
const NormalTextureInfo& operator=(const tinygltf::NormalTextureInfo& src);
|
||||
};
|
||||
|
||||
class OcclusionTextureInfo : public TextureInfo
|
||||
{
|
||||
public:
|
||||
F32 mStrength = 1.0f;
|
||||
|
||||
const OcclusionTextureInfo& operator=(const tinygltf::OcclusionTextureInfo& src);
|
||||
};
|
||||
|
||||
class PbrMetallicRoughness
|
||||
{
|
||||
public:
|
||||
glh::vec4f mBaseColorFactor = glh::vec4f(1.f,1.f,1.f,1.f);
|
||||
TextureInfo mBaseColorTexture;
|
||||
F32 mMetallicFactor = 1.0f;
|
||||
F32 mRoughnessFactor = 1.0f;
|
||||
TextureInfo mMetallicRoughnessTexture;
|
||||
const PbrMetallicRoughness& operator=(const tinygltf::PbrMetallicRoughness& src);
|
||||
};
|
||||
|
||||
|
||||
// use LLFetchedGLTFMaterial for now, but eventually we'll want to use
|
||||
// a more flexible GLTF material implementation instead of the fixed packing
|
||||
// version we use for sharable GLTF material assets
|
||||
LLPointer<LLFetchedGLTFMaterial> mMaterial;
|
||||
PbrMetallicRoughness mPbrMetallicRoughness;
|
||||
NormalTextureInfo mNormalTexture;
|
||||
OcclusionTextureInfo mOcclusionTexture;
|
||||
TextureInfo mEmissiveTexture;
|
||||
|
||||
|
||||
std::string mName;
|
||||
glh::vec3f mEmissiveFactor = glh::vec3f(0.f, 0.f, 0.f);
|
||||
std::string mAlphaMode = "OPAQUE";
|
||||
F32 mAlphaCutoff = 0.5f;
|
||||
bool mDoubleSided = false;
|
||||
|
||||
|
||||
const Material& operator=(const tinygltf::Material& src);
|
||||
|
||||
|
|
@ -179,11 +227,16 @@ namespace LL
|
|||
std::string mName;
|
||||
std::string mUri;
|
||||
std::string mMimeType;
|
||||
|
||||
S32 mBufferView = INVALID_INDEX;
|
||||
|
||||
std::vector<U8> mData;
|
||||
S32 mWidth;
|
||||
S32 mHeight;
|
||||
S32 mComponent;
|
||||
S32 mBits;
|
||||
S32 mPixelType;
|
||||
|
||||
LLPointer<LLViewerFetchedTexture> mTexture;
|
||||
|
||||
const Image& operator=(const tinygltf::Image& src)
|
||||
|
|
@ -196,10 +249,14 @@ namespace LL
|
|||
mHeight = src.height;
|
||||
mComponent = src.component;
|
||||
mBits = src.bits;
|
||||
|
||||
mBufferView = src.bufferView;
|
||||
mPixelType = src.pixel_type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// save image clear local data, and set uri
|
||||
void decompose(Asset& asset, const std::string& filename);
|
||||
|
||||
void allocateGLResources()
|
||||
{
|
||||
// allocate texture
|
||||
|
|
@ -208,7 +265,7 @@ namespace LL
|
|||
};
|
||||
|
||||
// C++ representation of a GLTF Asset
|
||||
class Asset : public LLRefCount
|
||||
class Asset
|
||||
{
|
||||
public:
|
||||
std::vector<Scene> mScenes;
|
||||
|
|
@ -224,6 +281,15 @@ namespace LL
|
|||
std::vector<Animation> mAnimations;
|
||||
std::vector<Skin> mSkins;
|
||||
|
||||
std::string mVersion;
|
||||
std::string mGenerator;
|
||||
std::string mMinVersion;
|
||||
std::string mCopyright;
|
||||
|
||||
S32 mDefaultScene = INVALID_INDEX;
|
||||
tinygltf::Value mExtras;
|
||||
|
||||
|
||||
// the last time update() was called according to gFrameTimeSeconds
|
||||
F32 mLastUpdateTime = gFrameTimeSeconds;
|
||||
|
||||
|
|
@ -258,7 +324,16 @@ namespace LL
|
|||
);
|
||||
|
||||
const Asset& operator=(const tinygltf::Model& src);
|
||||
|
||||
|
||||
// save the asset to a tinygltf model
|
||||
void save(tinygltf::Model& dst);
|
||||
|
||||
// decompose the asset to the given .gltf file
|
||||
void decompose(const std::string& filename);
|
||||
|
||||
// remove the bufferview at the given index
|
||||
// updates all bufferview indices in this Asset as needed
|
||||
void eraseBufferView(S32 bufferView);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,11 +66,95 @@ void GLTFSceneManager::load()
|
|||
}
|
||||
},
|
||||
LLFilePicker::FFLOAD_GLTF,
|
||||
true);
|
||||
false);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotificationsUtil::add("GLTFPreviewSelection");
|
||||
LLNotificationsUtil::add("GLTFOpenSelection");
|
||||
}
|
||||
}
|
||||
|
||||
void GLTFSceneManager::saveAs()
|
||||
{
|
||||
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().save(filenames[0]);
|
||||
}
|
||||
},
|
||||
LLFilePicker::FFSAVE_GLTF,
|
||||
"scene.gltf");
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotificationsUtil::add("GLTFSaveSelection");
|
||||
}
|
||||
}
|
||||
|
||||
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::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)
|
||||
{
|
||||
LLViewerObject* obj = LLSelectMgr::instance().getSelection()->getFirstRootObject();
|
||||
if (obj && obj->mGLTFAsset)
|
||||
{
|
||||
Asset* asset = obj->mGLTFAsset.get();
|
||||
tinygltf::Model model;
|
||||
asset->save(model);
|
||||
|
||||
LLTinyGLTFHelper::saveModel(filename, model);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +163,7 @@ void GLTFSceneManager::load(const std::string& filename)
|
|||
tinygltf::Model model;
|
||||
LLTinyGLTFHelper::loadModel(filename, model);
|
||||
|
||||
LLPointer<Asset> asset = new Asset();
|
||||
std::shared_ptr<Asset> asset = std::make_shared<Asset>();
|
||||
*asset = model;
|
||||
|
||||
gDebugProgram.bind(); // bind a shader to satisfy LLVertexBuffer assertions
|
||||
|
|
@ -126,10 +210,7 @@ void GLTFSceneManager::update()
|
|||
continue;
|
||||
}
|
||||
|
||||
Asset* asset = mObjects[i]->mGLTFAsset;
|
||||
|
||||
asset->update();
|
||||
|
||||
mObjects[i]->mGLTFAsset->update();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +232,7 @@ void GLTFSceneManager::render(bool opaque, bool rigged)
|
|||
continue;
|
||||
}
|
||||
|
||||
Asset* asset = mObjects[i]->mGLTFAsset;
|
||||
Asset* asset = mObjects[i]->mGLTFAsset.get();
|
||||
|
||||
gGL.pushMatrix();
|
||||
|
||||
|
|
@ -298,7 +379,7 @@ LLDrawable* GLTFSceneManager::lineSegmentIntersect(const LLVector4a& start, cons
|
|||
}
|
||||
|
||||
// temporary debug -- always double check objects that have GLTF scenes hanging off of them even if the ray doesn't intersect the object bounds
|
||||
if (lineSegmentIntersect((LLVOVolume*) mObjects[i].get(), mObjects[i]->mGLTFAsset, start, local_end, -1, pick_transparent, pick_rigged, pick_unselectable, node_hit, primitive_hit, &position, tex_coord, normal, tangent))
|
||||
if (lineSegmentIntersect((LLVOVolume*) mObjects[i].get(), mObjects[i]->mGLTFAsset.get(), start, local_end, -1, pick_transparent, pick_rigged, pick_unselectable, node_hit, primitive_hit, &position, tex_coord, normal, tangent))
|
||||
{
|
||||
local_end = position;
|
||||
if (intersection)
|
||||
|
|
@ -425,7 +506,7 @@ void GLTFSceneManager::renderDebug()
|
|||
|
||||
matMul(mat, modelview, modelview);
|
||||
|
||||
Asset* asset = obj->mGLTFAsset;
|
||||
Asset* asset = obj->mGLTFAsset.get();
|
||||
|
||||
for (auto& node : asset->mNodes)
|
||||
{
|
||||
|
|
@ -440,7 +521,7 @@ void GLTFSceneManager::renderDebug()
|
|||
continue;
|
||||
}
|
||||
|
||||
Asset* asset = obj->mGLTFAsset;
|
||||
Asset* asset = obj->mGLTFAsset.get();
|
||||
|
||||
LLMatrix4a mat = obj->getGLTFAssetToAgentTransform();
|
||||
|
||||
|
|
@ -477,7 +558,7 @@ void GLTFSceneManager::renderDebug()
|
|||
|
||||
matMul(mat, modelview, modelview);
|
||||
|
||||
Asset* asset = obj->mGLTFAsset;
|
||||
Asset* asset = obj->mGLTFAsset.get();
|
||||
|
||||
for (auto& node : asset->mNodes)
|
||||
{
|
||||
|
|
@ -538,7 +619,7 @@ void GLTFSceneManager::renderDebug()
|
|||
if (drawable)
|
||||
{
|
||||
gGL.pushMatrix();
|
||||
Asset* asset = drawable->getVObj()->mGLTFAsset;
|
||||
Asset* asset = drawable->getVObj()->mGLTFAsset.get();
|
||||
Node* node = &asset->mNodes[node_hit];
|
||||
Primitive* primitive = &asset->mMeshes[node->mMesh].mPrimitives[primitive_hit];
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,16 @@
|
|||
|
||||
#include "llsingleton.h"
|
||||
#include "llviewerobject.h"
|
||||
class LLVOVolume;
|
||||
class LLDrawable;
|
||||
|
||||
namespace LL
|
||||
{
|
||||
namespace GLTF
|
||||
{
|
||||
class Asset;
|
||||
}
|
||||
}
|
||||
|
||||
namespace LL
|
||||
{
|
||||
|
|
@ -40,6 +50,11 @@ namespace LL
|
|||
void load(); // open filepicker to choose asset
|
||||
void load(const std::string& filename); // load asset from filename
|
||||
|
||||
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 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 update();
|
||||
void render(bool opaque, bool rigged = false);
|
||||
void renderOpaque();
|
||||
|
|
|
|||
|
|
@ -6059,6 +6059,11 @@ void LLAppViewer::updateNameLookupUrl(const LLViewerRegion * regionp)
|
|||
}
|
||||
}
|
||||
|
||||
void LLAppViewer::postToMainCoro(const LL::WorkQueue::Work& work)
|
||||
{
|
||||
gMainloopWork.post(work);
|
||||
}
|
||||
|
||||
void LLAppViewer::idleNameCache()
|
||||
{
|
||||
// Neither old nor new name cache can function before agent has a region
|
||||
|
|
|
|||
|
|
@ -239,6 +239,9 @@ public:
|
|||
|
||||
void updateNameLookupUrl(const LLViewerRegion* regionp);
|
||||
|
||||
// post given work to the "mainloop" work queue for handling on the main thread
|
||||
void postToMainCoro(const LL::WorkQueue::Work& work);
|
||||
|
||||
protected:
|
||||
virtual bool initWindow(); // Initialize the viewer's window.
|
||||
virtual void initLoggingAndGetLastDuration(); // Initialize log files, logging system
|
||||
|
|
|
|||
|
|
@ -236,8 +236,6 @@ void LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro(std::string url, U
|
|||
!avatar->isControlAvatar() && // Not part of an animated object
|
||||
avatar->getObjectHost() == regionp->getHost()) // Ensure it's on the same region
|
||||
{
|
||||
avatar->calculateUpdateRenderComplexity(); // Make sure the numbers are up-to-date
|
||||
|
||||
LLSD info = LLSD::emptyMap();
|
||||
U32 avatar_complexity = avatar->getVisualComplexity();
|
||||
if (avatar_complexity > 0)
|
||||
|
|
|
|||
|
|
@ -702,6 +702,8 @@ void LLBumpImageList::addTextureStats(U8 bump, const LLUUID& base_image_id, F32
|
|||
|
||||
void LLBumpImageList::updateImages()
|
||||
{
|
||||
llassert(LLCoros::on_main_thread_main_coro()); // This code is not thread safe
|
||||
|
||||
for (bump_image_map_t::iterator iter = mBrightnessEntries.begin(); iter != mBrightnessEntries.end(); )
|
||||
{
|
||||
LLViewerTexture* image = iter->second;
|
||||
|
|
|
|||
|
|
@ -1666,12 +1666,12 @@ void LLEnvironment::updateEnvironment(LLSettingsBase::Seconds transition, bool f
|
|||
{
|
||||
if (transition != TRANSITION_INSTANT)
|
||||
{
|
||||
DayInstance::ptr_t trans = std::make_shared<DayTransition>(
|
||||
mCurrentEnvironment->getSky(), mCurrentEnvironment->getWater(), pinstance, transition);
|
||||
|
||||
trans->animate();
|
||||
|
||||
mCurrentEnvironment = trans;
|
||||
DayInstance::ptr_t trans = std::make_shared<DayTransition>(
|
||||
mCurrentEnvironment->getSky(), mCurrentEnvironment->getWater(), pinstance, transition);
|
||||
|
||||
trans->animate();
|
||||
|
||||
mCurrentEnvironment = trans;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -263,3 +263,4 @@ void LLFetchedGLTFMaterial::materialComplete(bool success)
|
|||
materialCompleteCallbacks.clear();
|
||||
materialCompleteCallbacks.shrink_to_fit();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -860,7 +860,7 @@ void set_nav_save_data(LLFilePicker::ESaveFilter filter, std::string &extension,
|
|||
case LLFilePicker::FFSAVE_GLTF:
|
||||
type = "\?\?\?\?";
|
||||
creator = "\?\?\?\?";
|
||||
extension = "glb";
|
||||
extension = "glb,gltf";
|
||||
break;
|
||||
|
||||
// <FS:TS> Compile fix
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ protected:
|
|||
void setPreviewTarget(LLImageRaw *imagep, F32 distance);
|
||||
void setTexture(U32 name) { mTextureName = name; }
|
||||
|
||||
bool render() override;
|
||||
bool render() override;
|
||||
void refresh();
|
||||
void rotate(F32 yaw_radians, F32 pitch_radians);
|
||||
void zoom(F32 zoom_amt);
|
||||
|
|
@ -88,7 +88,7 @@ public:
|
|||
void setTexture(U32 name) { mTextureName = name; }
|
||||
void clearPreviewTexture(const std::string& mesh_name);
|
||||
|
||||
bool render() override;
|
||||
bool render() override;
|
||||
void refresh();
|
||||
void rotate(F32 yaw_radians, F32 pitch_radians);
|
||||
void zoom(F32 zoom_amt);
|
||||
|
|
@ -114,14 +114,14 @@ public:
|
|||
LLFloaterImagePreview(const std::string& filename);
|
||||
virtual ~LLFloaterImagePreview();
|
||||
|
||||
bool postBuild() override;
|
||||
bool postBuild() override;
|
||||
|
||||
S32 getExpectedUploadCost() const override;
|
||||
|
||||
bool handleMouseDown(S32 x, S32 y, MASK mask) override;
|
||||
bool handleMouseUp(S32 x, S32 y, MASK mask) override;
|
||||
bool handleHover(S32 x, S32 y, MASK mask) override;
|
||||
bool handleScrollWheel(S32 x, S32 y, S32 clicks) override;
|
||||
bool handleMouseDown(S32 x, S32 y, MASK mask) override;
|
||||
bool handleMouseUp(S32 x, S32 y, MASK mask) override;
|
||||
bool handleHover(S32 x, S32 y, MASK mask) override;
|
||||
bool handleScrollWheel(S32 x, S32 y, S32 clicks) override;
|
||||
|
||||
static void onMouseCaptureLostImagePreview(LLMouseHandler*);
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ public:
|
|||
|
||||
void onOpen(const LLSD& key) override;
|
||||
void onClose(bool app_quitting) override;
|
||||
bool postBuild() override;
|
||||
bool postBuild() override;
|
||||
|
||||
static void processEstateOwnerRequest(LLMessageSystem* msg, void**);
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ public:
|
|||
virtual bool refreshFromRegion(LLViewerRegion* region);
|
||||
virtual bool estateUpdate(LLMessageSystem* msg) { return true; }
|
||||
|
||||
bool postBuild() override;
|
||||
bool postBuild() override;
|
||||
virtual void updateChild(LLUICtrl* child_ctrl);
|
||||
|
||||
void enableButton(const std::string& btn_name, bool enable = true);
|
||||
|
|
@ -214,7 +214,7 @@ public:
|
|||
|
||||
bool refreshFromRegion(LLViewerRegion* region) override;
|
||||
|
||||
bool postBuild() override;
|
||||
bool postBuild() override;
|
||||
|
||||
void onBtnSet();
|
||||
void setObjBonusFactor(F32 object_bonus_factor) {mObjBonusFactor = object_bonus_factor;}
|
||||
|
|
@ -242,12 +242,12 @@ public:
|
|||
: LLPanelRegionInfo(), mTargetAvatar() {}
|
||||
~LLPanelRegionDebugInfo() {}
|
||||
|
||||
bool postBuild() override;
|
||||
bool postBuild() override;
|
||||
|
||||
bool refreshFromRegion(LLViewerRegion* region) override;
|
||||
|
||||
protected:
|
||||
bool sendUpdate() override;
|
||||
bool sendUpdate() override;
|
||||
|
||||
void onClickChooseAvatar();
|
||||
void callbackAvatarID(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);
|
||||
|
|
@ -274,14 +274,14 @@ public:
|
|||
LLPanelRegionTerrainInfo();
|
||||
~LLPanelRegionTerrainInfo() {}
|
||||
|
||||
bool postBuild() override;
|
||||
bool postBuild() override;
|
||||
|
||||
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
|
||||
|
||||
bool validateTextureSizes();
|
||||
bool validateMaterials();
|
||||
bool validateTextureHeights();
|
||||
bool validateTextureHeights();
|
||||
|
||||
//static void onChangeAnything(LLUICtrl* ctrl, void* userData); // callback for any change, to enable commit button
|
||||
|
||||
|
|
@ -299,7 +299,7 @@ public:
|
|||
bool callbackTextureHeights(const LLSD& notification, const LLSD& response);
|
||||
|
||||
protected:
|
||||
BOOL sendUpdate() override;
|
||||
bool sendUpdate() override;
|
||||
|
||||
private:
|
||||
bool mConfirmedTextureHeights;
|
||||
|
|
@ -347,7 +347,7 @@ public:
|
|||
bool refreshFromRegion(LLViewerRegion* region) override;
|
||||
bool estateUpdate(LLMessageSystem* msg) override;
|
||||
|
||||
bool postBuild() override;
|
||||
bool postBuild() override;
|
||||
void updateChild(LLUICtrl* child_ctrl) override;
|
||||
void refresh() override;
|
||||
|
||||
|
|
@ -359,7 +359,7 @@ public:
|
|||
void setOwnerName(const std::string& name);
|
||||
|
||||
protected:
|
||||
bool sendUpdate() override;
|
||||
bool sendUpdate() override;
|
||||
// confirmation dialog callback
|
||||
bool callbackChangeLindenEstate(const LLSD& notification, const LLSD& response);
|
||||
|
||||
|
|
@ -379,7 +379,7 @@ public:
|
|||
LLPanelEstateCovenant();
|
||||
~LLPanelEstateCovenant() {}
|
||||
|
||||
bool postBuild() override;
|
||||
bool postBuild() override;
|
||||
void updateChild(LLUICtrl* child_ctrl) override;
|
||||
bool refreshFromRegion(LLViewerRegion* region) override;
|
||||
bool estateUpdate(LLMessageSystem* msg) override;
|
||||
|
|
@ -421,7 +421,7 @@ public:
|
|||
} EAssetStatus;
|
||||
|
||||
protected:
|
||||
bool sendUpdate() override;
|
||||
bool sendUpdate() override;
|
||||
LLTextBox* mEstateNameText;
|
||||
LLTextBox* mEstateOwnerText;
|
||||
LLTextBox* mLastModifiedText;
|
||||
|
|
@ -440,7 +440,7 @@ class LLPanelRegionExperiences : public LLPanelRegionInfo
|
|||
|
||||
public:
|
||||
LLPanelRegionExperiences(){}
|
||||
bool postBuild() override;
|
||||
bool postBuild() override;
|
||||
|
||||
static bool experienceCoreConfirm(const LLSD& notification, const LLSD& response);
|
||||
static void sendEstateExperienceDelta(U32 flags, const LLUUID& agent_id);
|
||||
|
|
@ -451,7 +451,7 @@ public:
|
|||
void processResponse( const LLSD& content );
|
||||
|
||||
protected:
|
||||
BOOL sendUpdate() override;
|
||||
bool sendUpdate() override;
|
||||
|
||||
private:
|
||||
void refreshRegionExperiences();
|
||||
|
|
@ -477,7 +477,7 @@ class LLPanelEstateAccess : public LLPanelRegionInfo
|
|||
public:
|
||||
LLPanelEstateAccess();
|
||||
|
||||
bool postBuild() override;
|
||||
bool postBuild() override;
|
||||
void updateChild(LLUICtrl* child_ctrl) override;
|
||||
|
||||
void updateControls(LLViewerRegion* region);
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ LLPointer<LLGLTFPreviewTexture> LLGLTFPreviewTexture::create(LLPointer<LLFetched
|
|||
return new LLGLTFPreviewTexture(material, LLPipeline::MAX_BAKE_WIDTH);
|
||||
}
|
||||
|
||||
BOOL LLGLTFPreviewTexture::needsRender()
|
||||
bool LLGLTFPreviewTexture::needsRender()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
|
||||
|
||||
|
|
@ -211,7 +211,7 @@ BOOL LLGLTFPreviewTexture::needsRender()
|
|||
return false;
|
||||
}
|
||||
|
||||
void LLGLTFPreviewTexture::preRender(BOOL clear_depth)
|
||||
void LLGLTFPreviewTexture::preRender(bool clear_depth)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
|
||||
|
||||
|
|
@ -419,7 +419,7 @@ struct SetTemporarily
|
|||
|
||||
}; // namespace
|
||||
|
||||
BOOL LLGLTFPreviewTexture::render()
|
||||
bool LLGLTFPreviewTexture::render()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
|
||||
|
||||
|
|
@ -557,7 +557,7 @@ BOOL LLGLTFPreviewTexture::render()
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
void LLGLTFPreviewTexture::postRender(BOOL success)
|
||||
void LLGLTFPreviewTexture::postRender(bool success)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
|
||||
|
||||
|
|
|
|||
|
|
@ -40,10 +40,10 @@ public:
|
|||
// Width scales with size of material's textures
|
||||
static LLPointer<LLGLTFPreviewTexture> create(LLPointer<LLFetchedGLTFMaterial> material);
|
||||
|
||||
BOOL needsRender() override;
|
||||
void preRender(BOOL clear_depth = TRUE) override;
|
||||
BOOL render() override;
|
||||
void postRender(BOOL success) override;
|
||||
bool needsRender() override;
|
||||
void preRender(bool clear_depth = TRUE) override;
|
||||
bool render() override;
|
||||
void postRender(bool success) override;
|
||||
|
||||
struct MaterialLoadLevels
|
||||
{
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@
|
|||
#include "llviewerjoystick.h"
|
||||
#include "llviewermediafocus.h"
|
||||
|
||||
extern BOOL gCubeSnapshot;
|
||||
extern BOOL gTeleportDisplay;
|
||||
extern bool gCubeSnapshot;
|
||||
extern bool gTeleportDisplay;
|
||||
|
||||
// get the next highest power of two of v (or v if v is already a power of two)
|
||||
//defined in llvertexbuffer.cpp
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ public:
|
|||
std::vector<LLVector3> mTextureScaleRatios;
|
||||
std::vector<LLVector3> mSilhouetteVertices; // array of vertices to render silhouette of object
|
||||
std::vector<LLVector3> mSilhouetteNormals; // array of normals to render silhouette of object
|
||||
bool mSilhouetteExists; // need to generate silhouette?
|
||||
bool mSilhouetteExists; // need to generate silhouette?
|
||||
S32 mSelectedGLTFNode = -1;
|
||||
S32 mSelectedGLTFPrimitive = -1;
|
||||
|
||||
|
|
|
|||
|
|
@ -583,10 +583,18 @@ void update_texture_fetch()
|
|||
|
||||
void set_flags_and_update_appearance()
|
||||
{
|
||||
LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
|
||||
LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op);
|
||||
// this may be called from a coroutine but has many side effects
|
||||
// in non-thread-safe classes, post to main loop
|
||||
auto work = []()
|
||||
{
|
||||
LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
|
||||
LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op);
|
||||
|
||||
LLInventoryModelBackgroundFetch::instance().start();
|
||||
};
|
||||
|
||||
LLAppViewer::instance()->postToMainCoro(work);
|
||||
|
||||
LLInventoryModelBackgroundFetch::instance().start();
|
||||
}
|
||||
|
||||
// Returns false to skip other idle processing. Should only return
|
||||
|
|
|
|||
|
|
@ -1944,7 +1944,7 @@ void LLTextureCtrl::onVisibilityChange(bool new_visibility)
|
|||
}
|
||||
}
|
||||
|
||||
void LLTextureCtrl::setVisible( bool visible )
|
||||
void LLTextureCtrl::setVisible(bool visible )
|
||||
{
|
||||
if( !visible )
|
||||
{
|
||||
|
|
@ -2053,6 +2053,9 @@ void LLTextureCtrl::showPicker(bool take_focus)
|
|||
if (texture_floaterp)
|
||||
{
|
||||
texture_floaterp->setOnFloaterCommitCallback(boost::bind(&LLTextureCtrl::onFloaterCommit, this, _1, _2, _3, _4, _5));
|
||||
}
|
||||
if (texture_floaterp)
|
||||
{
|
||||
texture_floaterp->setSetImageAssetIDCallback(boost::bind(&LLTextureCtrl::setImageAssetID, this, _1));
|
||||
|
||||
texture_floaterp->setBakeTextureEnabled(mBakeTextureEnabled);
|
||||
|
|
@ -2431,11 +2434,8 @@ void LLTextureCtrl::draw()
|
|||
}
|
||||
else
|
||||
{
|
||||
mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
|
||||
mTexturep->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
|
||||
mTexturep->forceToSaveRawImage(0);
|
||||
|
||||
preview = mTexturep;
|
||||
preview = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
|
||||
preview->setBoostLevel(LLGLTexture::BOOST_PREVIEW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ public:
|
|||
|
||||
void onVisibilityChange(bool new_visibility) override;
|
||||
|
||||
void setValid(BOOL valid);
|
||||
void setValid(bool valid);
|
||||
|
||||
// LLUICtrl interface
|
||||
void clear() override;
|
||||
|
|
|
|||
|
|
@ -251,6 +251,43 @@ bool LLTinyGLTFHelper::loadModel(const std::string& filename, tinygltf::Model& m
|
|||
return false;
|
||||
}
|
||||
|
||||
bool LLTinyGLTFHelper::saveModel(const std::string& filename, tinygltf::Model& model_in)
|
||||
{
|
||||
std::string exten = gDirUtilp->getExtension(filename);
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (exten == "gltf" || exten == "glb")
|
||||
{
|
||||
tinygltf::TinyGLTF writer;
|
||||
|
||||
std::string filename_lc = filename;
|
||||
LLStringUtil::toLower(filename_lc);
|
||||
|
||||
|
||||
bool embed_images = false;
|
||||
bool embed_buffers = false;
|
||||
bool pretty_print = true;
|
||||
bool write_binary = false;
|
||||
|
||||
|
||||
if (std::string::npos == filename_lc.rfind(".gltf"))
|
||||
{ // file is binary
|
||||
embed_images = embed_buffers = write_binary = true;
|
||||
}
|
||||
|
||||
success = writer.WriteGltfSceneToFile(&model_in, filename, embed_images, embed_buffers, pretty_print, write_binary);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
LL_WARNS("GLTF") << "Failed to save" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool LLTinyGLTFHelper::getMaterialFromModel(
|
||||
const std::string& filename,
|
||||
const tinygltf::Model& model_in,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ namespace LLTinyGLTFHelper
|
|||
LLImageRaw* getTexture(const std::string& folder, const tinygltf::Model& model, S32 texture_index, bool flip = true);
|
||||
|
||||
bool loadModel(const std::string& filename, tinygltf::Model& model_out);
|
||||
bool saveModel(const std::string& filename, tinygltf::Model& model_in);
|
||||
|
||||
bool getMaterialFromModel(
|
||||
const std::string& filename,
|
||||
|
|
|
|||
|
|
@ -1199,7 +1199,7 @@ void display_cube_face()
|
|||
LLSpatialGroup::sNoDelete = true;
|
||||
|
||||
S32 occlusion = LLPipeline::sUseOcclusion;
|
||||
LLPipeline::sUseOcclusion = 1; // occlusion data is from main camera point of view, don't read or write it during cube snapshots
|
||||
LLPipeline::sUseOcclusion = 0; // occlusion data is from main camera point of view, don't read or write it during cube snapshots
|
||||
//gDepthDirty = true; //let "real" render pipe know it can't trust the depth buffer for occlusion data
|
||||
|
||||
static LLCullResult result;
|
||||
|
|
|
|||
|
|
@ -1691,7 +1691,7 @@ void LLViewerMediaImpl::destroyMediaSource()
|
|||
cancelMimeTypeProbe();
|
||||
|
||||
{
|
||||
LLMutexLock lock(&mLock); // Delay tear-down while bg thread is updating
|
||||
LLCoros::LockType lock(mLock); // Delay tear-down while bg thread is updating
|
||||
if(mMediaSource)
|
||||
{
|
||||
mMediaSource->setDeleteOK(true) ;
|
||||
|
|
@ -3029,7 +3029,7 @@ bool LLViewerMediaImpl::preMediaTexUpdate(LLViewerMediaTexture*& media_tex, U8*&
|
|||
void LLViewerMediaImpl::doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* data, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool sync)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
|
||||
LLMutexLock lock(&mLock); // don't allow media source tear-down during update
|
||||
LLCoros::LockType lock(mLock); // don't allow media source tear-down during update
|
||||
|
||||
// wrap "data" in an LLImageRaw but do NOT make a copy
|
||||
LLPointer<LLImageRaw> raw = new LLImageRaw(data, media_tex->getWidth(), media_tex->getHeight(), media_tex->getComponents(), true);
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ private:
|
|||
|
||||
// Implementation functions not exported into header file
|
||||
class LLViewerMediaImpl
|
||||
: public LLMouseHandler, public LLRefCount, public LLPluginClassMediaOwner, public LLViewerMediaEventEmitter, public LLEditMenuHandler
|
||||
: public LLMouseHandler, public LLThreadSafeRefCount, public LLPluginClassMediaOwner, public LLViewerMediaEventEmitter, public LLEditMenuHandler
|
||||
{
|
||||
LOG_CLASS(LLViewerMediaImpl);
|
||||
public:
|
||||
|
|
@ -432,7 +432,7 @@ private:
|
|||
private:
|
||||
// a single media url with some data and an impl.
|
||||
std::shared_ptr<LLPluginClassMedia> mMediaSource;
|
||||
LLMutex mLock;
|
||||
LLCoros::Mutex mLock;
|
||||
F64 mZoomFactor;
|
||||
LLUUID mTextureId;
|
||||
bool mMovieImageHasMips;
|
||||
|
|
|
|||
|
|
@ -10041,7 +10041,7 @@ class LLAdvancedClickHDRIPreview: public view_listener_t
|
|||
};
|
||||
|
||||
|
||||
class LLAdvancedClickGLTFScenePreview : public view_listener_t
|
||||
class LLAdvancedClickGLTFOpen: public view_listener_t
|
||||
{
|
||||
bool handleEvent(const LLSD& userdata)
|
||||
{
|
||||
|
|
@ -10051,6 +10051,26 @@ class LLAdvancedClickGLTFScenePreview : public view_listener_t
|
|||
}
|
||||
};
|
||||
|
||||
class LLAdvancedClickGLTFSaveAs : public view_listener_t
|
||||
{
|
||||
bool handleEvent(const LLSD& userdata)
|
||||
{
|
||||
// open personal lighting floater when previewing an HDRI (keeps HDRI from implicitly unloading when opening build tools)
|
||||
LL::GLTFSceneManager::instance().saveAs();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class LLAdvancedClickGLTFDecompose : public view_listener_t
|
||||
{
|
||||
bool handleEvent(const LLSD& userdata)
|
||||
{
|
||||
// open personal lighting floater when previewing an HDRI (keeps HDRI from implicitly unloading when opening build tools)
|
||||
LL::GLTFSceneManager::instance().decomposeSelection();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// these are used in the gl menus to set control values that require shader recompilation
|
||||
class LLToggleShaderControl : public view_listener_t
|
||||
{
|
||||
|
|
@ -12504,7 +12524,9 @@ void initialize_menus()
|
|||
view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile");
|
||||
view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark");
|
||||
view_listener_t::addMenu(new LLAdvancedClickHDRIPreview(), "Advanced.ClickHDRIPreview");
|
||||
view_listener_t::addMenu(new LLAdvancedClickGLTFScenePreview(), "Advanced.ClickGLTFScenePreview");
|
||||
view_listener_t::addMenu(new LLAdvancedClickGLTFOpen(), "Advanced.ClickGLTFOpen");
|
||||
view_listener_t::addMenu(new LLAdvancedClickGLTFSaveAs(), "Advanced.ClickGLTFSaveAs");
|
||||
view_listener_t::addMenu(new LLAdvancedClickGLTFDecompose(), "Advanced.ClickGLTFDecompose");
|
||||
view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache");
|
||||
view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain");
|
||||
//[FIX FIRE-1927 - enable DoubleClickTeleport shortcut : SJ]
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@
|
|||
#include "llmeshrepository.h"
|
||||
#include "llgltfmateriallist.h"
|
||||
#include "llgl.h"
|
||||
#include "gltf/asset.h"
|
||||
// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a)
|
||||
#include "rlvactions.h"
|
||||
#include "rlvcommon.h"
|
||||
|
|
@ -4418,7 +4419,7 @@ LLMatrix4a LLViewerObject::getGLTFAssetToAgentTransform() const
|
|||
LLMatrix4 root;
|
||||
root.initScale(getScale());
|
||||
root.rotate(getRenderRotation());
|
||||
root.translate(getPositionAgent());
|
||||
root.translate(getRenderPosition());
|
||||
|
||||
LLMatrix4a mat;
|
||||
mat.loadu((F32*)root.mMatrix);
|
||||
|
|
@ -4442,7 +4443,7 @@ LLMatrix4a LLViewerObject::getAgentToGLTFAssetTransform() const
|
|||
scale.mV[1] = 1.f / scale.mV[1];
|
||||
scale.mV[2] = 1.f / scale.mV[2];
|
||||
|
||||
root.translate(-getPositionAgent());
|
||||
root.translate(-getRenderPosition());
|
||||
root.rotate(~getRenderRotation());
|
||||
|
||||
LLMatrix4 scale_mat;
|
||||
|
|
@ -4459,7 +4460,7 @@ LLMatrix4a LLViewerObject::getGLTFNodeTransformAgent(S32 node_index) const
|
|||
{
|
||||
LLMatrix4a mat;
|
||||
|
||||
if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size())
|
||||
if (mGLTFAsset && node_index >= 0 && node_index < mGLTFAsset->mNodes.size())
|
||||
{
|
||||
auto& node = mGLTFAsset->mNodes[node_index];
|
||||
|
||||
|
|
@ -4513,7 +4514,7 @@ void decomposeMatrix(const LLMatrix4a& mat, LLVector3& position, LLQuaternion& r
|
|||
|
||||
void LLViewerObject::setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion& rotation)
|
||||
{
|
||||
if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size())
|
||||
if (mGLTFAsset && node_index >= 0 && node_index < mGLTFAsset->mNodes.size())
|
||||
{
|
||||
auto& node = mGLTFAsset->mNodes[node_index];
|
||||
|
||||
|
|
@ -4545,7 +4546,7 @@ void LLViewerObject::setGLTFNodeRotationAgent(S32 node_index, const LLQuaternion
|
|||
|
||||
void LLViewerObject::moveGLTFNode(S32 node_index, const LLVector3& offset)
|
||||
{
|
||||
if (mGLTFAsset.notNull() && node_index >= 0 && node_index < mGLTFAsset->mNodes.size())
|
||||
if (mGLTFAsset && node_index >= 0 && node_index < mGLTFAsset->mNodes.size())
|
||||
{
|
||||
auto& node = mGLTFAsset->mNodes[node_index];
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,14 @@
|
|||
#include "llbbox.h"
|
||||
#include "llrigginginfo.h"
|
||||
#include "llreflectionmap.h"
|
||||
#include "gltf/asset.h"
|
||||
|
||||
namespace LL
|
||||
{
|
||||
namespace GLTF
|
||||
{
|
||||
class Asset;
|
||||
}
|
||||
}
|
||||
|
||||
#include "fsregioncross.h" // <FS:JN> Improved region crossing support
|
||||
|
||||
|
|
@ -753,7 +760,7 @@ public:
|
|||
F32 mPhysicsRestitution;
|
||||
|
||||
// Associated GLTF Asset
|
||||
LLPointer<LL::GLTF::Asset> mGLTFAsset;
|
||||
std::shared_ptr<LL::GLTF::Asset> mGLTFAsset;
|
||||
|
||||
// Pipeline classes
|
||||
LLPointer<LLDrawable> mDrawable;
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@
|
|||
#include "llcorehttputil.h"
|
||||
#include "llcallstack.h"
|
||||
#include "llsettingsdaycycle.h"
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
// Firestorm includes
|
||||
|
|
@ -2595,6 +2596,7 @@ bool LLViewerRegion::simulatorFeaturesReceived() const
|
|||
void LLViewerRegion::getSimulatorFeatures(LLSD& sim_features) const
|
||||
{
|
||||
sim_features = mSimulatorFeatures;
|
||||
|
||||
}
|
||||
|
||||
void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features)
|
||||
|
|
@ -2629,6 +2631,14 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features)
|
|||
gSavedSettings.setS32("max_texture_dimension_Y", 1024);
|
||||
}
|
||||
|
||||
bool mirrors_enabled = false;
|
||||
if (features.has("MirrorsEnabled"))
|
||||
{
|
||||
mirrors_enabled = features["MirrorsEnabled"].asBoolean();
|
||||
}
|
||||
|
||||
gSavedSettings.setBOOL("RenderMirrors", mirrors_enabled);
|
||||
|
||||
if (features.has("PBRTerrainEnabled"))
|
||||
{
|
||||
bool enabled = features["PBRTerrainEnabled"];
|
||||
|
|
@ -2650,11 +2660,8 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features)
|
|||
}
|
||||
};
|
||||
|
||||
auto workqueue = LL::WorkQueue::getInstance("mainloop");
|
||||
if (workqueue)
|
||||
{
|
||||
LL::WorkQueue::postMaybe(workqueue, work);
|
||||
}
|
||||
|
||||
LLAppViewer::instance()->postToMainCoro(work);
|
||||
|
||||
// <FS:CR> Opensim god names
|
||||
#ifdef OPENSIM
|
||||
|
|
|
|||
|
|
@ -6094,7 +6094,7 @@ bool LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
|
|||
// PRE SNAPSHOT
|
||||
gSnapshotNoPost = no_post;
|
||||
gDisplaySwapBuffers = false;
|
||||
|
||||
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // stencil buffer is deprecated | GL_STENCIL_BUFFER_BIT);
|
||||
setCursor(UI_CURSOR_WAIT);
|
||||
|
||||
|
|
@ -6554,7 +6554,7 @@ bool LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_
|
|||
|
||||
void display_cube_face();
|
||||
|
||||
BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face, F32 near_clip, bool dynamic_render, bool useCustomClipPlane, LLPlane clipPlane)
|
||||
bool LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face, F32 near_clip, bool dynamic_render, bool useCustomClipPlane, LLPlane clipPlane)
|
||||
{
|
||||
// NOTE: implementation derived from LLFloater360Capture::capture360Images() and simpleSnapshot
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
|
||||
|
|
|
|||
|
|
@ -339,7 +339,7 @@ public:
|
|||
LLView* getLoginPanelHolder() { return mLoginPanelHolder.get(); }
|
||||
bool handleKey(KEY key, MASK mask);
|
||||
bool handleKeyUp(KEY key, MASK mask);
|
||||
void handleScrollWheel(S32 clicks);
|
||||
void handleScrollWheel (S32 clicks);
|
||||
void handleScrollHWheel (S32 clicks);
|
||||
|
||||
// add and remove views from "popup" layer
|
||||
|
|
|
|||
|
|
@ -6597,40 +6597,46 @@ void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::ESta
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LL_DEBUGS("Voice")
|
||||
<< " " << LLVoiceClientStatusObserver::status2string(status)
|
||||
<< ", session URI " << getAudioSessionURI()
|
||||
<< ", proximal is " << inSpatialChannel()
|
||||
<< LL_ENDL;
|
||||
|
||||
for (status_observer_set_t::iterator it = mStatusObservers.begin();
|
||||
it != mStatusObservers.end();
|
||||
)
|
||||
{
|
||||
LLVoiceClientStatusObserver* observer = *it;
|
||||
observer->onChange(status, getAudioSessionURI(), inSpatialChannel());
|
||||
// In case onError() deleted an entry.
|
||||
it = mStatusObservers.upper_bound(observer);
|
||||
}
|
||||
// this function is called from a coroutine, shuttle application hook back to main loop
|
||||
auto work = [=]()
|
||||
{
|
||||
for (status_observer_set_t::iterator it = mStatusObservers.begin();
|
||||
it != mStatusObservers.end();
|
||||
)
|
||||
{
|
||||
LLVoiceClientStatusObserver* observer = *it;
|
||||
observer->onChange(status, getAudioSessionURI(), inSpatialChannel());
|
||||
// In case onError() deleted an entry.
|
||||
it = mStatusObservers.upper_bound(observer);
|
||||
}
|
||||
|
||||
// skipped to avoid speak button blinking
|
||||
if ( status != LLVoiceClientStatusObserver::STATUS_JOINING
|
||||
&& status != LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL
|
||||
&& status != LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED)
|
||||
{
|
||||
// <FS:Ansariel> Bypass LLCachedControls for voice status update
|
||||
//bool voice_status = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
|
||||
bool voice_status = LLVoiceClient::getInstance()->voiceEnabled(true) && LLVoiceClient::getInstance()->isVoiceWorking();
|
||||
// </FS:Ansariel>
|
||||
// skipped to avoid speak button blinking
|
||||
if (status != LLVoiceClientStatusObserver::STATUS_JOINING
|
||||
&& status != LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL
|
||||
&& status != LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED)
|
||||
{
|
||||
// <FS:Ansariel> Bypass LLCachedControls for voice status update
|
||||
//bool voice_status = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking();
|
||||
bool voice_status = LLVoiceClient::getInstance()->voiceEnabled(true) && LLVoiceClient::getInstance()->isVoiceWorking();
|
||||
// </FS:Ansariel>
|
||||
|
||||
gAgent.setVoiceConnected(voice_status);
|
||||
gAgent.setVoiceConnected(voice_status);
|
||||
|
||||
if (voice_status)
|
||||
{
|
||||
LLFirstUse::speak(true);
|
||||
}
|
||||
}
|
||||
if (voice_status)
|
||||
{
|
||||
LLFirstUse::speak(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
LLAppViewer::instance()->postToMainCoro(work);
|
||||
}
|
||||
|
||||
void LLVivoxVoiceClient::addObserver(LLFriendObserver* observer)
|
||||
|
|
|
|||
|
|
@ -4852,7 +4852,8 @@ LLVector3 LLVOVolume::volumeDirectionToAgent(const LLVector3& dir) const
|
|||
|
||||
|
||||
bool LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32 *face_hitp,
|
||||
LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
|
||||
LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
|
||||
|
||||
{
|
||||
if (!mbCanSelect
|
||||
|| mDrawable->isDead()
|
||||
|
|
|
|||
|
|
@ -842,7 +842,6 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
|
|||
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
|
||||
if (mRT == &mMainRT)
|
||||
{ // hacky -- allocate auxillary buffer
|
||||
|
||||
gCubeSnapshot = true;
|
||||
mReflectionMapManager.initReflectionMaps();
|
||||
mHeroProbeManager.initReflectionMaps();
|
||||
|
|
@ -7482,7 +7481,7 @@ void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst)
|
|||
LLVector4a result;
|
||||
result.clear();
|
||||
|
||||
gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, false, false, true, true, nullptr, nullptr, nullptr, &result);
|
||||
gViewerWindow->cursorIntersect(-1, -1, 512.f, nullptr, -1, false, false, true, true, nullptr, nullptr, nullptr, &result);
|
||||
|
||||
focus_point.set(result.getF32ptr());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4112,6 +4112,30 @@
|
|||
parameter="mem_leaking" />
|
||||
</menu_item_call>
|
||||
</menu>
|
||||
<menu
|
||||
create_jump_keys="true"
|
||||
label="GLTF"
|
||||
name="GLTF"
|
||||
tear_off="true">
|
||||
<menu_item_call
|
||||
label="Open..."
|
||||
name="Open...">
|
||||
<menu_item_call.on_click
|
||||
function="Advanced.ClickGLTFOpen" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="Save As..."
|
||||
name="Save As...">
|
||||
<menu_item_call.on_click
|
||||
function="Advanced.ClickGLTFSaveAs" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="Decompose..."
|
||||
name="Decompose...">
|
||||
<menu_item_call.on_click
|
||||
function="Advanced.ClickGLTFDecompose" />
|
||||
</menu_item_call>
|
||||
</menu>
|
||||
<menu
|
||||
create_jump_keys="true"
|
||||
label="Render Tests"
|
||||
|
|
@ -4164,12 +4188,6 @@
|
|||
<menu_item_call.on_click
|
||||
function="Advanced.ClickHDRIPreview" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="GLTF Scene Preview"
|
||||
name="GLTF Scene Preview">
|
||||
<menu_item_call.on_click
|
||||
function="Advanced.ClickGLTFScenePreview" />
|
||||
</menu_item_call>
|
||||
</menu>
|
||||
<menu
|
||||
create_jump_keys="true"
|
||||
|
|
|
|||
|
|
@ -14347,7 +14347,7 @@ This will replace the items in the selected outfit with the items you are wearin
|
|||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="GLTFPreviewSelection"
|
||||
name="GLTFOpenSelection"
|
||||
type="alert">
|
||||
You must select an object to act as a handle to the GLTF asset you are previewing.
|
||||
<tag>fail</tag>
|
||||
|
|
@ -14356,6 +14356,17 @@ This will replace the items in the selected outfit with the items you are wearin
|
|||
yestext="OK"/>
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="GLTFSaveSelection"
|
||||
type="alert">
|
||||
You must select an object that has a GLTF asset associated with it.
|
||||
<tag>fail</tag>
|
||||
<usetemplate
|
||||
name="okbutton"
|
||||
yestext="OK"/>
|
||||
</notification>
|
||||
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
|
|
|
|||
Loading…
Reference in New Issue